/**
 * InvokeModelGatewayProvider — Anthropic models behind a gateway that speaks the
 * Bedrock InvokeModel wire over plain HTTPS with an API-key header.
 *
 * Pattern: Adapter (GoF). Zero peer dependencies — uses `fetch`.
 * Role:    Outer ring. Translates `LLMRequest`/`LLMResponse` to and from the
 *          gateway's wire. Knows nothing about agents, skills or routing.
 *
 * ─── Why this is not `bedrock()` ────────────────────────────────────
 *
 * `bedrock()` drives the AWS SDK: SigV4 credentials against the CONVERSE
 * operation. Many organisations put the models behind their own gateway
 * instead — one that authenticates with an API-key header and forwards the
 * INVOKE operation. Neither the auth nor the operation matches, and
 * `providerFromEnv()` has no base URL for this wire, so until this adapter an
 * app had to write its own (the field case that prompted it was ~450 lines).
 *
 * ─── The wire ───────────────────────────────────────────────────────
 *
 *   POST {baseUrl}/model/{modelId}/invoke                      complete()
 *   POST {baseUrl}/model/{modelId}/invoke-with-response-stream stream()
 *   headers: content-type: application/json, {apiKeyHeader}: <key>
 *
 * The body is Anthropic's Messages API with two differences: the literal
 * `anthropic_version: "bedrock-2023-05-31"`, and NO `model` field — the model
 * is in the path. Everything else (`system` as a top-level field, content
 * blocks, `tools` with `input_schema`, `tool_choice`) is the shape
 * `anthropicMessagesWire.ts` owns.
 *
 * The stream answers SSE (`data: {…}` lines, with or without `event:` lines):
 * the gateway has already decoded AWS's binary event-stream framing, so there
 * is no SDK and no event-stream parser here.
 *
 * ─── Retries are NOT here ───────────────────────────────────────────
 *
 * This adapter makes ONE attempt per call. Every failure it raises is an
 * {@link InvokeModelGatewayError} carrying the two fields `withRetry`'s default
 * predicate reads: `status` on an HTTP refusal (429 and 5xx retried, other 4xx
 * not) and `retryable: false` on every failure that asking again cannot mend —
 * a refusal raised before any request, or a 2xx answer it could not read (a
 * re-send may run and bill the model again). So the default policy retries a
 * 429, a 5xx, a network failure and a timeout, and nothing else. Compose:
 *
 *   withRetry(invokeModelGateway({ ... }))
 *
 * A retry loop inside an adapter is a second policy nobody can see or tune.
 *
 * ─── What this adapter DOES own ─────────────────────────────────────
 *
 * - The stated wait. A throttled gateway says how long to wait — a
 *   `Retry-After` header when it feels like it, and often only in the body
 *   ("Rate limit is exceeded. Try again in 4 seconds."). The wording is this
 *   wire's, so it is read HERE and declared as `retryAfterMs` (header first);
 *   `withRetry` waits max(its schedule, that), capped by its `maxDelayMs`.
 * - The deadline. `timeoutMs` bounds the wait for the response headers, for a
 *   complete() body, and for EACH stream read (the first chunk and every gap
 *   between chunks — a stream that is still talking is never cut off), and
 *   for the response body to close. A miss
 *   aborts the request and raises `reason: 'timeout'`, retryable; the
 *   caller's `req.signal` still wins.
 */
import type { LLMCallHooks, LLMChunk, LLMProvider, LLMRequest, LLMResponse } from '../../provider-contract/types.js';
import type { ThinkingMode } from '../../thinking/types.js';
/** The literal this wire requires in the body in place of a version header. */
export declare const INVOKE_MODEL_ANTHROPIC_VERSION = "bedrock-2023-05-31";
/**
 * Where the key for a call comes from.
 *
 * - a string — one key for every model;
 * - a map from model id to key — for gateways that scope a key to a set of
 *   models (asking with the wrong key answers 403). A model id missing from
 *   the map is refused by name before any request is sent;
 * - a function of the model id — re-read before EVERY request, so a rotated
 *   key is picked up without rebuilding the provider.
 */
