Execution routing
July 26, 2026 · View on GitHub
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 or orchestrator-level custom
executionRouter. - The built-in
DeterministicRouter. - When
executionRouting.strategyishybridand the default/fallback deterministic result is Single, the semanticTaskProfilerand deterministic semantic policy.
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.
A valid custom Router decision is final and is never reinterpreted by the Profiler. If a custom Router fails and its deterministic fallback selects Single, Hybrid routing may profile that fallback candidate.
Hybrid semantic routing
Hybrid is opt-in. It preserves the cheap deterministic Team decision and adds at most one no-tool model call only when that router would otherwise choose Single:
const orchestrator = new OpenMultiAgent({
executionRouting: {
strategy: 'hybrid',
confidenceThreshold: 0.7,
failurePolicy: 'fallback',
},
})
LLMTaskProfiler produces a strict, provider-neutral TaskProfile containing
only inferred semantic signals: independent evidence sources, independent
review, conflicting objectives, side-effect intent, permission isolation,
decomposability, parallelism, complexity, confidence, and bounded reasons. The
goal is treated as untrusted data. The Profiler receives no Agent/Coordinator
system prompts, credentials, tool implementations, or complete permission
details and cannot call tools.
The model does not choose the topology. A deterministic policy consumes the profile together with framework-computed facts:
- high-confidence independent evidence, review, conflict, or genuinely parallel work may upgrade Single to Team;
- inferred side-effect/isolation needs that intersect with consequential
effective grants or multiple caller-declared
permissionBoundaryvalues produceROUTING_DECLARATION_REQUIRED; - low confidence or no material signal keeps Single;
- V1 never changes Team to Single.
ROUTING_DECLARATION_REQUIRED is raised before any Coordinator, worker, or
tool-capable Agent starts. A profile never creates requiredRoles, approves a
side effect, or proves that governance was satisfied.
The built-in Profiler resolves its adapter in this order:
- per-run
executionRouting.adapter; - orchestrator
executionRouting.adapter; - the effective Coordinator adapter;
- an adapter created from the orchestrator's default provider/model.
The selected adapter receives the goal text as untrusted user data. In
particular, step 4 can send the goal to defaultProvider even when every worker
uses its own adapter and the deterministic Single path previously needed no
default-provider call. Applications with data-residency or provider-boundary
requirements should configure executionRouting.adapter, provide a Coordinator
adapter, or select strategy: 'deterministic'.
executionRouting.model follows the same per-run-over-orchestrator precedence,
then the Coordinator model and default model. Profiler usage is charged to the
run token/cost budget and appears in routing tracing and
TeamRunResult.totalTokenUsage.
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
The default failurePolicy: 'fallback' keeps routing infrastructure advisory.
If a custom Router throws, rejects, times out, or returns an invalid decision,
OMA falls back to DeterministicRouter. Profiler timeout, refusal, throw, or
invalid structured output keeps that deterministic route.
Set failurePolicy: 'fail' to terminate instead. Profiler failures use
ROUTING_PROFILER_FAILED; Router/Profiler deadlines use ROUTING_TIMEOUT.
The run trace is closed with the corresponding error or timeout status before
the typed error is rethrown, so failed routing does not leave an incomplete run.
Machine-readable status, requestedRouterVersion, and fallbackCode fields
remove the need to parse human-readable 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',
// status: 'fallback',
// requestedRouterVersion: 'application-router-v1',
// fallbackCode: 'router-error'
// }
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.
When semantic profiling ran, semanticRoutingAssessment is attached both to
the result and routing record. It reports the inferred profile/version,
deterministic legacy decision, semantic recommendation, actual topology, usage,
and structured fallback state. The executed task topology, final tool grants,
and ExecutionReceipt remain governance truth.
Deterministic default
Omitting executionRouting uses the no-profiler deterministic router. Set the
strategy explicitly when you want configuration-level clarity:
const orchestrator = new OpenMultiAgent({
executionRouting: { strategy: 'deterministic' },
})
This makes no extra model call and retains deterministic Router results and custom-Router fallback behavior. Hybrid should be enabled only for providers and models that have passed the documented Shadow gate.
Explicitly installing new DeterministicRouter() as executionRouter also
makes that valid Router decision final under the precedence rules, so the
Profiler does not reinterpret it. Prefer strategy: 'deterministic' when the
intent is compatibility mode because it states the no-profiler behavior
directly.
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 remains intentionally cheap rather than semantically ambitious.
Hybrid routing corrects high-confidence false-Single cases after this step.
Applications that need domain-specific, authoritative decisions should still
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 and TaskProfiles cannot
satisfy named-role or independent-review requirements; those facts continue to
come from structured governance declarations and the executed topology.
Promotion criteria
Shadow evaluation is a release-engineering technique, not a user-facing runtime mode: run fixed fixtures in CI and canaries, compare its recommendation without changing production topology, and promote a provider/model to supported Hybrid use only after the documented accuracy, invalid-output, cost, and latency gates pass. Online historical-success learning and Team-to-Single optimization are outside V1.