Просмотр исходного кода

Revert pr that was mistakenly merged (#11844)

Aiden Cline 2 недель назад
Родитель
Сommit
aa6b552c39

+ 1 - 9
packages/opencode/src/session/processor.ts

@@ -172,14 +172,6 @@ export namespace SessionProcessor {
                 case "tool-result": {
                   const match = toolcalls[value.toolCallId]
                   if (match && match.state.status === "running") {
-                    const attachments = value.output.attachments?.map(
-                      (attachment: Omit<MessageV2.FilePart, "id" | "messageID" | "sessionID">) => ({
-                        ...attachment,
-                        id: Identifier.ascending("part"),
-                        messageID: match.messageID,
-                        sessionID: match.sessionID,
-                      }),
-                    )
                     await Session.updatePart({
                       ...match,
                       state: {
@@ -192,7 +184,7 @@ export namespace SessionProcessor {
                           start: match.state.time.start,
                           end: Date.now(),
                         },
-                        attachments,
+                        attachments: value.output.attachments,
                       },
                     })
 

+ 26 - 43
packages/opencode/src/session/prompt.ts

@@ -187,17 +187,13 @@ export namespace SessionPrompt {
         text: template,
       },
     ]
-    const matches = ConfigMarkdown.files(template)
+    const files = ConfigMarkdown.files(template)
     const seen = new Set<string>()
-    const names = matches
-      .map((match) => match[1])
-      .filter((name) => {
-        if (seen.has(name)) return false
+    await Promise.all(
+      files.map(async (match) => {
+        const name = match[1]
+        if (seen.has(name)) return
         seen.add(name)
-        return true
-      })
-    const resolved = await Promise.all(
-      names.map(async (name) => {
         const filepath = name.startsWith("~/")
           ? path.join(os.homedir(), name.slice(2))
           : path.resolve(Instance.worktree, name)
@@ -205,34 +201,33 @@ export namespace SessionPrompt {
         const stats = await fs.stat(filepath).catch(() => undefined)
         if (!stats) {
           const agent = await Agent.get(name)
-          if (!agent) return undefined
-          return {
-            type: "agent",
-            name: agent.name,
-          } satisfies PromptInput["parts"][number]
+          if (agent) {
+            parts.push({
+              type: "agent",
+              name: agent.name,
+            })
+          }
+          return
         }
 
         if (stats.isDirectory()) {
-          return {
+          parts.push({
             type: "file",
             url: `file://${filepath}`,
             filename: name,
             mime: "application/x-directory",
-          } satisfies PromptInput["parts"][number]
+          })
+          return
         }
 
-        return {
+        parts.push({
           type: "file",
           url: `file://${filepath}`,
           filename: name,
           mime: "text/plain",
-        } satisfies PromptInput["parts"][number]
+        })
       }),
     )
-    for (const item of resolved) {
-      if (!item) continue
-      parts.push(item)
-    }
     return parts
   }
 
@@ -432,12 +427,6 @@ export namespace SessionPrompt {
         assistantMessage.time.completed = Date.now()
         await Session.updateMessage(assistantMessage)
         if (result && part.state.status === "running") {
-          const attachments = result.attachments?.map((attachment) => ({
-            ...attachment,
-            id: Identifier.ascending("part"),
-            messageID: assistantMessage.id,
-            sessionID: assistantMessage.sessionID,
-          }))
           await Session.updatePart({
             ...part,
             state: {
@@ -446,7 +435,7 @@ export namespace SessionPrompt {
               title: result.title,
               metadata: result.metadata,
               output: result.output,
-              attachments,
+              attachments: result.attachments,
               time: {
                 ...part.state.time,
                 end: Date.now(),
@@ -785,13 +774,16 @@ export namespace SessionPrompt {
         )
 
         const textParts: string[] = []
-        const attachments: Omit<MessageV2.FilePart, "id" | "messageID" | "sessionID">[] = []
+        const attachments: MessageV2.FilePart[] = []
 
         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}`,
@@ -803,6 +795,9 @@ 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}`,
@@ -1051,7 +1046,6 @@ export namespace SessionPrompt {
                       pieces.push(
                         ...result.attachments.map((attachment) => ({
                           ...attachment,
-                          id: Identifier.ascending("part"),
                           synthetic: true,
                           filename: attachment.filename ?? part.filename,
                           messageID: info.id,
@@ -1189,18 +1183,7 @@ export namespace SessionPrompt {
           },
         ]
       }),
-    )
-      .then((x) => x.flat())
-      .then((drafts) =>
-        drafts.map(
-          (part): MessageV2.Part => ({
-            ...part,
-            id: Identifier.ascending("part"),
-            messageID: info.id,
-            sessionID: input.sessionID,
-          }),
-        ),
-      )
+    ).then((x) => x.flat())
 
     await Plugin.trigger(
       "chat.message",

+ 1 - 7
packages/opencode/src/tool/batch.ts

@@ -77,12 +77,6 @@ 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"),
-            messageID: ctx.messageID,
-            sessionID: ctx.sessionID,
-          }))
 
           await Session.updatePart({
             id: partID,
@@ -97,7 +91,7 @@ export const BatchTool = Tool.define("batch", async () => {
               output: result.output,
               title: result.title,
               metadata: result.metadata,
-              attachments,
+              attachments: result.attachments,
               time: {
                 start: callStartTime,
                 end: Date.now(),

+ 4 - 0
packages/opencode/src/tool/read.ts

@@ -6,6 +6,7 @@ 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"
 
@@ -78,6 +79,9 @@ 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")}`,

+ 1 - 1
packages/opencode/src/tool/tool.ts

@@ -36,7 +36,7 @@ export namespace Tool {
         title: string
         metadata: M
         output: string
-        attachments?: Omit<MessageV2.FilePart, "id" | "sessionID" | "messageID">[]
+        attachments?: MessageV2.FilePart[]
       }>
       formatValidationError?(error: z.ZodError): string
     }>

+ 0 - 62
packages/opencode/test/session/prompt.test.ts

@@ -1,62 +0,0 @@
-import path from "path"
-import { describe, expect, test } from "bun:test"
-import { Session } from "../../src/session"
-import { SessionPrompt } from "../../src/session/prompt"
-import { MessageV2 } from "../../src/session/message-v2"
-import { Instance } from "../../src/project/instance"
-import { Log } from "../../src/util/log"
-import { tmpdir } from "../fixture/fixture"
-
-Log.init({ print: false })
-
-describe("SessionPrompt ordering", () => {
-  test("keeps @file order with read output parts", async () => {
-    await using tmp = await tmpdir({
-      git: true,
-      init: async (dir) => {
-        await Bun.write(path.join(dir, "a.txt"), "28\n")
-        await Bun.write(path.join(dir, "b.txt"), "42\n")
-      },
-    })
-
-    await Instance.provide({
-      directory: tmp.path,
-      fn: async () => {
-        const session = await Session.create({})
-        const template = "What numbers are written in files @a.txt and @b.txt ?"
-        const parts = await SessionPrompt.resolvePromptParts(template)
-        const fileParts = parts.filter((part) => part.type === "file")
-
-        expect(fileParts.map((part) => part.filename)).toStrictEqual(["a.txt", "b.txt"])
-
-        const message = await SessionPrompt.prompt({
-          sessionID: session.id,
-          parts,
-          noReply: true,
-        })
-        const stored = await MessageV2.get({ sessionID: session.id, messageID: message.info.id })
-        const items = stored.parts
-        const aPath = path.join(tmp.path, "a.txt")
-        const bPath = path.join(tmp.path, "b.txt")
-        const sequence = items.flatMap((part) => {
-          if (part.type === "text") {
-            if (part.text.includes(aPath)) return ["input:a"]
-            if (part.text.includes(bPath)) return ["input:b"]
-            if (part.text.includes("00001| 28")) return ["output:a"]
-            if (part.text.includes("00001| 42")) return ["output:b"]
-            return []
-          }
-          if (part.type === "file") {
-            if (part.filename === "a.txt") return ["file:a"]
-            if (part.filename === "b.txt") return ["file:b"]
-          }
-          return []
-        })
-
-        expect(sequence).toStrictEqual(["input:a", "output:a", "file:a", "input:b", "output:b", "file:b"])
-
-        await Session.remove(session.id)
-      },
-    })
-  })
-})