6.8 KiB
Execution routing
Execution Routing decides the execution topology for an automatic runTeam() call: use one Agent directly (single) or ask the Coordinator to build and execute a Team plan (team). It is orthogonal to Model Routing, which chooses the model for calls inside the selected topology.
Precedence
runTeam() resolves topology in this order:
- Explicit
mode: 'single' | 'team'. - Declared governance topology or
preferredUnderBudgetdegradation policy. - The per-run
executionRouter. - The orchestrator-level
executionRouter. - The built-in
DeterministicRouter.
Routers run only for automatic, non-planOnly topology selection. They never override an explicit mode, declared role topology, or governance budget policy. governanceIntent: 'none' retains automatic topology selection, while still counting as an explicit governance declaration for consequential-tool confirmation.
Contract
import type {
ExecutionRouter,
RoutingContext,
RoutingDecision,
} from '@open-multi-agent/core'
class ApplicationRouter implements ExecutionRouter {
readonly version = 'application-router-v1'
decide(context: RoutingContext): RoutingDecision {
const mode = context.goal.startsWith('[team]') ? 'team' : 'single'
return {
mode,
reasons: [`Application policy selected ${mode}.`],
routerVersion: this.version,
}
}
}
RoutingContext contains the goal, a structured roster summary, and optional remaining token/cost ceilings at the point routing begins. Roster entries contain name, effective model, and an optional directly declared tool count. Full systemPrompt values, credentials, API keys, tool implementations, and model output are never supplied to the router. The summary is intentionally small so a later structured capability model can extend it without exposing prompts.
Set a default on the orchestrator or override it for one call:
const orchestrator = new OpenMultiAgent({
executionRouter: new ApplicationRouter(),
})
const result = await orchestrator.runTeam(team, goal, {
executionRouter: requestScopedRouter,
})
The per-run router wins over the orchestrator router. A decision is valid only when mode is single or team, reasons is a string array, routerVersion matches the router's non-empty version, optional confidence is between 0 and 1, and single has at least one roster member.
Failure behavior
Routing is advisory infrastructure and must not turn into a run failure. If a custom router throws, rejects, or returns an invalid decision, OMA falls back to DeterministicRouter. The returned decision uses the built-in router version and appends a fallback reason to reasons.
result.routingDecision
// {
// mode: 'single',
// reasons: [
// 'The goal has one concise action and no multi-stage structure.',
// 'Execution router fallback: custom decision failed (Error).'
// ],
// routerVersion: 'deterministic-v1'
// }
Every runTeam() topology choice exposes TeamRunResult.routingDecision.
Its source distinguishes caller override, governance declared, framework
policy, and automatic router decisions; only router records carry the
actual routerVersion. See the
five routing trace source classifications,
including the compatibility-only legacy-deterministic label.
Built-in deterministic policy
DeterministicRouter wraps the single isSimpleGoal() heuristic; OMA does not maintain a second competing heuristic.
- An empty roster cannot select the Single path; otherwise the goal heuristic decides.
- English sequence, coordination, parallelism, and multi-deliverable signals remain supported.
- Chinese sequence markers (
先…然后,第一步/第二步), circled steps, action enumerations, semicolon-separated clauses, and connected action verbs are recognized. - Japanese (
まず…次に,第一に…第二に,ステップ1/手順1) and Korean (먼저…그다음,첫째…둘째,1단계/2단계) sequence markers are recognized, and dense、enumeration counts for kana- and Hangul-initial lists as well as Han. Each marker pair must appear, so a lone marker does not force Team. - Length uses a cheap script-aware information estimate. CJK characters — Han, Japanese kana, and Korean Hangul — count as 2.25 units; ordinary Latin word runs approximate token density; long unbroken runs keep their raw length.
Language coverage is tiered honestly rather than claimed uniform:
- Chinese, Japanese, and Korean are one tier: the structural markers above plus 2.25-unit length weighting.
- Latin-script languages share English's length treatment (word runs approximate token density). The structural word patterns are English-specific, so other Latin languages are routed by length and punctuation, not by their own sequence words.
- Other scripts fall back conservatively: each non-space character counts as one unit and no structural markers apply, so routing relies on the length threshold alone.
CJK verb-connective sequencing is a deliberate non-goal. Chinese keeps a verb-connective pattern because its verbs are invariant tokens, but Japanese and Korean verbs inflect (Japanese て-form, Korean agglutinative endings), so matching them would require morphological analysis this heuristic intentionally avoids; explicit markers and enumeration cover the structural signal instead.
This policy is intentionally honest, cheap, and language-neutral rather than semantically ambitious. Semantically equivalent English, Chinese, Japanese, and Korean goals should select the same execution mode. Applications that need domain-specific semantics should inject an ExecutionRouter or declare an explicit mode/governance topology.
Governance boundary
Execution Routing does not declare governance. The consequential-tool fallback still treats only governanceIntent === undefined as undeclared, regardless of which router selected Single or Team. Router decisions also cannot satisfy named-role or independent-review requirements; those facts continue to come from structured governance declarations and the executed topology.
Behavior change
The built-in automatic route recognizes short CJK (Chinese, Japanese, Korean) multi-stage goals and script-weighted length instead of relying on English-only word patterns plus raw character count. Equivalent goals translated between English, Chinese, Japanese, and Korean no longer change Single/Team topology in the routing stability gate. Existing English and Chinese outcomes, including structural-pattern regressions, retain their previous behavior. Script weighting intentionally changes a detailed, long English single-action goal from team to single when its estimated information length remains bounded; this case is locked by a regression test. Multilingual applications may also observe corrected automatic routes for CJK structured goals.