/**
 * The MODEL seat: how a task names a model (`ModelRef`), the roles a deployment binds models to
 * (`ModelRole` / `RoleSpec` / `ModelRoles`), and the provider seat a ref resolves to (`Brain`). Layer 0
 * vocabulary beside `terminal-cause.ts` and `gate-outcome.ts` — no import above this layer, so any
 * module may read the words. `types.ts` re-exports every name below, so no consumer's import changes.
 */
import type { ThinkingLevel } from "../internal/harness.js";
import type { CompleteSimpleFn, Model, StreamFn } from "../internal/llm.js";
/** A model reference: either a fully-formed Model, or a `"provider/id"` ref resolved via a catalog. */
export type ModelRef = string | Model;
/**
 * Logical model roles, so a deployment declares its models once and every subsystem asks for its
 * role instead of repeating a model name. Resolved against `RunnerDeps.roles` / `TaskSpec.roles`
 * with a fallback chain (e.g. `summarize → default`, `classifier → summarize → default`). A key or a
 * `modelRole` value outside this vocabulary is refused by name (`config.unknown_role`), never ignored.
 * - `default` — the main task model when `TaskSpec.model` is omitted.
 * - `summarize` — between-turn compaction/summarization. Absent = the MAIN task model, which is the
 *   correct default baseline: the summary request FORKS the main conversation's already-paid
 *   prompt-cache prefix (design/169-A CC form — same system prompt, same message prefix, one
 *   appended instruction), so the marginal cost is a cache read plus one summary's output, not a
 *   full-price re-prefill. Configuring a separate cheap model here is an explicit deployment
 *   tradeoff (quality for price): an independent model cannot share the main prefix, so it pays the
 *   full independent-request serialization every boundary AND summarizes with a weaker model.
 * - `subagent` — delegated sub-runs (`createSubagentTool` without an explicit model).
 * - `verifier` — the verification gate's verifier leg (falls back to `default`).
 * - `classifier` — the auto-mode permission classifier (a roster-cheap tier; falls back
 *   `summarize → default`, tier default `flash` on tier-expanded catalogs).
 * - `consolidate` — the memory-consolidation distillation driver (design/376). Falls back to
 *   `summarize` and then REFUSES LOUDLY — deliberately never to `default`: one consolidation run
 *   is a whole-library read (~10⁵ prompt tokens), so silently escalating to the most expensive
 *   main-task model is the bad-value-silence family, not a convenience. The divergence from the
 *   classifier family's `→ default` tail is calibrated on call volume: a classifier resolves one
 *   short classification, this role resolves a full-library batch. An explicit
 *   `roles.consolidate = <main model>` is a legal deployment choice; the summarize hop is kept
 *   because a deployment that declared a cheap summarize tier has already made the cost choice
 *   this role wants (note the summarize DEFAULT rationale — prompt-cache forking — does not
 *   apply here: consolidation is an offline independent request with no shared prefix).
 */
export declare const MODEL_ROLES: readonly ["default", "summarize", "subagent", "verifier", "classifier", "consolidate"];
/** The role vocabulary, derived from {@link MODEL_ROLES} — one source; a consumer that needs the members at
 *  runtime (a settings schema, a parity pin, a doctor line) reads the tuple instead of transcribing it. */
export type ModelRole = (typeof MODEL_ROLES)[number];
/**
 * A role's model: a `ModelRef`, or a config object that pins a `model`, **selects** one by
 * capability/price (`select`, design/11 Layer 2), and/or sets a default `thinking` level.
 */
export type RoleSpec = ModelRef | {
    model?: ModelRef;
    select?: import("./select-model.js").ModelCriteria;
    thinking?: ThinkingLevel;
    /**
     * Optional preset system prompt for this role (e.g. {@link CODE_AGENT_PROMPT} for a dev role).
     * Used only when the task does not supply its own `TaskSpec.systemPrompt`. Lets coding roles run
     * a coding prompt while other roles keep the neutral default — without touching the global default.
     */
    systemPrompt?: string;
};
/** Map of role → model. `TaskSpec.roles` overrides `RunnerDeps.roles` per task/scenario. */
export type ModelRoles = Partial<Record<ModelRole, RoleSpec>>;
/** The "external brain": a streaming completion function plus a non-streaming one (auto-derived if omitted). */
export interface Brain {
    /** Streaming completion. Must follow the AssistantMessageEvent stream contract (never throw post-invocation).
     *
     * NOTE: the return type is a union — `Stream | Promise<Stream>`. Third-party direct callers must
     * normalize first (`const s = await brain.stream(...)`) before iterating or reading `.result()`,
     * otherwise TS reports TS2339 on the union. The Runner already handles this internally. */
    stream: StreamFn;
    /**
     * Optional non-streaming completion used by compaction/summarization.
     * If omitted, it is derived from `stream` by consuming the stream to its final result.
     *
     * This is exactly the runtime's `completeSimple` type: the engine forwards the value you supply
     * as-is, with no adapting wrapper in between.
     *
     * CONTRACT BEYOND WHAT THE TYPE STATES — every field named here is OPTIONAL on
     * {@link AssistantMessage}, so a message rebuilt from a field whitelist still typechecks while
     * silently disabling recovery:
     * - return the AssistantMessage with ALL fields intact, in particular `errorKind` (the compaction
     *   summary path keys its budget-escalation recovery on it) and `errorMessage`;
     * - honor `options.signal` — the summary call runs under a soft deadline that aborts through it;
     * - honor `options.maxTokens` — that is the escalating budget the recovery re-issues the call with.
     */
    complete?: CompleteSimpleFn;
    /**
     * Optional key↔URL pairing judge (see `src/brain/route-adjudicator.ts` for the law). Answers, for a
     * model this brain would serve, whether the credential the request would carry belongs to the URL
     * it would target — WITHOUT sending anything. `perModelAuth` is the caller's already-resolved
     * per-model auth (the `getApiKeyAndHeaders` result), so a resolution seat can pre-flight the exact
     * request it is about to make. First-party brains implement it against their own config; the
     * decorators (routing/failover/degrading/circuit-breaker) re-dispatch it the way their `stream`
     * would. `undefined` = this brain cannot judge (a custom brain without the face) — callers must
     * treat that as "no judgment", never as OK or as broken. A refusal is an `ok: false` verdict, never a
     * throw (the first-party faces include the per-call key handed beside its lane's own key header,
     * `route.credential_answer_conflict`); a throw from this face is a defect — an advisory pre-flight
     * abstains on it, and a failover chain's face lets it escape.
     *
     * The same law runs again inside the first-party brains' request build (single source, called
     * twice): a broken pairing that skips the pre-flight still refuses loudly at the request instead
     * of sending a credential to a host it is not paired with.
     */
    adjudicateRoute?: (model: Model, perModelAuth?: {
        apiKey?: string;
        headers?: Record<string, string>;
    }) => import("../internal/llm.js").RouteAdjudication | undefined;
}
