Skip to content

Commit 90088ab

Browse files
committed
Remove the tool call from the tool call response event
This tool call was already sent in previous events, no need to re-send it especially since it can be big for certain calls like write_file. We do need the tool call id though so that clients can still find the tool call that this is the result for Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>
1 parent b05f598 commit 90088ab

File tree

6 files changed

+36
-26
lines changed

6 files changed

+36
-26
lines changed

pkg/acp/agent.go

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,9 @@ func (a *Agent) runAgent(ctx context.Context, acpSess *Session) error {
382382

383383
eventsChan := acpSess.rt.RunStream(ctx, acpSess.sess)
384384

385+
// Tracks tool call arguments so that we can extract useful information
386+
// once the tool call was made.
387+
toolCallArgs := map[string]string{}
385388
for event := range eventsChan {
386389
if ctx.Err() != nil {
387390
return ctx.Err()
@@ -411,6 +414,7 @@ func (a *Agent) runAgent(ctx context.Context, acpSess *Session) error {
411414
}
412415

413416
case *runtime.ToolCallEvent:
417+
toolCallArgs[e.ToolCall.ID] = e.ToolCall.Function.Arguments
414418
if err := a.conn.SessionUpdate(ctx, acp.SessionNotification{
415419
SessionId: acp.SessionId(acpSess.id),
416420
Update: buildToolCallStart(e.ToolCall, e.ToolDefinition),
@@ -419,15 +423,21 @@ func (a *Agent) runAgent(ctx context.Context, acpSess *Session) error {
419423
}
420424

421425
case *runtime.ToolCallResponseEvent:
426+
args, ok := toolCallArgs[e.ToolCallID]
427+
// Should never happend but you know...
428+
if !ok {
429+
return fmt.Errorf("missing tool call arguments for tool call ID %s", e.ToolCallID)
430+
}
431+
delete(toolCallArgs, e.ToolCallID)
422432
if err := a.conn.SessionUpdate(ctx, acp.SessionNotification{
423433
SessionId: acp.SessionId(acpSess.id),
424-
Update: buildToolCallComplete(e.ToolCall, e.Response),
434+
Update: buildToolCallComplete(args, e),
425435
}); err != nil {
426436
return err
427437
}
428438

429439
// Check if this is a todo tool response and emit plan update
430-
if isTodoTool(e.ToolCall.Function.Name) && e.Result != nil && e.Result.Meta != nil {
440+
if isTodoTool(e.ToolDefinition.Name) && e.Result != nil && e.Result.Meta != nil {
431441
if planUpdate := buildPlanUpdateFromTodos(e.Result.Meta); planUpdate != nil {
432442
if err := a.conn.SessionUpdate(ctx, acp.SessionNotification{
433443
SessionId: acp.SessionId(acpSess.id),
@@ -666,24 +676,24 @@ func determineToolKind(toolName string, tool tools.Tool) acp.ToolKind {
666676
}
667677

668678
// buildToolCallComplete creates a tool call completion update
669-
func buildToolCallComplete(toolCall tools.ToolCall, output string) acp.SessionUpdate {
679+
func buildToolCallComplete(arguments string, event *runtime.ToolCallResponseEvent) acp.SessionUpdate {
670680
// Check if this is a file edit operation and try to extract diff info
671-
if isFileEditTool(toolCall.Function.Name) {
672-
if diffContent := extractDiffContent(toolCall, output); diffContent != nil {
681+
if isFileEditTool(event.ToolDefinition.Name) {
682+
if diffContent := extractDiffContent(event.ToolDefinition.Name, arguments); diffContent != nil {
673683
return acp.UpdateToolCall(
674-
acp.ToolCallId(toolCall.ID),
684+
acp.ToolCallId(event.ToolCallID),
675685
acp.WithUpdateStatus(acp.ToolCallStatusCompleted),
676686
acp.WithUpdateContent([]acp.ToolCallContent{*diffContent}),
677-
acp.WithUpdateRawOutput(map[string]any{"content": output}),
687+
acp.WithUpdateRawOutput(map[string]any{"content": event.Response}),
678688
)
679689
}
680690
}
681691

682692
return acp.UpdateToolCall(
683-
acp.ToolCallId(toolCall.ID),
693+
acp.ToolCallId(event.ToolCallID),
684694
acp.WithUpdateStatus(acp.ToolCallStatusCompleted),
685-
acp.WithUpdateContent([]acp.ToolCallContent{acp.ToolContent(acp.TextBlock(output))}),
686-
acp.WithUpdateRawOutput(map[string]any{"content": output}),
695+
acp.WithUpdateContent([]acp.ToolCallContent{acp.ToolContent(acp.TextBlock(event.Response))}),
696+
acp.WithUpdateRawOutput(map[string]any{"content": event.Response}),
687697
)
688698
}
689699

@@ -693,8 +703,8 @@ func isFileEditTool(toolName string) bool {
693703
}
694704

695705
// extractDiffContent tries to create a diff content block from edit tool arguments
696-
func extractDiffContent(toolCall tools.ToolCall, _ string) *acp.ToolCallContent {
697-
args := parseToolCallArguments(toolCall.Function.Arguments)
706+
func extractDiffContent(toolCallName, arguments string) *acp.ToolCallContent {
707+
args := parseToolCallArguments(arguments)
698708

699709
// Get the path from arguments
700710
path, ok := args["path"].(string)
@@ -703,7 +713,7 @@ func extractDiffContent(toolCall tools.ToolCall, _ string) *acp.ToolCallContent
703713
}
704714

705715
// For edit_file, extract the edits
706-
if toolCall.Function.Name == "edit_file" {
716+
if toolCallName == "edit_file" {
707717
edits, ok := args["edits"].([]any)
708718
if !ok || len(edits) == 0 {
709719
return nil
@@ -735,7 +745,7 @@ func extractDiffContent(toolCall tools.ToolCall, _ string) *acp.ToolCallContent
735745
}
736746

737747
// For write_file, the entire content is new
738-
if toolCall.Function.Name == "write_file" {
748+
if toolCallName == "write_file" {
739749
if content, ok := args["content"].(string); ok {
740750
diff := acp.ToolDiffContent(path, content)
741751
return &diff

pkg/cli/printer.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@ func (p *Printer) PrintToolCallWithConfirmation(ctx context.Context, toolCall to
134134
}
135135

136136
// PrintToolCallResponse prints a tool call response
137-
func (p *Printer) PrintToolCallResponse(toolCall tools.ToolCall, response string) {
138-
p.Printf("\n%s response%s\n", bold(toolCall.Function.Name), formatToolCallResponse(response))
137+
func (p *Printer) PrintToolCallResponse(name, response string) {
138+
p.Printf("\n%s response%s\n", bold(name), formatToolCallResponse(response))
139139
}
140140

141141
// PromptMaxIterationsContinue prompts the user to continue after max iterations

pkg/cli/runner.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,9 @@ func Run(ctx context.Context, out *Printer, cfg Config, rt runtime.Runtime, sess
185185
if cfg.HideToolCalls {
186186
continue
187187
}
188-
out.PrintToolCallResponse(e.ToolCall, e.Response)
188+
out.PrintToolCallResponse(e.ToolDefinition.Name, e.Response)
189189
// Clear the confirmed ID after the tool completes
190-
if e.ToolCall.ID == lastConfirmedToolCallID {
190+
if e.ToolCallID == lastConfirmedToolCallID {
191191
lastConfirmedToolCallID = ""
192192
}
193193
case *runtime.ErrorEvent:

pkg/runtime/event.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,19 +117,19 @@ func ToolCallConfirmation(toolCall tools.ToolCall, toolDefinition tools.Tool, ag
117117

118118
type ToolCallResponseEvent struct {
119119
Type string `json:"type"`
120-
ToolCall tools.ToolCall `json:"tool_call"`
120+
ToolCallID string `json:"tool_call_id"`
121121
ToolDefinition tools.Tool `json:"tool_definition"`
122122
Response string `json:"response"`
123123
Result *tools.ToolCallResult `json:"result,omitempty"`
124124
AgentContext
125125
}
126126

127-
func ToolCallResponse(toolCall tools.ToolCall, toolDefinition tools.Tool, result *tools.ToolCallResult, response, agentName string) Event {
127+
func ToolCallResponse(toolCallID string, toolDefinition tools.Tool, result *tools.ToolCallResult, response, agentName string) Event {
128128
return &ToolCallResponseEvent{
129129
Type: "tool_call_response",
130-
ToolCall: toolCall,
131130
Response: response,
132131
Result: result,
132+
ToolCallID: toolCallID,
133133
ToolDefinition: toolDefinition,
134134
AgentContext: newAgentContext(agentName),
135135
}

pkg/runtime/tool_dispatch.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ func (r *LocalRuntime) executeToolWithHandler(
277277
slog.Debug("Tool call completed", "tool", toolCall.Function.Name, "output_length", len(res.Output))
278278
}
279279

280-
events <- ToolCallResponse(toolCall, tool, res, res.Output, a.Name())
280+
events <- ToolCallResponse(toolCall.ID, tool, res, res.Output, a.Name())
281281

282282
// Ensure tool response content is not empty for API compatibility
283283
content := res.Output
@@ -432,7 +432,7 @@ func addAgentMessage(sess *session.Session, a *agent.Agent, msg *chat.Message, e
432432
// addToolErrorResponse adds a tool error response to the session and emits the event.
433433
// This consolidates the common pattern used by validation, rejection, and cancellation responses.
434434
func (r *LocalRuntime) addToolErrorResponse(_ context.Context, sess *session.Session, toolCall tools.ToolCall, tool tools.Tool, events chan Event, a *agent.Agent, errorMsg string) {
435-
events <- ToolCallResponse(toolCall, tool, tools.ResultError(errorMsg), errorMsg, a.Name())
435+
events <- ToolCallResponse(toolCall.ID, tool, tools.ResultError(errorMsg), errorMsg, a.Name())
436436

437437
toolResponseMsg := chat.Message{
438438
Role: chat.MessageRoleTool,

pkg/tui/components/messages/messages.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,8 +1337,8 @@ func (m *model) AddToolResult(msg *runtime.ToolCallResponseEvent, status types.T
13371337
for i := len(m.messages) - 1; i >= 0; i-- {
13381338
if m.messages[i].Type == types.MessageTypeAssistantReasoningBlock {
13391339
if block, ok := m.views[i].(*reasoningblock.Model); ok {
1340-
if block.HasToolCall(msg.ToolCall.ID) {
1341-
cmd := block.UpdateToolResult(msg.ToolCall.ID, msg.Response, status, msg.Result)
1340+
if block.HasToolCall(msg.ToolCallID) {
1341+
cmd := block.UpdateToolResult(msg.ToolCallID, msg.Response, status, msg.Result)
13421342
m.invalidateItem(i)
13431343
return cmd
13441344
}
@@ -1349,7 +1349,7 @@ func (m *model) AddToolResult(msg *runtime.ToolCallResponseEvent, status types.T
13491349
// Then check standalone tool call messages
13501350
for i := len(m.messages) - 1; i >= 0; i-- {
13511351
toolMessage := m.messages[i]
1352-
if toolMessage.Type == types.MessageTypeToolCall && toolMessage.ToolCall.ID == msg.ToolCall.ID {
1352+
if toolMessage.Type == types.MessageTypeToolCall && toolMessage.ToolCall.ID == msg.ToolCallID {
13531353
toolMessage.Content = strings.ReplaceAll(msg.Response, "\t", " ")
13541354
toolMessage.ToolStatus = status
13551355
toolMessage.ToolResult = msg.Result

0 commit comments

Comments
 (0)