|
1 | | -import type { ToolCallContent } from "@agentclientprotocol/sdk"; |
| 1 | +import type { ContentBlock, ToolCallContent } from "@agentclientprotocol/sdk"; |
2 | 2 | import { applyPatch, parsePatch, reversePatch } from "diff"; |
3 | 3 | import { readFile } from "node:fs/promises"; |
4 | 4 | import path from "node:path"; |
@@ -114,6 +114,69 @@ export async function createDynamicToolCallUpdate( |
114 | 114 | return createExecuteToolCallUpdate(item, item.tool, { arguments: item.arguments }) |
115 | 115 | } |
116 | 116 |
|
| 117 | +export function createImageViewUpdate( |
| 118 | + item: ThreadItem & { type: "imageView" } |
| 119 | +): UpdateSessionEvent { |
| 120 | + const displayPath = item.path; |
| 121 | + return { |
| 122 | + sessionUpdate: "tool_call", |
| 123 | + toolCallId: item.id, |
| 124 | + kind: "read", |
| 125 | + title: `View Image ${displayPath}`, |
| 126 | + status: "completed", |
| 127 | + content: [createContent({ |
| 128 | + type: "resource_link", |
| 129 | + name: displayPath, |
| 130 | + uri: displayPath, |
| 131 | + })], |
| 132 | + locations: [{ path: item.path }], |
| 133 | + rawInput: { |
| 134 | + path: item.path, |
| 135 | + }, |
| 136 | + }; |
| 137 | +} |
| 138 | + |
| 139 | +export function createImageGenerationStartUpdate( |
| 140 | + item: ThreadItem & { type: "imageGeneration" } |
| 141 | +): UpdateSessionEvent { |
| 142 | + return { |
| 143 | + sessionUpdate: "tool_call", |
| 144 | + toolCallId: item.id, |
| 145 | + kind: "other", |
| 146 | + title: "Image generation", |
| 147 | + status: "in_progress", |
| 148 | + rawInput: { |
| 149 | + id: item.id, |
| 150 | + }, |
| 151 | + }; |
| 152 | +} |
| 153 | + |
| 154 | +export function createImageGenerationCompleteUpdate( |
| 155 | + item: ThreadItem & { type: "imageGeneration" } |
| 156 | +): UpdateSessionEvent { |
| 157 | + return { |
| 158 | + sessionUpdate: "tool_call_update", |
| 159 | + toolCallId: item.id, |
| 160 | + status: imageGenerationToolStatus(item.status), |
| 161 | + content: imageGenerationContent(item), |
| 162 | + rawOutput: imageGenerationRawOutput(item), |
| 163 | + }; |
| 164 | +} |
| 165 | + |
| 166 | +export function createImageGenerationUpdate( |
| 167 | + item: ThreadItem & { type: "imageGeneration" } |
| 168 | +): UpdateSessionEvent { |
| 169 | + return { |
| 170 | + sessionUpdate: "tool_call", |
| 171 | + toolCallId: item.id, |
| 172 | + kind: "other", |
| 173 | + title: "Image generation", |
| 174 | + status: imageGenerationToolStatus(item.status), |
| 175 | + content: imageGenerationContent(item), |
| 176 | + rawOutput: imageGenerationRawOutput(item), |
| 177 | + }; |
| 178 | +} |
| 179 | + |
117 | 180 | export async function createExecuteToolCallUpdate( |
118 | 181 | item: ThreadItem & ({ type: "mcpToolCall" } | { type: "dynamicToolCall" }), |
119 | 182 | title: string, |
@@ -450,6 +513,74 @@ function shellQuote(arg: string): string { |
450 | 513 | return `'${arg.replace(/'/g, `'\\''`)}'`; |
451 | 514 | } |
452 | 515 |
|
| 516 | +function imageGenerationToolStatus(status: string): AcpToolCallStatus { |
| 517 | + switch (status) { |
| 518 | + case "completed": |
| 519 | + return "completed"; |
| 520 | + case "generating": |
| 521 | + case "in_progress": |
| 522 | + case "inProgress": |
| 523 | + case "incomplete": |
| 524 | + return "in_progress"; |
| 525 | + case "failed": |
| 526 | + return "failed"; |
| 527 | + default: |
| 528 | + return "completed"; |
| 529 | + } |
| 530 | +} |
| 531 | + |
| 532 | +function imageGenerationContent( |
| 533 | + item: ThreadItem & { type: "imageGeneration" } |
| 534 | +): ToolCallContent[] { |
| 535 | + const content: ToolCallContent[] = []; |
| 536 | + |
| 537 | + if (item.revisedPrompt && item.revisedPrompt.trim() !== "") { |
| 538 | + content.push(createContent({ |
| 539 | + type: "text", |
| 540 | + text: `Revised prompt: ${item.revisedPrompt}`, |
| 541 | + })); |
| 542 | + } |
| 543 | + |
| 544 | + if (item.result.trim() !== "") { |
| 545 | + const image: ContentBlock = item.savedPath && item.savedPath.trim() !== "" |
| 546 | + ? { |
| 547 | + type: "image", |
| 548 | + data: item.result, |
| 549 | + mimeType: "image/png", |
| 550 | + uri: item.savedPath, |
| 551 | + } |
| 552 | + : { |
| 553 | + type: "image", |
| 554 | + data: item.result, |
| 555 | + mimeType: "image/png", |
| 556 | + }; |
| 557 | + content.push(createContent(image)); |
| 558 | + } |
| 559 | + |
| 560 | + return content; |
| 561 | +} |
| 562 | + |
| 563 | +function imageGenerationRawOutput( |
| 564 | + item: ThreadItem & { type: "imageGeneration" } |
| 565 | +): Record<string, string | null> { |
| 566 | + const output: Record<string, string | null> = { |
| 567 | + status: item.status, |
| 568 | + revisedPrompt: item.revisedPrompt, |
| 569 | + result: item.result, |
| 570 | + }; |
| 571 | + if ("savedPath" in item) { |
| 572 | + output["savedPath"] = item.savedPath ?? null; |
| 573 | + } |
| 574 | + return output; |
| 575 | +} |
| 576 | + |
| 577 | +function createContent(content: ContentBlock): ToolCallContent { |
| 578 | + return { |
| 579 | + type: "content", |
| 580 | + content, |
| 581 | + }; |
| 582 | +} |
| 583 | + |
453 | 584 | async function createPatchContent(change: FileUpdateChange): Promise<ToolCallContent | null> { |
454 | 585 | try { |
455 | 586 | switch (change.kind.type) { |
|
0 commit comments