export type InvokeModelGatewayKey = string | Readonly<Record<string, string>> | ((modelId: string) => string | undefined | Promise<string | undefined>);
/** Anything `fetch`-shaped — an mTLS agent, a proxy, or a scripted test double. */
export type InvokeModelGatewayFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
export interface InvokeModelGatewayOptions {
    /**
     * The gateway root. Requests go to `{baseUrl}/model/{modelId}/invoke` and
     * `…/invoke-with-response-stream`. A trailing slash is ignored.
     */
    readonly baseUrl: string;
    /**
     * The header the gateway reads the key from, e.g. `'api-key'` or
     * `'x-api-key'`. Required — a guessed default would fail as a 401 that looks
     * like a bad key. For a bearer scheme use `'authorization'` and put
     * `'Bearer …'` in the key.
     */
    readonly apiKeyHeader: string;
    /** The key, a key per model id, or a function of the model id. */
    readonly apiKey: InvokeModelGatewayKey;
    /**
     * The model id the gateway knows, e.g. `'us.anthropic.claude-haiku-4-5-20251001-v1:0'`.
     * Used when `LLMRequest.model` is the shorthand `'invoke-model-gateway'`;
     * any other request model is sent as given.
     */
    readonly model?: string;
    /** Default `max_tokens` when the request sets none. Default 4096. */
    readonly defaultMaxTokens?: number;
    /**
     * May the model ask for several tools in one reply? `false` sends
     * `tool_choice: { type: 'auto', disable_parallel_tool_use: true }`.
     * Omitted sends nothing (the model's default — batching allowed).
     */
    readonly parallelToolCalls?: boolean;
    /**
     * Which thinking request a model takes, for an id the built-in table cannot
     * read — the alias your gateway knows, an application-inference-profile ARN,
     * a provisioned-model ARN. The table reads Bedrock ids
     * (`us.anthropic.claude-…-v1:0`) itself; an id it does not know is read as
     * adaptive (every Claude model since 4.7), so a budget-only model behind an
     * opaque id (Claude 4.5 or earlier) is declared here. Return `undefined` to
     * use the table. The provider declares the result AND sends that shape.
     *
     * @example
     *   invokeModelGateway({ …, model: 'haiku-fast', thinkingMode: (id) => (id === 'haiku-fast' ? 'budget' : undefined) })
     */
    readonly thinkingMode?: (model: string) => ThinkingMode | undefined;
    /** Replace `fetch` — for an mTLS agent, a proxy, or a test. Default: global `fetch`. */
    readonly fetch?: InvokeModelGatewayFetch;
    /**
     * Per-request deadline in ms. Bounds the wait for the response headers, for
     * a complete() body, and for each stream read — the first chunk and every
     * gap between chunks (an idle deadline: a stream that keeps talking is never
     * cut off), and the response body close. A miss aborts the request and raises an
     * {@link InvokeModelGatewayError} with `reason: 'timeout'`, `retryable:
     * true` — `withRetry` asks again only while no chunk has reached the caller.
     * A wrapper of your own that re-sends on `retryable` alone must make the
     * same check: a timeout BETWEEN chunks is also `retryable`, and re-sending
     * then would deliver the start of the answer twice. The caller's `req.signal` still wins. Omitted: no deadline (the default).
     */
    readonly timeoutMs?: number;
}
/** Which failure an {@link InvokeModelGatewayError} is. */
export type InvokeModelGatewayErrorReason = 
/** The options cannot make a request (no base URL, header, or key). */
'invalid-options'
/** The request named no model and the provider has no `model` to fall back to. */
 | 'no-model'
/** No key for this model id — the map lacks it, or the function returned none. */
 | 'no-key'
/** The gateway answered non-2xx. `status` is set; `bodyExcerpt` says why. */
 | 'http-status'
/** The request never got an answer (DNS, TLS, connection reset). */
 | 'network'
/** No answer — headers, body, or the next stream chunk — within `timeoutMs`. */
 | 'timeout'
/** complete() answered 2xx with a body that is not a Messages response. */
 | 'unreadable-response'
/** The stream answered 2xx with no body, sent an error event, or an unreadable event. */
 | 'stream'
