Skip to content

[A2c] Remove createDelegateTool in favor of the subagents option #239

Description

@LinuxDevil

Goal

createDelegateTool() wraps one child agent as a tool. The subagents option (one task tool, a catalog in the prompt, parallel tasks, background tasks, depth limits, approvals inside sub-agents) does the same job on the same delegation core and works on both createAgent() and AgentExecutor.execute(). The docs already say "Prefer subagents for new code". Removing the older API before 1.0 leaves one way to delegate. Audit evidence: .agent-loop/audit2/our-report.md section 5, row "Delegation" (409 lines, 5 exports, "superseded by subagents").

Current state

Verified on main at cc5ddb8:

  • src/execution/DelegationTool.ts exports DelegationDepthExceededError (:22, extends PropagatingToolError), DelegateAgentOptions (:58), DelegateAgentResult (:81), createDelegateTool() (:102). It keeps its own AsyncLocalStorage depth counter (:53). Re-exported by src/execution/index.ts:7 (export * from './DelegationTool'), so 4 names are in the root.
  • The shared core stays: src/execution/delegation.ts (runSubagent, SubagentSpec, SubagentRequest) is used by src/subagents/withSubagents.ts:16,217 and src/createAgent.ts:47. It is not exported from the root.
  • AgentExecutor.execute() accepts subagents and maxSubagentDepth (docs/sub-agents.md:45, src/subagents/withSubagents.ts:414), so executor users have a replacement.
  • Tests that import createDelegateTool: src/execution/DelegationTool.test.ts (whole file), src/execution/cancellation.test.ts:14,342-345, src/execution/subagentInheritance.test.ts:8,273-281,464-484, src/execution/usage.test.ts:5,128,161,361, src/tools/defineTool.test.ts:8,159, src/flows/FlowExecutor.test.ts:700-725 (uses a delegate tool only as "a tool"); src/tools/noAiToolImport.test.ts:21 lists execution/DelegationTool.ts.
  • Example: examples/ops-pipeline/fixer.ts:25-28,155-185 (createFixerDelegateTool() wraps createDelegateTool() and adds a patch field), used by examples/ops-pipeline/index.ts:34,115, examples/ops-pipeline/pipeline.eval.ts:35,51, examples/ops-pipeline/fixer.test.ts:2,82-105; examples/ops-pipeline/README.md:9 describes "the monitor's delegation to the fixer agent".
  • Comments that name createDelegateTool(): src/execution/agentEvents.ts:63, src/execution/AgentExecutor.ts:180, src/execution/hooks.ts:72, src/execution/subagentRuntime.ts:3, src/models/usage.ts:36, src/execution/propagatingToolError.ts:7-19,49, src/execution/resume.ts:607, src/execution/toolCallExecution.ts:432.
  • Docs: docs/sub-agents.md:461-502 (section "## createDelegateTool()", the last section of the page), :368, :434; docs/streaming.md:304; docs/api-overview.md:55 (table row), :205, and the "Delegation" box in the diagram at :25.
  • Agent Forge: no use (grep of apps/agent-forge/{src,server,shared}).

Scope

