fix(seahorse): prevent tool-call format leakage into LLM summaries#3279
Open
MrTreasure wants to merge 1 commit into
Open
fix(seahorse): prevent tool-call format leakage into LLM summaries#3279MrTreasure wants to merge 1 commit into
MrTreasure wants to merge 1 commit into
Conversation
partsToReadableContent used [tool_use: name, args: {...}] format for
FTS5 indexing and summary generation. When summaries containing this
format were fed back to LLMs, the models learned to mimic it and output
mock [tool_use: ...] text as content, which was then displayed to users.
Two fixes:
1. formatMessagesForSummary / truncateSummary: skip messages with empty
content (pure tool calls/results) — these are mechanical, not
conversational, and have no place in summaries.
2. partsToReadableContent: use emoji markers (🔧/📋) instead of the
bracket-colon format that LLMs are prone to mimic.
3. outboundMessageForTurn: strip any residual [tool_use: ...] patterns
from content before sending to channels, as a safety net.
Root cause: same class of bug as sipeed#3153 (Doubao <seed:tool_call> leak).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related: same symptom triggered by seahorse summaries
I just hit this exact class of bug — tool-call format leaking into user messages — but triggered through a different path: seahorse's
partsToReadableContent.The seahorse variant
partsToReadableContent(inpkg/seahorse/store.go) serializes tool calls as[tool_use: name, args: {...}]for FTS5 indexing. This format was also used as a fallback in two summary-generation paths (formatMessagesForSummaryandtruncateSummaryinshort_compaction.go). When summaries containing[tool_use: exec, args: {...}]were fed back into the LLM context, the model learned to mimic this format in its own responses — outputting mock tool calls as visible text content.The pipeline
Fix
PR incoming at: https://github.com/sipeed/picoclaw/pulls (MrTreasure:fix/seahorse-tool-call-leak)
Three changes:
short_compaction.go: Skip messages with empty content in summary/truncation paths — tool calls aren't conversational contentstore.go: Change FTS5 format from[tool_use: name, args: {...}]to emoji markers — the bracket-colon pattern is what LLMs latch ontoagent_utils.go: Strip residual[tool_use: ...]from outbound messages as a safety netSame root cause as this issue: LLM context leaking internal serialization format → model mimics it → user sees raw tool-call text. Different trigger (seahorse vs Doubao provider), same outcome.