Regent ControlLatency and failure

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:

PathRequestsp50p95p99
MCP endpoint (/mcp: tool listing, budget questions, decided calls)23 8822 ms120 ms155 ms
HTTP tool path (/gw/{tool}/…, decided and executed)6 9502 ms122 ms245 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

HopDefaultWhere it is set
Cloud Gateway → control plane (the decision)10 sgateway deployment
Cloud Gateway → provider (the executed call)10 sper tool in the catalog (timeout_seconds), when a provider needs longer
regent-control Python / TypeScript SDK → gate10 stimeout_seconds on the client
SDK → sidecar session30 stimeout_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_key is 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 an idempotency_key for 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 429 carries Retry-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_ERROR in 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_EXCEEDED on 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.