dsh-llm-adapters 1.2.1 → 1.2.2
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/DEVELOPMENT.md +66 -15
- package/FAQ.md +39 -8
- package/README.md +11 -10
- package/client.js +1802 -1822
- package/lib/index.js +181 -205
- package/lib/types/account-store.d.ts +10 -3
- package/lib/types/auth.d.ts +7 -0
- package/lib/types/codearts-oauth.d.ts +19 -0
- package/lib/types/codearts.d.ts +1 -5
- package/lib/types/config.d.ts +0 -5
- package/lib/types/index.d.ts +1 -4
- package/lib/types/raccoon.d.ts +79 -6
- package/package.json +1 -1
- package/src/account-store.ts +11 -3
- package/src/auth.ts +15 -1
- package/src/codearts-oauth.ts +36 -5
- package/src/codearts.ts +24 -29
- package/src/config.ts +258 -264
- package/src/index.ts +1 -26
- package/src/raccoon.ts +163 -50
- package/lib/types/codearts-window.d.ts +0 -65
- package/src/codearts-window.ts +0 -136
package/lib/index.js
CHANGED
|
@@ -788,6 +788,7 @@ function codeartsRecord(value) {
|
|
|
788
788
|
...text$5(raw.codeVerifier) === void 0 ? {} : { codeVerifier: text$5(raw.codeVerifier) },
|
|
789
789
|
...key === void 0 ? {} : { dpopPrivateJwk: key },
|
|
790
790
|
...text$5(raw.userName) === void 0 ? {} : { userName: text$5(raw.userName) },
|
|
791
|
+
...text$5(raw.otSessionId) === void 0 ? {} : { otSessionId: text$5(raw.otSessionId) },
|
|
791
792
|
...noBenefit.length === 0 ? {} : { noBenefit }
|
|
792
793
|
};
|
|
793
794
|
}
|
|
@@ -1425,6 +1426,18 @@ function readUserProfile(token) {
|
|
|
1425
1426
|
...domainId === void 0 ? {} : { domainId }
|
|
1426
1427
|
};
|
|
1427
1428
|
}
|
|
1429
|
+
/**
|
|
1430
|
+
* The session id this account should chat under, derived from who the account is.
|
|
1431
|
+
*
|
|
1432
|
+
* 32 lowercase hex, the shape the IDE's own kernel sends. Nothing but stability
|
|
1433
|
+
* matters here — the gateway uses the value as a key, not as an identity — so it
|
|
1434
|
+
* is hashed from the principal id rather than kept in a file.
|
|
1435
|
+
*/
|
|
1436
|
+
function otSessionIdOf(profile) {
|
|
1437
|
+
const seed = profile?.userId ?? profile?.userName;
|
|
1438
|
+
if (seed === void 0) return void 0;
|
|
1439
|
+
return createHash("sha256").update(`codearts-ot-session:${seed}`).digest("hex").slice(0, 32);
|
|
1440
|
+
}
|
|
1428
1441
|
/** The portal URL the browser opens; the callback is on loopback. */
|
|
1429
1442
|
function buildAuthorizeUrl(port, pkce, ticketId) {
|
|
1430
1443
|
return `${CODEARTS_PORTAL_AUTHORIZE}?theme=2&locale=zh-cn&uri_scheme=${CODEARTS_CLIENT_ID}&client_id=${CODEARTS_CLIENT_ID}&port=${port}&code_challenge=${pkce.codeChallenge}&code_challenge_method=SHA-256&ticket_id=${ticketId}&plugin-name=snap_AIIDE&plugin-version=5.2.0`;
|
|
@@ -1475,25 +1488,30 @@ async function exchangeRefreshToken(refreshToken, codeVerifier, keyPair, fetcher
|
|
|
1475
1488
|
grant_type: "refresh_token",
|
|
1476
1489
|
refresh_token: refreshToken
|
|
1477
1490
|
}, keyPair, fetcher), codeVerifier, keyPair);
|
|
1478
|
-
const
|
|
1491
|
+
const previous = readUserProfile(refreshToken);
|
|
1492
|
+
const userName = credential.userName ?? previous?.userName;
|
|
1493
|
+
const otSessionId = credential.otSessionId ?? otSessionIdOf(previous);
|
|
1479
1494
|
return {
|
|
1480
1495
|
...credential,
|
|
1481
1496
|
refreshToken: credential.refreshToken ?? refreshToken,
|
|
1482
|
-
...userName === void 0 ? {} : { userName }
|
|
1497
|
+
...userName === void 0 ? {} : { userName },
|
|
1498
|
+
...otSessionId === void 0 ? {} : { otSessionId }
|
|
1483
1499
|
};
|
|
1484
1500
|
}
|
|
1485
1501
|
function credentialFrom(token, codeVerifier, keyPair) {
|
|
1486
1502
|
const credentials = token.credentials ?? {};
|
|
1487
1503
|
const expiration = credentials.expiration;
|
|
1488
1504
|
const expiresAt = expiration === void 0 ? void 0 : Date.parse(expiration);
|
|
1489
|
-
const
|
|
1505
|
+
const profile = readUserProfile(token.refresh_token);
|
|
1506
|
+
const otSessionId = otSessionIdOf(profile);
|
|
1490
1507
|
return {
|
|
1491
1508
|
accessKeyId: credentials.access_key_id ?? "",
|
|
1492
1509
|
secretAccessKey: credentials.secret_access_key ?? "",
|
|
1493
1510
|
securityToken: credentials.security_token ?? "",
|
|
1494
1511
|
...expiresAt === void 0 || Number.isNaN(expiresAt) ? {} : { expiresAt },
|
|
1495
1512
|
...token.refresh_token === void 0 ? {} : { refreshToken: token.refresh_token },
|
|
1496
|
-
...userName === void 0 ? {} : { userName },
|
|
1513
|
+
...profile?.userName === void 0 ? {} : { userName: profile.userName },
|
|
1514
|
+
...otSessionId === void 0 ? {} : { otSessionId },
|
|
1497
1515
|
codeVerifier,
|
|
1498
1516
|
dpopPrivateJwk: keyPair.privateKeyJwk
|
|
1499
1517
|
};
|
|
@@ -2224,7 +2242,8 @@ function decodeJwtFacts(token) {
|
|
|
2224
2242
|
...typeof record.name === "string" ? { name: record.name } : {},
|
|
2225
2243
|
...typeof record.phone === "string" ? { phone: record.phone } : {},
|
|
2226
2244
|
...typeof record.owner_type === "string" ? { ownerType: record.owner_type } : {},
|
|
2227
|
-
...typeof record.sid === "string" ? { sessionId: record.sid } : {}
|
|
2245
|
+
...typeof record.sid === "string" ? { sessionId: record.sid } : {},
|
|
2246
|
+
...typeof record.sub === "string" ? { subject: record.sub } : {}
|
|
2228
2247
|
};
|
|
2229
2248
|
} catch {
|
|
2230
2249
|
return {};
|
|
@@ -2557,7 +2576,8 @@ var CodeArtsAuth = class {
|
|
|
2557
2576
|
securityToken: next.securityToken,
|
|
2558
2577
|
...next.expiresAt === void 0 ? {} : { expiresAt: next.expiresAt },
|
|
2559
2578
|
...next.refreshToken === void 0 ? {} : { refreshToken: next.refreshToken },
|
|
2560
|
-
...next.userName === void 0 ? {} : { userName: next.userName }
|
|
2579
|
+
...next.userName === void 0 ? {} : { userName: next.userName },
|
|
2580
|
+
...next.otSessionId === void 0 ? {} : { otSessionId: next.otSessionId }
|
|
2561
2581
|
});
|
|
2562
2582
|
this.lastError = void 0;
|
|
2563
2583
|
return next;
|
|
@@ -2577,6 +2597,7 @@ var CodeArtsAuth = class {
|
|
|
2577
2597
|
}
|
|
2578
2598
|
};
|
|
2579
2599
|
function credentialOf(record) {
|
|
2600
|
+
const otSessionId = record.otSessionId ?? otSessionIdOf(readUserProfile(record.refreshToken));
|
|
2580
2601
|
return {
|
|
2581
2602
|
accessKeyId: record.accessKeyId,
|
|
2582
2603
|
secretAccessKey: record.secretAccessKey,
|
|
@@ -2584,7 +2605,8 @@ function credentialOf(record) {
|
|
|
2584
2605
|
...record.expiresAt === void 0 ? {} : { expiresAt: record.expiresAt },
|
|
2585
2606
|
...record.refreshToken === void 0 ? {} : { refreshToken: record.refreshToken },
|
|
2586
2607
|
...record.codeVerifier === void 0 ? {} : { codeVerifier: record.codeVerifier },
|
|
2587
|
-
...record.dpopPrivateJwk === void 0 ? {} : { dpopPrivateJwk: record.dpopPrivateJwk }
|
|
2608
|
+
...record.dpopPrivateJwk === void 0 ? {} : { dpopPrivateJwk: record.dpopPrivateJwk },
|
|
2609
|
+
...otSessionId === void 0 ? {} : { otSessionId }
|
|
2588
2610
|
};
|
|
2589
2611
|
}
|
|
2590
2612
|
// src/config.ts
|
|
@@ -2631,8 +2653,7 @@ const Config$1 = z.object({
|
|
|
2631
2653
|
defaultMaxTokens: z.number().step(1).min(1).default(32e3).description("模型目录未声明输出上限时使用的输出上限。").volatile(),
|
|
2632
2654
|
modelCacheTtlSeconds: z.number().step(1).min(10).max(86400).default(120).description("模型列表缓存时长(秒)。调小可更快看到账号侧变化。").volatile(),
|
|
2633
2655
|
catalogFetchTimeoutSeconds: z.number().step(1).min(1).max(300).default(20).description("读取模型目录、额度等请求的时限(秒)。").volatile(),
|
|
2634
|
-
openRouterSyncMinutes: z.number().step(1).min(0).max(43200).default(60).description("OpenRouter 模型元数据的自动同步间隔(分钟)。0 表示关闭自动同步;缓存保存在本机,连不上时继续使用上次成功同步的数据。").volatile()
|
|
2635
|
-
raccoonCheckinMinutes: z.number().step(1).min(0).max(1440).default(30).description("小浣熊每日积分自动监测间隔(分钟):到点核对积分流水,未到账时按网页方式尝试触发。0 表示关闭自动监测;「打开网页签到」入口始终保留。").volatile()
|
|
2656
|
+
openRouterSyncMinutes: z.number().step(1).min(0).max(43200).default(60).description("OpenRouter 模型元数据的自动同步间隔(分钟)。0 表示关闭自动同步;缓存保存在本机,连不上时继续使用上次成功同步的数据。").volatile()
|
|
2636
2657
|
});
|
|
2637
2658
|
function liveConfig(config) {
|
|
2638
2659
|
const source = config ?? {};
|
|
@@ -2673,8 +2694,7 @@ function liveConfig(config) {
|
|
|
2673
2694
|
defaultMaxTokens: () => positive(field("defaultMaxTokens"), 32e3),
|
|
2674
2695
|
modelCacheTtlMs: () => positive(field("modelCacheTtlSeconds"), 120) * 1e3,
|
|
2675
2696
|
catalogFetchTimeoutMs: () => positive(field("catalogFetchTimeoutSeconds"), 20) * 1e3,
|
|
2676
|
-
openRouterSyncMinutes: () => nonNegative(field("openRouterSyncMinutes"), 60)
|
|
2677
|
-
raccoonCheckinMinutes: () => nonNegative(field("raccoonCheckinMinutes"), 30)
|
|
2697
|
+
openRouterSyncMinutes: () => nonNegative(field("openRouterSyncMinutes"), 60)
|
|
2678
2698
|
};
|
|
2679
2699
|
}
|
|
2680
2700
|
function resolveConfig(config) {
|
|
@@ -2712,8 +2732,7 @@ function resolveConfig(config) {
|
|
|
2712
2732
|
defaultMaxTokens: live.defaultMaxTokens(),
|
|
2713
2733
|
modelCacheTtlMs: live.modelCacheTtlMs(),
|
|
2714
2734
|
catalogFetchTimeoutMs: live.catalogFetchTimeoutMs(),
|
|
2715
|
-
openRouterSyncMinutes: live.openRouterSyncMinutes()
|
|
2716
|
-
raccoonCheckinMinutes: live.raccoonCheckinMinutes()
|
|
2735
|
+
openRouterSyncMinutes: live.openRouterSyncMinutes()
|
|
2717
2736
|
};
|
|
2718
2737
|
}
|
|
2719
2738
|
function text$4(value) {
|
|
@@ -3056,117 +3075,6 @@ function headersForFetch(signed) {
|
|
|
3056
3075
|
}
|
|
3057
3076
|
return out;
|
|
3058
3077
|
}
|
|
3059
|
-
// src/codearts-window.ts
|
|
3060
|
-
/**
|
|
3061
|
-
* The trial plan's chat budget.
|
|
3062
|
-
*
|
|
3063
|
-
* The gateway opens one "session" per chat request and allows **three per
|
|
3064
|
-
* rolling minute** for the whole account. The window is shared by every model,
|
|
3065
|
-
* it is not keyed by `session-id` (re-sending the same id does not buy a slot),
|
|
3066
|
-
* and a request rejected with `InferHub.4004.200` spends a slot just like a
|
|
3067
|
-
* successful one. Measured behaviour, three slots then a lockout:
|
|
3068
|
-
*
|
|
3069
|
-
* ```
|
|
3070
|
-
* t+0s ok ok ok cap cap cap burst of six
|
|
3071
|
-
* t+10s cap …
|
|
3072
|
-
* t+51s cap
|
|
3073
|
-
* t+61s ok ok ok the burst ages out of the window
|
|
3074
|
-
* ```
|
|
3075
|
-
*
|
|
3076
|
-
* So a turn cannot be made to "go faster" by retrying: the only way a request
|
|
3077
|
-
* stops failing is to spend the budget deliberately — wait for the oldest start
|
|
3078
|
-
* to age out instead of firing into a wall. This class owns that bookkeeping and
|
|
3079
|
-
* is shared by every provider instance in the process, because a hot reload
|
|
3080
|
-
* must not reset the count the gateway still remembers.
|
|
3081
|
-
*
|
|
3082
|
-
* @module dsh-llm-adapters/codearts-window
|
|
3083
|
-
*/
|
|
3084
|
-
/** Sessions the trial plan allows inside one window. */
|
|
3085
|
-
const CODEARTS_SESSION_LIMIT = 3;
|
|
3086
|
-
/** How long a start keeps its slot. Measured: the burst frees at ~60 s. */
|
|
3087
|
-
const CODEARTS_SESSION_WINDOW_MS = 6e4;
|
|
3088
|
-
/** A little slack so a request never lands a few milliseconds early. */
|
|
3089
|
-
const MARGIN_MS = 1500;
|
|
3090
|
-
function sleep$2(ms, signal) {
|
|
3091
|
-
return new Promise((resolve, reject) => {
|
|
3092
|
-
if (signal?.aborted === true) {
|
|
3093
|
-
reject(signal.reason instanceof Error ? signal.reason : /* @__PURE__ */ new Error("aborted"));
|
|
3094
|
-
return;
|
|
3095
|
-
}
|
|
3096
|
-
const onAbort = () => {
|
|
3097
|
-
clearTimeout(timer);
|
|
3098
|
-
reject(signal?.reason instanceof Error ? signal.reason : /* @__PURE__ */ new Error("aborted"));
|
|
3099
|
-
};
|
|
3100
|
-
const timer = setTimeout(() => {
|
|
3101
|
-
signal?.removeEventListener("abort", onAbort);
|
|
3102
|
-
resolve();
|
|
3103
|
-
}, ms);
|
|
3104
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
3105
|
-
});
|
|
3106
|
-
}
|
|
3107
|
-
var CodeArtsSessionWindow = class {
|
|
3108
|
-
limit;
|
|
3109
|
-
windowMs;
|
|
3110
|
-
now;
|
|
3111
|
-
starts = [];
|
|
3112
|
-
/** Serialises waiters so two callers cannot both take the last slot. */
|
|
3113
|
-
tail = Promise.resolve();
|
|
3114
|
-
constructor(limit = 3, windowMs = CODEARTS_SESSION_WINDOW_MS, now = Date.now) {
|
|
3115
|
-
this.limit = limit;
|
|
3116
|
-
this.windowMs = windowMs;
|
|
3117
|
-
this.now = now;
|
|
3118
|
-
}
|
|
3119
|
-
/** Starts recorded inside the current window. */
|
|
3120
|
-
get size() {
|
|
3121
|
-
this.trim();
|
|
3122
|
-
return this.starts.length;
|
|
3123
|
-
}
|
|
3124
|
-
/** Milliseconds until another start fits; `0` when the window has room. */
|
|
3125
|
-
waitMs() {
|
|
3126
|
-
this.trim();
|
|
3127
|
-
if (this.starts.length < this.limit) return 0;
|
|
3128
|
-
const oldest = this.starts[0] ?? 0;
|
|
3129
|
-
return Math.max(0, this.windowMs - (this.now() - oldest));
|
|
3130
|
-
}
|
|
3131
|
-
/**
|
|
3132
|
-
* Claim a slot, waiting for the window to roll over when it is full.
|
|
3133
|
-
*
|
|
3134
|
-
* The slot is recorded on return, not on completion: the gateway counts the
|
|
3135
|
-
* start, and holds it for a fixed time whether the answer was short or long.
|
|
3136
|
-
*/
|
|
3137
|
-
async open(signal) {
|
|
3138
|
-
const run = this.tail.then(async () => {
|
|
3139
|
-
for (;;) {
|
|
3140
|
-
const wait = this.waitMs();
|
|
3141
|
-
if (wait === 0) {
|
|
3142
|
-
const start = this.now();
|
|
3143
|
-
this.starts.push(start);
|
|
3144
|
-
return { release: () => {
|
|
3145
|
-
const index = this.starts.indexOf(start);
|
|
3146
|
-
if (index >= 0) this.starts.splice(index, 1);
|
|
3147
|
-
} };
|
|
3148
|
-
}
|
|
3149
|
-
await sleep$2(wait + MARGIN_MS, signal);
|
|
3150
|
-
}
|
|
3151
|
-
});
|
|
3152
|
-
this.tail = run.then(() => void 0, () => void 0);
|
|
3153
|
-
return await run;
|
|
3154
|
-
}
|
|
3155
|
-
/** Forget every start (tests, and a fresh login on another account). */
|
|
3156
|
-
reset() {
|
|
3157
|
-
this.starts.length = 0;
|
|
3158
|
-
}
|
|
3159
|
-
trim() {
|
|
3160
|
-
const now = this.now();
|
|
3161
|
-
while (this.starts.length > 0 && now - (this.starts[0] ?? 0) >= this.windowMs) this.starts.shift();
|
|
3162
|
-
}
|
|
3163
|
-
};
|
|
3164
|
-
let shared;
|
|
3165
|
-
/** The process-wide window; a plugin reload reuses it on purpose. */
|
|
3166
|
-
function sharedSessionWindow() {
|
|
3167
|
-
shared ??= new CodeArtsSessionWindow();
|
|
3168
|
-
return shared;
|
|
3169
|
-
}
|
|
3170
3078
|
// src/openrouter.ts
|
|
3171
3079
|
/**
|
|
3172
3080
|
* Live capability lookup from OpenRouter's public model catalog.
|
|
@@ -3692,18 +3600,20 @@ const sleep$1 = (ms, signal) => new Promise((resolve, reject) => {
|
|
|
3692
3600
|
}, ms);
|
|
3693
3601
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
3694
3602
|
});
|
|
3695
|
-
/** Retries for a gateway that is busy for reasons the
|
|
3603
|
+
/** Retries for a gateway that is busy for reasons the caller cannot predict. */
|
|
3696
3604
|
const QUEUE_ATTEMPTS = 3;
|
|
3697
|
-
/**
|
|
3605
|
+
/** Pause before retrying a rejected call. */
|
|
3698
3606
|
const QUEUE_BACKOFF_MS = 2e4;
|
|
3699
3607
|
/**
|
|
3700
3608
|
* The message a user sees once waiting is hopeless.
|
|
3701
3609
|
*
|
|
3702
|
-
* The raw gateway text (`TM.00001041`) reads like a bug
|
|
3703
|
-
* trial plan's, and
|
|
3610
|
+
* The raw gateway text (`TM.00001041`) reads like a bug. The three concurrent
|
|
3611
|
+
* sessions are the trial plan's, and one plugin chatting under a single session
|
|
3612
|
+
* id is not meant to reach them: the slots are being held by something else on
|
|
3613
|
+
* the same account.
|
|
3704
3614
|
*/
|
|
3705
3615
|
function queueExhausted() {
|
|
3706
|
-
return new ProviderHttpError("CodeArts
|
|
3616
|
+
return new ProviderHttpError("CodeArts 这个账号的 3 个并发会话已被占满(通常是码道 IDE 或另一台设备),请稍后再发,或关闭其它 CodeArts 会话。", 429);
|
|
3707
3617
|
}
|
|
3708
3618
|
/** Image transcripts live beside accounts.json, so a restart does not re-bill. */
|
|
3709
3619
|
const IMAGE_CACHE_FILE = "codearts-image-cache.json";
|
|
@@ -3736,7 +3646,6 @@ var CodeArtsProvider = class {
|
|
|
3736
3646
|
/** Models that answered `InferHub.4004.200`: no allowance pack to bill. */
|
|
3737
3647
|
noBenefit = /* @__PURE__ */ new Set();
|
|
3738
3648
|
noBenefitLoaded = false;
|
|
3739
|
-
window;
|
|
3740
3649
|
openRouter;
|
|
3741
3650
|
sessionId = randomUUID();
|
|
3742
3651
|
/**
|
|
@@ -3751,7 +3660,6 @@ var CodeArtsProvider = class {
|
|
|
3751
3660
|
imageCacheWrite = Promise.resolve();
|
|
3752
3661
|
constructor(options) {
|
|
3753
3662
|
this.options = options;
|
|
3754
|
-
this.window = options.window ?? sharedSessionWindow();
|
|
3755
3663
|
this.openRouter = options.openRouter ?? new OpenRouterCatalog(options.fetchImpl ?? fetch);
|
|
3756
3664
|
this.catalog = new ModelCatalog(() => this.loadModels(), options.ttlMs);
|
|
3757
3665
|
this.login = new CodeArtsLogin({
|
|
@@ -3760,7 +3668,6 @@ var CodeArtsProvider = class {
|
|
|
3760
3668
|
...options.logger === void 0 ? {} : { logger: options.logger },
|
|
3761
3669
|
save: async (account) => {
|
|
3762
3670
|
await options.store.saveCodearts(account);
|
|
3763
|
-
this.window.reset();
|
|
3764
3671
|
this.noBenefit.clear();
|
|
3765
3672
|
this.invalidateModels();
|
|
3766
3673
|
this.invalidateQuota();
|
|
@@ -4089,7 +3996,7 @@ var CodeArtsProvider = class {
|
|
|
4089
3996
|
}
|
|
4090
3997
|
}
|
|
4091
3998
|
}
|
|
4092
|
-
/** Ask the vision model to describe one image
|
|
3999
|
+
/** Ask the vision model to describe one image; another turn on the same session. */
|
|
4093
4000
|
async describeImage(dataUrl, signal) {
|
|
4094
4001
|
const payload = JSON.stringify({
|
|
4095
4002
|
model: CODEARTS_VISION_MODEL,
|
|
@@ -4110,7 +4017,6 @@ var CodeArtsProvider = class {
|
|
|
4110
4017
|
let authRefreshed = false;
|
|
4111
4018
|
let queueAttempts = 0;
|
|
4112
4019
|
for (;;) {
|
|
4113
|
-
const slot = await this.window.open(signal);
|
|
4114
4020
|
let response;
|
|
4115
4021
|
try {
|
|
4116
4022
|
response = await this.send(chatId, payload, CODEARTS_VISION_MODEL, false, signal);
|
|
@@ -4121,10 +4027,9 @@ var CodeArtsProvider = class {
|
|
|
4121
4027
|
continue;
|
|
4122
4028
|
}
|
|
4123
4029
|
if (error instanceof CodeArtsRetry && error.kind === "queue") {
|
|
4124
|
-
slot.release();
|
|
4125
4030
|
if (queueAttempts < QUEUE_ATTEMPTS) {
|
|
4126
4031
|
queueAttempts++;
|
|
4127
|
-
await sleep$1(
|
|
4032
|
+
await sleep$1(QUEUE_BACKOFF_MS, signal);
|
|
4128
4033
|
continue;
|
|
4129
4034
|
}
|
|
4130
4035
|
throw queueExhausted();
|
|
@@ -4145,10 +4050,9 @@ var CodeArtsProvider = class {
|
|
|
4145
4050
|
})) if (chunk.type === "text-delta") transcript += chunk.text;
|
|
4146
4051
|
} catch (error) {
|
|
4147
4052
|
if (error instanceof CodeArtsRetry && error.kind === "queue") {
|
|
4148
|
-
slot.release();
|
|
4149
4053
|
if (queueAttempts < QUEUE_ATTEMPTS) {
|
|
4150
4054
|
queueAttempts++;
|
|
4151
|
-
await sleep$1(
|
|
4055
|
+
await sleep$1(QUEUE_BACKOFF_MS, signal);
|
|
4152
4056
|
continue;
|
|
4153
4057
|
}
|
|
4154
4058
|
throw queueExhausted();
|
|
@@ -4187,7 +4091,6 @@ var CodeArtsProvider = class {
|
|
|
4187
4091
|
let benefitDropped = false;
|
|
4188
4092
|
let queueAttempts = 0;
|
|
4189
4093
|
for (;;) {
|
|
4190
|
-
const slot = await this.window.open(options.signal);
|
|
4191
4094
|
let response;
|
|
4192
4095
|
try {
|
|
4193
4096
|
response = await this.send(chatId, payload, model, benefitDropped, options.signal);
|
|
@@ -4210,8 +4113,7 @@ var CodeArtsProvider = class {
|
|
|
4210
4113
|
}
|
|
4211
4114
|
if (error.kind === "queue" && queueAttempts < QUEUE_ATTEMPTS) {
|
|
4212
4115
|
queueAttempts++;
|
|
4213
|
-
|
|
4214
|
-
await sleep$1(Math.max(this.window.waitMs(), QUEUE_BACKOFF_MS), options.signal);
|
|
4116
|
+
await sleep$1(QUEUE_BACKOFF_MS, options.signal);
|
|
4215
4117
|
continue;
|
|
4216
4118
|
}
|
|
4217
4119
|
if (error.kind === "queue") throw queueExhausted();
|
|
@@ -4238,8 +4140,7 @@ var CodeArtsProvider = class {
|
|
|
4238
4140
|
} catch (error) {
|
|
4239
4141
|
if (!produced && error instanceof CodeArtsRetry && error.kind === "queue" && queueAttempts < QUEUE_ATTEMPTS) {
|
|
4240
4142
|
queueAttempts++;
|
|
4241
|
-
|
|
4242
|
-
await sleep$1(Math.max(this.window.waitMs(), QUEUE_BACKOFF_MS), options.signal);
|
|
4143
|
+
await sleep$1(QUEUE_BACKOFF_MS, options.signal);
|
|
4243
4144
|
continue;
|
|
4244
4145
|
}
|
|
4245
4146
|
if (error instanceof CodeArtsRetry && error.kind === "queue") throw queueExhausted();
|
|
@@ -4259,13 +4160,17 @@ var CodeArtsProvider = class {
|
|
|
4259
4160
|
async send(chatId, payload, model, benefitDropped, signal) {
|
|
4260
4161
|
const credential = await this.credential();
|
|
4261
4162
|
const benefit = !benefitDropped && this.isBenefitModel(model);
|
|
4163
|
+
const otSessionId = credential.otSessionId ?? this.sessionId.replace(/-/g, "");
|
|
4262
4164
|
const headers = {
|
|
4263
4165
|
...headersForFetch(await signRequestHuawei(credential.accessKeyId, credential.secretAccessKey, credential.securityToken, "POST", CODEARTS_CHAT_URL, payload, benefit ? { maas_type: "benefit" } : void 0)),
|
|
4264
4166
|
"content-type": "application/json",
|
|
4265
4167
|
accept: "text/event-stream",
|
|
4266
4168
|
"chat-id": chatId,
|
|
4267
4169
|
"session-id": this.sessionId,
|
|
4268
|
-
lang: "en"
|
|
4170
|
+
lang: "en",
|
|
4171
|
+
"x-ot-session-id": otSessionId,
|
|
4172
|
+
"user-session-id": otSessionId,
|
|
4173
|
+
"x-ot-trace-id": randomUUID().replace(/-/g, "")
|
|
4269
4174
|
};
|
|
4270
4175
|
const timeout = AbortSignal.timeout(Math.max(this.options.timeoutMs(), 6e4));
|
|
4271
4176
|
const response = await this.fetcher(CODEARTS_CHAT_URL, {
|
|
@@ -4295,7 +4200,6 @@ var CodeArtsProvider = class {
|
|
|
4295
4200
|
}
|
|
4296
4201
|
async logoutAccount() {
|
|
4297
4202
|
await this.options.auth.logout();
|
|
4298
|
-
this.window.reset();
|
|
4299
4203
|
this.invalidateModels();
|
|
4300
4204
|
this.invalidateQuota();
|
|
4301
4205
|
}
|
|
@@ -6359,6 +6263,100 @@ function raccoonHeaders(token) {
|
|
|
6359
6263
|
"x-client-version": RACCOON_CLIENT_VERSION
|
|
6360
6264
|
};
|
|
6361
6265
|
}
|
|
6266
|
+
/** Wording the gateway has used alongside that code. */
|
|
6267
|
+
const RATE_LIMIT_WORDS = [
|
|
6268
|
+
"user_model_rate_limited",
|
|
6269
|
+
"rate_limit",
|
|
6270
|
+
"频率超限"
|
|
6271
|
+
];
|
|
6272
|
+
/**
|
|
6273
|
+
* Whether a rejection is the token wall rather than a generic failure.
|
|
6274
|
+
*
|
|
6275
|
+
* Matched on the status, the code and the wording, because the same condition
|
|
6276
|
+
* arrives as an HTTP 429 and as an error frame inside a 200 stream.
|
|
6277
|
+
*/
|
|
6278
|
+
function isRaccoonRateLimited(status, text) {
|
|
6279
|
+
if (status === 429) return true;
|
|
6280
|
+
const lower = text.toLowerCase();
|
|
6281
|
+
return RATE_LIMIT_WORDS.some((word) => lower.includes(word.toLowerCase()));
|
|
6282
|
+
}
|
|
6283
|
+
/**
|
|
6284
|
+
* The wall, as an error the caller can tell apart from a generic 429.
|
|
6285
|
+
*
|
|
6286
|
+
* A subclass rather than a flag: the in-band path and the HTTP path would
|
|
6287
|
+
* otherwise both be caught by the same handler, and the second pass would wrap
|
|
6288
|
+
* the message the first pass had already rewritten.
|
|
6289
|
+
*/
|
|
6290
|
+
var RaccoonRateLimitedError = class extends ProviderHttpError {
|
|
6291
|
+
constructor(message) {
|
|
6292
|
+
super(message, 429);
|
|
6293
|
+
this.name = "RaccoonRateLimitedError";
|
|
6294
|
+
}
|
|
6295
|
+
};
|
|
6296
|
+
/**
|
|
6297
|
+
* The message a user sees once the wall is hit.
|
|
6298
|
+
*
|
|
6299
|
+
* The raw text says "retry later" and gives no reason, which is why this reads
|
|
6300
|
+
* as the plugin being broken. The honest answer names the cause and the one
|
|
6301
|
+
* lever the user actually has on this side.
|
|
6302
|
+
*/
|
|
6303
|
+
function raccoonRateLimited(detail) {
|
|
6304
|
+
return new RaccoonRateLimitedError(`小浣熊账号的模型吞吐已达上限(不是每分钟请求数,而是按账号的 token 速率)。一轮对话带的上下文越大越快撞到,撞到后额度按吞吐缓慢回血,上游也没有给恢复时间。稍等一会儿再发;把该模型的上下文窗口调小,同一会话能撑得更久。上游原文:${detail}`);
|
|
6305
|
+
}
|
|
6306
|
+
/** The `error` object a compatible gateway puts in an SSE frame. */
|
|
6307
|
+
function frameFailure(frame) {
|
|
6308
|
+
const error = frame.error;
|
|
6309
|
+
if (error === void 0) return void 0;
|
|
6310
|
+
if (typeof error === "string") return { message: error };
|
|
6311
|
+
if (error === null || typeof error !== "object") return void 0;
|
|
6312
|
+
const record = error;
|
|
6313
|
+
const code = typeof record.code === "string" ? record.code : void 0;
|
|
6314
|
+
const message = typeof record.message === "string" ? record.message : void 0;
|
|
6315
|
+
return {
|
|
6316
|
+
...code === void 0 ? {} : { code },
|
|
6317
|
+
...message === void 0 ? {} : { message }
|
|
6318
|
+
};
|
|
6319
|
+
}
|
|
6320
|
+
/**
|
|
6321
|
+
* One conversation's session id, stable across the turns of that conversation.
|
|
6322
|
+
*
|
|
6323
|
+
* The official client never opens a session per request — measured on its own
|
|
6324
|
+
* logs, 125 calls over 26 minutes all carried one `sess-0-53927d74` — while an
|
|
6325
|
+
* implementation that mints a fresh id per request tells the gateway that one
|
|
6326
|
+
* account opened hundreds of sessions within minutes.
|
|
6327
|
+
*
|
|
6328
|
+
* The id is a pure function of (account, model) rather than a random value, so a
|
|
6329
|
+
* restarted or hot-reloaded process continues the same conversation instead of
|
|
6330
|
+
* presenting a new session, and two models stay two conversations. The principal
|
|
6331
|
+
* itself never leaves the process — only a truncated digest of it does.
|
|
6332
|
+
*/
|
|
6333
|
+
var RaccoonSessionIds = class {
|
|
6334
|
+
principal;
|
|
6335
|
+
/**
|
|
6336
|
+
* @param principal - a value that is stable for one account and identifies it
|
|
6337
|
+
* without being the token itself (the JWT's `sub`).
|
|
6338
|
+
*/
|
|
6339
|
+
constructor(principal) {
|
|
6340
|
+
this.principal = principal;
|
|
6341
|
+
}
|
|
6342
|
+
async for(model) {
|
|
6343
|
+
const principal = await this.principal();
|
|
6344
|
+
if (principal === void 0) return void 0;
|
|
6345
|
+
return raccoonSessionId(principal, model);
|
|
6346
|
+
}
|
|
6347
|
+
};
|
|
6348
|
+
/**
|
|
6349
|
+
* `sess-<sequence>-<8 hex>`, the shape the official client sends.
|
|
6350
|
+
*
|
|
6351
|
+
* The sequence is the official client's process-local counter and is pinned to 0
|
|
6352
|
+
* here on purpose: an incrementing value would make one conversation look like a
|
|
6353
|
+
* different session after a restart, which is the one thing this id exists to
|
|
6354
|
+
* prevent. Identity lives in the digest, which is truncated on purpose — the id
|
|
6355
|
+
* must separate accounts without naming them on the wire.
|
|
6356
|
+
*/
|
|
6357
|
+
function raccoonSessionId(principal, model) {
|
|
6358
|
+
return `sess-0-${createHash("sha256").update(`${principal}\0${model}`).digest("hex").slice(0, 8)}`;
|
|
6359
|
+
}
|
|
6362
6360
|
/** Whether the gateway accepts a token harvested from the browser. */
|
|
6363
6361
|
async function raccoonAccessTokenValid(token, fetchImpl = fetch) {
|
|
6364
6362
|
try {
|
|
@@ -6416,12 +6414,16 @@ var RaccoonProvider = class {
|
|
|
6416
6414
|
catalog;
|
|
6417
6415
|
quotaCache;
|
|
6418
6416
|
quotaInflight;
|
|
6419
|
-
checkinInflight;
|
|
6420
6417
|
loginFlow;
|
|
6421
6418
|
openRouter;
|
|
6419
|
+
sessionIds;
|
|
6422
6420
|
constructor(options) {
|
|
6423
6421
|
this.options = options;
|
|
6424
6422
|
this.openRouter = options.openRouter ?? new OpenRouterCatalog(options.fetchImpl ?? fetch);
|
|
6423
|
+
this.sessionIds = options.sessionIds ?? new RaccoonSessionIds(async () => {
|
|
6424
|
+
const stored = await options.store.raccoon();
|
|
6425
|
+
return stored === void 0 ? void 0 : decodeJwtFacts(stored.accessToken).subject;
|
|
6426
|
+
});
|
|
6425
6427
|
this.catalog = new ModelCatalog(() => this.fetchModels(), options.ttlMs);
|
|
6426
6428
|
}
|
|
6427
6429
|
async status() {
|
|
@@ -6475,6 +6477,21 @@ var RaccoonProvider = class {
|
|
|
6475
6477
|
headers(token) {
|
|
6476
6478
|
return raccoonHeaders(token);
|
|
6477
6479
|
}
|
|
6480
|
+
/**
|
|
6481
|
+
* The chat headers, including the session id the gateway counts sessions by.
|
|
6482
|
+
*
|
|
6483
|
+
* Only chat carries it: the catalogue, quota and check-in routes are plain
|
|
6484
|
+
* business calls the official client sends outside any session, so leaving
|
|
6485
|
+
* them alone keeps this change to the one route it was measured on.
|
|
6486
|
+
*/
|
|
6487
|
+
async chatHeaders(token, model) {
|
|
6488
|
+
const base = raccoonHeaders(token);
|
|
6489
|
+
const sessionId = await this.sessionIds.for(model).catch(() => void 0);
|
|
6490
|
+
return sessionId === void 0 ? base : {
|
|
6491
|
+
...base,
|
|
6492
|
+
"x-raccoon-session-id": sessionId
|
|
6493
|
+
};
|
|
6494
|
+
}
|
|
6478
6495
|
/** Run one JSON call; a rejected token means this login needs a new scan. */
|
|
6479
6496
|
async authorizedJson(path, init = {}, extraHeaders = {}) {
|
|
6480
6497
|
const token = await this.options.auth.accessToken();
|
|
@@ -6590,6 +6607,15 @@ var RaccoonProvider = class {
|
|
|
6590
6607
|
};
|
|
6591
6608
|
}
|
|
6592
6609
|
}
|
|
6610
|
+
/**
|
|
6611
|
+
* Read today's grant. **Read-only on purpose.**
|
|
6612
|
+
*
|
|
6613
|
+
* The gateway has no claim endpoint: points are issued on the day's first
|
|
6614
|
+
* website visit. Replaying that visit (`setting_info`) can trigger the grant
|
|
6615
|
+
* from here, but doing so takes a state-changing action on the account without
|
|
6616
|
+
* the user asking for it in that moment, so the plugin only reports. Claiming
|
|
6617
|
+
* is the website's job, and the card links there.
|
|
6618
|
+
*/
|
|
6593
6619
|
async checkinStatus() {
|
|
6594
6620
|
const grant = await this.dailyGrant();
|
|
6595
6621
|
if (grant !== void 0) return {
|
|
@@ -6609,46 +6635,6 @@ var RaccoonProvider = class {
|
|
|
6609
6635
|
url: RACCOON_CHECKIN_URL
|
|
6610
6636
|
};
|
|
6611
6637
|
}
|
|
6612
|
-
async claimCheckin() {
|
|
6613
|
-
await this.authorizedJson("/office/v3/setting_info", {}, {
|
|
6614
|
-
"x-client-platform": "web",
|
|
6615
|
-
"x-client-version": "131.0.0.0"
|
|
6616
|
-
});
|
|
6617
|
-
const grant = await this.dailyGrant();
|
|
6618
|
-
if (grant === void 0) return {
|
|
6619
|
-
available: true,
|
|
6620
|
-
claimed: false,
|
|
6621
|
-
deviceClaimed: false,
|
|
6622
|
-
message: "每日积分尚未到账;请打开网页签到",
|
|
6623
|
-
url: RACCOON_CHECKIN_URL
|
|
6624
|
-
};
|
|
6625
|
-
this.invalidateQuota();
|
|
6626
|
-
return {
|
|
6627
|
-
available: true,
|
|
6628
|
-
claimed: true,
|
|
6629
|
-
deviceClaimed: false,
|
|
6630
|
-
...grant.points === void 0 ? {} : { reward: grant.points },
|
|
6631
|
-
...grant.grantedAt === void 0 ? {} : { grantedAt: grant.grantedAt },
|
|
6632
|
-
message: "每日积分已到账",
|
|
6633
|
-
url: RACCOON_CHECKIN_URL
|
|
6634
|
-
};
|
|
6635
|
-
}
|
|
6636
|
-
/**
|
|
6637
|
-
* One automatic check-in pass: report today's grant, or ask the website path
|
|
6638
|
-
* to issue it. Shared so overlapping timers cannot spend two call slots.
|
|
6639
|
-
*/
|
|
6640
|
-
async ensureDailyCheckin() {
|
|
6641
|
-
if (this.checkinInflight !== void 0) return this.checkinInflight;
|
|
6642
|
-
this.checkinInflight = (async () => {
|
|
6643
|
-
const status = await this.checkinStatus();
|
|
6644
|
-
return status.claimed ? status : this.claimCheckin();
|
|
6645
|
-
})();
|
|
6646
|
-
try {
|
|
6647
|
-
return await this.checkinInflight;
|
|
6648
|
-
} finally {
|
|
6649
|
-
this.checkinInflight = void 0;
|
|
6650
|
-
}
|
|
6651
|
-
}
|
|
6652
6638
|
async *stream(options, model, readImage, onUnauthorized) {
|
|
6653
6639
|
const token = await this.options.auth.accessToken();
|
|
6654
6640
|
const body = buildBody(options, model, await buildMessages(options, readImage), buildTools(options));
|
|
@@ -6665,7 +6651,7 @@ var RaccoonProvider = class {
|
|
|
6665
6651
|
try {
|
|
6666
6652
|
yield* openAiStream({
|
|
6667
6653
|
url: `${RACCOON_BASE}/llm/v2/chat/completions`,
|
|
6668
|
-
headers: this.
|
|
6654
|
+
headers: await this.chatHeaders(token, model),
|
|
6669
6655
|
body,
|
|
6670
6656
|
signal: options.signal,
|
|
6671
6657
|
fetchImpl: this.options.fetchImpl,
|
|
@@ -6673,10 +6659,17 @@ var RaccoonProvider = class {
|
|
|
6673
6659
|
this.invalidateModels();
|
|
6674
6660
|
this.invalidateQuota();
|
|
6675
6661
|
onUnauthorized?.();
|
|
6662
|
+
},
|
|
6663
|
+
onFrame: (frame) => {
|
|
6664
|
+
const failure = frameFailure(frame);
|
|
6665
|
+
if (failure === void 0) return;
|
|
6666
|
+
const detail = failure.message ?? failure.code ?? "上游返回错误";
|
|
6667
|
+
throw isRaccoonRateLimited(void 0, `${failure.code ?? ""} ${detail}`) ? raccoonRateLimited(detail) : new ProviderHttpError(detail, 502);
|
|
6676
6668
|
}
|
|
6677
6669
|
});
|
|
6678
6670
|
} catch (error) {
|
|
6679
6671
|
if (error instanceof ProviderHttpError && (error.status === 401 || error.status === 403)) throw new Error("小浣熊登录已失效,请在设置页点「打开扫码登录」。");
|
|
6672
|
+
if (error instanceof ProviderHttpError && !(error instanceof RaccoonRateLimitedError) && error.status === 429) throw raccoonRateLimited(error.message);
|
|
6680
6673
|
throw error;
|
|
6681
6674
|
}
|
|
6682
6675
|
}
|
|
@@ -8883,23 +8876,6 @@ function apply(ctx, config) {
|
|
|
8883
8876
|
syncTimer.unref?.();
|
|
8884
8877
|
syncOpenRouter();
|
|
8885
8878
|
ctx.effect(() => () => clearInterval(syncTimer), "llm-adapters: openrouter sync");
|
|
8886
|
-
let lastRaccoonCheckin = Date.now();
|
|
8887
|
-
const checkinMonitor = () => {
|
|
8888
|
-
if (!live.raccoonEnabled()) return;
|
|
8889
|
-
const minutes = live.raccoonCheckinMinutes();
|
|
8890
|
-
if (minutes <= 0) return;
|
|
8891
|
-
if (Date.now() - lastRaccoonCheckin < minutes * 6e4) return;
|
|
8892
|
-
lastRaccoonCheckin = Date.now();
|
|
8893
|
-
(async () => {
|
|
8894
|
-
if (!await raccoonProvider.signedIn()) return;
|
|
8895
|
-
await raccoonProvider.ensureDailyCheckin();
|
|
8896
|
-
})().catch((error) => {
|
|
8897
|
-
ctx.logger?.warn(`llm-adapters: 小浣熊签到监测失败:${error instanceof Error ? error.message : String(error)}`);
|
|
8898
|
-
});
|
|
8899
|
-
};
|
|
8900
|
-
const checkinTimer = setInterval(checkinMonitor, 6e4);
|
|
8901
|
-
checkinTimer.unref?.();
|
|
8902
|
-
ctx.effect(() => () => clearInterval(checkinTimer), "llm-adapters: raccoon check-in monitor");
|
|
8903
8879
|
ctx.inject(["attachments"], (scope) => {
|
|
8904
8880
|
attachments = scope.attachments;
|
|
8905
8881
|
scope.effect(() => () => {
|
|
@@ -8965,4 +8941,4 @@ function apply(ctx, config) {
|
|
|
8965
8941
|
ctx.logger?.info(`llm-adapters: 设置接口已挂载于 ${API_PREFIX}`);
|
|
8966
8942
|
});
|
|
8967
8943
|
}
|
|
8968
|
-
export { API_PREFIX, AccountStore, BRANDS, CODEARTS_BENEFIT_FALLBACK, CODEARTS_BRAND, CODEARTS_CHAT_URL, CODEARTS_CONTEXT_WINDOWS, CODEARTS_DEFAULT_EFFORT, CODEARTS_EFFORTS, CODEARTS_EFFORT_LEVELS, CODEARTS_FALLBACK_CONTEXT_WINDOW, CODEARTS_MAX_OUTPUT_TOKENS, CODEARTS_PROVIDER,
|
|
8944
|
+
export { API_PREFIX, AccountStore, BRANDS, CODEARTS_BENEFIT_FALLBACK, CODEARTS_BRAND, CODEARTS_CHAT_URL, CODEARTS_CONTEXT_WINDOWS, CODEARTS_DEFAULT_EFFORT, CODEARTS_EFFORTS, CODEARTS_EFFORT_LEVELS, CODEARTS_FALLBACK_CONTEXT_WINDOW, CODEARTS_MAX_OUTPUT_TOKENS, CODEARTS_PROVIDER, CODEARTS_SNAP_BASE, CODEARTS_VISION_MODELS, CodeArtsAdapter, CodeArtsAuth, CodeArtsLogin, CodeArtsProvider, Config, EMPTY_OPENROUTER_INDEX, LOOMY_ACCOUNT_BASE, LOOMY_BASE, LOOMY_BRAND, LOOMY_PROVIDER, LOOMY_VERSION, LOOMY_WECHAT_APP_ID, LOOMY_WECHAT_REDIRECT_URI, LocalAdapter, LoomyAdapter, LoomyAuth, LoomyProvider, LoomyQrLogin, ModelCatalog, OpenRouterCatalog, ProviderHttpError, RACCOON_BASE, RACCOON_BRAND, RACCOON_CLIENT_VERSION, RACCOON_IAM_BASE, RACCOON_PROVIDER, RACCOON_QR_APP_NAME, RACCOON_QR_ORIGIN, RaccoonAdapter, RaccoonAuth, RaccoonIamError, RaccoonProvider, RaccoonQrLogin, RefreshTokenExpiredError, TRAE_APP_ID, TRAE_BRAND, TRAE_CHAT_FUNCTIONS, TRAE_CHECKIN_REQ_SOURCE, TRAE_DIRECTORY_FUNCTIONS, TRAE_PROVIDER, TRAE_REGION_PROFILES, TRAE_SOLO_CHAT_PATH, TRAE_WEB_USER_AGENT, TraeAdapter, TraeAuth, TraeProvider, TraeWebLogin, apply, buildAuthorizeUrl, buildLoomyWechatAuthUrl, buildMessages, buildOpenRouterIndex, buildQrMatrix, buildRows, buildTools, clampMaxTokens, codeartsContextWindow, codeartsEfforts, consumeOpenAiStream, createRaccoonQr, decodeJwtFacts, defaultEffortOf, effortLabel, exchangeAuthorizationCode, exchangeRefreshToken, extractWechatUuid, fetchLoomyWechatUuid, generateDpopKeyPair, generatePkcePair, headersForFetch, inject, isBrandId, liveConfig, loomyGatewaySessionValid, machineIdOf, mergeTraeModels, modelKey, name, normalizeCodeArtsModelId, normalizeEffort, normalizeTraeRegion, openAiStream, openTraeStream, otSessionIdOf, parseCodeArtsPackage, parseCodeArtsRoster, parseLoomyCatalog, parseModelName, parseOpenRouterModels, parseRaccoonCatalog, parseTraeCheckin, parseTraeClientStorage, parseTraeGlobalUsage, parseTraeRemoteModels, parseTraeUsage, parseTraeWireModels, pickActiveCredit, pollRaccoonQr, priceFactorOf, priceFactorOfLabel, raccoonAccessTokenValid, raccoonQrContent, raccoonRefreshCandidate, readJwtExpiry, readOpenRouter, readTraeClientLogin, renderQrSvg, resolveCapabilities, resolveConfig, resolveModelId, signDpopJws, signRequestHuawei, sseEvents, startLoginPage, traeClientDataDirs, traeMessages, traeTools };
|
|
@@ -83,12 +83,19 @@ export interface CodeArtsAccountRecord {
|
|
|
83
83
|
d: string;
|
|
84
84
|
};
|
|
85
85
|
userName?: string;
|
|
86
|
+
/**
|
|
87
|
+
* The `x-ot-session-id` this account chats under: one stable value instead of
|
|
88
|
+
* one per request, because the gateway counts concurrent sessions by it.
|
|
89
|
+
*
|
|
90
|
+
* A record written before the field existed derives the same value from the
|
|
91
|
+
* refresh token's profile, so an existing sign-in needs no new login.
|
|
92
|
+
*/
|
|
93
|
+
otSessionId?: string;
|
|
86
94
|
/**
|
|
87
95
|
* Models the account answered `InferHub.4004.200` for.
|
|
88
96
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* call cannot succeed.
|
|
97
|
+
* Worth persisting: the account has no allowance pack for them, so without the
|
|
98
|
+
* verdict every call would pay for a request that cannot succeed.
|
|
92
99
|
*/
|
|
93
100
|
noBenefit?: string[];
|
|
94
101
|
loginAt: number;
|