dsh-multi-router 0.5.9 → 0.6.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 (40) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +26 -1
  3. package/cordis.patch.yml +2 -2
  4. package/lib/accounts.js +4 -4
  5. package/lib/api-service.js +11 -0
  6. package/lib/api-service.js.map +7 -0
  7. package/lib/chunk-4V52V5GO.js +105 -0
  8. package/lib/chunk-4V52V5GO.js.map +7 -0
  9. package/lib/{chunk-S6ZQ45SS.js → chunk-JUOESKAK.js} +3 -3
  10. package/lib/{chunk-P43AWJ4Q.js → chunk-LLDJVBTQ.js} +3 -3
  11. package/lib/{chunk-U2MU2M5C.js → chunk-NSKCFVHP.js} +13 -111
  12. package/lib/chunk-NSKCFVHP.js.map +7 -0
  13. package/lib/{chunk-I4EW5TI7.js → chunk-OCMOMSB4.js} +46 -14
  14. package/lib/chunk-OCMOMSB4.js.map +7 -0
  15. package/lib/{chunk-FTM7RHQV.js → chunk-OK2T2UAZ.js} +4 -4
  16. package/lib/{chunk-J3XO7RTF.js → chunk-ROZINFTV.js} +3 -2
  17. package/lib/chunk-ROZINFTV.js.map +7 -0
  18. package/lib/chunk-SNEZMYNU.js +332 -0
  19. package/lib/chunk-SNEZMYNU.js.map +7 -0
  20. package/lib/{chunk-MCHV2R25.js → chunk-WVNY4LSL.js} +3 -1
  21. package/lib/{chunk-MCHV2R25.js.map → chunk-WVNY4LSL.js.map} +2 -2
  22. package/lib/cli.js +7 -6
  23. package/lib/cli.js.map +1 -1
  24. package/lib/client.js +340 -7
  25. package/lib/client.js.map +2 -2
  26. package/lib/clients.js +6 -5
  27. package/lib/{host-v0.5.9.js → host-v0.6.0.js} +18 -13
  28. package/lib/host.js +18 -13
  29. package/lib/index.js +18 -13
  30. package/lib/index.js.map +2 -2
  31. package/lib/manager.js +11 -7
  32. package/lib/router.js +2 -2
  33. package/lib/shim.js +3 -3
  34. package/package.json +1 -1
  35. package/lib/chunk-I4EW5TI7.js.map +0 -7
  36. package/lib/chunk-J3XO7RTF.js.map +0 -7
  37. package/lib/chunk-U2MU2M5C.js.map +0 -7
  38. /package/lib/{chunk-S6ZQ45SS.js.map → chunk-JUOESKAK.js.map} +0 -0
  39. /package/lib/{chunk-P43AWJ4Q.js.map → chunk-LLDJVBTQ.js.map} +0 -0
  40. /package/lib/{chunk-FTM7RHQV.js.map → chunk-OK2T2UAZ.js.map} +0 -0
package/lib/clients.js CHANGED
@@ -7,12 +7,13 @@ import {
7
7
  jsonCredential,
8
8
  refreshWorkBuddyCheckinCredential,
9
9
  workbuddyToken
10
- } from "./chunk-U2MU2M5C.js";
11
- import "./chunk-FTM7RHQV.js";
12
- import "./chunk-S5KMFAQM.js";
13
- import "./chunk-J3XO7RTF.js";
14
- import "./chunk-MCHV2R25.js";
10
+ } from "./chunk-NSKCFVHP.js";
11
+ import "./chunk-OK2T2UAZ.js";
15
12
  import "./chunk-TEZ2FMEO.js";
13
+ import "./chunk-S5KMFAQM.js";
14
+ import "./chunk-4V52V5GO.js";
15
+ import "./chunk-ROZINFTV.js";
16
+ import "./chunk-WVNY4LSL.js";
16
17
  export {
17
18
  cachedModels,
18
19
  claimTraeCheckin,
@@ -1,33 +1,36 @@
1
1
  import {
2
2
  createShim
3
- } from "./chunk-P43AWJ4Q.js";
3
+ } from "./chunk-LLDJVBTQ.js";
4
4
  import {
5
5
  MANAGEMENT_PATH,
6
6
  Manager,
7
7
  PluginReload,
8
+ SUMMARY_PATH,
8
9
  managementHandler,
9
10
  version
10
- } from "./chunk-I4EW5TI7.js";
11
+ } from "./chunk-OCMOMSB4.js";
11
12
  import {
12
13
  createAccountClient
13
- } from "./chunk-U2MU2M5C.js";
14
- import "./chunk-S6ZQ45SS.js";
15
- import "./chunk-FTM7RHQV.js";
14
+ } from "./chunk-NSKCFVHP.js";
15
+ import "./chunk-JUOESKAK.js";
16
+ import "./chunk-OK2T2UAZ.js";
17
+ import {
18
+ normalizeCredits
19
+ } from "./chunk-TEZ2FMEO.js";
16
20
  import "./chunk-S5KMFAQM.js";
21
+ import "./chunk-SNEZMYNU.js";
22
+ import "./chunk-4V52V5GO.js";
17
23
  import "./chunk-DNQPZMPF.js";
18
24
  import {
19
25
  Router,
20
26
  SessionMetrics,
21
27
  abortable
22
- } from "./chunk-J3XO7RTF.js";
28
+ } from "./chunk-ROZINFTV.js";
23
29
  import {
24
30
  PROVIDERS,
25
31
  PROVIDER_NAMES,
26
32
  ensureConfig
27
- } from "./chunk-MCHV2R25.js";
28
- import {
29
- normalizeCredits
30
- } from "./chunk-TEZ2FMEO.js";
33
+ } from "./chunk-WVNY4LSL.js";
31
34
 
32
35
  // src/index.mjs
33
36
  import z from "@deepseek-ai/schemastery";
@@ -265,7 +268,7 @@ async function apply(ctx, options = {}) {
265
268
  manager?.checkins.abort.abort();
266
269
  manager?.workbuddyLogin.abort.abort();
267
270
  for (const release of releases) release();
268
- return Promise.all([...shims.map((shim) => shim.close()), ...manager?.refreshes.values() ?? [], ...manager?.monitorFlights.values() ?? [], startup, manager?.localScan, manager?.checkins.flight, manager?.plugins.flight, manager?.plugins.saveQueue.catch(() => {
271
+ return Promise.all([manager?.api.close(), ...shims.map((shim) => shim.close()), ...manager?.refreshes.values() ?? [], ...manager?.monitorFlights.values() ?? [], startup, manager?.localScan, manager?.checkins.flight, manager?.plugins.flight, manager?.plugins.saveQueue.catch(() => {
269
272
  }), manager?.telemetry.queue.catch(() => {
270
273
  })]);
271
274
  });
@@ -291,9 +294,10 @@ async function apply(ctx, options = {}) {
291
294
  profile: () => ctx.get("profileContext"),
292
295
  canReload: () => !!ctx.get("hmr"),
293
296
  hmr: () => ctx.get("hmr"),
294
- busy: () => !!(manager.localScan || manager.requests || manager.plugins.flight || manager.checkins.flight || manager.workbuddyLogin.flight || manager.workbuddyLogin.pending || manager.refreshes.size || manager.monitorFlights.size || shims.some((s) => s.active()))
297
+ busy: () => !!(manager.localScan || manager.requests || manager.api.controllers.size || manager.plugins.flight || manager.checkins.flight || manager.workbuddyLogin.flight || manager.workbuddyLogin.pending || manager.refreshes.size || manager.monitorFlights.size || shims.some((s) => s.active()))
295
298
  });
296
299
  ctx.inject?.(["webServer"], (webCtx) => {
300
+ webCtx.effect(() => webCtx.webServer.register({ kind: "exact", path: SUMMARY_PATH, handler: managementHandler(manager, { summaryOnly: true }) }));
297
301
  webCtx.effect(() => webCtx.webServer.register({ kind: "exact", path: MANAGEMENT_PATH, handler: managementHandler(manager) }));
298
302
  });
299
303
  const metrics = new SessionMetrics(manager.telemetry);
@@ -363,6 +367,7 @@ async function apply(ctx, options = {}) {
363
367
  releases.push(ctx.llm.registerAdapter([provider], wrapper.adapter));
364
368
  }
365
369
  stopWatch = manager.watch(() => ctx.logger.warn("multi-router: invalid config change; keeping last valid configuration"));
370
+ await manager.api.reconcile();
366
371
  startup = (async () => {
367
372
  await manager.syncLocalAccounts().catch(() => ctx.logger.warn("multi-router: local login discovery failed; manual import remains available"));
368
373
  if (disposed) return;
@@ -393,7 +398,7 @@ async function apply(ctx, options = {}) {
393
398
  stopWatch?.();
394
399
  manager?.runtime?.stop();
395
400
  for (const release of releases) release();
396
- await Promise.all(shims.map((shim) => shim.close()));
401
+ await Promise.all([manager?.api.close(), ...shims.map((shim) => shim.close())]);
397
402
  ctx.logger.error("multi-router: initialization failed", error.code ?? error.message);
398
403
  throw error;
399
404
  }
package/lib/host.js CHANGED
@@ -1,33 +1,36 @@
1
1
  import {
2
2
  createShim
3
- } from "./chunk-P43AWJ4Q.js";
3
+ } from "./chunk-LLDJVBTQ.js";
4
4
  import {
5
5
  MANAGEMENT_PATH,
6
6
  Manager,
7
7
  PluginReload,
8
+ SUMMARY_PATH,
8
9
  managementHandler,
9
10
  version
10
- } from "./chunk-I4EW5TI7.js";
11
+ } from "./chunk-OCMOMSB4.js";
11
12
  import {
12
13
  createAccountClient
13
- } from "./chunk-U2MU2M5C.js";
14
- import "./chunk-S6ZQ45SS.js";
15
- import "./chunk-FTM7RHQV.js";
14
+ } from "./chunk-NSKCFVHP.js";
15
+ import "./chunk-JUOESKAK.js";
16
+ import "./chunk-OK2T2UAZ.js";
17
+ import {
18
+ normalizeCredits
19
+ } from "./chunk-TEZ2FMEO.js";
16
20
  import "./chunk-S5KMFAQM.js";
21
+ import "./chunk-SNEZMYNU.js";
22
+ import "./chunk-4V52V5GO.js";
17
23
  import "./chunk-DNQPZMPF.js";
18
24
  import {
19
25
  Router,
20
26
  SessionMetrics,
21
27
  abortable
22
- } from "./chunk-J3XO7RTF.js";
28
+ } from "./chunk-ROZINFTV.js";
23
29
  import {
24
30
  PROVIDERS,
25
31
  PROVIDER_NAMES,
26
32
  ensureConfig
27
- } from "./chunk-MCHV2R25.js";
28
- import {
29
- normalizeCredits
30
- } from "./chunk-TEZ2FMEO.js";
33
+ } from "./chunk-WVNY4LSL.js";
31
34
 
