pi2dsh 0.7.0 → 0.8.0

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.
Files changed (100) hide show
  1. package/README.md +1 -1
  2. package/README.zh.md +1 -1
  3. package/dist/analyzer-CKTsWVzn.mjs +628 -0
  4. package/dist/analyzer-CKTsWVzn.mjs.map +1 -0
  5. package/dist/cli.mjs +3 -1
  6. package/dist/cli.mjs.map +1 -1
  7. package/dist/compat/pi-ai.d.mts +1 -11
  8. package/dist/compat/pi-ai.d.mts.map +1 -1
  9. package/dist/compat/pi-ai.mjs +2 -2
  10. package/dist/credentials-oauth.mjs +1 -1
  11. package/dist/generator-eyViezvs.mjs +300 -0
  12. package/dist/generator-eyViezvs.mjs.map +1 -0
  13. package/dist/host.d.mts +2 -0
  14. package/dist/host.d.mts.map +1 -1
  15. package/dist/host.mjs +2 -1
  16. package/dist/host.mjs.map +1 -1
  17. package/dist/index.d.mts +28 -10
  18. package/dist/index.d.mts.map +1 -1
  19. package/dist/index.mjs +27 -4
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/mcp-config-Dlou-ZA-.mjs +707 -0
  22. package/dist/mcp-config-Dlou-ZA-.mjs.map +1 -0
  23. package/dist/{pi-ai-B4hucafU.mjs → pi-ai-C6Xag6xt.mjs} +2 -74
  24. package/dist/pi-ai-C6Xag6xt.mjs.map +1 -0
  25. package/dist/{runtime-k3IlCgjQ.mjs → runtime-B-Mun-jX.mjs} +44 -947
  26. package/dist/runtime-B-Mun-jX.mjs.map +1 -0
  27. package/dist/runtime.d.mts +11 -6
  28. package/dist/runtime.d.mts.map +1 -1
  29. package/dist/runtime.mjs +2 -2
  30. package/package.json +6 -3
  31. package/dist/all-BChhwMVE.mjs +0 -28512
  32. package/dist/all-BChhwMVE.mjs.map +0 -1
  33. package/dist/anthropic-messages-Dlw4T0S4.mjs +0 -6438
  34. package/dist/anthropic-messages-Dlw4T0S4.mjs.map +0 -1
  35. package/dist/azure-openai-responses-vGUNukZ7.mjs +0 -209
  36. package/dist/azure-openai-responses-vGUNukZ7.mjs.map +0 -1
  37. package/dist/deferred-tools-BD4g5QUx.mjs +0 -32
  38. package/dist/deferred-tools-BD4g5QUx.mjs.map +0 -1
  39. package/dist/diagnostics-CJye1UFh.mjs +0 -99
  40. package/dist/diagnostics-CJye1UFh.mjs.map +0 -1
  41. package/dist/dist-DY2GeEQ6.mjs +0 -1089
  42. package/dist/dist-DY2GeEQ6.mjs.map +0 -1
  43. package/dist/dist-DYfTHu0C.mjs +0 -1246
  44. package/dist/dist-DYfTHu0C.mjs.map +0 -1
  45. package/dist/error-body-DKA3lknR.mjs +0 -104
  46. package/dist/error-body-DKA3lknR.mjs.map +0 -1
  47. package/dist/github-copilot-headers-CZo2QHrt.mjs +0 -25
  48. package/dist/github-copilot-headers-CZo2QHrt.mjs.map +0 -1
  49. package/dist/google-generative-ai-C30gRjRi.mjs +0 -358
  50. package/dist/google-generative-ai-C30gRjRi.mjs.map +0 -1
  51. package/dist/google-shared-W8g3Esep.mjs +0 -29042
  52. package/dist/google-shared-W8g3Esep.mjs.map +0 -1
  53. package/dist/google-vertex--O_gyVYA.mjs +0 -402
  54. package/dist/google-vertex--O_gyVYA.mjs.map +0 -1
  55. package/dist/hash-Dbggamac.mjs +0 -19
  56. package/dist/hash-Dbggamac.mjs.map +0 -1
  57. package/dist/headers-CPzZhJQn.mjs +0 -17
  58. package/dist/headers-CPzZhJQn.mjs.map +0 -1
  59. package/dist/images-models-DJtHo9Rp.mjs +0 -1068
  60. package/dist/images-models-DJtHo9Rp.mjs.map +0 -1
  61. package/dist/json-parse-C-vG4_qc.mjs +0 -384
  62. package/dist/json-parse-C-vG4_qc.mjs.map +0 -1
  63. package/dist/mcp-config-Cful6uUS.mjs +0 -1618
  64. package/dist/mcp-config-Cful6uUS.mjs.map +0 -1
  65. package/dist/mistral-conversations-LSDG9sjq.mjs +0 -42007
  66. package/dist/mistral-conversations-LSDG9sjq.mjs.map +0 -1
  67. package/dist/multipart-parser-CoM3rwav.mjs +0 -301
  68. package/dist/multipart-parser-CoM3rwav.mjs.map +0 -1
  69. package/dist/openai-codex-responses-JxII_OUX.mjs +0 -1169
  70. package/dist/openai-codex-responses-JxII_OUX.mjs.map +0 -1
  71. package/dist/openai-completions-Dp-VwLzJ.mjs +0 -947
  72. package/dist/openai-completions-Dp-VwLzJ.mjs.map +0 -1
  73. package/dist/openai-completions-lite-BrM7gJzs.mjs +0 -316
  74. package/dist/openai-completions-lite-BrM7gJzs.mjs.map +0 -1
  75. package/dist/openai-prompt-cache-BDWtZRKh.mjs +0 -11
  76. package/dist/openai-prompt-cache-BDWtZRKh.mjs.map +0 -1
  77. package/dist/openai-responses-CWmNks8K.mjs +0 -247
  78. package/dist/openai-responses-CWmNks8K.mjs.map +0 -1
  79. package/dist/openai-responses-shared-CYgIDTf3.mjs +0 -572
  80. package/dist/openai-responses-shared-CYgIDTf3.mjs.map +0 -1
  81. package/dist/openrouter-images-DfAULV7l.mjs +0 -127
  82. package/dist/openrouter-images-DfAULV7l.mjs.map +0 -1
  83. package/dist/otel-Boafyju5.mjs +0 -24935
  84. package/dist/otel-Boafyju5.mjs.map +0 -1
  85. package/dist/pi-ai-B4hucafU.mjs.map +0 -1
  86. package/dist/pi-messages-HzGtvc5_.mjs +0 -306
  87. package/dist/pi-messages-HzGtvc5_.mjs.map +0 -1
  88. package/dist/provider-env-C9gOBFJi.mjs +0 -40
  89. package/dist/provider-env-C9gOBFJi.mjs.map +0 -1
  90. package/dist/provider-retry-Cw6YJ4cr.mjs +0 -80
  91. package/dist/provider-retry-Cw6YJ4cr.mjs.map +0 -1
  92. package/dist/runtime-k3IlCgjQ.mjs.map +0 -1
  93. package/dist/sanitize-unicode-wLA11KvZ.mjs +0 -29
  94. package/dist/sanitize-unicode-wLA11KvZ.mjs.map +0 -1
  95. package/dist/src-D0GRWCE8.mjs +0 -5031
  96. package/dist/src-D0GRWCE8.mjs.map +0 -1
  97. package/dist/transform-messages-DGq9mvhA.mjs +0 -379
  98. package/dist/transform-messages-DGq9mvhA.mjs.map +0 -1
  99. package/dist/uuid-DtFT7tOE.mjs +0 -65
  100. package/dist/uuid-DtFT7tOE.mjs.map +0 -1
@@ -1,6 +1,6 @@
1
1
 
2
- import { C as realBuiltinProvider, R as AssistantMessageEventStream, S as openAIResponsesApi, a as builtinProviders, i as anthropicMessagesApi, r as __setPiAiLlmBridge, x as openAICompletionsApi } from "./pi-ai-B4hucafU.mjs";
3
- import { r as normalizePath, t as getAgentDir } from "./pi-config-shim-CZ1wFzqM.mjs";
2
+ import { P as AssistantMessageEventStream, i as builtinProviders, r as __setPiAiLlmBridge } from "./pi-ai-C6Xag6xt.mjs";
3
+ import { t as getAgentDir } from "./pi-config-shim-CZ1wFzqM.mjs";
4
4
  import { E as __setSubagentSessionFactory, S as Theme, f as ExtensionRunner } from "./pi-coding-agent-CznNsOnV.mjs";
