dsh-connect-modelscope-token-plan 0.4.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { E as redactSecrets, _ as CODE, b as reclassifyStream, c as LLM_PROVIDER_ID, i as name, l as buildDescriptors, o as LLM_API_KEY_NAME, s as LLM_DISPLAY_NAME } from "./host-config.js";
1
+ import { D as redactSecrets, c as LLM_PROVIDER_ID, i as name, l as buildDescriptors, o as LLM_API_KEY_NAME, s as LLM_DISPLAY_NAME, v as CODE, x as reclassifyStream } from "./host-config.js";
2
2
  import { createProvider } from "@earendil-works/pi-ai";
3
3
  import { openAICompletionsApi } from "@earendil-works/pi-ai/api/openai-completions.lazy";
4
4
  import { PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
@@ -396,14 +396,15 @@ function eventOfChunk(chunk) {
396
396
  * 2. **失败也记账,但 token 为 null**。429/错误没有 usage chunk,计数照记、
397
397
  * 事件另记;「没有 token 数」与「token 是 0」在 wire 里是两件事。
398
398
  * 3. **写 sinks 永不抛**。`safe()` 把同步抛与异步拒一并吞掉:观测层不能成为
399
- * 对话失败的原因。
399
+ * 对话失败的原因。但失败会通过 `onError` 回调留痕(如果提供了)。
400
400
  *
401
401
  * @param {AsyncIterableIterator<unknown>} source - 内层流。
402
402
  * @param {string} modelId - 本次调用的模型 id(由出口处的 options 捕获)。
403
403
  * @param {UsageSinks} sinks - 写入口。
404
+ * @param {(error: unknown) => void} [onError] - 写入失败时的回调(如 logger.warn)。
404
405
  * @returns {AsyncGenerator<unknown>} 透传后的流。
405
406
  */
406
- async function* observeStream(source, modelId, sinks) {
407
+ async function* observeStream(source, modelId, sinks, onError) {
407
408
  let tokens = null;
408
409
  try {
409
410
  for await (const chunk of source) {
@@ -414,22 +415,36 @@ async function* observeStream(source, modelId, sinks) {
414
415
  modelId,
415
416
  kind: event.kind,
416
417
  message: event.message
417
- }));
418
+ }), onError);
418
419
  yield chunk;
419
420
  }
420
421
  } finally {
421
422
  safe(() => sinks.recordCall({
422
423
  modelId,
423
424
  tokens
424
- }));
425
+ }), onError);
425
426
  }
426
427
  }
427
- /** 调一个 sink 并吞掉它的任何失败(同步抛与异步拒都吞)。 */
428
- function safe(run) {
428
+ /**
429
+ * 调一个 sink 并吞掉它的任何失败(同步抛与异步拒都吞)。
430
+ *
431
+ * `onError` 是可选的失败回调:观测层不能成为对话失败的原因,但「观测层在丢数据」
432
+ * 这件事应该可见——否则用户发现计数不对时没有任何线索。index.ts 装配时传
433
+ * `ctx.logger.warn`,让写入失败(磁盘满、权限问题、版本守卫)在日志里留痕。
434
+ */
435
+ function safe(run, onError) {
429
436
  try {
430
437
  const result = run();
431
- if (result !== null && typeof result === "object" && typeof result.then === "function") result.then(void 0, () => {});
432
- } catch {}
438
+ if (result !== null && typeof result === "object" && typeof result.then === "function") result.then(void 0, (error) => {
439
+ try {
440
+ onError?.(error);
441
+ } catch {}
442
+ });
443
+ } catch (error) {
444
+ try {
445
+ onError?.(error);
446
+ } catch {}
447
+ }
433
448
  }
434
449
  /**
435
450
  * 读一条调用参数里的模型 id(`GenerateOptions.model`)。
@@ -457,14 +472,15 @@ function modelIdOfOptions(options) {
457
472
  *
458
473
  * @param {object} inner - 适配器实例。
459
474
  * @param {UsageSinks} sinks - 写入口。
475
+ * @param {(error: unknown) => void} [onError] - 写入失败时的回调(如 logger.warn)。
460
476
  * @returns {object} 套好观察层的适配器。
461
477
  */
