Cloud-routed agent
An agent reaching Anthropic, OpenAI, or Google models through AWS Bedrock, Azure OpenAI Service, or Vertex AI — IAM-federated, VPC-bound, region-enforced.
A cloud-routed agent is the shape an enterprise reaches for when
direct provider API keys are forbidden by policy and inference
has to land inside the customer's VPC. The model family is the
same as the direct-API shape — anthropic, openai,
google — but the transport is AWS Bedrock, Azure OpenAI
Service, or Google Vertex AI. IAM federates the credential;
region pinning is enforced by the cloud, not the runtime.
Transport packages not yet published.
@pleach/transport-bedrock, @pleach/transport-azure-openai, and
@pleach/transport-vertex are marked private in the monorepo and are
not on npm yet — the npm install / import lines below will not
resolve today. This page documents the planned integration shape; the
transport packages publish in a later cut.
This page walks the four pieces a security architect asks about: the transport-vs-family separation, IAM-federated credential resolution, region constraints, and the cost row that ties the cloud invoice back to the runtime.
Related shapes. Region-pinned agent if the same buyer also locks family per call class and runs a parity suite. Multi-tenant SaaS agent if one runtime serves many customers, each reaching their own cloud account. Regulated-domain agent if the regulator drives the constraint and the cloud is the substrate that makes the deployment reachable.
What you're building
A turn loop whose provider boundary is the cloud, not the lab. The shape is the same regardless of which cloud the buyer landed on:
- Family is the model's identity (
anthropic,openai,google); transport is the route to it (bedrock,azure-openai,vertex). - The credential is an IAM role, a managed identity, or a workload-identity binding — never a long-lived API key.
- The endpoint is a VPC endpoint, a PrivateLink, or a private service connect URL. The cloud enforces that the call doesn't leave the perimeter.
- The cost row carries the cloud, the region, and the model — so the runtime ledger reconciles to the cloud invoice.
Transport vs family
The same family routes through different transports without
forcing a different cascade decision. A session asking for
anthropic can land on the direct API, Bedrock, or both via
failover — the cascade rules don't change.
// lib/runtime.ts
import { SessionRuntime, definePleachPlugin } from "@pleach/core";
export function buildCloudRoutedRuntime(req: AuthedRequest) {
return new SessionRuntime({
provider: bedrockProvider, // transport
storage: new SupabaseAdapter({ client: supabase }),
checkpointer: new SupabaseSaver({ client: supabase }),
plugins: [definePleachPlugin("cleared-tools", { tools: clearedTools })],
permittedFamilies: new Set(["anthropic"]), // family lock
// Transport ("bedrock") and region ("us-east-1") are pinned at the
// provider — `bedrockProvider` above IS the transport, constructed
// against the cleared AWS region — not via a session-config field.
tenantId: req.tenantId,
});
}Why the separation matters under a contract clause: a buyer who
clears anthropic through Bedrock for us-east-1 hasn't cleared
the same family through Azure OpenAI for westeurope. The
transport pin is the structural piece that keeps the cascade
inside the cleared substrate.
IAM-federated credentials
The credential resolver is per-request — STS for AWS, managed identity for Azure, workload identity for Google. The runtime doesn't hold a long-lived key; the cloud's identity layer hands out a short-lived token that the transport adapter refreshes.
// lib/providers/bedrock.ts
import { createBedrockProvider } from "@pleach/transport-bedrock";
import { fromContainerMetadata } from "@aws-sdk/credential-providers";
export const bedrockProvider = createBedrockProvider({
region: "us-east-1",
credentials: await fromContainerMetadata()(),
defaultModelId: "anthropic.claude-3-5-sonnet-20241022-v2:0",
});The audit row records the role ARN (or the managed-identity principal, or the workload-identity binding) — not the short-lived token. A regulator asking "what identity made this call" reads one column; the credential itself is never persisted.
What today ships
Today, @pleach/core ships the family-strict cascade,
permittedFamilies, the deterministic replay path, and the
audit row that records family, model, and region. Bring-your-
own-provider via the AgentProvider contract is the supported
extension point: a host running a Bedrock, Azure OpenAI, or
Vertex endpoint implements the contract directly and threads
the cascade.
For the direct-API path (provider keys held by the runtime),
AnthropicSdkProvider and AiSdkProvider ship in core.
Roadmap
Roadmap pieces, in expected order:
@pleach/transport-bedrock. A first-party Bedrock transport with STS credential resolution, region pinning, and Bedrock-specific cost-event emission. Until it lands, hosts implementAgentProvideragainst the Bedrock Runtime API directly.@pleach/transport-azure-openai. A first-party Azure OpenAI transport with managed-identity credential resolution, deployment-name routing, and Azure-specific cost-event emission.@pleach/transport-vertex. A first-party Vertex AI transport with workload-identity credential resolution, region pinning, and Vertex-specific cost-event emission.- Cloud-attestation helpers. Per-cloud signed manifests that route audit rows into the cloud's native security surface — AWS Security Hub, Azure Sentinel, GCP Chronicle — so the cloud's existing compliance review absorbs the runtime's audit ledger.
- VPC endpoint discovery. A configuration map at v1; a service-discovery integration that resolves PrivateLink endpoints from VPC metadata later.
No dates. Track the upstream package READMEs and CHANGELOG for landing notices.
Region as a hard constraint
Region is enforced by the cloud at the endpoint URL. A request
to a us-east-1 Bedrock endpoint can't land on a us-west-2
model — the cloud rejects it before the runtime sees the
response. The runtime records the region in the audit row, so
an out-of-region attempt is visible in the ledger even when the
cloud has already rejected it.
A buyer with EU residency policy pins the runtime to a
eu-central-1 transport and rejects any session whose context
asks for a different region. The check is a one-line precondition
on buildCloudRoutedRuntime; the cloud is the enforcement
authority.
Cost reconciliation to the cloud invoice
The audit row carries the cloud, the region, the model, and the token count — the same columns the cloud's billing detail breaks out. Reconciliation is one join, not a parallel cost pipeline.
select
family,
model_id,
region,
count(*) as calls,
sum(input_tokens) as input_tokens,
sum(output_tokens) as output_tokens
from harness_auditable_calls
where transport = 'bedrock'
and created_at >= date_trunc('month', now())
group by family, model_id, region;The cloud invoice rolls up the same dimensions. A finance reviewer reading both surfaces sees the same numbers.
Where to go next
Providers
The AgentProvider contract — the extension point a cloud transport implements.
Family lock
The permittedFamilies constraint that scopes which families a session can ever reach.
Region-pinned agent
The sibling shape for direct-API buyers running per-call-class family pins and parity suites.
Audit ledger
The harness_auditable_calls schema and the columns the cost reconciliation reads.
Multi-tenant SaaS agent
Per-tenant runtime construction when each tenant reaches its own cloud account.
Air-gapped deployment
The substrate posture for a perimeter-bound deployment, when the cloud is fully on-prem.
runtime.tenant facet
The `runtime.tenant` primitive — `tenantId` + `subTenantId` accessors, `EventLogWriter` row stamping, RLS, `withTenantHeader`. The type-level surface.
Region-pinned agent
An agent that pins region, family, and model per call class — with parity-validation suites and deterministic failover discipline a procurement reviewer can read.