Skip to content

feat: add Parallel Emission opt-in across protocol surfaces - #147

Open
spacexun2 wants to merge 5 commits into
NanmiCoder:mainfrom
spacexun2:feat/parallel-emission
Open

feat: add Parallel Emission opt-in across protocol surfaces#147
spacexun2 wants to merge 5 commits into
NanmiCoder:mainfrom
spacexun2:feat/parallel-emission

Conversation

@spacexun2

@spacexun2 spacexun2 commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Summary

This implements Slice 1 — Parallel Emission of the split described in #62 (refs #62). Slice 2 (per-task probes, Next Probe At, Silent Kick / Captain Wake / Mailbox Wake) follows separately; nothing in that slice is touched here.

Parallel Emission is the opt-in ability for models that can emit several agent_teams_* tool calls in one assistant message. It is a single boolean in the new agent-teams settings namespace, parallelToolCalls, default off, surfaced as a 支持工具并行 checkbox on the plugin's Plugins-configuration card:

  • Host: the plugin registers the agent-teams namespace with exactly one field (schema default false) synchronously when the settings service is already mounted at plugin activation (the standard web profile mounts settings in its base composition, so the saved value is visible to the mount-time usage snapshot), and lazily via ctx.inject(['settings'], …) otherwise. Without the service (headless profiles, older hosts) the registration never happens, the switch reads false, and everything else is unaffected.
  • Protocol surfaces: the captain clause takes effect via the mount snapshot introduced by upstream capabilities (restart/remount applies the saved value); the member persona freezes the switch at spawn (already-spawned members are never rewritten); and the assignment prompt reads it live at dispatch. When on, the surfaces allow claim + in_progress, completed + report, and several create_task calls in one response; when off, the surfaces keep the serial protocol — member personas and assignment prompts are byte-identical to the previous text, and the usage section adds one explicit serial sentence ("Issue one agent_teams_* tool call per response ..."). Same-response calls still execute in order, so later creates can reference earlier ids from the same response — and dependency ids must still exist: create_task rejects unknown dependencies exactly as before (pinned by a new lifecycle check; PR 通过消除 status 轮询和启用并行工具调用减少 token 浪费 #48's empty-dependency branch stays rejected).
  • Web client: a Plugins-tab card keyed by the agent-teams namespace under the settings.plugin.item type-only slot contract. Both client imports are type-only and all writes go through the cordis settingsScope service, so the bundle purity gate mechanically guarantees no cross-plugin value import. The checkbox is disabled when the namespace is not served or the settings document is read-only (memory mode). It never writes maxParallelToolCalls — the Agent Loop execution pool stays on the Agent Loop card (negative source pins enforce this).

Docs: one sentence in each README's Configuration section and a short section in docs/usage.md.

Validation

  • tsc -p tsconfig.json --noEmit, tsc -p tsconfig.client.json --noEmit, and the full build (clean-build + both tsc passes + tsdown, including the client bundle purity gate) pass.
  • node scripts/verify.mjs: all 191 checks pass, including new pins for the settings schema default ({} resolves parallelToolCalls: false), persona / assignment / usage on-vs-off branches, the host-side settings registration (synchronous when the service is already mounted, threaded through to the usage snapshot), the type-only Plugins-tab registration keyed by the namespace, and negative guards keeping maxParallelToolCalls out of this plugin's sources.
  • node scripts/lifecycle-verify.mjs drives the real compiled create_task with a never-created dependency id and asserts it fails loud (no forward references).
  • fallback-tdd, member-failure-tdd (both harness modes), quality-gates-tdd, harness-compat-tdd, web-routes-verify, release-metadata, http-body, compatibility, doctor, and stress-verify all pass; node --test scripts/compatibility.test.mjs additionally skips its doctor-bin-symlink case on this machine (EPERM: operation not permitted, symlink — Windows without symlink privilege), reproduced identically on clean main.
  • Known-local flake note: two lifecycle-verify checks (unfinished captain takeover returns to a member when the captain becomes idle, activity refines residency through the live Agent registry) fail intermittently on this machine on clean main as well (reproduced in a pristine worktree, plain and --modern-harness variants) — pre-existing timing flakiness, unrelated to this branch.

Slice 2 follow-up will cover the per-task probe clock and the protocol rewrites around polling, wake, and end-of-turn.

@spacexun2
spacexun2 force-pushed the feat/parallel-emission branch from 543e7ad to 27d7dff Compare September 10, 2026 03:26
Register the agent-teams settings namespace (parallelToolCalls, default
false) where the host provides the settings service, and branch the three
protocol surfaces on the live value: the captain usage section reads it at
assemble time, member personas freeze it at spawn, and assignment prompts
read it at dispatch. The web client contributes a Plugins-tab checkbox
card keyed by the namespace through type-only slot contracts, writing only
parallelToolCalls and never the Agent Loop maxParallelToolCalls knob.
Hosts without the settings service keep the serial protocol unchanged.
Pin the settings schema default, the persona/assignment/usage on and off
branches, the type-only plugins-tab registration, and negative guards
keeping maxParallelToolCalls out of this plugin. Drive a real create_task
through the lifecycle harness to prove unknown dependency ids still fail
loud, so same-response emission cannot smuggle forward references. The
usage-snapshot pin follows the capabilities host: the settings scope
registers synchronously when the service is mounted, and the captain
clause rides the mount-time usage snapshot.
@spacexun2

Copy link
Copy Markdown
Contributor Author

Heads-up on the two red checks on this head: "Real Harness (0.1.2-alpha.5)" and the compatibility gate failed in the captain-idle-wakeup scenario (run 34555573487). The behavioral assertions all passed — member executed, task terminal, captain yielded, notified after idle — and the process exited 1 afterwards with a single stderr line: Error: session "…" is not live in this store.

The scenario driver and fixtures are byte-identical between this branch and 426024f, and the failure point is the fixture teardown flush loop, not anything this PR touches. I could not reproduce it locally: the documented alpha.5 flow passes all 7 scenarios on this branch's candidate and on a plain 426024f candidate alike, with the same request counts as the CI failure run. Details and the mechanism are in #154 — reading it as the pre-existing teardown race rather than something introduced here.

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