462
- function withUsageObserver(inner, sinks) {
478
+ function withUsageObserver(inner, sinks, onError) {
463
479
  const wrapStream = (stream, options) => {
464
480
  const modelId = modelIdOfOptions(options);
465
481
  const source = stream(options);
466
482
  if (modelId === "") return source;
467
- return observeStream(source, modelId, sinks);
483
+ return observeStream(source, modelId, sinks, onError);
468
484
  };
469
485
  return new Proxy(inner, { get(target, prop, receiver) {
470
486
  const value = Reflect.get(target, prop, receiver);
@@ -480,11 +496,12 @@ function withUsageObserver(inner, sinks) {
480
496
  const wrap = (handle) => {
481
497
  if (handle === null || typeof handle !== "object" || modelId === "") return handle;
482
498
  const inner = handle;
483
- if (typeof inner.stream !== "function") return handle;
484
- return {
485
- ...inner,
486
- stream: (o) => observeStream(inner.stream(o), modelId, sinks)
487
- };
499
+ const innerStream = inner.stream;
500
+ if (typeof innerStream !== "function") return handle;
501
+ return new Proxy(inner, { get(target, prop, receiver) {
502
+ if (prop === "stream") return (o) => observeStream(innerStream.call(target, o), modelId, sinks, onError);
503
+ return Reflect.get(target, prop, receiver);
504
+ } });
488
505
  };
489
506
  const promise = prepared;
490
507
  if (promise !== null && typeof promise.then === "function") return promise.then((p) => wrap(p));
@@ -541,18 +558,27 @@ function withUsageObserver(inner, sinks) {
541
558
  * `fs`)的服务解析器。
542
559
  * @param {string[]} [options.unavailableModelIds] - 额度耗尽的模型 id,从 offer 里
543
560
  * 排除,避免发出注定 429 的请求。
561
+ * @param {object} [options.maxTokensOverrides] - 逐模型输出上限覆盖(id → tokens),
562
+ * 归一后的 `ResolvedSettings.maxTokensOverrides`。**构造期读入**(apply 时随
563
+ * wiring 一次性 `resolveSettings`,与 `apiBase` 同理):改 patch 要 reload
564
+ * (apply 重跑)才生效,不是下一轮目录轮询。魔搭目录从不声明该字段,所以这是
565
+ * 输出上限唯一的真值来源(见 llm-models.ts 的 `maxTokensFor`)。
544
566
  * @param {UsageSinks} [options.usage] - 本地计数的写入口(usage-store 的两条
545
567
  * 方法)。**这是面板「今日次数 / 模型分布 / 趋势 / 429 事件流」唯一的生产
546
568
  * 者**——probe 那条写入路径已随目录表删除,缺了它四块面板恒为 0 与空。
547
569
  * 缺省不套观察层(零开销,见 `usage-observer.ts`)。
570
+ * @param {(error: unknown) => void} [options.onError] - 写入失败时的回调(如
571
+ * logger.warn)。观测层不能成为对话失败的原因,但「观测层在丢数据」这件事
572
+ * 应该可见——否则用户发现计数不对时没有任何线索。
548
573
  * @returns {{adapter: object, providerIds: string[]}} 适配器与它拥有的 ids。
549
574
  */
550
- function createModelScopeAdapter({ entries, enabledIds = [], baseUrl, resolveApiKey, get, unavailableModelIds = [], usage }) {
575
+ function createModelScopeAdapter({ entries, enabledIds = [], baseUrl, resolveApiKey, get, unavailableModelIds = [], maxTokensOverrides = {}, usage, onError }) {
551
576
  const models = buildDescriptors(entries, {
552
577
  providerId: LLM_PROVIDER_ID,
553
578
  baseUrl,
554
579
  enabledIds,
555
- unavailableModelIds
580
+ unavailableModelIds,
581
+ maxTokensOverrides
556
582
  });
557
583
  const built = assemblePiAiAdapter({
558
584
  providerId: LLM_PROVIDER_ID,
@@ -563,7 +589,7 @@ function createModelScopeAdapter({ entries, enabledIds = [], baseUrl, resolveApi
563
589
  ...get !== void 0 ? { get } : {}
564
590
  });
565
591
  return {
566
- adapter: usage === void 0 ? built.adapter : withUsageObserver(built.adapter, usage),
592
+ adapter: usage === void 0 ? built.adapter : withUsageObserver(built.adapter, usage, onError),
567
593
  providerIds: built.providerIds
568
594
  };
569
595
  }
package/package.json CHANGED
@@ -1,115 +1,115 @@
1
- {
2
- "name": "dsh-connect-modelscope-token-plan",
3
- "displayName": "DSH Connect ModelScope Token Plan",
4
- "icon": "./icon.svg",
5
- "version": "0.4.0",
6
- "homepage": "https://github.com/eghrhegpe/dsh-connect-modelscope-token-plan",
7
- "bugs": {
8
- "url": "https://github.com/eghrhegpe/dsh-connect-modelscope-token-plan/issues"
9
- },
10
- "author": "eghrhegpe",
11
- "description": "ModelScope (modelscope.cn) connect bundle for the Harness Web UI: the official Magicube balance plus, for calls made through this plugin, per-model counts, a daily trend, and a 429 error event list on the Plugins-page panel, plus a default-off switch that registers ModelScope models as a DSH LLM provider.",
12
- "keywords": [
13
- "dsh-plugin",
14
- "deepseek-harness",
15
- "modelscope",
16
- "token-plan",
17
- "quota",
18
- "api-inference"
19
- ],
20
- "type": "module",
21
- "main": "./lib/index.js",
22
- "exports": {
23
- ".": "./lib/index.js",
24
- "./client": "./client.js",
25
- "./locale/*.json": "./locale/*.json",
26
- "./package.json": "./package.json"
27
- },
28
- "files": [
29
- "lib",
30
- "client.js",
31
- "icon.svg",
32
- "locale",
33
- "assets",
34
- "cordis.patch.yml",
35
- "README.md",
36
- "CHANGELOG.md",
37
- "LICENSE",
38
- "screenshots.json"
39
- ],
40
- "scripts": {
41
- "typecheck": "tsc -p tsconfig.json",
42
- "build:client": "tsdown -c tsdown.config.mjs",
43
- "duplicate-check": "jscpd src --min-tokens 70 --reporters console-full",
44
- "test": "node test/run-all.mjs",
45
- "test:mutate": "node tools/dev/mutate.mjs tools/dev/mutate-spec.json",
46
- "doctor": "node tools/doctor.mjs",
47
- "doctor:json": "node tools/doctor.mjs --json",
48
- "build": "tsdown -c tsdown.config.mjs",
49
- "prepack": "npm run build"
50
- },
51
- "dsh": {
52
- "bundle": {
53
- "patch": "./cordis.patch.yml"
54
- },
55
- "client": {
56
- "platform": "web",
57
- "immediately": true,
58
- "inject": [
59
- "@deepseek-ai/dsh-client-locale",
60
- "@deepseek-ai/dsh-client-ui-renderer"
61
- ]
62
- }
63
- },
64
- "peerDependencies": {
65
- "@deepseek-ai/cordis": ">=4.0.2 <5.0.0",
66
- "@deepseek-ai/dsh-client-locale": ">=0.1.5 <0.3",
67
- "@deepseek-ai/dsh-client-ui-layout": ">=0.1.5 <0.3",
68
- "@deepseek-ai/dsh-client-ui-renderer": ">=0.1.5 <0.3",
69
- "@deepseek-ai/dsh-credentials": ">=0.1.5 <0.3",
70
- "@deepseek-ai/dsh-home-paths": ">=0.1.5 <0.3",
71
- "@deepseek-ai/dsh-host-webserver": ">=0.1.5 <0.3",
72
- "@deepseek-ai/dsh-llm": ">=0.1.5 <0.3",
73
- "@deepseek-ai/dsh-llm-pi-ai": ">=0.1.5 <0.3",
74
- "@deepseek-ai/dsh-settings": ">=0.1.5 <0.3",
75
- "@deepseek-ai/dsh-tools": ">=0.1.5 <0.3",
76
- "@deepseek-ai/schemastery": "^3.18.2",
77
- "@earendil-works/pi-ai": "^0.85.1"
78
- },
79
- "peerDependenciesMeta": {
80
- "@deepseek-ai/cordis": { "optional": true },
81
- "@deepseek-ai/dsh-client-locale": { "optional": true },
82
- "@deepseek-ai/dsh-client-ui-layout": { "optional": true },
83
- "@deepseek-ai/dsh-client-ui-renderer": { "optional": true },
84
- "@deepseek-ai/dsh-credentials": { "optional": true },
85
- "@deepseek-ai/dsh-home-paths": { "optional": true },
86
- "@deepseek-ai/dsh-host-webserver": { "optional": true },
87
- "@deepseek-ai/dsh-llm": { "optional": true },
88
- "@deepseek-ai/dsh-llm-pi-ai": { "optional": true },
89
- "@deepseek-ai/dsh-settings": { "optional": true },
90
- "@deepseek-ai/dsh-tools": { "optional": true },
91
- "@deepseek-ai/schemastery": { "optional": true },
92
- "@earendil-works/pi-ai": { "optional": true }
93
- },
94
- "engines": {
95
- "node": "^22.19.0 || >=24.0.0"
96
- },
97
- "repository": {
98
- "type": "git",
99
- "url": "git+https://github.com/eghrhegpe/dsh-connect-modelscope-token-plan.git"
100
- },
101
- "license": "MIT",
102
- "devDependencies": {
103
- "@types/node": "^22.19.0",
104
- "jscpd": "^5.4.0",
105
- "jsdom": "^30.1.3",
106
- "react": "18.3.1",
107
- "react-dom": "18.3.1",
108
- "tsdown": "0.23.0",
109
- "typescript": "5.9.3"
110
- },
111
- "overrides": {
112
- "rolldown": "1.2.12",
113
- "rolldown-plugin-dts": "0.28.6"
114
- }
115
- }
1
+ {
2
+ "name": "dsh-connect-modelscope-token-plan",
3
+ "displayName": "DSH Connect ModelScope Token Plan",
4
+ "icon": "./icon.svg",
5
+ "version": "0.6.1",
6
+ "homepage": "https://github.com/eghrhegpe/dsh-connect-modelscope-token-plan",
7
+ "bugs": {
8
+ "url": "https://github.com/eghrhegpe/dsh-connect-modelscope-token-plan/issues"
9
+ },
10
+ "author": "eghrhegpe",
11
+ "description": "ModelScope (modelscope.cn) connect bundle for the Harness Web UI: the official Magicube balance plus, for calls made through this plugin, per-model counts, a daily trend, and a 429 error event list on the Plugins-page panel, plus a default-off switch that registers ModelScope models as a DSH LLM provider.",
12
+ "keywords": [
13
+ "dsh-plugin",
14
+ "deepseek-harness",
15
+ "modelscope",
16
+ "token-plan",
17
+ "quota",
18
+ "api-inference"
19
+ ],
20
+ "type": "module",
21
+ "main": "./lib/index.js",
22
+ "exports": {
23
+ ".": "./lib/index.js",
24
+ "./client": "./client.js",
25
+ "./locale/*.json": "./locale/*.json",
26
+ "./package.json": "./package.json"
27
+ },
28
+ "files": [
29
+ "lib",
30
+ "client.js",
31
+ "icon.svg",
32
+ "locale",
33
+ "assets",
34
+ "cordis.patch.yml",
35
+ "README.md",
36
+ "CHANGELOG.md",
37
+ "LICENSE",
38
+ "screenshots.json"
39
+ ],
40
+ "scripts": {
41
+ "typecheck": "tsc -p tsconfig.json",
42
+ "build:client": "tsdown -c tsdown.config.mjs",
43
+ "duplicate-check": "jscpd src --min-tokens 70 --reporters console-full",
44
+ "test": "node test/run-all.mjs",
45
+ "test:mutate": "node tools/dev/mutate.mjs tools/dev/mutate-spec.json",
46
+ "doctor": "node tools/doctor.mjs",
47
+ "doctor:json": "node tools/doctor.mjs --json",
48
+ "build": "tsdown -c tsdown.config.mjs",
49
+ "prepack": "npm run build"
50
+ },
51
+ "dsh": {
52
+ "bundle": {
53
+ "patch": "./cordis.patch.yml"
54
+ },
55
+ "client": {
56
+ "platform": "web",
57
+ "immediately": true,
58
+ "inject": [
59
+ "@deepseek-ai/dsh-client-locale",
60
+ "@deepseek-ai/dsh-client-ui-renderer"
61
+ ]
62
+ }
63
+ },
64
+ "peerDependencies": {
65
+ "@deepseek-ai/cordis": ">=4.0.2 <5.0.0",
66
+ "@deepseek-ai/dsh-client-locale": ">=0.1.5 <0.3",
67
+ "@deepseek-ai/dsh-client-ui-layout": ">=0.1.5 <0.3",
68
+ "@deepseek-ai/dsh-client-ui-renderer": ">=0.1.5 <0.3",
69
+ "@deepseek-ai/dsh-credentials": ">=0.1.5 <0.3",
70
+ "@deepseek-ai/dsh-home-paths": ">=0.1.5 <0.3",
71
+ "@deepseek-ai/dsh-host-webserver": ">=0.1.5 <0.3",
72
+ "@deepseek-ai/dsh-llm": ">=0.1.5 <0.3",
73
+ "@deepseek-ai/dsh-llm-pi-ai": ">=0.1.5 <0.3",
74
+ "@deepseek-ai/dsh-settings": ">=0.1.5 <0.3",
75
+ "@deepseek-ai/dsh-tools": ">=0.1.5 <0.3",
76
+ "@deepseek-ai/schemastery": "^3.18.2",
77
+ "@earendil-works/pi-ai": "^0.85.1"
78
+ },
79
+ "peerDependenciesMeta": {
80
+ "@deepseek-ai/cordis": { "optional": true },
81
+ "@deepseek-ai/dsh-client-locale": { "optional": true },
82
+ "@deepseek-ai/dsh-client-ui-layout": { "optional": true },
83
+ "@deepseek-ai/dsh-client-ui-renderer": { "optional": true },
84
+ "@deepseek-ai/dsh-credentials": { "optional": true },
85
+ "@deepseek-ai/dsh-home-paths": { "optional": true },
86
+ "@deepseek-ai/dsh-host-webserver": { "optional": true },
87
+ "@deepseek-ai/dsh-llm": { "optional": true },
88
+ "@deepseek-ai/dsh-llm-pi-ai": { "optional": true },
89
+ "@deepseek-ai/dsh-settings": { "optional": true },
90
+ "@deepseek-ai/dsh-tools": { "optional": true },
91
+ "@deepseek-ai/schemastery": { "optional": true },
92
+ "@earendil-works/pi-ai": { "optional": true }
93
+ },
94
+ "engines": {
95
+ "node": "^22.19.0 || >=24.0.0"
96
+ },
97
+ "repository": {
98
+ "type": "git",
99
+ "url": "git+https://github.com/eghrhegpe/dsh-connect-modelscope-token-plan.git"
100
+ },
101
+ "license": "MIT",
102
+ "devDependencies": {
103
+ "@types/node": "^22.19.0",
104
+ "jscpd": "^5.4.0",
105
+ "jsdom": "^30.1.3",
106
+ "react": "18.3.1",
107
+ "react-dom": "18.3.1",
108
+ "tsdown": "0.23.0",
109
+ "typescript": "5.9.3"
110
+ },
111
+ "overrides": {
112
+ "rolldown": "1.2.12",
113
+ "rolldown-plugin-dts": "0.28.6"
114
+ }
115
+ }
package/screenshots.json CHANGED
@@ -1,4 +1,5 @@
1
1
  [
2
2
  "assets/tab-account-and-usage.png",
3
- "assets/tab-model-list.png"
3
+ "assets/tab-model-list.png",
4
+ "assets/tab-model-draw.png"
4
5
  ]
Binary file