Skip to content

[BUG] Inferred sub-agent recursively calls task() to spawn itself - CustomAgentConfig.tools not enforced #864

@brolnickij

Description

@brolnickij

Summary

A custom agent spawned as a sub-agent via task() sees task in its tool list, recognizes its own description among available agents, and recursively delegates to itself instead of using its tools directly.

CustomAgentConfig.tools does not prevent this — even an explicit allowlist without task is ignored at runtime.

Environment

  • @github/copilot-sdk 0.1.33-preview.0
  • Copilot CLI 1.0.5
  • Node.js / TypeScript, macOS

Repro

const research: CustomAgentConfig = {
  name: 'research',
  description: 'Searches repos via Sourcebot MCP',
  prompt: 'You ARE the research agent. Use your tools directly. Do NOT call task.',
  tools: ['sourcebot-*', 'context7-*', 'web_search', 'web_fetch', 'report_intent'], // no "task"
  infer: true,
}

const session = await client.createSession({
  model: 'claude-sonnet-4.6',
  mcpServers: {
    sourcebot: { type: 'http', url: '...', tools: ['*'] },
    context7: { type: 'local', command: 'npx', args: ['...'], tools: ['*'] },
  },
  customAgents: [research],
  onPermissionRequest: approveAll,
})

MCP servers are at session level because CustomAgentConfig.mcpServers was not functional in earlier versions (#553, since closed for .NET SDK — untested on Node.js).

What happens

Parent agent calls task(research) → spawned sub-agent calls task(research) → repeat.

Sub-agent reasoning from traces:

"Let me use the research agent which has access to Sourcebot tools."

It doesn't realize it is the research agent.

Measured impact (two live sessions)

Session task recursions MCP tool calls Cost Duration
AIT-46 (tools: null) 3 3 $0.44 82s
AIT-47 (tools: [explicit list without task]) 13 0 $0.56 102s

Setting tools made it worse — more recursions, zero actual work.

Key finding

CustomAgentConfig.tools is not enforced for sub-agents spawned via the task() inference path. This is similar to #859 (not enforced via SessionConfig.Agent) but affects a different code path — runtime-inferred sub-agent selection.

Additional finding: hooks break sub-agents

When SessionConfig.hooks.onPreToolUse is set (even returning undefined), all sub-agents become non-functional — spawned but make zero LLM calls. Removing hooks restores sub-agent functionality. This may warrant a separate issue.

Related issues

Request

  1. Enforce CustomAgentConfig.tools for sub-agents spawned via task()
  2. Prevent sub-agents from recursively spawning themselves via task()
  3. Or provide a way to exclude task from a sub-agent's tool universe

Metadata

Metadata

Assignees

No one assigned

    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