dsh-xdpool 2.4.2 → 2.4.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 +54 -0
- package/lib/bin.js +51 -2
- package/lib/client.js +149 -1
- package/lib/index.d.ts +189 -23
- package/lib/index.js +723 -34
- package/package.json +1 -1
- package/vendor/channel-pack/pack.js +97 -9
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "dsh-xdpool",
|
|
3
3
|
"displayName": "DSH XD Pool",
|
|
4
4
|
"description": "One DSH model pool for every free quota you have: merge all locally signed-in WorkBuddy accounts with auto-failover, sign in to 13 vendors by QR/web, aggregate 76 vendors' free tiers, plus a usage dashboard, model routing, a local OpenAI-compatible gateway and a points-automation suite.",
|
|
5
|
-
"version": "2.4.
|
|
5
|
+
"version": "2.4.3",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "XDTrees",
|
|
8
8
|
"homepage": "https://github.com/XDTrees/dsh-xdpool#readme",
|
|
@@ -30936,6 +30936,31 @@ function resolveHideWithoutAccountFlag(raw) {
|
|
|
30936
30936
|
|
|
30937
30937
|
// vendor/channel-pack/src/remote-catalog-gate.ts
|
|
30938
30938
|
var REMOTE_CATALOG_COOLDOWN_MS = 3e4;
|
|
30939
|
+
// [xdpool-local] How long a successfully fetched model catalog is trusted.
|
|
30940
|
+
//
|
|
30941
|
+
// Each adapter below caches its catalog for the life of the process ("if
|
|
30942
|
+
// remoteModels is set, return"), so a vendor renaming a model or changing its
|
|
30943
|
+
// multiplier only reached the card after a restart. The rename is often a price
|
|
30944
|
+
// change (the multiplier is part of `name`), which makes a restart-only refresh
|
|
30945
|
+
// a bad way to learn what a model costs. Ten minutes, overridable for testing.
|
|
30946
|
+
var REMOTE_CATALOG_TTL_MS = 6e5;
|
|
30947
|
+
var REMOTE_CATALOG_STAMP = new WeakMap();
|
|
30948
|
+
function remoteModelsStale(owner) {
|
|
30949
|
+
if (owner.remoteModels === void 0) return true;
|
|
30950
|
+
var override = Number(process.env.DSH_XDPOOL_CATALOG_TTL_MS ?? "");
|
|
30951
|
+
var ttl = Number.isFinite(override) && override >= 0 ? override : REMOTE_CATALOG_TTL_MS;
|
|
30952
|
+
var now = Date.now();
|
|
30953
|
+
var stamp = REMOTE_CATALOG_STAMP.get(owner);
|
|
30954
|
+
if (stamp === void 0 || now - stamp < ttl) {
|
|
30955
|
+
if (stamp === void 0) REMOTE_CATALOG_STAMP.set(owner, now);
|
|
30956
|
+
return false;
|
|
30957
|
+
}
|
|
30958
|
+
// Do NOT clear the cache: the loader below only overwrites on success, so a
|
|
30959
|
+
// failed refresh keeps serving the last known good catalog instead of falling
|
|
30960
|
+
// back to bare ids. The gate's 30s cooldown bounds the retry rate.
|
|
30961
|
+
REMOTE_CATALOG_STAMP.set(owner, now);
|
|
30962
|
+
return true;
|
|
30963
|
+
}
|
|
30939
30964
|
var RemoteCatalogGate = class {
|
|
30940
30965
|
inFlight;
|
|
30941
30966
|
retryAt;
|
|
@@ -32985,7 +33010,7 @@ var CodeArtsAdapter = class extends LlmAdapter {
|
|
|
32985
33010
|
*/
|
|
32986
33011
|
async ensureRemoteModels() {
|
|
32987
33012
|
const fetchRemote = this.options.fetchRemoteModels;
|
|
32988
|
-
if (
|
|
33013
|
+
if (fetchRemote === void 0 || !remoteModelsStale(this)) return;
|
|
32989
33014
|
await this.catalogGate.run(async () => {
|
|
32990
33015
|
const models = await fetchRemote();
|
|
32991
33016
|
if (models.length === 0) return false;
|
|
@@ -33141,6 +33166,38 @@ var CodeArtsAdapter = class extends LlmAdapter {
|
|
|
33141
33166
|
headers.set("Chat-Id", this.chatId);
|
|
33142
33167
|
headers.set("Session-Id", this.sessionId);
|
|
33143
33168
|
headers.set("lang", "en");
|
|
33169
|
+
// [xdpool-local] billion-context(bili)在 DSH 内做上下文压缩,而压缩必须重写请求体;
|
|
33170
|
+
// 本请求的签名覆盖请求体(SDK-HMAC-SHA256),重写即失效。bili 手里没有可重签的凭证,
|
|
33171
|
+
// 于是按它的 compress-or-refuse 契约**本地 403 拒绝转发**,而 pack 侧只看到 403
|
|
33172
|
+
// (httpErrorCode 对 403 无条件返回 "AUTH"),最终被 lib/index.js 的
|
|
33173
|
+
// SESSION_DEAD_MARKERS 归类成「API 密钥无效」—— 用户看到凭证失效,实际凭证完全有效。
|
|
33174
|
+
// 把签名三要素交给 bili,它就能自己重签,上下文压缩得以保留。
|
|
33175
|
+
//
|
|
33176
|
+
// 这两个头不参与华为签名(bili 的 SIGNED_HEADER_NAMES 只有 authorization /
|
|
33177
|
+
// x-sdk-date / x-sdk-content-sha256 / x-security-token / maas_type),且是在
|
|
33178
|
+
// signRequestHuawei 算完签名之后才设进去的,所以不影响上游校验。
|
|
33179
|
+
//
|
|
33180
|
+
// 安全前提(已实测确认):bili 在构造上游请求时**剥离**这两个头并用自己的凭证重签 ——
|
|
33181
|
+
// dist/index.js 的转发头复制循环里显式跳过 APIG_RESIGN_HEADER /
|
|
33182
|
+
// APIG_RESIGN_CREDENTIAL_HEADER,所以 secret_access_key 不会到达上游。
|
|
33183
|
+
//
|
|
33184
|
+
// 默认为什么仍是关:billion-context 只在 optionalDependencies 里,未安装时这两个头
|
|
33185
|
+
// 会直达上游;且 bili 的进程内 native client 自己就会构造这两个头(resignExtra),
|
|
33186
|
+
// 那条路径加不加都不影响它。开关留给「xdpool 直接对接 bili 代理路径」的场合。
|
|
33187
|
+
if (this.options.codeartsResignHeaders === true) {
|
|
33188
|
+
headers.set("x-bili-resign", "sdk-hmac-sha256");
|
|
33189
|
+
headers.set(
|
|
33190
|
+
"x-bili-resign-credential",
|
|
33191
|
+
Buffer.from(
|
|
33192
|
+
JSON.stringify({
|
|
33193
|
+
ak: credential.access_key_id,
|
|
33194
|
+
sk: credential.secret_access_key,
|
|
33195
|
+
token: credential.security_token ?? ""
|
|
33196
|
+
}),
|
|
33197
|
+
"utf8"
|
|
33198
|
+
).toString("base64")
|
|
33199
|
+
);
|
|
33200
|
+
}
|
|
33144
33201
|
response = await this.fetchImpl(url, {
|
|
33145
33202
|
method: "POST",
|
|
33146
33203
|
headers,
|
|
@@ -34977,7 +35034,7 @@ var BuddyAdapter = class _BuddyAdapter extends LlmAdapter2 {
|
|
|
34977
35034
|
}
|
|
34978
35035
|
async ensureRemoteModels() {
|
|
34979
35036
|
const fetchRemote = this.options.fetchRemoteModels;
|
|
34980
|
-
if (
|
|
35037
|
+
if (fetchRemote === void 0 || !remoteModelsStale(this)) return;
|
|
34981
35038
|
await this.catalogGate.run(async () => {
|
|
34982
35039
|
const models = await fetchRemote();
|
|
34983
35040
|
if (models.length === 0) return false;
|
|
@@ -35250,9 +35307,30 @@ var BuddyAdapter = class _BuddyAdapter extends LlmAdapter2 {
|
|
|
35250
35307
|
}
|
|
35251
35308
|
}
|
|
35252
35309
|
const messages = serializeMessages2(options.messages, imageUrls);
|
|
35310
|
+
// [xdpool-local] The WorkBuddy gateways refuse role "developer" with business
|
|
35311
|
+
// code 11128 ("Illegal API invocation from an unapproved channel"), and DSH
|
|
35312
|
+
// sends workspace instructions under exactly that role. Convert in place: role
|
|
35313
|
+
// only, no merging and no reordering, so a rule at the front stays at the
|
|
35314
|
+
// front and one injected mid-conversation stays where it was.
|
|
35315
|
+
for (const message of messages) {
|
|
35316
|
+
if (message.role === "developer") message.role = "system";
|
|
35317
|
+
}
|
|
35253
35318
|
if (options.system !== void 0 && options.system.length > 0) {
|
|
35254
35319
|
messages.unshift({ role: "system", content: options.system });
|
|
35255
35320
|
}
|
|
35321
|
+
// [xdpool-local] The same gateways scan system and assistant CONTENT for
|
|
35322
|
+
// other clients' fingerprints and answer 11128 / "this call failed channel
|
|
35323
|
+
// verification". The match is a case-insensitive substring, so the fix has
|
|
35324
|
+
// to rewrite the phrase, not shift it: a leading newline clears the
|
|
35325
|
+
// start-anchored one and does nothing to the "DeepSeek Harness Web GUI"
|
|
35326
|
+
// pair (measured on a live account 2026-10-21; the pool's own copy of this
|
|
35327
|
+
// list is BANNED_SYSTEM_PHRASES in src/upstream.ts). Runs AFTER the prepend
|
|
35328
|
+
// above, because that is where the host's system text lands.
|
|
35329
|
+
for (const message of messages) {
|
|
35330
|
+
if ((message.role === "system" || message.role === "assistant") && typeof message.content === "string") {
|
|
35331
|
+
message.content = message.content.replace(/powered by DeepSeek Harness/gi, "running on DeepSeek Harness").replace(/DeepSeek Harness Web GUI/gi, "DeepSeek Harness web interface");
|
|
35332
|
+
}
|
|
35333
|
+
}
|
|
35256
35334
|
const tools = options.tools?.map((tool) => ({
|
|
35257
35335
|
type: "function",
|
|
35258
35336
|
function: {
|
|
@@ -35493,6 +35571,16 @@ var BuddyAdapter = class _BuddyAdapter extends LlmAdapter2 {
|
|
|
35493
35571
|
headers.set("X-IDE-Version", this.product.clientVersion);
|
|
35494
35572
|
headers.set(HTTP_HEADER_PRODUCT, this.product.attributionName);
|
|
35495
35573
|
headers.set("User-Agent", resolveUserAgent(this.product, options.model));
|
|
35574
|
+
// [xdpool-local] The international gateway turned its channel verification
|
|
35575
|
+
// from soft to hard: missing ANY one of these three headers and every turn
|
|
35576
|
+
// comes back 400 / 11128 "request illegal", which reaches the user as a
|
|
35577
|
+
// blocked request with nothing wrong in the body. The official client sets all
|
|
35578
|
+
// three on every /v2/chat/completions. `sessionId` is already the process-
|
|
35579
|
+
// stable prompt-cache key, so it is the conversation; the other two are fresh
|
|
35580
|
+
// per request and per message.
|
|
35581
|
+
headers.set("X-Conversation-ID", this.sessionId);
|
|
35582
|
+
headers.set("X-Conversation-Request-ID", crypto.randomUUID());
|
|
35583
|
+
headers.set("X-Conversation-Message-ID", crypto.randomUUID());
|
|
35496
35584
|
try {
|
|
35497
35585
|
return await this.fetchImpl(`${this.product.endpoint}/v2/chat/completions`, {
|
|
35498
35586
|
method: "POST",
|
|
@@ -36490,7 +36578,7 @@ var LobsteraiAdapter = class extends LlmAdapter3 {
|
|
|
36490
36578
|
*/
|
|
36491
36579
|
async ensureRemoteModels() {
|
|
36492
36580
|
const fetchRemote = this.options.fetchRemoteModels;
|
|
36493
|
-
if (
|
|
36581
|
+
if (fetchRemote === void 0 || !remoteModelsStale(this)) return;
|
|
36494
36582
|
await this.catalogGate.run(async () => {
|
|
36495
36583
|
const models = await fetchRemote();
|
|
36496
36584
|
if (models.length === 0) return false;
|
|
@@ -40216,7 +40304,7 @@ var TraeAdapter = class extends LlmAdapter5 {
|
|
|
40216
40304
|
/** 懒加载远端模型目录(仅拉取一次)。 */
|
|
40217
40305
|
async ensureRemoteModels() {
|
|
40218
40306
|
const fetchRemote = this.options.fetchRemoteModels;
|
|
40219
|
-
if (
|
|
40307
|
+
if (fetchRemote === void 0 || !remoteModelsStale(this)) return;
|
|
40220
40308
|
await this.catalogGate.run(async () => {
|
|
40221
40309
|
const models = await fetchRemote();
|
|
40222
40310
|
if (models.length === 0) return false;
|
|
@@ -41718,7 +41806,7 @@ var ClineAdapter = class extends LlmAdapter6 {
|
|
|
41718
41806
|
* 不去重会打出多份重复的远端请求(两个端点各一次,乘以并发数)。
|
|
41719
41807
|
*/
|
|
41720
41808
|
async ensureRemoteModels() {
|
|
41721
|
-
if (this
|
|
41809
|
+
if (!remoteModelsStale(this)) return;
|
|
41722
41810
|
await this.catalogGate.run(async () => {
|
|
41723
41811
|
try {
|
|
41724
41812
|
const credential = await this.options.resolveCredential();
|
|
@@ -42385,7 +42473,7 @@ var LoomyAdapter = class extends LlmAdapter7 {
|
|
|
42385
42473
|
* 并用 {@link RemoteCatalogGate} 的冷却挡住「每模型重试一次」的放大。
|
|
42386
42474
|
*/
|
|
42387
42475
|
async loadModels() {
|
|
42388
|
-
if (this
|
|
42476
|
+
if (!remoteModelsStale(this)) return this.remoteModels;
|
|
42389
42477
|
const fetchRemote = this.options.fetchRemoteModels;
|
|
42390
42478
|
if (fetchRemote !== void 0) {
|
|
42391
42479
|
await this.catalogGate.run(async () => {
|
|
@@ -42841,7 +42929,7 @@ var RaccoonAdapter = class extends LlmAdapter8 {
|
|
|
42841
42929
|
* 并用 {@link RemoteCatalogGate} 的冷却挡住「每模型重试一次」的放大。
|
|
42842
42930
|
*/
|
|
42843
42931
|
async loadModels() {
|
|
42844
|
-
if (this
|
|
42932
|
+
if (!remoteModelsStale(this)) return this.remoteModels;
|
|
42845
42933
|
const fetchRemote = this.options.fetchRemoteModels;
|
|
42846
42934
|
if (fetchRemote !== void 0) {
|
|
42847
42935
|
await this.catalogGate.run(async () => {
|
|
@@ -54580,7 +54668,7 @@ var ZcodeAdapter = class extends LlmAdapter9 {
|
|
|
54580
54668
|
* 并用 {@link RemoteCatalogGate} 的冷却挡住「每模型重试一次」的放大。
|
|
54581
54669
|
*/
|
|
54582
54670
|
async loadModels() {
|
|
54583
|
-
if (this
|
|
54671
|
+
if (!remoteModelsStale(this)) return this.remoteModels;
|
|
54584
54672
|
const fetchRemote = this.options.fetchRemoteModels;
|
|
54585
54673
|
if (fetchRemote !== void 0) {
|
|
54586
54674
|
await this.catalogGate.run(async () => {
|
|
@@ -66156,7 +66244,7 @@ var MinimaxAdapter = class extends LlmAdapter11 {
|
|
|
66156
66244
|
* 并用 {@link RemoteCatalogGate} 的冷却挡住「每模型重试一次」的放大。
|
|
66157
66245
|
*/
|
|
66158
66246
|
async loadModels() {
|
|
66159
|
-
if (this
|
|
66247
|
+
if (!remoteModelsStale(this)) return this.remoteModels;
|
|
66160
66248
|
const fetchRemote = this.options.fetchRemoteModels;
|
|
66161
66249
|
if (fetchRemote !== void 0) {
|
|
66162
66250
|
await this.catalogGate.run(async () => {
|