Skip to content

[BUG]: Sub-agent tool calls bypass SDK session hooks and permission handlers (was: onPreToolUse hook does not fire for sub-agent tool calls) #64

Description

@bytehaufen

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

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions