From a580fb47d207150b0fdfe18297afb71edbdf577c Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Mon, 16 Feb 2026 14:59:57 -0600 Subject: [PATCH] tweak: drop ids from attachments in tools, assign them in prompt.ts instead (#13890) --- packages/opencode/src/session/prompt.ts | 30 +++++++++++++------- packages/opencode/src/tool/batch.ts | 8 +++++- packages/opencode/src/tool/read.ts | 4 --- packages/opencode/src/tool/tool.ts | 2 +- packages/opencode/src/tool/webfetch.ts | 4 --- packages/opencode/test/tool/read.test.ts | 6 ++++ packages/opencode/test/tool/webfetch.test.ts | 3 ++ 7 files changed, 37 insertions(+), 20 deletions(-) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index f705f209a..5890a4a73 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -445,6 +445,12 @@ export namespace SessionPrompt { log.error("subtask execution failed", { error, agent: task.agent, description: task.description }) return undefined }) + const attachments = result?.attachments?.map((attachment) => ({ + ...attachment, + id: Identifier.ascending("part"), + sessionID, + messageID: assistantMessage.id, + })) await Plugin.trigger( "tool.execute.after", { @@ -467,7 +473,7 @@ export namespace SessionPrompt { title: result.title, metadata: result.metadata, output: result.output, - attachments: result.attachments, + attachments, time: { ...part.state.time, end: Date.now(), @@ -797,6 +803,15 @@ export namespace SessionPrompt { }, ) const result = await item.execute(args, ctx) + const output = { + ...result, + attachments: result.attachments?.map((attachment) => ({ + ...attachment, + id: Identifier.ascending("part"), + sessionID: ctx.sessionID, + messageID: input.processor.message.id, + })), + } await Plugin.trigger( "tool.execute.after", { @@ -805,9 +820,9 @@ export namespace SessionPrompt { callID: ctx.callID, args, }, - result, + output, ) - return result + return output }, }) } @@ -855,16 +870,13 @@ export namespace SessionPrompt { ) const textParts: string[] = [] - const attachments: MessageV2.FilePart[] = [] + const attachments: Omit[] = [] for (const contentItem of result.content) { if (contentItem.type === "text") { textParts.push(contentItem.text) } else if (contentItem.type === "image") { attachments.push({ - id: Identifier.ascending("part"), - sessionID: input.session.id, - messageID: input.processor.message.id, type: "file", mime: contentItem.mimeType, url: `data:${contentItem.mimeType};base64,${contentItem.data}`, @@ -876,9 +888,6 @@ export namespace SessionPrompt { } if (resource.blob) { attachments.push({ - id: Identifier.ascending("part"), - sessionID: input.session.id, - messageID: input.processor.message.id, type: "file", mime: resource.mimeType ?? "application/octet-stream", url: `data:${resource.mimeType ?? "application/octet-stream"};base64,${resource.blob}`, @@ -1157,6 +1166,7 @@ export namespace SessionPrompt { pieces.push( ...result.attachments.map((attachment) => ({ ...attachment, + id: Identifier.ascending("part"), synthetic: true, filename: attachment.filename ?? part.filename, messageID: info.id, diff --git a/packages/opencode/src/tool/batch.ts b/packages/opencode/src/tool/batch.ts index ba34eb48f..eecbfe299 100644 --- a/packages/opencode/src/tool/batch.ts +++ b/packages/opencode/src/tool/batch.ts @@ -77,6 +77,12 @@ export const BatchTool = Tool.define("batch", async () => { }) const result = await tool.execute(validatedParams, { ...ctx, callID: partID }) + const attachments = result.attachments?.map((attachment) => ({ + ...attachment, + id: Identifier.ascending("part"), + sessionID: ctx.sessionID, + messageID: ctx.messageID, + })) await Session.updatePart({ id: partID, @@ -91,7 +97,7 @@ export const BatchTool = Tool.define("batch", async () => { output: result.output, title: result.title, metadata: result.metadata, - attachments: result.attachments, + attachments, time: { start: callStartTime, end: Date.now(), diff --git a/packages/opencode/src/tool/read.ts b/packages/opencode/src/tool/read.ts index 7f5a9a9bd..fbca89ad7 100644 --- a/packages/opencode/src/tool/read.ts +++ b/packages/opencode/src/tool/read.ts @@ -6,7 +6,6 @@ import { LSP } from "../lsp" import { FileTime } from "../file/time" import DESCRIPTION from "./read.txt" import { Instance } from "../project/instance" -import { Identifier } from "../id/id" import { assertExternalDirectory } from "./external-directory" import { InstructionPrompt } from "../session/instruction" @@ -127,9 +126,6 @@ export const ReadTool = Tool.define("read", { }, attachments: [ { - id: Identifier.ascending("part"), - sessionID: ctx.sessionID, - messageID: ctx.messageID, type: "file", mime, url: `data:${mime};base64,${Buffer.from(await file.bytes()).toString("base64")}`, diff --git a/packages/opencode/src/tool/tool.ts b/packages/opencode/src/tool/tool.ts index 3d17ea192..0e78ba665 100644 --- a/packages/opencode/src/tool/tool.ts +++ b/packages/opencode/src/tool/tool.ts @@ -36,7 +36,7 @@ export namespace Tool { title: string metadata: M output: string - attachments?: MessageV2.FilePart[] + attachments?: Omit[] }> formatValidationError?(error: z.ZodError): string }> diff --git a/packages/opencode/src/tool/webfetch.ts b/packages/opencode/src/tool/webfetch.ts index cd0d8dcde..a66e66c09 100644 --- a/packages/opencode/src/tool/webfetch.ts +++ b/packages/opencode/src/tool/webfetch.ts @@ -3,7 +3,6 @@ import { Tool } from "./tool" import TurndownService from "turndown" import DESCRIPTION from "./webfetch.txt" import { abortAfterAny } from "../util/abort" -import { Identifier } from "../id/id" const MAX_RESPONSE_SIZE = 5 * 1024 * 1024 // 5MB const DEFAULT_TIMEOUT = 30 * 1000 // 30 seconds @@ -103,9 +102,6 @@ export const WebFetchTool = Tool.define("webfetch", { metadata: {}, attachments: [ { - id: Identifier.ascending("part"), - sessionID: ctx.sessionID, - messageID: ctx.messageID, type: "file", mime, url: `data:${mime};base64,${base64Content}`, diff --git a/packages/opencode/test/tool/read.test.ts b/packages/opencode/test/tool/read.test.ts index 095c7bce2..ba3e22edc 100644 --- a/packages/opencode/test/tool/read.test.ts +++ b/packages/opencode/test/tool/read.test.ts @@ -349,6 +349,9 @@ describe("tool.read truncation", () => { expect(result.metadata.truncated).toBe(false) expect(result.attachments).toBeDefined() expect(result.attachments?.length).toBe(1) + expect(result.attachments?.[0]).not.toHaveProperty("id") + expect(result.attachments?.[0]).not.toHaveProperty("sessionID") + expect(result.attachments?.[0]).not.toHaveProperty("messageID") }, }) }) @@ -363,6 +366,9 @@ describe("tool.read truncation", () => { expect(result.attachments).toBeDefined() expect(result.attachments?.length).toBe(1) expect(result.attachments?.[0].type).toBe("file") + expect(result.attachments?.[0]).not.toHaveProperty("id") + expect(result.attachments?.[0]).not.toHaveProperty("sessionID") + expect(result.attachments?.[0]).not.toHaveProperty("messageID") }, }) }) diff --git a/packages/opencode/test/tool/webfetch.test.ts b/packages/opencode/test/tool/webfetch.test.ts index 10178af8f..0214700fe 100644 --- a/packages/opencode/test/tool/webfetch.test.ts +++ b/packages/opencode/test/tool/webfetch.test.ts @@ -46,6 +46,9 @@ describe("tool.webfetch", () => { expect(result.attachments?.[0].type).toBe("file") expect(result.attachments?.[0].mime).toBe("image/png") expect(result.attachments?.[0].url.startsWith("data:image/png;base64,")).toBe(true) + expect(result.attachments?.[0]).not.toHaveProperty("id") + expect(result.attachments?.[0]).not.toHaveProperty("sessionID") + expect(result.attachments?.[0]).not.toHaveProperty("messageID") }, }) },