5
5
  import { a as resolvePiProviderAuth, n as loginPiProvider, r as providerSupportsOAuth, t as FileCredentialStore } from "./oauth-bridge-CfyImWx4.mjs";
6
6
  import { createRequire } from "node:module";
@@ -15,9 +15,6 @@ import { createJiti } from "jiti";
15
15
  import { createUserMessage } from "@deepseek-ai/dsh-llm";
16
16
  import { renderPrompt } from "@deepseek-ai/dsh-system-prompt";
17
17
  import { randomUUID } from "node:crypto";
18
- import { execSync, spawnSync } from "child_process";
19
- import { Type } from "typebox";
20
- import { Compile } from "typebox/compile";
21
18
  //#region src/session-bridge.ts
22
19
  function sidecarDir() {
23
20
  return join(getAgentDir(), "session-entries");
@@ -1114,834 +1111,7 @@ async function* piEventsToDshChunks(events) {
1114
1111
  };
1115
1112
  }
1116
1113
  //#endregion
1117
- //#region src/compat/vendor/pi-json.ts
1118
- /** Strip `//` line comments and trailing commas from JSON, leaving string literals untouched. */
1119
- function stripJsonComments(input) {
1120
- return input.replace(/"(?:\\.|[^"\\])*"|\/\/[^\n]*/g, (m) => m[0] === "\"" ? m : "").replace(/"(?:\\.|[^"\\])*"|,(\s*[}\]])/g, (m, tail) => tail ?? (m[0] === "\"" ? m : ""));
1121
- }
1122
- //#endregion
1123
- //#region src/compat/vendor/pi-model-config.ts
1124
- /** Immutable, credential-blind models.json snapshot. */
1125
- const PercentileCutoffsSchema = Type.Object({
1126
- p50: Type.Optional(Type.Number()),
1127
- p75: Type.Optional(Type.Number()),
1128
- p90: Type.Optional(Type.Number()),
1129
- p99: Type.Optional(Type.Number())
1130
- });
1131
- const OpenRouterRoutingSchema = Type.Object({
1132
- allow_fallbacks: Type.Optional(Type.Boolean()),
1133
- require_parameters: Type.Optional(Type.Boolean()),
1134
- data_collection: Type.Optional(Type.Union([Type.Literal("deny"), Type.Literal("allow")])),
1135
- zdr: Type.Optional(Type.Boolean()),
1136
- enforce_distillable_text: Type.Optional(Type.Boolean()),
1137
- order: Type.Optional(Type.Array(Type.String())),
1138
- only: Type.Optional(Type.Array(Type.String())),
1139
- ignore: Type.Optional(Type.Array(Type.String())),
1140
- quantizations: Type.Optional(Type.Array(Type.String())),
1141
- sort: Type.Optional(Type.Union([Type.String(), Type.Object({
1142
- by: Type.Optional(Type.String()),
1143
- partition: Type.Optional(Type.Union([Type.String(), Type.Null()]))
1144
- })])),
1145
- max_price: Type.Optional(Type.Object({
1146
- prompt: Type.Optional(Type.Union([Type.Number(), Type.String()])),
1147
- completion: Type.Optional(Type.Union([Type.Number(), Type.String()])),
1148
- image: Type.Optional(Type.Union([Type.Number(), Type.String()])),
1149
- audio: Type.Optional(Type.Union([Type.Number(), Type.String()])),
1150
- request: Type.Optional(Type.Union([Type.Number(), Type.String()]))
1151
- })),
1152
- preferred_min_throughput: Type.Optional(Type.Union([Type.Number(), PercentileCutoffsSchema])),
1153
- preferred_max_latency: Type.Optional(Type.Union([Type.Number(), PercentileCutoffsSchema]))
1154
- });
1155
- const VercelGatewayRoutingSchema = Type.Object({
1156
- only: Type.Optional(Type.Array(Type.String())),
1157
- order: Type.Optional(Type.Array(Type.String()))
1158
- });
1159
- const ThinkingLevelMapValueSchema = Type.Union([Type.String(), Type.Null()]);
1160
- const ThinkingLevelMapSchema = Type.Object({
1161
- off: Type.Optional(ThinkingLevelMapValueSchema),
1162
- minimal: Type.Optional(ThinkingLevelMapValueSchema),
1163
- low: Type.Optional(ThinkingLevelMapValueSchema),
1164
- medium: Type.Optional(ThinkingLevelMapValueSchema),
1165
- high: Type.Optional(ThinkingLevelMapValueSchema),
1166
- xhigh: Type.Optional(ThinkingLevelMapValueSchema),
1167
- max: Type.Optional(ThinkingLevelMapValueSchema)
1168
- });
1169
- const ChatTemplateKwargScalarSchema = Type.Union([
1170
- Type.String(),
1171
- Type.Number(),
1172
- Type.Boolean(),
1173
- Type.Null()
1174
- ]);
1175
- const ChatTemplateKwargVariableSchema = Type.Object({
1176
- $var: Type.Union([Type.Literal("thinking.enabled"), Type.Literal("thinking.effort")]),
1177
- omitWhenOff: Type.Optional(Type.Boolean())
1178
- });
1179
- const ChatTemplateKwargSchema = Type.Union([ChatTemplateKwargScalarSchema, ChatTemplateKwargVariableSchema]);
1180
- const OpenAICompletionsCompatSchema = Type.Object({
1181
- supportsStore: Type.Optional(Type.Boolean()),
1182
- supportsDeveloperRole: Type.Optional(Type.Boolean()),
1183
- supportsReasoningEffort: Type.Optional(Type.Boolean()),
1184
- supportsUsageInStreaming: Type.Optional(Type.Boolean()),
1185
- maxTokensField: Type.Optional(Type.Union([Type.Literal("max_completion_tokens"), Type.Literal("max_tokens")])),
1186
- requiresToolResultName: Type.Optional(Type.Boolean()),
1187
- requiresAssistantAfterToolResult: Type.Optional(Type.Boolean()),
1188
- requiresThinkingAsText: Type.Optional(Type.Boolean()),
1189
- requiresReasoningContentOnAssistantMessages: Type.Optional(Type.Boolean()),
1190
- thinkingFormat: Type.Optional(Type.Union([
1191
- Type.Literal("openai"),
1192
- Type.Literal("openrouter"),
1193
- Type.Literal("together"),
1194
- Type.Literal("baseten"),
1195
- Type.Literal("deepseek"),
1196
- Type.Literal("zai"),
1197
- Type.Literal("qwen"),
1198
- Type.Literal("chat-template"),
1199
- Type.Literal("qwen-chat-template"),
1200
- Type.Literal("string-thinking"),
1201
- Type.Literal("ant-ling")
1202
- ])),
1203
- chatTemplateKwargs: Type.Optional(Type.Record(Type.String(), ChatTemplateKwargSchema)),
1204
- chatTemplateArgs: Type.Optional(Type.Record(Type.String(), ChatTemplateKwargSchema)),
1205
- cacheControlFormat: Type.Optional(Type.Literal("anthropic")),
1206
- openRouterRouting: Type.Optional(OpenRouterRoutingSchema),
1207
- vercelGatewayRouting: Type.Optional(VercelGatewayRoutingSchema),
1208
- supportsOpenAIGrammarTools: Type.Optional(Type.Boolean()),
1209
- supportsStrictMode: Type.Optional(Type.Boolean()),
1210
- sendSessionAffinityHeaders: Type.Optional(Type.Boolean()),
1211
- deferredToolsMode: Type.Optional(Type.Literal("kimi")),
1212
- sessionAffinityFormat: Type.Optional(Type.Union([
1213
- Type.Literal("openai"),
1214
- Type.Literal("openai-nosession"),
1215
- Type.Literal("openrouter")
1216
- ])),
1217
- supportsLongCacheRetention: Type.Optional(Type.Boolean())
1218
- });
1219
- const OpenAIResponsesCompatSchema = Type.Object({
1220
- supportsDeveloperRole: Type.Optional(Type.Boolean()),
1221
- sessionAffinityFormat: Type.Optional(Type.Union([
1222
- Type.Literal("openai"),
1223
- Type.Literal("openai-nosession"),
1224
- Type.Literal("openrouter")
1225
- ])),
1226
- supportsLongCacheRetention: Type.Optional(Type.Boolean()),
1227
- supportsStrictMode: Type.Optional(Type.Boolean()),
1228
- supportsOpenAIGrammarTools: Type.Optional(Type.Boolean()),
1229
- supportsAdditionalTools: Type.Optional(Type.Boolean()),
1230
- supportsToolSearch: Type.Optional(Type.Boolean())
1231
- });
1232
- const AnthropicMessagesCompatSchema = Type.Object({
1233
- supportsEagerToolInputStreaming: Type.Optional(Type.Boolean()),
1234
- supportsLongCacheRetention: Type.Optional(Type.Boolean()),
1235
- sendSessionAffinityHeaders: Type.Optional(Type.Boolean()),
1236
- supportsCacheControlOnTools: Type.Optional(Type.Boolean()),
1237
- supportsTemperature: Type.Optional(Type.Boolean()),
1238
- forceAdaptiveThinking: Type.Optional(Type.Boolean()),
1239
- allowEmptySignature: Type.Optional(Type.Boolean()),
1240
- supportsStrictTools: Type.Optional(Type.Boolean()),
1241
- supportsToolReferences: Type.Optional(Type.Boolean())
1242
- });
1243
- const ProviderCompatSchema = Type.Union([
1244
- OpenAICompletionsCompatSchema,
1245
- OpenAIResponsesCompatSchema,
1246
- AnthropicMessagesCompatSchema
1247
- ]);
1248
- const ModelCostRatesSchema = {
1249
- input: Type.Number(),
1250
- output: Type.Number(),
1251
- cacheRead: Type.Number(),
1252
- cacheWrite: Type.Number()
1253
- };
1254
- const ModelCostTierSchema = Type.Object({
1255
- inputTokensAbove: Type.Number(),
1256
- ...ModelCostRatesSchema
1257
- });
1258
- const ModelCostSchema = Type.Object({
1259
- ...ModelCostRatesSchema,
1260
- tiers: Type.Optional(Type.Array(ModelCostTierSchema))
1261
- });
1262
- const ModelDefinitionSchema = Type.Object({
1263
- id: Type.String({ minLength: 1 }),
1264
- name: Type.Optional(Type.String({ minLength: 1 })),
1265
- api: Type.Optional(Type.String({ minLength: 1 })),
1266
- baseUrl: Type.Optional(Type.String({ minLength: 1 })),
1267
- reasoning: Type.Optional(Type.Boolean()),
1268
- thinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),
1269
- input: Type.Optional(Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")]))),
1270
- cost: Type.Optional(ModelCostSchema),
1271
- contextWindow: Type.Optional(Type.Number()),
1272
- maxTokens: Type.Optional(Type.Number()),
1273
- samplingParams: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
1274
- headers: Type.Optional(Type.Record(Type.String(), Type.String())),
1275
- compat: Type.Optional(ProviderCompatSchema)
1276
- });
1277
- const ModelOverrideSchema = Type.Object({
1278
- name: Type.Optional(Type.String({ minLength: 1 })),
1279
- reasoning: Type.Optional(Type.Boolean()),
1280
- thinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),
1281
- input: Type.Optional(Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")]))),
1282
- cost: Type.Optional(Type.Object({
1283
- input: Type.Optional(Type.Number()),
1284
- output: Type.Optional(Type.Number()),
1285
- cacheRead: Type.Optional(Type.Number()),
1286
- cacheWrite: Type.Optional(Type.Number()),
1287
- tiers: Type.Optional(Type.Array(ModelCostTierSchema))
1288
- })),
1289
- contextWindow: Type.Optional(Type.Number()),
1290
- maxTokens: Type.Optional(Type.Number()),
1291
- samplingParams: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
1292
- headers: Type.Optional(Type.Record(Type.String(), Type.String())),
1293
- compat: Type.Optional(ProviderCompatSchema)
1294
- });
1295
- const ProviderConfigSchema = Type.Object({
1296
- name: Type.Optional(Type.String({ minLength: 1 })),
1297
- baseUrl: Type.Optional(Type.String({ minLength: 1 })),
1298
- apiKey: Type.Optional(Type.String({ minLength: 1 })),
1299
- api: Type.Optional(Type.String({ minLength: 1 })),
1300
- oauth: Type.Optional(Type.Literal("radius")),
1301
- headers: Type.Optional(Type.Record(Type.String(), Type.String())),
1302
- compat: Type.Optional(ProviderCompatSchema),
1303
- authHeader: Type.Optional(Type.Boolean()),
1304
- models: Type.Optional(Type.Array(ModelDefinitionSchema)),
1305
- modelOverrides: Type.Optional(Type.Record(Type.String(), ModelOverrideSchema))
1306
- });
1307
- const ModelsConfigSchema = Type.Object({ providers: Type.Record(Type.String(), ProviderConfigSchema) });
1308
- const validateModelsConfig = Compile(ModelsConfigSchema);
1309
- function formatValidationPath(error) {
1310
- if (error.keyword === "required") {
1311
- const requiredProperty = error.params.requiredProperties?.[0];
1312
- if (requiredProperty) {
1313
- const basePath = error.instancePath.replace(/^\//, "").replace(/\//g, ".");
1314
- return basePath ? `${basePath}.${requiredProperty}` : requiredProperty;
1315
- }
1316
- }
1317
- return error.instancePath.replace(/^\//, "").replace(/\//g, ".") || "root";
1318
- }
1319
- function deepFreeze(value) {
1320
- if (typeof value !== "object" || value === null || Object.isFrozen(value)) return value;
1321
- for (const child of Object.values(value)) deepFreeze(child);
1322
- return Object.freeze(value);
1323
- }
1324
- /** One immutable load of models.json. */
1325
- var ModelConfig = class ModelConfig {
1326
- providers;
1327
- error;
1328
- constructor(providers, error) {
1329
- this.providers = providers;
1330
- this.error = error;
1331
- }
1332
- static async load(modelsJsonPath) {
1333
- if (!modelsJsonPath) return new ModelConfig(/* @__PURE__ */ new Map());
1334
- const path = normalizePath(modelsJsonPath);
1335
- let content;
1336
- try {
1337
- content = await readFile(path, "utf-8");
1338
- } catch (error) {
1339
- if (error.code === "ENOENT") return new ModelConfig(/* @__PURE__ */ new Map());
1340
- return new ModelConfig(/* @__PURE__ */ new Map(), `Failed to load models.json: ${error instanceof Error ? error.message : error}\n\nFile: ${path}`);
1341
- }
1342
- let parsed;
1343
- try {
1344
- parsed = JSON.parse(stripJsonComments(content));
1345
- } catch (error) {
1346
- return new ModelConfig(/* @__PURE__ */ new Map(), `Failed to parse models.json: ${error instanceof Error ? error.message : error}\n\nFile: ${path}`);
1347
- }
1348
- if (!validateModelsConfig.Check(parsed)) {
1349
- const errors = validateModelsConfig.Errors(parsed).map((error) => ` - ${formatValidationPath(error)}: ${error.message}`).join("\n") || "Unknown schema error";
1350
- return new ModelConfig(/* @__PURE__ */ new Map(), `Invalid models.json schema:\n${errors}\n\nFile: ${path}`);
1351
- }
1352
- const config = parsed;
1353
- const providers = /* @__PURE__ */ new Map();
1354
- for (const [providerId, provider] of Object.entries(config.providers)) providers.set(providerId, deepFreeze(structuredClone(provider)));
1355
- return new ModelConfig(providers);
1356
- }
1357
- getProvider(providerId) {
1358
- return this.providers.get(providerId);
1359
- }
1360
- getProviderIds() {
1361
- return [...this.providers.keys()];
1362
- }
1363
- getError() {
1364
- return this.error;
1365
- }
1366
- };
1367
- //#endregion
1368
- //#region src/compat/vendor/pi-models-compose.ts
1369
- function mergeCompat(base, override) {
1370
- if (!override) return base;
1371
- const merged = {
1372
- ...base,
1373
- ...override
1374
- };
1375
- const baseNested = base;
1376
- const overrideNested = override;
1377
- const mergedNested = merged;
1378
- for (const key of [
1379
- "openRouterRouting",
1380
- "vercelGatewayRouting",
1381
- "chatTemplateKwargs",
1382
- "chatTemplateArgs"
1383
- ]) {
1384
- const baseValue = baseNested?.[key];
1385
- const overrideValue = overrideNested[key];
1386
- if (typeof baseValue === "object" && baseValue !== null || typeof overrideValue === "object" && overrideValue !== null) mergedNested[key] = {
1387
- ...baseValue,
1388
- ...overrideValue
1389
- };
1390
- }
1391
- return merged;
1392
- }
1393
- function applyModelOverride(model, override) {
1394
- return {
1395
- ...model,
1396
- name: override.name ?? model.name,
1397
- reasoning: override.reasoning ?? model.reasoning,
1398
- thinkingLevelMap: override.thinkingLevelMap ? {
1399
- ...model.thinkingLevelMap,
1400
- ...override.thinkingLevelMap
1401
- } : model.thinkingLevelMap,
1402
- input: override.input ?? model.input,
1403
- cost: override.cost ? {
1404
- input: override.cost.input ?? model.cost.input,
1405
- output: override.cost.output ?? model.cost.output,
1406
- cacheRead: override.cost.cacheRead ?? model.cost.cacheRead,
1407
- cacheWrite: override.cost.cacheWrite ?? model.cost.cacheWrite,
1408
- tiers: override.cost.tiers ?? model.cost.tiers
1409
- } : model.cost,
1410
- contextWindow: override.contextWindow ?? model.contextWindow,
1411
- maxTokens: override.maxTokens ?? model.maxTokens,
1412
- samplingParams: override.samplingParams ? {
1413
- ...model.samplingParams,
1414
- ...override.samplingParams
1415
- } : model.samplingParams,
1416
- compat: mergeCompat(model.compat, override.compat)
1417
- };
1418
- }
1419
- function modelFromJson(providerId, definition, providerConfig, defaults) {
1420
- const api = definition.api ?? providerConfig.api ?? defaults?.api;
1421
- if (!api) throw new Error(`Provider ${providerId}, model ${definition.id}: no "api" specified. Set at provider or model level.`);
1422
- const baseUrl = definition.baseUrl ?? providerConfig.baseUrl ?? defaults?.baseUrl;
1423
- if (!baseUrl) throw new Error(`Provider ${providerId}: "baseUrl" is required when defining custom models.`);
1424
- if (definition.contextWindow !== void 0 && definition.contextWindow <= 0) throw new Error(`Provider ${providerId}, model ${definition.id}: invalid contextWindow`);
1425
- if (definition.maxTokens !== void 0 && definition.maxTokens <= 0) throw new Error(`Provider ${providerId}, model ${definition.id}: invalid maxTokens`);
1426
- return {
1427
- id: definition.id,
1428
- name: definition.name ?? definition.id,
1429
- api,
1430
- provider: providerId,
1431
- baseUrl,
1432
- reasoning: definition.reasoning ?? false,
1433
- thinkingLevelMap: definition.thinkingLevelMap,
1434
- input: definition.input ?? ["text"],
1435
- cost: definition.cost ?? {
1436
- input: 0,
1437
- output: 0,
1438
- cacheRead: 0,
1439
- cacheWrite: 0
1440
- },
1441
- contextWindow: definition.contextWindow ?? 128e3,
1442
- maxTokens: definition.maxTokens ?? 16384,
1443
- samplingParams: definition.samplingParams,
1444
- headers: void 0,
1445
- compat: mergeCompat(providerConfig.compat, definition.compat)
1446
- };
1447
- }
1448
- function applyModelsJson(providerId, baseModels, config) {
1449
- if (!config) return [...baseModels];
1450
- if (config.oauth && !config.baseUrl) throw new Error(`Provider ${providerId}: "baseUrl" is required when "oauth" is set.`);
1451
- const hasOverrides = config.modelOverrides && Object.keys(config.modelOverrides).length > 0;
1452
- if (!config.models?.length && !config.baseUrl && !config.headers && !config.compat && !hasOverrides && !config.apiKey && !config.oauth && config.authHeader === void 0) throw new Error(`Provider ${providerId}: must specify "baseUrl", "headers", "compat", "modelOverrides", or "models".`);
1453
- const models = baseModels.map((model) => ({
1454
- ...model,
1455
- baseUrl: config.oauth === "radius" ? model.baseUrl : config.baseUrl ?? model.baseUrl,
1456
- compat: mergeCompat(model.compat, config.compat)
1457
- }));
1458
- for (const definition of config.models ?? []) {
1459
- const existingIndex = models.findIndex((model) => model.id === definition.id);
1460
- const model = modelFromJson(providerId, definition, config, existingIndex >= 0 ? models[existingIndex] : models[0]);
1461
- if (existingIndex >= 0) models[existingIndex] = model;
1462
- else models.push(model);
1463
- }
1464
- return models;
1465
- }
1466
- //#endregion
1467
- //#region src/compat/vendor/pi-shell-config.ts
1468
- function isLegacyWslBashPath(path) {
1469
- const normalized = path.replace(/\//g, "\\").toLowerCase();
1470
- return /^[a-z]:\\windows\\(?:system32|sysnative)\\bash\.exe$/.test(normalized);
1471
- }
1472
- function getBashShellConfig(shell) {
1473
- return isLegacyWslBashPath(shell) ? {
1474
- shell,
1475
- args: ["-s"],
1476
- commandTransport: "stdin"
1477
- } : {
1478
- shell,
1479
- args: ["-c"]
1480
- };
1481
- }
1482
- function findBashOnPath() {
1483
- if (process.platform === "win32") {
1484
- try {
1485
- const result = spawnSync("where", ["bash.exe"], {
1486
- encoding: "utf-8",
1487
- timeout: 5e3,
1488
- windowsHide: true
1489
- });
1490
- if (result.status === 0 && result.stdout) {
1491
- const firstMatch = result.stdout.trim().split(/\r?\n/)[0];
1492
- if (firstMatch && existsSync(firstMatch)) return firstMatch;
1493
- }
1494
- } catch {}
1495
- return null;
1496
- }
1497
- try {
1498
- const result = spawnSync("which", ["bash"], {
1499
- encoding: "utf-8",
1500
- timeout: 5e3
1501
- });
1502
- if (result.status === 0 && result.stdout) {
1503
- const firstMatch = result.stdout.trim().split(/\r?\n/)[0];
1504
- if (firstMatch) return firstMatch;
1505
- }
1506
- } catch {}
1507
- return null;
1508
- }
1509
- /**
1510
- * Resolve shell configuration based on platform and an optional explicit shell path.
1511
- * Resolution order:
1512
- * 1. User-specified shellPath
1513
- * 2. On Windows: Git Bash in known locations, then bash on PATH
1514
- * 3. On Unix: /bin/bash, then bash on PATH, then fallback to sh
1515
- */
1516
- function getShellConfig(customShellPath) {
1517
- if (customShellPath) {
1518
- if (existsSync(customShellPath)) return getBashShellConfig(customShellPath);
1519
- throw new Error(`Custom shell path not found: ${customShellPath}`);
1520
- }
1521
- if (process.platform === "win32") {
1522
- const paths = [];
1523
- const programFiles = process.env.ProgramFiles;
1524
- if (programFiles) paths.push(`${programFiles}\\Git\\bin\\bash.exe`);
1525
- const programFilesX86 = process.env["ProgramFiles(x86)"];
1526
- if (programFilesX86) paths.push(`${programFilesX86}\\Git\\bin\\bash.exe`);
1527
- for (const path of paths) if (existsSync(path)) return getBashShellConfig(path);
1528
- const bashOnPath = findBashOnPath();
1529
- if (bashOnPath) return getBashShellConfig(bashOnPath);
1530
- throw new Error(`No bash shell found. Options:
1531
- 1. Install Git for Windows: https://git-scm.com/download/win
1532
- 2. Add your bash to PATH (Cygwin, MSYS2, etc.)
1533
- 3. Set shellPath in settings.json
1534
-
1535
- Searched Git Bash in:\n${paths.map((p) => ` ${p}`).join("\n")}`);
1536
- }
1537
- if (existsSync("/bin/bash")) return getBashShellConfig("/bin/bash");
1538
- const bashOnPath = findBashOnPath();
1539
- if (bashOnPath) return getBashShellConfig(bashOnPath);
1540
- return {
1541
- shell: "sh",
1542
- args: ["-c"]
1543
- };
1544
- }
1545
- //#endregion
1546
- //#region src/compat/vendor/pi-resolve-config-value.ts
1547
- /**
1548
- * Resolve configuration values that may be shell commands, environment variables, or literals.
1549
- * Used by auth-storage.ts and model-registry.ts.
1550
- */
1551
- const ENV_VAR_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
1552
- const ENV_VAR_NAME_PREFIX_RE = /^[A-Za-z_][A-Za-z0-9_]*/;
1553
- function appendLiteral(parts, value) {
1554
- if (!value) return;
1555
- const previousPart = parts[parts.length - 1];
1556
- if (previousPart?.type === "literal") {
1557
- previousPart.value += value;
1558
- return;
1559
- }
1560
- parts.push({
1561
- type: "literal",
1562
- value
1563
- });
1564
- }
1565
- function parseConfigValueTemplate(config) {
1566
- const parts = [];
1567
- let index = 0;
1568
- while (index < config.length) {
1569
- const dollarIndex = config.indexOf("$", index);
1570
- if (dollarIndex < 0) {
1571
- appendLiteral(parts, config.slice(index));
1572
- break;
1573
- }
1574
- appendLiteral(parts, config.slice(index, dollarIndex));
1575
- const nextChar = config[dollarIndex + 1];
1576
- if (nextChar === "$" || nextChar === "!") {
1577
- appendLiteral(parts, nextChar);
1578
- index = dollarIndex + 2;
1579
- continue;
1580
- }
1581
- if (nextChar === "{") {
1582
- const endIndex = config.indexOf("}", dollarIndex + 2);
1583
- if (endIndex < 0) {
1584
- appendLiteral(parts, "$");
1585
- index = dollarIndex + 1;
1586
- continue;
1587
- }
1588
- const name = config.slice(dollarIndex + 2, endIndex);
1589
- if (ENV_VAR_NAME_RE.test(name)) parts.push({
1590
- type: "env",
1591
- name
1592
- });
1593
- else appendLiteral(parts, config.slice(dollarIndex, endIndex + 1));
1594
- index = endIndex + 1;
1595
- continue;
1596
- }
1597
- const match = config.slice(dollarIndex + 1).match(ENV_VAR_NAME_PREFIX_RE);
1598
- if (match) {
1599
- parts.push({
1600
- type: "env",
1601
- name: match[0]
1602
- });
1603
- index = dollarIndex + 1 + match[0].length;
1604
- continue;
1605
- }
1606
- appendLiteral(parts, "$");
1607
- index = dollarIndex + 1;
1608
- }
1609
- return parts;
1610
- }
1611
- function parseConfigValueReference(config) {
1612
- if (config.startsWith("!")) return {
1613
- type: "command",
1614
- config
1615
- };
1616
- return {
1617
- type: "template",
1618
- parts: parseConfigValueTemplate(config)
1619
- };
1620
- }
1621
- function resolveEnvConfigValue(name, env) {
1622
- return env?.[name] || process.env[name] || void 0;
1623
- }
1624
- function getTemplateEnvVarNames(parts) {
1625
- const names = [];
1626
- for (const part of parts) {
1627
- if (part.type !== "env" || names.includes(part.name)) continue;
1628
- names.push(part.name);
1629
- }
1630
- return names;
1631
- }
1632
- function resolveTemplate(parts, env) {
1633
- let resolved = "";
1634
- for (const part of parts) {
1635
- if (part.type === "literal") {
1636
- resolved += part.value;
1637
- continue;
1638
- }
1639
- const envValue = resolveEnvConfigValue(part.name, env);
1640
- if (envValue === void 0) return void 0;
1641
- resolved += envValue;
1642
- }
1643
- return resolved;
1644
- }
1645
- function getConfigValueEnvVarNames(config) {
1646
- const reference = parseConfigValueReference(config);
1647
- return reference.type === "template" ? getTemplateEnvVarNames(reference.parts) : [];
1648
- }
1649
- function getMissingConfigValueEnvVarNames(config, env) {
1650
- return getConfigValueEnvVarNames(config).filter((name) => resolveEnvConfigValue(name, env) === void 0);
1651
- }
1652
- function isCommandConfigValue(config) {
1653
- return parseConfigValueReference(config).type === "command";
1654
- }
1655
- function isConfigValueConfigured(config, env) {
1656
- return getMissingConfigValueEnvVarNames(config, env).length === 0;
1657
- }
1658
- function executeWithConfiguredShell(command) {
1659
- try {
1660
- const { shell, args, commandTransport } = getShellConfig();
1661
- const commandFromStdin = commandTransport === "stdin";
1662
- const result = spawnSync(shell, commandFromStdin ? args : [...args, command], {
1663
- encoding: "utf-8",
1664
- input: commandFromStdin ? command : void 0,
1665
- timeout: 1e4,
1666
- stdio: [
1667
- commandFromStdin ? "pipe" : "ignore",
1668
- "pipe",
1669
- "ignore"
1670
- ],
1671
- shell: false,
1672
- windowsHide: true
1673
- });
1674
- if (result.error) {
1675
- if (result.error.code === "ENOENT") return {
1676
- executed: false,
1677
- value: void 0
1678
- };
1679
- return {
1680
- executed: true,
1681
- value: void 0
1682
- };
1683
- }
1684
- if (result.status !== 0) return {
1685
- executed: true,
1686
- value: void 0
1687
- };
1688
- return {
1689
- executed: true,
1690
- value: (result.stdout ?? "").trim() || void 0
1691
- };
1692
- } catch {
1693
- return {
1694
- executed: false,
1695
- value: void 0
1696
- };
1697
- }
1698
- }
1699
- function executeWithDefaultShell(command) {
1700
- try {
1701
- return execSync(command, {
1702
- encoding: "utf-8",
1703
- timeout: 1e4,
1704
- stdio: [
1705
- "ignore",
1706
- "pipe",
1707
- "ignore"
1708
- ]
1709
- }).trim() || void 0;
1710
- } catch {
1711
- return;
1712
- }
1713
- }
1714
- function executeCommandUncached(commandConfig) {
1715
- const command = commandConfig.slice(1);
1716
- return process.platform === "win32" ? (() => {
1717
- const configuredResult = executeWithConfiguredShell(command);
1718
- return configuredResult.executed ? configuredResult.value : executeWithDefaultShell(command);
1719
- })() : executeWithDefaultShell(command);
1720
- }
1721
- /**
1722
- * Resolve all header values using the same resolution logic as API keys.
1723
- */
1724
- function resolveConfigValueUncached(config, env) {
1725
- const reference = parseConfigValueReference(config);
1726
- if (reference.type === "command") return executeCommandUncached(reference.config);
1727
- return resolveTemplate(reference.parts, env);
1728
- }
1729
- function resolveConfigValueOrThrow(config, description, env) {
1730
- const resolvedValue = resolveConfigValueUncached(config, env);
1731
- if (resolvedValue !== void 0) return resolvedValue;
1732
- const reference = parseConfigValueReference(config);
1733
- if (reference.type === "command") throw new Error(`Failed to resolve ${description} from shell command: ${reference.config.slice(1)}`);
1734
- if (reference.type === "template") {
1735
- const missingEnvVars = getMissingConfigValueEnvVarNames(config, env);
1736
- if (missingEnvVars.length === 1) throw new Error(`Failed to resolve ${description} from environment variable: ${missingEnvVars[0]}`);
1737
- if (missingEnvVars.length > 1) throw new Error(`Failed to resolve ${description} from environment variables: ${missingEnvVars.join(", ")}`);
1738
- }
1739
- throw new Error(`Failed to resolve ${description}`);
1740
- }
1741
- function resolveHeadersOrThrow(headers, description, env) {
1742
- if (!headers) return void 0;
1743
- const resolved = {};
1744
- for (const [key, value] of Object.entries(headers)) resolved[key] = resolveConfigValueOrThrow(value, `${description} header "${key}"`, env);
1745
- return Object.keys(resolved).length > 0 ? resolved : void 0;
1746
- }
1747
- //#endregion
1748
- //#region src/models-json.ts
1749
- function modelsJsonPath() {
1750
- return join(getAgentDir(), "models.json");
1751
- }
1752
- const emptySnapshot = () => ({
1753
- models: [],
1754
- providers: /* @__PURE__ */ new Map(),
1755
- errors: [],
1756
- companions: /* @__PURE__ */ new Map()
1757
- });
1758
- function companionImageModels(provider) {
1759
- if (provider.baseUrl !== void 0 || provider.models !== void 0 || provider.apiKey !== void 0) return void 0;
1760
- const overrides = provider.modelOverrides;
1761
- if (overrides === void 0) return void 0;
1762
- const imageModels = /* @__PURE__ */ new Set();
1763
- for (const [modelId, override] of Object.entries(overrides)) if (Array.isArray(override.input) && override.input.includes("image")) imageModels.add(modelId);
1764
- return imageModels.size > 0 ? imageModels : void 0;
1765
- }
1766
- /**
1767
- * One load of models.json projected to Pi Model objects. Mirrors Pi's
1768
- * composeModelProvider composition order: base (builtin) models →
1769
- * applyModelsJson upserts → modelOverrides as the topmost user-config layer.
1770
- * A provider that fails composition contributes an error and is skipped —
1771
- * the same per-entry isolation the rest of the bridge applies to extensions.
1772
- */
1773
- async function loadModelsJsonSnapshot(baseProviderOf) {
1774
- const snapshot = emptySnapshot();
1775
- const config = await ModelConfig.load(modelsJsonPath());
1776
- const loadError = config.getError();
1777
- if (loadError !== void 0) {
1778
- snapshot.errors.push(loadError);
1779
- return snapshot;
1780
- }
1781
- for (const providerId of config.getProviderIds()) {
1782
- const providerConfig = config.getProvider(providerId);
1783
- if (providerConfig === void 0) continue;
1784
- const imageModels = companionImageModels(providerConfig);
1785
- if (imageModels !== void 0) {
1786
- snapshot.companions.set(providerId, imageModels);
1787
- continue;
1788
- }
1789
- try {
1790
- const base = await baseProviderOf?.(providerId);
1791
- const composed = applyModelsJson(providerId, typeof base?.getModels === "function" ? base.getModels() : [], providerConfig).map((model) => {
1792
- const override = providerConfig.modelOverrides?.[String(model.id)];
1793
- return override ? applyModelOverride(model, override) : model;
1794
- });
1795
- snapshot.models.push(...composed);
1796
- snapshot.providers.set(providerId, providerConfig);
1797
- } catch (error) {
1798
- snapshot.errors.push(error instanceof Error ? error.message : String(error));
1799
- }
1800
- }
1801
- return snapshot;
1802
- }
1803
- /**
1804
- * Pi's configured-auth answer for a models.json provider, following
1805
- * composeApiKeyAuth.resolve + withConfiguredAuth and the registry's
1806
- * translation of their failures:
1807
- * - a configured apiKey resolves through $ENV/!command or fails loudly with
1808
- * the resolver's message;
1809
- * - authHeader folds the resolved key into an Authorization header and,
1810
- * without a key, becomes Pi's "No API key found" answer;
1811
- * - a provider with neither key nor authHeader answers with its resolved
1812
- * headers only (the registry's compatibility path).
1813
- */
1814
- function resolveModelsJsonAuth(providerId, provider) {
1815
- try {
1816
- const headers = resolveHeadersOrThrow(provider.headers, `provider "${providerId}"`);
1817
- const rawKey = provider.apiKey;
1818
- if (rawKey === void 0) {
1819
- if (provider.authHeader ?? false) return {
1820
- ok: false,
1821
- error: `No API key found for "${providerId}"`
1822
- };
1823
- return {
1824
- ok: true,
1825
- ...headers === void 0 ? {} : { headers }
1826
- };
1827
- }
1828
- const apiKey = resolveConfigValueOrThrow(rawKey, `API key for provider "${providerId}"`);
1829
- const merged = provider.authHeader ?? false ? {
1830
- ...headers,
1831
- Authorization: `Bearer ${apiKey}`
1832
- } : headers;
1833
- return {
1834
- ok: true,
1835
- apiKey,
1836
- ...merged === void 0 ? {} : { headers: merged }
1837
- };
1838
- } catch (error) {
1839
- return {
1840
- ok: false,
1841
- error: error instanceof Error ? error.message : String(error)
1842
- };
1843
- }
1844
- }
1845
- /**
1846
- * Pi's withConfiguredAuth layered over an auth resolved by another family
1847
- * (an extension-registered provider or a builtin): models.json headers
1848
- * override the resolved ones, and authHeader folds the resolved key into
1849
- * an Authorization header — failing loudly without one, as Pi does.
1850
- */
1851
- function applyModelsJsonConfiguredAuth(providerId, provider, auth) {
1852
- try {
1853
- const configured = resolveHeadersOrThrow(provider.headers, `provider "${providerId}"`);
1854
- let headers = auth.headers || configured ? {
1855
- ...auth.headers,
1856
- ...configured
1857
- } : void 0;
1858
- if (provider.authHeader ?? false) {
1859
- if (auth.apiKey === void 0) return {
1860
- ok: false,
1861
- error: `No API key found for "${providerId}"`
1862
- };
1863
- headers = {
1864
- ...headers,
1865
- Authorization: `Bearer ${auth.apiKey}`
1866
- };
1867
- }
1868
- return {
1869
- ok: true,
1870
- ...auth.apiKey === void 0 ? {} : { apiKey: auth.apiKey },
1871
- ...headers === void 0 ? {} : { headers }
1872
- };
1873
- } catch (error) {
1874
- return {
1875
- ok: false,
1876
- error: error instanceof Error ? error.message : String(error)
1877
- };
1878
- }
1879
- }
1880
- /**
1881
- * One models.json provider as a Pi Provider object: the composed Pi Models
1882
- * as its catalog and Pi's per-api wire clients as its transport (attached by
1883
- * the provider adapter's synthesis). Registered as a DSH llm route, this
1884
- * makes the DSH directory the single model directory — the Pi registry
1885
- * projects it back, and registry.getProvider() answers a genuine Pi
1886
- * Provider, so packages that stream through the provider surface work
1887
- * unchanged.
1888
- */
1889
- function modelsJsonPiProvider(providerId, provider, models) {
1890
- return {
1891
- id: providerId,
1892
- name: provider.name ?? providerId,
1893
- ...provider.baseUrl === void 0 ? {} : { baseUrl: provider.baseUrl },
1894
- ...provider.api === void 0 ? {} : { api: provider.api },
1895
- getModels: () => models
1896
- };
1897
- }
1898
- /**
1899
- * Pi's configured-check (not liveness) for a models.json provider — the
1900
- * configuredRequestAuthStatus semantics: a literal or !command key counts as
1901
- * configured, a templated key counts only when its env vars are present, and
1902
- * a provider without an apiKey defers to the other credential families.
1903
- */
1904
- function modelsJsonAuthConfigured(provider) {
1905
- const value = provider.apiKey;
1906
- if (value === void 0) return void 0;
1907
- if (isCommandConfigValue(value)) return true;
1908
- if (getConfigValueEnvVarNames(value).length > 0) return isConfigValueConfigured(value);
1909
- return true;
1910
- }
1911
- //#endregion
1912
1114
  //#region src/provider-adapter.ts
1913
- const PI_API_FACTORIES = {
1914
- "openai-completions": openAICompletionsApi,
1915
- "openai-responses": openAIResponsesApi,
1916
- "anthropic-messages": anthropicMessagesApi
1917
- };
1918
- function piApiClientFor(api) {
1919
- const factory = typeof api === "string" ? PI_API_FACTORIES[api] : void 0;
1920
- return factory === void 0 ? void 0 : factory();
1921
- }
1922
- /**
1923
- * Give a config-only Pi provider (models.json entries, packages that declare
1924
- * models without a stream) Pi's own transport: each call dispatches on the
1925
- * model's declared `api` to the real pi-ai client, exactly as Pi's
1926
- * provider composer does. Undispatchable providers (no models, or an api
1927
- * with no client) answer undefined and stay off the directory.
1928
- */
1929
- function withSynthesizedTransport(provider) {
1930
- const models = typeof provider.getModels === "function" ? provider.getModels() : Array.isArray(provider.models) ? provider.models : [];
1931
- if (models.length === 0) return void 0;
1932
- if (!models.some((model) => piApiClientFor(model.api) !== void 0)) return void 0;
1933
- const dispatch = (simple) => (model, context, options) => {
1934
- const client = piApiClientFor(model.api);
1935
- if (client === void 0) throw new Error(`pi2dsh: no wire-protocol client for api ${JSON.stringify(String(model.api))} (model ${String(model.provider)}/${String(model.id)})`);
1936
- return (simple ? client.streamSimple ?? client.stream : client.stream).call(client, model, context, options);
1937
- };
1938
- return {
1939
- ...provider,
1940
- getModels: () => models,
1941
- stream: dispatch(false),
1942
- streamSimple: dispatch(true)
1943
- };
1944
- }
1945
1115
  function providerCarriesTransport(value) {
1946
1116
  return typeof value?.stream === "function";
1947
1117
  }
@@ -2044,7 +1214,7 @@ async function textOnlyMessages(messages, materialize) {
2044
1214
  }
2045
1215
  /**
2046
1216
  * A DSH route that admits images on behalf of a text-only route — the
2047
- * single-directory answer to models.json modelOverrides declaring
1217
+ * single-directory answer to host configuration declaring
2048
1218
  * `input: ["text", "image"]` for models of a route this bridge does not own.
2049
1219
  * The companion honestly declares image input (so the host's admission and
2050
1220
  * model-switch checks pass), replaces image blocks with an explicit notice,
@@ -2100,10 +1270,12 @@ function imageAdmissionCompanionAdapter(options) {
2100
1270
  function registerPiProviderRoute(options) {
2101
1271
  const { llm, providerId, provider, host } = options;
2102
1272
  if (llm === void 0) return void 0;
2103
- const transport = providerCarriesTransport(provider) ? provider : withSynthesizedTransport(provider);
2104
- if (transport === void 0) return void 0;
1273
+ if (!providerCarriesTransport(provider)) {
1274
+ host.warn(`[pi2dsh] Pi provider ${JSON.stringify(providerId)} declares a model catalog but no transport; it was not added as a DSH llm route — configure the gateway in the host's llm settings instead`);
1275
+ return;
1276
+ }
2105
1277
  try {
2106
- return llm.registerAdapter([providerId], piProviderDshAdapter(providerId, transport, host));
1278
+ return llm.registerAdapter([providerId], piProviderDshAdapter(providerId, provider, host));
2107
1279
  } catch (error) {
2108
1280
  host.warn(`[pi2dsh] Pi provider ${JSON.stringify(providerId)} was not added as a DSH llm route (${error instanceof Error ? error.message : String(error)}); the existing route keeps the name`);
2109
1281
  return;
@@ -2457,7 +1629,7 @@ function contextFor(ctx, state, agent, signal, command = false) {
2457
1629
  const providerConfig = (name) => state.providers.get(name);
2458
1630
  const catalog = state.modelCatalog;
2459
1631
  const piNativeEntry = (provider, id) => {
2460
- const source = state.modelsJsonProviders.get(provider) ?? (state.providerRouteDisposers.has(provider) ? state.providers.get(provider) : void 0);
1632
+ const source = state.providerRouteDisposers.has(provider) ? state.providers.get(provider) : void 0;
2461
1633
  if (source === void 0) return void 0;
2462
1634
  let models;
2463
1635
  try {
@@ -2509,24 +1681,15 @@ function contextFor(ctx, state, agent, signal, command = false) {
2509
1681
  const entry = catalog?.find(provider, modelId);
2510
1682
  return entry === void 0 ? void 0 : restorePiShape(entry);
2511
1683
  },
2512
- getError: () => {
2513
- const problems = state.modelsJson?.errors ?? [];
2514
- return problems.length > 0 ? problems.join("\n") : void 0;
2515
- },
1684
+ getError: () => void 0,
2516
1685
  hasConfiguredAuth: (model) => {
2517
1686
  const provider = String(model?.provider ?? "");
2518
1687
  if (provider.length === 0) return false;
2519
- const jsonProvider = state.modelsJson?.providers.get(provider);
2520
- if (jsonProvider !== void 0) {
2521
- const configured = modelsJsonAuthConfigured(jsonProvider);
2522
- if (configured !== void 0) return configured;
2523
- }
2524
- return state.providers.has(provider) || (catalog?.all() ?? []).some((entry) => entry.provider === provider) || jsonProvider !== void 0;
1688
+ return state.providers.has(provider) || (catalog?.all() ?? []).some((entry) => entry.provider === provider);
2525
1689
  },
2526
1690
  getApiKeyAndHeaders: async (model) => {
2527
1691
  const provider = String(model?.provider ?? "");
2528
- const jsonProvider = state.modelsJson?.providers.get(provider);
2529
- const config = providerConfig(provider) ?? (jsonProvider?.apiKey !== void 0 ? void 0 : await realBuiltinProvider(provider));
1692
+ const config = providerConfig(provider);
2530
1693
  if (config !== void 0) {
2531
1694
  const auth = (await resolvePiProviderAuth({
2532
1695
  providerId: provider,
@@ -2534,34 +1697,13 @@ function contextFor(ctx, state, agent, signal, command = false) {
2534
1697
  store: oauthStoreOf(state)
2535
1698
  }))?.auth;
2536
1699
  if (auth?.apiKey === void 0) return { ok: false };
2537
- const configured = jsonProvider === void 0 ? void 0 : applyModelsJsonConfiguredAuth(provider, jsonProvider, {
2538
- apiKey: auth.apiKey,
2539
- ...auth.headers === void 0 ? {} : { headers: auth.headers }
2540
- });
2541
- if (configured !== void 0 && !configured.ok) return {
2542
- ok: false,
2543
- error: configured.error
2544
- };
2545
- const headers = configured?.ok ? configured.headers : auth.headers;
2546
1700
  return {
2547
1701
  ok: true,
2548
1702
  apiKey: auth.apiKey,
2549
- ...headers === void 0 ? {} : { headers },
1703
+ ...auth.headers === void 0 ? {} : { headers: auth.headers },
2550
1704
  ...auth.baseUrl === void 0 && config.baseUrl === void 0 ? {} : { baseUrl: auth.baseUrl ?? config.baseUrl }
2551
1705
  };
2552
1706
  }
2553
- if (jsonProvider !== void 0) {
2554
- const resolved = resolveModelsJsonAuth(provider, jsonProvider);
2555
- if (!resolved.ok) return {
2556
- ok: false,
2557
- error: resolved.error
2558
- };
2559
- return {
2560
- ok: true,
2561
- ...resolved.apiKey === void 0 ? {} : { apiKey: resolved.apiKey },
2562
- ...resolved.headers === void 0 ? {} : { headers: resolved.headers }
2563
- };
2564
- }
2565
1707
  try {
2566
1708
  const entry = llmOf(ctx)?.listConfigurableProviders?.()?.find((candidate) => candidate.provider === provider);
2567
1709
  if (entry === void 0) return { ok: false };
@@ -2580,8 +1722,8 @@ function contextFor(ctx, state, agent, signal, command = false) {
2580
1722
  },
2581
1723
  getProviderAuthStatus: (provider) => providerSupportsOAuth(providerConfig(provider)) ? "oauth" : "none",
2582
1724
  getProvider: (provider) => {
2583
- const base = providerConfig(provider) ?? state.modelsJsonProviders.get(provider);
2584
- if (base !== void 0) return state.providerRouteDisposers.has(provider) || state.providerRouteDisposers.has(`${MODELS_JSON_ROUTE_PREFIX}${provider}`) ? dshRoutedPiProvider(base, provider) : base;
1725
+ const base = providerConfig(provider);
1726
+ if (base !== void 0) return state.providerRouteDisposers.has(provider) ? dshRoutedPiProvider(base, provider) : base;
2585
1727
  if ((catalog?.all() ?? []).some((entry) => entry.provider === provider)) return dshRoutedPiProvider({
2586
1728
  id: provider,
2587
1729
  name: provider
@@ -2595,7 +1737,7 @@ function contextFor(ctx, state, agent, signal, command = false) {
2595
1737
  getRegisteredProviderConfig: (provider) => providerConfig(provider),
2596
1738
  getRegisteredProviderIds: () => [...state.providers.keys()],
2597
1739
  getProviderDisplayName: (provider) => {
2598
- const config = providerConfig(provider) ?? state.modelsJsonProviders.get(provider);
1740
+ const config = providerConfig(provider);
2599
1741
  return typeof config?.name === "string" ? config.name : provider;
2600
1742
  },
2601
1743
  getProviderAuth: async (provider) => {
@@ -2629,11 +1771,10 @@ function contextFor(ctx, state, agent, signal, command = false) {
2629
1771
  return provider.length > 0 && providerSupportsOAuth(providerConfig(provider));
2630
1772
  },
2631
1773
  refresh: async () => {
2632
- await reloadModelsJson(ctx, state, true);
2633
1774
  await catalog?.refresh();
2634
1775
  return {
2635
1776
  models: allModels(),
2636
- errors: [...state.modelsJson?.errors ?? []]
1777
+ errors: []
2637
1778
  };
2638
1779
  }
2639
1780
  },
@@ -3170,14 +2311,13 @@ function oauthStoreOf(state) {
3170
2311
  state.shared.oauthStore ??= new FileCredentialStore(join(getAgentDir(), "auth.json"));
3171
2312
  return state.shared.oauthStore;
3172
2313
  }
3173
- const MODELS_JSON_ROUTE_PREFIX = "models.json/";
2314
+ const COMPANION_ROUTE_PREFIX = "pi2dsh-companion/";
3174
2315
  const SHARED_HOST_STATE = /* @__PURE__ */ new WeakMap();
3175
2316
  function sharedHostStateOf(ctx) {
3176
2317
  const key = ctx.root ?? ctx;
3177
2318
  let shared = SHARED_HOST_STATE.get(key);
3178
2319
  if (shared === void 0) {
3179
2320
  shared = {
3180
- modelsJsonProviders: /* @__PURE__ */ new Map(),
3181
2321
  companionRoutes: /* @__PURE__ */ new Map(),
3182
2322
  providerRouteDisposers: /* @__PURE__ */ new Map(),
3183
2323
  providers: /* @__PURE__ */ new Map()
@@ -3187,84 +2327,42 @@ function sharedHostStateOf(ctx) {
3187
2327
  return shared;
3188
2328
  }
3189
2329
  /**
3190
- * Load models.json routes for a host with NO mounted Pi package yet — the
3191
- * single-directory capability (custom providers + image-admission
3192
- * companions in the DSH picker) is the bridge's own, not any plugin's.
3193
- * A later package mount adopts the same shared snapshot.
2330
+ * Image-admission companion routes, configured on the DSH side (the
2331
+ * engine's or a bundle's cordis config): `{ <existingRoute>: [modelIds] }`
2332
+ * registers a `<route>-vision` route that admits images at the host's
2333
+ * admission checks, replaces image blocks with explicit path-carrying
2334
+ * notices, and forwards text-only to the original route. The companion is
2335
+ * an ordinary directory entry (single-directory contract); Pi's ctx.model
2336
+ * reports the original route for it (companionRoutes). Idempotent per
2337
+ * host: repeated calls (several packages, engine + bundle) keep one live
2338
+ * adapter and one mapping.
3194
2339
  */
3195
- async function ensureModelsJsonRoutes(ctx) {
2340
+ function registerVisionCompanions(ctx, companions) {
2341
+ if (companions === void 0) return;
3196
2342
  const shared = sharedHostStateOf(ctx);
3197
- await reloadModelsJson(ctx, {
3198
- shared,
3199
- modelsJsonProviders: shared.modelsJsonProviders,
3200
- companionRoutes: shared.companionRoutes,
3201
- providerRouteDisposers: shared.providerRouteDisposers
3202
- });
3203
- }
3204
- async function reloadModelsJson(ctx, state, force = false) {
3205
- if (!force && state.shared.modelsJson !== void 0) {
3206
- state.modelsJson = state.shared.modelsJson;
2343
+ const llm = llmOf(ctx);
2344
+ if (llm === void 0) {
2345
+ logger(ctx).warn("[pi2dsh] visionCompanions configured, but this composition mounts no llm service; no companion route was registered");
3207
2346
  return;
3208
2347
  }
3209
- for (const [key, dispose] of state.providerRouteDisposers) {
3210
- if (!key.startsWith(MODELS_JSON_ROUTE_PREFIX)) continue;
3211
- state.providerRouteDisposers.delete(key);
3212
- dispose();
3213
- }
3214
- state.modelsJsonProviders.clear();
3215
- state.companionRoutes.clear();
3216
- state.modelsJson = await loadModelsJsonSnapshot(realBuiltinProvider);
3217
- state.shared.modelsJson = state.modelsJson;
3218
- for (const problem of state.modelsJson.errors) logger(ctx).warn(`[pi2dsh] models.json: ${problem}`);
3219
- for (const [providerId, providerConfig] of state.modelsJson.providers) {
3220
- const models = state.modelsJson.models.filter((model) => model.provider === providerId);
3221
- const provider = modelsJsonPiProvider(providerId, providerConfig, models);
3222
- const routeDisposer = registerPiProviderRoute({
3223
- llm: llmOf(ctx),
3224
- providerId,
3225
- provider,
3226
- host: {
3227
- resolveAuth: async () => {
3228
- const resolved = resolveModelsJsonAuth(providerId, providerConfig);
3229
- if (!resolved.ok) return void 0;
3230
- return { auth: {
3231
- ...resolved.apiKey === void 0 ? {} : { apiKey: resolved.apiKey },
3232
- ...resolved.headers === void 0 ? {} : { headers: resolved.headers },
3233
- ...providerConfig.baseUrl === void 0 ? {} : { baseUrl: providerConfig.baseUrl }
3234
- } };
3235
- },
3236
- warn: (message) => logger(ctx).warn(message)
3237
- }
3238
- });
3239
- if (routeDisposer !== void 0) {
3240
- state.modelsJsonProviders.set(providerId, provider);
3241
- state.providerRouteDisposers.set(`${MODELS_JSON_ROUTE_PREFIX}${providerId}`, routeDisposer);
3242
- logger(ctx).info(`[pi2dsh] models.json provider ${JSON.stringify(providerId)} registered as a native DSH llm route (${models.length} models)`);
3243
- }
3244
- }
3245
- registerCompanionRoutes(ctx, state);
3246
- }
3247
- function registerCompanionRoutes(ctx, state) {
3248
- const companions = state.modelsJson?.companions;
3249
- if (companions === void 0 || companions.size === 0) return;
3250
- const llm = llmOf(ctx);
3251
- if (llm === void 0) return;
3252
- for (const [originalId, imageModels] of companions) {
2348
+ for (const [originalId, modelIds] of Object.entries(companions)) {
2349
+ if (!Array.isArray(modelIds) || modelIds.length === 0) continue;
2350
+ const companionId = `${originalId}-vision`;
2351
+ shared.companionRoutes.set(companionId, originalId);
3253
2352
  if (!llm.listProviders().some((provider) => provider.id === originalId)) {
3254
- logger(ctx).warn(`[pi2dsh] models.json: modelOverrides for ${JSON.stringify(originalId)} declare image input, but no such llm route exists; no companion route was registered`);
2353
+ logger(ctx).warn(`[pi2dsh] visionCompanions names route ${JSON.stringify(originalId)}, but no such llm route exists; no companion route was registered`);
3255
2354
  continue;
3256
2355
  }
3257
- const companionId = `${originalId}-vision`;
3258
- state.companionRoutes.set(companionId, originalId);
2356
+ if (shared.providerRouteDisposers.has(`${COMPANION_ROUTE_PREFIX}${companionId}`)) continue;
3259
2357
  try {
3260
2358
  const dispose = llm.registerAdapter([companionId], imageAdmissionCompanionAdapter({
3261
2359
  originalId,
3262
- imageModels,
2360
+ imageModels: new Set(modelIds.map(String)),
3263
2361
  llm,
3264
2362
  materializeImage: (attachment) => materializeAttachmentImage(ctx, attachment)
3265
2363
  }));
3266
- state.providerRouteDisposers.set(`${MODELS_JSON_ROUTE_PREFIX}${companionId}`, dispose);
3267
- logger(ctx).info(`[pi2dsh] image-admission companion route ${JSON.stringify(companionId)} registered for ${JSON.stringify(originalId)} (${imageModels.size} models)`);
2364
+ shared.providerRouteDisposers.set(`${COMPANION_ROUTE_PREFIX}${companionId}`, dispose);
2365
+ logger(ctx).info(`[pi2dsh] image-admission companion route ${JSON.stringify(companionId)} registered for ${JSON.stringify(originalId)} (${modelIds.length} models)`);
3268
2366
  } catch (error) {
3269
2367
  logger(ctx).warn(`[pi2dsh] companion route ${JSON.stringify(companionId)} already has a live adapter in this host (${error instanceof Error ? error.message : String(error)}); reusing it`);
3270
2368
  }
@@ -3874,7 +2972,6 @@ async function applyPiPackage(ctx, options) {
3874
2972
  toolRestrictions: /* @__PURE__ */ new WeakMap(),
3875
2973
  commands: /* @__PURE__ */ new Map(),
3876
2974
  commandDisposers: /* @__PURE__ */ new Map(),
3877
- modelsJsonProviders: shared.modelsJsonProviders,
3878
2975
  companionRoutes: shared.companionRoutes,
3879
2976
  flags: /* @__PURE__ */ new Map(),
3880
2977
  notifications: [],
@@ -3924,7 +3021,7 @@ async function applyPiPackage(ctx, options) {
3924
3021
  }
3925
3022
  const llm = llmOf(ctx);
3926
3023
  state.modelCatalog = shared.modelCatalog ??= new ModelCatalog(llm);
3927
- await reloadModelsJson(ctx, state);
3024
+ registerVisionCompanions(ctx, options.config?.visionCompanions);
3928
3025
  if (llm !== void 0) {
3929
3026
  if (shared.catalogSubscribed !== true) {
3930
3027
  shared.catalogSubscribed = true;
@@ -3971,6 +3068,6 @@ const runtimeInternals = {
3971
3068
  textBlocks
3972
3069
  };
3973
3070
  //#endregion
3974
- export { runtimeInternals as i, ensureModelsJsonRoutes as n, normalizeToolSchema as r, applyPiPackage as t };
3071
+ export { runtimeInternals as i, normalizeToolSchema as n, registerVisionCompanions as r, applyPiPackage as t };
3975
3072
 
3976
- //# sourceMappingURL=runtime-k3IlCgjQ.mjs.map
3073
+ //# sourceMappingURL=runtime-B-Mun-jX.mjs.map