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.

typescript
// 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

typescript
// Structured approval with a custom UI form
const 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

FieldTypeRequiredDescription
reasonstringYesWhy escalating. Shown to the human.
contextRecord<string, unknown>YesData for the human to make an informed decision.
requiredCapabilitystringNoOnly humans with this capability can respond.
timeoutnumberNoMax wait in ms. Default: 3600000 (1 hour).
priority'low' | 'medium' | 'high' | 'critical'NoAffects notification urgency.
allowedActionsstring[]Noe.g. ["approve", "reject", "modify"]
uiobjectNoCustom UI type and fields for structured decisions.
grantActionIdstringNoWith grantScope, checks a scoped approval grant (Redis) before creating a new approval row.
grantScopestringNoScope key for grant lookup (e.g. recipient id or org scope).
requestDataunknownNoStored 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.

typescript
// Call another agent by URI
const result = await ctx.call.agent(
'agent://org/acme/invoice-processor@v1',
{ invoicePath: '/uploads/invoice-2024.pdf' },
);
console.log(result.data); // InvoiceProcessorOutput
console.log(result.execution.cost.usd); // Cost of the sub-agent call
console.log(result.execution.provenanceId); // Audit trail for the sub-call
console.log(result.delegationChain); // ['did:agent:abc...', 'did:agent:xyz...']

Addressing modes

typescript
// Three ways to address an agent:
// 1. Agent URI (recommended) — human-readable, org-scoped
await 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 reference
await ctx.call.agent('did:agent:7f3a2b9c-4e1d-4a5b-b3c2-8d9e0f1a2b3c', input);
// 3. Capability string — HUMΛN routes to best available agent
await ctx.call.agent('invoice/process', input);

Options

OptionTypeDefaultDescription
timeoutnumber30000Max wait time in ms.
allowSubDelegationbooleantrueCan the target agent delegate further?
maxDepthnumber5Max delegation chain depth.
retry.maxAttemptsnumber3Retry 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.

typescript
// Call multiple agents simultaneously
const [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 together
const 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.

typescript
// Route by capability — HUMΛN finds the best agent
const 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.

See Also