Merge #21: repair dangling tool_use on every request, not just load
Some checks are pending
ci / test (macos-latest) (push) Waiting to run
ci / test (ubuntu-latest) (push) Waiting to run
ci / test (windows-latest) (push) Waiting to run

Run repairToolUseResultPairs on outbound messages in oneTurn so an
in-process aborted turn (cancel, connection drop, ECONNREFUSED) no
longer leaves a dangling tool_use that gets rejected by Anthropic/OpenAI
on the next request. Pure and idempotent, no-op on valid transcripts.
This commit is contained in:
patriceckhart 2026-06-09 12:58:39 +02:00
commit 3d031dde26

View file

@ -502,9 +502,17 @@ func (a *Agent) dropLastAssistantMessage() {
// and the assembled assistant message (already appended to the transcript).
func (a *Agent) oneTurn(ctx context.Context, sink func(AgentEvent)) (provider.StopReason, provider.Message, error) {
req := provider.Request{
Model: a.Model,
System: a.System,
Messages: a.Messages(),
Model: a.Model,
System: a.System,
// Repair any dangling tool_use blocks before sending. A turn
// aborted mid-flight (cancel, connection drop, ECONNREFUSED to a
// dev server, etc.) can leave an assistant tool_use with no
// matching tool_result in the live transcript. The load-time
// repair in OpenSession only runs on restart, so without this the
// next in-process request is rejected by providers like Anthropic
// with "tool_use ids were found without tool_result blocks". The
// repair is pure and a no-op on already-valid transcripts.
Messages: repairToolUseResultPairs(a.Messages()),
Tools: a.Tools.Specs(),
Reasoning: a.Reasoning,
}