import type { CredentialRef, ModelFamilyListing } from "@yanlinglabs/winter-agent-sdk"; import type { VersionMatrixReport } from "../version-matrix.js"; import type { CredentialPresence, ProviderAuthView, RuntimeSelection, SelectionAuthFamily, SelectionInput, SelectionRefusal, SelectionVersions } from "./runtime-selection.js"; /** The family id the D13 table names. The catalog's own id (WS-13c §1, `CLAUDE_FAMILY_ID`). */ export declare const CLAUDE_FAMILY_ID = "claude"; /** WS-13 §5's Anthropic wire dialect, as the catalog's provider descriptors spell it. */ export declare const ANTHROPIC_PROTOCOL = "anthropic-messages"; /** * The provider ids treated as Anthropic-protocol backends when the host declares no `protocols`. * * A FALLBACK, NOT A POLICY. When `CredentialPresence.authByProvider[id].protocols` is present it is * authoritative and this list is not consulted. It exists because the alternative — treating an * undeclared backend as Anthropic-protocol — would route a Claude model resold through an * OpenAI-shaped gateway to the official runtime, which is precisely WS-13 §9's third row inverted. * The conservative direction is the safe one: an undeclared, unlisted backend goes to Winter, which * serves every family, rather than to a runtime that speaks one wire protocol. * * ONE ENTRY, and that is not an oversight: Bedrock and Vertex reach the official branch through their * AUTH FAMILY (`cloud-credential-chain`, WS-14 §12's own table rows), not through this list — their * catalog dialects are `bedrock-converse` and `google-generate-content`, and claiming otherwise here * would be a false statement about the catalog. */ export declare const ANTHROPIC_PROTOCOL_PROVIDER_FALLBACK: readonly string[]; /** * D25's reserved slot names, which resolve into the `claude` family from any active set (WS-13c §3's * acceptance order, mirrored from the catalog's `CLAUDE_RESERVED_SLOT_NAMES`). */ export declare const CLAUDE_RESERVED_SLOT_NAMES: readonly string[]; /** * D14's ship gate, as the shipped default. WS-23: nothing reads the gate any more (a Claude OAuth * credential is refused whatever it says); the constant stays exported for a host that still names it. */ export declare const D14_CLAUDE_OAUTH_APPROVED_DEFAULT = false; /** What a `RuntimeSelection` records when the caller supplied no version identity for that runtime. */ export declare const UNKNOWN_VERSION = "unknown"; /** * The auth families the official branch serves (R-7b-1 as clarified 2026-09-08), before any per-rule * gate. * * THE ONE HOME FOR THE SET. `officialServesBackend` DERIVES from this list rather than restating it — * the alternative was two places to edit, and review r1's I1 was the first time that cost something * real (a family was added to the rule and the constant said otherwise, with nothing failing). */ export declare const OFFICIAL_SERVED_AUTH_FAMILIES: readonly SelectionAuthFamily[]; /** * Every branch this selector can take, with the sentence a host renders. * * IDS RATHER THAN PROSE MATCHING. `RuntimeSelection.reason` is `": "`, so a test asserts on * `D13-1` while a user reads the sentence, and rewording the sentence never breaks a test (nor does * a test pin prose a product person should be free to improve). */ export declare const SELECTION_RULES: { readonly "D13-1": "a Claude OAuth credential always routes to the official runtime (WS-13 §9, D13 row 1)"; readonly "D13-2": "a Claude-family model on an Anthropic-protocol backend in Code mode routes to the official runtime (WS-13 §9, D13 row 2)"; readonly "D13-3-endpoint": "a Claude-family model reached through a backend the official branch does not serve routes to the Winter runtime (WS-13 §9, D13 row 3)"; readonly "D13-3-mode": "Dispatch and Chat run in-daemon on the Winter runtime (WS-13 §9 row 3, D4)"; readonly D28: "a non-Claude family routes to the Winter runtime (WS-13c §0, D28)"; readonly "R-7b-1-no-peer": "this router holds no official runtime, so the Claude-family slot resolves through WS-13c §4's order onto the Winter runtime (R-7b-1)"; readonly persisted: "the selection persisted at session creation wins; a change is the certified handoff or a visible fork, never a silent rewrite (WS-00 §2, D13)"; }; export type SelectionRuleId = keyof typeof SELECTION_RULES; /** `": "` — the exact string a produced record carries in `reason`. */ export declare function reasonFor(rule: SelectionRuleId): string; /** * The rule id a produced record was decided by, recovered from its `reason`. * * `Object.hasOwn`, NOT `in` — `in` walks the prototype chain, so a persisted record whose `reason` * began `toString:` would have come back as a `SelectionRuleId` and `SELECTION_RULES[id]` would have * handed the caller a `Function` where it expects a sentence. A `RuntimeSelection` arrives off a * host's durable store, so it is exactly the kind of input that must not be trusted to be one of ours. */ export declare function ruleIdOf(selection: RuntimeSelection): SelectionRuleId | undefined; type FamilyEntry = ModelFamilyListing["families"][number]; type ModelEntry = FamilyEntry["models"][number]; /** One catalog row as the listing publishes it: the provider-qualified `key` is the identity (row 17). */ export type ModelRow = ModelEntry["rows"][number]; /** A row that survived WS-13c §4's filter, with the family it belongs to. */ export interface SelectionCandidate { family: string; canonicalModelId: string; row: ModelRow; auth: ProviderAuthView; } /** * The auth family implied by a credential ref's STORAGE KIND, for a provider the host did not describe. * * THE ONE RULE THAT MATTERS HERE: an OAuth family is never inferred. `keychain`, `env` and `inline` * are where an API key lives and are also where a subscription credential could live, and guessing * `claude-oauth` from a keychain entry would let an ambient credential trip D14's ship gate — the * exact shape WS-14's Phase 6 amendment forbids ("never by ambient environment scan"). `file` is * genuinely undeterminable (the ref's `format` distinguishes an AWS credentials file from a raw key, * and the kind alone does not carry it), so it reports `custom`, which no rule routes to the official * runtime. Everything unknown therefore lands on Winter, which serves every family. */ export declare function authFamilyFromRefKind(kind: CredentialRef["kind"]): SelectionAuthFamily; /** The host's view of a provider, or the conservative one derived from its ref kind. */ export declare function providerAuthView(providerId: string, credentials: CredentialPresence): ProviderAuthView | undefined; /** WS-13 §9's "Anthropic-protocol backend" test: the declared dialects, else the fallback list. */ export declare function speaksAnthropicProtocol(providerId: string, auth: ProviderAuthView): boolean; /** * Can the OFFICIAL branch serve this backend at all? (R-7b-1's served set, WS-14 §12's table.) * * MEMBERSHIP FIRST, THEN THE PROTOCOL GATE. A family outside `OFFICIAL_SERVED_AUTH_FAMILIES` is not * served, full stop; a family inside it is served either unconditionally or only on a backend that * speaks the Anthropic dialect, and which of the two it is follows from what the family means: * * `claude-oauth` — served (and gated separately, because it is D13's own row 1). * `cloud-credential-chain` — served. These are WS-14 §12's Bedrock and Vertex rows: their catalog * dialects are NOT `anthropic-messages`, and the official runtime * speaks them itself, so the auth family is the honest test there. * `api-key`, `console-oauth` — served ONLY on an Anthropic-dialect backend. Both are token-priced * bearer credentials the official runtime accepts through its bearer * variable (R-7b-1 as clarified 2026-09-08), so neither is a reason to * route away from the official branch — but a Claude model resold over * an OpenAI-shaped endpoint still is, which is WS-13 §9's row 3 and the * one place the protocol test does the work. * * `console-oauth` was excluded here until review r1's I1. The reasoning had been WS-13c §6's "the * `anthropic` provider first (api-key or Console OAuth credential)" — but that sentence sits inside * §6's WINTER-ALONE paragraph, and the router leg is the next sentence ("With the runtime SDK present: * `claude` slots prefer the official SDK per D13"). The exclusion was never required by the spec, and * it contradicted D28's "anthropic models always prefer claude agent sdk". */ export declare function officialServesBackend(providerId: string, auth: ProviderAuthView): boolean; /** * WS-13c §4, end to end: what the session asked for → the one row it will run on. * * ORDER OF PRECEDENCE: an explicit slot, else an explicit model, else the session's active slot set — * whose slots are tried in the order the listing publishes them, because that order IS §4's * deterministic order (the listing's own row order; WS-20: a request always names its provider, so * order is never a tie-break). This package re-sorts nothing: the listing is produced by the code that * owns those rules, and a second ordering here would be a second answer. */ /** A candidate list that is non-empty BY TYPE, so a caller never has to guard an impossible empty. */ export type NonEmptyCandidates = [SelectionCandidate, ...SelectionCandidate[]]; /** * EVERY candidate row for an explicitly named model or catalog row key, in the listing's own order. * * `resolveCandidate` below takes the first of these and is what a fresh decision uses. A RESUME needs * the whole list instead (`resumeChildSelection`): its question is not "which row would we pick now" * but "is the row this child is RECORDED on still servable", and those differ the moment one provider * serves two rows for one canonical model. Review r1's M1 is exactly that difference — the old code * compared against the first row and called it a provider check, which the provider pin had already * guaranteed. */ export declare function resolveCandidateRows(input: SelectionInput & { requested: { model: string; }; }): NonEmptyCandidates | SelectionRefusal; export declare function resolveCandidate(input: SelectionInput): SelectionCandidate | SelectionRefusal; /** * The D13/D28 table itself, over an already-resolved candidate. * * Exported because both entry points evaluate the SAME table — R-7b-1's "a child runs on the runtime * its OWN slot's family selects under D13/D28" is implemented by calling this with the child's own * candidate, not by a second table that would drift from this one. */ export declare function decideRuntime(candidate: SelectionCandidate, input: SelectionInput): RuntimeSelection | SelectionRefusal; /** * D13/D28, pure — the router's runtime selection. * * Returns the PERSISTED record untouched when there is one, otherwise the row this session resolves * to plus the runtime the table picks, otherwise a typed refusal. */ export declare function selectRuntime(input: SelectionInput): RuntimeSelection | SelectionRefusal; /** * What a fresh decision would say about a session that already has a persisted selection. * * `unchanged` — the table still picks the same runtime, provider and model. `handoff-required` — it * would pick something else: WS-00 §2's D13 says that change "is the certified handoff or a visible * fork, never a silent rewrite", so this is reported to the host (which renders the choice, R-7b-3) * and the persisted record is returned untouched either way. `fresh-refused` — the session's * persisted selection is no longer servable at all (a credential removed, a row withdrawn); the * record still stands, and the refusal says why a fresh decision could not be made. */ export type SelectionReview = { kind: "unchanged"; selection: RuntimeSelection; fresh: RuntimeSelection; } | { kind: "handoff-required"; persisted: RuntimeSelection; fresh: RuntimeSelection; changed: Array<"runtimeKind" | "providerId" | "modelRef" | "family" | "authFamily">; detail: string; } | { kind: "fresh-refused"; persisted: RuntimeSelection; refusal: SelectionRefusal; }; /** * Compares a session's persisted selection against what the table would decide today. * * NEVER RETURNS A REWRITTEN RECORD. Every branch carries the persisted object itself; `fresh` is * offered beside it as the *proposal* a handoff (WS-05 §12) or a visible fork would realise. The * host, not this function, decides what to do with a `handoff-required`. */ export declare function reviewPersistedSelection(input: SelectionInput & { persisted: RuntimeSelection; }): SelectionReview; /** * The version identities the constructor already measured, in the shape a selection stamps. * * `RuntimeSdk.versions` is a `VersionMatrixReport`; `SelectionInput.versions` is what the record * needs. This is the one-line bridge, so a host does not hand-copy two fields and get the second one * wrong for the runtime it did not test. */ export declare function selectionVersionsFrom(report: VersionMatrixReport): SelectionVersions; export {};