Skip to content

fix(agent): repair transcript pairing after compaction and truncation#1470

Open
daotri wants to merge 1 commit into
nextlevelbuilder:mainfrom
daotri:fix/transcript-pairing-after-compaction
Open

fix(agent): repair transcript pairing after compaction and truncation#1470
daotri wants to merge 1 commit into
nextlevelbuilder:mainfrom
daotri:fix/transcript-pairing-after-compaction

Conversation

@daotri

@daotri daotri commented Jul 23, 2026

Copy link
Copy Markdown

Problem

When a conversation is compacted mid-loop or truncated by the background
summarizer, the split point could land in the middle of a tool-chain,
leaving an orphaned role:"tool" message with no preceding
assistant message carrying tool_calls. Providers reject this — OpenAI
returns a 400 on the next request.

Fix

Repair transcript pairing at both truncation points, addressing the
root cause rather than a single call site:

  1. Mid-loop compaction — the compacted slice (persisted verbatim as run
    history) now runs through sanitizeHistory, so orphaned tool messages
    never reach the provider. A slog.Warn("post_compaction_sanitize", ...)
    surfaces when a repair happens.
  2. Background summarization — truncation now walks back to a clean
    tool-chain boundary via a shared toolChainSplitIndex helper, so the kept
    tail never starts mid tool-chain.

The backward-walk logic (previously inlined in compaction) is extracted into
toolChainSplitIndex and reused by both paths, with an added bounds guard
(splitIdx < len(messages)) that also fixes a latent out-of-range access when
the split index equals the message count.

Changes

File Change
internal/agent/loop_compact.go Extract shared toolChainSplitIndex helper
internal/agent/loop_history_sanitize.go Summarizer truncates on tool-chain boundary
internal/agent/loop_pipeline_callbacks.go Sanitize compacted history before persist
internal/agent/loop_compact_boundary_test.go Table-driven unit tests (new)

Testing

  • go build ./internal/agent/
  • go vet ./internal/agent/
  • go test ./internal/agent/ -run 'TestToolChainSplitIndex|TestMakeCompactMessages_SanitizesOrphanTool|TestMaybeSummarize_ToolChainBoundary'

New unit tests cover: clean boundary stays put, split on tool result walks
back before assistant(tool_calls), consecutive tool results walk the whole
chain, compaction callback sanitizes orphans, and summarizer truncates on the
tool-chain boundary.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Eeg3HGEWSqhPxsSQKAbe2x

Mid-loop compaction output now runs through sanitizeHistory so orphaned
tool messages never reach the provider (OpenAI rejects role:tool without
a preceding assistant tool_calls). Background summarization truncates on
tool-chain boundaries via the shared toolChainSplitIndex helper so the
kept tail never starts mid tool-chain.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants