@oh-my-pi/pi-catalog 17.4.0 → 17.4.2

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.
@@ -25,6 +25,12 @@ export declare enum DiagnosticSeverity {
25
25
  INFORMATION = 3,
26
26
  HINT = 4
27
27
  }
28
+ /** Cursor agent enum CursorRuleSource. */
29
+ export declare enum CursorRuleSource {
30
+ UNSPECIFIED = 0,
31
+ TEAM = 1,
32
+ USER = 2
33
+ }
28
34
  /** Cursor agent enum ForceBackgroundShellStatus. */
29
35
  export declare enum ForceBackgroundShellStatus {
30
36
  UNSPECIFIED = 0,
@@ -102,6 +102,13 @@ export declare const isMinimaxM3FamilyModelId: (modelId: string) => boolean;
102
102
  * and `none`.
103
103
  */
104
104
  export declare const isOpenAIGptOssModelId: (modelId: string) => boolean;
105
+ /**
106
+ * Meta Muse Spark ids (`muse-spark-1.1`, `muse-spark-1.2`,
107
+ * `muse-spark-1.2-contributor`, `meta/muse-spark-1.2`). The Responses
108
+ * `reasoning.effort` wire accepts `none` (thinking-off) plus
109
+ * `minimal`/`low`/`medium`/`high`/`xhigh`.
110
+ */
111
+ export declare const isMuseSparkModelId: (modelId: string) => boolean;
105
112
  /** OpenAI model ids (gpt-*, chatgpt-*, o1/o3/o4 SKUs, codex-*, or openai/*). */
106
113
  export declare const isOpenAIModelId: (modelId: string) => boolean;
107
114
  /**
@@ -16,3 +16,4 @@ export * from "./wire/codex.js";
16
16
  export * from "./wire/coreweave.js";
17
17
  export * from "./wire/gemini-headers.js";
18
18
  export * from "./wire/github-copilot.js";
19
+ export * from "./wire/image-fetchers.js";
@@ -31,11 +31,11 @@ export interface ModelManagerOptions<TApi extends Api = Api, TModelsDevPayload =
31
31
  /** Cached model ids whose presence forces refresh when the static or migration-policy fingerprint changes. */
32
32
  dropCachedModelIdsOnStaticMismatch?: readonly string[];
33
33
  /**
34
- * Trusted, provider-wide request headers (compile-time constants, never
35
- * credentials) that the cache may restore by value for any model whose live
36
- * headers matched them at write time. Lets header-bearing dynamic models
37
- * without a bundled static entry survive offline reads instead of being
38
- * dropped as unrestorable (e.g. GitHub Copilot's User-Agent + API version).
34
+ * Trusted, provider-wide request headers that can be safely re-derived at
35
+ * cache-read time. The cache never persists their values. Models whose live
36
+ * headers matched this record at write time can survive offline reads without
37
+ * a bundled static source, including configured discovery providers whose
38
+ * bearer header comes from the current local config.
39
39
  */
40
40
  restorableHeaderFallback?: Record<string, string>;
41
41
  /** Optional dynamic endpoint fetcher. */
@@ -2,6 +2,8 @@ export interface ModelCacheProviderIdOptions {
2
2
  apiKey?: string;
3
3
  baseUrl?: string;
4
4
  }
5
+ /** Whether a provider's model-cache namespace requires its resolved credential. */
6
+ export declare function isCredentialScopedModelCacheProvider(providerId: string): boolean;
5
7
  export declare function getDefaultModelDiscoveryBaseUrl(providerId: string): string | undefined;
6
8
  /** Resolve an Ollama model-cache namespace scoped to the normalized discovery endpoint. */
7
9
  export declare function resolveOllamaModelCacheProviderId(providerId: string, baseUrl?: string): string;
@@ -205,7 +205,7 @@ export declare const CATALOG_PROVIDERS: readonly [{
205
205
  readonly id: "litellm";
206
206
  readonly defaultModel: "claude-opus-4-8";
207
207
  readonly envVars: readonly ["LITELLM_API_KEY"];
208
- readonly createModelManagerOptions: (config: ModelManagerConfig) => import("../index.js").ModelManagerOptions<"openai-completions", unknown>;
208
+ readonly createModelManagerOptions: (config: ModelManagerConfig) => import("../index.js").ModelManagerOptions<import("../index.js").Api, unknown>;
209
209
  readonly catalogDiscovery: {
210
210
  readonly label: "LiteLLM";
211
211
  readonly allowUnauthenticated: true;
@@ -568,12 +568,14 @@ export interface FetchLiteLLMRichModelsOptions<TApi extends Api> {
568
568
  signal?: AbortSignal;
569
569
  timeoutMs?: number;
570
570
  referenceResolver?: (modelId: string) => ModelSpec<TApi> | undefined;
571
+ resolveApi?: (entry: Record<string, unknown>, modelId: string) => TApi;
571
572
  }
572
573
  export declare const OPENAI_COMPAT_DISCOVERY_DEFAULT_CONTEXT_WINDOW = 128000;
573
574
  export declare const OPENAI_COMPAT_DISCOVERY_DEFAULT_MAX_TOKENS = 32768;
574
575
  export declare function normalizeLiteLLMManagementBaseUrl(baseUrl: string): string;
576
+ export declare function resolveLiteLLMApi(entry: Record<string, unknown> | undefined, id: string, fallbackApi?: Api): Api;
575
577
  export declare function fetchLiteLLMRichModels<TApi extends Api>(options: FetchLiteLLMRichModelsOptions<TApi>): Promise<ModelSpec<TApi>[] | null>;
576
- export declare function litellmModelManagerOptions(config?: LiteLLMModelManagerConfig): ModelManagerOptions<"openai-completions">;
578
+ export declare function litellmModelManagerOptions(config?: LiteLLMModelManagerConfig): ModelManagerOptions<Api>;
577
579
  export interface VllmModelManagerConfig {
578
580
  apiKey?: string;
579
581
  baseUrl?: string;
@@ -123,7 +123,7 @@ export interface Usage {
123
123
  }
124
124
  export type OpenAIReasoningFormat = "openai" | "openrouter" | "zai" | "kimi" | "qwen" | "qwen-chat-template";
125
125
  export type OpenAIReasoningDisableMode = "omit" | "lowest-effort" | "none-effort" | "openrouter-enabled-false" | "zai-thinking-disabled" | "qwen-enable-thinking-false" | "qwen-template-false";
126
- export type OpenAIStreamMarkupHealingPattern = "kimi" | "dsml" | "thinking";
126
+ export type OpenAIStreamMarkupHealingPattern = "kimi" | "dsml" | "qwen" | "thinking";
127
127
  /**
128
128
  * Compatibility settings for openai-completions API.
129
129
  * Use this to override URL-based auto-detection for custom providers.
@@ -812,6 +812,8 @@ export interface Model<TApi extends Api = Api> {
812
812
  preferWebsockets?: boolean;
813
813
  /** Codex Responses Lite transport: send the lite marker and carry instructions/tools as input items (mirrors codex-rs `use_responses_lite`). */
814
814
  useResponsesLite?: boolean;
815
+ /** Codex Code Mode restriction: model expects tools routed through a programmatic exec surface (mirrors codex-rs `tool_mode`). */
816
+ toolMode?: "code_mode_only";
815
817
  /** Preferred model to switch to when context promotion is triggered (model id or provider/id). */
816
818
  contextPromotionTarget?: string;
817
819
  /** Preferred model to use only for compaction (model id or provider/id); the active session model is unchanged. */
@@ -58,7 +58,7 @@ export declare const ANTIGRAVITY_VARIANT_COLLAPSE_TABLE: VariantCollapseTable;
58
58
  /** `google-gemini-cli` Gemini families on the official CLI's level transport. */
59
59
  export declare const GEMINI_CLI_VARIANT_COLLAPSE_TABLE: VariantCollapseTable;
60
60
  export declare const DEVIN_VARIANT_COLLAPSE_TABLE: VariantCollapseTable;
61
- /** `cursor` Grok families: per-effort siblings collapsed per service-tier lane. */
61
+ /** `cursor` per-effort sibling families collapsed per service-tier lane: Grok 4.5/4.6 plus GPT-5.6 Luna/Sol/Terra. */
62
62
  export declare const CURSOR_VARIANT_COLLAPSE_TABLE: VariantCollapseTable;
63
63
  /** Provider id → hand collapse table. The CCA providers diverge on thinking transport. */
64
64
  export declare const VARIANT_COLLAPSE_TABLES: Readonly<Record<string, VariantCollapseTable>>;
@@ -91,10 +91,11 @@ export declare function isVariantCollapsedSpec(spec: VariantSpecLike): boolean;
91
91
  */
92
92
  export declare function collapseEffortVariants<TSpec extends VariantSpecLike>(specs: readonly TSpec[], table: VariantCollapseTable): TSpec[];
93
93
  /**
94
- * Collapse a full mixed-provider list: per provider, the hand table (when
95
- * registered) plus the automatic `X`/`X-thinking` pair rule. Used by the
96
- * catalog generator; the runtime equivalent lives at the model-manager merge
97
- * point. Output is regrouped by provider — callers re-sort.
94
+ * Collapse a full mixed-provider list: per provider, the hand table, Cursor's
95
+ * conservative live effort-sibling rule, and the automatic `X`/`X-thinking`
96
+ * pair rule. Used by the catalog generator; the runtime equivalent lives at
97
+ * the model-manager merge point. Output is regrouped by provider — callers
98
+ * re-sort.
98
99
  */
99
100
  export declare function collapseEffortVariantsAcrossProviders<TSpec extends VariantSpecLike>(specs: readonly TSpec[]): TSpec[];
100
101
  /**
@@ -107,29 +108,30 @@ export declare function collapseEffortVariantsAcrossProviders<TSpec extends Vari
107
108
  export declare function collapseBuiltModelVariants<TApi extends Api>(models: readonly Model<TApi>[]): Model<TApi>[];
108
109
  /**
109
110
  * Resolve a retired effort-tier variant id (collapsed member, recycled id) to
110
- * its replacement model id for `provider` via the hand table. Returns
111
- * `undefined` when the id is not a known alias; derived `X-thinking` members
112
- * resolve through `stripThinkingVariantToken` instead. Callers must try an
113
- * exact model lookup first — a live model always wins over an alias.
111
+ * its replacement model id for `provider` via hand-table or registered live
112
+ * aliases. Returns `undefined` when the id is not a known alias; derived
113
+ * `X-thinking` members also resolve through `stripThinkingVariantToken`.
114
+ * Callers must try an exact model lookup first — a live model always wins over
115
+ * an alias.
114
116
  */
115
117
  export declare function resolveVariantAlias(provider: Provider, modelId: string): string | undefined;
116
118
  /** Bare-id alias hit: replacement id plus the providers declaring it. */
117
119
  export interface BareVariantAliasHit {
118
120
  id: string;
119
- /** Providers whose table declares the alias — candidates from these win ties. */
121
+ /** Providers declaring the alias — candidates from these win ties. */
120
122
  providers: readonly Provider[];
121
123
  }
122
124
  /**
123
- * Provider-agnostic hand-table alias lookup for bare-id selectors. Returns
124
- * the declaring providers so callers can prefer their models when the
125
- * replacement id exists on unrelated providers too (e.g. a retired Cursor
126
- * tier id must not resolve to `openai/gpt-5.4`).
125
+ * Provider-agnostic alias lookup for bare-id selectors. Returns the declaring
126
+ * providers so callers can prefer their models when the replacement id exists
127
+ * on unrelated providers too (e.g. a retired Cursor tier id must not resolve
128
+ * to `openai/gpt-5.4`).
127
129
  */
128
130
  export declare function resolveBareVariantAlias(modelId: string): BareVariantAliasHit | undefined;
129
131
  /**
130
132
  * Reverse alias lookup: the retired ids that resolve to `modelId` for
131
- * `provider` via the hand table. Used to re-key config keyed by raw member
132
- * ids (models.yml `modelOverrides`, suppressed selectors) onto the collapsed
133
- * model. Empty for providers without a table.
133
+ * `provider` via hand-table or registered live aliases. Used to re-key config
134
+ * keyed by raw member ids (models.yml `modelOverrides`, suppressed selectors)
135
+ * onto the collapsed model.
134
136
  */
135
137
  export declare function getVariantAliasSources(provider: Provider, modelId: string): readonly string[];
@@ -26,6 +26,8 @@ export declare const OPENAI_HEADERS: {
26
26
  readonly RESPONSES_LITE: "x-openai-internal-codex-responses-lite";
27
27
  /** DeviceCheck attestation envelope (codex-rs `X_OAI_ATTESTATION_HEADER`); sent on ChatGPT-OAuth requests. */
28
28
  readonly ATTESTATION: "x-oai-attestation";
29
+ /** Client-declared data residency for region-pinned enterprise workspaces. */
30
+ readonly RESIDENCY: "x-openai-internal-codex-residency";
29
31
  };
30
32
  export declare const OPENAI_HEADER_VALUES: {
31
33
  readonly BETA_RESPONSES: "responses=experimental";
@@ -43,3 +45,22 @@ export declare const JWT_CLAIM_PATH: "https://api.openai.com/auth";
43
45
  * Returns undefined if the token is not a valid Codex JWT.
44
46
  */
45
47
  export declare function getCodexAccountId(accessToken: string): string | undefined;
48
+ /**
49
+ * Extract the account's data residency from a Codex JWT access token.
50
+ *
51
+ * Enterprise ChatGPT workspaces can be pinned to a region. Such a workspace
52
+ * rejects a Codex request whose egress does not match it — HTTP 401
53
+ * `Workspace is not authorized in this region.` — unless the client declares
54
+ * the residency itself. The token already carries it, so no configuration is
55
+ * needed: `chatgpt_data_residency` is the authoritative claim, with
56
+ * `chatgpt_compute_residency` as the fallback for tokens that only carry that.
57
+ *
58
+ * Returns undefined for a non-JWT token, or for the (common) accounts whose
59
+ * claims omit residency entirely — those workspaces are not region-pinned.
60
+ */
61
+ export declare function getCodexResidency(accessToken: string): string | undefined;
62
+ /**
63
+ * Adds the token's workspace residency to Codex request headers without
64
+ * replacing a caller-supplied value.
65
+ */
66
+ export declare function applyCodexResidencyHeader(headers: Headers | Record<string, string>, accessToken: string): void;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Identification of provider-side image fetchers.
3
+ *
4
+ * A request may carry an image either inline (base64) or as a URL. With a URL,
5
+ * the provider's backend performs its own server-side GET against that URL, so
6
+ * a local blob server sees an inbound request from vendor infrastructure rather
7
+ * than from the client. This module names those fetchers, letting a blob server
8
+ * attribute an inbound GET to the vendor that issued it — which is how a caller
9
+ * learns where a request actually landed when a router sits between them and
10
+ * the model.
11
+ *
12
+ * NOT an authentication mechanism. Every value here is a request header chosen
13
+ * by the caller and is trivially forged. Authorize blob reads with an
14
+ * unguessable URL (single-use capability token, short TTL) and treat a fetcher
15
+ * match as attribution/telemetry only.
16
+ *
17
+ * Each entry was captured from a live fetch triggered by handing that vendor's
18
+ * API a URL-sourced image.
19
+ */
20
+ /** Vendor whose infrastructure performed an inbound fetch. */
21
+ export type ImageFetcherVendor = "openai" | "anthropic" | "xai" | "google";
22
+ /** Registry key for a known fetcher. */
23
+ export type ImageFetcherId = "openai-file-downloader" | "anthropic-claude-user" | "anthropic-claude-user-preview" | "xai-image-api-fetch" | "google";
24
+ /** Request signature of one provider-side fetcher. */
25
+ export interface ImageFetcherIdentity {
26
+ vendor: ImageFetcherVendor;
27
+ /** Human-readable name for logs and UI. */
28
+ label: string;
29
+ /**
30
+ * `User-Agent` contract: an exact string for fetchers that send a fixed
31
+ * value, or a pattern for those embedding a client version.
32
+ */
33
+ userAgent: string | RegExp;
34
+ /**
35
+ * Vendor-proprietary headers observed alongside the agent, used to
36
+ * corroborate a `User-Agent` claim. Generic infrastructure headers
37
+ * (`traceparent`, `x-cloud-trace-context`) are deliberately excluded: they
38
+ * are emitted by unrelated infrastructure and corroborate nothing. Empty
39
+ * means the agent string is the only available signal, so
40
+ * {@link ImageFetcherMatch.corroborated} can never be true for that entry.
41
+ */
42
+ markerHeaders: readonly string[];
43
+ /** API surface the capture came from. */
44
+ observedVia: string;
45
+ /** Operational caveats a blob server should account for. */
46
+ note?: string;
47
+ }
48
+ /**
49
+ * Known provider-side fetchers.
50
+ *
51
+ * Agent contracts do not overlap — exact strings never collide with the
52
+ * versioned patterns — so lookup order carries no meaning.
53
+ */
54
+ export declare const IMAGE_FETCHERS: Readonly<Record<ImageFetcherId, ImageFetcherIdentity>>;
55
+ /** Attribution outcome for one inbound request. */
56
+ export interface ImageFetcherMatch {
57
+ id: ImageFetcherId;
58
+ identity: ImageFetcherIdentity;
59
+ /**
60
+ * Whether every proprietary marker header for the matched identity is
61
+ * present. Always false for identities declaring no markers — absence of
62
+ * corroboration is not evidence against the match.
63
+ */
64
+ corroborated: boolean;
65
+ }
66
+ /** Inbound header bag, as exposed by either `fetch` or a Node-style server. */
67
+ export type InboundHeaders = Headers | Readonly<Record<string, string | readonly string[] | undefined>>;
68
+ /**
69
+ * Attribute an inbound blob request to a known provider-side fetcher, or
70
+ * `null` when the agent matches none.
71
+ *
72
+ * Matches on `User-Agent` alone and reports marker-header corroboration
73
+ * separately; callers MUST NOT treat either as proof of origin. Gate access on
74
+ * the unguessable URL.
75
+ */
76
+ export declare function identifyImageFetcher(headers: InboundHeaders): ImageFetcherMatch | null;
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-catalog",
4
- "version": "17.4.0",
4
+ "version": "17.4.2",
5
5
  "description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
6
6
  "homepage": "https://omp.sh",
7
- "author": "Can Boluk",
7
+ "author": "Stencil Labs, Inc.",
8
8
  "license": "MIT",
9
9
  "repository": {
10
10
  "type": "git",
@@ -34,11 +34,11 @@
34
34
  "gen:proto": "bun scripts/generate-protocols.ts"
35
35
  },
36
36
  "dependencies": {
37
- "@oh-my-pi/omptype": "17.4.0",
38
- "@oh-my-pi/pi-utils": "17.4.0"
37
+ "@oh-my-pi/omptype": "17.4.2",
38
+ "@oh-my-pi/pi-utils": "17.4.2"
39
39
  },
40
40
  "devDependencies": {
41
- "@oh-my-pi/pi-ai": "17.4.0",
41
+ "@oh-my-pi/pi-ai": "17.4.2",
42
42
  "@types/bun": "^1.3.14"
43
43
  },
44
44
  "engines": {
@@ -48,6 +48,8 @@
48
48
  "src",
49
49
  "README.md",
50
50
  "CHANGELOG.md",
51
+ "LICENSE",
52
+ "THIRD-PARTY-NOTICES.txt",
51
53
  "dist/types"
52
54
  ],
53
55
  "exports": {
@@ -759,7 +759,7 @@ export function buildOpenAIResponsesCompat(spec: OpenAIResponsesSpecLike): Resol
759
759
  disableReasoningOnForcedToolChoice: isKimiModel,
760
760
  disableReasoningOnToolChoice: isDeepseekFamily && reasoningCapable && !isOpenRouter,
761
761
  supportsToolChoice: true,
762
- supportsForcedToolChoice: true,
762
+ supportsForcedToolChoice: spec.provider !== "opencode-go" && spec.provider !== "opencode-zen",
763
763
  supportsNamedToolChoice: STRING_ONLY_NAMED_TOOL_CHOICE_PROVIDERS[spec.provider] !== true,
764
764
  reasoningContentField: "reasoning_content",
765
765
  requiresReasoningContentForToolCalls:
@@ -68,6 +68,7 @@ const codexModelEntrySchema = type({
68
68
  "priority?": "unknown",
69
69
  "prefer_websockets?": "unknown",
70
70
  "use_responses_lite?": "unknown",
71
+ "tool_mode?": "unknown",
71
72
  });
72
73
 
73
74
  const codexModelsResponseSchema = type({
@@ -282,6 +283,7 @@ interface ParsedCodexModelEntry {
282
283
  input: ("text" | "image")[];
283
284
  preferWebsockets: boolean;
284
285
  useResponsesLite: boolean;
286
+ toolMode: boolean;
285
287
  priority: number;
286
288
  }
287
289
 
@@ -310,6 +312,7 @@ function parseCodexModelEntry(entry: unknown): ParsedCodexModelEntry | null {
310
312
  input: normalizeInputModalities(payload.input_modalities),
311
313
  preferWebsockets: toBoolean(payload.prefer_websockets) === true,
312
314
  useResponsesLite: toBoolean(payload.use_responses_lite) === true,
315
+ toolMode: payload.tool_mode === "code_mode_only",
313
316
  priority: toFiniteNumber(payload.priority) ?? Number.MAX_SAFE_INTEGER,
314
317
  };
315
318
  }
@@ -360,6 +363,7 @@ function buildNormalizedCodexModel(
360
363
  maxTokens,
361
364
  ...(parsed.preferWebsockets ? { preferWebsockets: true } : {}),
362
365
  ...(parsed.useResponsesLite ? { useResponsesLite: true } : {}),
366
+ ...(parsed.toolMode ? { toolMode: "code_mode_only" as const } : {}),
363
367
  ...(parsed.priority !== Number.MAX_SAFE_INTEGER ? { priority: parsed.priority } : {}),
364
368
  },
365
369
  };
@@ -31,6 +31,13 @@ export enum DiagnosticSeverity {
31
31
  HINT = 4,
32
32
  }
33
33
 
34
+ /** Cursor agent enum CursorRuleSource. */
35
+ export enum CursorRuleSource {
36
+ UNSPECIFIED = 0,
37
+ TEAM = 1,
38
+ USER = 2,
39
+ }
40
+
34
41
  /** Cursor agent enum ForceBackgroundShellStatus. */
35
42
  export enum ForceBackgroundShellStatus {
36
43
  UNSPECIFIED = 0,
@@ -209,6 +209,16 @@ export const isOpenAIGptOssModelId = memo((modelId: string): boolean => {
209
209
  return /(^|\/)gpt-oss[-:]/i.test(modelId);
210
210
  });
211
211
 
212
+ /**
213
+ * Meta Muse Spark ids (`muse-spark-1.1`, `muse-spark-1.2`,
214
+ * `muse-spark-1.2-contributor`, `meta/muse-spark-1.2`). The Responses
215
+ * `reasoning.effort` wire accepts `none` (thinking-off) plus
216
+ * `minimal`/`low`/`medium`/`high`/`xhigh`.
217
+ */
218
+ export const isMuseSparkModelId = memo((modelId: string): boolean => {
219
+ return /(^|\/)muse-spark(?:[-.]|$)/i.test(modelId);
220
+ });
221
+
212
222
  /** OpenAI model ids (gpt-*, chatgpt-*, o1/o3/o4 SKUs, codex-*, or openai/*). */
213
223
  export const isOpenAIModelId = memo((modelId: string): boolean => {
214
224
  return (
package/src/index.ts CHANGED
@@ -16,3 +16,4 @@ export * from "./wire/codex";
16
16
  export * from "./wire/coreweave";
17
17
  export * from "./wire/gemini-headers";
18
18
  export * from "./wire/github-copilot";
19
+ export * from "./wire/image-fetchers";
@@ -309,9 +309,9 @@ export function writeModelCache<TApi extends Api>(
309
309
  const staticHeaderSource =
310
310
  staticById.get(model.id) ?? (model.requestModelId ? staticById.get(model.requestModelId) : undefined);
311
311
  // A model with no static source is still restorable when its live
312
- // headers equal the provider's trusted constant (a compile-time,
313
- // non-credential value the reader can reattach by value). This keeps
314
- // reference-less Copilot models (e.g. claude-opus-5) alive offline.
312
+ // headers equal a trusted provider-wide fallback that the reader can
313
+ // re-derive without persisting it. This keeps reference-less models
314
+ // with constant or configured headers alive offline.
315
315
  const matchesStatic = staticHeaderSource
316
316
  ? headersEqual(model.headers, staticHeaderSource.headers)
317
317
  : headersEqual(model.headers, restorableHeaderFallback);
@@ -42,11 +42,11 @@ export interface ModelManagerOptions<TApi extends Api = Api, TModelsDevPayload =
42
42
  /** Cached model ids whose presence forces refresh when the static or migration-policy fingerprint changes. */
43
43
  dropCachedModelIdsOnStaticMismatch?: readonly string[];
44
44
  /**
45
- * Trusted, provider-wide request headers (compile-time constants, never
46
- * credentials) that the cache may restore by value for any model whose live
47
- * headers matched them at write time. Lets header-bearing dynamic models
48
- * without a bundled static entry survive offline reads instead of being
49
- * dropped as unrestorable (e.g. GitHub Copilot's User-Agent + API version).
45
+ * Trusted, provider-wide request headers that can be safely re-derived at
46
+ * cache-read time. The cache never persists their values. Models whose live
47
+ * headers matched this record at write time can survive offline reads without
48
+ * a bundled static source, including configured discovery providers whose
49
+ * bearer header comes from the current local config.
50
50
  */
51
51
  restorableHeaderFallback?: Record<string, string>;
52
52
  /** Optional dynamic endpoint fetcher. */