dsh-multi-router 0.5.6 → 0.5.8
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.
- package/CHANGELOG.md +13 -0
- package/README.md +10 -4
- package/cordis.patch.yml +2 -2
- package/lib/{chunk-XKDXPB5T.js → chunk-ILRW3ELD.js} +28 -11
- package/lib/chunk-ILRW3ELD.js.map +7 -0
- package/lib/{chunk-CT6ZYIAF.js → chunk-P43AWJ4Q.js} +9 -5
- package/lib/chunk-P43AWJ4Q.js.map +7 -0
- package/lib/client.js +93 -37
- package/lib/client.js.map +3 -3
- package/lib/host-v0.5.8.js +514 -0
- package/lib/host.js +154 -24
- package/lib/index.js +154 -24
- package/lib/index.js.map +4 -4
- package/lib/manager.js +1 -1
- package/lib/shim.js +1 -1
- package/package.json +1 -1
- package/lib/chunk-CT6ZYIAF.js.map +0 -7
- package/lib/chunk-XKDXPB5T.js.map +0 -7
package/lib/host.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createShim
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-P43AWJ4Q.js";
|
|
4
4
|
import {
|
|
5
5
|
MANAGEMENT_PATH,
|
|
6
6
|
Manager,
|
|
7
|
-
managementHandler
|
|
8
|
-
|
|
7
|
+
managementHandler,
|
|
8
|
+
version
|
|
9
|
+
} from "./chunk-ILRW3ELD.js";
|
|
9
10
|
import {
|
|
10
11
|
createAccountClient
|
|
11
12
|
} from "./chunk-U2MU2M5C.js";
|
|
@@ -31,7 +32,7 @@ import {
|
|
|
31
32
|
import z from "@deepseek-ai/schemastery";
|
|
32
33
|
import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
|
|
33
34
|
import { resolveRetryPolicy as resolveRetryPolicy2, resolveImageAttachmentAccess } from "@deepseek-ai/dsh-llm";
|
|
34
|
-
import { join, resolve } from "node:path";
|
|
35
|
+
import { join as join2, resolve } from "node:path";
|
|
35
36
|
|
|
36
37
|
// upstream/workbuddy/src/adapter.ts
|
|
37
38
|
import { createProvider } from "@earendil-works/pi-ai";
|
|
@@ -245,24 +246,132 @@ var WorkBuddyPiAiAdapter = class extends PiAiAdapter {
|
|
|
245
246
|
}
|
|
246
247
|
};
|
|
247
248
|
|
|
249
|
+
// src/plugin-reload.mjs
|
|
250
|
+
import { readFile } from "node:fs/promises";
|
|
251
|
+
import { watch } from "node:fs";
|
|
252
|
+
import { join } from "node:path";
|
|
253
|
+
function outsideActivation(hmr, operation) {
|
|
254
|
+
const scope = hmr?.executing;
|
|
255
|
+
return typeof scope?.exit === "function" ? scope.exit(operation) : operation();
|
|
256
|
+
}
|
|
257
|
+
var PluginReload = class {
|
|
258
|
+
constructor({ service, profile, canReload, hmr = () => void 0, busy = () => false, now = Date.now, runningVersion }) {
|
|
259
|
+
Object.assign(this, { service, profile, canReload, hmr, busy, now, runningVersion });
|
|
260
|
+
this.phase = "current";
|
|
261
|
+
this.installedVersion = runningVersion;
|
|
262
|
+
this.retryAt = 0;
|
|
263
|
+
}
|
|
264
|
+
state() {
|
|
265
|
+
return { runningVersion: this.runningVersion, installedVersion: this.installedVersion, phase: this.phase, canReload: !!this.canReload(), message: this.message };
|
|
266
|
+
}
|
|
267
|
+
start() {
|
|
268
|
+
const dir = this.profile()?.dir;
|
|
269
|
+
if (dir) try {
|
|
270
|
+
this.watcher = watch(dir, () => this.schedule());
|
|
271
|
+
this.watcher.unref();
|
|
272
|
+
} catch {
|
|
273
|
+
}
|
|
274
|
+
this.schedule();
|
|
275
|
+
}
|
|
276
|
+
schedule(delay = 500) {
|
|
277
|
+
if (this.closed) return;
|
|
278
|
+
clearTimeout(this.timer);
|
|
279
|
+
this.timer = setTimeout(() => {
|
|
280
|
+
void this.check().catch(() => {
|
|
281
|
+
});
|
|
282
|
+
}, delay);
|
|
283
|
+
this.timer.unref();
|
|
284
|
+
}
|
|
285
|
+
stop() {
|
|
286
|
+
this.closed = true;
|
|
287
|
+
clearTimeout(this.timer);
|
|
288
|
+
this.watcher?.close();
|
|
289
|
+
}
|
|
290
|
+
check() {
|
|
291
|
+
if (this.closed) return Promise.resolve();
|
|
292
|
+
if (this.flight) return this.flight;
|
|
293
|
+
this.flight = this.inspect().finally(() => {
|
|
294
|
+
this.flight = void 0;
|
|
295
|
+
});
|
|
296
|
+
return this.flight;
|
|
297
|
+
}
|
|
298
|
+
async inspect() {
|
|
299
|
+
const dir = this.profile()?.dir;
|
|
300
|
+
if (!dir) return;
|
|
301
|
+
let manifest, installed;
|
|
302
|
+
try {
|
|
303
|
+
manifest = JSON.parse(await readFile(join(dir, "package.json"), "utf8"));
|
|
304
|
+
installed = JSON.parse(await readFile(join(dir, "node_modules/dsh-multi-router/package.json"), "utf8"));
|
|
305
|
+
} catch {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
if (this.closed || !manifest.dsh?.profile?.bundles?.includes("dsh-multi-router")) return;
|
|
309
|
+
if (installed.name !== "dsh-multi-router" || !/^\d+\.\d+\.\d+(?:-[\w.-]+)?$/.test(installed.version)) return;
|
|
310
|
+
this.installedVersion = installed.version;
|
|
311
|
+
if (installed.version === this.runningVersion) {
|
|
312
|
+
this.phase = "current";
|
|
313
|
+
this.message = void 0;
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
if (!this.canReload() || !this.service()?.setBundleEnabled) {
|
|
317
|
+
this.phase = "restart-required";
|
|
318
|
+
this.message = "\u5F53\u524D DSH \u672A\u63D0\u4F9B\u8FD0\u884C\u4E2D\u91CD\u8F7D\uFF0C\u8BF7\u5347\u7EA7 DSH \u6216\u91CD\u542F\u5E94\u7528\u3002";
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
if (this.busy()) {
|
|
322
|
+
this.phase = "waiting";
|
|
323
|
+
this.message = "\u65B0\u7248\u672C\u5DF2\u5B89\u88C5\uFF0C\u7B49\u5F85\u5F53\u524D\u8BF7\u6C42\u548C\u8D26\u53F7\u64CD\u4F5C\u7ED3\u675F\u540E\u81EA\u52A8\u751F\u6548\u3002";
|
|
324
|
+
this.schedule(1e3);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const root = join(dir, "node_modules/dsh-multi-router");
|
|
328
|
+
try {
|
|
329
|
+
const patch = await readFile(join(root, "cordis.patch.yml"), "utf8");
|
|
330
|
+
if (!patch.includes(`id: llm-multi-router-v2-${installed.version}
|
|
331
|
+
`) || !patch.includes(`name: ./lib/host-v${installed.version}.js`)) throw Error("legacy entry");
|
|
332
|
+
await readFile(join(root, `lib/host-v${installed.version}.js`));
|
|
333
|
+
} catch {
|
|
334
|
+
this.phase = "restart-required";
|
|
335
|
+
this.message = "\u5B89\u88C5\u7248\u672C\u7F3A\u5C11\u7248\u672C\u5316\u5165\u53E3\uFF0C\u91CD\u65B0\u5B89\u88C5\u6700\u65B0\u7248\u540E\u518D\u8BD5\u3002";
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (this.now() < this.retryAt) return;
|
|
339
|
+
this.phase = "reloading";
|
|
340
|
+
this.message = "\u6B63\u5728\u91CD\u65B0\u52A0\u8F7D\u63D2\u4EF6\u4E0E\u914D\u7F6E\u9762\u677F\u2026";
|
|
341
|
+
this.retryAt = this.now() + 6e4;
|
|
342
|
+
try {
|
|
343
|
+
const result = await outsideActivation(this.hmr(), () => this.service().setBundleEnabled("dsh-multi-router", true));
|
|
344
|
+
if (this.closed) return;
|
|
345
|
+
this.phase = "restart-required";
|
|
346
|
+
this.message = result.application === "applied" ? "DSH \u5C1A\u672A\u5207\u6362\u5230\u65B0\u7248\u672C\uFF0C\u8BF7\u91CD\u65B0\u52A0\u8F7D\u63D2\u4EF6\u6216\u67E5\u770B\u7EC4\u4EF6\u9519\u8BEF\u3002" : "DSH \u672A\u80FD\u91CD\u8F7D\u63D2\u4EF6\uFF0C\u8BF7\u5347\u7EA7 DSH \u6216\u91CD\u542F\u5E94\u7528\u3002";
|
|
347
|
+
} catch {
|
|
348
|
+
if (!this.closed) {
|
|
349
|
+
this.phase = "failed";
|
|
350
|
+
this.message = "\u63D2\u4EF6\u91CD\u8F7D\u672A\u5B8C\u6210\uFF0C\u53EF\u7A0D\u540E\u91CD\u8BD5\uFF1B\u5DF2\u4FDD\u5B58\u7684\u914D\u7F6E\u4FDD\u6301\u4E0D\u53D8\u3002";
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
|
|
248
356
|
// src/index.mjs
|
|
249
357
|
var name = "dsh-multi-router";
|
|
250
358
|
var inject = ["llm"];
|
|
251
|
-
var defaultConfigFile = () =>
|
|
359
|
+
var defaultConfigFile = () => join2(resolveDshHome(), "multi-router", "router.json");
|
|
252
360
|
var Config = z.object({ configFile: z.string().description("Absolute path to multi-account router.json") });
|
|
253
361
|
async function apply(ctx, options = {}) {
|
|
254
|
-
let disposed = false, manager, stopWatch, monitorTimer;
|
|
362
|
+
let disposed = false, manager, stopWatch, monitorTimer, startup;
|
|
255
363
|
const releases = [], shims = [], wrappers = [];
|
|
256
364
|
ctx.effect(() => () => {
|
|
257
365
|
disposed = true;
|
|
258
366
|
stopWatch?.();
|
|
259
367
|
clearInterval(monitorTimer);
|
|
368
|
+
manager?.runtime?.stop();
|
|
260
369
|
if (manager) manager.closed = true;
|
|
261
370
|
manager?.plugins.abort.abort();
|
|
262
371
|
manager?.checkins.abort.abort();
|
|
263
372
|
manager?.workbuddyLogin.abort.abort();
|
|
264
373
|
for (const release of releases) release();
|
|
265
|
-
return Promise.all([...shims.map((shim) => shim.close()), ...manager?.refreshes.values() ?? [], ...manager?.monitorFlights.values() ?? [], manager?.localScan, manager?.checkins.flight, manager?.plugins.flight, manager?.plugins.saveQueue.catch(() => {
|
|
374
|
+
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(() => {
|
|
266
375
|
}), manager?.telemetry.queue.catch(() => {
|
|
267
376
|
})]);
|
|
268
377
|
});
|
|
@@ -280,6 +389,19 @@ async function apply(ctx, options = {}) {
|
|
|
280
389
|
ctx.emit("llm/adapters-updated");
|
|
281
390
|
}, { service: () => ctx.get("pluginManager"), profile: () => ctx.get("profileContext") });
|
|
282
391
|
await manager.load();
|
|
392
|
+
if (disposed) return;
|
|
393
|
+
manager.startup = { phase: "discovering" };
|
|
394
|
+
manager.runtime = new PluginReload({
|
|
395
|
+
runningVersion: version,
|
|
396
|
+
service: () => ctx.get("pluginManager"),
|
|
397
|
+
profile: () => ctx.get("profileContext"),
|
|
398
|
+
canReload: () => !!ctx.get("hmr"),
|
|
399
|
+
hmr: () => ctx.get("hmr"),
|
|
400
|
+
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()))
|
|
401
|
+
});
|
|
402
|
+
ctx.inject?.(["webServer"], (webCtx) => {
|
|
403
|
+
webCtx.effect(() => webCtx.webServer.register({ kind: "exact", path: MANAGEMENT_PATH, handler: managementHandler(manager) }));
|
|
404
|
+
});
|
|
283
405
|
const metrics = new SessionMetrics(manager.telemetry);
|
|
284
406
|
ctx.on("session/event", (session, event) => {
|
|
285
407
|
try {
|
|
@@ -289,20 +411,6 @@ async function apply(ctx, options = {}) {
|
|
|
289
411
|
}
|
|
290
412
|
});
|
|
291
413
|
ctx.on("session/disposed", (session) => metrics.dispose(session));
|
|
292
|
-
await manager.syncLocalAccounts().catch(() => ctx.logger.warn("multi-router: local login discovery failed; manual import remains available"));
|
|
293
|
-
await manager.finishInitialSetup().catch(() => ctx.logger.warn("multi-router: first-install guidance could not be saved"));
|
|
294
|
-
manager.checkins.tick();
|
|
295
|
-
void manager.plugins.tick().catch(() => ctx.logger.warn("multi-router: automatic update check unavailable"));
|
|
296
|
-
if (disposed) return;
|
|
297
|
-
void manager.checkFreeModels().catch(() => ctx.logger.warn("multi-router: free catalog persistence failed"));
|
|
298
|
-
void manager.monitorAll().catch(() => ctx.logger.warn("multi-router: usage persistence failed"));
|
|
299
|
-
monitorTimer = setInterval(() => {
|
|
300
|
-
void manager.syncLocalAccounts().then(() => manager.monitorAll()).catch(() => ctx.logger.warn("multi-router: local login discovery or usage persistence failed"));
|
|
301
|
-
manager.checkins.tick();
|
|
302
|
-
void manager.plugins.tick().catch(() => ctx.logger.warn("multi-router: automatic update check unavailable"));
|
|
303
|
-
void manager.checkFreeModels().catch(() => ctx.logger.warn("multi-router: free catalog persistence failed"));
|
|
304
|
-
}, 6e4);
|
|
305
|
-
monitorTimer.unref();
|
|
306
414
|
for (const provider of ["multi-router", ...PROVIDERS]) {
|
|
307
415
|
if (disposed) return;
|
|
308
416
|
const isRouter = provider === "multi-router";
|
|
@@ -361,13 +469,35 @@ async function apply(ctx, options = {}) {
|
|
|
361
469
|
releases.push(ctx.llm.registerAdapter([provider], wrapper.adapter));
|
|
362
470
|
}
|
|
363
471
|
stopWatch = manager.watch(() => ctx.logger.warn("multi-router: invalid config change; keeping last valid configuration"));
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
472
|
+
startup = (async () => {
|
|
473
|
+
await manager.syncLocalAccounts().catch(() => ctx.logger.warn("multi-router: local login discovery failed; manual import remains available"));
|
|
474
|
+
if (disposed) return;
|
|
475
|
+
await manager.finishInitialSetup().catch(() => ctx.logger.warn("multi-router: first-install guidance could not be saved"));
|
|
476
|
+
if (disposed) return;
|
|
477
|
+
manager.startup = { phase: "ready" };
|
|
478
|
+
manager.checkins.tick();
|
|
479
|
+
void manager.checkFreeModels().catch(() => ctx.logger.warn("multi-router: free catalog persistence failed"));
|
|
480
|
+
void manager.monitorAll().catch(() => ctx.logger.warn("multi-router: usage persistence failed"));
|
|
481
|
+
})();
|
|
482
|
+
void manager.plugins.tick().catch(() => ctx.logger.warn("multi-router: automatic update check unavailable"));
|
|
483
|
+
manager.runtime.start();
|
|
484
|
+
ctx.on("plugin-manager/changed", () => manager.runtime.schedule());
|
|
485
|
+
monitorTimer = setInterval(() => {
|
|
486
|
+
void manager.syncLocalAccounts().then(() => {
|
|
487
|
+
if (!disposed) return manager.monitorAll();
|
|
488
|
+
}).catch(() => ctx.logger.warn("multi-router: local login discovery or usage persistence failed"));
|
|
489
|
+
manager.checkins.tick();
|
|
490
|
+
void manager.plugins.tick().catch(() => ctx.logger.warn("multi-router: automatic update check unavailable"));
|
|
491
|
+
void manager.checkFreeModels().catch(() => ctx.logger.warn("multi-router: free catalog persistence failed"));
|
|
492
|
+
void manager.runtime.check().catch(() => {
|
|
493
|
+
});
|
|
494
|
+
}, 6e4);
|
|
495
|
+
monitorTimer.unref();
|
|
367
496
|
ctx.emit("llm/adapters-updated");
|
|
368
497
|
} catch (error) {
|
|
369
498
|
clearInterval(monitorTimer);
|
|
370
499
|
stopWatch?.();
|
|
500
|
+
manager?.runtime?.stop();
|
|
371
501
|
for (const release of releases) release();
|
|
372
502
|
await Promise.all(shims.map((shim) => shim.close()));
|
|
373
503
|
ctx.logger.error("multi-router: initialization failed", error.code ?? error.message);
|
package/lib/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createShim
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-P43AWJ4Q.js";
|
|
4
4
|
import {
|
|
5
5
|
MANAGEMENT_PATH,
|
|
6
6
|
Manager,
|
|
7
|
-
managementHandler
|
|
8
|
-
|
|
7
|
+
managementHandler,
|
|
8
|
+
version
|
|
9
|
+
} from "./chunk-ILRW3ELD.js";
|
|
9
10
|
import {
|
|
10
11
|
createAccountClient
|
|
11
12
|
} from "./chunk-U2MU2M5C.js";
|
|
@@ -31,7 +32,7 @@ import {
|
|
|
31
32
|
import z from "@deepseek-ai/schemastery";
|
|
32
33
|
import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
|
|
33
34
|
import { resolveRetryPolicy as resolveRetryPolicy2, resolveImageAttachmentAccess } from "@deepseek-ai/dsh-llm";
|
|
34
|
-
import { join, resolve } from "node:path";
|
|
35
|
+
import { join as join2, resolve } from "node:path";
|
|
35
36
|
|
|
36
37
|
// upstream/workbuddy/src/adapter.ts
|
|
37
38
|
import { createProvider } from "@earendil-works/pi-ai";
|
|
@@ -245,24 +246,132 @@ var WorkBuddyPiAiAdapter = class extends PiAiAdapter {
|
|
|
245
246
|
}
|
|
246
247
|
};
|
|
247
248
|
|
|
249
|
+
// src/plugin-reload.mjs
|
|
250
|
+
import { readFile } from "node:fs/promises";
|
|
251
|
+
import { watch } from "node:fs";
|
|
252
|
+
import { join } from "node:path";
|
|
253
|
+
function outsideActivation(hmr, operation) {
|
|
254
|
+
const scope = hmr?.executing;
|
|
255
|
+
return typeof scope?.exit === "function" ? scope.exit(operation) : operation();
|
|
256
|
+
}
|
|
257
|
+
var PluginReload = class {
|
|
258
|
+
constructor({ service, profile, canReload, hmr = () => void 0, busy = () => false, now = Date.now, runningVersion }) {
|
|
259
|
+
Object.assign(this, { service, profile, canReload, hmr, busy, now, runningVersion });
|
|
260
|
+
this.phase = "current";
|
|
261
|
+
this.installedVersion = runningVersion;
|
|
262
|
+
this.retryAt = 0;
|
|
263
|
+
}
|
|
264
|
+
state() {
|
|
265
|
+
return { runningVersion: this.runningVersion, installedVersion: this.installedVersion, phase: this.phase, canReload: !!this.canReload(), message: this.message };
|
|
266
|
+
}
|
|
267
|
+
start() {
|
|
268
|
+
const dir = this.profile()?.dir;
|
|
269
|
+
if (dir) try {
|
|
270
|
+
this.watcher = watch(dir, () => this.schedule());
|
|
271
|
+
this.watcher.unref();
|
|
272
|
+
} catch {
|
|
273
|
+
}
|
|
274
|
+
this.schedule();
|
|
275
|
+
}
|
|
276
|
+
schedule(delay = 500) {
|
|
277
|
+
if (this.closed) return;
|
|
278
|
+
clearTimeout(this.timer);
|
|
279
|
+
this.timer = setTimeout(() => {
|
|
280
|
+
void this.check().catch(() => {
|
|
281
|
+
});
|
|
282
|
+
}, delay);
|
|
283
|
+
this.timer.unref();
|
|
284
|
+
}
|
|
285
|
+
stop() {
|
|
286
|
+
this.closed = true;
|
|
287
|
+
clearTimeout(this.timer);
|
|
288
|
+
this.watcher?.close();
|
|
289
|
+
}
|
|
290
|
+
check() {
|
|
291
|
+
if (this.closed) return Promise.resolve();
|
|
292
|
+
if (this.flight) return this.flight;
|
|
293
|
+
this.flight = this.inspect().finally(() => {
|
|
294
|
+
this.flight = void 0;
|
|
295
|
+
});
|
|
296
|
+
return this.flight;
|
|
297
|
+
}
|
|
298
|
+
async inspect() {
|
|
299
|
+
const dir = this.profile()?.dir;
|
|
300
|
+
if (!dir) return;
|
|
301
|
+
let manifest, installed;
|
|
302
|
+
try {
|
|
303
|
+
manifest = JSON.parse(await readFile(join(dir, "package.json"), "utf8"));
|
|
304
|
+
installed = JSON.parse(await readFile(join(dir, "node_modules/dsh-multi-router/package.json"), "utf8"));
|
|
305
|
+
} catch {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
if (this.closed || !manifest.dsh?.profile?.bundles?.includes("dsh-multi-router")) return;
|
|
309
|
+
if (installed.name !== "dsh-multi-router" || !/^\d+\.\d+\.\d+(?:-[\w.-]+)?$/.test(installed.version)) return;
|
|
310
|
+
this.installedVersion = installed.version;
|
|
311
|
+
if (installed.version === this.runningVersion) {
|
|
312
|
+
this.phase = "current";
|
|
313
|
+
this.message = void 0;
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
if (!this.canReload() || !this.service()?.setBundleEnabled) {
|
|
317
|
+
this.phase = "restart-required";
|
|
318
|
+
this.message = "\u5F53\u524D DSH \u672A\u63D0\u4F9B\u8FD0\u884C\u4E2D\u91CD\u8F7D\uFF0C\u8BF7\u5347\u7EA7 DSH \u6216\u91CD\u542F\u5E94\u7528\u3002";
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
if (this.busy()) {
|
|
322
|
+
this.phase = "waiting";
|
|
323
|
+
this.message = "\u65B0\u7248\u672C\u5DF2\u5B89\u88C5\uFF0C\u7B49\u5F85\u5F53\u524D\u8BF7\u6C42\u548C\u8D26\u53F7\u64CD\u4F5C\u7ED3\u675F\u540E\u81EA\u52A8\u751F\u6548\u3002";
|
|
324
|
+
this.schedule(1e3);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const root = join(dir, "node_modules/dsh-multi-router");
|
|
328
|
+
try {
|
|
329
|
+
const patch = await readFile(join(root, "cordis.patch.yml"), "utf8");
|
|
330
|
+
if (!patch.includes(`id: llm-multi-router-v2-${installed.version}
|
|
331
|
+
`) || !patch.includes(`name: ./lib/host-v${installed.version}.js`)) throw Error("legacy entry");
|
|
332
|
+
await readFile(join(root, `lib/host-v${installed.version}.js`));
|
|
333
|
+
} catch {
|
|
334
|
+
this.phase = "restart-required";
|
|
335
|
+
this.message = "\u5B89\u88C5\u7248\u672C\u7F3A\u5C11\u7248\u672C\u5316\u5165\u53E3\uFF0C\u91CD\u65B0\u5B89\u88C5\u6700\u65B0\u7248\u540E\u518D\u8BD5\u3002";
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (this.now() < this.retryAt) return;
|
|
339
|
+
this.phase = "reloading";
|
|
340
|
+
this.message = "\u6B63\u5728\u91CD\u65B0\u52A0\u8F7D\u63D2\u4EF6\u4E0E\u914D\u7F6E\u9762\u677F\u2026";
|
|
341
|
+
this.retryAt = this.now() + 6e4;
|
|
342
|
+
try {
|
|
343
|
+
const result = await outsideActivation(this.hmr(), () => this.service().setBundleEnabled("dsh-multi-router", true));
|
|
344
|
+
if (this.closed) return;
|
|
345
|
+
this.phase = "restart-required";
|
|
346
|
+
this.message = result.application === "applied" ? "DSH \u5C1A\u672A\u5207\u6362\u5230\u65B0\u7248\u672C\uFF0C\u8BF7\u91CD\u65B0\u52A0\u8F7D\u63D2\u4EF6\u6216\u67E5\u770B\u7EC4\u4EF6\u9519\u8BEF\u3002" : "DSH \u672A\u80FD\u91CD\u8F7D\u63D2\u4EF6\uFF0C\u8BF7\u5347\u7EA7 DSH \u6216\u91CD\u542F\u5E94\u7528\u3002";
|
|
347
|
+
} catch {
|
|
348
|
+
if (!this.closed) {
|
|
349
|
+
this.phase = "failed";
|
|
350
|
+
this.message = "\u63D2\u4EF6\u91CD\u8F7D\u672A\u5B8C\u6210\uFF0C\u53EF\u7A0D\u540E\u91CD\u8BD5\uFF1B\u5DF2\u4FDD\u5B58\u7684\u914D\u7F6E\u4FDD\u6301\u4E0D\u53D8\u3002";
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
|
|
248
356
|
// src/index.mjs
|
|
249
357
|
var name = "dsh-multi-router";
|
|
250
358
|
var inject = ["llm"];
|
|
251
|
-
var defaultConfigFile = () =>
|
|
359
|
+
var defaultConfigFile = () => join2(resolveDshHome(), "multi-router", "router.json");
|
|
252
360
|
var Config = z.object({ configFile: z.string().description("Absolute path to multi-account router.json") });
|
|
253
361
|
async function apply(ctx, options = {}) {
|
|
254
|
-
let disposed = false, manager, stopWatch, monitorTimer;
|
|
362
|
+
let disposed = false, manager, stopWatch, monitorTimer, startup;
|
|
255
363
|
const releases = [], shims = [], wrappers = [];
|
|
256
364
|
ctx.effect(() => () => {
|
|
257
365
|
disposed = true;
|
|
258
366
|
stopWatch?.();
|
|
259
367
|
clearInterval(monitorTimer);
|
|
368
|
+
manager?.runtime?.stop();
|
|
260
369
|
if (manager) manager.closed = true;
|
|
261
370
|
manager?.plugins.abort.abort();
|
|
262
371
|
manager?.checkins.abort.abort();
|
|
263
372
|
manager?.workbuddyLogin.abort.abort();
|
|
264
373
|
for (const release of releases) release();
|
|
265
|
-
return Promise.all([...shims.map((shim) => shim.close()), ...manager?.refreshes.values() ?? [], ...manager?.monitorFlights.values() ?? [], manager?.localScan, manager?.checkins.flight, manager?.plugins.flight, manager?.plugins.saveQueue.catch(() => {
|
|
374
|
+
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(() => {
|
|
266
375
|
}), manager?.telemetry.queue.catch(() => {
|
|
267
376
|
})]);
|
|
268
377
|
});
|
|
@@ -280,6 +389,19 @@ async function apply(ctx, options = {}) {
|
|
|
280
389
|
ctx.emit("llm/adapters-updated");
|
|
281
390
|
}, { service: () => ctx.get("pluginManager"), profile: () => ctx.get("profileContext") });
|
|
282
391
|
await manager.load();
|
|
392
|
+
if (disposed) return;
|
|
393
|
+
manager.startup = { phase: "discovering" };
|
|
394
|
+
manager.runtime = new PluginReload({
|
|
395
|
+
runningVersion: version,
|
|
396
|
+
service: () => ctx.get("pluginManager"),
|
|
397
|
+
profile: () => ctx.get("profileContext"),
|
|
398
|
+
canReload: () => !!ctx.get("hmr"),
|
|
399
|
+
hmr: () => ctx.get("hmr"),
|
|
400
|
+
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()))
|
|
401
|
+
});
|
|
402
|
+
ctx.inject?.(["webServer"], (webCtx) => {
|
|
403
|
+
webCtx.effect(() => webCtx.webServer.register({ kind: "exact", path: MANAGEMENT_PATH, handler: managementHandler(manager) }));
|
|
404
|
+
});
|
|
283
405
|
const metrics = new SessionMetrics(manager.telemetry);
|
|
284
406
|
ctx.on("session/event", (session, event) => {
|
|
285
407
|
try {
|
|
@@ -289,20 +411,6 @@ async function apply(ctx, options = {}) {
|
|
|
289
411
|
}
|
|
290
412
|
});
|
|
291
413
|
ctx.on("session/disposed", (session) => metrics.dispose(session));
|
|
292
|
-
await manager.syncLocalAccounts().catch(() => ctx.logger.warn("multi-router: local login discovery failed; manual import remains available"));
|
|
293
|
-
await manager.finishInitialSetup().catch(() => ctx.logger.warn("multi-router: first-install guidance could not be saved"));
|
|
294
|
-
manager.checkins.tick();
|
|
295
|
-
void manager.plugins.tick().catch(() => ctx.logger.warn("multi-router: automatic update check unavailable"));
|
|
296
|
-
if (disposed) return;
|
|
297
|
-
void manager.checkFreeModels().catch(() => ctx.logger.warn("multi-router: free catalog persistence failed"));
|
|
298
|
-
void manager.monitorAll().catch(() => ctx.logger.warn("multi-router: usage persistence failed"));
|
|
299
|
-
monitorTimer = setInterval(() => {
|
|
300
|
-
void manager.syncLocalAccounts().then(() => manager.monitorAll()).catch(() => ctx.logger.warn("multi-router: local login discovery or usage persistence failed"));
|
|
301
|
-
manager.checkins.tick();
|
|
302
|
-
void manager.plugins.tick().catch(() => ctx.logger.warn("multi-router: automatic update check unavailable"));
|
|
303
|
-
void manager.checkFreeModels().catch(() => ctx.logger.warn("multi-router: free catalog persistence failed"));
|
|
304
|
-
}, 6e4);
|
|
305
|
-
monitorTimer.unref();
|
|
306
414
|
for (const provider of ["multi-router", ...PROVIDERS]) {
|
|
307
415
|
if (disposed) return;
|
|
308
416
|
const isRouter = provider === "multi-router";
|
|
@@ -361,13 +469,35 @@ async function apply(ctx, options = {}) {
|
|
|
361
469
|
releases.push(ctx.llm.registerAdapter([provider], wrapper.adapter));
|
|
362
470
|
}
|
|
363
471
|
stopWatch = manager.watch(() => ctx.logger.warn("multi-router: invalid config change; keeping last valid configuration"));
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
472
|
+
startup = (async () => {
|
|
473
|
+
await manager.syncLocalAccounts().catch(() => ctx.logger.warn("multi-router: local login discovery failed; manual import remains available"));
|
|
474
|
+
if (disposed) return;
|
|
475
|
+
await manager.finishInitialSetup().catch(() => ctx.logger.warn("multi-router: first-install guidance could not be saved"));
|
|
476
|
+
if (disposed) return;
|
|
477
|
+
manager.startup = { phase: "ready" };
|
|
478
|
+
manager.checkins.tick();
|
|
479
|
+
void manager.checkFreeModels().catch(() => ctx.logger.warn("multi-router: free catalog persistence failed"));
|
|
480
|
+
void manager.monitorAll().catch(() => ctx.logger.warn("multi-router: usage persistence failed"));
|
|
481
|
+
})();
|
|
482
|
+
void manager.plugins.tick().catch(() => ctx.logger.warn("multi-router: automatic update check unavailable"));
|
|
483
|
+
manager.runtime.start();
|
|
484
|
+
ctx.on("plugin-manager/changed", () => manager.runtime.schedule());
|
|
485
|
+
monitorTimer = setInterval(() => {
|
|
486
|
+
void manager.syncLocalAccounts().then(() => {
|
|
487
|
+
if (!disposed) return manager.monitorAll();
|
|
488
|
+
}).catch(() => ctx.logger.warn("multi-router: local login discovery or usage persistence failed"));
|
|
489
|
+
manager.checkins.tick();
|
|
490
|
+
void manager.plugins.tick().catch(() => ctx.logger.warn("multi-router: automatic update check unavailable"));
|
|
491
|
+
void manager.checkFreeModels().catch(() => ctx.logger.warn("multi-router: free catalog persistence failed"));
|
|
492
|
+
void manager.runtime.check().catch(() => {
|
|
493
|
+
});
|
|
494
|
+
}, 6e4);
|
|
495
|
+
monitorTimer.unref();
|
|
367
496
|
ctx.emit("llm/adapters-updated");
|
|
368
497
|
} catch (error) {
|
|
369
498
|
clearInterval(monitorTimer);
|
|
370
499
|
stopWatch?.();
|
|
500
|
+
manager?.runtime?.stop();
|
|
371
501
|
for (const release of releases) release();
|
|
372
502
|
await Promise.all(shims.map((shim) => shim.close()));
|
|
373
503
|
ctx.logger.error("multi-router: initialization failed", error.code ?? error.message);
|