fix: Fold tool results as user messages instead of imitable text pattern

Gemini 2.5 flash doesn't return thought_signature, causing
collapseToolCallsWithoutSig to convert tool_calls to "(Used tool ...)"
text that Gemini imitates instead of making real tool calls.

Now strips tool_calls and folds results into plain user messages
so the model retains context without an imitable pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
viettranxandClaude Opus 4.6 committed 2026-02-27 21:03:44 +07:00
1 parent ef3c35a8b5
commit 40425d3ad2
1 file changed
+17 -4
+17 -4
View File
@@ -1,11 +1,14 @@
package providers
// collapseToolCallsWithoutSig strips tool_call cycles that lack thought_signature
import "strings"
// collapseToolCallsWithoutSig rewrites tool_call cycles that lack thought_signature
// (required by Gemini 2.5+). Old session history stored before the thought_signature
// capture fix doesn't have it, and Gemini rejects those messages with HTTP 400.
//
// The assistant's original text content (if any) is preserved; only the tool_calls
// and their corresponding tool-result messages are dropped.
// The assistant's tool_calls are stripped, and the corresponding tool-result messages
// are folded into a single user message with the tool output content. This preserves
// context for the model without using a format that triggers tool-call imitation.
func collapseToolCallsWithoutSig(msgs []Message) []Message {
// Collect tool_call IDs that need collapsing.
collapseIDs := make(map[string]bool)
@@ -39,9 +42,19 @@ func collapseToolCallsWithoutSig(msgs []Message) []Message {
})
}
// Skip consecutive tool results belonging to these tool_calls.
// Collect consecutive tool results → fold into one user message.
var parts []string
for i+1 < len(msgs) && msgs[i+1].Role == "tool" && collapseIDs[msgs[i+1].ToolCallID] {
i++
if content := strings.TrimSpace(msgs[i].Content); content != "" {
parts = append(parts, content)
}
}
if len(parts) > 0 {
result = append(result, Message{
Role: "user",
Content: strings.Join(parts, "\n\n"),
})
}
continue
}