dsh-cmtoken-oauth 1.6.0 → 1.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.
- package/lib/client.js +6 -6
- package/lib/index.js +35 -21
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -137,12 +137,12 @@ window.__ModuleLoader__.load({
|
|
|
137
137
|
if (phase === "loading") {
|
|
138
138
|
authCard = react.createElement("div", { className: "co-card" },
|
|
139
139
|
react.createElement("div", { className: "co-card-title" }, "认证"),
|
|
140
|
-
react.createElement("p", { className: "co-hint" }, "
|
|
140
|
+
react.createElement("p", { className: "co-hint" }, "中国移动算力豆一键认证:扫码即自动创建专属 DSH API key,长期有效,无需刷新令牌。"),
|
|
141
141
|
react.createElement("div", { className: "co-hint" }, "加载中…"));
|
|
142
142
|
} else if (phase === "qr" && flow) {
|
|
143
143
|
authCard = react.createElement("div", { className: "co-card" },
|
|
144
144
|
react.createElement("div", { className: "co-card-title" }, "认证"),
|
|
145
|
-
react.createElement("p", { className: "co-hint" }, "
|
|
145
|
+
react.createElement("p", { className: "co-hint" }, "中国移动算力豆一键认证:扫码即自动创建专属 DSH API key,长期有效,无需刷新令牌。"),
|
|
146
146
|
react.createElement("div", { className: "co-qr" },
|
|
147
147
|
react.createElement("div", { dangerouslySetInnerHTML: { __html: flow.qr_svg } }),
|
|
148
148
|
react.createElement("div", { className: "co-hint" }, "扫码登录中国移动账号,一次扫码完成认证与用量关联,约 " + Math.round(flow.expires_in || 180) + " 秒内有效")
|
|
@@ -153,7 +153,7 @@ window.__ModuleLoader__.load({
|
|
|
153
153
|
} else if (phase === "done") {
|
|
154
154
|
authCard = react.createElement("div", { className: "co-card" },
|
|
155
155
|
react.createElement("div", { className: "co-card-title" }, "认证"),
|
|
156
|
-
react.createElement("p", { className: "co-hint" }, "
|
|
156
|
+
react.createElement("p", { className: "co-hint" }, "中国移动算力豆一键认证:扫码即自动创建专属 DSH API key,长期有效,无需刷新令牌。"),
|
|
157
157
|
react.createElement("div", { className: "co-auth-ok" }, "✅ 已认证" + (models.length ? ",已接入 " + models.length + " 个模型" : "")),
|
|
158
158
|
react.createElement("div", { className: "co-row" },
|
|
159
159
|
react.createElement(Button, { variant: "outline", size: "md", onClick: doRefresh }, "刷新模型与用量"),
|
|
@@ -161,14 +161,14 @@ window.__ModuleLoader__.load({
|
|
|
161
161
|
} else if (phase === "error") {
|
|
162
162
|
authCard = react.createElement("div", { className: "co-card" },
|
|
163
163
|
react.createElement("div", { className: "co-card-title" }, "认证"),
|
|
164
|
-
react.createElement("p", { className: "co-hint" }, "
|
|
164
|
+
react.createElement("p", { className: "co-hint" }, "中国移动算力豆一键认证:扫码即自动创建专属 DSH API key,长期有效,无需刷新令牌。"),
|
|
165
165
|
react.createElement("div", { className: "co-err" }, "❌ " + (error || "认证失败")),
|
|
166
166
|
react.createElement("div", { className: "co-row" },
|
|
167
167
|
react.createElement(Button, { variant: "primary", size: "md", onClick: () => { setPhase("ok"); setError(null); } }, "返回重试")));
|
|
168
168
|
} else if (authenticated) {
|
|
169
169
|
authCard = react.createElement("div", { className: "co-card" },
|
|
170
170
|
react.createElement("div", { className: "co-card-title" }, "认证"),
|
|
171
|
-
react.createElement("p", { className: "co-hint" }, "
|
|
171
|
+
react.createElement("p", { className: "co-hint" }, "中国移动算力豆一键认证:扫码即自动创建专属 DSH API key,长期有效,无需刷新令牌。"),
|
|
172
172
|
react.createElement("div", { className: "co-auth-ok" },
|
|
173
173
|
"✅ 已认证",
|
|
174
174
|
status && status.sessionExpired ? react.createElement("span", { className: "co-hint" }, "(管理会话已过期,重新扫码可刷新模型列表)") : null),
|
|
@@ -178,7 +178,7 @@ window.__ModuleLoader__.load({
|
|
|
178
178
|
} else {
|
|
179
179
|
authCard = react.createElement("div", { className: "co-card" },
|
|
180
180
|
react.createElement("div", { className: "co-card-title" }, "认证"),
|
|
181
|
-
react.createElement("p", { className: "co-hint" }, "
|
|
181
|
+
react.createElement("p", { className: "co-hint" }, "中国移动算力豆一键认证:扫码即自动创建专属 DSH API key,长期有效,无需刷新令牌。"),
|
|
182
182
|
react.createElement("div", { className: "co-hint" }, "准备二维码…"));
|
|
183
183
|
}
|
|
184
184
|
|
package/lib/index.js
CHANGED
|
@@ -22,7 +22,7 @@ export const inject = ['connection', 'settings', 'credentials', 'tools', 'llm',
|
|
|
22
22
|
export const Config = z.object({});
|
|
23
23
|
|
|
24
24
|
// ---------------- 协议常量 ----------------
|
|
25
|
-
// 旧通道(广东移动 MaaS OAuth Device Grant)已由
|
|
25
|
+
// 旧通道(广东移动 MaaS OAuth Device Grant)已由 中国移动算力豆 API-key 通道取代(见下)。
|
|
26
26
|
|
|
27
27
|
const API_KEY_ENV = 'CMTOKEN_API_KEY';
|
|
28
28
|
const REFRESH_ENV = 'CMTOKEN_REFRESH_TOKEN';
|
|
@@ -114,10 +114,10 @@ async function komect(path, { method = 'GET', token, body, timeout = 20_000 } =
|
|
|
114
114
|
});
|
|
115
115
|
const json = await res.json().catch(() => undefined);
|
|
116
116
|
if (res.status === 401 || json?.code === 3004) {
|
|
117
|
-
throw new Error('
|
|
117
|
+
throw new Error('中国移动算力豆管理会话已失效,请重新扫码认证');
|
|
118
118
|
}
|
|
119
119
|
if (!res.ok || json?.code !== 0) {
|
|
120
|
-
throw new Error(
|
|
120
|
+
throw new Error(`算力豆 ${path} 失败 ${res.status}: ${String(json?.message ?? '').slice(0, 200) || 'unknown'}`);
|
|
121
121
|
}
|
|
122
122
|
return json.data;
|
|
123
123
|
}
|
|
@@ -143,7 +143,7 @@ async function ensureDshApiKey(session) {
|
|
|
143
143
|
const revealed = await komect(`/api-keys/${encodeURIComponent(item.id)}/reveal`, { method: 'POST', token: session });
|
|
144
144
|
const apiKey = revealed?.api_key;
|
|
145
145
|
if (typeof apiKey !== 'string' || !apiKey.startsWith('lx_sk_')) {
|
|
146
|
-
throw new Error('
|
|
146
|
+
throw new Error('算力豆密钥 reveal 失败:未返回有效的 lx_sk_ 密钥');
|
|
147
147
|
}
|
|
148
148
|
return apiKey;
|
|
149
149
|
}
|
|
@@ -156,20 +156,34 @@ async function fetchKomectModels(session) {
|
|
|
156
156
|
headers: { Accept: 'application/json', Authorization: `Bearer ${session}` },
|
|
157
157
|
});
|
|
158
158
|
const json = await res.json().catch(() => undefined);
|
|
159
|
-
if (res.status === 401) throw new Error('
|
|
159
|
+
if (res.status === 401) throw new Error('中国移动算力豆管理会话已失效,请重新扫码认证');
|
|
160
160
|
if (!res.ok || json?.code !== 0 || !Array.isArray(json?.data)) {
|
|
161
|
-
throw new Error(
|
|
161
|
+
throw new Error(`算力豆模型发现失败 ${res.status}: ${String(json?.message ?? '').slice(0, 200) || 'unknown'}`);
|
|
162
162
|
}
|
|
163
163
|
return json.data
|
|
164
164
|
.filter((m) => typeof m?.modelName === 'string' && m?.modelType === 'llm')
|
|
165
|
-
.map((m) =>
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
165
|
+
.map((m) => {
|
|
166
|
+
// 限时免费模型(名称/描述带「限时免费」)服务端对 max_tokens 的实际上限低于声明值,
|
|
167
|
+
// 超限直接网关 500。按 2026-09-18 实测的各模型最大可用值精确收口:
|
|
168
|
+
// flash:262144 ✓ / 512000 ✗;Qwen3.6:196608 ✓ / 262144 ✗;qwen38:256000 ✓
|
|
169
|
+
// 未列入映射的免费标记模型保守收口 131072;付费模型按平台声明值。
|
|
170
|
+
const free = /限时免费|限量免费/.test(`${m.name ?? ''}${m.desc ?? ''}`);
|
|
171
|
+
const maxOut = m.extInfo?.limits?.max_output_tokens ?? DEFAULT_MODEL_SPEC.maxTokens;
|
|
172
|
+
const FREE_MODEL_MAX_TOKENS = {
|
|
173
|
+
'deepseekv4-flash-guangdong': 262_144,
|
|
174
|
+
'qwen3.6-35b-guangdong': 196_608,
|
|
175
|
+
'qwen38-27b-guangdong': 256_000,
|
|
176
|
+
};
|
|
177
|
+
const freeCap = FREE_MODEL_MAX_TOKENS[String(m.modelName).toLowerCase()] ?? 131_072;
|
|
178
|
+
return {
|
|
179
|
+
id: m.modelName,
|
|
180
|
+
name: m.name ?? m.modelName,
|
|
181
|
+
contextWindow: m.extInfo?.limits?.max_input_tokens ?? DEFAULT_MODEL_SPEC.contextWindow,
|
|
182
|
+
maxTokens: free ? Math.min(maxOut, freeCap) : maxOut,
|
|
183
|
+
// 图片准入以服务端 supports_images 声明为准
|
|
184
|
+
input: m.extInfo?.supports_images === true ? ['text', 'image'] : ['text'],
|
|
185
|
+
};
|
|
186
|
+
});
|
|
173
187
|
}
|
|
174
188
|
|
|
175
189
|
|
|
@@ -354,8 +368,8 @@ function registerRpc(ctx) {
|
|
|
354
368
|
models = await fetchKomectModels(session);
|
|
355
369
|
} catch (e) {
|
|
356
370
|
// 模型发现失败:密钥照存,配置给最小模型集,报错提示
|
|
357
|
-
ctx.logger?.warn?.('[cmtoken-oauth]
|
|
358
|
-
models = [{ id: 'deepseekv4-flash-guangdong', name: 'DeepSeek V4 Flash', contextWindow: 512_000, maxTokens:
|
|
371
|
+
ctx.logger?.warn?.('[cmtoken-oauth] 算力豆模型发现失败: ' + String(e.message || e));
|
|
372
|
+
models = [{ id: 'deepseekv4-flash-guangdong', name: 'DeepSeek V4 Flash', contextWindow: 512_000, maxTokens: 262_144, input: ['text'] }];
|
|
359
373
|
}
|
|
360
374
|
await writeConfigAndCreds(ctx, { apiKey, session, expires }, models);
|
|
361
375
|
return {
|
|
@@ -472,7 +486,7 @@ async function writeConfigAndCreds(ctx, { apiKey, session, expires }, models) {
|
|
|
472
486
|
const section = {
|
|
473
487
|
providers: {
|
|
474
488
|
cmtoken: {
|
|
475
|
-
displayName: '
|
|
489
|
+
displayName: '中国移动算力豆',
|
|
476
490
|
apiKeyEnv: API_KEY_ENV,
|
|
477
491
|
api: 'openai-completions',
|
|
478
492
|
baseURL: GW_BASE,
|
|
@@ -656,7 +670,7 @@ async function describeImage({ baseURL, apiKey, model, dataUri, focus, signal })
|
|
|
656
670
|
}
|
|
657
671
|
if (!res.ok) {
|
|
658
672
|
const text = (await res.text().catch(() => '')).slice(0, 300);
|
|
659
|
-
if (res.status === 401) throw new Error('
|
|
673
|
+
if (res.status === 401) throw new Error('算力豆 API key 无效,请在设置 → cmtoken 认证里重新认证');
|
|
660
674
|
if (res.status === 403 && /订阅套餐|订阅已过期|余额不足/.test(text)) throw new Error('订阅错误:' + text);
|
|
661
675
|
throw new Error(`视觉模型识图失败 ${res.status}: ${text}`);
|
|
662
676
|
}
|
|
@@ -695,7 +709,7 @@ function registerVisionTool(ctx) {
|
|
|
695
709
|
if (!model) throw new Error('cmtoken 未配置视觉模型:请先在 DSH 设置 → cmtoken 认证完成一键认证');
|
|
696
710
|
|
|
697
711
|
const key = await ctx.credentials?.resolve(credentialRef(API_KEY_ENV));
|
|
698
|
-
if (!key) throw new Error('
|
|
712
|
+
if (!key) throw new Error('算力豆 API key 不可用:请先在 DSH 设置 → cmtoken 认证完成一键认证');
|
|
699
713
|
|
|
700
714
|
const bytes = await loadImageBytes(source, exec?.signal);
|
|
701
715
|
if (bytes.length === 0) throw new Error('图片内容为空');
|
|
@@ -796,7 +810,7 @@ async function evidenceForBlock(ctx, block, signal, cache) {
|
|
|
796
810
|
const model = await resolveVisionModel(ctx);
|
|
797
811
|
if (!model) throw new Error('cmtoken 未配置视觉模型,请先完成一键认证');
|
|
798
812
|
const keyRes = await ctx.credentials?.resolve(credentialRef(API_KEY_ENV));
|
|
799
|
-
if (!keyRes) throw new Error('
|
|
813
|
+
if (!keyRes) throw new Error('算力豆 API key 不可用,请重新认证');
|
|
800
814
|
const baseURL = ctx.settings?.get?.(settingsNamespace('llm-pi-ai'))?.providers?.cmtoken?.baseURL || GW_BASE;
|
|
801
815
|
const signals = [AbortSignal.timeout(VISION_TOOL_TIMEOUT_MS)];
|
|
802
816
|
if (signal) signals.push(signal);
|
|
@@ -1156,7 +1170,7 @@ export function apply(ctx, cfg = {}) {
|
|
|
1156
1170
|
disposeVisionAdapter();
|
|
1157
1171
|
};
|
|
1158
1172
|
}, 'cmtoken-oauth: host service');
|
|
1159
|
-
ctx.logger?.info?.('[cmtoken-oauth] host
|
|
1173
|
+
ctx.logger?.info?.('[cmtoken-oauth] host 服务已启动(中国移动算力豆 API-key 通道:密钥长期有效,无需定时刷新)');
|
|
1160
1174
|
}
|
|
1161
1175
|
|
|
1162
1176
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-cmtoken-oauth",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"description": "DeepSeek Harness 插件:在 DSH 设置页一键完成中国移动算力豆平台(komect)扫码认证——一次扫码自动桥接密钥管理会话、创建专属 DSH API key(lx_sk_,长期有效)、发现模型(上下文/输出/图片支持由平台动态提供)并写入 llm-pi-ai provider 配置,同时展示算力豆用量余额;粘贴识图让纯文本模型直接收图,另有 cmtoken_read_image 工具与可选的 cmtoken-vision 包装路由。零第三方运行时依赖。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|