mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-14 12:16:54 +00:00
fix(agent): defer warning messages after parallel tool results
When parallel tool calls trigger loop detection warnings, the warning messages (role="user") were inserted between tool result messages (role="tool"). This breaks the Anthropic API when routed through OpenAI-compatible proxies (e.g. LiteLLM): the proxy groups consecutive tool messages into a single user message with tool_result blocks, but an intervening user warning splits the group, causing orphaned tool_results and HTTP 400 "tool_use ids without tool_result blocks". Fix: accumulate warning messages during parallel result processing and append them after all tool results, preserving the consecutive grouping. Closes #642
This commit is contained in:
1 parent
bfd65828a6
commit
4e4a835795
1 file changed
+9
-1
@@ -699,7 +699,13 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (result *RunResult,
|
||||
|
||||
// 5. Process results sequentially: emit events, append messages, save to session
|
||||
// Note: tool span start/end already emitted inside goroutines above.
|
||||
// IMPORTANT: warning messages (role="user") must be deferred until AFTER all
|
||||
// tool results are appended. Inserting a user message between tool results
|
||||
// breaks the Anthropic API requirement that all tool_results for a set of
|
||||
// tool_uses must be consecutive (causes "tool_use ids without tool_result"
|
||||
// errors when routed through LiteLLM OpenAI→Anthropic conversion).
|
||||
var loopStuck bool
|
||||
var deferredWarnings []providers.Message
|
||||
for _, r := range collected {
|
||||
// Record tool execution time for adaptive thresholds.
|
||||
toolTiming.Record(r.tc.Name, time.Since(r.spanStart).Milliseconds())
|
||||
@@ -708,12 +714,14 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (result *RunResult,
|
||||
toolMsg, warningMsgs, action := l.processToolResult(ctx, rs, &req, emitRun, r.tc, r.registryName, r.result, hadBootstrap)
|
||||
messages = append(messages, toolMsg)
|
||||
rs.pendingMsgs = append(rs.pendingMsgs, toolMsg)
|
||||
messages = append(messages, warningMsgs...)
|
||||
deferredWarnings = append(deferredWarnings, warningMsgs...)
|
||||
if action == toolResultBreak {
|
||||
loopStuck = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// Append deferred warnings after all tool results to preserve consecutive grouping.
|
||||
messages = append(messages, deferredWarnings...)
|
||||
|
||||
// Check read-only streak after processing all parallel results.
|
||||
if !loopStuck {
|
||||
|
||||
Reference in new issue
Block a user