32
35
  // src/index.mjs
33
36
  import z from "@deepseek-ai/schemastery";
@@ -265,7 +268,7 @@ async function apply(ctx, options = {}) {
265
268
  manager?.checkins.abort.abort();
266
269
  manager?.workbuddyLogin.abort.abort();
267
270
  for (const release of releases) release();
268
- return Promise.all([...shims.map((shim) => shim.close()), ...manager?.refreshes.values() ?? [], ...manager?.monitorFlights.values() ?? [], startup, manager?.localScan, manager?.checkins.flight, manager?.plugins.flight, manager?.plugins.saveQueue.catch(() => {
271
+ return Promise.all([manager?.api.close(), ...shims.map((shim) => shim.close()), ...manager?.refreshes.values() ?? [], ...manager?.monitorFlights.values() ?? [], startup, manager?.localScan, manager?.checkins.flight, manager?.plugins.flight, manager?.plugins.saveQueue.catch(() => {
269
272
  }), manager?.telemetry.queue.catch(() => {
270
273
  })]);
271
274
  });
@@ -291,9 +294,10 @@ async function apply(ctx, options = {}) {
291
294
  profile: () => ctx.get("profileContext"),
292
295
  canReload: () => !!ctx.get("hmr"),
293
296
  hmr: () => ctx.get("hmr"),
294
- busy: () => !!(manager.localScan || manager.requests || manager.plugins.flight || manager.checkins.flight || manager.workbuddyLogin.flight || manager.workbuddyLogin.pending || manager.refreshes.size || manager.monitorFlights.size || shims.some((s) => s.active()))
297
+ busy: () => !!(manager.localScan || manager.requests || manager.api.controllers.size || manager.plugins.flight || manager.checkins.flight || manager.workbuddyLogin.flight || manager.workbuddyLogin.pending || manager.refreshes.size || manager.monitorFlights.size || shims.some((s) => s.active()))
295
298
  });
296
299
  ctx.inject?.(["webServer"], (webCtx) => {
300
+ webCtx.effect(() => webCtx.webServer.register({ kind: "exact", path: SUMMARY_PATH, handler: managementHandler(manager, { summaryOnly: true }) }));
297
301
  webCtx.effect(() => webCtx.webServer.register({ kind: "exact", path: MANAGEMENT_PATH, handler: managementHandler(manager) }));
298
302
  });
299
303
  const metrics = new SessionMetrics(manager.telemetry);
@@ -363,6 +367,7 @@ async function apply(ctx, options = {}) {
363
367
  releases.push(ctx.llm.registerAdapter([provider], wrapper.adapter));
364
368
  }
365
369
  stopWatch = manager.watch(() => ctx.logger.warn("multi-router: invalid config change; keeping last valid configuration"));
370
+ await manager.api.reconcile();
366
371
  startup = (async () => {
367
372
  await manager.syncLocalAccounts().catch(() => ctx.logger.warn("multi-router: local login discovery failed; manual import remains available"));
368
373
  if (disposed) return;
@@ -393,7 +398,7 @@ async function apply(ctx, options = {}) {
393
398
  stopWatch?.();
394
399
  manager?.runtime?.stop();
395
400
  for (const release of releases) release();
396
- await Promise.all(shims.map((shim) => shim.close()));
401
+ await Promise.all([manager?.api.close(), ...shims.map((shim) => shim.close())]);
397
402
  ctx.logger.error("multi-router: initialization failed", error.code ?? error.message);
398
403
  throw error;
399
404
  }
package/lib/index.js CHANGED
@@ -1,33 +1,36 @@
1
1
  import {
2
2
  createShim
3
- } from "./chunk-P43AWJ4Q.js";
3
+ } from "./chunk-LLDJVBTQ.js";
4
4
  import {
5
5
  MANAGEMENT_PATH,
6
6
  Manager,
7
7
  PluginReload,
8
+ SUMMARY_PATH,
8
9
  managementHandler,
9
10
  version
10
- } from "./chunk-I4EW5TI7.js";
11
+ } from "./chunk-OCMOMSB4.js";
11
12
  import {
12
13
  createAccountClient
13
- } from "./chunk-U2MU2M5C.js";
14
- import "./chunk-S6ZQ45SS.js";
15
- import "./chunk-FTM7RHQV.js";
14
+ } from "./chunk-NSKCFVHP.js";
15
+ import "./chunk-JUOESKAK.js";
16
+ import "./chunk-OK2T2UAZ.js";
17
+ import {
18
+ normalizeCredits
19
+ } from "./chunk-TEZ2FMEO.js";
16
20
  import "./chunk-S5KMFAQM.js";
21
+ import "./chunk-SNEZMYNU.js";
22
+ import "./chunk-4V52V5GO.js";
17
23
  import "./chunk-DNQPZMPF.js";
18
24
  import {
19
25
  Router,
20
26
  SessionMetrics,
21
27
  abortable
22
- } from "./chunk-J3XO7RTF.js";
28
+ } from "./chunk-ROZINFTV.js";
23
29
  import {
24
30
  PROVIDERS,
25
31
  PROVIDER_NAMES,
26
32
  ensureConfig
27
- } from "./chunk-MCHV2R25.js";
28
- import {
29
- normalizeCredits
30
- } from "./chunk-TEZ2FMEO.js";
33
+ } from "./chunk-WVNY4LSL.js";
31
34
 
32
35
  // src/index.mjs
33
36
  import z from "@deepseek-ai/schemastery";
