on main help sign in
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

commit2928dcb2e81dd68919b5fde3b1abd2ca4172c8c8 authorChris Chen <fuleinist@outlook.com> dateFri 27 Mar 2026, 01:01 (7 months ago) parent4a3df1e
1 file changed+10−4
internal/agent/agent.go+10−4
internal/agent/agent.go+10−4
@@ -364,7 +364,9 @@ func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy
364364 Finished: false,
365365 }
366366 currentAssistant.AddToolCall(toolCall)
367− return a.messages.Update(genCtx, *currentAssistant)
367+ // Use parent ctx instead of genCtx to ensure the update succeeds
368+ // even if the request is canceled mid-stream
369+ return a.messages.Update(ctx, *currentAssistant)
368370 },
369371 OnRetry: func(err *fantasy.ProviderError, delay time.Duration) {
370372 // TODO: implement
@@ -378,11 +380,15 @@ func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy
378380 Finished: true,
379381 }
380382 currentAssistant.AddToolCall(toolCall)
381− return a.messages.Update(genCtx, *currentAssistant)
383+ // Use parent ctx instead of genCtx to ensure the update succeeds
384+ // even if the request is canceled mid-stream
385+ return a.messages.Update(ctx, *currentAssistant)
382386 },
383387 OnToolResult: func(result fantasy.ToolResultContent) error {
384388 toolResult := a.convertToToolResult(result)
385− _, createMsgErr := a.messages.Create(genCtx, currentAssistant.SessionID, message.CreateMessageParams{
389+ // Use parent ctx instead of genCtx to ensure the message is created
390+ // even if the request is canceled mid-stream
391+ _, createMsgErr := a.messages.Create(ctx, currentAssistant.SessionID, message.CreateMessageParams{
386392 Role: message.Tool,
387393 Parts: []message.ContentPart{
388394 toolResult,
@@ -485,7 +491,7 @@ func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy
485491 }
486492 content := "There was an error while executing the tool"
487493 if isCancelErr {
488− content = "Tool execution canceled by user"
494+ content = "Error: user cancelled assistant tool calling"
489495 } else if isPermissionErr {
490496 content = "User denied permission"
491497 }