agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
98 lines (97 loc) • 5.94 kB
TypeScript
/**
* sessionBusy — the retry strategy: AgentCore Runtime's "session operation in
* progress", recognised. One small function, on purpose.
*
* ── What the service says, in its own words ──────────────────────────────────
* The AgentCore Runtime MCP protocol contract maps the runtime's exceptions onto
* JSON-RPC errors, and exactly one of them is retryable by design:
*
* -32005 RetryableConflictException HTTP 200 "Session operation in progress, please retry"
*
* returned "when a second operation targets a session while the service is
* provisioning or tearing down that session. Because MCP returns HTTP 200 with
* the error in the JSON-RPC body, the caller must inspect the response body and
* retry with short exponential backoff — MCP clients do not auto-retry it."
*
* So no status code says it, and the MCP SDK will not wait for it: left alone,
* it reaches the model as a failed tool call, a moment after the session it was
* waiting for came up.
*
* ── What asking again relies on ──────────────────────────────────────────────
* AWS's contract returns this refusal while the service is provisioning or
* tearing down the session: the PLATFORM's answer, about the session, not the
* MCP server's. The retry series relies on that, as it relies on a 429 being a
* rejection before execution: an assumption with a basis, not proof that
* nothing ran (see `mcp/throttleRetry.ts` · `RetryDecision`). The adapter
* retries it as its OWN policy ({@link SESSION_BUSY_ASSUMES}): each repeat
* records that assumption (`permission: { by: 'adapter', assumes }`), and every
* attempt's effect stays `unknown` (`mcp/replay.ts`).
*
* ── The known limit ──────────────────────────────────────────────────────────
* The HTTP 200 form is matched by its code and message, so a server behind the
* runtime can raise the same error itself — after it ran the call — and the
* match cannot tell the two apart. Neither AWS page says a matching body ran
* nothing. That is why the record never says so; the 409 form carries the
* platform's own `x-amzn-errortype`.
*
* ── What it must NOT match ───────────────────────────────────────────────────
* `ConflictException` shares the code -32005 ("Resource conflict - Resource
* already exists") and is not retryable; the contract tells the two apart only
* by the message, so the message is part of the match. Anything else — another
* status, an SSE stream, a batch reply, a body that is not JSON — is delivered
* as it is.
*
* ── The API-layer form ───────────────────────────────────────────────────────
* `InvokeAgentRuntime`'s API reference gives the same exception as an HTTP 409,
* its type in the `x-amzn-errortype` header (the REST protocol's error-type
* header; the SigV4 strategy rebuilds exactly that from the SDK's exception,
* because the transport's SDK client has its own retry off). It is the same
* refusal, so it is the same decision — matched by the type, never by the 409
* alone.
*
* Pattern: Strategy (a `RetryDecision`). Role: outer ring, vendor fact.
*/
import type { RetryVerdict } from '../../../mcp/throttleRetry.js';
/**
* What the adapter assumes in retrying this refusal as its own policy: that
* the platform refused the request before running it. Attached to the
* session-busy retry rule (`transport.ts`) and recorded beside each repeat —
* an assumption, never evidence.
*/
export declare const SESSION_BUSY_ASSUMES: "refused-before-execution";
/**
* Where AgentCore documents the refusal this file recognises, in both forms —
* the basis of the adapter's retry policy. Neither page says that a matching
* reply ran nothing, so the record never does:
*
* 1. The AgentCore Runtime MCP protocol contract, "Error handling": the row
* `-32005 · RetryableConflictException · HTTP 200 · "Session operation in
* progress, please retry"`, returned "when a second operation targets a
* session while the service is provisioning or tearing down that session".
* 2. The `InvokeAgentRuntime` API reference, "Errors":
* `RetryableConflictException`, HTTP 409 — "a temporary condition that may
* resolve itself with retries".
*/
export declare const SESSION_BUSY_DOCUMENTATION: readonly string[];
/** The JSON-RPC error code the contract gives `RetryableConflictException`. */
export declare const SESSION_BUSY_CODE = -32005;
/**
* Is this response AgentCore Runtime's session-busy refusal — in either form:
* the MCP contract's HTTP 200 with JSON-RPC -32005, or the API's 409
* `RetryableConflictException`?
*
* Reads a CLONE of the body, so the response is delivered intact either way.
* Answers `{}` (wait the loop's own backoff, then send the same request again)
* or `undefined` (deliver it).
*
* `signal` is the request's: when it fires mid-read (the call's deadline, the
* caller's cancellation), the clone's read is cancelled and released, and this
* rejects with the abort — a stalled body never leaves a reader behind.
*/
export declare function sessionBusy(response: Response, signal?: AbortSignal): Promise<RetryVerdict | undefined>;
/**
* The match itself, over a parsed body: ONE JSON-RPC reply whose error carries
* the contract's code and message. A batch is never retried whole — some of
* its replies may be the record of work that ran.
*/
export declare function isSessionBusyReply(body: unknown): boolean;