Super Router decomposes complex work into dependency-aware subtasks, scores each branch for complexity and risk, and executes it on the right model role. It combines PRO/FLASH routing, provider fallback, FLASH retry and escalation, metadata extraction, LangSmith tracing, and token usage accounting into one auditable LangGraph workflow.
For any request to use super-router, super_router, or 走 super-router, do this exact workflow:
exec tool to run: /opt/homebrew/Caskroom/miniforge/base/bin/python /Users/fanyadan/.openclaw/skills/super-router/scripts/router.py '
exec returns Command still running, call the OpenClaw process tool with action="poll" on the returned sessionId until the process exits.Router result: or Router failed: and must include a concrete detail from the router output.Do not run openclaw super_router, openclaw super-router, openclaw skill, openclaw skills, or a nested openclaw agent command to satisfy this skill. Those are not the router.
Use super-router when you need:
Not needed for: Simple single-turn tasks, tasks where you already know which model to use, or when you want manual control over every routing decision.
To achieve true parallel execution (when ROUTER_MAX_CONCURRENCY > 1), the Planner must be instructed to use Atomic Decomposition.
planned_subtasks count matches the entity count. If the planner groups entities, treat as capability failure and retry with correction prompt.| Node | Function |
|---|---|
| ------ | ---------- |
| Planner | Decomposes original task into a JSON array of atomic, actionable subtasks. Uses Atomic Decomposition for maximum parallelism. |
| Judge | Scores each subtask on 5 dimensions: reasoning_depth, code_change_scope, ambiguity, risk, io_heaviness; combines with thresholds + confidence to decide PRO/FLASH |
| Executor Fanout | Uses LangGraph Send(...) to dispatch independent subtasks concurrently, then joins ordered results by original step number |
| PRO Executor Branch | Heavy reasoning model (override via ROUTER_PRO_MODEL) |
| FLASH Executor Branch | Fast model with review/retry logic (override via ROUTER_FLASH_MODEL) |
| FLASH Review | Validates output quality; distinguishes infra failures from capability failures; retries FLASH or escalates to PRO |
| Metadata Extractor | Extracts 'Technical Gold' (atomic high-precision facts) from step output to prevent finalizer timeouts and loss of detail |
| Recorder/Finalizer | Logs every step; compiles final report using a hybrid of Technical Gold and full audit trails; supports FLASH→PRO→deterministic fallback chain |
Dependency handling is part of the router's execution contract, not just a
planning hint.
depends_on and dependency_reason fields. Independent subtasks should use depends_on: [].
it must keep the planner's existing subtask IDs and must not add, remove,
merge, split, or rewrite subtasks.
self-dependencies, and cycles. If validation fails, the router falls back to a
conservative serial dependency chain instead of crashing the graph.
dependency_scheduler computes the ready set on each wave. A subtask is ready only when every ID in depends_on has completed.
Send(...); completed waveresults are joined, ordered by original step, and scheduling repeats until all
subtask IDs are complete.
This keeps synthesis, comparison, validation-after-implementation, and final
reporting work from running before their evidence-producing branches finish.
dependency_deadlockrecords blocked fallback results and errors so the finalizer can report the
dependency issue.
For maximum parallelism, prompt multi-entity work as atomic per-entity
decomposition, and ensure final synthesis/reporting subtasks depend on the
evidence-producing subtasks they summarize.
langgraph is the required Python runtime dependency.langsmith is optional and used only when LangSmith telemetry is enabled.Pillow is optional and needed only when regenerating super-router.png.Codex CLI, Gemini CLI, Claude Code CLI, or Ollama.
# Required: LangGraph
pip install langgraph
# Optional: LangSmith telemetry
pip install langsmith
# Optional: architecture diagram regeneration
pip install pillow
All model and provider choices are configured via ROUTER_* variables in the OpenClaw environment config file ~/.openclaw/.env. The router loads that file itself and still honors any explicit process environment overrides. No model names are hardcoded in the skill.
Set ROUTER_* environment variables in ~/.openclaw/.env. OpenClaw normally exposes this file to exec child processes, and router.py also loads it directly before reading os.environ, so the same command works from OpenClaw and from a plain shell.
To see current values: grep '^ROUTER_' ~/.openclaw/.env
To use one model for every router role, set ROUTER_MODEL:
ROUTER_MODEL=gpt-5.5
# Equivalent explicit form:
# ROUTER_MODEL=codex/gpt-5.5
Role-specific variables such as ROUTER_PRO_MODEL and ROUTER_FLASH_MODEL override ROUTER_MODEL when set.
When the user says "走 super-router", "use super-router", or asks for router analysis, invoke router.py directly through OpenClaw exec:
exec(
command="/opt/homebrew/Caskroom/miniforge/base/bin/python /Users/fanyadan/.openclaw/skills/super-router/scripts/router.py 'Analyze K8s YAML errors and rewrite config'"
)
exec(command="/opt/homebrew/Caskroom/miniforge/base/bin/python /Users/fanyadan/.openclaw/skills/super-router/scripts/router.py --stream 'Your complex task'")
For agents that struggle with non-ASCII arguments, pass the task via ROUTER_TASK:
exec(
command="/opt/homebrew/Caskroom/miniforge/base/bin/python /Users/fanyadan/.openclaw/skills/super-router/scripts/router.py",
env={"ROUTER_TASK": "Your complex task description"},
)
If exec returns "Command still running":
# Continue polling with process tool
process(action="poll", session_id="<session_id_from_exec>")
# Wait for completion
process(action="wait", session_id="<session_id_from_exec>", timeout=300)
For background launches requested by the user, use exec(background=true, notify_on_complete=true) and verify the process is actually running with an immediate process(action="poll"). If a background router launch exits immediately, inspect the preview and relaunch with the fix rather than reporting success.
For complex or multiline ROUTER_TASK prompts, avoid fragile inline heredocs inside zsh -lic. Write the task to a prompt file first, then launch with:
export ROUTER_TASK="$(/bin/cat "$HOME/.openclaw/logs/<task-name>.txt")"
/opt/homebrew/Caskroom/miniforge/base/bin/python "$HOME/.openclaw/skills/super-router/scripts/router.py" --stream 2>&1 | tee "$HOME/.openclaw/logs/<task-name>.log"
This preserves quotes/apostrophes in the task, keeps an auditable prompt artifact, and avoids zsh parse failures from nested heredocs.
Important: Once process shows completion, your next assistant message MUST start with Router result: or Router failed: and include at least one real detail from the output (e.g., "Planner fallback", "timeout", "BTC"). Never reply with just ---, punctuation, or empty lines.
For router runs that create or modify artifacts (reports, JSON logs, database ingests, generated files), do not trust the router final stdout alone. Before reporting success to the user:
stat, read the JSON/Markdown headers, count expected sections/cards when relevant).status, checked/accepted/skipped counts, threshold, document list) and ensure the user-facing Markdown/HTML item set matches the accepted ingested documents.All ROUTER_* variables are loaded from ~/.openclaw/.env by router.py before the router resolves defaults. Explicit process environment values win over .env values.
| Variable | Purpose | Default |
|---|---|---|
| ---------- | --------- | --------- |
ROUTER_MODEL | Global model default for planner, judge, PRO, and FLASH roles | None |
ROUTER_PLANNER_MODEL | Task decomposition model | internal default |
ROUTER_PLANNER_TASK_CHAR_LIMIT | Character budget for the compact planner-only context manifest JSON | 6000 |
ROUTER_PLANNER_MAX_OUTPUT_TOKENS | Planner JSON subtask output token cap | 4096 |
ROUTER_JUDGE_CONTEXT_CHAR_LIMIT | Character budget for judge context JSON | 3000 |
ROUTER_EXECUTOR_CONTEXT_CHAR_LIMIT | Character budget for executor context JSON | 8000 |
ROUTER_METADATA_OUTPUT_CHAR_LIMIT | Character budget for metadata extraction context JSON and output excerpts | 6000 |
ROUTER_FINALIZER_CONTEXT_CHAR_LIMIT | Character budget for finalizer context JSON | 12000 |
ROUTER_JUDGE_MODEL | Complexity scoring model | internal default |
ROUTER_PRO_MODEL | Heavy reasoning executor | internal default |
ROUTER_FLASH_MODEL | Fast executor | internal default |
ROUTER_PRO_FALLBACK_MODELS | Comma-separated PRO fallback list | None |
ROUTER_FLASH_FALLBACK_MODELS | Comma-separated FLASH fallback list | None |
ROUTER_CODEX_CLI | Codex CLI executable path for Codex-backed model names | first codex on PATH, else codex |
ROUTER_CODEX_CWD | Optional working directory passed to codex exec --cd | None |
ROUTER_CODEX_SANDBOX | Sandbox mode passed to codex exec --sandbox | read-only |
ROUTER_CLAUDE_CLI | Claude Code CLI executable path for Claude-backed model names | first claude on PATH, else claude |
ROUTER_FLASH_RETRY_BUDGET | Max FLASH retries before escalation | 1 |
ROUTER_RECURSION_LIMIT | Python recursion limit | 128 |
ROUTER_JUDGE_TIMEOUT | Timeout for Judge node LLM calls (seconds) | 300 |
ROUTER_MAX_CONCURRENCY | Max concurrent LangGraph branches for judge and executor fanout | Auto |
ROUTER_OLLAMA_URL | Ollama API endpoint (if used) | http://localhost:11434/api/generate |
ROUTER_FINALIZER_TIMEOUT | Timeout for the final reporting synthesis (seconds) | 600 |
ROUTER_DEBUG | Print raw diagnostic snippets | Off |
ROUTER_LANGSMITH_ENABLED | Enable optional LangSmith graph and model-call telemetry when LANGSMITH_API_KEY is set | Off |
ROUTER_LANGSMITH_PROJECT | LangSmith project name | super-router |
ROUTER_LANGSMITH_TAGS | Comma-separated extra LangSmith tags | None |
ROUTER_LANGSMITH_TRACE_PROMPTS | Include prompt previews in custom model-call traces | Off |
ROUTER_LANGSMITH_TRACE_OUTPUTS | Include output previews in custom model-call traces | Off |
ROUTER_LANGSMITH_HIDE_INPUTS | Request LangSmith SDK input hiding for graph traces | Off |
ROUTER_LANGSMITH_HIDE_OUTPUTS | Request LangSmith SDK output hiding for graph traces | Off |
ROUTER_LANGSMITH_FLUSH | Flush LangSmith traces before process exit | On |
ROUTER_TOKEN_USAGE_LEDGER | Optional append-only JSONL path for per-call token usage records | None |
Large local models may require higher timeouts and ROUTER_MAX_CONCURRENCY=1.
Provider selection is model-name based:
codex/..., bare gpt-, bare chatgpt-, or bare o plus digit names such as codex/gpt-5.5 or gpt-5.5. The router passes --sandbox but intentionally does not pass --ask-for-approval, because some codex exec versions do not support that option.
google-gemini-cli/..., gemini-*, pro, flash, flash-lite, or auto.claude/... or bare claude-* model names.ollama/....LangSmith is optional and non-fatal. Enable it only when external trace upload
is desired:
ROUTER_LANGSMITH_ENABLED=1
LANGSMITH_API_KEY=<your-langsmith-key>
ROUTER_LANGSMITH_PROJECT=super-router
The router adds graph tags/metadata and traces raw provider calls as child LLM
runs. Ollama token usage is captured from prompt_eval_count and eval_count.
Claude Code CLI token usage is captured from JSON total_input_tokens and
total_output_tokens. Gemini CLI token usage is captured from JSON
stats.models.*.tokens when available, with usageMetadata-style fields as a
fallback. Prompt and output text previews are disabled by default; enable them
explicitly with ROUTER_LANGSMITH_TRACE_PROMPTS=1 or
ROUTER_LANGSMITH_TRACE_OUTPUTS=1.
Token usage is tracked even when LangSmith is disabled. The router records every
successful provider call in a run-local ledger, prints a token summary after the
final report, and returns token_usage plus token_usage_summary in the final
state. Calls without provider token data are recorded as
usage_source=unavailable. Set
ROUTER_TOKEN_USAGE_LEDGER=~/.openclaw/super-router-usage.jsonl to persist the
per-call records as append-only JSONL.
If a super-router process stops before the final token ledger is printed, Gemini
CLI may still have persisted exact per-call token records in
~/.gemini/tmp/. This applies to planning-capture
termination, timeouts, manual kills, crashes, executor fanout interruptions, and
metadata/finalizer failures. Use references/gemini-cli-token-recovery.md to
recover input, output, cached, thoughts, tool, and total fields from
matching session JSONL files. Treat recovered values as provider telemetry;
treat dollar cost separately because cached-token billing depends on provider
pricing.
The Judge scores each subtask on:
| Condition | Route |
|---|---|
| ----------- | ------- |
complexity_score >= 5 | PRO |
complexity_score <= 2 | FLASH |
| Summary-like task (no deep work) | FLASH |
| High-risk incident diagnosis | PRO |
| High-risk evidence gathering | PRO |
| High-risk decision/rollback evaluation | PRO |
| Boundary case + low confidence | PRO (safe default) |
The router applies automatic adjustments:
reasoning_depth, risk, ambiguityWhen FLASH execution fails or produces questionable output:
infra_transient: timeout, network, rate limit, service unavailablecapability_quality: "need more info", empty output, too short, repeated taskROUTER_FLASH_RETRY_BUDGET)Final report generation follows:
FLASH finalizer -> (if fails) -> PRO finalizer -> (if fails) -> Deterministic template
{
"task": "original task string",
"planner_model": "model name used for planning",
"judge_model": "model name used for complexity scoring",
"pro_model": "primary PRO model",
"flash_model": "primary FLASH model",
"planned_subtasks": [{"desc": "..."}],
"subtasks": [
{
"desc": "...",
"model": "PRO|FLASH",
"assessment": {
"scores": {"reasoning_depth": 5, "code_change_scope": 3, "ambiguity": 2, "risk": 4, "io_heaviness": 1},
"complexity_score": 15,
"suggested_route": "PRO",
"final_route": "PRO",
"confidence": 0.85,
"reason": "...",
"judge_source": "llm|heuristic"
}
}
],
"results": [
{
"step": 1,
"planned_route": "PRO",
"route": "PRO",
"model_name": "...",
"desc": "...",
"output": "...",
"status": "success|failed",
"attempt_count": 1,
"retry_count": 0,
"escalated_from_flash": false,
"used_provider_fallback": false,
"flash_review": {"decision": "record", "failure_type": "none", "reason": "..."},
"attempt_log": ["..."]
}
],
"final_report": "...",
"finalizer_outcome": {
"route": "FLASH|PRO|DETERMINISTIC",
"model_name": "...",
"status": "...",
"used_provider_fallback": false,
"reason": "...",
"attempt_log": ["..."]
}
}
| File | Purpose |
|---|---|
| ------ | --------- |
scripts/router.py | Main LangGraph router script |
SKILL.md | This documentation |
references/long-running-quantitative-tasks.md | Guidance for heavy Monte Carlo / financial modeling tasks and background execution |
references/background-artifact-launches.md | Wrapper pattern for background router runs that produce durable artifacts: prompt/context capture, stream logs, verification, and safe handling of blocked launches |
references/source-html-background-wrapper.md | Concrete pattern for source-tree-to-HTML hierarchy/explainer jobs: source JSON collector, compact router prompt, HTML generator from context+log, background launch, immediate poll, and artifact verification |
references/linux-mm-source-html-example.md | Session-specific exemplar for a large Linux mm/ source hierarchy HTML guide: bucket taxonomy, artifact sections, and verification thresholds. Use as a model for similarly large kernel/subsystem explainers. |
templates/source-html-background-wrapper.sh | Copyable shell wrapper template for source-tree-to-HTML background jobs. Use it to avoid retyping the run/status/log/verification scaffold; replace placeholders and tune verification thresholds per artifact. |
To audit which model each stage actually used, run with --stream and check the output:
规划模型: in the routing plan summary判定模型: in the routing plan summary-> per step in executor fanout-> per stepfinalizer_outcome.route / finalizer_outcome.model_name in the returned stateVerification Audit Pattern: For explicit per-phase LLM validation runs (e.g. K8s anomaly detection tasks), execute the router with a complex high-risk task, capture the full streaming transcript, then synthesize a self-contained HTML report. The report should include:
This produces an auditable artifact that confirms the 5-node flow (Planner → Judge → Executor Fanout → Metadata → Finalizer) and surfaces any provider-specific issues like TerminalQuotaError without altering the core router logic.
Even at temperature=0.0, cloud-hosted models may produce different decompositions across runs due to backend inference differences. The router is deterministic in its routing logic, not in upstream model sampling. For guaranteed reproducibility, cache planner results by task hash or use a seed parameter if the provider supports it.
--stream and increase the terminal/process timeout if the Planner itself may take longer than 60s.ROUTER_JUDGE_TIMEOUT or ROUTER_FINALIZER_TIMEOUT higher for large models.~/.openclaw/.env or the OpenClaw process environment contains stale ROUTER_*_MODEL values.Task may be simple enough to not need decomposition, or the planner model may benefit from stronger prompting for atomic decomposition.
Task may genuinely require heavy reasoning. Consider configuring a stronger FLASH model via ROUTER_FLASH_MODEL.
共 3 个版本