The short-circuit block in runTeam() called this.runAgent(), which emits
its own agent_start/agent_complete events and increments completedTaskCount.
The short-circuit block then emitted the same events again, and
buildTeamRunResult() incremented the count a second time.
Fix: call buildAgent() + agent.run() directly, bypassing runAgent().
Events and counting are handled once by the short-circuit block and
buildTeamRunResult() respectively.
Addresses all five review points from @JackChen-me on PR #70:
1. Extract shared keyword helpers into src/utils/keywords.ts so the
short-circuit selector and Scheduler.capability-match cannot drift.
Both orchestrator.ts and scheduler.ts now import the same module.
2. selectBestAgent now mirrors Scheduler.capability-match exactly,
including the asymmetric use of agent.model: agentKeywords includes
model, agentText does not. This restores parity with the documented
capability-match behaviour.
3. Remove isSimpleGoal and selectBestAgent from the public barrel
(src/index.ts). They remain exported from orchestrator.ts for unit
tests but are no longer part of the package API surface.
4. Forward the AbortSignal from runTeam(options) through the
short-circuit path. runAgent() now accepts an optional
{ abortSignal } argument; runTeam's short-circuit branch passes
the caller's signal so cancellation works for simple goals too.
5. Tighten the collaborate/coordinate complexity regexes so they only
fire on imperative directives ("collaborate with X", "coordinate
the team") and not on descriptive uses ("explain how pods
coordinate", "what is microservice collaboration").
Also fixes a pre-existing test failure in token-budget.test.ts:
"enforces orchestrator budget in runTeam" was using "Do work" as its
goal which now short-circuits, so the coordinator path the test was
exercising never ran. Switched to a multi-step goal.
Adds 60 new tests across short-circuit.test.ts and the new
keywords.test.ts covering all five fixes.
Co-Authored-By: Claude <noreply@anthropic.com>
When a goal is short (<200 chars) and contains no multi-step or
coordination signals, runTeam() now dispatches directly to the
best-matching agent — skipping the coordinator decomposition and
synthesis round-trips. This saves ~2 LLM calls worth of tokens
and latency for genuinely simple goals.
Complexity detection uses regex patterns for sequencing markers
(first...then, step N, numbered lists), coordination language
(collaborate, coordinate, work together), parallel execution
signals, and multi-deliverable patterns.
Agent selection reuses the same keyword-affinity scoring as the
capability-match scheduler strategy to pick the most relevant
agent from the team roster.
- Add isSimpleGoal() and selectBestAgent() (exported for testing)
- Add 35 unit tests covering heuristic edge cases and integration
- Update existing runTeam tests to use complex goals
Co-Authored-By: Claude <noreply@anthropic.com>