@@ -265,7 +268,7 @@ async function apply(ctx, options = {}) {
265
268
  manager?.checkins.abort.abort();
266
269
  manager?.workbuddyLogin.abort.abort();
267
270
  for (const release of releases) release();
268
- return Promise.all([...shims.map((shim) => shim.close()), ...manager?.refreshes.values() ?? [], ...manager?.monitorFlights.values() ?? [], startup, manager?.localScan, manager?.checkins.flight, manager?.plugins.flight, manager?.plugins.saveQueue.catch(() => {
271
+ return Promise.all([manager?.api.close(), ...shims.map((shim) => shim.close()), ...manager?.refreshes.values() ?? [], ...manager?.monitorFlights.values() ?? [], startup, manager?.localScan, manager?.checkins.flight, manager?.plugins.flight, manager?.plugins.saveQueue.catch(() => {
269
272
  }), manager?.telemetry.queue.catch(() => {
270
273
  })]);
271
274
  });
@@ -291,9 +294,10 @@ async function apply(ctx, options = {}) {
291
294
  profile: () => ctx.get("profileContext"),
292
295
  canReload: () => !!ctx.get("hmr"),
293
296
  hmr: () => ctx.get("hmr"),
294
- busy: () => !!(manager.localScan || manager.requests || manager.plugins.flight || manager.checkins.flight || manager.workbuddyLogin.flight || manager.workbuddyLogin.pending || manager.refreshes.size || manager.monitorFlights.size || shims.some((s) => s.active()))
297
+ busy: () => !!(manager.localScan || manager.requests || manager.api.controllers.size || manager.plugins.flight || manager.checkins.flight || manager.workbuddyLogin.flight || manager.workbuddyLogin.pending || manager.refreshes.size || manager.monitorFlights.size || shims.some((s) => s.active()))
295
298
  });
296
299
  ctx.inject?.(["webServer"], (webCtx) => {
300
+ webCtx.effect(() => webCtx.webServer.register({ kind: "exact", path: SUMMARY_PATH, handler: managementHandler(manager, { summaryOnly: true }) }));
297
301
  webCtx.effect(() => webCtx.webServer.register({ kind: "exact", path: MANAGEMENT_PATH, handler: managementHandler(manager) }));
298
302
  });
299
303
  const metrics = new SessionMetrics(manager.telemetry);
@@ -363,6 +367,7 @@ async function apply(ctx, options = {}) {
363
367
  releases.push(ctx.llm.registerAdapter([provider], wrapper.adapter));
364
368
  }
365
369
  stopWatch = manager.watch(() => ctx.logger.warn("multi-router: invalid config change; keeping last valid configuration"));
370
+ await manager.api.reconcile();
366
371
  startup = (async () => {
367
372
  await manager.syncLocalAccounts().catch(() => ctx.logger.warn("multi-router: local login discovery failed; manual import remains available"));
368
373
  if (disposed) return;
@@ -393,7 +398,7 @@ async function apply(ctx, options = {}) {
393
398
  stopWatch?.();
394
399
  manager?.runtime?.stop();
395
400
  for (const release of releases) release();
396
- await Promise.all(shims.map((shim) => shim.close()));
401
+ await Promise.all([manager?.api.close(), ...shims.map((shim) => shim.close())]);
397
402
  ctx.logger.error("multi-router: initialization failed", error.code ?? error.message);
398
403
  throw error;
399
404
  }
package/lib/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.mjs", "../upstream/workbuddy/src/adapter.ts"],
4
- "sourcesContent": ["import z from '@deepseek-ai/schemastery';\nimport { resolveDshHome } from '@deepseek-ai/dsh-home-paths';\nimport { resolveRetryPolicy, resolveImageAttachmentAccess } from '@deepseek-ai/dsh-llm';\nimport { join, resolve } from 'node:path';\nimport { createWorkBuddyAdapter } from '../upstream/workbuddy/src/adapter.ts';\nimport { ensureConfig, PROVIDERS, PROVIDER_NAMES } from './config.mjs';\nimport { createAccountClient } from './clients.mjs';\nimport { SessionMetrics } from './telemetry.mjs';\nimport { Router, abortable } from './router.mjs';\nimport { createShim } from './shim.mjs';\nimport { Manager, managementHandler, MANAGEMENT_PATH } from './manager.mjs';\nimport { PluginReload } from './plugin-reload.mjs';\nimport { version as pluginVersion } from '../package.json';\n\nexport const name = 'dsh-multi-router';\nexport const inject = ['llm'];\nexport const defaultConfigFile = () => join(resolveDshHome(), 'multi-router', 'router.json');\nexport const Config = z.object({ configFile: z.string().description('Absolute path to multi-account router.json') });\nexport async function apply(ctx, options = {}) {\n let disposed = false, manager, stopWatch, monitorTimer, startup;\n const releases = [], shims = [], wrappers = [];\n ctx.effect(() => () => {\n disposed = true; stopWatch?.(); clearInterval(monitorTimer); manager?.runtime?.stop();\n if (manager) manager.closed = true;\n manager?.plugins.abort.abort();\n manager?.checkins.abort.abort();\n manager?.workbuddyLogin.abort.abort();\n for (const release of releases) release();\n return Promise.all([...shims.map(shim => shim.close()), ...(manager?.refreshes.values() ?? []), ...(manager?.monitorFlights.values() ?? []), startup, manager?.localScan, manager?.checkins.flight, manager?.plugins.flight, manager?.plugins.saveQueue.catch(() => {}), manager?.telemetry.queue.catch(() => {})]);\n });\n const file = resolve(options.configFile ?? process.env.DSH_MULTI_ROUTER_CONFIG ?? defaultConfigFile());\n try {\n const config = await ensureConfig(file);\n if (disposed) return;\n const router = new Router(config, a => createAccountClient(a, manager?.config ?? config, ctx.get('attachments')),\n event => ctx.logger.info('multi-router', JSON.stringify(event)));\n manager = new Manager(file, router, () => {\n for (const wrapper of wrappers) wrapper.invalidate();\n ctx.emit('llm/adapters-updated');\n }, { service: () => ctx.get('pluginManager'), profile: () => ctx.get('profileContext'), hmr: () => ctx.get('hmr') });\n await manager.load();\n if (disposed) return;\n manager.startup = { phase: 'discovering' };\n manager.runtime = new PluginReload({ runningVersion: pluginVersion, service: () => ctx.get('pluginManager'), profile: () => ctx.get('profileContext'), canReload: () => !!ctx.get('hmr'), hmr: () => ctx.get('hmr'),\n busy: () => !!(manager.localScan || manager.requests || manager.plugins.flight || manager.checkins.flight || manager.workbuddyLogin.flight || manager.workbuddyLogin.pending || manager.refreshes.size || manager.monitorFlights.size || shims.some(s => s.active())) });\n ctx.inject?.(['webServer'], webCtx => {\n webCtx.effect(() => webCtx.webServer.register({ kind: 'exact', path: MANAGEMENT_PATH, handler: managementHandler(manager) }));\n });\n const metrics = new SessionMetrics(manager.telemetry);\n ctx.on('session/event', (session, event) => { try { return metrics.event(session, event)?.catch(() => ctx.logger.warn('multi-router: performance persistence failed')); } catch { ctx.logger.warn('multi-router: performance event unavailable'); } });\n ctx.on('session/disposed', session => metrics.dispose(session));\n for (const provider of ['multi-router', ...PROVIDERS]) {\n if (disposed) return;\n const isRouter = provider === 'multi-router';\n const shim = createShim(router, { modelPrefix: isRouter ? '' : `${provider}::` });\n shims.push(shim); await shim.ready;\n if (disposed) { await shim.close(); return; }\n const wrapper = createWorkBuddyAdapter({ providerId: provider,\n displayName: isRouter ? '\u7EDF\u4E00\u8DEF\u7531' : `${PROVIDER_NAMES[provider]} \u00B7 \u5185\u7F6E\u8D26\u53F7\u6C60`, shim,\n catalog: { current: () => isRouter ? manager.adapterModels() : manager.providerModels(provider) },\n hidden: () => isRouter ? manager.adapterModels().filter(r => r.visible === false).map(r => r.id) : manager.hiddenModels(provider),\n region: provider.endsWith('global') || provider === 'workbuddy-ai' ? 'global' : 'cn',\n resolveAttachments: () => ctx.get('attachments'),\n resolveImageAccess: (attachments, ref) => resolveImageAttachmentAccess(attachments,\n path => ctx.get('fs')?.processPathFromHostPath(path), ref) });\n if (!isRouter) {\n // Discovery and transport are bundled here; no call uses another DSH provider adapter.\n for (const method of ['listModels', 'resolveModel', 'prepareCall']) {\n const original = wrapper.adapter[method].bind(wrapper.adapter);\n wrapper.adapter[method] = async (...args) => { await abortable(manager.ensureCatalog(provider), args[2]); return original(...args); };\n }\n }\n // pi-ai omits explicit Off before serialization. Keep each call's selection\n // in its own snapshot/header so Default, Off and configured defaults stay distinct.\n const streamWithSnapshot = wrapper.adapter.streamWithSnapshot.bind(wrapper.adapter);\n wrapper.adapter.streamWithSnapshot = (options, snapshot) => {\n const call = metrics.beginCall(options.sessionId, options.purpose);\n const route = router.config.routes[(isRouter ? '' : `${provider}::`) + options.model];\n const effort = options.reasoningEffort ?? route?.reasoningEffort;\n const profiles = new Map(snapshot.profiles), profile = profiles.get(options.provider);\n if (!profile) return streamWithSnapshot(options, snapshot);\n profiles.set(options.provider, { ...profile, headers: { ...profile.headers, 'X-Multi-Router-Reasoning': effort ?? 'default', 'X-Multi-Router-Call': call.callId, ...(call.session ? { 'X-Multi-Router-Session': call.session } : {}) } });\n return streamWithSnapshot({ ...options, ...(effort ? { reasoningEffort: effort } : {}) }, { ...snapshot, profiles });\n };\n const withDefault = model => {\n const effort = router.config.routes[(isRouter ? '' : `${provider}::`) + model.id]?.reasoningEffort;\n return effort && model.reasoning ? { ...model, reasoning: { ...model.reasoning, defaultEffort: effort } } : model;\n };\n const resolveModel = wrapper.adapter.resolveModel.bind(wrapper.adapter), prepareCall = wrapper.adapter.prepareCall.bind(wrapper.adapter);\n wrapper.adapter.resolveModel = async (...args) => withDefault(await resolveModel(...args));\n wrapper.adapter.prepareCall = async (...args) => { const prepared = await prepareCall(...args); return { ...prepared, model: withDefault(prepared.model) }; };\n wrapper.adapter.providerRetryPolicy = () => resolveRetryPolicy({ mode: 'normal', maxRetries: 0 }, provider);\n wrappers.push(wrapper);\n releases.push(ctx.llm.registerAdapter([provider], wrapper.adapter));\n }\n stopWatch = manager.watch(() => ctx.logger.warn('multi-router: invalid config change; keeping last valid configuration'));\n // Desktop helpers, network probes and inventory scans must not block the\n // settings endpoint or activation. Cached routes are usable immediately.\n startup = (async () => {\n await manager.syncLocalAccounts().catch(() => ctx.logger.warn('multi-router: local login discovery failed; manual import remains available'));\n if (disposed) return;\n await manager.finishInitialSetup().catch(() => ctx.logger.warn('multi-router: first-install guidance could not be saved'));\n if (disposed) return;\n manager.startup = { phase: 'ready' };\n manager.checkins.tick();\n void manager.checkFreeModels().catch(() => ctx.logger.warn('multi-router: free catalog persistence failed'));\n void manager.monitorAll().catch(() => ctx.logger.warn('multi-router: usage persistence failed'));\n })();\n void manager.plugins.tick().catch(() => ctx.logger.warn('multi-router: automatic update check unavailable'));\n manager.runtime.start();\n ctx.on('plugin-manager/changed', () => manager.runtime.schedule());\n monitorTimer = setInterval(() => { void manager.syncLocalAccounts().then(() => { if (!disposed) return manager.monitorAll(); }).catch(() => ctx.logger.warn('multi-router: local login discovery or usage persistence failed'));\n manager.checkins.tick();\n void manager.plugins.tick().catch(() => ctx.logger.warn('multi-router: automatic update check unavailable'));\n void manager.checkFreeModels().catch(() => ctx.logger.warn('multi-router: free catalog persistence failed'));\n void manager.runtime.check().catch(() => {}); }, 60000);\n monitorTimer.unref();\n ctx.emit('llm/adapters-updated');\n } catch (error) {\n clearInterval(monitorTimer); stopWatch?.(); manager?.runtime?.stop(); for (const release of releases) release();\n await Promise.all(shims.map(shim => shim.close()));\n ctx.logger.error('multi-router: initialization failed', error.code ?? error.message);\n throw error;\n }\n}\n", "/**\n * The `workbuddy` pi-ai provider: one loopback-backed adapter registered\n * into the Harness LLM seam, assembled from public `dsh-llm-pi-ai`\n * extension points the way `dsh-codex-connect` assembles its Codex route.\n *\n * @module dsh-workbuddy-connect/adapter\n */\n\nimport { createProvider } from '@earendil-works/pi-ai'\nimport type { Api, AuthContext, CredentialStore, Model, ModelThinkingLevel, Provider, ThinkingLevelMap } from '@earendil-works/pi-ai'\nimport { openAICompletionsApi } from '@earendil-works/pi-ai/api/openai-completions.lazy'\nimport { resolveRetryPolicy } from '@deepseek-ai/dsh-llm'\nimport type { LlmModelInfo, LlmResolvedModelInfo } from '@deepseek-ai/dsh-llm'\nimport { PiAiAdapter } from '@deepseek-ai/dsh-llm-pi-ai'\nimport type { PiAiAdapterOptions, ResolvedPiAiProviderProfile } from '@deepseek-ai/dsh-llm-pi-ai'\nimport type { AttachmentStore } from '@deepseek-ai/dsh-attachment'\nimport type { WorkBuddyCredentialStore } from './auth.ts'\nimport type { WorkBuddyCatalog, WorkBuddyModelInfo } from './catalog.ts'\nimport type { WorkBuddyProbeRecord } from './probe-store.ts'\nimport type { WorkBuddyShim } from './shim.ts'\nimport { normalizeCredits, type WorkBuddyRegion } from './upstream.ts'\n\n/** Provider route this bundle owns. */\nexport const WORKBUDDY_PROVIDER = 'workbuddy'\n\n/** Provider idle ceiling while one stream read is outstanding. */\nexport const WORKBUDDY_STREAM_IDLE_TIMEOUT_MS = 300_000\n\n/**\n * Image-request budgets at the dsh-llm-pi-ai defaults; the profile type made\n * them required in 0.1.1-rc.2. They bound requests to models whose catalog\n * entry declares `supportsImages`; text-only models never receive images.\n */\nconst REQUEST_IMAGE_BUDGETS = {\n maxRequestImageBytes: 20_971_520,\n requestImagePixelBudget: 4_194_304,\n requestImageMaxBytes: 1_048_576,\n} as const\n\n/**\n * Inert pi-ai auth plane. The workbuddy route authenticates only through the\n * shim shared secret resolved per request by `resolveApiKey`, so pi-ai's own\n * credential lifecycle and ambient discovery must never manufacture a\n * credential for it. `PiAiAdapterOptions.auth` is required since 0.1.1-rc.2;\n * every ambient question here answers \"nothing stored, nothing set\".\n */\nconst INERT_AUTH: { credentials: CredentialStore; authContext: AuthContext } = {\n credentials: {\n async read() { return undefined },\n async list() { return [] },\n async modify() {\n throw new Error('dsh-workbuddy-connect: the workbuddy route has no pi-ai credential lifecycle')\n },\n async delete() {},\n },\n authContext: {\n async env() { return undefined },\n async fileExists() { return false },\n },\n}\n\n/** No per-token pricing is knowable for a subscription quota; report zero. */\nconst NO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 } as const\n\n/**\n * Translate the request-image contract across the two attachment-service\n * generations a link-installed plugin can straddle.\n *\n * A `link:` install resolves its platform imports from the *repository's*\n * node_modules (Node follows the symlink's real path), so this adapter always\n * runs against the pi-ai it was built with \u2014 while the attachment service\n * comes from the host. Those two generations disagree on what\n * `readImageRequest(ref, policyOrTarget)` receives:\n *\n * - dsh-attachment-local \u22640.1.5: a route policy `{ maxPixels, maxBytes }`,\n * and `validatePolicy` throws `Image request maxPixels must be a positive\n * integer.` when `maxPixels` is missing.\n * - 0.1.6+: a per-image target `{ width, height, maxBytes }` with no\n * `maxPixels` at all, validated by `validateTarget`.\n *\n * A 0.1.6-built pi-ai on a 0.1.5 host therefore hands the old store a target\n * the old store rejects, and every image-bearing request fails before it is\n * sent. The wrapper below fills the route's own pixel budget into a target\n * that lacks it: the 0.1.5 store then computes the same dimensions pi-ai's\n * budget already chose, and a 0.1.6 store ignores the extra key.\n */\nfunction withLegacyImageBudget(store: AttachmentStore): AttachmentStore {\n return new Proxy(store, {\n get(target, property, receiver) {\n if (property === 'imageHostPath') {\n // The access resolver calls through this proxy; keep the concrete\n // store as `this` for implementations that use private fields.\n return target.imageHostPath.bind(target)\n }\n if (property !== 'readImageRequest') return Reflect.get(target, property, receiver)\n return (...args: Parameters<AttachmentStore['readImageRequest']>) => {\n const [ref, policy, signal] = args\n // The \u22640.1.5 store's own validity rule is \"safe integer AND positive\";\n // a present-but-non-positive maxPixels would pass an isSafeInteger-only\n // check and still be rejected there, so it is replaced too.\n const present = (policy as { maxPixels?: number } | undefined)?.maxPixels\n const withPixels = Number.isSafeInteger(present) && (present as number) > 0\n ? policy\n : { ...policy, maxPixels: REQUEST_IMAGE_BUDGETS.requestImagePixelBudget } as typeof policy\n return target.readImageRequest(ref, withPixels, signal)\n }\n },\n })\n}\n\n/**\n * The suffix appended to a model's display name so its billing rate is visible\n * wherever the name is shown.\n *\n * The separator is a middle dot rather than a hyphen or colon: model names\n * already contain hyphens (`GLM-5.3-Flash`, `Deepseek-V4-Flash`), so a hyphen\n * separator would be ambiguous about where the name ends and the rate begins.\n */\nconst RATE_SEPARATOR = ' \u00B7 '\n\n/**\n * Append the billing rate to one model's display name.\n *\n * The rate AND the declared promo badges ride the *name* alone: since DSH\n * 0.1.2 the composer's model seat (`ModelSelect`) renders `model.name` only \u2014\n * `description` is no longer read there at all (the 0.1.1-era client rendered\n * it, which is why the badges used to be visible in the seat). The `/model`\n * popup renders the name too, so a separate `description` copy would either\n * duplicate (rate) or vanish (badges) depending on client generation.\n *\n * This is display-only and cannot affect routing: the wire request is built\n * from `model.id` (pi-ai's completions API sets `model: model.id`), the\n * selection a picker submits is `{provider, model: id, reasoningEffort}`, and\n * `dsh-llm` validates `name` as a non-empty string without comparing its\n * contents. Nothing in the host resolves a model *by* name.\n */\n\n/**\n * The catalog display suffix: the billing rate followed by the declared promo\n * badges (`\u9650\u65F6\u514D\u8D39`, `\u591C\u95F4\u6298\u6263`), or undefined when the row carries neither.\n * The badge labels are the upstream's own spellings and the host seam has no\n * locale service, so non-Chinese UIs see them verbatim \u2014 accepted until the\n * picker grows a localized badge slot.\n */\nfunction displaySuffix(info: WorkBuddyModelInfo): string | undefined {\n const parts = [\n normalizeCredits(info.billing?.credits),\n ...(info.billing?.badges ?? []),\n ].filter((part): part is string => part !== undefined && part !== '')\n return parts.length === 0 ? undefined : parts.join(' \u00B7 ')\n}\n\n/** Append the catalog display suffix to one model's display name. */\nfunction withCatalogDisplay(name: string, info: WorkBuddyModelInfo): string {\n const suffix = displaySuffix(info)\n return suffix === undefined ? name : `${name}${RATE_SEPARATOR}${suffix}`\n}\n\n/** Constructor dependencies. */\nexport interface WorkBuddyAdapterOptions {\n providerId?: string\n displayName?: string\n /**\n * Which endpoint this adapter serves, from the variant descriptor. Decides\n * only whether the CN `onlyReasoning` veto hides `off` (#87); defaults to\n * `'cn'`, the same legacy default `providerId` carries.\n */\n region?: WorkBuddyRegion\n shim: WorkBuddyShim\n store: WorkBuddyCredentialStore\n catalog: WorkBuddyCatalog\n /** Resolve the durable attachment service at request time, when present. */\n resolveAttachments?: () => AttachmentStore | undefined\n /** Resolve one image's path in the current model-tool execution world. */\n resolveImageAccess?: NonNullable<PiAiAdapterOptions['resolveImageAccess']>\n /**\n * Look up a local probe observation for a model. Consulted only for rows the\n * upstream left undeclared; absent means declared-set-only behavior.\n */\n observe?: (modelId: string) => WorkBuddyProbeRecord | undefined\n /**\n * Model ids the current account has hidden from the picker, resolved per\n * read so an account switch is honored without rebuilding the adapter.\n *\n * Hiding is a *listing* concern only: `buildModels()` keeps serving the full\n * catalog because pi-ai's `resolveModel`/`prepareCall` resolve from the same\n * snapshot `listModels` reads \u2014 filtering the descriptors there would make a\n * hidden model unresolvable and break sessions already using it. The filter\n * therefore lives in this adapter's `listModels` override alone.\n */\n hidden?: () => readonly string[]\n}\n\n/** What {@link createWorkBuddyAdapter} hands back. */\nexport interface WorkBuddyAdapter {\n adapter: PiAiAdapter\n /** Rebuild the adapter's provider snapshot; call after a catalog update. */\n invalidate: () => void\n}\n\n/**\n * Resolve a WorkBuddy model's reasoning capability into pi-ai's\n * `thinkingLevelMap` (every level pinned to its wire spelling or `null` for\n * unsupported), mirroring `dsh-llm-pi-ai`'s own `resolveModelReasoning`.\n *\n * Two sources, strictly ordered (`docs/reasoning-effort-probe-plan.md` \u00A75):\n *\n * 1. **The declared set.** When the upstream declares a non-empty\n * `supportedEfforts`, exactly those values are offered and nothing else.\n * This always wins: an observation never widens or narrows a declared set.\n * 2. **A local observation.** Rows without a declared set (the older\n * `{effort, summary}` shape) normally get no control at all \u2014 their\n * selectable set is client-side knowledge the catalog does not carry, and\n * the desktop app differs per model there. If the user authorized a probe\n * and it established that the upstream *validates* the parameter, the\n * verified spellings are offered.\n *\n * A `non-validating` observation deliberately yields no control: the upstream\n * accepts values that cannot exist (measured on `glm-5.2`), so every per-level\n * acceptance it produced would be a false positive.\n *\n * `off` is offered only when the upstream declares `canDisableThinking: true`.\n * It is never probed \u2014 disabling thinking is a separate capability, and the\n * per-model acceptance of `off` cannot be inferred from the row's shape.\n *\n * The CN endpoint vetoes `off` further, on models declaring `onlyReasoning`\n * (#87) \u2014 see {@link region} below. That rule is deliberately region-scoped:\n * the contradiction it resolves was measured on the CN catalog, and applying\n * it everywhere would have changed which levels the international picker\n * offers, which is outside this issue.\n *\n * The offered set is described internally as \"verified accepted\", never as\n * \"verified effective\": acceptance proves the upstream did not reject the\n * spelling, not that it changes what the model does.\n *\n * @param region - the endpoint this descriptor is for. Decides only whether\n * the `onlyReasoning` veto applies; every other rule is shared. Passed from\n * the variant descriptor, never inferred from a model id or a name.\n */\nexport function reasoningFields(\n info: WorkBuddyModelInfo,\n observed?: WorkBuddyProbeRecord,\n region: WorkBuddyRegion = 'cn',\n): { reasoning: boolean; thinkingLevelMap?: ThinkingLevelMap } {\n const reasoning = info.reasoning\n if (reasoning === undefined || reasoning.supports !== true) {\n // Not a reasoning model: pi-ai reads a falsy `reasoning` as \"off only\".\n return { reasoning: false }\n }\n const declared = reasoning.supportedEfforts\n const efforts = declared !== undefined && declared.length > 0\n ? declared\n // Only a validating observation may supply a set, and only for rows the\n // upstream left undeclared.\n : observed?.validation === 'validating' && observed.efforts.length > 0\n ? observed.efforts\n : undefined\n if (efforts === undefined) {\n // Undeclared and unobserved (or observed as non-validating): no thinking\n // control, and no `reasoning_effort` on the wire.\n return { reasoning: false }\n }\n const map: Record<ModelThinkingLevel, string | null> = {\n // Probing never grants `off`; only an explicit declaration does.\n //\n // On CN, `onlyReasoning` vetoes it even when declared (#87). That catalog\n // ships both flags true on `deepseek-v4.1-flash` and `kimi-k2.8-preview`,\n // which cannot both hold \u2014 a model that only ever reasons has no\n // non-thinking mode to select \u2014 and the endpoint sides with\n // `onlyReasoning`, answering HTTP 400 (\u300C\u6A21\u578B\u4E0D\u652F\u6301\u8BE5\u601D\u8003\u5F3A\u5EA6\u300D) for every\n // `off` request. Offering a level that is certain to fail is worse than not\n // offering it, so the contradiction is resolved toward the flag the wire\n // agrees with.\n //\n // Scoped to CN on purpose: the international catalog does not carry this\n // contradiction, and hiding Off there would remove a level those models\n // can still use. The request layer strips the spelling in both regions\n // (`dropUnsupportedEffort`), so a model whose flags flip between catalog\n // reads cannot put `off` on the wire either way.\n off: reasoning.canDisableThinking === true\n && (region !== 'cn' || reasoning.onlyReasoning !== true)\n && declared !== undefined && declared.length > 0 ? 'off' : null,\n // `minimal` is not in the upstream effort vocabulary (EFFORT_VALUES), so\n // no declared set \u2014 and no probe candidate \u2014 can ever contain it.\n minimal: null,\n low: efforts.includes('low') ? 'low' : null,\n medium: efforts.includes('medium') ? 'medium' : null,\n high: efforts.includes('high') ? 'high' : null,\n xhigh: efforts.includes('xhigh') ? 'xhigh' : null,\n max: efforts.includes('max') ? 'max' : null,\n }\n return { reasoning: true, thinkingLevelMap: map as ThinkingLevelMap }\n}\n\n/** Build one pi-ai model descriptor pointing at the loopback shim. */\nfunction toPiModel(info: WorkBuddyModelInfo, baseUrl: string, observed: WorkBuddyProbeRecord | undefined, providerId: string, region: WorkBuddyRegion): Model<Api> {\n return {\n id: info.id,\n name: info.name,\n api: 'openai-completions',\n provider: providerId,\n baseUrl,\n input: info.supportsImages === true ? ['text', 'image'] : ['text'],\n ...reasoningFields(info, observed, region),\n cost: NO_COST,\n contextWindow: info.contextWindow,\n maxTokens: info.maxTokens,\n // pi-ai cannot infer WorkBuddy's field spelling from the shim's random\n // loopback URL, so name the upstream-required field explicitly.\n compat: { maxTokensField: 'max_tokens' },\n } as unknown as Model<Api>\n}\n\n/**\n * Assemble the adapter. The provider's `getModels` reads the live catalog,\n * and every model's `baseUrl` is re-resolved per read so the shim's\n * ephemeral port applies from the first snapshot after startup.\n *\n * The profile is constructed by hand rather than through dsh-llm-pi-ai's\n * internal `resolveProfiles()`: that helper is not part of the package's\n * public export surface (root entry, `lib/` deep imports blocked by the\n * exports map, `src/` not shipped), so hand-assembly is the only supported\n * path and every newly required field must be adopted here explicitly \u2014\n * `modelErrors` since 0.1.5-alpha.2 (#12).\n */\nexport function createWorkBuddyAdapter(options: WorkBuddyAdapterOptions): WorkBuddyAdapter {\n const { shim, store, catalog, resolveAttachments, resolveImageAccess, observe, hidden } = options\n const providerId = options.providerId ?? WORKBUDDY_PROVIDER\n const displayName = options.displayName ?? 'WorkBuddy'\n const region = options.region ?? 'cn'\n\n const buildModels = (): Model<Api>[] => {\n // The OpenAI SDK pi-ai drives appends `/chat/completions` to baseURL,\n // so the shim's routes line up with the `/v1` prefix in place.\n const baseUrl = `${shim.baseUrl()}/v1`\n return catalog.current().map(info => toPiModel(info, baseUrl, observe?.(info.id), providerId, region))\n }\n\n const base = createProvider({\n id: providerId,\n name: displayName,\n auth: {\n apiKey: {\n name: 'WorkBuddy OAuth bearer token',\n async resolve({ credential }) {\n const apiKey = credential?.key\n return apiKey === undefined || apiKey.length === 0\n ? undefined\n : { auth: { apiKey }, source: 'WorkBuddy' }\n },\n },\n },\n models: buildModels(),\n api: openAICompletionsApi(),\n })\n\n // `getModels` is delegated to a live read (the reuse-catalog pattern from\n // dsh-llm-pi-ai): stream dispatch still runs through the constructed\n // provider, while the catalog answer tracks the upstream refresh.\n const provider: Provider = { ...base, getModels: () => buildModels() }\n\n const profile: ResolvedPiAiProviderProfile = {\n provider: providerId,\n displayName,\n streamIdleTimeoutMs: WORKBUDDY_STREAM_IDLE_TIMEOUT_MS,\n retryPolicy: resolveRetryPolicy(undefined, 'dsh-workbuddy-connect retryPolicy'),\n configuredMaxTokens: new Map(),\n // Required since 0.1.5-alpha.2; the live catalog only exposes models that\n // probed successfully, so there is never a per-model failure to report.\n modelErrors: new Map(),\n ...REQUEST_IMAGE_BUDGETS,\n piProvider: provider,\n }\n\n let profiles = new Map<string, ResolvedPiAiProviderProfile>([[providerId, profile]])\n\n const adapter = new WorkBuddyPiAiAdapter(catalog, hidden ?? (() => []), {\n profiles: () => profiles,\n auth: INERT_AUTH,\n // Resolve the shim's per-process shared secret as the OpenAI apiKey so\n // pi-ai sends it as `Authorization: Bearer <shared-secret>`. The shim\n // validates this before forwarding and resolves the real WorkBuddy token\n // itself via the store, so the secret never reaches upstream.\n resolveApiKey: async () => shim.token(),\n // Every store the adapter hands to pi-ai passes the legacy-budget wrapper:\n // see withLegacyImageBudget \u2014 the mismatch it heals depends on which host\n // generation owns the attachment service, not on anything observable here.\n ...resolveAttachments === undefined\n ? {}\n : {\n resolveAttachments: () => {\n const store = resolveAttachments()\n return store === undefined ? undefined : withLegacyImageBudget(store)\n },\n },\n ...(resolveImageAccess === undefined ? {} : { resolveImageAccess }),\n })\n\n return {\n adapter,\n invalidate: () => {\n profiles = new Map<string, ResolvedPiAiProviderProfile>([[providerId, profile]])\n },\n }\n}\n\n/**\n * The WorkBuddy route's adapter: `PiAiAdapter` with the billing rate folded\n * into the catalog answers it returns to the DSH model pickers.\n *\n * `PiAiAdapter.listModels()` and `.resolveModel()` build their answers straight\n * from the pi-ai descriptors, which carry no billing fact, so the rate is\n * layered on here by looking the model up in the live catalog. Both overrides\n * delegate to `super` and then rewrite only the display fields, so streaming,\n * capability resolution, and effort mapping stay exactly as `dsh-llm-pi-ai`\n * implements them.\n *\n * A model missing from the catalog (an id the shim would serve but the last\n * upstream refresh did not list) falls through with its name untouched rather\n * than being dropped: catalog membership is advisory, and the seam tolerates\n * serving an unlisted id.\n */\nclass WorkBuddyPiAiAdapter extends PiAiAdapter {\n constructor(\n private readonly catalog: WorkBuddyCatalog,\n private readonly hidden: () => readonly string[],\n options: ConstructorParameters<typeof PiAiAdapter>[0],\n ) {\n super(options)\n }\n\n /** Catalog entry for one model id, or undefined when the catalog omits it. */\n private infoFor(model: string): WorkBuddyModelInfo | undefined {\n return this.catalog.current().find(entry => entry.id === model)\n }\n\n override async listModels(provider: string): Promise<readonly LlmModelInfo[]> {\n const models = await super.listModels(provider)\n // Resolved fresh per call: the picker reads this after every\n // `llm/adapters-updated`, so an account switch or a toggle takes effect on\n // the next read without rebuilding anything.\n const hidden = new Set(this.hidden())\n return models.flatMap(model => {\n // Selectability only \u2014 `resolveModel` below deliberately does not apply\n // this filter, so a session already using a hidden model keeps working.\n if (hidden.has(model.id)) return []\n const info = this.infoFor(model.id)\n if (info === undefined) return [model]\n return [{ ...model, name: withCatalogDisplay(model.name, info) }]\n })\n }\n\n override async resolveModel(provider: string, model: string, signal?: AbortSignal): Promise<LlmResolvedModelInfo> {\n const resolved = await super.resolveModel(provider, model, signal)\n const info = this.infoFor(model)\n if (info === undefined) return resolved\n return { ...resolved, name: withCatalogDisplay(resolved.name, info) }\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import z from '@deepseek-ai/schemastery';\nimport { resolveDshHome } from '@deepseek-ai/dsh-home-paths';\nimport { resolveRetryPolicy, resolveImageAttachmentAccess } from '@deepseek-ai/dsh-llm';\nimport { join, resolve } from 'node:path';\nimport { createWorkBuddyAdapter } from '../upstream/workbuddy/src/adapter.ts';\nimport { ensureConfig, PROVIDERS, PROVIDER_NAMES } from './config.mjs';\nimport { createAccountClient } from './clients.mjs';\nimport { SessionMetrics } from './telemetry.mjs';\nimport { Router, abortable } from './router.mjs';\nimport { createShim } from './shim.mjs';\nimport { Manager, managementHandler, MANAGEMENT_PATH, SUMMARY_PATH } from './manager.mjs';\nimport { PluginReload } from './plugin-reload.mjs';\nimport { version as pluginVersion } from '../package.json';\n\nexport const name = 'dsh-multi-router';\nexport const inject = ['llm'];\nexport const defaultConfigFile = () => join(resolveDshHome(), 'multi-router', 'router.json');\nexport const Config = z.object({ configFile: z.string().description('Absolute path to multi-account router.json') });\nexport async function apply(ctx, options = {}) {\n let disposed = false, manager, stopWatch, monitorTimer, startup;\n const releases = [], shims = [], wrappers = [];\n ctx.effect(() => () => {\n disposed = true; stopWatch?.(); clearInterval(monitorTimer); manager?.runtime?.stop();\n if (manager) manager.closed = true;\n manager?.plugins.abort.abort();\n manager?.checkins.abort.abort();\n manager?.workbuddyLogin.abort.abort();\n for (const release of releases) release();\n return Promise.all([manager?.api.close(), ...shims.map(shim => shim.close()), ...(manager?.refreshes.values() ?? []), ...(manager?.monitorFlights.values() ?? []), startup, manager?.localScan, manager?.checkins.flight, manager?.plugins.flight, manager?.plugins.saveQueue.catch(() => {}), manager?.telemetry.queue.catch(() => {})]);\n });\n const file = resolve(options.configFile ?? process.env.DSH_MULTI_ROUTER_CONFIG ?? defaultConfigFile());\n try {\n const config = await ensureConfig(file);\n if (disposed) return;\n const router = new Router(config, a => createAccountClient(a, manager?.config ?? config, ctx.get('attachments')),\n event => ctx.logger.info('multi-router', JSON.stringify(event)));\n manager = new Manager(file, router, () => {\n for (const wrapper of wrappers) wrapper.invalidate();\n ctx.emit('llm/adapters-updated');\n }, { service: () => ctx.get('pluginManager'), profile: () => ctx.get('profileContext'), hmr: () => ctx.get('hmr') });\n await manager.load();\n if (disposed) return;\n manager.startup = { phase: 'discovering' };\n manager.runtime = new PluginReload({ runningVersion: pluginVersion, service: () => ctx.get('pluginManager'), profile: () => ctx.get('profileContext'), canReload: () => !!ctx.get('hmr'), hmr: () => ctx.get('hmr'),\n busy: () => !!(manager.localScan || manager.requests || manager.api.controllers.size || manager.plugins.flight || manager.checkins.flight || manager.workbuddyLogin.flight || manager.workbuddyLogin.pending || manager.refreshes.size || manager.monitorFlights.size || shims.some(s => s.active())) });\n ctx.inject?.(['webServer'], webCtx => {\n webCtx.effect(() => webCtx.webServer.register({ kind: 'exact', path: SUMMARY_PATH, handler: managementHandler(manager, { summaryOnly: true }) }));\n webCtx.effect(() => webCtx.webServer.register({ kind: 'exact', path: MANAGEMENT_PATH, handler: managementHandler(manager) }));\n });\n const metrics = new SessionMetrics(manager.telemetry);\n ctx.on('session/event', (session, event) => { try { return metrics.event(session, event)?.catch(() => ctx.logger.warn('multi-router: performance persistence failed')); } catch { ctx.logger.warn('multi-router: performance event unavailable'); } });\n ctx.on('session/disposed', session => metrics.dispose(session));\n for (const provider of ['multi-router', ...PROVIDERS]) {\n if (disposed) return;\n const isRouter = provider === 'multi-router';\n const shim = createShim(router, { modelPrefix: isRouter ? '' : `${provider}::` });\n shims.push(shim); await shim.ready;\n if (disposed) { await shim.close(); return; }\n const wrapper = createWorkBuddyAdapter({ providerId: provider,\n displayName: isRouter ? '\u7EDF\u4E00\u8DEF\u7531' : `${PROVIDER_NAMES[provider]} \u00B7 \u5185\u7F6E\u8D26\u53F7\u6C60`, shim,\n catalog: { current: () => isRouter ? manager.adapterModels() : manager.providerModels(provider) },\n hidden: () => isRouter ? manager.adapterModels().filter(r => r.visible === false).map(r => r.id) : manager.hiddenModels(provider),\n region: provider.endsWith('global') || provider === 'workbuddy-ai' ? 'global' : 'cn',\n resolveAttachments: () => ctx.get('attachments'),\n resolveImageAccess: (attachments, ref) => resolveImageAttachmentAccess(attachments,\n path => ctx.get('fs')?.processPathFromHostPath(path), ref) });\n if (!isRouter) {\n // Discovery and transport are bundled here; no call uses another DSH provider adapter.\n for (const method of ['listModels', 'resolveModel', 'prepareCall']) {\n const original = wrapper.adapter[method].bind(wrapper.adapter);\n wrapper.adapter[method] = async (...args) => { await abortable(manager.ensureCatalog(provider), args[2]); return original(...args); };\n }\n }\n // pi-ai omits explicit Off before serialization. Keep each call's selection\n // in its own snapshot/header so Default, Off and configured defaults stay distinct.\n const streamWithSnapshot = wrapper.adapter.streamWithSnapshot.bind(wrapper.adapter);\n wrapper.adapter.streamWithSnapshot = (options, snapshot) => {\n const call = metrics.beginCall(options.sessionId, options.purpose);\n const route = router.config.routes[(isRouter ? '' : `${provider}::`) + options.model];\n const effort = options.reasoningEffort ?? route?.reasoningEffort;\n const profiles = new Map(snapshot.profiles), profile = profiles.get(options.provider);\n if (!profile) return streamWithSnapshot(options, snapshot);\n profiles.set(options.provider, { ...profile, headers: { ...profile.headers, 'X-Multi-Router-Reasoning': effort ?? 'default', 'X-Multi-Router-Call': call.callId, ...(call.session ? { 'X-Multi-Router-Session': call.session } : {}) } });\n return streamWithSnapshot({ ...options, ...(effort ? { reasoningEffort: effort } : {}) }, { ...snapshot, profiles });\n };\n const withDefault = model => {\n const effort = router.config.routes[(isRouter ? '' : `${provider}::`) + model.id]?.reasoningEffort;\n return effort && model.reasoning ? { ...model, reasoning: { ...model.reasoning, defaultEffort: effort } } : model;\n };\n const resolveModel = wrapper.adapter.resolveModel.bind(wrapper.adapter), prepareCall = wrapper.adapter.prepareCall.bind(wrapper.adapter);\n wrapper.adapter.resolveModel = async (...args) => withDefault(await resolveModel(...args));\n wrapper.adapter.prepareCall = async (...args) => { const prepared = await prepareCall(...args); return { ...prepared, model: withDefault(prepared.model) }; };\n wrapper.adapter.providerRetryPolicy = () => resolveRetryPolicy({ mode: 'normal', maxRetries: 0 }, provider);\n wrappers.push(wrapper);\n releases.push(ctx.llm.registerAdapter([provider], wrapper.adapter));\n }\n stopWatch = manager.watch(() => ctx.logger.warn('multi-router: invalid config change; keeping last valid configuration'));\n await manager.api.reconcile();\n // Desktop helpers, network probes and inventory scans must not block the\n // settings endpoint or activation. Cached routes are usable immediately.\n startup = (async () => {\n await manager.syncLocalAccounts().catch(() => ctx.logger.warn('multi-router: local login discovery failed; manual import remains available'));\n if (disposed) return;\n await manager.finishInitialSetup().catch(() => ctx.logger.warn('multi-router: first-install guidance could not be saved'));\n if (disposed) return;\n manager.startup = { phase: 'ready' };\n manager.checkins.tick();\n void manager.checkFreeModels().catch(() => ctx.logger.warn('multi-router: free catalog persistence failed'));\n void manager.monitorAll().catch(() => ctx.logger.warn('multi-router: usage persistence failed'));\n })();\n void manager.plugins.tick().catch(() => ctx.logger.warn('multi-router: automatic update check unavailable'));\n manager.runtime.start();\n ctx.on('plugin-manager/changed', () => manager.runtime.schedule());\n monitorTimer = setInterval(() => { void manager.syncLocalAccounts().then(() => { if (!disposed) return manager.monitorAll(); }).catch(() => ctx.logger.warn('multi-router: local login discovery or usage persistence failed'));\n manager.checkins.tick();\n void manager.plugins.tick().catch(() => ctx.logger.warn('multi-router: automatic update check unavailable'));\n void manager.checkFreeModels().catch(() => ctx.logger.warn('multi-router: free catalog persistence failed'));\n void manager.runtime.check().catch(() => {}); }, 60000);\n monitorTimer.unref();\n ctx.emit('llm/adapters-updated');\n } catch (error) {\n clearInterval(monitorTimer); stopWatch?.(); manager?.runtime?.stop(); for (const release of releases) release();\n await Promise.all([manager?.api.close(), ...shims.map(shim => shim.close())]);\n ctx.logger.error('multi-router: initialization failed', error.code ?? error.message);\n throw error;\n }\n}\n", "/**\n * The `workbuddy` pi-ai provider: one loopback-backed adapter registered\n * into the Harness LLM seam, assembled from public `dsh-llm-pi-ai`\n * extension points the way `dsh-codex-connect` assembles its Codex route.\n *\n * @module dsh-workbuddy-connect/adapter\n */\n\nimport { createProvider } from '@earendil-works/pi-ai'\nimport type { Api, AuthContext, CredentialStore, Model, ModelThinkingLevel, Provider, ThinkingLevelMap } from '@earendil-works/pi-ai'\nimport { openAICompletionsApi } from '@earendil-works/pi-ai/api/openai-completions.lazy'\nimport { resolveRetryPolicy } from '@deepseek-ai/dsh-llm'\nimport type { LlmModelInfo, LlmResolvedModelInfo } from '@deepseek-ai/dsh-llm'\nimport { PiAiAdapter } from '@deepseek-ai/dsh-llm-pi-ai'\nimport type { PiAiAdapterOptions, ResolvedPiAiProviderProfile } from '@deepseek-ai/dsh-llm-pi-ai'\nimport type { AttachmentStore } from '@deepseek-ai/dsh-attachment'\nimport type { WorkBuddyCredentialStore } from './auth.ts'\nimport type { WorkBuddyCatalog, WorkBuddyModelInfo } from './catalog.ts'\nimport type { WorkBuddyProbeRecord } from './probe-store.ts'\nimport type { WorkBuddyShim } from './shim.ts'\nimport { normalizeCredits, type WorkBuddyRegion } from './upstream.ts'\n\n/** Provider route this bundle owns. */\nexport const WORKBUDDY_PROVIDER = 'workbuddy'\n\n/** Provider idle ceiling while one stream read is outstanding. */\nexport const WORKBUDDY_STREAM_IDLE_TIMEOUT_MS = 300_000\n\n/**\n * Image-request budgets at the dsh-llm-pi-ai defaults; the profile type made\n * them required in 0.1.1-rc.2. They bound requests to models whose catalog\n * entry declares `supportsImages`; text-only models never receive images.\n */\nconst REQUEST_IMAGE_BUDGETS = {\n maxRequestImageBytes: 20_971_520,\n requestImagePixelBudget: 4_194_304,\n requestImageMaxBytes: 1_048_576,\n} as const\n\n/**\n * Inert pi-ai auth plane. The workbuddy route authenticates only through the\n * shim shared secret resolved per request by `resolveApiKey`, so pi-ai's own\n * credential lifecycle and ambient discovery must never manufacture a\n * credential for it. `PiAiAdapterOptions.auth` is required since 0.1.1-rc.2;\n * every ambient question here answers \"nothing stored, nothing set\".\n */\nconst INERT_AUTH: { credentials: CredentialStore; authContext: AuthContext } = {\n credentials: {\n async read() { return undefined },\n async list() { return [] },\n async modify() {\n throw new Error('dsh-workbuddy-connect: the workbuddy route has no pi-ai credential lifecycle')\n },\n async delete() {},\n },\n authContext: {\n async env() { return undefined },\n async fileExists() { return false },\n },\n}\n\n/** No per-token pricing is knowable for a subscription quota; report zero. */\nconst NO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 } as const\n\n/**\n * Translate the request-image contract across the two attachment-service\n * generations a link-installed plugin can straddle.\n *\n * A `link:` install resolves its platform imports from the *repository's*\n * node_modules (Node follows the symlink's real path), so this adapter always\n * runs against the pi-ai it was built with \u2014 while the attachment service\n * comes from the host. Those two generations disagree on what\n * `readImageRequest(ref, policyOrTarget)` receives:\n *\n * - dsh-attachment-local \u22640.1.5: a route policy `{ maxPixels, maxBytes }`,\n * and `validatePolicy` throws `Image request maxPixels must be a positive\n * integer.` when `maxPixels` is missing.\n * - 0.1.6+: a per-image target `{ width, height, maxBytes }` with no\n * `maxPixels` at all, validated by `validateTarget`.\n *\n * A 0.1.6-built pi-ai on a 0.1.5 host therefore hands the old store a target\n * the old store rejects, and every image-bearing request fails before it is\n * sent. The wrapper below fills the route's own pixel budget into a target\n * that lacks it: the 0.1.5 store then computes the same dimensions pi-ai's\n * budget already chose, and a 0.1.6 store ignores the extra key.\n */\nfunction withLegacyImageBudget(store: AttachmentStore): AttachmentStore {\n return new Proxy(store, {\n get(target, property, receiver) {\n if (property === 'imageHostPath') {\n // The access resolver calls through this proxy; keep the concrete\n // store as `this` for implementations that use private fields.\n return target.imageHostPath.bind(target)\n }\n if (property !== 'readImageRequest') return Reflect.get(target, property, receiver)\n return (...args: Parameters<AttachmentStore['readImageRequest']>) => {\n const [ref, policy, signal] = args\n // The \u22640.1.5 store's own validity rule is \"safe integer AND positive\";\n // a present-but-non-positive maxPixels would pass an isSafeInteger-only\n // check and still be rejected there, so it is replaced too.\n const present = (policy as { maxPixels?: number } | undefined)?.maxPixels\n const withPixels = Number.isSafeInteger(present) && (present as number) > 0\n ? policy\n : { ...policy, maxPixels: REQUEST_IMAGE_BUDGETS.requestImagePixelBudget } as typeof policy\n return target.readImageRequest(ref, withPixels, signal)\n }\n },\n })\n}\n\n/**\n * The suffix appended to a model's display name so its billing rate is visible\n * wherever the name is shown.\n *\n * The separator is a middle dot rather than a hyphen or colon: model names\n * already contain hyphens (`GLM-5.3-Flash`, `Deepseek-V4-Flash`), so a hyphen\n * separator would be ambiguous about where the name ends and the rate begins.\n */\nconst RATE_SEPARATOR = ' \u00B7 '\n\n/**\n * Append the billing rate to one model's display name.\n *\n * The rate AND the declared promo badges ride the *name* alone: since DSH\n * 0.1.2 the composer's model seat (`ModelSelect`) renders `model.name` only \u2014\n * `description` is no longer read there at all (the 0.1.1-era client rendered\n * it, which is why the badges used to be visible in the seat). The `/model`\n * popup renders the name too, so a separate `description` copy would either\n * duplicate (rate) or vanish (badges) depending on client generation.\n *\n * This is display-only and cannot affect routing: the wire request is built\n * from `model.id` (pi-ai's completions API sets `model: model.id`), the\n * selection a picker submits is `{provider, model: id, reasoningEffort}`, and\n * `dsh-llm` validates `name` as a non-empty string without comparing its\n * contents. Nothing in the host resolves a model *by* name.\n */\n\n/**\n * The catalog display suffix: the billing rate followed by the declared promo\n * badges (`\u9650\u65F6\u514D\u8D39`, `\u591C\u95F4\u6298\u6263`), or undefined when the row carries neither.\n * The badge labels are the upstream's own spellings and the host seam has no\n * locale service, so non-Chinese UIs see them verbatim \u2014 accepted until the\n * picker grows a localized badge slot.\n */\nfunction displaySuffix(info: WorkBuddyModelInfo): string | undefined {\n const parts = [\n normalizeCredits(info.billing?.credits),\n ...(info.billing?.badges ?? []),\n ].filter((part): part is string => part !== undefined && part !== '')\n return parts.length === 0 ? undefined : parts.join(' \u00B7 ')\n}\n\n/** Append the catalog display suffix to one model's display name. */\nfunction withCatalogDisplay(name: string, info: WorkBuddyModelInfo): string {\n const suffix = displaySuffix(info)\n return suffix === undefined ? name : `${name}${RATE_SEPARATOR}${suffix}`\n}\n\n/** Constructor dependencies. */\nexport interface WorkBuddyAdapterOptions {\n providerId?: string\n displayName?: string\n /**\n * Which endpoint this adapter serves, from the variant descriptor. Decides\n * only whether the CN `onlyReasoning` veto hides `off` (#87); defaults to\n * `'cn'`, the same legacy default `providerId` carries.\n */\n region?: WorkBuddyRegion\n shim: WorkBuddyShim\n store: WorkBuddyCredentialStore\n catalog: WorkBuddyCatalog\n /** Resolve the durable attachment service at request time, when present. */\n resolveAttachments?: () => AttachmentStore | undefined\n /** Resolve one image's path in the current model-tool execution world. */\n resolveImageAccess?: NonNullable<PiAiAdapterOptions['resolveImageAccess']>\n /**\n * Look up a local probe observation for a model. Consulted only for rows the\n * upstream left undeclared; absent means declared-set-only behavior.\n */\n observe?: (modelId: string) => WorkBuddyProbeRecord | undefined\n /**\n * Model ids the current account has hidden from the picker, resolved per\n * read so an account switch is honored without rebuilding the adapter.\n *\n * Hiding is a *listing* concern only: `buildModels()` keeps serving the full\n * catalog because pi-ai's `resolveModel`/`prepareCall` resolve from the same\n * snapshot `listModels` reads \u2014 filtering the descriptors there would make a\n * hidden model unresolvable and break sessions already using it. The filter\n * therefore lives in this adapter's `listModels` override alone.\n */\n hidden?: () => readonly string[]\n}\n\n/** What {@link createWorkBuddyAdapter} hands back. */\nexport interface WorkBuddyAdapter {\n adapter: PiAiAdapter\n /** Rebuild the adapter's provider snapshot; call after a catalog update. */\n invalidate: () => void\n}\n\n/**\n * Resolve a WorkBuddy model's reasoning capability into pi-ai's\n * `thinkingLevelMap` (every level pinned to its wire spelling or `null` for\n * unsupported), mirroring `dsh-llm-pi-ai`'s own `resolveModelReasoning`.\n *\n * Two sources, strictly ordered (`docs/reasoning-effort-probe-plan.md` \u00A75):\n *\n * 1. **The declared set.** When the upstream declares a non-empty\n * `supportedEfforts`, exactly those values are offered and nothing else.\n * This always wins: an observation never widens or narrows a declared set.\n * 2. **A local observation.** Rows without a declared set (the older\n * `{effort, summary}` shape) normally get no control at all \u2014 their\n * selectable set is client-side knowledge the catalog does not carry, and\n * the desktop app differs per model there. If the user authorized a probe\n * and it established that the upstream *validates* the parameter, the\n * verified spellings are offered.\n *\n * A `non-validating` observation deliberately yields no control: the upstream\n * accepts values that cannot exist (measured on `glm-5.2`), so every per-level\n * acceptance it produced would be a false positive.\n *\n * `off` is offered only when the upstream declares `canDisableThinking: true`.\n * It is never probed \u2014 disabling thinking is a separate capability, and the\n * per-model acceptance of `off` cannot be inferred from the row's shape.\n *\n * The CN endpoint vetoes `off` further, on models declaring `onlyReasoning`\n * (#87) \u2014 see {@link region} below. That rule is deliberately region-scoped:\n * the contradiction it resolves was measured on the CN catalog, and applying\n * it everywhere would have changed which levels the international picker\n * offers, which is outside this issue.\n *\n * The offered set is described internally as \"verified accepted\", never as\n * \"verified effective\": acceptance proves the upstream did not reject the\n * spelling, not that it changes what the model does.\n *\n * @param region - the endpoint this descriptor is for. Decides only whether\n * the `onlyReasoning` veto applies; every other rule is shared. Passed from\n * the variant descriptor, never inferred from a model id or a name.\n */\nexport function reasoningFields(\n info: WorkBuddyModelInfo,\n observed?: WorkBuddyProbeRecord,\n region: WorkBuddyRegion = 'cn',\n): { reasoning: boolean; thinkingLevelMap?: ThinkingLevelMap } {\n const reasoning = info.reasoning\n if (reasoning === undefined || reasoning.supports !== true) {\n // Not a reasoning model: pi-ai reads a falsy `reasoning` as \"off only\".\n return { reasoning: false }\n }\n const declared = reasoning.supportedEfforts\n const efforts = declared !== undefined && declared.length > 0\n ? declared\n // Only a validating observation may supply a set, and only for rows the\n // upstream left undeclared.\n : observed?.validation === 'validating' && observed.efforts.length > 0\n ? observed.efforts\n : undefined\n if (efforts === undefined) {\n // Undeclared and unobserved (or observed as non-validating): no thinking\n // control, and no `reasoning_effort` on the wire.\n return { reasoning: false }\n }\n const map: Record<ModelThinkingLevel, string | null> = {\n // Probing never grants `off`; only an explicit declaration does.\n //\n // On CN, `onlyReasoning` vetoes it even when declared (#87). That catalog\n // ships both flags true on `deepseek-v4.1-flash` and `kimi-k2.8-preview`,\n // which cannot both hold \u2014 a model that only ever reasons has no\n // non-thinking mode to select \u2014 and the endpoint sides with\n // `onlyReasoning`, answering HTTP 400 (\u300C\u6A21\u578B\u4E0D\u652F\u6301\u8BE5\u601D\u8003\u5F3A\u5EA6\u300D) for every\n // `off` request. Offering a level that is certain to fail is worse than not\n // offering it, so the contradiction is resolved toward the flag the wire\n // agrees with.\n //\n // Scoped to CN on purpose: the international catalog does not carry this\n // contradiction, and hiding Off there would remove a level those models\n // can still use. The request layer strips the spelling in both regions\n // (`dropUnsupportedEffort`), so a model whose flags flip between catalog\n // reads cannot put `off` on the wire either way.\n off: reasoning.canDisableThinking === true\n && (region !== 'cn' || reasoning.onlyReasoning !== true)\n && declared !== undefined && declared.length > 0 ? 'off' : null,\n // `minimal` is not in the upstream effort vocabulary (EFFORT_VALUES), so\n // no declared set \u2014 and no probe candidate \u2014 can ever contain it.\n minimal: null,\n low: efforts.includes('low') ? 'low' : null,\n medium: efforts.includes('medium') ? 'medium' : null,\n high: efforts.includes('high') ? 'high' : null,\n xhigh: efforts.includes('xhigh') ? 'xhigh' : null,\n max: efforts.includes('max') ? 'max' : null,\n }\n return { reasoning: true, thinkingLevelMap: map as ThinkingLevelMap }\n}\n\n/** Build one pi-ai model descriptor pointing at the loopback shim. */\nfunction toPiModel(info: WorkBuddyModelInfo, baseUrl: string, observed: WorkBuddyProbeRecord | undefined, providerId: string, region: WorkBuddyRegion): Model<Api> {\n return {\n id: info.id,\n name: info.name,\n api: 'openai-completions',\n provider: providerId,\n baseUrl,\n input: info.supportsImages === true ? ['text', 'image'] : ['text'],\n ...reasoningFields(info, observed, region),\n cost: NO_COST,\n contextWindow: info.contextWindow,\n maxTokens: info.maxTokens,\n // pi-ai cannot infer WorkBuddy's field spelling from the shim's random\n // loopback URL, so name the upstream-required field explicitly.\n compat: { maxTokensField: 'max_tokens' },\n } as unknown as Model<Api>\n}\n\n/**\n * Assemble the adapter. The provider's `getModels` reads the live catalog,\n * and every model's `baseUrl` is re-resolved per read so the shim's\n * ephemeral port applies from the first snapshot after startup.\n *\n * The profile is constructed by hand rather than through dsh-llm-pi-ai's\n * internal `resolveProfiles()`: that helper is not part of the package's\n * public export surface (root entry, `lib/` deep imports blocked by the\n * exports map, `src/` not shipped), so hand-assembly is the only supported\n * path and every newly required field must be adopted here explicitly \u2014\n * `modelErrors` since 0.1.5-alpha.2 (#12).\n */\nexport function createWorkBuddyAdapter(options: WorkBuddyAdapterOptions): WorkBuddyAdapter {\n const { shim, store, catalog, resolveAttachments, resolveImageAccess, observe, hidden } = options\n const providerId = options.providerId ?? WORKBUDDY_PROVIDER\n const displayName = options.displayName ?? 'WorkBuddy'\n const region = options.region ?? 'cn'\n\n const buildModels = (): Model<Api>[] => {\n // The OpenAI SDK pi-ai drives appends `/chat/completions` to baseURL,\n // so the shim's routes line up with the `/v1` prefix in place.\n const baseUrl = `${shim.baseUrl()}/v1`\n return catalog.current().map(info => toPiModel(info, baseUrl, observe?.(info.id), providerId, region))\n }\n\n const base = createProvider({\n id: providerId,\n name: displayName,\n auth: {\n apiKey: {\n name: 'WorkBuddy OAuth bearer token',\n async resolve({ credential }) {\n const apiKey = credential?.key\n return apiKey === undefined || apiKey.length === 0\n ? undefined\n : { auth: { apiKey }, source: 'WorkBuddy' }\n },\n },\n },\n models: buildModels(),\n api: openAICompletionsApi(),\n })\n\n // `getModels` is delegated to a live read (the reuse-catalog pattern from\n // dsh-llm-pi-ai): stream dispatch still runs through the constructed\n // provider, while the catalog answer tracks the upstream refresh.\n const provider: Provider = { ...base, getModels: () => buildModels() }\n\n const profile: ResolvedPiAiProviderProfile = {\n provider: providerId,\n displayName,\n streamIdleTimeoutMs: WORKBUDDY_STREAM_IDLE_TIMEOUT_MS,\n retryPolicy: resolveRetryPolicy(undefined, 'dsh-workbuddy-connect retryPolicy'),\n configuredMaxTokens: new Map(),\n // Required since 0.1.5-alpha.2; the live catalog only exposes models that\n // probed successfully, so there is never a per-model failure to report.\n modelErrors: new Map(),\n ...REQUEST_IMAGE_BUDGETS,\n piProvider: provider,\n }\n\n let profiles = new Map<string, ResolvedPiAiProviderProfile>([[providerId, profile]])\n\n const adapter = new WorkBuddyPiAiAdapter(catalog, hidden ?? (() => []), {\n profiles: () => profiles,\n auth: INERT_AUTH,\n // Resolve the shim's per-process shared secret as the OpenAI apiKey so\n // pi-ai sends it as `Authorization: Bearer <shared-secret>`. The shim\n // validates this before forwarding and resolves the real WorkBuddy token\n // itself via the store, so the secret never reaches upstream.\n resolveApiKey: async () => shim.token(),\n // Every store the adapter hands to pi-ai passes the legacy-budget wrapper:\n // see withLegacyImageBudget \u2014 the mismatch it heals depends on which host\n // generation owns the attachment service, not on anything observable here.\n ...resolveAttachments === undefined\n ? {}\n : {\n resolveAttachments: () => {\n const store = resolveAttachments()\n return store === undefined ? undefined : withLegacyImageBudget(store)\n },\n },\n ...(resolveImageAccess === undefined ? {} : { resolveImageAccess }),\n })\n\n return {\n adapter,\n invalidate: () => {\n profiles = new Map<string, ResolvedPiAiProviderProfile>([[providerId, profile]])\n },\n }\n}\n\n/**\n * The WorkBuddy route's adapter: `PiAiAdapter` with the billing rate folded\n * into the catalog answers it returns to the DSH model pickers.\n *\n * `PiAiAdapter.listModels()` and `.resolveModel()` build their answers straight\n * from the pi-ai descriptors, which carry no billing fact, so the rate is\n * layered on here by looking the model up in the live catalog. Both overrides\n * delegate to `super` and then rewrite only the display fields, so streaming,\n * capability resolution, and effort mapping stay exactly as `dsh-llm-pi-ai`\n * implements them.\n *\n * A model missing from the catalog (an id the shim would serve but the last\n * upstream refresh did not list) falls through with its name untouched rather\n * than being dropped: catalog membership is advisory, and the seam tolerates\n * serving an unlisted id.\n */\nclass WorkBuddyPiAiAdapter extends PiAiAdapter {\n constructor(\n private readonly catalog: WorkBuddyCatalog,\n private readonly hidden: () => readonly string[],\n options: ConstructorParameters<typeof PiAiAdapter>[0],\n ) {\n super(options)\n }\n\n /** Catalog entry for one model id, or undefined when the catalog omits it. */\n private infoFor(model: string): WorkBuddyModelInfo | undefined {\n return this.catalog.current().find(entry => entry.id === model)\n }\n\n override async listModels(provider: string): Promise<readonly LlmModelInfo[]> {\n const models = await super.listModels(provider)\n // Resolved fresh per call: the picker reads this after every\n // `llm/adapters-updated`, so an account switch or a toggle takes effect on\n // the next read without rebuilding anything.\n const hidden = new Set(this.hidden())\n return models.flatMap(model => {\n // Selectability only \u2014 `resolveModel` below deliberately does not apply\n // this filter, so a session already using a hidden model keeps working.\n if (hidden.has(model.id)) return []\n const info = this.infoFor(model.id)\n if (info === undefined) return [model]\n return [{ ...model, name: withCatalogDisplay(model.name, info) }]\n })\n }\n\n override async resolveModel(provider: string, model: string, signal?: AbortSignal): Promise<LlmResolvedModelInfo> {\n const resolved = await super.resolveModel(provider, model, signal)\n const info = this.infoFor(model)\n if (info === undefined) return resolved\n return { ...resolved, name: withCatalogDisplay(resolved.name, info) }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["resolveRetryPolicy", "name", "store", "options", "resolveRetryPolicy"]
7
7
  }
package/lib/manager.js CHANGED
@@ -2,21 +2,25 @@ import {
2
2
  MANAGEMENT_PATH,
3
3
  ManagementError,
4
4
  Manager,
5
+ SUMMARY_PATH,
5
6
  managementHandler,
6
7
  modelInfo
7
- } from "./chunk-I4EW5TI7.js";
8
- import "./chunk-U2MU2M5C.js";
9
- import "./chunk-S6ZQ45SS.js";
10
- import "./chunk-FTM7RHQV.js";
8
+ } from "./chunk-OCMOMSB4.js";
9
+ import "./chunk-NSKCFVHP.js";
10
+ import "./chunk-JUOESKAK.js";
11
+ import "./chunk-OK2T2UAZ.js";
12
+ import "./chunk-TEZ2FMEO.js";
11
13
  import "./chunk-S5KMFAQM.js";
14
+ import "./chunk-SNEZMYNU.js";
15
+ import "./chunk-4V52V5GO.js";
12
16
  import "./chunk-DNQPZMPF.js";
13
- import "./chunk-J3XO7RTF.js";
14
- import "./chunk-MCHV2R25.js";
15
- import "./chunk-TEZ2FMEO.js";
17
+ import "./chunk-ROZINFTV.js";
18
+ import "./chunk-WVNY4LSL.js";
16
19
  export {
17
20
  MANAGEMENT_PATH,
18
21
  ManagementError,
19
22
  Manager,
23
+ SUMMARY_PATH,
20
24
  managementHandler,
21
25
  modelInfo
22
26
  };
package/lib/router.js CHANGED
@@ -3,8 +3,8 @@ import {
3
3
  Router,
4
4
  abortable,
5
5
  matchModel
6
- } from "./chunk-J3XO7RTF.js";
7
- import "./chunk-MCHV2R25.js";
6
+ } from "./chunk-ROZINFTV.js";
7
+ import "./chunk-WVNY4LSL.js";
8
8
  export {
9
9
  RouteError,
10
10
  Router,
package/lib/shim.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  createShim
3
- } from "./chunk-P43AWJ4Q.js";
3
+ } from "./chunk-LLDJVBTQ.js";
4
4
  import "./chunk-DNQPZMPF.js";
5
- import "./chunk-J3XO7RTF.js";
6
- import "./chunk-MCHV2R25.js";
5
+ import "./chunk-ROZINFTV.js";
6
+ import "./chunk-WVNY4LSL.js";
7
7
  export {
8
8
  createShim
9
9
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-multi-router",
3
- "version": "0.5.9",
3
+ "version": "0.6.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/AndroidSix/dsh-multi-router.git"