feat(go): support custom tools in subagents#962
Open
ductrung-nguyen wants to merge 1 commit intogithub:mainfrom
Open
feat(go): support custom tools in subagents#962ductrung-nguyen wants to merge 1 commit intogithub:mainfrom
ductrung-nguyen wants to merge 1 commit intogithub:mainfrom
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR enables Go SDK sessions to handle custom tool calls originating from CLI-created subagent (child) sessions by resolving child session IDs back to the parent session and enforcing per-agent tool allowlists.
Changes:
- Track child→parent (and child→agent) session lineage from
subagent.*lifecycle events and resolve incoming RPC requests against the parent session. - Enforce
CustomAgentConfig.Toolsallowlists for tool calls coming from child sessions. - Add Go docs plus unit/integration tests and placeholder replay snapshots for future E2E capture.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
go/client.go |
Adds child-session lineage tracking, resolveSession, and allowlist enforcement for child-originated tool calls; updates request handlers to resolve via parent. |
go/session.go |
Stores custom agent configs on the session and adds an onDestroy callback for client-side cleanup. |
go/client_subagent_test.go |
Adds unit tests covering session resolution, allowlists, subagent tracking, cleanup, and concurrency safety. |
go/internal/e2e/subagent_tool_test.go |
Adds integration-tagged tests exercising real CLI subagent tool invocation and deny behavior. |
go/README.md |
Documents subagent custom tool routing and tool access control semantics. |
test/snapshots/subagent_tool/subagent_invokes_parent_custom_tool.yaml |
Placeholder snapshot intended to be captured from a real CLI session for subagent custom tool flow. |
test/snapshots/subagent_tool/subagent_denied_unlisted_tool_returns_unsupported.yaml |
Placeholder snapshot intended to be captured from a real CLI session for denied-tool flow. |
Comments suppressed due to low confidence (3)
go/client.go:1706
- Now that child session IDs are resolved to the parent session via
resolveSession, the user-input handler invoked viasession.handleUserInputRequest(...)will receiveUserInputInvocation.SessionID == parentSessionID(because the invocation is built insideSession). This loses the child session context for subagent-originated prompts. Consider plumbing the originalreq.SessionIDthrough so handlers can distinguish parent vs child/subagent requests.
session, _, err := c.resolveSession(req.SessionID)
if err != nil {
return nil, &jsonrpc2.Error{Code: -32602, Message: err.Error()}
}
response, err := session.handleUserInputRequest(UserInputRequest{
Question: req.Question,
Choices: req.Choices,
AllowFreeform: req.AllowFreeform,
})
go/client.go:1726
- Similar to user input: after resolving a child session to the parent,
session.handleHooksInvoke(...)will buildHookInvocation.SessionIDfrom the parent session ID. That makes hook handlers unable to attribute hook invocations to the originating child/subagent session. Consider passing the originalreq.SessionIDthrough (or extending the invocation type) so hook consumers can enforce policy per subagent session when needed.
session, _, err := c.resolveSession(req.SessionID)
if err != nil {
return nil, &jsonrpc2.Error{Code: -32602, Message: err.Error()}
}
output, err := session.handleHooksInvoke(req.Type, req.Input)
if err != nil {
go/client.go:1853
- After
resolveSessionenables permission requests from child sessions,PermissionInvocation.SessionIDis still populated from the resolved parent session (session.SessionID). That prevents permission handlers from knowing which child/subagent session requested the permission. Consider using the originalreq.SessionID(and/or addingParentSessionID) so permission handlers can implement subagent-specific policy.
session, _, err := c.resolveSession(req.SessionID)
if err != nil {
return nil, &jsonrpc2.Error{Code: -32602, Message: err.Error()}
}
handler := session.getPermissionHandler()
if handler == nil {
All three SDKs (Go, Python, Node) use per-session tool handler lookup keyed to the exact session ID. When the CLI creates child sessions for subagents, those child session IDs are never registered in the SDK's sessions map. Tool calls arriving with a child session ID fail with "unknown session". This PR adds the ability to call custom tools for sub-agents in Go, following the proposal in github#947
524cf68 to
0b6a41d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
All three SDKs (Go, Python, Node) use per-session tool handler lookup keyed to the exact session ID. When the CLI creates child sessions for subagents, those child session IDs are never registered in the SDK's
sessionsmap. Tool calls arriving with a child session ID fail with"unknown session <id>".This PR only brings the ability to call custom tools for sub-agent in Go, by following the proposal in #947