Răsfoiți Sursa

file attachments

Dax Raad 7 luni în urmă
părinte
comite
ee01f01271

+ 50 - 14
packages/opencode/src/session/index.ts

@@ -1,4 +1,4 @@
-import path from "path"
+import path from "node:path"
 import { App } from "../app/app"
 import { Identifier } from "../id/id"
 import { Storage } from "../storage/storage"
@@ -15,6 +15,7 @@ import {
   type UIMessage,
   type ProviderMetadata,
   wrapLanguageModel,
+  type Attachment,
 } from "ai"
 import { z, ZodSchema } from "zod"
 import { Decimal } from "decimal.js"
@@ -187,7 +188,6 @@ export namespace Session {
   export async function unshare(id: string) {
     const share = await getShare(id)
     if (!share) return
-    console.log("share", share)
     await Storage.remove("session/share/" + id)
     await update(id, (draft) => {
       draft.share = undefined
@@ -361,6 +361,36 @@ export namespace Session {
     if (lastSummary) msgs = msgs.filter((msg) => msg.id >= lastSummary.id)
 
     const app = App.info()
+    input.parts = await Promise.all(
+      input.parts.map(async (part) => {
+        if (part.type === "file") {
+          const url = new URL(part.url)
+          switch (url.protocol) {
+            case "file:":
+              let content = await Bun.file(
+                path.join(app.path.cwd, url.pathname),
+              ).text()
+              const range = {
+                start: url.searchParams.get("start"),
+                end: url.searchParams.get("end"),
+              }
+              if (range.start != null) {
+                const lines = content.split("\n")
+                const start = parseInt(range.start)
+                const end = range.end ? parseInt(range.end) : lines.length
+                content = lines.slice(start, end).join("\n")
+              }
+              return {
+                type: "file",
+                url: "data:text/plain;base64," + btoa(content),
+                mediaType: "text/plain",
+                filename: part.filename,
+              }
+          }
+        }
+        return part
+      }),
+    )
     if (msgs.length === 0 && !session.parentID) {
       generateText({
         maxTokens: input.providerID === "google" ? 1024 : 20,
@@ -376,7 +406,7 @@ export namespace Session {
             {
               role: "user",
               content: "",
-              parts: toParts(input.parts),
+              ...toParts(input.parts),
             },
           ]),
         ],
@@ -1028,7 +1058,7 @@ function toUIMessage(msg: Message.Info): UIMessage {
       id: msg.id,
       role: "assistant",
       content: "",
-      parts: toParts(msg.parts),
+      ...toParts(msg.parts),
     }
   }
 
@@ -1037,35 +1067,41 @@ function toUIMessage(msg: Message.Info): UIMessage {
       id: msg.id,
       role: "user",
       content: "",
-      parts: toParts(msg.parts),
+      ...toParts(msg.parts),
     }
   }
 
   throw new Error("not implemented")
 }
 
-function toParts(parts: Message.MessagePart[]): UIMessage["parts"] {
-  const result: UIMessage["parts"] = []
+function toParts(parts: Message.MessagePart[]) {
+  const result: {
+    parts: UIMessage["parts"]
+    experimental_attachments: Attachment[]
+  } = {
+    parts: [],
+    experimental_attachments: [],
+  }
   for (const part of parts) {
     switch (part.type) {
       case "text":
-        result.push({ type: "text", text: part.text })
+        result.parts.push({ type: "text", text: part.text })
         break
       case "file":
-        result.push({
-          type: "file",
-          data: part.url,
-          mimeType: part.mediaType,
+        result.experimental_attachments.push({
+          url: part.url,
+          contentType: part.mediaType,
+          name: part.filename,
         })
         break
       case "tool-invocation":
-        result.push({
+        result.parts.push({
           type: "tool-invocation",
           toolInvocation: part.toolInvocation,
         })
         break
       case "step-start":
-        result.push({
+        result.parts.push({
           type: "step-start",
         })
         break

+ 1 - 1
packages/tui/internal/components/chat/editor.go

@@ -108,7 +108,7 @@ func (m *editorComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 			attachment := &textarea.Attachment{
 				ID:        uuid.NewString(),
 				Display:   "@" + fileName,
-				URL:       fmt.Sprintf("file://%s", filePath),
+				URL:       fmt.Sprintf("file://./%s", filePath),
 				Filename:  fileName,
 				MediaType: mediaType,
 			}