zot/internal/core
patriceckhart c16e929f32 fix(core): repair orphan tool_use rows on session load
Resuming a session whose transcript contains an assistant
tool_use block without a matching tool_result in the next
message caused Anthropic (and OpenAI's responses API) to
refuse the first request with:

  http 400: messages.N: `tool_use` ids were found without
  `tool_result` blocks immediately after: toolu_...

Two ways the corrupt state gets onto disk:

  - Older zot builds persisted the assistant tool_use row
    before the tool_result row, then crashed or were killed
    between the two writes.
  - Earlier abort paths didn't drop the mid-turn assistant
    message cleanly before it reached the session file.

OpenSession now passes the hydrated message slice through
repairToolUseResultPairs before returning it. For every
assistant tool_use whose id isn't covered by a tool_result in
the next message, the repair injects a stub

  ToolResultBlock{
    CallID:  <id>,
    Content: [TextBlock{"tool call was aborted; no result recorded."}],
    IsError: true,
  }

The stub is merged into the following tool-role message if
one exists (preserves row count), otherwise a new tool-role
message is inserted right after the assistant. Model sees
the aborted context and decides whether to retry.

Runs once per OpenSession call; the hot runtime path is
untouched. Live abort handling already drops partial
assistant messages, so this is purely a safety net for
legacy-corrupted files and the crash-between-writes case.

Tests in session_repair_test.go cover:

  - stub appended when no tool-role message follows
  - stub merged into partial tool-role message
  - valid transcripts pass through unchanged
  - nil/empty input handled safely
2026-04-21 19:36:47 +02:00
..
agent.go feat(tui): live-stream file body during write/edit tool calls 2026-04-20 08:37:14 +02:00
compact.go initial commit 2026-04-17 20:36:38 +02:00
confirm.go fix(no-yolo): don't auto-refuse tool calls in non-interactive modes 2026-04-19 19:17:05 +02:00
confirm_test.go feat(tool-gate): --no-yolo flag, confirm dialog, /yolo runtime toggle 2026-04-19 19:12:45 +02:00
core_test.go fix ci on windows: close reopened session in TestSessionRoundTrip 2026-04-18 11:01:42 +02:00
cost.go initial commit 2026-04-17 20:36:38 +02:00
events.go feat(tui): live-stream file body during write/edit tool calls 2026-04-20 08:37:14 +02:00
intercept_test.go feat(ext): phase 4 - full-event interception, arg rewrites, /reload-ext 2026-04-19 17:02:04 +02:00
session.go fix(core): repair orphan tool_use rows on session load 2026-04-21 19:36:47 +02:00
session_portable.go feat(session): /session fork + /session tree 2026-04-20 11:10:56 +02:00
session_portable_test.go feat(session): /session fork + /session tree 2026-04-20 11:10:56 +02:00
session_repair_test.go fix(core): repair orphan tool_use rows on session load 2026-04-21 19:36:47 +02:00
tool.go perf(anthropic): fix cost double-count, tighten caching, correct catalog 2026-04-19 18:57:18 +02:00