zot/internal
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 fix(tui): slash popup + transient overlays swallow esc before busy-cancel 2026-04-21 18:32:22 +02:00
assets assets: refresh zot logo to cleaner pixel-art Z 2026-04-20 12:01:43 +02:00
auth feat(auth,tui): dark login pages + /logout picker 2026-04-19 20:14:22 +02:00
core fix(core): repair orphan tool_use rows on session load 2026-04-21 19:36:47 +02:00
extproto feat(ext): phase 4 - full-event interception, arg rewrites, /reload-ext 2026-04-19 17:02:04 +02:00
provider perf(anthropic): fix cost double-count, tighten caching, correct catalog 2026-04-19 18:57:18 +02:00
skills perf(prompt): cut system prompt to the bone (410 -> 54 tokens) 2026-04-19 17:39:38 +02:00
tui tweak(tui): image-block spacing + indent 2026-04-21 19:12:04 +02:00