/** A tool call's streamed argument JSON did not parse. Refused, never run as `{}`. */
 | 'malformed-tool-args';
/**
 * Every failure `invokeModelGateway()` raises, told in words that name the
 * model and the fix. `reason` is the discriminator.
 *
 * `retryable` is `true` for a 429, a 5xx, a network failure and a timeout, and `false`
 * for every other reason, and `withRetry`'s default predicate honours the
 * `false` — so a refusal raised before any request (`no-key`, `no-model`,
 * `invalid-options`) is never repeated, and a 2xx answer it could not read
 * (`unreadable-response`) is never re-sent to a model that may already have
 * run. `status` is set ONLY for `'http-status'`. The key is never in the
 * message.
 */
export declare class InvokeModelGatewayError extends Error {
    readonly name = "InvokeModelGatewayError";
    readonly reason: InvokeModelGatewayErrorReason;
    /** The model id the call was for, when one was resolved. */
    readonly modelId?: string;
    /** The HTTP status, for `'http-status'` only. */
    readonly status?: number;
    /**
     * Whether asking again can mend it: a 429, a 5xx, a network failure, or a
     * timeout. `withRetry`'s default predicate reads the `false`.
     */
    readonly retryable: boolean;
    /** The gateway's `Retry-After` header, in seconds, when it sent a number. */
    readonly retryAfterSeconds?: number;
    /**
     * The wait the gateway STATED, in ms: its `Retry-After` header (seconds or
     * an HTTP-date) or, when there is none, its body's "try again in N
     * seconds". `withRetry` waits at least this long (capped by `maxDelayMs`).
     */
    readonly retryAfterMs?: number;
    /** The first 400 characters of the gateway's refusal body. */
    readonly bodyExcerpt?: string;
    /** For `'malformed-tool-args'`: the tool whose arguments did not parse. */
    readonly toolName?: string;
    constructor(init: {
        reason: InvokeModelGatewayErrorReason;
        message: string;
        modelId?: string;
        status?: number;
        retryAfterSeconds?: number;
        retryAfterMs?: number;
        bodyExcerpt?: string;
        toolName?: string;
        cause?: unknown;
    });
}
/**
 * An `LLMProvider` for Anthropic models behind a gateway that speaks the
 * Bedrock InvokeModel wire with an API-key header.
 *
 * @example
 * ```ts
 * import { Agent } from 'agentfootprint';
 * import { invokeModelGateway } from 'agentfootprint/providers';
 * import { withRetry } from 'agentfootprint/resilience';
 *
 * const provider = withRetry(
 *   invokeModelGateway({
 *     baseUrl: 'https://llm-gateway.example.com/bedrock',
 *     apiKeyHeader: 'api-key',
 *     apiKey: process.env.GATEWAY_KEY!,
 *     model: 'us.anthropic.claude-haiku-4-5-20251001-v1:0',
 *   }),
 * );
 * const agent = Agent.create({ provider, model: 'invoke-model-gateway' }).build();
 * ```
 */
export declare function invokeModelGateway(options: InvokeModelGatewayOptions): LLMProvider;
/**
 * Class form of {@link invokeModelGateway}, for code that prefers `new`.
 */
export declare class InvokeModelGatewayProvider implements LLMProvider {
    readonly name = "invoke-model-gateway";
    readonly carriesForcedToolChoice = true;
    /** The inner declaration resolves this adapter's shorthand before looking up the model. */
    readonly supportsForcedToolChoice: (model: string) => boolean;
    readonly thinkingHandler: import("../../thinking/types.js").ThinkingHandler;
    /** The inner provider's own function — a closure, safe to forward unbound. */
    readonly thinkingMode: (model: string) => ThinkingMode;
    private readonly inner;
    constructor(options: InvokeModelGatewayOptions);
    complete(req: LLMRequest, hooks?: LLMCallHooks): Promise<LLMResponse>;
    stream(req: LLMRequest, hooks?: LLMCallHooks): AsyncIterable<LLMChunk>;
}
//# sourceMappingURL=InvokeModelGatewayProvider.d.ts.map