@yanlinglabs/winter-provider-catalog 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,385 @@
1
+ /** The wire dialect an adapter speaks. One adapter family per protocol (WS-13 §5) — never one ported executor per upstream row. */
2
+ export type ProviderProtocol = "openai-responses" | "openai-chat-completions" | "anthropic-messages" | "google-generate-content" | "bedrock-converse" | "azure-openai" | "custom";
3
+ /** How a provider is authenticated. `local-none` is a real, first-class kind — a local endpoint with no key is not a degenerate api-key case (WS-13 §6). */
4
+ export type ProviderAuthKind = "api-key" | "oauth-approved" | "cloud-credential-chain" | "local-none" | "custom";
5
+ /**
6
+ * Where a capability claim came from. Ordered loosely from most to least durable.
7
+ *
8
+ * The last two are WINTER'S OWN, and they exist because the alternative was a false label. The
9
+ * upstream mapper has to stamp `outputModalities` on every row, upstream's `RegistryModel` declares
10
+ * no output modality for ANY model, and the only members available were provider-shaped -- so
11
+ * `["text"]`, which is Winter's inference for a chat registry, shipped as `source: "upstream-static"`
12
+ * with the caveat pushed into a `sourceRef` sentence nothing reads programmatically. A reader
13
+ * filtering for "what upstream said" got a Winter guess (whole-branch review, Lane X r1 carry).
14
+ *
15
+ * `winter-default` — a value WINTER chose in the absence of any upstream or vendor statement. Not
16
+ * a normalization of anything: the field is required and something has to be in it.
17
+ * `local-override` — a value from a LOCAL, non-vendor declaration: an operator's own configuration
18
+ * for a local endpoint, which is neither a vendor document nor a probe of one.
19
+ *
20
+ * Both are strictly less durable than `user-override` (a deliberate human statement about a specific
21
+ * row), so they sort last. Neither may ever carry `confidence: "verified"`; the validator enforces it.
22
+ */
23
+ export type EvidenceSource = "official-doc" | "live-discovery" | "live-probe" | "upstream-static" | "user-override" | "local-override" | "winter-default";
24
+ /** How much the reader should trust the claim. `unknown` is a legitimate, recordable state — never a reason to omit the evidence wrapper and assert a bare value. */
25
+ export type EvidenceConfidence = "verified" | "declared" | "inferred" | "unknown";
26
+ /** A capability claim with its provenance. `observedAt` is an ISO-8601 instant when present. */
27
+ export interface CapabilityEvidence<T> {
28
+ value: T;
29
+ source: EvidenceSource;
30
+ sourceRef?: string;
31
+ observedAt?: string;
32
+ confidence: EvidenceConfidence;
33
+ }
34
+ /**
35
+ * WS-13 §8.1's three-state tool capability. `native` becomes agent-eligible only after schema/
36
+ * streaming proof; `emulated` is DISABLED BY DEFAULT for agent modes; `none` fails capability
37
+ * negotiation when the mode requires tools. Silently dropping tools and continuing as plain chat is
38
+ * prohibited — which is why this is three states and not a boolean.
39
+ *
40
+ * Disclosed divergence (derived-shapes-p6.md item (d), OQ-P6-3): the pinned `ModelInfo` has NO
41
+ * tool-capability field at all, so this three-state model is a Winter extension with no pinned
42
+ * counterpart, not a mirror of one.
43
+ */
44
+ export type ToolCalling = "native" | "emulated" | "none";
45
+ /**
46
+ * A row's promotion state. Every row a lane adds starts `candidate`; promotion to `supported`
47
+ * requires the behavioural corpus (WS-13 §13). `blocked` is the only value the registry refuses to
48
+ * resolve — a `candidate` row is resolvable (that is what makes a lane's own fixtures runnable).
49
+ */
50
+ export type ModelStatus = "candidate" | "experimental" | "supported" | "deprecated" | "blocked";
51
+ /**
52
+ * WS-13 §8.2, amended 2026-09-02 from the reasoning-continuity report. "Provider" is NOT the
53
+ * capability unit here — the exact endpoint+model is: same-provider does not imply same
54
+ * continuation domain (Anthropic strips thinking across Claude models), so `continuationDomain`
55
+ * lists the models PROVEN to accept this endpoint's native continuation object.
56
+ */
57
+ export interface ReasoningCapabilities {
58
+ supported: CapabilityEvidence<boolean>;
59
+ /** The model's own effort vocabulary, verbatim. Vocabularies are NOT interchangeable across providers (WS-13 §8.2). */
60
+ efforts: string[];
61
+ defaultEffort?: string;
62
+ continuation: "none" | "plaintext" | "opaque-provider-state" | "server-response-handle";
63
+ readableState?: CapabilityEvidence<"none" | "summary" | "full-exposed">;
64
+ /** e.g. Anthropic `display: "summarized"`, OpenAI `reasoning.summary`, Gemini `includeThoughts`. */
65
+ summaryRequest?: CapabilityEvidence<{
66
+ field: string;
67
+ values: string[];
68
+ }>;
69
+ replayScope?: CapabilityEvidence<"current-tool-loop" | "current-turn" | "selected-turns" | "all-turns">;
70
+ continuationDomain?: CapabilityEvidence<string[]>;
71
+ /** The stream/final event from which the COMPLETE replay object must be captured — never an earlier partial copy. */
72
+ completionEvent?: CapabilityEvidence<string>;
73
+ /** What missing reasoning state costs mid-tool-loop (DeepSeek with tools: a 400). */
74
+ toolLoopRequirement?: CapabilityEvidence<"hard-error" | "silent-degradation" | "not-required">;
75
+ }
76
+ /** List prices, USD per million tokens. R6-H: the ONLY price source Winter has — an unpriced model reports `0` / `costBasis: "unknown"`, never an invented number. */
77
+ export interface ModelPricing {
78
+ inputPerMTokUsd: number;
79
+ outputPerMTokUsd: number;
80
+ cacheReadPerMTokUsd?: number;
81
+ cacheWritePerMTokUsd?: number;
82
+ }
83
+ /**
84
+ * WS-13c §2: where a slot's ranking and its description came from.
85
+ *
86
+ * `user-ruling` carries the user's own framing verbatim (or a faithful one-sentence condensation
87
+ * that keeps the user's key phrase); `vendor-doc` cites the vendor's model page; `winter-curated` is
88
+ * Winter's own editorial judgement and enters `candidate` until the user reviews it (§9).
89
+ */
90
+ export type SlotBasis = "user-ruling" | "vendor-doc" | "winter-curated";
91
+ /** A slot's promotion state, mirroring `ModelStatus`'s two reviewed values (WS-13c §2/§9). */
92
+ export type SlotStatus = "candidate" | "supported";
93
+ /**
94
+ * One ranked option in a family's lineup (WS-13c §2).
95
+ *
96
+ * POSITION IN THE ARRAY IS THE OPTION ORDER, NOT A STRENGTH CLAIM (D26): the Gemini case is the
97
+ * whole reason the two text fields are required and separate — 3.8 Flash is documented as the
98
+ * strongest while 3.1 Pro still leads the list on breadth. `description` says what it is good for
99
+ * and `reason` says why it holds this position; neither may carry a currency amount, because pricing
100
+ * lives on model rows with its own evidence wrapper and a price copied into prose is a price nobody
101
+ * can audit or update.
102
+ */
103
+ export interface FamilySlot {
104
+ /** The facing enum token people know (`astra`, `flash`, `grok-4.6`). Matches `^[a-z0-9][a-z0-9.-]{0,31}$`; never a version number alone. */
105
+ name: string;
106
+ /** Resolves to at least one model row's `canonicalModelId` — the integrity suite refuses a slot on a missing row, so no id is invented into `generated/`. */
107
+ canonicalModelId: string;
108
+ /** Pins a serving provider id (WS-13c §4 step 4). Optional; it must survive the credential/enablement filter or the slot is unservable. */
109
+ provider?: string;
110
+ /** What this option is for. No currency amounts. */
111
+ description: string;
112
+ /** Why it holds this position in the lineup. */
113
+ reason: string;
114
+ basis: SlotBasis;
115
+ citation: string;
116
+ status: SlotStatus;
117
+ }
118
+ /**
119
+ * A vendor lineup, independent of the provider that serves it (WS-13c §1).
120
+ *
121
+ * `matchers` are anchored RegExp SOURCES evaluated over `canonicalModelId`, first match wins. They
122
+ * are authored DISJOINT (`^gpt-(?!oss)` beside `^gpt-oss-`) so the pipeline's sort-by-id can never
123
+ * change a row's stamp; `catalog-integrity.test.ts` asserts that order independence over the real
124
+ * catalog rather than trusting the authoring.
125
+ *
126
+ * `vendorProviders` is ORDERED and is step 3-i of slot resolution: the vendor's own rows first, a
127
+ * configured SUBSCRIPTION row before a token row of the same vendor.
128
+ */
129
+ export interface ModelFamilyDescriptor {
130
+ /** `^[a-z0-9][a-z0-9-]{0,31}$`. `other` is the reserved id for a row no matcher claims. */
131
+ id: string;
132
+ displayName: string;
133
+ vendor: string;
134
+ /** Ordered provider ids, subscription row before token row of the same vendor (WS-13c §4 step 3-i). */
135
+ vendorProviders: string[];
136
+ /** Anchored RegExp sources over `canonicalModelId`; first match wins. Authored disjoint. */
137
+ matchers: Array<{
138
+ pattern: string;
139
+ note: string;
140
+ }>;
141
+ /** 0..4, unique names. A family with zero slots is legal — it is listed under "more options" only. */
142
+ slots: FamilySlot[];
143
+ status: "candidate" | "supported";
144
+ citation: string;
145
+ }
146
+ export interface WinterModelDescriptor {
147
+ /** The stable Winter key, `<providerId>/<model>` (WS-13 §8.3). Globally unique across the catalog. */
148
+ key: string;
149
+ providerId: string;
150
+ /** The provider-local id sent on the wire. Unique within a provider, and never assumed unique across providers. */
151
+ upstreamId: string;
152
+ /**
153
+ * WS-13c §1: the family id this row's model belongs to, or `"other"` when no matcher claims it.
154
+ *
155
+ * DERIVED AT BUILD by `stampFamilyFields`; an overlay row MAY set it as an override, and the
156
+ * stamper never overwrites a value that is already there. Never `WinterProviderDescriptor.family`,
157
+ * which is the ADAPTER family and keeps its own meaning (R13c-1).
158
+ */
159
+ modelFamily: string;
160
+ /**
161
+ * WS-13c §1: the vendor's model identity with the provider's spelling removed, so
162
+ * `deepseek/deepseek-v4-pro`, `vertex/DeepSeek-V4-Pro` and `qwen-cloud/deepseek-v4-pro` are ONE
163
+ * canonical model.
164
+ *
165
+ * DERIVED AT BUILD by `stampFamilyFields` (via `canonicalModelIdOf`); an overlay row MAY set it as
166
+ * an override, which is how `kimi-coding/k3` — whose coding-plan id is just `k3` — reaches the
167
+ * same canonical model as `moonshot/kimi-k3`.
168
+ */
169
+ canonicalModelId: string;
170
+ displayName: string;
171
+ aliases: string[];
172
+ endpoints: Array<"chat" | "responses" | "embeddings" | "image" | "audio" | "video">;
173
+ contextWindow?: CapabilityEvidence<number>;
174
+ maxInputTokens?: CapabilityEvidence<number>;
175
+ maxOutputTokens?: CapabilityEvidence<number>;
176
+ inputModalities: CapabilityEvidence<string[]>;
177
+ outputModalities: CapabilityEvidence<string[]>;
178
+ toolCalling: CapabilityEvidence<ToolCalling>;
179
+ nativeTools: CapabilityEvidence<boolean>;
180
+ parallelTools?: CapabilityEvidence<boolean>;
181
+ structuredOutput?: CapabilityEvidence<boolean>;
182
+ promptCaching?: CapabilityEvidence<boolean>;
183
+ reasoning?: ReasoningCapabilities;
184
+ pricing?: CapabilityEvidence<ModelPricing>;
185
+ /** R6-14: set only after the safety corpus passes live. A worker with no configured classifier route serves only when this is true AND `structuredOutput.confidence === "verified"`. */
186
+ classifierEligible?: CapabilityEvidence<boolean>;
187
+ /** Request parameters this model rejects. Adapters must not send them (WS-13 §8.2: reject the selection BEFORE sending). */
188
+ unsupportedParameters: string[];
189
+ status: ModelStatus;
190
+ }
191
+ export interface WinterProviderDescriptor {
192
+ id: string;
193
+ displayName: string;
194
+ protocols: ProviderProtocol[];
195
+ authKinds: ProviderAuthKind[];
196
+ /** Generated endpoints are IMMUTABLE (R6-11): a user override rides `ConnectionProfile.baseUrl` and goes through the endpoint policy instead. */
197
+ defaultEndpoints: Record<string, string>;
198
+ modelDiscovery: "none" | "openai-models" | "provider-native" | "local";
199
+ /**
200
+ * Whether the live catalog is the last word on which models exist. `authoritative` means an id
201
+ * absent from live discovery does not exist; anything else means the compiled seed may still be
202
+ * right — and, per R6-F, is the precondition for an `allowUnlisted` connection passing an
203
+ * unlisted id straight through.
204
+ */
205
+ liveCatalogAuthority: "authoritative" | "partial" | "unknown";
206
+ adapterId: string;
207
+ /** The adapter FAMILY this provider's wire mapping belongs to; mirrors `ProviderFamily` in provider-runtime (kept a bare string here so the data package stays free of the runtime's unions). */
208
+ family: string;
209
+ /** `project: "winter"` marks a Winter-owned provider (codex-oauth per D11, and every local id) that no upstream extraction produced. */
210
+ upstream: {
211
+ project: "OmniRoute" | "winter";
212
+ commit: string;
213
+ sourcePaths: string[];
214
+ };
215
+ risk: {
216
+ class: "approved" | "review-required" | "blocked";
217
+ reasons: string[];
218
+ };
219
+ /** WS-13 §4: only `llm` rows feed the Agent SDK's model selection; the other scopes feed separate subsystems and must never reach the worker-model picker. */
220
+ scope: "llm" | "stt" | "tts" | "embedding" | "image" | "video" | "search";
221
+ /**
222
+ * WS-13b §1: how the vendor charges for the credential Winter actually uses.
223
+ *
224
+ * DATA, not a derived guess, and it is the whole reason the field exists: R6-H prices a turn from
225
+ * the model row's `pricing` evidence, and a subscription-priced backend (the ChatGPT Codex
226
+ * entitlement, a "coding plan") has list prices published for its API twin that do NOT describe
227
+ * what this credential is billed. `subscription`/`free` rows never feed `total_cost_usd`/
228
+ * `modelUsage` — a per-token number for a seat is not a smaller error than no number, it is a
229
+ * wrong one that reads as authoritative.
230
+ */
231
+ pricingBasis: "token" | "subscription" | "free";
232
+ /**
233
+ * WS-13b §1 (D21): the documented third-party path this row ships through, and the citation that
234
+ * admits it.
235
+ *
236
+ * R6b-3 makes the citation load-bearing rather than decorative: `validateCatalog` refuses a row
237
+ * whose `citation` is absent or empty (`admission-missing`), and refuses one that cites the
238
+ * audit's own `unknown` evidence class (`admission-unknown`) — "the decisive document was not
239
+ * found" is a disposition to EXCLUDE, so a row may not ship carrying it.
240
+ *
241
+ * `citation` forms, in order of strength: a URL to the vendor document; `audit:<section>` for the
242
+ * third-party-access audit's evidence table; `spec:<section>` for a Winter spec ruling that admits
243
+ * a class of rows (WS-13 §1's disposition table admits the reviewed api-key/cloud allowlist rows);
244
+ * `local` for a `local-none` row, whose "vendor" is the operator's own machine.
245
+ */
246
+ admission: {
247
+ basis: "api-key" | "oauth-documented" | "keyless-documented" | "local" | "cloud-credential";
248
+ citation: string;
249
+ tier: AdmissionTier;
250
+ };
251
+ /**
252
+ * WS-13b §2/§7/§8.4 (fix-wave ruling R-FW-2): the SECOND identity field this vendor names, if it
253
+ * names one.
254
+ *
255
+ * Winter's `User-Agent` is unconditional and lives in code (`identity.ts`). This is the per-row
256
+ * half: AI Horde documents a `Client-Agent: <name>:<version>:<contact>` field, and the spec's own
257
+ * words are "a truthful `Client-Agent`" — an obligation that fell between the row author (who
258
+ * cited the header) and the adapter owner (whose lane was the live gate), and shipped as prose on
259
+ * neither side. Making it DATA on the row is what stops that: the row that documents the header is
260
+ * the row that carries it, and one seam applies every row's.
261
+ *
262
+ * WHAT MAY BE HERE, enforced by `validateCatalog` rather than by review:
263
+ * - the NAME must be one of a Winter-authored allowlist (`Client-Agent` today). A row may not
264
+ * invent a header name, and it may certainly not name a vendor's product-identity field —
265
+ * that is the exact thing WS-13 §5 and D21 forbid, and a free-text name field would be a hole
266
+ * straight through both.
267
+ * - the VALUE must begin with the `<product>` PLACEHOLDER. The running product names ITSELF in
268
+ * every identity field; a value naming an editor, a CLI or a first-party product is not a
269
+ * configuration mistake to fix later, it is impersonation. The literal Winter package name was
270
+ * accepted here until the P7a fix wave, for "rows written before the profile existed" — no row
271
+ * was ever written that way, and a hard-coded product token is precisely what this rule calls
272
+ * impersonation when somebody else does it.
273
+ * - THREE PLACEHOLDERS are substituted by the adapter at request time (provider-runtime's
274
+ * `renderIdentityHeaders`): `<version>` with this build's own version, so a release cannot
275
+ * leave a stale number on the wire; `<product>` (P7a, D19) with the running brand's
276
+ * `packageName`, so a REUSER's identity header names the reuser rather than Winter; and
277
+ * `<contact>` (P7a fix wave) with `brand.contactUrl`. The contact is the half of the
278
+ * `<name>:<version>:<contact>` triple a vendor actually acts on, so a row hard-coding a
279
+ * repository URL sends every reuser's traffic to whoever owns that repository — the same
280
+ * untruth as the product token, and less visible, because the row still LOOKS rebranded.
281
+ *
282
+ * NOT routed through `applyPrivilegedHeaders`. This is Winter's own identity, the same class as
283
+ * the `User-Agent` beside it — it discloses nothing about the operator, and gating it on a
284
+ * generated endpoint would silently drop it for every multi-provider row, whose reviewed endpoint
285
+ * is COPIED into the connection profile and therefore evaluated as a user endpoint (seam 1c).
286
+ * `aihorde` is exactly such a row, so a privileged reading would have delivered the header in a
287
+ * fixture and never in production.
288
+ */
289
+ identityHeaders?: Record<string, string>;
290
+ /**
291
+ * P7a carry (Lane D): a PER-TENANT provider whose API endpoint is the customer's own resource, so
292
+ * the row ships with NO usable `defaultEndpoints.api` at all (`azure-ai`, `oci`).
293
+ *
294
+ * `true` is the only value: absence means "the row's endpoint is usable as shipped", and a `false`
295
+ * would be a claim no row needs to make. A session selecting such a row without supplying an
296
+ * endpoint is a typed `endpoint-required` refusal — never a request sent to a placeholder host.
297
+ *
298
+ * DECLARED AT P7a'S SPINE, RULED ON BY LANE D: the validator ACCEPTS this field (shape only) so
299
+ * both halves can land independently; the rules that bind it to `defaultEndpoints`, and the rows
300
+ * that set it, are Lane D's.
301
+ */
302
+ requiresUserEndpoint?: true;
303
+ /**
304
+ * DOCUMENTATION ONLY, never sent: the shape a user's own endpoint takes for a
305
+ * `requiresUserEndpoint` row, e.g. `"https://<resource>.services.ai.azure.com/models"`.
306
+ *
307
+ * It exists so a host can TELL the user what to paste. Nothing resolves it, nothing substitutes
308
+ * into it, and no request is ever built from it — a template that reached the wire would be a
309
+ * request to a literal `<resource>` host.
310
+ */
311
+ endpointTemplate?: string;
312
+ }
313
+ /**
314
+ * WS-13b §1 (fix-wave ruling R-FW-3): HOW GOOD the evidence behind `admission.citation` is, as DATA.
315
+ *
316
+ * The tiers were prose before this — a marker inside the citation STRING, explained in PROVENANCE.md
317
+ * — and the one test that claimed to keep the fifteen reviewed rows out of the weakest tier could
318
+ * not: it matched `^https?:\/\/`, which a pinned-upstream citation also satisfies. Nothing in the
319
+ * validator, the live gate or the promotion path could key on a substring, so the label drifted from
320
+ * the rows it described (`minimax` sat in the weak tier while its own sibling cited a fetched
321
+ * MiniMax document naming the same base URL).
322
+ *
323
+ * `fetched-document` a page this repository's lane FETCHED and READ, quoted in the citation with
324
+ * the date it was retrieved. The strongest tier and the only one a `supported`
325
+ * model may sit on.
326
+ * `pinned-upstream` the vendor's own site as OmniRoute's product catalog records it at the pin,
327
+ * plus the pinned `RegistryEntry` (auth type, dialect, base URL). An admission
328
+ * of the PATH and a placeholder for the DOCUMENT: honest, consequential
329
+ * (`review-required`, models `candidate`), and never a claimed review that did
330
+ * not happen.
331
+ * `spec-ruling` a Winter spec ruling admits the row as a class (WS-13b §0 D20).
332
+ * `audit` the third-party-access audit's own evidence table.
333
+ * `local` the "vendor" is the operator's own machine.
334
+ *
335
+ * PROMOTION IS TWO-KEY (ruling (b)): a live-gate pass AND a fetched vendor document, with the
336
+ * citation upgraded in the same reviewed commit. `catalog-integrity.test.ts` asserts the half a test
337
+ * can hold — no `approved` row and no `supported` model on `pinned-upstream` — and the live gate's
338
+ * report row prints the tier so a promotion cannot be made from a pinned row by habit.
339
+ */
340
+ export type AdmissionTier = "fetched-document" | "pinned-upstream" | "spec-ruling" | "local" | "audit";
341
+ export interface WinterCatalog {
342
+ /** 2 since WS-13c: every model row carries `modelFamily`/`canonicalModelId` and the document carries `families`. */
343
+ schemaVersion: 2;
344
+ catalogVersion: string;
345
+ /** The upstream pin the generated layer came from. All-empty on the hand-authored SEED (`catalogVersion: "0.0.0-seed"`) — that emptiness is what says "not extracted". */
346
+ upstream: {
347
+ tag: string;
348
+ tagObject: string;
349
+ commit: string;
350
+ extractorVersion: string;
351
+ overlayVersion: string;
352
+ };
353
+ providers: WinterProviderDescriptor[];
354
+ models: WinterModelDescriptor[];
355
+ /** WS-13c §1: the vendor lineups, generated from `overlay/families.json` and sorted by `id`. May be empty (a layer validated standalone has no families). */
356
+ families: ModelFamilyDescriptor[];
357
+ }
358
+ /**
359
+ * One validation failure.
360
+ *
361
+ * `message` is the whole human sentence, `path`-prefixed — byte-identical to the strings this
362
+ * result used to be an array of, so every existing consumer (`loadCatalog`'s throw, the two
363
+ * scripts' stderr, the tests' `includes` helper) reads the same text it always did.
364
+ *
365
+ * `code` is P6.5's addition and the reason the shape changed at all: R6b-3 is a rule a GATE has to
366
+ * key on ("a row without an admission citation fails validation"), and keying a gate on prose is
367
+ * how a reworded message silently disarms it. Codes are opt-in — every pre-existing check reports
368
+ * the generic `invalid`, and only the rules something else keys on carry a specific one. Widening
369
+ * that is a later, deliberate edit, not a prerequisite for this one.
370
+ */
371
+ export interface CatalogValidationError {
372
+ code: string;
373
+ /** JSON-pointer-ish location of the offending value, e.g. `providers[3].admission.citation`. */
374
+ path: string;
375
+ /** `${path}: ${reason}` — the complete sentence. */
376
+ message: string;
377
+ }
378
+ /** The result of `validateCatalog`. A failure carries EVERY error found, not just the first — a generator run wants the whole list. */
379
+ export type CatalogValidationResult = {
380
+ ok: true;
381
+ catalog: WinterCatalog;
382
+ } | {
383
+ ok: false;
384
+ errors: CatalogValidationError[];
385
+ };
@@ -0,0 +1,98 @@
1
+ import type { CatalogValidationResult, EvidenceConfidence, EvidenceSource, ModelStatus, ProviderAuthKind, ProviderProtocol, SlotBasis, SlotStatus, ToolCalling, WinterCatalog, WinterModelDescriptor, WinterProviderDescriptor } from "./types.js";
2
+ /**
3
+ * The header NAMES a reviewed row may put in `identityHeaders` (fix-wave R-FW-2).
4
+ *
5
+ * ONE ENTRY, and widening it is a deliberate edit with a vendor document behind it. `Client-Agent`
6
+ * is AI Horde's documented `<name>:<version>:<contact>` client-identity field. A row that needs a
7
+ * different second identity field adds its name here, in review, beside the document that names it —
8
+ * which is the whole difference between a Winter-authored identity and an imported one.
9
+ */
10
+ export declare const WINTER_IDENTITY_HEADER_NAMES: readonly string[];
11
+ /**
12
+ * The THREE tokens an `identityHeaders` VALUE may carry, substituted by the adapter at request time
13
+ * (provider-runtime's `renderIdentityHeaders`).
14
+ *
15
+ * `<version>` predates P7a. `<product>` is D19's: the product token is `brand.packageName`, so a row
16
+ * that hard-codes Winter's own name is honest for Winter and a LIE for a reuser — it would put
17
+ * Winter's identity on a request the reuser's product made. `<contact>` is the P7a fix wave's (item
18
+ * 7, Lane A review M-4): a vendor identity field is a `<name>:<version>:<contact>` triple and the
19
+ * contact is the half a vendor ACTS on, so a row hard-coding Winter's repository URL points every
20
+ * reuser's traffic at Winter's issue tracker — the same untruth as the product token, and less
21
+ * visible, because the row still LOOKS rebranded once `<product>` has moved.
22
+ *
23
+ * A ROW MUST NOW START WITH `<product>`; the literal Winter package name is no longer accepted (P7a
24
+ * fix wave, item 8's enabler). It was a back-compat spelling for "rows written before the profile
25
+ * existed", and there are none — the one shipped row uses the placeholder. Keeping it would mean
26
+ * a validator that calls a hard-coded product token impersonation in its own error message while
27
+ * accepting exactly that, and it was the last raw brand literal in the four source trees.
28
+ */
29
+ export declare const IDENTITY_PRODUCT_PLACEHOLDER = "<product>";
30
+ export declare const IDENTITY_VERSION_PLACEHOLDER = "<version>";
31
+ export declare const IDENTITY_CONTACT_PLACEHOLDER = "<contact>";
32
+ /**
33
+ * The closed vocabularies, exported as ONE object so the JSON Schema can be checked against the
34
+ * validator rather than the two drifting apart in silence.
35
+ *
36
+ * The schema is the cross-language contract (Lane X's generator, the Swift decoder) and nothing in
37
+ * this repo executes it — no ajv in the fence — so without a parity test its `enum` arrays are
38
+ * prose. A validator that rejects a value the schema permits (or the reverse) is a row that passes
39
+ * one gate and fails the other, discovered by whoever is furthest from the change.
40
+ */
41
+ export declare const CATALOG_VOCABULARIES: {
42
+ readonly protocols: readonly ProviderProtocol[];
43
+ readonly authKinds: readonly ProviderAuthKind[];
44
+ readonly evidenceSources: readonly EvidenceSource[];
45
+ readonly evidenceConfidences: readonly EvidenceConfidence[];
46
+ readonly toolCalling: readonly ToolCalling[];
47
+ readonly modelStatuses: readonly ModelStatus[];
48
+ readonly modelEndpoints: readonly ["chat", "responses", "embeddings", "image", "audio", "video"];
49
+ readonly modelDiscovery: readonly ["none", "openai-models", "provider-native", "local"];
50
+ readonly catalogAuthority: readonly ["authoritative", "partial", "unknown"];
51
+ readonly riskClasses: readonly ["approved", "review-required", "blocked"];
52
+ readonly providerScopes: readonly ["llm", "stt", "tts", "embedding", "image", "video", "search"];
53
+ readonly upstreamProjects: readonly ["OmniRoute", "winter"];
54
+ readonly pricingBases: readonly ["token", "subscription", "free"];
55
+ readonly admissionBases: readonly ["api-key", "oauth-documented", "keyless-documented", "local", "cloud-credential"];
56
+ readonly admissionTiers: readonly ["fetched-document", "pinned-upstream", "spec-ruling", "local", "audit"];
57
+ readonly slotBases: readonly SlotBasis[];
58
+ readonly slotStatuses: readonly SlotStatus[];
59
+ readonly familyStatuses: readonly ("candidate" | "supported")[];
60
+ readonly identityHeaderNames: readonly string[];
61
+ readonly continuations: readonly ["none", "plaintext", "opaque-provider-state", "server-response-handle"];
62
+ readonly readableStates: readonly ["none", "summary", "full-exposed"];
63
+ readonly replayScopes: readonly ["current-tool-loop", "current-turn", "selected-turns", "all-turns"];
64
+ readonly toolLoopRequirements: readonly ["hard-error", "silent-degradation", "not-required"];
65
+ };
66
+ /**
67
+ * Recursively scans any JSON value for credential material. Exported because Lane X's generator
68
+ * runs it over the RAW extraction before a row ever reaches a descriptor, and the catalog's own
69
+ * test runs it over the committed file — one implementation, two call sites, no drift.
70
+ *
71
+ * Depth- and breadth-bounded and cycle-safe: a hostile or malformed input can make it return
72
+ * findings, never hang or overflow the stack.
73
+ */
74
+ export declare function scanForSecrets(value: unknown, path?: string, seen?: Set<object>, depth?: number): string[];
75
+ /**
76
+ * A citation that names the audit's `unknown` evidence class rather than a document.
77
+ *
78
+ * Anchored, and case-insensitive on the class name only: `audit:unknown`, `audit:unknown-pending`,
79
+ * or the bare word. It deliberately does NOT match a URL that merely contains "unknown" somewhere in
80
+ * its path — the rule is about a row that admits it has no decisive document, not about spelling.
81
+ */
82
+ export declare const UNKNOWN_CITATION_RE: RegExp;
83
+ /**
84
+ * Validates any JSON value as a `WinterCatalog`. Never throws.
85
+ *
86
+ * Beyond per-field shape and closed-vocabulary checks it enforces the four structural invariants
87
+ * WS-13 §13's acceptance list names, plus the secrets floor:
88
+ *
89
+ * - provider `id` unique across the catalog;
90
+ * - model `key` unique across the catalog (this is the registry's primary index);
91
+ * - within ONE provider, `upstreamId ∪ aliases` is collision-free — alias scope is per-provider by
92
+ * design (two providers may both serve a model called `sonnet`), and an alias colliding with a
93
+ * sibling's real id would make resolution order load-bearing;
94
+ * - every model's `providerId` names a provider that exists (an orphan row is unresolvable);
95
+ * - no credential-shaped field or value anywhere in the document.
96
+ */
97
+ export declare function validateCatalog(json: unknown): CatalogValidationResult;
98
+ export type { WinterCatalog, WinterModelDescriptor, WinterProviderDescriptor };