dsh-model-groups 0.3.8 → 0.3.10

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.
@@ -3,12 +3,12 @@
3
3
  "packageName": "@deepseek-ai/dsh-llm-pi-ai",
4
4
  "target": "node_modules/@deepseek-ai/dsh-llm-pi-ai/lib/index.js",
5
5
  "baseSha256": "070c839e2c00e2d5f7c5d82307ca3d84dbb2323e46979daf265908751bbe8ae8",
6
- "resultSha256": "bd5b251b3d1d8441ee7aa552b537d0331b3f8f78c0f9f26f3b5035e5a36fe5ed",
6
+ "resultSha256": "41db75564a03d9f97889ab9305414147be719b2d8063d86566b59dd1e7ae2a5c",
7
7
  "variants": [
8
8
  {
9
9
  "source": "multi-key revision before per-entry API overrides",
10
10
  "baseSha256": "070c839e2c00e2d5f7c5d82307ca3d84dbb2323e46979daf265908751bbe8ae8",
11
- "resultSha256": "56b60061cc2ca642d3572214a40dbd679390c7f5427e739a11b3230ac2169ded",
11
+ "resultSha256": "e8399ddb7b55a89b5ba8f5628ee78523bf51dc7ff7c175d1d841bd22a3cf0bf2",
12
12
  "replacements": [
13
13
  {
14
14
  "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
@@ -88,11 +88,11 @@
88
88
  },
89
89
  {
90
90
  "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
91
- "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tmodels: z.array(modelProfile).required()\n});"
91
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tmodels: z.array(modelProfile).required()\n});"
92
92
  },
93
93
  {
94
94
  "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
95
- "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (!Array.isArray(entry.models))"
95
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (entry.sortOrder !== void 0 && (!Number.isSafeInteger(entry.sortOrder) || entry.sortOrder < 0)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" sortOrder must be a nonnegative safe integer`);\n\t\t\tif (!Array.isArray(entry.models))"
96
96
  },
97
97
  {
98
98
  "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
@@ -125,13 +125,37 @@
125
125
  {
126
126
  "before": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${base.endsWith(\"/v1\") ? base.slice(0, -3) : base}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;",
127
127
  "after": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${anthropicRoot(base)}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;"
128
+ },
129
+ {
130
+ "before": "* gateway documentation publishes both spellings of the same root. Only this\n* listing URL normalizes that segment; model requests receive the configured\n* `baseURL` unchanged.\n*/",
131
+ "after": "* gateway documentation publishes both spellings of the same root. Anthropic\n* listings and model requests both normalize it, because the Anthropic SDK\n* appends `/v1/messages` on its own while OpenAI protocols append\n* `/chat/completions`; without this, one root would work for chat and double\n* the segment for Anthropic.\n*/"
132
+ },
133
+ {
134
+ "before": "const modelProfile = z.object({\n\tid: z.string().required(),\n\t...modelFields\n});",
135
+ "after": "function applyModelCapabilities(model, defaults) {\n const object = value => value !== null && typeof value === 'object' && !Array.isArray(value);\n const overrides = model.capabilityOverrides;\n if (defaults !== undefined && (!object(defaults) || Object.keys(defaults).some(key => key !== 'vision' && key !== 'reasoning') || typeof defaults.vision !== 'boolean' || typeof defaults.reasoning !== 'boolean')) {\n throw new TypeError('capabilityDefaults must contain only boolean vision and reasoning');\n }\n if (overrides !== undefined && (!object(overrides) || Object.keys(overrides).some(key => key !== 'vision' && key !== 'reasoning') || Object.values(overrides).some(value => typeof value !== 'boolean' && value !== 'original'))) {\n throw new TypeError('capabilityOverrides must contain only boolean or original vision and reasoning');\n }\n const { capabilityOverrides: ignored, ...effective } = model;\n if (defaults === undefined) return effective;\n const choice = key => overrides?.[key] === 'original' ? undefined : overrides?.[key] ?? defaults[key];\n const vision = choice('vision');\n if (vision !== undefined) {\n const input = Array.isArray(model.input) ? [...model.input] : ['text'];\n effective.input = [...new Set(input.filter(value => vision || value !== 'image'))];\n if (effective.input.length === 0) effective.input.push('text');\n if (vision && !effective.input.includes('image')) effective.input.push('image');\n }\n const reasoning = choice('reasoning');\n if (reasoning === false) effective.reasoningEfforts = false;\n if (reasoning === true) {\n const levels = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];\n const efforts = model.reasoningEfforts;\n const valid = object(efforts) && Object.keys(efforts).every(key => levels.includes(key)) && Object.entries(efforts).every(([key, value]) => key === 'off' && value === null || typeof value === 'string' && value.length > 0) && Object.keys(efforts).some(key => key !== 'off');\n effective.reasoningEfforts = valid ? { ...efforts } : { off: null, low: 'low', medium: 'medium', high: 'high' };\n }\n return effective;\n}\nconst capabilityDefaultsProfile = z.union([z.object({ vision: z.boolean().required(), reasoning: z.boolean().required() })]);\nconst capabilityOverridesProfile = z.union([z.object({ vision: z.union([z.boolean(), z.const(\"original\")]), reasoning: z.union([z.boolean(), z.const(\"original\")]) })]);\nconst modelProfile = z.object({\n\tid: z.string().required(),\n\t...modelFields,\n\tcapabilityOverrides: capabilityOverridesProfile\n});"
136
+ },
137
+ {
138
+ "before": "\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tmodels: z.array(modelProfile).required()",
139
+ "after": "\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tcapabilityDefaults: capabilityDefaultsProfile,\n\tmodels: z.array(modelProfile).required()"
140
+ },
141
+ {
142
+ "before": "\t\tassertWireModels(source.models, \"models\");",
143
+ "after": "\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const model of source.models ?? []) applyModelCapabilities(model);"
144
+ },
145
+ {
146
+ "before": "\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);",
147
+ "after": "\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t\tapplyModelCapabilities({}, entry.capabilityDefaults);\n\t\t\tfor (const model of entry.models) applyModelCapabilities(model, entry.capabilityDefaults);"
148
+ },
149
+ {
150
+ "before": "\t\t\t\tmodels: entry.models,",
151
+ "after": "\t\t\t\tmodels: entry.models.map(model => applyModelCapabilities(model, entry.capabilityDefaults)),"
128
152
  }
129
153
  ]
130
154
  },
131
155
  {
132
156
  "source": "multi-key revision before per-entry API overrides",
133
157
  "baseSha256": "070c839e2c00e2d5f7c5d82307ca3d84dbb2323e46979daf265908751bbe8ae8",
134
- "resultSha256": "7c234a4d68794ee54112583c4d4bfaf7c9819b9227c3149f58fa7584883c7aff",
158
+ "resultSha256": "759e4bf808f126e3f9509cf3fe48c8bbf0c2e72f7b9519da8215be516957d34d",
135
159
  "replacements": [
136
160
  {
137
161
  "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
@@ -211,11 +235,11 @@
211
235
  },
212
236
  {
213
237
  "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
214
- "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tmodels: z.array(modelProfile).required()\n});"
238
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tmodels: z.array(modelProfile).required()\n});"
215
239
  },
216
240
  {
217
241
  "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
218
- "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (!Array.isArray(entry.models))"
242
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (entry.sortOrder !== void 0 && (!Number.isSafeInteger(entry.sortOrder) || entry.sortOrder < 0)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" sortOrder must be a nonnegative safe integer`);\n\t\t\tif (!Array.isArray(entry.models))"
219
243
  },
220
244
  {
221
245
  "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
@@ -236,13 +260,49 @@
236
260
  {
237
261
  "before": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,",
238
262
  "after": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\tapi: profile.api,\n\t\t\tbaseURL: profile.baseURL ?? catalogProvider(provider)?.baseUrl,\n\t\t\theaders: profile.headers,"
263
+ },
264
+ {
265
+ "before": "function listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");",
266
+ "after": "/** Strip trailing slashes and one trailing `/v1`, the segment the Anthropic SDK adds itself. */\nfunction anthropicRoot(baseURL) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");\n\treturn base.endsWith(\"/v1\") ? base.slice(0, -3) : base;\n}\nfunction listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");"
267
+ },
268
+ {
269
+ "before": "\t\tconst baseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (baseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);",
270
+ "after": "\t\tconst configuredBaseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (configuredBaseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);\n\t\tconst baseUrl = api === \"anthropic-messages\" ? anthropicRoot(configuredBaseUrl) : configuredBaseUrl;"
271
+ },
272
+ {
273
+ "before": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${base.endsWith(\"/v1\") ? base.slice(0, -3) : base}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;",
274
+ "after": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${anthropicRoot(base)}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;"
275
+ },
276
+ {
277
+ "before": "* gateway documentation publishes both spellings of the same root. Only this\n* listing URL normalizes that segment; model requests receive the configured\n* `baseURL` unchanged.\n*/",
278
+ "after": "* gateway documentation publishes both spellings of the same root. Anthropic\n* listings and model requests both normalize it, because the Anthropic SDK\n* appends `/v1/messages` on its own while OpenAI protocols append\n* `/chat/completions`; without this, one root would work for chat and double\n* the segment for Anthropic.\n*/"
279
+ },
280
+ {
281
+ "before": "const modelProfile = z.object({\n\tid: z.string().required(),\n\t...modelFields\n});",
282
+ "after": "function applyModelCapabilities(model, defaults) {\n const object = value => value !== null && typeof value === 'object' && !Array.isArray(value);\n const overrides = model.capabilityOverrides;\n if (defaults !== undefined && (!object(defaults) || Object.keys(defaults).some(key => key !== 'vision' && key !== 'reasoning') || typeof defaults.vision !== 'boolean' || typeof defaults.reasoning !== 'boolean')) {\n throw new TypeError('capabilityDefaults must contain only boolean vision and reasoning');\n }\n if (overrides !== undefined && (!object(overrides) || Object.keys(overrides).some(key => key !== 'vision' && key !== 'reasoning') || Object.values(overrides).some(value => typeof value !== 'boolean' && value !== 'original'))) {\n throw new TypeError('capabilityOverrides must contain only boolean or original vision and reasoning');\n }\n const { capabilityOverrides: ignored, ...effective } = model;\n if (defaults === undefined) return effective;\n const choice = key => overrides?.[key] === 'original' ? undefined : overrides?.[key] ?? defaults[key];\n const vision = choice('vision');\n if (vision !== undefined) {\n const input = Array.isArray(model.input) ? [...model.input] : ['text'];\n effective.input = [...new Set(input.filter(value => vision || value !== 'image'))];\n if (!effective.input.includes('text')) effective.input.unshift('text');\n if (vision && !effective.input.includes('image')) effective.input.push('image');\n }\n const reasoning = choice('reasoning');\n if (reasoning === false) effective.reasoningEfforts = false;\n if (reasoning === true) {\n const levels = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];\n const efforts = model.reasoningEfforts;\n const valid = object(efforts) && Object.keys(efforts).every(key => levels.includes(key)) && Object.entries(efforts).every(([key, value]) => key === 'off' && value === null || typeof value === 'string' && value.length > 0) && Object.keys(efforts).some(key => key !== 'off');\n effective.reasoningEfforts = valid ? { ...efforts } : { off: null, low: 'low', medium: 'medium', high: 'high' };\n }\n return effective;\n}\nconst capabilityDefaultsProfile = z.union([z.object({ vision: z.boolean().required(), reasoning: z.boolean().required() })]);\nconst capabilityOverridesProfile = z.union([z.object({ vision: z.union([z.boolean(), z.const(\"original\")]), reasoning: z.union([z.boolean(), z.const(\"original\")]) })]);\nconst modelProfile = z.object({\n\tid: z.string().required(),\n\t...modelFields,\n\tcapabilityOverrides: capabilityOverridesProfile\n});"
283
+ },
284
+ {
285
+ "before": "\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tmodels: z.array(modelProfile).required()",
286
+ "after": "\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tcapabilityDefaults: capabilityDefaultsProfile,\n\tmodels: z.array(modelProfile).required()"
287
+ },
288
+ {
289
+ "before": "\t\tassertWireModels(source.models, \"models\");",
290
+ "after": "\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const model of source.models ?? []) applyModelCapabilities(model);"
291
+ },
292
+ {
293
+ "before": "\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);",
294
+ "after": "\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t\tapplyModelCapabilities({}, entry.capabilityDefaults);\n\t\t\tfor (const model of entry.models) applyModelCapabilities(model, entry.capabilityDefaults);"
295
+ },
296
+ {
297
+ "before": "\t\t\t\tmodels: entry.models,",
298
+ "after": "\t\t\t\tmodels: entry.models.map(model => applyModelCapabilities(model, entry.capabilityDefaults)),"
239
299
  }
240
300
  ]
241
301
  },
242
302
  {
243
303
  "source": "multi-key revision before per-entry API overrides",
244
304
  "baseSha256": "070c839e2c00e2d5f7c5d82307ca3d84dbb2323e46979daf265908751bbe8ae8",
245
- "resultSha256": "a7cd7d9731924338995b4693f180fb2986887d7908a4f56c13132461cacc4bb1",
305
+ "resultSha256": "7c91a878438fd82f047e365a07235aa0aabd62fb749a1bc0292fef91e0f16809",
246
306
  "replacements": [
247
307
  {
248
308
  "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
@@ -322,11 +382,11 @@
322
382
  },
323
383
  {
324
384
  "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
325
- "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tmodels: z.array(modelProfile).required()\n});"
385
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tmodels: z.array(modelProfile).required()\n});"
326
386
  },
327
387
  {
328
388
  "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
329
- "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (!Array.isArray(entry.models))"
389
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (entry.sortOrder !== void 0 && (!Number.isSafeInteger(entry.sortOrder) || entry.sortOrder < 0)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" sortOrder must be a nonnegative safe integer`);\n\t\t\tif (!Array.isArray(entry.models))"
330
390
  },
331
391
  {
332
392
  "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
@@ -334,7 +394,7 @@
334
394
  },
335
395
  {
336
396
  "before": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {",
337
- "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api ?? selectedStored?.api ?? \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
397
+ "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api !== void 0 ? request.api : selectedStored?.api !== void 0 ? selectedStored.api : \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
338
398
  },
339
399
  {
340
400
  "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);",
@@ -347,13 +407,29 @@
347
407
  {
348
408
  "before": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,",
349
409
  "after": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\tapi: profile.api,\n\t\t\tbaseURL: profile.baseURL ?? catalogProvider(provider)?.baseUrl,\n\t\t\theaders: profile.headers,"
410
+ },
411
+ {
412
+ "before": "function listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");",
413
+ "after": "/** Strip trailing slashes and one trailing `/v1`, the segment the Anthropic SDK adds itself. */\nfunction anthropicRoot(baseURL) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");\n\treturn base.endsWith(\"/v1\") ? base.slice(0, -3) : base;\n}\nfunction listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");"
414
+ },
415
+ {
416
+ "before": "\t\tconst baseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (baseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);",
417
+ "after": "\t\tconst configuredBaseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (configuredBaseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);\n\t\tconst baseUrl = api === \"anthropic-messages\" ? anthropicRoot(configuredBaseUrl) : configuredBaseUrl;"
418
+ },
419
+ {
420
+ "before": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${base.endsWith(\"/v1\") ? base.slice(0, -3) : base}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;",
421
+ "after": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${anthropicRoot(base)}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;"
422
+ },
423
+ {
424
+ "before": "* gateway documentation publishes both spellings of the same root. Only this\n* listing URL normalizes that segment; model requests receive the configured\n* `baseURL` unchanged.\n*/",
425
+ "after": "* gateway documentation publishes both spellings of the same root. Anthropic\n* listings and model requests both normalize it, because the Anthropic SDK\n* appends `/v1/messages` on its own while OpenAI protocols append\n* `/chat/completions`; without this, one root would work for chat and double\n* the segment for Anthropic.\n*/"
350
426
  }
351
427
  ]
352
428
  },
353
429
  {
354
430
  "source": "multi-key revision before per-entry API overrides",
355
431
  "baseSha256": "070c839e2c00e2d5f7c5d82307ca3d84dbb2323e46979daf265908751bbe8ae8",
356
- "resultSha256": "a2b3bcda38015026ed58074cef0d508bbd2d7cb1423c00331651fcbd1a9f6b55",
432
+ "resultSha256": "bd5b251b3d1d8441ee7aa552b537d0331b3f8f78c0f9f26f3b5035e5a36fe5ed",
357
433
  "replacements": [
358
434
  {
359
435
  "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
@@ -430,96 +506,57 @@
430
506
  {
431
507
  "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
432
508
  "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
433
- }
434
- ]
435
- },
436
- {
437
- "source": "0.2.2-rc.1 with tool lookup optimization and credential cancellation",
438
- "baseSha256": "0a99a2fc903a4285044b09114b3bd20ee1e612f39aa381e4a71b10d48ee9e9f7",
439
- "resultSha256": "c87f965d9fcc5bbcd386e98ea3b292b05ec7a55d80df1266e18234031b80990e",
440
- "replacements": [
441
- {
442
- "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
443
- "after": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\n// Model selection carries an opaque entry identity, never a credential or a wire alias.\nconst KEY_MODEL_PREFIX = \"@dsh-key/\";\nconst KEY_ENTRY_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;\nconst FORBIDDEN_KEY_ENTRY_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst AUTH_HEADER_NAMES = new Set([\"authorization\", \"proxy-authorization\", \"x-api-key\", \"api-key\", \"cf-aig-authorization\"]);\nfunction validKeyEntryId(id) {\n\treturn KEY_ENTRY_ID.test(id) && !FORBIDDEN_KEY_ENTRY_IDS.has(id);\n}\nfunction keyModelId(entryId, model) {\n\treturn `${KEY_MODEL_PREFIX}${encodeURIComponent(entryId)}/${encodeURIComponent(model)}`;\n}\nfunction keyModelRoute(model) {\n\tif (!model.startsWith(KEY_MODEL_PREFIX)) return void 0;\n\ttry {\n\t\tconst parts = model.slice(KEY_MODEL_PREFIX.length).split(\"/\");\n\t\tif (parts.length === 2) {\n\t\t\tconst entryId = decodeURIComponent(parts[0]);\n\t\t\tconst wireModel = decodeURIComponent(parts[1]);\n\t\t\tif (validKeyEntryId(entryId) && wireModel.length > 0 && !wireModel.startsWith(KEY_MODEL_PREFIX) && keyModelId(entryId, wireModel) === model) return { entryId, wireModel };\n\t\t}\n\t} catch {}\n\tthrow new LlmError(`invalid multi-key model selection \"${model}\"`, \"UNKNOWN_MODEL\");\n}\nconst keyEntryProfile = z.object({\n\tname: z.string().max(120).required(),\n\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});\nconst profile = z.object({\n\tmultiKey: z.boolean().default(false),\n\tkeyEntries: z.dict(keyEntryProfile).default({}),\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n"
444
- },
445
- {
446
- "before": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\") {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n",
447
- "after": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\", forKeyEntry = false) {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n"
448
- },
449
- {
450
- "before": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n",
451
- "after": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst entrySources = source.keyEntries ?? {};\n\t\tif (typeof entrySources !== \"object\" || entrySources === null || Array.isArray(entrySources)) throw new Error(`llm-pi-ai: provider \"${provider}\" keyEntries must be a dictionary`);\n\t\tconst assertWireModels = (models, site) => {\n\t\t\tfor (const model of models ?? []) if (typeof model.id !== \"string\" || model.id.length === 0 || model.id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} must use non-empty upstream model ids outside the reserved ${KEY_MODEL_PREFIX} prefix`);\n\t\t};\n\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const id of Object.keys(source.modelOverrides ?? {})) if (id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" modelOverrides uses reserved prefix ${KEY_MODEL_PREFIX}`);\n\t\tfor (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tif (!validKeyEntryId(id)) throw new Error(`llm-pi-ai: provider \"${provider}\" has an invalid key entry id \"${id}\"`);\n\t\t\tif (typeof entry !== \"object\" || entry === null || typeof entry.name !== \"string\" || entry.name.trim().length === 0 || entry.name.length > 120) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs a name of 1-120 characters`);\n\t\t\tif (typeof entry.apiKeyEnv !== \"string\" || entry.apiKeyEnv.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own apiKeyEnv`);\n\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own models list`);\n\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t}\n\t\tconst assertEntryHeaders = (headers, site) => {\n\t\t\tfor (const name of Object.keys(headers ?? {})) if (AUTH_HEADER_NAMES.has(name.toLowerCase())) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} authentication header \"${name}\" would override the selected key; remove it before enabling multiKey`);\n\t\t};\n\t\tif (source.multiKey === true || forKeyEntry) {\n\t\t\tassertEntryHeaders(source.headers, \"shared\");\n\t\t\tfor (const model of source.models ?? []) assertEntryHeaders(model.headers, `model \"${model.id}\"`);\n\t\t\tfor (const [id, override] of Object.entries(source.modelOverrides ?? {})) assertEntryHeaders(override.headers, `model override \"${id}\"`);\n\t\t}\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n"
452
- },
453
- {
454
- "before": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\ttry {\n\t\t\tcatalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n",
455
- "after": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tconst keyEntries = new Map();\n\t\t// Disabled entries remain stored, but cannot constrain legacy single-key runtime behavior.\n\t\tif (source.multiKey === true) for (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,\n\t\t\t\tkeyEntries: {},\n\t\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\t\tmodels: entry.models,\n\t\t\t\tmodelOverrides: void 0\n\t\t\t} }, validation, true).get(provider);\n\t\t\t// Entry auth must not consult a catalog provider's ambient/OAuth credential or endpoint.\n\t\t\tkeyEntries.set(id, {\n\t\t\t\t...child,\n\t\t\t\tkeyEntryId: id,\n\t\t\t\tkeyEntryName: entry.name,\n\t\t\t\t...child.piProvider === void 0 ? {} : { piProvider: { ...child.piProvider, auth: { apiKey: harnessApiKeyAuth(entry.name) } } }\n\t\t\t});\n\t\t}\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\tconst entryOnly = forKeyEntry && source.models.length === 0 || source.multiKey === true && keyEntries.size > 0 && (source.models ?? []).length === 0 && catalogModels(provider).size === 0;\n\t\ttry {\n\t\t\tif (entryOnly) catalog = { models: [], configuredMaxTokens: new Map(), modelErrors: new Map() };\n\t\t\telse catalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n"
456
- },
457
- {
458
- "before": "\t\t\t}, validation);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;",
459
- "after": "\t\t\t}, validation);\n\t\t\tif (source.multiKey === true || forKeyEntry) for (const model of catalog.models) assertEntryHeaders(model.headers, `resolved model \"${model.id}\"`);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;"
460
- },
461
- {
462
- "before": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },",
463
- "after": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, keyEntries: _keyEntries, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\tkeyEntries,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },"
464
- },
465
- {
466
- "before": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/**\n* pi-ai-backed multi-provider adapter.",
467
- "after": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/** Decode only the selected replay owner at the pi boundary; never merge equal wire ids across keys. */\nfunction replayContextForRoute(context, provider, requestedModel, wireModel) {\n\tconst selectedEntry = requestedModel.startsWith(KEY_MODEL_PREFIX);\n\treturn {\n\t\t...context,\n\t\tmessages: context.messages.map((message) => {\n\t\t\tif (message.role !== \"assistant\") return message;\n\t\t\tif (message.provider === provider && message.model === requestedModel) return { ...message, model: wireModel.id };\n\t\t\tif (!message.model.startsWith(KEY_MODEL_PREFIX) && !(selectedEntry && message.provider === provider && message.model === wireModel.id)) return message;\n\t\t\treturn {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tapi: \"dsh-foreign\",\n\t\t\t\tprovider: message.provider,\n\t\t\t\tmodel: \"dsh-foreign\",\n\t\t\t\tcontent: message.content.flatMap((block) => {\n\t\t\t\t\tif (block.type === \"thinking\") return [];\n\t\t\t\t\tif (block.type === \"text\") return [{ type: \"text\", text: block.text }];\n\t\t\t\t\tif (block.type === \"toolCall\") return [{ type: \"toolCall\", id: block.id, name: block.name, arguments: block.arguments }];\n\t\t\t\t\treturn [block];\n\t\t\t\t}),\n\t\t\t\tusage: message.usage,\n\t\t\t\tstopReason: message.stopReason,\n\t\t\t\ttimestamp: message.timestamp\n\t\t\t};\n\t\t})\n\t};\n}\n/**\n* pi-ai-backed multi-provider adapter."
468
- },
469
- {
470
- "before": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tfor (const profile of profiles.values()) if (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n",
471
- "after": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tconst entryModels = new Map();\n\t\tfor (const [provider, profile] of profiles) {\n\t\t\tif (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\t\tconst entries = new Map();\n\t\t\tfor (const [id, entry] of profile.keyEntries) {\n\t\t\t\tconst collection = createModels(this.config.auth);\n\t\t\t\tif (entry.piProvider !== void 0) collection.setProvider(entry.piProvider);\n\t\t\t\tentries.set(id, collection);\n\t\t\t}\n\t\t\tentryModels.set(provider, entries);\n\t\t}\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels,\n\t\t\tentryModels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n"
472
509
  },
473
510
  {
474
- "before": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst failure = profile.modelErrors.get(model) ?? (profile.piProvider === void 0 ? profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = snapshot.models.getModel(provider, model);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n",
475
- "after": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** Bind the public selection to an exact profile, independent model collection, and upstream id. */\n\trouteOf(snapshot, provider, model) {\n\t\tconst root = this.profileOf(snapshot, provider);\n\t\tconst entry = keyModelRoute(model);\n\t\tif (entry === void 0) return { profile: root, models: snapshot.models, wireModel: model };\n\t\tif (root.multiKey !== true) throw new LlmError(`multi-key selection is disabled for provider \"${provider}\"`, \"UNKNOWN_MODEL\");\n\t\tconst profile = root.keyEntries.get(entry.entryId);\n\t\tconst models = snapshot.entryModels.get(provider)?.get(entry.entryId);\n\t\tif (profile === void 0 || models === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${entry.entryId}\"`, \"UNKNOWN_MODEL\");\n\t\treturn { profile, models, wireModel: entry.wireModel };\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst route = this.routeOf(snapshot, provider, model);\n\t\tconst failure = route.profile.modelErrors.get(route.wireModel) ?? (route.profile.piProvider === void 0 ? route.profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = route.models.getModel(provider, route.wireModel);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n"
511
+ "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
512
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tmodels: z.array(modelProfile).required()\n});"
476
513
  },
477
514
  {
478
- "before": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\ttry {\n\t\t\t\tawait this.config.resolveApiKey(provider, profile);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return [];\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn snapshot.models.getModels(provider).map((model) => ({\n\t\t\t\tprovider,\n\t\t\t\tid: model.id,\n\t\t\t\tname: model.name,\n\t\t\t\tinputModalities: [...model.input]\n\t\t\t}));\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n",
479
- "after": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\tconst listed = [];\n\t\t\tconst append = async (owner, models, entryId) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst key = await this.config.resolveApiKey(provider, owner);\n\t\t\t\t\tif (entryId !== void 0 && (key === void 0 || key.length === 0)) return;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return;\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tfor (const model of models.getModels(provider)) listed.push({\n\t\t\t\t\tprovider,\n\t\t\t\t\tid: entryId === void 0 ? model.id : keyModelId(entryId, model.id),\n\t\t\t\t\tname: model.name,\n\t\t\t\t\tinputModalities: [...model.input]\n\t\t\t\t});\n\t\t\t};\n\t\t\t// Keep raw root models advertised so old sessions remain routable without changing keys.\n\t\t\tawait append(profile, snapshot.models);\n\t\t\tif (profile.multiKey === true) for (const [id, entry] of profile.keyEntries) await append(entry, snapshot.entryModels.get(provider).get(id), id);\n\t\t\treturn listed;\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n"
515
+ "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
516
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (!Array.isArray(entry.models))"
480
517
  },
481
518
  {
482
- "before": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(model);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n",
483
- "after": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst { profile, wireModel } = this.routeOf(snapshot, provider, model);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(wireModel);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n"
519
+ "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
520
+ "after": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\t...entry.api === void 0 ? {} : { api: entry.api },\n\t\t\t\tmultiKey: false,"
484
521
  },
485
522
  {
486
- "before": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => this.streamWithSnapshot(options, snapshot)\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot(options, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n",
487
- "after": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => {\n\t\t\t\tif (options.provider !== provider || options.model !== model) throw new LlmError(\"prepared multi-key model selection changed before adapter dispatch\", \"INVALID_CONFIG\");\n\t\t\t\t// Async generators are lazy; pin the owner before returning one to caller-owned code.\n\t\t\t\treturn this.streamWithSnapshot({ ...options, provider, model }, snapshot);\n\t\t\t}\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot({ ...options }, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n"
523
+ "before": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {",
524
+ "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api !== void 0 ? request.api : selectedStored?.api !== void 0 ? selectedStored.api : \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
488
525
  },
489
526
  {
490
- "before": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst profile = this.profileOf(snapshot, options.provider);\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n",
491
- "after": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst route = this.routeOf(snapshot, options.provider, options.model);\n\t\t\tconst profile = route.profile;\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n"
527
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);",
528
+ "after": "\tconst baseURL = request.baseURL ?? selectedStored?.baseURL;\n\tif (baseURL === void 0 || baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(baseURL, api);"
492
529
  },
493
530
  {
494
- "before": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n",
495
- "after": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tif (profile.keyEntryId !== void 0 && (apiKey === void 0 || apiKey.length === 0)) throw new LlmError(`provider \"${options.provider}\" key entry \"${profile.keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n"
531
+ "before": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),",
532
+ "after": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tapi: entry.api,\n\t\t\tmodels: entry.piProvider?.getModels(),"
496
533
  },
497
534
  {
498
- "before": "\t\t\t\tconst iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, model.id)[Symbol.asyncIterator]();",
499
- "after": "\t\t\t\tconst iterator = toStreamChunks(route.models.streamSimple(model, replayContextForRoute(context, options.provider, options.model, model), {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, options.model)[Symbol.asyncIterator]();"
535
+ "before": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,",
536
+ "after": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\tapi: profile.api,\n\t\t\tbaseURL: profile.baseURL ?? catalogProvider(provider)?.baseUrl,\n\t\t\theaders: profile.headers,"
500
537
  },
501
538
  {
502
- "before": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n",
503
- "after": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\t// Validate host-owned entry identity even on the installed-catalog shortcut.\n\tconst selectedStored = request.keyEntryId === void 0 ? void 0 : storedProfile?.();\n\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n"
539
+ "before": "function listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");",
540
+ "after": "/** Strip trailing slashes and one trailing `/v1`, the segment the Anthropic SDK adds itself. */\nfunction anthropicRoot(baseURL) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");\n\treturn base.endsWith(\"/v1\") ? base.slice(0, -3) : base;\n}\nfunction listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");"
504
541
  },
505
542
  {
506
- "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n",
507
- "after": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = selectedStored ?? storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n"
543
+ "before": "\t\tconst baseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (baseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);",
544
+ "after": "\t\tconst configuredBaseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (configuredBaseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);\n\t\tconst baseUrl = api === \"anthropic-messages\" ? anthropicRoot(configuredBaseUrl) : configuredBaseUrl;"
508
545
  },
509
546
  {
510
- "before": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n",
511
- "after": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy,\n\t\tmultiKey: profile.multiKey === true,\n\t\tapiKeyEnv: profile.apiKeyEnv,\n\t\tmodels: profile.piProvider?.getModels(),\n\t\tmodelErrors: [...profile.modelErrors],\n\t\tkeyEntries: [...profile.keyEntries].map(([id, entry]) => ({\n\t\t\tid,\n\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),\n\t\t\tmodelErrors: [...entry.modelErrors]\n\t\t})).sort((left, right) => left.id.localeCompare(right.id))\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n"
547
+ "before": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${base.endsWith(\"/v1\") ? base.slice(0, -3) : base}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;",
548
+ "after": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${anthropicRoot(base)}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;"
512
549
  },
513
550
  {
514
- "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
515
- "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
551
+ "before": "* gateway documentation publishes both spellings of the same root. Only this\n* listing URL normalizes that segment; model requests receive the configured\n* `baseURL` unchanged.\n*/",
552
+ "after": "* gateway documentation publishes both spellings of the same root. Anthropic\n* listings and model requests both normalize it, because the Anthropic SDK\n* appends `/v1/messages` on its own while OpenAI protocols append\n* `/chat/completions`; without this, one root would work for chat and double\n* the segment for Anthropic.\n*/"
516
553
  }
517
554
  ]
518
555
  },
519
556
  {
520
- "source": "npm official 0.2.2-rc.1",
521
- "baseSha256": "1a3ae58f9b4493e15459cc5000ec80f21b5d3f4a9dea6ffb6bc28e5b8817ae8a",
522
- "resultSha256": "b9416207cc7c27aff40cb2b877c9176e53809eb2f6dc741828c2ed6f6bdf541b",
557
+ "source": "multi-key revision before per-entry API overrides",
558
+ "baseSha256": "070c839e2c00e2d5f7c5d82307ca3d84dbb2323e46979daf265908751bbe8ae8",
559
+ "resultSha256": "56b60061cc2ca642d3572214a40dbd679390c7f5427e739a11b3230ac2169ded",
523
560
  "replacements": [
524
561
  {
525
562
  "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
@@ -596,13 +633,53 @@
596
633
  {
597
634
  "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
598
635
  "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
636
+ },
637
+ {
638
+ "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
639
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tmodels: z.array(modelProfile).required()\n});"
640
+ },
641
+ {
642
+ "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
643
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (!Array.isArray(entry.models))"
644
+ },
645
+ {
646
+ "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
647
+ "after": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\t...entry.api === void 0 ? {} : { api: entry.api },\n\t\t\t\tmultiKey: false,"
648
+ },
649
+ {
650
+ "before": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {",
651
+ "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api !== void 0 ? request.api : selectedStored?.api !== void 0 ? selectedStored.api : \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
652
+ },
653
+ {
654
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);",
655
+ "after": "\tconst baseURL = request.baseURL ?? selectedStored?.baseURL;\n\tif (baseURL === void 0 || baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(baseURL, api);"
656
+ },
657
+ {
658
+ "before": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),",
659
+ "after": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tapi: entry.api,\n\t\t\tmodels: entry.piProvider?.getModels(),"
660
+ },
661
+ {
662
+ "before": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,",
663
+ "after": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\tapi: profile.api,\n\t\t\tbaseURL: profile.baseURL ?? catalogProvider(provider)?.baseUrl,\n\t\t\theaders: profile.headers,"
664
+ },
665
+ {
666
+ "before": "function listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");",
667
+ "after": "/** Strip trailing slashes and one trailing `/v1`, the segment the Anthropic SDK adds itself. */\nfunction anthropicRoot(baseURL) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");\n\treturn base.endsWith(\"/v1\") ? base.slice(0, -3) : base;\n}\nfunction listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");"
668
+ },
669
+ {
670
+ "before": "\t\tconst baseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (baseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);",
671
+ "after": "\t\tconst configuredBaseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (configuredBaseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);\n\t\tconst baseUrl = api === \"anthropic-messages\" ? anthropicRoot(configuredBaseUrl) : configuredBaseUrl;"
672
+ },
673
+ {
674
+ "before": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${base.endsWith(\"/v1\") ? base.slice(0, -3) : base}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;",
675
+ "after": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${anthropicRoot(base)}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;"
599
676
  }
600
677
  ]
601
678
  },
602
679
  {
603
- "source": "npm official 0.2.2-rc.1 with per-entry API overrides",
604
- "baseSha256": "1a3ae58f9b4493e15459cc5000ec80f21b5d3f4a9dea6ffb6bc28e5b8817ae8a",
605
- "resultSha256": "5ea8e84da726c04caa6bb321cf41617051ad9a80444834328007643b09b43a32",
680
+ "source": "multi-key revision before per-entry API overrides",
681
+ "baseSha256": "070c839e2c00e2d5f7c5d82307ca3d84dbb2323e46979daf265908751bbe8ae8",
682
+ "resultSha256": "7c234a4d68794ee54112583c4d4bfaf7c9819b9227c3149f58fa7584883c7aff",
606
683
  "replacements": [
607
684
  {
608
685
  "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
@@ -694,7 +771,7 @@
694
771
  },
695
772
  {
696
773
  "before": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {",
697
- "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api ?? selectedStored?.api ?? \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
774
+ "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api !== void 0 ? request.api : selectedStored?.api !== void 0 ? selectedStored.api : \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
698
775
  },
699
776
  {
700
777
  "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);",
@@ -711,9 +788,9 @@
711
788
  ]
712
789
  },
713
790
  {
714
- "source": "npm official 0.2.2-rc.1 with per-entry API overrides",
715
- "baseSha256": "1a3ae58f9b4493e15459cc5000ec80f21b5d3f4a9dea6ffb6bc28e5b8817ae8a",
716
- "resultSha256": "9ca2b07c19694a4521a29c82b7948fb6326d80ee7741200a1d7b0f3f06e1da19",
791
+ "source": "multi-key revision before per-entry API overrides",
792
+ "baseSha256": "070c839e2c00e2d5f7c5d82307ca3d84dbb2323e46979daf265908751bbe8ae8",
793
+ "resultSha256": "a7cd7d9731924338995b4693f180fb2986887d7908a4f56c13132461cacc4bb1",
717
794
  "replacements": [
718
795
  {
719
796
  "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
@@ -805,7 +882,7 @@
805
882
  },
806
883
  {
807
884
  "before": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {",
808
- "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api !== void 0 ? request.api : selectedStored?.api !== void 0 ? selectedStored.api : \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
885
+ "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api ?? selectedStored?.api ?? \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
809
886
  },
810
887
  {
811
888
  "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);",
@@ -822,9 +899,9 @@
822
899
  ]
823
900
  },
824
901
  {
825
- "source": "0.2.2-rc.1 with tool lookup optimization and credential cancellation with per-entry API overrides",
826
- "baseSha256": "0a99a2fc903a4285044b09114b3bd20ee1e612f39aa381e4a71b10d48ee9e9f7",
827
- "resultSha256": "e999e1a7f2352177c653ff0cea6485c3b1d1ea95b40ea613fc0549e2c8e49662",
902
+ "source": "multi-key revision before per-entry API overrides",
903
+ "baseSha256": "070c839e2c00e2d5f7c5d82307ca3d84dbb2323e46979daf265908751bbe8ae8",
904
+ "resultSha256": "a2b3bcda38015026ed58074cef0d508bbd2d7cb1423c00331651fcbd1a9f6b55",
828
905
  "replacements": [
829
906
  {
830
907
  "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
@@ -901,41 +978,13 @@
901
978
  {
902
979
  "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
903
980
  "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
904
- },
905
- {
906
- "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
907
- "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tmodels: z.array(modelProfile).required()\n});"
908
- },
909
- {
910
- "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
911
- "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (!Array.isArray(entry.models))"
912
- },
913
- {
914
- "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
915
- "after": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\t...entry.api === void 0 ? {} : { api: entry.api },\n\t\t\t\tmultiKey: false,"
916
- },
917
- {
918
- "before": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {",
919
- "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api !== void 0 ? request.api : selectedStored?.api !== void 0 ? selectedStored.api : \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
920
- },
921
- {
922
- "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);",
923
- "after": "\tconst baseURL = request.baseURL ?? selectedStored?.baseURL;\n\tif (baseURL === void 0 || baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(baseURL, api);"
924
- },
925
- {
926
- "before": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),",
927
- "after": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tapi: entry.api,\n\t\t\tmodels: entry.piProvider?.getModels(),"
928
- },
929
- {
930
- "before": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,",
931
- "after": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\tapi: profile.api,\n\t\t\tbaseURL: profile.baseURL ?? catalogProvider(provider)?.baseUrl,\n\t\t\theaders: profile.headers,"
932
981
  }
933
982
  ]
934
983
  },
935
984
  {
936
- "source": "0.2.2-rc.1 with tool lookup optimization and credential cancellation with per-entry API overrides",
985
+ "source": "0.2.2-rc.1 with tool lookup optimization and credential cancellation",
937
986
  "baseSha256": "0a99a2fc903a4285044b09114b3bd20ee1e612f39aa381e4a71b10d48ee9e9f7",
938
- "resultSha256": "0a398e35a7e66f0cb547da9c421e33123b9959bd058c3d006baf3c587ff4c596",
987
+ "resultSha256": "c87f965d9fcc5bbcd386e98ea3b292b05ec7a55d80df1266e18234031b80990e",
939
988
  "replacements": [
940
989
  {
941
990
  "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
@@ -1012,14 +1061,1414 @@
1012
1061
  {
1013
1062
  "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
1014
1063
  "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
1015
- },
1064
+ }
1065
+ ]
1066
+ },
1067
+ {
1068
+ "source": "npm official 0.2.2-rc.1",
1069
+ "baseSha256": "1a3ae58f9b4493e15459cc5000ec80f21b5d3f4a9dea6ffb6bc28e5b8817ae8a",
1070
+ "resultSha256": "b9416207cc7c27aff40cb2b877c9176e53809eb2f6dc741828c2ed6f6bdf541b",
1071
+ "replacements": [
1016
1072
  {
1017
- "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
1018
- "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tmodels: z.array(modelProfile).required()\n});"
1073
+ "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
1074
+ "after": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\n// Model selection carries an opaque entry identity, never a credential or a wire alias.\nconst KEY_MODEL_PREFIX = \"@dsh-key/\";\nconst KEY_ENTRY_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;\nconst FORBIDDEN_KEY_ENTRY_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst AUTH_HEADER_NAMES = new Set([\"authorization\", \"proxy-authorization\", \"x-api-key\", \"api-key\", \"cf-aig-authorization\"]);\nfunction validKeyEntryId(id) {\n\treturn KEY_ENTRY_ID.test(id) && !FORBIDDEN_KEY_ENTRY_IDS.has(id);\n}\nfunction keyModelId(entryId, model) {\n\treturn `${KEY_MODEL_PREFIX}${encodeURIComponent(entryId)}/${encodeURIComponent(model)}`;\n}\nfunction keyModelRoute(model) {\n\tif (!model.startsWith(KEY_MODEL_PREFIX)) return void 0;\n\ttry {\n\t\tconst parts = model.slice(KEY_MODEL_PREFIX.length).split(\"/\");\n\t\tif (parts.length === 2) {\n\t\t\tconst entryId = decodeURIComponent(parts[0]);\n\t\t\tconst wireModel = decodeURIComponent(parts[1]);\n\t\t\tif (validKeyEntryId(entryId) && wireModel.length > 0 && !wireModel.startsWith(KEY_MODEL_PREFIX) && keyModelId(entryId, wireModel) === model) return { entryId, wireModel };\n\t\t}\n\t} catch {}\n\tthrow new LlmError(`invalid multi-key model selection \"${model}\"`, \"UNKNOWN_MODEL\");\n}\nconst keyEntryProfile = z.object({\n\tname: z.string().max(120).required(),\n\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});\nconst profile = z.object({\n\tmultiKey: z.boolean().default(false),\n\tkeyEntries: z.dict(keyEntryProfile).default({}),\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n"
1075
+ },
1076
+ {
1077
+ "before": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\") {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n",
1078
+ "after": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\", forKeyEntry = false) {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n"
1079
+ },
1080
+ {
1081
+ "before": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n",
1082
+ "after": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst entrySources = source.keyEntries ?? {};\n\t\tif (typeof entrySources !== \"object\" || entrySources === null || Array.isArray(entrySources)) throw new Error(`llm-pi-ai: provider \"${provider}\" keyEntries must be a dictionary`);\n\t\tconst assertWireModels = (models, site) => {\n\t\t\tfor (const model of models ?? []) if (typeof model.id !== \"string\" || model.id.length === 0 || model.id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} must use non-empty upstream model ids outside the reserved ${KEY_MODEL_PREFIX} prefix`);\n\t\t};\n\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const id of Object.keys(source.modelOverrides ?? {})) if (id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" modelOverrides uses reserved prefix ${KEY_MODEL_PREFIX}`);\n\t\tfor (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tif (!validKeyEntryId(id)) throw new Error(`llm-pi-ai: provider \"${provider}\" has an invalid key entry id \"${id}\"`);\n\t\t\tif (typeof entry !== \"object\" || entry === null || typeof entry.name !== \"string\" || entry.name.trim().length === 0 || entry.name.length > 120) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs a name of 1-120 characters`);\n\t\t\tif (typeof entry.apiKeyEnv !== \"string\" || entry.apiKeyEnv.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own apiKeyEnv`);\n\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own models list`);\n\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t}\n\t\tconst assertEntryHeaders = (headers, site) => {\n\t\t\tfor (const name of Object.keys(headers ?? {})) if (AUTH_HEADER_NAMES.has(name.toLowerCase())) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} authentication header \"${name}\" would override the selected key; remove it before enabling multiKey`);\n\t\t};\n\t\tif (source.multiKey === true || forKeyEntry) {\n\t\t\tassertEntryHeaders(source.headers, \"shared\");\n\t\t\tfor (const model of source.models ?? []) assertEntryHeaders(model.headers, `model \"${model.id}\"`);\n\t\t\tfor (const [id, override] of Object.entries(source.modelOverrides ?? {})) assertEntryHeaders(override.headers, `model override \"${id}\"`);\n\t\t}\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n"
1083
+ },
1084
+ {
1085
+ "before": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\ttry {\n\t\t\tcatalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n",
1086
+ "after": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tconst keyEntries = new Map();\n\t\t// Disabled entries remain stored, but cannot constrain legacy single-key runtime behavior.\n\t\tif (source.multiKey === true) for (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,\n\t\t\t\tkeyEntries: {},\n\t\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\t\tmodels: entry.models,\n\t\t\t\tmodelOverrides: void 0\n\t\t\t} }, validation, true).get(provider);\n\t\t\t// Entry auth must not consult a catalog provider's ambient/OAuth credential or endpoint.\n\t\t\tkeyEntries.set(id, {\n\t\t\t\t...child,\n\t\t\t\tkeyEntryId: id,\n\t\t\t\tkeyEntryName: entry.name,\n\t\t\t\t...child.piProvider === void 0 ? {} : { piProvider: { ...child.piProvider, auth: { apiKey: harnessApiKeyAuth(entry.name) } } }\n\t\t\t});\n\t\t}\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\tconst entryOnly = forKeyEntry && source.models.length === 0 || source.multiKey === true && keyEntries.size > 0 && (source.models ?? []).length === 0 && catalogModels(provider).size === 0;\n\t\ttry {\n\t\t\tif (entryOnly) catalog = { models: [], configuredMaxTokens: new Map(), modelErrors: new Map() };\n\t\t\telse catalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n"
1087
+ },
1088
+ {
1089
+ "before": "\t\t\t}, validation);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;",
1090
+ "after": "\t\t\t}, validation);\n\t\t\tif (source.multiKey === true || forKeyEntry) for (const model of catalog.models) assertEntryHeaders(model.headers, `resolved model \"${model.id}\"`);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;"
1091
+ },
1092
+ {
1093
+ "before": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },",
1094
+ "after": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, keyEntries: _keyEntries, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\tkeyEntries,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },"
1095
+ },
1096
+ {
1097
+ "before": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/**\n* pi-ai-backed multi-provider adapter.",
1098
+ "after": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/** Decode only the selected replay owner at the pi boundary; never merge equal wire ids across keys. */\nfunction replayContextForRoute(context, provider, requestedModel, wireModel) {\n\tconst selectedEntry = requestedModel.startsWith(KEY_MODEL_PREFIX);\n\treturn {\n\t\t...context,\n\t\tmessages: context.messages.map((message) => {\n\t\t\tif (message.role !== \"assistant\") return message;\n\t\t\tif (message.provider === provider && message.model === requestedModel) return { ...message, model: wireModel.id };\n\t\t\tif (!message.model.startsWith(KEY_MODEL_PREFIX) && !(selectedEntry && message.provider === provider && message.model === wireModel.id)) return message;\n\t\t\treturn {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tapi: \"dsh-foreign\",\n\t\t\t\tprovider: message.provider,\n\t\t\t\tmodel: \"dsh-foreign\",\n\t\t\t\tcontent: message.content.flatMap((block) => {\n\t\t\t\t\tif (block.type === \"thinking\") return [];\n\t\t\t\t\tif (block.type === \"text\") return [{ type: \"text\", text: block.text }];\n\t\t\t\t\tif (block.type === \"toolCall\") return [{ type: \"toolCall\", id: block.id, name: block.name, arguments: block.arguments }];\n\t\t\t\t\treturn [block];\n\t\t\t\t}),\n\t\t\t\tusage: message.usage,\n\t\t\t\tstopReason: message.stopReason,\n\t\t\t\ttimestamp: message.timestamp\n\t\t\t};\n\t\t})\n\t};\n}\n/**\n* pi-ai-backed multi-provider adapter."
1099
+ },
1100
+ {
1101
+ "before": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tfor (const profile of profiles.values()) if (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n",
1102
+ "after": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tconst entryModels = new Map();\n\t\tfor (const [provider, profile] of profiles) {\n\t\t\tif (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\t\tconst entries = new Map();\n\t\t\tfor (const [id, entry] of profile.keyEntries) {\n\t\t\t\tconst collection = createModels(this.config.auth);\n\t\t\t\tif (entry.piProvider !== void 0) collection.setProvider(entry.piProvider);\n\t\t\t\tentries.set(id, collection);\n\t\t\t}\n\t\t\tentryModels.set(provider, entries);\n\t\t}\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels,\n\t\t\tentryModels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n"
1103
+ },
1104
+ {
1105
+ "before": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst failure = profile.modelErrors.get(model) ?? (profile.piProvider === void 0 ? profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = snapshot.models.getModel(provider, model);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n",
1106
+ "after": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** Bind the public selection to an exact profile, independent model collection, and upstream id. */\n\trouteOf(snapshot, provider, model) {\n\t\tconst root = this.profileOf(snapshot, provider);\n\t\tconst entry = keyModelRoute(model);\n\t\tif (entry === void 0) return { profile: root, models: snapshot.models, wireModel: model };\n\t\tif (root.multiKey !== true) throw new LlmError(`multi-key selection is disabled for provider \"${provider}\"`, \"UNKNOWN_MODEL\");\n\t\tconst profile = root.keyEntries.get(entry.entryId);\n\t\tconst models = snapshot.entryModels.get(provider)?.get(entry.entryId);\n\t\tif (profile === void 0 || models === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${entry.entryId}\"`, \"UNKNOWN_MODEL\");\n\t\treturn { profile, models, wireModel: entry.wireModel };\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst route = this.routeOf(snapshot, provider, model);\n\t\tconst failure = route.profile.modelErrors.get(route.wireModel) ?? (route.profile.piProvider === void 0 ? route.profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = route.models.getModel(provider, route.wireModel);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n"
1107
+ },
1108
+ {
1109
+ "before": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\ttry {\n\t\t\t\tawait this.config.resolveApiKey(provider, profile);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return [];\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn snapshot.models.getModels(provider).map((model) => ({\n\t\t\t\tprovider,\n\t\t\t\tid: model.id,\n\t\t\t\tname: model.name,\n\t\t\t\tinputModalities: [...model.input]\n\t\t\t}));\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n",
1110
+ "after": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\tconst listed = [];\n\t\t\tconst append = async (owner, models, entryId) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst key = await this.config.resolveApiKey(provider, owner);\n\t\t\t\t\tif (entryId !== void 0 && (key === void 0 || key.length === 0)) return;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return;\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tfor (const model of models.getModels(provider)) listed.push({\n\t\t\t\t\tprovider,\n\t\t\t\t\tid: entryId === void 0 ? model.id : keyModelId(entryId, model.id),\n\t\t\t\t\tname: model.name,\n\t\t\t\t\tinputModalities: [...model.input]\n\t\t\t\t});\n\t\t\t};\n\t\t\t// Keep raw root models advertised so old sessions remain routable without changing keys.\n\t\t\tawait append(profile, snapshot.models);\n\t\t\tif (profile.multiKey === true) for (const [id, entry] of profile.keyEntries) await append(entry, snapshot.entryModels.get(provider).get(id), id);\n\t\t\treturn listed;\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n"
1111
+ },
1112
+ {
1113
+ "before": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(model);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n",
1114
+ "after": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst { profile, wireModel } = this.routeOf(snapshot, provider, model);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(wireModel);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n"
1115
+ },
1116
+ {
1117
+ "before": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => this.streamWithSnapshot(options, snapshot)\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot(options, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n",
1118
+ "after": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => {\n\t\t\t\tif (options.provider !== provider || options.model !== model) throw new LlmError(\"prepared multi-key model selection changed before adapter dispatch\", \"INVALID_CONFIG\");\n\t\t\t\t// Async generators are lazy; pin the owner before returning one to caller-owned code.\n\t\t\t\treturn this.streamWithSnapshot({ ...options, provider, model }, snapshot);\n\t\t\t}\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot({ ...options }, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n"
1119
+ },
1120
+ {
1121
+ "before": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst profile = this.profileOf(snapshot, options.provider);\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n",
1122
+ "after": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst route = this.routeOf(snapshot, options.provider, options.model);\n\t\t\tconst profile = route.profile;\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n"
1123
+ },
1124
+ {
1125
+ "before": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n",
1126
+ "after": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tif (profile.keyEntryId !== void 0 && (apiKey === void 0 || apiKey.length === 0)) throw new LlmError(`provider \"${options.provider}\" key entry \"${profile.keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n"
1127
+ },
1128
+ {
1129
+ "before": "\t\t\t\tconst iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, model.id)[Symbol.asyncIterator]();",
1130
+ "after": "\t\t\t\tconst iterator = toStreamChunks(route.models.streamSimple(model, replayContextForRoute(context, options.provider, options.model, model), {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, options.model)[Symbol.asyncIterator]();"
1131
+ },
1132
+ {
1133
+ "before": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n",
1134
+ "after": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\t// Validate host-owned entry identity even on the installed-catalog shortcut.\n\tconst selectedStored = request.keyEntryId === void 0 ? void 0 : storedProfile?.();\n\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n"
1135
+ },
1136
+ {
1137
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n",
1138
+ "after": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = selectedStored ?? storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n"
1139
+ },
1140
+ {
1141
+ "before": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n",
1142
+ "after": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy,\n\t\tmultiKey: profile.multiKey === true,\n\t\tapiKeyEnv: profile.apiKeyEnv,\n\t\tmodels: profile.piProvider?.getModels(),\n\t\tmodelErrors: [...profile.modelErrors],\n\t\tkeyEntries: [...profile.keyEntries].map(([id, entry]) => ({\n\t\t\tid,\n\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),\n\t\t\tmodelErrors: [...entry.modelErrors]\n\t\t})).sort((left, right) => left.id.localeCompare(right.id))\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n"
1143
+ },
1144
+ {
1145
+ "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
1146
+ "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
1147
+ }
1148
+ ]
1149
+ },
1150
+ {
1151
+ "source": "npm official 0.2.2-rc.1 with per-entry API overrides",
1152
+ "baseSha256": "1a3ae58f9b4493e15459cc5000ec80f21b5d3f4a9dea6ffb6bc28e5b8817ae8a",
1153
+ "resultSha256": "5ea8e84da726c04caa6bb321cf41617051ad9a80444834328007643b09b43a32",
1154
+ "replacements": [
1155
+ {
1156
+ "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
1157
+ "after": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\n// Model selection carries an opaque entry identity, never a credential or a wire alias.\nconst KEY_MODEL_PREFIX = \"@dsh-key/\";\nconst KEY_ENTRY_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;\nconst FORBIDDEN_KEY_ENTRY_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst AUTH_HEADER_NAMES = new Set([\"authorization\", \"proxy-authorization\", \"x-api-key\", \"api-key\", \"cf-aig-authorization\"]);\nfunction validKeyEntryId(id) {\n\treturn KEY_ENTRY_ID.test(id) && !FORBIDDEN_KEY_ENTRY_IDS.has(id);\n}\nfunction keyModelId(entryId, model) {\n\treturn `${KEY_MODEL_PREFIX}${encodeURIComponent(entryId)}/${encodeURIComponent(model)}`;\n}\nfunction keyModelRoute(model) {\n\tif (!model.startsWith(KEY_MODEL_PREFIX)) return void 0;\n\ttry {\n\t\tconst parts = model.slice(KEY_MODEL_PREFIX.length).split(\"/\");\n\t\tif (parts.length === 2) {\n\t\t\tconst entryId = decodeURIComponent(parts[0]);\n\t\t\tconst wireModel = decodeURIComponent(parts[1]);\n\t\t\tif (validKeyEntryId(entryId) && wireModel.length > 0 && !wireModel.startsWith(KEY_MODEL_PREFIX) && keyModelId(entryId, wireModel) === model) return { entryId, wireModel };\n\t\t}\n\t} catch {}\n\tthrow new LlmError(`invalid multi-key model selection \"${model}\"`, \"UNKNOWN_MODEL\");\n}\nconst keyEntryProfile = z.object({\n\tname: z.string().max(120).required(),\n\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});\nconst profile = z.object({\n\tmultiKey: z.boolean().default(false),\n\tkeyEntries: z.dict(keyEntryProfile).default({}),\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n"
1158
+ },
1159
+ {
1160
+ "before": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\") {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n",
1161
+ "after": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\", forKeyEntry = false) {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n"
1162
+ },
1163
+ {
1164
+ "before": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n",
1165
+ "after": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst entrySources = source.keyEntries ?? {};\n\t\tif (typeof entrySources !== \"object\" || entrySources === null || Array.isArray(entrySources)) throw new Error(`llm-pi-ai: provider \"${provider}\" keyEntries must be a dictionary`);\n\t\tconst assertWireModels = (models, site) => {\n\t\t\tfor (const model of models ?? []) if (typeof model.id !== \"string\" || model.id.length === 0 || model.id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} must use non-empty upstream model ids outside the reserved ${KEY_MODEL_PREFIX} prefix`);\n\t\t};\n\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const id of Object.keys(source.modelOverrides ?? {})) if (id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" modelOverrides uses reserved prefix ${KEY_MODEL_PREFIX}`);\n\t\tfor (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tif (!validKeyEntryId(id)) throw new Error(`llm-pi-ai: provider \"${provider}\" has an invalid key entry id \"${id}\"`);\n\t\t\tif (typeof entry !== \"object\" || entry === null || typeof entry.name !== \"string\" || entry.name.trim().length === 0 || entry.name.length > 120) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs a name of 1-120 characters`);\n\t\t\tif (typeof entry.apiKeyEnv !== \"string\" || entry.apiKeyEnv.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own apiKeyEnv`);\n\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own models list`);\n\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t}\n\t\tconst assertEntryHeaders = (headers, site) => {\n\t\t\tfor (const name of Object.keys(headers ?? {})) if (AUTH_HEADER_NAMES.has(name.toLowerCase())) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} authentication header \"${name}\" would override the selected key; remove it before enabling multiKey`);\n\t\t};\n\t\tif (source.multiKey === true || forKeyEntry) {\n\t\t\tassertEntryHeaders(source.headers, \"shared\");\n\t\t\tfor (const model of source.models ?? []) assertEntryHeaders(model.headers, `model \"${model.id}\"`);\n\t\t\tfor (const [id, override] of Object.entries(source.modelOverrides ?? {})) assertEntryHeaders(override.headers, `model override \"${id}\"`);\n\t\t}\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n"
1166
+ },
1167
+ {
1168
+ "before": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\ttry {\n\t\t\tcatalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n",
1169
+ "after": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tconst keyEntries = new Map();\n\t\t// Disabled entries remain stored, but cannot constrain legacy single-key runtime behavior.\n\t\tif (source.multiKey === true) for (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,\n\t\t\t\tkeyEntries: {},\n\t\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\t\tmodels: entry.models,\n\t\t\t\tmodelOverrides: void 0\n\t\t\t} }, validation, true).get(provider);\n\t\t\t// Entry auth must not consult a catalog provider's ambient/OAuth credential or endpoint.\n\t\t\tkeyEntries.set(id, {\n\t\t\t\t...child,\n\t\t\t\tkeyEntryId: id,\n\t\t\t\tkeyEntryName: entry.name,\n\t\t\t\t...child.piProvider === void 0 ? {} : { piProvider: { ...child.piProvider, auth: { apiKey: harnessApiKeyAuth(entry.name) } } }\n\t\t\t});\n\t\t}\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\tconst entryOnly = forKeyEntry && source.models.length === 0 || source.multiKey === true && keyEntries.size > 0 && (source.models ?? []).length === 0 && catalogModels(provider).size === 0;\n\t\ttry {\n\t\t\tif (entryOnly) catalog = { models: [], configuredMaxTokens: new Map(), modelErrors: new Map() };\n\t\t\telse catalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n"
1170
+ },
1171
+ {
1172
+ "before": "\t\t\t}, validation);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;",
1173
+ "after": "\t\t\t}, validation);\n\t\t\tif (source.multiKey === true || forKeyEntry) for (const model of catalog.models) assertEntryHeaders(model.headers, `resolved model \"${model.id}\"`);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;"
1174
+ },
1175
+ {
1176
+ "before": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },",
1177
+ "after": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, keyEntries: _keyEntries, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\tkeyEntries,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },"
1178
+ },
1179
+ {
1180
+ "before": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/**\n* pi-ai-backed multi-provider adapter.",
1181
+ "after": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/** Decode only the selected replay owner at the pi boundary; never merge equal wire ids across keys. */\nfunction replayContextForRoute(context, provider, requestedModel, wireModel) {\n\tconst selectedEntry = requestedModel.startsWith(KEY_MODEL_PREFIX);\n\treturn {\n\t\t...context,\n\t\tmessages: context.messages.map((message) => {\n\t\t\tif (message.role !== \"assistant\") return message;\n\t\t\tif (message.provider === provider && message.model === requestedModel) return { ...message, model: wireModel.id };\n\t\t\tif (!message.model.startsWith(KEY_MODEL_PREFIX) && !(selectedEntry && message.provider === provider && message.model === wireModel.id)) return message;\n\t\t\treturn {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tapi: \"dsh-foreign\",\n\t\t\t\tprovider: message.provider,\n\t\t\t\tmodel: \"dsh-foreign\",\n\t\t\t\tcontent: message.content.flatMap((block) => {\n\t\t\t\t\tif (block.type === \"thinking\") return [];\n\t\t\t\t\tif (block.type === \"text\") return [{ type: \"text\", text: block.text }];\n\t\t\t\t\tif (block.type === \"toolCall\") return [{ type: \"toolCall\", id: block.id, name: block.name, arguments: block.arguments }];\n\t\t\t\t\treturn [block];\n\t\t\t\t}),\n\t\t\t\tusage: message.usage,\n\t\t\t\tstopReason: message.stopReason,\n\t\t\t\ttimestamp: message.timestamp\n\t\t\t};\n\t\t})\n\t};\n}\n/**\n* pi-ai-backed multi-provider adapter."
1182
+ },
1183
+ {
1184
+ "before": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tfor (const profile of profiles.values()) if (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n",
1185
+ "after": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tconst entryModels = new Map();\n\t\tfor (const [provider, profile] of profiles) {\n\t\t\tif (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\t\tconst entries = new Map();\n\t\t\tfor (const [id, entry] of profile.keyEntries) {\n\t\t\t\tconst collection = createModels(this.config.auth);\n\t\t\t\tif (entry.piProvider !== void 0) collection.setProvider(entry.piProvider);\n\t\t\t\tentries.set(id, collection);\n\t\t\t}\n\t\t\tentryModels.set(provider, entries);\n\t\t}\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels,\n\t\t\tentryModels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n"
1186
+ },
1187
+ {
1188
+ "before": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst failure = profile.modelErrors.get(model) ?? (profile.piProvider === void 0 ? profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = snapshot.models.getModel(provider, model);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n",
1189
+ "after": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** Bind the public selection to an exact profile, independent model collection, and upstream id. */\n\trouteOf(snapshot, provider, model) {\n\t\tconst root = this.profileOf(snapshot, provider);\n\t\tconst entry = keyModelRoute(model);\n\t\tif (entry === void 0) return { profile: root, models: snapshot.models, wireModel: model };\n\t\tif (root.multiKey !== true) throw new LlmError(`multi-key selection is disabled for provider \"${provider}\"`, \"UNKNOWN_MODEL\");\n\t\tconst profile = root.keyEntries.get(entry.entryId);\n\t\tconst models = snapshot.entryModels.get(provider)?.get(entry.entryId);\n\t\tif (profile === void 0 || models === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${entry.entryId}\"`, \"UNKNOWN_MODEL\");\n\t\treturn { profile, models, wireModel: entry.wireModel };\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst route = this.routeOf(snapshot, provider, model);\n\t\tconst failure = route.profile.modelErrors.get(route.wireModel) ?? (route.profile.piProvider === void 0 ? route.profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = route.models.getModel(provider, route.wireModel);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n"
1190
+ },
1191
+ {
1192
+ "before": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\ttry {\n\t\t\t\tawait this.config.resolveApiKey(provider, profile);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return [];\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn snapshot.models.getModels(provider).map((model) => ({\n\t\t\t\tprovider,\n\t\t\t\tid: model.id,\n\t\t\t\tname: model.name,\n\t\t\t\tinputModalities: [...model.input]\n\t\t\t}));\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n",
1193
+ "after": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\tconst listed = [];\n\t\t\tconst append = async (owner, models, entryId) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst key = await this.config.resolveApiKey(provider, owner);\n\t\t\t\t\tif (entryId !== void 0 && (key === void 0 || key.length === 0)) return;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return;\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tfor (const model of models.getModels(provider)) listed.push({\n\t\t\t\t\tprovider,\n\t\t\t\t\tid: entryId === void 0 ? model.id : keyModelId(entryId, model.id),\n\t\t\t\t\tname: model.name,\n\t\t\t\t\tinputModalities: [...model.input]\n\t\t\t\t});\n\t\t\t};\n\t\t\t// Keep raw root models advertised so old sessions remain routable without changing keys.\n\t\t\tawait append(profile, snapshot.models);\n\t\t\tif (profile.multiKey === true) for (const [id, entry] of profile.keyEntries) await append(entry, snapshot.entryModels.get(provider).get(id), id);\n\t\t\treturn listed;\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n"
1194
+ },
1195
+ {
1196
+ "before": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(model);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n",
1197
+ "after": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst { profile, wireModel } = this.routeOf(snapshot, provider, model);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(wireModel);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n"
1198
+ },
1199
+ {
1200
+ "before": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => this.streamWithSnapshot(options, snapshot)\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot(options, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n",
1201
+ "after": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => {\n\t\t\t\tif (options.provider !== provider || options.model !== model) throw new LlmError(\"prepared multi-key model selection changed before adapter dispatch\", \"INVALID_CONFIG\");\n\t\t\t\t// Async generators are lazy; pin the owner before returning one to caller-owned code.\n\t\t\t\treturn this.streamWithSnapshot({ ...options, provider, model }, snapshot);\n\t\t\t}\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot({ ...options }, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n"
1202
+ },
1203
+ {
1204
+ "before": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst profile = this.profileOf(snapshot, options.provider);\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n",
1205
+ "after": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst route = this.routeOf(snapshot, options.provider, options.model);\n\t\t\tconst profile = route.profile;\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n"
1206
+ },
1207
+ {
1208
+ "before": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n",
1209
+ "after": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tif (profile.keyEntryId !== void 0 && (apiKey === void 0 || apiKey.length === 0)) throw new LlmError(`provider \"${options.provider}\" key entry \"${profile.keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n"
1210
+ },
1211
+ {
1212
+ "before": "\t\t\t\tconst iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, model.id)[Symbol.asyncIterator]();",
1213
+ "after": "\t\t\t\tconst iterator = toStreamChunks(route.models.streamSimple(model, replayContextForRoute(context, options.provider, options.model, model), {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, options.model)[Symbol.asyncIterator]();"
1214
+ },
1215
+ {
1216
+ "before": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n",
1217
+ "after": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\t// Validate host-owned entry identity even on the installed-catalog shortcut.\n\tconst selectedStored = request.keyEntryId === void 0 ? void 0 : storedProfile?.();\n\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n"
1218
+ },
1219
+ {
1220
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n",
1221
+ "after": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = selectedStored ?? storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n"
1222
+ },
1223
+ {
1224
+ "before": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n",
1225
+ "after": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy,\n\t\tmultiKey: profile.multiKey === true,\n\t\tapiKeyEnv: profile.apiKeyEnv,\n\t\tmodels: profile.piProvider?.getModels(),\n\t\tmodelErrors: [...profile.modelErrors],\n\t\tkeyEntries: [...profile.keyEntries].map(([id, entry]) => ({\n\t\t\tid,\n\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),\n\t\t\tmodelErrors: [...entry.modelErrors]\n\t\t})).sort((left, right) => left.id.localeCompare(right.id))\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n"
1226
+ },
1227
+ {
1228
+ "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
1229
+ "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
1230
+ },
1231
+ {
1232
+ "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
1233
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tmodels: z.array(modelProfile).required()\n});"
1234
+ },
1235
+ {
1236
+ "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
1237
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (!Array.isArray(entry.models))"
1238
+ },
1239
+ {
1240
+ "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
1241
+ "after": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\t...entry.api === void 0 ? {} : { api: entry.api },\n\t\t\t\tmultiKey: false,"
1242
+ },
1243
+ {
1244
+ "before": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {",
1245
+ "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api ?? selectedStored?.api ?? \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
1246
+ },
1247
+ {
1248
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);",
1249
+ "after": "\tconst baseURL = request.baseURL ?? selectedStored?.baseURL;\n\tif (baseURL === void 0 || baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(baseURL, api);"
1250
+ },
1251
+ {
1252
+ "before": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),",
1253
+ "after": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tapi: entry.api,\n\t\t\tmodels: entry.piProvider?.getModels(),"
1254
+ },
1255
+ {
1256
+ "before": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,",
1257
+ "after": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\tapi: profile.api,\n\t\t\tbaseURL: profile.baseURL ?? catalogProvider(provider)?.baseUrl,\n\t\t\theaders: profile.headers,"
1258
+ }
1259
+ ]
1260
+ },
1261
+ {
1262
+ "source": "npm official 0.2.2-rc.1 with per-entry API overrides",
1263
+ "baseSha256": "1a3ae58f9b4493e15459cc5000ec80f21b5d3f4a9dea6ffb6bc28e5b8817ae8a",
1264
+ "resultSha256": "9ca2b07c19694a4521a29c82b7948fb6326d80ee7741200a1d7b0f3f06e1da19",
1265
+ "replacements": [
1266
+ {
1267
+ "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
1268
+ "after": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\n// Model selection carries an opaque entry identity, never a credential or a wire alias.\nconst KEY_MODEL_PREFIX = \"@dsh-key/\";\nconst KEY_ENTRY_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;\nconst FORBIDDEN_KEY_ENTRY_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst AUTH_HEADER_NAMES = new Set([\"authorization\", \"proxy-authorization\", \"x-api-key\", \"api-key\", \"cf-aig-authorization\"]);\nfunction validKeyEntryId(id) {\n\treturn KEY_ENTRY_ID.test(id) && !FORBIDDEN_KEY_ENTRY_IDS.has(id);\n}\nfunction keyModelId(entryId, model) {\n\treturn `${KEY_MODEL_PREFIX}${encodeURIComponent(entryId)}/${encodeURIComponent(model)}`;\n}\nfunction keyModelRoute(model) {\n\tif (!model.startsWith(KEY_MODEL_PREFIX)) return void 0;\n\ttry {\n\t\tconst parts = model.slice(KEY_MODEL_PREFIX.length).split(\"/\");\n\t\tif (parts.length === 2) {\n\t\t\tconst entryId = decodeURIComponent(parts[0]);\n\t\t\tconst wireModel = decodeURIComponent(parts[1]);\n\t\t\tif (validKeyEntryId(entryId) && wireModel.length > 0 && !wireModel.startsWith(KEY_MODEL_PREFIX) && keyModelId(entryId, wireModel) === model) return { entryId, wireModel };\n\t\t}\n\t} catch {}\n\tthrow new LlmError(`invalid multi-key model selection \"${model}\"`, \"UNKNOWN_MODEL\");\n}\nconst keyEntryProfile = z.object({\n\tname: z.string().max(120).required(),\n\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});\nconst profile = z.object({\n\tmultiKey: z.boolean().default(false),\n\tkeyEntries: z.dict(keyEntryProfile).default({}),\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n"
1269
+ },
1270
+ {
1271
+ "before": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\") {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n",
1272
+ "after": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\", forKeyEntry = false) {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n"
1273
+ },
1274
+ {
1275
+ "before": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n",
1276
+ "after": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst entrySources = source.keyEntries ?? {};\n\t\tif (typeof entrySources !== \"object\" || entrySources === null || Array.isArray(entrySources)) throw new Error(`llm-pi-ai: provider \"${provider}\" keyEntries must be a dictionary`);\n\t\tconst assertWireModels = (models, site) => {\n\t\t\tfor (const model of models ?? []) if (typeof model.id !== \"string\" || model.id.length === 0 || model.id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} must use non-empty upstream model ids outside the reserved ${KEY_MODEL_PREFIX} prefix`);\n\t\t};\n\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const id of Object.keys(source.modelOverrides ?? {})) if (id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" modelOverrides uses reserved prefix ${KEY_MODEL_PREFIX}`);\n\t\tfor (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tif (!validKeyEntryId(id)) throw new Error(`llm-pi-ai: provider \"${provider}\" has an invalid key entry id \"${id}\"`);\n\t\t\tif (typeof entry !== \"object\" || entry === null || typeof entry.name !== \"string\" || entry.name.trim().length === 0 || entry.name.length > 120) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs a name of 1-120 characters`);\n\t\t\tif (typeof entry.apiKeyEnv !== \"string\" || entry.apiKeyEnv.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own apiKeyEnv`);\n\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own models list`);\n\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t}\n\t\tconst assertEntryHeaders = (headers, site) => {\n\t\t\tfor (const name of Object.keys(headers ?? {})) if (AUTH_HEADER_NAMES.has(name.toLowerCase())) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} authentication header \"${name}\" would override the selected key; remove it before enabling multiKey`);\n\t\t};\n\t\tif (source.multiKey === true || forKeyEntry) {\n\t\t\tassertEntryHeaders(source.headers, \"shared\");\n\t\t\tfor (const model of source.models ?? []) assertEntryHeaders(model.headers, `model \"${model.id}\"`);\n\t\t\tfor (const [id, override] of Object.entries(source.modelOverrides ?? {})) assertEntryHeaders(override.headers, `model override \"${id}\"`);\n\t\t}\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n"
1277
+ },
1278
+ {
1279
+ "before": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\ttry {\n\t\t\tcatalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n",
1280
+ "after": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tconst keyEntries = new Map();\n\t\t// Disabled entries remain stored, but cannot constrain legacy single-key runtime behavior.\n\t\tif (source.multiKey === true) for (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,\n\t\t\t\tkeyEntries: {},\n\t\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\t\tmodels: entry.models,\n\t\t\t\tmodelOverrides: void 0\n\t\t\t} }, validation, true).get(provider);\n\t\t\t// Entry auth must not consult a catalog provider's ambient/OAuth credential or endpoint.\n\t\t\tkeyEntries.set(id, {\n\t\t\t\t...child,\n\t\t\t\tkeyEntryId: id,\n\t\t\t\tkeyEntryName: entry.name,\n\t\t\t\t...child.piProvider === void 0 ? {} : { piProvider: { ...child.piProvider, auth: { apiKey: harnessApiKeyAuth(entry.name) } } }\n\t\t\t});\n\t\t}\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\tconst entryOnly = forKeyEntry && source.models.length === 0 || source.multiKey === true && keyEntries.size > 0 && (source.models ?? []).length === 0 && catalogModels(provider).size === 0;\n\t\ttry {\n\t\t\tif (entryOnly) catalog = { models: [], configuredMaxTokens: new Map(), modelErrors: new Map() };\n\t\t\telse catalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n"
1281
+ },
1282
+ {
1283
+ "before": "\t\t\t}, validation);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;",
1284
+ "after": "\t\t\t}, validation);\n\t\t\tif (source.multiKey === true || forKeyEntry) for (const model of catalog.models) assertEntryHeaders(model.headers, `resolved model \"${model.id}\"`);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;"
1285
+ },
1286
+ {
1287
+ "before": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },",
1288
+ "after": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, keyEntries: _keyEntries, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\tkeyEntries,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },"
1289
+ },
1290
+ {
1291
+ "before": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/**\n* pi-ai-backed multi-provider adapter.",
1292
+ "after": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/** Decode only the selected replay owner at the pi boundary; never merge equal wire ids across keys. */\nfunction replayContextForRoute(context, provider, requestedModel, wireModel) {\n\tconst selectedEntry = requestedModel.startsWith(KEY_MODEL_PREFIX);\n\treturn {\n\t\t...context,\n\t\tmessages: context.messages.map((message) => {\n\t\t\tif (message.role !== \"assistant\") return message;\n\t\t\tif (message.provider === provider && message.model === requestedModel) return { ...message, model: wireModel.id };\n\t\t\tif (!message.model.startsWith(KEY_MODEL_PREFIX) && !(selectedEntry && message.provider === provider && message.model === wireModel.id)) return message;\n\t\t\treturn {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tapi: \"dsh-foreign\",\n\t\t\t\tprovider: message.provider,\n\t\t\t\tmodel: \"dsh-foreign\",\n\t\t\t\tcontent: message.content.flatMap((block) => {\n\t\t\t\t\tif (block.type === \"thinking\") return [];\n\t\t\t\t\tif (block.type === \"text\") return [{ type: \"text\", text: block.text }];\n\t\t\t\t\tif (block.type === \"toolCall\") return [{ type: \"toolCall\", id: block.id, name: block.name, arguments: block.arguments }];\n\t\t\t\t\treturn [block];\n\t\t\t\t}),\n\t\t\t\tusage: message.usage,\n\t\t\t\tstopReason: message.stopReason,\n\t\t\t\ttimestamp: message.timestamp\n\t\t\t};\n\t\t})\n\t};\n}\n/**\n* pi-ai-backed multi-provider adapter."
1293
+ },
1294
+ {
1295
+ "before": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tfor (const profile of profiles.values()) if (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n",
1296
+ "after": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tconst entryModels = new Map();\n\t\tfor (const [provider, profile] of profiles) {\n\t\t\tif (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\t\tconst entries = new Map();\n\t\t\tfor (const [id, entry] of profile.keyEntries) {\n\t\t\t\tconst collection = createModels(this.config.auth);\n\t\t\t\tif (entry.piProvider !== void 0) collection.setProvider(entry.piProvider);\n\t\t\t\tentries.set(id, collection);\n\t\t\t}\n\t\t\tentryModels.set(provider, entries);\n\t\t}\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels,\n\t\t\tentryModels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n"
1297
+ },
1298
+ {
1299
+ "before": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst failure = profile.modelErrors.get(model) ?? (profile.piProvider === void 0 ? profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = snapshot.models.getModel(provider, model);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n",
1300
+ "after": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** Bind the public selection to an exact profile, independent model collection, and upstream id. */\n\trouteOf(snapshot, provider, model) {\n\t\tconst root = this.profileOf(snapshot, provider);\n\t\tconst entry = keyModelRoute(model);\n\t\tif (entry === void 0) return { profile: root, models: snapshot.models, wireModel: model };\n\t\tif (root.multiKey !== true) throw new LlmError(`multi-key selection is disabled for provider \"${provider}\"`, \"UNKNOWN_MODEL\");\n\t\tconst profile = root.keyEntries.get(entry.entryId);\n\t\tconst models = snapshot.entryModels.get(provider)?.get(entry.entryId);\n\t\tif (profile === void 0 || models === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${entry.entryId}\"`, \"UNKNOWN_MODEL\");\n\t\treturn { profile, models, wireModel: entry.wireModel };\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst route = this.routeOf(snapshot, provider, model);\n\t\tconst failure = route.profile.modelErrors.get(route.wireModel) ?? (route.profile.piProvider === void 0 ? route.profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = route.models.getModel(provider, route.wireModel);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n"
1301
+ },
1302
+ {
1303
+ "before": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\ttry {\n\t\t\t\tawait this.config.resolveApiKey(provider, profile);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return [];\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn snapshot.models.getModels(provider).map((model) => ({\n\t\t\t\tprovider,\n\t\t\t\tid: model.id,\n\t\t\t\tname: model.name,\n\t\t\t\tinputModalities: [...model.input]\n\t\t\t}));\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n",
1304
+ "after": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\tconst listed = [];\n\t\t\tconst append = async (owner, models, entryId) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst key = await this.config.resolveApiKey(provider, owner);\n\t\t\t\t\tif (entryId !== void 0 && (key === void 0 || key.length === 0)) return;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return;\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tfor (const model of models.getModels(provider)) listed.push({\n\t\t\t\t\tprovider,\n\t\t\t\t\tid: entryId === void 0 ? model.id : keyModelId(entryId, model.id),\n\t\t\t\t\tname: model.name,\n\t\t\t\t\tinputModalities: [...model.input]\n\t\t\t\t});\n\t\t\t};\n\t\t\t// Keep raw root models advertised so old sessions remain routable without changing keys.\n\t\t\tawait append(profile, snapshot.models);\n\t\t\tif (profile.multiKey === true) for (const [id, entry] of profile.keyEntries) await append(entry, snapshot.entryModels.get(provider).get(id), id);\n\t\t\treturn listed;\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n"
1305
+ },
1306
+ {
1307
+ "before": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(model);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n",
1308
+ "after": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst { profile, wireModel } = this.routeOf(snapshot, provider, model);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(wireModel);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n"
1309
+ },
1310
+ {
1311
+ "before": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => this.streamWithSnapshot(options, snapshot)\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot(options, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n",
1312
+ "after": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => {\n\t\t\t\tif (options.provider !== provider || options.model !== model) throw new LlmError(\"prepared multi-key model selection changed before adapter dispatch\", \"INVALID_CONFIG\");\n\t\t\t\t// Async generators are lazy; pin the owner before returning one to caller-owned code.\n\t\t\t\treturn this.streamWithSnapshot({ ...options, provider, model }, snapshot);\n\t\t\t}\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot({ ...options }, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n"
1313
+ },
1314
+ {
1315
+ "before": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst profile = this.profileOf(snapshot, options.provider);\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n",
1316
+ "after": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst route = this.routeOf(snapshot, options.provider, options.model);\n\t\t\tconst profile = route.profile;\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n"
1317
+ },
1318
+ {
1319
+ "before": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n",
1320
+ "after": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tif (profile.keyEntryId !== void 0 && (apiKey === void 0 || apiKey.length === 0)) throw new LlmError(`provider \"${options.provider}\" key entry \"${profile.keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n"
1321
+ },
1322
+ {
1323
+ "before": "\t\t\t\tconst iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, model.id)[Symbol.asyncIterator]();",
1324
+ "after": "\t\t\t\tconst iterator = toStreamChunks(route.models.streamSimple(model, replayContextForRoute(context, options.provider, options.model, model), {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, options.model)[Symbol.asyncIterator]();"
1325
+ },
1326
+ {
1327
+ "before": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n",
1328
+ "after": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\t// Validate host-owned entry identity even on the installed-catalog shortcut.\n\tconst selectedStored = request.keyEntryId === void 0 ? void 0 : storedProfile?.();\n\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n"
1329
+ },
1330
+ {
1331
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n",
1332
+ "after": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = selectedStored ?? storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n"
1333
+ },
1334
+ {
1335
+ "before": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n",
1336
+ "after": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy,\n\t\tmultiKey: profile.multiKey === true,\n\t\tapiKeyEnv: profile.apiKeyEnv,\n\t\tmodels: profile.piProvider?.getModels(),\n\t\tmodelErrors: [...profile.modelErrors],\n\t\tkeyEntries: [...profile.keyEntries].map(([id, entry]) => ({\n\t\t\tid,\n\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),\n\t\t\tmodelErrors: [...entry.modelErrors]\n\t\t})).sort((left, right) => left.id.localeCompare(right.id))\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n"
1337
+ },
1338
+ {
1339
+ "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
1340
+ "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
1341
+ },
1342
+ {
1343
+ "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
1344
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tmodels: z.array(modelProfile).required()\n});"
1345
+ },
1346
+ {
1347
+ "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
1348
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (!Array.isArray(entry.models))"
1349
+ },
1350
+ {
1351
+ "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
1352
+ "after": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\t...entry.api === void 0 ? {} : { api: entry.api },\n\t\t\t\tmultiKey: false,"
1353
+ },
1354
+ {
1355
+ "before": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {",
1356
+ "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api !== void 0 ? request.api : selectedStored?.api !== void 0 ? selectedStored.api : \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
1357
+ },
1358
+ {
1359
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);",
1360
+ "after": "\tconst baseURL = request.baseURL ?? selectedStored?.baseURL;\n\tif (baseURL === void 0 || baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(baseURL, api);"
1361
+ },
1362
+ {
1363
+ "before": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),",
1364
+ "after": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tapi: entry.api,\n\t\t\tmodels: entry.piProvider?.getModels(),"
1365
+ },
1366
+ {
1367
+ "before": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,",
1368
+ "after": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\tapi: profile.api,\n\t\t\tbaseURL: profile.baseURL ?? catalogProvider(provider)?.baseUrl,\n\t\t\theaders: profile.headers,"
1369
+ }
1370
+ ]
1371
+ },
1372
+ {
1373
+ "source": "0.2.2-rc.1 with tool lookup optimization and credential cancellation with per-entry API overrides",
1374
+ "baseSha256": "0a99a2fc903a4285044b09114b3bd20ee1e612f39aa381e4a71b10d48ee9e9f7",
1375
+ "resultSha256": "e999e1a7f2352177c653ff0cea6485c3b1d1ea95b40ea613fc0549e2c8e49662",
1376
+ "replacements": [
1377
+ {
1378
+ "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
1379
+ "after": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\n// Model selection carries an opaque entry identity, never a credential or a wire alias.\nconst KEY_MODEL_PREFIX = \"@dsh-key/\";\nconst KEY_ENTRY_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;\nconst FORBIDDEN_KEY_ENTRY_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst AUTH_HEADER_NAMES = new Set([\"authorization\", \"proxy-authorization\", \"x-api-key\", \"api-key\", \"cf-aig-authorization\"]);\nfunction validKeyEntryId(id) {\n\treturn KEY_ENTRY_ID.test(id) && !FORBIDDEN_KEY_ENTRY_IDS.has(id);\n}\nfunction keyModelId(entryId, model) {\n\treturn `${KEY_MODEL_PREFIX}${encodeURIComponent(entryId)}/${encodeURIComponent(model)}`;\n}\nfunction keyModelRoute(model) {\n\tif (!model.startsWith(KEY_MODEL_PREFIX)) return void 0;\n\ttry {\n\t\tconst parts = model.slice(KEY_MODEL_PREFIX.length).split(\"/\");\n\t\tif (parts.length === 2) {\n\t\t\tconst entryId = decodeURIComponent(parts[0]);\n\t\t\tconst wireModel = decodeURIComponent(parts[1]);\n\t\t\tif (validKeyEntryId(entryId) && wireModel.length > 0 && !wireModel.startsWith(KEY_MODEL_PREFIX) && keyModelId(entryId, wireModel) === model) return { entryId, wireModel };\n\t\t}\n\t} catch {}\n\tthrow new LlmError(`invalid multi-key model selection \"${model}\"`, \"UNKNOWN_MODEL\");\n}\nconst keyEntryProfile = z.object({\n\tname: z.string().max(120).required(),\n\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});\nconst profile = z.object({\n\tmultiKey: z.boolean().default(false),\n\tkeyEntries: z.dict(keyEntryProfile).default({}),\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n"
1380
+ },
1381
+ {
1382
+ "before": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\") {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n",
1383
+ "after": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\", forKeyEntry = false) {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n"
1384
+ },
1385
+ {
1386
+ "before": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n",
1387
+ "after": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst entrySources = source.keyEntries ?? {};\n\t\tif (typeof entrySources !== \"object\" || entrySources === null || Array.isArray(entrySources)) throw new Error(`llm-pi-ai: provider \"${provider}\" keyEntries must be a dictionary`);\n\t\tconst assertWireModels = (models, site) => {\n\t\t\tfor (const model of models ?? []) if (typeof model.id !== \"string\" || model.id.length === 0 || model.id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} must use non-empty upstream model ids outside the reserved ${KEY_MODEL_PREFIX} prefix`);\n\t\t};\n\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const id of Object.keys(source.modelOverrides ?? {})) if (id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" modelOverrides uses reserved prefix ${KEY_MODEL_PREFIX}`);\n\t\tfor (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tif (!validKeyEntryId(id)) throw new Error(`llm-pi-ai: provider \"${provider}\" has an invalid key entry id \"${id}\"`);\n\t\t\tif (typeof entry !== \"object\" || entry === null || typeof entry.name !== \"string\" || entry.name.trim().length === 0 || entry.name.length > 120) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs a name of 1-120 characters`);\n\t\t\tif (typeof entry.apiKeyEnv !== \"string\" || entry.apiKeyEnv.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own apiKeyEnv`);\n\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own models list`);\n\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t}\n\t\tconst assertEntryHeaders = (headers, site) => {\n\t\t\tfor (const name of Object.keys(headers ?? {})) if (AUTH_HEADER_NAMES.has(name.toLowerCase())) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} authentication header \"${name}\" would override the selected key; remove it before enabling multiKey`);\n\t\t};\n\t\tif (source.multiKey === true || forKeyEntry) {\n\t\t\tassertEntryHeaders(source.headers, \"shared\");\n\t\t\tfor (const model of source.models ?? []) assertEntryHeaders(model.headers, `model \"${model.id}\"`);\n\t\t\tfor (const [id, override] of Object.entries(source.modelOverrides ?? {})) assertEntryHeaders(override.headers, `model override \"${id}\"`);\n\t\t}\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n"
1388
+ },
1389
+ {
1390
+ "before": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\ttry {\n\t\t\tcatalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n",
1391
+ "after": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tconst keyEntries = new Map();\n\t\t// Disabled entries remain stored, but cannot constrain legacy single-key runtime behavior.\n\t\tif (source.multiKey === true) for (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,\n\t\t\t\tkeyEntries: {},\n\t\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\t\tmodels: entry.models,\n\t\t\t\tmodelOverrides: void 0\n\t\t\t} }, validation, true).get(provider);\n\t\t\t// Entry auth must not consult a catalog provider's ambient/OAuth credential or endpoint.\n\t\t\tkeyEntries.set(id, {\n\t\t\t\t...child,\n\t\t\t\tkeyEntryId: id,\n\t\t\t\tkeyEntryName: entry.name,\n\t\t\t\t...child.piProvider === void 0 ? {} : { piProvider: { ...child.piProvider, auth: { apiKey: harnessApiKeyAuth(entry.name) } } }\n\t\t\t});\n\t\t}\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\tconst entryOnly = forKeyEntry && source.models.length === 0 || source.multiKey === true && keyEntries.size > 0 && (source.models ?? []).length === 0 && catalogModels(provider).size === 0;\n\t\ttry {\n\t\t\tif (entryOnly) catalog = { models: [], configuredMaxTokens: new Map(), modelErrors: new Map() };\n\t\t\telse catalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n"
1392
+ },
1393
+ {
1394
+ "before": "\t\t\t}, validation);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;",
1395
+ "after": "\t\t\t}, validation);\n\t\t\tif (source.multiKey === true || forKeyEntry) for (const model of catalog.models) assertEntryHeaders(model.headers, `resolved model \"${model.id}\"`);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;"
1396
+ },
1397
+ {
1398
+ "before": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },",
1399
+ "after": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, keyEntries: _keyEntries, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\tkeyEntries,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },"
1400
+ },
1401
+ {
1402
+ "before": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/**\n* pi-ai-backed multi-provider adapter.",
1403
+ "after": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/** Decode only the selected replay owner at the pi boundary; never merge equal wire ids across keys. */\nfunction replayContextForRoute(context, provider, requestedModel, wireModel) {\n\tconst selectedEntry = requestedModel.startsWith(KEY_MODEL_PREFIX);\n\treturn {\n\t\t...context,\n\t\tmessages: context.messages.map((message) => {\n\t\t\tif (message.role !== \"assistant\") return message;\n\t\t\tif (message.provider === provider && message.model === requestedModel) return { ...message, model: wireModel.id };\n\t\t\tif (!message.model.startsWith(KEY_MODEL_PREFIX) && !(selectedEntry && message.provider === provider && message.model === wireModel.id)) return message;\n\t\t\treturn {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tapi: \"dsh-foreign\",\n\t\t\t\tprovider: message.provider,\n\t\t\t\tmodel: \"dsh-foreign\",\n\t\t\t\tcontent: message.content.flatMap((block) => {\n\t\t\t\t\tif (block.type === \"thinking\") return [];\n\t\t\t\t\tif (block.type === \"text\") return [{ type: \"text\", text: block.text }];\n\t\t\t\t\tif (block.type === \"toolCall\") return [{ type: \"toolCall\", id: block.id, name: block.name, arguments: block.arguments }];\n\t\t\t\t\treturn [block];\n\t\t\t\t}),\n\t\t\t\tusage: message.usage,\n\t\t\t\tstopReason: message.stopReason,\n\t\t\t\ttimestamp: message.timestamp\n\t\t\t};\n\t\t})\n\t};\n}\n/**\n* pi-ai-backed multi-provider adapter."
1404
+ },
1405
+ {
1406
+ "before": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tfor (const profile of profiles.values()) if (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n",
1407
+ "after": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tconst entryModels = new Map();\n\t\tfor (const [provider, profile] of profiles) {\n\t\t\tif (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\t\tconst entries = new Map();\n\t\t\tfor (const [id, entry] of profile.keyEntries) {\n\t\t\t\tconst collection = createModels(this.config.auth);\n\t\t\t\tif (entry.piProvider !== void 0) collection.setProvider(entry.piProvider);\n\t\t\t\tentries.set(id, collection);\n\t\t\t}\n\t\t\tentryModels.set(provider, entries);\n\t\t}\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels,\n\t\t\tentryModels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n"
1408
+ },
1409
+ {
1410
+ "before": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst failure = profile.modelErrors.get(model) ?? (profile.piProvider === void 0 ? profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = snapshot.models.getModel(provider, model);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n",
1411
+ "after": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** Bind the public selection to an exact profile, independent model collection, and upstream id. */\n\trouteOf(snapshot, provider, model) {\n\t\tconst root = this.profileOf(snapshot, provider);\n\t\tconst entry = keyModelRoute(model);\n\t\tif (entry === void 0) return { profile: root, models: snapshot.models, wireModel: model };\n\t\tif (root.multiKey !== true) throw new LlmError(`multi-key selection is disabled for provider \"${provider}\"`, \"UNKNOWN_MODEL\");\n\t\tconst profile = root.keyEntries.get(entry.entryId);\n\t\tconst models = snapshot.entryModels.get(provider)?.get(entry.entryId);\n\t\tif (profile === void 0 || models === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${entry.entryId}\"`, \"UNKNOWN_MODEL\");\n\t\treturn { profile, models, wireModel: entry.wireModel };\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst route = this.routeOf(snapshot, provider, model);\n\t\tconst failure = route.profile.modelErrors.get(route.wireModel) ?? (route.profile.piProvider === void 0 ? route.profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = route.models.getModel(provider, route.wireModel);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n"
1412
+ },
1413
+ {
1414
+ "before": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\ttry {\n\t\t\t\tawait this.config.resolveApiKey(provider, profile);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return [];\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn snapshot.models.getModels(provider).map((model) => ({\n\t\t\t\tprovider,\n\t\t\t\tid: model.id,\n\t\t\t\tname: model.name,\n\t\t\t\tinputModalities: [...model.input]\n\t\t\t}));\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n",
1415
+ "after": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\tconst listed = [];\n\t\t\tconst append = async (owner, models, entryId) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst key = await this.config.resolveApiKey(provider, owner);\n\t\t\t\t\tif (entryId !== void 0 && (key === void 0 || key.length === 0)) return;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return;\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tfor (const model of models.getModels(provider)) listed.push({\n\t\t\t\t\tprovider,\n\t\t\t\t\tid: entryId === void 0 ? model.id : keyModelId(entryId, model.id),\n\t\t\t\t\tname: model.name,\n\t\t\t\t\tinputModalities: [...model.input]\n\t\t\t\t});\n\t\t\t};\n\t\t\t// Keep raw root models advertised so old sessions remain routable without changing keys.\n\t\t\tawait append(profile, snapshot.models);\n\t\t\tif (profile.multiKey === true) for (const [id, entry] of profile.keyEntries) await append(entry, snapshot.entryModels.get(provider).get(id), id);\n\t\t\treturn listed;\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n"
1416
+ },
1417
+ {
1418
+ "before": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(model);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n",
1419
+ "after": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst { profile, wireModel } = this.routeOf(snapshot, provider, model);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(wireModel);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n"
1420
+ },
1421
+ {
1422
+ "before": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => this.streamWithSnapshot(options, snapshot)\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot(options, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n",
1423
+ "after": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => {\n\t\t\t\tif (options.provider !== provider || options.model !== model) throw new LlmError(\"prepared multi-key model selection changed before adapter dispatch\", \"INVALID_CONFIG\");\n\t\t\t\t// Async generators are lazy; pin the owner before returning one to caller-owned code.\n\t\t\t\treturn this.streamWithSnapshot({ ...options, provider, model }, snapshot);\n\t\t\t}\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot({ ...options }, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n"
1424
+ },
1425
+ {
1426
+ "before": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst profile = this.profileOf(snapshot, options.provider);\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n",
1427
+ "after": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst route = this.routeOf(snapshot, options.provider, options.model);\n\t\t\tconst profile = route.profile;\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n"
1428
+ },
1429
+ {
1430
+ "before": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n",
1431
+ "after": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tif (profile.keyEntryId !== void 0 && (apiKey === void 0 || apiKey.length === 0)) throw new LlmError(`provider \"${options.provider}\" key entry \"${profile.keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n"
1432
+ },
1433
+ {
1434
+ "before": "\t\t\t\tconst iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, model.id)[Symbol.asyncIterator]();",
1435
+ "after": "\t\t\t\tconst iterator = toStreamChunks(route.models.streamSimple(model, replayContextForRoute(context, options.provider, options.model, model), {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, options.model)[Symbol.asyncIterator]();"
1436
+ },
1437
+ {
1438
+ "before": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n",
1439
+ "after": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\t// Validate host-owned entry identity even on the installed-catalog shortcut.\n\tconst selectedStored = request.keyEntryId === void 0 ? void 0 : storedProfile?.();\n\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n"
1440
+ },
1441
+ {
1442
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n",
1443
+ "after": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = selectedStored ?? storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n"
1444
+ },
1445
+ {
1446
+ "before": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n",
1447
+ "after": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy,\n\t\tmultiKey: profile.multiKey === true,\n\t\tapiKeyEnv: profile.apiKeyEnv,\n\t\tmodels: profile.piProvider?.getModels(),\n\t\tmodelErrors: [...profile.modelErrors],\n\t\tkeyEntries: [...profile.keyEntries].map(([id, entry]) => ({\n\t\t\tid,\n\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),\n\t\t\tmodelErrors: [...entry.modelErrors]\n\t\t})).sort((left, right) => left.id.localeCompare(right.id))\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n"
1448
+ },
1449
+ {
1450
+ "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
1451
+ "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
1452
+ },
1453
+ {
1454
+ "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
1455
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tmodels: z.array(modelProfile).required()\n});"
1456
+ },
1457
+ {
1458
+ "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
1459
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (!Array.isArray(entry.models))"
1460
+ },
1461
+ {
1462
+ "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
1463
+ "after": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\t...entry.api === void 0 ? {} : { api: entry.api },\n\t\t\t\tmultiKey: false,"
1464
+ },
1465
+ {
1466
+ "before": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {",
1467
+ "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api !== void 0 ? request.api : selectedStored?.api !== void 0 ? selectedStored.api : \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
1468
+ },
1469
+ {
1470
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);",
1471
+ "after": "\tconst baseURL = request.baseURL ?? selectedStored?.baseURL;\n\tif (baseURL === void 0 || baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(baseURL, api);"
1472
+ },
1473
+ {
1474
+ "before": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),",
1475
+ "after": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tapi: entry.api,\n\t\t\tmodels: entry.piProvider?.getModels(),"
1476
+ },
1477
+ {
1478
+ "before": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,",
1479
+ "after": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\tapi: profile.api,\n\t\t\tbaseURL: profile.baseURL ?? catalogProvider(provider)?.baseUrl,\n\t\t\theaders: profile.headers,"
1480
+ }
1481
+ ]
1482
+ },
1483
+ {
1484
+ "source": "0.2.2-rc.1 with tool lookup optimization and credential cancellation with per-entry API overrides",
1485
+ "baseSha256": "0a99a2fc903a4285044b09114b3bd20ee1e612f39aa381e4a71b10d48ee9e9f7",
1486
+ "resultSha256": "0a398e35a7e66f0cb547da9c421e33123b9959bd058c3d006baf3c587ff4c596",
1487
+ "replacements": [
1488
+ {
1489
+ "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
1490
+ "after": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\n// Model selection carries an opaque entry identity, never a credential or a wire alias.\nconst KEY_MODEL_PREFIX = \"@dsh-key/\";\nconst KEY_ENTRY_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;\nconst FORBIDDEN_KEY_ENTRY_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst AUTH_HEADER_NAMES = new Set([\"authorization\", \"proxy-authorization\", \"x-api-key\", \"api-key\", \"cf-aig-authorization\"]);\nfunction validKeyEntryId(id) {\n\treturn KEY_ENTRY_ID.test(id) && !FORBIDDEN_KEY_ENTRY_IDS.has(id);\n}\nfunction keyModelId(entryId, model) {\n\treturn `${KEY_MODEL_PREFIX}${encodeURIComponent(entryId)}/${encodeURIComponent(model)}`;\n}\nfunction keyModelRoute(model) {\n\tif (!model.startsWith(KEY_MODEL_PREFIX)) return void 0;\n\ttry {\n\t\tconst parts = model.slice(KEY_MODEL_PREFIX.length).split(\"/\");\n\t\tif (parts.length === 2) {\n\t\t\tconst entryId = decodeURIComponent(parts[0]);\n\t\t\tconst wireModel = decodeURIComponent(parts[1]);\n\t\t\tif (validKeyEntryId(entryId) && wireModel.length > 0 && !wireModel.startsWith(KEY_MODEL_PREFIX) && keyModelId(entryId, wireModel) === model) return { entryId, wireModel };\n\t\t}\n\t} catch {}\n\tthrow new LlmError(`invalid multi-key model selection \"${model}\"`, \"UNKNOWN_MODEL\");\n}\nconst keyEntryProfile = z.object({\n\tname: z.string().max(120).required(),\n\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});\nconst profile = z.object({\n\tmultiKey: z.boolean().default(false),\n\tkeyEntries: z.dict(keyEntryProfile).default({}),\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n"
1491
+ },
1492
+ {
1493
+ "before": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\") {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n",
1494
+ "after": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\", forKeyEntry = false) {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n"
1495
+ },
1496
+ {
1497
+ "before": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n",
1498
+ "after": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst entrySources = source.keyEntries ?? {};\n\t\tif (typeof entrySources !== \"object\" || entrySources === null || Array.isArray(entrySources)) throw new Error(`llm-pi-ai: provider \"${provider}\" keyEntries must be a dictionary`);\n\t\tconst assertWireModels = (models, site) => {\n\t\t\tfor (const model of models ?? []) if (typeof model.id !== \"string\" || model.id.length === 0 || model.id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} must use non-empty upstream model ids outside the reserved ${KEY_MODEL_PREFIX} prefix`);\n\t\t};\n\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const id of Object.keys(source.modelOverrides ?? {})) if (id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" modelOverrides uses reserved prefix ${KEY_MODEL_PREFIX}`);\n\t\tfor (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tif (!validKeyEntryId(id)) throw new Error(`llm-pi-ai: provider \"${provider}\" has an invalid key entry id \"${id}\"`);\n\t\t\tif (typeof entry !== \"object\" || entry === null || typeof entry.name !== \"string\" || entry.name.trim().length === 0 || entry.name.length > 120) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs a name of 1-120 characters`);\n\t\t\tif (typeof entry.apiKeyEnv !== \"string\" || entry.apiKeyEnv.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own apiKeyEnv`);\n\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own models list`);\n\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t}\n\t\tconst assertEntryHeaders = (headers, site) => {\n\t\t\tfor (const name of Object.keys(headers ?? {})) if (AUTH_HEADER_NAMES.has(name.toLowerCase())) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} authentication header \"${name}\" would override the selected key; remove it before enabling multiKey`);\n\t\t};\n\t\tif (source.multiKey === true || forKeyEntry) {\n\t\t\tassertEntryHeaders(source.headers, \"shared\");\n\t\t\tfor (const model of source.models ?? []) assertEntryHeaders(model.headers, `model \"${model.id}\"`);\n\t\t\tfor (const [id, override] of Object.entries(source.modelOverrides ?? {})) assertEntryHeaders(override.headers, `model override \"${id}\"`);\n\t\t}\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n"
1499
+ },
1500
+ {
1501
+ "before": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\ttry {\n\t\t\tcatalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n",
1502
+ "after": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tconst keyEntries = new Map();\n\t\t// Disabled entries remain stored, but cannot constrain legacy single-key runtime behavior.\n\t\tif (source.multiKey === true) for (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,\n\t\t\t\tkeyEntries: {},\n\t\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\t\tmodels: entry.models,\n\t\t\t\tmodelOverrides: void 0\n\t\t\t} }, validation, true).get(provider);\n\t\t\t// Entry auth must not consult a catalog provider's ambient/OAuth credential or endpoint.\n\t\t\tkeyEntries.set(id, {\n\t\t\t\t...child,\n\t\t\t\tkeyEntryId: id,\n\t\t\t\tkeyEntryName: entry.name,\n\t\t\t\t...child.piProvider === void 0 ? {} : { piProvider: { ...child.piProvider, auth: { apiKey: harnessApiKeyAuth(entry.name) } } }\n\t\t\t});\n\t\t}\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\tconst entryOnly = forKeyEntry && source.models.length === 0 || source.multiKey === true && keyEntries.size > 0 && (source.models ?? []).length === 0 && catalogModels(provider).size === 0;\n\t\ttry {\n\t\t\tif (entryOnly) catalog = { models: [], configuredMaxTokens: new Map(), modelErrors: new Map() };\n\t\t\telse catalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n"
1503
+ },
1504
+ {
1505
+ "before": "\t\t\t}, validation);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;",
1506
+ "after": "\t\t\t}, validation);\n\t\t\tif (source.multiKey === true || forKeyEntry) for (const model of catalog.models) assertEntryHeaders(model.headers, `resolved model \"${model.id}\"`);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;"
1507
+ },
1508
+ {
1509
+ "before": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },",
1510
+ "after": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, keyEntries: _keyEntries, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\tkeyEntries,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },"
1511
+ },
1512
+ {
1513
+ "before": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/**\n* pi-ai-backed multi-provider adapter.",
1514
+ "after": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/** Decode only the selected replay owner at the pi boundary; never merge equal wire ids across keys. */\nfunction replayContextForRoute(context, provider, requestedModel, wireModel) {\n\tconst selectedEntry = requestedModel.startsWith(KEY_MODEL_PREFIX);\n\treturn {\n\t\t...context,\n\t\tmessages: context.messages.map((message) => {\n\t\t\tif (message.role !== \"assistant\") return message;\n\t\t\tif (message.provider === provider && message.model === requestedModel) return { ...message, model: wireModel.id };\n\t\t\tif (!message.model.startsWith(KEY_MODEL_PREFIX) && !(selectedEntry && message.provider === provider && message.model === wireModel.id)) return message;\n\t\t\treturn {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tapi: \"dsh-foreign\",\n\t\t\t\tprovider: message.provider,\n\t\t\t\tmodel: \"dsh-foreign\",\n\t\t\t\tcontent: message.content.flatMap((block) => {\n\t\t\t\t\tif (block.type === \"thinking\") return [];\n\t\t\t\t\tif (block.type === \"text\") return [{ type: \"text\", text: block.text }];\n\t\t\t\t\tif (block.type === \"toolCall\") return [{ type: \"toolCall\", id: block.id, name: block.name, arguments: block.arguments }];\n\t\t\t\t\treturn [block];\n\t\t\t\t}),\n\t\t\t\tusage: message.usage,\n\t\t\t\tstopReason: message.stopReason,\n\t\t\t\ttimestamp: message.timestamp\n\t\t\t};\n\t\t})\n\t};\n}\n/**\n* pi-ai-backed multi-provider adapter."
1515
+ },
1516
+ {
1517
+ "before": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tfor (const profile of profiles.values()) if (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n",
1518
+ "after": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tconst entryModels = new Map();\n\t\tfor (const [provider, profile] of profiles) {\n\t\t\tif (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\t\tconst entries = new Map();\n\t\t\tfor (const [id, entry] of profile.keyEntries) {\n\t\t\t\tconst collection = createModels(this.config.auth);\n\t\t\t\tif (entry.piProvider !== void 0) collection.setProvider(entry.piProvider);\n\t\t\t\tentries.set(id, collection);\n\t\t\t}\n\t\t\tentryModels.set(provider, entries);\n\t\t}\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels,\n\t\t\tentryModels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n"
1519
+ },
1520
+ {
1521
+ "before": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst failure = profile.modelErrors.get(model) ?? (profile.piProvider === void 0 ? profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = snapshot.models.getModel(provider, model);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n",
1522
+ "after": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** Bind the public selection to an exact profile, independent model collection, and upstream id. */\n\trouteOf(snapshot, provider, model) {\n\t\tconst root = this.profileOf(snapshot, provider);\n\t\tconst entry = keyModelRoute(model);\n\t\tif (entry === void 0) return { profile: root, models: snapshot.models, wireModel: model };\n\t\tif (root.multiKey !== true) throw new LlmError(`multi-key selection is disabled for provider \"${provider}\"`, \"UNKNOWN_MODEL\");\n\t\tconst profile = root.keyEntries.get(entry.entryId);\n\t\tconst models = snapshot.entryModels.get(provider)?.get(entry.entryId);\n\t\tif (profile === void 0 || models === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${entry.entryId}\"`, \"UNKNOWN_MODEL\");\n\t\treturn { profile, models, wireModel: entry.wireModel };\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst route = this.routeOf(snapshot, provider, model);\n\t\tconst failure = route.profile.modelErrors.get(route.wireModel) ?? (route.profile.piProvider === void 0 ? route.profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = route.models.getModel(provider, route.wireModel);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n"
1523
+ },
1524
+ {
1525
+ "before": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\ttry {\n\t\t\t\tawait this.config.resolveApiKey(provider, profile);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return [];\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn snapshot.models.getModels(provider).map((model) => ({\n\t\t\t\tprovider,\n\t\t\t\tid: model.id,\n\t\t\t\tname: model.name,\n\t\t\t\tinputModalities: [...model.input]\n\t\t\t}));\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n",
1526
+ "after": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\tconst listed = [];\n\t\t\tconst append = async (owner, models, entryId) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst key = await this.config.resolveApiKey(provider, owner);\n\t\t\t\t\tif (entryId !== void 0 && (key === void 0 || key.length === 0)) return;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return;\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tfor (const model of models.getModels(provider)) listed.push({\n\t\t\t\t\tprovider,\n\t\t\t\t\tid: entryId === void 0 ? model.id : keyModelId(entryId, model.id),\n\t\t\t\t\tname: model.name,\n\t\t\t\t\tinputModalities: [...model.input]\n\t\t\t\t});\n\t\t\t};\n\t\t\t// Keep raw root models advertised so old sessions remain routable without changing keys.\n\t\t\tawait append(profile, snapshot.models);\n\t\t\tif (profile.multiKey === true) for (const [id, entry] of profile.keyEntries) await append(entry, snapshot.entryModels.get(provider).get(id), id);\n\t\t\treturn listed;\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n"
1527
+ },
1528
+ {
1529
+ "before": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(model);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n",
1530
+ "after": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst { profile, wireModel } = this.routeOf(snapshot, provider, model);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(wireModel);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n"
1531
+ },
1532
+ {
1533
+ "before": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => this.streamWithSnapshot(options, snapshot)\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot(options, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n",
1534
+ "after": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => {\n\t\t\t\tif (options.provider !== provider || options.model !== model) throw new LlmError(\"prepared multi-key model selection changed before adapter dispatch\", \"INVALID_CONFIG\");\n\t\t\t\t// Async generators are lazy; pin the owner before returning one to caller-owned code.\n\t\t\t\treturn this.streamWithSnapshot({ ...options, provider, model }, snapshot);\n\t\t\t}\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot({ ...options }, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n"
1535
+ },
1536
+ {
1537
+ "before": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst profile = this.profileOf(snapshot, options.provider);\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n",
1538
+ "after": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst route = this.routeOf(snapshot, options.provider, options.model);\n\t\t\tconst profile = route.profile;\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n"
1539
+ },
1540
+ {
1541
+ "before": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n",
1542
+ "after": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tif (profile.keyEntryId !== void 0 && (apiKey === void 0 || apiKey.length === 0)) throw new LlmError(`provider \"${options.provider}\" key entry \"${profile.keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n"
1543
+ },
1544
+ {
1545
+ "before": "\t\t\t\tconst iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, model.id)[Symbol.asyncIterator]();",
1546
+ "after": "\t\t\t\tconst iterator = toStreamChunks(route.models.streamSimple(model, replayContextForRoute(context, options.provider, options.model, model), {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, options.model)[Symbol.asyncIterator]();"
1547
+ },
1548
+ {
1549
+ "before": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n",
1550
+ "after": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\t// Validate host-owned entry identity even on the installed-catalog shortcut.\n\tconst selectedStored = request.keyEntryId === void 0 ? void 0 : storedProfile?.();\n\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n"
1551
+ },
1552
+ {
1553
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n",
1554
+ "after": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = selectedStored ?? storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n"
1555
+ },
1556
+ {
1557
+ "before": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n",
1558
+ "after": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy,\n\t\tmultiKey: profile.multiKey === true,\n\t\tapiKeyEnv: profile.apiKeyEnv,\n\t\tmodels: profile.piProvider?.getModels(),\n\t\tmodelErrors: [...profile.modelErrors],\n\t\tkeyEntries: [...profile.keyEntries].map(([id, entry]) => ({\n\t\t\tid,\n\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),\n\t\t\tmodelErrors: [...entry.modelErrors]\n\t\t})).sort((left, right) => left.id.localeCompare(right.id))\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n"
1559
+ },
1560
+ {
1561
+ "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
1562
+ "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
1563
+ },
1564
+ {
1565
+ "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
1566
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tmodels: z.array(modelProfile).required()\n});"
1567
+ },
1568
+ {
1569
+ "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
1570
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (!Array.isArray(entry.models))"
1571
+ },
1572
+ {
1573
+ "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
1574
+ "after": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\t...entry.api === void 0 ? {} : { api: entry.api },\n\t\t\t\tmultiKey: false,"
1575
+ },
1576
+ {
1577
+ "before": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {",
1578
+ "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api !== void 0 ? request.api : selectedStored?.api !== void 0 ? selectedStored.api : \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
1579
+ },
1580
+ {
1581
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);",
1582
+ "after": "\tconst baseURL = request.baseURL ?? selectedStored?.baseURL;\n\tif (baseURL === void 0 || baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(baseURL, api);"
1583
+ },
1584
+ {
1585
+ "before": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),",
1586
+ "after": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tapi: entry.api,\n\t\t\tmodels: entry.piProvider?.getModels(),"
1587
+ },
1588
+ {
1589
+ "before": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,",
1590
+ "after": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\tapi: profile.api,\n\t\t\tbaseURL: profile.baseURL ?? catalogProvider(provider)?.baseUrl,\n\t\t\theaders: profile.headers,"
1591
+ },
1592
+ {
1593
+ "before": "function listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");",
1594
+ "after": "/** Strip trailing slashes and one trailing `/v1`, the segment the Anthropic SDK adds itself. */\nfunction anthropicRoot(baseURL) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");\n\treturn base.endsWith(\"/v1\") ? base.slice(0, -3) : base;\n}\nfunction listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");"
1595
+ },
1596
+ {
1597
+ "before": "\t\tconst baseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (baseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);",
1598
+ "after": "\t\tconst configuredBaseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (configuredBaseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);\n\t\tconst baseUrl = api === \"anthropic-messages\" ? anthropicRoot(configuredBaseUrl) : configuredBaseUrl;"
1599
+ },
1600
+ {
1601
+ "before": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${base.endsWith(\"/v1\") ? base.slice(0, -3) : base}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;",
1602
+ "after": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${anthropicRoot(base)}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;"
1603
+ }
1604
+ ]
1605
+ },
1606
+ {
1607
+ "source": "npm official 0.2.2-rc.1 with per-entry API overrides",
1608
+ "baseSha256": "1a3ae58f9b4493e15459cc5000ec80f21b5d3f4a9dea6ffb6bc28e5b8817ae8a",
1609
+ "resultSha256": "432b9050dff97c9dae6744b6c6189e0c4a4363321afab6310aec4d5fcb418681",
1610
+ "replacements": [
1611
+ {
1612
+ "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
1613
+ "after": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\n// Model selection carries an opaque entry identity, never a credential or a wire alias.\nconst KEY_MODEL_PREFIX = \"@dsh-key/\";\nconst KEY_ENTRY_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;\nconst FORBIDDEN_KEY_ENTRY_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst AUTH_HEADER_NAMES = new Set([\"authorization\", \"proxy-authorization\", \"x-api-key\", \"api-key\", \"cf-aig-authorization\"]);\nfunction validKeyEntryId(id) {\n\treturn KEY_ENTRY_ID.test(id) && !FORBIDDEN_KEY_ENTRY_IDS.has(id);\n}\nfunction keyModelId(entryId, model) {\n\treturn `${KEY_MODEL_PREFIX}${encodeURIComponent(entryId)}/${encodeURIComponent(model)}`;\n}\nfunction keyModelRoute(model) {\n\tif (!model.startsWith(KEY_MODEL_PREFIX)) return void 0;\n\ttry {\n\t\tconst parts = model.slice(KEY_MODEL_PREFIX.length).split(\"/\");\n\t\tif (parts.length === 2) {\n\t\t\tconst entryId = decodeURIComponent(parts[0]);\n\t\t\tconst wireModel = decodeURIComponent(parts[1]);\n\t\t\tif (validKeyEntryId(entryId) && wireModel.length > 0 && !wireModel.startsWith(KEY_MODEL_PREFIX) && keyModelId(entryId, wireModel) === model) return { entryId, wireModel };\n\t\t}\n\t} catch {}\n\tthrow new LlmError(`invalid multi-key model selection \"${model}\"`, \"UNKNOWN_MODEL\");\n}\nconst keyEntryProfile = z.object({\n\tname: z.string().max(120).required(),\n\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});\nconst profile = z.object({\n\tmultiKey: z.boolean().default(false),\n\tkeyEntries: z.dict(keyEntryProfile).default({}),\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n"
1614
+ },
1615
+ {
1616
+ "before": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\") {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n",
1617
+ "after": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\", forKeyEntry = false) {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n"
1618
+ },
1619
+ {
1620
+ "before": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n",
1621
+ "after": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst entrySources = source.keyEntries ?? {};\n\t\tif (typeof entrySources !== \"object\" || entrySources === null || Array.isArray(entrySources)) throw new Error(`llm-pi-ai: provider \"${provider}\" keyEntries must be a dictionary`);\n\t\tconst assertWireModels = (models, site) => {\n\t\t\tfor (const model of models ?? []) if (typeof model.id !== \"string\" || model.id.length === 0 || model.id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} must use non-empty upstream model ids outside the reserved ${KEY_MODEL_PREFIX} prefix`);\n\t\t};\n\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const id of Object.keys(source.modelOverrides ?? {})) if (id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" modelOverrides uses reserved prefix ${KEY_MODEL_PREFIX}`);\n\t\tfor (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tif (!validKeyEntryId(id)) throw new Error(`llm-pi-ai: provider \"${provider}\" has an invalid key entry id \"${id}\"`);\n\t\t\tif (typeof entry !== \"object\" || entry === null || typeof entry.name !== \"string\" || entry.name.trim().length === 0 || entry.name.length > 120) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs a name of 1-120 characters`);\n\t\t\tif (typeof entry.apiKeyEnv !== \"string\" || entry.apiKeyEnv.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own apiKeyEnv`);\n\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own models list`);\n\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t}\n\t\tconst assertEntryHeaders = (headers, site) => {\n\t\t\tfor (const name of Object.keys(headers ?? {})) if (AUTH_HEADER_NAMES.has(name.toLowerCase())) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} authentication header \"${name}\" would override the selected key; remove it before enabling multiKey`);\n\t\t};\n\t\tif (source.multiKey === true || forKeyEntry) {\n\t\t\tassertEntryHeaders(source.headers, \"shared\");\n\t\t\tfor (const model of source.models ?? []) assertEntryHeaders(model.headers, `model \"${model.id}\"`);\n\t\t\tfor (const [id, override] of Object.entries(source.modelOverrides ?? {})) assertEntryHeaders(override.headers, `model override \"${id}\"`);\n\t\t}\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n"
1622
+ },
1623
+ {
1624
+ "before": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\ttry {\n\t\t\tcatalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n",
1625
+ "after": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tconst keyEntries = new Map();\n\t\t// Disabled entries remain stored, but cannot constrain legacy single-key runtime behavior.\n\t\tif (source.multiKey === true) for (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,\n\t\t\t\tkeyEntries: {},\n\t\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\t\tmodels: entry.models,\n\t\t\t\tmodelOverrides: void 0\n\t\t\t} }, validation, true).get(provider);\n\t\t\t// Entry auth must not consult a catalog provider's ambient/OAuth credential or endpoint.\n\t\t\tkeyEntries.set(id, {\n\t\t\t\t...child,\n\t\t\t\tkeyEntryId: id,\n\t\t\t\tkeyEntryName: entry.name,\n\t\t\t\t...child.piProvider === void 0 ? {} : { piProvider: { ...child.piProvider, auth: { apiKey: harnessApiKeyAuth(entry.name) } } }\n\t\t\t});\n\t\t}\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\tconst entryOnly = forKeyEntry && source.models.length === 0 || source.multiKey === true && keyEntries.size > 0 && (source.models ?? []).length === 0 && catalogModels(provider).size === 0;\n\t\ttry {\n\t\t\tif (entryOnly) catalog = { models: [], configuredMaxTokens: new Map(), modelErrors: new Map() };\n\t\t\telse catalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n"
1626
+ },
1627
+ {
1628
+ "before": "\t\t\t}, validation);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;",
1629
+ "after": "\t\t\t}, validation);\n\t\t\tif (source.multiKey === true || forKeyEntry) for (const model of catalog.models) assertEntryHeaders(model.headers, `resolved model \"${model.id}\"`);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;"
1630
+ },
1631
+ {
1632
+ "before": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },",
1633
+ "after": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, keyEntries: _keyEntries, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\tkeyEntries,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },"
1634
+ },
1635
+ {
1636
+ "before": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/**\n* pi-ai-backed multi-provider adapter.",
1637
+ "after": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/** Decode only the selected replay owner at the pi boundary; never merge equal wire ids across keys. */\nfunction replayContextForRoute(context, provider, requestedModel, wireModel) {\n\tconst selectedEntry = requestedModel.startsWith(KEY_MODEL_PREFIX);\n\treturn {\n\t\t...context,\n\t\tmessages: context.messages.map((message) => {\n\t\t\tif (message.role !== \"assistant\") return message;\n\t\t\tif (message.provider === provider && message.model === requestedModel) return { ...message, model: wireModel.id };\n\t\t\tif (!message.model.startsWith(KEY_MODEL_PREFIX) && !(selectedEntry && message.provider === provider && message.model === wireModel.id)) return message;\n\t\t\treturn {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tapi: \"dsh-foreign\",\n\t\t\t\tprovider: message.provider,\n\t\t\t\tmodel: \"dsh-foreign\",\n\t\t\t\tcontent: message.content.flatMap((block) => {\n\t\t\t\t\tif (block.type === \"thinking\") return [];\n\t\t\t\t\tif (block.type === \"text\") return [{ type: \"text\", text: block.text }];\n\t\t\t\t\tif (block.type === \"toolCall\") return [{ type: \"toolCall\", id: block.id, name: block.name, arguments: block.arguments }];\n\t\t\t\t\treturn [block];\n\t\t\t\t}),\n\t\t\t\tusage: message.usage,\n\t\t\t\tstopReason: message.stopReason,\n\t\t\t\ttimestamp: message.timestamp\n\t\t\t};\n\t\t})\n\t};\n}\n/**\n* pi-ai-backed multi-provider adapter."
1638
+ },
1639
+ {
1640
+ "before": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tfor (const profile of profiles.values()) if (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n",
1641
+ "after": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tconst entryModels = new Map();\n\t\tfor (const [provider, profile] of profiles) {\n\t\t\tif (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\t\tconst entries = new Map();\n\t\t\tfor (const [id, entry] of profile.keyEntries) {\n\t\t\t\tconst collection = createModels(this.config.auth);\n\t\t\t\tif (entry.piProvider !== void 0) collection.setProvider(entry.piProvider);\n\t\t\t\tentries.set(id, collection);\n\t\t\t}\n\t\t\tentryModels.set(provider, entries);\n\t\t}\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels,\n\t\t\tentryModels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n"
1642
+ },
1643
+ {
1644
+ "before": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst failure = profile.modelErrors.get(model) ?? (profile.piProvider === void 0 ? profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = snapshot.models.getModel(provider, model);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n",
1645
+ "after": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** Bind the public selection to an exact profile, independent model collection, and upstream id. */\n\trouteOf(snapshot, provider, model) {\n\t\tconst root = this.profileOf(snapshot, provider);\n\t\tconst entry = keyModelRoute(model);\n\t\tif (entry === void 0) return { profile: root, models: snapshot.models, wireModel: model };\n\t\tif (root.multiKey !== true) throw new LlmError(`multi-key selection is disabled for provider \"${provider}\"`, \"UNKNOWN_MODEL\");\n\t\tconst profile = root.keyEntries.get(entry.entryId);\n\t\tconst models = snapshot.entryModels.get(provider)?.get(entry.entryId);\n\t\tif (profile === void 0 || models === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${entry.entryId}\"`, \"UNKNOWN_MODEL\");\n\t\treturn { profile, models, wireModel: entry.wireModel };\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst route = this.routeOf(snapshot, provider, model);\n\t\tconst failure = route.profile.modelErrors.get(route.wireModel) ?? (route.profile.piProvider === void 0 ? route.profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = route.models.getModel(provider, route.wireModel);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n"
1646
+ },
1647
+ {
1648
+ "before": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\ttry {\n\t\t\t\tawait this.config.resolveApiKey(provider, profile);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return [];\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn snapshot.models.getModels(provider).map((model) => ({\n\t\t\t\tprovider,\n\t\t\t\tid: model.id,\n\t\t\t\tname: model.name,\n\t\t\t\tinputModalities: [...model.input]\n\t\t\t}));\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n",
1649
+ "after": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\tconst listed = [];\n\t\t\tconst append = async (owner, models, entryId) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst key = await this.config.resolveApiKey(provider, owner);\n\t\t\t\t\tif (entryId !== void 0 && (key === void 0 || key.length === 0)) return;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return;\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tfor (const model of models.getModels(provider)) listed.push({\n\t\t\t\t\tprovider,\n\t\t\t\t\tid: entryId === void 0 ? model.id : keyModelId(entryId, model.id),\n\t\t\t\t\tname: model.name,\n\t\t\t\t\tinputModalities: [...model.input]\n\t\t\t\t});\n\t\t\t};\n\t\t\t// Keep raw root models advertised so old sessions remain routable without changing keys.\n\t\t\tawait append(profile, snapshot.models);\n\t\t\tif (profile.multiKey === true) for (const [id, entry] of profile.keyEntries) await append(entry, snapshot.entryModels.get(provider).get(id), id);\n\t\t\treturn listed;\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n"
1650
+ },
1651
+ {
1652
+ "before": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(model);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n",
1653
+ "after": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst { profile, wireModel } = this.routeOf(snapshot, provider, model);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(wireModel);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n"
1654
+ },
1655
+ {
1656
+ "before": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => this.streamWithSnapshot(options, snapshot)\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot(options, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n",
1657
+ "after": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => {\n\t\t\t\tif (options.provider !== provider || options.model !== model) throw new LlmError(\"prepared multi-key model selection changed before adapter dispatch\", \"INVALID_CONFIG\");\n\t\t\t\t// Async generators are lazy; pin the owner before returning one to caller-owned code.\n\t\t\t\treturn this.streamWithSnapshot({ ...options, provider, model }, snapshot);\n\t\t\t}\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot({ ...options }, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n"
1658
+ },
1659
+ {
1660
+ "before": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst profile = this.profileOf(snapshot, options.provider);\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n",
1661
+ "after": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst route = this.routeOf(snapshot, options.provider, options.model);\n\t\t\tconst profile = route.profile;\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n"
1662
+ },
1663
+ {
1664
+ "before": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n",
1665
+ "after": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tif (profile.keyEntryId !== void 0 && (apiKey === void 0 || apiKey.length === 0)) throw new LlmError(`provider \"${options.provider}\" key entry \"${profile.keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n"
1666
+ },
1667
+ {
1668
+ "before": "\t\t\t\tconst iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, model.id)[Symbol.asyncIterator]();",
1669
+ "after": "\t\t\t\tconst iterator = toStreamChunks(route.models.streamSimple(model, replayContextForRoute(context, options.provider, options.model, model), {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, options.model)[Symbol.asyncIterator]();"
1670
+ },
1671
+ {
1672
+ "before": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n",
1673
+ "after": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\t// Validate host-owned entry identity even on the installed-catalog shortcut.\n\tconst selectedStored = request.keyEntryId === void 0 ? void 0 : storedProfile?.();\n\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n"
1674
+ },
1675
+ {
1676
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n",
1677
+ "after": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = selectedStored ?? storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n"
1678
+ },
1679
+ {
1680
+ "before": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n",
1681
+ "after": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy,\n\t\tmultiKey: profile.multiKey === true,\n\t\tapiKeyEnv: profile.apiKeyEnv,\n\t\tmodels: profile.piProvider?.getModels(),\n\t\tmodelErrors: [...profile.modelErrors],\n\t\tkeyEntries: [...profile.keyEntries].map(([id, entry]) => ({\n\t\t\tid,\n\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),\n\t\t\tmodelErrors: [...entry.modelErrors]\n\t\t})).sort((left, right) => left.id.localeCompare(right.id))\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n"
1682
+ },
1683
+ {
1684
+ "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
1685
+ "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
1686
+ },
1687
+ {
1688
+ "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
1689
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tmodels: z.array(modelProfile).required()\n});"
1690
+ },
1691
+ {
1692
+ "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
1693
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (!Array.isArray(entry.models))"
1694
+ },
1695
+ {
1696
+ "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
1697
+ "after": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\t...entry.api === void 0 ? {} : { api: entry.api },\n\t\t\t\tmultiKey: false,"
1698
+ },
1699
+ {
1700
+ "before": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {",
1701
+ "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api !== void 0 ? request.api : selectedStored?.api !== void 0 ? selectedStored.api : \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
1702
+ },
1703
+ {
1704
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);",
1705
+ "after": "\tconst baseURL = request.baseURL ?? selectedStored?.baseURL;\n\tif (baseURL === void 0 || baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(baseURL, api);"
1706
+ },
1707
+ {
1708
+ "before": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),",
1709
+ "after": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tapi: entry.api,\n\t\t\tmodels: entry.piProvider?.getModels(),"
1710
+ },
1711
+ {
1712
+ "before": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,",
1713
+ "after": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\tapi: profile.api,\n\t\t\tbaseURL: profile.baseURL ?? catalogProvider(provider)?.baseUrl,\n\t\t\theaders: profile.headers,"
1714
+ },
1715
+ {
1716
+ "before": "function listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");",
1717
+ "after": "/** Strip trailing slashes and one trailing `/v1`, the segment the Anthropic SDK adds itself. */\nfunction anthropicRoot(baseURL) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");\n\treturn base.endsWith(\"/v1\") ? base.slice(0, -3) : base;\n}\nfunction listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");"
1718
+ },
1719
+ {
1720
+ "before": "\t\tconst baseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (baseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);",
1721
+ "after": "\t\tconst configuredBaseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (configuredBaseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);\n\t\tconst baseUrl = api === \"anthropic-messages\" ? anthropicRoot(configuredBaseUrl) : configuredBaseUrl;"
1722
+ },
1723
+ {
1724
+ "before": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${base.endsWith(\"/v1\") ? base.slice(0, -3) : base}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;",
1725
+ "after": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${anthropicRoot(base)}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;"
1726
+ }
1727
+ ]
1728
+ },
1729
+ {
1730
+ "source": "0.2.2-rc.1 with tool lookup optimization and credential cancellation with per-entry API overrides",
1731
+ "baseSha256": "0a99a2fc903a4285044b09114b3bd20ee1e612f39aa381e4a71b10d48ee9e9f7",
1732
+ "resultSha256": "c7d20ebe93753ae6f30d614121bac533fe5a8fa9372ea1c5fdc8bf2f7eba1d1d",
1733
+ "replacements": [
1734
+ {
1735
+ "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
1736
+ "after": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\n// Model selection carries an opaque entry identity, never a credential or a wire alias.\nconst KEY_MODEL_PREFIX = \"@dsh-key/\";\nconst KEY_ENTRY_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;\nconst FORBIDDEN_KEY_ENTRY_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst AUTH_HEADER_NAMES = new Set([\"authorization\", \"proxy-authorization\", \"x-api-key\", \"api-key\", \"cf-aig-authorization\"]);\nfunction validKeyEntryId(id) {\n\treturn KEY_ENTRY_ID.test(id) && !FORBIDDEN_KEY_ENTRY_IDS.has(id);\n}\nfunction keyModelId(entryId, model) {\n\treturn `${KEY_MODEL_PREFIX}${encodeURIComponent(entryId)}/${encodeURIComponent(model)}`;\n}\nfunction keyModelRoute(model) {\n\tif (!model.startsWith(KEY_MODEL_PREFIX)) return void 0;\n\ttry {\n\t\tconst parts = model.slice(KEY_MODEL_PREFIX.length).split(\"/\");\n\t\tif (parts.length === 2) {\n\t\t\tconst entryId = decodeURIComponent(parts[0]);\n\t\t\tconst wireModel = decodeURIComponent(parts[1]);\n\t\t\tif (validKeyEntryId(entryId) && wireModel.length > 0 && !wireModel.startsWith(KEY_MODEL_PREFIX) && keyModelId(entryId, wireModel) === model) return { entryId, wireModel };\n\t\t}\n\t} catch {}\n\tthrow new LlmError(`invalid multi-key model selection \"${model}\"`, \"UNKNOWN_MODEL\");\n}\nconst keyEntryProfile = z.object({\n\tname: z.string().max(120).required(),\n\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});\nconst profile = z.object({\n\tmultiKey: z.boolean().default(false),\n\tkeyEntries: z.dict(keyEntryProfile).default({}),\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n"
1737
+ },
1738
+ {
1739
+ "before": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\") {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n",
1740
+ "after": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\", forKeyEntry = false) {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n"
1741
+ },
1742
+ {
1743
+ "before": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n",
1744
+ "after": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst entrySources = source.keyEntries ?? {};\n\t\tif (typeof entrySources !== \"object\" || entrySources === null || Array.isArray(entrySources)) throw new Error(`llm-pi-ai: provider \"${provider}\" keyEntries must be a dictionary`);\n\t\tconst assertWireModels = (models, site) => {\n\t\t\tfor (const model of models ?? []) if (typeof model.id !== \"string\" || model.id.length === 0 || model.id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} must use non-empty upstream model ids outside the reserved ${KEY_MODEL_PREFIX} prefix`);\n\t\t};\n\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const id of Object.keys(source.modelOverrides ?? {})) if (id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" modelOverrides uses reserved prefix ${KEY_MODEL_PREFIX}`);\n\t\tfor (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tif (!validKeyEntryId(id)) throw new Error(`llm-pi-ai: provider \"${provider}\" has an invalid key entry id \"${id}\"`);\n\t\t\tif (typeof entry !== \"object\" || entry === null || typeof entry.name !== \"string\" || entry.name.trim().length === 0 || entry.name.length > 120) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs a name of 1-120 characters`);\n\t\t\tif (typeof entry.apiKeyEnv !== \"string\" || entry.apiKeyEnv.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own apiKeyEnv`);\n\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own models list`);\n\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t}\n\t\tconst assertEntryHeaders = (headers, site) => {\n\t\t\tfor (const name of Object.keys(headers ?? {})) if (AUTH_HEADER_NAMES.has(name.toLowerCase())) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} authentication header \"${name}\" would override the selected key; remove it before enabling multiKey`);\n\t\t};\n\t\tif (source.multiKey === true || forKeyEntry) {\n\t\t\tassertEntryHeaders(source.headers, \"shared\");\n\t\t\tfor (const model of source.models ?? []) assertEntryHeaders(model.headers, `model \"${model.id}\"`);\n\t\t\tfor (const [id, override] of Object.entries(source.modelOverrides ?? {})) assertEntryHeaders(override.headers, `model override \"${id}\"`);\n\t\t}\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n"
1745
+ },
1746
+ {
1747
+ "before": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\ttry {\n\t\t\tcatalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n",
1748
+ "after": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tconst keyEntries = new Map();\n\t\t// Disabled entries remain stored, but cannot constrain legacy single-key runtime behavior.\n\t\tif (source.multiKey === true) for (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,\n\t\t\t\tkeyEntries: {},\n\t\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\t\tmodels: entry.models,\n\t\t\t\tmodelOverrides: void 0\n\t\t\t} }, validation, true).get(provider);\n\t\t\t// Entry auth must not consult a catalog provider's ambient/OAuth credential or endpoint.\n\t\t\tkeyEntries.set(id, {\n\t\t\t\t...child,\n\t\t\t\tkeyEntryId: id,\n\t\t\t\tkeyEntryName: entry.name,\n\t\t\t\t...child.piProvider === void 0 ? {} : { piProvider: { ...child.piProvider, auth: { apiKey: harnessApiKeyAuth(entry.name) } } }\n\t\t\t});\n\t\t}\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\tconst entryOnly = forKeyEntry && source.models.length === 0 || source.multiKey === true && keyEntries.size > 0 && (source.models ?? []).length === 0 && catalogModels(provider).size === 0;\n\t\ttry {\n\t\t\tif (entryOnly) catalog = { models: [], configuredMaxTokens: new Map(), modelErrors: new Map() };\n\t\t\telse catalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n"
1749
+ },
1750
+ {
1751
+ "before": "\t\t\t}, validation);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;",
1752
+ "after": "\t\t\t}, validation);\n\t\t\tif (source.multiKey === true || forKeyEntry) for (const model of catalog.models) assertEntryHeaders(model.headers, `resolved model \"${model.id}\"`);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;"
1753
+ },
1754
+ {
1755
+ "before": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },",
1756
+ "after": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, keyEntries: _keyEntries, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\tkeyEntries,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },"
1757
+ },
1758
+ {
1759
+ "before": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/**\n* pi-ai-backed multi-provider adapter.",
1760
+ "after": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/** Decode only the selected replay owner at the pi boundary; never merge equal wire ids across keys. */\nfunction replayContextForRoute(context, provider, requestedModel, wireModel) {\n\tconst selectedEntry = requestedModel.startsWith(KEY_MODEL_PREFIX);\n\treturn {\n\t\t...context,\n\t\tmessages: context.messages.map((message) => {\n\t\t\tif (message.role !== \"assistant\") return message;\n\t\t\tif (message.provider === provider && message.model === requestedModel) return { ...message, model: wireModel.id };\n\t\t\tif (!message.model.startsWith(KEY_MODEL_PREFIX) && !(selectedEntry && message.provider === provider && message.model === wireModel.id)) return message;\n\t\t\treturn {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tapi: \"dsh-foreign\",\n\t\t\t\tprovider: message.provider,\n\t\t\t\tmodel: \"dsh-foreign\",\n\t\t\t\tcontent: message.content.flatMap((block) => {\n\t\t\t\t\tif (block.type === \"thinking\") return [];\n\t\t\t\t\tif (block.type === \"text\") return [{ type: \"text\", text: block.text }];\n\t\t\t\t\tif (block.type === \"toolCall\") return [{ type: \"toolCall\", id: block.id, name: block.name, arguments: block.arguments }];\n\t\t\t\t\treturn [block];\n\t\t\t\t}),\n\t\t\t\tusage: message.usage,\n\t\t\t\tstopReason: message.stopReason,\n\t\t\t\ttimestamp: message.timestamp\n\t\t\t};\n\t\t})\n\t};\n}\n/**\n* pi-ai-backed multi-provider adapter."
1761
+ },
1762
+ {
1763
+ "before": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tfor (const profile of profiles.values()) if (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n",
1764
+ "after": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tconst entryModels = new Map();\n\t\tfor (const [provider, profile] of profiles) {\n\t\t\tif (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\t\tconst entries = new Map();\n\t\t\tfor (const [id, entry] of profile.keyEntries) {\n\t\t\t\tconst collection = createModels(this.config.auth);\n\t\t\t\tif (entry.piProvider !== void 0) collection.setProvider(entry.piProvider);\n\t\t\t\tentries.set(id, collection);\n\t\t\t}\n\t\t\tentryModels.set(provider, entries);\n\t\t}\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels,\n\t\t\tentryModels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n"
1765
+ },
1766
+ {
1767
+ "before": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst failure = profile.modelErrors.get(model) ?? (profile.piProvider === void 0 ? profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = snapshot.models.getModel(provider, model);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n",
1768
+ "after": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** Bind the public selection to an exact profile, independent model collection, and upstream id. */\n\trouteOf(snapshot, provider, model) {\n\t\tconst root = this.profileOf(snapshot, provider);\n\t\tconst entry = keyModelRoute(model);\n\t\tif (entry === void 0) return { profile: root, models: snapshot.models, wireModel: model };\n\t\tif (root.multiKey !== true) throw new LlmError(`multi-key selection is disabled for provider \"${provider}\"`, \"UNKNOWN_MODEL\");\n\t\tconst profile = root.keyEntries.get(entry.entryId);\n\t\tconst models = snapshot.entryModels.get(provider)?.get(entry.entryId);\n\t\tif (profile === void 0 || models === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${entry.entryId}\"`, \"UNKNOWN_MODEL\");\n\t\treturn { profile, models, wireModel: entry.wireModel };\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst route = this.routeOf(snapshot, provider, model);\n\t\tconst failure = route.profile.modelErrors.get(route.wireModel) ?? (route.profile.piProvider === void 0 ? route.profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = route.models.getModel(provider, route.wireModel);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n"
1769
+ },
1770
+ {
1771
+ "before": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\ttry {\n\t\t\t\tawait this.config.resolveApiKey(provider, profile);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return [];\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn snapshot.models.getModels(provider).map((model) => ({\n\t\t\t\tprovider,\n\t\t\t\tid: model.id,\n\t\t\t\tname: model.name,\n\t\t\t\tinputModalities: [...model.input]\n\t\t\t}));\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n",
1772
+ "after": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\tconst listed = [];\n\t\t\tconst append = async (owner, models, entryId) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst key = await this.config.resolveApiKey(provider, owner);\n\t\t\t\t\tif (entryId !== void 0 && (key === void 0 || key.length === 0)) return;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return;\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tfor (const model of models.getModels(provider)) listed.push({\n\t\t\t\t\tprovider,\n\t\t\t\t\tid: entryId === void 0 ? model.id : keyModelId(entryId, model.id),\n\t\t\t\t\tname: model.name,\n\t\t\t\t\tinputModalities: [...model.input]\n\t\t\t\t});\n\t\t\t};\n\t\t\t// Keep raw root models advertised so old sessions remain routable without changing keys.\n\t\t\tawait append(profile, snapshot.models);\n\t\t\tif (profile.multiKey === true) for (const [id, entry] of profile.keyEntries) await append(entry, snapshot.entryModels.get(provider).get(id), id);\n\t\t\treturn listed;\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n"
1773
+ },
1774
+ {
1775
+ "before": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(model);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n",
1776
+ "after": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst { profile, wireModel } = this.routeOf(snapshot, provider, model);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(wireModel);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n"
1777
+ },
1778
+ {
1779
+ "before": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => this.streamWithSnapshot(options, snapshot)\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot(options, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n",
1780
+ "after": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => {\n\t\t\t\tif (options.provider !== provider || options.model !== model) throw new LlmError(\"prepared multi-key model selection changed before adapter dispatch\", \"INVALID_CONFIG\");\n\t\t\t\t// Async generators are lazy; pin the owner before returning one to caller-owned code.\n\t\t\t\treturn this.streamWithSnapshot({ ...options, provider, model }, snapshot);\n\t\t\t}\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot({ ...options }, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n"
1781
+ },
1782
+ {
1783
+ "before": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst profile = this.profileOf(snapshot, options.provider);\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n",
1784
+ "after": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst route = this.routeOf(snapshot, options.provider, options.model);\n\t\t\tconst profile = route.profile;\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n"
1785
+ },
1786
+ {
1787
+ "before": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n",
1788
+ "after": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tif (profile.keyEntryId !== void 0 && (apiKey === void 0 || apiKey.length === 0)) throw new LlmError(`provider \"${options.provider}\" key entry \"${profile.keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n"
1789
+ },
1790
+ {
1791
+ "before": "\t\t\t\tconst iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, model.id)[Symbol.asyncIterator]();",
1792
+ "after": "\t\t\t\tconst iterator = toStreamChunks(route.models.streamSimple(model, replayContextForRoute(context, options.provider, options.model, model), {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, options.model)[Symbol.asyncIterator]();"
1793
+ },
1794
+ {
1795
+ "before": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n",
1796
+ "after": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\t// Validate host-owned entry identity even on the installed-catalog shortcut.\n\tconst selectedStored = request.keyEntryId === void 0 ? void 0 : storedProfile?.();\n\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n"
1797
+ },
1798
+ {
1799
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n",
1800
+ "after": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = selectedStored ?? storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n"
1801
+ },
1802
+ {
1803
+ "before": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n",
1804
+ "after": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy,\n\t\tmultiKey: profile.multiKey === true,\n\t\tapiKeyEnv: profile.apiKeyEnv,\n\t\tmodels: profile.piProvider?.getModels(),\n\t\tmodelErrors: [...profile.modelErrors],\n\t\tkeyEntries: [...profile.keyEntries].map(([id, entry]) => ({\n\t\t\tid,\n\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),\n\t\t\tmodelErrors: [...entry.modelErrors]\n\t\t})).sort((left, right) => left.id.localeCompare(right.id))\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n"
1805
+ },
1806
+ {
1807
+ "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
1808
+ "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
1809
+ },
1810
+ {
1811
+ "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
1812
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tmodels: z.array(modelProfile).required()\n});"
1813
+ },
1814
+ {
1815
+ "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
1816
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (!Array.isArray(entry.models))"
1817
+ },
1818
+ {
1819
+ "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
1820
+ "after": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\t...entry.api === void 0 ? {} : { api: entry.api },\n\t\t\t\tmultiKey: false,"
1821
+ },
1822
+ {
1823
+ "before": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {",
1824
+ "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api !== void 0 ? request.api : selectedStored?.api !== void 0 ? selectedStored.api : \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
1825
+ },
1826
+ {
1827
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);",
1828
+ "after": "\tconst baseURL = request.baseURL ?? selectedStored?.baseURL;\n\tif (baseURL === void 0 || baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(baseURL, api);"
1829
+ },
1830
+ {
1831
+ "before": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),",
1832
+ "after": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tapi: entry.api,\n\t\t\tmodels: entry.piProvider?.getModels(),"
1833
+ },
1834
+ {
1835
+ "before": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,",
1836
+ "after": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\tapi: profile.api,\n\t\t\tbaseURL: profile.baseURL ?? catalogProvider(provider)?.baseUrl,\n\t\t\theaders: profile.headers,"
1837
+ },
1838
+ {
1839
+ "before": "function listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");",
1840
+ "after": "/** Strip trailing slashes and one trailing `/v1`, the segment the Anthropic SDK adds itself. */\nfunction anthropicRoot(baseURL) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");\n\treturn base.endsWith(\"/v1\") ? base.slice(0, -3) : base;\n}\nfunction listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");"
1841
+ },
1842
+ {
1843
+ "before": "\t\tconst baseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (baseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);",
1844
+ "after": "\t\tconst configuredBaseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (configuredBaseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);\n\t\tconst baseUrl = api === \"anthropic-messages\" ? anthropicRoot(configuredBaseUrl) : configuredBaseUrl;"
1845
+ },
1846
+ {
1847
+ "before": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${base.endsWith(\"/v1\") ? base.slice(0, -3) : base}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;",
1848
+ "after": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${anthropicRoot(base)}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;"
1849
+ },
1850
+ {
1851
+ "before": "* gateway documentation publishes both spellings of the same root. Only this\n* listing URL normalizes that segment; model requests receive the configured\n* `baseURL` unchanged.\n*/",
1852
+ "after": "* gateway documentation publishes both spellings of the same root. Anthropic\n* listings and model requests both normalize it, because the Anthropic SDK\n* appends `/v1/messages` on its own while OpenAI protocols append\n* `/chat/completions`; without this, one root would work for chat and double\n* the segment for Anthropic.\n*/"
1853
+ }
1854
+ ]
1855
+ },
1856
+ {
1857
+ "source": "npm official 0.2.2-rc.1 with per-entry API overrides",
1858
+ "baseSha256": "1a3ae58f9b4493e15459cc5000ec80f21b5d3f4a9dea6ffb6bc28e5b8817ae8a",
1859
+ "resultSha256": "2e00ea0c1b447153e341a1ca675ed6a829094c7caf62c6524e6809bd6540be71",
1860
+ "replacements": [
1861
+ {
1862
+ "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
1863
+ "after": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\n// Model selection carries an opaque entry identity, never a credential or a wire alias.\nconst KEY_MODEL_PREFIX = \"@dsh-key/\";\nconst KEY_ENTRY_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;\nconst FORBIDDEN_KEY_ENTRY_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst AUTH_HEADER_NAMES = new Set([\"authorization\", \"proxy-authorization\", \"x-api-key\", \"api-key\", \"cf-aig-authorization\"]);\nfunction validKeyEntryId(id) {\n\treturn KEY_ENTRY_ID.test(id) && !FORBIDDEN_KEY_ENTRY_IDS.has(id);\n}\nfunction keyModelId(entryId, model) {\n\treturn `${KEY_MODEL_PREFIX}${encodeURIComponent(entryId)}/${encodeURIComponent(model)}`;\n}\nfunction keyModelRoute(model) {\n\tif (!model.startsWith(KEY_MODEL_PREFIX)) return void 0;\n\ttry {\n\t\tconst parts = model.slice(KEY_MODEL_PREFIX.length).split(\"/\");\n\t\tif (parts.length === 2) {\n\t\t\tconst entryId = decodeURIComponent(parts[0]);\n\t\t\tconst wireModel = decodeURIComponent(parts[1]);\n\t\t\tif (validKeyEntryId(entryId) && wireModel.length > 0 && !wireModel.startsWith(KEY_MODEL_PREFIX) && keyModelId(entryId, wireModel) === model) return { entryId, wireModel };\n\t\t}\n\t} catch {}\n\tthrow new LlmError(`invalid multi-key model selection \"${model}\"`, \"UNKNOWN_MODEL\");\n}\nconst keyEntryProfile = z.object({\n\tname: z.string().max(120).required(),\n\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});\nconst profile = z.object({\n\tmultiKey: z.boolean().default(false),\n\tkeyEntries: z.dict(keyEntryProfile).default({}),\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n"
1864
+ },
1865
+ {
1866
+ "before": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\") {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n",
1867
+ "after": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\", forKeyEntry = false) {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n"
1868
+ },
1869
+ {
1870
+ "before": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n",
1871
+ "after": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst entrySources = source.keyEntries ?? {};\n\t\tif (typeof entrySources !== \"object\" || entrySources === null || Array.isArray(entrySources)) throw new Error(`llm-pi-ai: provider \"${provider}\" keyEntries must be a dictionary`);\n\t\tconst assertWireModels = (models, site) => {\n\t\t\tfor (const model of models ?? []) if (typeof model.id !== \"string\" || model.id.length === 0 || model.id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} must use non-empty upstream model ids outside the reserved ${KEY_MODEL_PREFIX} prefix`);\n\t\t};\n\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const id of Object.keys(source.modelOverrides ?? {})) if (id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" modelOverrides uses reserved prefix ${KEY_MODEL_PREFIX}`);\n\t\tfor (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tif (!validKeyEntryId(id)) throw new Error(`llm-pi-ai: provider \"${provider}\" has an invalid key entry id \"${id}\"`);\n\t\t\tif (typeof entry !== \"object\" || entry === null || typeof entry.name !== \"string\" || entry.name.trim().length === 0 || entry.name.length > 120) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs a name of 1-120 characters`);\n\t\t\tif (typeof entry.apiKeyEnv !== \"string\" || entry.apiKeyEnv.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own apiKeyEnv`);\n\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own models list`);\n\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t}\n\t\tconst assertEntryHeaders = (headers, site) => {\n\t\t\tfor (const name of Object.keys(headers ?? {})) if (AUTH_HEADER_NAMES.has(name.toLowerCase())) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} authentication header \"${name}\" would override the selected key; remove it before enabling multiKey`);\n\t\t};\n\t\tif (source.multiKey === true || forKeyEntry) {\n\t\t\tassertEntryHeaders(source.headers, \"shared\");\n\t\t\tfor (const model of source.models ?? []) assertEntryHeaders(model.headers, `model \"${model.id}\"`);\n\t\t\tfor (const [id, override] of Object.entries(source.modelOverrides ?? {})) assertEntryHeaders(override.headers, `model override \"${id}\"`);\n\t\t}\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n"
1872
+ },
1873
+ {
1874
+ "before": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\ttry {\n\t\t\tcatalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n",
1875
+ "after": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tconst keyEntries = new Map();\n\t\t// Disabled entries remain stored, but cannot constrain legacy single-key runtime behavior.\n\t\tif (source.multiKey === true) for (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,\n\t\t\t\tkeyEntries: {},\n\t\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\t\tmodels: entry.models,\n\t\t\t\tmodelOverrides: void 0\n\t\t\t} }, validation, true).get(provider);\n\t\t\t// Entry auth must not consult a catalog provider's ambient/OAuth credential or endpoint.\n\t\t\tkeyEntries.set(id, {\n\t\t\t\t...child,\n\t\t\t\tkeyEntryId: id,\n\t\t\t\tkeyEntryName: entry.name,\n\t\t\t\t...child.piProvider === void 0 ? {} : { piProvider: { ...child.piProvider, auth: { apiKey: harnessApiKeyAuth(entry.name) } } }\n\t\t\t});\n\t\t}\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\tconst entryOnly = forKeyEntry && source.models.length === 0 || source.multiKey === true && keyEntries.size > 0 && (source.models ?? []).length === 0 && catalogModels(provider).size === 0;\n\t\ttry {\n\t\t\tif (entryOnly) catalog = { models: [], configuredMaxTokens: new Map(), modelErrors: new Map() };\n\t\t\telse catalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n"
1876
+ },
1877
+ {
1878
+ "before": "\t\t\t}, validation);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;",
1879
+ "after": "\t\t\t}, validation);\n\t\t\tif (source.multiKey === true || forKeyEntry) for (const model of catalog.models) assertEntryHeaders(model.headers, `resolved model \"${model.id}\"`);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;"
1880
+ },
1881
+ {
1882
+ "before": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },",
1883
+ "after": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, keyEntries: _keyEntries, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\tkeyEntries,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },"
1884
+ },
1885
+ {
1886
+ "before": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/**\n* pi-ai-backed multi-provider adapter.",
1887
+ "after": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/** Decode only the selected replay owner at the pi boundary; never merge equal wire ids across keys. */\nfunction replayContextForRoute(context, provider, requestedModel, wireModel) {\n\tconst selectedEntry = requestedModel.startsWith(KEY_MODEL_PREFIX);\n\treturn {\n\t\t...context,\n\t\tmessages: context.messages.map((message) => {\n\t\t\tif (message.role !== \"assistant\") return message;\n\t\t\tif (message.provider === provider && message.model === requestedModel) return { ...message, model: wireModel.id };\n\t\t\tif (!message.model.startsWith(KEY_MODEL_PREFIX) && !(selectedEntry && message.provider === provider && message.model === wireModel.id)) return message;\n\t\t\treturn {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tapi: \"dsh-foreign\",\n\t\t\t\tprovider: message.provider,\n\t\t\t\tmodel: \"dsh-foreign\",\n\t\t\t\tcontent: message.content.flatMap((block) => {\n\t\t\t\t\tif (block.type === \"thinking\") return [];\n\t\t\t\t\tif (block.type === \"text\") return [{ type: \"text\", text: block.text }];\n\t\t\t\t\tif (block.type === \"toolCall\") return [{ type: \"toolCall\", id: block.id, name: block.name, arguments: block.arguments }];\n\t\t\t\t\treturn [block];\n\t\t\t\t}),\n\t\t\t\tusage: message.usage,\n\t\t\t\tstopReason: message.stopReason,\n\t\t\t\ttimestamp: message.timestamp\n\t\t\t};\n\t\t})\n\t};\n}\n/**\n* pi-ai-backed multi-provider adapter."
1888
+ },
1889
+ {
1890
+ "before": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tfor (const profile of profiles.values()) if (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n",
1891
+ "after": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tconst entryModels = new Map();\n\t\tfor (const [provider, profile] of profiles) {\n\t\t\tif (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\t\tconst entries = new Map();\n\t\t\tfor (const [id, entry] of profile.keyEntries) {\n\t\t\t\tconst collection = createModels(this.config.auth);\n\t\t\t\tif (entry.piProvider !== void 0) collection.setProvider(entry.piProvider);\n\t\t\t\tentries.set(id, collection);\n\t\t\t}\n\t\t\tentryModels.set(provider, entries);\n\t\t}\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels,\n\t\t\tentryModels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n"
1892
+ },
1893
+ {
1894
+ "before": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst failure = profile.modelErrors.get(model) ?? (profile.piProvider === void 0 ? profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = snapshot.models.getModel(provider, model);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n",
1895
+ "after": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** Bind the public selection to an exact profile, independent model collection, and upstream id. */\n\trouteOf(snapshot, provider, model) {\n\t\tconst root = this.profileOf(snapshot, provider);\n\t\tconst entry = keyModelRoute(model);\n\t\tif (entry === void 0) return { profile: root, models: snapshot.models, wireModel: model };\n\t\tif (root.multiKey !== true) throw new LlmError(`multi-key selection is disabled for provider \"${provider}\"`, \"UNKNOWN_MODEL\");\n\t\tconst profile = root.keyEntries.get(entry.entryId);\n\t\tconst models = snapshot.entryModels.get(provider)?.get(entry.entryId);\n\t\tif (profile === void 0 || models === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${entry.entryId}\"`, \"UNKNOWN_MODEL\");\n\t\treturn { profile, models, wireModel: entry.wireModel };\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst route = this.routeOf(snapshot, provider, model);\n\t\tconst failure = route.profile.modelErrors.get(route.wireModel) ?? (route.profile.piProvider === void 0 ? route.profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = route.models.getModel(provider, route.wireModel);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n"
1896
+ },
1897
+ {
1898
+ "before": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\ttry {\n\t\t\t\tawait this.config.resolveApiKey(provider, profile);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return [];\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn snapshot.models.getModels(provider).map((model) => ({\n\t\t\t\tprovider,\n\t\t\t\tid: model.id,\n\t\t\t\tname: model.name,\n\t\t\t\tinputModalities: [...model.input]\n\t\t\t}));\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n",
1899
+ "after": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\tconst listed = [];\n\t\t\tconst append = async (owner, models, entryId) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst key = await this.config.resolveApiKey(provider, owner);\n\t\t\t\t\tif (entryId !== void 0 && (key === void 0 || key.length === 0)) return;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return;\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tfor (const model of models.getModels(provider)) listed.push({\n\t\t\t\t\tprovider,\n\t\t\t\t\tid: entryId === void 0 ? model.id : keyModelId(entryId, model.id),\n\t\t\t\t\tname: model.name,\n\t\t\t\t\tinputModalities: [...model.input]\n\t\t\t\t});\n\t\t\t};\n\t\t\t// Keep raw root models advertised so old sessions remain routable without changing keys.\n\t\t\tawait append(profile, snapshot.models);\n\t\t\tif (profile.multiKey === true) for (const [id, entry] of profile.keyEntries) await append(entry, snapshot.entryModels.get(provider).get(id), id);\n\t\t\treturn listed;\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n"
1900
+ },
1901
+ {
1902
+ "before": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(model);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n",
1903
+ "after": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst { profile, wireModel } = this.routeOf(snapshot, provider, model);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(wireModel);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n"
1904
+ },
1905
+ {
1906
+ "before": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => this.streamWithSnapshot(options, snapshot)\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot(options, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n",
1907
+ "after": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => {\n\t\t\t\tif (options.provider !== provider || options.model !== model) throw new LlmError(\"prepared multi-key model selection changed before adapter dispatch\", \"INVALID_CONFIG\");\n\t\t\t\t// Async generators are lazy; pin the owner before returning one to caller-owned code.\n\t\t\t\treturn this.streamWithSnapshot({ ...options, provider, model }, snapshot);\n\t\t\t}\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot({ ...options }, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n"
1908
+ },
1909
+ {
1910
+ "before": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst profile = this.profileOf(snapshot, options.provider);\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n",
1911
+ "after": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst route = this.routeOf(snapshot, options.provider, options.model);\n\t\t\tconst profile = route.profile;\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n"
1912
+ },
1913
+ {
1914
+ "before": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n",
1915
+ "after": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tif (profile.keyEntryId !== void 0 && (apiKey === void 0 || apiKey.length === 0)) throw new LlmError(`provider \"${options.provider}\" key entry \"${profile.keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n"
1916
+ },
1917
+ {
1918
+ "before": "\t\t\t\tconst iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, model.id)[Symbol.asyncIterator]();",
1919
+ "after": "\t\t\t\tconst iterator = toStreamChunks(route.models.streamSimple(model, replayContextForRoute(context, options.provider, options.model, model), {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, options.model)[Symbol.asyncIterator]();"
1920
+ },
1921
+ {
1922
+ "before": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n",
1923
+ "after": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\t// Validate host-owned entry identity even on the installed-catalog shortcut.\n\tconst selectedStored = request.keyEntryId === void 0 ? void 0 : storedProfile?.();\n\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n"
1924
+ },
1925
+ {
1926
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n",
1927
+ "after": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = selectedStored ?? storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n"
1928
+ },
1929
+ {
1930
+ "before": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n",
1931
+ "after": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy,\n\t\tmultiKey: profile.multiKey === true,\n\t\tapiKeyEnv: profile.apiKeyEnv,\n\t\tmodels: profile.piProvider?.getModels(),\n\t\tmodelErrors: [...profile.modelErrors],\n\t\tkeyEntries: [...profile.keyEntries].map(([id, entry]) => ({\n\t\t\tid,\n\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),\n\t\t\tmodelErrors: [...entry.modelErrors]\n\t\t})).sort((left, right) => left.id.localeCompare(right.id))\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n"
1932
+ },
1933
+ {
1934
+ "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
1935
+ "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
1936
+ },
1937
+ {
1938
+ "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
1939
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tmodels: z.array(modelProfile).required()\n});"
1940
+ },
1941
+ {
1942
+ "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
1943
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (!Array.isArray(entry.models))"
1944
+ },
1945
+ {
1946
+ "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
1947
+ "after": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\t...entry.api === void 0 ? {} : { api: entry.api },\n\t\t\t\tmultiKey: false,"
1948
+ },
1949
+ {
1950
+ "before": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {",
1951
+ "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api !== void 0 ? request.api : selectedStored?.api !== void 0 ? selectedStored.api : \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
1952
+ },
1953
+ {
1954
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);",
1955
+ "after": "\tconst baseURL = request.baseURL ?? selectedStored?.baseURL;\n\tif (baseURL === void 0 || baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(baseURL, api);"
1956
+ },
1957
+ {
1958
+ "before": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),",
1959
+ "after": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tapi: entry.api,\n\t\t\tmodels: entry.piProvider?.getModels(),"
1960
+ },
1961
+ {
1962
+ "before": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,",
1963
+ "after": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\tapi: profile.api,\n\t\t\tbaseURL: profile.baseURL ?? catalogProvider(provider)?.baseUrl,\n\t\t\theaders: profile.headers,"
1964
+ },
1965
+ {
1966
+ "before": "function listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");",
1967
+ "after": "/** Strip trailing slashes and one trailing `/v1`, the segment the Anthropic SDK adds itself. */\nfunction anthropicRoot(baseURL) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");\n\treturn base.endsWith(\"/v1\") ? base.slice(0, -3) : base;\n}\nfunction listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");"
1968
+ },
1969
+ {
1970
+ "before": "\t\tconst baseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (baseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);",
1971
+ "after": "\t\tconst configuredBaseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (configuredBaseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);\n\t\tconst baseUrl = api === \"anthropic-messages\" ? anthropicRoot(configuredBaseUrl) : configuredBaseUrl;"
1972
+ },
1973
+ {
1974
+ "before": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${base.endsWith(\"/v1\") ? base.slice(0, -3) : base}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;",
1975
+ "after": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${anthropicRoot(base)}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;"
1976
+ },
1977
+ {
1978
+ "before": "* gateway documentation publishes both spellings of the same root. Only this\n* listing URL normalizes that segment; model requests receive the configured\n* `baseURL` unchanged.\n*/",
1979
+ "after": "* gateway documentation publishes both spellings of the same root. Anthropic\n* listings and model requests both normalize it, because the Anthropic SDK\n* appends `/v1/messages` on its own while OpenAI protocols append\n* `/chat/completions`; without this, one root would work for chat and double\n* the segment for Anthropic.\n*/"
1980
+ }
1981
+ ]
1982
+ },
1983
+ {
1984
+ "source": "npm official 0.2.2-rc.1 with per-entry API overrides",
1985
+ "baseSha256": "1a3ae58f9b4493e15459cc5000ec80f21b5d3f4a9dea6ffb6bc28e5b8817ae8a",
1986
+ "resultSha256": "97baad73bbaa8e71c7a4b0a76cab946d0aee8d94a81bafc1cdbfa9100feec3b6",
1987
+ "replacements": [
1988
+ {
1989
+ "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
1990
+ "after": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\n// Model selection carries an opaque entry identity, never a credential or a wire alias.\nconst KEY_MODEL_PREFIX = \"@dsh-key/\";\nconst KEY_ENTRY_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;\nconst FORBIDDEN_KEY_ENTRY_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst AUTH_HEADER_NAMES = new Set([\"authorization\", \"proxy-authorization\", \"x-api-key\", \"api-key\", \"cf-aig-authorization\"]);\nfunction validKeyEntryId(id) {\n\treturn KEY_ENTRY_ID.test(id) && !FORBIDDEN_KEY_ENTRY_IDS.has(id);\n}\nfunction keyModelId(entryId, model) {\n\treturn `${KEY_MODEL_PREFIX}${encodeURIComponent(entryId)}/${encodeURIComponent(model)}`;\n}\nfunction keyModelRoute(model) {\n\tif (!model.startsWith(KEY_MODEL_PREFIX)) return void 0;\n\ttry {\n\t\tconst parts = model.slice(KEY_MODEL_PREFIX.length).split(\"/\");\n\t\tif (parts.length === 2) {\n\t\t\tconst entryId = decodeURIComponent(parts[0]);\n\t\t\tconst wireModel = decodeURIComponent(parts[1]);\n\t\t\tif (validKeyEntryId(entryId) && wireModel.length > 0 && !wireModel.startsWith(KEY_MODEL_PREFIX) && keyModelId(entryId, wireModel) === model) return { entryId, wireModel };\n\t\t}\n\t} catch {}\n\tthrow new LlmError(`invalid multi-key model selection \"${model}\"`, \"UNKNOWN_MODEL\");\n}\nconst keyEntryProfile = z.object({\n\tname: z.string().max(120).required(),\n\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});\nconst profile = z.object({\n\tmultiKey: z.boolean().default(false),\n\tkeyEntries: z.dict(keyEntryProfile).default({}),\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n"
1991
+ },
1992
+ {
1993
+ "before": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\") {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n",
1994
+ "after": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\", forKeyEntry = false) {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n"
1995
+ },
1996
+ {
1997
+ "before": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n",
1998
+ "after": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst entrySources = source.keyEntries ?? {};\n\t\tif (typeof entrySources !== \"object\" || entrySources === null || Array.isArray(entrySources)) throw new Error(`llm-pi-ai: provider \"${provider}\" keyEntries must be a dictionary`);\n\t\tconst assertWireModels = (models, site) => {\n\t\t\tfor (const model of models ?? []) if (typeof model.id !== \"string\" || model.id.length === 0 || model.id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} must use non-empty upstream model ids outside the reserved ${KEY_MODEL_PREFIX} prefix`);\n\t\t};\n\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const id of Object.keys(source.modelOverrides ?? {})) if (id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" modelOverrides uses reserved prefix ${KEY_MODEL_PREFIX}`);\n\t\tfor (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tif (!validKeyEntryId(id)) throw new Error(`llm-pi-ai: provider \"${provider}\" has an invalid key entry id \"${id}\"`);\n\t\t\tif (typeof entry !== \"object\" || entry === null || typeof entry.name !== \"string\" || entry.name.trim().length === 0 || entry.name.length > 120) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs a name of 1-120 characters`);\n\t\t\tif (typeof entry.apiKeyEnv !== \"string\" || entry.apiKeyEnv.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own apiKeyEnv`);\n\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own models list`);\n\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t}\n\t\tconst assertEntryHeaders = (headers, site) => {\n\t\t\tfor (const name of Object.keys(headers ?? {})) if (AUTH_HEADER_NAMES.has(name.toLowerCase())) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} authentication header \"${name}\" would override the selected key; remove it before enabling multiKey`);\n\t\t};\n\t\tif (source.multiKey === true || forKeyEntry) {\n\t\t\tassertEntryHeaders(source.headers, \"shared\");\n\t\t\tfor (const model of source.models ?? []) assertEntryHeaders(model.headers, `model \"${model.id}\"`);\n\t\t\tfor (const [id, override] of Object.entries(source.modelOverrides ?? {})) assertEntryHeaders(override.headers, `model override \"${id}\"`);\n\t\t}\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n"
1999
+ },
2000
+ {
2001
+ "before": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\ttry {\n\t\t\tcatalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n",
2002
+ "after": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tconst keyEntries = new Map();\n\t\t// Disabled entries remain stored, but cannot constrain legacy single-key runtime behavior.\n\t\tif (source.multiKey === true) for (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,\n\t\t\t\tkeyEntries: {},\n\t\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\t\tmodels: entry.models,\n\t\t\t\tmodelOverrides: void 0\n\t\t\t} }, validation, true).get(provider);\n\t\t\t// Entry auth must not consult a catalog provider's ambient/OAuth credential or endpoint.\n\t\t\tkeyEntries.set(id, {\n\t\t\t\t...child,\n\t\t\t\tkeyEntryId: id,\n\t\t\t\tkeyEntryName: entry.name,\n\t\t\t\t...child.piProvider === void 0 ? {} : { piProvider: { ...child.piProvider, auth: { apiKey: harnessApiKeyAuth(entry.name) } } }\n\t\t\t});\n\t\t}\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\tconst entryOnly = forKeyEntry && source.models.length === 0 || source.multiKey === true && keyEntries.size > 0 && (source.models ?? []).length === 0 && catalogModels(provider).size === 0;\n\t\ttry {\n\t\t\tif (entryOnly) catalog = { models: [], configuredMaxTokens: new Map(), modelErrors: new Map() };\n\t\t\telse catalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n"
2003
+ },
2004
+ {
2005
+ "before": "\t\t\t}, validation);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;",
2006
+ "after": "\t\t\t}, validation);\n\t\t\tif (source.multiKey === true || forKeyEntry) for (const model of catalog.models) assertEntryHeaders(model.headers, `resolved model \"${model.id}\"`);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;"
2007
+ },
2008
+ {
2009
+ "before": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },",
2010
+ "after": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, keyEntries: _keyEntries, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\tkeyEntries,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },"
2011
+ },
2012
+ {
2013
+ "before": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/**\n* pi-ai-backed multi-provider adapter.",
2014
+ "after": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/** Decode only the selected replay owner at the pi boundary; never merge equal wire ids across keys. */\nfunction replayContextForRoute(context, provider, requestedModel, wireModel) {\n\tconst selectedEntry = requestedModel.startsWith(KEY_MODEL_PREFIX);\n\treturn {\n\t\t...context,\n\t\tmessages: context.messages.map((message) => {\n\t\t\tif (message.role !== \"assistant\") return message;\n\t\t\tif (message.provider === provider && message.model === requestedModel) return { ...message, model: wireModel.id };\n\t\t\tif (!message.model.startsWith(KEY_MODEL_PREFIX) && !(selectedEntry && message.provider === provider && message.model === wireModel.id)) return message;\n\t\t\treturn {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tapi: \"dsh-foreign\",\n\t\t\t\tprovider: message.provider,\n\t\t\t\tmodel: \"dsh-foreign\",\n\t\t\t\tcontent: message.content.flatMap((block) => {\n\t\t\t\t\tif (block.type === \"thinking\") return [];\n\t\t\t\t\tif (block.type === \"text\") return [{ type: \"text\", text: block.text }];\n\t\t\t\t\tif (block.type === \"toolCall\") return [{ type: \"toolCall\", id: block.id, name: block.name, arguments: block.arguments }];\n\t\t\t\t\treturn [block];\n\t\t\t\t}),\n\t\t\t\tusage: message.usage,\n\t\t\t\tstopReason: message.stopReason,\n\t\t\t\ttimestamp: message.timestamp\n\t\t\t};\n\t\t})\n\t};\n}\n/**\n* pi-ai-backed multi-provider adapter."
2015
+ },
2016
+ {
2017
+ "before": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tfor (const profile of profiles.values()) if (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n",
2018
+ "after": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tconst entryModels = new Map();\n\t\tfor (const [provider, profile] of profiles) {\n\t\t\tif (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\t\tconst entries = new Map();\n\t\t\tfor (const [id, entry] of profile.keyEntries) {\n\t\t\t\tconst collection = createModels(this.config.auth);\n\t\t\t\tif (entry.piProvider !== void 0) collection.setProvider(entry.piProvider);\n\t\t\t\tentries.set(id, collection);\n\t\t\t}\n\t\t\tentryModels.set(provider, entries);\n\t\t}\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels,\n\t\t\tentryModels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n"
2019
+ },
2020
+ {
2021
+ "before": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst failure = profile.modelErrors.get(model) ?? (profile.piProvider === void 0 ? profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = snapshot.models.getModel(provider, model);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n",
2022
+ "after": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** Bind the public selection to an exact profile, independent model collection, and upstream id. */\n\trouteOf(snapshot, provider, model) {\n\t\tconst root = this.profileOf(snapshot, provider);\n\t\tconst entry = keyModelRoute(model);\n\t\tif (entry === void 0) return { profile: root, models: snapshot.models, wireModel: model };\n\t\tif (root.multiKey !== true) throw new LlmError(`multi-key selection is disabled for provider \"${provider}\"`, \"UNKNOWN_MODEL\");\n\t\tconst profile = root.keyEntries.get(entry.entryId);\n\t\tconst models = snapshot.entryModels.get(provider)?.get(entry.entryId);\n\t\tif (profile === void 0 || models === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${entry.entryId}\"`, \"UNKNOWN_MODEL\");\n\t\treturn { profile, models, wireModel: entry.wireModel };\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst route = this.routeOf(snapshot, provider, model);\n\t\tconst failure = route.profile.modelErrors.get(route.wireModel) ?? (route.profile.piProvider === void 0 ? route.profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = route.models.getModel(provider, route.wireModel);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n"
2023
+ },
2024
+ {
2025
+ "before": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\ttry {\n\t\t\t\tawait this.config.resolveApiKey(provider, profile);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return [];\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn snapshot.models.getModels(provider).map((model) => ({\n\t\t\t\tprovider,\n\t\t\t\tid: model.id,\n\t\t\t\tname: model.name,\n\t\t\t\tinputModalities: [...model.input]\n\t\t\t}));\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n",
2026
+ "after": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\tconst listed = [];\n\t\t\tconst append = async (owner, models, entryId) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst key = await this.config.resolveApiKey(provider, owner);\n\t\t\t\t\tif (entryId !== void 0 && (key === void 0 || key.length === 0)) return;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return;\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tfor (const model of models.getModels(provider)) listed.push({\n\t\t\t\t\tprovider,\n\t\t\t\t\tid: entryId === void 0 ? model.id : keyModelId(entryId, model.id),\n\t\t\t\t\tname: model.name,\n\t\t\t\t\tinputModalities: [...model.input]\n\t\t\t\t});\n\t\t\t};\n\t\t\t// Keep raw root models advertised so old sessions remain routable without changing keys.\n\t\t\tawait append(profile, snapshot.models);\n\t\t\tif (profile.multiKey === true) for (const [id, entry] of profile.keyEntries) await append(entry, snapshot.entryModels.get(provider).get(id), id);\n\t\t\treturn listed;\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n"
2027
+ },
2028
+ {
2029
+ "before": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(model);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n",
2030
+ "after": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst { profile, wireModel } = this.routeOf(snapshot, provider, model);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(wireModel);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n"
2031
+ },
2032
+ {
2033
+ "before": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => this.streamWithSnapshot(options, snapshot)\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot(options, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n",
2034
+ "after": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => {\n\t\t\t\tif (options.provider !== provider || options.model !== model) throw new LlmError(\"prepared multi-key model selection changed before adapter dispatch\", \"INVALID_CONFIG\");\n\t\t\t\t// Async generators are lazy; pin the owner before returning one to caller-owned code.\n\t\t\t\treturn this.streamWithSnapshot({ ...options, provider, model }, snapshot);\n\t\t\t}\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot({ ...options }, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n"
2035
+ },
2036
+ {
2037
+ "before": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst profile = this.profileOf(snapshot, options.provider);\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n",
2038
+ "after": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst route = this.routeOf(snapshot, options.provider, options.model);\n\t\t\tconst profile = route.profile;\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n"
2039
+ },
2040
+ {
2041
+ "before": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n",
2042
+ "after": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tif (profile.keyEntryId !== void 0 && (apiKey === void 0 || apiKey.length === 0)) throw new LlmError(`provider \"${options.provider}\" key entry \"${profile.keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n"
2043
+ },
2044
+ {
2045
+ "before": "\t\t\t\tconst iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, model.id)[Symbol.asyncIterator]();",
2046
+ "after": "\t\t\t\tconst iterator = toStreamChunks(route.models.streamSimple(model, replayContextForRoute(context, options.provider, options.model, model), {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, options.model)[Symbol.asyncIterator]();"
2047
+ },
2048
+ {
2049
+ "before": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n",
2050
+ "after": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\t// Validate host-owned entry identity even on the installed-catalog shortcut.\n\tconst selectedStored = request.keyEntryId === void 0 ? void 0 : storedProfile?.();\n\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n"
2051
+ },
2052
+ {
2053
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n",
2054
+ "after": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = selectedStored ?? storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n"
2055
+ },
2056
+ {
2057
+ "before": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n",
2058
+ "after": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy,\n\t\tmultiKey: profile.multiKey === true,\n\t\tapiKeyEnv: profile.apiKeyEnv,\n\t\tmodels: profile.piProvider?.getModels(),\n\t\tmodelErrors: [...profile.modelErrors],\n\t\tkeyEntries: [...profile.keyEntries].map(([id, entry]) => ({\n\t\t\tid,\n\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),\n\t\t\tmodelErrors: [...entry.modelErrors]\n\t\t})).sort((left, right) => left.id.localeCompare(right.id))\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n"
2059
+ },
2060
+ {
2061
+ "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
2062
+ "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
2063
+ },
2064
+ {
2065
+ "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
2066
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tmodels: z.array(modelProfile).required()\n});"
2067
+ },
2068
+ {
2069
+ "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
2070
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (entry.sortOrder !== void 0 && (!Number.isSafeInteger(entry.sortOrder) || entry.sortOrder < 0)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" sortOrder must be a nonnegative safe integer`);\n\t\t\tif (!Array.isArray(entry.models))"
2071
+ },
2072
+ {
2073
+ "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
2074
+ "after": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\t...entry.api === void 0 ? {} : { api: entry.api },\n\t\t\t\tmultiKey: false,"
2075
+ },
2076
+ {
2077
+ "before": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {",
2078
+ "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api !== void 0 ? request.api : selectedStored?.api !== void 0 ? selectedStored.api : \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
2079
+ },
2080
+ {
2081
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);",
2082
+ "after": "\tconst baseURL = request.baseURL ?? selectedStored?.baseURL;\n\tif (baseURL === void 0 || baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(baseURL, api);"
2083
+ },
2084
+ {
2085
+ "before": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),",
2086
+ "after": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tapi: entry.api,\n\t\t\tmodels: entry.piProvider?.getModels(),"
2087
+ },
2088
+ {
2089
+ "before": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,",
2090
+ "after": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\tapi: profile.api,\n\t\t\tbaseURL: profile.baseURL ?? catalogProvider(provider)?.baseUrl,\n\t\t\theaders: profile.headers,"
2091
+ },
2092
+ {
2093
+ "before": "function listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");",
2094
+ "after": "/** Strip trailing slashes and one trailing `/v1`, the segment the Anthropic SDK adds itself. */\nfunction anthropicRoot(baseURL) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");\n\treturn base.endsWith(\"/v1\") ? base.slice(0, -3) : base;\n}\nfunction listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");"
2095
+ },
2096
+ {
2097
+ "before": "\t\tconst baseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (baseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);",
2098
+ "after": "\t\tconst configuredBaseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (configuredBaseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);\n\t\tconst baseUrl = api === \"anthropic-messages\" ? anthropicRoot(configuredBaseUrl) : configuredBaseUrl;"
2099
+ },
2100
+ {
2101
+ "before": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${base.endsWith(\"/v1\") ? base.slice(0, -3) : base}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;",
2102
+ "after": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${anthropicRoot(base)}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;"
2103
+ },
2104
+ {
2105
+ "before": "* gateway documentation publishes both spellings of the same root. Only this\n* listing URL normalizes that segment; model requests receive the configured\n* `baseURL` unchanged.\n*/",
2106
+ "after": "* gateway documentation publishes both spellings of the same root. Anthropic\n* listings and model requests both normalize it, because the Anthropic SDK\n* appends `/v1/messages` on its own while OpenAI protocols append\n* `/chat/completions`; without this, one root would work for chat and double\n* the segment for Anthropic.\n*/"
2107
+ }
2108
+ ]
2109
+ },
2110
+ {
2111
+ "source": "0.2.2-rc.1 with tool lookup optimization and credential cancellation with per-entry API overrides",
2112
+ "baseSha256": "0a99a2fc903a4285044b09114b3bd20ee1e612f39aa381e4a71b10d48ee9e9f7",
2113
+ "resultSha256": "70dd30c46c5504422738a158acf789bb6fe43cff9b134d5ddf5e5c3da3236340",
2114
+ "replacements": [
2115
+ {
2116
+ "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
2117
+ "after": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\n// Model selection carries an opaque entry identity, never a credential or a wire alias.\nconst KEY_MODEL_PREFIX = \"@dsh-key/\";\nconst KEY_ENTRY_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;\nconst FORBIDDEN_KEY_ENTRY_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst AUTH_HEADER_NAMES = new Set([\"authorization\", \"proxy-authorization\", \"x-api-key\", \"api-key\", \"cf-aig-authorization\"]);\nfunction validKeyEntryId(id) {\n\treturn KEY_ENTRY_ID.test(id) && !FORBIDDEN_KEY_ENTRY_IDS.has(id);\n}\nfunction keyModelId(entryId, model) {\n\treturn `${KEY_MODEL_PREFIX}${encodeURIComponent(entryId)}/${encodeURIComponent(model)}`;\n}\nfunction keyModelRoute(model) {\n\tif (!model.startsWith(KEY_MODEL_PREFIX)) return void 0;\n\ttry {\n\t\tconst parts = model.slice(KEY_MODEL_PREFIX.length).split(\"/\");\n\t\tif (parts.length === 2) {\n\t\t\tconst entryId = decodeURIComponent(parts[0]);\n\t\t\tconst wireModel = decodeURIComponent(parts[1]);\n\t\t\tif (validKeyEntryId(entryId) && wireModel.length > 0 && !wireModel.startsWith(KEY_MODEL_PREFIX) && keyModelId(entryId, wireModel) === model) return { entryId, wireModel };\n\t\t}\n\t} catch {}\n\tthrow new LlmError(`invalid multi-key model selection \"${model}\"`, \"UNKNOWN_MODEL\");\n}\nconst keyEntryProfile = z.object({\n\tname: z.string().max(120).required(),\n\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});\nconst profile = z.object({\n\tmultiKey: z.boolean().default(false),\n\tkeyEntries: z.dict(keyEntryProfile).default({}),\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n"
2118
+ },
2119
+ {
2120
+ "before": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\") {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n",
2121
+ "after": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\", forKeyEntry = false) {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n"
2122
+ },
2123
+ {
2124
+ "before": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n",
2125
+ "after": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst entrySources = source.keyEntries ?? {};\n\t\tif (typeof entrySources !== \"object\" || entrySources === null || Array.isArray(entrySources)) throw new Error(`llm-pi-ai: provider \"${provider}\" keyEntries must be a dictionary`);\n\t\tconst assertWireModels = (models, site) => {\n\t\t\tfor (const model of models ?? []) if (typeof model.id !== \"string\" || model.id.length === 0 || model.id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} must use non-empty upstream model ids outside the reserved ${KEY_MODEL_PREFIX} prefix`);\n\t\t};\n\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const id of Object.keys(source.modelOverrides ?? {})) if (id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" modelOverrides uses reserved prefix ${KEY_MODEL_PREFIX}`);\n\t\tfor (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tif (!validKeyEntryId(id)) throw new Error(`llm-pi-ai: provider \"${provider}\" has an invalid key entry id \"${id}\"`);\n\t\t\tif (typeof entry !== \"object\" || entry === null || typeof entry.name !== \"string\" || entry.name.trim().length === 0 || entry.name.length > 120) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs a name of 1-120 characters`);\n\t\t\tif (typeof entry.apiKeyEnv !== \"string\" || entry.apiKeyEnv.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own apiKeyEnv`);\n\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own models list`);\n\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t}\n\t\tconst assertEntryHeaders = (headers, site) => {\n\t\t\tfor (const name of Object.keys(headers ?? {})) if (AUTH_HEADER_NAMES.has(name.toLowerCase())) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} authentication header \"${name}\" would override the selected key; remove it before enabling multiKey`);\n\t\t};\n\t\tif (source.multiKey === true || forKeyEntry) {\n\t\t\tassertEntryHeaders(source.headers, \"shared\");\n\t\t\tfor (const model of source.models ?? []) assertEntryHeaders(model.headers, `model \"${model.id}\"`);\n\t\t\tfor (const [id, override] of Object.entries(source.modelOverrides ?? {})) assertEntryHeaders(override.headers, `model override \"${id}\"`);\n\t\t}\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n"
2126
+ },
2127
+ {
2128
+ "before": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\ttry {\n\t\t\tcatalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n",
2129
+ "after": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tconst keyEntries = new Map();\n\t\t// Disabled entries remain stored, but cannot constrain legacy single-key runtime behavior.\n\t\tif (source.multiKey === true) for (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,\n\t\t\t\tkeyEntries: {},\n\t\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\t\tmodels: entry.models,\n\t\t\t\tmodelOverrides: void 0\n\t\t\t} }, validation, true).get(provider);\n\t\t\t// Entry auth must not consult a catalog provider's ambient/OAuth credential or endpoint.\n\t\t\tkeyEntries.set(id, {\n\t\t\t\t...child,\n\t\t\t\tkeyEntryId: id,\n\t\t\t\tkeyEntryName: entry.name,\n\t\t\t\t...child.piProvider === void 0 ? {} : { piProvider: { ...child.piProvider, auth: { apiKey: harnessApiKeyAuth(entry.name) } } }\n\t\t\t});\n\t\t}\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\tconst entryOnly = forKeyEntry && source.models.length === 0 || source.multiKey === true && keyEntries.size > 0 && (source.models ?? []).length === 0 && catalogModels(provider).size === 0;\n\t\ttry {\n\t\t\tif (entryOnly) catalog = { models: [], configuredMaxTokens: new Map(), modelErrors: new Map() };\n\t\t\telse catalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n"
2130
+ },
2131
+ {
2132
+ "before": "\t\t\t}, validation);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;",
2133
+ "after": "\t\t\t}, validation);\n\t\t\tif (source.multiKey === true || forKeyEntry) for (const model of catalog.models) assertEntryHeaders(model.headers, `resolved model \"${model.id}\"`);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;"
2134
+ },
2135
+ {
2136
+ "before": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },",
2137
+ "after": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, keyEntries: _keyEntries, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\tkeyEntries,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },"
2138
+ },
2139
+ {
2140
+ "before": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/**\n* pi-ai-backed multi-provider adapter.",
2141
+ "after": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/** Decode only the selected replay owner at the pi boundary; never merge equal wire ids across keys. */\nfunction replayContextForRoute(context, provider, requestedModel, wireModel) {\n\tconst selectedEntry = requestedModel.startsWith(KEY_MODEL_PREFIX);\n\treturn {\n\t\t...context,\n\t\tmessages: context.messages.map((message) => {\n\t\t\tif (message.role !== \"assistant\") return message;\n\t\t\tif (message.provider === provider && message.model === requestedModel) return { ...message, model: wireModel.id };\n\t\t\tif (!message.model.startsWith(KEY_MODEL_PREFIX) && !(selectedEntry && message.provider === provider && message.model === wireModel.id)) return message;\n\t\t\treturn {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tapi: \"dsh-foreign\",\n\t\t\t\tprovider: message.provider,\n\t\t\t\tmodel: \"dsh-foreign\",\n\t\t\t\tcontent: message.content.flatMap((block) => {\n\t\t\t\t\tif (block.type === \"thinking\") return [];\n\t\t\t\t\tif (block.type === \"text\") return [{ type: \"text\", text: block.text }];\n\t\t\t\t\tif (block.type === \"toolCall\") return [{ type: \"toolCall\", id: block.id, name: block.name, arguments: block.arguments }];\n\t\t\t\t\treturn [block];\n\t\t\t\t}),\n\t\t\t\tusage: message.usage,\n\t\t\t\tstopReason: message.stopReason,\n\t\t\t\ttimestamp: message.timestamp\n\t\t\t};\n\t\t})\n\t};\n}\n/**\n* pi-ai-backed multi-provider adapter."
2142
+ },
2143
+ {
2144
+ "before": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tfor (const profile of profiles.values()) if (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n",
2145
+ "after": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tconst entryModels = new Map();\n\t\tfor (const [provider, profile] of profiles) {\n\t\t\tif (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\t\tconst entries = new Map();\n\t\t\tfor (const [id, entry] of profile.keyEntries) {\n\t\t\t\tconst collection = createModels(this.config.auth);\n\t\t\t\tif (entry.piProvider !== void 0) collection.setProvider(entry.piProvider);\n\t\t\t\tentries.set(id, collection);\n\t\t\t}\n\t\t\tentryModels.set(provider, entries);\n\t\t}\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels,\n\t\t\tentryModels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n"
2146
+ },
2147
+ {
2148
+ "before": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst failure = profile.modelErrors.get(model) ?? (profile.piProvider === void 0 ? profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = snapshot.models.getModel(provider, model);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n",
2149
+ "after": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** Bind the public selection to an exact profile, independent model collection, and upstream id. */\n\trouteOf(snapshot, provider, model) {\n\t\tconst root = this.profileOf(snapshot, provider);\n\t\tconst entry = keyModelRoute(model);\n\t\tif (entry === void 0) return { profile: root, models: snapshot.models, wireModel: model };\n\t\tif (root.multiKey !== true) throw new LlmError(`multi-key selection is disabled for provider \"${provider}\"`, \"UNKNOWN_MODEL\");\n\t\tconst profile = root.keyEntries.get(entry.entryId);\n\t\tconst models = snapshot.entryModels.get(provider)?.get(entry.entryId);\n\t\tif (profile === void 0 || models === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${entry.entryId}\"`, \"UNKNOWN_MODEL\");\n\t\treturn { profile, models, wireModel: entry.wireModel };\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst route = this.routeOf(snapshot, provider, model);\n\t\tconst failure = route.profile.modelErrors.get(route.wireModel) ?? (route.profile.piProvider === void 0 ? route.profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = route.models.getModel(provider, route.wireModel);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n"
2150
+ },
2151
+ {
2152
+ "before": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\ttry {\n\t\t\t\tawait this.config.resolveApiKey(provider, profile);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return [];\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn snapshot.models.getModels(provider).map((model) => ({\n\t\t\t\tprovider,\n\t\t\t\tid: model.id,\n\t\t\t\tname: model.name,\n\t\t\t\tinputModalities: [...model.input]\n\t\t\t}));\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n",
2153
+ "after": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\tconst listed = [];\n\t\t\tconst append = async (owner, models, entryId) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst key = await this.config.resolveApiKey(provider, owner);\n\t\t\t\t\tif (entryId !== void 0 && (key === void 0 || key.length === 0)) return;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return;\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tfor (const model of models.getModels(provider)) listed.push({\n\t\t\t\t\tprovider,\n\t\t\t\t\tid: entryId === void 0 ? model.id : keyModelId(entryId, model.id),\n\t\t\t\t\tname: model.name,\n\t\t\t\t\tinputModalities: [...model.input]\n\t\t\t\t});\n\t\t\t};\n\t\t\t// Keep raw root models advertised so old sessions remain routable without changing keys.\n\t\t\tawait append(profile, snapshot.models);\n\t\t\tif (profile.multiKey === true) for (const [id, entry] of profile.keyEntries) await append(entry, snapshot.entryModels.get(provider).get(id), id);\n\t\t\treturn listed;\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n"
2154
+ },
2155
+ {
2156
+ "before": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(model);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n",
2157
+ "after": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst { profile, wireModel } = this.routeOf(snapshot, provider, model);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(wireModel);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n"
2158
+ },
2159
+ {
2160
+ "before": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => this.streamWithSnapshot(options, snapshot)\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot(options, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n",
2161
+ "after": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => {\n\t\t\t\tif (options.provider !== provider || options.model !== model) throw new LlmError(\"prepared multi-key model selection changed before adapter dispatch\", \"INVALID_CONFIG\");\n\t\t\t\t// Async generators are lazy; pin the owner before returning one to caller-owned code.\n\t\t\t\treturn this.streamWithSnapshot({ ...options, provider, model }, snapshot);\n\t\t\t}\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot({ ...options }, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n"
2162
+ },
2163
+ {
2164
+ "before": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst profile = this.profileOf(snapshot, options.provider);\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n",
2165
+ "after": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst route = this.routeOf(snapshot, options.provider, options.model);\n\t\t\tconst profile = route.profile;\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n"
2166
+ },
2167
+ {
2168
+ "before": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n",
2169
+ "after": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tif (profile.keyEntryId !== void 0 && (apiKey === void 0 || apiKey.length === 0)) throw new LlmError(`provider \"${options.provider}\" key entry \"${profile.keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n"
2170
+ },
2171
+ {
2172
+ "before": "\t\t\t\tconst iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, model.id)[Symbol.asyncIterator]();",
2173
+ "after": "\t\t\t\tconst iterator = toStreamChunks(route.models.streamSimple(model, replayContextForRoute(context, options.provider, options.model, model), {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, options.model)[Symbol.asyncIterator]();"
2174
+ },
2175
+ {
2176
+ "before": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n",
2177
+ "after": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\t// Validate host-owned entry identity even on the installed-catalog shortcut.\n\tconst selectedStored = request.keyEntryId === void 0 ? void 0 : storedProfile?.();\n\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n"
2178
+ },
2179
+ {
2180
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n",
2181
+ "after": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = selectedStored ?? storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n"
2182
+ },
2183
+ {
2184
+ "before": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n",
2185
+ "after": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy,\n\t\tmultiKey: profile.multiKey === true,\n\t\tapiKeyEnv: profile.apiKeyEnv,\n\t\tmodels: profile.piProvider?.getModels(),\n\t\tmodelErrors: [...profile.modelErrors],\n\t\tkeyEntries: [...profile.keyEntries].map(([id, entry]) => ({\n\t\t\tid,\n\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),\n\t\t\tmodelErrors: [...entry.modelErrors]\n\t\t})).sort((left, right) => left.id.localeCompare(right.id))\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n"
2186
+ },
2187
+ {
2188
+ "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
2189
+ "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
2190
+ },
2191
+ {
2192
+ "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
2193
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tmodels: z.array(modelProfile).required()\n});"
2194
+ },
2195
+ {
2196
+ "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
2197
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (entry.sortOrder !== void 0 && (!Number.isSafeInteger(entry.sortOrder) || entry.sortOrder < 0)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" sortOrder must be a nonnegative safe integer`);\n\t\t\tif (!Array.isArray(entry.models))"
2198
+ },
2199
+ {
2200
+ "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
2201
+ "after": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\t...entry.api === void 0 ? {} : { api: entry.api },\n\t\t\t\tmultiKey: false,"
2202
+ },
2203
+ {
2204
+ "before": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {",
2205
+ "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api !== void 0 ? request.api : selectedStored?.api !== void 0 ? selectedStored.api : \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
2206
+ },
2207
+ {
2208
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);",
2209
+ "after": "\tconst baseURL = request.baseURL ?? selectedStored?.baseURL;\n\tif (baseURL === void 0 || baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(baseURL, api);"
2210
+ },
2211
+ {
2212
+ "before": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),",
2213
+ "after": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tapi: entry.api,\n\t\t\tmodels: entry.piProvider?.getModels(),"
2214
+ },
2215
+ {
2216
+ "before": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,",
2217
+ "after": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\tapi: profile.api,\n\t\t\tbaseURL: profile.baseURL ?? catalogProvider(provider)?.baseUrl,\n\t\t\theaders: profile.headers,"
2218
+ },
2219
+ {
2220
+ "before": "function listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");",
2221
+ "after": "/** Strip trailing slashes and one trailing `/v1`, the segment the Anthropic SDK adds itself. */\nfunction anthropicRoot(baseURL) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");\n\treturn base.endsWith(\"/v1\") ? base.slice(0, -3) : base;\n}\nfunction listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");"
2222
+ },
2223
+ {
2224
+ "before": "\t\tconst baseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (baseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);",
2225
+ "after": "\t\tconst configuredBaseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (configuredBaseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);\n\t\tconst baseUrl = api === \"anthropic-messages\" ? anthropicRoot(configuredBaseUrl) : configuredBaseUrl;"
2226
+ },
2227
+ {
2228
+ "before": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${base.endsWith(\"/v1\") ? base.slice(0, -3) : base}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;",
2229
+ "after": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${anthropicRoot(base)}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;"
2230
+ },
2231
+ {
2232
+ "before": "* gateway documentation publishes both spellings of the same root. Only this\n* listing URL normalizes that segment; model requests receive the configured\n* `baseURL` unchanged.\n*/",
2233
+ "after": "* gateway documentation publishes both spellings of the same root. Anthropic\n* listings and model requests both normalize it, because the Anthropic SDK\n* appends `/v1/messages` on its own while OpenAI protocols append\n* `/chat/completions`; without this, one root would work for chat and double\n* the segment for Anthropic.\n*/"
2234
+ }
2235
+ ]
2236
+ },
2237
+ {
2238
+ "source": "npm official 0.2.2-rc.1 with per-entry API overrides",
2239
+ "baseSha256": "1a3ae58f9b4493e15459cc5000ec80f21b5d3f4a9dea6ffb6bc28e5b8817ae8a",
2240
+ "resultSha256": "77bbab114ae7ea64df49e7b1f610fae893990c8e477ed7408f1b6cfc3cef717a",
2241
+ "replacements": [
2242
+ {
2243
+ "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
2244
+ "after": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\n// Model selection carries an opaque entry identity, never a credential or a wire alias.\nconst KEY_MODEL_PREFIX = \"@dsh-key/\";\nconst KEY_ENTRY_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;\nconst FORBIDDEN_KEY_ENTRY_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst AUTH_HEADER_NAMES = new Set([\"authorization\", \"proxy-authorization\", \"x-api-key\", \"api-key\", \"cf-aig-authorization\"]);\nfunction validKeyEntryId(id) {\n\treturn KEY_ENTRY_ID.test(id) && !FORBIDDEN_KEY_ENTRY_IDS.has(id);\n}\nfunction keyModelId(entryId, model) {\n\treturn `${KEY_MODEL_PREFIX}${encodeURIComponent(entryId)}/${encodeURIComponent(model)}`;\n}\nfunction keyModelRoute(model) {\n\tif (!model.startsWith(KEY_MODEL_PREFIX)) return void 0;\n\ttry {\n\t\tconst parts = model.slice(KEY_MODEL_PREFIX.length).split(\"/\");\n\t\tif (parts.length === 2) {\n\t\t\tconst entryId = decodeURIComponent(parts[0]);\n\t\t\tconst wireModel = decodeURIComponent(parts[1]);\n\t\t\tif (validKeyEntryId(entryId) && wireModel.length > 0 && !wireModel.startsWith(KEY_MODEL_PREFIX) && keyModelId(entryId, wireModel) === model) return { entryId, wireModel };\n\t\t}\n\t} catch {}\n\tthrow new LlmError(`invalid multi-key model selection \"${model}\"`, \"UNKNOWN_MODEL\");\n}\nconst keyEntryProfile = z.object({\n\tname: z.string().max(120).required(),\n\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});\nconst profile = z.object({\n\tmultiKey: z.boolean().default(false),\n\tkeyEntries: z.dict(keyEntryProfile).default({}),\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n"
2245
+ },
2246
+ {
2247
+ "before": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\") {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n",
2248
+ "after": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\", forKeyEntry = false) {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n"
2249
+ },
2250
+ {
2251
+ "before": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n",
2252
+ "after": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst entrySources = source.keyEntries ?? {};\n\t\tif (typeof entrySources !== \"object\" || entrySources === null || Array.isArray(entrySources)) throw new Error(`llm-pi-ai: provider \"${provider}\" keyEntries must be a dictionary`);\n\t\tconst assertWireModels = (models, site) => {\n\t\t\tfor (const model of models ?? []) if (typeof model.id !== \"string\" || model.id.length === 0 || model.id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} must use non-empty upstream model ids outside the reserved ${KEY_MODEL_PREFIX} prefix`);\n\t\t};\n\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const id of Object.keys(source.modelOverrides ?? {})) if (id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" modelOverrides uses reserved prefix ${KEY_MODEL_PREFIX}`);\n\t\tfor (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tif (!validKeyEntryId(id)) throw new Error(`llm-pi-ai: provider \"${provider}\" has an invalid key entry id \"${id}\"`);\n\t\t\tif (typeof entry !== \"object\" || entry === null || typeof entry.name !== \"string\" || entry.name.trim().length === 0 || entry.name.length > 120) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs a name of 1-120 characters`);\n\t\t\tif (typeof entry.apiKeyEnv !== \"string\" || entry.apiKeyEnv.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own apiKeyEnv`);\n\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own models list`);\n\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t}\n\t\tconst assertEntryHeaders = (headers, site) => {\n\t\t\tfor (const name of Object.keys(headers ?? {})) if (AUTH_HEADER_NAMES.has(name.toLowerCase())) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} authentication header \"${name}\" would override the selected key; remove it before enabling multiKey`);\n\t\t};\n\t\tif (source.multiKey === true || forKeyEntry) {\n\t\t\tassertEntryHeaders(source.headers, \"shared\");\n\t\t\tfor (const model of source.models ?? []) assertEntryHeaders(model.headers, `model \"${model.id}\"`);\n\t\t\tfor (const [id, override] of Object.entries(source.modelOverrides ?? {})) assertEntryHeaders(override.headers, `model override \"${id}\"`);\n\t\t}\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n"
2253
+ },
2254
+ {
2255
+ "before": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\ttry {\n\t\t\tcatalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n",
2256
+ "after": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tconst keyEntries = new Map();\n\t\t// Disabled entries remain stored, but cannot constrain legacy single-key runtime behavior.\n\t\tif (source.multiKey === true) for (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,\n\t\t\t\tkeyEntries: {},\n\t\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\t\tmodels: entry.models,\n\t\t\t\tmodelOverrides: void 0\n\t\t\t} }, validation, true).get(provider);\n\t\t\t// Entry auth must not consult a catalog provider's ambient/OAuth credential or endpoint.\n\t\t\tkeyEntries.set(id, {\n\t\t\t\t...child,\n\t\t\t\tkeyEntryId: id,\n\t\t\t\tkeyEntryName: entry.name,\n\t\t\t\t...child.piProvider === void 0 ? {} : { piProvider: { ...child.piProvider, auth: { apiKey: harnessApiKeyAuth(entry.name) } } }\n\t\t\t});\n\t\t}\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\tconst entryOnly = forKeyEntry && source.models.length === 0 || source.multiKey === true && keyEntries.size > 0 && (source.models ?? []).length === 0 && catalogModels(provider).size === 0;\n\t\ttry {\n\t\t\tif (entryOnly) catalog = { models: [], configuredMaxTokens: new Map(), modelErrors: new Map() };\n\t\t\telse catalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n"
2257
+ },
2258
+ {
2259
+ "before": "\t\t\t}, validation);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;",
2260
+ "after": "\t\t\t}, validation);\n\t\t\tif (source.multiKey === true || forKeyEntry) for (const model of catalog.models) assertEntryHeaders(model.headers, `resolved model \"${model.id}\"`);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;"
2261
+ },
2262
+ {
2263
+ "before": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },",
2264
+ "after": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, keyEntries: _keyEntries, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\tkeyEntries,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },"
2265
+ },
2266
+ {
2267
+ "before": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/**\n* pi-ai-backed multi-provider adapter.",
2268
+ "after": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/** Decode only the selected replay owner at the pi boundary; never merge equal wire ids across keys. */\nfunction replayContextForRoute(context, provider, requestedModel, wireModel) {\n\tconst selectedEntry = requestedModel.startsWith(KEY_MODEL_PREFIX);\n\treturn {\n\t\t...context,\n\t\tmessages: context.messages.map((message) => {\n\t\t\tif (message.role !== \"assistant\") return message;\n\t\t\tif (message.provider === provider && message.model === requestedModel) return { ...message, model: wireModel.id };\n\t\t\tif (!message.model.startsWith(KEY_MODEL_PREFIX) && !(selectedEntry && message.provider === provider && message.model === wireModel.id)) return message;\n\t\t\treturn {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tapi: \"dsh-foreign\",\n\t\t\t\tprovider: message.provider,\n\t\t\t\tmodel: \"dsh-foreign\",\n\t\t\t\tcontent: message.content.flatMap((block) => {\n\t\t\t\t\tif (block.type === \"thinking\") return [];\n\t\t\t\t\tif (block.type === \"text\") return [{ type: \"text\", text: block.text }];\n\t\t\t\t\tif (block.type === \"toolCall\") return [{ type: \"toolCall\", id: block.id, name: block.name, arguments: block.arguments }];\n\t\t\t\t\treturn [block];\n\t\t\t\t}),\n\t\t\t\tusage: message.usage,\n\t\t\t\tstopReason: message.stopReason,\n\t\t\t\ttimestamp: message.timestamp\n\t\t\t};\n\t\t})\n\t};\n}\n/**\n* pi-ai-backed multi-provider adapter."
2269
+ },
2270
+ {
2271
+ "before": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tfor (const profile of profiles.values()) if (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n",
2272
+ "after": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tconst entryModels = new Map();\n\t\tfor (const [provider, profile] of profiles) {\n\t\t\tif (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\t\tconst entries = new Map();\n\t\t\tfor (const [id, entry] of profile.keyEntries) {\n\t\t\t\tconst collection = createModels(this.config.auth);\n\t\t\t\tif (entry.piProvider !== void 0) collection.setProvider(entry.piProvider);\n\t\t\t\tentries.set(id, collection);\n\t\t\t}\n\t\t\tentryModels.set(provider, entries);\n\t\t}\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels,\n\t\t\tentryModels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n"
2273
+ },
2274
+ {
2275
+ "before": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst failure = profile.modelErrors.get(model) ?? (profile.piProvider === void 0 ? profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = snapshot.models.getModel(provider, model);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n",
2276
+ "after": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** Bind the public selection to an exact profile, independent model collection, and upstream id. */\n\trouteOf(snapshot, provider, model) {\n\t\tconst root = this.profileOf(snapshot, provider);\n\t\tconst entry = keyModelRoute(model);\n\t\tif (entry === void 0) return { profile: root, models: snapshot.models, wireModel: model };\n\t\tif (root.multiKey !== true) throw new LlmError(`multi-key selection is disabled for provider \"${provider}\"`, \"UNKNOWN_MODEL\");\n\t\tconst profile = root.keyEntries.get(entry.entryId);\n\t\tconst models = snapshot.entryModels.get(provider)?.get(entry.entryId);\n\t\tif (profile === void 0 || models === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${entry.entryId}\"`, \"UNKNOWN_MODEL\");\n\t\treturn { profile, models, wireModel: entry.wireModel };\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst route = this.routeOf(snapshot, provider, model);\n\t\tconst failure = route.profile.modelErrors.get(route.wireModel) ?? (route.profile.piProvider === void 0 ? route.profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = route.models.getModel(provider, route.wireModel);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n"
2277
+ },
2278
+ {
2279
+ "before": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\ttry {\n\t\t\t\tawait this.config.resolveApiKey(provider, profile);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return [];\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn snapshot.models.getModels(provider).map((model) => ({\n\t\t\t\tprovider,\n\t\t\t\tid: model.id,\n\t\t\t\tname: model.name,\n\t\t\t\tinputModalities: [...model.input]\n\t\t\t}));\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n",
2280
+ "after": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\tconst listed = [];\n\t\t\tconst append = async (owner, models, entryId) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst key = await this.config.resolveApiKey(provider, owner);\n\t\t\t\t\tif (entryId !== void 0 && (key === void 0 || key.length === 0)) return;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return;\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tfor (const model of models.getModels(provider)) listed.push({\n\t\t\t\t\tprovider,\n\t\t\t\t\tid: entryId === void 0 ? model.id : keyModelId(entryId, model.id),\n\t\t\t\t\tname: model.name,\n\t\t\t\t\tinputModalities: [...model.input]\n\t\t\t\t});\n\t\t\t};\n\t\t\t// Keep raw root models advertised so old sessions remain routable without changing keys.\n\t\t\tawait append(profile, snapshot.models);\n\t\t\tif (profile.multiKey === true) for (const [id, entry] of profile.keyEntries) await append(entry, snapshot.entryModels.get(provider).get(id), id);\n\t\t\treturn listed;\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n"
2281
+ },
2282
+ {
2283
+ "before": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(model);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n",
2284
+ "after": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst { profile, wireModel } = this.routeOf(snapshot, provider, model);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(wireModel);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n"
2285
+ },
2286
+ {
2287
+ "before": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => this.streamWithSnapshot(options, snapshot)\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot(options, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n",
2288
+ "after": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => {\n\t\t\t\tif (options.provider !== provider || options.model !== model) throw new LlmError(\"prepared multi-key model selection changed before adapter dispatch\", \"INVALID_CONFIG\");\n\t\t\t\t// Async generators are lazy; pin the owner before returning one to caller-owned code.\n\t\t\t\treturn this.streamWithSnapshot({ ...options, provider, model }, snapshot);\n\t\t\t}\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot({ ...options }, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n"
2289
+ },
2290
+ {
2291
+ "before": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst profile = this.profileOf(snapshot, options.provider);\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n",
2292
+ "after": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst route = this.routeOf(snapshot, options.provider, options.model);\n\t\t\tconst profile = route.profile;\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n"
2293
+ },
2294
+ {
2295
+ "before": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n",
2296
+ "after": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tif (profile.keyEntryId !== void 0 && (apiKey === void 0 || apiKey.length === 0)) throw new LlmError(`provider \"${options.provider}\" key entry \"${profile.keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n"
2297
+ },
2298
+ {
2299
+ "before": "\t\t\t\tconst iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, model.id)[Symbol.asyncIterator]();",
2300
+ "after": "\t\t\t\tconst iterator = toStreamChunks(route.models.streamSimple(model, replayContextForRoute(context, options.provider, options.model, model), {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, options.model)[Symbol.asyncIterator]();"
2301
+ },
2302
+ {
2303
+ "before": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n",
2304
+ "after": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\t// Validate host-owned entry identity even on the installed-catalog shortcut.\n\tconst selectedStored = request.keyEntryId === void 0 ? void 0 : storedProfile?.();\n\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n"
2305
+ },
2306
+ {
2307
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n",
2308
+ "after": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = selectedStored ?? storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n"
2309
+ },
2310
+ {
2311
+ "before": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n",
2312
+ "after": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy,\n\t\tmultiKey: profile.multiKey === true,\n\t\tapiKeyEnv: profile.apiKeyEnv,\n\t\tmodels: profile.piProvider?.getModels(),\n\t\tmodelErrors: [...profile.modelErrors],\n\t\tkeyEntries: [...profile.keyEntries].map(([id, entry]) => ({\n\t\t\tid,\n\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),\n\t\t\tmodelErrors: [...entry.modelErrors]\n\t\t})).sort((left, right) => left.id.localeCompare(right.id))\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n"
2313
+ },
2314
+ {
2315
+ "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
2316
+ "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
2317
+ },
2318
+ {
2319
+ "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
2320
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tmodels: z.array(modelProfile).required()\n});"
2321
+ },
2322
+ {
2323
+ "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
2324
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (entry.sortOrder !== void 0 && (!Number.isSafeInteger(entry.sortOrder) || entry.sortOrder < 0)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" sortOrder must be a nonnegative safe integer`);\n\t\t\tif (!Array.isArray(entry.models))"
2325
+ },
2326
+ {
2327
+ "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
2328
+ "after": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\t...entry.api === void 0 ? {} : { api: entry.api },\n\t\t\t\tmultiKey: false,"
2329
+ },
2330
+ {
2331
+ "before": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {",
2332
+ "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api !== void 0 ? request.api : selectedStored?.api !== void 0 ? selectedStored.api : \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
2333
+ },
2334
+ {
2335
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);",
2336
+ "after": "\tconst baseURL = request.baseURL ?? selectedStored?.baseURL;\n\tif (baseURL === void 0 || baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(baseURL, api);"
2337
+ },
2338
+ {
2339
+ "before": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),",
2340
+ "after": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tapi: entry.api,\n\t\t\tmodels: entry.piProvider?.getModels(),"
2341
+ },
2342
+ {
2343
+ "before": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,",
2344
+ "after": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\tapi: profile.api,\n\t\t\tbaseURL: profile.baseURL ?? catalogProvider(provider)?.baseUrl,\n\t\t\theaders: profile.headers,"
2345
+ },
2346
+ {
2347
+ "before": "function listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");",
2348
+ "after": "/** Strip trailing slashes and one trailing `/v1`, the segment the Anthropic SDK adds itself. */\nfunction anthropicRoot(baseURL) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");\n\treturn base.endsWith(\"/v1\") ? base.slice(0, -3) : base;\n}\nfunction listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");"
2349
+ },
2350
+ {
2351
+ "before": "\t\tconst baseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (baseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);",
2352
+ "after": "\t\tconst configuredBaseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (configuredBaseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);\n\t\tconst baseUrl = api === \"anthropic-messages\" ? anthropicRoot(configuredBaseUrl) : configuredBaseUrl;"
2353
+ },
2354
+ {
2355
+ "before": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${base.endsWith(\"/v1\") ? base.slice(0, -3) : base}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;",
2356
+ "after": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${anthropicRoot(base)}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;"
2357
+ },
2358
+ {
2359
+ "before": "* gateway documentation publishes both spellings of the same root. Only this\n* listing URL normalizes that segment; model requests receive the configured\n* `baseURL` unchanged.\n*/",
2360
+ "after": "* gateway documentation publishes both spellings of the same root. Anthropic\n* listings and model requests both normalize it, because the Anthropic SDK\n* appends `/v1/messages` on its own while OpenAI protocols append\n* `/chat/completions`; without this, one root would work for chat and double\n* the segment for Anthropic.\n*/"
2361
+ },
2362
+ {
2363
+ "before": "const modelProfile = z.object({\n\tid: z.string().required(),\n\t...modelFields\n});",
2364
+ "after": "function applyModelCapabilities(model, defaults) {\n const object = value => value !== null && typeof value === 'object' && !Array.isArray(value);\n const overrides = model.capabilityOverrides;\n if (defaults !== undefined && (!object(defaults) || Object.keys(defaults).some(key => key !== 'vision' && key !== 'reasoning') || typeof defaults.vision !== 'boolean' || typeof defaults.reasoning !== 'boolean')) {\n throw new TypeError('capabilityDefaults must contain only boolean vision and reasoning');\n }\n if (overrides !== undefined && (!object(overrides) || Object.keys(overrides).some(key => key !== 'vision' && key !== 'reasoning') || Object.values(overrides).some(value => typeof value !== 'boolean' && value !== 'original'))) {\n throw new TypeError('capabilityOverrides must contain only boolean or original vision and reasoning');\n }\n const { capabilityOverrides: ignored, ...effective } = model;\n if (defaults === undefined) return effective;\n const choice = key => overrides?.[key] === 'original' ? undefined : overrides?.[key] ?? defaults[key];\n const vision = choice('vision');\n if (vision !== undefined) {\n const input = Array.isArray(model.input) ? [...model.input] : ['text'];\n effective.input = [...new Set(input.filter(value => vision || value !== 'image'))];\n if (!effective.input.includes('text')) effective.input.unshift('text');\n if (vision && !effective.input.includes('image')) effective.input.push('image');\n }\n const reasoning = choice('reasoning');\n if (reasoning === false) effective.reasoningEfforts = false;\n if (reasoning === true) {\n const levels = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];\n const efforts = model.reasoningEfforts;\n const valid = object(efforts) && Object.keys(efforts).every(key => levels.includes(key)) && Object.entries(efforts).every(([key, value]) => key === 'off' && value === null || typeof value === 'string' && value.length > 0) && Object.keys(efforts).some(key => key !== 'off');\n effective.reasoningEfforts = valid ? { ...efforts } : { off: null, low: 'low', medium: 'medium', high: 'high' };\n }\n return effective;\n}\nconst capabilityDefaultsProfile = z.union([z.object({ vision: z.boolean().required(), reasoning: z.boolean().required() })]);\nconst capabilityOverridesProfile = z.union([z.object({ vision: z.union([z.boolean(), z.const(\"original\")]), reasoning: z.union([z.boolean(), z.const(\"original\")]) })]);\nconst modelProfile = z.object({\n\tid: z.string().required(),\n\t...modelFields,\n\tcapabilityOverrides: capabilityOverridesProfile\n});"
2365
+ },
2366
+ {
2367
+ "before": "\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tmodels: z.array(modelProfile).required()",
2368
+ "after": "\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tcapabilityDefaults: capabilityDefaultsProfile,\n\tmodels: z.array(modelProfile).required()"
2369
+ },
2370
+ {
2371
+ "before": "\t\tassertWireModels(source.models, \"models\");",
2372
+ "after": "\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const model of source.models ?? []) applyModelCapabilities(model);"
2373
+ },
2374
+ {
2375
+ "before": "\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);",
2376
+ "after": "\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t\tapplyModelCapabilities({}, entry.capabilityDefaults);\n\t\t\tfor (const model of entry.models) applyModelCapabilities(model, entry.capabilityDefaults);"
2377
+ },
2378
+ {
2379
+ "before": "\t\t\t\tmodels: entry.models,",
2380
+ "after": "\t\t\t\tmodels: entry.models.map(model => applyModelCapabilities(model, entry.capabilityDefaults)),"
2381
+ }
2382
+ ]
2383
+ },
2384
+ {
2385
+ "source": "0.2.2-rc.1 with tool lookup optimization and credential cancellation with per-entry API overrides",
2386
+ "baseSha256": "0a99a2fc903a4285044b09114b3bd20ee1e612f39aa381e4a71b10d48ee9e9f7",
2387
+ "resultSha256": "a611e953f9ffa8468dec99faded5f5fb5412f6409681ee0da424558d21d73577",
2388
+ "replacements": [
2389
+ {
2390
+ "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
2391
+ "after": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\n// Model selection carries an opaque entry identity, never a credential or a wire alias.\nconst KEY_MODEL_PREFIX = \"@dsh-key/\";\nconst KEY_ENTRY_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;\nconst FORBIDDEN_KEY_ENTRY_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst AUTH_HEADER_NAMES = new Set([\"authorization\", \"proxy-authorization\", \"x-api-key\", \"api-key\", \"cf-aig-authorization\"]);\nfunction validKeyEntryId(id) {\n\treturn KEY_ENTRY_ID.test(id) && !FORBIDDEN_KEY_ENTRY_IDS.has(id);\n}\nfunction keyModelId(entryId, model) {\n\treturn `${KEY_MODEL_PREFIX}${encodeURIComponent(entryId)}/${encodeURIComponent(model)}`;\n}\nfunction keyModelRoute(model) {\n\tif (!model.startsWith(KEY_MODEL_PREFIX)) return void 0;\n\ttry {\n\t\tconst parts = model.slice(KEY_MODEL_PREFIX.length).split(\"/\");\n\t\tif (parts.length === 2) {\n\t\t\tconst entryId = decodeURIComponent(parts[0]);\n\t\t\tconst wireModel = decodeURIComponent(parts[1]);\n\t\t\tif (validKeyEntryId(entryId) && wireModel.length > 0 && !wireModel.startsWith(KEY_MODEL_PREFIX) && keyModelId(entryId, wireModel) === model) return { entryId, wireModel };\n\t\t}\n\t} catch {}\n\tthrow new LlmError(`invalid multi-key model selection \"${model}\"`, \"UNKNOWN_MODEL\");\n}\nconst keyEntryProfile = z.object({\n\tname: z.string().max(120).required(),\n\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});\nconst profile = z.object({\n\tmultiKey: z.boolean().default(false),\n\tkeyEntries: z.dict(keyEntryProfile).default({}),\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n"
2392
+ },
2393
+ {
2394
+ "before": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\") {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n",
2395
+ "after": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\", forKeyEntry = false) {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n"
2396
+ },
2397
+ {
2398
+ "before": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n",
2399
+ "after": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst entrySources = source.keyEntries ?? {};\n\t\tif (typeof entrySources !== \"object\" || entrySources === null || Array.isArray(entrySources)) throw new Error(`llm-pi-ai: provider \"${provider}\" keyEntries must be a dictionary`);\n\t\tconst assertWireModels = (models, site) => {\n\t\t\tfor (const model of models ?? []) if (typeof model.id !== \"string\" || model.id.length === 0 || model.id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} must use non-empty upstream model ids outside the reserved ${KEY_MODEL_PREFIX} prefix`);\n\t\t};\n\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const id of Object.keys(source.modelOverrides ?? {})) if (id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" modelOverrides uses reserved prefix ${KEY_MODEL_PREFIX}`);\n\t\tfor (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tif (!validKeyEntryId(id)) throw new Error(`llm-pi-ai: provider \"${provider}\" has an invalid key entry id \"${id}\"`);\n\t\t\tif (typeof entry !== \"object\" || entry === null || typeof entry.name !== \"string\" || entry.name.trim().length === 0 || entry.name.length > 120) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs a name of 1-120 characters`);\n\t\t\tif (typeof entry.apiKeyEnv !== \"string\" || entry.apiKeyEnv.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own apiKeyEnv`);\n\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own models list`);\n\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t}\n\t\tconst assertEntryHeaders = (headers, site) => {\n\t\t\tfor (const name of Object.keys(headers ?? {})) if (AUTH_HEADER_NAMES.has(name.toLowerCase())) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} authentication header \"${name}\" would override the selected key; remove it before enabling multiKey`);\n\t\t};\n\t\tif (source.multiKey === true || forKeyEntry) {\n\t\t\tassertEntryHeaders(source.headers, \"shared\");\n\t\t\tfor (const model of source.models ?? []) assertEntryHeaders(model.headers, `model \"${model.id}\"`);\n\t\t\tfor (const [id, override] of Object.entries(source.modelOverrides ?? {})) assertEntryHeaders(override.headers, `model override \"${id}\"`);\n\t\t}\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n"
2400
+ },
2401
+ {
2402
+ "before": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\ttry {\n\t\t\tcatalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n",
2403
+ "after": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tconst keyEntries = new Map();\n\t\t// Disabled entries remain stored, but cannot constrain legacy single-key runtime behavior.\n\t\tif (source.multiKey === true) for (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,\n\t\t\t\tkeyEntries: {},\n\t\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\t\tmodels: entry.models,\n\t\t\t\tmodelOverrides: void 0\n\t\t\t} }, validation, true).get(provider);\n\t\t\t// Entry auth must not consult a catalog provider's ambient/OAuth credential or endpoint.\n\t\t\tkeyEntries.set(id, {\n\t\t\t\t...child,\n\t\t\t\tkeyEntryId: id,\n\t\t\t\tkeyEntryName: entry.name,\n\t\t\t\t...child.piProvider === void 0 ? {} : { piProvider: { ...child.piProvider, auth: { apiKey: harnessApiKeyAuth(entry.name) } } }\n\t\t\t});\n\t\t}\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\tconst entryOnly = forKeyEntry && source.models.length === 0 || source.multiKey === true && keyEntries.size > 0 && (source.models ?? []).length === 0 && catalogModels(provider).size === 0;\n\t\ttry {\n\t\t\tif (entryOnly) catalog = { models: [], configuredMaxTokens: new Map(), modelErrors: new Map() };\n\t\t\telse catalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n"
2404
+ },
2405
+ {
2406
+ "before": "\t\t\t}, validation);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;",
2407
+ "after": "\t\t\t}, validation);\n\t\t\tif (source.multiKey === true || forKeyEntry) for (const model of catalog.models) assertEntryHeaders(model.headers, `resolved model \"${model.id}\"`);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;"
2408
+ },
2409
+ {
2410
+ "before": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },",
2411
+ "after": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, keyEntries: _keyEntries, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\tkeyEntries,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },"
2412
+ },
2413
+ {
2414
+ "before": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/**\n* pi-ai-backed multi-provider adapter.",
2415
+ "after": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/** Decode only the selected replay owner at the pi boundary; never merge equal wire ids across keys. */\nfunction replayContextForRoute(context, provider, requestedModel, wireModel) {\n\tconst selectedEntry = requestedModel.startsWith(KEY_MODEL_PREFIX);\n\treturn {\n\t\t...context,\n\t\tmessages: context.messages.map((message) => {\n\t\t\tif (message.role !== \"assistant\") return message;\n\t\t\tif (message.provider === provider && message.model === requestedModel) return { ...message, model: wireModel.id };\n\t\t\tif (!message.model.startsWith(KEY_MODEL_PREFIX) && !(selectedEntry && message.provider === provider && message.model === wireModel.id)) return message;\n\t\t\treturn {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tapi: \"dsh-foreign\",\n\t\t\t\tprovider: message.provider,\n\t\t\t\tmodel: \"dsh-foreign\",\n\t\t\t\tcontent: message.content.flatMap((block) => {\n\t\t\t\t\tif (block.type === \"thinking\") return [];\n\t\t\t\t\tif (block.type === \"text\") return [{ type: \"text\", text: block.text }];\n\t\t\t\t\tif (block.type === \"toolCall\") return [{ type: \"toolCall\", id: block.id, name: block.name, arguments: block.arguments }];\n\t\t\t\t\treturn [block];\n\t\t\t\t}),\n\t\t\t\tusage: message.usage,\n\t\t\t\tstopReason: message.stopReason,\n\t\t\t\ttimestamp: message.timestamp\n\t\t\t};\n\t\t})\n\t};\n}\n/**\n* pi-ai-backed multi-provider adapter."
2416
+ },
2417
+ {
2418
+ "before": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tfor (const profile of profiles.values()) if (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n",
2419
+ "after": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tconst entryModels = new Map();\n\t\tfor (const [provider, profile] of profiles) {\n\t\t\tif (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\t\tconst entries = new Map();\n\t\t\tfor (const [id, entry] of profile.keyEntries) {\n\t\t\t\tconst collection = createModels(this.config.auth);\n\t\t\t\tif (entry.piProvider !== void 0) collection.setProvider(entry.piProvider);\n\t\t\t\tentries.set(id, collection);\n\t\t\t}\n\t\t\tentryModels.set(provider, entries);\n\t\t}\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels,\n\t\t\tentryModels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n"
2420
+ },
2421
+ {
2422
+ "before": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst failure = profile.modelErrors.get(model) ?? (profile.piProvider === void 0 ? profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = snapshot.models.getModel(provider, model);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n",
2423
+ "after": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** Bind the public selection to an exact profile, independent model collection, and upstream id. */\n\trouteOf(snapshot, provider, model) {\n\t\tconst root = this.profileOf(snapshot, provider);\n\t\tconst entry = keyModelRoute(model);\n\t\tif (entry === void 0) return { profile: root, models: snapshot.models, wireModel: model };\n\t\tif (root.multiKey !== true) throw new LlmError(`multi-key selection is disabled for provider \"${provider}\"`, \"UNKNOWN_MODEL\");\n\t\tconst profile = root.keyEntries.get(entry.entryId);\n\t\tconst models = snapshot.entryModels.get(provider)?.get(entry.entryId);\n\t\tif (profile === void 0 || models === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${entry.entryId}\"`, \"UNKNOWN_MODEL\");\n\t\treturn { profile, models, wireModel: entry.wireModel };\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst route = this.routeOf(snapshot, provider, model);\n\t\tconst failure = route.profile.modelErrors.get(route.wireModel) ?? (route.profile.piProvider === void 0 ? route.profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = route.models.getModel(provider, route.wireModel);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n"
2424
+ },
2425
+ {
2426
+ "before": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\ttry {\n\t\t\t\tawait this.config.resolveApiKey(provider, profile);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return [];\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn snapshot.models.getModels(provider).map((model) => ({\n\t\t\t\tprovider,\n\t\t\t\tid: model.id,\n\t\t\t\tname: model.name,\n\t\t\t\tinputModalities: [...model.input]\n\t\t\t}));\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n",
2427
+ "after": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\tconst listed = [];\n\t\t\tconst append = async (owner, models, entryId) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst key = await this.config.resolveApiKey(provider, owner);\n\t\t\t\t\tif (entryId !== void 0 && (key === void 0 || key.length === 0)) return;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return;\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tfor (const model of models.getModels(provider)) listed.push({\n\t\t\t\t\tprovider,\n\t\t\t\t\tid: entryId === void 0 ? model.id : keyModelId(entryId, model.id),\n\t\t\t\t\tname: model.name,\n\t\t\t\t\tinputModalities: [...model.input]\n\t\t\t\t});\n\t\t\t};\n\t\t\t// Keep raw root models advertised so old sessions remain routable without changing keys.\n\t\t\tawait append(profile, snapshot.models);\n\t\t\tif (profile.multiKey === true) for (const [id, entry] of profile.keyEntries) await append(entry, snapshot.entryModels.get(provider).get(id), id);\n\t\t\treturn listed;\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n"
2428
+ },
2429
+ {
2430
+ "before": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(model);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n",
2431
+ "after": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst { profile, wireModel } = this.routeOf(snapshot, provider, model);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(wireModel);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n"
2432
+ },
2433
+ {
2434
+ "before": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => this.streamWithSnapshot(options, snapshot)\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot(options, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n",
2435
+ "after": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => {\n\t\t\t\tif (options.provider !== provider || options.model !== model) throw new LlmError(\"prepared multi-key model selection changed before adapter dispatch\", \"INVALID_CONFIG\");\n\t\t\t\t// Async generators are lazy; pin the owner before returning one to caller-owned code.\n\t\t\t\treturn this.streamWithSnapshot({ ...options, provider, model }, snapshot);\n\t\t\t}\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot({ ...options }, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n"
2436
+ },
2437
+ {
2438
+ "before": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst profile = this.profileOf(snapshot, options.provider);\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n",
2439
+ "after": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst route = this.routeOf(snapshot, options.provider, options.model);\n\t\t\tconst profile = route.profile;\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n"
2440
+ },
2441
+ {
2442
+ "before": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n",
2443
+ "after": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tif (profile.keyEntryId !== void 0 && (apiKey === void 0 || apiKey.length === 0)) throw new LlmError(`provider \"${options.provider}\" key entry \"${profile.keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n"
2444
+ },
2445
+ {
2446
+ "before": "\t\t\t\tconst iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, model.id)[Symbol.asyncIterator]();",
2447
+ "after": "\t\t\t\tconst iterator = toStreamChunks(route.models.streamSimple(model, replayContextForRoute(context, options.provider, options.model, model), {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, options.model)[Symbol.asyncIterator]();"
2448
+ },
2449
+ {
2450
+ "before": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n",
2451
+ "after": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\t// Validate host-owned entry identity even on the installed-catalog shortcut.\n\tconst selectedStored = request.keyEntryId === void 0 ? void 0 : storedProfile?.();\n\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n"
2452
+ },
2453
+ {
2454
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n",
2455
+ "after": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = selectedStored ?? storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n"
2456
+ },
2457
+ {
2458
+ "before": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n",
2459
+ "after": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy,\n\t\tmultiKey: profile.multiKey === true,\n\t\tapiKeyEnv: profile.apiKeyEnv,\n\t\tmodels: profile.piProvider?.getModels(),\n\t\tmodelErrors: [...profile.modelErrors],\n\t\tkeyEntries: [...profile.keyEntries].map(([id, entry]) => ({\n\t\t\tid,\n\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),\n\t\t\tmodelErrors: [...entry.modelErrors]\n\t\t})).sort((left, right) => left.id.localeCompare(right.id))\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n"
2460
+ },
2461
+ {
2462
+ "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
2463
+ "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
2464
+ },
2465
+ {
2466
+ "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
2467
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tmodels: z.array(modelProfile).required()\n});"
1019
2468
  },
1020
2469
  {
1021
2470
  "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
1022
- "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (!Array.isArray(entry.models))"
2471
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (entry.sortOrder !== void 0 && (!Number.isSafeInteger(entry.sortOrder) || entry.sortOrder < 0)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" sortOrder must be a nonnegative safe integer`);\n\t\t\tif (!Array.isArray(entry.models))"
1023
2472
  },
1024
2473
  {
1025
2474
  "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
@@ -1052,13 +2501,37 @@
1052
2501
  {
1053
2502
  "before": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${base.endsWith(\"/v1\") ? base.slice(0, -3) : base}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;",
1054
2503
  "after": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${anthropicRoot(base)}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;"
2504
+ },
2505
+ {
2506
+ "before": "* gateway documentation publishes both spellings of the same root. Only this\n* listing URL normalizes that segment; model requests receive the configured\n* `baseURL` unchanged.\n*/",
2507
+ "after": "* gateway documentation publishes both spellings of the same root. Anthropic\n* listings and model requests both normalize it, because the Anthropic SDK\n* appends `/v1/messages` on its own while OpenAI protocols append\n* `/chat/completions`; without this, one root would work for chat and double\n* the segment for Anthropic.\n*/"
2508
+ },
2509
+ {
2510
+ "before": "const modelProfile = z.object({\n\tid: z.string().required(),\n\t...modelFields\n});",
2511
+ "after": "function applyModelCapabilities(model, defaults) {\n const object = value => value !== null && typeof value === 'object' && !Array.isArray(value);\n const overrides = model.capabilityOverrides;\n if (defaults !== undefined && (!object(defaults) || Object.keys(defaults).some(key => key !== 'vision' && key !== 'reasoning') || typeof defaults.vision !== 'boolean' || typeof defaults.reasoning !== 'boolean')) {\n throw new TypeError('capabilityDefaults must contain only boolean vision and reasoning');\n }\n if (overrides !== undefined && (!object(overrides) || Object.keys(overrides).some(key => key !== 'vision' && key !== 'reasoning') || Object.values(overrides).some(value => typeof value !== 'boolean' && value !== 'original'))) {\n throw new TypeError('capabilityOverrides must contain only boolean or original vision and reasoning');\n }\n const { capabilityOverrides: ignored, ...effective } = model;\n if (defaults === undefined) return effective;\n const choice = key => overrides?.[key] === 'original' ? undefined : overrides?.[key] ?? defaults[key];\n const vision = choice('vision');\n if (vision !== undefined) {\n const input = Array.isArray(model.input) ? [...model.input] : ['text'];\n effective.input = [...new Set(input.filter(value => vision || value !== 'image'))];\n if (!effective.input.includes('text')) effective.input.unshift('text');\n if (vision && !effective.input.includes('image')) effective.input.push('image');\n }\n const reasoning = choice('reasoning');\n if (reasoning === false) effective.reasoningEfforts = false;\n if (reasoning === true) {\n const levels = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];\n const efforts = model.reasoningEfforts;\n const valid = object(efforts) && Object.keys(efforts).every(key => levels.includes(key)) && Object.entries(efforts).every(([key, value]) => key === 'off' && value === null || typeof value === 'string' && value.length > 0) && Object.keys(efforts).some(key => key !== 'off');\n effective.reasoningEfforts = valid ? { ...efforts } : { off: null, low: 'low', medium: 'medium', high: 'high' };\n }\n return effective;\n}\nconst capabilityDefaultsProfile = z.union([z.object({ vision: z.boolean().required(), reasoning: z.boolean().required() })]);\nconst capabilityOverridesProfile = z.union([z.object({ vision: z.union([z.boolean(), z.const(\"original\")]), reasoning: z.union([z.boolean(), z.const(\"original\")]) })]);\nconst modelProfile = z.object({\n\tid: z.string().required(),\n\t...modelFields,\n\tcapabilityOverrides: capabilityOverridesProfile\n});"
2512
+ },
2513
+ {
2514
+ "before": "\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tmodels: z.array(modelProfile).required()",
2515
+ "after": "\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tcapabilityDefaults: capabilityDefaultsProfile,\n\tmodels: z.array(modelProfile).required()"
2516
+ },
2517
+ {
2518
+ "before": "\t\tassertWireModels(source.models, \"models\");",
2519
+ "after": "\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const model of source.models ?? []) applyModelCapabilities(model);"
2520
+ },
2521
+ {
2522
+ "before": "\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);",
2523
+ "after": "\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t\tapplyModelCapabilities({}, entry.capabilityDefaults);\n\t\t\tfor (const model of entry.models) applyModelCapabilities(model, entry.capabilityDefaults);"
2524
+ },
2525
+ {
2526
+ "before": "\t\t\t\tmodels: entry.models,",
2527
+ "after": "\t\t\t\tmodels: entry.models.map(model => applyModelCapabilities(model, entry.capabilityDefaults)),"
1055
2528
  }
1056
2529
  ]
1057
2530
  },
1058
2531
  {
1059
2532
  "source": "npm official 0.2.2-rc.1 with per-entry API overrides",
1060
2533
  "baseSha256": "1a3ae58f9b4493e15459cc5000ec80f21b5d3f4a9dea6ffb6bc28e5b8817ae8a",
1061
- "resultSha256": "432b9050dff97c9dae6744b6c6189e0c4a4363321afab6310aec4d5fcb418681",
2534
+ "resultSha256": "b7a189885f4d805096ae4fc250c1978002232374e20af2a8fa5778094273c523",
1062
2535
  "replacements": [
1063
2536
  {
1064
2537
  "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
@@ -1138,11 +2611,11 @@
1138
2611
  },
1139
2612
  {
1140
2613
  "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
1141
- "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tmodels: z.array(modelProfile).required()\n});"
2614
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tmodels: z.array(modelProfile).required()\n});"
1142
2615
  },
1143
2616
  {
1144
2617
  "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
1145
- "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (!Array.isArray(entry.models))"
2618
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (entry.sortOrder !== void 0 && (!Number.isSafeInteger(entry.sortOrder) || entry.sortOrder < 0)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" sortOrder must be a nonnegative safe integer`);\n\t\t\tif (!Array.isArray(entry.models))"
1146
2619
  },
1147
2620
  {
1148
2621
  "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
@@ -1175,19 +2648,190 @@
1175
2648
  {
1176
2649
  "before": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${base.endsWith(\"/v1\") ? base.slice(0, -3) : base}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;",
1177
2650
  "after": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${anthropicRoot(base)}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;"
2651
+ },
2652
+ {
2653
+ "before": "* gateway documentation publishes both spellings of the same root. Only this\n* listing URL normalizes that segment; model requests receive the configured\n* `baseURL` unchanged.\n*/",
2654
+ "after": "* gateway documentation publishes both spellings of the same root. Anthropic\n* listings and model requests both normalize it, because the Anthropic SDK\n* appends `/v1/messages` on its own while OpenAI protocols append\n* `/chat/completions`; without this, one root would work for chat and double\n* the segment for Anthropic.\n*/"
2655
+ },
2656
+ {
2657
+ "before": "const modelProfile = z.object({\n\tid: z.string().required(),\n\t...modelFields\n});",
2658
+ "after": "function applyModelCapabilities(model, defaults) {\n const object = value => value !== null && typeof value === 'object' && !Array.isArray(value);\n const overrides = model.capabilityOverrides;\n if (defaults !== undefined && (!object(defaults) || Object.keys(defaults).some(key => key !== 'vision' && key !== 'reasoning') || typeof defaults.vision !== 'boolean' || typeof defaults.reasoning !== 'boolean')) {\n throw new TypeError('capabilityDefaults must contain only boolean vision and reasoning');\n }\n if (overrides !== undefined && (!object(overrides) || Object.keys(overrides).some(key => key !== 'vision' && key !== 'reasoning') || Object.values(overrides).some(value => typeof value !== 'boolean' && value !== 'original'))) {\n throw new TypeError('capabilityOverrides must contain only boolean or original vision and reasoning');\n }\n const { capabilityOverrides: ignored, ...effective } = model;\n if (defaults === undefined) return effective;\n const choice = key => overrides?.[key] === 'original' ? undefined : overrides?.[key] ?? defaults[key];\n const vision = choice('vision');\n if (vision !== undefined) {\n const input = Array.isArray(model.input) ? [...model.input] : ['text'];\n effective.input = [...new Set(input.filter(value => vision || value !== 'image'))];\n if (effective.input.length === 0) effective.input.push('text');\n if (vision && !effective.input.includes('image')) effective.input.push('image');\n }\n const reasoning = choice('reasoning');\n if (reasoning === false) effective.reasoningEfforts = false;\n if (reasoning === true) {\n const levels = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];\n const efforts = model.reasoningEfforts;\n const valid = object(efforts) && Object.keys(efforts).every(key => levels.includes(key)) && Object.entries(efforts).every(([key, value]) => key === 'off' && value === null || typeof value === 'string' && value.length > 0) && Object.keys(efforts).some(key => key !== 'off');\n effective.reasoningEfforts = valid ? { ...efforts } : { off: null, low: 'low', medium: 'medium', high: 'high' };\n }\n return effective;\n}\nconst capabilityDefaultsProfile = z.union([z.object({ vision: z.boolean().required(), reasoning: z.boolean().required() })]);\nconst capabilityOverridesProfile = z.union([z.object({ vision: z.union([z.boolean(), z.const(\"original\")]), reasoning: z.union([z.boolean(), z.const(\"original\")]) })]);\nconst modelProfile = z.object({\n\tid: z.string().required(),\n\t...modelFields,\n\tcapabilityOverrides: capabilityOverridesProfile\n});"
2659
+ },
2660
+ {
2661
+ "before": "\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tmodels: z.array(modelProfile).required()",
2662
+ "after": "\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tcapabilityDefaults: capabilityDefaultsProfile,\n\tmodels: z.array(modelProfile).required()"
2663
+ },
2664
+ {
2665
+ "before": "\t\tassertWireModels(source.models, \"models\");",
2666
+ "after": "\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const model of source.models ?? []) applyModelCapabilities(model);"
2667
+ },
2668
+ {
2669
+ "before": "\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);",
2670
+ "after": "\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t\tapplyModelCapabilities({}, entry.capabilityDefaults);\n\t\t\tfor (const model of entry.models) applyModelCapabilities(model, entry.capabilityDefaults);"
2671
+ },
2672
+ {
2673
+ "before": "\t\t\t\tmodels: entry.models,",
2674
+ "after": "\t\t\t\tmodels: entry.models.map(model => applyModelCapabilities(model, entry.capabilityDefaults)),"
1178
2675
  }
1179
2676
  ]
1180
2677
  },
1181
2678
  {
1182
2679
  "source": "0.2.2-rc.1 with tool lookup optimization and credential cancellation with per-entry API overrides",
1183
2680
  "baseSha256": "0a99a2fc903a4285044b09114b3bd20ee1e612f39aa381e4a71b10d48ee9e9f7",
1184
- "resultSha256": "c7d20ebe93753ae6f30d614121bac533fe5a8fa9372ea1c5fdc8bf2f7eba1d1d",
1185
- "current": true
2681
+ "resultSha256": "580fa3abca9a8f9c3f42897aa041bd77eae9a5b692e7a94fd53bfa80cec13a4d",
2682
+ "replacements": [
2683
+ {
2684
+ "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
2685
+ "after": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\n// Model selection carries an opaque entry identity, never a credential or a wire alias.\nconst KEY_MODEL_PREFIX = \"@dsh-key/\";\nconst KEY_ENTRY_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;\nconst FORBIDDEN_KEY_ENTRY_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst AUTH_HEADER_NAMES = new Set([\"authorization\", \"proxy-authorization\", \"x-api-key\", \"api-key\", \"cf-aig-authorization\"]);\nfunction validKeyEntryId(id) {\n\treturn KEY_ENTRY_ID.test(id) && !FORBIDDEN_KEY_ENTRY_IDS.has(id);\n}\nfunction keyModelId(entryId, model) {\n\treturn `${KEY_MODEL_PREFIX}${encodeURIComponent(entryId)}/${encodeURIComponent(model)}`;\n}\nfunction keyModelRoute(model) {\n\tif (!model.startsWith(KEY_MODEL_PREFIX)) return void 0;\n\ttry {\n\t\tconst parts = model.slice(KEY_MODEL_PREFIX.length).split(\"/\");\n\t\tif (parts.length === 2) {\n\t\t\tconst entryId = decodeURIComponent(parts[0]);\n\t\t\tconst wireModel = decodeURIComponent(parts[1]);\n\t\t\tif (validKeyEntryId(entryId) && wireModel.length > 0 && !wireModel.startsWith(KEY_MODEL_PREFIX) && keyModelId(entryId, wireModel) === model) return { entryId, wireModel };\n\t\t}\n\t} catch {}\n\tthrow new LlmError(`invalid multi-key model selection \"${model}\"`, \"UNKNOWN_MODEL\");\n}\nconst keyEntryProfile = z.object({\n\tname: z.string().max(120).required(),\n\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});\nconst profile = z.object({\n\tmultiKey: z.boolean().default(false),\n\tkeyEntries: z.dict(keyEntryProfile).default({}),\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n"
2686
+ },
2687
+ {
2688
+ "before": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\") {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n",
2689
+ "after": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\", forKeyEntry = false) {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n"
2690
+ },
2691
+ {
2692
+ "before": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n",
2693
+ "after": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst entrySources = source.keyEntries ?? {};\n\t\tif (typeof entrySources !== \"object\" || entrySources === null || Array.isArray(entrySources)) throw new Error(`llm-pi-ai: provider \"${provider}\" keyEntries must be a dictionary`);\n\t\tconst assertWireModels = (models, site) => {\n\t\t\tfor (const model of models ?? []) if (typeof model.id !== \"string\" || model.id.length === 0 || model.id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} must use non-empty upstream model ids outside the reserved ${KEY_MODEL_PREFIX} prefix`);\n\t\t};\n\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const id of Object.keys(source.modelOverrides ?? {})) if (id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" modelOverrides uses reserved prefix ${KEY_MODEL_PREFIX}`);\n\t\tfor (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tif (!validKeyEntryId(id)) throw new Error(`llm-pi-ai: provider \"${provider}\" has an invalid key entry id \"${id}\"`);\n\t\t\tif (typeof entry !== \"object\" || entry === null || typeof entry.name !== \"string\" || entry.name.trim().length === 0 || entry.name.length > 120) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs a name of 1-120 characters`);\n\t\t\tif (typeof entry.apiKeyEnv !== \"string\" || entry.apiKeyEnv.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own apiKeyEnv`);\n\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own models list`);\n\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t}\n\t\tconst assertEntryHeaders = (headers, site) => {\n\t\t\tfor (const name of Object.keys(headers ?? {})) if (AUTH_HEADER_NAMES.has(name.toLowerCase())) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} authentication header \"${name}\" would override the selected key; remove it before enabling multiKey`);\n\t\t};\n\t\tif (source.multiKey === true || forKeyEntry) {\n\t\t\tassertEntryHeaders(source.headers, \"shared\");\n\t\t\tfor (const model of source.models ?? []) assertEntryHeaders(model.headers, `model \"${model.id}\"`);\n\t\t\tfor (const [id, override] of Object.entries(source.modelOverrides ?? {})) assertEntryHeaders(override.headers, `model override \"${id}\"`);\n\t\t}\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n"
2694
+ },
2695
+ {
2696
+ "before": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\ttry {\n\t\t\tcatalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n",
2697
+ "after": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tconst keyEntries = new Map();\n\t\t// Disabled entries remain stored, but cannot constrain legacy single-key runtime behavior.\n\t\tif (source.multiKey === true) for (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,\n\t\t\t\tkeyEntries: {},\n\t\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\t\tmodels: entry.models,\n\t\t\t\tmodelOverrides: void 0\n\t\t\t} }, validation, true).get(provider);\n\t\t\t// Entry auth must not consult a catalog provider's ambient/OAuth credential or endpoint.\n\t\t\tkeyEntries.set(id, {\n\t\t\t\t...child,\n\t\t\t\tkeyEntryId: id,\n\t\t\t\tkeyEntryName: entry.name,\n\t\t\t\t...child.piProvider === void 0 ? {} : { piProvider: { ...child.piProvider, auth: { apiKey: harnessApiKeyAuth(entry.name) } } }\n\t\t\t});\n\t\t}\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\tconst entryOnly = forKeyEntry && source.models.length === 0 || source.multiKey === true && keyEntries.size > 0 && (source.models ?? []).length === 0 && catalogModels(provider).size === 0;\n\t\ttry {\n\t\t\tif (entryOnly) catalog = { models: [], configuredMaxTokens: new Map(), modelErrors: new Map() };\n\t\t\telse catalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n"
2698
+ },
2699
+ {
2700
+ "before": "\t\t\t}, validation);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;",
2701
+ "after": "\t\t\t}, validation);\n\t\t\tif (source.multiKey === true || forKeyEntry) for (const model of catalog.models) assertEntryHeaders(model.headers, `resolved model \"${model.id}\"`);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;"
2702
+ },
2703
+ {
2704
+ "before": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },",
2705
+ "after": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, keyEntries: _keyEntries, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\tkeyEntries,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },"
2706
+ },
2707
+ {
2708
+ "before": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/**\n* pi-ai-backed multi-provider adapter.",
2709
+ "after": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/** Decode only the selected replay owner at the pi boundary; never merge equal wire ids across keys. */\nfunction replayContextForRoute(context, provider, requestedModel, wireModel) {\n\tconst selectedEntry = requestedModel.startsWith(KEY_MODEL_PREFIX);\n\treturn {\n\t\t...context,\n\t\tmessages: context.messages.map((message) => {\n\t\t\tif (message.role !== \"assistant\") return message;\n\t\t\tif (message.provider === provider && message.model === requestedModel) return { ...message, model: wireModel.id };\n\t\t\tif (!message.model.startsWith(KEY_MODEL_PREFIX) && !(selectedEntry && message.provider === provider && message.model === wireModel.id)) return message;\n\t\t\treturn {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tapi: \"dsh-foreign\",\n\t\t\t\tprovider: message.provider,\n\t\t\t\tmodel: \"dsh-foreign\",\n\t\t\t\tcontent: message.content.flatMap((block) => {\n\t\t\t\t\tif (block.type === \"thinking\") return [];\n\t\t\t\t\tif (block.type === \"text\") return [{ type: \"text\", text: block.text }];\n\t\t\t\t\tif (block.type === \"toolCall\") return [{ type: \"toolCall\", id: block.id, name: block.name, arguments: block.arguments }];\n\t\t\t\t\treturn [block];\n\t\t\t\t}),\n\t\t\t\tusage: message.usage,\n\t\t\t\tstopReason: message.stopReason,\n\t\t\t\ttimestamp: message.timestamp\n\t\t\t};\n\t\t})\n\t};\n}\n/**\n* pi-ai-backed multi-provider adapter."
2710
+ },
2711
+ {
2712
+ "before": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tfor (const profile of profiles.values()) if (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n",
2713
+ "after": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tconst entryModels = new Map();\n\t\tfor (const [provider, profile] of profiles) {\n\t\t\tif (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\t\tconst entries = new Map();\n\t\t\tfor (const [id, entry] of profile.keyEntries) {\n\t\t\t\tconst collection = createModels(this.config.auth);\n\t\t\t\tif (entry.piProvider !== void 0) collection.setProvider(entry.piProvider);\n\t\t\t\tentries.set(id, collection);\n\t\t\t}\n\t\t\tentryModels.set(provider, entries);\n\t\t}\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels,\n\t\t\tentryModels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n"
2714
+ },
2715
+ {
2716
+ "before": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst failure = profile.modelErrors.get(model) ?? (profile.piProvider === void 0 ? profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = snapshot.models.getModel(provider, model);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n",
2717
+ "after": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** Bind the public selection to an exact profile, independent model collection, and upstream id. */\n\trouteOf(snapshot, provider, model) {\n\t\tconst root = this.profileOf(snapshot, provider);\n\t\tconst entry = keyModelRoute(model);\n\t\tif (entry === void 0) return { profile: root, models: snapshot.models, wireModel: model };\n\t\tif (root.multiKey !== true) throw new LlmError(`multi-key selection is disabled for provider \"${provider}\"`, \"UNKNOWN_MODEL\");\n\t\tconst profile = root.keyEntries.get(entry.entryId);\n\t\tconst models = snapshot.entryModels.get(provider)?.get(entry.entryId);\n\t\tif (profile === void 0 || models === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${entry.entryId}\"`, \"UNKNOWN_MODEL\");\n\t\treturn { profile, models, wireModel: entry.wireModel };\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst route = this.routeOf(snapshot, provider, model);\n\t\tconst failure = route.profile.modelErrors.get(route.wireModel) ?? (route.profile.piProvider === void 0 ? route.profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = route.models.getModel(provider, route.wireModel);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n"
2718
+ },
2719
+ {
2720
+ "before": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\ttry {\n\t\t\t\tawait this.config.resolveApiKey(provider, profile);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return [];\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn snapshot.models.getModels(provider).map((model) => ({\n\t\t\t\tprovider,\n\t\t\t\tid: model.id,\n\t\t\t\tname: model.name,\n\t\t\t\tinputModalities: [...model.input]\n\t\t\t}));\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n",
2721
+ "after": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\tconst listed = [];\n\t\t\tconst append = async (owner, models, entryId) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst key = await this.config.resolveApiKey(provider, owner);\n\t\t\t\t\tif (entryId !== void 0 && (key === void 0 || key.length === 0)) return;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return;\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tfor (const model of models.getModels(provider)) listed.push({\n\t\t\t\t\tprovider,\n\t\t\t\t\tid: entryId === void 0 ? model.id : keyModelId(entryId, model.id),\n\t\t\t\t\tname: model.name,\n\t\t\t\t\tinputModalities: [...model.input]\n\t\t\t\t});\n\t\t\t};\n\t\t\t// Keep raw root models advertised so old sessions remain routable without changing keys.\n\t\t\tawait append(profile, snapshot.models);\n\t\t\tif (profile.multiKey === true) for (const [id, entry] of profile.keyEntries) await append(entry, snapshot.entryModels.get(provider).get(id), id);\n\t\t\treturn listed;\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n"
2722
+ },
2723
+ {
2724
+ "before": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(model);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n",
2725
+ "after": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst { profile, wireModel } = this.routeOf(snapshot, provider, model);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(wireModel);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n"
2726
+ },
2727
+ {
2728
+ "before": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => this.streamWithSnapshot(options, snapshot)\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot(options, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n",
2729
+ "after": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => {\n\t\t\t\tif (options.provider !== provider || options.model !== model) throw new LlmError(\"prepared multi-key model selection changed before adapter dispatch\", \"INVALID_CONFIG\");\n\t\t\t\t// Async generators are lazy; pin the owner before returning one to caller-owned code.\n\t\t\t\treturn this.streamWithSnapshot({ ...options, provider, model }, snapshot);\n\t\t\t}\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot({ ...options }, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n"
2730
+ },
2731
+ {
2732
+ "before": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst profile = this.profileOf(snapshot, options.provider);\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n",
2733
+ "after": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst route = this.routeOf(snapshot, options.provider, options.model);\n\t\t\tconst profile = route.profile;\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n"
2734
+ },
2735
+ {
2736
+ "before": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n",
2737
+ "after": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tif (profile.keyEntryId !== void 0 && (apiKey === void 0 || apiKey.length === 0)) throw new LlmError(`provider \"${options.provider}\" key entry \"${profile.keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n"
2738
+ },
2739
+ {
2740
+ "before": "\t\t\t\tconst iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, model.id)[Symbol.asyncIterator]();",
2741
+ "after": "\t\t\t\tconst iterator = toStreamChunks(route.models.streamSimple(model, replayContextForRoute(context, options.provider, options.model, model), {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, options.model)[Symbol.asyncIterator]();"
2742
+ },
2743
+ {
2744
+ "before": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n",
2745
+ "after": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\t// Validate host-owned entry identity even on the installed-catalog shortcut.\n\tconst selectedStored = request.keyEntryId === void 0 ? void 0 : storedProfile?.();\n\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n"
2746
+ },
2747
+ {
2748
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n",
2749
+ "after": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = selectedStored ?? storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n"
2750
+ },
2751
+ {
2752
+ "before": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n",
2753
+ "after": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy,\n\t\tmultiKey: profile.multiKey === true,\n\t\tapiKeyEnv: profile.apiKeyEnv,\n\t\tmodels: profile.piProvider?.getModels(),\n\t\tmodelErrors: [...profile.modelErrors],\n\t\tkeyEntries: [...profile.keyEntries].map(([id, entry]) => ({\n\t\t\tid,\n\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),\n\t\t\tmodelErrors: [...entry.modelErrors]\n\t\t})).sort((left, right) => left.id.localeCompare(right.id))\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n"
2754
+ },
2755
+ {
2756
+ "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
2757
+ "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
2758
+ },
2759
+ {
2760
+ "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
2761
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tmodels: z.array(modelProfile).required()\n});"
2762
+ },
2763
+ {
2764
+ "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
2765
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (entry.sortOrder !== void 0 && (!Number.isSafeInteger(entry.sortOrder) || entry.sortOrder < 0)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" sortOrder must be a nonnegative safe integer`);\n\t\t\tif (!Array.isArray(entry.models))"
2766
+ },
2767
+ {
2768
+ "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
2769
+ "after": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\t...entry.api === void 0 ? {} : { api: entry.api },\n\t\t\t\tmultiKey: false,"
2770
+ },
2771
+ {
2772
+ "before": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {",
2773
+ "after": "\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tconst api = request.api !== void 0 ? request.api : selectedStored?.api !== void 0 ? selectedStored.api : \"openai-completions\";\n\tif (!supportedProtocols().includes(api)) throw new LlmError(`pi-ai model discovery api must be a supported protocol`, \"INVALID_CONFIG\");\n\t// A selected entry must probe its effective protocol, not a catalog for another API.\n\tconst entryProtocol = request.keyEntryId !== void 0 && (request.api !== void 0 || selectedStored.api !== void 0);\n\tif (!entryProtocol && request.provider !== void 0) {"
2774
+ },
2775
+ {
2776
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);",
2777
+ "after": "\tconst baseURL = request.baseURL ?? selectedStored?.baseURL;\n\tif (baseURL === void 0 || baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(baseURL, api);"
2778
+ },
2779
+ {
2780
+ "before": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),",
2781
+ "after": "\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tapi: entry.api,\n\t\t\tmodels: entry.piProvider?.getModels(),"
2782
+ },
2783
+ {
2784
+ "before": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,",
2785
+ "after": "\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\tapi: profile.api,\n\t\t\tbaseURL: profile.baseURL ?? catalogProvider(provider)?.baseUrl,\n\t\t\theaders: profile.headers,"
2786
+ },
2787
+ {
2788
+ "before": "function listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");",
2789
+ "after": "/** Strip trailing slashes and one trailing `/v1`, the segment the Anthropic SDK adds itself. */\nfunction anthropicRoot(baseURL) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");\n\treturn base.endsWith(\"/v1\") ? base.slice(0, -3) : base;\n}\nfunction listingUrl(baseURL, api) {\n\tconst base = baseURL.replace(/\\/+$/, \"\");"
2790
+ },
2791
+ {
2792
+ "before": "\t\tconst baseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (baseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);",
2793
+ "after": "\t\tconst configuredBaseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;\n\t\tif (configuredBaseUrl === void 0) invalid(provider, `model \"${entry.id}\" needs a baseURL; the installed catalog does not describe this route`);\n\t\tconst baseUrl = api === \"anthropic-messages\" ? anthropicRoot(configuredBaseUrl) : configuredBaseUrl;"
2794
+ },
2795
+ {
2796
+ "before": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${base.endsWith(\"/v1\") ? base.slice(0, -3) : base}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;",
2797
+ "after": "\tif (api !== \"anthropic-messages\") return `${base}/models`;\n\treturn `${anthropicRoot(base)}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`;"
2798
+ },
2799
+ {
2800
+ "before": "* gateway documentation publishes both spellings of the same root. Only this\n* listing URL normalizes that segment; model requests receive the configured\n* `baseURL` unchanged.\n*/",
2801
+ "after": "* gateway documentation publishes both spellings of the same root. Anthropic\n* listings and model requests both normalize it, because the Anthropic SDK\n* appends `/v1/messages` on its own while OpenAI protocols append\n* `/chat/completions`; without this, one root would work for chat and double\n* the segment for Anthropic.\n*/"
2802
+ },
2803
+ {
2804
+ "before": "const modelProfile = z.object({\n\tid: z.string().required(),\n\t...modelFields\n});",
2805
+ "after": "function applyModelCapabilities(model, defaults) {\n const object = value => value !== null && typeof value === 'object' && !Array.isArray(value);\n const overrides = model.capabilityOverrides;\n if (defaults !== undefined && (!object(defaults) || Object.keys(defaults).some(key => key !== 'vision' && key !== 'reasoning') || typeof defaults.vision !== 'boolean' || typeof defaults.reasoning !== 'boolean')) {\n throw new TypeError('capabilityDefaults must contain only boolean vision and reasoning');\n }\n if (overrides !== undefined && (!object(overrides) || Object.keys(overrides).some(key => key !== 'vision' && key !== 'reasoning') || Object.values(overrides).some(value => typeof value !== 'boolean' && value !== 'original'))) {\n throw new TypeError('capabilityOverrides must contain only boolean or original vision and reasoning');\n }\n const { capabilityOverrides: ignored, ...effective } = model;\n if (defaults === undefined) return effective;\n const choice = key => overrides?.[key] === 'original' ? undefined : overrides?.[key] ?? defaults[key];\n const vision = choice('vision');\n if (vision !== undefined) {\n const input = Array.isArray(model.input) ? [...model.input] : ['text'];\n effective.input = [...new Set(input.filter(value => vision || value !== 'image'))];\n if (effective.input.length === 0) effective.input.push('text');\n if (vision && !effective.input.includes('image')) effective.input.push('image');\n }\n const reasoning = choice('reasoning');\n if (reasoning === false) effective.reasoningEfforts = false;\n if (reasoning === true) {\n const levels = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];\n const efforts = model.reasoningEfforts;\n const valid = object(efforts) && Object.keys(efforts).every(key => levels.includes(key)) && Object.entries(efforts).every(([key, value]) => key === 'off' && value === null || typeof value === 'string' && value.length > 0) && Object.keys(efforts).some(key => key !== 'off');\n effective.reasoningEfforts = valid ? { ...efforts } : { off: null, low: 'low', medium: 'medium', high: 'high' };\n }\n return effective;\n}\nconst capabilityDefaultsProfile = z.union([z.object({ vision: z.boolean().required(), reasoning: z.boolean().required() })]);\nconst capabilityOverridesProfile = z.union([z.object({ vision: z.union([z.boolean(), z.const(\"original\")]), reasoning: z.union([z.boolean(), z.const(\"original\")]) })]);\nconst modelProfile = z.object({\n\tid: z.string().required(),\n\t...modelFields,\n\tcapabilityOverrides: capabilityOverridesProfile\n});"
2806
+ },
2807
+ {
2808
+ "before": "\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tmodels: z.array(modelProfile).required()",
2809
+ "after": "\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tcapabilityDefaults: capabilityDefaultsProfile,\n\tmodels: z.array(modelProfile).required()"
2810
+ },
2811
+ {
2812
+ "before": "\t\tassertWireModels(source.models, \"models\");",
2813
+ "after": "\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const model of source.models ?? []) applyModelCapabilities(model);"
2814
+ },
2815
+ {
2816
+ "before": "\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);",
2817
+ "after": "\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t\tapplyModelCapabilities({}, entry.capabilityDefaults);\n\t\t\tfor (const model of entry.models) applyModelCapabilities(model, entry.capabilityDefaults);"
2818
+ },
2819
+ {
2820
+ "before": "\t\t\t\tmodels: entry.models,",
2821
+ "after": "\t\t\t\tmodels: entry.models.map(model => applyModelCapabilities(model, entry.capabilityDefaults)),"
2822
+ }
2823
+ ]
1186
2824
  },
1187
2825
  {
1188
2826
  "source": "npm official 0.2.2-rc.1 with per-entry API overrides",
1189
2827
  "baseSha256": "1a3ae58f9b4493e15459cc5000ec80f21b5d3f4a9dea6ffb6bc28e5b8817ae8a",
1190
- "resultSha256": "2e00ea0c1b447153e341a1ca675ed6a829094c7caf62c6524e6809bd6540be71",
2828
+ "resultSha256": "0206db4d8c2aed56f905edc893541efe519aade4ed65173fc1051d4c41f883fc",
2829
+ "current": true
2830
+ },
2831
+ {
2832
+ "source": "0.2.2-rc.1 with tool lookup optimization and credential cancellation with per-entry API overrides",
2833
+ "baseSha256": "0a99a2fc903a4285044b09114b3bd20ee1e612f39aa381e4a71b10d48ee9e9f7",
2834
+ "resultSha256": "e6cb26e24b4f29dc9eefa8b10a70d3887b698d41479a60e11cfba5c0609250a4",
1191
2835
  "current": true
1192
2836
  }
1193
2837
  ],
@@ -1270,11 +2914,11 @@
1270
2914
  },
1271
2915
  {
1272
2916
  "before": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});",
1273
- "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tmodels: z.array(modelProfile).required()\n});"
2917
+ "after": "\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tapi: z.union(supportedProtocols()),\n\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tmodels: z.array(modelProfile).required()\n});"
1274
2918
  },
1275
2919
  {
1276
2920
  "before": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models))",
1277
- "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (!Array.isArray(entry.models))"
2921
+ "after": "\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (entry.api !== void 0 && !supportedProtocols().includes(entry.api)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" api must be a supported protocol`);\n\t\t\tif (entry.sortOrder !== void 0 && (!Number.isSafeInteger(entry.sortOrder) || entry.sortOrder < 0)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" sortOrder must be a nonnegative safe integer`);\n\t\t\tif (!Array.isArray(entry.models))"
1278
2922
  },
1279
2923
  {
1280
2924
  "before": "\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,",
@@ -1311,6 +2955,26 @@
1311
2955
  {
1312
2956
  "before": "* gateway documentation publishes both spellings of the same root. Only this\n* listing URL normalizes that segment; model requests receive the configured\n* `baseURL` unchanged.\n*/",
1313
2957
  "after": "* gateway documentation publishes both spellings of the same root. Anthropic\n* listings and model requests both normalize it, because the Anthropic SDK\n* appends `/v1/messages` on its own while OpenAI protocols append\n* `/chat/completions`; without this, one root would work for chat and double\n* the segment for Anthropic.\n*/"
2958
+ },
2959
+ {
2960
+ "before": "const modelProfile = z.object({\n\tid: z.string().required(),\n\t...modelFields\n});",
2961
+ "after": "function applyModelCapabilities(model, defaults) {\n const object = value => value !== null && typeof value === 'object' && !Array.isArray(value);\n const overrides = model.capabilityOverrides;\n if (defaults !== undefined && (!object(defaults) || Object.keys(defaults).some(key => key !== 'vision' && key !== 'reasoning') || typeof defaults.vision !== 'boolean' || typeof defaults.reasoning !== 'boolean')) {\n throw new TypeError('capabilityDefaults must contain only boolean vision and reasoning');\n }\n if (overrides !== undefined && (!object(overrides) || Object.keys(overrides).some(key => key !== 'vision' && key !== 'reasoning') || Object.values(overrides).some(value => typeof value !== 'boolean' && value !== 'original'))) {\n throw new TypeError('capabilityOverrides must contain only boolean or original vision and reasoning');\n }\n const { capabilityOverrides: ignored, ...effective } = model;\n if (defaults === undefined) return effective;\n const choice = key => overrides?.[key] === 'original' ? undefined : overrides?.[key] ?? defaults[key];\n const vision = choice('vision');\n if (vision !== undefined) {\n const input = Array.isArray(model.input) ? [...model.input] : ['text'];\n effective.input = [...new Set(input.filter(value => vision || value !== 'image'))];\n if (effective.input.length === 0) effective.input.push('text');\n if (vision && !effective.input.includes('image')) effective.input.push('image');\n }\n const reasoning = choice('reasoning');\n if (reasoning === false) effective.reasoningEfforts = false;\n if (reasoning === true) {\n const levels = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];\n const efforts = model.reasoningEfforts;\n const valid = object(efforts) && Object.keys(efforts).every(key => levels.includes(key)) && Object.entries(efforts).every(([key, value]) => key === 'off' && value === null || typeof value === 'string' && value.length > 0) && Object.keys(efforts).some(key => key !== 'off');\n effective.reasoningEfforts = valid ? { ...efforts } : { off: null, low: 'low', medium: 'medium', high: 'high' };\n }\n return effective;\n}\nfunction validateCapabilityBatch(batch) {\n if (batch !== undefined && (batch === null || typeof batch !== 'object' || Array.isArray(batch) || Object.keys(batch).some(key => key !== 'vision' && key !== 'reasoning') || Object.values(batch).some(value => typeof value !== 'boolean'))) {\n throw new TypeError('capabilityBatch must contain only boolean vision and reasoning');\n }\n return batch;\n}\nconst capabilityBatchProfile = z.union([z.object({ vision: z.boolean(), reasoning: z.boolean() })]);\nconst capabilityDefaultsProfile = z.union([z.object({ vision: z.boolean().required(), reasoning: z.boolean().required() })]);\nconst capabilityOverridesProfile = z.union([z.object({ vision: z.union([z.boolean(), z.const(\"original\")]), reasoning: z.union([z.boolean(), z.const(\"original\")]) })]);\nconst modelProfile = z.object({\n\tid: z.string().required(),\n\t...modelFields,\n\tcapabilityOverrides: capabilityOverridesProfile\n});"
2962
+ },
2963
+ {
2964
+ "before": "\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tmodels: z.array(modelProfile).required()",
2965
+ "after": "\tsortOrder: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER),\n\tcapabilityDefaults: capabilityDefaultsProfile,\n\tcapabilityBatch: capabilityBatchProfile,\n\tmodels: z.array(modelProfile).required()"
2966
+ },
2967
+ {
2968
+ "before": "\t\tassertWireModels(source.models, \"models\");",
2969
+ "after": "\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const model of source.models ?? []) applyModelCapabilities(model);"
2970
+ },
2971
+ {
2972
+ "before": "\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);",
2973
+ "after": "\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t\tapplyModelCapabilities({}, entry.capabilityDefaults);\n\t\t\tvalidateCapabilityBatch(entry.capabilityBatch);\n\t\t\tfor (const model of entry.models) applyModelCapabilities(model, entry.capabilityDefaults);"
2974
+ },
2975
+ {
2976
+ "before": "\t\t\t\tmodels: entry.models,",
2977
+ "after": "\t\t\t\tmodels: entry.models.map(model => applyModelCapabilities(model, entry.capabilityDefaults)),"
1314
2978
  }
1315
2979
  ],
1316
2980
  "current": true,