Skip to content

feat(subagents): programmatic dispatch API via a unified resolution pipeline - #832

Open
northwang-lucky wants to merge 7 commits into
agegr:mainfrom
northwang-lucky:feat/subagent-dispatch-api-pipeline
Open

northwang-lucky wants to merge 7 commits into
agegr:mainfrom
northwang-lucky:feat/subagent-dispatch-api-pipeline

Conversation

@northwang-lucky

Copy link
Copy Markdown
Contributor

Part of the discussion in #829 — this is the unified resolution pipeline of the two reference implementations (the incremental variant is #831). Same behavior contract (the dispatch contract suite is byte-identical between the two branches), different internal structure: one resolveSubagentResources() pipeline produces a typed resolution plan consumed once by the runtime, instead of per-control inline logic. Either one is ready to walk forward; whichever the maintainer prefers, we'll rework against your review (or close both without hard feelings).

What it adds (5 commits, branched from main @ 8366762):

  • lib/subagent-dispatch.ts — programmatic dispatch API (registerDispatchRuntime() -> globalThis.__piSubagentDispatch: startSubagentDispatch(parentSessionId, params), per-dispatch tools / disallowedTools / extensions / denyExtensions / excludeTools, signal / onUpdate, lifecycle events carrying runtime-resolved effective model/thinking/activeTools — not request echoes) plus the unified resolveSubagentResources() plan
  • lib/subagent-state.ts — one typed globalThis registry replacing scattered lazy-global writes, hot-reload safe
  • per-dispatch persistSession: false — in-memory child session (nothing hits disk) with audit metadata redirected to the parent; profile-level fallback additionally pinned by a driven behavioral test
  • no concurrency policy: queueing and per-parent limits stay with the upstream SubagentQueue (b77a25f)

Tests: 1065 passing (upstream 1020 + 45), tsc / eslint clean; same live validation as #831 (dispatch round-trip, non-echoed effective values, in-memory run leaves no .jsonl with audit on the parent).

…ture (G1)

Introduce the G1 programmatic subagent dispatch API on the upstream base,
using the pipeline architecture pattern from the old feat/subagent-pipeline
branch.  This is the first slice of the replat-pipeline branch — G1 only,
with G2/G3/C deferred to later slices.

New files:
- lib/subagent-dispatch.ts: createDispatchRuntime() factory,
  resolveSubagentResources() unified resolution pipeline (G1 shell),
  globalThis.__piSubagentDispatch registry, registerDispatchRuntime().
- lib/subagent-state.ts: centralized globalThis typed registry for
  active-dispatch tracking (getActiveDispatches()).
- lib/subagent-dispatch.test.mjs: S1 + S4 contract suite (15 tests).

Modified files:
- lib/subagents.ts: extend SubagentRunInfo with G4 fields (model,
  thinking, activeTools, tools) so the dispatch module can read
  authoritative effective values from the run.
- lib/rpc-manager.ts: import registerDispatchRuntime and wire the
  production binding after SUBAGENT_CONTROLLER creation.

Architecture decisions:
- Pipeline pattern: resolveSubagentResources() produces a typed
  ResolvedSubagentResources plan; dispatch reads effective values
  from SubagentRunInfo (run-anchored, not param-echoed).
- G5 concurrency gating deferred (upstream SubagentQueue handles it).
- AbortSignal listener detached on all terminal paths (no leaks).
- onUpdate callback exceptions never break dispatch (try/catch).
- No side-channel writes to production request objects; test fakes
  correlate via _runIds tracking and completion event childSessionId.
- _getParentState on the request is a frozen-test DI seam (P5 ledger:
  adjudication-p5-audit-findings §2); only as unknown as in the module.

Three gates:
- tsc --noEmit: clean (0 errors)
- npm run lint: clean (0 errors)
- npm test: 1035 pass / 0 fail (upstream baseline 1020 + 15 new)
… + G4 model/thinking (R2b)

- Add extensionFilterKey + filterExtensionsBySource to subagent-runtime.ts
  (C fix: stable key derivation from npm/file-path extension sources,
  real-shape guardrail for sourceInfo.path)
- Wire G3 extension filtering (extensions/denyExtensions) into start()
  using filterExtensionsBySource with allow/deny sets
- Wire G2 tool resolution (tools/disallowedTools) into start():
  request.tools ?? profile.tools as base, disallowedTools subtract after merge
- Replace ephemeral with persistSession (three-level fallback:
  request → profile → true) and add auditSessionManager for in-memory sessions
- Add model/thinking/activeTools to resourceSnapshot and initialRun
  (G4: authoritative effective values from three-level fallback)
- Update SubagentResourceSnapshot interface with model/thinking fields
- Update StartSubagentRequest with G2/G3/G6 fields (tools, disallowedTools,
  extensions, denyExtensions, excludeTools, persistSession)
- Update dispatch: persistSession forwarding + sessionId on request
- All shared test suites byte-identical to replat-api branch
- 1064 tests pass, tsc clean, lint clean
…dd behavioral test

- Add profilePersistSession param to resolveSubagentResources so the
  three-level fallback (dispatch → profile → true) is preserved in the
  unified pipeline, not lost during the R2b-to-R2c refactoring.
- Restore G6 source assertion to read from dispatch.ts with the original
  three-level regex (strength recovered).
- Add behavioral test proving profile.persistSession=false propagates
  through the resolver when the request omits persistSession.
The ported feature branches had dropped the AGENTS.md coverage their
predecessor carried: add the file-map rows for lib/subagent-dispatch.ts
and lib/subagent-state.ts plus a short section describing the
programmatic dispatch entry point, the per-dispatch parameter overrides,
and the centralized resolveSubagentResources() pipeline.
  - The dispatch runtime never reads settings; concurrency policy belongs
    to the upstream SubagentQueue. Remove the interface member, the
    production binding, and the fake key (kept byte-identical with the
    incremental branch's contract suite).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant