Dax Raad 3 месяцев назад
Родитель
Сommit
aeca8051d5

+ 36 - 22
packages/opencode/src/agent/agent.ts

@@ -42,20 +42,19 @@ export namespace Agent {
 
   const state = Instance.state(async () => {
     const cfg = await Config.get()
-    const permission: PermissionNext.Ruleset = PermissionNext.merge(
-      PermissionNext.fromConfig({
-        "*": "allow",
-        doom_loop: "ask",
-        external_directory: "ask",
-      }),
-      PermissionNext.fromConfig(cfg.permission ?? {}),
-    )
+
+    const defaults = PermissionNext.fromConfig({
+      "*": "allow",
+      doom_loop: "ask",
+      external_directory: "ask",
+    })
+    const user = PermissionNext.fromConfig(cfg.permission ?? {})
 
     const result: Record<string, Info> = {
       build: {
         name: "build",
         options: {},
-        permission,
+        permission: PermissionNext.merge(defaults, user),
         mode: "primary",
         native: true,
       },
@@ -63,13 +62,14 @@ export namespace Agent {
         name: "plan",
         options: {},
         permission: PermissionNext.merge(
-          permission,
+          defaults,
           PermissionNext.fromConfig({
             edit: {
               "*": "deny",
               ".opencode/plan/*.md": "allow",
             },
           }),
+          user,
         ),
         mode: "primary",
         native: true,
@@ -78,11 +78,12 @@ export namespace Agent {
         name: "general",
         description: `General-purpose agent for researching complex questions and executing multi-step tasks. Use this agent to execute multiple units of work in parallel.`,
         permission: PermissionNext.merge(
-          permission,
+          defaults,
           PermissionNext.fromConfig({
             todoread: "deny",
             todowrite: "deny",
           }),
+          user,
         ),
         options: {},
         mode: "subagent",
@@ -92,7 +93,7 @@ export namespace Agent {
       explore: {
         name: "explore",
         permission: PermissionNext.merge(
-          permission,
+          defaults,
           PermissionNext.fromConfig({
             "*": "deny",
             grep: "allow",
@@ -104,6 +105,7 @@ export namespace Agent {
             codesearch: "allow",
             read: "allow",
           }),
+          user,
         ),
         description: `Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (eg. "src/components/**/*.tsx"), search code for keywords (eg. "API endpoints"), or answer questions about the codebase (eg. "how do API endpoints work?"). When calling this agent, specify the desired thoroughness level: "quick" for basic searches, "medium" for moderate exploration, or "very thorough" for comprehensive analysis across multiple locations and naming conventions.`,
         prompt: PROMPT_EXPLORE,
@@ -117,9 +119,13 @@ export namespace Agent {
         native: true,
         hidden: true,
         prompt: PROMPT_COMPACTION,
-        permission: PermissionNext.fromConfig({
-          "*": "deny",
-        }),
+        permission: PermissionNext.merge(
+          defaults,
+          PermissionNext.fromConfig({
+            "*": "deny",
+          }),
+          user,
+        ),
         options: {},
       },
       title: {
@@ -128,9 +134,13 @@ export namespace Agent {
         options: {},
         native: true,
         hidden: true,
-        permission: PermissionNext.fromConfig({
-          "*": "deny",
-        }),
+        permission: PermissionNext.merge(
+          defaults,
+          PermissionNext.fromConfig({
+            "*": "deny",
+          }),
+          user,
+        ),
         prompt: PROMPT_TITLE,
       },
       summary: {
@@ -139,9 +149,13 @@ export namespace Agent {
         options: {},
         native: true,
         hidden: true,
-        permission: PermissionNext.fromConfig({
-          "*": "deny",
-        }),
+        permission: PermissionNext.merge(
+          defaults,
+          PermissionNext.fromConfig({
+            "*": "deny",
+          }),
+          user,
+        ),
         prompt: PROMPT_SUMMARY,
       },
     }
@@ -156,7 +170,7 @@ export namespace Agent {
         item = result[key] = {
           name: key,
           mode: "all",
-          permission,
+          permission: PermissionNext.merge(defaults, user),
           options: {},
           native: false,
         }

+ 3 - 4
packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx

@@ -161,10 +161,9 @@ export function PermissionPrompt(props: { request: PermissionRequest }) {
               </Match>
               <Match when={props.request.permission === "task"}>
                 <TextBody
-                  icon="◉"
-                  title={
-                    `${Locale.titlecase(input().subagent_type as string)} Task "` + (input().description ?? "") + `"`
-                  }
+                  icon="#"
+                  title={`${Locale.titlecase((input().subagent_type as string) ?? "Unknown")} Task`}
+                  description={"◉ " + input().description}
                 />
               </Match>
               <Match when={props.request.permission === "webfetch"}>

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

@@ -153,7 +153,7 @@ export namespace SessionProcessor {
                           JSON.stringify(p.state.input) === JSON.stringify(value.input),
                       )
                     ) {
-                      const agent = await Agent.get(input.assistantMessage.mode)
+                      const agent = await Agent.get(input.assistantMessage.agent)
                       await PermissionNext.ask({
                         permission: "doom_loop",
                         patterns: [value.toolName],

+ 11 - 10
packages/opencode/src/session/prompt.ts

@@ -241,6 +241,7 @@ export namespace SessionPrompt {
     using _ = defer(() => cancel(sessionID))
 
     let step = 0
+    const session = await Session.get(sessionID)
     while (true) {
       SessionStatus.set(sessionID, { type: "busy" })
       log.info("loop", { step, sessionID })
@@ -277,7 +278,7 @@ export namespace SessionPrompt {
       step++
       if (step === 1)
         ensureTitle({
-          session: await Session.get(sessionID),
+          session,
           modelID: lastUser.model.modelID,
           providerID: lastUser.model.providerID,
           message: msgs.find((m) => m.info.role === "user")!,
@@ -519,7 +520,7 @@ export namespace SessionPrompt {
       })
       const tools = await resolveTools({
         agent,
-        sessionID,
+        session,
         model,
         tools: lastUser.tools,
         processor,
@@ -589,7 +590,7 @@ export namespace SessionPrompt {
   async function resolveTools(input: {
     agent: Agent.Info
     model: Provider.Model
-    sessionID: string
+    session: Session.Info
     tools?: Record<string, boolean>
     processor: SessionProcessor.Info
   }) {
@@ -606,7 +607,7 @@ export namespace SessionPrompt {
             "tool.execute.before",
             {
               tool: item.id,
-              sessionID: input.sessionID,
+              sessionID: input.session.id,
               callID: options.toolCallId,
             },
             {
@@ -614,7 +615,7 @@ export namespace SessionPrompt {
             },
           )
           const ctx: Tool.Context = {
-            sessionID: input.sessionID,
+            sessionID: input.session.id,
             abort: options.abortSignal!,
             messageID: input.processor.message.id,
             callID: options.toolCallId,
@@ -640,7 +641,7 @@ export namespace SessionPrompt {
             async ask(req) {
               await PermissionNext.ask({
                 ...req,
-                sessionID: input.sessionID,
+                sessionID: input.session.parentID ?? input.session.id,
                 tool: { messageID: input.processor.message.id, callID: options.toolCallId },
                 ruleset: input.agent.permission,
               })
@@ -651,7 +652,7 @@ export namespace SessionPrompt {
             "tool.execute.after",
             {
               tool: item.id,
-              sessionID: input.sessionID,
+              sessionID: input.session.id,
               callID: options.toolCallId,
             },
             result,
@@ -676,7 +677,7 @@ export namespace SessionPrompt {
           "tool.execute.before",
           {
             tool: key,
-            sessionID: input.sessionID,
+            sessionID: input.session.id,
             callID: opts.toolCallId,
           },
           {
@@ -689,7 +690,7 @@ export namespace SessionPrompt {
           "tool.execute.after",
           {
             tool: key,
-            sessionID: input.sessionID,
+            sessionID: input.session.id,
             callID: opts.toolCallId,
           },
           result,
@@ -704,7 +705,7 @@ export namespace SessionPrompt {
           } else if (contentItem.type === "image") {
             attachments.push({
               id: Identifier.ascending("part"),
-              sessionID: input.sessionID,
+              sessionID: input.session.id,
               messageID: input.processor.message.id,
               type: "file",
               mime: contentItem.mimeType,