feat(core): implement fork subagent for context sharing#2936
feat(core): implement fork subagent for context sharing#2936
Conversation
📋 Review SummaryThis PR implements the Fork Subagent (P0) feature along with a 🔍 General Feedback
🎯 Specific Feedback🔴 Critical
🟡 High
🟢 Medium
🔵 Low
✅ Highlights
|
Code Coverage Summary
CLI Package - Full Text ReportCore Package - Full Text ReportFor detailed HTML reports, please see the 'coverage-reports-22.x-ubuntu-latest' artifact from the main CI run. |
- Make subagent_type optional in AgentTool - Add forkSubagent.ts to build identical tool result prefixes - Run fork processes in the background to preserve UX
…ubagent_type - Skip pathReader and edit tool permission tests when running as root - Fix agent.test.ts to correctly mock execute call with extraHistory - Remove unused imports in forkSubagent.ts
51728dc to
db79f3b
Compare
Response to Review Feedback
🔴 Critical — Both Resolved1. Fork detection after FORK_AGENT assignment (agent.ts:520-530) 2. Background execution error boundary (agent.ts:588-600) 🟡 High — All Resolved3. "Your system prompt says 'default to forking.' IGNORE IT" (forkSubagent.ts:78-95) 4. Complex extraHistory branching (agent.ts:500-515) 5. prePlanMode tracking (config.ts:1662-1670) 🟢 Medium — Addressed or N/A6. Validation error messages (agent.ts:242-254) — The "Available subagents" message only shows when 7-8. savePlan / planCommand / exitPlanMode — No longer in this PR. 🔵 Low9. buildChildMessage template string — Kept as-is for readability. Extracting rules to a separate constant adds indirection without benefit for a single-use template. 10. Missing fork-specific tests — Acknowledged. The current tests cover the non-fork subagent path. Fork-specific tests (recursive detection, extraHistory construction, background execution) should be added in a follow-up. Additional Fixes Since ReviewBeyond the review feedback, the following bugs were found and fixed:
|
Bug fixes:
- Fix AgentParams.subagent_type type: string -> string? (match schema)
- Fix undefined agentType passed to hook system (fallback to subagentConfig.name)
- Fix hook continuation missing extraHistory parameter
- Fix functionResponse missing id field (match coreToolScheduler pattern)
- Fix consecutive user messages in Gemini API (ensure history ends with model)
- Fix duplicate task_prompt when directive already in extraHistory
- Fix FORK_AGENT.systemPrompt empty string causing createChat to throw
- Fix redundant dynamic import of forkSubagent.js (merge into single import)
- Fix non-fork agent returning empty string on execution failure
- Fix misleading fork child rule referencing non-existent system prompt config
- Fix functionResponse.response key from {result:} to {output:} for consistency
CacheSafeParams integration:
- Retrieve parent's generationConfig via getCacheSafeParams() for cache sharing
- Add generationConfigOverride to CreateChatOptions and AgentHeadless.execute()
- Add toolsOverride to AgentHeadless.execute() for parent tool declarations
- Fork API requests now share byte-identical prefix with parent (DashScope cache hits)
- Graceful degradation when CacheSafeParams unavailable (first turn)
Docs:
- Add Fork Subagent section to sub-agents.md user manual
- Add fork-subagent-design.md design document
db79f3b to
b6ba5d2
Compare
Update: PR Reworked (rebase + additional fixes)What changed since the last response1. Rebased onto
2. CacheSafeParams integration — The initial Gemini implementation was missing the core cache optimization from the improvement report. Added:
3. 12 bugs fixed total — See previous response for the full list. Key fixes:
4. Documentation added:
Comparison with Claude Code referencePR description now includes a detailed comparison table. Summary of completion:
The gaps are documented in PR description under "Known Gaps" and in user docs under "Current Limitations". Test results
|
Summary
Implement Fork Subagent (P0) — omitting
subagent_typein the Agent tool triggers an implicit fork that inherits the parent's full conversation context, runs in the background, and shares the parent's prompt cache viaCacheSafeParams.Reference: improvement report item-2
Before / After
subagent_typeextraHistorygenerationConfigviaCacheSafeParams<fork-boilerplate>tag; returns errorComparison with Claude Code
subagent_type+ feature gate (FORK_SUBAGENT)subagent_type(always enabled)buildForkedMessages()clones assistant msg + placeholdertool_resultfunctionResponsewithidmatching)CacheSafeParamsthreads parent's rendered system prompt bytesgetCacheSafeParams()threads parent'sgenerationConfig(systemInstruction + tools)cache_controlmarkers, ~90% discount on cached tokensX-DashScope-CacheControl: enable, server-side prefix cachingrunAsyncAgentLifecycle()with progress tracking, task notification, summarizationvoid executeSubagent()fire-and-forget, display-only progress<task-notification>injects fork results into parent conversationpermissionMode: 'bubble'surfaces prompts to parent terminalPermissionMode.DefaultisCoordinatorMode()buildWorktreeNotice()for git worktree forksKnown Gaps (deferred to follow-up PRs)
<task-notification>to notify the parent when forks complete. Current implementation only updates display state — the parent LLM cannot observe fork results.PermissionMode.Defaultinstead of bubbling to the parent terminal.Key Design Decisions
generationConfigviagetCacheSafeParams()and passes it asgenerationConfigOverride+toolsOverride. SkipsgetInitialChatHistory()to avoid duplicating env context. Gracefully degrades when CacheSafeParams unavailable.[model(calls), user(responses+directive), model(ack)]inextraHistory. When no function calls, history ends with model and directive goes viatask_prompt.functionResponse.idmatching: Each function response includes theidfrom the corresponding function call, consistent withcoreToolScheduler.ts.createChat()throws on falsysystemPrompt. Used as fallback when CacheSafeParams is unavailable; overridden by parent's config when available.Files Changed
packages/core/src/agents/runtime/forkSubagent.tsbuildForkedMessages(),isInForkChild(),buildChildMessage()packages/core/src/tools/agent.tssubagent_typeoptional, fork path withextraHistoryconstruction, CacheSafeParams retrieval, background execution, error handlingpackages/core/src/agents/runtime/agent-headless.tsexecute()acceptsgenerationConfigOverride+toolsOverrideoptionspackages/core/src/agents/runtime/agent-core.tsCreateChatOptions.generationConfigOverride, skip env history for forkdocs/users/features/sub-agents.mddocs/design/fork-subagent/fork-subagent-design.mdTest Plan
agent.test.ts— 39 tests passagent-headless.test.ts— 23 tests passedit.test.ts/pathReader.test.ts— root execution test fixes pass