fix(chat): prevent double-escape corruption of messages/tools in agentic bridge #20

Open
will.anderson wants to merge 2 commits from fix/bridge-save-serialization into main
Owner

Summary

  • bridge_save was calling json_safe() on messages and tools_json before storing them as JSON string fields. Both values are already well-formed JSON arrays containing double quotes, so json_safe added a second escape layer. agentic_resume called json_get() which strips only one layer, leaving the messages array corrupted before passing it back to agentic_loop.
  • Fix: store messages as messages_raw and tools_json as tools_raw as inline raw JSON values (not string-escaped), and read them back with json_get_raw. Scalar strings (model, safe_sys, tools_log, tool_use_id) remain as string fields via json_safe/json_get since they do not contain nested JSON structure.
  • Backward compatibility: agentic_resume falls back to the old string-escaped fields if the raw fields are absent, so any session suspended before this fix can still be resumed.
  • Also fixes write_file returning a pre-escaped literal instead of calling json_safe consistently with every other tool result.

Test plan

  • Trigger an agentic session that suspends on an MCP tool (bridge save)
  • POST the tool result to resume -- verify the messages array is intact and the conversation continues correctly
  • Verify multi-turn agentic chaining (multiple tool suspensions in sequence) works end-to-end
  • Verify write_file tool result parses correctly in the tool loop
## Summary - `bridge_save` was calling `json_safe()` on `messages` and `tools_json` before storing them as JSON string fields. Both values are already well-formed JSON arrays containing double quotes, so `json_safe` added a second escape layer. `agentic_resume` called `json_get()` which strips only one layer, leaving the messages array corrupted before passing it back to `agentic_loop`. - Fix: store `messages` as `messages_raw` and `tools_json` as `tools_raw` as inline raw JSON values (not string-escaped), and read them back with `json_get_raw`. Scalar strings (`model`, `safe_sys`, `tools_log`, `tool_use_id`) remain as string fields via `json_safe`/`json_get` since they do not contain nested JSON structure. - Backward compatibility: `agentic_resume` falls back to the old string-escaped fields if the raw fields are absent, so any session suspended before this fix can still be resumed. - Also fixes `write_file` returning a pre-escaped literal instead of calling `json_safe` consistently with every other tool result. ## Test plan - [ ] Trigger an agentic session that suspends on an MCP tool (bridge save) - [ ] POST the tool result to resume -- verify the messages array is intact and the conversation continues correctly - [ ] Verify multi-turn agentic chaining (multiple tool suspensions in sequence) works end-to-end - [ ] Verify `write_file` tool result parses correctly in the tool loop
will.anderson added 2 commits 2026-06-15 18:07:36 +00:00
The first registration called route_sessions() which searched for a
'session-start' label that no longer exists, returning an empty array
on every list request and making the sidebar appear empty after restart.
The second registration (dead code) called the correct session_list().

Removes route_sessions() entirely and the stale first route block.
Also wires up session_delete() and session_update_patch() — both existed
in sessions.el but had no HTTP routes — via new DELETE and PATCH blocks.
bridge_save was wrapping messages and tools_json with json_safe() before
storing them as string fields. Since both are already well-formed JSON arrays
containing double quotes, json_safe added a second escape layer. agentic_resume
then called json_get() which stripped only one layer, leaving the messages array
corrupted before it was passed back into agentic_loop.

Fix: store messages as messages_raw and tools_json as tools_raw as inline raw
JSON values (unquoted), and read them back with json_get_raw. Backward
compatibility: fall back to the old string-escaped fields if the raw fields are
absent, so sessions saved before this fix can still be resumed.

Also fixes write_file returning a pre-escaped literal instead of calling
json_safe consistently with every other tool result.
Some required checks failed
Neuron Soul CI / build (pull_request) Failing after 12m13s
You are not authorized to merge this pull request.
This pull request can be merged automatically.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin fix/bridge-save-serialization:fix/bridge-save-serialization
git checkout fix/bridge-save-serialization
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: neuron-technologies/neuron#20