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

Callers 1

PackFunction · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected