POST /v1/route/decision¶
Dry-run a routing decision. The gateway runs the same policy
pipeline as /v1/chat/completions but does not make an upstream
OpenRouter call. Use this to debug routing behavior, preview a
decision, or build test fixtures.
Request¶
Headers¶
| Header | Required | Notes |
|---|---|---|
Authorization |
yes | Bearer <SMART_GATEWAY_API_KEY> |
Content-Type |
yes | application/json |
Body¶
{
"task": {
"task_id": "task-17",
"goal_id": "goal-oauth",
"kind": "DEBUG",
"instruction": "Find the root cause of the refresh-token race.",
"sensitive": true,
"repo_context_present": true,
"risk_level": "HIGH",
"blast_radius": "HIGH",
"reasoning_requirement": 0.8,
"ambiguity": 0.2,
"dependency_depth": 0.7,
"verification_difficulty": 0.6,
"estimated_tool_depth": 9,
"metadata": {"session_id": "proj-A"}
},
"runtime": {
"attempts": 1,
"flash_attempts": 1,
"same_error_count": 1,
"tests_failed": 2,
"files_touched": 8,
"tool_depth": 9,
"failure_class": "UNKNOWN",
"last_model": "deepseek_v4_flash"
}
}
task fields:
| Field | Type | Default | Notes |
|---|---|---|---|
task_id |
string | required | Routing identifier. |
goal_id |
string | adhoc |
Goal scope. |
kind |
enum | OTHER |
One of CODING, DEBUG, ARCHITECTURE, SECURITY, AUTH, PAYMENT, DESTRUCTIVE_MIGRATION, TEST, SUMMARIZE, CLASSIFY, PUBLIC_REVIEW, RESEARCH, OTHER. |
instruction |
string | required | Free text. |
explicit_route |
enum | AUTO |
AUTO, PRO, FLASH, NEMOTRON. |
reasoning |
enum | AUTO |
AUTO or HIGH. |
sensitive |
bool | true |
Privacy tier. |
repo_context_present |
bool | false |
Affects free-model eligibility. |
repo_free_opt_in |
bool | false |
Opt-in to free models on repo work. |
risk_level |
enum | LOW |
LOW, MEDIUM, HIGH, CRITICAL. |
blast_radius |
enum | LOW |
Same scale. |
reasoning_requirement |
float 0..1 | 0.3 |
Complexity dimension. |
ambiguity |
float 0..1 | 0.3 |
|
dependency_depth |
float 0..1 | 0.3 |
|
verification_difficulty |
float 0..1 | 0.3 |
|
estimated_tool_depth |
int | 0 |
Combined with runtime.tool_depth. |
metadata |
object | {} |
Free-form. |
runtime fields:
| Field | Type | Default | Notes |
|---|---|---|---|
attempts |
int | 0 |
Total attempts in this task. |
flash_attempts |
int | 0 |
Flash-tier attempts; triggers hard Pro at 2. |
same_error_count |
int | 0 |
Triggers hard Pro at 2. |
error_signature |
string | null |
Hash of normalized error text. |
tests_failed |
int | 0 |
Last-seen test failures. |
files_touched |
int | 0 |
Triggers hard Pro at 20. |
tool_depth |
int | 0 |
Triggers hard Pro at 16. |
failure_class |
enum | NONE |
NONE, LOCAL, STRUCTURAL. |
last_model |
string | null |
Internal alias key. |
Response¶
200 OK:
{
"task_id": "task-17",
"action": "ROUTE",
"model": "deepseek_v4_pro",
"purpose": "EXECUTE",
"cause": "hard_pro_rule",
"score": 65.0,
"confidence": 0.98,
"hard_rule": true,
"sensitive_block_applied": false,
"evidence": ["task_kind=AUTH", "risk=HIGH"],
"policy_version": "1"
}
| Field | Type | Notes |
|---|---|---|
task_id |
string | Echoed from the request. |
action |
enum | ROUTE, SCOUT, STOP_FOR_HUMAN, DENY. |
model |
string or null | Internal alias key (deepseek_v4_pro, etc.) or null for STOP_FOR_HUMAN / DENY. |
purpose |
enum | EXECUTE, SCOUT, NONE. |
cause |
string | The rule that fired (hard_pro_rule, score_flash, score_pro, gray_zone_scout, budget_hard_cap_exceeded, all_models_unhealthy, ...). |
score |
float 0..100 | Weighted complexity score. |
confidence |
float 0..1 | Routing-decision confidence. |
hard_rule |
bool | Whether a hard rule triggered this decision. |
sensitive_block_applied |
bool | Whether the privacy gate forced a downgrade or denial. |
evidence |
array of strings | Per-rule evidence entries. |
policy_version |
string | 1 for v1.0.0. |
Status codes¶
| Status | When |
|---|---|
200 |
Decision computed. |
401 |
Missing or malformed Authorization. |
422 |
Pydantic validation error. |
Examples¶
Force Pro for an AUTH task¶
curl -sS "$BASE/v1/route/decision" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{
"task": {
"task_id":"t1","goal_id":"g1","kind":"AUTH",
"instruction":"audit refresh-token rotation",
"sensitive":true,"risk_level":"HIGH"
},
"runtime":{"same_error_count":0}
}'
Trigger structural-failure escalation¶
curl -sS "$BASE/v1/route/decision" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{
"task":{"task_id":"t2","instruction":"fix the parser","kind":"DEBUG","sensitive":true},
"runtime":{"failure_class":"STRUCTURAL"}
}'
Trigger same-error-twice escalation¶
curl -sS "$BASE/v1/route/decision" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{
"task":{"task_id":"t3","instruction":"make this test pass"},
"runtime":{"same_error_count":2}
}'
Trigger hard budget cap¶
The dry-run endpoint always assumes budget_spent_usd = 0. To
exercise the hard-cap code path, override
ROUTING_POLICY_PATH with a policy that has
budget.per_goal_hard_usd: 0.0001 and re-call /v1/route/decision.
Related¶
- User guide → Routing behavior — narrative view.
- Architecture → Routing pipeline — full precedence.