From 0ba6bde93e973fe4fcf4281596179576761fa2f8 Mon Sep 17 00:00:00 2001 From: Christian Gunderman Date: Mon, 16 Feb 2026 11:58:27 -0800 Subject: [PATCH] Define generalist tool name. --- .../core/src/agents/generalist-agent.test.ts | 3 +- packages/core/src/agents/generalist-agent.ts | 3 +- packages/core/src/agents/registry.test.ts | 11 +-- packages/core/src/prompts/snippets.legacy.ts | 13 ++- packages/core/src/prompts/snippets.ts | 86 +++++++++++-------- packages/core/src/tools/tool-names.ts | 1 + 6 files changed, 69 insertions(+), 48 deletions(-) diff --git a/packages/core/src/agents/generalist-agent.test.ts b/packages/core/src/agents/generalist-agent.test.ts index 84426b926b..fbed15611a 100644 --- a/packages/core/src/agents/generalist-agent.test.ts +++ b/packages/core/src/agents/generalist-agent.test.ts @@ -10,6 +10,7 @@ import { makeFakeConfig } from '../test-utils/config.js'; import type { ToolRegistry } from '../tools/tool-registry.js'; import type { AgentRegistry } from './registry.js'; import { DiscoveredMCPTool } from '../tools/mcp-tool.js'; +import { GENERALIST_TOOL_NAME } from '../tools/tool-names.js'; describe('GeneralistAgent', () => { it('should create a valid generalist agent definition', () => { @@ -30,7 +31,7 @@ describe('GeneralistAgent', () => { const agent = GeneralistAgent(config); - expect(agent.name).toBe('generalist'); + expect(agent.name).toBe(GENERALIST_TOOL_NAME); expect(agent.kind).toBe('local'); expect(agent.modelConfig.model).toBe('inherit'); expect(agent.toolConfig?.tools).toBeDefined(); diff --git a/packages/core/src/agents/generalist-agent.ts b/packages/core/src/agents/generalist-agent.ts index db2c56f61d..264e178802 100644 --- a/packages/core/src/agents/generalist-agent.ts +++ b/packages/core/src/agents/generalist-agent.ts @@ -9,6 +9,7 @@ import type { Config } from '../config/config.js'; import { getCoreSystemPrompt } from '../core/prompts.js'; import type { LocalAgentDefinition } from './types.js'; import { DiscoveredMCPTool } from '../tools/mcp-tool.js'; +import { GENERALIST_TOOL_NAME } from '../tools/tool-names.js'; const GeneralistAgentSchema = z.object({ response: z.string().describe('The final response from the agent.'), @@ -22,7 +23,7 @@ export const GeneralistAgent = ( config: Config, ): LocalAgentDefinition => ({ kind: 'local', - name: 'generalist', + name: GENERALIST_TOOL_NAME, displayName: 'Generalist Agent', description: `A general-purpose AI agent with access to all tools. - ALWAYS use it to break up and parallelize independent pieces of a larger task, when possible. diff --git a/packages/core/src/agents/registry.test.ts b/packages/core/src/agents/registry.test.ts index 2068968428..51a8688d35 100644 --- a/packages/core/src/agents/registry.test.ts +++ b/packages/core/src/agents/registry.test.ts @@ -27,6 +27,7 @@ import type { ToolRegistry } from '../tools/tool-registry.js'; import { ThinkingLevel } from '@google/genai'; import type { AcknowledgedAgentsService } from './acknowledgedAgents.js'; import { PolicyDecision } from '../policy/types.js'; +import { GENERALIST_TOOL_NAME } from '../tools/tool-names.js'; vi.mock('./agentLoader.js', () => ({ loadAgentsFromDirectory: vi @@ -302,14 +303,14 @@ describe('AgentRegistry', () => { await registry.initialize(); - expect(registry.getDefinition('generalist')).toBeUndefined(); + expect(registry.getDefinition(GENERALIST_TOOL_NAME)).toBeUndefined(); }); it('should register generalist agent if explicitly enabled via override', async () => { const config = makeMockedConfig({ agents: { overrides: { - generalist: { enabled: true }, + [GENERALIST_TOOL_NAME]: { enabled: true }, }, }, }); @@ -317,7 +318,7 @@ describe('AgentRegistry', () => { await registry.initialize(); - expect(registry.getDefinition('generalist')).toBeDefined(); + expect(registry.getDefinition(GENERALIST_TOOL_NAME)).toBeDefined(); }); it('should NOT register a non-experimental agent if enabled is false', async () => { @@ -340,7 +341,7 @@ describe('AgentRegistry', () => { const config = makeMockedConfig({ agents: { overrides: { - generalist: { enabled: false }, + [GENERALIST_TOOL_NAME]: { enabled: false }, }, }, }); @@ -348,7 +349,7 @@ describe('AgentRegistry', () => { await registry.initialize(); - expect(registry.getDefinition('generalist')).toBeUndefined(); + expect(registry.getDefinition(GENERALIST_TOOL_NAME)).toBeUndefined(); }); it('should load agents from active extensions', async () => { diff --git a/packages/core/src/prompts/snippets.legacy.ts b/packages/core/src/prompts/snippets.legacy.ts index b301a97afe..4a98648f39 100644 --- a/packages/core/src/prompts/snippets.legacy.ts +++ b/packages/core/src/prompts/snippets.legacy.ts @@ -11,6 +11,7 @@ import { EDIT_TOOL_NAME, ENTER_PLAN_MODE_TOOL_NAME, EXIT_PLAN_MODE_TOOL_NAME, + GENERALIST_TOOL_NAME, GLOB_TOOL_NAME, GREP_TOOL_NAME, MEMORY_TOOL_NAME, @@ -497,15 +498,19 @@ function workflowStepPlan(options: PrimaryWorkflowsOptions): string { return `2. **Plan:** An approved plan is available for this task. Use this file as a guide for your implementation. You MUST read this file before proceeding. If you discover new requirements or need to change the approach, confirm with the user and update this plan file to reflect the updated design decisions or discovered requirements.`; } if (options.enableCodebaseInvestigator && options.enableWriteTodosTool) { - return `2. **Plan:** Build a coherent and grounded (based on the understanding in step 1) plan for how you intend to resolve the user's task. If the user's request implies a change but does not explicitly state it, **YOU MUST ASK** for confirmation before modifying code. If 'codebase_investigator' was used, do not ignore the output of the agent, you must use it as the foundation of your plan. For complex tasks, break them down into smaller, manageable subtasks and use the \`${WRITE_TODOS_TOOL_NAME}\` tool to track your progress. When these subtasks are independent, leverage the 'generalist' agent to execute them in parallel, increasing efficiency. Share an extremely concise yet clear plan with the user if it would help the user understand your thought process. As part of the plan, you should use an iterative development process that includes writing unit tests to verify your changes. Use output logs or debug statements as part of this process to arrive at a solution.`; + return `2. **Plan:** Build a coherent and grounded (based on the understanding in step 1) plan for how you intend to resolve the user's task. If the user's request implies a change but does not explicitly state it, **YOU MUST ASK** for confirmation before modifying code. If 'codebase_investigator' was used, do not ignore the output of the agent, you must use it as the foundation of your plan. For complex tasks, break them down into smaller, manageable subtasks and use the \`${WRITE_TODOS_TOOL_NAME}\` tool to track your progress. When these subtasks are independent, leverage the '${GENERALIST_TOOL_NAME}' agent to execute them in parallel, increasing efficiency. Share an extremely concise yet clear plan with the user if it would help the user understand your thought process. As part of the plan, you should use an iterative development process that includes writing unit tests to verify your changes. Use output logs or debug statements as part of this process to arrive at a solution.`; } if (options.enableCodebaseInvestigator) { - return `2. **Plan:** Build a coherent and grounded (based on the understanding in step 1) plan for how you intend to resolve the user's task. If the user's request implies a change but does not explicitly state it, **YOU MUST ASK** for confirmation before modifying code. If 'codebase_investigator' was used, do not ignore the output of the agent, you must use it as the foundation of your plan. For tasks that can be broken down into independent sub-tasks, leverage the 'generalist' agent to parallelize their execution. Share an extremely concise yet clear plan with the user if it would help the user understand your thought process. As part of the plan, you should use an iterative development process that includes writing unit tests to verify your changes. Use output logs or debug statements as part of this process to arrive at a solution.`; + return `2. **Plan:** Build a coherent and grounded (based on the understanding in step 1) plan for how you intend to resolve the user's task. If the user's request implies a change but does not explicitly state it, **YOU MUST ASK** for confirmation before modifying code. If 'codebase_investigator' was used, do not ignore the output of the agent, you must use it as the foundation of your plan. For tasks that can be broken down into independent sub-tasks, leverage the '${GENERALIST_TOOL_NAME}' agent to parallelize their execution. Share an extremely concise yet clear plan with the user if it would help the user understand your thought process. As part of the plan, you should use an iterative development process that includes writing unit tests to verify your changes. Use output logs or debug statements as part of this process to arrive at a solution.`; } if (options.enableWriteTodosTool) { - return `2. **Plan:** Build a coherent and grounded (based on the understanding in step 1) plan for how you intend to resolve the user's task. If the user's request implies a change but does not explicitly state it, **YOU MUST ASK** for confirmation before modifying code. For complex tasks, break them down into smaller, manageable subtasks and use the \`${WRITE_TODOS_TOOL_NAME}\` tool to track your progress. When these subtasks are independent, leverage the 'generalist' agent to execute them in parallel, increasing efficiency. Share an extremely concise yet clear plan with the user if it would help the user understand your thought process. As part of the plan, you should use an iterative development process that includes writing unit tests to verify your changes. Use output logs or debug statements as part of this process to arrive at a solution.`; + return `2. **Plan:** Build a coherent and grounded (based on the understanding in step 1) plan for how you intend to resolve the user's task. If the user's request implies a change but does not explicitly state it, **YOU MUST ASK** for confirmation before modifying code. For complex tasks, break them down into smaller, manageable subtasks and use the \`${WRITE_TODOS_TOOL_NAME}\` tool to track your progress. When these subtasks are independent, leverage the '${GENERALIST_TOOL_NAME}' agent to execute them in parallel, increasing efficiency. Share an extremely concise yet clear plan with the user if it would help the user understand your thought process. As part of the plan, you should use an iterative development process that includes writing unit tests to verify your changes. Use output logs or debug statements as part of this process to arrive at a solution.`; } - return "2. **Plan:** Build a coherent and grounded (based on the understanding in step 1) plan for how you intend to resolve the user's task. If the user's request implies a change but does not explicitly state it, **YOU MUST ASK** for confirmation before modifying code. For tasks that can be broken down into independent sub-tasks, leverage the 'generalist' agent to parallelize their execution. Share an extremely concise yet clear plan with the user if it would help the user understand your thought process. As part of the plan, you should use an iterative development process that includes writing unit tests to verify your changes. Use output logs or debug statements as part of this process to arrive at a solution."; + return ( + "2. **Plan:** Build a coherent and grounded (based on the understanding in step 1) plan for how you intend to resolve the user's task. If the user's request implies a change but does not explicitly state it, **YOU MUST ASK** for confirmation before modifying code. For tasks that can be broken down into independent sub-tasks, leverage the '" + + GENERALIST_TOOL_NAME + + "' agent to parallelize their execution. Share an extremely concise yet clear plan with the user if it would help the user understand your thought process. As part of the plan, you should use an iterative development process that includes writing unit tests to verify your changes. Use output logs or debug statements as part of this process to arrive at a solution." + ); } function workflowVerifyStandardsSuffix(interactive: boolean): string { diff --git a/packages/core/src/prompts/snippets.ts b/packages/core/src/prompts/snippets.ts index 57b6b2dac2..4f938ed778 100644 --- a/packages/core/src/prompts/snippets.ts +++ b/packages/core/src/prompts/snippets.ts @@ -10,6 +10,7 @@ import { EDIT_TOOL_NAME, ENTER_PLAN_MODE_TOOL_NAME, EXIT_PLAN_MODE_TOOL_NAME, + GENERALIST_TOOL_NAME, GLOB_TOOL_NAME, GREP_TOOL_NAME, MEMORY_TOOL_NAME, @@ -168,42 +169,6 @@ export function renderCoreMandates(options?: CoreMandatesOptions): string { - Always scope and limit your searches to avoid context window exhaustion and ensure high-signal results. Use include to target relevant files and strictly limit results using total_max_matches and max_matches_per_file, especially during the research phase. - For broad discovery, use names_only=true or max_matches_per_file=1 to identify files without retrieving their context. -## Parallelism -You MUST ALWAYS utilize the generalist subagent to conserve context when doing repetitive tasks and parallelize independent bodies of work, even if you think you don't need to. This is very IMPORTANT to ensure you stay on track on repetitive tasks and/or complete tasks in a timely fashion. - -Tasks that should be delegated include: - -- Creating, refactoring, building, or updating independent projects or directories, one per generalist call. -- Refactor separate files by splitting them into batches, one batch for each generalist. -- Parallelizing finding the answer to multiple questions, one parallel generalist call per question. -- Repetitive changes across a codebase should be batched and delegated to a subagent. - - - -Try to delegate similarly sized pieces to the generalist. For example: -- Creating two projects -> each can be its own delegation. -- Repetitive code changes -> first, check the size of the work, and split it into batches of similar size. -- You can use up to 4 parallel subagents. Use as many as you can to complete the task faster. - - -Always use parallel agents (via calls to \`generalist\`) or parallel tool calls when -able to do so safely. - - -Generally safe to parallelize and minimal risk of concurrency issues: - -- Edits to different files. -- Multi-step tasks that touch different folders, with generalist. -- Multi-step read-only investigations, with generalist. -- grep_search and ls to different directories. - - -Not safe to parallelize. Will likely cause concurrency issues. - -- generalist tasks that involve making builds or edits to the same set of files. - - - ## Engineering Standards - **Contextual Precedence:** Instructions found in ${formattedFilenames} files are foundational mandates. They take absolute precedence over the general workflows and tool defaults described in this system prompt. - **Conventions & Style:** Rigorously adhere to existing workspace conventions, architectural patterns, and style (naming, formatting, typing, commenting). During the research phase, analyze surrounding files, tests, and configuration to ensure your changes are seamless, idiomatic, and consistent with the local context. Never compromise idiomatic quality or completeness (e.g., proper declarations, type safety, documentation) to minimize tool calls; all supporting changes required by local conventions are part of a surgical update. @@ -230,6 +195,12 @@ export function renderSubAgents(subAgents?: SubAgentOptions[]): string { ) .join('\n'); + const parallelismInstructions = subAgents.some( + (agent) => agent.name === GENERALIST_TOOL_NAME, + ) + ? renderParallelismInstructions() + : ''; + return ` # Available Sub-Agents @@ -243,7 +214,9 @@ Remember that the closest relevant sub-agent should still be used even if its ex For example: - A license-agent -> Should be used for a range of tasks, including reading, validating, and updating licenses and headers. -- A test-fixing-agent -> Should be used both for fixing tests as well as investigating test failures.`.trim(); +- A test-fixing-agent -> Should be used both for fixing tests as well as investigating test failures. + +${parallelismInstructions}`.trim(); } export function renderAgentSkills(skills?: AgentSkillOptions[]): string { @@ -500,6 +473,45 @@ An approved plan is available for this task at \`${approvedPlanPath}\`. `; } +function renderParallelismInstructions(): string { + return ` +## Parallelism +You MUST ALWAYS utilize the generalist subagent to conserve context when doing repetitive tasks and parallelize independent bodies of work, even if you think you don't need to. This is very IMPORTANT to ensure you stay on track on repetitive tasks and/or complete tasks in a timely fashion. + +Tasks that should be delegated include: + +- Creating, refactoring, building, or updating independent projects or directories, one per generalist call. +- Refactor separate files by splitting them into batches, one batch for each generalist. +- Parallelizing finding the answer to multiple questions, one parallel generalist call per question. +- Repetitive changes across a codebase should be batched and delegated to a subagent. + + + +Try to delegate similarly sized pieces to the generalist. For example: +- Creating two projects -> each can be its own delegation. +- Repetitive code changes -> first, check the size of the work, and split it into batches of similar size. +- You can use up to 4 parallel subagents. Use as many as you can to complete the task faster. + + +Always use parallel agents (via calls to \`generalist\`) or parallel tool calls when +able to do so safely. + + +Generally safe to parallelize and minimal risk of concurrency issues: + +- Edits to different files. +- Multi-step tasks that touch different folders, with generalist. +- Multi-step read-only investigations, with generalist. +- grep_search and ls to different directories. + + +Not safe to parallelize. Will likely cause concurrency issues. + +- generalist tasks that involve making builds or edits to the same set of files. + +`; +} + // --- Leaf Helpers (Strictly strings or simple calls) --- function mandateConfirm(interactive: boolean): string { diff --git a/packages/core/src/tools/tool-names.ts b/packages/core/src/tools/tool-names.ts index 88041ec7fe..6b9a1ce703 100644 --- a/packages/core/src/tools/tool-names.ts +++ b/packages/core/src/tools/tool-names.ts @@ -43,6 +43,7 @@ export const ASK_USER_TOOL_NAME = 'ask_user'; export const ASK_USER_DISPLAY_NAME = 'Ask User'; export const EXIT_PLAN_MODE_TOOL_NAME = 'exit_plan_mode'; export const ENTER_PLAN_MODE_TOOL_NAME = 'enter_plan_mode'; +export const GENERALIST_TOOL_NAME = 'generalist'; /** * Mapping of legacy tool names to their current names.