MCPcopy Create free account
hub / github.com/codehamr/codehamr / dropDanglingToolCalls

Function dropDanglingToolCalls

internal/ctx/ctx.go:360–390  ·  view source on GitHub ↗

dropDanglingToolCalls removes any assistant message whose tool_calls include an id with no answering tool message in the kept slice: the mirror of dropOrphanTools. An assistant.tool_calls followed by fewer tool results than calls issued 400s every OpenAI-compatible backend with "missing tool respons

(kept []Message)

Source from the content-addressed store, hash-verified

358 out = append(out, m)
359 }
360 return out
361}
362
363// dropDanglingToolCalls removes any assistant message whose tool_calls include
364// an id with no answering tool message in the kept slice: the mirror of
365// dropOrphanTools. An assistant.tool_calls followed by fewer tool results than
366// calls issued 400s every OpenAI-compatible backend with "missing tool
367// response". This shape is produced whenever a turn is aborted mid-tool: the
368// TUI appends the assistant.tool_calls as soon as the round closes, but a Ctrl+C
369// / stream-error / idle-stall then drops the pending calls so their tool results
370// never arrive (see tui.endTurn). On the user's next request that dangling
371// assistant would otherwise reach the wire and wedge the conversation until
372// /clear. Empty ids count as unanswered: an unidentifiable call can't be paired.
373func dropDanglingToolCalls(kept []Message) []Message {
374 out := kept[:0]
375 for i, m := range kept {
376 if m.Role == RoleAssistant && len(m.ToolCalls) > 0 {
377 // Answers must come from the contiguous run of tool messages that
378 // follows THIS assistant, the only shape the wire accepts. A global
379 // ID lookup would let a later turn's reused ID (index-derived
380 // "call_0"-style IDs are common on local backends) vouch for an
381 // aborted call here, sending the dangling assistant to the wire and
382 // wedging the conversation with 400s until /clear.
383 answered := map[string]bool{}
384 for j := i + 1; j < len(kept) && kept[j].Role == RoleTool; j++ {
385 if kept[j].ToolCallID != "" {
386 answered[kept[j].ToolCallID] = true
387 }
388 }
389 dangling := false
390 for _, tc := range m.ToolCalls {
391 if !answered[tc.ID] {
392 dangling = true
393 break

Callers 1

PackFunction · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected