Skip to content

Comments

feat: Support overriding built-in tools#522

Open
patniko wants to merge 1 commit intomainfrom
support-tool-overrides
Open

feat: Support overriding built-in tools#522
patniko wants to merge 1 commit intomainfrom
support-tool-overrides

Conversation

@patniko
Copy link
Contributor

@patniko patniko commented Feb 20, 2026

Summary

Closes #411

When users register tools via SessionConfig.tools with names matching built-in CLI tools (e.g., edit_file, read_file), the CLI previously handled them itself instead of dispatching to the user's handler.

This PR makes user-registered tools automatically take precedence by adding their names to excludedTools in the RPC payload, so the CLI's built-in version is excluded and the SDK's local dispatch handles the call instead.

Changes

Implemented consistently across all 4 SDKs:

SDK Code Tests Docs
Node.js mergeExcludedTools() helper in client.ts 4 tests in client.test.ts README updated
Python Inline merge in client.py 4 tests in test_client.py README updated
Go mergeExcludedTools() helper in client.go 4 tests in client_test.go README updated
.NET MergeExcludedTools() helper in Client.cs 5 tests in MergeExcludedToolsTests.cs README updated

How it works

  1. Before sending session.create / session.resume RPC, collect tool names from user-registered tools
  2. Merge them into excludedTools (with deduplication)
  3. CLI receives the merged list and won't handle those tools itself
  4. SDK dispatches tool calls to the user's local handler

Backward compatibility

  • Fully backward-compatible: users who don't name tools after built-ins see no behavior change
  • If a user already explicitly lists a tool in excludedTools, deduplication avoids issues

When users register tools via SessionConfig with names matching built-in
CLI tools, automatically add those names to excludedTools in the RPC
payload so the SDK's local handler takes precedence.

Implemented consistently across all 4 SDKs (Node.js, Python, Go, .NET)
with unit tests and documentation updates.

Closes #411

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link

✅ Cross-SDK Consistency Review

Excellent work! This PR demonstrates exemplary cross-SDK consistency for implementing the tool override feature. All four SDK implementations (Node.js, Python, Go, and .NET) are well-aligned.

Summary of Changes

All SDKs now allow user-registered tools to automatically override built-in CLI tools by merging tool names into the excludedTools list sent to the CLI.

Consistency Analysis

✅ Implementation Approach

All four SDKs implement the same logic:

  • Node.js: mergeExcludedTools() helper function using Set for deduplication
  • Python: Inline merge using dict.fromkeys() for deduplication
  • Go: mergeExcludedTools() helper function using map-based deduplication
  • .NET: MergeExcludedTools() helper using LINQ Union() for deduplication

✅ API Consistency

The feature is applied consistently to both session operations:

  • createSession / create_session / CreateSession / CreateSessionAsync
  • resumeSession / resume_session / ResumeSession / ResumeSessionAsync

✅ Test Coverage

All SDKs have equivalent test scenarios:

  • Node.js: 4 test cases covering create/resume and merge/dedup scenarios
  • Python: 4 test cases covering create/resume and merge/dedup scenarios
  • Go: 4 test cases covering tool addition, deduplication, and edge cases
  • .NET: 5 test cases covering all scenarios plus edge case validation

✅ Documentation

All four README files include:

  • "Overriding Built-in Tools" section in the same location (after tool registration docs)
  • Consistent messaging about precedence and use cases
  • Language-idiomatic code examples

No Issues Found

This PR maintains excellent feature parity across all SDK implementations. No consistency issues detected.

Recommendation: ✅ Approve from a cross-SDK consistency perspective.

AI generated by SDK Consistency Review Agent

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements automatic tool overriding across all four SDKs (Node.js, Python, Go, .NET) to allow user-registered tools to take precedence over built-in CLI tools when they share the same name. The implementation adds tool names from SessionConfig.tools to the excludedTools list before sending RPC requests to the CLI, ensuring the CLI doesn't handle those tools and instead delegates to the SDK's local dispatcher.

Changes:

  • Implemented automatic tool name merging into excludedTools across all SDKs
  • Added comprehensive unit tests for the merge logic in all SDKs
  • Updated documentation in all four SDK READEs with examples of overriding built-in tools

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
nodejs/src/client.ts Added mergeExcludedTools helper and integrated it into session create/resume
nodejs/test/client.test.ts Added 4 unit tests covering tool override scenarios
nodejs/README.md Added documentation section explaining tool override feature
python/copilot/client.py Inline merge logic in both create_session and resume_session
python/test_client.py Added 4 unit tests for tool exclusion behavior
python/README.md Added documentation section with override example
go/client.go Added mergeExcludedTools helper used in CreateSession and ResumeSessionWithOptions
go/client_test.go Added 4 unit tests for the merge helper function
go/README.md Added documentation section explaining override capability
dotnet/src/Client.cs Added internal MergeExcludedTools helper called in both session methods
dotnet/src/GitHub.Copilot.SDK.csproj Added InternalsVisibleTo for test assembly access
dotnet/test/MergeExcludedToolsTests.cs New test file with 5 unit tests for the merge logic
dotnet/README.md Added documentation section with C# override example

Comment on lines 1354 to +1356
// buildUnsupportedToolResult creates a failure ToolResult for an unsupported tool.
// mergeExcludedTools returns a deduplicated list combining excludedTools with
// the names of any SDK-registered tools, so the CLI won't handle them.
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

The comment for mergeExcludedTools (lines 1355-1356) is positioned between the comment for buildUnsupportedToolResult (line 1354) and the function definition (line 1357). This creates confusion about which function the comment belongs to. Move the comment for mergeExcludedTools to immediately precede the function definition on line 1357.

Copilot uses AI. Check for mistakes.

@define_tool(name="edit_file", description="Custom file editor with project-specific validation")
async def edit_file(params: EditFileParams) -> str:
# your logic
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

The documentation example shows an incomplete function handler with only a comment placeholder. While concise, it would be more helpful to show a minimal but complete example that returns a value, such as return f"Edited {path}" to demonstrate the expected return type and give developers a working starting point.

Suggested change
# your logic
# Example: perform custom validation and editing logic here
return f"Edited {params.path}"

Copilot uses AI. Check for mistakes.
defineTool("edit_file", {
description: "Custom file editor with project-specific validation",
parameters: z.object({ path: z.string(), content: z.string() }),
handler: async ({ path, content }) => { /* your logic */ },
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

The documentation example shows an incomplete function handler with only a comment placeholder. While concise, it would be more helpful to show a minimal but complete example that returns a value, such as return "File edited successfully" to demonstrate the expected return type and give developers a working starting point.

Suggested change
handler: async ({ path, content }) => { /* your logic */ },
handler: async ({ path, content }) => {
// your logic here, e.g. validate and write file contents
return "File edited successfully";
},

Copilot uses AI. Check for mistakes.
Comment on lines +275 to +276
func(params EditFileParams, inv copilot.ToolInvocation) (any, error) {
// your logic
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

The documentation example references EditFileParams which is not defined anywhere in the example. Either define this type in the example or use a simpler inline parameter list. For example: func(path string, content string, inv copilot.ToolInvocation) (any, error) { return "File edited", nil }

Suggested change
func(params EditFileParams, inv copilot.ToolInvocation) (any, error) {
// your logic
func(path string, content string, inv copilot.ToolInvocation) (any, error) {
// your logic
return "File edited", nil

Copilot uses AI. Check for mistakes.
Comment on lines +423 to +429
AIFunctionFactory.Create(
async ([Description("File path")] string path, [Description("New content")] string content) => {
// your logic
},
"edit_file",
"Custom file editor with project-specific validation")
```
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

The documentation example shows an incomplete function handler with only a comment placeholder. While concise, it would be more helpful to show a minimal but complete example that returns a value, such as return "File edited successfully"; to demonstrate the expected return type and give developers a working starting point.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support overriding built-in tools

1 participant