Procházet zdrojové kódy

fix: resolve @file references in slash commands with subagents (#4221)

Rafał Krzyważnia před 3 měsíci
rodič
revize
491a2adf8d

+ 49 - 45
packages/opencode/src/session/prompt.ts

@@ -145,6 +145,54 @@ export namespace SessionPrompt {
     ),
   })
   export type PromptInput = z.infer<typeof PromptInput>
+
+  export async function resolvePromptParts(template: string): Promise<PromptInput["parts"]> {
+    const parts: PromptInput["parts"] = [
+      {
+        type: "text",
+        text: template,
+      },
+    ]
+    const files = ConfigMarkdown.files(template)
+    await Promise.all(
+      files.map(async (match) => {
+        const name = match[1]
+        const filepath = name.startsWith("~/")
+          ? path.join(os.homedir(), name.slice(2))
+          : path.resolve(Instance.worktree, name)
+
+        const stats = await fs.stat(filepath).catch(() => undefined)
+        if (!stats) {
+          const agent = await Agent.get(name)
+          if (agent) {
+            parts.push({
+              type: "agent",
+              name: agent.name,
+            })
+          }
+          return
+        }
+
+        if (stats.isDirectory()) {
+          parts.push({
+            type: "file",
+            url: `file://${filepath}`,
+            filename: name,
+            mime: "application/x-directory",
+          })
+          return
+        }
+
+        parts.push({
+          type: "file",
+          url: `file://${filepath}`,
+          filename: name,
+          mime: "text/plain",
+        })
+      }),
+    )
+    return parts
+  }
   export async function prompt(input: PromptInput): Promise<MessageV2.WithParts> {
     const l = log.clone().tag("session", input.sessionID)
     l.info("prompt")
@@ -1605,51 +1653,7 @@ export namespace SessionPrompt {
     }
     template = template.trim()
 
-    const parts = [
-      {
-        type: "text",
-        text: template,
-      },
-    ] as PromptInput["parts"]
-
-    const files = ConfigMarkdown.files(template)
-    await Promise.all(
-      files.map(async (match) => {
-        const name = match[1]
-        const filepath = name.startsWith("~/")
-          ? path.join(os.homedir(), name.slice(2))
-          : path.resolve(Instance.worktree, name)
-
-        const stats = await fs.stat(filepath).catch(() => undefined)
-        if (!stats) {
-          const agent = await Agent.get(name)
-          if (agent) {
-            parts.push({
-              type: "agent",
-              name: agent.name,
-            })
-          }
-          return
-        }
-
-        if (stats.isDirectory()) {
-          parts.push({
-            type: "file",
-            url: `file://${filepath}`,
-            filename: name,
-            mime: "application/x-directory",
-          })
-          return
-        }
-
-        parts.push({
-          type: "file",
-          url: `file://${filepath}`,
-          filename: name,
-          mime: "text/plain",
-        })
-      }),
-    )
+    const parts = await resolvePromptParts(template)
 
     const model = await (async () => {
       if (command.model) {

+ 2 - 7
packages/opencode/src/tool/task.ts

@@ -65,6 +65,7 @@ export const TaskTool = Tool.define("task", async () => {
       ctx.abort.addEventListener("abort", () => {
         SessionLock.abort(session.id)
       })
+      const promptParts = await SessionPrompt.resolvePromptParts(params.prompt)
       const result = await SessionPrompt.prompt({
         messageID,
         sessionID: session.id,
@@ -79,13 +80,7 @@ export const TaskTool = Tool.define("task", async () => {
           task: false,
           ...agent.tools,
         },
-        parts: [
-          {
-            id: Identifier.ascending("part"),
-            type: "text",
-            text: params.prompt,
-          },
-        ],
+        parts: promptParts,
       })
       unsub()
       let all