What happened?
When a parent agent delegates work to a sub-agent via the task tool, the onPreToolUse session hook only fires for the parent's own tool calls — not for any tools the sub-agent invokes.
This makes it impossible to intercept, audit, or deny tool calls made by sub-agents.
JUnit 5 test that should succeed
@Test
void onPreToolUse_should_fire_for_subagent_tool_calls() throws Exception {
List<String> seenTools = new CopyOnWriteArrayList<>();
SessionHooks hooks = new SessionHooks().setOnPreToolUse((input, invocation) -> {
seenTools.add(input.getToolName());
System.out.println("onPreToolUse: " + input.getToolName());
return CompletableFuture.completedFuture(PreToolUseHookOutput.allow());
});
CustomAgentConfig parent = new CustomAgentConfig()
.setName("parent")
.setTools(List.of("task"))
.setPrompt("Delegate all work to the sub-agent.");
CustomAgentConfig child = new CustomAgentConfig()
.setName("child")
.setTools(List.of("glob"))
.setPrompt("Use glob to list files, then respond.");
SessionConfig config = new SessionConfig()
.setModel("gpt-4.1")
.setHooks(hooks)
.setCustomAgents(List.of(parent, child))
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL);
try (CopilotClient client = new CopilotClient()) {
client.createSession(config)
.get()
.sendAndWait(new MessageOptions()
.setPrompt("Use the sub-agent `child` to list files in the current directory."))
.get(60, TimeUnit.SECONDS);
}
System.out.println("Seen tools: " + seenTools);
// Observed: seenTools typically contains only ["task"].
// Expected: it should also contain "glob".
assertTrue(
seenTools.contains("glob"),
"Expected onPreToolUse to fire for sub-agent tool calls as well"
);
}
Expected
onPreToolUse fires for all tool calls: the parent's task call and the sub-agent's glob call.
Actual
onPreToolUse only fires for task. The sub-agent's glob call is invisible to the hook.
Impact
- Security: SDK users cannot enforce tool restrictions on sub-agents.
- Observability: No way to log or audit what sub-agents actually do.
PermissionHandler has the same gap — it fires for sub-agent MCP tools but with null tool identity (extensionData is empty), making per-tool decisions impossible.
Versions
copilot-sdk-java: 0.2.2-java.1
maven: 3.9.12
copilot-cli: 1.0.22
Relevant log output
Code of Conduct
What happened?
When a parent agent delegates work to a sub-agent via the
tasktool, theonPreToolUsesession hook only fires for the parent's own tool calls — not for any tools the sub-agent invokes.This makes it impossible to intercept, audit, or deny tool calls made by sub-agents.
JUnit 5 test that should succeed
Expected
onPreToolUsefires for all tool calls: the parent'staskcall and the sub-agent'sglobcall.Actual
onPreToolUseonly fires fortask. The sub-agent'sglobcall is invisible to the hook.Impact
PermissionHandlerhas the same gap — it fires for sub-agent MCP tools but withnulltool identity (extensionDatais empty), making per-tool decisions impossible.Versions
copilot-sdk-java: 0.2.2-java.1
maven: 3.9.12
copilot-cli: 1.0.22
Relevant log output
Code of Conduct