SIGN IN SIGN UP

feat(subagent): opt-in recursion via experimental.subagent_recursion (#65)

* feat(subagent): opt-in recursion via experimental.subagent_recursion

Adds a configuration flag that lets research subagents (explore,
librarian) spawn further subagents via call_omo_agent. Default OFF -
when absent or set to { enabled: false }, behavior is identical to
before. Existing background_task.maxDepth (default 3) and
maxDescendants (default 50) guardrails stay active.

Config shape:
  experimental.subagent_recursion = {
    enabled?: boolean,
    allowed_agents?: string[],  // defaults to ['explore', 'librarian']
  }

Design choices:
- Only call_omo_agent is ungated. The core OpenCode 'task' tool stays
  blocked for subagents even when the flag is on, because 'task'
  bypasses the OmO BackgroundManager.assertCanSpawn budget system.
  call_omo_agent goes through the budget, so depth and descendant
  limits are enforced exactly as they already are for orchestrator
  spawns.
- Oracle is NOT in the default allowed_agents list. Oracle is a leaf
  consultant by design; enabling recursion for it would invite
  runaway consultation chains. Users who want to opt Oracle in can
  still do so explicitly via allowed_agents.
- Implementation leaves the existing getAgentToolRestrictions signature
  unchanged (15 call sites). A new getAgentToolRestrictionsForSpawn
  wraps it with the flag-aware strip. Only the 2 manager.ts spawn
  sites migrate to the new function.

Files changed:
- src/config/schema/experimental.ts: adds SubagentRecursionConfigSchema
  and experimental.subagent_recursion field.
- src/shared/agent-tool-restrictions.ts: adds isSubagentRecursionAllowed
  and getAgentToolRestrictionsForSpawn. Exports automatically via the
  shared barrel.
- src/features/background-agent/manager.ts: new subagentRecursionConfig
  constructor option; both spawn sites (initial prompt line 585, resume
  prompt line 894) call getAgentToolRestrictionsForSpawn instead of
  getAgentToolRestrictions.
- src/create-managers.ts: threads pluginConfig.experimental?.subagent_recursion
  into the BackgroundManager constructor.

Tests added: src/shared/agent-tool-restrictions.test.ts (23 cases
covering baseline, flag-off, flag-on defaults, case-insensitivity,
invisible-char stripping, explicit allowed_agents override, oracle
leaf-by-default, empty allowed_agents, custom agents).

Verification:
- bun run typecheck: clean
- bun test: 5655 pass, 0 fail (5640 -> 5655)
- lsp_diagnostics on src/: no new errors

Resolves the 6-item plan item 5 (OmO depth-2 opt-in config).

* fix(subagent-recursion): wire config through sync paths + normalize allowed_agents

Addresses reviewer feedback on PR #65:

1. Sync paths now honor the recursion flag (Copilot, codex, cubic)
   Before: getAgentToolRestrictionsForSpawn was only called in the
   BackgroundManager async/resume paths. Sync spawn (call_omo_agent
   synchronous) and sync delegate-task (task run_in_background=false)
   still used plain getAgentToolRestrictions, which means the flag
   was a no-op for every synchronous subagent invocation. That's the
   majority path for research tasks (explore/librarian orchestrated
   synchronously).

   After: thread SubagentRecursionConfig through:
   - createCallOmoAgent -> executeSync -> tools spread
   - createDelegateTask options -> ExecutorContext -> sendSyncPrompt
     and executeSyncContinuation -> tools spread
   All three spawn sites (manager launch, manager resume, call_omo_agent
   sync, delegate-task sync, delegate-task resume) now consult the
   flag.

2. Normalize allowed_agents entries (Copilot)
   New normalizeAgentName() strips invisibles, trims whitespace, and
   lowercases - applied to BOTH the incoming agentName AND each entry
   in allowed_agents. Config entries like '\u200BExplore ' now match
   the runtime 'explore' agent name correctly.

3. Remove hardcoded line number references from comment (Copilot)
   The comment previously named manager.ts lines 578 and 887, which
   would drift on future edits. Rewritten to describe the spread-order
   invariant generically.

Test coverage added:
- Regression test for invisible/whitespace normalization in
  allowed_agents entries.

Verification:
- bun run typecheck: clean
- bun test: 5656 pass, 0 fail (5655 -> 5656, +1 test)
- lsp_diagnostics on src/: no new errors
V
Vacbo committed
d276ccc90265c1c232f8fa5930d18a1c89240b99
Parent: 4f80aa7
Committed by GitHub <noreply@github.com> on 4/22/2026, 2:50:23 AM