UNPKG

agentfootprint

Version:

The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.

228 lines (227 loc) • 12.7 kB
/** * agentCoreRuntimeMcpTransport — an MCP server hosted on AWS Bedrock * **AgentCore Runtime**, reached as an ordinary MCP transport. * * const orders = await mcpClient({ * name: 'orders', * transport: agentCoreRuntimeMcpTransport({ * agentRuntimeArn: 'arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/orders_mcp-a1b2c3', * region: 'us-west-2', * }), * }); * * ── Why this exists ────────────────────────────────────────────────────────── * `agentCoreGatewayTransport` reaches a Gateway; `agentCoreRuntimeHost` hosts * OUR agent on Runtime. Neither calls an MCP server somebody deployed TO * Runtime, and that server is not reachable as a plain URL: every request goes * through `InvokeAgentRuntime`, it lands in a runtime SESSION that has to be * carried from call to call, and the platform answers a request that arrives * while that session is still coming up with an HTTP 200 whose body says * "Session operation in progress, please retry" — which no MCP client retries. * * ── What it is: one port, three strategies ─────────────────────────────────── * The port is the existing one: this returns an `http` member of * `McpTransport`, so `mcpClient` builds it like any other Streamable HTTP * server and knows nothing about AgentCore. Everything AgentCore-specific sits * in the `fetch` it carries, composed from three choices, one file each: * * session (`session.ts`) 'per-call' (the default: a session per request), * or 'reuse' (one session per MCP client, keyed by * a handle the transport issues) * retry (`sessionBusy.ts`) the session-busy refusal, retried with bounded * backoff by the SAME loop `mcpClient` uses for a * 429 (`mcp/throttleRetry.ts` · `retryingFetchFor`, * one footprintjs `attempt()` series per request) * auth (`invoke.ts`) 'sigv4' through the AWS SDK's InvokeAgentRuntime, * or a bearer token over the documented HTTPS * endpoint — the SDK has no bearer scheme, and the * API reference says an OAuth caller must use HTTPS * * in that order, outermost first: the session is applied once per request, so * every attempt of it lands in the same runtime session, and every attempt is * signed (or vended) afresh, the ordering `mcp/throttleRetry.ts` requires. * What the MCP client reads of a failure is rewritten from the library's own * fixed sentences and safe ids (`safeAnswer.ts`), never the service's text. * * `mcpClient`'s own 429 retry does not wrap this fetch: the fetch is joinable * (`joinableRetry`), so the 429 rule joins the transport's series INSIDE the * session and the rewrite. One request is one series — one attempt count, one * waiting total, one deadline — so the two retries can never multiply requests, * and every attempt, a 429's included, lands in the same runtime session. The * client's request ledger joins the same way, so a call the agent dispatched * gets this series' attempts in its run (`mcp/requestLedger.ts`). * * ── What it does NOT do ────────────────────────────────────────────────────── * Deploy or manage a runtime (a control-plane job), or host one (that is * `agentCoreRuntimeHost`). This is the CLIENT side of a server somebody already * deployed with `--protocol MCP`. * * Pattern: Facade over three Strategies. Role: outer ring, vendor adapter. */ import { type FetchLike } from '../../../mcp/gatewayTransport.js'; import { type RetryDefaults, type ThrottleRetryOptions } from '../../../mcp/throttleRetry.js'; import type { McpHttpTransport } from '../../../mcp/types.js'; import type { CredentialProvider } from '../../../identity/types.js'; import { type AgentCoreRuntimeSdkClient, type BedrockAgentCoreRuntimeSdkModule } from './invoke.js'; import { type AgentCoreRuntimeSession } from './session.js'; /** * A bearer token, for a runtime whose inbound auth is OAuth (a JWT authorizer). * * Vended PER REQUEST by the provider — the same once-and-dropped rule as * `gatewayTransport`, through the same code. */ export interface AgentCoreRuntimeBearerAuth { /** Who vends the token. `agentCoreIdentity()` or any `CredentialProvider`. */ readonly bearer: CredentialProvider; /** The downstream service id your provider keys on. Default `'runtime'`. */ readonly service?: string; /** OAuth scopes, when the provider uses them. */ readonly scopes?: readonly string[]; /** * `'machine'` (2-legged), the only mode. `'user'` is refused: the transport * asks for its token without naming any user, so a user-delegated token * would be sent for whoever calls through the client. For a token per user, * build a transport per user whose provider vends that user's token. */ readonly mode?: 'machine'; /** * Your own `fetch`, called UNDERNEATH the per-request vending — an HTTP * agent, a proxy. It sees the final headers, the vended one included. */ readonly fetch?: FetchLike; } /** * How requests are authenticated — the runtime's inbound auth decides which. * * - `'sigv4'` — IAM. The AWS SDK signs `InvokeAgentRuntime` with your AWS * credentials (the default chain, or the `client` you pass). * - `{ bearer }` — OAuth. A plain HTTPS request with `Authorization: Bearer`, * because the SDK cannot send a bearer token. */ export type AgentCoreRuntimeAuth = 'sigv4' | AgentCoreRuntimeBearerAuth; /** * The session-busy retry: the same options and the same `onRetry` report as * `mcpClient`'s `retryOnThrottle`, applied to AgentCore's own refusal — with * this transport's defaults (see {@link AgentCoreRuntimeMcpTransportOptions.retry}). */ export type AgentCoreRuntimeRetryOptions = ThrottleRetryOptions; /** Options for {@link agentCoreRuntimeMcpTransport}. */ export interface AgentCoreRuntimeMcpTransportOptions { /** * The runtime hosting the MCP server — its ARN, as `agentcore deploy` prints * it, or its id together with {@link accountId}. */ readonly agentRuntimeArn: string; /** The region it runs in, e.g. `'us-west-2'`. */ readonly region: string; /** The endpoint (version) to invoke. The runtime's default endpoint when omitted. */ readonly qualifier?: string; /** The owning account — required by AgentCore when `agentRuntimeArn` is an id, not an ARN. */ readonly accountId?: string; /** How requests are authenticated. Default `'sigv4'`. */ readonly auth?: AgentCoreRuntimeAuth; /** * Which runtime session each request lands in. Default `'per-call'`. * * - `'per-call'` — every request in a session of its own; nothing carries * over, so one client can serve every user of a process. Needs a * stateless server (the runtime's recommended default). * - `'reuse'` — one session per CLIENT: each `mcpClient` built on this * transport keeps its own runtime session for its life. **Build one * client per conversation**: a client shared by two users is one * session — one microVM, one server state — for both. */ readonly session?: AgentCoreRuntimeSession; /** * Retry AgentCore's "session operation in progress" refusal — the MCP * contract's HTTP 200 with JSON-RPC -32005, or the API's 409 * `RetryableConflictException`. `false` lets the refusal through on the * first attempt. * * On by default, set by its MINIMUM total wait: AgentCore can take about * 2.5 s, and up to about 3.4 s, to bring a runtime session up, and refuses * every request until it has. Up to 5 attempts, waiting 500 ms doubling with * equal jitter — 250–500 ms, 500–1000 ms, 1–2 s, 2–4 s — is 3.75 s of waiting * at the shortest draw and 7.5 s at the longest, inside the 10 s ceiling on * waiting (`maxWaitMs`). No deadline (`maxElapsedMs`) and no cap on the * scheduled wait (`maxDelayMs`) unless you set them. * * These are the call's overall limits. Under `mcpClient`, its 429 retry * joins this retry's series rather than wrapping it, so a call makes at most * `maxAttempts` requests whichever refusals it meets, and `retryOnThrottle`'s * own values limit only the 429 retries inside that. A 5xx, a dropped * connection or any other JSON-RPC error (throttling's -32003 included) is * delivered as it is — it may be the record of work that ran. */ readonly retry?: boolean | AgentCoreRuntimeRetryOptions; /** * SigV4 only: a `BedrockAgentCoreClient` you built, so its credentials, * region and retry settings are the ones used. Refused with `{ bearer }`. * * **Build it with `maxAttempts: 1`.** The client this transport builds has * the SDK's own retry off, because the SDK's standard policy re-sends a call * after a 5xx or a dropped connection — work that may already have run. Your * client keeps whatever policy you gave it. */ readonly client?: AgentCoreRuntimeSdkClient; /** * SigV4 only: the `@aws-sdk/client-bedrock-agentcore` module, imported by * YOU. Refused with `{ bearer }`, which loads no AWS SDK. * * Without it the transport loads the SDK itself through a lazy `require`, * which a bundler (esbuild, webpack) cannot follow. Pass it when your app is * bundled, so the bundler sees a static import: import * `BedrockAgentCoreClient` and `InvokeAgentRuntimeCommand` from * `@aws-sdk/client-bedrock-agentcore` and pass * `sdk: { BedrockAgentCoreClient, InvokeAgentRuntimeCommand }` (named * imports let the bundler drop the rest of the client). * * The transport still builds its own client from it, with the SDK's retry * off. Either way the SDK is read when the transport is built, so a missing * one is refused there, not at the first tool call. */ readonly sdk?: BedrockAgentCoreRuntimeSdkModule; /** * @deprecated Use {@link AgentCoreRuntimeMcpTransportOptions.sdk}. Kept * because it shipped in the published options type; it means exactly `sdk`, * and passing both with different modules is refused. */ readonly _sdk?: BedrockAgentCoreRuntimeSdkModule; } /** * The session-busy retry's defaults, chosen by their MINIMUM total wait. * AgentCore can take about 2.5 s, and up to about 3.4 s, to bring a runtime * session up. 500 ms doubling with equal jitter over 5 attempts waits * 250 + 500 + 1000 + 2000 = 3750 ms at the shortest draw and * 500 + 1000 + 2000 + 4000 = 7500 ms at the longest: the slowest start is * covered on every draw, and the longest stays inside the 10 s ceiling on * waiting, so the ceiling never cuts the schedule short. */ export declare const SESSION_BUSY_RETRY_DEFAULTS: RetryDefaults; /** * An MCP transport for a server hosted on AgentCore Runtime. * * @throws when the runtime or region is missing, when a strategy is unknown, * when `client` or `sdk` is given beside `{ bearer }`, or — for `'sigv4'` — * when the AWS SDK peer dependency cannot be loaded and no `sdk` was passed. * All of these are thrown here, when the transport is built, never at the * first call. */ export declare function agentCoreRuntimeMcpTransport(options: AgentCoreRuntimeMcpTransportOptions): McpHttpTransport; /** Where a runtime's MCP endpoint is, as {@link agentCoreRuntimeUrl} needs it. */ export interface AgentCoreRuntimeUrlOptions { readonly agentRuntimeArn: string; readonly region: string; readonly qualifier?: string; readonly accountId?: string; } /** * The HTTPS endpoint of a runtime's MCP server: * `https://bedrock-agentcore.{region}.amazonaws.com/runtimes/{url-encoded ARN}/invocations`, * with `qualifier` / `accountId` as query parameters when given — the request * line of `InvokeAgentRuntime`, and the URL AgentCore's own MCP examples dial. * * @throws when `agentRuntimeArn` or `region` is missing, or the region is not * shaped like one (it becomes part of a hostname). */ export declare function agentCoreRuntimeUrl(options: AgentCoreRuntimeUrlOptions): string;