pleach
Operate

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 implement AgentProvider against 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

On this page