dsh-multi-router 0.6.11 → 1.0.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 (56) hide show
  1. package/README.md +2 -427
  2. package/package.json +5 -81
  3. package/CHANGELOG.md +0 -237
  4. package/LICENSE +0 -21
  5. package/THIRD_PARTY_NOTICES.md +0 -171
  6. package/cordis.patch.yml +0 -3
  7. package/lib/accounts.js +0 -19
  8. package/lib/accounts.js.map +0 -7
  9. package/lib/api-service.js +0 -11
  10. package/lib/api-service.js.map +0 -7
  11. package/lib/chunk-2UM45OXY.js +0 -181
  12. package/lib/chunk-2UM45OXY.js.map +0 -7
  13. package/lib/chunk-4L2CBGXN.js +0 -674
  14. package/lib/chunk-4L2CBGXN.js.map +0 -7
  15. package/lib/chunk-4V52V5GO.js +0 -105
  16. package/lib/chunk-4V52V5GO.js.map +0 -7
  17. package/lib/chunk-DNQPZMPF.js +0 -33
  18. package/lib/chunk-DNQPZMPF.js.map +0 -7
  19. package/lib/chunk-FLL3DUVP.js +0 -2017
  20. package/lib/chunk-FLL3DUVP.js.map +0 -7
  21. package/lib/chunk-GEBZMIMA.js +0 -287
  22. package/lib/chunk-GEBZMIMA.js.map +0 -7
  23. package/lib/chunk-KWXLQJS5.js +0 -1102
  24. package/lib/chunk-KWXLQJS5.js.map +0 -7
  25. package/lib/chunk-NZF36O5I.js +0 -5421
  26. package/lib/chunk-NZF36O5I.js.map +0 -7
  27. package/lib/chunk-S5KMFAQM.js +0 -50
  28. package/lib/chunk-S5KMFAQM.js.map +0 -7
  29. package/lib/chunk-TM5XDMGY.js +0 -332
  30. package/lib/chunk-TM5XDMGY.js.map +0 -7
  31. package/lib/chunk-WDIT4E2W.js +0 -120
  32. package/lib/chunk-WDIT4E2W.js.map +0 -7
  33. package/lib/chunk-YCAO7GCT.js +0 -2059
  34. package/lib/chunk-YCAO7GCT.js.map +0 -7
  35. package/lib/cli.js +0 -103
  36. package/lib/cli.js.map +0 -7
  37. package/lib/client.js +0 -2793
  38. package/lib/client.js.map +0 -7
  39. package/lib/clients.js +0 -30
  40. package/lib/clients.js.map +0 -7
  41. package/lib/host-v0.6.11.js +0 -414
  42. package/lib/host.js +0 -414
  43. package/lib/index.js +0 -414
  44. package/lib/index.js.map +0 -7
  45. package/lib/manager.js +0 -27
  46. package/lib/manager.js.map +0 -7
  47. package/lib/region-DO3KAV7V.js +0 -15
  48. package/lib/region-DO3KAV7V.js.map +0 -7
  49. package/lib/router.js +0 -14
  50. package/lib/router.js.map +0 -7
  51. package/lib/shim.js +0 -10
  52. package/lib/shim.js.map +0 -7
  53. package/lib/upstream-VP6J7LU2.js +0 -25
  54. package/lib/upstream-VP6J7LU2.js.map +0 -7
  55. package/router.example.json +0 -289
  56. package/upstream-lock.json +0 -17
