mslxdff 0.1.174 → 0.1.175
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/bin/mslxdff.js +3 -3
- package/package.json +1 -1
- package/src/auto.js +254 -254
- package/src/bench/cline-bench.js +42 -42
- package/src/bench/probe.js +70 -70
- package/src/bench/report.js +162 -162
- package/src/bench/runner.js +77 -77
- package/src/bench/via-probe.js +124 -124
- package/src/bench/via-routes.js +87 -87
- package/src/bench/workbuddy-bench.js +54 -54
- package/src/chat/engine.js +160 -160
- package/src/chat/gateway.js +163 -163
- package/src/chat/orchestrator.js +234 -234
- package/src/chat/prompt.js +70 -70
- package/src/chat/repl.js +88 -88
- package/src/chat/terminal.js +135 -135
- package/src/chat/tools.js +306 -306
- package/src/chat-pipeline/auto-race.js +26 -1
- package/src/chat-pipeline/index.js +131 -131
- package/src/chat-pipeline/policy.js +84 -84
- package/src/chat-pipeline/serial-trial.js +35 -8
- package/src/chat-pipeline/terminal-verdict.js +109 -0
- package/src/cli/commands/group.js +249 -249
- package/src/cli/commands/model/picks.js +50 -50
- package/src/cli/commands/provider/bench-via.js +247 -247
- package/src/cli/commands/provider/bench.js +141 -141
- package/src/cli/commands/provider/index.js +136 -133
- package/src/cli/commands/provider/keys-guard.js +50 -0
- package/src/cli/commands/provider/keys.js +7 -0
- package/src/cli/commands/provider/models.js +145 -145
- package/src/cli/commands/provider/qwenwork-login.js +119 -119
- package/src/cli/commands/provider/traework-checkin.js +144 -0
- package/src/cli/commands/provider/traework-login.js +7 -45
- package/src/cli/commands/sync.js +310 -310
- package/src/cli/help.js +3 -0
- package/src/cli/status.js +279 -279
- package/src/daemon.js +112 -112
- package/src/model-capabilities/enrich.js +86 -86
- package/src/model-capabilities/index.js +183 -183
- package/src/model-capabilities/parse.js +70 -70
- package/src/model-trace.js +2 -0
- package/src/models.js +225 -225
- package/src/providers/cline/auth.js +228 -228
- package/src/providers/cline/chat.js +307 -307
- package/src/providers/cline.js +2 -2
- package/src/providers/codearts/chat.js +7 -1
- package/src/providers/codearts/const.js +6 -1
- package/src/providers/codearts/index.js +18 -11
- package/src/providers/globalqwenwork/cosy.js +123 -123
- package/src/providers/globalqwenwork/crypto.js +218 -218
- package/src/providers/globalqwenwork/http.js +20 -20
- package/src/providers/globalqwenwork/rsa.js +54 -54
- package/src/providers/globalqwenwork/sse.js +268 -268
- package/src/providers/globalqwenwork/stream.js +130 -130
- package/src/providers/globalqwenwork/upstream.js +122 -122
- package/src/providers/keyring.js +60 -60
- package/src/providers/qoder/chat.js +203 -203
- package/src/providers/qoder/index.js +249 -249
- package/src/providers/qoder/sse.js +145 -145
- package/src/providers/qwenwork/account-store.js +133 -133
- package/src/providers/qwenwork/constants.js +67 -67
- package/src/providers/qwenwork/cosy.js +120 -120
- package/src/providers/qwenwork/crypto.js +218 -218
- package/src/providers/qwenwork/http.js +20 -20
- package/src/providers/qwenwork/index.js +327 -327
- package/src/providers/qwenwork/payload.js +144 -144
- package/src/providers/qwenwork/rsa.js +54 -54
- package/src/providers/qwenwork/sse.js +268 -268
- package/src/providers/qwenwork/stream.js +130 -130
- package/src/providers/qwenwork/upstream.js +120 -120
- package/src/providers/qwenwork.js +1 -1
- package/src/providers/registry.js +79 -79
- package/src/providers/traework/account-store.js +87 -2
- package/src/providers/traework/checkin.js +51 -9
- package/src/providers/traework/constants.js +20 -0
- package/src/providers/traework/headers.js +42 -10
- package/src/providers/traework/index.js +14 -4
- package/src/providers/traework/market-identity.js +116 -0
- package/src/providers/workbuddy/chat.js +248 -248
- package/src/providers/workbuddy/reshape.js +152 -152
- package/src/providers/workbuddy.js +2 -2
- package/src/reasoning.js +32 -32
- package/src/routes/chat/gateway.js +46 -46
- package/src/routes/chat/relay-pipeline.js +294 -294
- package/src/routes/chat/via-route-handler.js +146 -146
- package/src/routes/hedge.js +255 -255
- package/src/routes/models-route.js +167 -167
- package/src/routes/peers.js +273 -273
- package/src/routes/stream.js +385 -385
- package/src/runtime/bootstrap.js +50 -50
- package/src/runtime/provider-gate.js +36 -36
- package/src/runtime/providers-setup.js +168 -165
- package/src/runtime/traework-checkin.js +26 -11
- package/src/server.js +69 -69
- package/src/state/schemas/allowlist.js +92 -92
- package/src/sync-opencode.js +280 -280
- package/src/transport/index.js +244 -244
- package/src/transport/pool.js +56 -56
- package/src/transport/retry.js +24 -24
- package/src/transport/sse.js +93 -93
- package/src/upstream-probe/display.js +52 -52
- package/src/upstream-probe/probe.js +49 -49
- package/src/upstream-probe/rotate.js +110 -110
- package/src/upstream-probe/start.js +45 -45
- package/src/upstream.js +291 -289
- package/src/warp-pool/config.js +71 -0
- package/src/warp-pool/health.js +65 -0
- package/src/warp-pool/index.js +252 -0
- package/src/warp-pool/keys.js +29 -0
- package/src/warp-pool/nodes.js +94 -0
- package/src/warp-pool/register.js +113 -0
- package/src/warp-pool/rotate.js +150 -0
- package/src/warp-pool/strategy.js +43 -0
- package/src/warp-pool/wireproxy.js +153 -0
- package/docs/cli_help_mini.md +0 -143
- package/src/providers/AGENTS.md +0 -49
- package/src/routes/AGENTS.md +0 -37
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import crypto from "node:crypto";
|
|
4
4
|
import { joinUrl } from "../base.js";
|
|
5
5
|
import { createTransport } from "../../transport/index.js";
|
|
6
|
-
import { SNAP_BASE, EP_CHAT_V2, chatBaseHeaders, MAAS_TYPE_HEADER, MAAS_BENEFIT } from "./const.js";
|
|
6
|
+
import { SNAP_BASE, EP_CHAT_V2, chatBaseHeaders, MAAS_TYPE_HEADER, MAAS_BENEFIT, MAX_TOKENS_CEILING } from "./const.js";
|
|
7
7
|
import { signRequest } from "./sign.js";
|
|
8
8
|
import { newChatId, preflightResponse, sseToOpenAIResponse, aggregateToCompletion, UpstreamEventError } from "./stream.js";
|
|
9
9
|
|
|
@@ -36,8 +36,14 @@ export function buildUpstreamBody(body, { chatId, upstreamModel }) {
|
|
|
36
36
|
chat_id: chatId,
|
|
37
37
|
};
|
|
38
38
|
for (const k of PASSTHROUGH_KEYS) {
|
|
39
|
+
if (k === "max_completion_tokens") continue; // v2 端点不认这个名字(透传 → InferHub.001001005.400,2026-10-16 现网 A/B 复现)
|
|
39
40
|
if (body?.[k] !== undefined && body?.[k] !== null) out[k] = body[k];
|
|
40
41
|
}
|
|
42
|
+
// Responses 风格客户端只发 max_completion_tokens:映射成 v2 认的 max_tokens(显式 max_tokens 优先)
|
|
43
|
+
if (out.max_tokens === undefined && body?.max_completion_tokens != null) out.max_tokens = body.max_completion_tokens;
|
|
44
|
+
// 超上限的 max_tokens 上游一律回 InferHub.001001005.400(参数非法),在这里夹住(env 可放宽)
|
|
45
|
+
const ceiling = Number.parseInt(process.env.MSLXDFF_CODEARTS_MAX_TOKENS_CEILING ?? "", 10) || MAX_TOKENS_CEILING;
|
|
46
|
+
if (typeof out.max_tokens === "number" && out.max_tokens > ceiling) out.max_tokens = ceiling;
|
|
41
47
|
return out;
|
|
42
48
|
}
|
|
43
49
|
|
|
@@ -44,7 +44,8 @@ export const MAAS_TYPE_HEADER = "maas_type";
|
|
|
44
44
|
export const MAAS_BENEFIT = "benefit";
|
|
45
45
|
|
|
46
46
|
// 冷启动种子:福利套餐轮换后新模型在首次发现前也按福利路由(宁多带不少带,少带即 404)。
|
|
47
|
-
|
|
47
|
+
// 现网取证 2026-10-16(福利网关 /api/v1/gateway/config,error_code=0000)共 4 位:下列 4 个 id 逐字对齐上游。
|
|
48
|
+
export const SEED_BENEFIT_MODELS = ["deepseek-v4-flash-0731", "deepseek-v4-pro-0813", "deepseek-v4.1-flash", "glm-5.3-flash"];
|
|
48
49
|
// 内置模型种子(仅用于大小写归一,不标福利)。
|
|
49
50
|
export const SEED_KNOWN_MODELS = [
|
|
50
51
|
"GLM-5.2", "GLM-5.2-ArkTS-SPARK", "GLM-5.1", "GLM-4.7",
|
|
@@ -58,3 +59,7 @@ export const CATALOG_TTL_MS = 60 * 60 * 1000;
|
|
|
58
59
|
export const MODELS_CACHE_TTL_MS = 10 * 60 * 1000;
|
|
59
60
|
// STS 凭证提前刷新量(对齐 codearts2api RefreshSkew 30min)。
|
|
60
61
|
export const REFRESH_SKEW_MS_DEFAULT = 30 * 60 * 1000;
|
|
62
|
+
|
|
63
|
+
// 上游 max_tokens 真实上限:福利网关自报 131072~393216 是假的 —— 现网实测 65536 通、
|
|
64
|
+
// 98304 即 InferHub.001001005.400(2026-10-16 定位);此前成功请求均为 64000。
|
|
65
|
+
export const MAX_TOKENS_CEILING = 65536;
|
|
@@ -98,20 +98,27 @@ export function createCodeartsProvider({
|
|
|
98
98
|
// 三路发现(主账号);结果写目录(benefit 判定按账号隔离)
|
|
99
99
|
let discovering = null;
|
|
100
100
|
async function discover(force = false) {
|
|
101
|
-
const
|
|
102
|
-
if (!
|
|
103
|
-
if (!force && !catalog.isStale(primary.userId, clock())) return catalog.accountModels(primary.userId);
|
|
101
|
+
const candidates = pool.aliveAccounts();
|
|
102
|
+
if (!candidates.length) throw new Error("codearts: no alive account — run: mslxdff -provider codearts login");
|
|
104
103
|
if (discovering) return discovering;
|
|
105
104
|
discovering = (async () => {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
105
|
+
let lastErr = null;
|
|
106
|
+
// 逐个账号试(blob 顺序 = 主账号优先):state 里可能留着已被轮转消费的僵尸凭证(实测 STS5.1806
|
|
107
|
+
// "the refresh token has been used",login 只追加不清旧,死号会永远排在第一个)。一个死号绝不能
|
|
108
|
+
// 把整个目录变成空表——福利套餐轮换出的新模型全靠这里发现。
|
|
109
|
+
for (const candidate of candidates) {
|
|
110
|
+
if (!force && !catalog.isStale(candidate.userId, clock())) return catalog.accountModels(candidate.userId);
|
|
111
|
+
try {
|
|
112
|
+
const account = await pool.getCredential(candidate.blob);
|
|
113
|
+
const { models, builtinOk, benefitOk } = await discoverAccountModels({ account, snapBase: resolvedBase, benefitHost, autoClaim, fetchImpl });
|
|
114
|
+
catalog.setAccount(account.userId, models, { keepBenefit: builtinOk && !benefitOk, now: clock() });
|
|
115
|
+
return models;
|
|
116
|
+
} catch (err) {
|
|
117
|
+
lastErr = err; // 死号/该号三路全空 → 换下一个号
|
|
118
|
+
}
|
|
113
119
|
}
|
|
114
|
-
|
|
120
|
+
throw lastErr || new Error("codearts: no account could list models — run: mslxdff -provider codearts login");
|
|
121
|
+
})().finally(() => { discovering = null; });
|
|
115
122
|
return discovering;
|
|
116
123
|
}
|
|
117
124
|
|
|
@@ -1,123 +1,123 @@
|
|
|
1
|
-
// cosy.js(COSY 会话 + 签名头)— vendor 自 src/providers/qwenwork/cosy.js 逐字搬;
|
|
2
|
-
// 本目录 import 全为相对路径,自动绑定本目录 constants/crypto/rsa。线上头 x-qwenwork-* 与 cn 同名,**禁止改名**(实测 .ai 接受)。
|
|
3
|
-
// 关键不变式(改动即 403):
|
|
4
|
-
// · identity/payload 都必须 key 升序紧凑 JSON(sortedCompact)
|
|
5
|
-
// · 签名 = md5(payloadB64 \n cosyKey \n date \n body \n pathSig),pathSig 去 /algo 前缀、不含 query
|
|
6
|
-
// · authorization = `Bearer COSY.${payloadB64}.${sig}`;payloadB64 是**标准 base64(带 padding)**
|
|
7
|
-
// · 同一 requestId 重放会被上游判 `code 103 Duplicate request`
|
|
8
|
-
import { uuid, b64, b64url, utf8, aesCbcEncrypt, md5 } from "./crypto.js";
|
|
9
|
-
import { rsaPkcs1Encrypt } from "./rsa.js";
|
|
10
|
-
import {
|
|
11
|
-
COSY_VERSION, IDE_VERSION, RELEASE_VERSION, BUILD, CLIENT_TYPE,
|
|
12
|
-
BUSINESS_PRODUCT, BUSINESS_TYPE, SCENE, MACHINE_OS, UA,
|
|
13
|
-
} from "./constants.js";
|
|
14
|
-
|
|
15
|
-
const cache = new Map();
|
|
16
|
-
|
|
17
|
-
function sortedCompact(obj) {
|
|
18
|
-
const keys = Object.keys(obj).sort();
|
|
19
|
-
let out = "{";
|
|
20
|
-
for (let i = 0; i < keys.length; i++) {
|
|
21
|
-
if (i > 0) out += ",";
|
|
22
|
-
out += JSON.stringify(keys[i]) + ":" + JSON.stringify(obj[keys[i]]);
|
|
23
|
-
}
|
|
24
|
-
return out + "}";
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function newSession(account) {
|
|
28
|
-
const machineID = uuid();
|
|
29
|
-
const seed = (uuid() + uuid()).slice(0, 50);
|
|
30
|
-
const machineToken = b64url(utf8(seed));
|
|
31
|
-
const machineType = uuid().replace(/-/g, "").slice(0, 18);
|
|
32
|
-
const tempKey = uuid().replace(/-/g, "").slice(0, 16);
|
|
33
|
-
|
|
34
|
-
const identity = sortedCompact({
|
|
35
|
-
uid: account.uid || "",
|
|
36
|
-
aid: account.uid || "",
|
|
37
|
-
name: account.nickname || "",
|
|
38
|
-
email: account.email || "",
|
|
39
|
-
security_oauth_token: account.accessToken,
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
machineID,
|
|
44
|
-
machineToken,
|
|
45
|
-
machineType,
|
|
46
|
-
tempKey,
|
|
47
|
-
cosyKey: rsaPkcs1Encrypt(utf8(tempKey)),
|
|
48
|
-
info: b64(aesCbcEncrypt(utf8(identity), utf8(tempKey))),
|
|
49
|
-
accessToken: account.accessToken,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function sessionFor(account) {
|
|
54
|
-
if (!account || !account.accessToken) throw new Error("cosy: empty access token");
|
|
55
|
-
const key = account.id || account.uid || account.accessToken.slice(0, 16);
|
|
56
|
-
const hit = cache.get(key);
|
|
57
|
-
if (hit && hit.accessToken === account.accessToken) return hit;
|
|
58
|
-
if (cache.size > 128) cache.clear();
|
|
59
|
-
const sess = newSession(account);
|
|
60
|
-
cache.set(key, sess);
|
|
61
|
-
return sess;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function invalidateSession(account) {
|
|
65
|
-
const key = account && (account.id || account.uid);
|
|
66
|
-
if (key) cache.delete(key);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function pathSig(rawURL) {
|
|
70
|
-
const u = new URL(rawURL);
|
|
71
|
-
let p = u.pathname;
|
|
72
|
-
if (p.startsWith("/algo")) p = p.slice("/algo".length);
|
|
73
|
-
return p;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function signHeaders(account, body, rawURL, modelKey, accept) {
|
|
77
|
-
const sess = sessionFor(account);
|
|
78
|
-
const payload = sortedCompact({
|
|
79
|
-
cosyVersion: COSY_VERSION,
|
|
80
|
-
ideVersion: IDE_VERSION,
|
|
81
|
-
info: sess.info,
|
|
82
|
-
requestId: uuid(),
|
|
83
|
-
version: "v1",
|
|
84
|
-
});
|
|
85
|
-
const payloadB64 = b64(utf8(payload));
|
|
86
|
-
const date = Math.floor(Date.now() / 1000).toString();
|
|
87
|
-
const sig = md5(`${payloadB64}\n${sess.cosyKey}\n${date}\n${body}\n${pathSig(rawURL)}`);
|
|
88
|
-
|
|
89
|
-
const headers = {
|
|
90
|
-
accept: accept || "text/event-stream",
|
|
91
|
-
"content-type": "application/json",
|
|
92
|
-
"user-agent": UA,
|
|
93
|
-
"x-request-id": uuid(),
|
|
94
|
-
"x-qwenwork-version": IDE_VERSION,
|
|
95
|
-
"x-qwenwork-release-version": RELEASE_VERSION,
|
|
96
|
-
"x-qwenwork-build": BUILD,
|
|
97
|
-
"x-qwenwork-platform": "win32",
|
|
98
|
-
"x-qwenwork-arch": "x64",
|
|
99
|
-
"x-qwenwork-channel": "stable",
|
|
100
|
-
"cosy-version": COSY_VERSION,
|
|
101
|
-
"cosy-clienttype": CLIENT_TYPE,
|
|
102
|
-
"cosy-business-product": BUSINESS_PRODUCT,
|
|
103
|
-
"cosy-business-type": BUSINESS_TYPE,
|
|
104
|
-
"cosy-scene": SCENE,
|
|
105
|
-
"cosy-machineos": MACHINE_OS,
|
|
106
|
-
"login-version": "v2",
|
|
107
|
-
authorization: `Bearer COSY.${payloadB64}.${sig}`,
|
|
108
|
-
"cosy-key": sess.cosyKey,
|
|
109
|
-
"cosy-user": account.uid || "",
|
|
110
|
-
"cosy-date": date,
|
|
111
|
-
"cosy-machineid": sess.machineID,
|
|
112
|
-
"accept-encoding": "identity",
|
|
113
|
-
connection: "keep-alive",
|
|
114
|
-
"cache-control": "no-cache",
|
|
115
|
-
};
|
|
116
|
-
if (modelKey) {
|
|
117
|
-
headers["x-model-key"] = modelKey;
|
|
118
|
-
headers["x-model-source"] = "system";
|
|
119
|
-
}
|
|
120
|
-
return headers;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// globalqwenwork 变体(国际站 gateway.qwenwork.ai):协议与 cn 逐字同构,2026-10-01 现网实测签名/请求 200 — 见 docs/adr/0041-globalqwenwork-international-provider.md
|
|
1
|
+
// cosy.js(COSY 会话 + 签名头)— vendor 自 src/providers/qwenwork/cosy.js 逐字搬;
|
|
2
|
+
// 本目录 import 全为相对路径,自动绑定本目录 constants/crypto/rsa。线上头 x-qwenwork-* 与 cn 同名,**禁止改名**(实测 .ai 接受)。
|
|
3
|
+
// 关键不变式(改动即 403):
|
|
4
|
+
// · identity/payload 都必须 key 升序紧凑 JSON(sortedCompact)
|
|
5
|
+
// · 签名 = md5(payloadB64 \n cosyKey \n date \n body \n pathSig),pathSig 去 /algo 前缀、不含 query
|
|
6
|
+
// · authorization = `Bearer COSY.${payloadB64}.${sig}`;payloadB64 是**标准 base64(带 padding)**
|
|
7
|
+
// · 同一 requestId 重放会被上游判 `code 103 Duplicate request`
|
|
8
|
+
import { uuid, b64, b64url, utf8, aesCbcEncrypt, md5 } from "./crypto.js";
|
|
9
|
+
import { rsaPkcs1Encrypt } from "./rsa.js";
|
|
10
|
+
import {
|
|
11
|
+
COSY_VERSION, IDE_VERSION, RELEASE_VERSION, BUILD, CLIENT_TYPE,
|
|
12
|
+
BUSINESS_PRODUCT, BUSINESS_TYPE, SCENE, MACHINE_OS, UA,
|
|
13
|
+
} from "./constants.js";
|
|
14
|
+
|
|
15
|
+
const cache = new Map();
|
|
16
|
+
|
|
17
|
+
function sortedCompact(obj) {
|
|
18
|
+
const keys = Object.keys(obj).sort();
|
|
19
|
+
let out = "{";
|
|
20
|
+
for (let i = 0; i < keys.length; i++) {
|
|
21
|
+
if (i > 0) out += ",";
|
|
22
|
+
out += JSON.stringify(keys[i]) + ":" + JSON.stringify(obj[keys[i]]);
|
|
23
|
+
}
|
|
24
|
+
return out + "}";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function newSession(account) {
|
|
28
|
+
const machineID = uuid();
|
|
29
|
+
const seed = (uuid() + uuid()).slice(0, 50);
|
|
30
|
+
const machineToken = b64url(utf8(seed));
|
|
31
|
+
const machineType = uuid().replace(/-/g, "").slice(0, 18);
|
|
32
|
+
const tempKey = uuid().replace(/-/g, "").slice(0, 16);
|
|
33
|
+
|
|
34
|
+
const identity = sortedCompact({
|
|
35
|
+
uid: account.uid || "",
|
|
36
|
+
aid: account.uid || "",
|
|
37
|
+
name: account.nickname || "",
|
|
38
|
+
email: account.email || "",
|
|
39
|
+
security_oauth_token: account.accessToken,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
machineID,
|
|
44
|
+
machineToken,
|
|
45
|
+
machineType,
|
|
46
|
+
tempKey,
|
|
47
|
+
cosyKey: rsaPkcs1Encrypt(utf8(tempKey)),
|
|
48
|
+
info: b64(aesCbcEncrypt(utf8(identity), utf8(tempKey))),
|
|
49
|
+
accessToken: account.accessToken,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function sessionFor(account) {
|
|
54
|
+
if (!account || !account.accessToken) throw new Error("cosy: empty access token");
|
|
55
|
+
const key = account.id || account.uid || account.accessToken.slice(0, 16);
|
|
56
|
+
const hit = cache.get(key);
|
|
57
|
+
if (hit && hit.accessToken === account.accessToken) return hit;
|
|
58
|
+
if (cache.size > 128) cache.clear();
|
|
59
|
+
const sess = newSession(account);
|
|
60
|
+
cache.set(key, sess);
|
|
61
|
+
return sess;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function invalidateSession(account) {
|
|
65
|
+
const key = account && (account.id || account.uid);
|
|
66
|
+
if (key) cache.delete(key);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function pathSig(rawURL) {
|
|
70
|
+
const u = new URL(rawURL);
|
|
71
|
+
let p = u.pathname;
|
|
72
|
+
if (p.startsWith("/algo")) p = p.slice("/algo".length);
|
|
73
|
+
return p;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function signHeaders(account, body, rawURL, modelKey, accept) {
|
|
77
|
+
const sess = sessionFor(account);
|
|
78
|
+
const payload = sortedCompact({
|
|
79
|
+
cosyVersion: COSY_VERSION,
|
|
80
|
+
ideVersion: IDE_VERSION,
|
|
81
|
+
info: sess.info,
|
|
82
|
+
requestId: uuid(),
|
|
83
|
+
version: "v1",
|
|
84
|
+
});
|
|
85
|
+
const payloadB64 = b64(utf8(payload));
|
|
86
|
+
const date = Math.floor(Date.now() / 1000).toString();
|
|
87
|
+
const sig = md5(`${payloadB64}\n${sess.cosyKey}\n${date}\n${body}\n${pathSig(rawURL)}`);
|
|
88
|
+
|
|
89
|
+
const headers = {
|
|
90
|
+
accept: accept || "text/event-stream",
|
|
91
|
+
"content-type": "application/json",
|
|
92
|
+
"user-agent": UA,
|
|
93
|
+
"x-request-id": uuid(),
|
|
94
|
+
"x-qwenwork-version": IDE_VERSION,
|
|
95
|
+
"x-qwenwork-release-version": RELEASE_VERSION,
|
|
96
|
+
"x-qwenwork-build": BUILD,
|
|
97
|
+
"x-qwenwork-platform": "win32",
|
|
98
|
+
"x-qwenwork-arch": "x64",
|
|
99
|
+
"x-qwenwork-channel": "stable",
|
|
100
|
+
"cosy-version": COSY_VERSION,
|
|
101
|
+
"cosy-clienttype": CLIENT_TYPE,
|
|
102
|
+
"cosy-business-product": BUSINESS_PRODUCT,
|
|
103
|
+
"cosy-business-type": BUSINESS_TYPE,
|
|
104
|
+
"cosy-scene": SCENE,
|
|
105
|
+
"cosy-machineos": MACHINE_OS,
|
|
106
|
+
"login-version": "v2",
|
|
107
|
+
authorization: `Bearer COSY.${payloadB64}.${sig}`,
|
|
108
|
+
"cosy-key": sess.cosyKey,
|
|
109
|
+
"cosy-user": account.uid || "",
|
|
110
|
+
"cosy-date": date,
|
|
111
|
+
"cosy-machineid": sess.machineID,
|
|
112
|
+
"accept-encoding": "identity",
|
|
113
|
+
connection: "keep-alive",
|
|
114
|
+
"cache-control": "no-cache",
|
|
115
|
+
};
|
|
116
|
+
if (modelKey) {
|
|
117
|
+
headers["x-model-key"] = modelKey;
|
|
118
|
+
headers["x-model-source"] = "system";
|
|
119
|
+
}
|
|
120
|
+
return headers;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// globalqwenwork 变体(国际站 gateway.qwenwork.ai):协议与 cn 逐字同构,2026-10-01 现网实测签名/请求 200 — 见 docs/adr/0041-globalqwenwork-international-provider.md
|