feat: Auto-exclude built-in tools overridden by user-registered tools#523
feat: Auto-exclude built-in tools overridden by user-registered tools#523
Conversation
Auto-add user-registered tool names to excludedTools in session.create/resume RPC payloads so that SDK-registered tools override CLI built-in tools. - Node.js: mergeExcludedTools() helper + createSession/resumeSession updates - Python: inline merge logic in create_session/resume_session - Go: mergeExcludedTools() helper + CreateSession/ResumeSessionWithOptions updates - .NET: MergeExcludedTools() helper + CreateSessionAsync/ResumeSessionAsync updates - Tests added for all 4 SDKs - All 4 READMEs updated with "Overriding Built-in Tools" documentation Co-authored-by: patniko <26906478+patniko@users.noreply.github.com>
Resolve merge conflicts in 4 files: - dotnet/src/Client.cs: Keep MergeExcludedTools with main's non-nullable config access - go/client.go: Keep mergeExcludedTools with main's direct config access (no nil guard) - go/client_test.go: Keep both MergeExcludedTools tests and permission handler tests - python/test_client.py: Merge imports (both define_tool and PermissionHandler) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add E2E tests across all 4 SDKs verifying that registering a custom tool with the same name as a built-in tool (e.g., 'grep') causes the custom tool to be invoked instead of the built-in. This validates the mergeExcludedTools feature end-to-end. - Add 'overrides built-in tool with custom tool' test to Node, Python, Go, .NET - Add YAML snapshot for the replay proxy - Add test/scenarios/tools/tool-overrides/ with all 4 language implementations Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix Python tests: add missing required argument to create_session() calls - Fix Go: separate misplaced buildUnsupportedToolResult doc comment from mergeExcludedTools - Fix Go sample: whitespace alignment from merge Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
✅ Cross-SDK Consistency Review: PASSEDI've reviewed PR #523 for consistency across all four SDK implementations (Node.js/TypeScript, Python, Go, and .NET). This PR demonstrates exemplary cross-SDK consistency in implementing the feature to auto-exclude built-in tools overridden by user-registered tools. Feature Implementation ConsistencyAll four SDKs implement the same core functionality with appropriate language-specific idioms: 1️⃣ Helper Function Pattern
All implementations properly deduplicate and merge tool names with existing excludedTools. 2️⃣ Integration PointsAll SDKs apply the merge logic in both:
3️⃣ Unit Test CoverageEach SDK includes comprehensive unit tests covering:
Test locations:
4️⃣ E2E Test CoverageAll SDKs include E2E tests verifying the feature works end-to-end:
All E2E tests use the same approach: register a custom 5️⃣ Documentation ConsistencyAll four READMEs include an identical "Overriding Built-in Tools" subsection with:
6️⃣ Test Scenarios & SnapshotsThe PR includes cross-language example implementations in
Language-Specific Differences (All Appropriate)The only differences are idiomatic language conventions, which are correctly applied:
All approaches are idiomatic and achieve the same result. Conclusion🎉 This PR maintains perfect feature parity across all four SDK implementations. The feature is:
No cross-SDK consistency issues found. Excellent work! 👏
|
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
✅ Cross-SDK Consistency Review: PASSEDThis PR demonstrates excellent cross-language consistency in implementing the auto-exclude feature for user-registered tools that override built-ins. All four SDK implementations maintain feature parity with properly adapted API patterns. Summary of ChangesThe PR adds functionality across all SDKs to automatically merge user-registered tool names into Consistency Analysis✅ Core Implementation PatternAll SDKs implement the same logic with language-appropriate patterns:
✅ Integration PointsConsistently applied in both ✅ Test CoverageAll SDKs include comprehensive unit and E2E tests: Unit Tests (testing the merge logic):
E2E Tests (testing actual override behavior):
All E2E tests use the same pattern: register a custom ✅ DocumentationIdentical "Overriding Built-in Tools" subsections added to all four READMEs with language-appropriate code examples, consistent messaging, and proper placement in the "Custom Tools" section. ✅ Naming ConventionsProperly adapted to language idioms:
Edge Cases Handled ConsistentlyAll implementations correctly handle:
No Issues FoundThis PR maintains excellent cross-SDK consistency. The feature is implemented uniformly across all languages with appropriate adaptations for each ecosystem's conventions and idioms. Great work! 🎉
|
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
✅ Cross-SDK Consistency Review: PR #523I've completed a comprehensive review of this PR across all four SDK implementations (Node.js, Python, Go, .NET). Overall, this PR demonstrates excellent cross-SDK consistency with proper feature parity across all languages. 📊 Summary
✅ Consistent Implementation PatternsEach SDK correctly implements the auto-exclusion logic with language-appropriate idioms: Node.js (
|
| Concept | Node.js | Python | Go | .NET |
|---|---|---|---|---|
| Function | mergeExcludedTools |
(inlined) | mergeExcludedTools |
MergeExcludedTools |
| Config Key | excludedTools |
excluded_tools |
ExcludedTools |
ExcludedTools |
| Create | createSession |
create_session |
CreateSession |
CreateSessionAsync |
| Resume | resumeSession |
resume_session |
ResumeSessionWithOptions |
ResumeSessionAsync |
All naming follows the established language conventions (camelCase for JS/TS, snake_case for Python, PascalCase for Go/C# public APIs).
💡 Minor Enhancement Suggestion (Non-Blocking)
Python only: Consider extracting a _merge_excluded_tools() helper function to match the pattern used in the other three SDKs. Current inline approach works fine, but a dedicated function would:
- Improve testability (can unit test in isolation)
- Match the architectural pattern of Go/.NET/Node.js
- Make the code easier to maintain if logic needs to be enhanced
Example:
def _merge_excluded_tools(excluded_tools: list[str] | None, tool_names: list[str] | None) -> list[str] | None:
if not tool_names:
return excluded_tools
return list(dict.fromkeys((excluded_tools or []) + tool_names))🎉 Conclusion
This PR is an exemplary model of cross-SDK consistency. The feature:
- ✅ Has identical behavior across all 4 languages
- ✅ Uses language-appropriate idioms and conventions
- ✅ Includes comprehensive test coverage everywhere
- ✅ Has consistent documentation
- ✅ Handles edge cases uniformly (empty lists, null/undefined, deduplication)
No blocking consistency issues found. The minor Python suggestion above is purely optional for architectural alignment.
Great work maintaining feature parity! 🚀
AI generated by SDK Consistency Review Agent
|
Waiting on runtime change to land in separate PR. |
Summary
When users register tools whose names collide with CLI built-ins (e.g.
grep,edit,view), the CLI would intercept those calls instead of dispatching to the user's handler. The fix: automatically merge user-registered tool names intoexcludedToolsonsession.create/session.resume, so the CLI skips its built-in and the SDK dispatches locally.Closes #411
Important
Requires runtime change: This PR depends on
built-in-tool-overrideincopilot-agent-runtime, which exempts external (SDK-registered) tools fromexcludedToolsfiltering. Without the runtime fix, adding tool names toexcludedToolsalso hides the SDK's own external tool definitions from the model.How it works
grep(or any built-in name)"grep"to theexcludedToolsarray in thesession.create/session.resumeRPC payloadexcludedTools: ["grep"]+ external tool definition for"grep"isToolAvailable()disables the built-ingrepbut keeps the externalgrepvisible to the modelgrep→ runtime dispatches to the SDK → SDK runs the user's handlerChanges
SDK (all 4 languages)
mergeExcludedTools()helper inclient.ts; applied increateSession+resumeSessiondict.fromkeys()for dedup inclient.py; applied increate_session+resume_sessionmergeExcludedTools()helper with map-based dedup inclient.go; applied inCreateSession+ResumeSessionWithOptionsMergeExcludedTools()internal static helper usingUnion()inClient.cs; applied inCreateSessionAsync+ResumeSessionAsync; addedInternalsVisibleTofor test projectTests
greptool override dispatches to the user handler (via replay proxy)test/snapshots/tools/overrides_built_in_tool_with_custom_tool.yaml)Docs
Samples
test/scenarios/tools/tool-overrides/— sample implementations in TypeScript, Python, Go, C# with averify.shbuild + run scriptExample (Node.js)
Backward-compatible: users with no name collisions see no behavior change.