Skip to content

[BUG]: onPreToolUse hook does not fire for sub-agent tool calls #64

@bytehaufen

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

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions