feat(orchestrator): add research tools
- commit
- 0cfe50a3a2ee1eaf018ecdec4f9e469dc9815056
- author
- brice · · 2026-08-19 04:52 UTC
- parent
- 9a87de4
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
4 files · +79 -13
M README.md +2 -2
| @@ -425,7 +425,7 @@ The fair global scheduler defaults to six concurrent turns, one active turn per | |||
| 425 | 425 | ||
| 426 | 426 | Worktree isolation captures a patch and changed-file list without applying it. Shared children use the host checkout. The available logical references are `subagent://<id>`, `subagent://<id>/history`, `subagent://<id>/result`, and `subagent://<id>/patch`. | |
| 427 | 427 | ||
| 428 | - | **Subagent Orchestrator.** With `/settings` → **Subagent Orchestrator** on (or `/orchestrator`), the primary delegates implementation, debugging/testing, and code review to named profiles or explicitly described general children. It coordinates and synthesizes completion updates rather than doing direct implementation. The canonical resident tools remain available for user-requested delegation when the setting is off, subject to launch-time permissions. Do not poll `subagent_status` or journal files solely to wait for completion. | |
| 428 | + | **Subagent Orchestrator.** With `/settings` → **Subagent Orchestrator** on (or `/orchestrator`), the primary delegates implementation, debugging/testing, and code review to named profiles or explicitly described general children. It may use `read` and `grep` for codebase exploration and `web_search` for public-web research before dispatching work, but does not implement directly. These research tools remain available after a requested tool allowlist is applied unless tools are disabled with `--no-tools`. The canonical resident tools remain available for user-requested delegation when the setting is off, subject to launch-time permissions. Do not poll `subagent_status` or journal files solely to wait for completion. | |
| 429 | 429 | ||
| 430 | 430 | ### Named subagent profiles | |
| 431 | 431 | ||
| @@ -439,7 +439,7 @@ Opens a dialog with every persistent setting. `up`/`down` to navigate, `enter` o | |||
| 439 | 439 | - **render images when supported** — draw screenshots / `read`-returned images inline using the terminal's image protocol, or fall back to a text placeholder. Auto-detected from `TERM_PROGRAM`; the toggle overrides the detection. The row is greyed out and forced off on terminals that don't speak any image protocol. | |
| 440 | 440 | - **terminal alerts** — emit a terminal bell when the main session stops with work that may need attention, or when an extension raises a structured alert. Enabled by default; changes apply immediately and persist as `terminal_alerts_enabled`. Terminal emulators may render the bell audibly, visually, or not at all. | |
| 441 | 441 | - **AI terminal titles** — after the first real prompt of a fresh interactive session, make one small hidden request to the active model and set the terminal title to `zut: <title>`. The title is limited to 40 Unicode characters, persisted with the session, restored on resume, and never added to the conversation. Enabled by default; disable it to avoid the extra model request. The toggle applies immediately, but title generation still waits for the first real prompt and never starts from startup context, resumed history, or slash commands. Persists as `terminal_title_enabled`. | |
| 442 | - | - **Subagent Orchestrator** — enable strict primary-agent orchestrator mode: delegate implementation, debugging/testing, and code-review work to named or general workers; the primary agent coordinates but does not make direct implementation changes. It can spawn optional or required background sub-agents via `subagent_spawn` and query live state via `subagent_status` when those tools are permitted. If delegation is unavailable because of launch-time restrictions, the contract remains active, profile metadata is withheld, and the primary reports the limitation rather than implementing directly. Off by default. When off, the permitted canonical subagent tools and profile manifest remain available for user-requested delegation or when an active skill workflow requires it; the primary otherwise works directly without the strict orchestrator contract. The tools accept named profiles, reasoning, per-spawn fast-mode overrides, and shared/worktree isolation where applicable; lifecycle and result references are persisted. Completion is host-event-driven through `[auto-subagents update]` for every worker; required work stays asynchronous, persists its outcome, and prevents only the terminal parent response until satisfied or explicitly waived by user removal. Do not poll or inspect dashboards, metadata, event logs, or files solely to wait. See `/subagents` and [docs/subagents.md](docs/subagents.md) for details. | |
| 442 | + | - **Subagent Orchestrator** — enable strict primary-agent orchestrator mode: delegate implementation, debugging/testing, and code-review work to named or general workers; the primary agent may use `read`, `grep`, and `web_search` for read-only research to prepare precise tasks, but does not make direct implementation changes. In orchestrated sessions, these research tools are added after the requested tool allowlist is applied unless tools are disabled with `--no-tools`. It can spawn optional or required background sub-agents via `subagent_spawn` and query live state via `subagent_status` when those tools are permitted. If delegation is unavailable because of launch-time restrictions, the contract remains active, profile metadata is withheld, and the primary reports the limitation rather than implementing directly. Off by default. When off, the permitted canonical subagent tools and profile manifest remain available for user-requested delegation or when an active skill workflow requires it; the primary otherwise works directly without the strict orchestrator contract. The tools accept named profiles, reasoning, per-spawn fast-mode overrides, and shared/worktree isolation where applicable; lifecycle and result references are persisted. Completion is host-event-driven through `[auto-subagents update]` for every worker; required work stays asynchronous, persists its outcome, and prevents only the terminal parent response until satisfied or explicitly waived by user removal. Do not poll or inspect dashboards, metadata, event logs, or files solely to wait. See `/subagents` and [docs/subagents.md](docs/subagents.md) for details. | |
| 443 | 443 | - **Ponytail coding mode** — include compact engineering guidance in each resolved system prompt; the guidance tells the model to apply it to coding, debugging, and review work rather than ordinary conversation. It favors understanding the real flow, small validated changes, reuse, and preserving safety checks. Enabled by default; changes apply to the next model call and persist as `ponytail_enabled` in `$ZUT_HOME/config.json`. It is included by interactive, print, stream, JSON, RPC, subagent, bot, SDK, and Zutfile agents. | |
| 444 | 444 | - **fast mode** — request the provider's fast tier where supported. It currently uses OpenAI's Fast service tier for OpenAI, OpenAI Responses, and OpenAI Codex models. Off by default; toggle it with `/fast` or `/settings`; changes apply on the next model call and persist as `fast_mode`. Other providers currently return an unsupported-provider error. Fast mode may cost more and depends on the selected model/account. | |
| 445 | 445 | - **lsp in main session** — enable the built-in `lsp` tool and code diagnostics for the main agent. Enabled by default; changes persist as `lsp_enabled`. | |
| @@ -425,7 +425,7 @@ The fair global scheduler defaults to six concurrent turns, one active turn per | |||||
| 425 | 425 | ||||
| 426 | Worktree isolation captures a patch and changed-file list without applying it. Shared children use the host checkout. The available logical references are `subagent://<id>`, `subagent://<id>/history`, `subagent://<id>/result`, and `subagent://<id>/patch`. | 426 | Worktree isolation captures a patch and changed-file list without applying it. Shared children use the host checkout. The available logical references are `subagent://<id>`, `subagent://<id>/history`, `subagent://<id>/result`, and `subagent://<id>/patch`. | ||
| 427 | 427 | ||||
| 428 | - | **Subagent Orchestrator.** With `/settings` → **Subagent Orchestrator** on (or `/orchestrator`), the primary delegates implementation, debugging/testing, and code review to named profiles or explicitly described general children. It coordinates and synthesizes completion updates rather than doing direct implementation. The canonical resident tools remain available for user-requested delegation when the setting is off, subject to launch-time permissions. Do not poll `subagent_status` or journal files solely to wait for completion. | 428 | + | **Subagent Orchestrator.** With `/settings` → **Subagent Orchestrator** on (or `/orchestrator`), the primary delegates implementation, debugging/testing, and code review to named profiles or explicitly described general children. It may use `read` and `grep` for codebase exploration and `web_search` for public-web research before dispatching work, but does not implement directly. These research tools remain available after a requested tool allowlist is applied unless tools are disabled with `--no-tools`. The canonical resident tools remain available for user-requested delegation when the setting is off, subject to launch-time permissions. Do not poll `subagent_status` or journal files solely to wait for completion. |
| 429 | 429 | ||||
| 430 | ### Named subagent profiles | 430 | ### Named subagent profiles | ||
| 431 | 431 | ||||
| @@ -439,7 +439,7 @@ Opens a dialog with every persistent setting. `up`/`down` to navigate, `enter` o | |||||
| 439 | - **render images when supported** — draw screenshots / `read`-returned images inline using the terminal's image protocol, or fall back to a text placeholder. Auto-detected from `TERM_PROGRAM`; the toggle overrides the detection. The row is greyed out and forced off on terminals that don't speak any image protocol. | 439 | - **render images when supported** — draw screenshots / `read`-returned images inline using the terminal's image protocol, or fall back to a text placeholder. Auto-detected from `TERM_PROGRAM`; the toggle overrides the detection. The row is greyed out and forced off on terminals that don't speak any image protocol. | ||
| 440 | - **terminal alerts** — emit a terminal bell when the main session stops with work that may need attention, or when an extension raises a structured alert. Enabled by default; changes apply immediately and persist as `terminal_alerts_enabled`. Terminal emulators may render the bell audibly, visually, or not at all. | 440 | - **terminal alerts** — emit a terminal bell when the main session stops with work that may need attention, or when an extension raises a structured alert. Enabled by default; changes apply immediately and persist as `terminal_alerts_enabled`. Terminal emulators may render the bell audibly, visually, or not at all. | ||
| 441 | - **AI terminal titles** — after the first real prompt of a fresh interactive session, make one small hidden request to the active model and set the terminal title to `zut: <title>`. The title is limited to 40 Unicode characters, persisted with the session, restored on resume, and never added to the conversation. Enabled by default; disable it to avoid the extra model request. The toggle applies immediately, but title generation still waits for the first real prompt and never starts from startup context, resumed history, or slash commands. Persists as `terminal_title_enabled`. | 441 | - **AI terminal titles** — after the first real prompt of a fresh interactive session, make one small hidden request to the active model and set the terminal title to `zut: <title>`. The title is limited to 40 Unicode characters, persisted with the session, restored on resume, and never added to the conversation. Enabled by default; disable it to avoid the extra model request. The toggle applies immediately, but title generation still waits for the first real prompt and never starts from startup context, resumed history, or slash commands. Persists as `terminal_title_enabled`. | ||
| 442 | - | - **Subagent Orchestrator** — enable strict primary-agent orchestrator mode: delegate implementation, debugging/testing, and code-review work to named or general workers; the primary agent coordinates but does not make direct implementation changes. It can spawn optional or required background sub-agents via `subagent_spawn` and query live state via `subagent_status` when those tools are permitted. If delegation is unavailable because of launch-time restrictions, the contract remains active, profile metadata is withheld, and the primary reports the limitation rather than implementing directly. Off by default. When off, the permitted canonical subagent tools and profile manifest remain available for user-requested delegation or when an active skill workflow requires it; the primary otherwise works directly without the strict orchestrator contract. The tools accept named profiles, reasoning, per-spawn fast-mode overrides, and shared/worktree isolation where applicable; lifecycle and result references are persisted. Completion is host-event-driven through `[auto-subagents update]` for every worker; required work stays asynchronous, persists its outcome, and prevents only the terminal parent response until satisfied or explicitly waived by user removal. Do not poll or inspect dashboards, metadata, event logs, or files solely to wait. See `/subagents` and [docs/subagents.md](docs/subagents.md) for details. | 442 | + | - **Subagent Orchestrator** — enable strict primary-agent orchestrator mode: delegate implementation, debugging/testing, and code-review work to named or general workers; the primary agent may use `read`, `grep`, and `web_search` for read-only research to prepare precise tasks, but does not make direct implementation changes. In orchestrated sessions, these research tools are added after the requested tool allowlist is applied unless tools are disabled with `--no-tools`. It can spawn optional or required background sub-agents via `subagent_spawn` and query live state via `subagent_status` when those tools are permitted. If delegation is unavailable because of launch-time restrictions, the contract remains active, profile metadata is withheld, and the primary reports the limitation rather than implementing directly. Off by default. When off, the permitted canonical subagent tools and profile manifest remain available for user-requested delegation or when an active skill workflow requires it; the primary otherwise works directly without the strict orchestrator contract. The tools accept named profiles, reasoning, per-spawn fast-mode overrides, and shared/worktree isolation where applicable; lifecycle and result references are persisted. Completion is host-event-driven through `[auto-subagents update]` for every worker; required work stays asynchronous, persists its outcome, and prevents only the terminal parent response until satisfied or explicitly waived by user removal. Do not poll or inspect dashboards, metadata, event logs, or files solely to wait. See `/subagents` and [docs/subagents.md](docs/subagents.md) for details. |
| 443 | - **Ponytail coding mode** — include compact engineering guidance in each resolved system prompt; the guidance tells the model to apply it to coding, debugging, and review work rather than ordinary conversation. It favors understanding the real flow, small validated changes, reuse, and preserving safety checks. Enabled by default; changes apply to the next model call and persist as `ponytail_enabled` in `$ZUT_HOME/config.json`. It is included by interactive, print, stream, JSON, RPC, subagent, bot, SDK, and Zutfile agents. | 443 | - **Ponytail coding mode** — include compact engineering guidance in each resolved system prompt; the guidance tells the model to apply it to coding, debugging, and review work rather than ordinary conversation. It favors understanding the real flow, small validated changes, reuse, and preserving safety checks. Enabled by default; changes apply to the next model call and persist as `ponytail_enabled` in `$ZUT_HOME/config.json`. It is included by interactive, print, stream, JSON, RPC, subagent, bot, SDK, and Zutfile agents. | ||
| 444 | - **fast mode** — request the provider's fast tier where supported. It currently uses OpenAI's Fast service tier for OpenAI, OpenAI Responses, and OpenAI Codex models. Off by default; toggle it with `/fast` or `/settings`; changes apply on the next model call and persist as `fast_mode`. Other providers currently return an unsupported-provider error. Fast mode may cost more and depends on the selected model/account. | 444 | - **fast mode** — request the provider's fast tier where supported. It currently uses OpenAI's Fast service tier for OpenAI, OpenAI Responses, and OpenAI Codex models. Off by default; toggle it with `/fast` or `/settings`; changes apply on the next model call and persist as `fast_mode`. Other providers currently return an unsupported-provider error. Fast mode may cost more and depends on the selected model/account. | ||
| 445 | - **lsp in main session** — enable the built-in `lsp` tool and code diagnostics for the main agent. Enabled by default; changes persist as `lsp_enabled`. | 445 | - **lsp in main session** — enable the built-in `lsp` tool and code diagnostics for the main agent. Enabled by default; changes persist as `lsp_enabled`. | ||
M packages/agent/build.go +11 -9
| @@ -1247,15 +1247,17 @@ func buildToolRegistry(args Args, cwd string, sandbox *tools.Sandbox, lspEnabled | |||
| 1247 | 1247 | for _, t := range all { | |
| 1248 | 1248 | reg[t.Name()] = t | |
| 1249 | 1249 | } | |
| 1250 | - | return reg | |
| 1251 | - | } | |
| 1252 | - | for _, name := range args.Tools { | |
| 1253 | - | if t, ok := all[name]; ok { | |
| 1254 | - | reg[name] = t | |
| 1250 | + | } else { | |
| 1251 | + | for _, name := range args.Tools { | |
| 1252 | + | if t, ok := all[name]; ok { | |
| 1253 | + | reg[name] = t | |
| 1254 | + | } | |
| 1255 | 1255 | } | |
| 1256 | 1256 | } | |
| 1257 | - | if orchestratorReadToolAllowed(args) { | |
| 1257 | + | if orchestratorExplorationToolsAllowed(args) { | |
| 1258 | 1258 | reg["read"] = all["read"] | |
| 1259 | + | reg["grep"] = all["grep"] | |
| 1260 | + | reg["web_search"] = tools.NewWebSearchTool() | |
| 1259 | 1261 | } | |
| 1260 | 1262 | return reg | |
| 1261 | 1263 | } | |
| @@ -1285,9 +1287,9 @@ func autoSubagentsToolAllowed(args Args) bool { | |||
| 1285 | 1287 | return autoSubagentsToolAllowedFor(args, "subagent_spawn") | |
| 1286 | 1288 | } | |
| 1287 | 1289 | ||
| 1288 | - | // orchestratorReadToolAllowed keeps read-only codebase exploration available | |
| 1289 | - | // to the primary orchestrator without widening its launch-time tool policy. | |
| 1290 | - | func orchestratorReadToolAllowed(args Args) bool { | |
| 1290 | + | // orchestratorExplorationToolsAllowed keeps the primary orchestrator's | |
| 1291 | + | // read-only exploration tools available without enabling implementation tools. | |
| 1292 | + | func orchestratorExplorationToolsAllowed(args Args) bool { | |
| 1291 | 1293 | return args.Orchestrate && !args.NoTools | |
| 1292 | 1294 | } | |
| 1293 | 1295 | ||
| @@ -1247,15 +1247,17 @@ func buildToolRegistry(args Args, cwd string, sandbox *tools.Sandbox, lspEnabled | |||||
| 1247 | for _, t := range all { | 1247 | for _, t := range all { | ||
| 1248 | reg[t.Name()] = t | 1248 | reg[t.Name()] = t | ||
| 1249 | } | 1249 | } | ||
| 1250 | - | return reg | 1250 | + | } else { |
| 1251 | - | } | 1251 | + | for _, name := range args.Tools { |
| 1252 | - | for _, name := range args.Tools { | 1252 | + | if t, ok := all[name]; ok { |
| 1253 | - | if t, ok := all[name]; ok { | 1253 | + | reg[name] = t |
| 1254 | - | reg[name] = t | 1254 | + | } |
| 1255 | } | 1255 | } | ||
| 1256 | } | 1256 | } | ||
| 1257 | - | if orchestratorReadToolAllowed(args) { | 1257 | + | if orchestratorExplorationToolsAllowed(args) { |
| 1258 | reg["read"] = all["read"] | 1258 | reg["read"] = all["read"] | ||
| 1259 | + | reg["grep"] = all["grep"] | |||
| 1260 | + | reg["web_search"] = tools.NewWebSearchTool() | |||
| 1259 | } | 1261 | } | ||
| 1260 | return reg | 1262 | return reg | ||
| 1261 | } | 1263 | } | ||
| @@ -1285,9 +1287,9 @@ func autoSubagentsToolAllowed(args Args) bool { | |||||
| 1285 | return autoSubagentsToolAllowedFor(args, "subagent_spawn") | 1287 | return autoSubagentsToolAllowedFor(args, "subagent_spawn") | ||
| 1286 | } | 1288 | } | ||
| 1287 | 1289 | ||||
| 1288 | - | // orchestratorReadToolAllowed keeps read-only codebase exploration available | 1290 | + | // orchestratorExplorationToolsAllowed keeps the primary orchestrator's |
| 1289 | - | // to the primary orchestrator without widening its launch-time tool policy. | 1291 | + | // read-only exploration tools available without enabling implementation tools. |
| 1290 | - | func orchestratorReadToolAllowed(args Args) bool { | 1292 | + | func orchestratorExplorationToolsAllowed(args Args) bool { |
| 1291 | return args.Orchestrate && !args.NoTools | 1293 | return args.Orchestrate && !args.NoTools | ||
| 1292 | } | 1294 | } | ||
| 1293 | 1295 | ||||
A packages/agent/build_orchestrator_test.go +64 -0
| @@ -0,0 +1,64 @@ | |||
| 1 | + | package agent | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "testing" | |
| 5 | + | ||
| 6 | + | "github.com/bnema/zut/packages/agent/subagents" | |
| 7 | + | "github.com/bnema/zut/packages/agent/tools" | |
| 8 | + | ) | |
| 9 | + | ||
| 10 | + | func TestOrchestratorAlwaysReceivesResearchTools(t *testing.T) { | |
| 11 | + | for _, tc := range []struct { | |
| 12 | + | name string | |
| 13 | + | args Args | |
| 14 | + | wantResearch bool | |
| 15 | + | wantWriteTool bool | |
| 16 | + | }{ | |
| 17 | + | { | |
| 18 | + | name: "requested allowlist", | |
| 19 | + | args: Args{Orchestrate: true, ToolsSet: true, Tools: []string{"subagent_spawn"}}, | |
| 20 | + | wantResearch: true, | |
| 21 | + | wantWriteTool: false, | |
| 22 | + | }, | |
| 23 | + | { | |
| 24 | + | name: "web search policy disabled", | |
| 25 | + | args: Args{Orchestrate: true, WebSearchPolicy: subagents.WebSearchDeny}, | |
| 26 | + | wantResearch: true, | |
| 27 | + | wantWriteTool: true, | |
| 28 | + | }, | |
| 29 | + | { | |
| 30 | + | name: "tools disabled", | |
| 31 | + | args: Args{Orchestrate: true, NoTools: true, ToolsSet: true, Tools: []string{"write"}}, | |
| 32 | + | wantResearch: false, | |
| 33 | + | wantWriteTool: false, | |
| 34 | + | }, | |
| 35 | + | { | |
| 36 | + | name: "normal session", | |
| 37 | + | args: Args{ToolsSet: true, Tools: []string{"write"}}, | |
| 38 | + | wantResearch: false, | |
| 39 | + | wantWriteTool: true, | |
| 40 | + | }, | |
| 41 | + | } { | |
| 42 | + | t.Run(tc.name, func(t *testing.T) { | |
| 43 | + | registry := buildToolRegistry(tc.args, t.TempDir(), nil, false, false, false) | |
| 44 | + | ||
| 45 | + | if got := orchestratorExplorationToolsAllowed(tc.args); got != tc.wantResearch { | |
| 46 | + | t.Fatalf("orchestratorExplorationToolsAllowed = %v, want %v", got, tc.wantResearch) | |
| 47 | + | } | |
| 48 | + | _, gotRead := registry["read"] | |
| 49 | + | if gotRead != tc.wantResearch { | |
| 50 | + | t.Fatalf("read present = %v, want %v", gotRead, tc.wantResearch) | |
| 51 | + | } | |
| 52 | + | if _, ok := registry["grep"].(*tools.GrepTool); ok != tc.wantResearch { | |
| 53 | + | t.Fatalf("grep = %T, want research tool present = %v", registry["grep"], tc.wantResearch) | |
| 54 | + | } | |
| 55 | + | if _, ok := registry["web_search"].(*tools.WebSearchTool); ok != tc.wantResearch { | |
| 56 | + | t.Fatalf("web_search = %T, want research tool present = %v", registry["web_search"], tc.wantResearch) | |
| 57 | + | } | |
| 58 | + | _, gotWrite := registry["write"] | |
| 59 | + | if gotWrite != tc.wantWriteTool { | |
| 60 | + | t.Fatalf("write present = %v, want %v", gotWrite, tc.wantWriteTool) | |
| 61 | + | } | |
| 62 | + | }) | |
| 63 | + | } | |
| 64 | + | } | |
| @@ -0,0 +1,64 @@ | |||||
| 1 | + | package agent | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "testing" | |||
| 5 | + | ||||
| 6 | + | "github.com/bnema/zut/packages/agent/subagents" | |||
| 7 | + | "github.com/bnema/zut/packages/agent/tools" | |||
| 8 | + | ) | |||
| 9 | + | ||||
| 10 | + | func TestOrchestratorAlwaysReceivesResearchTools(t *testing.T) { | |||
| 11 | + | for _, tc := range []struct { | |||
| 12 | + | name string | |||
| 13 | + | args Args | |||
| 14 | + | wantResearch bool | |||
| 15 | + | wantWriteTool bool | |||
| 16 | + | }{ | |||
| 17 | + | { | |||
| 18 | + | name: "requested allowlist", | |||
| 19 | + | args: Args{Orchestrate: true, ToolsSet: true, Tools: []string{"subagent_spawn"}}, | |||
| 20 | + | wantResearch: true, | |||
| 21 | + | wantWriteTool: false, | |||
| 22 | + | }, | |||
| 23 | + | { | |||
| 24 | + | name: "web search policy disabled", | |||
| 25 | + | args: Args{Orchestrate: true, WebSearchPolicy: subagents.WebSearchDeny}, | |||
| 26 | + | wantResearch: true, | |||
| 27 | + | wantWriteTool: true, | |||
| 28 | + | }, | |||
| 29 | + | { | |||
| 30 | + | name: "tools disabled", | |||
| 31 | + | args: Args{Orchestrate: true, NoTools: true, ToolsSet: true, Tools: []string{"write"}}, | |||
| 32 | + | wantResearch: false, | |||
| 33 | + | wantWriteTool: false, | |||
| 34 | + | }, | |||
| 35 | + | { | |||
| 36 | + | name: "normal session", | |||
| 37 | + | args: Args{ToolsSet: true, Tools: []string{"write"}}, | |||
| 38 | + | wantResearch: false, | |||
| 39 | + | wantWriteTool: true, | |||
| 40 | + | }, | |||
| 41 | + | } { | |||
| 42 | + | t.Run(tc.name, func(t *testing.T) { | |||
| 43 | + | registry := buildToolRegistry(tc.args, t.TempDir(), nil, false, false, false) | |||
| 44 | + | ||||
| 45 | + | if got := orchestratorExplorationToolsAllowed(tc.args); got != tc.wantResearch { | |||
| 46 | + | t.Fatalf("orchestratorExplorationToolsAllowed = %v, want %v", got, tc.wantResearch) | |||
| 47 | + | } | |||
| 48 | + | _, gotRead := registry["read"] | |||
| 49 | + | if gotRead != tc.wantResearch { | |||
| 50 | + | t.Fatalf("read present = %v, want %v", gotRead, tc.wantResearch) | |||
| 51 | + | } | |||
| 52 | + | if _, ok := registry["grep"].(*tools.GrepTool); ok != tc.wantResearch { | |||
| 53 | + | t.Fatalf("grep = %T, want research tool present = %v", registry["grep"], tc.wantResearch) | |||
| 54 | + | } | |||
| 55 | + | if _, ok := registry["web_search"].(*tools.WebSearchTool); ok != tc.wantResearch { | |||
| 56 | + | t.Fatalf("web_search = %T, want research tool present = %v", registry["web_search"], tc.wantResearch) | |||
| 57 | + | } | |||
| 58 | + | _, gotWrite := registry["write"] | |||
| 59 | + | if gotWrite != tc.wantWriteTool { | |||
| 60 | + | t.Fatalf("write present = %v, want %v", gotWrite, tc.wantWriteTool) | |||
| 61 | + | } | |||
| 62 | + | }) | |||
| 63 | + | } | |||
| 64 | + | } | |||
M packages/agent/settings_store.go +2 -2
| @@ -254,9 +254,9 @@ func AutoSubagentsEnabled() bool { | |||
| 254 | 254 | // orchestrator. | |
| 255 | 255 | const AutoSubagentsSystemAddendum = `Auto-subagents are enabled. You are the primary-agent orchestrator, not an implementer. | |
| 256 | 256 | ||
| 257 | - | - Use the read tool only for read-only codebase exploration before dispatching work. | |
| 257 | + | - Use read and grep only for read-only codebase exploration before dispatching work. Use web_search only for public-web research that improves worker task instructions. | |
| 258 | 258 | - Delegate all implementation, debugging/testing, and code-review work to an appropriately named subagent profile or a clearly described general worker. | |
| 259 | - | - Do not write or edit code yourself, make direct implementation tool calls, inspect or review code through implementation tools, or apply worker patches. You may inspect files with read for read-only exploration and review worker reports. | |
| 259 | + | - Do not write or edit code yourself, make direct implementation tool calls, inspect or review code through implementation tools, or apply worker patches. You may use read, grep, and web_search for the read-only research above and review worker reports. | |
| 260 | 260 | - Give every worker a self-contained task and synthesize the results. | |
| 261 | 261 | ||
| 262 | 262 | Workers start without this conversation's context. Shared-worktree workers edit the same working directory, so coordinate dependent work and avoid conflicting edits. Use isolation:"worktree" for parallel coding when workers need separate trees; its changes are returned as a patch for a worker to integrate, not for you to apply. Do not invent feature scope beyond the user's request. Child workers cannot recursively spawn more sub-agents in v1. | |
| @@ -254,9 +254,9 @@ func AutoSubagentsEnabled() bool { | |||||
| 254 | // orchestrator. | 254 | // orchestrator. | ||
| 255 | const AutoSubagentsSystemAddendum = `Auto-subagents are enabled. You are the primary-agent orchestrator, not an implementer. | 255 | const AutoSubagentsSystemAddendum = `Auto-subagents are enabled. You are the primary-agent orchestrator, not an implementer. | ||
| 256 | 256 | ||||
| 257 | - | - Use the read tool only for read-only codebase exploration before dispatching work. | 257 | + | - Use read and grep only for read-only codebase exploration before dispatching work. Use web_search only for public-web research that improves worker task instructions. |
| 258 | - Delegate all implementation, debugging/testing, and code-review work to an appropriately named subagent profile or a clearly described general worker. | 258 | - Delegate all implementation, debugging/testing, and code-review work to an appropriately named subagent profile or a clearly described general worker. | ||
| 259 | - | - Do not write or edit code yourself, make direct implementation tool calls, inspect or review code through implementation tools, or apply worker patches. You may inspect files with read for read-only exploration and review worker reports. | 259 | + | - Do not write or edit code yourself, make direct implementation tool calls, inspect or review code through implementation tools, or apply worker patches. You may use read, grep, and web_search for the read-only research above and review worker reports. |
| 260 | - Give every worker a self-contained task and synthesize the results. | 260 | - Give every worker a self-contained task and synthesize the results. | ||
| 261 | 261 | ||||
| 262 | Workers start without this conversation's context. Shared-worktree workers edit the same working directory, so coordinate dependent work and avoid conflicting edits. Use isolation:"worktree" for parallel coding when workers need separate trees; its changes are returned as a patch for a worker to integrate, not for you to apply. Do not invent feature scope beyond the user's request. Child workers cannot recursively spawn more sub-agents in v1. | 262 | Workers start without this conversation's context. Shared-worktree workers edit the same working directory, so coordinate dependent work and avoid conflicting edits. Use isolation:"worktree" for parallel coding when workers need separate trees; its changes are returned as a patch for a worker to integrate, not for you to apply. Do not invent feature scope beyond the user's request. Child workers cannot recursively spawn more sub-agents in v1. | ||