mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-10 14:10:37 -07:00
feat(plan): enable built-in research subagents in plan mode (#20972)
This commit is contained in:
@@ -25,7 +25,7 @@ implementation. It allows you to:
|
||||
- [Customizing Planning with Skills](#customizing-planning-with-skills)
|
||||
- [Customizing Policies](#customizing-policies)
|
||||
- [Example: Allow git commands in Plan Mode](#example-allow-git-commands-in-plan-mode)
|
||||
- [Example: Enable research subagents in Plan Mode](#example-enable-research-subagents-in-plan-mode)
|
||||
- [Example: Enable custom subagents in Plan Mode](#example-enable-custom-subagents-in-plan-mode)
|
||||
- [Custom Plan Directory and Policies](#custom-plan-directory-and-policies)
|
||||
- [Automatic Model Routing](#automatic-model-routing)
|
||||
- [Cleanup](#cleanup)
|
||||
@@ -134,6 +134,7 @@ These are the only allowed tools:
|
||||
|
||||
- **FileSystem (Read):** [`read_file`], [`list_directory`], [`glob`]
|
||||
- **Search:** [`grep_search`], [`google_web_search`]
|
||||
- **Research Subagents:** [`codebase_investigator`], [`cli_help`]
|
||||
- **Interaction:** [`ask_user`]
|
||||
- **MCP Tools (Read):** Read-only [MCP tools] (e.g., `github_read_issue`,
|
||||
`postgres_read_schema`) are allowed.
|
||||
@@ -204,16 +205,17 @@ priority = 100
|
||||
modes = ["plan"]
|
||||
```
|
||||
|
||||
#### Example: Enable research subagents in Plan Mode
|
||||
#### Example: Enable custom subagents in Plan Mode
|
||||
|
||||
You can enable experimental research [subagents] like `codebase_investigator` to
|
||||
help gather architecture details during the planning phase.
|
||||
Built-in research [subagents] like [`codebase_investigator`] and [`cli_help`]
|
||||
are enabled by default in Plan Mode. You can enable additional [custom
|
||||
subagents] by adding a rule to your policy.
|
||||
|
||||
`~/.gemini/policies/research-subagents.toml`
|
||||
|
||||
```toml
|
||||
[[rule]]
|
||||
toolName = "codebase_investigator"
|
||||
toolName = "my_custom_subagent"
|
||||
decision = "allow"
|
||||
priority = 100
|
||||
modes = ["plan"]
|
||||
@@ -319,7 +321,10 @@ those files are not automatically deleted and must be managed manually.
|
||||
[MCP tools]: /docs/tools/mcp-server.md
|
||||
[`save_memory`]: /docs/tools/memory.md
|
||||
[`activate_skill`]: /docs/cli/skills.md
|
||||
[`codebase_investigator`]: /docs/core/subagents.md#codebase_investigator
|
||||
[`cli_help`]: /docs/core/subagents.md#cli_help
|
||||
[subagents]: /docs/core/subagents.md
|
||||
[custom subagents]: /docs/core/subagents.md#creating-custom-subagents
|
||||
[policy engine]: /docs/reference/policy-engine.md
|
||||
[`enter_plan_mode`]: /docs/tools/planning.md#1-enter_plan_mode-enterplanmode
|
||||
[`exit_plan_mode`]: /docs/tools/planning.md#2-exit_plan_mode-exitplanmode
|
||||
|
||||
@@ -72,7 +72,16 @@ priority = 70
|
||||
modes = ["plan"]
|
||||
|
||||
[[rule]]
|
||||
toolName = ["glob", "grep_search", "list_directory", "read_file", "google_web_search", "activate_skill"]
|
||||
toolName = [
|
||||
"glob",
|
||||
"grep_search",
|
||||
"list_directory",
|
||||
"read_file",
|
||||
"google_web_search",
|
||||
"activate_skill",
|
||||
"codebase_investigator",
|
||||
"cli_help"
|
||||
]
|
||||
decision = "allow"
|
||||
priority = 70
|
||||
modes = ["plan"]
|
||||
|
||||
@@ -1593,7 +1593,7 @@ describe('PolicyEngine', () => {
|
||||
modes: [ApprovalMode.PLAN],
|
||||
},
|
||||
{
|
||||
toolName: 'codebase_investigator',
|
||||
toolName: 'unknown_subagent',
|
||||
decision: PolicyDecision.ALLOW,
|
||||
priority: PRIORITY_SUBAGENT_TOOL,
|
||||
},
|
||||
@@ -1605,7 +1605,7 @@ describe('PolicyEngine', () => {
|
||||
});
|
||||
|
||||
const fixedResult = await fixedEngine.check(
|
||||
{ name: 'codebase_investigator' },
|
||||
{ name: 'unknown_subagent' },
|
||||
undefined,
|
||||
);
|
||||
|
||||
|
||||
@@ -909,7 +909,7 @@ priority = 100
|
||||
}
|
||||
});
|
||||
|
||||
it('should override default subagent rules when in Plan Mode', async () => {
|
||||
it('should override default subagent rules when in Plan Mode for unknown subagents', async () => {
|
||||
const planTomlPath = path.resolve(__dirname, 'policies', 'plan.toml');
|
||||
const fileContent = await fs.readFile(planTomlPath, 'utf-8');
|
||||
const tempPolicyDir = await fs.mkdtemp(
|
||||
@@ -931,9 +931,9 @@ priority = 100
|
||||
approvalMode: ApprovalMode.PLAN,
|
||||
});
|
||||
|
||||
// 3. Simulate a Subagent being registered (Dynamic Rule)
|
||||
// 3. Simulate an unknown Subagent being registered (Dynamic Rule)
|
||||
engine.addRule({
|
||||
toolName: 'codebase_investigator',
|
||||
toolName: 'unknown_subagent',
|
||||
decision: PolicyDecision.ALLOW,
|
||||
priority: PRIORITY_SUBAGENT_TOOL,
|
||||
source: 'AgentRegistry (Dynamic)',
|
||||
@@ -942,13 +942,13 @@ priority = 100
|
||||
// 4. Verify Behavior:
|
||||
// The Plan Mode "Catch-All Deny" (from plan.toml) should override the Subagent Allow
|
||||
const checkResult = await engine.check(
|
||||
{ name: 'codebase_investigator' },
|
||||
{ name: 'unknown_subagent' },
|
||||
undefined,
|
||||
);
|
||||
|
||||
expect(
|
||||
checkResult.decision,
|
||||
'Subagent should be DENIED in Plan Mode',
|
||||
'Unknown subagent should be DENIED in Plan Mode',
|
||||
).toBe(PolicyDecision.DENY);
|
||||
|
||||
// 5. Verify Explicit Allows still work
|
||||
@@ -958,6 +958,25 @@ priority = 100
|
||||
readResult.decision,
|
||||
'Explicitly allowed tools (read_file) should be ALLOWED in Plan Mode',
|
||||
).toBe(PolicyDecision.ALLOW);
|
||||
|
||||
// 6. Verify Built-in Research Subagents are ALLOWED
|
||||
const codebaseResult = await engine.check(
|
||||
{ name: 'codebase_investigator' },
|
||||
undefined,
|
||||
);
|
||||
expect(
|
||||
codebaseResult.decision,
|
||||
'codebase_investigator should be ALLOWED in Plan Mode',
|
||||
).toBe(PolicyDecision.ALLOW);
|
||||
|
||||
const cliHelpResult = await engine.check(
|
||||
{ name: 'cli_help' },
|
||||
undefined,
|
||||
);
|
||||
expect(
|
||||
cliHelpResult.decision,
|
||||
'cli_help should be ALLOWED in Plan Mode',
|
||||
).toBe(PolicyDecision.ALLOW);
|
||||
} finally {
|
||||
await fs.rm(tempPolicyDir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user