/** OpenAI request-body keys core owns; `extraBody` cannot override these. */
export declare const OPENAI_RESERVED: ReadonlySet<string>;
/** Anthropic request-body keys core owns; `extraBody` cannot override these. (Note the asymmetry vs
 *  OpenAI — e.g. `stop`/`stop_sequences` is NOT reserved here because the Anthropic brain never sets it.) */
export declare const ANTHROPIC_RESERVED: ReadonlySet<string>;
/**
 * Open Responses request-body keys core owns; `extraBody` cannot override these (design/163).
 *
 * The last three are NOT keys the adapter sets — they are keys it must be IMPOSSIBLE to set. The
 * Open Responses lane is stateless by contract (this engine is the transcript authority), and
 * `extraBody` is the only other path to the request body, so `store` / `previous_response_id` /
 * `conversation` are reserved purely to close it. A deployment that sets one gets a stripped key on the
 * wire and the drop announced, never a silently server-linked turn.
 */
export declare const RESPONSES_RESERVED: ReadonlySet<string>;
/**
 * Merge `extraBody` into a brain's already-built request `body`, dropping any key the brain owns so core
 * always wins. `body` is a NEW object (passthrough keys first, then core keys) when `extraBody` is set; the
 * exact `body` reference (no allocation, byte-identical serialization) when it isn't — so an existing
 * deployment with no `extraBody` is unaffected.
 *
 * `dropped` is the keys of `extraBody` that were stripped, in `extraBody`'s insertion order, names only (a
 * value never leaves this function except inside `body`). It is a property of the same walk that strips, so
 * what is said and what is dropped cannot disagree; empty when nothing was stripped.
 */
export declare function applyExtraBody(body: Record<string, unknown>, extraBody: Record<string, unknown> | undefined, reserved: ReadonlySet<string>): {
    body: Record<string, unknown>;
    dropped: readonly string[];
};
/**
 * #343 — the shared USER-HEADER merge layer (`model.headers` → construction `config.headers` →
 * per-call `options.headers`, later bag wins), CASE-FOLD deduplicated: HTTP header field names are
 * case-insensitive (RFC 9110), but a plain-object spread keys by exact spelling, so an `X-Tenant`
 * in one bag and an `x-tenant` in another both reach the wire, where fetch's Headers folds them
 * into one comma-joined value ("a, b") — neither writer's value, the later layer's documented
 * override silently defeated. A later bag's entry replaces an earlier case-variant instead; the
 * WINNER'S spelling and value survive (a single-spelling config is byte-identical on the wire).
 *
 * EXEMPT: the credential headers ({@link isCredentialHeaderName}, the engine's one reading of which
 * header carries a credential: `authorization`, `x-api-key`, `api-key`, `cookie`, …, any case) pass
 * through with plain spread semantics (same-spelling override only, no case-fold dedup), so that the
 * credential enforcement (`applyRouteCredentialHeaders`, route-adjudicator.ts) stays the ONE authority
 * over credential spelling and this layer never becomes a second, subtly different one.
 *
 * The exemption is NOT what keeps a header-only `ANTHROPIC_AUTH_TOKEN` alive: dedup keeps the
 * winner's spelling, a lone `Authorization` has nothing to dedup against, and the credential
 * enforcement already deletes every spelling present when a per-model credential wins. What the
 * exemption really costs is measured, not reasoned:
 * `mergeHeaders({Authorization:A},{authorization:B})` keeps BOTH, and the platform `Headers` fold
 * sends `authorization: A, B`.
 *
 * STATED RESIDUAL (deliberately not fixed here), NARROWED by the credential enforcement: where a
 * PER-MODEL credential wins (an options- or entry-bag carrier), every carrier is stripped and only
 * the winning bag's re-asserted, so a cross-layer double spelling now folds to the winner. What
 * remains is the DEPLOYMENT-CONFIG arm — its bytes ride untouched by design — so a config bag that
 * itself spells the SAME auth carrier two ways still ships both, comma-folded. Held, not denied, on
 * severity: no server accepts a comma-joined credential, so that failure is a LOUD 401 attributable
 * to the misconfiguration, while the non-auth case this function exists for produces a silently
 * WRONG value (`X-Tenant: a, b`). Tightening it changes which credential reaches the wire, so it
 * belongs in a window that discloses an auth-face behavior change.
 */
/**
 * #343 — assign a STRUCTURAL locked header under its canonical lowercase name, deleting every
 * case-variant spelling first. The brains hard-lock `content-type` / `anthropic-version` AFTER the
 * user-bag merge precisely so they "can NEVER be overridden" (council design/40) — and without the
 * delete a user bag carrying `Content-Type: text/plain` survives BESIDE the lowercase lock, the
 * platform `Headers` fold turning the pair into `text/plain, application/json` on the wire: a lock
 * that decides nothing. WHICH credential headers ride is the jurisdiction of `applyRouteCredentialHeaders`
 * (route-adjudicator.ts); the key header a brain writes after it (`authorization` / `x-api-key`, from the
 * apiKey knob) is a lock like any other — one value per name, whatever spelling a bag carried.
 */
export declare function lockHeader(headers: Record<string, string>, lowerName: string, value: string): void;
/**
 * #343 (review r4) — case-fold READ-AND-CLAIM for an AUGMENTABLE structural header (`anthropic-beta`):
 * returns the current value under whatever spelling the user bag carried and deletes that spelling,
 * so the caller's canonical lowercase write REPLACES it instead of duplicating beside it (the
 * read-modify-write used to key the read by the exact lowercase name and miss `Anthropic-Beta`,
 * losing the user's betas from the merge AND double-sending the header).
 */
export declare function takeHeaderCasefold(headers: Record<string, string>, lowerName: string): string | undefined;
/** A caller's header bag read ONCE, into a plain copy of its own enumerable entries — what a request build hands both
 *  the route law (which credential rides, and its identity) and the merge (what goes on the wire), so a bag whose getters
 *  or keys answer differently on a second read cannot be judged as one bag and sent as another. */
export declare function headerBagOnce(bag: Readonly<Record<string, string>> | undefined): Record<string, string> | undefined;
export declare function mergeHeaders(...bags: Array<Record<string, string> | undefined>): Record<string, string>;
/**
 * The output-cap key(s) each lane's wire form uses. A lane's set is exactly the keys THAT lane's
 * endpoint reads — a stray cap key belonging to another wire form is inert there and must not be
 * mistaken for a bound this request carries.
 */
export declare const OUTPUT_CAP_KEYS: Readonly<Record<"openai" | "anthropic" | "responses", readonly string[]>>;
/**
 * The per-request output cap a FINAL (post-`extraBody`) request body actually carries — the SMALLEST
 * of the lane's cap keys that is present and usable, or `undefined` when none is.
 *
 * Read off the merged body rather than off the knob the adapter set, because those are not the same
 * thing: `extraBody` can contribute a cap under a spelling the adapter did not choose, and a
 * consumer that treats the adapter's own number as "the cap on the wire" would be wrong about a
 * request that carries two. Smallest wins so a consumer reasoning about the bound stays conservative.
 */
export declare function effectiveOutputCap(body: Record<string, unknown>, keys: readonly string[]): number | undefined;
