dsh-codearts 1.2.2 → 1.2.3
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 +18 -0
- package/lib/bin.mjs +2 -2
- package/lib/client/index.d.cts +7 -0
- package/lib/client/index.js +231 -113
- package/lib/index.mjs +144 -2
- package/lib/{usage-DztQaswb.mjs → usage-CzJjkqOp.mjs} +42 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,24 @@
|
|
|
3
3
|
本文件记录本插件的重要改动。格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
|
|
4
4
|
版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
|
5
5
|
|
|
6
|
+
## [1.2.3] - 2026-11-02
|
|
7
|
+
|
|
8
|
+
### 新增
|
|
9
|
+
|
|
10
|
+
- **模型列表里给「上游说不可用」的模型挂「异常」Tag**:某个模型被上游回
|
|
11
|
+
`InferHub.ModelArts.81003.401`(模型不存在 / 本账号无权限)后,设置卡片的勾选区
|
|
12
|
+
会挂一个「异常」Tag,悬浮显示上游原始原因。**只标记,不替用户取消勾选**,也
|
|
13
|
+
**不随「刷新模型列表」清掉** —— 刷新只重拉上游清单,而清单里照样有它(2026-11-02
|
|
14
|
+
实测),复活不了;标记按本地日期自然过期,第二天自动重试。多账号下这个错误只有在
|
|
15
|
+
所有号都试过之后才会浮上来,所以按模型记全局。
|
|
16
|
+
- **勾选的模型可以点「测试」实测一次**:模型行上多一个「测试」按钮(只对已勾选的
|
|
17
|
+
模型出现),点一下就用一句 `ping`、`max_tokens: 16` 真发一次请求,逐账号轮着试 ——
|
|
18
|
+
清单里有 ≠ 能调通,只有实测才知道。成功显示「通过」并**清掉该模型的「异常」标记**;
|
|
19
|
+
失败显示「失败」,悬浮可看上游原因。同一时间只测一个,不占满上游并发槽位。
|
|
20
|
+
- **点开积分弹层也能看到每个账号今天用了多少 token**:那张逐号明细表多了「今日 Token」
|
|
21
|
+
一列,数字口径与设置卡片「用量」区块一致(输入 + 输出,按人类习惯缩写成 12.3k),
|
|
22
|
+
悬浮还能看到输入/输出拆分与请求数。只统计本机经插件发出的请求,不是账号总额度。
|
|
23
|
+
|
|
6
24
|
## [1.2.2] - 2026-11-02
|
|
7
25
|
|
|
8
26
|
### 修复
|
package/lib/bin.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { R as isBenefitModel, V as CodeArtsAccountStore, W as codeartsAccountsPath, d as fetchCallerIdentity, n as codeartsUsagePath, r as discoverModels, t as CodeArtsUsageTracker } from "./usage-CzJjkqOp.mjs";
|
|
3
3
|
import { existsSync, statSync } from "node:fs";
|
|
4
4
|
//#region src/version.ts
|
|
5
|
-
const CODEARTS_VERSION = "1.2.
|
|
5
|
+
const CODEARTS_VERSION = "1.2.3";
|
|
6
6
|
//#endregion
|
|
7
7
|
//#region src/bin.ts
|
|
8
8
|
/**
|
package/lib/client/index.d.cts
CHANGED
|
@@ -41,6 +41,11 @@ interface CodeArtsSettingsKey {
|
|
|
41
41
|
benefitBlocked: string;
|
|
42
42
|
benefitBlockedHint: string;
|
|
43
43
|
modelImages: string;
|
|
44
|
+
modelError: string;
|
|
45
|
+
testModel: string;
|
|
46
|
+
testingModel: string;
|
|
47
|
+
testOk: string;
|
|
48
|
+
testFailed: string;
|
|
44
49
|
refreshModels: string;
|
|
45
50
|
refreshing: string;
|
|
46
51
|
refreshed: string;
|
|
@@ -91,6 +96,8 @@ interface CodeArtsSettingsKey {
|
|
|
91
96
|
creditsDockRefreshing: string;
|
|
92
97
|
creditsDockColAccount: string;
|
|
93
98
|
creditsDockColBalance: string;
|
|
99
|
+
creditsDockColTokens: string;
|
|
100
|
+
creditsDockNoTokens: string;
|
|
94
101
|
creditsDockEmpty: string;
|
|
95
102
|
creditsDockExpiring: string;
|
|
96
103
|
creditsDockUpdated: string;
|
package/lib/client/index.js
CHANGED
|
@@ -33,70 +33,70 @@ if (typeof document !== "undefined" && document.querySelector("style[data-plugin
|
|
|
33
33
|
document.head.appendChild(tag);
|
|
34
34
|
}
|
|
35
35
|
var CodeArtsPluginCard_module_css_default = {
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"modelShare": "xoziZG_modelShare",
|
|
47
|
-
"creditBlock": "xoziZG_creditBlock",
|
|
48
|
-
"manualForm": "xoziZG_manualForm",
|
|
36
|
+
"accountNameRow": "xoziZG_accountNameRow",
|
|
37
|
+
"balanceRow": "xoziZG_balanceRow",
|
|
38
|
+
"modelFill": "xoziZG_modelFill",
|
|
39
|
+
"danger": "xoziZG_danger",
|
|
40
|
+
"expiryRow": "xoziZG_expiryRow",
|
|
41
|
+
"accountEntry": "xoziZG_accountEntry",
|
|
42
|
+
"accountHint": "xoziZG_accountHint",
|
|
43
|
+
"manualSummary": "xoziZG_manualSummary",
|
|
44
|
+
"body": "xoziZG_body",
|
|
45
|
+
"barFill": "xoziZG_barFill",
|
|
49
46
|
"updated": "xoziZG_updated",
|
|
50
|
-
"
|
|
47
|
+
"error": "xoziZG_error",
|
|
48
|
+
"avatar": "xoziZG_avatar",
|
|
49
|
+
"balanceMeta": "xoziZG_balanceMeta",
|
|
50
|
+
"desc": "xoziZG_desc",
|
|
51
51
|
"name": "xoziZG_name",
|
|
52
|
-
"
|
|
53
|
-
"usageFill": "xoziZG_usageFill",
|
|
54
|
-
"modelName": "xoziZG_modelName",
|
|
55
|
-
"statusLine": "xoziZG_statusLine",
|
|
56
|
-
"count": "xoziZG_count",
|
|
57
|
-
"modelFill": "xoziZG_modelFill",
|
|
52
|
+
"tabPanel": "xoziZG_tabPanel",
|
|
58
53
|
"accountInfo": "xoziZG_accountInfo",
|
|
59
|
-
"avatar": "xoziZG_avatar",
|
|
60
|
-
"headText": "xoziZG_headText",
|
|
61
54
|
"card": "xoziZG_card",
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"claimAllRow": "xoziZG_claimAllRow",
|
|
67
|
-
"modelTrack": "xoziZG_modelTrack",
|
|
68
|
-
"manual": "xoziZG_manual",
|
|
69
|
-
"accountEntry": "xoziZG_accountEntry",
|
|
55
|
+
"balanceUnit": "xoziZG_balanceUnit",
|
|
56
|
+
"sectionHead": "xoziZG_sectionHead",
|
|
57
|
+
"choiceRow": "xoziZG_choiceRow",
|
|
58
|
+
"balance": "xoziZG_balance",
|
|
70
59
|
"creditLink": "xoziZG_creditLink",
|
|
71
60
|
"accountRow": "xoziZG_accountRow",
|
|
61
|
+
"usageFill": "xoziZG_usageFill",
|
|
62
|
+
"modelTrack": "xoziZG_modelTrack",
|
|
63
|
+
"area": "xoziZG_area",
|
|
64
|
+
"check": "xoziZG_check",
|
|
65
|
+
"headText": "xoziZG_headText",
|
|
66
|
+
"accountRowActions": "xoziZG_accountRowActions",
|
|
72
67
|
"creditHint": "xoziZG_creditHint",
|
|
73
|
-
"header": "xoziZG_header",
|
|
74
|
-
"accountName": "xoziZG_accountName",
|
|
75
|
-
"modelChart": "xoziZG_modelChart",
|
|
76
|
-
"creditFooter": "xoziZG_creditFooter",
|
|
77
|
-
"section": "xoziZG_section",
|
|
78
|
-
"fieldLabel": "xoziZG_fieldLabel",
|
|
79
|
-
"manualSummary": "xoziZG_manualSummary",
|
|
80
|
-
"modelRow": "xoziZG_modelRow",
|
|
81
|
-
"accountHint": "xoziZG_accountHint",
|
|
82
|
-
"expiryRow": "xoziZG_expiryRow",
|
|
83
|
-
"error": "xoziZG_error",
|
|
84
68
|
"actions": "xoziZG_actions",
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"tabs": "xoziZG_tabs",
|
|
69
|
+
"accountCard": "xoziZG_accountCard",
|
|
70
|
+
"claimAllRow": "xoziZG_claimAllRow",
|
|
88
71
|
"link": "xoziZG_link",
|
|
89
|
-
"
|
|
90
|
-
"
|
|
72
|
+
"modelTokens": "xoziZG_modelTokens",
|
|
73
|
+
"sectionLabel": "xoziZG_sectionLabel",
|
|
74
|
+
"usageBar": "xoziZG_usageBar",
|
|
75
|
+
"section": "xoziZG_section",
|
|
76
|
+
"modelName": "xoziZG_modelName",
|
|
77
|
+
"meta": "xoziZG_meta",
|
|
78
|
+
"bar": "xoziZG_bar",
|
|
79
|
+
"header": "xoziZG_header",
|
|
80
|
+
"fieldLabel": "xoziZG_fieldLabel",
|
|
81
|
+
"choices": "xoziZG_choices",
|
|
82
|
+
"creditBlock": "xoziZG_creditBlock",
|
|
91
83
|
"creditRow": "xoziZG_creditRow",
|
|
92
84
|
"field": "xoziZG_field",
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"
|
|
85
|
+
"hint": "xoziZG_hint",
|
|
86
|
+
"count": "xoziZG_count",
|
|
87
|
+
"accountName": "xoziZG_accountName",
|
|
88
|
+
"tabs": "xoziZG_tabs",
|
|
89
|
+
"manualForm": "xoziZG_manualForm",
|
|
90
|
+
"creditFooter": "xoziZG_creditFooter",
|
|
91
|
+
"modelRow": "xoziZG_modelRow",
|
|
92
|
+
"manual": "xoziZG_manual",
|
|
93
|
+
"modelChart": "xoziZG_modelChart",
|
|
94
|
+
"modelRequests": "xoziZG_modelRequests",
|
|
95
|
+
"accountToolbar": "xoziZG_accountToolbar",
|
|
96
|
+
"statusLine": "xoziZG_statusLine",
|
|
97
|
+
"creditRows": "xoziZG_creditRows",
|
|
98
|
+
"expiryLabel": "xoziZG_expiryLabel",
|
|
99
|
+
"modelShare": "xoziZG_modelShare"
|
|
100
100
|
};
|
|
101
101
|
//#endregion
|
|
102
102
|
//#region src/client/CodeArtsPluginCard.tsx
|
|
@@ -115,7 +115,7 @@ function modelName(choice) {
|
|
|
115
115
|
/** 官方用量明细页。 */
|
|
116
116
|
const OFFICIAL_USAGE_URL = "https://codearts.huaweicloud.com/portal/settings/personal-usage";
|
|
117
117
|
/** token 数按人类习惯缩写:12345 -> 12.3k。 */
|
|
118
|
-
function formatTokens(value) {
|
|
118
|
+
function formatTokens$1(value) {
|
|
119
119
|
if (!Number.isFinite(value)) return "0";
|
|
120
120
|
if (value >= 1e6) return `${(value / 1e6).toFixed(1)}M`;
|
|
121
121
|
if (value >= 1e3) return `${(value / 1e3).toFixed(1)}k`;
|
|
@@ -375,8 +375,8 @@ function UsageBars({ rows, t }) {
|
|
|
375
375
|
const value = valueOf(row);
|
|
376
376
|
const share = sum > 0 ? value / sum * 100 : 0;
|
|
377
377
|
const detail = [t("usageRequests", { n: formatCount(row.totals.requests) }), t("usageTokens", {
|
|
378
|
-
prompt: formatTokens(row.totals.promptTokens),
|
|
379
|
-
completion: formatTokens(row.totals.completionTokens)
|
|
378
|
+
prompt: formatTokens$1(row.totals.promptTokens),
|
|
379
|
+
completion: formatTokens$1(row.totals.completionTokens)
|
|
380
380
|
})].join(" · ");
|
|
381
381
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
382
382
|
className: CodeArtsPluginCard_module_css_default.modelRow,
|
|
@@ -395,7 +395,7 @@ function UsageBars({ rows, t }) {
|
|
|
395
395
|
}),
|
|
396
396
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
397
397
|
className: CodeArtsPluginCard_module_css_default.modelTokens,
|
|
398
|
-
children: tokenMode ? formatTokens(value) : formatCount(value)
|
|
398
|
+
children: tokenMode ? formatTokens$1(value) : formatCount(value)
|
|
399
399
|
}),
|
|
400
400
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
401
401
|
className: CodeArtsPluginCard_module_css_default.modelShare,
|
|
@@ -465,8 +465,8 @@ function UsageSection({ usage, accounts, t }) {
|
|
|
465
465
|
t("usageRequests", { n: formatCount(total) }),
|
|
466
466
|
" · ",
|
|
467
467
|
t("usageTokens", {
|
|
468
|
-
prompt: formatTokens(usage.today.promptTokens),
|
|
469
|
-
completion: formatTokens(usage.today.completionTokens)
|
|
468
|
+
prompt: formatTokens$1(usage.today.promptTokens),
|
|
469
|
+
completion: formatTokens$1(usage.today.completionTokens)
|
|
470
470
|
})
|
|
471
471
|
]
|
|
472
472
|
})]
|
|
@@ -482,8 +482,8 @@ function UsageSection({ usage, accounts, t }) {
|
|
|
482
482
|
t("usageRequests", { n: formatCount(usage.last30.requests) }),
|
|
483
483
|
" · ",
|
|
484
484
|
t("usageTokens", {
|
|
485
|
-
prompt: formatTokens(usage.last30.promptTokens),
|
|
486
|
-
completion: formatTokens(usage.last30.completionTokens)
|
|
485
|
+
prompt: formatTokens$1(usage.last30.promptTokens),
|
|
486
|
+
completion: formatTokens$1(usage.last30.completionTokens)
|
|
487
487
|
})
|
|
488
488
|
]
|
|
489
489
|
})]
|
|
@@ -548,6 +548,10 @@ function CodeArtsPluginCard({ t }) {
|
|
|
548
548
|
const [modelError, setModelError] = (0, react.useState)(null);
|
|
549
549
|
const [refreshing, setRefreshing] = (0, react.useState)(false);
|
|
550
550
|
const [refreshMsg, setRefreshMsg] = (0, react.useState)(null);
|
|
551
|
+
/** 正在实测的模型 id;同一时间只测一个,避免把上游并发槽位占满。 */
|
|
552
|
+
const [testingId, setTestingId] = (0, react.useState)(null);
|
|
553
|
+
/** 逐模型的测试结果(通过/失败 + 原因)。 */
|
|
554
|
+
const [testResults, setTestResults] = (0, react.useState)({});
|
|
551
555
|
/** 正在领取的账号 id;批量领取时是 CLAIM_ALL。null 表示没有在飞。 */
|
|
552
556
|
const [claimingId, setClaimingId] = (0, react.useState)(null);
|
|
553
557
|
/** 逐账号的领取结果文案。 */
|
|
@@ -763,6 +767,51 @@ function CodeArtsPluginCard({ t }) {
|
|
|
763
767
|
}
|
|
764
768
|
}
|
|
765
769
|
/**
|
|
770
|
+
* 实测某个模型现在能不能调用。
|
|
771
|
+
*
|
|
772
|
+
* 上游的清单会列出调不动的模型(81003.401),刷新救不了;只有真发一次最小请求
|
|
773
|
+
* 才知道。测试成功会清掉后端记的「异常」标记,所以结束后重拉一次 selection。
|
|
774
|
+
*/
|
|
775
|
+
async function testModel(id) {
|
|
776
|
+
setTestingId(id);
|
|
777
|
+
setTestResults((current) => {
|
|
778
|
+
const next = { ...current };
|
|
779
|
+
delete next[id];
|
|
780
|
+
return next;
|
|
781
|
+
});
|
|
782
|
+
try {
|
|
783
|
+
const res = await fetch("/api/codearts/test-model", {
|
|
784
|
+
method: "POST",
|
|
785
|
+
headers: {
|
|
786
|
+
"Content-Type": "application/json",
|
|
787
|
+
Accept: "application/json"
|
|
788
|
+
},
|
|
789
|
+
body: JSON.stringify({ id })
|
|
790
|
+
});
|
|
791
|
+
const data = await res.json().catch(() => null);
|
|
792
|
+
if (!res.ok) throw new Error(data?.message ?? `HTTP ${res.status}`);
|
|
793
|
+
setTestResults((current) => ({
|
|
794
|
+
...current,
|
|
795
|
+
[id]: {
|
|
796
|
+
ok: data?.ok === true,
|
|
797
|
+
message: data?.message ?? "",
|
|
798
|
+
ms: data?.ms
|
|
799
|
+
}
|
|
800
|
+
}));
|
|
801
|
+
await refreshSelection();
|
|
802
|
+
} catch (err) {
|
|
803
|
+
setTestResults((current) => ({
|
|
804
|
+
...current,
|
|
805
|
+
[id]: {
|
|
806
|
+
ok: false,
|
|
807
|
+
message: err instanceof Error ? err.message : String(err)
|
|
808
|
+
}
|
|
809
|
+
}));
|
|
810
|
+
} finally {
|
|
811
|
+
setTestingId(null);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
/**
|
|
766
815
|
* 手动重拉一次模型目录。
|
|
767
816
|
*
|
|
768
817
|
* 存在的理由:限时福利名单会轮换(模型被移出、被转正),后台每小时才拉一次,
|
|
@@ -1143,30 +1192,55 @@ function CodeArtsPluginCard({ t }) {
|
|
|
1143
1192
|
}),
|
|
1144
1193
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1145
1194
|
className: CodeArtsPluginCard_module_css_default.choices,
|
|
1146
|
-
children: selection.choices.map((choice) =>
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1195
|
+
children: selection.choices.map((choice) => {
|
|
1196
|
+
const result = testResults[choice.id];
|
|
1197
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1198
|
+
className: CodeArtsPluginCard_module_css_default.choiceRow,
|
|
1199
|
+
children: [
|
|
1200
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Checkbox, {
|
|
1201
|
+
className: CodeArtsPluginCard_module_css_default.check,
|
|
1202
|
+
checked: draft.includes(choice.id),
|
|
1203
|
+
disabled: !selection.writable || savingModels,
|
|
1204
|
+
onChange: (on) => setModel(choice.id, on),
|
|
1205
|
+
label: modelName(choice)
|
|
1206
|
+
}),
|
|
1207
|
+
choice.benefit === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
|
|
1208
|
+
tone: choice.blocked === true ? "warning" : "success",
|
|
1209
|
+
children: choice.blocked === true ? t("benefitBlocked") : t("benefit")
|
|
1210
|
+
}),
|
|
1211
|
+
choice.error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1212
|
+
title: choice.error,
|
|
1213
|
+
style: { cursor: "help" },
|
|
1214
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
|
|
1215
|
+
tone: "warning",
|
|
1216
|
+
children: t("modelError")
|
|
1217
|
+
})
|
|
1218
|
+
}),
|
|
1219
|
+
choice.ratio !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
|
|
1220
|
+
tone: "quiet",
|
|
1221
|
+
children: choice.ratio
|
|
1222
|
+
}),
|
|
1223
|
+
choice.supportsImages === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
|
|
1224
|
+
tone: "quiet",
|
|
1225
|
+
children: t("modelImages")
|
|
1226
|
+
}),
|
|
1227
|
+
draft.includes(choice.id) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1228
|
+
variant: "outline",
|
|
1229
|
+
size: "sm",
|
|
1230
|
+
disabled: testingId !== null,
|
|
1231
|
+
onClick: () => void testModel(choice.id),
|
|
1232
|
+
children: testingId === choice.id ? t("testingModel") : t("testModel")
|
|
1233
|
+
}),
|
|
1234
|
+
result !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1235
|
+
title: result.ms === void 0 ? result.message : `${result.message}(${result.ms} ms)`,
|
|
1236
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
|
|
1237
|
+
tone: result.ok ? "success" : "warning",
|
|
1238
|
+
children: result.ok ? t("testOk") : t("testFailed")
|
|
1239
|
+
})
|
|
1240
|
+
})
|
|
1241
|
+
]
|
|
1242
|
+
}, choice.id);
|
|
1243
|
+
})
|
|
1170
1244
|
}),
|
|
1171
1245
|
selection.writable && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1172
1246
|
className: CodeArtsPluginCard_module_css_default.actions,
|
|
@@ -1443,6 +1517,13 @@ function isCodeArts(selection) {
|
|
|
1443
1517
|
function formatNumber(value) {
|
|
1444
1518
|
return new Intl.NumberFormat().format(Math.round(value));
|
|
1445
1519
|
}
|
|
1520
|
+
/** 与设置卡片「用量」区块同一口径:12345 -> 12.3k。 */
|
|
1521
|
+
function formatTokens(value) {
|
|
1522
|
+
if (!Number.isFinite(value)) return "0";
|
|
1523
|
+
if (value >= 1e6) return `${(value / 1e6).toFixed(1)}M`;
|
|
1524
|
+
if (value >= 1e3) return `${(value / 1e3).toFixed(1)}k`;
|
|
1525
|
+
return String(Math.round(value));
|
|
1526
|
+
}
|
|
1446
1527
|
function formatClock(ts) {
|
|
1447
1528
|
if (ts === void 0 || !Number.isFinite(ts)) return "";
|
|
1448
1529
|
try {
|
|
@@ -1473,11 +1554,13 @@ function rowsOf(data) {
|
|
|
1473
1554
|
creditsError: data.creditsError
|
|
1474
1555
|
} : void 0);
|
|
1475
1556
|
const snapshot = entry?.credits;
|
|
1557
|
+
const usage = data.usage?.byAccountToday?.[account.id];
|
|
1476
1558
|
return {
|
|
1477
1559
|
id: account.id,
|
|
1478
1560
|
name: accountName(account),
|
|
1479
1561
|
remain: snapshot?.credits.total.remain ?? null,
|
|
1480
1562
|
expiring: snapshot?.credits.total.expiring ?? 0,
|
|
1563
|
+
...usage === void 0 ? {} : { usage },
|
|
1481
1564
|
...snapshot?.credits.fetchedAt === void 0 ? {} : { fetchedAt: snapshot.credits.fetchedAt },
|
|
1482
1565
|
...entry?.creditsError === void 0 ? {} : { error: entry.creditsError }
|
|
1483
1566
|
};
|
|
@@ -1760,7 +1843,7 @@ function CodeArtsCreditDock({ useProjection, t }) {
|
|
|
1760
1843
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1761
1844
|
style: {
|
|
1762
1845
|
display: "grid",
|
|
1763
|
-
gridTemplateColumns: "minmax(0, 1fr) auto",
|
|
1846
|
+
gridTemplateColumns: "minmax(0, 1fr) auto auto",
|
|
1764
1847
|
gap: "4px 12px",
|
|
1765
1848
|
alignItems: "center",
|
|
1766
1849
|
borderTop: "0.5px solid var(--dsw-alias-border-l2, rgba(127, 127, 127, 0.22))",
|
|
@@ -1769,6 +1852,10 @@ function CodeArtsCreditDock({ useProjection, t }) {
|
|
|
1769
1852
|
},
|
|
1770
1853
|
children: [
|
|
1771
1854
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("creditsDockColAccount") }),
|
|
1855
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1856
|
+
style: { justifySelf: "end" },
|
|
1857
|
+
children: t("creditsDockColTokens")
|
|
1858
|
+
}),
|
|
1772
1859
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1773
1860
|
style: { justifySelf: "end" },
|
|
1774
1861
|
children: t("creditsDockColBalance")
|
|
@@ -1777,33 +1864,50 @@ function CodeArtsCreditDock({ useProjection, t }) {
|
|
|
1777
1864
|
style: { gridColumn: "1 / -1" },
|
|
1778
1865
|
children: t("creditsDockEmpty")
|
|
1779
1866
|
}),
|
|
1780
|
-
rows.map((row) =>
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1867
|
+
rows.map((row) => {
|
|
1868
|
+
const detail = row.usage === void 0 ? "" : [t("usageTokens", {
|
|
1869
|
+
prompt: formatTokens(row.usage.promptTokens),
|
|
1870
|
+
completion: formatTokens(row.usage.completionTokens)
|
|
1871
|
+
}), t("usageRequestCount", { n: formatNumber(row.usage.requests) })].join(" · ");
|
|
1872
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1873
|
+
style: { display: "contents" },
|
|
1874
|
+
children: [
|
|
1875
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1876
|
+
style: {
|
|
1877
|
+
display: "flex",
|
|
1878
|
+
alignItems: "center",
|
|
1879
|
+
gap: 6,
|
|
1880
|
+
minWidth: 0
|
|
1881
|
+
},
|
|
1882
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: row.remain === null ? "warning" : "done" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1883
|
+
style: {
|
|
1884
|
+
overflow: "hidden",
|
|
1885
|
+
textOverflow: "ellipsis",
|
|
1886
|
+
whiteSpace: "nowrap",
|
|
1887
|
+
color: "var(--dsw-alias-label-primary)"
|
|
1888
|
+
},
|
|
1889
|
+
title: row.error === void 0 ? row.name : row.error,
|
|
1890
|
+
children: row.name
|
|
1891
|
+
})]
|
|
1892
|
+
}),
|
|
1893
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1894
|
+
style: {
|
|
1895
|
+
justifySelf: "end",
|
|
1896
|
+
fontVariantNumeric: "tabular-nums"
|
|
1897
|
+
},
|
|
1898
|
+
title: row.usage === void 0 ? t("creditsDockNoTokens") : detail,
|
|
1899
|
+
children: row.usage === void 0 ? "—" : formatTokens(row.usage.totalTokens)
|
|
1900
|
+
}),
|
|
1901
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1902
|
+
style: {
|
|
1903
|
+
justifySelf: "end",
|
|
1904
|
+
fontVariantNumeric: "tabular-nums"
|
|
1905
|
+
},
|
|
1906
|
+
children: row.remain === null ? "—" : formatNumber(row.remain)
|
|
1907
|
+
})
|
|
1908
|
+
]
|
|
1909
|
+
}, row.id);
|
|
1910
|
+
})
|
|
1807
1911
|
]
|
|
1808
1912
|
}),
|
|
1809
1913
|
rows.filter((row) => row.expiring > 0).map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
@@ -1868,6 +1972,11 @@ const zh = {
|
|
|
1868
1972
|
benefitBlocked: "福利今日不可用",
|
|
1869
1973
|
benefitBlockedHint: "{n} 个福利模型今天被上游判定没有权益(活动领完或渠道未开),发出去会直接报 benefit not found。",
|
|
1870
1974
|
modelImages: "识图",
|
|
1975
|
+
modelError: "异常",
|
|
1976
|
+
testModel: "测试",
|
|
1977
|
+
testingModel: "测试中…",
|
|
1978
|
+
testOk: "通过",
|
|
1979
|
+
testFailed: "失败",
|
|
1871
1980
|
refreshModels: "刷新模型列表",
|
|
1872
1981
|
refreshing: "刷新中…",
|
|
1873
1982
|
refreshed: "已刷新:{n} 个模型,其中 {benefit} 个走福利路由",
|
|
@@ -1918,6 +2027,8 @@ const zh = {
|
|
|
1918
2027
|
creditsDockRefreshing: "刷新中…",
|
|
1919
2028
|
creditsDockColAccount: "账号",
|
|
1920
2029
|
creditsDockColBalance: "剩余积分",
|
|
2030
|
+
creditsDockColTokens: "今日 Token",
|
|
2031
|
+
creditsDockNoTokens: "今天还没有经插件发出的请求",
|
|
1921
2032
|
creditsDockEmpty: "暂时没有积分数据",
|
|
1922
2033
|
creditsDockExpiring: "{account}:{expiring} 积分将在本周期结束时作废",
|
|
1923
2034
|
creditsDockUpdated: "最近刷新 {time}",
|
|
@@ -1984,6 +2095,11 @@ const en = {
|
|
|
1984
2095
|
benefitBlocked: "Benefit unavailable today",
|
|
1985
2096
|
benefitBlockedHint: "{n} benefit model(s) were told they have no entitlement today (campaign exhausted or channel not opened); sending to them fails with benefit not found.",
|
|
1986
2097
|
modelImages: "Images",
|
|
2098
|
+
modelError: "Unavailable",
|
|
2099
|
+
testModel: "Test",
|
|
2100
|
+
testingModel: "Testing…",
|
|
2101
|
+
testOk: "Passed",
|
|
2102
|
+
testFailed: "Failed",
|
|
1987
2103
|
refreshModels: "Refresh models",
|
|
1988
2104
|
refreshing: "Refreshing…",
|
|
1989
2105
|
refreshed: "Refreshed: {n} models, {benefit} on the benefit route",
|
|
@@ -2034,6 +2150,8 @@ const en = {
|
|
|
2034
2150
|
creditsDockRefreshing: "Refreshing…",
|
|
2035
2151
|
creditsDockColAccount: "Account",
|
|
2036
2152
|
creditsDockColBalance: "Credits left",
|
|
2153
|
+
creditsDockColTokens: "Tokens today",
|
|
2154
|
+
creditsDockNoTokens: "No requests through the plugin today yet",
|
|
2037
2155
|
creditsDockEmpty: "No credit data yet",
|
|
2038
2156
|
creditsDockExpiring: "{account}: {expiring} credits expire when this cycle ends",
|
|
2039
2157
|
creditsDockUpdated: "Last updated {time}",
|
package/lib/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as upstreamErrorMessage, B as modelUnavailableReason, C as isWelfareClaimedStatus, D as prepareChatBody, E as pickDailyWelfareCampaign, F as filterEnabledModels, G as codeartsAuthPath, H as CodeArtsCredentialStore, I as forgetModelUnavailable, K as startLogin, L as isBenefitBlocked, M as FALLBACK_CODEARTS_MODELS, N as clearBenefitBlocked, O as rateLimitFrame, P as creditRatioLabel, R as isBenefitModel, S as isTpmLimit, T as modelUnavailableReasonText, U as MANUAL_ACCOUNT_ID, V as CodeArtsAccountStore, W as codeartsAccountsPath, _ as isIamTokenError, a as SNAP_HOST, b as isParamInvalidFrame, c as claimDailyWelfare, d as fetchCallerIdentity, f as fetchModels, g as isConcurrencyCap, h as firstFrameError, i as refreshCatalog, j as CodeArtsCatalog, k as signedGet, l as clearQueueStatus, m as fetchWelfareCampaigns, n as codeartsUsagePath, o as canonicalModel, p as fetchQueueStatus, r as discoverModels, s as chatStream, t as CodeArtsUsageTracker, u as degradeTokenCeiling, v as isModelNotAccessible, w as maxTokensCeilingFor, x as isQueueableRate, y as isNotMultimodal, z as markModelUnavailable } from "./usage-CzJjkqOp.mjs";
|
|
2
2
|
import { i as lazyApi, r as createProvider } from "./models-CgKCibpk.mjs";
|
|
3
3
|
import z from "@deepseek-ai/schemastery";
|
|
4
4
|
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
@@ -1115,6 +1115,7 @@ function createCodeArtsShim(options) {
|
|
|
1115
1115
|
reader.releaseLock();
|
|
1116
1116
|
await result.stream.cancel().catch(() => {});
|
|
1117
1117
|
logger?.warn(`dsh-codearts: ${prepared.model} 首帧报上游错误(${detail.slice(0, 160)})`);
|
|
1118
|
+
if (isModelNotAccessible(detail)) markModelUnavailable(prepared.model, modelUnavailableReasonText(detail));
|
|
1118
1119
|
const kind = isIamTokenError(detail) ? "iam_stale" : isModelNotAccessible(detail) ? "not_found" : "client";
|
|
1119
1120
|
return {
|
|
1120
1121
|
prepared,
|
|
@@ -1437,6 +1438,13 @@ const CODEARTS_ACCOUNTS_PATH = "/api/codearts/accounts";
|
|
|
1437
1438
|
const CODEARTS_CLAIM_PATH = "/api/codearts/claim";
|
|
1438
1439
|
/** POST /api/codearts/refresh-models — 立刻重拉一次模型目录,并清掉「福利今日不可用」标记。 */
|
|
1439
1440
|
const CODEARTS_REFRESH_MODELS_PATH = "/api/codearts/refresh-models";
|
|
1441
|
+
/**
|
|
1442
|
+
* POST /api/codearts/test-model — 用最小请求实测某个模型能不能调通。
|
|
1443
|
+
*
|
|
1444
|
+
* 存在理由:上游的模型清单会列出调不动的模型(`InferHub.ModelArts.81003.401`),
|
|
1445
|
+
* 刷新救不了;只有真发一次请求才知道。成功会清掉该模型的「异常」标记。
|
|
1446
|
+
*/
|
|
1447
|
+
const CODEARTS_TEST_MODEL_PATH = "/api/codearts/test-model";
|
|
1440
1448
|
/** GET /api/codearts/queue — 上游排队位置(只在等开流期间有值,底部积分条旁边展示)。 */
|
|
1441
1449
|
const CODEARTS_QUEUE_PATH = "/api/codearts/queue";
|
|
1442
1450
|
/**
|
|
@@ -1463,6 +1471,7 @@ function selectionOf(models, enabled, writable) {
|
|
|
1463
1471
|
blocked: m.blocked,
|
|
1464
1472
|
ratio: m.ratio,
|
|
1465
1473
|
supportsImages: m.supportsImages,
|
|
1474
|
+
...m.error === void 0 ? {} : { error: m.error },
|
|
1466
1475
|
enabled: restricted ? allowed.has(m.id) : true
|
|
1467
1476
|
})),
|
|
1468
1477
|
restricted,
|
|
@@ -1474,13 +1483,15 @@ function choicesOf(deps) {
|
|
|
1474
1483
|
return deps.models().map((m) => {
|
|
1475
1484
|
const benefit = isBenefitModel(m.id);
|
|
1476
1485
|
const ratio = creditRatioLabel(m.ratio, benefit);
|
|
1486
|
+
const error = modelUnavailableReason(m.id);
|
|
1477
1487
|
return {
|
|
1478
1488
|
id: m.id,
|
|
1479
1489
|
name: m.name,
|
|
1480
1490
|
benefit,
|
|
1481
1491
|
blocked: isBenefitBlocked(m.id),
|
|
1482
1492
|
...ratio === void 0 ? {} : { ratio },
|
|
1483
|
-
...m.supportsImages === true ? { supportsImages: true } : {}
|
|
1493
|
+
...m.supportsImages === true ? { supportsImages: true } : {},
|
|
1494
|
+
...error === void 0 ? {} : { error }
|
|
1484
1495
|
};
|
|
1485
1496
|
});
|
|
1486
1497
|
}
|
|
@@ -1968,6 +1979,131 @@ function refreshModelsHandler(deps) {
|
|
|
1968
1979
|
}
|
|
1969
1980
|
};
|
|
1970
1981
|
}
|
|
1982
|
+
/**
|
|
1983
|
+
* 逐账号发一次最小聊天,验证模型**真的能调用**(清单里有 ≠ 能调)。
|
|
1984
|
+
*
|
|
1985
|
+
* 只发一句 ping、max_tokens 16:目的是让上游过一遍权限与路由检查,不是拿内容。
|
|
1986
|
+
* 必须逐账号试 —— 池里的正常请求也是这么轮的;只测第一个号会把「这个号没权限」
|
|
1987
|
+
* 误报成「模型不可用」。
|
|
1988
|
+
*/
|
|
1989
|
+
async function probeModel(deps, id, signal) {
|
|
1990
|
+
const ids = await deps.store.ids();
|
|
1991
|
+
if (ids.length === 0) return {
|
|
1992
|
+
ok: false,
|
|
1993
|
+
message: "没有已登录的账号,请先在设置卡片登录。"
|
|
1994
|
+
};
|
|
1995
|
+
const raw = JSON.stringify({
|
|
1996
|
+
model: id,
|
|
1997
|
+
stream: true,
|
|
1998
|
+
max_tokens: 16,
|
|
1999
|
+
messages: [{
|
|
2000
|
+
role: "user",
|
|
2001
|
+
content: "ping"
|
|
2002
|
+
}]
|
|
2003
|
+
});
|
|
2004
|
+
let last = "没有可用的账号";
|
|
2005
|
+
for (const accountId of ids.slice(0, 3)) {
|
|
2006
|
+
if (signal.aborted) break;
|
|
2007
|
+
const credential = await deps.store.resolve(accountId);
|
|
2008
|
+
if (credential === void 0) {
|
|
2009
|
+
last = "凭据不可用,请重新登录";
|
|
2010
|
+
continue;
|
|
2011
|
+
}
|
|
2012
|
+
const result = await chatStream(credential, prepareChatBody(raw), signal);
|
|
2013
|
+
if (!result.ok) {
|
|
2014
|
+
last = upstreamErrorMessage(result.message, result.status);
|
|
2015
|
+
if (result.kind === "iam_stale") await deps.store.forceRefresh(accountId, credential.token).catch(() => void 0);
|
|
2016
|
+
continue;
|
|
2017
|
+
}
|
|
2018
|
+
const reader = result.stream.getReader();
|
|
2019
|
+
try {
|
|
2020
|
+
for (let frame = 0; frame < 6; frame += 1) {
|
|
2021
|
+
const next = await reader.read();
|
|
2022
|
+
if (next.done) return {
|
|
2023
|
+
ok: true,
|
|
2024
|
+
message: "上游已响应",
|
|
2025
|
+
accountId
|
|
2026
|
+
};
|
|
2027
|
+
const text = new TextDecoder().decode(next.value);
|
|
2028
|
+
const error = firstFrameError(text);
|
|
2029
|
+
if (error !== void 0) {
|
|
2030
|
+
const detail = `${error.code}: ${error.message}`.replace(/^: /, "");
|
|
2031
|
+
if (isModelNotAccessible(detail)) markModelUnavailable(id, modelUnavailableReasonText(detail));
|
|
2032
|
+
return {
|
|
2033
|
+
ok: false,
|
|
2034
|
+
message: upstreamErrorMessage(detail),
|
|
2035
|
+
accountId
|
|
2036
|
+
};
|
|
2037
|
+
}
|
|
2038
|
+
if (text.includes("\"choices\"")) return {
|
|
2039
|
+
ok: true,
|
|
2040
|
+
message: "上游正常响应",
|
|
2041
|
+
accountId
|
|
2042
|
+
};
|
|
2043
|
+
}
|
|
2044
|
+
return {
|
|
2045
|
+
ok: true,
|
|
2046
|
+
message: "上游已开流",
|
|
2047
|
+
accountId
|
|
2048
|
+
};
|
|
2049
|
+
} finally {
|
|
2050
|
+
await reader.cancel().catch(() => void 0);
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
return {
|
|
2054
|
+
ok: false,
|
|
2055
|
+
message: last
|
|
2056
|
+
};
|
|
2057
|
+
}
|
|
2058
|
+
/**
|
|
2059
|
+
* POST /api/codearts/test-model — 实测一个模型现在能不能调用。
|
|
2060
|
+
*
|
|
2061
|
+
* 成功会清掉它的「异常」标记(测试就是重新验证一次);`81003.401` 会重新记上。
|
|
2062
|
+
* 失败也可能只是撞了并发上限/限流,所以除模型级错误外不动标记。
|
|
2063
|
+
*/
|
|
2064
|
+
function testModelHandler(deps) {
|
|
2065
|
+
return async (req, res) => {
|
|
2066
|
+
if (req.method !== "POST") {
|
|
2067
|
+
json(res, 405, { error: "method not allowed" });
|
|
2068
|
+
return;
|
|
2069
|
+
}
|
|
2070
|
+
if (!loopbackRequest(req)) {
|
|
2071
|
+
json(res, 403, { error: "request-not-trusted" });
|
|
2072
|
+
return;
|
|
2073
|
+
}
|
|
2074
|
+
let id = "";
|
|
2075
|
+
try {
|
|
2076
|
+
const body = JSON.parse(await readBody(req));
|
|
2077
|
+
if (typeof body.id === "string") id = body.id.trim();
|
|
2078
|
+
} catch {
|
|
2079
|
+
json(res, 400, { error: "expected {\"id\": string}" });
|
|
2080
|
+
return;
|
|
2081
|
+
}
|
|
2082
|
+
if (id === "") {
|
|
2083
|
+
json(res, 400, { error: "expected {\"id\": string}" });
|
|
2084
|
+
return;
|
|
2085
|
+
}
|
|
2086
|
+
if (!deps.models().some((model) => model.id === id)) {
|
|
2087
|
+
json(res, 404, { error: `unknown model: ${id}` });
|
|
2088
|
+
return;
|
|
2089
|
+
}
|
|
2090
|
+
const started = Date.now();
|
|
2091
|
+
try {
|
|
2092
|
+
const result = await probeModel(deps, id, AbortSignal.timeout(45e3));
|
|
2093
|
+
if (result.ok) forgetModelUnavailable(id);
|
|
2094
|
+
json(res, 200, {
|
|
2095
|
+
...result,
|
|
2096
|
+
ms: Date.now() - started
|
|
2097
|
+
});
|
|
2098
|
+
} catch (error) {
|
|
2099
|
+
json(res, 200, {
|
|
2100
|
+
ok: false,
|
|
2101
|
+
message: safeMessage(error),
|
|
2102
|
+
ms: Date.now() - started
|
|
2103
|
+
});
|
|
2104
|
+
}
|
|
2105
|
+
};
|
|
2106
|
+
}
|
|
1971
2107
|
/** GET /api/codearts/queue — 排队位置快照(无跟踪器/无排队时给空数组)。 */
|
|
1972
2108
|
function queueHandler(deps) {
|
|
1973
2109
|
return async (req, res) => {
|
|
@@ -2047,6 +2183,11 @@ function registerCodeArtsStatusRoute(ctx, deps) {
|
|
|
2047
2183
|
path: CODEARTS_REFRESH_MODELS_PATH,
|
|
2048
2184
|
handler: refreshModelsHandler(deps)
|
|
2049
2185
|
});
|
|
2186
|
+
const disposeTestModel = ctx.webServer.register({
|
|
2187
|
+
kind: "exact",
|
|
2188
|
+
path: CODEARTS_TEST_MODEL_PATH,
|
|
2189
|
+
handler: testModelHandler(deps)
|
|
2190
|
+
});
|
|
2050
2191
|
const disposeQueue = ctx.webServer.register({
|
|
2051
2192
|
kind: "exact",
|
|
2052
2193
|
path: CODEARTS_QUEUE_PATH,
|
|
@@ -2072,6 +2213,7 @@ function registerCodeArtsStatusRoute(ctx, deps) {
|
|
|
2072
2213
|
disposeAccounts();
|
|
2073
2214
|
disposeClaim();
|
|
2074
2215
|
disposeRefresh();
|
|
2216
|
+
disposeTestModel();
|
|
2075
2217
|
disposeQueue();
|
|
2076
2218
|
disposeDock();
|
|
2077
2219
|
disposeDebug();
|
|
@@ -1068,6 +1068,37 @@ function clearBenefitBlocked() {
|
|
|
1068
1068
|
benefitBlocked.clear();
|
|
1069
1069
|
}
|
|
1070
1070
|
/**
|
|
1071
|
+
* 今天被上游明确拒绝「模型不存在 / 本账号无权限」的模型(小写 id -> 原因)。
|
|
1072
|
+
*
|
|
1073
|
+
* 判据只有聊天回的 `InferHub.ModelArts.81003.401`。上游的模型发现**照样列出它**
|
|
1074
|
+
* (2026-11-02 实测 `deepseek-v4.1-flash` 两路都在清单里),所以刷新模型列表救不了 ——
|
|
1075
|
+
* 只能等上游修好,或第二天再看。这也是「刷新清单 ≠ 验证可调用」的落点。
|
|
1076
|
+
*
|
|
1077
|
+
* 与福利缺失标记同口径:**只标记,不替用户取消勾选**。多账号下这个错误只有在
|
|
1078
|
+
* 所有号都试过之后才会浮上来,所以按模型记全局(不按账号)。
|
|
1079
|
+
*/
|
|
1080
|
+
const unavailableModels = /* @__PURE__ */ new Map();
|
|
1081
|
+
/** 记一次「上游判定这个模型不可用」。 */
|
|
1082
|
+
function markModelUnavailable(id, reason) {
|
|
1083
|
+
const key = id.trim().toLowerCase();
|
|
1084
|
+
if (key !== "") unavailableModels.set(key, {
|
|
1085
|
+
day: localDayKey(),
|
|
1086
|
+
reason
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1089
|
+
/** 该模型今天是否已被上游判定不可用;是则返回原因(卡片悬浮显示)。 */
|
|
1090
|
+
function modelUnavailableReason(id) {
|
|
1091
|
+
const key = id.trim().toLowerCase();
|
|
1092
|
+
const entry = unavailableModels.get(key);
|
|
1093
|
+
if (entry === void 0) return void 0;
|
|
1094
|
+
if (entry.day === localDayKey()) return entry.reason;
|
|
1095
|
+
unavailableModels.delete(key);
|
|
1096
|
+
}
|
|
1097
|
+
/** 单独清掉一个模型的不可用标记(手动测试成功后调)。 */
|
|
1098
|
+
function forgetModelUnavailable(id) {
|
|
1099
|
+
unavailableModels.delete(id.trim().toLowerCase());
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1071
1102
|
* 合并多路来源的模型清单(内置 / 限时福利 / agent-center)。
|
|
1072
1103
|
*
|
|
1073
1104
|
* 规则对齐 codearts2api 的 `MergeModels`:
|
|
@@ -1276,6 +1307,7 @@ var upstream_exports = /* @__PURE__ */ __exportAll({
|
|
|
1276
1307
|
isTpmLimit: () => isTpmLimit,
|
|
1277
1308
|
isWelfareClaimedStatus: () => isWelfareClaimedStatus,
|
|
1278
1309
|
maxTokensCeilingFor: () => maxTokensCeilingFor,
|
|
1310
|
+
modelUnavailableReasonText: () => modelUnavailableReasonText,
|
|
1279
1311
|
pickDailyWelfareCampaign: () => pickDailyWelfareCampaign,
|
|
1280
1312
|
prepareChatBody: () => prepareChatBody,
|
|
1281
1313
|
rateLimitFrame: () => rateLimitFrame,
|
|
@@ -1671,6 +1703,12 @@ function isModelNotAccessible(message) {
|
|
|
1671
1703
|
function isNotMultimodal(message) {
|
|
1672
1704
|
return message.includes("InferHub.001001020.406") || message.toLowerCase().includes("the request model is not multimodal");
|
|
1673
1705
|
}
|
|
1706
|
+
/** 记进目录的原因文案(卡片「异常」Tag 的悬浮说明)。 */
|
|
1707
|
+
function modelUnavailableReasonText(detail) {
|
|
1708
|
+
const trimmed = detail.trim();
|
|
1709
|
+
const prefix = "上游判定该模型当前不可用(模型不存在或当前账号没有权限,换号也无效)";
|
|
1710
|
+
return trimmed === "" ? prefix : `${prefix}:${trimmed}`;
|
|
1711
|
+
}
|
|
1674
1712
|
/**
|
|
1675
1713
|
* 从**首帧**(已转成 OpenAI 形状)里取出上游错误码与文本;没有错误返回 undefined。
|
|
1676
1714
|
*
|
|
@@ -1815,6 +1853,7 @@ async function chatStream(credential, prepared, signal) {
|
|
|
1815
1853
|
if (!resp.ok) {
|
|
1816
1854
|
const text = await resp.text().catch(() => "");
|
|
1817
1855
|
if (isBenefitMissing("", text)) markBenefitBlocked(prepared.model);
|
|
1856
|
+
if (isModelNotAccessible(text)) markModelUnavailable(prepared.model, modelUnavailableReasonText(text.slice(0, 200)));
|
|
1818
1857
|
return {
|
|
1819
1858
|
ok: false,
|
|
1820
1859
|
kind: classify(resp.status, text),
|
|
@@ -1874,6 +1913,8 @@ async function chatStream(credential, prepared, signal) {
|
|
|
1874
1913
|
}
|
|
1875
1914
|
if (ev.error_code && ev.error_code !== "0" && ev.error_code !== 0) {
|
|
1876
1915
|
if (isBenefitMissing(String(ev.error_code), String(ev.error_msg ?? ""))) markBenefitBlocked(model);
|
|
1916
|
+
const errorDetail = `${String(ev.error_code)}: ${String(ev.error_msg ?? "upstream error")}`;
|
|
1917
|
+
if (isModelNotAccessible(errorDetail)) markModelUnavailable(model, modelUnavailableReasonText(errorDetail));
|
|
1877
1918
|
controller.enqueue(openAIData({
|
|
1878
1919
|
choices: [{
|
|
1879
1920
|
delta: { content: "" },
|
|
@@ -2864,4 +2905,4 @@ function sumOf(store) {
|
|
|
2864
2905
|
return out;
|
|
2865
2906
|
}
|
|
2866
2907
|
//#endregion
|
|
2867
|
-
export {
|
|
2908
|
+
export { upstreamErrorMessage as A, modelUnavailableReason as B, isWelfareClaimedStatus as C, prepareChatBody as D, pickDailyWelfareCampaign as E, filterEnabledModels as F, codeartsAuthPath as G, CodeArtsCredentialStore as H, forgetModelUnavailable as I, startLogin as K, isBenefitBlocked as L, FALLBACK_CODEARTS_MODELS as M, clearBenefitBlocked as N, rateLimitFrame as O, creditRatioLabel as P, isBenefitModel as R, isTpmLimit as S, modelUnavailableReasonText as T, MANUAL_ACCOUNT_ID as U, CodeArtsAccountStore as V, codeartsAccountsPath as W, isIamTokenError as _, SNAP_HOST as a, isParamInvalidFrame as b, claimDailyWelfare as c, fetchCallerIdentity as d, fetchModels as f, isConcurrencyCap as g, firstFrameError as h, refreshCatalog as i, CodeArtsCatalog as j, signedGet as k, clearQueueStatus as l, fetchWelfareCampaigns as m, codeartsUsagePath as n, canonicalModel as o, fetchQueueStatus as p, discoverModels as r, chatStream as s, CodeArtsUsageTracker as t, degradeTokenCeiling as u, isModelNotAccessible as v, maxTokensCeilingFor as w, isQueueableRate as x, isNotMultimodal as y, markModelUnavailable as z };
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "dsh-codearts",
|
|
3
3
|
"displayName": "DSH CodeArts Connect",
|
|
4
4
|
"description": "把华为云 CodeArts 接入 DeepSeek Harness —— 内置 OAuth2 登录(PKCE + DPoP),登录后即可在 DSH 对话窗口使用 CodeArts 的模型。",
|
|
5
|
-
"version": "1.2.
|
|
5
|
+
"version": "1.2.3",
|
|
6
6
|
"packageManager": "pnpm@11.24.0",
|
|
7
7
|
"author": "elegant01",
|
|
8
8
|
"keywords": [
|