From 2928dcb2e81dd68919b5fde3b1abd2ca4172c8c8 Mon Sep 17 00:00:00 2001 From: Chris Chen Date: Fri, 27 Mar 2026 01:01:43 +1100 Subject: [PATCH] fix: append error tool message when tool call is cancelled (#2492) When a user cancels a tool call by pressing Esc twice, the assistant message with tool_calls was remaining in the conversation history but no tool response followed. This caused 400 Bad Request errors from model providers on the next message. The fix uses the parent context (ctx) instead of the request context (genCtx) when updating messages during tool call tracking and tool result creation. This ensures that even if the request is cancelled mid-stream, the message updates and creations succeed. Additionally, the error message was updated from 'Tool execution canceled by user' to 'Error: user cancelled assistant tool calling' to better indicate the cancellation occurred during the assistant tool calling phase. Fixes #529 Fixes #1206 --- internal/agent/agent.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/internal/agent/agent.go b/internal/agent/agent.go index 11a87f58554729048cd7a0629979a0c6bb3babd2..c7c96cd42cfce58eab918e9ae2e267ac3f78ad8d 100644 --- a/internal/agent/agent.go +++ b/internal/agent/agent.go @@ -364,7 +364,9 @@ func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy Finished: false, } currentAssistant.AddToolCall(toolCall) - return a.messages.Update(genCtx, *currentAssistant) + // Use parent ctx instead of genCtx to ensure the update succeeds + // even if the request is canceled mid-stream + return a.messages.Update(ctx, *currentAssistant) }, OnRetry: func(err *fantasy.ProviderError, delay time.Duration) { // TODO: implement @@ -378,11 +380,15 @@ func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy Finished: true, } currentAssistant.AddToolCall(toolCall) - return a.messages.Update(genCtx, *currentAssistant) + // Use parent ctx instead of genCtx to ensure the update succeeds + // even if the request is canceled mid-stream + return a.messages.Update(ctx, *currentAssistant) }, OnToolResult: func(result fantasy.ToolResultContent) error { toolResult := a.convertToToolResult(result) - _, createMsgErr := a.messages.Create(genCtx, currentAssistant.SessionID, message.CreateMessageParams{ + // Use parent ctx instead of genCtx to ensure the message is created + // even if the request is canceled mid-stream + _, createMsgErr := a.messages.Create(ctx, currentAssistant.SessionID, message.CreateMessageParams{ Role: message.Tool, Parts: []message.ContentPart{ toolResult, @@ -485,7 +491,7 @@ func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy } content := "There was an error while executing the tool" if isCancelErr { - content = "Tool execution canceled by user" + content = "Error: user cancelled assistant tool calling" } else if isPermissionErr { content = "User denied permission" }