dsh-connect-modelscope-token-plan 0.4.0 → 0.5.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.
- package/CHANGELOG.md +30 -0
- package/README.md +18 -12
- package/assets/tab-account-and-usage.png +0 -0
- package/assets/tab-model-draw.png +0 -0
- package/assets/tab-model-list.png +0 -0
- package/client.js +632 -150
- package/cordis.patch.yml +9 -4
- package/lib/host-config.js +138 -6
- package/lib/index.js +586 -143
- package/lib/llm-adapter.js +38 -18
- package/package.json +1 -1
- package/screenshots.json +2 -1
- package/assets/icon-preview.png +0 -0
package/lib/llm-adapter.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
-
/**
|
|
428
|
-
|
|
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
|
-
|
|
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
|
-
|
|
484
|
-
return
|
|
485
|
-
|
|
486
|
-
stream
|
|
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));
|
|
@@ -545,9 +562,12 @@ function withUsageObserver(inner, sinks) {
|
|
|
545
562
|
* 方法)。**这是面板「今日次数 / 模型分布 / 趋势 / 429 事件流」唯一的生产
|
|
546
563
|
* 者**——probe 那条写入路径已随目录表删除,缺了它四块面板恒为 0 与空。
|
|
547
564
|
* 缺省不套观察层(零开销,见 `usage-observer.ts`)。
|
|
565
|
+
* @param {(error: unknown) => void} [options.onError] - 写入失败时的回调(如
|
|
566
|
+
* logger.warn)。观测层不能成为对话失败的原因,但「观测层在丢数据」这件事
|
|
567
|
+
* 应该可见——否则用户发现计数不对时没有任何线索。
|
|
548
568
|
* @returns {{adapter: object, providerIds: string[]}} 适配器与它拥有的 ids。
|
|
549
569
|
*/
|
|
550
|
-
function createModelScopeAdapter({ entries, enabledIds = [], baseUrl, resolveApiKey, get, unavailableModelIds = [], usage }) {
|
|
570
|
+
function createModelScopeAdapter({ entries, enabledIds = [], baseUrl, resolveApiKey, get, unavailableModelIds = [], usage, onError }) {
|
|
551
571
|
const models = buildDescriptors(entries, {
|
|
552
572
|
providerId: LLM_PROVIDER_ID,
|
|
553
573
|
baseUrl,
|
|
@@ -563,7 +583,7 @@ function createModelScopeAdapter({ entries, enabledIds = [], baseUrl, resolveApi
|
|
|
563
583
|
...get !== void 0 ? { get } : {}
|
|
564
584
|
});
|
|
565
585
|
return {
|
|
566
|
-
adapter: usage === void 0 ? built.adapter : withUsageObserver(built.adapter, usage),
|
|
586
|
+
adapter: usage === void 0 ? built.adapter : withUsageObserver(built.adapter, usage, onError),
|
|
567
587
|
providerIds: built.providerIds
|
|
568
588
|
};
|
|
569
589
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "dsh-connect-modelscope-token-plan",
|
|
3
3
|
"displayName": "DSH Connect ModelScope Token Plan",
|
|
4
4
|
"icon": "./icon.svg",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.5.0",
|
|
6
6
|
"homepage": "https://github.com/eghrhegpe/dsh-connect-modelscope-token-plan",
|
|
7
7
|
"bugs": {
|
|
8
8
|
"url": "https://github.com/eghrhegpe/dsh-connect-modelscope-token-plan/issues"
|
package/screenshots.json
CHANGED
package/assets/icon-preview.png
DELETED
|
Binary file
|