Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@abhipatel12
Copy link
Collaborator

@abhipatel12 abhipatel12 commented Dec 9, 2025

Summary

Refactors the delegate_to_agent tool to use a Zod discriminated union for its input schema. This provides explicit, strongly-typed argument schemas for each subagent directly within the tool definition, improving type safety and guiding the model more effectively. It also simplifies the AgentRegistry directory context and updates the tool description to be dynamic.

Details

  • DelegateToAgentTool: Now uses z.discriminatedUnion keyed by agentName. This allows the model to see the specific arguments required for the chosen agent.
  • AgentRegistry: getDirectoryContext() now returns a simplified list of agents with their descriptions and "when to use" guidance, removing the redundant full schema dump.
  • Dynamic Description: The tool's description now lists the currently available agents to help the model choose.
  • Tests: Updated DelegateToAgentTool tests and fixed config.test.ts and prompts.test.ts to align with these changes.
  • Mocking: Added ResourceRegistry mock to config.test.ts and updated prompts.test.ts mocks.

Related Issues

Closes #14316

How to Validate

  1. Run npm test --workspace=packages/core to verify all core tests pass.
  2. Inspect packages/core/src/agents/delegate-to-agent-tool.ts to see the new schema implementation.

Pre-Merge Checklist

  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker

@abhipatel12 abhipatel12 requested a review from a team as a code owner December 9, 2025 04:29
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @abhipatel12, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the delegate_to_agent tool by implementing a Zod discriminated union for its input schema. This change brings enhanced type safety and provides clearer, more explicit argument definitions for subagents, which in turn helps the model better understand and utilize these tools. Additionally, the AgentRegistry's context for available agents has been simplified, and the tool's description is now dynamically generated, making the system more robust and user-friendly for both developers and the AI model.

Highlights

  • Discriminated Union for DelegateToAgentTool: The delegate_to_agent tool now uses a Zod discriminated union for its input schema, providing explicit and strongly-typed arguments for each subagent.
  • Simplified AgentRegistry Context: The AgentRegistry's getDirectoryContext() method has been simplified to return a concise list of agents with descriptions, removing verbose schema details.
  • Dynamic Tool Description: The DelegateToAgentTool's description now dynamically lists currently available agents, improving model guidance.
  • Updated Test Suite: Comprehensive tests for DelegateToAgentTool have been added, and existing tests in config.test.ts and prompts.test.ts were updated to align with the new implementation.
  • Refactored Tool Registration: The Config class now registers the DelegateToAgentTool directly instead of SubagentToolWrapper, streamlining agent tool integration.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request is a great refactoring that introduces a DelegateToAgentTool using a Zod discriminated union. This improves type safety and makes the agent delegation mechanism more scalable and maintainable. The changes are well-implemented across the codebase, including updates to configuration, tests, and prompts.

I've found one high-severity issue related to a missing validation check that could cause the application to crash at startup if a sub-agent is defined with a reserved parameter name. I've included a specific comment with a suggested fix for this.

@github-actions
Copy link

github-actions bot commented Dec 9, 2025

Size Change: +2.82 kB (+0.01%)

Total Size: 21.6 MB

Filename Size Change
./bundle/gemini.js 21.6 MB +2.82 kB (+0.01%)
ℹ️ View Unchanged
Filename Size
./bundle/sandbox-macos-permissive-closed.sb 1.03 kB
./bundle/sandbox-macos-permissive-open.sb 890 B
./bundle/sandbox-macos-permissive-proxied.sb 1.31 kB
./bundle/sandbox-macos-restrictive-closed.sb 3.29 kB
./bundle/sandbox-macos-restrictive-open.sb 3.36 kB
./bundle/sandbox-macos-restrictive-proxied.sb 3.56 kB

compressed-size-action

@abhipatel12
Copy link
Collaborator Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request is a great refactoring of the agent delegation mechanism. Using a Zod discriminated union to dynamically generate the delegate_to_agent tool's schema is a clever and robust approach that improves type safety and provides better guidance to the model. The simplification of the AgentRegistry and the dynamic tool description are also excellent improvements.

I have one suggestion to further improve the robustness of the new DelegateToAgentTool by ensuring the input type mapping is exhaustive, which will help prevent potential bugs in the future.

@abhipatel12
Copy link
Collaborator Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a significant and well-executed refactoring of the agent delegation mechanism. By replacing individual agent tool wrappers with a single DelegateToAgentTool, and leveraging Zod's discriminated unions to dynamically generate a strongly-typed input schema, the changes greatly improve type safety, maintainability, and the model's ability to correctly invoke sub-agents. The simplification of the AgentRegistry and the dynamic updates to the tool's description and system prompt are also excellent improvements. The new tests are comprehensive and cover the new functionality well. Overall, this is a high-quality contribution that enhances the robustness and scalability of the agent framework. I found no issues of high or critical severity.

@abhipatel12 abhipatel12 force-pushed the abhipatel12/agent-tool branch from 4cdf81e to 369f359 Compare December 9, 2025 16:16

