Latency and failure
A service that stands in front of money has to say what it costs in time and what it does when it breaks. This page has the numbers and the rules; nothing here depends on how the decision is made inside.
Latency
Measured at the edge of the Cloud Gateway over the seven days to 26 October 2026, all organizations, all tools, production and sandbox together:
| Path | Requests | p50 | p95 | p99 |
|---|---|---|---|---|
MCP endpoint (/mcp: tool listing, budget questions, decided calls) | 23 882 | 2 ms | 120 ms | 155 ms |
HTTP tool path (/gw/{tool}/…, decided and executed) | 6 950 | 2 ms | 122 ms | 245 ms |
The HTTP tool path includes the provider’s own response time for executed calls, so its tail
is the provider’s tail. A decision
on its own (identity, mandate, policy, behavioural score, token) sits inside these figures.
A decision that needs a person (escalate) is not a latency figure at all: the call returns
at once and the agent resumes after the person answers.
All traffic is served from one region, United States (Virginia), over TLS. There are no regional endpoints yet; a customer in another region adds that round trip.
Timeouts
| Hop | Default | Where it is set |
|---|---|---|
| Cloud Gateway → control plane (the decision) | 10 s | gateway deployment |
| Cloud Gateway → provider (the executed call) | 10 s | per tool in the catalog (timeout_seconds), when a provider needs longer |
regent-control Python / TypeScript SDK → gate | 10 s | timeout_seconds on the client |
| SDK → sidecar session | 30 s | timeout_seconds on the session |
Agent asking a person (regent-control onboard, enrolment) | 15 min | --timeout |
A decision that has not been answered inside its timeout is a failure, and a failure is a refusal (next section). Set your own outer timeout above the gate’s, not below it, or you will abandon decisions that were about to arrive.
When Regent cannot be reached
The gate, the gateway, the sidecar and the SDKs fail closed. A timeout, a DNS failure, a
5xx from the control plane or a refused key all produce the same thing: no provider is called,
no money moves, and the caller gets a refusal with code INTERNAL_ERROR
("control plane unreachable; failing closed"; HTTP 403 on the gateway, a raised error in the
SDKs). The refusal is not a decision and leaves no receipt; it is recorded as a transport
failure.
Fail-open exists as a deliberate setting on things you run yourself (the sidecar, the SDK’s
enforcement hook: fail_open: true), is off by default, and is printed in the hook’s own status
line so nobody discovers it in an incident. The hosted gateway does not fail open.
Rails that answer with a decision of their own (Stripe’s response, Agentcard’s order events, a custodian’s transaction) are read the same way: a provider that did not answer is a decision left open, never a success assumed. For rails that report by event, a decision the rail never reported on within two hours, and never said was placed, is closed as not settled and its hold on the budget is released; the audit trail says so.
Idempotency and retries
idempotency_keyis the resume handle. Send a stable key per logical action. A retry with the same key replays the earlier decision: an allow is returned again with the same decision id, a refusal is returned again, an escalation that has since been approved becomes the allow. Nothing is decided twice and nothing is counted twice.INTERNAL_ERROR: retry with the same key after a short back-off. Because a replay never double-decides, retrying is safe; because the gate failed closed, there is nothing to undo.DUPLICATE_REQUEST: an identical money request was allowed moments ago and this one carried no key. Look at that decision; pass anidempotency_keyfor a deliberate repeat.VELOCITY_EXCEEDED: this agent asked too often in the window. Back off; do not retry in a loop, each retry is another ask.ESCALATION_REQUIRED: not a failure. Stop, tell the person where to look (the console, the e-mail, the card in the chat), retry the same call with the same key after they answer.- Rate limits on the platform API: 30 requests per second per IP with a burst of 20;
login and signup 5 per minute. A
429carriesRetry-After; honour it.
Settlement after a decision
A decision is a promise of what may happen; the receipt records what did. On rails that
answer synchronously (a Stripe call), the provider’s answer closes the decision as soon as it
returns. On rails that report later (an Agentcard order, a custodian’s transfer), the decision
stays open and the hold on the budget stands until the rail reports; the receipt then carries
settlement_source: provider or custodian and the rail’s own reference. An agent’s own
/complete on such rails is recorded as the agent’s report, not as settlement. The two-hour
rule above is the backstop for a rail that never reports.
What to monitor on your side
- The share of
INTERNAL_ERRORin your decisions: it should be zero in steady state. A non-zero share is Regent unreachable from where you run, or a key problem, before it is anything else. - Decisions left open longer than the rail usually takes: visible per decision in the console and over the API.
VELOCITY_EXCEEDEDon an agent: a loop, a stuck retry, or an agent doing something you did not intend.
Current status of the platform, including planned regions and the public status page, is on Status.