/** * Cross-environment executor adapter for the Anthropic Messages API. * * @module @nhtio/adk/batteries/llm/anthropic_messages/adapter * * @remarks * Native Anthropic Messages adapter targeting `client.messages.create` from `@anthropic-ai/sdk` * (a hard static dependency of this battery). Node-first: an Anthropic API key in a browser * bundle is unacceptably exposed, so browser is deliberately not a target or gate for this * adapter — `dangerouslyAllowBrowser` exists only for the caller who accepts that risk knowingly. * * Structurally a sibling of the native Ollama and OpenAI Chat Completions adapters, with the * Anthropic-wire divergences: * * - Transport: the Anthropic SDK owns the HTTP call (`client.messages.create`), not raw `fetch`. * ADK owns retry (`maxRetries: 0` on the client) and timeout (`requestTimeoutMs` fences an * internal `AbortController` linked with `ctx.abortSignal`; when `requestTimeoutMs` is `0` a * large explicit sentinel is set on the SDK client so the SDK's own silent 10-minute default is * never silently inherited). * - Streaming: `Stream` — an `AsyncIterable` the SDK already filters `ping` * frames out of; a mid-stream provider error surfaces as a **thrown `APIError`** from `for * await` iteration, not a discriminated event variant, so the consumption loop is wrapped in a * `try`/`catch`. * - Content-block state machine keyed by `index`: `content_block_start` carries the ONLY * occurrence of a `tool_use` block's `id`/`name` and a `redacted_thinking` block's `data`; * `content_block_delta` carries five delta variants (`text_delta`, `thinking_delta`, * `signature_delta`, `input_json_delta`, `citations_delta` — the last is out of scope for v1 and * is a no-op); `content_block_stop` finalizes only that index. `message_stop` is not trusted to * arrive; finalization is reachable from stream EOF too. * - Stop reasons: all seven (`end_turn`, `max_tokens`, `stop_sequence`, `tool_use`, `pause_turn`, * `refusal`, `model_context_window_exceeded`) are handled explicitly — `refusal` is a real * terminal HTTP-200 outcome (never mistaken for an error), `model_context_window_exceeded` maps * to `E_ANTHROPIC_MESSAGES_CONTEXT_OVERFLOW`. * - Error translation: typed SDK error classes (`BadRequestError`, `AuthenticationError`, * `PermissionDeniedError`, `NotFoundError`, `ConflictError`, `UnprocessableEntityError`, * `RateLimitError`, `InternalServerError`, `APIConnectionTimeoutError`, `APIConnectionError`, * `APIUserAbortError`, generic `APIError`) are narrowed and mapped to ADK exceptions. Context * overflow arrives as a 400 `BadRequestError` and is detected from body text (`prompt is too * long`), not status. A real upstream 529 `overloaded_error` is retriable * (`E_ANTHROPIC_MESSAGES_HTTP_ERROR`) — never routed into the fatal same-numbered * adapter-side exceptions, which use 529 as their own unrelated status code. * - Thinking persistence: signed `thinking` blocks persist as a `Thought` carrying a * `{variant:'thinking', thinking, signature, prefixFingerprint}` payload; `redacted_thinking` * blocks carry `{variant:'redacted_thinking', data, prefixFingerprint}`. The fingerprint is * computed via the exported `fingerprintAnthropicMessagesPrefix` helper — never reimplemented. * - No request repair: a `tool_choice` that appears not to have been honored (forces a name the * response never calls) only warns via `helpers.log.warn` — `AnthropicMessagesAdapterOptions` * has no `strictToolChoice` escape hatch, consistent with the "warn loudly, send anyway" ethos. * * Per-iteration flow (steps 1–9 of the plan): * 1. Merge constructor / executor / stash options and re-validate. * 2. Resolve helpers, falling back to bundled `default*` for each unset field. * 3. Artifact-reader tools: pre-forged onto `ctx.tools` by the DispatchRunner core; read as-is. * 4. Pre-render every persisted tool-call result into an Anthropic tool-result content block. * 5. When `tokenEncoding !== null`, sum the token weight of every persisted bucket and throw * {@link @nhtio/adk/batteries!E_ANTHROPIC_MESSAGES_CONTEXT_OVERFLOW} when the total exceeds `contextWindow`. * 6. Build the request via `buildAnthropicMessagesHistory`. * 7. Call `client.messages.create` with retry/timeout ownership; classify and translate errors. * 8. Streaming path: content-block state machine + usage latching + stop-reason handling. * 9. Non-streaming path: same persistence + tool-execution loop, from a single `Message`. */ import type { AnthropicMessagesCountTokensRequestInput } from "./count_tokens"; import type { DispatchExecutorFn } from "../../../dispatch_runner"; import type { AnthropicMessagesAdapterOptions, AnthropicMessagesCountTokensInput } from "./types"; /** * Opinionated cross-environment LLM adapter for the Anthropic Messages wire shape. * * @remarks * Construction validates options eagerly via {@link validateOptions} and throws * {@link @nhtio/adk/batteries/llm/anthropic_messages!E_INVALID_ANTHROPIC_MESSAGES_OPTIONS} on * failure. The returned instance is reusable: call {@link AnthropicMessagesAdapter.executor} once * per `DispatchRunner` configuration to obtain a {@link @nhtio/adk!DispatchExecutorFn} bound to * the baseline plus optional executor-scope overrides. Per-iteration overrides live on * `ctx.stash.anthropicMessages` and take highest precedence; `headers`, `helpers`, and `retry` * merge key-by-key across all three layers, every other field is replaced wholesale at the * highest layer that sets it. Node-first: browser is explicitly not a target — an Anthropic API * key in a browser bundle is unacceptably exposed. */ export declare class AnthropicMessagesAdapter { #private; /** Customary key for per-iteration overrides on `ctx.stash`. */ static readonly STASH_KEY: "anthropicMessages"; /** * @param options - Constructor-baseline options. Re-validated on every iteration after * per-dispatch and per-iteration overrides are layered in. * @throws {@link @nhtio/adk/batteries/llm/anthropic_messages!E_INVALID_ANTHROPIC_MESSAGES_OPTIONS} when `options` does not satisfy `anthropicMessagesOptionsSchema`. */ constructor(options: unknown); /** * Returns a {@link @nhtio/adk!DispatchExecutorFn} bound to this adapter's baseline plus optional * executor-scope overrides. * * @param overrides - Optional executor-scope overrides. Higher precedence than the baseline, * lower precedence than `ctx.stash[STASH_KEY]`. */ executor(overrides?: Partial): DispatchExecutorFn; /** * Counts the input tokens a request would consume, without generating. * * Uses Anthropic's dedicated count-tokens surface (a distinct parameter shape from a create * request, and one that takes no `maxTokens`), and returns a named field plus the raw upstream * body rather than leaking the vendor type through this battery's public API. * * `input` accepts either a dispatch context — whose prompt is assembled with the same helpers the * executor uses — or a pre-built Anthropic-shaped request. Option precedence, revalidation, * timeout ownership, and error translation all match {@link AnthropicMessagesAdapter.executor}. */ countTokens(input: AnthropicMessagesCountTokensRequestInput | AnthropicMessagesCountTokensInput, overrides?: Partial): Promise<{ inputTokens: number; raw: unknown; }>; /** * Returns `true` when `value` is an {@link AnthropicMessagesAdapter} instance. */ static isAnthropicMessagesAdapter(value: unknown): value is AnthropicMessagesAdapter; }