pi2dsh 0.8.0 → 0.9.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.
@@ -1,5 +1,5 @@
1
1
 
2
- import { P as AssistantMessageEventStream, i as builtinProviders, r as __setPiAiLlmBridge } from "./pi-ai-C6Xag6xt.mjs";
2
+ import { P as AssistantMessageEventStream, i as builtinProviders, r as __setPiAiLlmBridge } from "./pi-ai-BA3h0Dwv.mjs";
3
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";
@@ -1223,7 +1223,8 @@ async function textOnlyMessages(messages, materialize) {
1223
1223
  * extension handles the turn's entering messages.
1224
1224
  */
1225
1225
  function imageAdmissionCompanionAdapter(options) {
1226
- const { originalId, imageModels, llm } = options;
1226
+ const { originalId, llm } = options;
1227
+ const admits = (modelId) => options.imageModels === void 0 || options.imageModels.has(modelId);
1227
1228
  const materialize = options.materializeImage ?? (async () => void 0);
1228
1229
  const admitImage = (info, id) => {
1229
1230
  const modalities = Array.isArray(info.inputModalities) ? info.inputModalities.slice() : ["text"];
@@ -1242,10 +1243,10 @@ function imageAdmissionCompanionAdapter(options) {
1242
1243
  };
1243
1244
  },
1244
1245
  providerRetryPolicy: () => void 0,
1245
- listModels: async (id) => (await llm.listModels(originalId)).filter((model) => imageModels.has(String(model.id))).map((model) => admitImage(model, id)),
1246
+ listModels: async (id) => (await llm.listModels(originalId)).filter((model) => admits(String(model.id))).map((model) => admitImage(model, id)),
1246
1247
  resolveModel: async (id, modelId) => {
1247
1248
  const info = await llm.resolveModelInfo(originalId, modelId);
1248
- return imageModels.has(modelId) ? admitImage(info, id) : {
1249
+ return admits(modelId) ? admitImage(info, id) : {
1249
1250
  ...info,
1250
1251
  provider: id
1251
1252
  };
@@ -2327,45 +2328,102 @@ function sharedHostStateOf(ctx) {
2327
2328
  return shared;
2328
2329
  }
2329
2330
  /**
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
2331
+ * Image-admission companion routes: for every text-only route in the DSH
2332
+ * llm directory, a `<route>-vision` route that admits images at the host's
2333
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.
2334
+ * notices, and forwards text-only to the original route. What happens to
2335
+ * an admitted image is decided at run time by whatever is mounted — a
2336
+ * vision extension analyzes it through the turn's entering messages, and
2337
+ * without one the notice's file path lets any image-capable tool read it —
2338
+ * so companions need no knowledge of any particular plugin and are
2339
+ * registered AUTOMATICALLY (zero configuration). `visionCompanions: false`
2340
+ * turns them off; an explicit `{ <route>: [modelIds] }` map narrows them.
2341
+ * The directory is live: adapters-updated re-sweeps, adding companions for
2342
+ * new text-only routes and disposing companions whose original vanished.
2343
+ * The companion is an ordinary directory entry (single-directory
2344
+ * contract); Pi's ctx.model reports the original route for it
2345
+ * (companionRoutes). Idempotent per host.
2339
2346
  */
2340
- function registerVisionCompanions(ctx, companions) {
2341
- if (companions === void 0) return;
2347
+ function registerVisionCompanions(ctx, config) {
2348
+ if (config === false) return;
2342
2349
  const shared = sharedHostStateOf(ctx);
2343
2350
  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");
2346
- return;
2347
- }
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);
2352
- if (!llm.listProviders().some((provider) => provider.id === originalId)) {
2353
- logger(ctx).warn(`[pi2dsh] visionCompanions names route ${JSON.stringify(originalId)}, but no such llm route exists; no companion route was registered`);
2354
- continue;
2355
- }
2356
- if (shared.providerRouteDisposers.has(`${COMPANION_ROUTE_PREFIX}${companionId}`)) continue;
2357
- try {
2358
- const dispose = llm.registerAdapter([companionId], imageAdmissionCompanionAdapter({
2351
+ if (llm === void 0) return;
2352
+ const sweep = async () => {
2353
+ const explicit = config;
2354
+ const providers = llm.listProviders();
2355
+ const wanted = /* @__PURE__ */ new Map();
2356
+ if (explicit !== void 0) for (const [originalId, modelIds] of Object.entries(explicit)) {
2357
+ if (!Array.isArray(modelIds) || modelIds.length === 0) continue;
2358
+ if (!providers.some((provider) => provider.id === originalId)) {
2359
+ logger(ctx).warn(`[pi2dsh] visionCompanions names route ${JSON.stringify(originalId)}, but no such llm route exists; no companion route was registered`);
2360
+ continue;
2361
+ }
2362
+ wanted.set(`${originalId}-vision`, {
2359
2363
  originalId,
2360
- imageModels: new Set(modelIds.map(String)),
2361
- llm,
2362
- materializeImage: (attachment) => materializeAttachmentImage(ctx, attachment)
2363
- }));
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)`);
2366
- } catch (error) {
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`);
2364
+ imageModels: new Set(modelIds.map(String))
2365
+ });
2366
+ }
2367
+ else for (const provider of providers) {
2368
+ if (shared.companionRoutes.has(provider.id)) continue;
2369
+ try {
2370
+ const models = await llm.listModels(provider.id);
2371
+ if (models.length === 0) continue;
2372
+ if (models.every((model) => !(Array.isArray(model.inputModalities) && model.inputModalities.includes("image")))) wanted.set(`${provider.id}-vision`, {
2373
+ originalId: provider.id,
2374
+ imageModels: void 0
2375
+ });
2376
+ } catch {}
2368
2377
  }
2378
+ for (const [key, dispose] of shared.providerRouteDisposers) {
2379
+ if (!key.startsWith(COMPANION_ROUTE_PREFIX)) continue;
2380
+ const companionId = key.slice(17);
2381
+ const originalId = shared.companionRoutes.get(companionId);
2382
+ if (originalId !== void 0 && !providers.some((provider) => provider.id === originalId)) {
2383
+ shared.providerRouteDisposers.delete(key);
2384
+ dispose();
2385
+ logger(ctx).info(`[pi2dsh] companion route ${JSON.stringify(companionId)} disposed (its original route ${JSON.stringify(originalId)} left the directory)`);
2386
+ }
2387
+ }
2388
+ for (const [companionId, spec] of wanted) {
2389
+ shared.companionRoutes.set(companionId, spec.originalId);
2390
+ if (shared.providerRouteDisposers.has(`${COMPANION_ROUTE_PREFIX}${companionId}`)) continue;
2391
+ try {
2392
+ const dispose = llm.registerAdapter([companionId], imageAdmissionCompanionAdapter({
2393
+ originalId: spec.originalId,
2394
+ ...spec.imageModels === void 0 ? {} : { imageModels: spec.imageModels },
2395
+ llm,
2396
+ materializeImage: (attachment) => materializeAttachmentImage(ctx, attachment)
2397
+ }));
2398
+ shared.providerRouteDisposers.set(`${COMPANION_ROUTE_PREFIX}${companionId}`, dispose);
2399
+ logger(ctx).info(`[pi2dsh] image-admission companion route ${JSON.stringify(companionId)} registered for ${JSON.stringify(spec.originalId)}`);
2400
+ } catch (error) {
2401
+ 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`);
2402
+ }
2403
+ }
2404
+ };
2405
+ let sweeping = false;
2406
+ let queued = false;
2407
+ const runSweep = () => {
2408
+ if (sweeping) {
2409
+ queued = true;
2410
+ return;
2411
+ }
2412
+ sweeping = true;
2413
+ sweep().finally(() => {
2414
+ sweeping = false;
2415
+ if (queued) {
2416
+ queued = false;
2417
+ runSweep();
2418
+ }
2419
+ });
2420
+ };
2421
+ runSweep();
2422
+ if (shared.companionSweepSubscribed !== true) {
2423
+ shared.companionSweepSubscribed = true;
2424
+ ctx.on("llm/adapters-updated", () => {
2425
+ runSweep();
2426
+ });
2369
2427
  }
2370
2428
  }
2371
2429
  const IMAGE_EXTENSIONS = {
@@ -3070,4 +3128,4 @@ const runtimeInternals = {
3070
3128
  //#endregion
3071
3129
  export { runtimeInternals as i, normalizeToolSchema as n, registerVisionCompanions as r, applyPiPackage as t };
3072
3130
 
3073
- //# sourceMappingURL=runtime-B-Mun-jX.mjs.map
3131
+ //# sourceMappingURL=runtime-DMEJknhK.mjs.map