UNPKG

agentfootprint

Version:

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

138 lines (137 loc) • 8.32 kB
/** * invoke — the SigV4 auth strategy: Streamable HTTP, carried by the AWS SDK's * `InvokeAgentRuntime`. * * The MCP client speaks HTTP — a POST, a few headers, a JSON body — and the SDK * operation carries exactly that, field for field. This file is the mapping and * nothing else. Every name in it is the SDK's own (`InvokeAgentRuntimeRequest` * / `InvokeAgentRuntimeResponse` in `@aws-sdk/client-bedrock-agentcore`), read * off an installed package rather than recalled: * * request InvokeAgentRuntimeRequest * ───────────────────────────────────────────── ──────────────────────── * body payload (bytes) * content-type contentType * accept accept * mcp-session-id mcpSessionId * mcp-protocol-version mcpProtocolVersion * x-amzn-bedrock-agentcore-runtime-session-id runtimeSessionId * (the runtime, from options) agentRuntimeArn, qualifier, accountId * * InvokeAgentRuntimeResponse response * ───────────────────────────────────────────── ──────────────────────── * statusCode status * contentType content-type * mcpSessionId mcp-session-id * mcpProtocolVersion mcp-protocol-version * runtimeSessionId x-amzn-bedrock-agentcore-runtime-session-id * response (a stream) body * * The signature is the SDK's: `send` signs every attempt with the client's own * credentials, so no credential passes through this file. * * ── The SDK's own retry is OFF ─────────────────────────────────────────────── * The client built here has `maxAttempts: 1`. The SDK's standard policy would * re-send a `tools/call` after a 5xx or a dropped connection — a call that may * already have run, in the same pinned session — which a retry here must never * do on its own. Every retry goes through the transport's single loop instead, * which repeats only what the replay rule permits (`mcp/replay.ts`): the * refusals its retry policy recognises — the session-busy reply and a 429, each * assumed, not proven, to have run nothing — and a dropped connection only when * the app declared that for the tool. A `client` you pass keeps ITS policy: * build it with `maxAttempts: 1` for the same guarantee. * * ── A service exception is an ANSWER ───────────────────────────────────────── * When the service answers with a non-2xx status, the SDK throws instead of * returning — `RetryableConflictException` (409), `ThrottlingException` (429), * or a hosted server's own 404 as `Unknown`. Each is handed on as the `Response` * an HTTPS caller would have read: its status, its error type in * `x-amzn-errortype`, `retry-after` when the service sent one, and as the body * the server's own JSON-RPC error when it sent one (the SDK spreads a body it * cannot model onto the exception) — never the exception's message, which can * quote the signed request. What the MCP client may read of it is decided * once, by `safeAnswer.ts`. So the transport's retry decision sees the 409, * `mcpClient`'s 429 retry sees the 429, and the MCP client reports the * status. A failure with no status — the * network, an abort — never reached the service as an answer, and is thrown as * it is. * * ── What the operation cannot carry ────────────────────────────────────────── * Any method but POST. A GET (the optional server-message stream) and a DELETE * are answered HERE with 405, which the MCP Streamable HTTP spec defines as "not * offered" for both, so the MCP client carries on. And any header the operation * does not model — it has no field to put one in. A `'reuse'` connection's * DELETE never reaches this far: the session strategy turns it into a stop * (`STOP_RUNTIME_SESSION`), sent as `StopRuntimeSessionCommand`. * * ── The send gate runs after signing ───────────────────────────────────────── * A request the MCP client pool sent carries its send gate (`mcp/requestGuard.ts`). * Signing is asynchronous work inside the AWS SDK's `send`, so the gate is a * step on each COMMAND's own middleware stack, after the request is signed and * before the request handler sends it — never on the client's stack, so an AWS * client the app passed is not changed. A command with no stack (a double) has * the gate asked just before `send`, as every command also does. * * Pattern: Adapter (fetch ↔ command). Role: outer ring, lazy AWS peer dep. */ import type { ThrottleFetch } from '../../../mcp/throttleRetry.js'; /** A command-based SDK client — `send` is the only member this strategy uses. */ export interface AgentCoreRuntimeSdkClient { send(command: unknown, options?: { abortSignal?: AbortSignal; }): Promise<unknown>; } /** The slice of `@aws-sdk/client-bedrock-agentcore` this strategy touches. */ export interface BedrockAgentCoreRuntimeSdkModule { readonly BedrockAgentCoreClient?: new (config: { region?: string; maxAttempts?: number; }) => AgentCoreRuntimeSdkClient; readonly InvokeAgentRuntimeCommand?: new (input: unknown) => unknown; /** Needed under `session: 'reuse'`, where ending a client stops its runtime session. */ readonly StopRuntimeSessionCommand?: new (input: unknown) => unknown; } /** * @internal The `init` key a `'reuse'` connection's stop rides under: the * runtime session id to stop (`transport.ts` · `stopSession`). A symbol, so no * request the MCP client makes can ever claim it. */ export declare const STOP_RUNTIME_SESSION: unique symbol; /** Which runtime every request goes to, as the operation names it. */ export interface InvokeTarget { readonly agentRuntimeArn: string; readonly qualifier?: string; readonly accountId?: string; } /** What the strategy is built from: a region, and optionally what was injected. */ export interface InvokeSdkOptions { readonly region: string; /** * A client the caller built — its credentials, region and retry settings win, * so build it with `maxAttempts: 1` (see the module note). */ readonly client?: AgentCoreRuntimeSdkClient; /** The SDK module the caller imported; otherwise the peer dep is loaded. */ readonly sdk?: BedrockAgentCoreRuntimeSdkModule; } /** * The client and the command constructor this strategy sends with. * * Loaded when the transport is BUILT, not at the first call, so a missing peer * dependency is refused where the transport is declared rather than mid-run. * * @throws when the SDK cannot be loaded, or when it lacks what is needed. */ export declare function invokeSdk(options: InvokeSdkOptions): { readonly client: AgentCoreRuntimeSdkClient; readonly InvokeAgentRuntimeCommand: new (input: unknown) => unknown; readonly StopRuntimeSessionCommand?: new (input: unknown) => unknown; }; /** * A `fetch` that sends each request as one `InvokeAgentRuntimeCommand`. * * The URL the MCP client passes is ignored on purpose: it names the endpoint for * reports and errors, while the invocation goes to `target` — the SDK resolves * the endpoint itself, from the client's region. */ export declare function invokeFetch(target: InvokeTarget, client: AgentCoreRuntimeSdkClient, InvokeAgentRuntimeCommand: new (input: unknown) => unknown, StopRuntimeSessionCommand?: new (input: unknown) => unknown): ThrottleFetch;