/** SDK-owned platform module. This implementation is maintained in goodvibes-sdk. */ /** * Per-model reasoning-effort resolution. * * One place decides what a given model actually accepts for "reasoning * effort", and which request field the adapter must put it on. Four sources, * highest precedence first: * * 1. the live models.dev catalog entry for the exact model id, its * `reasoning_options` array, parsed by {@link parseReasoningOptions}; * 2. a declaration attached to this exact model by whoever configured it, * a plugin manifest, a custom-model file, or the traits of the local * server actually holding the weights; * 3. a curated per-family-generation table for models the live catalog does * not carry (see `reasoning-effort-families.ts`); * 4. a best-guess ladder that says in its own note that it is a guess * rather than verified provider data. * * {@link resolveEffortForModel} maps a requested level onto whatever the * resolved model actually offers. It only ever snaps DOWN the severity * ordering: silently spending more reasoning tokens than the caller asked for * is a cost and latency change they did not consent to. When nothing at or * below the request exists, the level is dropped entirely and the provider's * own default applies, still never a promotion. */ /** Where a resolved spec's information came from. */ export type ReasoningEffortSource = 'catalog' | 'declared' | 'family' | 'fallback'; /** Precedence of a spec source; higher outranks lower. */ export declare function reasoningEffortSourceRank(source: ReasoningEffortSource): number; /** Reasoning levels ordered from least to most reasoning spend. */ export declare const REASONING_EFFORT_SEVERITY: readonly string[]; /** * Thinking-token budget for each level, for providers whose only control is a * token budget (Claude 4.5 and earlier, Gemini 2.5.x). `interface.ts` derives * the legacy four-level `REASONING_BUDGET_MAP` from this table so the two * cannot drift apart. */ export declare const REASONING_EFFORT_BUDGET_TOKENS: Readonly>; interface ReasoningEffortSpecBase { /** Selectable levels for this model, ordered least to most reasoning spend. */ readonly values: readonly string[]; /** The level the provider applies when the field is omitted, when documented. */ readonly defaultValue?: string | undefined; readonly source: ReasoningEffortSource; /** Plain-language caveat shown to the user; always set when source is 'fallback'. */ readonly note?: string | undefined; } /** The model takes a named effort level (`output_config.effort`, `reasoning_effort`, `thinking_level`). */ export interface ReasoningEffortLevelsSpec extends ReasoningEffortSpecBase { readonly kind: 'effort'; } /** The model takes a thinking-token budget (`thinking.budget_tokens`, `thinking_budget`). */ export interface ReasoningEffortBudgetSpec extends ReasoningEffortSpecBase { readonly kind: 'budget_tokens'; readonly minBudgetTokens: number; readonly maxBudgetTokens?: number | undefined; /** * Whether this model can be told not to reason at all. * * Not the same question as `minBudgetTokens === 0`, because the two vendors * express "off" differently: Anthropic omits the `thinking` block entirely * while still documenting a 1024-token floor for an enabled budget, whereas * Gemini sends the budget as a literal number and 2.5 Pro rejects a zero one. * Only when this is true do the zero-budget levels (`none`, `instant`) appear * among the model's offered levels. */ readonly canDisableReasoning: boolean; } /** The model only exposes reasoning on/off, with no depth control. */ export interface ReasoningEffortToggleSpec extends ReasoningEffortSpecBase { readonly kind: 'toggle'; } /** The model reasons at a fixed depth, or does not reason at all, nothing to send. */ export interface ReasoningEffortUnavailableSpec extends ReasoningEffortSpecBase { readonly kind: 'unavailable'; readonly values: readonly []; } /** What a specific model accepts for reasoning effort, and how to send it. */ export type ReasoningEffortSpec = ReasoningEffortLevelsSpec | ReasoningEffortBudgetSpec | ReasoningEffortToggleSpec | ReasoningEffortUnavailableSpec; /** One entry of a models.dev `reasoning_options` array. */ export interface ModelsDevReasoningOption { readonly type?: string | undefined; readonly values?: readonly string[] | undefined; readonly min?: number | undefined; readonly max?: number | undefined; } /** Used when nothing else resolves. Labelled as a guess, never presented as verified. */ export declare const FALLBACK_REASONING_EFFORT_SPEC: ReasoningEffortLevelsSpec; /** The selectable levels of a spec, for surfaces that carry a plain list. */ export declare function reasoningEffortLevels(spec: ReasoningEffortSpec | undefined): readonly string[]; /** * Build a spec from a hand-declared level list. * * The boundary for author-supplied declarations, plugin manifests, custom * model files, which name levels rather than a wire shape. Marked `declared` * because the author is naming the levels of the exact endpoint they * configured: better than both the best-guess ladder and the prefix-matched * family table, and still outranked by the live catalog. */ export declare function reasoningEffortSpecFromLevels(levels: readonly string[] | undefined, source?: ReasoningEffortSource): ReasoningEffortSpec | undefined; /** Position in the severity ordering, or -1 when the level is not a known one. */ export declare function reasoningEffortRank(level: string): number; /** * Read an untrusted `reasoningEffort` field into a level, or undefined when it * is not one. * * The single gate for job and request payloads arriving over HTTP. Hand-written * value lists at those boundaries drift behind the ladder as new levels ship, * a job whose contract-valid policy asked for `xhigh` silently ran at the * model's default, so every such boundary reads through here instead. Which of * these levels a given MODEL accepts is a separate question, settled per model * by {@link resolveEffortForModel} once the job reaches a provider. */ export declare function readReasoningEffortLevel(value: unknown): string | undefined; /** * Levels a token-budget model can express within its documented min/max. * * The zero-budget levels are offered only when the model can genuinely be told * not to reason: Gemini 2.5 Pro documents a 128-token minimum and answers a * zero budget with a 400, so listing `none` for it would offer a level the * model rejects. */ export declare function budgetLevels(min: number, max: number | undefined, canDisableReasoning: boolean): string[]; /** Thinking-token budget for a level under a budget-typed spec, clamped to its range. */ export declare function budgetTokensForLevel(level: string, spec: ReasoningEffortBudgetSpec): number; /** * Parse a models.dev `reasoning_options` array into a spec. * * Returns undefined when the field is absent, that is "the catalog says * nothing", which must fall through to the curated family table, and is a * different statement from an empty array, which says "this model reasons but * exposes no configurable levels" (models.dev publishes exactly that for * `deepseek-reasoner`). */ export declare function parseReasoningOptions(options: readonly ModelsDevReasoningOption[] | undefined): ReasoningEffortSpec | undefined; /** Everything `resolveEffortForModel` needs from a model. */ export interface ReasoningEffortModel { readonly id?: string | undefined; readonly displayName?: string | undefined; readonly reasoningEffort?: ReasoningEffortSpec | undefined; } /** Outcome of mapping a requested level onto one model's real options. */ export interface ResolvedReasoningEffort { /** The level to send, or undefined to omit the field and take the provider default. */ readonly value: string | undefined; /** The spec the decision was made against. */ readonly spec: ReasoningEffortSpec; /** Plain-language explanation, present whenever the answer is not exactly what was asked for. */ readonly note?: string | undefined; } /** Highest available level at or below `requested`; undefined when none exists. */ export declare function snapEffortDown(requested: string, values: readonly string[]): string | undefined; /** * Map a requested reasoning level onto what one model actually accepts. * * Never returns a level above the request: an unavailable request snaps down * to the closest lower level, and when there is none the level is dropped so * the provider applies its own default. */ export declare function resolveEffortForModel(requested: string | undefined, model: ReasoningEffortModel): ResolvedReasoningEffort; /** * A sentence naming the reasoning level as the likely cause of a rejection, * or undefined when the provider's own text does not point that way. * * A 400 already surfaces to the user, it is not in the retryable set, so the * only gap this closes is that the message never named the setting responsible. * Deliberately conservative: it fires only on a 400 whose body mentions a * reasoning field, so an unrelated validation error is not blamed on effort. */ export declare function describeReasoningRejection(status: number, providerText: string, effort: string | undefined): string | undefined; /** * Publish a model's resolved levels; pass null to clear. * * @param sessionId Scopes the publication to one session. Omit it to write the * process-wide slot used when there is only ever one session. */ export declare function setActiveReasoningEffortOptions(values: readonly string[] | null, sessionId?: string): void; /** * A model's resolved levels, or null when none have been published. * * With a session id, that session's own levels, falling back to the unkeyed * slot so an embedder that never passes a session id still reads its own * publication. Without one, only the unkeyed slot. */ export declare function getActiveReasoningEffortOptions(sessionId?: string): readonly string[] | null; /** * Whether a `provider.reasoningEffort` value is acceptable right now. * * Given a session id, the answer is that session's own resolved levels. Without * one, the config schema's validator has no session in hand, because the * setting itself is not per session, a level is acceptable when ANY session * that has published offers it. Rejecting a level valid on the session the user * is actually looking at, because a different session ran a turn more recently, * would be the multi-session bleed this scoping exists to prevent. A level no * live model offers is still rejected, and before anything has published the * known severity ladder is the floor, so a typo never gets through. */ export declare function isAcceptableReasoningEffortSetting(value: unknown, sessionId?: string): boolean; /** * One line describing what this model receives on the wire, for the `/effort` * explainer. Generated from the resolved spec so it cannot go stale the way a * hand-written per-provider string does. */ export declare function describeReasoningWire(spec: ReasoningEffortSpec, providerId?: string): string; export {}; //# sourceMappingURL=reasoning-effort.d.ts.map