One transport
Every LLM call goes through a single transport, directly or through the metering decorator composed over it. The transport owns the request, the timeout, retry with error classification, and token-usage accounting.
It carries tool definitions, tool choice including required, streaming and usage reporting - so no
call site has a structural reason to build its own request.
Enforced in CI. A source-scanning boundary test fails the build on any direct call site outside a two-entry allowlist: the transport itself, and the provider connection test, which probes an unsaved configuration and must not be metered.
Retry is opt-in and bounded, defaulting to a single attempt. Falling back to a different provider mid-request is not part of it.
Metering composes over the transport, not inside it
Credit metering takes the call as a callback: it opens a reservation, runs what it is given, and settles against reported usage. It is transport-agnostic by construction.
The separation is load-bearing. Retry and error classification sit in the transport, below the reservation - so a network retry does not extend the lifetime of a held credit hold.
Billing is idempotent per attempt. Each attempt derives a fresh request id. Against the credit engine's replay rule, a request id held constant across attempts does not double-bill - it unbills, because writes after the first are treated as replays.
A tenant running its own provider key is not metered by the platform.
The tool pipeline
Stages run in order, at one insertion point per side of dispatch, not per branch.
- Guardrails before approval. Deterministic checks run first; a call that cannot be allowed never reaches a human.
- Fail-closed approval. A
writeorexternalcall is denied when there is no approver, when the approver returnsunavailable, and when the approver throws. A digital employee runs unattended, so an unanswerable approval is a denial by construction. - Approval is argument-bound. The record is durable and single-use, and authorises those arguments - not that tool in general.
- A denial is its own event, with its own status and a reason code separating a guardrail block from a refused approval.
Risk is declared
Risk is a property of a registered tool, not a judgment made at the moment of use. Every MCP tool declares one; chat-only surfaces are covered by a static table beside the registry.
- A completeness test covers every tool name offerable in chat, so a new tool cannot ship unclassified.
- An unknown name escalates. A dynamically activated tenant skill is not statically enumerable;
an unresolvable name maps to
externaland routes through a human decision instead of defaulting to safe or being hard-denied.
Guardrails, both sides of dispatch
Pre-dispatch guardrails can block a call before it runs. The shipped rule refuses a call that would send personal data to a third-party channel - a messenger notification, a proxied external tool.
Post-dispatch guardrails redact arguments and output on the way to the audit trail, so the record of an action is not itself a store of personal data.
Two pipelines, not one: sending data outward and recording it internally are different risks with different verdicts.
Resolved configuration
An admin-gated endpoint returns the state a live turn for a given agent would resolve to: model, tool scope, prompt hash - after provider configuration, per-agent overrides, domain scoping and prompt assembly have been applied.
Where an agent builds a curated tool list instead of taking the domain-filtered registry scope, the response carries an explicit caveat field marking the part of the list it does not cover.
Related
- The decision trace - what the pipeline writes when it is done.
- Budgets and metering - the money side of the same transport.
- Tools and MCP - what the gate is gating, and under whose authority a tool runs.
- Built for a multi-tenant platform - why these defaults are set the way they are.