package/lib/clients.js DELETED
@@ -1,30 +0,0 @@
1
- import {
2
- cachedModels,
3
- claimTraeCheckin,
4
- createAccountClient,
5
- createQoderCheckin,
6
- createWorkBuddyCheckin,
7
- jsonCredential,
8
- refreshWorkBuddyCheckinCredential,
9
- workbuddyToken
10
- } from "./chunk-NZF36O5I.js";
11
- import "./chunk-FLL3DUVP.js";
12
- import "./chunk-KWXLQJS5.js";
13
- import "./chunk-S5KMFAQM.js";
14
- import "./chunk-4V52V5GO.js";
15
- import {
16
- qoderContextModel
17
- } from "./chunk-4L2CBGXN.js";
18
- import "./chunk-GEBZMIMA.js";
19
- export {
20
- cachedModels,
21
- claimTraeCheckin,
22
- createAccountClient,
23
- createQoderCheckin,
24
- createWorkBuddyCheckin,
25
- jsonCredential,
26
- qoderContextModel,
27
- refreshWorkBuddyCheckinCredential,
28
- workbuddyToken
29
- };
30
- //# sourceMappingURL=clients.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1,414 +0,0 @@
1
- import {
2
- createShim
3
- } from "./chunk-WDIT4E2W.js";
4
- import {
5
- MANAGEMENT_PATH,
6
- Manager,
7
- PluginReload,
8
- SUMMARY_PATH,
9
- managementHandler,
10
- version
11
- } from "./chunk-YCAO7GCT.js";
12
- import {
13
- createAccountClient
14
- } from "./chunk-NZF36O5I.js";
15
- import "./chunk-2UM45OXY.js";
16
- import "./chunk-FLL3DUVP.js";
17
- import {
18
- normalizeCredits
19
- } from "./chunk-KWXLQJS5.js";
20
- import "./chunk-S5KMFAQM.js";
21
- import "./chunk-TM5XDMGY.js";
22
- import "./chunk-4V52V5GO.js";
23
- import "./chunk-DNQPZMPF.js";
24
- import {
25
- Router,
26
- SessionMetrics,
27
- abortable
28
- } from "./chunk-4L2CBGXN.js";
29
- import {
30
- PROVIDERS,
31
- PROVIDER_NAMES,
32
- ensureConfig
33
- } from "./chunk-GEBZMIMA.js";
34
-
35
- // src/index.mjs
36
- import z from "@deepseek-ai/schemastery";
37
- import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
38
- import { resolveRetryPolicy as resolveRetryPolicy2, resolveImageAttachmentAccess } from "@deepseek-ai/dsh-llm";
39
- import { join, resolve } from "node:path";
40
-
41
- // upstream/workbuddy/src/adapter.ts
42
- import { createProvider } from "@earendil-works/pi-ai";
43
- import { openAICompletionsApi } from "@earendil-works/pi-ai/api/openai-completions.lazy";
44
- import { resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
45
- import { PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
46
- var WORKBUDDY_PROVIDER = "workbuddy";
47
- var WORKBUDDY_STREAM_IDLE_TIMEOUT_MS = 3e5;
48
- var REQUEST_IMAGE_BUDGETS = {
49
- maxRequestImageBytes: 20971520,
50
- requestImagePixelBudget: 4194304,
51
- requestImageMaxBytes: 1048576
52
- };
53
- var INERT_AUTH = {
54
- credentials: {
55
- async read() {
56
- return void 0;
57
- },
58
- async list() {
59
- return [];
60
- },
61
- async modify() {
62
- throw new Error("dsh-workbuddy-connect: the workbuddy route has no pi-ai credential lifecycle");
63
- },
64
- async delete() {
65
- }
66
- },
67
- authContext: {
68
- async env() {
69
- return void 0;
70
- },
71
- async fileExists() {
72
- return false;
73
- }
74
- }
75
- };
76
- var NO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
77
- function withLegacyImageBudget(store) {
78
- return new Proxy(store, {
79
- get(target, property, receiver) {
80
- if (property === "imageHostPath") {
81
- return target.imageHostPath.bind(target);
82
- }
83
- if (property !== "readImageRequest") return Reflect.get(target, property, receiver);
84
- return (...args) => {
85
- const [ref, policy, signal] = args;
86
- const present = policy?.maxPixels;
87
- const withPixels = Number.isSafeInteger(present) && present > 0 ? policy : { ...policy, maxPixels: REQUEST_IMAGE_BUDGETS.requestImagePixelBudget };
88
- return target.readImageRequest(ref, withPixels, signal);
89
- };
90
- }
91
- });
92
- }
93
- var RATE_SEPARATOR = " \xB7 ";
94
- function displaySuffix(info) {
95
- const parts = [
96
- normalizeCredits(info.billing?.credits),
97
- ...info.billing?.badges ?? []
98
- ].filter((part) => part !== void 0 && part !== "");
99
- return parts.length === 0 ? void 0 : parts.join(" \xB7 ");
100
- }
101
- function withCatalogDisplay(name2, info) {
102
- const suffix = displaySuffix(info);
103
- return suffix === void 0 ? name2 : `${name2}${RATE_SEPARATOR}${suffix}`;
104
- }
105
- function reasoningFields(info, observed, region = "cn") {
106
- const reasoning = info.reasoning;
107
- if (reasoning === void 0 || reasoning.supports !== true) {
108
- return { reasoning: false };
109
- }
110
- const declared = reasoning.supportedEfforts;
111
- const efforts = declared !== void 0 && declared.length > 0 ? declared : observed?.validation === "validating" && observed.efforts.length > 0 ? observed.efforts : void 0;
112
- if (efforts === void 0) {
113
- return { reasoning: false };
114
- }
115
- const map = {
116
- // Probing never grants `off`; only an explicit declaration does.
117
- //
118
- // On CN, `onlyReasoning` vetoes it even when declared (#87). That catalog
119
- // ships both flags true on `deepseek-v4.1-flash` and `kimi-k2.8-preview`,
120
- // which cannot both hold — a model that only ever reasons has no
121
- // non-thinking mode to select — and the endpoint sides with
122
- // `onlyReasoning`, answering HTTP 400 (「模型不支持该思考强度」) for every
123
- // `off` request. Offering a level that is certain to fail is worse than not
124
- // offering it, so the contradiction is resolved toward the flag the wire
125
- // agrees with.
126
- //
127
- // Scoped to CN on purpose: the international catalog does not carry this
128
- // contradiction, and hiding Off there would remove a level those models
129
- // can still use. The request layer strips the spelling in both regions
130
- // (`dropUnsupportedEffort`), so a model whose flags flip between catalog
131
- // reads cannot put `off` on the wire either way.
132
- off: reasoning.canDisableThinking === true && (region !== "cn" || reasoning.onlyReasoning !== true) && declared !== void 0 && declared.length > 0 ? "off" : null,
133
- // `minimal` is not in the upstream effort vocabulary (EFFORT_VALUES), so
134
- // no declared set — and no probe candidate — can ever contain it.
135
- minimal: null,
136
- low: efforts.includes("low") ? "low" : null,
137
- medium: efforts.includes("medium") ? "medium" : null,
138
- high: efforts.includes("high") ? "high" : null,
139
- xhigh: efforts.includes("xhigh") ? "xhigh" : null,
140
- max: efforts.includes("max") ? "max" : null
141
- };
142
- return { reasoning: true, thinkingLevelMap: map };
143
- }
144
- function toPiModel(info, baseUrl, observed, providerId, region) {
145
- return {
146
- id: info.id,
147
- name: info.name,
148
- api: "openai-completions",
149
- provider: providerId,
150
- baseUrl,
151
- input: info.supportsImages === true ? ["text", "image"] : ["text"],
152
- ...reasoningFields(info, observed, region),
153
- cost: NO_COST,
154
- contextWindow: info.contextWindow,
155
- maxTokens: info.maxTokens,
156
- // pi-ai cannot infer WorkBuddy's field spelling from the shim's random
157
- // loopback URL, so name the upstream-required field explicitly.
158
- compat: { maxTokensField: "max_tokens" }
159
- };
160
- }
161
- function createWorkBuddyAdapter(options) {
162
- const { shim, store, catalog, resolveAttachments, resolveImageAccess, observe, hidden } = options;
163
- const providerId = options.providerId ?? WORKBUDDY_PROVIDER;
164
- const displayName = options.displayName ?? "WorkBuddy";
165
- const region = options.region ?? "cn";
166
- const buildModels = () => {
167
- const baseUrl = `${shim.baseUrl()}/v1`;
168
- return catalog.current().map((info) => toPiModel(info, baseUrl, observe?.(info.id), providerId, region));
169
- };
170
- const base = createProvider({
171
- id: providerId,
172
- name: displayName,
173
- auth: {
174
- apiKey: {
175
- name: "WorkBuddy OAuth bearer token",
176
- async resolve({ credential }) {
177
- const apiKey = credential?.key;
178
- return apiKey === void 0 || apiKey.length === 0 ? void 0 : { auth: { apiKey }, source: "WorkBuddy" };
179
- }
180
- }
181
- },
182
- models: buildModels(),
183
- api: openAICompletionsApi()
184
- });
185
- const provider = { ...base, getModels: () => buildModels() };
186
- const profile = {
187
- provider: providerId,
188
- displayName,
189
- streamIdleTimeoutMs: WORKBUDDY_STREAM_IDLE_TIMEOUT_MS,
190
- retryPolicy: resolveRetryPolicy(void 0, "dsh-workbuddy-connect retryPolicy"),
191
- configuredMaxTokens: /* @__PURE__ */ new Map(),
192
- // Required since 0.1.5-alpha.2; the live catalog only exposes models that
193
- // probed successfully, so there is never a per-model failure to report.
194
- modelErrors: /* @__PURE__ */ new Map(),
195
- ...REQUEST_IMAGE_BUDGETS,
196
- piProvider: provider
197
- };
198
- let profiles = /* @__PURE__ */ new Map([[providerId, profile]]);
199
- const adapter = new WorkBuddyPiAiAdapter(catalog, hidden ?? (() => []), {
200
- profiles: () => profiles,
201
- auth: INERT_AUTH,
202
- // Resolve the shim's per-process shared secret as the OpenAI apiKey so
203
- // pi-ai sends it as `Authorization: Bearer <shared-secret>`. The shim
204
- // validates this before forwarding and resolves the real WorkBuddy token
205
- // itself via the store, so the secret never reaches upstream.
206
- resolveApiKey: async () => shim.token(),
207
- // Every store the adapter hands to pi-ai passes the legacy-budget wrapper:
208
- // see withLegacyImageBudget — the mismatch it heals depends on which host
209
- // generation owns the attachment service, not on anything observable here.
210
- ...resolveAttachments === void 0 ? {} : {
211
- resolveAttachments: () => {
212
- const store2 = resolveAttachments();
213
- return store2 === void 0 ? void 0 : withLegacyImageBudget(store2);
214
- }
215
- },
216
- ...resolveImageAccess === void 0 ? {} : { resolveImageAccess }
217
- });
218
- return {
219
- adapter,
220
- invalidate: () => {
221
- profiles = /* @__PURE__ */ new Map([[providerId, profile]]);
222
- }
223
- };
224
- }
225
- var WorkBuddyPiAiAdapter = class extends PiAiAdapter {
226
- constructor(catalog, hidden, options) {
227
- super(options);
228
- this.catalog = catalog;
229
- this.hidden = hidden;
230
- }
231
- /** Catalog entry for one model id, or undefined when the catalog omits it. */
232
- infoFor(model) {
233
- return this.catalog.current().find((entry) => entry.id === model);
234
- }
235
- async listModels(provider) {
236
- const models = await super.listModels(provider);
237
- const hidden = new Set(this.hidden());
238
- return models.flatMap((model) => {
239
- if (hidden.has(model.id)) return [];
240
- const info = this.infoFor(model.id);
241
- if (info === void 0) return [model];
242
- return [{ ...model, name: withCatalogDisplay(model.name, info) }];
243
- });
244
- }
245
- async resolveModel(provider, model, signal) {
246
- const resolved = await super.resolveModel(provider, model, signal);
247
- const info = this.infoFor(model);
248
- if (info === void 0) return resolved;
249
- return { ...resolved, name: withCatalogDisplay(resolved.name, info) };
250
- }
251
- };
252
-
253
- // src/index.mjs
254
- var name = "dsh-multi-router";
255
- var inject = ["llm"];
256
- var defaultConfigFile = () => join(resolveDshHome(), "multi-router", "router.json");
257
- var Config = z.object({ configFile: z.string().description("Absolute path to multi-account router.json") });
258
- async function apply(ctx, options = {}) {
259
- let disposed = false, manager, stopWatch, monitorTimer, startup;
260
- const releases = [], shims = [], wrappers = [];
261
- ctx.effect(() => () => {
262
- disposed = true;
263
- stopWatch?.();
264
- clearInterval(monitorTimer);
265
- manager?.runtime?.stop();
266
- if (manager) manager.closed = true;
267
- manager?.plugins.abort.abort();
268
- manager?.checkins.abort.abort();
269
- manager?.workbuddyLogin.abort.abort();
270
- manager?.modelTestAbort?.abort();
271
- for (const release of releases) release();
272
- 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(() => {
273
- }), manager?.telemetry.queue.catch(() => {
274
- })]);
275
- });
276
- const file = resolve(options.configFile ?? process.env.DSH_MULTI_ROUTER_CONFIG ?? defaultConfigFile());
277
- try {
278
- const config = await ensureConfig(file);
279
- if (disposed) return;
280
- const router = new Router(
281
- config,
282
- (a) => createAccountClient(a, manager?.config ?? config, ctx.get("attachments")),
283
- (event) => ctx.logger.info("multi-router", JSON.stringify(event))
284
- );
285
- manager = new Manager(file, router, () => {
286
- for (const wrapper of wrappers) wrapper.invalidate();
287
- ctx.emit("llm/adapters-updated");
288
- }, { service: () => ctx.get("pluginManager"), profile: () => ctx.get("profileContext"), hmr: () => ctx.get("hmr") });
289
- await manager.load();
290
- if (disposed) return;
291
- manager.startup = { phase: "discovering" };
292
- manager.runtime = new PluginReload({
293
- runningVersion: version,
294
- service: () => ctx.get("pluginManager"),
295
- profile: () => ctx.get("profileContext"),
296
- canReload: () => !!ctx.get("hmr"),
297
- hmr: () => ctx.get("hmr"),
298
- 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()))
299
- });
300
- ctx.inject?.(["webServer"], (webCtx) => {
301
- webCtx.effect(() => webCtx.webServer.register({ kind: "exact", path: SUMMARY_PATH, handler: managementHandler(manager, { summaryOnly: true }) }));
302
- webCtx.effect(() => webCtx.webServer.register({ kind: "exact", path: MANAGEMENT_PATH, handler: managementHandler(manager) }));
303
- });
304
- const metrics = new SessionMetrics(manager.telemetry);
305
- ctx.on("session/event", (session, event) => {
306
- try {
307
- return metrics.event(session, event)?.catch(() => ctx.logger.warn("multi-router: performance persistence failed"));
308
- } catch {
309
- ctx.logger.warn("multi-router: performance event unavailable");
310
- }
311
- });
312
- ctx.on("session/disposed", (session) => metrics.dispose(session));
313
- for (const provider of ["multi-router", ...PROVIDERS]) {
314
- if (disposed) return;
315
- const isRouter = provider === "multi-router";
316
- const shim = createShim(router, { modelPrefix: isRouter ? "" : `${provider}::` });
317
- shims.push(shim);
318
- await shim.ready;
319
- if (disposed) {
320
- await shim.close();
321
- return;
322
- }
323
- const wrapper = createWorkBuddyAdapter({
324
- providerId: provider,
325
- displayName: isRouter ? "\u7EDF\u4E00\u8DEF\u7531" : `${PROVIDER_NAMES[provider]} \xB7 \u5185\u7F6E\u8D26\u53F7\u6C60`,
326
- shim,
327
- catalog: { current: () => isRouter ? manager.adapterModels() : manager.providerModels(provider) },
328
- hidden: () => isRouter ? manager.adapterModels().filter((r) => r.visible === false).map((r) => r.id) : manager.hiddenModels(provider),
329
- region: provider.endsWith("global") || provider === "workbuddy-ai" ? "global" : "cn",
330
- resolveAttachments: () => ctx.get("attachments"),
331
- resolveImageAccess: (attachments, ref) => resolveImageAttachmentAccess(
332
- attachments,
333
- (path) => ctx.get("fs")?.processPathFromHostPath(path),
334
- ref
335
- )
336
- });
337
- if (!isRouter) {
338
- for (const method of ["listModels", "resolveModel", "prepareCall"]) {
339
- const original = wrapper.adapter[method].bind(wrapper.adapter);
340
- wrapper.adapter[method] = async (...args) => {
341
- await abortable(manager.ensureCatalog(provider), args[2]);
342
- return original(...args);
343
- };
344
- }
345
- }
346
- const streamWithSnapshot = wrapper.adapter.streamWithSnapshot.bind(wrapper.adapter);
347
- wrapper.adapter.streamWithSnapshot = (options2, snapshot) => {
348
- const call = metrics.beginCall(options2.sessionId, options2.purpose);
349
- const route = router.config.routes[(isRouter ? "" : `${provider}::`) + options2.model];
350
- const effort = options2.reasoningEffort ?? route?.reasoningEffort;
351
- const profiles = new Map(snapshot.profiles), profile = profiles.get(options2.provider);
352
- if (!profile) return streamWithSnapshot(options2, snapshot);
353
- profiles.set(options2.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 } : {} } });
354
- return streamWithSnapshot({ ...options2, ...effort ? { reasoningEffort: effort } : {} }, { ...snapshot, profiles });
355
- };
356
- const withDefault = (model) => {
357
- const effort = router.config.routes[(isRouter ? "" : `${provider}::`) + model.id]?.reasoningEffort;
358
- return effort && model.reasoning ? { ...model, reasoning: { ...model.reasoning, defaultEffort: effort } } : model;
359
- };
360
- const resolveModel = wrapper.adapter.resolveModel.bind(wrapper.adapter), prepareCall = wrapper.adapter.prepareCall.bind(wrapper.adapter);
361
- wrapper.adapter.resolveModel = async (...args) => withDefault(await resolveModel(...args));
362
- wrapper.adapter.prepareCall = async (...args) => {
363
- const prepared = await prepareCall(...args);
364
- return { ...prepared, model: withDefault(prepared.model) };
365
- };
366
- wrapper.adapter.providerRetryPolicy = () => resolveRetryPolicy2({ mode: "normal", maxRetries: 0 }, provider);
367
- wrappers.push(wrapper);
368
- releases.push(ctx.llm.registerAdapter([provider], wrapper.adapter));
369
- }
370
- stopWatch = manager.watch(() => ctx.logger.warn("multi-router: invalid config change; keeping last valid configuration"));
371
- await manager.api.reconcile();
372
- startup = (async () => {
373
- await manager.syncLocalAccounts().catch(() => ctx.logger.warn("multi-router: local login discovery failed; manual import remains available"));
374
- if (disposed) return;
375
- await manager.finishInitialSetup().catch(() => ctx.logger.warn("multi-router: first-install guidance could not be saved"));
376
- if (disposed) return;
377
- manager.startup = { phase: "ready" };
378
- manager.checkins.tick();
379
- void manager.checkFreeModels().catch(() => ctx.logger.warn("multi-router: free catalog persistence failed"));
380
- void manager.monitorAll().catch(() => ctx.logger.warn("multi-router: usage persistence failed"));
381
- })();
382
- void manager.plugins.tick().catch(() => ctx.logger.warn("multi-router: automatic update check unavailable"));
383
- manager.runtime.start();
384
- ctx.on("plugin-manager/changed", () => manager.runtime.schedule());
385
- monitorTimer = setInterval(() => {
386
- void manager.syncLocalAccounts().then(() => {
387
- if (!disposed) return manager.monitorAll();
388
- }).catch(() => ctx.logger.warn("multi-router: local login discovery or usage persistence failed"));
389
- manager.checkins.tick();
390
- void manager.plugins.tick().catch(() => ctx.logger.warn("multi-router: automatic update check unavailable"));
391
- void manager.checkFreeModels().catch(() => ctx.logger.warn("multi-router: free catalog persistence failed"));
392
- void manager.runtime.check().catch(() => {
393
- });
394
- }, 6e4);
395
- monitorTimer.unref();
396
- ctx.emit("llm/adapters-updated");
397
- } catch (error) {
398
- clearInterval(monitorTimer);
399
- stopWatch?.();
400
- manager?.runtime?.stop();
401
- for (const release of releases) release();
402
- await Promise.all([manager?.api.close(), ...shims.map((shim) => shim.close())]);
403
- ctx.logger.error("multi-router: initialization failed", error.code ?? error.message);
404
- throw error;
405
- }
406
- }
407
- export {
408
- Config,
409
- apply,
410
- defaultConfigFile,
411
- inject,
412
- name
413
- };
414
- //# sourceMappingURL=index.js.map