// Instantiate the Subagent Loop
const subagentInvocation = new SubagentInvocation(
agentArgs as AgentInputs,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we do any sort of validation of the type instead of casting?

Is there any potential that we might get an unexpected type for agentArgs?

Alternatively, should SubagentInvocation and this.params be updated to use the same type?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So in this case, we technically don't need the cast at all since in both cases the type would be Record<string, unknown>. It was originally kept to act as documentation, but we can remove it if you think that's best?

And then for validation, the zod discriminated union should have already validated by the time the execute is called, so we should be in good shape for that as well.

WDYT?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial thought is that if it's not needed to compile we should omit it. It could turn a compile time issue into a failure at runtime if the code is changed in the future.

* Returns a list of all registered agent names.
*/
getAllAgentNames(): string[] {
return Array.from(this.agents.keys());
Copy link
Member

@gundermanc gundermanc Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that the codebase seems to have a lot of these sorts of getter methods implemented as actual methods instead of using TS's getter and setter constructs.

get allAgentNames(): string[] {
  return Array.from(this.agents.keys());
}

Is this an intentional team convention?

https://www.typescriptlang.org/docs/handbook/classes.html#accessors

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's a good question. I took a quick look and it does seem that a majority of places uses the getter methods. it seems to just be the repo practice but not sure if it was intentional. If there are benefits, maybe in a separate PR/epic we can consolidate this to the constructs you mentioned!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of us in the early days of the project were new to typescript and we relied heavily on the models we were using to build the product. So I would say these kinds of patterns are more organic from that process than intentional.

Copy link
Member

@gundermanc gundermanc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

super(
DELEGATE_TO_AGENT_TOOL_NAME,
'Delegate to Agent',
`Delegates to a specialized sub-agent (available: ${agentList}). Use for deep analysis tasks like bug investigation or refactoring scope.`,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine we'd want to expose the description of the agents in this description as well? Or nay?

Also what's the motivation for the "Use for deep analysis tasks like bug investigation or refactoring scope."? That seems like it may pigeon hole the delegation tech

Copy link
Member

@gundermanc gundermanc Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for description being important.

Also thinking...

  • Ideally that description should be agent-author provided and indicate what the agent is for.
  • Part of the tool description should indicate which scenarios it should be called in, and its input and output and behavior expectations (e.g.: how do you prevent the outer agent from just "asking" the delegate agent a question instead of asking it to do the actual work?). This could be part of the agent description, a separate schema item that gets folded into the tool description, or just some common string.
  • Finally, I wonder if it'd be easier for users to reason about if the behavior is instead to always delegate when an agent that purports to be relevant is present. i.e.: if I add a test debugging agent, I'm going to expect that it's always used to debug tests vs. leaving it up to the model's judgement of the complexity of the task.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point about the agent descriptions. I missed that and agree that we should have agent descriptions in the tools. Currently, we do have this directly in the system prompt where we use getDirectoryContext(). So we technically already have the descriptions of the subagents in the system prompt, but by adding them in the tool description we can have them in both places. Does that sound alright?

That seems like it may pigeon hole the delegation tech

That's a good point. I don't think we need that. i'll remove it. It's hyperspecific to codebase investigator

Ideally that description should be agent-author provided and indicate what the agent is for.

+1. The agent definition already has this description so we can just use that. We're already doing that in the sys prompt and i've added this to the tool description as well.

Part of the tool description should indicate which scenarios it should be called in, and its input and output and behavior expectations (e.g.: how do you prevent the outer agent from just "asking" the delegate agent a question instead of asking it to do the actual work?). This could be part of the agent description, a separate schema item that gets folded into the tool description, or just some common string.

So we're already using the description and then also have the actual input and output schema being provided to the tool descriptions. Do you think we need an additional field on the AgentDefinition for when to use the agent or can we expect that the description should handle that via natural language?

I wonder if it'd be easier for users to reason about if the behavior is instead to always delegate when an agent that purports to be relevant is present. i.e.: if I add a test debugging agent, I'm going to expect that it's always used to debug tests vs. leaving it up to the model's judgement of the complexity of the task.

Good question. Initially for this v1, i would think it may be best to leave this to the judgment of the model and then allow users to explicitly ask or use context files to push for further usage. And then in the future, we can tweak the system prompt and/or the tool description to make this more explicit. Wdyt?

@abhipatel12 abhipatel12 force-pushed the abhipatel12/agent-tool branch from 369f359 to e17dcc9 Compare December 9, 2025 20:04
Copy link
Collaborator Author

@abhipatel12 abhipatel12 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review!


// Instantiate the Subagent Loop
const subagentInvocation = new SubagentInvocation(
agentArgs as AgentInputs,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So in this case, we technically don't need the cast at all since in both cases the type would be Record<string, unknown>. It was originally kept to act as documentation, but we can remove it if you think that's best?

And then for validation, the zod discriminated union should have already validated by the time the execute is called, so we should be in good shape for that as well.

WDYT?

super(
DELEGATE_TO_AGENT_TOOL_NAME,
'Delegate to Agent',
`Delegates to a specialized sub-agent (available: ${agentList}). Use for deep analysis tasks like bug investigation or refactoring scope.`,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point about the agent descriptions. I missed that and agree that we should have agent descriptions in the tools. Currently, we do have this directly in the system prompt where we use getDirectoryContext(). So we technically already have the descriptions of the subagents in the system prompt, but by adding them in the tool description we can have them in both places. Does that sound alright?

That seems like it may pigeon hole the delegation tech

That's a good point. I don't think we need that. i'll remove it. It's hyperspecific to codebase investigator

Ideally that description should be agent-author provided and indicate what the agent is for.

+1. The agent definition already has this description so we can just use that. We're already doing that in the sys prompt and i've added this to the tool description as well.

Part of the tool description should indicate which scenarios it should be called in, and its input and output and behavior expectations (e.g.: how do you prevent the outer agent from just "asking" the delegate agent a question instead of asking it to do the actual work?). This could be part of the agent description, a separate schema item that gets folded into the tool description, or just some common string.

So we're already using the description and then also have the actual input and output schema being provided to the tool descriptions. Do you think we need an additional field on the AgentDefinition for when to use the agent or can we expect that the description should handle that via natural language?

I wonder if it'd be easier for users to reason about if the behavior is instead to always delegate when an agent that purports to be relevant is present. i.e.: if I add a test debugging agent, I'm going to expect that it's always used to debug tests vs. leaving it up to the model's judgement of the complexity of the task.

Good question. Initially for this v1, i would think it may be best to leave this to the judgment of the model and then allow users to explicitly ask or use context files to push for further usage. And then in the future, we can tweak the system prompt and/or the tool description to make this more explicit. Wdyt?

* Returns a list of all registered agent names.
*/
getAllAgentNames(): string[] {
return Array.from(this.agents.keys());
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's a good question. I took a quick look and it does seem that a majority of places uses the getter methods. it seems to just be the repo practice but not sure if it was intentional. If there are benefits, maybe in a separate PR/epic we can consolidate this to the constructs you mentioned!

@gemini-cli gemini-cli bot added size/l A large sized PR review/involved PRs that may take a lot of work to review labels Dec 9, 2025
// Fallback if no agents are registered (mostly for testing/safety)
schema = z.object({
agent_name: z.string().describe('No agents are currently available.'),
});
Copy link
Collaborator

@joshualitt joshualitt Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm okay with this approach, but I think all of the validation logic can be simplified using the ajv validator.

To do this, should be very straightforward. Essentially, we can add a validateSchema method to our existing schema validator here, which can just call the validateSchema method method in the AJV API. Then after validation we can just use the inputDef directly. I think there are 3 major benefits to doing this:

  1. This will ensure consistent reporting and semantics of validation for schemas between tools and agents.
  2. Lets us remove the custom validation logic.
  3. Gives us full JSON schema type semantics "for free."

However, we can always do this in a follow-up.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took a look and agreed! Since this will require some broader changes to get working with the AJV validation, i'll create an issue to separate out this task and keep this PR focused.

@abhipatel12 abhipatel12 force-pushed the abhipatel12/agent-tool branch from e17dcc9 to 182bdcf Compare December 10, 2025 02:14
Copy link
Collaborator

@allenhutchison allenhutchison left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, but you should update the default policy documents with delegate_to_agent and assign a default permission (likely ASK_USER). While this isn't necessary for the tool confirmation system, it's good practice to document our default policies.

…update tests

Refactors the delegation tool to use a Zod discriminated union for better type safety and model guidance. Updates AgentRegistry to provide simplified directory context. Updates Config and Prompts to support the new tool and ResourceRegistry. Fixes all related tests.
Adds validation to DelegateToAgentTool to throw an error if a sub-agent defines an input parameter named 'agentName', which would conflict with the discriminated union discriminator. Adds a regression test.
Replaces if/else chain with a switch statement and exhaustive check to ensure all input types are handled at compile time.
@abhipatel12 abhipatel12 force-pushed the abhipatel12/agent-tool branch from 182bdcf to 0460ff5 Compare December 10, 2025 20:57
@abhipatel12
Copy link
Collaborator Author

Looks good to me, but you should update the default policy documents with delegate_to_agent and assign a default permission (likely ASK_USER). While this isn't necessary for the tool confirmation system, it's good practice to document our default policies.

Yep 100%. Added this as allow since the subagent delegation doesn't need approval since the actual actions will require confirmation as needed.

@abhipatel12 abhipatel12 added this pull request to the merge queue Dec 10, 2025
Merged via the queue into main with commit 91b15fc Dec 10, 2025
20 checks passed
@abhipatel12 abhipatel12 deleted the abhipatel12/agent-tool branch December 10, 2025 21:28
thacio added a commit to thacio/auditaria that referenced this pull request Dec 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review/involved PRs that may take a lot of work to review size/l A large sized PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] Create a delegate to agent tool

6 participants