Fix auto-memory JSON leak: tool call printed raw to UI
The JSON filter only suppresses tool calls at line boundaries. When
"Memory checkpoint: " was printed without a trailing newline, the LLM
response `{"tool": "remember", ...}` appeared on the same line and
leaked through to the UI.
Fix:
- Add trailing newline to "Memory checkpoint:" message
- Reset JSON filter state before streaming the response
Added test: test_tool_call_not_at_line_start_passes_through
Documents the filter behavior and references the fix location.
This commit is contained in:
@@ -487,4 +487,25 @@ mod tests {
|
||||
let result = filter_json_tool_calls(input);
|
||||
assert_eq!(result, "Before\n\nAfter");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tool_call_not_at_line_start_passes_through() {
|
||||
// IMPORTANT: Tool calls that don't start at a line boundary should NOT be filtered.
|
||||
// This is by design - the filter only suppresses tool calls that appear at the
|
||||
// start of a line (after newline + optional whitespace).
|
||||
//
|
||||
// This test documents the behavior that caused the "auto-memory JSON leak" bug:
|
||||
// When "Memory checkpoint: " was printed without a trailing newline, the LLM's
|
||||
// response `{"tool": "remember", ...}` appeared on the same line and was not
|
||||
// filtered. The fix was to ensure the prompt ends with a newline AND reset
|
||||
// the filter state before streaming.
|
||||
//
|
||||
// See: send_auto_memory_reminder() in g3-core/src/lib.rs
|
||||
reset_json_tool_state();
|
||||
|
||||
// Tool call immediately after text on same line - should NOT be filtered
|
||||
let input = "Memory checkpoint: {\"tool\": \"remember\", \"args\": {}}";
|
||||
let result = filter_json_tool_calls(input);
|
||||
assert_eq!(result, input, "Tool calls not at line start should pass through");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1541,7 +1541,15 @@ impl<W: UiWriter> Agent<W> {
|
||||
tools_called.len(),
|
||||
tools_called
|
||||
);
|
||||
self.ui_writer.print_context_status("\nMemory checkpoint: ");
|
||||
// IMPORTANT: The message MUST end with a newline so the LLM's response starts on a new line.
|
||||
// The JSON filter only suppresses tool calls that appear at line boundaries (after newline).
|
||||
// Without the trailing newline, tool call JSON like `{"tool": "remember", ...}` would
|
||||
// appear on the same line as "Memory checkpoint:" and leak through to the UI.
|
||||
// See test: test_tool_call_not_at_line_start_passes_through in filter_json.rs
|
||||
self.ui_writer.print_context_status("\nMemory checkpoint:\n");
|
||||
|
||||
// Reset JSON filter state so it starts fresh for this response
|
||||
self.ui_writer.reset_json_filter();
|
||||
|
||||
let reminder = r#"MEMORY CHECKPOINT: If you discovered code locations worth remembering, call `remember` now.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user