You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When the utility gate intercepts a tool call (Retrieve/Respond/Verify/Stop action), the LLM assistant message containing the tool_use block is saved to SQLite via persist_message. The matching user message with the ToolResult ([skipped]/[stopped] text) should also be saved via save_only, but on the next session startup the orphan repair in sanitize_tool_pairs fires and emits WARN for the same tool_use ID.
WARN zeph_core::agent::persistence: stripping orphaned mid-history tool_use parts from assistant message tool_ids={"call_vPsWTzWOGWyIb29CukSynS6v"} index=7
WARN zeph_core::agent::persistence: stripping orphaned mid-history tool_result parts from user message tool_use_ids={"call_vPsWTzWOGWyIb29CukSynS6v"} index=8
WARN zeph_core::agent::persistence: skipped 2 empty/orphaned message(s) from history
Expected Behavior
No orphaned tool pairs in history after a utility-gated session. If a tool_use is saved, its matching tool_result must also be loadable on the next startup.
Actual Behavior
The sanitize_tool_pairs repair fires on session startup, emitting 3 WARN messages and soft-deleting the orphaned message pair from SQLite.
First observed in CI-571 session.log. The orphaned tool_use ID call_vPsWTzWOGWyIb29CukSynS6v corresponds to an invoke_skill call that was intercepted by the utility gate (Retrieve action) in the previous session.
Root cause hypothesis: the tool_use message is saved by the assistant turn persist path, but the matching user tool_result message may be saved with a Retrieve-action system hint injected between them — causing orphaned_tool_use_ids() to see a System message as next_msg instead of the User tool_result message.
Related: #3163 (invoke_skill blocked by utility gate — the proximate cause of the intercepted call)
Description
When the utility gate intercepts a tool call (Retrieve/Respond/Verify/Stop action), the LLM assistant message containing the
tool_useblock is saved to SQLite viapersist_message. The matchingusermessage with theToolResult([skipped]/[stopped] text) should also be saved viasave_only, but on the next session startup the orphan repair insanitize_tool_pairsfires and emits WARN for the same tool_use ID.Reproduction Steps
Retrieveaction)Expected Behavior
No orphaned tool pairs in history after a utility-gated session. If a tool_use is saved, its matching tool_result must also be loadable on the next startup.
Actual Behavior
The
sanitize_tool_pairsrepair fires on session startup, emitting 3 WARN messages and soft-deleting the orphaned message pair from SQLite.Environment
Logs / Evidence
First observed in CI-571 session.log. The orphaned tool_use ID
call_vPsWTzWOGWyIb29CukSynS6vcorresponds to aninvoke_skillcall that was intercepted by the utility gate (Retrieve action) in the previous session.Root cause hypothesis: the tool_use message is saved by the assistant turn persist path, but the matching user tool_result message may be saved with a
Retrieve-action system hint injected between them — causingorphaned_tool_use_ids()to see a System message asnext_msginstead of the User tool_result message.Related: #3163 (invoke_skill blocked by utility gate — the proximate cause of the intercepted call)