In:

  • Delete src/execution/DelegationTool.ts and src/execution/DelegationTool.test.ts; remove src/execution/index.ts:7.
  • Keep PropagatingToolError (public, src/execution/propagatingToolError.ts): it is the general "rethrow, do not feed back to the model" signal. Rewrite its comments so they no longer use DelegationDepthExceededError as the example.
  • Tests: in cancellation.test.ts, subagentInheritance.test.ts and usage.test.ts, port each createDelegateTool case to the task tool (subagents on AgentExecutor.execute()), unless a task case with the same assertion already exists in the same file or in src/subagents/*.test.ts; then delete it and name the existing test in the pull request. In defineTool.test.ts:159 and FlowExecutor.test.ts:700-725, replace the delegate tool with a defineTool() tool (they only need "a tool"). Remove the line from noAiToolImport.test.ts.
  • Example: replace createFixerDelegateTool(opts) in examples/ops-pipeline/fixer.ts with createFixerTool({ agent, provider }): a defineTool() tool with input { task: string } whose execute(args, context) runs the fixer agent with AgentExecutor.execute({ agent, input: args.task, provider, signal: context.signal }), extracts the diff with extractDiffBlock(), throws EmptyPatchError when it is empty, and returns { text, patch }. Update index.ts, pipeline.eval.ts, fixer.test.ts and README.md of the example to the new name; the example's tests must keep passing.
  • Update the comments listed above to name only the task tool.
  • Docs: delete the "## createDelegateTool()" section of docs/sub-agents.md (it is the last heading, so no other heading moves); fix :368, :434; docs/streaming.md:304; docs/api-overview.md:55 row and :205; replace "Delegation" in the diagram with "Sub-agents".
  • Add the 4 names to src/publicSurface.test.ts / .test-d.ts (created by A1) as absent from the root.
  • CHANGELOG ### Breaking entry with the migration note below.

Out:

  • runSubagent and the delegation core in src/execution/delegation.ts: unchanged.
  • Background sub-agents needing approval: M4.

Acceptance criteria

  • grep -rn "createDelegateTool\|DelegationDepthExceededError\|DelegateAgentOptions\|DelegationTool" src examples docs/*.md README.md apps/agent-forge --include=*.ts --include=*.md finds nothing (CHANGELOG excepted).
  • Root exports exactly 4 fewer names (both numbers in the pull request).
  • Every ported or deleted test is listed in the pull request with the task test that now covers it; the inheritance (hooks, usage roll-up), cancellation and approval-inside-child behaviors keep at least one test each through the task tool.
  • npx vitest run examples/ops-pipeline passes.
  • Full verification list in BRIEF-2.md passes, including the four Agent Forge checks.
  • Docs updated; npm run docs:llms re-run. The pull request notes for the docs site that sub-agents lost its last section (the Arabic page must drop it too).
  • CHANGELOG ### Breaking entry:

    Removed createDelegateTool(), DelegateAgentOptions, DelegateAgentResult and DelegationDepthExceededError. Use the subagents option instead, on createAgent() or AgentExecutor.execute(): create the child with createAgent({ provider, instructions, description }) and pass subagents: { billing }. The model gets one task tool for every sub-agent, with the same inheritance (hooks, permissions, abort, usage roll-up) and a depth limit (maxSubagentDepth, default 1). A run at the depth limit is not offered the task tool, so a delegation cycle can no longer start; DelegationDepthExceededError is gone. See docs/sub-agents.md.

Live test

None: this ticket spends nothing.

Dependencies

  • A1 and A2b must merge first (A2b ports the same three test files away from ExecutionEvent; doing A2c second avoids rewriting them twice).
  • Owner decision required before starting (see Notes).
  • Conflicts: M4 and M10b edit sub-agent code and docs/sub-agents.md; rebase if they merged.

Notes for the implementer

  • Owner question (record the answer in the issue before starting): "May A2c remove createDelegateTool() (documented as superseded by subagents) in the next alpha?"
  • subagents takes agents built with createAgent({ ..., description }) (see docs/sub-agents.md:17-43), not inline specs; maxSubagentDepth defaults to 1 (docs/sub-agents.md:338). The migration note uses that shape.
  • The delegate tool's depth guard (AsyncLocalStorage) disappears. The task tool's guard is maxSubagentDepth (src/subagents/withSubagents.ts:72-80,406-417); a test that relied on an A -> B -> A cycle throwing should become "the task tool is not offered past the depth limit".
  • subagentInheritance.test.ts runs both paths through the same core; most delegate-tool cases there duplicate a task case. Delete duplicates instead of porting them.

Round 2 ticket A2c. Before starting, read the agent brief (worktree rules, verification list, live-test budget) and the plan. One ticket is one pull request; put Closes #<this issue> in it.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    breakingBreaking change: CHANGELOG entry with migration notemodel:opusRun loop, security or API design; needs Opusowner-decisionNeeds the owner's answer before work startsround-2Round 2 plan ticketwave-4Round 2, wave 4

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions