Skip to main content

When it runs

The ScenarioOrchestrator._resolve_scenario_for_job resolution has four tiers:
  1. Explicit pinmetadata.scenario_id wins. Used by replay, admin tooling, and the chain primitive itself when re-dispatching.
  2. Intent route mappingmetadata.intent_route looked up in each scenario’s declared intent_routes.
  3. Tier-3: classifier defaultmetadata.kind == "task" with no higher-priority pin routes here. This is the path the command-widget Task card sends.
  4. Orchestrator defaultAMOS_DEFAULT_SCENARIO or code_build.
The classifier is not registered for any intent_route. Leaving intent_routes: [] keeps it from claiming any route name and prevents it from recommending itself as a target.

Architecture

Two-level shape

classify is a pure prompt level. It synthesizes every classifier-eligible scenario into the prompt’s AVAILABLE SCENARIOS block:
The model returns a JSON envelope:
A schema intra-verifier catches malformed envelopes; the level retries once. If both attempts fail, the orchestrator’s classifier-failure safety net chains to quick_qa. disambiguate only runs on the low-confidence branch. The first model turn emits an ask_user envelope carrying an enum schema; the FE renders this as a button panel inside the task modal; the user clicks their pick; the resume folds the answer back; the second turn emits the final chosen_intent_route JSON.

Catalog construction

The orchestrator builds the classifier catalog once at startup in __post_init__:
A scenario is “classifier-eligible” iff it declares a non-empty examples: block. That keeps admin/debug scenarios (code_build_strict, parallel_review_demo) out of the catalog without a separate flag. The catalog is threaded into the LangGraph state as state["classifier_catalog"] so the prompt builder reads it without needing to touch the orchestrator directly.

Chain primitive

ScenarioResult carries two new fields:
  • chained_intent_route: str | None
  • chain_reason: str | None
When any level’s output_parsed contains a chosen_intent_route field, the runner promotes it onto top-level state. The orchestrator’s run() reads this after the compiled-graph invocation, builds a new payload pinned to the target scenario via metadata.scenario_id, bumps _chain_depth, emits a scenario_chained event, and recurses. MAX_CHAIN_DEPTH = 3 caps the chain depth. The classifier counts as one hop, so composite follow-ups have two more slots before the cap. CLASSIFIER_FALLBACK_SCENARIO_ID = "quick_qa" is the safety net the orchestrator chains to when:
  • the classifier emitted no chained_intent_route AND its aborted_reason is set or output is empty, OR
  • the classifier emitted a chosen_intent_route that isn’t a loaded scenario id (hallucination).
Both cases preserve the user’s job — they get a useful response instead of a routing fault.

Files

  • knowledge-hub/scenarios/intent_classifier.yaml — the scenario YAML
  • worker/worker/graph/scenarios/prompts.pyintent_classifier_route + intent_classifier_disambiguate
  • worker/worker/graph/scenarios/orchestrator.py — tier-3 rule, chain loop, classifier-failure safety net (MAX_CHAIN_DEPTH, INTENT_CLASSIFIER_SCENARIO_ID, CLASSIFIER_FALLBACK_SCENARIO_ID)
  • worker/worker/graph/scenarios/runners.py — auto-populates output_parsed on JSON levels; promotes chosen_intent_route to state
  • worker/worker/graph/scenarios/state.pychained_intent_route, chain_reason, classifier_catalog fields on ScenarioState
  • apps/frontend/components/layout/footer/ask-user-enum-panel.tsx — the FE button-panel renderer

Configuration

Locked decisions (2026-05-18):

Future composition

Once chained_intent_route is a first-class field, scenarios chain arbitrarily. Examples this primitive unlocks:
  • incident_response — classify alert → fetch logs (aws_pulse-like) → diagnose (LLM) → propose fix → chain to github_pr_fix if the user approves.
  • monitoring_digest — aws_pulse + vercel_status + github_open_prs → synthesize a single morning brief.
  • ambient_oncall — long-running scenario that periodically chains to whichever specialist scenario the latest alert maps to.
The intent_classifier is the first instance; the infrastructure it needed (chain field + depth cap + scenario_chained event) is generic.