Skip to content

Commit 5345c98

Browse files
committed
fix(acp): emit tool_call_update with content/title and raw I/O
1 parent 9b6db08 commit 5345c98

1 file changed

Lines changed: 28 additions & 66 deletions

File tree

packages/opencode/src/acp/agent.ts

Lines changed: 28 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import { LoadAPIKeyError } from "ai"
5151
import type { AssistantMessage, Event, OpencodeClient, SessionMessageResponse, ToolPart } from "@opencode-ai/sdk/v2"
5252
import { applyPatch } from "diff"
5353
import { InstallationVersion } from "@/installation/version"
54+
import { toolCallFromPart, toolResultFromPart } from "./tool-format"
5455

5556
type ModeOption = { id: string; name: string; description?: string }
5657
type ModelOption = { modelId: string; name: string }
@@ -198,16 +199,17 @@ export class Agent implements ACPAgent {
198199
.then(async () => {
199200
const directory = session.cwd
200201

202+
const permissionInfo = toolCallFromPart(permission.permission, permission.metadata ?? {})
201203
const res = await this.connection
202204
.requestPermission({
203205
sessionId: permission.sessionID,
204206
toolCall: {
205207
toolCallId: permission.tool?.callID ?? permission.id,
206208
status: "pending",
207-
title: permission.permission,
208-
rawInput: permission.metadata,
209-
kind: toToolKind(permission.permission),
210-
locations: toLocations(permission.permission, permission.metadata),
209+
title: permissionInfo.title,
210+
rawInput: permissionInfo.rawInput,
211+
kind: permissionInfo.kind,
212+
locations: permissionInfo.locations,
211213
},
212214
options: this.permissionOptions,
213215
})
@@ -279,13 +281,14 @@ export class Agent implements ACPAgent {
279281

280282
if (part.type === "tool") {
281283
await this.toolStart(sessionId, part)
284+
const info = toolCallFromPart(part.tool, part.state.input)
282285

283286
switch (part.state.status) {
284287
case "pending":
285288
this.bashSnapshots.delete(part.callID)
286289
return
287290

288-
case "running":
291+
case "running": {
289292
const output = this.bashOutput(part)
290293
const content: ToolCallContent[] = []
291294
if (output) {
@@ -299,10 +302,10 @@ export class Agent implements ACPAgent {
299302
sessionUpdate: "tool_call_update",
300303
toolCallId: part.callID,
301304
status: "in_progress",
302-
kind: toToolKind(part.tool),
303-
title: part.tool,
304-
locations: toLocations(part.tool, part.state.input),
305-
rawInput: part.state.input,
305+
kind: info.kind,
306+
title: info.title,
307+
locations: info.locations,
308+
rawInput: info.rawInput,
306309
},
307310
})
308311
.catch((error) => {
@@ -327,49 +330,23 @@ export class Agent implements ACPAgent {
327330
sessionUpdate: "tool_call_update",
328331
toolCallId: part.callID,
329332
status: "in_progress",
330-
kind: toToolKind(part.tool),
331-
title: part.tool,
332-
locations: toLocations(part.tool, part.state.input),
333-
rawInput: part.state.input,
333+
kind: info.kind,
334+
title: info.title,
335+
locations: info.locations,
336+
rawInput: info.rawInput,
334337
...(content.length > 0 && { content }),
335338
},
336339
})
337340
.catch((error) => {
338341
log.error("failed to send tool in_progress to ACP", { error })
339342
})
340343
return
344+
}
341345

342346
case "completed": {
343347
this.toolStarts.delete(part.callID)
344348
this.bashSnapshots.delete(part.callID)
345-
const kind = toToolKind(part.tool)
346-
const content: ToolCallContent[] = [
347-
{
348-
type: "content",
349-
content: {
350-
type: "text",
351-
text: part.state.output,
352-
},
353-
},
354-
]
355-
356-
if (kind === "edit") {
357-
const input = part.state.input
358-
const filePath = typeof input["filePath"] === "string" ? input["filePath"] : ""
359-
const oldText = typeof input["oldString"] === "string" ? input["oldString"] : ""
360-
const newText =
361-
typeof input["newString"] === "string"
362-
? input["newString"]
363-
: typeof input["content"] === "string"
364-
? input["content"]
365-
: ""
366-
content.push({
367-
type: "diff",
368-
path: filePath,
369-
oldText,
370-
newText,
371-
})
372-
}
349+
const result = toolResultFromPart(part.tool, part.state.input, part.state.output, false)
373350

374351
if (part.tool === "todowrite") {
375352
const parsedTodos = z.array(Todo.Info).safeParse(JSON.parse(part.state.output))
@@ -405,53 +382,38 @@ export class Agent implements ACPAgent {
405382
sessionUpdate: "tool_call_update",
406383
toolCallId: part.callID,
407384
status: "completed",
408-
kind,
409-
content,
410-
title: part.state.title,
411-
rawInput: part.state.input,
412-
rawOutput: {
413-
output: part.state.output,
414-
metadata: part.state.metadata,
415-
},
385+
content: result.content,
386+
rawOutput: result.rawOutput,
387+
...(result.title ? { title: result.title } : {}),
416388
},
417389
})
418390
.catch((error) => {
419391
log.error("failed to send tool completed to ACP", { error })
420392
})
421393
return
422394
}
423-
case "error":
395+
case "error": {
424396
this.toolStarts.delete(part.callID)
425397
this.bashSnapshots.delete(part.callID)
398+
const result = toolResultFromPart(part.tool, part.state.input, part.state.error, true)
399+
426400
await this.connection
427401
.sessionUpdate({
428402
sessionId,
429403
update: {
430404
sessionUpdate: "tool_call_update",
431405
toolCallId: part.callID,
432406
status: "failed",
433-
kind: toToolKind(part.tool),
434-
title: part.tool,
435-
rawInput: part.state.input,
436-
content: [
437-
{
438-
type: "content",
439-
content: {
440-
type: "text",
441-
text: part.state.error,
442-
},
443-
},
444-
],
445-
rawOutput: {
446-
error: part.state.error,
447-
metadata: part.state.metadata,
448-
},
407+
content: result.content,
408+
rawOutput: result.rawOutput,
409+
...(result.title ? { title: result.title } : {}),
449410
},
450411
})
451412
.catch((error) => {
452413
log.error("failed to send tool error to ACP", { error })
453414
})
454415
return
416+
}
455417
}
456418
}
457419

0 commit comments

Comments
 (0)