Escalations¶
An escalation is created when evaluate() returns status == "escalated". It represents an agent output that requires human review before being served to the user.
Escalation Lifecycle¶
stateDiagram-v2
[*] --> pending : evaluate() → escalated
pending --> approved : resolve(decision="approved")
pending --> rejected : resolve(decision="rejected")
pending --> corrected : resolve(decision="corrected")
approved --> [*]
rejected --> [*]
corrected --> [*]
Who may resolve an escalation¶
An escalation carries a resolver policy, set when it was created:
resolver |
Who may close it | From an SDK? |
|---|---|---|
"self" (default) |
Anyone holding a valid API key for the account | Yes — resolve() |
"role:<name>" |
Only a person holding that role, proven by a reviewer assertion | No — Console or resume hook |
A reviewer assertion is a signed statement that the person resolving the decision holds the
required role. Only the Coalex Console issues one; an SDK cannot, because an API key proves which
workload is calling rather than which person approved. Calling resolve() on a role-gated
escalation therefore returns a 403 explaining this — see
resolve() · Role-gated decisions.
Escalation Data¶
Each escalation contains:
| Field | Description |
|---|---|
escalation_id |
Unique identifier (use this with resolve()) |
agent_id |
The agent that produced the output |
request_id |
Links the escalation to its trace |
input |
The agent's input data |
output |
The agent's output that needs review |
risk_score |
The computed risk score (0.0 – 1.0) |
metrics |
Declared metric functions (computed at resolve-time) |
status |
pending, approved, rejected, or corrected |
created_at |
When the escalation was created |
Routing Escalations¶
Coalex creates escalations but does not prescribe how you route them to reviewers. Common patterns:
Webhook¶
Configure a webhook URL in the dashboard. Coalex sends a POST request when an escalation is created:
{
"escalation_id": "esc-001",
"agent_id": "claims-bot",
"risk_score": 0.73,
"output": {"diagnosis": "..."},
"created_at": "2025-01-15T10:30:00Z"
}
Polling¶
Query pending escalations from your review UI:
curl "https://traces.coalex.ai/api/v1/escalations?status=pending" \
-H "Authorization: Bearer $COALEX_API_KEY"
Dashboard¶
The admin dashboard lists every escalation and opens one to show what was asked, what the agent answered, who decided and what the reviewer corrected. It is read-only: a person approves, rejects or corrects in the Coalex Console, where their identity and approval role are verified, or an SDK resolves it with resolve().
To get to the Console, open Settings in the dashboard: the Operator Console section, where an admin switches the Console on for the organisation, has an Open the Console link that opens the Console in a new tab. It leads to the Console of the environment the dashboard is served from: https://console.coalex.ai from dashboard.coalex.ai, and https://console-staging.coalex.ai from the staging dashboard. Every member sees it, whether the Console is on or off. On any other address (local development, a preview) the link is not shown.
Each escalation has an address: the dashboard's Escalations page with ?escalation=<escalation id> opens its review. The title in each row is that link, so a row opens in a new tab and a copied link opens the same review for anyone who belongs to the organisation. An id that no escalation of the organisation has reads "Escalation not found".
The page searches and sorts on the server, across every escalation and not only the 50 on screen. The search field matches text inside the reason the agent gave, the reviewer's reason, the tool, the request id and the escalation id, ignoring case, and the totals above the table count the matches. The sort offers newest first (the default), oldest first, and deadline, which lists the pending escalations by the soonest deadline (those with none last) and the rest newest first. The search and the sort are in the address as ?q= and ?order= (created_asc or expires_asc), so a link keeps them; the same two parameters, q and order, are on GET /v1/escalations.
Resolving Escalations¶
Once a human reviewer has assessed the output, submit their decision with resolve():
result = coalex.resolve(
escalation_id="esc-001",
decision="approved",
reviewer={"name": "Dr. Smith", "email": "dr.smith@hospital.org"},
reason="Output is clinically accurate.",
)
See Resolve for decision types and the full API.
Audit Trail¶
All escalations — including auto-approved evaluations — are stored permanently for compliance purposes. This gives you:
- Complete history of every agent decision
- Reviewer identity and reasoning for each resolution
- Quality metrics for corrected outputs
- Data for EU AI Act, ISO 42001, and SOC 2 reporting