ctx.escalate & ctx.call
Start with ctx.escalate() for human-in-the-loop and capability-based routing — then use ctx.call to compose agents in parallel or by route. For policy that requires a verified human only, use ctx.call.human() (alias of ctx.escalate with a human-only constraint).
Why it exists
Composition without tight coupling. Call by capability, not by endpoint. Human-in-the-loop: one call to get a human in the loop with proper routing and UI hints—no custom approval UIs or ad-hoc escalation.
How it makes life better
Use ctx.call.agent / ctx.call.route and you get capability-based routing and a clear delegation chain. Use ctx.escalate and you get a full audit trail and built-in approval UX. (ctx.call.human remains a strict alias when a verified human is required by policy.) Bypass with direct HTTP or custom approval flows and you take on routing, audit, and consistency yourself.
Installed an agent from the Command Plane marketplace? After install, the console shows a copy-ready POST /v1/agents/call example (URL, JSON body, and curl). For API tokens and scopes (including human_api:agents:invoke), see the Quickstart.
The Fourth Law
ctx.escalate() embodies the principle that AI should defer to humans on high-stakes decisions. It's not an escape hatch — it's a first-class workflow step that creates a full audit trail: who was asked, what they decided, how long it took, and why.
ctx.escalate(request)
Escalate for approval or decision (routes by capability — human, workforce, or supervised agent). Execution pauses until the approver responds (or timeout expires). The human receives a notification in the HUMΛN dashboard or integrations (Slack, email, etc.) based on their notification preferences.
// Escalate when the stakes are too high for AI to decide alone (capability-first routing)const decision = await ctx.escalate({ reason: 'Invoice total mismatch — requires human verification before payment', context: { expected_total: 15000, computed_total: 14200, vendor: 'Acme Supplies', line_items: lineItems, }, requiredCapability: 'finance/approve', priority: 'high', allowedActions: ['approve', 'reject', 'request-clarification'],});
if (decision.approved) { await processPayment(invoiceId); console.log('Approved by:', decision.humanId); console.log('Decision time:', decision.metadata.duration, 'ms');} else { console.log('Rejected. Reason:', decision.reason);}With a structured UI form
// Structured approval with a custom UI formconst decision = await ctx.escalate({ reason: 'New vendor onboarding requires compliance review', context: { vendor_name: 'Supplier Co', contract_value: 50000 }, requiredCapability: 'procurement/approve', priority: 'medium', ui: { type: 'structured', fields: [ { key: 'risk_level', label: 'Risk Level', type: 'select', options: ['low', 'medium', 'high'], required: true }, { key: 'notes', label: 'Compliance Notes', type: 'textarea', required: false }, ], },});
console.log('Risk assessed as:', decision.data?.risk_level);Request fields
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | Yes | Why escalating. Shown to the human. |
context | Record<string, unknown> | Yes | Data for the human to make an informed decision. |
requiredCapability | string | No | Only humans with this capability can respond. |
timeout | number | No | Max wait in ms. Default: 3600000 (1 hour). |
priority | 'low' | 'medium' | 'high' | 'critical' | No | Affects notification urgency. |
allowedActions | string[] | No | e.g. ["approve", "reject", "modify"] |
ui | object | No | Custom UI type and fields for structured decisions. |
grantActionId | string | No | With grantScope, checks a scoped approval grant (Redis) before creating a new approval row. |
grantScope | string | No | Scope key for grant lookup (e.g. recipient id or org scope). |
requestData | unknown | No | Stored verbatim on the approval row for resume/replay (gateway & HITL callers). |
Regulated flows that must not route to a non-human: use ctx.call.human() — same pipeline with a human-only routing constraint.
ctx.call.agent(target, input, options?)
Call another agent. The calling agent's delegation is verified; the target agent runs with a derived delegation that cannot exceed the caller's authority.
// Call another agent by URIconst result = await ctx.call.agent( 'agent://org/acme/invoice-processor@v1', { invoicePath: '/uploads/invoice-2024.pdf' },);
console.log(result.data); // InvoiceProcessorOutputconsole.log(result.execution.cost.usd); // Cost of the sub-agent callconsole.log(result.execution.provenanceId); // Audit trail for the sub-callconsole.log(result.delegationChain); // ['did:agent:abc...', 'did:agent:xyz...']Addressing modes
// Three ways to address an agent:
// 1. Agent URI (recommended) — human-readable, org-scopedawait ctx.call.agent('agent://org/acme/invoice-processor@v1', input);await ctx.call.agent('agent://org/acme/invoice-processor', input); // latest
// 2. Agent DID — cryptographic, immutable referenceawait ctx.call.agent('did:agent:7f3a2b9c-4e1d-4a5b-b3c2-8d9e0f1a2b3c', input);
// 3. Capability string — HUMΛN routes to best available agentawait ctx.call.agent('invoice/process', input);Options
| Option | Type | Default | Description |
|---|---|---|---|
timeout | number | 30000 | Max wait time in ms. |
allowSubDelegation | boolean | true | Can the target agent delegate further? |
maxDepth | number | 5 | Max delegation chain depth. |
retry.maxAttempts | number | 3 | Retry on transient failures. |
retry.backoff | 'exponential' | 'linear' | 'none' | 'exponential' | Retry backoff strategy. |
ctx.call.parallel(calls)
Call multiple agents simultaneously. Results arrive together when all complete. Useful for fan-out patterns: gather research, then synthesize.
// Call multiple agents simultaneouslyconst [research, competitor, sentiment] = await ctx.call.parallel([ { agent: 'agent://org/acme/web-researcher', input: { query: topic } }, { agent: 'agent://org/acme/competitor-analyst', input: { topic } }, { agent: 'agent://org/acme/sentiment-analyzer', input: { text: context } },]);
// All three ran concurrently, results available togetherconst report = await ctx.llm.complete({ prompt: synthesizePrompt(research.data, competitor.data, sentiment.data),});ctx.call.route(capability, input, options?)
Route a request to the best available agent with a required capability. HUMΛN matches capability, confidence, cost, and region automatically.
// Route by capability — HUMΛN finds the best agentconst result = await ctx.call.route( 'document/extract', // Required capability { documentPath: filePath }, { optimize: 'quality', // 'quality' or 'cost' minConfidence: 0.8, // Only use agents above this confidence });Errors
AccessDeniedErrorCaller does not have permission to call the target agent.TimeoutErrorAgent call or human escalation exceeded the timeout.DelegationExpiredErrorThe calling delegation has expired.NotFoundErrorNo agent found matching the target URI or capability.In the wild
Reference agents that demonstrate ctx.escalate and ctx.call in production.
ctx.escalate() chainmulti-level-approval
Manager → VP → CFO escalation with capability-gated approvals at each level.
ctx.call.agent()newsletter-orchestrator
Multi-agent orchestration: fetch → summarize → send, each step a separate agent call.
ctx.escalate() escalationinvoice-processor
Escalates on total mismatch. Canonical Fourth Law (P10) pattern.