Skip to content

fix(tools): don't leak unparsed tool-call JSON to the user (closes #378) - #380

Merged
ai-hpc merged 2 commits into
mainfrom
fix/leak-unparsed-tool-call-378
Jun 3, 2026
Merged

fix(tools): don't leak unparsed tool-call JSON to the user (closes #378)#380
ai-hpc merged 2 commits into
mainfrom
fix/leak-unparsed-tool-call-378

Conversation

@ai-hpc

@ai-hpc ai-hpc commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #378. Found during Jetson validation (#375): when the local model emits a
tool-call-shaped output that is not valid JSON (e.g. {"tool":"set_timer","arguments":{"seconds":60*60*12,...}}60*60*12 is a JS expression), try_tool_call_with_context returns None and the chat paths rendered the raw model output to the user verbatim, leaking tool-call JSON.

Changes

  • tools/parser.rs — add is_unparsed_tool_call() (structurally looks like a tool call but no valid tool-call JSON can be extracted) + UNPARSED_TOOL_CALL_FALLBACK, with unit tests (incl. the exact Jetson leak string).
  • tools/mod.rs — re-export both.
  • server.rs — guard the three API chat render sites — /api/chat/stream, /api/chat, and the OpenAI-compatible bridge — so a botched tool call falls back to a graceful reply instead of the raw JSON. Default/normal replies are unchanged.

Scope note

Voice and REPL stream + speak the response incrementally, so guarding them is a separate, more involved change (post-stream rewrite); noted as follow-up. This PR fixes the observed surface (the port-3000 chat API). It does not close the umbrella #375.

The model emitting invalid JSON / picking the wrong tool is tracked separately in #379 (routing accuracy); this PR only stops the leak.

Real Behavior Proof

  • I have built and run the affected code locally.
  • I have verified the change end-to-end on Jetson hardware.
  • I have NOT verified on Jetson hardware, and I explain the validation gap below.

Tested profile / hardware:

  • laptop

What I ran

cargo build -p genie-core
cargo test -p genie-core --lib tools::parser
cargo test -p genie-core --lib -- --skip binary_size_budget
cargo fmt --all --check
cargo clippy --workspace --all-targets --locked -- -D warnings

What I observed

  • fmt + clippy clean; 704 genie-core lib tests pass incl. 3 new detector tests (the invalid-JSON leak string is detected; valid tool calls and normal prose are not flagged).
  • Pure agent-side render-boundary logic — no Jetson runtime path touched. The original leak was reproduced on Jetson under Validate tool-dispatch gate + memory subsystem on Jetson Orin Nano 8GB #375; on-device re-confirmation that the fallback now shows instead of raw JSON is the remaining gap.

When the local model emits a tool-call-shaped output that is not valid JSON
(e.g. {"seconds": 60*60*12}, observed on Jetson), try_tool_call_with_context
returns None and the chat paths' else branch rendered the raw model output to
the user verbatim. Add is_unparsed_tool_call() + a fallback message and guard
the three API chat render sites (/api/chat/stream, /api/chat, and the
OpenAI-compatible bridge) so a botched tool call falls back to a graceful reply
instead of leaking raw tool-call JSON.

Voice and REPL stream/speak incrementally; guarding those is noted as follow-up.
@ai-hpc ai-hpc added the M1 M1: Jetson 4096-token BFCL agent harness focus label Jun 3, 2026
The desktop session (display manager + X/Wayland + shell) holds a few hundred
MB of the Orin Nano's 8 GB unified memory — the same pool the local LLM/KV-cache
competes for. This adds a reversible, idempotent helper to drop to a console
(multi-user) target and free that memory now and across reboots, with an
--enable flag to restore the GUI.
@ai-hpc

ai-hpc commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

Also bundling deploy/scripts/genie-disable-gui.sh into this PR (per request): a reversible helper to disable the desktop GUI on Jetson and free unified memory for the local LLM (relevant to #375/#376 memory pressure). Standalone deploy script — no Rust changes, doesn't affect the build/tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

M1 M1: Jetson 4096-token BFCL agent harness focus

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tool-call gate: unparsed tool-call JSON is rendered to the user as a reply

1 participant