dsh-multi-router 0.5.4 → 0.5.6
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 +15 -0
- package/README.md +31 -14
- package/THIRD_PARTY_NOTICES.md +31 -0
- package/lib/{chunk-GDUBJ4Z4.js → chunk-CT6ZYIAF.js} +3 -3
- package/lib/{chunk-GDUBJ4Z4.js.map → chunk-CT6ZYIAF.js.map} +2 -2
- package/lib/{chunk-6ZXEVC3R.js → chunk-J3XO7RTF.js} +88 -11
- package/lib/chunk-J3XO7RTF.js.map +7 -0
- package/lib/{chunk-LADXRFL7.js → chunk-U2MU2M5C.js} +11 -4
- package/lib/chunk-U2MU2M5C.js.map +7 -0
- package/lib/{chunk-KCAJ4OAN.js → chunk-XKDXPB5T.js} +283 -33
- package/lib/chunk-XKDXPB5T.js.map +7 -0
- package/lib/cli.js +2 -2
- package/lib/client.js +260 -19
- package/lib/client.js.map +3 -3
- package/lib/clients.js +6 -4
- package/lib/host.js +21 -6
- package/lib/index.js +21 -6
- package/lib/index.js.map +2 -2
- package/lib/manager.js +3 -3
- package/lib/router.js +1 -1
- package/lib/shim.js +2 -2
- package/package.json +1 -1
- package/lib/chunk-6ZXEVC3R.js.map +0 -7
- package/lib/chunk-KCAJ4OAN.js.map +0 -7
- package/lib/chunk-LADXRFL7.js.map +0 -7
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/clients.mjs", "../upstream/trae/src/usage.ts", "../upstream/trae/src/refresh.ts", "../upstream/trae/src/protocol.ts", "../upstream/trae/src/reasoning.ts", "../upstream/trae/src/solo.ts", "../upstream/trae/src/model-metadata.ts", "../upstream/trae/src/solo-remote.ts", "../upstream/trae/src/solo-bridge.ts", "../upstream/trae/src/sse.ts", "../upstream/trae/src/catalog.ts", "../upstream/qoder/src/upstream.ts", "../upstream/qoder/src/probe.ts", "../upstream/qoder/src/qoder/errors.ts", "../upstream/qoder/src/qoder/codes.ts", "../upstream/qoder/src/qoder/transport/default-transport.ts", "../upstream/qoder/src/qoder/transport/endpoints.ts", "../upstream/qoder/src/qoder/transport/machine-id.ts", "../upstream/qoder/src/paths.ts", "../upstream/qoder/src/qoder/transport/request.ts", "../upstream/qoder/src/qoder/transport/logging.ts", "../upstream/qoder/src/qoder/transport/wire/cosy.ts", "../upstream/qoder/src/qoder/transport/auth.ts", "../upstream/qoder/src/qoder/catalog.ts", "../upstream/qoder/src/qoder/transport/catalog-reader.ts", "../upstream/qoder/src/qoder/transport/wire/serialize.ts", "../upstream/qoder/src/qoder/transport/wire/translate.ts", "../upstream/qoder/src/qoder/transport/image-upload.ts", "../upstream/qoder/src/qoder/transport/account-reader.ts", "../upstream/qoder/src/utc8.ts", "../upstream/qoder/src/qoder/transport/checkin.ts", "../upstream/qoder/src/qoder/transport/chat.ts", "../upstream/qoder/src/qoder/transport/wire/encoding.ts", "../upstream/qoder/src/qoder/transport/wire/sse.ts", "../upstream/qoder/src/qoder/transport/wire/thinking.ts", "../upstream/qoder/src/qoder/transport/index.ts", "../src/checkins.mjs", "../src/stream.mjs"],
|
|
4
|
-
"sourcesContent": ["import { readFile } from 'node:fs/promises';\nimport { setTimeout as delay } from 'node:timers/promises';\nimport { WorkBuddyCredentialStore } from '../upstream/workbuddy/src/auth.ts';\nimport { WorkBuddyUpstreamClient, prepareChatBody, modelWithCurrentPromotion } from '../upstream/workbuddy/src/upstream.ts';\nimport { WORKBUDDY_VARIANTS } from '../upstream/workbuddy/src/variants.ts';\nimport { TraeCredentialStore, traeAccountId } from '../upstream/trae/src/auth.ts';\nimport { TraeUsageClient } from '../upstream/trae/src/usage.ts';\nimport { refreshTraeCredential } from '../upstream/trae/src/refresh.ts';\nimport { TraeSoloUpstreamClient } from '../upstream/trae/src/solo.ts';\nimport { TraeSoloRemoteCatalogClient } from '../upstream/trae/src/solo-remote.ts';\nimport { TraeSoloBridge } from '../upstream/trae/src/solo-bridge.ts';\nimport { mergeTraeModelSources } from '../upstream/trae/src/catalog.ts';\nimport { QoderUpstreamClient } from '../upstream/qoder/src/upstream.ts';\nimport { createQoderTransport } from '../upstream/qoder/src/qoder/transport/index.ts';\nimport { getMachineId } from '../upstream/qoder/src/qoder/transport/machine-id.ts';\nimport { QoderLlmError } from '../upstream/qoder/src/qoder/errors.ts';\nimport { QoderAuthService } from '../upstream/qoder/src/qoder/transport/auth.ts';\nimport { QoderCheckInService } from '../upstream/qoder/src/qoder/transport/checkin.ts';\nimport { readLimitedText } from '../upstream/qoder/src/qoder/transport/request.ts';\nimport { checkinFailure } from './checkins.mjs';\nimport { RouteError, abortable } from './router.mjs';\nimport { preflightStream } from './stream.mjs';\n\nconst expiryMs = value => { const n = typeof value === 'number' ? (value < 1e12 ? value * 1000 : value) : Date.parse(value || ''); return Number.isFinite(n) && n > 0 ? n : undefined; };\nexport async function jsonCredential(file) {\n try { return JSON.parse(await readFile(file, 'utf8')); }\n catch { throw new RouteError(401, 'credential_unreadable'); }\n}\nexport function cachedModels(discover, ttl) {\n let cached, expires = 0, inflight;\n return async (signal, force = false) => {\n if (!force && cached && expires > Date.now()) return cached;\n // Shared metadata discovery has its own deadline; a departing caller cannot cancel others.\n inflight ??= discover(AbortSignal.timeout(60000)).then(rows => { cached = rows; expires = Date.now() + ttl; return rows; }).finally(() => { inflight = undefined; });\n return abortable(inflight, signal);\n };\n}\nexport async function createAccountClient(account, config, attachments) {\n let chat, discover, accountInfo, checkin;\n if (account.provider.startsWith('workbuddy')) {\n const client = new WorkBuddyUpstreamClient();\n const variant = WORKBUDDY_VARIANTS.find(v => v.id === account.provider);\n const store = new WorkBuddyCredentialStore({ variant, ownPath: account.credentialFile,\n desktopPath: `${account.credentialFile}.no-desktop`, refresh: c => account.provider === 'workbuddy' ? refreshWorkBuddyCheckinCredential(c) : client.refreshToken(c) });\n const credential = async () => {\n try { return await store.resolve(); }\n catch { throw new RouteError(401, 'credential_refresh_failed'); }\n };\n discover = async signal => (await client.fetchModels(await credential(), signal)).map(m => modelWithCurrentPromotion(m));\n accountInfo = async () => {\n const c = await credential(), credits = await client.fetchCredits(c);\n return { login: { state: 'valid', identity: c.uid, name: c.nickname || c.uid, expiresAt: c.expiresAtMs,\n refreshExpiresAt: c.refreshExpiresAtMs, refreshable: !!c.refreshToken, kind: '\u5BA2\u6237\u7AEF\u767B\u5F55\u6001' },\n remaining: credits.unlimited ? null : credits.total, unlimited: !!credits.unlimited, unit: 'credits',\n cycle: credits.cycleResetTime || credits.accounts.map(p => `${p.packageName}:${p.endTimeMs || ''}`).sort().join('|'),\n packages: credits.accounts.map(p => ({ name: p.packageName, remaining: p.remain, total: p.size, expiresAt: p.endTimeMs, unlimited: !!p.unlimited })), fetchedAt: Date.now() };\n };\n chat = async (input, signal) => client.chatStream(await credential(), prepareChatBody(JSON.stringify(input)), signal);\n if (account.provider === 'workbuddy') checkin = createWorkBuddyCheckin(() => store.resolve());\n } else if (account.provider.startsWith('trae')) {\n const snapshot = await jsonCredential(account.credentialFile);\n const saved = snapshot.credential;\n if (snapshot.version !== 1 || !saved?.accessToken || !['cn', 'sg', 'solo', 'solo-sg'].includes(saved.edition)) throw new RouteError(401, 'invalid_trae_credential');\n const identity = async () => {\n if (!account.identityFile) throw new RouteError(401, 'trae_identity_required');\n const value = await jsonCredential(account.identityFile);\n if (!value.machineId || !value.deviceId || value.edition !== saved.edition) throw new RouteError(401, 'invalid_trae_identity');\n return value;\n };\n const store = new TraeCredentialStore({ ownPath: account.credentialFile,\n storagePath: `${account.credentialFile}.no-desktop`, legacyOwnPath: `${account.credentialFile}.no-legacy`,\n accountId: traeAccountId(saved), region: account.provider === 'trae' ? 'cn' : 'ai',\n refresh: async c => refreshTraeCredential(c, undefined, await identity()) });\n const credential = async () => {\n try { return await store.resolve(); }\n catch { throw new RouteError(401, 'credential_refresh_failed'); }\n };\n const usage = new TraeUsageClient({ credential, deviceId: async () => (await identity()).deviceId });\n if (account.provider === 'trae') {\n const checkinCredential = () => store.resolve();\n const checkinUsage = new TraeUsageClient({ credential: checkinCredential, deviceId: async () => (await identity()).deviceId,\n fetchImpl: async (url, options) => {\n const response = await fetch(url, options);\n if (!response.ok) throw Object.assign(Error('checkin_http_error'), { status: response.status });\n if (String(url).endsWith('/status')) {\n const body = await response.clone().json();\n if ((body.code !== undefined && body.code !== 0) || typeof body.checked_in !== 'boolean' || typeof body.did_checked_in !== 'boolean') throw Object.assign(Error('checkin_status_rejected'), { status: 403 });\n }\n if (String(url).endsWith('/claim') && !Number.isFinite((await response.clone().json()).code)) throw Error('checkin_claim_invalid');\n return response;\n } });\n checkin = { identity: async () => ({ account: (await checkinCredential()).userId, device: (await identity()).deviceId }),\n claim: signal => claimTraeCheckin(checkinUsage, signal) };\n }\n accountInfo = async signal => {\n const c = await credential();\n const login = { state: 'valid', identity: c.userId, name: c.accountName || c.userId, expiresAt: c.expiresAtMs,\n refreshExpiresAt: c.refreshExpiresAtMs, refreshable: !!c.refreshToken, kind: '\u5BA2\u6237\u7AEF\u767B\u5F55\u6001', edition: c.edition };\n if (account.provider === 'trae-global') { const plan = await usage.payStatus(signal); return { login, plan: plan.payIdentityStr || '\u672A\u8FD4\u56DE\u5957\u9910\u540D\u79F0', unit: 'subscription', remaining: null, packages: [], fetchedAt: Date.now() }; }\n const result = await usage.snapshot(signal), packs = result.packs;\n return { login, unit: result.isCreditsBilling ? 'credits' : 'billing', remaining: result.isCreditsBilling ? Math.max(0, result.summary.totalAmount - result.summary.consumedAmount) : null,\n total: result.summary.totalAmount, used: result.summary.consumedAmount,\n cycle: packs.map(p => `${p.entitlementId}:${p.endTimeMs}`).sort().join('|'),\n packages: packs.map(p => ({ name: p.displayDesc, total: p.creditsLimit, remaining: typeof p.creditsLimit === 'number' && typeof p.consumedCredits === 'number' ? Math.max(0, p.creditsLimit - p.consumedCredits) : null, expiresAt: p.endTimeMs })), fetchedAt: Date.now() };\n };\n const solo = new TraeSoloUpstreamClient({ credential, identity });\n const remote = new TraeSoloRemoteCatalogClient({ credential });\n let rows = [];\n discover = async signal => {\n const [skeleton, wire] = await Promise.all([remote.fetchModels(signal), solo.fetchModels(signal)]);\n rows = mergeTraeModelSources(skeleton, wire);\n return rows;\n };\n const bridge = new TraeSoloBridge(solo, { current: () => rows });\n chat = (input, signal) => bridge.chatStream(JSON.stringify(input), signal);\n } else {\n const region = account.provider === 'qoder' ? 'china' : 'global';\n const getPat = async () => {\n const value = await jsonCredential(account.credentialFile);\n if (value.version !== 2 || value.region !== region || typeof value.pat !== 'string' || !value.pat.trim()) throw new RouteError(401, 'invalid_qoder_credential');\n return value.pat;\n };\n const transport = createQoderTransport({ region, resolvePat: getPat,\n // Reuse the official CLI identity (or one persisted plugin seed) for this physical device.\n resolveMachineId: () => getMachineId(),\n ...(attachments ? { attachments } : {}) });\n const client = new QoderUpstreamClient({ region, providerId: account.provider, getPat, transport,\n ...(attachments ? { attachments } : {}) });\n checkin = createQoderCheckin(region, getPat);\n accountInfo = async signal => {\n const result = await transport.readAccount({ force: true, signal });\n const buckets = [['\u4E2A\u4EBA\u5957\u9910', result.usage?.userQuota], ['\u9644\u52A0\u989D\u5EA6', result.usage?.addOnQuota], ['\u7EC4\u7EC7\u989D\u5EA6', result.usage?.orgResourcePackage]].filter(([, p]) => p).map(([name, p]) => ({ ...p, name }));\n const creditBuckets = buckets.filter(p => /credit|point|\u79EF\u5206/i.test(p.unit));\n return { login: { state: 'valid', identity: result.profile.id, name: result.profile.name || result.profile.email || result.profile.id, kind: 'PAT', refreshable: false },\n plan: result.plan?.planTierName, remaining: creditBuckets.length ? creditBuckets.reduce((n, p) => n + p.remaining, 0) : null,\n unit: creditBuckets.length ? 'credits' : 'unknown', cycle: result.usage?.expiresAt || result.plan?.endDate || '',\n packages: buckets.map(p => ({ name: p.name, total: p.total, remaining: p.remaining, unit: p.unit, expiresAt: expiryMs(result.usage?.expiresAt || result.plan?.endDate) })), fetchedAt: Date.now() };\n };\n discover = signal => client.fetchModels(signal);\n chat = (input, signal) => client.chatStream(JSON.stringify(input), signal);\n }\n return { models: cachedModels(discover, config.catalogTtlMs), accountInfo, checkin,\n async chat(input, signal) {\n const result = await chat(input, signal);\n return result.ok ? preflightStream(result.response, signal) : result;\n } };\n}\n\nexport async function claimTraeCheckin(usage, signal) {\n let submitted = false;\n try {\n const status = await usage.checkinStatus(signal);\n if (status.checkedIn) return { status: 'already-claimed' };\n if (status.didCheckedIn) return { status: 'device-used' };\n if (!status.enabled) return { status: 'no-campaign' };\n submitted = true;\n const claim = await usage.claimCheckin(signal);\n if (claim.code === 9095) return { status: 'device-used' };\n if (!claim.claimed) return { status: 'paused' };\n // A success response is authoritative; do not turn a failed follow-up balance read into a retry.\n return { status: 'claimed', ...(Number.isFinite(status.credits) ? { amount: status.credits + (status.extraCredits || 0) } : {}) };\n } catch (e) {\n return checkinFailure(e, submitted);\n }\n}\n\nexport function createQoderCheckin(region, getPat, { fetchImpl = (...args) => fetch(...args), now = Date.now } = {}) {\n const guardedFetch = async (url, options) => {\n try {\n const response = await fetchImpl(url, options);\n // No metadata/auth healing retries in a check-in operation; preserve status without raw bodies.\n if (!response.ok) throw new QoderLlmError('checkin_http_error', 'PROVIDER_ERROR', { status: response.status });\n if (String(url).endsWith('/campaigns') && !Array.isArray((await response.clone().json()).campaigns)) throw Error('checkin_campaigns_invalid');\n return response;\n } catch (error) {\n if (error instanceof QoderLlmError) throw error;\n throw new QoderLlmError('checkin_network_error', 'PROVIDER_ERROR');\n }\n };\n const auth = new QoderAuthService({ region, fetch: guardedFetch, resolveMachineId: () => getMachineId() });\n const campaigns = new QoderCheckInService({ region, authService: auth, fetch: guardedFetch });\n const credentials = async signal => auth.getCredentials(await getPat(), signal);\n return {\n identity: async signal => ({ account: (await credentials(signal)).userID }),\n claim: async signal => {\n let submitted = false;\n try {\n const token = (await credentials(signal)).authToken;\n const rows = await campaigns.fetchCampaigns(token, signal), time = now();\n const benefits = rows.filter(c => c.actionType === 'CLAIM_BENEFIT');\n const active = benefits.filter(c => (!Number.isFinite(c.startAt) || c.startAt * 1000 <= time)\n && (!Number.isFinite(c.endAt) || c.endAt * 1000 > time));\n const target = active.find(c => c.claimStatus === 'CLAIMABLE' && typeof c.campaignId === 'string' && c.campaignId);\n if (!target) {\n if (active.some(c => c.claimStatus === 'CLAIMED')) return { status: 'already-claimed' };\n return { status: benefits.some(c => c.startAt * 1000 > time || c.endAt * 1000 <= time) ? 'before-window' : 'no-campaign' };\n }\n submitted = true;\n const result = await campaigns.claimCampaign(token, target.campaignId, signal);\n if (result.status !== 'CLAIMED') return { status: 'paused' };\n return { status: result.replayed ? 'already-claimed' : 'claimed',\n ...(Number.isFinite(result.benefit?.amount) && result.benefit.amount >= 0 ? { amount: result.benefit.amount } : {}) };\n } catch (error) { return checkinFailure(error, submitted); }\n },\n };\n}\n\n// The JWT is decoded only to bind this saved login to its uid and CN issuer; the server verifies its signature.\nfunction workbuddyToken(token) {\n try {\n const [head, body, signature, extra] = token.split('.');\n const header = JSON.parse(Buffer.from(head, 'base64url')), payload = JSON.parse(Buffer.from(body, 'base64url'));\n if (extra || !signature || header.alg !== 'RS256' || payload.iss !== 'https://www.codebuddy.cn/auth/realms/copilot'\n || typeof payload.sub !== 'string' || !payload.sub) throw Error();\n return payload;\n } catch { throw Object.assign(Error('HTTP 401 invalid_workbuddy_cn_token'), { status: 401 }); }\n}\nasync function workbuddyPost(url, headers, signal, fetchImpl) {\n let response;\n try { response = await fetchImpl(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept-Encoding': 'identity', ...headers }, body: '{}', signal }); }\n catch { throw Object.assign(Error('workbuddy_checkin_network'), { transient: !signal?.aborted }); }\n if (!response.ok) throw Object.assign(Error(`HTTP ${response.status} workbuddy_checkin_http`), { status: response.status, transient: response.status >= 500 });\n const body = JSON.parse(await readLimitedText(response, 256 * 1024, 'Check-in'));\n if (body?.code === 401 || body?.code === 40100) throw Object.assign(Error('HTTP 401 workbuddy_checkin_auth'), { status: 401 });\n if ([403, 429].includes(body?.code)) throw Object.assign(Error(`HTTP ${body.code} workbuddy_checkin_restricted`), { status: body.code });\n return body;\n}\nexport async function refreshWorkBuddyCheckinCredential(credential, { fetchImpl = (...args) => fetch(...args), signal = AbortSignal.timeout(30000) } = {}) {\n const body = await workbuddyPost('https://copilot.tencent.com/v2/plugin/auth/token/refresh', {\n 'X-Refresh-Token': credential.refreshToken, 'X-Auth-Refresh-Source': 'plugin',\n }, signal, fetchImpl);\n if (body.code !== 0 || typeof body.data?.accessToken !== 'string') throw Error('workbuddy_refresh_rejected');\n const token = workbuddyToken(body.data.accessToken);\n if (token.sub !== credential.uid || !(token.exp * 1000 > Date.now())) throw Object.assign(Error('HTTP 401 workbuddy_refresh_identity'), { status: 401 });\n return { accessToken: body.data.accessToken, expiresInSec: (token.exp * 1000 - Date.now()) / 1000,\n ...(typeof body.data.refreshToken === 'string' && body.data.refreshToken ? { refreshToken: body.data.refreshToken } : {}) };\n}\nexport function createWorkBuddyCheckin(credential, { fetchImpl = (...args) => fetch(...args), sleep = delay, now = Date.now } = {}) {\n const login = async () => {\n const c = await credential(), token = workbuddyToken(c.accessToken);\n if (c.uid !== token.sub) throw Object.assign(Error('workbuddy_uid_mismatch'), { status: 401 });\n return { ...c, uid: token.sub };\n };\n const post = (path, c, signal) => workbuddyPost(`https://www.workbuddy.cn/v2/billing/meter/${path}`, {\n Authorization: `Bearer ${c.accessToken}`, 'X-User-Id': c.uid, Origin: 'https://www.workbuddy.cn',\n Referer: 'https://www.workbuddy.cn/profile/growth-center', 'User-Agent': 'Mozilla/5.0',\n }, signal, fetchImpl);\n const activity = data => {\n const rawEnd = data.end_time;\n const endsAt = typeof rawEnd === 'string' ? Date.parse(/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$/.test(rawEnd) ? `${rawEnd.replace(' ', 'T')}+08:00` : rawEnd) : undefined;\n return { streakDays: data.streak_days, totalCredits: data.total_credits, nextStreakDay: data.next_streak_day, endsAt };\n };\n return {\n identity: async () => ({ account: (await login()).uid }),\n claim: async signal => {\n let submitted = false;\n try {\n const c = await login();\n let state;\n for (let attempt = 0; ; attempt++) {\n try { state = await post('checkin-activity-status', c, signal); break; }\n catch (error) {\n if (!error.transient || attempt >= 2 || signal?.aborted) throw error;\n await sleep((attempt + 1) * 2000, undefined, { signal });\n }\n }\n if (![0, 200].includes(state?.code) || !state.data || typeof state.data !== 'object') throw Error('workbuddy_status_invalid');\n const stats = activity(state.data);\n if (state.data.today_checked_in === true) return { status: 'already-claimed', activity: stats };\n if (state.data.active === false || stats.endsAt <= now()) return { status: 'no-campaign', activity: stats };\n if (state.data.today_checked_in !== false) throw Error('workbuddy_status_unknown');\n submitted = true;\n const result = await post('daily-checkin', c, signal);\n const claimed = [0, 200].includes(result?.code), already = /\u4ECA\u5929\u5DF2\u7B7E\u5230|\u4ECA\u65E5\u5DF2\u7B7E\u5230|already\\s+(?:checked|signed)/i.test(result?.msg || '');\n if (!claimed && !already) return { status: Number.isFinite(result?.code) ? 'paused' : 'uncertain' };\n let updated = stats, paused = false;\n try { const after = await post('checkin-activity-status', c, signal); if ([0, 200].includes(after?.code) && after.data) updated = activity(after.data); }\n catch (error) { paused = checkinFailure(error).status === 'paused'; } // An accepted claim stays recorded even if the following read fails.\n return { status: already ? 'already-claimed' : 'claimed', activity: updated, ...(paused ? { paused: true } : {}),\n ...(claimed && Number.isFinite(result.data?.credit) && result.data.credit >= 0 ? { amount: result.data.credit } : {}) };\n } catch (error) { return checkinFailure(error, submitted); }\n },\n };\n}\n", "import type { TraeCredential } from './auth.ts'\nimport { REGION_GATEWAYS, regionOfCredential } from './region.ts'\n\n/**\n * Read-only Trae usage/credits client.\n *\n * CN sources the verified `api.trae.cn` pay/ug endpoints (see\n * `docs/USAGE_API_RESEARCH.md`); the international (ai) region is\n * subscription-based and reads `ide_user_pay_status` on its own gateway\n * (verified 2026-09-15, docs/INTL_SG_EVIDENCE.md \u00A74). All queries are\n * read-only and do not consume Trae credits. The per-session consumption\n * detail table is deliberately not included: the endpoint returns no rows\n * for the current account, so we only expose what is actually retrievable.\n */\n\nexport const TRAE_PAY_BASE = 'https://api.trae.cn'\n\nexport interface TraeUsageOptions {\n credential(): Promise<TraeCredential | undefined>\n /**\n * Device identity of the credential's own installation, sent as\n * `x-device-id` on the check-in routes.\n *\n * The claim endpoint is the one WRITE in this client, and it is guarded\n * server-side by that header: with the same Authorization but no\n * `x-device-id`, the upstream answers HTTP 200 with business code `9004`\n * (\"The submitted order parameters are incorrect\") and grants nothing \u2014\n * verified 2026-09-24 against a live CN account, where adding the header\n * flipped the same request to `code: 0` and the daily reward landed. The\n * official client sends it on every check-in call\n * (`main.js`'s `fb(headers)` sets `x-device-id` from `guaranteedDeviceId`).\n * Absent, the client still reads status; only the claim refuses.\n */\n deviceId?(): Promise<string | undefined>\n fetchImpl?: typeof fetch\n baseUrl?: string\n timeoutMs?: number\n}\n\n/**\n * Subscription/pay status of an international (ai) account, parsed from the\n * `ide_user_pay_status` answer. The international region has no Work-credit\n * packs, so this \u2014 not `snapshot` \u2014 is its usage surface.\n */\nexport interface TraePayStatus {\n isDollarUsageBilling: boolean\n hasPackage: boolean\n isPayFreshman: boolean\n inTrial: boolean\n trialEndTimeMs: number\n enableSoloLite: boolean\n enableSoloBuilder: boolean\n enableSoloCoder: boolean\n enableSoloWeb: boolean\n /**\n * The account's plan identity (`user_pay_identity`), Trae's authoritative\n * tier number: `0` is Free. Measured 2026-10-01 on a live SG community\n * account, which reported `0` / `\"Free\"`.\n *\n * This is a DIFFERENT question from {@link hasPackage}, which asks whether a\n * package/entitlement object exists. A paying member can hold a plan\n * identity without any package row, which is why issue #19 saw \"No active\n * package\" on a Pro account \u2014 the card only ever read `has_package`.\n */\n payIdentity?: number\n /** The plan identity as Trae spells it (`user_pay_identity_str`), e.g. `Free`. */\n payIdentityStr?: string\n /** The fission (referral) program window and cap, when exposed. */\n fission?: { startTimeMs: number; expireTimeMs: number; maxUsage: number }\n}\n\nexport interface TraeUsageSummary {\n totalAmount: number\n consumedAmount: number\n consumptionRatio: number\n}\n\nexport interface TraeUsagePack {\n displayDesc: string\n entitlementId: string\n endTimeMs: number\n currency: number\n /** 0 = non-Work/general endpoint, 1 = Work endpoint. */\n availableEndpoint?: number\n creditsLimit?: number\n /** Credits consumed from this pack (`usage.credits_amount`). */\n consumedCredits?: number\n}\n\nexport interface TraeUsageSnapshot {\n isCreditsBilling: boolean\n isDollarUsageBilling: boolean\n isPayFreshman: boolean\n inTrial: boolean\n trialEndTimeMs: number\n summary: TraeUsageSummary\n packs: TraeUsagePack[]\n}\n\nexport interface TraeCheckinStatus {\n /**\n * Whether the account's REWARD PACK for today already exists. This is the\n * account-wide answer and it is the one that decides whether there is\n * anything left to claim: a day with `checkedIn: true` has already been paid\n * out, whichever device produced it.\n */\n checkedIn: boolean\n /** Reward for one check-in, as reported by the upstream (`credits`). */\n credits: number\n enabled: boolean\n /**\n * Whether THIS device's claim for today was already recorded. The upstream\n * keys this on the `x-device-id` the request carries \u2014 not on the account \u2014\n * so it answers `true` for the device that claimed and `false` for the same\n * account and day read from any other device.\n *\n * Measured 2026-09-26 on a live CN account whose claim had succeeded minutes\n * earlier: `did_checked_in` was `true` with the claiming device id and\n * `false` with the header omitted, with a synthetic id, and with another\n * install's id. Repeating the read never flips it, so it is not \"have I seen\n * you before\" state either \u2014 only an actual claim sets it.\n *\n * It is therefore NOT a \"today is done\" signal on its own (claiming again\n * answers the upstream's own 9095 \"\u8BE5\u8BBE\u5907\u4ECA\u65E5\u5DF2\u53C2\u4E0E\u7B7E\u5230\" refusal); it is\n * evidence that this exact device is already accounted for, which is what\n * makes a claim safe to skip.\n */\n didCheckedIn: boolean\n /** Bonus credit granted on top of the base reward, when the upstream reports one. */\n extraCredits?: number\n}\n\n/** Result of claiming today's check-in reward. */\nexport interface TraeCheckinClaim {\n /** Whether the upstream accepted the claim (`code === 0`). */\n claimed: boolean\n /** Business code from the answer; `0` on success. */\n code: number\n /** Upstream message, verbatim but truncated \u2014 never token material. */\n message: string\n}\n\nexport interface TraeActivityRule {\n activityId: string\n enabled: boolean\n activityType: number\n startTimeMs: number\n endTimeMs: number\n workExtra?: Record<string, unknown>\n}\n\nexport interface TraeUsageView {\n snapshot: TraeUsageSnapshot\n checkin: TraeCheckinStatus\n activities: TraeActivityRule[]\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined\n}\n\n/**\n * Normalize an upstream epoch to milliseconds.\n *\n * The pack's `end_time` arrives in SECONDS while {@link TraeUsagePack.endTimeMs}\n * names milliseconds. Measured against a live CN account: `1788340660` is\n * 2026-09-02, and reading it as milliseconds would place the pack in 1970 \u2014 a\n * date that sorts ahead of every real one and reads as \"long expired\". The\n * magnitude test is the same one `auth.ts` applies to stored expiry fields, so\n * an upstream that ever switches to milliseconds is passed through instead of\n * being multiplied into the year 57000.\n */\nfunction epochToMs(value: number | undefined): number {\n if (value === undefined || !Number.isFinite(value) || value <= 0) return 0\n return value > 1e12 ? value : value * 1000\n}\n\nfunction parseUsageSnapshot(payload: Record<string, unknown>): TraeUsageSnapshot {\n const summaryRaw = payload['usage_summary'] as Record<string, unknown> | undefined\n const summary: TraeUsageSummary = {\n totalAmount: asNumber(summaryRaw?.['total_amount']) ?? 0,\n consumedAmount: asNumber(summaryRaw?.['consumed_amount']) ?? 0,\n consumptionRatio: asNumber(summaryRaw?.['consumption_ratio']) ?? 0,\n }\n const trial = payload['trial_status'] as Record<string, unknown> | undefined\n const packs: TraeUsagePack[] = []\n const rawPacks = Array.isArray(payload['user_entitlement_pack_list']) ? payload['user_entitlement_pack_list'] : []\n for (const raw of rawPacks) {\n if (typeof raw !== 'object' || raw === null) continue\n const pack = raw as Record<string, unknown>\n const base = pack['entitlement_base_info'] as Record<string, unknown> | undefined\n const quota = base?.['quota'] as Record<string, unknown> | undefined\n const usage = pack['usage'] as Record<string, unknown> | undefined\n const productExtra = base?.['product_extra'] as Record<string, unknown> | undefined\n const packageExtra = productExtra?.['package_extra'] as Record<string, unknown> | undefined\n const packageQuota = packageExtra?.['quota'] as Record<string, unknown> | undefined\n const creditsLimit = asNumber(packageQuota?.['credits_limit']) ?? asNumber(quota?.['credits_limit'])\n const consumedCredits = asNumber(usage?.['credits_amount'])\n const availableEndpoint = asNumber(base?.['available_endpoint'])\n packs.push({\n displayDesc: typeof pack['display_desc'] === 'string' ? pack['display_desc'] : '',\n entitlementId: typeof base?.['entitlement_id'] === 'string' ? base['entitlement_id'] : '',\n endTimeMs: epochToMs(asNumber(base?.['end_time'])),\n currency: asNumber(base?.['currency']) ?? 0,\n ...availableEndpoint === undefined ? {} : { availableEndpoint },\n ...creditsLimit === undefined ? {} : { creditsLimit },\n ...consumedCredits === undefined ? {} : { consumedCredits },\n })\n }\n return {\n isCreditsBilling: payload['is_credits_billing'] === true,\n isDollarUsageBilling: payload['is_dollar_usage_billing'] === true,\n isPayFreshman: payload['is_pay_freshman'] === true,\n inTrial: trial?.['is_in_trial'] === true,\n trialEndTimeMs: asNumber(trial?.['trial_end_time']) ?? 0,\n summary,\n packs,\n }\n}\n\n/**\n * A client for the verified Trae usage/credits endpoints.\n *\n * Every method is read-only except {@link TraeUsageClient.claimCheckin}, which\n * claims the daily check-in reward \u2014 the one deliberate mutation, requested by\n * the user from the card and guarded before it is sent.\n */\nexport class TraeUsageClient {\n private readonly fetchImpl: typeof fetch\n private readonly baseUrl: string | undefined\n private readonly timeoutMs: number\n\n constructor(private readonly options: TraeUsageOptions) {\n this.fetchImpl = options.fetchImpl ?? fetch\n this.baseUrl = options.baseUrl\n this.timeoutMs = options.timeoutMs ?? 30_000\n }\n\n /** Region of the current credential; `cn` when unresolvable. */\n private async currentRegion(): Promise<'cn' | 'ai'> {\n const credential = await this.options.credential()\n return credential === undefined ? 'cn' : regionOfCredential(credential)\n }\n\n /**\n * Pay base for the current credential's region. An explicit baseUrl (tests,\n * diagnostics) pins the endpoint; otherwise CN uses `api.trae.cn` and the\n * international region its own verified pay gateway.\n */\n private async payBase(): Promise<string> {\n return this.baseUrl ?? REGION_GATEWAYS[await this.currentRegion()].pay\n }\n\n /**\n * Device id for the check-in routes, or undefined when the machine's\n * installation identity cannot be read. Best-effort on purpose: a missing\n * identity must not break the read-only status query, which the upstream\n * answers with or without the header.\n */\n private async deviceIdHeader(): Promise<Record<string, string>> {\n try {\n const deviceId = await this.options.deviceId?.()\n return deviceId === undefined || deviceId === '' ? {} : { 'x-device-id': deviceId }\n } catch {\n return {}\n }\n }\n\n private async authedHeaders(): Promise<Record<string, string>> {\n const credential = await this.options.credential()\n if (credential === undefined || credential.accessToken === '') {\n throw new Error('Trae credential is not available; cannot query usage')\n }\n const origin = await this.currentRegion() === 'ai' ? 'https://www.trae.ai' : 'https://www.trae.cn'\n return {\n 'Authorization': `Cloud-IDE-JWT ${credential.accessToken}`,\n 'Content-Type': 'application/json',\n 'User-Agent': 'Mozilla/5.0',\n 'Origin': origin,\n 'Referer': `${origin}/`,\n }\n }\n\n private async post<T>(\n path: string,\n data: Record<string, unknown>,\n signal?: AbortSignal,\n extraHeaders: Record<string, string> = {},\n ): Promise<T> {\n const headers = { ...await this.authedHeaders(), ...extraHeaders }\n const response = await this.fetchImpl(`${await this.payBase()}${path}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(data),\n signal: signal ?? AbortSignal.timeout(this.timeoutMs),\n })\n if (!response.ok) throw new Error(`Trae usage endpoint ${path} returned HTTP ${response.status}`)\n return await response.json() as T\n }\n\n /**\n * Subscription/pay status of an international (ai) account. The CN region\n * never calls this (its contract is unverified there); the ai region uses\n * this instead of the Work-credit `snapshot`.\n */\n async payStatus(signal?: AbortSignal): Promise<TraePayStatus> {\n const region = await this.currentRegion()\n if (region !== 'ai') throw new Error('Trae pay status is only available for the international (ai) region')\n const payload = await this.post<Record<string, unknown>>('/trae/api/v1/pay/ide_user_pay_status', {}, signal)\n const flag = (key: string): boolean => payload[key] === true\n const trial = typeof payload['trial_status'] === 'object' && payload['trial_status'] !== null\n ? payload['trial_status'] as Record<string, unknown>\n : {}\n const fissionStart = asNumber(payload['solo_fission_start_time'])\n const fissionExpire = asNumber(payload['solo_fission_expire_time'])\n const fissionMax = asNumber(payload['solo_fission_max_usage'])\n const payIdentity = asNumber(payload['user_pay_identity'])\n const payIdentityStr = typeof payload['user_pay_identity_str'] === 'string' && payload['user_pay_identity_str'].trim() !== ''\n ? payload['user_pay_identity_str'].trim()\n : undefined\n return {\n isDollarUsageBilling: flag('is_dollar_usage_billing'),\n hasPackage: flag('has_package'),\n isPayFreshman: flag('is_pay_freshman') || flag('is_pay_freshman_v2'),\n inTrial: trial['is_in_trial'] === true,\n trialEndTimeMs: asNumber(trial['trial_end_time']) ?? 0,\n enableSoloLite: flag('enable_solo_lite'),\n enableSoloBuilder: flag('enable_solo_builder'),\n enableSoloCoder: flag('enable_solo_coder'),\n enableSoloWeb: flag('enable_solo_web'),\n ...payIdentity === undefined ? {} : { payIdentity },\n ...payIdentityStr === undefined ? {} : { payIdentityStr },\n ...fissionStart === undefined || fissionExpire === undefined || fissionMax === undefined ? {} : {\n fission: { startTimeMs: fissionStart, expireTimeMs: fissionExpire, maxUsage: fissionMax },\n },\n }\n }\n\n /**\n * The Work-credit endpoints are CN-only. The international region is\n * subscription-based and must read {@link payStatus} instead; guarding here\n * keeps the card's degraded `creditsError` message diagnosable rather than\n * letting an ai credential hit an unverified path on its pay gateway.\n */\n private async requireCnRegion(method: string): Promise<void> {\n if (await this.currentRegion() !== 'cn') {\n throw new Error(`Trae ${method} is only available for the CN region; the international (ai) region uses payStatus`)\n }\n }\n\n /** Total entitlements / credits and per-pack breakdown. */\n async snapshot(signal?: AbortSignal): Promise<TraeUsageSnapshot> {\n await this.requireCnRegion('usage snapshot')\n const payload = await this.post<Record<string, unknown>>('/trae/api/v2/pay/web_user_ent_usage', { require_usage: true }, signal)\n return parseUsageSnapshot(payload)\n }\n\n /**\n * Daily check-in status. Read-only, and answered with or without the device\n * header \u2014 the claim is what needs it.\n *\n * The read DOES carry the header whenever this installation has one, and\n * that is deliberate rather than incidental: `did_checked_in` is answered\n * per device, so omitting the header would make a device that already claimed\n * today look identical to one that never has (measured 2026-09-26, see\n * {@link TraeCheckinStatus.didCheckedIn}).\n */\n async checkinStatus(signal?: AbortSignal): Promise<TraeCheckinStatus> {\n await this.requireCnRegion('check-in status')\n const headers = await this.deviceIdHeader()\n const payload = await this.post<Record<string, unknown>>('/trae/api/v2/ug/checkin_credits/status', {}, signal, headers)\n const extraCredits = asNumber(payload['extra_credits'])\n return {\n checkedIn: payload['checked_in'] === true,\n credits: asNumber(payload['credits']) ?? 0,\n enabled: payload['enable'] !== false,\n didCheckedIn: payload['did_checked_in'] === true,\n ...extraCredits === undefined || extraCredits <= 0 ? {} : { extraCredits },\n }\n }\n\n /**\n * Claim today's check-in reward. The ONLY state-changing call in this client.\n *\n * The upstream is idempotent per Beijing day (verified 2026-09-24: repeating\n * the call on an already-claimed day answers `code: 0` while the entitlement\n * total stays byte-identical), so a double click cannot double-grant. The\n * card and its route still guard, because \"cannot double-grant\" is a property\n * of the upstream we verify rather than one we rely on.\n *\n * A business refusal arrives as HTTP 200 with a non-zero `code` \u2014 most often\n * `9004` when the request carries no `x-device-id`. That is reported as\n * `claimed: false` rather than thrown, so the caller can tell \"the upstream\n * refused this\" apart from \"the request never arrived\".\n */\n async claimCheckin(signal?: AbortSignal): Promise<TraeCheckinClaim> {\n await this.requireCnRegion('check-in claim')\n const headers = await this.deviceIdHeader()\n const payload = await this.post<Record<string, unknown>>('/trae/api/v2/ug/checkin_credits/claim', {}, signal, headers)\n const code = asNumber(payload['code']) ?? 0\n return {\n claimed: code === 0,\n code,\n message: typeof payload['message'] === 'string' ? payload['message'].slice(0, 200) : '',\n }\n }\n\n /** Rewards / activity rules. */\n async activities(signal?: AbortSignal): Promise<TraeActivityRule[]> {\n await this.requireCnRegion('activities')\n const payload = await this.post<Record<string, unknown>>('/trae/api/v2/ug/activity/info', {}, signal)\n const rawActivities = Array.isArray(payload['commercial_activities']) ? payload['commercial_activities'] : []\n const activities: TraeActivityRule[] = []\n for (const raw of rawActivities) {\n if (typeof raw !== 'object' || raw === null) continue\n const rule = raw as Record<string, unknown>\n activities.push({\n activityId: typeof rule['activity_id'] === 'string' ? rule['activity_id'] : '',\n enabled: rule['Enabled'] === true,\n activityType: asNumber(rule['activity_type']) ?? 0,\n startTimeMs: asNumber(rule['start_time_ms']) ?? 0,\n endTimeMs: asNumber(rule['end_time_ms']) ?? 0,\n ...rule['work_extra'] === undefined ? {} : { workExtra: rule['work_extra'] as Record<string, unknown> },\n })\n }\n return activities\n }\n\n /** Convenience: snapshot + check-in + activities in one call (best-effort, non-fatal on missing). */\n async view(signal?: AbortSignal): Promise<TraeUsageView> {\n const [snapshot, checkin, activities] = await Promise.all([\n this.snapshot(signal),\n this.checkinStatus(signal),\n this.activities(signal),\n ])\n return { snapshot, checkin, activities }\n }\n}\n", "import type { TraeCredential, TraeRefreshOutcome } from './auth.ts'\nimport type { TraeEdition } from './paths.ts'\nimport { hostname } from 'node:os'\nimport { randomBytes, sign } from 'node:crypto'\n\n/**\n * Per-edition refresh contracts (docs/INTL_SG_EVIDENCE.md \u00A72.2; re-verified\n * 2026-10-11 against the shipped 3.4.2 / 3.6.2 clients AND their own request\n * logs).\n *\n * History matters here, because the contract has MOVED:\n *\n * - The pre-3.x clients (and every plugin release up to 3.0.1) refreshed on\n * `/cloudide/api/v3/trae/oauth/ExchangeToken` with no proof. That shape is\n * still answered with HTTP 200 today for ALL FOUR editions \u2014 but only when\n * the ClientID matches the credential's own OAuth client (see below), so it\n * is kept as the fallback.\n * - The current clients refresh on `/trae/api/v3/oauth/ExchangeToken` and\n * attach a `DeviceProof`: an ECDSA P-256 signature made with the per-install\n * keypair stored in the same `storage.json`. Sending the new path without\n * that proof is refused with `20405 Device proof required`, and sending it\n * with a proof from a different key is refused with `20403 Token device not\n * match` \u2014 so the proof is both required and verified, and the keypair is\n * not optional.\n *\n * The refresh contract is the ONE contract that forks by edition rather than by\n * region. Every request hangs off the credential's own host, never a hardcoded\n * base.\n *\n * Verified matrix (all four editions answered HTTP 200 on BOTH contracts):\n *\n * | edition | ClientID | PlatformCode |\n * |---------|------------------|--------------|\n * | cn | ono9krqynydwx5 | IDE_PC |\n * | sg | ono9krqynydwx5 | IDE_PC |\n * | solo | en1oxy7wnw8j9n | SOLO_PC |\n * | solo-sg | en1oxy7wnw8j9n | SOLO_PC |\n *\n * The ClientID split follows the official client's own branch exactly: every\n * SOLO package (CN and international alike) takes the SOLO ClientID and\n * `SOLO_PC`, and everything else takes the desktop one and `IDE_PC`.\n *\n * That split is enforced by the OAuth CLIENT rather than by the endpoint, so it\n * applies on the LEGACY path too: a SOLO refresh token is refused by the desktop\n * client on either path with `10101 refresh token is not matched to the client`.\n * Both contracts therefore read `CURRENT_CONTRACT[edition].clientId`.\n */\ninterface TraeRefreshContract {\n readonly path: string\n readonly clientId: string\n /** Value the official client sends as `PlatformCode`. */\n readonly platformCode: string\n}\n\n/** Path of the current token-exchange endpoint, relative to the credential host. */\nexport const TRAE_EXCHANGE_TOKEN_PATH = '/trae/api/v3/oauth/ExchangeToken'\n\n/** Path of the superseded endpoint; only reachable as the fallback. */\nexport const TRAE_LEGACY_EXCHANGE_TOKEN_PATH = '/cloudide/api/v3/trae/oauth/ExchangeToken'\n\n/** Shared desktop ClientID; the current contract also uses it for `cn` / `sg`. */\nconst DESKTOP_CLIENT_ID = 'ono9krqynydwx5'\n\n/** SOLO ClientID; every SOLO package uses it, CN and international alike. */\nconst SOLO_CLIENT_ID = 'en1oxy7wnw8j9n'\n\n/** The current contract: `/trae/api/v3`, per-edition ClientID, always proofed. */\nconst CURRENT_CONTRACT: Readonly<Record<TraeEdition, TraeRefreshContract>> = {\n cn: { path: TRAE_EXCHANGE_TOKEN_PATH, clientId: DESKTOP_CLIENT_ID, platformCode: 'IDE_PC' },\n sg: { path: TRAE_EXCHANGE_TOKEN_PATH, clientId: DESKTOP_CLIENT_ID, platformCode: 'IDE_PC' },\n solo: { path: TRAE_EXCHANGE_TOKEN_PATH, clientId: SOLO_CLIENT_ID, platformCode: 'SOLO_PC' },\n 'solo-sg': { path: TRAE_EXCHANGE_TOKEN_PATH, clientId: SOLO_CLIENT_ID, platformCode: 'SOLO_PC' },\n}\n\n/**\n * Stable device identity for the DeviceInfo body, sourced from the app's own\n * storage. Every field except `deviceId`/`machineId` is optional: the server\n * requires `DeviceID`, `PlatformCode` and `DeviceType` (verified: dropping\n * `DeviceType` yields `20403`, dropping `MachineID` does not), so a machine that\n * cannot read the cosmetic fields must still be able to refresh.\n */\nexport interface TraeRefreshDevice {\n deviceId: string\n machineId: string\n deviceName?: string\n deviceModel?: string\n deviceBrand?: string\n deviceCpu?: string\n osVersion?: string\n appVersion?: string\n /**\n * The install's registered keypair, read from `storage.json`. Its presence is\n * exactly what decides whether the CURRENT contract can be attempted: without\n * it there is no proof to sign, and the server would answer `20405`.\n */\n deviceKeyPair?: { privateKeyPEM: string; publicKeyPEM: string }\n}\n\n/** The ClientID the official client uses for one edition. */\nexport function refreshClientIdOf(edition: TraeEdition): string {\n return CURRENT_CONTRACT[edition].clientId\n}\n\n/**\n * The `PlatformCode` the official client sends for one edition. Exported so the\n * settings card and diagnostics can describe the same table the refresh uses.\n */\nexport function refreshPlatformCodeOf(edition: TraeEdition): string {\n return CURRENT_CONTRACT[edition].platformCode\n}\n\nfunction normalizeHost(host: string): string {\n const value = host.trim()\n if (value === '') throw new Error('Trae refresh host is missing')\n return value.replace(/\\/$/, '')\n}\n\n/** `OSInfo` value the official client sends (a bare platform word). */\nfunction osInfo(platform: NodeJS.Platform = process.platform): string {\n return platform === 'darwin' ? 'mac' : platform === 'win32' ? 'windows' : platform\n}\n\n/**\n * Build the exact string the official client signs.\n *\n * The separator is a NEWLINE, not a space: the shipped bundle joins the six\n * fields with `.join(\"\\n\")`. This is load-bearing rather than cosmetic \u2014 a\n * space-joined message of identical fields is rejected with `20403 Token device\n * not match`, which is indistinguishable from a wrong key and sends debugging\n * in entirely the wrong direction.\n */\nexport function traeDeviceProofMessage(input: {\n path: string\n clientId: string\n refreshToken: string\n timestamp: number\n nonce: string\n}): string {\n return ['POST', input.path, input.clientId, input.refreshToken, String(input.timestamp), input.nonce].join('\\n')\n}\n\n/**\n * Sign a device proof with the install's own private key.\n *\n * `timestamp`/`nonce` are injectable so tests can pin a deterministic signature;\n * the defaults are the whole-second timestamp and 16 random bytes the official\n * client uses.\n */\nexport function signTraeDeviceProof(input: {\n path: string\n clientId: string\n refreshToken: string\n privateKeyPEM: string\n timestamp?: number\n nonce?: string\n}): { Signature: string; Timestamp: number; Nonce: string } {\n const timestamp = input.timestamp ?? Math.floor(Date.now() / 1000)\n const nonce = input.nonce ?? randomBytes(16).toString('hex')\n const message = traeDeviceProofMessage({\n path: input.path, clientId: input.clientId, refreshToken: input.refreshToken, timestamp, nonce,\n })\n const Signature = sign('sha256', Buffer.from(message), input.privateKeyPEM).toString('base64')\n return { Signature, Timestamp: timestamp, Nonce: nonce }\n}\n\n/** The `DeviceInfo` block the current contract sends. */\nexport function traeDeviceInfoBody(contract: TraeRefreshContract, device: TraeRefreshDevice, platform?: NodeJS.Platform): Record<string, unknown> {\n const os = osInfo(platform)\n return {\n DeviceID: device.deviceId,\n MachineID: device.machineId,\n PlatformCode: contract.platformCode,\n DeviceType: 'PC',\n ...device.deviceName === undefined ? {} : { DeviceName: device.deviceName },\n ...device.deviceModel === undefined ? {} : { DeviceModel: device.deviceModel },\n ...device.appVersion === undefined ? {} : { ClientVersion: device.appVersion },\n ...device.deviceKeyPair === undefined ? {} : { DevicePublicKey: device.deviceKeyPair.publicKeyPEM },\n ...device.deviceBrand === undefined ? {} : { DeviceBrand: device.deviceBrand },\n ...device.deviceCpu === undefined ? {} : { DeviceCPU: device.deviceCpu },\n OSInfo: os,\n OSVersion: device.osVersion ?? `${os} ${hostname()}`,\n }\n}\n\n/** The current contract's complete request body. */\nfunction currentBody(credential: TraeCredential, contract: TraeRefreshContract, device: TraeRefreshDevice): Record<string, unknown> {\n return {\n ClientID: contract.clientId,\n ClientSecret: '',\n RefreshToken: credential.refreshToken,\n DeviceInfo: traeDeviceInfoBody(contract, device),\n DeviceProof: signTraeDeviceProof({\n path: contract.path,\n clientId: contract.clientId,\n refreshToken: credential.refreshToken ?? '',\n privateKeyPEM: device.deviceKeyPair!.privateKeyPEM,\n }),\n ...device.appVersion === undefined ? {} : { IDEVersion: device.appVersion },\n }\n}\n\n/**\n * The superseded shape, kept as a fallback for installs the current contract\n * cannot serve: a machine whose `storage.json` carries no device keypair (an\n * older install that has never refreshed on the new contract, or a CLI-only\n * home) has nothing to sign a proof with.\n *\n * The ClientID split is the SAME one the current contract uses, and that is not\n * a coincidence \u2014 it is enforced by the OAuth CLIENT, not by the endpoint: a\n * SOLO-package refresh token is refused by the DESKTOP client with `10101\n * refresh token is not matched to the client`, and vice versa, on this path\n * exactly as on the current one. Verified 2026-10-11 across all four editions:\n * each answers 200 here with its own ClientID and 400 with the other one.\n *\n * The pre-3.1.0 code hardcoded the desktop ClientID on this path, which is why\n * an international SOLO account had no working fallback at all.\n */\nfunction legacyBody(credential: TraeCredential, clientId: string): Record<string, unknown> {\n return {\n ClientID: clientId,\n ClientSecret: '-',\n RefreshToken: credential.refreshToken,\n UserID: credential.userId,\n }\n}\n\n/** Parse one ExchangeToken response into an outcome, or throw with the reason. */\nfunction outcomeOf(payload: { Result?: Record<string, unknown> }, label: string): TraeRefreshOutcome {\n const result = payload.Result\n const accessToken = typeof result?.['Token'] === 'string' ? result['Token'] : ''\n if (accessToken === '') throw new Error(`${label} returned no token`)\n const expiry = result?.['TokenExpireAt']\n const expiresAtMs = typeof expiry === 'number' ? expiry : typeof expiry === 'string' ? Date.parse(expiry) : Number.NaN\n if (!Number.isFinite(expiresAtMs)) throw new Error(`${label} returned an invalid expiry`)\n const refreshToken = typeof result?.['RefreshToken'] === 'string' && result['RefreshToken'] !== '' ? result['RefreshToken'] : undefined\n // The current contract also reports when the REFRESH token dies. Recording it\n // is what lets the store know a refresh is impossible before asking again,\n // instead of surfacing the same 401 forever.\n const refreshExpiry = result?.['RefreshExpireAt']\n const parsedRefreshExpiry = typeof refreshExpiry === 'string' ? Date.parse(refreshExpiry) : Number.NaN\n const refreshExpiresAtMs = typeof refreshExpiry === 'number' && Number.isFinite(refreshExpiry) && refreshExpiry > 0\n ? refreshExpiry\n : Number.isFinite(parsedRefreshExpiry) ? parsedRefreshExpiry : undefined\n return {\n accessToken,\n ...refreshToken === undefined ? {} : { refreshToken },\n expiresAtMs,\n ...refreshExpiresAtMs === undefined ? {} : { refreshExpiresAtMs },\n }\n}\n\n/** POST one refresh body and parse it, labelling failures with the path tried. */\nasync function postExchangeToken(\n host: string,\n path: string,\n body: Record<string, unknown>,\n signal: AbortSignal | undefined,\n label: string,\n): Promise<TraeRefreshOutcome> {\n const response = await fetch(`${normalizeHost(host)}${path}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: signal ?? AbortSignal.timeout(30_000),\n })\n if (!response.ok) throw new Error(`${label} failed (http ${response.status})`)\n return outcomeOf(await response.json() as { Result?: Record<string, unknown> }, label)\n}\n\n/**\n * Exchange a refresh token for a fresh access token.\n *\n * The CURRENT contract is attempted first whenever it is possible at all \u2014 it is\n * what the shipped clients use. It needs the install's device keypair; without\n * one there is nothing to sign, so the request is skipped rather than sent to be\n * rejected with `20405`.\n *\n * The SUPERSEDED contract is then tried as a fallback, which is what keeps older\n * installs and CLI-only machines working; it carries no device block but the\n * SAME per-edition ClientID, because that split belongs to the OAuth client\n * rather than to the endpoint (see {@link legacyBody}). When both are impossible\n * or both fail, the error names every attempt so a \"sign in again\" verdict is\n * diagnosable rather than mysterious.\n */\nexport async function refreshTraeCredential(\n credential: TraeCredential,\n signal?: AbortSignal,\n device?: TraeRefreshDevice,\n): Promise<TraeRefreshOutcome> {\n const contract = CURRENT_CONTRACT[credential.edition]\n if (contract === undefined) throw new Error(`Trae ${credential.edition} refresh contract is not verified`)\n if (credential.refreshToken === undefined) throw new Error('Trae refresh token is missing')\n\n const attempts: string[] = []\n\n // --- Current contract: needs a registered device keypair to sign with. ---\n if (device?.deviceKeyPair === undefined) {\n attempts.push(`${contract.path}: no device keypair in this install's storage`)\n } else {\n try {\n return await postExchangeToken(credential.host, contract.path, currentBody(credential, contract, device), signal, 'Trae token refresh')\n } catch (error: unknown) {\n attempts.push(`${contract.path}: ${error instanceof Error ? error.message : String(error)}`)\n }\n }\n\n // --- Superseded contract: no device block, but the same ClientID split. ---\n try {\n return await postExchangeToken(credential.host, TRAE_LEGACY_EXCHANGE_TOKEN_PATH, legacyBody(credential, contract.clientId), signal, 'Trae token refresh (legacy)')\n } catch (error: unknown) {\n attempts.push(`${TRAE_LEGACY_EXCHANGE_TOKEN_PATH}: ${error instanceof Error ? error.message : String(error)}`)\n }\n\n throw new Error(`Trae token refresh failed \u2014 ${attempts.join('; ')}`)\n}\n", "import { randomUUID } from 'node:crypto'\nimport type { TraeCredential } from './auth.ts'\nimport type { TraeIdentity } from './identity.ts'\nimport { identityHeaders } from './identity.ts'\n\nexport const TRAE_CN_AGENT_TASK_PATH = '/api/agent/v3/create_agent_task'\nexport const TRAE_CN_TITLE_PATH = '/api/agent/v3/llm_utils_chat'\n\nexport interface OpenAITextMessage {\n role: 'assistant' | 'system' | 'user'\n content: string\n}\n\nexport interface TraeAgentTaskBody {\n messages: { role: OpenAITextMessage['role']; content: { type: 'text'; text: string }[] }[]\n model: string\n function: string\n stream: true\n request_id: string\n session_id: string\n max_tokens?: number\n}\n\n/**\n * Evidence-bounded body draft. It is intentionally pure and offline; the\n * network client remains disabled until a controlled request validates it.\n */\nexport function buildTraeAgentTaskBody(\n messages: readonly OpenAITextMessage[],\n model: string,\n options: { maxTokens?: number; requestId?: string; sessionId?: string } = {},\n): TraeAgentTaskBody {\n if (messages.length === 0) throw new Error('Trae agent task requires at least one message')\n const requestId = options.requestId ?? randomUUID()\n const sessionId = options.sessionId ?? requestId\n return {\n messages: messages.map(message => ({ role: message.role, content: [{ type: 'text', text: message.content }] })),\n model,\n function: 'inline_chat',\n stream: true,\n request_id: requestId,\n session_id: sessionId,\n ...options.maxTokens === undefined ? {} : { max_tokens: options.maxTokens },\n }\n}\n\nexport type TraeHeaderProfile = 'agent-task' | 'model-detail' | 'raw-chat' | 'native-curl'\n\n/**\n * Numeric version code sent when the persisted build version is not a plain\n * integer. The upstream binds `x-app-version-code` / `x-ide-version-code` as a\n * number: Trae stores `iCubeLastVersion` as a dotted build string (observed\n * `2.3.76922` on TRAE SOLO CN 0.1.56), which the server rejects with\n * `4001 ... expr_path=app_version_code, cause=parameter type does not match\n * binding data`. Verified 2026-08-29: with a numeric code the same request\n * returns HTTP 200 + `text/event-stream` on\n * `/api/agent/v3/llm_utils_chat` (`solo_work_lite`).\n *\n * Only the *format* of this field is normalised. Machine, device and app\n * version stay exactly as persisted \u2014 nothing here impersonates a device.\n */\nexport const TRAE_VERSION_CODE_FALLBACK = '20260716'\n\n/** Keep a purely numeric build version; fall back when it cannot bind. */\nexport function normalizeTraeVersionCode(buildVersion: string | undefined): string {\n if (buildVersion === undefined || buildVersion.trim() === '') return TRAE_VERSION_CODE_FALLBACK\n const trimmed = buildVersion.trim()\n return /^\\d+$/.test(trimmed) ? trimmed : TRAE_VERSION_CODE_FALLBACK\n}\n\n/**\n * Headers shared by every Trae edition. The same shape is accepted by both\n * gateways (verified read-only on the international gateway 2026-09-15,\n * docs/INTL_SG_EVIDENCE.md \u00A72.3: identical `x-app-id`, identity headers, and\n * `Cloud-IDE-JWT` auth), so there is no per-edition branch any more.\n */\nexport function buildTraeHeaders(\n credential: TraeCredential,\n identity: TraeIdentity,\n options: { appId?: string; requestId?: string; profile?: TraeHeaderProfile } = {},\n): Record<string, string> {\n const requestId = options.requestId ?? randomUUID()\n const traceId = requestId.replaceAll('-', '').slice(0, 32)\n const profile = options.profile ?? 'agent-task'\n const common = {\n 'Authorization': `Cloud-IDE-JWT ${credential.accessToken}`,\n 'X-Ide-Token': credential.accessToken,\n 'x-plugin-channel': 'icube-ai',\n 'User-Agent': `Trae/${identity.appVersion ?? identity.buildVersion ?? 'unknown'}`,\n 'x-app-id': options.appId ?? '6eefa01c-1036-4c7e-9ca5-d891f63bfcd8',\n ...identityHeaders(identity),\n // The upstream binds these as numbers; a dotted build string is rejected.\n 'x-app-version-code': normalizeTraeVersionCode(identity.buildVersion),\n 'x-ide-version-code': normalizeTraeVersionCode(identity.buildVersion),\n 'x-custom-trace-id': traceId,\n 'x-flow-traceparent': `04-${traceId}-${traceId.slice(0, 16)}-01`,\n 'request-traffic-type': 'prod',\n 'Content-Type': 'application/json',\n }\n if (profile === 'native-curl') {\n // Exact set printed by Trae 3.3.83's own get_skill_detail curl diagnostic.\n // No Authorization, plugin channel, User-Agent or speculative bridge headers.\n return {\n 'Content-Type': 'application/json',\n 'request-traffic-type': 'prod',\n 'x-app-id': options.appId ?? '6eefa01c-1036-4c7e-9ca5-d891f63bfcd8',\n ...identityHeaders(identity),\n 'x-custom-trace-id': traceId,\n 'x-flow-traceparent': `04-${traceId}-${traceId.slice(0, 16)}-01`,\n 'X-Ide-Token': credential.accessToken,\n }\n }\n if (profile === 'model-detail') return { ...common, 'Accept': 'application/json' }\n if (profile === 'raw-chat') return { ...common, 'Accept': 'text/event-stream' }\n return {\n ...common,\n 'X-Cloudide-Token': credential.accessToken,\n 'x-uid': credential.userId,\n 'x-request-id': requestId,\n 'x-trae-request-id': requestId,\n 'Accept': 'text/event-stream',\n }\n}\n\n/** Backwards-compatible alias; the headers are no longer CN-specific. */\nexport const buildTraeCnHeaders = buildTraeHeaders\n\nexport function traeEndpoint(baseUrl: string, path: string): string {\n return `${baseUrl.replace(/\\/$/, '')}/${path.replace(/^\\//, '')}`\n}\n", "export const TRAE_REASONING_EFFORTS = ['minimal', 'low', 'medium', 'high', 'xhigh'] as const\nexport type TraeReasoningEffort = typeof TRAE_REASONING_EFFORTS[number]\n\nexport interface TraeReasoningCapability {\n supported: readonly TraeReasoningEffort[]\n defaultEffort?: TraeReasoningEffort\n}\n\nexport function parseReasoningCapability(value: unknown): TraeReasoningCapability | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined\n const record = value as Record<string, unknown>\n const rawOptions = Array.isArray(record['reasoning_effort_options']) ? record['reasoning_effort_options'] : []\n const supported = rawOptions.filter((item): item is TraeReasoningEffort =>\n typeof item === 'string' && (TRAE_REASONING_EFFORTS as readonly string[]).includes(item))\n const rawDefault = record['default_reasoning_effort']\n const defaultEffort = typeof rawDefault === 'string' && supported.includes(rawDefault as TraeReasoningEffort)\n ? rawDefault as TraeReasoningEffort\n : undefined\n if (supported.length === 0 && defaultEffort === undefined) return undefined\n return { supported, ...defaultEffort === undefined ? {} : { defaultEffort } }\n}\n\n/** Add effort only when the selected model advertises that exact value. */\nexport function applyReasoningEffort<T extends Record<string, unknown>>(\n body: T,\n effort: TraeReasoningEffort | undefined,\n capability: TraeReasoningCapability | undefined,\n): T & { reasoning_effort?: TraeReasoningEffort } {\n if (effort === undefined) return body\n if (capability === undefined || !capability.supported.includes(effort)) {\n throw new Error(`Trae model does not advertise reasoning effort ${effort}`)\n }\n return { ...body, reasoning_effort: effort }\n}\n", "import type { TraeCredential } from './auth.ts'\nimport type { TraeIdentity } from './identity.ts'\nimport { buildTraeCnHeaders, traeEndpoint } from './protocol.ts'\nimport { REGION_GATEWAYS, regionOfCredential, type TraeRegion } from './region.ts'\nimport { parseReasoningCapability, type TraeReasoningCapability } from './reasoning.ts'\nimport type { TraeChatResult, TraeUpstreamErrorKind } from './upstream.ts'\n\nexport const TRAE_SOLO_FUNCTION = 'solo_work_lite'\n\n/**\n * `llm_utils_chat` functions to union per region, in priority order.\n *\n * Trae spreads its callable roster across several SOLO-mode functions, and a\n * model is only usable through the one that lists it: `glm-5.3` is absent from\n * `solo_work_lite` but present in `solo_work_remote` (verified 2026-09-15 \u2014\n * calling it through the former answers `4001 param is invalid`, through the\n * latter streams normally). Rather than betting on a single function, the\n * directory unions them; the first function to provide a config wins, so the\n * order below decides which wire name AND which function a model is called with.\n *\n * THIS LIST IS NOT \"directory functions\" \u2014 it is the set of functions\n * `llm_utils_chat` actually accepts, because ownership here is what the chat\n * call replays. `solo_agent` is deliberately ABSENT (measured 2026-10-01 on a\n * live SG credential, issue #19): it is a Remote-agent roster function, not a\n * chat function. Every model sent with `function: \"solo_agent\"` \u2014 `gpt-5.4`,\n * `gpt-5.6-sol`, `gpt-6-astra`, `glm-5.2`, `kimi-k2.7-code` \u2014 answered\n * `event:error {\"code\":4011}`, while the same model with the same body answered\n * normally under `solo_work_remote` / `solo_work_lite` / `solo_agent_remote`.\n * Issue #33 corrected the reading of that code: `4011` is Trae's rate limit on\n * the route that was asked (its own text says so, and issue #33's reporter hit\n * it on the CORRECT function), and the \"this route does not serve that model\"\n * condition is `4001` \u2014 measured on all 22 functions of a live CN credential.\n * The conclusion for this list is unchanged either way: a route that refuses\n * chat is not a chat route, so `solo_agent` stays out.\n *\n * Note `get_detail_param` DOES answer `solo_agent` with a 43-entry list, so\n * asking it looks helpful while making 8 of the 10 exposed ai-region models\n * uncallable: it won precedence and stamped its own name onto configs it\n * cannot serve. `solo_agent_remote` is the chat-callable half of that roster\n * (it answers `minimax-m3`, `gemini-3.1-pro`, \u2026 that no `solo_work_*` lists)\n * and therefore takes the last slot \u2014 after the two IDE functions that serve\n * their shared configs without the Remote plan gate.\n *\n * `chat_v3` is the widest chat roster of all (measured 2026-10-01 on live\n * credentials, issue #19 follow-up): its `get_detail_param` answers 40\n * config_names on `ai` \u2014 more than any other function except `solo_agent` (43,\n * which cannot serve chat). It lists models NO other chat function names, and\n * it is joined LAST so it only fills gaps: a config two functions list keeps\n * the earlier function, so no precedence is disturbed. The ai models it unlocks\n * were each verified callable end-to-end through the plugin's own\n * `prepareSoloBody` envelope:\n *\n * ai (+6): kimi-k2.7-code, deepseek-v4-flash-0731, deepseek-v3.2,\n * gemini-3-flash-premium, gemini_2.5_flash_premium, Dola-Seed-2.0-Code\n *\n * CN joins `chat_v3` and `solo_coder` too (2026-10-02). Both are callable there\n * \u2014 verified per model through `prepareSoloBody`, calling each model under a\n * function whose roster names it: `glm-5` / `glm-5.1` / `qwen-3.5` and\n * `deepseek-v4-pro` / `deepseek-v4-flash` under `solo_coder`, and\n * `doubao-seed-2.0-code` under `solo_coder` / `solo_work_remote` /\n * `solo_work_lite`. An earlier note here claimed those three answered `4001`\n * \"under every function\" \u2014 that was a measurement error, not an upstream\n * refusal: the probe had called them by display id while the chat endpoint needs\n * the config_name its owning function returned.\n *\n * This also corrects an older note that `Doubao-Seed-Code` \"has no config_name\n * and must stay hidden\" (docs/MODEL_MANAGEMENT_DESIGN.md): it does have one,\n * under `chat_v3`.\n *\n * A model in NO chat function's roster is still left to the merge: it ships\n * with no wire target and its call fails with a readable upstream message\n * rather than being hidden (see mergeTraeModelSources).\n */\nexport const TRAE_DIRECTORY_FUNCTIONS: Readonly<Record<TraeRegion, readonly string[]>> = {\n cn: ['solo_work_remote', TRAE_SOLO_FUNCTION, 'solo_agent_remote', 'chat_v3', 'solo_coder'],\n ai: ['solo_work_remote', TRAE_SOLO_FUNCTION, 'solo_agent_remote', 'chat_v3'],\n}\nexport const TRAE_SOLO_CHAT_PATH = '/api/agent/v3/llm_utils_chat'\nexport const TRAE_SOLO_MODELS_PATH = '/api/ide/v1/get_detail_param'\n\nfunction classify(status: number): TraeUpstreamErrorKind {\n if (status === 401 || status === 403) return 'authentication'\n if (status === 402) return 'hard_credit'\n if (status === 429) return 'soft_rate'\n if (status === 404) return 'not_found'\n if (status >= 500) return 'server'\n return 'client'\n}\n\nfunction finitePositive(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : undefined\n}\n\nexport function prepareSoloBody(source: string, defaultModel = 'glm-5.2', functionName?: string): string {\n const input = JSON.parse(source) as Record<string, unknown>\n const requestedModel = typeof input['model'] === 'string' && input['model'].trim() !== '' ? input['model'].trim() : defaultModel\n const model = requestedModel\n // llm_utils_chat is not an OpenAI-compatible endpoint. Build its evidenced\n // envelope explicitly so optional Pi/OpenAI fields (temperature, max_tokens,\n // tool_choice, response_format, etc.) cannot make every model fail validation.\n const body: Record<string, unknown> = {\n ...Array.isArray(input['messages']) ? { messages: input['messages'] } : {},\n model,\n config_name: model,\n // The directory function that actually lists this model (see\n // TRAE_DIRECTORY_FUNCTIONS). The bridge may have already stamped the exact\n // function it learned from the directory, which wins over the default.\n function: typeof input['function'] === 'string' && input['function'] !== ''\n ? input['function']\n : (functionName ?? TRAE_SOLO_FUNCTION),\n stream: true,\n ...Array.isArray(input['tools']) ? { tools: input['tools'] } : {},\n ...typeof input['reasoning_effort'] === 'string' ? { reasoning_effort: input['reasoning_effort'] } : {},\n }\n if (Array.isArray(body['messages'])) {\n for (const raw of body['messages']) {\n if (typeof raw !== 'object' || raw === null) continue\n const message = raw as Record<string, unknown>\n // DSH sends the system prompt as the OpenAI `developer` role, which the\n // Trae `llm_utils_chat` upstream rejects with a 400 (it accepts only\n // system / assistant / user / tool / function). Normalise it.\n if (message['role'] === 'developer') message['role'] = 'system'\n if (typeof message['content'] === 'string') message['content'] = [{ type: 'text', text: message['content'] }]\n if (message['role'] === 'assistant' && Array.isArray(message['tool_calls'])) {\n for (const rawCall of message['tool_calls']) {\n if (typeof rawCall !== 'object' || rawCall === null) continue\n const call = rawCall as Record<string, unknown>\n if (typeof call['function'] === 'object' && call['function'] !== null) {\n call['function_call'] = call['function']\n delete call['function']\n }\n }\n }\n if (message['role'] === 'tool') {\n message['role'] = 'tool'\n if (typeof message['tool_call_id'] !== 'string' || message['tool_call_id'] === '') {\n throw new Error('Trae SOLO tool message requires tool_call_id')\n }\n }\n }\n }\n if (Array.isArray(body['tools'])) {\n for (const raw of body['tools']) {\n if (typeof raw !== 'object' || raw === null) continue\n const fn = (raw as Record<string, unknown>)['function']\n if (typeof fn !== 'object' || fn === null) continue\n const record = fn as Record<string, unknown>\n if (typeof record['parameters'] === 'object' && record['parameters'] !== null) record['parameters'] = JSON.stringify(record['parameters'])\n }\n }\n return JSON.stringify(body)\n}\n\nexport interface TraeSoloModel {\n id: string\n name: string\n contextWindow?: number\n maxTokens?: number\n reasoning?: TraeReasoningCapability\n /** Effective (post-discount) credit multiplier, as the Trae IDE shows it. */\n creditMultiplier?: number\n /** The directory function that listed this config (replayed when calling it). */\n function?: string\n}\n\n/**\n * Read the effective credit multiplier from a `get_detail_param` row.\n *\n * The rate the Trae IDE renders lives in `display_contact_config` \u2014 a *string*\n * holding a second JSON document \u2014 and its `consumption_rate.data.rate` is\n * already the post-discount value (verified 2026-09-13, commit 1.4.2: the\n * Remote directory reports the undiscounted figure, e.g. `0.8`, while the IDE\n * and this field both say `0.08` under a \u9650\u65F6 1 \u6298 promotion \u2014 up to a 10x\n * difference). The wire figure therefore wins over the Remote one during the\n * merge; this parser is what feeds it.\n *\n * The international (ai) gateway serves no `consumption_rate` anywhere (its\n * subscription models carry only `features.cost` tags), so rows without the\n * field keep their bare name \u2014 parsed-but-absent, never fabricated.\n */\nfunction wireCreditMultiplier(config: Record<string, unknown>): number | undefined {\n const raw = config['display_contact_config']\n if (typeof raw !== 'string' || raw === '') return undefined\n let parsed: unknown\n try { parsed = JSON.parse(raw) } catch { return undefined }\n if (typeof parsed !== 'object' || parsed === null) return undefined\n const consumption = (parsed as Record<string, unknown>)['consumption_rate']\n if (typeof consumption !== 'object' || consumption === null) return undefined\n const entry = consumption as Record<string, unknown>\n if (entry['enable'] !== true) return undefined\n const data = entry['data']\n if (typeof data !== 'object' || data === null) return undefined\n return finitePositive((data as Record<string, unknown>)['rate'])\n}\n\nexport interface TraeSoloClientOptions {\n credential(): Promise<TraeCredential>\n identity(): Promise<TraeIdentity>\n baseUrl?: string\n fetchImpl?: typeof fetch\n log?: (message: string, detail?: unknown) => void\n}\n\nexport class TraeSoloUpstreamClient {\n private readonly fetchImpl: typeof fetch\n constructor(private readonly options: TraeSoloClientOptions) { this.fetchImpl = options.fetchImpl ?? fetch }\n\n /**\n * Read the callable roster for this credential's region.\n *\n * Every function in {@link TRAE_DIRECTORY_FUNCTIONS} is asked, in order, and\n * their answers are unioned: the first function to list a `config_name` owns\n * it. Trae splits its roster across SOLO modes, and a model is only callable\n * through the function that lists it (glm-5.3 exists solely under\n * `solo_work_remote` on the CN gateway). Asking one function therefore\n * silently hides models that the other one serves. The remote directory\n * remains the merge skeleton, so agent-internal entries (search_agent_*,\n * paygo variants) never surface even though they appear here.\n */\n async fetchModels(signal?: AbortSignal): Promise<TraeSoloModel[]> {\n const [credential, identity] = await Promise.all([this.options.credential(), this.options.identity()])\n const region = regionOfCredential(credential)\n const base = this.options.baseUrl ?? REGION_GATEWAYS[region].chat\n const headers = { ...buildTraeCnHeaders(credential, identity), Accept: 'application/json' }\n const byId = new Map<string, TraeSoloModel>()\n const failures: string[] = []\n for (const directoryFunction of TRAE_DIRECTORY_FUNCTIONS[region]) {\n let list: unknown[]\n try {\n const response = await this.fetchImpl(traeEndpoint(base, TRAE_SOLO_MODELS_PATH), {\n method: 'POST',\n headers,\n body: JSON.stringify({\n function: directoryFunction,\n config_names: null,\n need_prompt: false,\n current_config_info: null,\n poly_prompt: true,\n mode_type: null,\n agent_type: null,\n }),\n signal: signal ?? AbortSignal.timeout(30_000),\n })\n if (!response.ok) throw new Error(`HTTP ${response.status}`)\n const document = await response.json() as Record<string, unknown>\n list = Array.isArray(document['config_info_list']) ? document['config_info_list'] : []\n } catch (error: unknown) {\n // One function failing must not hide the others' rosters.\n failures.push(`${directoryFunction}: ${String(error).slice(0, 80)}`)\n continue\n }\n this.collectModels(list, directoryFunction, byId)\n }\n const models = [...byId.values()]\n if (models.length === 0) {\n throw new Error(`Trae SOLO models response contained no models (${failures.join('; ') || 'empty directory'})`)\n }\n return models\n }\n\n /** Merge one function's config list into the shared catalogue (first wins). */\n private collectModels(list: readonly unknown[], directoryFunction: string, byId: Map<string, TraeSoloModel>): void {\n for (const raw of list) {\n if (typeof raw !== 'object' || raw === null) continue\n const config = raw as Record<string, unknown>\n const id = typeof config['config_name'] === 'string' ? config['config_name'] : ''\n if (id === '') continue\n const display = typeof config['display_config'] === 'object' && config['display_config'] !== null ? config['display_config'] as Record<string, unknown> : {}\n const details = Array.isArray(config['model_detail_list']) ? config['model_detail_list'] : []\n const detail = typeof details[0] === 'object' && details[0] !== null ? details[0] as Record<string, unknown> : {}\n // get_detail_param's real field names (verified 2026-08-30): the context\n // window is `model_detail_list[].prompt_max_tokens` (or the top-level\n // `context_window_tokens.dev`), and max output is `model_detail_list[].max_tokens`.\n // There are no `max_input_tokens` / `max_output_tokens` fields; reading them\n // made every row's windows nil. The wire `config_name` (what `llm_utils_chat`\n // accepts) is `config_name` itself \u2014 NOT `model_name` (a `__dev`/`__max`\n // variant that only names the underlying checkpoint).\n const contextTokens = typeof config['context_window_tokens'] === 'object' && config['context_window_tokens'] !== null ? config['context_window_tokens'] as Record<string, unknown> : {}\n const promptMaxTokens = finitePositive(detail['prompt_max_tokens'])\n const devTokens = finitePositive(contextTokens['dev'])\n const contextWindow = promptMaxTokens ?? devTokens\n const maxTokens = finitePositive(detail['max_tokens'])\n const reasoning = parseReasoningCapability({ ...config, ...detail })\n const creditMultiplier = wireCreditMultiplier(config)\n // First function to list a config_name owns it: TRAE_DIRECTORY_FUNCTIONS\n // is ordered by precedence, and this is what makes a model callable (the\n // chat call replays this exact function).\n if (byId.has(id)) continue\n byId.set(id, {\n id,\n name: typeof display['display_name'] === 'string' && display['display_name'] !== '' ? display['display_name'] : id,\n ...contextWindow === undefined ? {} : { contextWindow },\n ...maxTokens === undefined ? {} : { maxTokens },\n ...reasoning === undefined ? {} : { reasoning },\n ...creditMultiplier === undefined ? {} : { creditMultiplier },\n function: directoryFunction,\n })\n }\n }\n\n async chatStream(bodyJson: string, signal?: AbortSignal, functionName?: string): Promise<TraeChatResult> {\n let prepared: string\n try { prepared = prepareSoloBody(bodyJson, undefined, functionName) }\n catch { return { ok: false, status: 400, kind: 'client', message: 'invalid JSON request' } }\n const [credential, identity] = await Promise.all([this.options.credential(), this.options.identity()])\n const headers = buildTraeCnHeaders(credential, identity)\n const base = this.options.baseUrl ?? REGION_GATEWAYS[regionOfCredential(credential)].chat\n let response: Response\n try {\n response = await this.fetchImpl(traeEndpoint(base, TRAE_SOLO_CHAT_PATH), {\n method: 'POST', headers, body: prepared, signal: signal ?? AbortSignal.timeout(120_000),\n })\n } catch (error: unknown) {\n return { ok: false, status: 0, kind: 'server', message: `transport error: ${String(error)}` }\n }\n if (response.ok) return { ok: true, response }\n const text = (await response.text()).slice(0, 1024)\n this.options.log?.('dsh-connect-trae: llm_utils_chat rejected', {\n status: response.status,\n model: JSON.parse(prepared)['model'],\n configName: JSON.parse(prepared)['config_name'],\n reasoningEffort: JSON.parse(prepared)['reasoning_effort'],\n body: text,\n })\n return { ok: false, status: response.status, kind: classify(response.status), message: text || `Trae SOLO returned HTTP ${response.status}` }\n }\n}\n", "import type { TraeReasoningEffort } from './reasoning.ts'\n\nexport interface TraeModelContextWindows {\n dev?: number\n max?: number\n}\n\nexport interface TraeDiscoveredReasoning {\n supported: TraeReasoningEffort[]\n defaultEffort?: TraeReasoningEffort\n}\n\nexport interface TraeDiscoveredModel {\n id: string\n name: string\n multimodal: boolean\n contextWindow?: number\n maxContextWindow?: number\n creditMultiplier?: number\n reasoningSupported: boolean\n reasoning?: TraeDiscoveredReasoning\n}\n\ninterface RawTraeRemoteModel {\n name?: unknown\n display_name?: unknown\n multimodal?: unknown\n max_mode?: unknown\n context_window_tokens?: unknown\n reasoning_effort_config?: unknown\n features?: unknown\n}\n\nfunction finitePositive(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : undefined\n}\n\nfunction record(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? value as Record<string, unknown>\n : undefined\n}\n\nfunction parseFeatures(value: unknown): Record<string, unknown> | undefined {\n if (typeof value !== 'string' || value === '') return undefined\n try { return record(JSON.parse(value) as unknown) } catch { return undefined }\n}\n\nconst EFFORT_MAP: Readonly<Record<string, TraeReasoningEffort>> = {\n light: 'low',\n high: 'high',\n extra_high: 'xhigh',\n}\n\n/** Parse only capabilities explicitly advertised by Trae's remote model API. */\nexport function parseTraeRemoteModel(value: unknown): TraeDiscoveredModel | undefined {\n const raw = record(value) as RawTraeRemoteModel | undefined\n if (raw === undefined || typeof raw.name !== 'string' || raw.name === '') return undefined\n const context = record(raw.context_window_tokens)\n const dev = finitePositive(context?.['dev'])\n const max = raw.max_mode === true ? finitePositive(context?.['max']) : undefined\n const features = parseFeatures(raw.features)\n const consumption = record(features?.['consumption_rate'])\n const consumptionData = record(consumption?.['data'])\n const creditMultiplier = consumption?.['enable'] === true ? finitePositive(consumptionData?.['rate']) : undefined\n const reasoningFeature = record(features?.['reasoning'])\n const reasoningSupported = reasoningFeature?.['enable'] === true\n const reasoningConfig = record(raw.reasoning_effort_config)\n const rawOptions = Array.isArray(reasoningConfig?.['options']) ? reasoningConfig['options'] : []\n const supported = rawOptions.flatMap(option => {\n if (typeof option !== 'string') return []\n const effort = EFFORT_MAP[option]\n return effort === undefined ? [] : [effort]\n })\n const rawDefault = reasoningConfig?.['default_level']\n const mappedDefault = typeof rawDefault === 'string' ? EFFORT_MAP[rawDefault] : undefined\n const defaultEffort = mappedDefault !== undefined && supported.includes(mappedDefault) ? mappedDefault : undefined\n return {\n id: raw.name,\n name: typeof raw.display_name === 'string' && raw.display_name !== '' ? raw.display_name : raw.name,\n multimodal: raw.multimodal === true,\n ...dev === undefined ? {} : { contextWindow: dev },\n ...max === undefined ? {} : { maxContextWindow: max },\n ...creditMultiplier === undefined ? {} : { creditMultiplier },\n reasoningSupported,\n ...supported.length === 0 ? {} : { reasoning: { supported, ...defaultEffort === undefined ? {} : { defaultEffort } } },\n }\n}\n", "import type { TraeCredential } from './auth.ts'\nimport { parseTraeRemoteModel, type TraeDiscoveredModel } from './model-metadata.ts'\nimport { REGION_GATEWAYS, regionOfCredential, type TraeRegion } from './region.ts'\n\nexport const TRAE_SOLO_REMOTE_BASE = 'https://solo.trae.cn/api/remote/v1'\n\n/**\n * Remote-directory functions to ask for, per region.\n *\n * The remote `/models` answer is **grouped by function** and the groups are not\n * interchangeable (measured 2026-10-01, issue #19):\n *\n * ```\n * solo_agent : 19 models \u2190 superset; also the ONLY source of\n * gpt-6-astra / gpt-5.6-sol|terra|luna /\n * glm-5.2 / gpt-5.5 / Seed-2.1-Turbo\n * solo_agent_remote : 10 models \u2190 what this client used to read, and all it\n * read: the preferred group only\n * ```\n *\n * `solo_agent` \u2287 `solo_agent_remote`, so reading just the latter hid nine\n * models that the Trae IDE does show \u2014 exactly what the reporter saw. Both\n * groups are therefore requested, and every returned group is unioned.\n *\n * Asking for a function the gateway does not serve is harmless: unknown names\n * are ignored rather than rejected (`solo_work_remote` returns no group on\n * `ai`, and the request still answers HTTP 200).\n *\n * `chat_v3` was added on 2026-10-01 (issue #19 follow-up) because it carries\n * three ai-region models that appear in NO other group \u2014 `deepseek-v3.2`,\n * `gemini-3-flash-premium`, `gemini_2.5_flash_premium` \u2014 and those three are\n * callable through it (see TRAE_DIRECTORY_FUNCTIONS in solo.ts).\n *\n * Both regions now ask the SAME group list (2026-10-02). CN previously asked\n * only `solo_agent_remote` + `solo_work_remote`, which left its `solo_coder`\n * group (12 models) unread \u2014 the same shape of miss as the ai one. Every group\n * below was measured to exist on both gateways; a region that does not serve a\n * name simply returns no group for it, which the union tolerates. Reading costs\n * one query and the merge no longer discards rows for lacking a wire match (see\n * mergeTraeModelSources), so an unread group is a model silently missing from\n * the user's own list \u2014 the failure this list exists to prevent.\n *\n * `builder_v3` is included for the same reason even though neither region's\n * current wire lists name it: its rows are real directory entries, and whether\n * a paying account can call one is not something this client can determine.\n */\nexport const TRAE_REMOTE_DIRECTORY_FUNCTIONS: Readonly<Record<TraeRegion, readonly string[]>> = {\n cn: ['solo_agent', 'solo_agent_remote', 'solo_work_remote', 'solo_work_lite', 'chat_v3', 'solo_coder', 'builder_v3'],\n ai: ['solo_agent', 'solo_agent_remote', 'solo_work_remote', 'solo_work_lite', 'chat_v3', 'solo_coder', 'builder_v3'],\n}\n\nexport interface TraeSoloRemoteCatalogOptions {\n credential(): Promise<TraeCredential>\n fetchImpl?: typeof fetch\n baseUrl?: string\n}\n\n/**\n * Of two rows for the SAME model id, the one that advertises the stronger\n * capacity (issue #23).\n *\n * The gateway groups its directory by function and reports a model's capacity\n * per group, with the group order varying between calls. Keeping the strongest\n * row makes the published window deterministic. The comparison is\n * LEXICOGRAPHIC and must be applied all the way down, or ordering leaks back in\n * at the next field:\n *\n * 1. a row with a Max tier beats one without (`maxContextWindow` is only set\n * when the group reported `max_mode: true` with a positive max);\n * 2. two Max rows: the larger max wins;\n * 3. max equal (or absent on both): the WIDER dev window wins;\n * 4. both equal: keep the incumbent, so the model order stays the gateway's.\n *\n * Step 3 is not an afterthought. With equal `max` the first version of this\n * function stopped and kept the incumbent, which left the dev window decided by\n * arrival order \u2014 measured 2026-10-05: `glm-5.2` came back as `dev=116000` when\n * `chat_v3` won and `dev=200000` when `solo_agent_remote` did, both with\n * `max=1000000` (9 of 30 CN models behaved that way, reported by JiewiW on\n * Windows). A budgeted model still resolved to 1M either way, but the DEFAULT\n * window of an unbudgeted model \u2014 what DSH shows and compresses against \u2014 was\n * a coin flip, which is the same defect this function exists to remove.\n */\nexport function preferStrongerRow(\n candidate: TraeDiscoveredModel,\n incumbent: TraeDiscoveredModel | undefined,\n): TraeDiscoveredModel {\n if (incumbent === undefined) return candidate\n const candidateMax = candidate.maxContextWindow\n const incumbentMax = incumbent.maxContextWindow\n if (candidateMax !== undefined && incumbentMax === undefined) return candidate\n if (candidateMax === undefined && incumbentMax !== undefined) return incumbent\n if (candidateMax !== undefined && incumbentMax !== undefined && candidateMax !== incumbentMax) {\n return candidateMax > incumbentMax ? candidate : incumbent\n }\n // Equal Max (or neither advertises one): the wider dev window wins.\n return (candidate.contextWindow ?? 0) > (incumbent.contextWindow ?? 0) ? candidate : incumbent\n}\n\n/**\n * Region-scoped request dressing. The CN portal is `solo.trae.cn` with the\n * CN locale headers; the international directory lives on the shared\n * `coresg-normal.trae.ai` gateway and was verified (2026-09-15) with the\n * English/Singapore headers \u2014 both forms are accepted, each region keeps the\n * shape its own portal sends.\n */\nfunction remoteDressing(region: TraeRegion): { referer: string; timezone: string; language: string } {\n return region === 'ai'\n ? { referer: 'https://coresg-normal.trae.ai/', timezone: 'Asia/Singapore', language: 'en' }\n : { referer: 'https://solo.trae.cn/', timezone: 'Asia/Shanghai', language: 'zh-cn' }\n}\n\n/**\n * Read-only model catalog client for the SOLO Web API.\n *\n * This deliberately has no chat/session method: the Remote session protocol\n * only exposes a final answer and cannot preserve DSH's structured tool loop.\n */\nexport class TraeSoloRemoteCatalogClient {\n private readonly fetchImpl: typeof fetch\n private readonly baseUrl: string | undefined\n\n constructor(private readonly options: TraeSoloRemoteCatalogOptions) {\n this.fetchImpl = options.fetchImpl ?? fetch\n this.baseUrl = options.baseUrl\n }\n\n private async headers(region: TraeRegion): Promise<Record<string, string>> {\n const credential = await this.options.credential()\n const dressing = remoteDressing(region)\n return {\n 'Authorization': `Cloud-IDE-JWT ${credential.accessToken}`,\n 'Content-Type': 'application/json',\n 'x-trae-client-type': 'web',\n 'x-trae-user-timezone': dressing.timezone,\n 'x-preferenced-language': dressing.language,\n 'Referer': dressing.referer,\n 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',\n }\n }\n\n async fetchModels(signal?: AbortSignal): Promise<TraeDiscoveredModel[]> {\n // The directory gateway follows the credential's own region; an explicit\n // baseUrl (tests, diagnostics) still pins the endpoint.\n const credential = await this.options.credential()\n const region = regionOfCredential(credential)\n const base = this.baseUrl ?? REGION_GATEWAYS[region].remote\n const headers = await this.headers(region)\n const functions = TRAE_REMOTE_DIRECTORY_FUNCTIONS[region].join(',')\n const response = await this.fetchImpl(`${base}/models?functions=${functions}`, { headers, signal: signal ?? AbortSignal.timeout(30_000) })\n if (!response.ok) throw new Error(`SOLO remote models returned HTTP ${response.status}`)\n const json = await response.json() as { code?: number; data?: { list?: { function?: string; models?: unknown[] }[] } }\n const groups = json.data?.list ?? []\n // Union EVERY group, not just the preferred one. Each group is a roster the\n // gateway is willing to serve; a model listed by any of them is a model the\n // IDE can offer, and the wire join downstream (see mergeTraeModelSources)\n // is what decides whether it is actually callable. Restricting this to\n // `solo_agent_remote` dropped the nine models issue #19 was opened about.\n //\n // A model appears in SEVERAL groups and the groups disagree about its\n // capacity, so dedupe keeps the MOST CAPABLE row rather than the first one\n // (issue #23). \"First wins\" assumed the group order was stable; measured\n // 2026-10-05 on a live CN credential it is not \u2014 five calls returned five\n // different orders \u2014 so the published window became a coin flip:\n // `Doubao-Seed-2.1-Pro` came back as `116000`/no-Max (`builder_v3`), or\n // `256000`/no-Max (`solo_work_*`), or `256000`/`1000000` (`chat_v3`,\n // `solo_agent*`) depending on which group answered first. The Max tier is\n // the one users enable in the IDE, and `applyContextBudgets` can only raise\n // a window to `maxContextWindow` \u2014 so losing that field silently capped\n // every configured 1M model at 256K or less, and DSH compressed far earlier\n // than the chosen budget implied.\n //\n // Ordering rule: a row advertising a Max tier beats one that does not, a\n // larger Max wins over a smaller one, and with no Max on either side the\n // wider dev window wins. Every row for one id carries the same\n // `multimodal` / `reasoning` / credit facts (verified the same day), so\n // choosing on capacity loses no capability. The result no longer depends on\n // the gateway's group order.\n const byId = new Map<string, TraeDiscoveredModel>()\n for (const group of groups) {\n for (const raw of group.models ?? []) {\n const model = parseTraeRemoteModel(raw)\n if (model === undefined) continue\n byId.set(model.id, preferStrongerRow(model, byId.get(model.id)))\n }\n }\n const models = [...byId.values()]\n if (models.length === 0) throw new Error('SOLO remote models response contained no models')\n return models\n }\n}\n", "import { randomUUID } from 'node:crypto'\nimport { SseDecoder, decodeTraeEvent } from './sse.ts'\nimport type { TraeCatalog } from './catalog.ts'\nimport type { TraeChatResult, TraeUpstreamClient, TraeUpstreamErrorKind } from './upstream.ts'\n\ninterface OpenAIToolCallDelta {\n index: number\n id?: string\n type?: 'function'\n function?: { name?: string; arguments?: string }\n}\n\n/**\n * One upstream failure as Trae reports it inside a 200 SSE body: an `error`\n * event, or any event carrying a `code` at or above Trae's error band.\n */\ninterface TraeFailure {\n code?: number\n message: string\n extra?: unknown\n}\n\n/**\n * What Trae's in-stream error codes mean. Measured 2026-10-01 on live\n * credentials (issue #19), and re-measured 2026-10-12 on a live CN credential\n * (issue #33) with a 22-function \u00D7 6-model chat matrix:\n *\n * - `1005` \u2014 the model needs a paid plan. Trae answers HTTP 200 with\n * `event:error {\"code\":1005,\"message\":\"\",\"extra\":\"{\\\"plan\\\":1}\"}`, so the\n * gate is only visible in `extra.plan`; `gpt-6-sol` returned it under both\n * `solo_work_remote` and `solo_agent_remote` on a free account.\n * - `4011` \u2014 Trae throttled the SOLO route for this account. Trae's own text\n * is `your requests have exceeded the rate limit. Please wait and try again\n * later.`, and issue #33 is why that text is now taken at face value: the\n * earlier reading of 4011 as \"this function does not serve that model\" is\n * contradicted by measurement. On CN that condition is `4001`, and all 22\n * functions answered `4001` \u2014 never `4011` \u2014 for a model absent from their\n * roster, while `glm-5.3` streamed normally under its own function. Rate\n * limiting is per account, route and moment, which is exactly the shape of\n * that report: the same model through the same function was fine for days\n * and then failed, with Trae's own text saying \"rate limit\".\n * - `4001` \u2014 `config_name` is not one this function serves.\n * - `4008` \u2014 the account's SOLO quota is exhausted. Deliberately a different\n * code from `4011`: Trae words this one `your requests have exceeded the\n * quota`, so \"I still have plenty of credits\" and \"I am being throttled\" are\n * two different statements, and a user hits the second without touching the\n * first (issue #33).\n * - `4023` \u2014 the model name is unknown on the route that was asked.\n */\nconst TRAE_ERROR_HINTS: Readonly<Record<number, string>> = {\n 1005: 'Trae requires a paid plan for this model; the current account\\'s plan does not cover it',\n 4001: 'Trae does not serve this model under the SOLO function the request used (config_name rejected)',\n 4008: 'Trae reports the account\\'s SOLO quota is exhausted for this request',\n 4011: 'Trae throttled the SOLO channel for this account (a rate limit, not the credit balance)',\n 4023: 'Trae does not recognise this model name on the SOLO route that was asked',\n}\n\n/** `extra` is a JSON *string* on the wire; unwrap it to read `plan`. */\nfunction traeErrorPlan(extra: unknown): number | undefined {\n let value = extra\n if (typeof value === 'string') {\n try { value = JSON.parse(value) as unknown } catch { return undefined }\n }\n if (typeof value !== 'object' || value === null) return undefined\n const plan = (value as Record<string, unknown>)['plan']\n return typeof plan === 'number' ? plan : undefined\n}\n\n/** A readable message for an in-stream Trae failure, with its code preserved. */\nexport function describeTraeFailure(failure: TraeFailure): string {\n const plan = traeErrorPlan(failure.extra)\n const parts = [\n failure.code === undefined ? 'Trae refused the request' : TRAE_ERROR_HINTS[failure.code] ?? 'Trae refused the request',\n ...plan === undefined ? [] : [`plan ${plan}`],\n ...failure.code === undefined ? [] : [`Trae code ${failure.code}`],\n ]\n const detail = failure.message.trim()\n // Trae's own text is appended as detail rather than replacing the hint, so the\n // message carries both the plugin's reading of the code and the upstream's own\n // words. It is NOT dropped: the client classifies an error by this text (see\n // classifyTraeFailure), and upstream wording is evidence \u2014 issue #33 showed\n // the plugin's own 4011 hint asserting a cause Trae's text contradicted.\n return detail === '' ? parts.join(' \u00B7 ') : `${parts.join(' \u00B7 ')} \u00B7 upstream: ${detail}`\n}\n\n/**\n * HTTP status + error kind for an in-stream failure, so the loopback shim can\n * answer with a real error instead of a truncated 200 stream.\n *\n * `1005` is a subscription gate: 402 is what makes clients stop rather than\n * retry, and it is truthful.\n *\n * `4011` is a rate limit and is reported as one \u2014 `429` / `soft_rate` (issue\n * #33). It previously answered `400` / `client`, which contradicted both its own\n * message and the client's own behaviour: pi-ai classifies an error by its text\n * (`/\\b429\\b|rate.?limit/i` \u2192 `RATE_LIMIT`), and `RATE_LIMIT` is retryable, so\n * the kernel retried five times with backoff while this function called the same\n * failure a non-retryable client error. Reporting the real status makes all\n * three agree, and `soft_rate` is already what `fallback-upstream` refuses to\n * replay \u2014 correct, since a throttled route is not a route-compatibility\n * problem.\n *\n * Everything else stays a client-side rejection.\n */\nfunction classifyTraeFailure(failure: TraeFailure): { status: number; kind: TraeUpstreamErrorKind } {\n if (failure.code === 1005) return { status: 402, kind: 'hard_credit' }\n if (failure.code === 4011) return { status: 429, kind: 'soft_rate' }\n return { status: 400, kind: 'client' }\n}\n\n/** Recognise an in-stream failure event, or return undefined for anything else. */\nfunction traeFailureOf(decoded: ReturnType<typeof decodeTraeEvent>): TraeFailure | undefined {\n if (decoded.type !== 'unknown') return undefined\n const payload = decoded.data as Record<string, unknown> | undefined\n const code = typeof payload?.['code'] === 'number' ? payload['code'] : undefined\n if (decoded.event !== 'error' && !(code !== undefined && code >= 4000)) return undefined\n return {\n ...code === undefined ? {} : { code },\n message: typeof payload?.['message'] === 'string' ? payload['message'] : '',\n ...payload?.['extra'] === undefined ? {} : { extra: payload['extra'] },\n }\n}\n\nfunction normalizeToolCalls(value: unknown): OpenAIToolCallDelta[] {\n if (!Array.isArray(value)) return []\n const calls: OpenAIToolCallDelta[] = []\n for (const raw of value) {\n if (typeof raw !== 'object' || raw === null) continue\n const record = raw as Record<string, unknown>\n const rawFunction = typeof record['function_call'] === 'object' && record['function_call'] !== null\n ? record['function_call'] as Record<string, unknown>\n : typeof record['function'] === 'object' && record['function'] !== null\n ? record['function'] as Record<string, unknown>\n : {}\n const fn = {\n ...typeof rawFunction['name'] === 'string' ? { name: rawFunction['name'] } : {},\n ...typeof rawFunction['arguments'] === 'string' ? { arguments: rawFunction['arguments'] } : {},\n }\n calls.push({\n index: typeof record['index'] === 'number' ? record['index'] : calls.length,\n ...typeof record['id'] === 'string' ? { id: record['id'] } : {},\n ...record['type'] === 'function' ? { type: 'function' as const } : {},\n ...Object.keys(fn).length === 0 ? {} : { function: fn },\n })\n }\n return calls\n}\n\n/** Convert Trae's named SSE events into OpenAI chat-completion SSE chunks. */\nexport function bridgeTraeSoloStream(response: Response, model: string): Response {\n const source = response.body\n if (source === null) return new Response(null, { status: 502 })\n return bridgeTraeSource(source, model)\n}\n\n/** {@link bridgeTraeSoloStream} over an already-opened byte stream. */\nfunction bridgeTraeSource(source: ReadableStream<Uint8Array>, model: string): Response {\n const id = `chatcmpl-${randomUUID().replaceAll('-', '').slice(0, 24)}`\n const created = Math.floor(Date.now() / 1000)\n const decoder = new TextDecoder()\n const encoder = new TextEncoder()\n const sse = new SseDecoder()\n let sawToolCalls = false\n let emittedFinishReason = false\n let upstreamEnded = false\n let upstreamError: Error | undefined\n // OpenAI-shaped usage object. It is mostly flat counters, but\n // `prompt_tokens_details` nests the cache breakdown, so the value type is\n // widened beyond `number` rather than narrowing the cache fields away.\n let usage: Record<string, number | Record<string, number>> | undefined\n\n const chunk = (delta: Record<string, unknown>, finishReason: string | null = null): Uint8Array => encoder.encode(`data: ${JSON.stringify({\n id,\n object: 'chat.completion.chunk',\n created,\n model,\n choices: [{ index: 0, delta, finish_reason: finishReason }],\n ...usage === undefined ? {} : { usage },\n })}\\n\\n`)\n\n const stream = new ReadableStream<Uint8Array>({\n async start(controller) {\n const reader = source.getReader()\n const consume = (event: ReturnType<SseDecoder['push']>[number]): void => {\n const decoded = decodeTraeEvent(event)\n if (decoded.type === 'unknown') {\n const failure = traeFailureOf(decoded)\n if (failure !== undefined) {\n // Trae surfaces quota/authorisation failures as an `error` event.\n // Surface it as a real upstream failure instead of letting DSH see\n // a completed-but-empty response (EMPTY_RESPONSE). Codes that arrive\n // before any output are turned into a real HTTP error by\n // {@link bridgeTraeSoloStreamOrFail}, which is the path the bridge\n // actually uses; this arm only covers a failure that interrupts an\n // already-streaming answer.\n upstreamError = new Error(describeTraeFailure(failure))\n }\n return\n }\n if (decoded.type === 'delta') {\n const delta: Record<string, unknown> = {}\n if (decoded.text !== '') delta['content'] = decoded.text\n if (decoded.reasoning !== undefined && decoded.reasoning !== '') delta['reasoning_content'] = decoded.reasoning\n const toolCalls = normalizeToolCalls(decoded.toolCalls)\n if (toolCalls.length > 0) {\n sawToolCalls = true\n delta['tool_calls'] = toolCalls\n }\n if (Object.keys(delta).length > 0) controller.enqueue(chunk(delta))\n } else if (decoded.type === 'usage') {\n // Trae reports cache accounting as `cache_read_input_tokens` /\n // `cache_creation_input_tokens`, a subset of `prompt_tokens` (OpenAI\n // convention, verified in docs/ISSUE10_DIAGNOSIS.md). Both are\n // forwarded under the canonical OpenAI spelling, which is what\n // pi-ai's parseChunkUsage reads (`prompt_tokens_details.cached_tokens`\n // / `.cache_write_tokens`); dropping them made every session report\n // \"0 cache\" even when Trae was serving a warm prefix cache.\n const cacheRead = decoded.cacheReadTokens\n const cacheWrite = decoded.cacheWriteTokens\n const details = {\n ...cacheRead === undefined ? {} : { cached_tokens: cacheRead },\n ...cacheWrite === undefined ? {} : { cache_write_tokens: cacheWrite },\n }\n usage = {\n ...decoded.inputTokens === undefined ? {} : { prompt_tokens: decoded.inputTokens },\n ...decoded.outputTokens === undefined ? {} : { completion_tokens: decoded.outputTokens },\n ...decoded.totalTokens === undefined ? {} : { total_tokens: decoded.totalTokens },\n // Omit the details object entirely when Trae sent neither field, so\n // a provider that never reports cache keeps its previous wire shape\n // instead of gaining `prompt_tokens_details: {}`.\n ...Object.keys(details).length === 0 ? {} : { prompt_tokens_details: details },\n }\n } else if (decoded.type === 'done') {\n upstreamEnded = true\n // Trae may send both `event: done` and a trailing `[DONE]`. Emit one\n // OpenAI finish chunk only; pi-ai requires a non-null finish_reason\n // before the stream closes.\n if (!emittedFinishReason) {\n // Mark the terminal state before erroring the controller so the\n // post-loop fallback never enqueues after controller.error().\n emittedFinishReason = true\n if (upstreamError !== undefined) {\n controller.error(upstreamError)\n return\n }\n controller.enqueue(chunk({}, sawToolCalls ? 'tool_calls' : decoded.finishReason || 'stop'))\n }\n }\n }\n try {\n while (true) {\n const next = await reader.read()\n if (next.done) break\n for (const event of sse.push(decoder.decode(next.value, { stream: true }))) consume(event)\n }\n for (const event of sse.finish()) consume(event)\n if (upstreamError !== undefined && !upstreamEnded) {\n controller.error(upstreamError)\n return\n }\n // A clean EOF is a valid Trae termination even when it omits an\n // explicit done event. Synthesize the required OpenAI finish chunk.\n if (!emittedFinishReason) {\n emittedFinishReason = true\n controller.enqueue(chunk({}, sawToolCalls ? 'tool_calls' : 'stop'))\n }\n controller.enqueue(encoder.encode('data: [DONE]\\n\\n'))\n controller.close()\n } catch (error) {\n controller.error(error)\n } finally {\n reader.releaseLock()\n }\n },\n cancel(reason) { return source.cancel(reason) },\n })\n return new Response(stream, { status: 200, headers: { 'Content-Type': 'text/event-stream' } })\n}\n\n/**\n * How far {@link openTraeSource} reads before giving up on finding a failure.\n * Trae opens a real answer with small `metadata` / `timing_cost` events, so a\n * healthy stream is recognised well inside these bounds; they exist only so a\n * pathological stream cannot stall the response headers.\n */\nconst PEEK_MAX_CHUNKS = 64\nconst PEEK_MAX_BYTES = 262_144\n\n/** Replay the bytes the peek consumed, then drain the rest of the upstream. */\nfunction replayTraeSource(\n buffered: readonly Uint8Array[],\n reader: ReadableStreamDefaultReader<Uint8Array>,\n ended: boolean,\n): ReadableStream<Uint8Array> {\n let index = 0\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n const chunk = buffered[index]\n if (chunk !== undefined) {\n index += 1\n controller.enqueue(chunk)\n return\n }\n if (ended) { controller.close(); return }\n const next = await reader.read()\n if (next.done) { controller.close(); return }\n controller.enqueue(next.value)\n },\n async cancel(reason) { await reader.cancel(reason).catch(() => {}) },\n })\n}\n\n/**\n * Open the upstream answer, failing fast when Trae refuses BEFORE producing any\n * output.\n *\n * This exists because Trae reports authorisation and subscription failures\n * inside a **200** SSE body. Relaying that as a 200 and aborting mid-stream\n * (what this bridge used to do) loses the code at the HTTP boundary: pi-ai only\n * sees a truncated stream and reports `Stream ended without finish_reason`,\n * which reads as a network fault and is retried five times \u2014 the exact symptom\n * in issue #19. Peeking until the first real output lets a refusal become a\n * normal error response with its code and plan intact.\n *\n * The peek is limited to the head of the stream and replayed verbatim, so a\n * healthy answer keeps streaming with no buffering beyond the first event.\n */\nasync function openTraeSource(response: Response): Promise<\n { ok: true; source: ReadableStream<Uint8Array> } | { ok: false; status: number; kind: TraeUpstreamErrorKind; message: string }\n> {\n const body = response.body\n if (body === null) return { ok: false, status: 502, kind: 'server', message: 'Trae upstream returned no response body' }\n const reader = body.getReader()\n const decoder = new TextDecoder()\n const sse = new SseDecoder()\n const buffered: Uint8Array[] = []\n let bytes = 0\n let ended = false\n try {\n while (buffered.length < PEEK_MAX_CHUNKS && bytes < PEEK_MAX_BYTES) {\n const next = await reader.read()\n if (next.done) { ended = true; break }\n buffered.push(next.value)\n bytes += next.value.byteLength\n let answered = false\n for (const event of sse.push(decoder.decode(next.value, { stream: true }))) {\n const decoded = decodeTraeEvent(event)\n const failure = traeFailureOf(decoded)\n if (failure !== undefined) {\n await reader.cancel().catch(() => {})\n return { ok: false, ...classifyTraeFailure(failure), message: describeTraeFailure(failure) }\n }\n // Anything Trae itself recognises (`delta`, `usage`, `queue`,\n // `progress`, `done`) means it accepted the request; stop peeking and\n // stream from here.\n if (decoded.type !== 'unknown') answered = true\n }\n if (answered) break\n }\n } catch (error) {\n reader.releaseLock()\n return { ok: false, status: 0, kind: 'server', message: `transport error: ${String(error)}` }\n }\n return { ok: true, source: replayTraeSource(buffered, reader, ended) }\n}\n\n/**\n * Bridge an upstream answer, turning an early refusal into a real error result.\n *\n * The sibling {@link bridgeTraeSoloStream} stays synchronous and always answers\n * 200; it is the primitive, and this is the policy the bridge class uses.\n */\nexport async function bridgeTraeSoloStreamOrFail(response: Response, model: string): Promise<TraeChatResult> {\n const opened = await openTraeSource(response)\n if (!opened.ok) return opened\n return { ok: true, response: bridgeTraeSource(opened.source, model) }\n}\n\n/**\n * One resolved wire target: the `config_name` `llm_utils_chat` accepts, plus\n * the directory function that listed it. Trae's roster is split across several\n * SOLO-mode functions and a model is only callable through the one listing it\n * (glm-5.3 answers only under `solo_work_remote`), so the chat call replays it.\n */\nexport interface TraeWireTarget {\n configName: string\n function?: string\n}\n\n/** Resolves a display model id to its wire target (config_name + function). */\nexport type TraeWireResolver = (displayId: string) => TraeWireTarget | undefined\n\n/** Native SOLO client wrapper used by the loopback OpenAI adapter. */\nexport class TraeSoloBridge implements TraeUpstreamClient {\n constructor(\n private readonly upstream: TraeUpstreamClient,\n private readonly catalog?: Pick<TraeCatalog, 'current'>,\n private readonly wireResolver?: TraeWireResolver,\n ) {}\n\n async chatStream(bodyJson: string, signal?: AbortSignal): Promise<TraeChatResult> {\n // The model id doubles as the SSE chunk label; one model = one id, so the\n // label is exactly what DSH requested. DSH may retain a reasoning selection\n // while switching models: strip that stale option unless this exact model\n // advertises the corresponding wire value.\n let model = 'glm-5.2'\n let prepared = bodyJson\n try {\n const input = JSON.parse(bodyJson) as Record<string, unknown>\n if (typeof input['model'] === 'string' && input['model'] !== '') model = input['model']\n // Resolve the display model id to the real llm_utils_chat config_name.\n // The Remote directory id may differ from the wire id (e.g. Seed-Code).\n // Prefer the persisted catalog's `wireConfigName` when present, then fall\n // back to the startup wire resolver keyed by display name/id; the resolver\n // never depends on a user-refreshed or re-saved directory.\n const entry = this.catalog?.current().find(item => item.id === model)\n // The catalog row carries both halves once discovery has run; the\n // resolver covers ids that came from elsewhere (startup wire map).\n const fromCatalog = entry?.wireConfigName === undefined\n ? undefined\n : { configName: entry.wireConfigName, ...entry.wireFunction === undefined ? {} : { function: entry.wireFunction } }\n const fromResolver = this.wireResolver?.(model) ?? this.wireResolver?.(entry?.name ?? '')\n const target = fromCatalog ?? fromResolver\n const wireModel = target?.configName ?? model\n const wireFunction = target?.function ?? entry?.wireFunction\n if (wireModel !== input['model']) {\n input['model'] = wireModel\n }\n // Stamp the directory function the model was discovered under, so the\n // upstream is asked through the function that actually lists it.\n if (wireFunction !== undefined && input['function'] !== wireFunction) {\n input['function'] = wireFunction\n }\n if (wireModel !== JSON.parse(bodyJson)['model'] || wireFunction !== undefined) {\n prepared = JSON.stringify(input)\n }\n if (typeof input['reasoning_effort'] === 'string') {\n const info = entry\n const efforts = info?.reasoningEfforts\n const requested = input['reasoning_effort']\n const mapped = efforts?.[requested as keyof typeof efforts]\n const allowed = efforts === undefined\n ? []\n : Object.values(efforts).filter((value): value is string => typeof value === 'string')\n if (typeof mapped === 'string') input['reasoning_effort'] = mapped\n else if (!allowed.includes(requested)) delete input['reasoning_effort']\n prepared = JSON.stringify(input)\n }\n } catch {\n return { ok: false, status: 400, kind: 'client', message: 'invalid JSON request' }\n }\n const result = await this.upstream.chatStream(prepared, signal)\n if (!result.ok) return result\n return await bridgeTraeSoloStreamOrFail(result.response, model)\n }\n}\n", "export interface SseEvent {\n event?: string\n data: string\n id?: string\n retry?: number\n}\n\n/** Incremental SSE decoder supporting CRLF, chunk splits and multi-line data. */\nexport class SseDecoder {\n private buffer = ''\n private event: string | undefined\n private id: string | undefined\n private retry: number | undefined\n private data: string[] = []\n\n push(chunk: string): SseEvent[] {\n this.buffer += chunk\n const events: SseEvent[] = []\n while (true) {\n const match = /\\r?\\n/.exec(this.buffer)\n if (match === null || match.index === undefined) break\n const line = this.buffer.slice(0, match.index)\n this.buffer = this.buffer.slice(match.index + match[0].length)\n const emitted = this.consumeLine(line)\n if (emitted !== undefined) events.push(emitted)\n }\n return events\n }\n\n finish(): SseEvent[] {\n const events: SseEvent[] = []\n if (this.buffer !== '') {\n const emitted = this.consumeLine(this.buffer)\n this.buffer = ''\n if (emitted !== undefined) events.push(emitted)\n }\n const final = this.dispatch()\n if (final !== undefined) events.push(final)\n return events\n }\n\n private consumeLine(line: string): SseEvent | undefined {\n if (line === '') return this.dispatch()\n if (line.startsWith(':')) return undefined\n const colon = line.indexOf(':')\n const field = colon === -1 ? line : line.slice(0, colon)\n let value = colon === -1 ? '' : line.slice(colon + 1)\n if (value.startsWith(' ')) value = value.slice(1)\n if (field === 'event') this.event = value\n else if (field === 'data') this.data.push(value)\n else if (field === 'id' && !value.includes('\\0')) this.id = value\n else if (field === 'retry' && /^\\d+$/.test(value)) this.retry = Number(value)\n return undefined\n }\n\n private dispatch(): SseEvent | undefined {\n if (this.data.length === 0) {\n this.event = undefined\n this.retry = undefined\n return undefined\n }\n const result: SseEvent = {\n ...this.event === undefined || this.event === '' ? {} : { event: this.event },\n data: this.data.join('\\n'),\n ...this.id === undefined ? {} : { id: this.id },\n ...this.retry === undefined ? {} : { retry: this.retry },\n }\n this.event = undefined\n this.retry = undefined\n this.data = []\n return result\n }\n}\n\nexport type TraeStreamEvent =\n | { type: 'queue'; position?: number }\n | { type: 'progress'; notice: unknown }\n | { type: 'delta'; text: string; reasoning?: string; toolCalls?: unknown }\n | {\n type: 'usage'\n inputTokens?: number\n outputTokens?: number\n totalTokens?: number\n reasoningTokens?: number\n /**\n * Trae's prompt-cache accounting (`cache_read_input_tokens` /\n * `cache_creation_input_tokens` on the `token_usage` event). Verified\n * 2026-09-22 (docs/ISSUE10_DIAGNOSIS.md): a byte-identical 9224-token\n * prompt reports `prompt_tokens: 9224` while `cache_read_input_tokens`\n * rises to 9216, so these are a *subset* of `prompt_tokens` \u2014 the OpenAI\n * convention, not Anthropic's exclusive one. Forwarding them as\n * `cached_tokens` is therefore arithmetically correct.\n */\n cacheReadTokens?: number\n cacheWriteTokens?: number\n }\n | { type: 'done'; finishReason: string }\n | { type: 'unknown'; event?: string; data: unknown }\n\nexport function decodeTraeEvent(event: SseEvent): TraeStreamEvent {\n if (event.data === '[DONE]') return { type: 'done', finishReason: 'stop' }\n let payload: unknown\n try { payload = JSON.parse(event.data) as unknown } catch { return { type: 'unknown', ...event.event === undefined ? {} : { event: event.event }, data: event.data } }\n const record = typeof payload === 'object' && payload !== null && !Array.isArray(payload) ? payload as Record<string, unknown> : {}\n if (event.event === 'request_wait_in_queue') {\n return { type: 'queue', ...typeof record['position'] === 'number' ? { position: record['position'] } : {} }\n }\n if (event.event === 'progress_notice') return { type: 'progress', notice: payload }\n if (event.event === 'token_usage') {\n return {\n type: 'usage',\n ...typeof record['prompt_tokens'] === 'number' ? { inputTokens: record['prompt_tokens'] } : {},\n ...typeof record['completion_tokens'] === 'number' ? { outputTokens: record['completion_tokens'] } : {},\n ...typeof record['total_tokens'] === 'number' ? { totalTokens: record['total_tokens'] } : {},\n ...typeof record['reasoning_tokens'] === 'number' ? { reasoningTokens: record['reasoning_tokens'] } : {},\n ...typeof record['cache_read_input_tokens'] === 'number' ? { cacheReadTokens: record['cache_read_input_tokens'] } : {},\n ...typeof record['cache_creation_input_tokens'] === 'number' ? { cacheWriteTokens: record['cache_creation_input_tokens'] } : {},\n }\n }\n if (event.event === 'done' || typeof record['finish_reason'] === 'string' && record['response'] === undefined) {\n return { type: 'done', finishReason: typeof record['finish_reason'] === 'string' ? record['finish_reason'] : 'stop' }\n }\n if (event.event === 'output' || record['response'] !== undefined || record['reasoning_content'] !== undefined) {\n return {\n type: 'delta',\n text: typeof record['response'] === 'string' ? record['response'] : '',\n ...typeof record['reasoning_content'] === 'string' ? { reasoning: record['reasoning_content'] } : {},\n ...record['tool_calls'] === undefined || record['tool_calls'] === null ? {} : { toolCalls: record['tool_calls'] },\n }\n }\n return { type: 'unknown', ...event.event === undefined ? {} : { event: event.event }, data: payload }\n}\n", "import type { TraeDiscoveredModel, TraeDiscoveredReasoning } from './model-metadata.ts'\nimport type { TraeReasoningEffort } from './reasoning.ts'\nimport type { TraeReasoningCapability } from './reasoning.ts'\nimport type { TraeRegion } from './region.ts'\n\nexport type TraeInputModality = 'text' | 'image'\n\n/**\n * One model the adapter exposes. `contextWindow` is the effective DSH context\n * after the user's budget; `maxContextWindow` is the native Max window Trae\n * advertises (capability display only \u2014 never a second model entry).\n */\nexport interface TraeModelInfo {\n id: string\n name: string\n contextWindow?: number\n maxTokens?: number\n input?: TraeInputModality[]\n creditMultiplier?: number\n reasoningSupported?: boolean\n reasoning?: TraeDiscoveredReasoning\n reasoningEfforts?: Partial<Record<TraeReasoningEffort, string | null>>\n maxContextWindow?: number\n /** The `config_name` `llm_utils_chat` accepts; absent means `id` is already the wire id. */\n wireConfigName?: string\n /** The directory function this model must be called through (see {@link TraeWireModel.function}). */\n wireFunction?: string\n /**\n * Trae's own `multimodal` flag for this model, carried through from the\n * directory that advertised it. It is the upstream's answer to \"does this\n * model read images\", and {@link applyImageSelection} unions it with the\n * user's explicit opt-ins.\n *\n * Deliberately NOT the same thing as `input`: `input` is what DSH is told\n * this route accepts, while this field records what Trae said. Keeping both\n * lets a future refresh re-derive `input` without losing the upstream fact,\n * and lets the card explain WHY a model is image-capable.\n *\n * Absent means the directory did not say (an older `lastCatalog` saved before\n * this field existed, a fallback row, or a directory entry that omitted the\n * key). Absent is treated as false, never as \"assume capable\": sending an\n * image to a model that cannot read one burns credits for a silent failure.\n */\n multimodal?: boolean\n}\n\n/**\n * Bootstrap catalog: identity only where current Trae metadata has not been\n * fetched yet.\n *\n * Every id here must be a `config_name` that `llm_utils_chat` actually accepts,\n * because this list is served verbatim before the first live refresh lands and\n * it is NOT filtered against the wire map (the wire map can only confirm ids it\n * happens to know, so filtering would delete the safety net exactly when it is\n * needed \u2014 see `fallbackModels` in index.ts). The current CN roster was\n * verified against the live remote directory on 2026-09-15\n * (docs/DS41_CALLABILITY.md): `DeepSeek-V4-Flash-Official` and\n * `DeepSeek-V4-Pro-Official` carry the `-Official` suffix, and there is no\n * `auto` config_name \u2014 an `auto` row was previously served here and would have\n * failed on selection.\n *\n * Every row MUST also carry a positive-integer `contextWindow`. DSH rejects an\n * adapter whose model has no usable context (`INVALID_MODEL_CONTEXT`), and that\n * failure is per-provider \u2014 one bad row takes the whole region offline. These\n * rows are exactly the ones served when no live directory is available (no\n * install for that region, signed out, or a failed refresh), which is precisely\n * when the fallback is doing its job, so a missing field here is fatal rather\n * than cosmetic. See docs/ISSUE8_DIAGNOSIS.md.\n */\nexport const FALLBACK_TRAE_MODELS: readonly TraeModelInfo[] = [\n { id: 'DeepSeek-V4-Flash-Official', name: 'DeepSeek-V4-Flash', contextWindow: 200_000 },\n { id: 'DeepSeek-V4-Pro-Official', name: 'DeepSeek-V4-Pro', contextWindow: 200_000 },\n { id: 'glm-5.2', name: 'GLM-5.2', contextWindow: 200_000 },\n { id: 'kimi-k2.6', name: 'Kimi-K2.6', contextWindow: 200_000 },\n]\n\n/**\n * Bootstrap catalog for the international (ai) region, captured from the\n * live `coresg-normal.trae.ai/api/remote/v1/models` directory on 2026-09-15\n * (docs/INTL_SG_EVIDENCE.md \u00A73). The two rosters barely overlap (the CN list\n * has no Gemini/GPT/MiniMax entries), so an international account must never\n * be seeded with the CN list. Like the CN fallback it is replaced by the live\n * refresh; image input stays the user's explicit opt-in (`imageModelIds`).\n *\n * The `contextWindow` values are the measured ones from that same capture\n * (`docs/INTL_SG_EVIDENCE.md` \u00A73) and are required for the same reason as the\n * CN fallback: without them the whole `trae-global` provider fails to load.\n */\nexport const FALLBACK_TRAE_MODELS_AI: readonly TraeModelInfo[] = [\n { id: 'gemini-3.1-pro', name: 'Gemini-3.1-Pro-Preview', contextWindow: 200_000 },\n { id: 'gemini-3-flash-solo', name: 'Gemini-3-Flash-Preview', contextWindow: 200_000 },\n { id: 'minimax-m3', name: 'MiniMax-M3', contextWindow: 200_000 },\n { id: 'minimax-m2.7', name: 'MiniMax-M2.7', contextWindow: 200_000 },\n { id: 'kimi-k2.5', name: 'Kimi-K2.5', contextWindow: 200_000 },\n { id: 'gpt-5.4', name: 'GPT-5.4', contextWindow: 272_000 },\n { id: 'gpt-5.2', name: 'GPT-5.2', contextWindow: 272_000 },\n]\n\n/**\n * Static fallback directory for a region. Each region keeps its own model\n * slot in settings; the fallback must match the region so an account never\n * shows the other region's roster.\n */\nexport function fallbackModelsFor(region: TraeRegion): readonly TraeModelInfo[] {\n return region === 'ai' ? FALLBACK_TRAE_MODELS_AI : FALLBACK_TRAE_MODELS\n}\n\n/** Exact DSH modalities for one catalog entry; absent metadata is text-only. */\nexport function traeInputModalities(model: Pick<TraeModelInfo, 'input'>): TraeInputModality[] {\n return [...(model.input ?? ['text'])]\n}\n\n/**\n * Compose the DSH-facing model name: Trae's own model picker renders each\n * entry as `Name \u00B7 x<rate>`, so the credit multiplier is shown inside the\n * name. `TraeModelInfo.name` keeps the pure Trae display name \u2014 every join\n * (wire resolution, callable-key filtering) must keep matching the\n * undecorated name; only the model rows handed to DSH (adapter catalog and\n * model discovery) use this decorated name.\n */\nexport function traeModelDisplayName(model: Pick<TraeModelInfo, 'name' | 'creditMultiplier'>): string {\n return model.creditMultiplier === undefined\n ? model.name\n : `${model.name} \u00B7 x${model.creditMultiplier.toFixed(2)}`\n}\n\n/**\n * Whether one model should be offered image input.\n *\n * Two independent sources, unioned (issue #16):\n *\n * - the user's explicit `imageModelIds` opt-in, which stays authoritative and\n * can still switch an individual model on;\n * - Trae's own `multimodal` flag, which is what makes \"auto\" work at all.\n *\n * Rationale: Trae's IDE enables its attach-image button purely from this flag\n * (`metadata.capabilities.vision`), with no user switch, so a model Trae itself\n * calls multimodal is one the vendor expects to receive images. Requiring a\n * manual tick for those made this plugin the only place where a vendor-declared\n * capability had to be re-enabled by hand.\n *\n * Why the flag alone is not enough, and the union is:\n *\n * - the flag is advisory, not a contract. `llm_utils_chat` is a lightweight\n * SOLO channel and this plugin has been burned by `4001 param is invalid`\n * for ids that LOOKED valid, so the flag is not treated as proof of\n * callability \u2014 a model still has to have survived the wire join to appear\n * at all. The flag only decides image input, never model availability.\n * - Users who already ticked a model keep that tick even after a refresh stops\n * reporting the flag, so the union never silently revokes a working setup.\n * - `input` remains the ONLY thing told to DSH: a model that ends up without\n * `image` here is one DSH will degrade images to text for, which is the\n * safe direction for a model whose capability we cannot confirm.\n *\n * `multimodal === true` is a strict test: absent, `false`, or any non-boolean\n * leaves the model text-only unless the user opted in.\n */\nexport function traeModelAcceptsImage(\n model: Pick<TraeModelInfo, 'id' | 'multimodal'>,\n selected: ReadonlySet<string>,\n): boolean {\n return selected.has(model.id) || model.multimodal === true\n}\n\n/** Apply the user's explicit image opt-ins plus Trae's own multimodal flag. */\nexport function applyImageSelection(\n models: readonly TraeModelInfo[],\n selected: ReadonlySet<string>,\n): TraeModelInfo[] {\n return models.map(model => ({\n ...model,\n input: traeModelAcceptsImage(model, selected) ? ['text', 'image'] : ['text'],\n }))\n}\n\n/** One row from `get_detail_param`: the authoritative llm_utils_chat wire id + display name. */\nexport interface TraeWireModel {\n id: string\n name: string\n contextWindow?: number\n maxTokens?: number\n reasoning?: TraeReasoningCapability\n /**\n * Effective (post-discount) credit multiplier, read from the row's\n * `display_contact_config` \u2014 the figure the Trae IDE renders (see\n * `wireCreditMultiplier` in solo.ts). Wins over the Remote directory's own\n * `consumption_rate`, which reports the undiscounted value.\n */\n creditMultiplier?: number\n /**\n * The `get_detail_param` function this config_name came from. Trae splits its\n * callable roster across several functions (SOLO modes), and a model is only\n * callable through the function that actually lists it \u2014 glm-5.3 answers\n * `solo_work_remote` but rejects `solo_work_lite` with 4001. The chat call\n * therefore has to replay the directory's own function.\n */\n function?: string\n}\n\n/** Normalise a display name for cross-source joining. */\nfunction displayKey(name: string): string {\n return name.trim().toLowerCase()\n}\n\n/**\n * Merge the two Trae model sources into one authoritative catalog.\n *\n * `remote` (the solo.trae.cn `/models` directory) is the authoritative model\n * skeleton: it supplies the display id, display name, context windows, credit\n * multiplier, reasoning and multimodal flags. `wire` (from `get_detail_param`)\n * supplies the real `llm_utils_chat` `config_name` \u2014 the only id the chat\n * endpoint actually accepts \u2014 plus the authoritative post-discount credit\n * multiplier when `display_contact_config` carries one.\n *\n * A remote row with no wire match is STILL KEPT (decision 2026-10-02, issue\n * #19). It previously was dropped, on the reasoning that a row with no\n * `config_name` is sent as an invalid one and rejected with 4001. That\n * reasoning holds only for the accounts and functions we can measure, and\n * measuring is the problem: whether a roster contains a model is ACCOUNT-\n * SCOPED, so \"no wire entry on a free account\" cannot prove a paying account\n * cannot call it. Dropping on that evidence silently denied those users models\n * their own Trae IDE offers. The row therefore ships, and its call fails\n * honestly: the bridge now translates the in-stream refusal into a readable\n * error (`4001` \u2192 \"Trae does not serve this model under the SOLO function the\n * request used\", `4011` \u2192 \"Trae throttled the SOLO channel for this account\",\n * the second one corrected by issue #33 \u2014 4011 is a rate limit, see\n * src/solo-bridge.ts), so a user who picks an unusable model is told why instead\n * of seeing nothing. This reverses the 2026-08-30 note about `Doubao-Seed-Code`,\n * which later turned out to be callable under `chat_v3`.\n *\n * Credit multiplier precedence: the wire's `display_contact_config` rate wins\n * whenever present (it is the post-discount figure the Trae IDE renders \u2014 the\n * Remote directory can report up to 10x the undiscounted value, see\n * `wireCreditMultiplier` in solo.ts); the Remote `consumption_rate` is the\n * fallback when the wire row carries none.\n *\n * Joining is two-tier, in priority order:\n * 1. `wire.id` (the `config_name`) equals the remote id \u2014 the model's display\n * id is already its wire id (the common case: glm-5.2,\n * DeepSeek-V4-Flash-Official, kimi-k3, \u2026).\n * 2. `wire.name` (the `display_name`) equals the remote display name \u2014 for\n * models whose display id differs from the wire id across Trae versions.\n * When the matched wire `config_name` differs from the remote id it is recorded\n * as `wireConfigName`; otherwise it is left undefined (id is already the wire id).\n */\nexport function mergeTraeModelSources(\n remote: readonly TraeDiscoveredModel[],\n wire: readonly TraeWireModel[],\n): TraeModelInfo[] {\n const wireByName = new Map<string, TraeWireModel>()\n const wireById = new Map<string, TraeWireModel>()\n for (const model of wire) {\n wireByName.set(displayKey(model.name), model)\n wireById.set(displayKey(model.id), model)\n }\n const result: TraeModelInfo[] = []\n for (const model of remote) {\n const wireModel = wireById.get(displayKey(model.id)) ?? wireByName.get(displayKey(model.name))\n // A row with no wire match still ships (see the note above): the wire lists\n // are account-scoped, so their silence is not proof of uncallability. With\n // no `wireConfigName` the bridge sends the display id and the default\n // function, and an upstream refusal comes back as a readable message\n // rather than a silent absence.\n // The wire rate wins whenever it is present \u2014 it is the post-discount\n // figure the Trae IDE renders (`display_contact_config`); the Remote\n // directory's own `consumption_rate` can report up to 10x the undiscounted\n // value under a live promotion (e.g. 0.80 vs the IDE's 0.08).\n const creditMultiplier = wireModel?.creditMultiplier ?? model.creditMultiplier\n result.push({\n id: model.id,\n name: model.name,\n ...model.contextWindow === undefined ? {} : { contextWindow: model.contextWindow },\n ...model.maxContextWindow === undefined ? {} : { maxContextWindow: model.maxContextWindow },\n ...creditMultiplier === undefined ? {} : { creditMultiplier },\n input: ['text'],\n // Trae's own answer to \"does this model read images\". Carried through so\n // `applyImageSelection` can union it with the user's opt-ins (issue #16);\n // `input` stays text here and is decided by that single later pass.\n ...model.multimodal === undefined ? {} : { multimodal: model.multimodal },\n reasoningSupported: model.reasoningSupported,\n ...model.reasoning === undefined ? {} : {\n reasoning: model.reasoning,\n reasoningEfforts: Object.fromEntries(model.reasoning.supported.map(effort => [effort, effort === 'low' ? 'light' : effort === 'xhigh' ? 'extra_high' : 'high'])) as Partial<Record<TraeReasoningEffort, string>>,\n },\n ...wireModel !== undefined && wireModel.id !== '' && wireModel.id !== model.id ? { wireConfigName: wireModel.id } : {},\n ...wireModel?.function === undefined ? {} : { wireFunction: wireModel.function },\n })\n }\n return result\n}\n\n/** Local DSH context budget per model; a value may only select an advertised window. */\nexport type TraeContextBudget = number\n\n/**\n * Apply the saved local budget. Trae advertises two windows per model (dev and\n * Max), so the budget may only switch a model to its own advertised Max value \u2014\n * never to a fabricated number. Everything else keeps the dev window.\n */\nexport function applyContextBudgets(\n catalog: readonly TraeModelInfo[],\n budgets: Readonly<Record<string, TraeContextBudget | undefined>> = {},\n): TraeModelInfo[] {\n return catalog.map(model => ({\n ...model,\n ...(model.maxContextWindow !== undefined && budgets[model.id] === model.maxContextWindow\n ? { contextWindow: model.maxContextWindow }\n : {}),\n }))\n}\n\n/** Convert Trae metadata into catalog rows; image input is decided by {@link applyImageSelection}. */\nexport function discoveredCatalog(models: readonly TraeDiscoveredModel[]): TraeModelInfo[] {\n const result: TraeModelInfo[] = []\n for (const model of models) {\n result.push({\n id: model.id,\n name: model.name,\n ...model.contextWindow === undefined ? {} : { contextWindow: model.contextWindow },\n ...model.maxContextWindow === undefined ? {} : { maxContextWindow: model.maxContextWindow },\n input: ['text'],\n ...model.creditMultiplier === undefined ? {} : { creditMultiplier: model.creditMultiplier },\n // See mergeTraeModelSources: the upstream flag travels with the row so the\n // one later image pass can union it with the user's explicit opt-ins.\n ...model.multimodal === undefined ? {} : { multimodal: model.multimodal },\n reasoningSupported: model.reasoningSupported,\n ...model.reasoning === undefined ? {} : {\n reasoning: model.reasoning,\n reasoningEfforts: Object.fromEntries(model.reasoning.supported.map(effort => [effort, effort === 'low' ? 'light' : effort === 'xhigh' ? 'extra_high' : 'high'])) as Partial<Record<TraeReasoningEffort, string>>,\n },\n })\n }\n return result\n}\n\n/**\n * Drop rows saved by older releases that generated `@1m` variant models, so a\n * stale configuration cannot resurrect a variant the runtime no longer builds.\n */\nexport function sanitizeCatalog(catalog: readonly TraeModelInfo[]): TraeModelInfo[] {\n return catalog.filter(model => {\n if (model.id.endsWith('@1m')) return false\n const legacy = model as Partial<{ baseModelId: unknown; maxContext: unknown }>\n return legacy.baseModelId === undefined && legacy.maxContext !== true\n })\n}\n\n/**\n * Derive the runtime catalog from the last refreshed Trae directory plus the\n * user's explicit selection and context budgets. An empty selection falls back\n * to the whole directory: a plugin that has never been configured must still\n * serve models rather than nothing. This is the single source of truth for\n * what DSH actually exposes, so saving only the selection and budgets is\n * enough to rebuild it after a restart.\n */\nexport function deriveCatalog(\n catalog: readonly TraeModelInfo[],\n enabled: ReadonlySet<string>,\n budgets: Readonly<Record<string, TraeContextBudget | undefined>> = {},\n): TraeModelInfo[] {\n const selected = enabled.size === 0 ? catalog : catalog.filter(model => enabled.has(model.id))\n return applyContextBudgets(selected, budgets)\n}\n\nexport class TraeCatalog {\n private models: readonly TraeModelInfo[]\n\n /**\n * @param region Seeds the static fallback for this region; each region's\n * provider must never serve the other region's roster before its first live\n * refresh lands.\n */\n constructor(region: TraeRegion = 'cn') {\n this.models = fallbackModelsFor(region)\n }\n\n current(): readonly TraeModelInfo[] {\n return this.models\n }\n\n set(models: readonly TraeModelInfo[]): void {\n if (models.length === 0) throw new Error('trae model catalog cannot be empty')\n this.models = models.map(model => ({ ...model, ...model.input === undefined ? {} : { input: [...model.input] } }))\n }\n}\n", "/**\r\n * Qoder upstream client \u2014 the loopback shim's OpenAI-shaped surface, carried\r\n * over to the Qoder transport.\r\n *\r\n * The plugin's browser card, the CLI, and DSH's pi-ai adapter all reach Qoder\r\n * through this one module. The wire reality changed underneath the WorkBuddy\r\n * edition it replaces: there is no HTTP endpoint that accepts an OpenAI JSON\r\n * body any more. Instead this module\r\n *\r\n * - **translates** the narrow OpenAI chat-completions request the shim forwards\r\n * (model, messages, tools, `max_tokens`, `temperature`, `stop`,\r\n * `reasoning_effort`) into dsh-llm's `GenerateOptions`, and\r\n * - **re-serializes** the transport's `StreamChunk` vocabulary back into\r\n * `chat.completion.chunk` SSE frames, so the adapter side needs nothing\r\n * Qoder-specific, and\r\n * - maps catalog discovery (`transport.discoverModels`) into the plugin's\r\n * model rows, and the account read (`transport.readAccount`) into the\r\n * card's credit shape.\r\n *\r\n * Failure classification follows the transport's error taxonomy\r\n * (`QoderLlmError.failure.code` plus the HTTP status it carried); the\r\n * WorkBuddy-era session/credit marker lists are gone with the upstream they\r\n * described.\r\n *\r\n * @module dsh-qoder-connect/upstream\r\n */\r\n\r\nimport { randomBytes } from 'node:crypto'\r\nimport {\r\n createAssistantMessage,\r\n createUserMessage,\r\n createToolResultMessage,\r\n LlmError,\r\n ReasoningEffortId,\r\n ToolCallId,\r\n type ContentBlock,\r\n type GenerateOptions,\r\n type Message,\r\n type StreamChunk,\r\n type ToolSchema,\r\n} from '@deepseek-ai/dsh-llm'\r\nimport type { AttachmentStore, ImageMediaType } from '@deepseek-ai/dsh-attachment'\r\nimport { PROBE_MAX_TOKENS, PROBE_PROMPT, type ProbeAttempt } from './probe.ts'\r\nimport type { QoderCatalogModel } from './qoder/catalog.ts'\r\nimport type { QoderRegion } from './qoder/region.ts'\r\nimport type { QoderAccountInfo, QoderQuotaUsage } from './qoder/account.ts'\r\nimport { qoderQueueSignal } from './qoder/errors.ts'\r\nimport { qoderResultCode } from './qoder/codes.ts'\r\nimport { createQoderTransport, type QoderCheckInResult, type QoderTransport } from './qoder/transport/index.ts'\r\nimport type { QoderModelBilling, QoderModelInfo, QoderModelReasoning } from './catalog.ts'\r\n\r\n/**\r\n * The reasoning-effort vocabulary the probe sweeps and the effort map speak.\r\n * Mirrors the canonical order of `src/qoder/catalog.ts` (`low` \u2026 `max`).\r\n * `minimal` and `off` are deliberately absent: `off` is a separate capability\r\n * the upstream must declare, never something probing may infer.\r\n */\r\nexport type QoderEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max'\r\n\r\n/** How the shim should present an upstream failure to its OpenAI client. */\r\nexport type UpstreamErrorKind =\r\n | 'missing_credential'\r\n | 'auth'\r\n | 'soft_rate'\r\n | 'quota_exceeded'\r\n | 'timeout'\r\n | 'server'\r\n | 'client'\r\n\r\n/**\r\n * HTTP status the shim answers each failure kind with.\r\n *\r\n * `timeout` is 408 and deliberately not 504: the harness's pi-ai classifier tests\r\n * `/\\b5\\d\\d\\b/` *before* its `timeout` test, so a 5xx status would be read as\r\n * SERVER no matter what the message says. 408 is also the honest answer for a\r\n * request the upstream never completed.\r\n */\r\nexport const KIND_STATUS: Readonly<Record<UpstreamErrorKind, number>> = {\r\n missing_credential: 401,\r\n auth: 401,\r\n soft_rate: 429,\r\n quota_exceeded: 402,\r\n timeout: 408,\r\n server: 502,\r\n client: 400,\r\n}\r\n\r\n/** The chat-completions answer: a streaming `Response`, or a classified failure. */\r\nexport type QoderChatResult =\r\n | { ok: true; response: Response }\r\n | { ok: false; status: number; kind: UpstreamErrorKind; message: string }\r\n\r\n/** Provenance of the last successful catalog fetch. */\r\nexport interface QoderCatalogFetch {\r\n fetchedAtMs: number\r\n source: string\r\n}\r\n\r\n/** One quota package and its remaining credit, as the card renders it. */\r\nexport interface QoderCreditAccount {\r\n packageName: string\r\n remain: number\r\n size: number\r\n unlimited?: true\r\n /** Expiry of this package, verbatim from the upstream (ISO string). */\r\n packageEndTime?: string\r\n}\r\n\r\n/** The aggregated credit answer the card renders. */\r\nexport interface QoderCredits {\r\n /** Usage percentage of the personal quota (0..100). */\r\n total: number\r\n /** Summed per-package totals \u2014 the denominator of the dashboard's bar. */\r\n totalSize?: number\r\n accounts: readonly QoderCreditAccount[]\r\n /** The account's quota is uncapped; renderers test this flag first. */\r\n unlimited?: true\r\n /** When the current quota cycle ends, verbatim from the upstream. */\r\n cycleResetTime?: string\r\n}\r\n\r\n/**\r\n * Normalize a billing rate label for display.\r\n *\r\n * Qoder reports a `priceFactor` number; the host spells it `x<n>` (and the\r\n * WorkBuddy-era saved files sometimes carried a trailing \" credits\"). The card\r\n * wants one shape: a trimmed multiplier without the suffix.\r\n */\r\nexport function normalizeCredits(credits: string | undefined): string | undefined {\r\n if (credits === undefined) return undefined\r\n const trimmed = credits.trim().replace(/\\s+credits?$/iu, '')\r\n return trimmed === '' ? undefined : trimmed\r\n}\r\n\r\n/**\r\n * Classify a raw HTTP upstream failure from status and a body excerpt.\r\n *\r\n * Status first, then phrases: a throttling body often also says \"quota\r\n * exceeded\", and reading that as an exhausted balance parks a healthy account\r\n * until the next billing day instead of retrying shortly.\r\n */\r\nexport function classifyUpstreamError(status: number, body: string): UpstreamErrorKind {\r\n const lower = body.toLowerCase()\r\n // Qoder announces a saturated queue (or an unavailable region service) with\r\n // a 401/403 whose body carries the queue markers. That is a throttle: the\r\n // host retries soft_rate and honors retryAfterSeconds, while 'auth' would\r\n // park the account until the user intervenes.\r\n if (qoderQueueSignal(body) !== undefined) return 'soft_rate'\r\n // A *documented* quota code outranks the status arms below. Qoder answers a\r\n // spent daily window with HTTP 403 `{\"code\":\"110\",\"message\":\"Billing daily\r\n // count exceeded\"}`, which the status alone reads as a dead credential (#10).\r\n // The numeric code is the only signal that separates the two, and status-first\r\n // cannot: the caution the arms below encode \u2014 a throttling body often also says\r\n // \"quota exceeded\" \u2014 is about *prose*, and it still holds for every body that\r\n // names no code.\r\n const documented = qoderResultCode(body)\r\n if (documented?.family === 'quota') return 'quota_exceeded'\r\n // A documented request/policy code is the same shape of answer: Qoder can name\r\n // 406/80411 while answering 401/403, and the status arm below would read that as\r\n // a dead credential. pi-ai has no code for those, so the shim's request arm is\r\n // the honest floor. Only a documented code counts, so the status-first caution\r\n // below still holds for every body that names none.\r\n if (documented?.family === 'request') return 'client'\r\n if (status === 402) return 'quota_exceeded'\r\n if (status === 429) return 'soft_rate'\r\n if (status === 401 || status === 403) return 'auth'\r\n for (const marker of ['quota exceeded', 'insufficient quota', 'quota_exhausted', 'exhausted']) {\r\n if (lower.includes(marker)) return 'quota_exceeded'\r\n }\r\n for (const marker of ['rate limit', 'too many requests', 'throttl']) {\r\n if (lower.includes(marker)) return 'soft_rate'\r\n }\r\n for (const marker of ['invalid token', 'invalid pat', 'invalid job token', 'token expired', 'token has expired', 'unauthorized', 'forbidden', 'not authenticated']) {\r\n if (lower.includes(marker)) return 'auth'\r\n }\r\n if (status === 408) return 'timeout'\r\n if (status === 0 || status >= 500) return 'server'\r\n return 'client'\r\n}\r\n\r\n/**\r\n * Map one structured transport failure onto the shim's error kind.\r\n *\r\n * The transport's taxonomy (`src/qoder/errors.ts`) codes an HTTP 402 as\r\n * `INVALID_REQUEST`, so the status gets the last say for the quota and auth\r\n * families before the code-based defaults apply.\r\n *\r\n * `RATE_LIMIT` is tested before the auth family because the upstream's queue\r\n * answer keeps its 401/403 status: a saturated qfmodel queue reads\r\n * `code: RATE_LIMIT, status: 403` (body carries 10605/isQueued/\r\n * retryAfterSeconds), and letting the status arm claim it reported a dead\r\n * credential \u2014 which the host never retries \u2014 instead of a throttle it would.\r\n *\r\n * `QUOTA` and the request family are tested before the auth family for the same\r\n * reason: both keep the upstream's 401/403 (see `qoderHttpError`), and the status\r\n * arm would call a spent daily window or a refused request a credential\r\n * rejection. `status === 402` is tested before the request arm so that a 402 the\r\n * transport coded `INVALID_REQUEST` (its 4xx fallback) still reads as a quota.\r\n */\r\nexport function kindFromQoderFailure(failure: { code: string; status?: number | undefined }): UpstreamErrorKind {\r\n if (failure.code === 'MISSING_CREDENTIAL') return 'missing_credential'\r\n if (failure.code === 'RATE_LIMIT') return 'soft_rate'\r\n // A quota code outranks the status arms, exactly as RATE_LIMIT above does. The\r\n // transport codes a spent daily window QUOTA while keeping the upstream's 403,\r\n // so testing the status first would claim it as an authorization rejection and\r\n // the shim would answer 401 \"auth\" \u2014 the \"API \u5BC6\u94A5\u65E0\u6548\" report this fix exists to\r\n // remove (#10). Only these two code strings count; every other failure still\r\n // routes exactly as before.\r\n //\r\n // `QUOTA` is what this plugin's transport emits. `ACCOUNT_QUOTA` is the kernel's\r\n // more specific code for an account-level balance, accepted as an alias so the\r\n // two names cannot route differently. Nothing in the installed stack produces it\r\n // today \u2014 this transport emits QUOTA, and dsh-llm-pi-ai only ever returns QUOTA \u2014\r\n // so it is a forward-compatible alias, not a live input.\r\n if (failure.code === 'QUOTA' || failure.code === 'ACCOUNT_QUOTA') return 'quota_exceeded'\r\n // 402 comes before the request arm so that a 402 the transport coded\r\n // INVALID_REQUEST (its 4xx fallback) still reads as an exhausted balance.\r\n if (failure.status === 402) return 'quota_exceeded'\r\n // The request/policy arm precedes auth for the same reason: the transport keeps\r\n // the upstream's 401/403 when a documented request code was named (see\r\n // qoderHttpError), and the status arm would otherwise call a content refusal a\r\n // credential rejection.\r\n if (failure.code.startsWith('INVALID_') || failure.code.startsWith('UNSUPPORTED_') || failure.code === 'ATTACHMENT') {\r\n return 'client'\r\n }\r\n if (failure.code === 'AUTH' || failure.status === 401 || failure.status === 403) return 'auth'\r\n if (failure.status === 429) return 'soft_rate'\r\n // A timeout keeps its own kind so the shim can answer 408 with the word in the\r\n // message. Folding it into `server` answered 502, and pi-ai reads a 5xx number\r\n // as SERVER before it ever tests for a timeout \u2014 so a stalled request reported a\r\n // server fault.\r\n if (failure.code === 'TIMEOUT') return 'timeout'\r\n // SERVER, EMPTY_RESPONSE, MALFORMED_RESPONSE, TRANSPORT, PROVIDER_ERROR, and\r\n // anything unrecognized: a server-side condition.\r\n return 'server'\r\n}\r\n\r\n/** Whether a Personal Access Token works against one region's endpoints. */\r\nexport async function validateApiKey(\r\n pat: string,\r\n region: QoderRegion,\r\n options: { timeoutMs?: number; fetch?: typeof fetch } = {},\r\n): Promise<boolean> {\r\n const trimmed = pat.trim()\r\n if (trimmed === '') return false\r\n try {\r\n const transport = createQoderTransport({\r\n region,\r\n resolvePat: async () => trimmed,\r\n ...options.fetch === undefined ? {} : { fetch: options.fetch },\r\n metadataTimeoutMs: options.timeoutMs ?? 15_000,\r\n })\r\n await transport.discoverModels(AbortSignal.timeout(options.timeoutMs ?? 15_000))\r\n return true\r\n } catch {\r\n // Any failure \u2014 bad token, unreachable endpoint, timeout \u2014 answers the\r\n // card's one question the same way: this token cannot be saved.\r\n return false\r\n }\r\n}\r\n\r\n/** A request the OpenAI layer itself could not accept; the shim answers 400. */\r\nclass UpstreamRequestError extends Error {}\r\n\r\n/** One `data:` frame of a `chat.completion.chunk` SSE body. */\r\nfunction sseFrame(payload: unknown): string {\r\n return `data: ${JSON.stringify(payload)}\\n\\n`\r\n}\r\n\r\nconst SSE_DONE = 'data: [DONE]\\n\\n'\r\n\r\n/** The media types the attachment service normalizes; anything else is refused. */\r\nconst IMAGE_MEDIA_TYPES: readonly string[] = ['image/png', 'image/jpeg', 'image/webp', 'image/gif']\r\n\r\nfunction isRecord(value: unknown): value is Record<string, unknown> {\r\n return typeof value === 'object' && value !== null && !Array.isArray(value)\r\n}\r\n\r\nfunction requiredString(value: unknown, what: string): string {\r\n if (typeof value !== 'string' || value.trim() === '') {\r\n throw new UpstreamRequestError(`${what} must be a non-empty string`)\r\n }\r\n return value\r\n}\r\n\r\n/** Decode one `data:image/...;base64,` URL into typed bytes. */\r\nfunction decodeDataImage(url: string): { mediaType: ImageMediaType; data: Uint8Array } {\r\n const match = /^data:([a-z]+\\/[a-z0-9.+-]+)(?:;[a-z0-9;=+.-]*)?,(.*)$/iu.exec(url)\r\n if (match === null) throw new UpstreamRequestError('image_url data URL is malformed')\r\n const mediaType = match[1]!.toLowerCase()\r\n if (!IMAGE_MEDIA_TYPES.includes(mediaType)) {\r\n throw new UpstreamRequestError(`image media type \"${mediaType}\" is not supported (png, jpeg, webp, gif)`)\r\n }\r\n let data: Uint8Array\r\n try {\r\n data = new Uint8Array(Buffer.from(match[2] ?? '', 'base64'))\r\n } catch {\r\n throw new UpstreamRequestError('image_url base64 payload could not be decoded')\r\n }\r\n if (data.byteLength === 0) throw new UpstreamRequestError('image_url payload is empty')\r\n return { mediaType: mediaType as ImageMediaType, data }\r\n}\r\n\r\n/**\r\n * Parse one OpenAI content value (string or parts array) into text.\r\n *\r\n * With `imagesAs`, image parts are offered for commit \u2014 and a request that\r\n * carries them without any commit path fails as a client error, because the\r\n * Qoder wire can only ever transport a durable attachment reference.\r\n */\r\nasync function openAiContentBlocks(\r\n content: unknown,\r\n role: 'user' | 'assistant',\r\n imagesAs: { commit(part: { mediaType: ImageMediaType; data: Uint8Array }): Promise<ContentBlock> } | undefined,\r\n): Promise<ContentBlock[]> {\r\n const blocks: ContentBlock[] = []\r\n const parts: readonly unknown[] = typeof content === 'string' || content === null || content === undefined\r\n ? (typeof content === 'string' && content !== '' ? [{ type: 'text', text: content }] : [])\r\n : Array.isArray(content)\r\n ? content\r\n : (() => { throw new UpstreamRequestError(`${role} message content must be a string or a parts array`) })()\r\n for (const raw of parts) {\r\n if (!isRecord(raw) || typeof raw['type'] !== 'string') {\r\n throw new UpstreamRequestError(`${role} message content part is malformed`)\r\n }\r\n switch (raw['type']) {\r\n case 'text':\r\n blocks.push({ type: 'text', text: typeof raw['text'] === 'string' ? raw['text'] : '' })\r\n break\r\n case 'image_url': {\r\n if (role !== 'user') throw new UpstreamRequestError('image parts are valid only in user messages')\r\n const imageUrl = raw['image_url']\r\n const url = isRecord(imageUrl) && typeof imageUrl['url'] === 'string' ? imageUrl['url'] : ''\r\n if (!url.toLowerCase().startsWith('data:')) {\r\n throw new UpstreamRequestError('image_url must be an inline data: URL; remote image URLs are not fetched')\r\n }\r\n if (imagesAs === undefined) {\r\n throw new UpstreamRequestError('image input requires the DSH attachment service')\r\n }\r\n const decoded = decodeDataImage(url)\r\n blocks.push(await imagesAs.commit(decoded))\r\n break\r\n }\r\n default:\r\n throw new UpstreamRequestError(`unsupported content part type \"${raw['type']}\"`)\r\n }\r\n }\r\n return blocks\r\n}\r\n\r\n/**\r\n * Translate one OpenAI chat-completions body into a `GenerateOptions` request.\r\n *\r\n * The layer is deliberately narrow: it accepts exactly what pi-ai's\r\n * `openai-completions` API sends, and rejects anything else with an\r\n * attributable 400 rather than silently dropping a caller's intent. System\r\n * prompts ride `options.system` (the transport's own slot), not a leading\r\n * message; tool results become dedicated user-role messages the Qoder\r\n * serializer accepts.\r\n */\r\nasync function toGenerateOptions(\r\n bodyJson: string,\r\n context: { providerId: string, attachments: Pick<AttachmentStore, 'saveImage'> | undefined, signal?: AbortSignal | undefined },\r\n): Promise<GenerateOptions> {\r\n let parsed: unknown\r\n try {\r\n parsed = JSON.parse(bodyJson)\r\n } catch {\r\n throw new UpstreamRequestError('request body is not valid JSON')\r\n }\r\n if (!isRecord(parsed)) throw new UpstreamRequestError('request body must be a JSON object')\r\n\r\n const model = requiredString(parsed['model'], 'model')\r\n const rawMessages = parsed['messages']\r\n if (!Array.isArray(rawMessages) || rawMessages.length === 0) {\r\n throw new UpstreamRequestError('messages must be a non-empty array')\r\n }\r\n\r\n const systemParts: string[] = []\r\n const messages: Message[] = []\r\n for (const raw of rawMessages) {\r\n if (!isRecord(raw)) throw new UpstreamRequestError('each message must be an object')\r\n const role = raw['role']\r\n switch (role) {\r\n case 'system':\r\n case 'developer': {\r\n if (typeof raw['content'] !== 'string') throw new UpstreamRequestError('system message content must be a string')\r\n if (raw['content'] !== '') systemParts.push(raw['content'])\r\n break\r\n }\r\n case 'user': {\r\n const content = await openAiContentBlocks(raw['content'], 'user',\r\n context.attachments === undefined ? undefined : {\r\n commit: async part => ({\r\n type: 'image' as const,\r\n attachment: await context.attachments!.saveImage({ data: part.data, mediaType: part.mediaType }),\r\n }),\r\n })\r\n messages.push(createUserMessage({ content, source: { kind: 'user' } }))\r\n break\r\n }\r\n case 'assistant': {\r\n const content = await openAiContentBlocks(raw['content'], 'assistant', undefined)\r\n const rawCalls = raw['tool_calls']\r\n if (Array.isArray(rawCalls)) {\r\n for (const rawCall of rawCalls) {\r\n if (!isRecord(rawCall)) throw new UpstreamRequestError('each tool call must be an object')\r\n const fn = isRecord(rawCall['function']) ? rawCall['function'] : rawCall\r\n content.push({\r\n type: 'tool-call',\r\n id: ToolCallId(requiredString(rawCall['id'], 'tool call id')),\r\n name: requiredString(fn['name'], 'tool call function name'),\r\n arguments: typeof fn['arguments'] === 'string' ? fn['arguments'] : '',\r\n })\r\n }\r\n }\r\n if (content.length === 0) break // an empty assistant turn carries nothing the wire may show\r\n messages.push(createAssistantMessage({\r\n content,\r\n source: { provider: context.providerId, model },\r\n }))\r\n break\r\n }\r\n case 'tool': {\r\n const callId = requiredString(raw['tool_call_id'], 'tool_call_id')\r\n const content = raw['content']\r\n let text: string\r\n if (typeof content === 'string') {\r\n text = content\r\n } else if (Array.isArray(content)) {\r\n text = content\r\n .filter((part): part is Record<string, unknown> => isRecord(part) && part['type'] === 'text')\r\n .map(part => typeof part['text'] === 'string' ? part['text'] : '')\r\n .join('')\r\n if (content.some(part => isRecord(part) && part['type'] !== 'text')) {\r\n throw new UpstreamRequestError('tool result content is limited to text')\r\n }\r\n } else {\r\n throw new UpstreamRequestError('tool message content must be a string or a text-parts array')\r\n }\r\n messages.push(createToolResultMessage({\r\n callId: ToolCallId(callId),\r\n content: [{ type: 'text', text }],\r\n isError: false,\r\n }))\r\n break\r\n }\r\n default:\r\n throw new UpstreamRequestError(`unsupported message role \"${String(role)}\"`)\r\n }\r\n }\r\n if (messages.length === 0) throw new UpstreamRequestError('the request carries no model-facing message')\r\n\r\n const tools: ToolSchema[] | undefined = Array.isArray(parsed['tools'])\r\n ? parsed['tools'].map((raw): ToolSchema => {\r\n if (!isRecord(raw)) throw new UpstreamRequestError('each tool must be an object')\r\n const fn = isRecord(raw['function']) ? raw['function'] : raw\r\n if (!isRecord(fn)) throw new UpstreamRequestError('each tool must carry a function object')\r\n return {\r\n name: requiredString(fn['name'], 'tool name'),\r\n description: typeof fn['description'] === 'string' ? fn['description'] : '',\r\n parameters: isRecord(fn['parameters']) ? fn['parameters'] : {},\r\n }\r\n })\r\n : undefined\r\n\r\n const effort = parsed['reasoning_effort']\r\n const stop = parsed['stop']\r\n const temperature = parsed['temperature']\r\n const maxTokens = parsed['max_tokens']\r\n\r\n return {\r\n provider: context.providerId,\r\n model,\r\n messages,\r\n ...systemParts.length > 0 ? { system: systemParts.join('\\n') } : {},\r\n ...tools === undefined || tools.length === 0 ? {} : { tools },\r\n ...typeof temperature === 'number' && Number.isFinite(temperature) ? { temperature } : {},\r\n ...typeof maxTokens === 'number' && Number.isFinite(maxTokens) && maxTokens > 0 ? { maxTokens: Math.floor(maxTokens) } : {},\r\n ...typeof effort === 'string' && effort.trim() !== '' ? { reasoningEffort: ReasoningEffortId(effort.trim()) } : {},\r\n ...Array.isArray(stop)\r\n ? { stop: stop.filter((entry): entry is string => typeof entry === 'string') }\r\n : typeof stop === 'string' ? { stop: [stop] } : {},\r\n ...context.signal === undefined ? {} : { signal: context.signal },\r\n }\r\n}\r\n\r\n/**\r\n * Re-serialize one `StreamChunk` sequence into OpenAI chunk frames.\r\n *\r\n * One assistant choice, deltas keyed by a per-block tool-call index that\r\n * restarts at zero per block like OpenAI's own, reasoning streamed as\r\n * `delta.reasoning_content` (the compatible extension other gateways use),\r\n * usage as a choices-less frame before the terminal finish, and `data:\r\n * [DONE]` last. A failed or aborted finish mid-stream becomes an error JSON\r\n * frame and then `[DONE]`: the HTTP status is already sent and cannot carry\r\n * the failure.\r\n */\r\nclass ChunkEncoder {\r\n private readonly id: string\r\n private readonly created: number\r\n private readonly model: string\r\n private started = false\r\n terminal = false\r\n private readonly toolIndexByBlock = new Map<number, number>()\r\n private readonly announcedTools = new Set<number>()\r\n private nextToolIndex = 0\r\n\r\n constructor(model: string) {\r\n this.id = `chatcmpl-${randomBytes(12).toString('hex')}`\r\n this.created = Math.floor(Date.now() / 1000)\r\n this.model = model\r\n }\r\n\r\n private frame(extra: Record<string, unknown>): string {\r\n return sseFrame({\r\n id: this.id,\r\n object: 'chat.completion.chunk',\r\n created: this.created,\r\n model: this.model,\r\n ...extra,\r\n })\r\n }\r\n\r\n /** The role frame opens every stream, once. */\r\n start(): string[] {\r\n if (this.started) return []\r\n this.started = true\r\n return [this.frame({ choices: [{ index: 0, delta: { role: 'assistant' }, finish_reason: null }] })]\r\n }\r\n\r\n /** Translate one transport chunk into zero or more SSE frames. */\r\n frames(chunk: StreamChunk): string[] {\r\n switch (chunk.type) {\r\n case 'block-start':\r\n case 'block-end':\r\n return []\r\n case 'text-delta':\r\n return [this.frame({ choices: [{ index: 0, delta: { content: chunk.text }, finish_reason: null }] })]\r\n case 'reasoning-delta':\r\n return [this.frame({ choices: [{ index: 0, delta: { reasoning_content: chunk.text }, finish_reason: null }] })]\r\n case 'tool-call-delta': {\r\n let toolIndex = this.toolIndexByBlock.get(chunk.index)\r\n if (toolIndex === undefined) {\r\n toolIndex = this.nextToolIndex++\r\n this.toolIndexByBlock.set(chunk.index, toolIndex)\r\n }\r\n const first = !this.announcedTools.has(chunk.index)\r\n if (first) this.announcedTools.add(chunk.index)\r\n const call: Record<string, unknown> = {\r\n index: toolIndex,\r\n ...(first\r\n ? {\r\n id: String(chunk.id),\r\n type: 'function',\r\n function: { name: chunk.name ?? '', arguments: chunk.argumentsDelta },\r\n }\r\n : { function: { arguments: chunk.argumentsDelta } }),\r\n }\r\n return [this.frame({ choices: [{ index: 0, delta: { tool_calls: [call] }, finish_reason: null }] })]\r\n }\r\n case 'usage': {\r\n const cacheRead = chunk.usage.cacheReadTokens\r\n const cacheWrite = chunk.usage.cacheWriteTokens\r\n const prompt = chunk.usage.inputTokens\r\n + (cacheRead ?? 0)\r\n + (cacheWrite ?? 0)\r\n const completion = chunk.usage.outputTokens\r\n const reasoning = chunk.usage.reasoningTokens\r\n // The token counts are DISJOINT by contract (`inputTokens` excludes\r\n // cached input), so the OpenAI `prompt_tokens` total is the sum.\r\n //\r\n // `prompt_tokens_details` MUST ride back out with it: the harness\r\n // reads the cache-hit share off `prompt_tokens_details.cached_tokens`,\r\n // so a usage frame that carries only the three aggregate counters\r\n // silently reports every cached token as a miss (cache hit pinned to\r\n // 0% however warm the upstream prefix cache actually was). Emit the\r\n // details object only when the transport reported at least one of the\r\n // two cache counters, so requests that never saw cache fields keep the\r\n // exact same frame shape as before.\r\n const details = cacheRead === undefined && cacheWrite === undefined\r\n ? undefined\r\n : {\r\n ...(cacheRead === undefined ? {} : { cached_tokens: cacheRead }),\r\n ...(cacheWrite === undefined ? {} : { cache_write_tokens: cacheWrite }),\r\n }\r\n return [this.frame({\r\n choices: [],\r\n usage: {\r\n prompt_tokens: prompt,\r\n completion_tokens: completion,\r\n total_tokens: chunk.usage.totalTokens ?? prompt + completion,\r\n ...(details === undefined ? {} : { prompt_tokens_details: details }),\r\n ...(reasoning === undefined ? {} : {\r\n completion_tokens_details: {\r\n reasoning_tokens: reasoning,\r\n },\r\n }),\r\n },\r\n })]\r\n }\r\n case 'finish': {\r\n this.terminal = true\r\n const reason = chunk.reason\r\n if (reason.kind === 'error' || reason.kind === 'aborted') {\r\n return [\r\n sseFrame({ error: { message: reason.failure.message, type: 'server_error', code: reason.failure.code } }),\r\n SSE_DONE,\r\n ]\r\n }\r\n const finishReason = reason.kind === 'max-tokens' ? 'length' : reason.kind === 'tool-calls' ? 'tool_calls' : 'stop'\r\n return [\r\n this.frame({ choices: [{ index: 0, delta: {}, finish_reason: finishReason }] }),\r\n SSE_DONE,\r\n ]\r\n }\r\n }\r\n }\r\n\r\n /** Fallback finish when the chunk source ended without a finish chunk. */\r\n finishFallback(): string[] {\r\n if (this.terminal) return []\r\n this.terminal = true\r\n return [\r\n this.frame({ choices: [{ index: 0, delta: {}, finish_reason: 'stop' }] }),\r\n SSE_DONE,\r\n ]\r\n }\r\n\r\n /** A thrown mid-stream failure, phrased as one error frame and the end. */\r\n abortFrames(message: string, code: string): string[] {\r\n this.terminal = true\r\n return [sseFrame({ error: { message, type: 'server_error', code } }), SSE_DONE]\r\n }\r\n}\r\n\r\n/** Turn any thrown failure into the shim's classified pre-stream result. */\r\nfunction failureResult(error: unknown): QoderChatResult {\r\n if (error instanceof UpstreamRequestError) {\r\n return { ok: false, status: 400, kind: 'client', message: error.message }\r\n }\r\n if (error instanceof LlmError) {\r\n const kind = kindFromQoderFailure(error.failure)\r\n const status = typeof error.failure.status === 'number' && error.failure.status >= 100 && error.failure.status <= 599\r\n ? error.failure.status\r\n : KIND_STATUS[kind]\r\n return { ok: false, status, kind, message: error.failure.message }\r\n }\r\n return { ok: false, status: 502, kind: 'server', message: String(error) }\r\n}\r\n\r\n/** Constructor options for {@link QoderUpstreamClient}. */\r\nexport interface QoderUpstreamClientOptions {\r\n /** Which upstream region this client's transport talks to. */\r\n region: QoderRegion\r\n /** Provider id stamped into translated requests. */\r\n providerId: string\r\n /** Resolves the current Personal Access Token (rejects when none). */\r\n getPat: () => Promise<string>\r\n /** The transport this client drives. */\r\n transport: QoderTransport\r\n /**\r\n * The attachment service's image commit path. Without it, any request\r\n * carrying image parts fails as a client error \u2014 the Qoder wire only ever\r\n * transports durable references.\r\n */\r\n attachments?: Pick<AttachmentStore, 'saveImage'> | undefined\r\n /**\r\n * Extra catalog lookup used when a requested model is not one this client\r\n * fetched itself. The transport validates effort and image support against\r\n * the model row, so a stream must carry it whenever one is known.\r\n */\r\n catalogProvider?: ((id: string) => QoderCatalogModel | undefined) | undefined\r\n}\r\n\r\nexport class QoderUpstreamClient {\r\n private readonly region: QoderRegion\r\n private readonly providerId: string\r\n private readonly getPat: () => Promise<string>\r\n private readonly transport: QoderTransport\r\n private readonly attachments: Pick<AttachmentStore, 'saveImage'> | undefined\r\n private readonly externalCatalog: ((id: string) => QoderCatalogModel | undefined) | undefined\r\n /** The raw discovery rows of the last successful `fetchModels`, by id. */\r\n private readonly discovered = new Map<string, QoderCatalogModel>()\r\n /** Provenance of the last successful catalog fetch, for the status card. */\r\n lastCatalog: QoderCatalogFetch | undefined\r\n\r\n constructor(options: QoderUpstreamClientOptions) {\r\n this.region = options.region\r\n this.providerId = options.providerId\r\n this.getPat = options.getPat\r\n this.transport = options.transport\r\n this.attachments = options.attachments\r\n this.externalCatalog = options.catalogProvider\r\n }\r\n\r\n /** The region this client's transport serves. */\r\n get clientRegion(): QoderRegion {\r\n return this.region\r\n }\r\n\r\n /**\r\n * The catalog row for one model id: this client's own discovery answers\r\n * first (it is the same data the upstream catalog call produced), and an\r\n * externally supplied provider \u2014 the plugin's fallback roster, say \u2014 fills\r\n * ids the discovery never listed.\r\n */\r\n catalogModelFor(id: string): QoderCatalogModel | undefined {\r\n return this.discovered.get(id) ?? this.externalCatalog?.(id)\r\n }\r\n\r\n /**\r\n * Discover this variant's models and translate them into plugin rows.\r\n *\r\n * The raw rows stay addressable via {@link catalogModelFor}: a chat request\r\n * for a discovered model must hand the transport its row, because effort\r\n * support, image capability, and the output cap are all validated against\r\n * it. The last successful fetch's provenance lands in {@link lastCatalog}\r\n * for the status card.\r\n */\r\n async fetchModels(signal?: AbortSignal): Promise<QoderModelInfo[]> {\r\n const models = await this.transport.discoverModels(signal)\r\n this.discovered.clear()\r\n for (const model of models) this.discovered.set(model.id, model)\r\n this.lastCatalog = { fetchedAtMs: Date.now(), source: `${this.providerId}:discovery` }\r\n return models.map(modelInfoOf)\r\n }\r\n\r\n /**\r\n * The subscriber's quota answer, mapped onto the card's credit shape.\r\n *\r\n * Qoder reports one personal quota and an optional organization resource\r\n * package; each becomes a package row the card already knows how to draw.\r\n * An unbounded personal allowance (`total === 0`, not exceeded) is the\r\n * account's \"unlimited\" state.\r\n */\r\n async fetchCredits(signal?: AbortSignal): Promise<QoderCredits> {\r\n const account: QoderAccountInfo = await this.transport.readAccount({ force: true, ...signal === undefined ? {} : { signal } })\r\n const usage: QoderQuotaUsage = account.usage ?? {}\r\n const accounts: QoderCreditAccount[] = []\r\n const personal = usage.userQuota\r\n if (personal !== undefined) {\r\n accounts.push({\r\n packageName: '\u4E2A\u4EBA\u989D\u5EA6',\r\n remain: personal.remaining,\r\n size: personal.total,\r\n ...usage.expiresAt === undefined ? {} : { packageEndTime: usage.expiresAt },\r\n })\r\n }\r\n const org = usage.orgResourcePackage\r\n if (org !== undefined) {\r\n accounts.push({\r\n packageName: '\u7EC4\u7EC7\u8D44\u6E90\u5305',\r\n remain: org.remaining,\r\n size: org.total,\r\n ...usage.expiresAt === undefined ? {} : { packageEndTime: usage.expiresAt },\r\n })\r\n }\r\n // Bonus credits sit beside the plan upstream (the daily campaign's 100 land\r\n // here). Dropping the bucket made the card list fewer packages than the\r\n // account actually holds \u2014 the web showed two, the card showed one.\r\n const addOn = usage.addOnQuota\r\n if (addOn !== undefined) {\r\n accounts.push({\r\n packageName: '\u8D60\u9001\u989D\u5EA6',\r\n remain: addOn.remaining,\r\n size: addOn.total,\r\n ...usage.expiresAt === undefined ? {} : { packageEndTime: usage.expiresAt },\r\n })\r\n }\r\n const unlimited = usage.isQuotaExceeded === false && personal !== undefined && personal.total === 0\r\n return {\r\n total: usage.totalUsagePercentage ?? personal?.percentage ?? 0,\r\n totalSize: accounts.reduce((sum, entry) => sum + entry.size, 0),\r\n accounts,\r\n ...(unlimited ? { unlimited: true as const } : {}),\r\n ...usage.expiresAt === undefined ? {} : { cycleResetTime: usage.expiresAt },\r\n }\r\n }\r\n\r\n /**\r\n * Run daily benefit check-in for this client's variant.\r\n */\r\n async checkIn(signal?: AbortSignal): Promise<QoderCheckInResult> {\r\n return this.transport.checkIn(signal)\r\n }\r\n\r\n /**\r\n * Stream one translated chat-completions request.\r\n *\r\n * The first transport chunk is pulled before the response is constructed:\r\n * everything the transport can reject without touching the network \u2014 a\r\n * missing or empty credential, an effort the model does not advertise, an\r\n * image on a text-only model \u2014 must still be able to answer as a real HTTP\r\n * status, not as a 200 whose first frame is an error. Once streaming has\r\n * begun, failures degrade to the error-frame-then-`[DONE]` form the\r\n * {@link ChunkEncoder} documents.\r\n */\r\n async chatStream(bodyJson: string, signal?: AbortSignal): Promise<QoderChatResult> {\r\n let options: GenerateOptions\r\n try {\r\n options = await toGenerateOptions(bodyJson, {\r\n providerId: this.providerId,\r\n attachments: this.attachments,\r\n ...signal === undefined ? {} : { signal },\r\n })\r\n } catch (error) {\r\n return failureResult(error)\r\n }\r\n\r\n // Fail fast, before the transport's own check can spend a request, when\r\n // no credential exists at all.\r\n try {\r\n await this.getPat()\r\n } catch {\r\n return { ok: false, status: KIND_STATUS.missing_credential, kind: 'missing_credential', message: 'no Qoder Personal Access Token is configured' }\r\n }\r\n\r\n const encoder = new ChunkEncoder(options.model)\r\n let iterator: AsyncIterator<StreamChunk>\r\n try {\r\n iterator = this.transport.stream(options, this.catalogModelFor(options.model))[Symbol.asyncIterator]()\r\n } catch (error) {\r\n return failureResult(error)\r\n }\r\n try {\r\n const first = await iterator.next()\r\n if (!first.done) {\r\n // A terminal first chunk (a failure finish raised as its first and only\r\n // delivery) still classifies into an HTTP status, because no byte of\r\n // the response has gone out yet.\r\n const earlyFailure = first.value.type === 'finish' && (first.value.reason.kind === 'error' || first.value.reason.kind === 'aborted')\r\n ? first.value.reason.failure\r\n : undefined\r\n if (earlyFailure !== undefined) {\r\n await iterator.return?.()\r\n const kind = kindFromQoderFailure(earlyFailure)\r\n return { ok: false, status: earlyFailure.status ?? KIND_STATUS[kind], kind, message: earlyFailure.message }\r\n }\r\n }\r\n const stream = this.bodyStream(iterator, first, encoder)\r\n return {\r\n ok: true,\r\n response: new Response(stream, {\r\n status: 200,\r\n headers: {\r\n 'Content-Type': 'text/event-stream; charset=utf-8',\r\n 'Cache-Control': 'no-cache',\r\n 'Connection': 'keep-alive',\r\n },\r\n }),\r\n }\r\n } catch (error) {\r\n await iterator.return?.()\r\n return failureResult(error)\r\n }\r\n }\r\n\r\n /** Drive the SSE body from an already-started chunk iterator. */\r\n private bodyStream(\r\n iterator: AsyncIterator<StreamChunk>,\r\n first: IteratorResult<StreamChunk>,\r\n encoder: ChunkEncoder,\r\n ): ReadableStream<Uint8Array> {\r\n const encoderRef = encoder\r\n const toBytes = (() => {\r\n const text = new TextEncoder()\r\n return (frame: string): Uint8Array => text.encode(frame)\r\n })()\r\n let queue: string[] = []\r\n let pending: IteratorResult<StreamChunk> | undefined = first\r\n return new ReadableStream<Uint8Array>({\r\n pull: async controller => {\r\n try {\r\n while (queue.length === 0 && !encoderRef.terminal) {\r\n if (pending === undefined) {\r\n pending = await iterator.next()\r\n }\r\n const next = pending\r\n pending = undefined\r\n if (next.done) {\r\n queue.push(...encoderRef.finishFallback())\r\n break\r\n }\r\n queue.push(...encoderRef.start(), ...encoderRef.frames(next.value))\r\n }\r\n } catch (error: unknown) {\r\n const message = error instanceof LlmError ? error.failure.message : String(error)\r\n const code = error instanceof LlmError ? error.failure.code : 'TRANSPORT'\r\n queue = encoderRef.abortFrames(message, code)\r\n }\r\n if (queue.length > 0) {\r\n controller.enqueue(toBytes(queue.shift()!))\r\n if (encoderRef.terminal && queue.length === 0) controller.close()\r\n return\r\n }\r\n controller.close()\r\n },\r\n cancel: async () => {\r\n await iterator.return?.()\r\n },\r\n })\r\n }\r\n\r\n /**\r\n * One minimal reasoning-effort request, as the probe sweep needs it.\r\n *\r\n * A row that declares efforts is still checked locally, so an unlisted value\r\n * costs no request. A row that declares none \u2014 the only kind detection is\r\n * offered for \u2014 sends the value to the upstream and waits for its answer,\r\n * because the endpoint is the only authority on spellings the catalog never\r\n * lists. Either refusal is reported as an attributable 400 with code\r\n * `UNSUPPORTED_REASONING_EFFORT`, and an accepted value costs exactly one\r\n * streamed request, which this method ends after the first chunk arrives \u2014\r\n * see the module docs in `probe.ts`.\r\n */\r\n async probeEffort(model: string, effort: string | undefined, signal: AbortSignal): Promise<ProbeAttempt> {\r\n try {\r\n await this.getPat()\r\n } catch {\r\n return { status: 401, streamed: false, errorCode: 'MISSING_CREDENTIAL', detail: 'no Personal Access Token configured' }\r\n }\r\n const options: GenerateOptions = {\r\n provider: this.providerId,\r\n model,\r\n messages: [createUserMessage({\r\n content: [{ type: 'text', text: PROBE_PROMPT }],\r\n source: { kind: 'user' },\r\n })],\r\n maxTokens: PROBE_MAX_TOKENS,\r\n ...(effort === undefined ? {} : { reasoningEffort: ReasoningEffortId(effort) }),\r\n signal,\r\n }\r\n try {\r\n const iterator = this.transport.stream(options, this.catalogModelFor(model))[Symbol.asyncIterator]()\r\n try {\r\n const first = await iterator.next()\r\n return { status: first.done ? 502 : 200, streamed: !first.done }\r\n } finally {\r\n await iterator.return?.()\r\n }\r\n } catch (error) {\r\n if (error instanceof LlmError) {\r\n const status = error.failure.status ?? defaultStatusForProbe(error.failure.code)\r\n // A refusal the endpoint itself issued must reach the sweep under the\r\n // same code as one refused locally, or the sweep reads it as an\r\n // unattributable failure and reports `unknown` instead of a finding.\r\n // Classify from the full message, before `detail` is capped: both\r\n // markers sit far enough into Qoder's error body that the cap can cut\r\n // them off.\r\n const code = status === 400 && blamesReasoningEffort(error.failure.message)\r\n ? 'UNSUPPORTED_REASONING_EFFORT'\r\n : error.failure.code\r\n return { status, streamed: false, errorCode: code, detail: error.failure.message.slice(0, 300) }\r\n }\r\n return { status: 0, streamed: false, detail: `transport error: ${String(error)}` }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Whether an upstream 400 blames the `reasoning_effort` value it was sent.\r\n *\r\n * Qoder answers an impossible effort with a `provider_error` body whose nested\r\n * error names `invalid_parameter_error` and quotes `reasoning_effort`. Both\r\n * markers are required: a 400 naming only one of them is some other parameter\r\n * problem, and the sweep must not record it as a rejected level.\r\n */\r\nfunction blamesReasoningEffort(message: string): boolean {\r\n return message.includes('invalid_parameter_error') && message.includes('reasoning_effort')\r\n}\r\n\r\n/** Statuses {@link probeEffort} reports for failures the transport raised pre-network. */\r\nfunction defaultStatusForProbe(code: string): number {\r\n switch (code) {\r\n case 'UNSUPPORTED_REASONING_EFFORT':\r\n case 'UNSUPPORTED_CONTENT':\r\n case 'INVALID_REQUEST':\r\n return 400\r\n case 'MISSING_CREDENTIAL':\r\n case 'AUTH':\r\n return 401\r\n case 'RATE_LIMIT':\r\n return 429\r\n case 'QUOTA':\r\n return 402\r\n default:\r\n return 502\r\n }\r\n}\r\n\r\n/**\r\n * Translate one Qoder catalog row into the plugin's model-info shape.\r\n *\r\n * The Qoder vocabulary carries less than the WorkBuddy one did \u2014 no badges,\r\n * no promotions, no free/credits strings \u2014 so the billing section reports the\r\n * price factor only, spelled `x<n>`, and says so honestly when the upstream\r\n * reported nothing (`rateUnknown`). Context capacity comes from the effective\r\n * window, with the declared options kept for the card and the maximum-window\r\n * preference; a row with no capacity at all takes the transport's own default.\r\n */\r\nexport function modelInfoOf(model: QoderCatalogModel): QoderModelInfo {\r\n const options = Object.values(model.contextOptions ?? {})\r\n .map(option => option.tokenCount)\r\n .filter((count): count is number => typeof count === 'number' && Number.isFinite(count) && count > 0)\r\n const supportedContextWindows = [...new Set(options)].sort((left, right) => left - right)\r\n const defaultOptions = Object.values(model.contextOptions ?? {}).filter(option => option.isDefault === true)\r\n const contextWindow = model.contextWindow\r\n ?? (defaultOptions.length === 1 ? defaultOptions[0]?.tokenCount : undefined)\r\n ?? DEFAULT_CONTEXT_WINDOW\r\n const reasoning: QoderModelReasoning | undefined = model.isReasoning === true || model.supportsEffort === true\r\n ? {\r\n supports: true,\r\n ...model.reasoningEfforts === undefined || model.reasoningEfforts.length === 0\r\n ? {}\r\n : { supportedEfforts: model.reasoningEfforts.map(effort => effort.id) },\r\n ...model.defaultReasoningEffort === undefined ? {} : { defaultEffort: model.defaultReasoningEffort },\r\n canDisableThinking: false,\r\n }\r\n : undefined\r\n const billing: QoderModelBilling = model.priceFactor === undefined\r\n ? { free: false, rateUnknown: true }\r\n : model.priceFactor === 0\r\n ? { credits: 'x0', free: true }\r\n : { credits: `x${model.priceFactor}`, free: false }\r\n return {\r\n id: model.id,\r\n name: model.name === '' ? model.id : model.name,\r\n contextWindow,\r\n ...defaultOptions.length === 1 && defaultOptions[0]?.tokenCount !== undefined\r\n ? { defaultContextWindow: defaultOptions[0].tokenCount }\r\n : {},\r\n ...supportedContextWindows.length > 1 ? { supportedContextWindows } : {},\r\n maxTokens: model.maxTokens ?? DEFAULT_MAX_TOKENS,\r\n supportsImages: model.supportsImages === true,\r\n ...reasoning === undefined ? {} : { reasoning },\r\n billing,\r\n ...model.source === undefined ? {} : { source: model.source },\r\n }\r\n}\r\n\r\n/** The transport's own output cap for rows that declare none. */\r\nconst DEFAULT_MAX_TOKENS = 32_768\r\n\r\n/** A conservative input budget for rows that declare none. */\r\nconst DEFAULT_CONTEXT_WINDOW = 180_000\r\n", "/**\n * The reasoning-effort probe: decide whether a model's `reasoning_effort`\n * parameter is actually validated, and if so which canonical values it accepts.\n *\n * Implements `docs/reasoning-effort-probe-plan.md` \u00A74. The order matters and is\n * not an optimization:\n *\n * 1. **Baseline** (no `reasoning_effort`) proves the model, credential, and\n * request shape work at all, so a later rejection can be attributed.\n * 2. **Sentinel** (a fresh random, impossible-to-collide value) answers the one\n * question a per-level sweep cannot: does the upstream validate the field?\n * A model that accepts the sentinel answers 200 to *everything*, so its\n * per-level results would be uniformly false positives.\n * 3. **Levels**, only after the sentinel was refused.\n *\n * The result is an observation, never a capability claim. Even a fully\n * successful sweep means \"the upstream accepted these spellings\", not \"these\n * spellings change how the model thinks\".\n *\n * @module dsh-qoder-connect/probe\n */\n\nimport { randomBytes } from 'node:crypto'\nimport type { QoderEffort } from './upstream.ts'\n\n/**\n * The canonical values a probe tests, in a fixed order.\n *\n * `minimal` is absent: it appears in no upstream vocabulary. `off` is absent\n * by policy \u2014 disabling thinking is a separate capability the upstream must\n * declare through `canDisableThinking`, never something probing may infer.\n */\nexport const PROBE_EFFORT_CANDIDATES: readonly QoderEffort[] = ['low', 'medium', 'high', 'xhigh', 'max']\n\n/** Prompt body used by every probe request; carries nothing user-specific. */\nexport const PROBE_PROMPT = 'ping'\n\n/** Output ceiling for a probe request; the answer itself is never read. */\nexport const PROBE_MAX_TOKENS = 1\n\n/** Per-request ceiling so one hung probe cannot stall the queue. */\nexport const PROBE_REQUEST_TIMEOUT_MS = 30_000\n\n/** Sentinel generator; injectable so tests get deterministic values. */\nexport type SentinelFactory = () => string\n\n/** Default sentinel: unmistakably non-canonical, different on every call. */\nexport function randomSentinel(): string {\n return `probe_sentinel_${randomBytes(12).toString('hex')}`\n}\n\n/**\n * One response as the probe sees it, split into the only distinctions the\n * attribution rule needs.\n */\nexport interface ProbeAttempt {\n /** HTTP status, or 0 for a transport failure. */\n status: number\n /** True when a parseable SSE event arrived. */\n streamed: boolean\n /** `extError.code` from a JSON error body, when present. */\n errorCode?: string\n /** Free-form detail for logs; never shown as a capability claim. */\n detail?: string\n}\n\n/** How one attempt is performed; the caller owns credentials and HTTP. */\nexport type ProbeSender = (effort: string | undefined, signal: AbortSignal) => Promise<ProbeAttempt>\n\n/** The outcome of probing one model. */\nexport type ProbeOutcome =\n | { validation: 'validating'; efforts: readonly QoderEffort[]; requests: number }\n | { validation: 'non-validating'; efforts: readonly []; requests: number }\n | { validation: 'unknown'; efforts: readonly []; requests: number; reason: string }\n\n/**\n * The code a refused effort arrives under, wherever it was refused\n * (`src/qoder/transport/wire/serialize.ts` for a declared row, `probeEffort`\n * for a refusal the endpoint issued itself).\n *\n * Only a row that declares efforts can be refused locally. An undeclared row \u2014\n * the only kind a sweep is offered for \u2014 sends every candidate to the wire and\n * lets the sentinel measure the endpoint rather than this plugin's own reading\n * of the catalog.\n */\nconst INVALID_EFFORT_CODE = 'UNSUPPORTED_REASONING_EFFORT'\n\n/** Whether an attempt is an attributable rejection of the effort value. */\nfunction isEffortRejection(attempt: ProbeAttempt): boolean {\n return attempt.status === 400 && attempt.errorCode === INVALID_EFFORT_CODE\n}\n\n/** Whether an attempt shows the upstream accepted the request and streamed. */\nfunction isAcceptance(attempt: ProbeAttempt): boolean {\n return attempt.status === 200 && attempt.streamed\n}\n\n/** Why an attempt ended in `unknown`, phrased for a log line. */\nfunction unknownReason(stage: string, attempt: ProbeAttempt): string {\n const code = attempt.errorCode === undefined ? '' : ` (${attempt.errorCode})`\n const detail = attempt.detail === undefined ? '' : `: ${attempt.detail}`\n return `${stage} status ${attempt.status}${code}${detail}`\n}\n\n/**\n * Probe one model.\n *\n * `options.candidates` exists so tests can shorten the sweep; production always\n * uses {@link PROBE_EFFORT_CANDIDATES}.\n */\nexport async function probeModel(options: {\n send: ProbeSender\n sentinel?: SentinelFactory\n candidates?: readonly QoderEffort[]\n timeoutMs?: number\n}): Promise<ProbeOutcome> {\n const sentinel = options.sentinel ?? randomSentinel\n const candidates = options.candidates ?? PROBE_EFFORT_CANDIDATES\n const timeoutMs = options.timeoutMs ?? PROBE_REQUEST_TIMEOUT_MS\n let requests = 0\n\n const attempt = async (effort: string | undefined): Promise<ProbeAttempt> => {\n requests += 1\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeoutMs)\n try {\n return await options.send(effort, controller.signal)\n } catch (error: unknown) {\n return { status: 0, streamed: false, detail: `transport error: ${String(error)}` }\n } finally {\n clearTimeout(timer)\n }\n }\n\n // 1. Baseline: proves the request path itself is sound. Without this a 400\n // on the sentinel could just as well be an unrelated request problem.\n const baseline = await attempt(undefined)\n if (!isAcceptance(baseline)) {\n return { validation: 'unknown', efforts: [], requests, reason: unknownReason('baseline', baseline) }\n }\n\n // 2. Sentinel: the only step that can distinguish \"validates the field\" from\n // \"accepts anything\".\n const probe = sentinel()\n const sentinelAttempt = await attempt(probe)\n if (isAcceptance(sentinelAttempt)) {\n // The upstream took a value that cannot exist. Any per-level acceptance\n // would be equally meaningless, so stop here rather than spend more\n // requests producing false positives.\n return { validation: 'non-validating', efforts: [], requests }\n }\n if (!isEffortRejection(sentinelAttempt)) {\n return { validation: 'unknown', efforts: [], requests, reason: unknownReason('sentinel', sentinelAttempt) }\n }\n\n // 3. Levels: meaningful only because the sentinel was refused.\n const accepted: QoderEffort[] = []\n for (const effort of candidates) {\n const levelAttempt = await attempt(effort)\n if (isAcceptance(levelAttempt)) {\n accepted.push(effort)\n continue\n }\n if (isEffortRejection(levelAttempt)) continue\n // A non-decisive answer mid-sweep: the partial list is not a finding, so\n // report the whole run as unknown rather than under-claiming a model.\n return {\n validation: 'unknown',\n efforts: [],\n requests,\n reason: unknownReason(`level ${effort}`, levelAttempt),\n }\n }\n\n return { validation: 'validating', efforts: accepted, requests }\n}\n", "/**\r\n * DSH-compatible LLM error representation.\r\n *\r\n * @module dsh-provider-qoder/qoder/errors\r\n */\r\n\r\nimport { LlmError, ProviderRequestId, type LlmErrorOptions } from '@deepseek-ai/dsh-llm'\r\nimport { qoderResultCode } from './codes.ts'\r\n\r\nexport class QoderLlmError extends LlmError {\r\n constructor(message: string, code: string = 'UNKNOWN_ERROR', options?: LlmErrorOptions) {\r\n super(message, code, options)\r\n }\r\n}\r\n\r\n/** The queue/limit markers Qoder puts in a rejection body (observed 2026-09-26). */\r\nconst QUEUE_BODY_MARKERS: readonly RegExp[] = [\r\n /\"code\"\\s*:\\s*\"?10605\"?/u,\r\n /\"isQueued\"\\s*:\\s*true/u,\r\n /\"queueCount\"/u,\r\n /\"serviceAvailable\"\\s*:\\s*false/u,\r\n] as const\r\n\r\n/**\r\n * Whether an upstream rejection body is Qoder's **queue/limit** answer rather\r\n * than an authorization failure.\r\n *\r\n * Qoder answers a saturated per-model queue (and a region whose service is not\r\n * available) with an HTTP 401/403 \u2014 or a 200 SSE envelope carrying\r\n * `statusCodeValue: 403` \u2014 whose body says `code: 10605`, `isQueued: true`,\r\n * `queueCount`, `retryAfterSeconds` and sometimes `serviceAvailable: false`.\r\n * Observed verbatim on 2026-09-26:\r\n *\r\n * {\"code\":\"10605\",\"message\":\"{\\\"isQueued\\\":true,\\\"modelKey\\\":\\\"qfmodel\\\",\r\n * \\\"queueCount\\\":8887,\\\"queueType\\\":\\\"p3\\\",\\\"retryAfterSeconds\\\":30,\r\n * \\\"serviceAvailable\\\":true,\\\"waitTime\\\":274}\"}\r\n *\r\n * Reading that status as AUTH made the self-heal exchange fresh job tokens\r\n * against a queue no token can jump, and \u2014 because the host retries\r\n * `RATE_LIMIT` but deliberately not `AUTH` \u2014 it also suppressed the automatic\r\n * retry that would have sailed through the 30-second window. The body is the\r\n * only place the distinction is visible, so it gets the last say over status.\r\n */\r\nexport function qoderQueueSignal(body: string | undefined): { retryAfterMs?: number } | undefined {\r\n if (body === undefined || body === '') return undefined\r\n // The body often arrives JSON-nested inside the SSE envelope's own JSON,\r\n // which escapes every inner quote (`\\\"retryAfterSeconds\\\":30`). Dropping the\r\n // escapes keeps the markers readable at any nesting depth; for detection\r\n // this only removes ASCII backslashes, which no marker depends on.\r\n const text = body.replace(/\\\\/gu, '')\r\n if (!QUEUE_BODY_MARKERS.some(marker => marker.test(text))) return undefined\r\n const match = /\"retryAfterSeconds\"\\s*:\\s*(\\d+)/u.exec(text)\r\n return match === null ? {} : { retryAfterMs: Number(match[1]) * 1000 }\r\n}\r\n\r\n/**\r\n * Replace status digits that read as authorization failure with a neutral\r\n * word, for messages the upstream used to announce something other than a dead\r\n * credential.\r\n *\r\n * `dsh-llm-pi-ai`'s error classifier is a text matcher whose first test is\r\n * `/\\b(?:401|403)\\b/` \u2014 ahead of its 429/rate-limit test and ahead of every\r\n * quota test \u2014 so any message carrying those digits classifies AUTH no matter\r\n * the structured code travelling beside it. An answer that is really a\r\n * throttle or an exhausted quota must not reach that matcher as-is, or the user\r\n * sees \"API \u5BC6\u94A5\u65E0\u6548\" for a limit that clears on its own (observed verbatim on\r\n * 2026-09-26 23:30 and again at 23:40 for the queue; reproduced 2026-10-08 for\r\n * the daily counter reported in #10).\r\n *\r\n * @param message - the message to neutralize.\r\n * @param replacement - the neutral word substituted for the digits. `throttled`\r\n * for the queue answer, whose wording users and tests already know; `limited`\r\n * for a quota answer, which is not a throttle.\r\n */\r\nfunction deauthorizeDigits(message: string, replacement = 'throttled'): string {\r\n return message.replace(/\\b(?:401|403)\\b/gu, replacement)\r\n}\r\n\r\nexport function qoderHttpError(\r\n message: string,\r\n response: { status: number; headers?: Pick<Headers, 'get'> },\r\n body?: string,\r\n): QoderLlmError {\r\n const { status } = response\r\n const headerRetryAfterMs = retryAfterMs(response.headers?.get('retry-after') ?? null)\r\n const requestId = qoderRequestId(response.headers)\r\n // A 401/403 the upstream used to announce a queue is a throttle, not an\r\n // authorization failure. The body is passed in by the caller when it was\r\n // read; when it was not, the message often embeds it (the SSE envelope\r\n // path formats the body into the message), so fall back to the message.\r\n const queue = status === 401 || status === 403 || status === 429\r\n ? qoderQueueSignal(body ?? message)\r\n : undefined\r\n if (queue !== undefined) {\r\n const retryAfterMs = queue.retryAfterMs ?? headerRetryAfterMs\r\n // The message must not carry the upstream's 401/403 digits. The harness's\r\n // pi-ai error classifier matches those numbers in message TEXT ahead of\r\n // every other signal (`/\\b(?:401|403)\\b/` before `/\\b429\\b|rate.?limit/`),\r\n // so an answer that is really a queue read as a dead credential two layers\r\n // up \u2014 \"API \u5BC6\u94A5\u65E0\u6548\" in the UI \u2014 even with code RATE_LIMIT intact. The\r\n // facts survive: status stays 403 in `failure.status`, the body still\r\n // names 10605 / isQueued / retryAfterSeconds, and the retry hint rides\r\n // on providerRetryAfterMs.\r\n return new QoderLlmError(deauthorizeDigits(message), 'RATE_LIMIT', {\r\n status,\r\n ...retryAfterMs === undefined ? {} : { providerRetryAfterMs: retryAfterMs },\r\n ...requestId === undefined ? {} : { requestId },\r\n })\r\n }\r\n // A documented quota code is the one thing HTTP status cannot express. Qoder\r\n // answers an exhausted daily billing counter with 403 `{\"code\":\"110\",\r\n // \"message\":\"Billing daily count exceeded\"}`, which the status arm below would\r\n // read as a dead credential (#10): the user was told the PAT was revoked, a\r\n // fresh job token was exchanged that no token can fix, and the real cause \u2014 a\r\n // counter that resets the next day \u2014 was never shown.\r\n //\r\n // The code has the last word here regardless of status, for the same reason\r\n // `RATE_LIMIT` is exempted from the status arms below: the body is the only\r\n // place the distinction is visible. Only a *documented* code counts, so a 403\r\n // whose mirrored `code` field is the status itself, or whose prose merely\r\n // mentions a quota, still routes by status \u2014 a throttling answer that happens\r\n // to say \"quota exceeded\" must never be parked as an exhausted balance.\r\n const documented = qoderResultCode(body ?? message)\r\n if (documented?.family === 'quota') {\r\n // No `providerRetryAfterMs`: a spent daily window is not a \"try again in N\r\n // seconds\" hint, and the host's retry policy never retries QUOTA.\r\n return new QoderLlmError(deauthorizeDigits(message, 'limited'), 'QUOTA', {\r\n status,\r\n ...requestId === undefined ? {} : { requestId },\r\n })\r\n }\r\n // The same trap one family over: Qoder can name a request/policy code\r\n // (406/416/430/80411/80412) while answering 401/403, and the status arm below\r\n // would report \"API \u5BC6\u94A5\u65E0\u6548\" for a content refusal or an over-long input. pi-ai\r\n // has no code for either \u2014 its vocabulary stops at INVALID_REQUEST \u2014 so a\r\n // request failure is the honest floor.\r\n //\r\n // Only the trap is corrected: a 4xx status already reads as a request failure\r\n // on its own, and no other status has been observed carrying these codes.\r\n if (documented?.family === 'request' && (status === 401 || status === 403)) {\r\n return new QoderLlmError(deauthorizeDigits(message, 'rejected'), 'INVALID_REQUEST', {\r\n status,\r\n ...requestId === undefined ? {} : { requestId },\r\n })\r\n }\r\n const code = status === 401 || status === 403\r\n ? 'AUTH'\r\n : status === 408\r\n ? 'TIMEOUT'\r\n : status === 429\r\n ? 'RATE_LIMIT'\r\n : status >= 500 && status <= 599\r\n ? 'SERVER'\r\n : status >= 400 && status <= 499\r\n ? 'INVALID_REQUEST'\r\n : 'PROVIDER_ERROR'\r\n return new QoderLlmError(message, code, {\r\n status,\r\n ...headerRetryAfterMs === undefined ? {} : { providerRetryAfterMs: headerRetryAfterMs },\r\n ...requestId === undefined ? {} : { requestId },\r\n })\r\n}\r\n\r\nexport function qoderRequestId(headers?: Pick<Headers, 'get'>): ReturnType<typeof ProviderRequestId> | undefined {\r\n const value = headers?.get('x-request-id')\r\n ?? headers?.get('request-id')\r\n ?? headers?.get('x-amzn-requestid')\r\n const normalized = value?.trim()\r\n return normalized ? ProviderRequestId(normalized) : undefined\r\n}\r\n\r\n/**\r\n * Codes that keep the upstream's 401/403 status without being credential\r\n * rejections, so the status arm of {@link isQoderAuthRejection} must not claim\r\n * them.\r\n *\r\n * `RATE_LIMIT` is the queue answer (code 10605 / isQueued / retryAfterSeconds)\r\n * and `QUOTA`/`ACCOUNT_QUOTA` is a spent usage window (#10, e.g. code 110 with\r\n * `Billing daily count exceeded`). Both arrive as 401/403 and neither is fixed\r\n * by a fresh job token \u2014 the queue cannot be jumped and a quota cannot be\r\n * exchanged away \u2014 so healing either one spends an exchange and suppresses the\r\n * retry that would actually help (the queue) or reports a failure notice for a\r\n * condition that clears on its own (the quota).\r\n */\r\nconst NON_AUTH_STATUS_CODES: readonly string[] = ['RATE_LIMIT', 'QUOTA', 'ACCOUNT_QUOTA']\r\n\r\n/**\r\n * Whether this failure is an upstream authorization rejection worth one\r\n * re-auth retry.\r\n *\r\n * The job token the transport signs requests with is cached in memory; an\r\n * upstream that invalidates it mid-lifetime (gateway rotation or a fault\r\n * window) answers HTTP 401/403 before any payload is produced. That state is\r\n * distinguishable from a genuinely revoked PAT only by trying a fresh\r\n * exchange, so callers clear their credential cache and retry once before\r\n * reporting `AUTH` to the user.\r\n *\r\n * A code in {@link NON_AUTH_STATUS_CODES} is never a re-auth candidate, **even\r\n * when its status is 401/403**: those answers keep the status while saying the\r\n * credential was not the problem. Healing one exchanged job tokens against a\r\n * condition no token can change (observed 2026-09-26 for the queue, and again\r\n * 2026-10-08 for the daily counter), and by consuming the retry it suppressed\r\n * the rate-limit retry that would have ridden out the window.\r\n */\r\nexport function isQoderAuthRejection(error: unknown): error is LlmError {\r\n if (!(error instanceof LlmError)) return false\r\n if (NON_AUTH_STATUS_CODES.includes(error.code)) return false\r\n return error.code === 'AUTH' || error.failure.status === 401 || error.failure.status === 403\r\n}\r\n\r\nexport function retryAfterMs(value: string | null, nowMs = Date.now()): number | undefined {\r\n const normalized = value?.trim()\r\n if (!normalized) return undefined\r\n if (/^\\d+$/u.test(normalized)) {\r\n const delayMs = Number(normalized) * 1000\r\n return Number.isFinite(delayMs) && delayMs > 0 ? delayMs : undefined\r\n }\r\n const retryAt = Date.parse(normalized)\r\n if (Number.isNaN(retryAt)) return undefined\r\n const delayMs = retryAt - nowMs\r\n return delayMs > 0 ? delayMs : undefined\r\n}\r\n", "/**\n * Qoder's documented result error codes, and the reader that finds one in a\n * rejection body.\n *\n * @module dsh-qoder-connect/qoder/codes\n */\n\n/**\n * What a documented code means for routing.\n *\n * `quota` is the only family this module changes routing for: every other\n * family is already read correctly from the HTTP status (see\n * `qoderHttpError`), and guessing beyond the documented table is worse than\n * leaving the existing status-based fallback in place.\n */\nexport type QoderResultCodeFamily = 'auth' | 'quota' | 'request' | 'runtime'\n\n/** One documented Qoder result code. */\nexport interface QoderResultCode {\n /** The numeric code as the upstream reports it in a body's `code` field. */\n readonly code: string\n /** The upstream's own one-line meaning, verbatim from the reference. */\n readonly name: string\n /** Which family decides routing. */\n readonly family: QoderResultCodeFamily\n}\n\nconst table = (family: QoderResultCodeFamily, rows: readonly (readonly [string, string])[]): QoderResultCode[] =>\n rows.map(([code, name]) => ({ code, name, family }))\n\n/**\n * The documented code table.\n *\n * Source: Qoder's *Errors and error codes* reference\n * (https://docs.qoder.com/cli/sdk/errors), \"Result error codes\" \u2014 the same\n * reference also states the rule this module exists to serve: \"Authentication,\n * quota, policy, input, and configuration errors require a change before\n * retrying.\"\n *\n * Scope note on evidence. That page documents the Agent SDK / qodercli surface,\n * not the loopback HTTP endpoint this plugin talks to. Two of its codes are\n * confirmed on our own path, with matching semantics:\n *\n * - `10605` \u2014 observed verbatim: `{\"code\":\"10605\",\"message\":\"{\\\"isQueued\\\":true,\n * ...\\\"retryAfterSeconds\\\":30}\"}` (see `qoderQueueSignal`).\n * - `110` \u2014 reported in dsh-qoder-connect#10 and reproduced by injecting the\n * reported body through this transport: `{\"code\":\"110\",\"message\":\"Billing\n * daily count exceeded\"}`.\n *\n * The rest are carried as the upstream's documented vocabulary. They are read\n * only to identify the family; an undocumented code is never guessed at, so a\n * body this table does not recognize keeps whatever routing the HTTP status\n * already gives it.\n */\nexport const QODER_RESULT_CODES: readonly QoderResultCode[] = Object.freeze([\n ...table('auth', [\n ['105', 'Login or access token expired'],\n ]),\n ...table('quota', [\n ['110', 'Daily usage limit reached'],\n ['113', 'Usage quota exhausted'],\n ['114', 'Free-trial account limit reached'],\n ['115', 'Free-user quota reached'],\n ['116', 'Team administrator Credits exhausted'],\n ['117', 'Team member Credits exhausted'],\n ['118', 'Personal Credits exhausted'],\n ['119', 'Free usage limit for the selected model reached'],\n ['122', 'Billing-group Credits limit reached'],\n ]),\n ...table('request', [\n ['406', 'Request blocked because of sensitive content or model refusal'],\n ['416', 'Requested range or request shape is not satisfiable'],\n ['430', 'Requested capability is not supported'],\n ['47902', 'Maximum Agent turns reached'],\n ['48716', 'A Hook blocked Agent execution'],\n ['80411', 'Input content is too long'],\n ['80412', 'Too many images or documents'],\n ]),\n ...table('runtime', [\n ['500', 'Request or network failure'],\n ['10408', 'Request timed out'],\n ['10500', 'Model service internal error'],\n ['10605', 'Model request is queued'],\n ]),\n])\n\nconst byCode = new Map(QODER_RESULT_CODES.map(entry => [entry.code, entry]))\n\n/**\n * The documented result code a rejection body names, if it names one.\n *\n * Qoder nests: a queue answer arrives as `{\"code\":\"10605\",\"message\":\"{\\\"isQueued\\\":\n * true,...}\"}`, so the inner payload is escaped JSON and a marker can sit at any\n * depth. Dropping the ASCII backslashes keeps every layer readable at once \u2014 the\n * same trick `qoderQueueSignal` uses, and for the same reason; no marker this\n * module looks for depends on a backslash.\n *\n * Only a *quoted* `code` key counts. Qoder also mirrors raw HTTP statuses into a\n * `code` field (`\"code\":\"429\"`, `\"code\":403`), and a message that merely mentions\n * a code in prose must not be read as one; both stay unrecognized because neither\n * names a documented result code.\n *\n * @param body - the upstream error body, or the formatted message when the body\n * was only embedded in it.\n * @returns the matching table entry, or `undefined` when the body names no\n * documented code \u2014 never a guess.\n */\nexport function qoderResultCode(body: string | undefined): QoderResultCode | undefined {\n if (body === undefined || body === '') return undefined\n const text = body.replace(/\\\\/gu, '')\n for (const match of text.matchAll(/\"(?:error_)?code\"\\s*:\\s*\"?(\\d+)\"?/gu)) {\n const entry = byCode.get(match[1] as string)\n if (entry !== undefined) return entry\n }\n return undefined\n}\n", "/** Deep module owning all communication with Qoder. */\r\n\r\nimport { LlmError, type GenerateOptions, type StreamChunk } from '@deepseek-ai/dsh-llm'\r\nimport type { AttachmentStore } from '@deepseek-ai/dsh-attachment'\r\nimport { QoderAuthService } from './auth.ts'\r\nimport type { QoderCatalogModel } from '../catalog.ts'\r\nimport type { QoderRegion } from './endpoints.ts'\r\nimport { QoderLlmError, isQoderAuthRejection } from '../errors.ts'\r\nimport type { QoderLogger } from './logging.ts'\r\nimport { fetchQoderModels } from './catalog-reader.ts'\r\nimport {\r\n defaultResponseHeaderTimeoutMs,\r\n opaqueCredentialKey,\r\n retryMetadataRead,\r\n SingleFlight,\r\n} from './request.ts'\r\nimport { translateQoderMessages, validateQoderRequestShape } from './wire/serialize.ts'\r\nimport { QoderImageUploader } from './image-upload.ts'\r\nimport { QoderUsageReader } from './account-reader.ts'\r\nimport { QoderCheckInService, type QoderCheckInResult } from './checkin.ts'\r\nimport type { QoderAccountInfo } from '../account.ts'\r\nimport type { QoderTransport, QoderTransportOptions } from './index.ts'\r\nimport { streamQoderChat } from './chat.ts'\r\nimport type { CosyCredentials } from './wire/cosy.ts'\r\nimport type { QoderWireMessage } from './wire/wire-types.ts'\r\n\r\nexport const defaultStreamIdleTimeoutMs = 5 * 60 * 1000\r\n\r\n/**\r\n * How long a rotated-token notice may wait for an accepting chat.\r\n *\r\n * The heal's own retry can lose a race with a transient fault and be rescued\r\n * by a later attempt, so the notice is deferred until some chat is accepted.\r\n * That deferral has to be bounded: an unbounded one let a rotation from\r\n * minutes earlier surface as a fresh-looking row whose timestamp named a\r\n * moment the user could not connect to the row appearing now. Five minutes\r\n * comfortably covers the host's own retry cycle (its backoff caps at 10s)\r\n * while keeping the row adjacent to the event it describes.\r\n */\r\nconst jobTokenNoticeMaxAgeMs = 5 * 60 * 1000\r\n\r\nfunction aborted(message: string): QoderLlmError {\r\n return new QoderLlmError(message, 'ABORTED')\r\n}\r\n\r\nexport class DefaultQoderTransport implements QoderTransport {\r\n private readonly region: QoderRegion\r\n private readonly resolvePat: () => Promise<string>\r\n private readonly fetchImpl: typeof fetch\r\n private readonly logger: QoderLogger | undefined\r\n private readonly streamIdleTimeoutMs: number\r\n private readonly responseHeaderTimeoutMs: number\r\n private readonly metadataTimeoutMs: number | undefined\r\n private readonly auth: QoderAuthService\r\n private readonly usage: QoderUsageReader\r\n private readonly checkInService: QoderCheckInService\r\n private readonly modelFlights = new SingleFlight<readonly QoderCatalogModel[]>()\r\n private readonly attachments: Pick<AttachmentStore, 'imageLimits' | 'readImageRequest'> | undefined\r\n private readonly imageUploader: QoderImageUploader\r\n private readonly preserveThinking: boolean | undefined\r\n private readonly onJobTokenRefreshed: QoderTransportOptions['onJobTokenRefreshed']\r\n private readonly onJobTokenRefreshFailed: QoderTransportOptions['onJobTokenRefreshFailed']\r\n /**\r\n * Set when the self-heal exchanged a fresh job token, cleared when a chat\r\n * afterwards succeeds. The notice reports \"the token was rotated because the\r\n * old one was rejected\", which is true from that exchange on \u2014 so it must\r\n * not be tied to the heal's OWN retry, which can still lose a race with a\r\n * transient upstream timeout and be rescued by a later attempt.\r\n */\r\n private pendingRefreshAt: number | undefined\r\n /**\r\n * Whether the current unresolved heal failure has already been reported.\r\n *\r\n * One upstream rejection can outlive many host-level retries (an observed\r\n * storm ran 59 of them across 75 steps), and the transport re-heals inside\r\n * every one of them. Without this latch the failure notice would print once\r\n * per retry; with it, the user is told once per outage. Cleared as soon as\r\n * any chat is accepted, so the next outage announces itself again.\r\n */\r\n private refreshFailureAnnounced = false\r\n\r\n constructor(options: QoderTransportOptions) {\r\n this.region = options.region\r\n this.resolvePat = options.resolvePat\r\n this.fetchImpl = options.fetch ?? globalThis.fetch\r\n this.logger = options.logger\r\n this.streamIdleTimeoutMs = options.streamIdleTimeoutMs ?? defaultStreamIdleTimeoutMs\r\n this.responseHeaderTimeoutMs = options.responseHeaderTimeoutMs ?? defaultResponseHeaderTimeoutMs\r\n this.metadataTimeoutMs = options.metadataTimeoutMs\r\n this.attachments = options.attachments\r\n this.preserveThinking = options.preserveThinking\r\n this.onJobTokenRefreshed = options.onJobTokenRefreshed\r\n this.onJobTokenRefreshFailed = options.onJobTokenRefreshFailed\r\n this.auth = new QoderAuthService({\r\n fetch: this.fetchImpl,\r\n logger: this.logger,\r\n region: this.region,\r\n resolveMachineId: options.resolveMachineId,\r\n })\r\n this.imageUploader = new QoderImageUploader({\r\n fetch: this.fetchImpl,\r\n logger: this.logger,\r\n region: this.region,\r\n ...options.imageUploadTimeoutMs === undefined ? {} : { timeoutMs: options.imageUploadTimeoutMs },\r\n ...options.imageUrlCacheTtlMs === undefined ? {} : { cacheTtlMs: options.imageUrlCacheTtlMs },\r\n refreshCredentials: async (signal) => {\r\n const pat = await this.requirePat(signal)\r\n this.auth.clear(pat)\r\n return this.auth.getCredentials(pat, signal)\r\n },\r\n })\r\n this.usage = new QoderUsageReader({\r\n authService: this.auth,\r\n fetch: this.fetchImpl,\r\n logger: this.logger,\r\n region: this.region,\r\n timeoutMs: this.metadataTimeoutMs,\r\n })\r\n this.checkInService = new QoderCheckInService({\r\n authService: this.auth,\r\n fetch: this.fetchImpl,\r\n logger: this.logger,\r\n region: this.region,\r\n timeoutMs: this.metadataTimeoutMs,\r\n })\r\n }\r\n\r\n stream(options: GenerateOptions, model?: QoderCatalogModel): AsyncIterable<StreamChunk> {\r\n return this.generate(options, model)\r\n }\r\n\r\n /**\r\n * Report the pending self-heal once a chat is accepted, then clear it.\r\n *\r\n * The notice means \"the stale token was rejected, so it was rotated, and the\r\n * chat works again\" \u2014 all three are true by the time a chat is accepted\r\n * after the refresh, no matter which attempt delivered it.\r\n */\r\n private flushPendingRefreshNotice(): void {\r\n if (this.pendingRefreshAt === undefined) return\r\n const at = this.pendingRefreshAt\r\n this.pendingRefreshAt = undefined\r\n // A rotation whose acceptance took this long is no longer news. Printing\r\n // it would drop a row into the conversation long after the fact, and its\r\n // timestamp would name a moment the user has no reason to connect to now \u2014\r\n // which reads exactly like a clock bug (observed: a 16:56 rotation\r\n // reported at 17:47). Dropping it keeps the notice meaningful.\r\n if (Date.now() - at > jobTokenNoticeMaxAgeMs) return\r\n this.logger?.warn?.('[Qoder Stream] Job token was auto-refreshed after an upstream rejection; the chat has recovered')\r\n this.onJobTokenRefreshed?.({ region: this.region, at })\r\n }\r\n\r\n /**\r\n * Drop a pending rotation notice whose heal did not rescue anything.\r\n *\r\n * The heal's own retry was rejected too, so \"the rotation fixed it\" is not\r\n * what happened. Leaving the notice pending made a LATER, unrelated chat\r\n * acceptance flush it \u2014 printing a success row that contradicts the failure\r\n * row already shown, stamped with the old rotation time.\r\n */\r\n private discardPendingRefreshNotice(): void {\r\n this.pendingRefreshAt = undefined\r\n }\r\n\r\n /**\r\n * Note that the upstream accepted a chat, ending any unresolved heal failure.\r\n *\r\n * `streamChat` calls this the moment its first chunk arrives \u2014 the only point\r\n * at which \"the credential was accepted\" is actually known. A rejected chat\r\n * throws before that, so this never fires on a failing attempt.\r\n */\r\n private onChatAccepted(): void {\r\n this.refreshFailureAnnounced = false\r\n this.flushPendingRefreshNotice()\r\n }\r\n\r\n async discoverModels(signal?: AbortSignal): Promise<readonly QoderCatalogModel[]> {\r\n const pat = await this.requirePat(signal)\r\n const key = opaqueCredentialKey(pat)\r\n return this.modelFlights.run(\r\n key,\r\n signal,\r\n async (sharedSignal) => {\r\n const credentials = await this.auth.getCredentials(pat, sharedSignal)\r\n return retryMetadataRead(sharedSignal, () => fetchQoderModels(credentials, {\r\n fetch: this.fetchImpl,\r\n signal: sharedSignal,\r\n logger: this.logger,\r\n region: this.region,\r\n timeoutMs: this.metadataTimeoutMs,\r\n }))\r\n },\r\n () => aborted('Qoder model discovery was aborted.'),\r\n )\r\n }\r\n\r\n async readAccount(options?: { force?: boolean | undefined; signal?: AbortSignal | undefined }): Promise<QoderAccountInfo> {\r\n const pat = await this.requirePat(options?.signal)\r\n return this.usage.readAccount(pat, {\r\n force: options?.force,\r\n signal: options?.signal,\r\n })\r\n }\r\n\r\n async checkIn(signal?: AbortSignal): Promise<QoderCheckInResult> {\r\n const pat = await this.requirePat(signal)\r\n return this.checkInService.checkIn(pat, signal)\r\n }\r\n\r\n private async requirePat(signal?: AbortSignal): Promise<string> {\r\n if (signal?.aborted) throw aborted('Qoder request was aborted.')\r\n const pat = (await this.resolvePat()).trim()\r\n if (!pat) {\r\n throw new QoderLlmError(\r\n 'Qoder Personal Access Token is missing. Configure Qoder in the Qoder settings page.',\r\n 'MISSING_CREDENTIAL',\r\n )\r\n }\r\n if (signal?.aborted) throw aborted('Qoder request was aborted.')\r\n return pat\r\n }\r\n\r\n /**\r\n * Stream one chat, reporting acceptance as soon as the FIRST chunk arrives.\r\n *\r\n * `streamQoderChat` throws before yielding anything when the upstream rejects\r\n * the request, so a first chunk means the credential was accepted. Reporting\r\n * at that moment \u2014 rather than after the whole stream drains \u2014 matters\r\n * because the consumer may close the stream early, and code after a\r\n * completed `yield*` would then never run.\r\n *\r\n * @param onAccepted - Called once, before the first chunk is forwarded.\r\n */\r\n private async * streamChat(\r\n options: GenerateOptions,\r\n model: QoderCatalogModel | undefined,\r\n credentials: CosyCredentials,\r\n messages: QoderWireMessage[],\r\n onAccepted: () => void,\r\n ): AsyncGenerator<StreamChunk> {\r\n const stream = streamQoderChat(options, model, credentials, messages, {\r\n fetch: this.fetchImpl,\r\n logger: this.logger,\r\n region: this.region,\r\n responseHeaderTimeoutMs: this.responseHeaderTimeoutMs,\r\n streamIdleTimeoutMs: this.streamIdleTimeoutMs,\r\n })\r\n const first = await stream.next()\r\n onAccepted()\r\n if (!first.done) yield first.value\r\n yield* stream\r\n }\r\n\r\n private async * generate(\r\n options: GenerateOptions,\r\n model?: QoderCatalogModel,\r\n ): AsyncGenerator<StreamChunk> {\r\n if (options.signal?.aborted) throw aborted('Request was aborted prior to generation.')\r\n\r\n // Phase 1: static validation finishes before credential resolution or any\r\n // provider I/O, so an unusable request never consumes a subscription.\r\n validateQoderRequestShape(options, model)\r\n // Phase 2: credentials, which the center image exchange must be able to sign with.\r\n const pat = await this.requirePat(options.signal)\r\n const credentials = await this.auth.getCredentials(pat, options.signal)\r\n // Phase 3: read attachments, publish images, and assemble wire messages.\r\n const messages = await translateQoderMessages(options, this.attachments, {\r\n uploader: this.imageUploader,\r\n credentials,\r\n preserveThinking: this.preserveThinking,\r\n })\r\n // Image publication may have refreshed a rejected job token, so the chat\r\n // credential is read once more: it must be the token that actually signs.\r\n const chatCredentials = await this.auth.getCredentials(pat, options.signal)\r\n try {\r\n // A pending notice from an earlier heal is reported as soon as this\r\n // request is accepted (see `streamChat`).\r\n yield* this.streamChat(options, model, chatCredentials, messages, () => {\r\n this.onChatAccepted()\r\n })\r\n return\r\n } catch (error: unknown) {\r\n // A cached job token the upstream has started rejecting (a gateway-side\r\n // invalidation or its own rotation) reads as HTTP 401 before any stream\r\n // byte is produced. One fresh exchange self-heals that window; a\r\n // genuinely revoked PAT fails the retry identically, and the retry\r\n // trades one extra exchange call against turning a transient gateway\r\n // state into a false \"sign in again\" report for the user.\r\n //\r\n // Note what is NOT healed: a 401/403 the upstream used to announce a\r\n // saturated queue (body carries code 10605 / isQueued / retryAfterSeconds)\r\n // now classifies as RATE_LIMIT, not AUTH \u2014 see qoderQueueSignal. A fresh\r\n // token cannot jump a queue, so those rejections surface immediately and\r\n // let the host's retry policy (which retries RATE_LIMIT, never AUTH)\r\n // ride out the window instead.\r\n if (!isQoderAuthRejection(error) || options.signal?.aborted) throw error\r\n this.logger?.warn?.(\r\n '[Qoder Stream] Chat rejected as unauthorized; exchanging a fresh job token and retrying once',\r\n { status: error.failure.status },\r\n )\r\n }\r\n // A gateway fault window outlives one immediate retry (observed 2026-09-20:\r\n // ~09:49-11:27 local, 401s lasting minutes). Two paced rounds cover a\r\n // short window; a revoked PAT still terminates honestly at the first\r\n // round's failure, just two exchanges later. Each retry exchanges OUTSIDE\r\n // the shared single-flight (exchangeFresh): the flight can be aborted by a\r\n // departing concurrent waiter (quota poll, catalog sweep), and a retry\r\n // joined to it would be cancelled by a path unrelated to the chat.\r\n let lastRejection: unknown\r\n // The rotation this request armed for its own heal. The pending notice is\r\n // instance state shared by every in-flight request on this transport, so\r\n // discarding on failure must clear only what this request armed \u2014 a\r\n // concurrent request may have armed its own (successful) notice after ours\r\n // and deserves it.\r\n let noticeAt: number | undefined\r\n for (let round = 0; round < 2; round++) {\r\n const refreshed = await this.auth.exchangeFresh(pat, options.signal)\r\n // The rotation has happened; the first chat accepted afterwards \u2014 this\r\n // round's retry or any subsequent one \u2014 is what makes it reportable.\r\n this.pendingRefreshAt = Date.now()\r\n noticeAt = this.pendingRefreshAt\r\n try {\r\n yield* this.streamChat(options, model, refreshed, messages, () => {\r\n this.onChatAccepted()\r\n })\r\n return\r\n } catch (error: unknown) {\r\n if (!isQoderAuthRejection(error) || options.signal?.aborted) throw error\r\n lastRejection = error\r\n if (round + 1 < 2) {\r\n this.logger?.warn?.('[Qoder Stream] Fresh job token also rejected; waiting 2s and retrying once more', {\r\n status: error.failure.status,\r\n round: round + 1,\r\n })\r\n await new Promise<void>((resolve, reject) => {\r\n const timer = setTimeout(resolve, 2_000)\r\n options.signal?.addEventListener('abort', () => {\r\n clearTimeout(timer)\r\n reject(aborted('Request was aborted during the re-auth backoff.'))\r\n }, { once: true })\r\n })\r\n }\r\n }\r\n }\r\n // Both paced rounds exhausted on authorization rejections: the honest\r\n // answer is the last rejection, not a silently empty stream.\r\n //\r\n // The rotation did NOT rescue this chat, so the deferred success notice it\r\n // would otherwise have qualified for is void. Dropping it here is what\r\n // stops a later, unrelated chat acceptance from printing \"\u5DF2\u81EA\u52A8\u91CD\u6362\u5E76\u6062\u590D\"\r\n // with a stale rotation time \u2014 the row that made the notice look broken.\r\n // Only this request's own notice is void, though: a concurrent heal that\r\n // armed the pending slot after ours must keep it.\r\n if (this.pendingRefreshAt === noticeAt) this.discardPendingRefreshNotice()\r\n // Report the failed heal once per outage. The success notice covers \"the\r\n // rotation rescued the chat\"; without this, a rejection the rotation could\r\n // NOT rescue was announced nowhere at all, and the user was left reading a\r\n // bare authorization failure with no hint that recovery had been attempted.\r\n if (!this.refreshFailureAnnounced) {\r\n this.refreshFailureAnnounced = true\r\n this.logger?.warn?.('[Qoder Stream] Job token refresh did not recover the chat; the upstream still rejects it', {\r\n status: lastRejection instanceof LlmError ? lastRejection.failure.status : undefined,\r\n })\r\n this.onJobTokenRefreshFailed?.({\r\n region: this.region,\r\n at: Date.now(),\r\n ...(lastRejection instanceof LlmError && lastRejection.failure.status !== undefined\r\n ? { status: lastRejection.failure.status }\r\n : {}),\r\n })\r\n }\r\n throw lastRejection\r\n }\r\n}\r\n", "/** Qoder transport endpoints for Global and China service regions. */\n\nimport type { QoderRegion } from '../region.ts'\n\nexport type { QoderRegion } from '../region.ts'\n\nexport interface QoderRegionEndpoints {\n baseUrl: string\n openApiUrl: string\n /** Center service that owns durable image objects for multimodal input. */\n centerUrl: string\n}\n\nexport const qoderRegionEndpoints: Record<QoderRegion, QoderRegionEndpoints> = {\n global: {\n baseUrl: 'https://api3.qoder.sh/',\n openApiUrl: 'https://openapi.qoder.sh',\n centerUrl: 'https://center.qoder.sh',\n },\n china: {\n baseUrl: 'https://gateway.qoder.com.cn/',\n openApiUrl: 'https://openapi.qoder.com.cn',\n centerUrl: 'https://gateway.qoder.com.cn',\n },\n}\n\n/** Signed path of the center image upload route; it never carries an `/algo` prefix. */\nexport const qoderImageUploadPath = '/api/v2/image/upload'\n\nexport const qoderGlobalBaseUrl = qoderRegionEndpoints.global.baseUrl\nexport const qoderGlobalOpenApiUrl = qoderRegionEndpoints.global.openApiUrl\n\nexport function resolveQoderEndpoints(region: QoderRegion = 'global'): QoderRegionEndpoints {\n return qoderRegionEndpoints[region] ?? qoderRegionEndpoints.global\n}\n\nexport function getQoderChatUrl(region: QoderRegion = 'global'): string {\n const { baseUrl } = resolveQoderEndpoints(region)\n return `${baseUrl}algo/api/v2/service/pro/sse/agent_chat_generation?FetchKeys=llm_model_result&AgentId=agent_common&Encode=1`\n}\n\nexport function getQoderModelListUrl(region: QoderRegion = 'global'): string {\n const { baseUrl } = resolveQoderEndpoints(region)\n return `${baseUrl}algo/api/v2/model/list?Encode=1`\n}\n\nexport function getQoderImageUploadUrl(region: QoderRegion = 'global', requestId?: string): string {\n const { centerUrl } = resolveQoderEndpoints(region)\n // qodercli's WASM prepareRequest adds /algo to the HTTP URL, but not the signature path.\n const base = `${centerUrl.replace(/\\/+$/u, '')}/algo${qoderImageUploadPath}`\n return requestId === undefined ? base : `${base}?request_id=${encodeURIComponent(requestId)}`\n}\n\nexport function getQoderExchangeUrl(region: QoderRegion = 'global'): string {\n const { openApiUrl } = resolveQoderEndpoints(region)\n return `${openApiUrl}/api/v1/jobToken/exchange`\n}\n\nexport function getQoderUserInfoUrl(region: QoderRegion = 'global'): string {\n const { openApiUrl } = resolveQoderEndpoints(region)\n return `${openApiUrl}/api/v1/userinfo`\n}\n\nexport function getQoderUsageUrl(region: QoderRegion = 'global'): string {\n const { openApiUrl } = resolveQoderEndpoints(region)\n return `${openApiUrl}/api/v2/quota/usage`\n}\n\nexport function getQoderUserPlanUrl(region: QoderRegion = 'global'): string {\n const { openApiUrl } = resolveQoderEndpoints(region)\n return `${openApiUrl}/api/v2/user/plan`\n}\n\nexport function getQoderUserStatusUrl(region: QoderRegion = 'global'): string {\n const { openApiUrl } = resolveQoderEndpoints(region)\n return `${openApiUrl}/api/v3/user/status`\n}\n\n/** Path of the center web search route. */\nexport const qoderWebSearchPath = '/api/v1/webSearch/oneSearch'\n\nexport function getQoderWebSearchUrl(region: QoderRegion = 'global'): string {\n const { centerUrl } = resolveQoderEndpoints(region)\n return `${centerUrl.replace(/\\/+$/u, '')}/algo${qoderWebSearchPath}?Encode=1`\n}\n\nexport function getQoderCampaignsUrl(region: QoderRegion = 'global'): string {\n const { openApiUrl } = resolveQoderEndpoints(region)\n return `${openApiUrl}/sash/api/v1/me/campaigns`\n}\n\nexport function getQoderClaimCampaignUrl(region: QoderRegion = 'global', campaignId: string): string {\n const { openApiUrl } = resolveQoderEndpoints(region)\n return `${openApiUrl}/sash/api/v1/me/campaigns/${encodeURIComponent(campaignId)}/claim`\n}\n\n", "import crypto from 'node:crypto'\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { dirname, join } from 'node:path'\nimport { qoderMachineIdPath } from '../../paths.ts'\n\n/**\n * The machine id Qoder's own desktop CLI keeps at\n * `$HOME/.qoder/.auth/machine_id`.\n *\n * Strictly a read source for this plugin: when the official client generated\n * one, the transport reuses it so the same device presents one stable\n * identity upstream. The plugin never writes there \u2014 that tree belongs to\n * the official CLI.\n */\nfunction officialMachineIdPath(): string {\n return join(homedir(), '.qoder', '.auth', 'machine_id')\n}\n\n/**\n * The trusted locations consulted when a caller nominates no chain: the\n * official Qoder CLI's id first, this plugin's own seed second.\n *\n * A freshly created id is saved ONLY at the end of the chain, which is now\n * always inside the plugin's data directory. An earlier default ended the\n * chain at `~/.dsh/qoder/machine_id`, derived from `os.homedir()` rather\n * than the resolved harness home, so any host with `DSH_HOME` pointed at\n * another location got a device credential scattered into the wrong `$HOME`\n * \u2014 outside every profile, with no owner deleting it. That fallback is\n * gone.\n */\nfunction defaultMachineIdPaths(): string[] {\n return [officialMachineIdPath(), qoderMachineIdPath()]\n}\n\n/**\n * Read Qoder's machine id, or create this plugin's seed at the chain's end.\n *\n * `paths` is the read chain; its last entry doubles as the create point.\n * Passing no chain defaults to {@link defaultMachineIdPaths}; passing an\n * empty array nominates no save location, which keeps the id process-local.\n */\nexport function getMachineId(paths: readonly string[] = defaultMachineIdPaths()): string {\n for (const path of paths) {\n if (!existsSync(path)) continue\n try {\n const value = readFileSync(path, 'utf8').trim()\n if (value) return value\n } catch {\n // Try the next trusted location.\n }\n }\n\n const machineId = crypto.randomUUID()\n const savePath = paths.at(-1)\n if (savePath === undefined) return machineId\n try {\n mkdirSync(dirname(savePath), { recursive: true })\n writeFileSync(savePath, machineId, { encoding: 'utf8', flag: 'wx' })\n } catch {\n // Another process may have won creation; prefer its stable value.\n try {\n const existing = readFileSync(savePath, 'utf8').trim()\n if (existing) return existing\n } catch {\n // An ephemeral id is still sufficient for this process.\n }\n }\n return machineId\n}\n", "/**\n * The plugin's data directory \u2014 the ONE place every file the plugin owns\n * lives.\n *\n * Layout: `<profile>/.dsh-qoder-connect/state/` (the profile discovered\n * the same way the credential store always did). Everything \u2014 PAT files,\n * saved catalogs, probe records, the host heartbeat, and the machine-id\n * seed \u2014 writes there, so a profile directory never collects loose\n * `.qoder-*` files and the whole plugin's footprint is one folder.\n *\n * Fallbacks, in order: `DSH_QODER_DATA_DIR` env override \u2192 the discovered\n * profile \u2192 the Harness home (a checkout running its own tests, or a host\n * loading the plugin from outside any profile).\n *\n * Split out of `auth.ts` so catalog/probe/heartbeat stores can import the\n * directory without pulling in the credential code (and its upstream\n * dependency) \u2014 these modules stay leaf-light on purpose.\n *\n * @module dsh-qoder-connect/paths\n */\n\nimport { readFileSync, readdirSync, realpathSync, type Dirent } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { resolveDshHome } from '@deepseek-ai/dsh-home-paths'\n\n/** The per-profile directory the plugin's data folder lives under. */\nexport const QODER_DATA_DIR_NAME = '.dsh-qoder-connect'\n\n/** The directory inside the data dir where the rebuildable state files live. */\nexport const QODER_STATE_DIR_NAME = 'state'\n\n/** Environment override for the whole data directory. */\nexport const QODER_DATA_DIR_ENV = 'DSH_QODER_DATA_DIR'\n\nconst PROFILES_DIR_NAME = 'profiles'\n\n/** The npm name of this package, as a profile's manifest declares it. */\nconst PLUGIN_PACKAGE_NAME = 'dsh-qoder-connect'\n\nfunction pluginPackageRoot(): string | undefined {\n try {\n // `<root>/lib/paths.js` in a build, `<root>/src/paths.ts` from source.\n return dirname(dirname(fileURLToPath(import.meta.url)))\n } catch {\n // Not loaded from a file URL (a bundled or synthetic module).\n return undefined\n }\n}\n\n/**\n * Whether a profile directory declares this plugin.\n *\n * Read from the profile's manifest rather than inferred from this module's own\n * location, because DSH installs a plugin into a profile by *link*: the manifest\n * carries `\"dsh-qoder-connect\": \"link:/path/to/checkout\"`, while Node\n * resolves the module to that real path, which lies outside `$DSH_HOME` entirely.\n * Walking up from the module would therefore miss the profile for exactly the\n * install shape a developer uses.\n */\nfunction profileDeclaresPlugin(profileDir: string): boolean {\n try {\n const manifest = JSON.parse(readFileSync(join(profileDir, 'package.json'), 'utf8')) as {\n dependencies?: Record<string, unknown>\n devDependencies?: Record<string, unknown>\n }\n return typeof manifest.dependencies?.[PLUGIN_PACKAGE_NAME] === 'string'\n || typeof manifest.devDependencies?.[PLUGIN_PACKAGE_NAME] === 'string'\n } catch {\n // Not a profile, or unreadable: it simply is not a candidate.\n return false\n }\n}\n\n/**\n * Whether a profile's installed copy of this plugin resolves to this package.\n *\n * This is what separates two profiles that both declare the plugin \u2014 a `web` and\n * a `desktop` profile can each list it \u2014 so the data directory follows the\n * profile whose copy is actually running rather than the first one found.\n */\nfunction profileLinksToThisPackage(profileDir: string): boolean {\n const own = pluginPackageRoot()\n if (own === undefined) return false\n try {\n return realpathSync(join(profileDir, 'node_modules', PLUGIN_PACKAGE_NAME)) === realpathSync(own)\n } catch {\n // No installed copy, or an unreadable link.\n return false\n }\n}\n\n/**\n * The profile directory this plugin belongs to, or undefined when none can be\n * determined.\n *\n * A single declaring profile is accepted without the link test, so a normal\n * (non-linked) install still resolves.\n */\nfunction discoverProfileDir(): string | undefined {\n const profilesRoot = join(resolveDshHome(), PROFILES_DIR_NAME)\n let entries: Dirent[]\n try {\n entries = readdirSync(profilesRoot, { withFileTypes: true })\n } catch {\n // No profiles directory at all: nothing to discover.\n return undefined\n }\n const candidates: string[] = []\n for (const entry of entries) {\n if (!entry.isDirectory() && !entry.isSymbolicLink()) continue\n const dir = join(profilesRoot, entry.name)\n if (profileDeclaresPlugin(dir)) candidates.push(dir)\n }\n if (candidates.length === 0) return undefined\n if (candidates.length === 1) return candidates[0]\n return candidates.find(candidate => profileLinksToThisPackage(candidate))\n}\n\n/**\n * The plugin's data directory: `<profile>/.dsh-qoder-connect`.\n *\n * Falls back to the Harness home when no profile can be discovered \u2014 a\n * checkout running its own tests, or a host that loads the plugin from\n * outside a profile \u2014 so the plugin always has somewhere to write, and\n * `DSH_QODER_DATA_DIR` overrides either way.\n */\nexport function qoderPluginDataDir(): string {\n const override = process.env[QODER_DATA_DIR_ENV]\n if (override !== undefined && override.trim() !== '') return override\n const base = discoverProfileDir() ?? resolveDshHome()\n return join(base, QODER_DATA_DIR_NAME)\n}\n\n/**\n * The directory the rebuildable state files live in:\n * `<data dir>/state/` (saved catalogs, probe records, the host heartbeat).\n */\nexport function qoderStateDir(): string {\n return join(qoderPluginDataDir(), QODER_STATE_DIR_NAME)\n}\n\n/**\n * The plugin-owned seed for the Qoder transport's machine id.\n *\n * The transport's `getMachineId(paths)` helper reads a list of trusted\n * locations and writes its created UUID into the last one; this is the\n * DSH-side location the host wires into that chain, so the identifier stays\n * inside the plugin's own folder instead of scattering files near `$HOME`.\n */\nexport function qoderMachineIdPath(): string {\n return join(qoderStateDir(), '.qoder-machine-id')\n}\n", "/** Internal request lifecycle primitives for the Qoder transport. */\r\n\r\nimport { createHash } from 'node:crypto'\r\nimport { brotliDecompressSync, gunzipSync, inflateSync } from 'node:zlib'\r\nimport { QoderLlmError, qoderHttpError, qoderRequestId } from '../errors.ts'\r\nimport { logParsedResponse, redactLogPayload, type QoderLogger } from './logging.ts'\r\nimport { defaultUserAgent, qoderClientType } from './wire/cosy.ts'\r\n\r\nexport const defaultMetadataTimeoutMs = 15_000\r\nexport const defaultResponseHeaderTimeoutMs = 60_000\r\nexport const defaultMaxJsonBytes = 2 * 1024 * 1024\r\nexport const defaultMaxErrorBytes = 16 * 1024\r\nconst metadataRetryBaseDelayMs = 200\r\nconst maxProviderRetryDelayMs = 10_000\r\n\r\nexport function opaqueCredentialKey(value: string): string {\r\n return createHash('sha256').update(value).digest('hex')\r\n}\r\n\r\nfunction retryableMetadataError(error: unknown): error is QoderLlmError {\r\n return error instanceof QoderLlmError\r\n && ['RATE_LIMIT', 'SERVER', 'TIMEOUT', 'TRANSPORT'].includes(error.code)\r\n}\r\n\r\nfunction abortableDelay(ms: number, signal: AbortSignal): Promise<void> {\r\n if (signal.aborted) return Promise.reject(new DOMException('aborted', 'AbortError'))\r\n return new Promise((resolve, reject) => {\r\n const timer = setTimeout(() => {\r\n signal.removeEventListener('abort', onAbort)\r\n resolve()\r\n }, ms)\r\n const onAbort = (): void => {\r\n clearTimeout(timer)\r\n reject(new DOMException('aborted', 'AbortError'))\r\n }\r\n signal.addEventListener('abort', onAbort, { once: true })\r\n })\r\n}\r\n\r\nexport async function retryMetadataRead<T>(\r\n signal: AbortSignal,\r\n operation: () => Promise<T>,\r\n): Promise<T> {\r\n try {\r\n return await operation()\r\n } catch (error) {\r\n if (!retryableMetadataError(error) || signal.aborted) throw error\r\n const providerDelay = error.failure.providerRetryAfterMs\r\n const delayMs = providerDelay === undefined\r\n ? metadataRetryBaseDelayMs + Math.floor(Math.random() * 41)\r\n : Math.min(providerDelay, maxProviderRetryDelayMs)\r\n await abortableDelay(delayMs, signal)\r\n return operation()\r\n }\r\n}\r\n\r\nexport function withDeadline(\r\n signal: AbortSignal | undefined,\r\n timeoutMs: number,\r\n): { signal: AbortSignal; timeoutSignal: AbortSignal } {\r\n const timeoutSignal = AbortSignal.timeout(timeoutMs)\r\n return {\r\n timeoutSignal,\r\n signal: signal === undefined ? timeoutSignal : AbortSignal.any([signal, timeoutSignal]),\r\n }\r\n}\r\n\r\nexport async function readLimitedText(\r\n response: Response,\r\n maxBytes: number,\r\n label: string,\r\n): Promise<string> {\r\n const declaredLength = Number(response.headers.get('content-length'))\r\n if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {\r\n await response.body?.cancel().catch(() => undefined)\r\n throw new QoderLlmError(`${label} exceeded its response size limit.`, 'MALFORMED_RESPONSE')\r\n }\r\n if (!response.body) return ''\r\n\r\n const reader = response.body.getReader()\r\n const chunks: Uint8Array[] = []\r\n let bytes = 0\r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read()\r\n if (done) break\r\n bytes += value.byteLength\r\n if (bytes > maxBytes) {\r\n throw new QoderLlmError(`${label} exceeded its response size limit.`, 'MALFORMED_RESPONSE')\r\n }\r\n chunks.push(value)\r\n }\r\n } finally {\r\n await reader.cancel().catch(() => undefined)\r\n reader.releaseLock()\r\n }\r\n\r\n // Decode at the byte level: a host fetch whose stack does not decompress\r\n // (the Electron desktop host) yields the compressed stream verbatim, and a\r\n // TextDecoder pass would destroy those bytes irreversibly. The encoding is\r\n // taken from the response header; when that is missing too, the gzip magic\r\n // number is the fallback signal.\r\n let payload = Buffer.concat(chunks.map(chunk => Buffer.from(chunk)))\r\n const encoding = (response.headers.get('content-encoding') ?? '').toLowerCase()\r\n const looksGzipped = payload.length >= 2 && payload[0] === 0x1f && payload[1] === 0x8b\r\n if (encoding !== '' || looksGzipped) {\r\n try {\r\n if (encoding.includes('gzip') || (encoding === '' && looksGzipped)) {\r\n payload = gunzipSync(payload)\r\n } else if (encoding.includes('br')) {\r\n payload = brotliDecompressSync(payload)\r\n } else if (encoding.includes('deflate')) {\r\n payload = inflateSync(payload)\r\n }\r\n } catch {\r\n throw new QoderLlmError(`${label} arrived compressed but could not be decompressed.`, 'MALFORMED_RESPONSE')\r\n }\r\n if (payload.byteLength > maxBytes) {\r\n throw new QoderLlmError(`${label} exceeded its response size limit.`, 'MALFORMED_RESPONSE')\r\n }\r\n }\r\n return new TextDecoder().decode(payload)\r\n}\r\n\r\ninterface Flight<T> {\r\n controller: AbortController\r\n promise: Promise<T>\r\n settled: boolean\r\n waiters: number\r\n}\r\n\r\nexport class SingleFlight<T> {\r\n private readonly flights = new Map<string, Flight<T>>()\r\n\r\n run(\r\n key: string,\r\n signal: AbortSignal | undefined,\r\n start: (signal: AbortSignal) => Promise<T>,\r\n abortedError: () => Error,\r\n ): Promise<T> {\r\n if (signal?.aborted) return Promise.reject(abortedError())\r\n\r\n let flight = this.flights.get(key)\r\n if (flight === undefined || flight.controller.signal.aborted) {\r\n const controller = new AbortController()\r\n const created = {} as Flight<T>\r\n created.controller = controller\r\n created.settled = false\r\n created.waiters = 0\r\n created.promise = start(controller.signal).finally(() => {\r\n created.settled = true\r\n if (this.flights.get(key) === created) this.flights.delete(key)\r\n })\r\n flight = created\r\n this.flights.set(key, created)\r\n }\r\n\r\n flight.waiters++\r\n return new Promise<T>((resolve, reject) => {\r\n let finished = false\r\n const finish = (callback: () => void): void => {\r\n if (finished) return\r\n finished = true\r\n signal?.removeEventListener('abort', onAbort)\r\n flight.waiters--\r\n if (flight.waiters === 0 && !flight.settled) {\r\n if (this.flights.get(key) === flight) this.flights.delete(key)\r\n flight.controller.abort('all callers aborted')\r\n }\r\n callback()\r\n }\r\n const onAbort = (): void => finish(() => reject(abortedError()))\r\n signal?.addEventListener('abort', onAbort, { once: true })\r\n flight.promise.then(\r\n value => finish(() => resolve(value)),\r\n error => finish(() => reject(error)),\r\n )\r\n })\r\n }\r\n}\r\n\r\nexport interface OpenApiJsonRequestOptions {\r\n url: string\r\n method?: 'GET' | 'POST' | undefined\r\n token?: string | undefined\r\n machineId?: string | undefined\r\n body?: unknown\r\n headers?: Record<string, string> | undefined\r\n signal?: AbortSignal | undefined\r\n timeoutMs?: number | undefined\r\n logger?: QoderLogger | undefined\r\n operation: string\r\n logCategory?: string | undefined\r\n userAgent?: string | undefined\r\n}\r\n\r\nexport async function openApiJsonRequest<T>(\r\n fetchImpl: typeof fetch,\r\n options: OpenApiJsonRequestOptions,\r\n): Promise<T> {\r\n const method = options.method ?? (options.body !== undefined ? 'POST' : 'GET')\r\n const timeoutMs = options.timeoutMs ?? defaultMetadataTimeoutMs\r\n const timeoutSignal = AbortSignal.timeout(timeoutMs)\r\n const requestSignal = options.signal === undefined\r\n ? timeoutSignal\r\n : AbortSignal.any([options.signal, timeoutSignal])\r\n const startedAt = performance.now()\r\n\r\n options.logger?.debug?.(`[Qoder ${options.operation}] Requesting`, { url: options.url, method })\r\n\r\n try {\r\n const headers: Record<string, string> = {\r\n accept: 'application/json',\r\n // Keep the upstream from compressing: the Electron desktop host's fetch\r\n // does not decompress the body, and a compressed stream would reach the\r\n // JSON parser as binary noise. `identity` states the preference\r\n // explicitly; readLimitedText decompresses as a fallback.\r\n 'accept-encoding': 'identity',\r\n 'user-agent': options.userAgent ?? defaultUserAgent,\r\n 'cosy-version': '1.0.1',\r\n 'cosy-clienttype': qoderClientType,\r\n ...options.headers,\r\n }\r\n if (options.token) {\r\n headers.authorization = `Bearer ${options.token}`\r\n }\r\n if (options.machineId) {\r\n headers['Cosy-MachineToken'] = options.machineId\r\n headers['Cosy-MachineType'] = 'host'\r\n }\r\n let bodyText: string | undefined\r\n if (options.body !== undefined) {\r\n headers['content-type'] = 'application/json'\r\n bodyText = typeof options.body === 'string' ? options.body : JSON.stringify(options.body)\r\n }\r\n\r\n const response = await fetchImpl(options.url, {\r\n method,\r\n headers,\r\n // Under exactOptionalPropertyTypes RequestInit forbids an explicit\r\n // `body: undefined`; omit the property when there is no payload.\r\n ...bodyText === undefined ? {} : { body: bodyText },\r\n signal: requestSignal,\r\n })\r\n\r\n options.logger?.debug?.(`[Qoder ${options.operation}] Request completed`, {\r\n status: response.status,\r\n statusText: response.statusText,\r\n durationMs: Math.round(performance.now() - startedAt),\r\n ...qoderRequestId(response.headers) === undefined ? {} : { requestId: qoderRequestId(response.headers) },\r\n })\r\n\r\n const text = await readLimitedText(\r\n response,\r\n response.ok ? defaultMaxJsonBytes : defaultMaxErrorBytes,\r\n `Qoder ${options.operation} response`,\r\n )\r\n\r\n if (!response.ok) {\r\n options.logger?.error?.(`[Qoder ${options.operation}] Request failed`, redactLogPayload(text))\r\n // The body rides along so a 401/403 that is really the upstream's\r\n // queue answer (code 10605 / isQueued) classifies as a rate limit\r\n // instead of an authorization failure \u2014 see qoderQueueSignal.\r\n throw qoderHttpError(\r\n `Failed to execute Qoder ${options.operation} with status ${response.status}.`,\r\n response,\r\n text,\r\n )\r\n }\r\n\r\n let data: unknown\r\n try {\r\n data = JSON.parse(text)\r\n } catch {\r\n options.logger?.error?.(`[Qoder ${options.operation}] Invalid JSON response`, redactLogPayload(text))\r\n throw new QoderLlmError(`Failed to parse Qoder ${options.operation} JSON response`, 'MALFORMED_RESPONSE')\r\n }\r\n\r\n if (options.logCategory) {\r\n logParsedResponse(options.logger, options.logCategory, data)\r\n }\r\n\r\n return data as T\r\n } catch (error: unknown) {\r\n if (error instanceof QoderLlmError) throw error\r\n if (options.signal?.aborted) {\r\n throw new QoderLlmError(`Qoder ${options.operation} request was aborted.`, 'ABORTED')\r\n }\r\n if (timeoutSignal.aborted) {\r\n throw new QoderLlmError(`Qoder ${options.operation} request timed out.`, 'TIMEOUT')\r\n }\r\n throw new QoderLlmError(`Qoder ${options.operation} network request failed.`, 'TRANSPORT', { cause: error })\r\n }\r\n}\r\n", "/** Bounded, redacted diagnostics internal to the Qoder transport. */\n\nexport interface QoderLogger {\n debug?(message: string, ...details: unknown[]): void\n warn?(message: string, ...details: unknown[]): void\n error?(message: string, ...details: unknown[]): void\n}\n\nconst sensitiveKey = /(?:authorization|credential|password|secret|token)/iu\nconst identifierKey = /^(?:accountId|id|uid|userId)$/iu\nconst tokenValue = /\\b(?:jrt|jt|pt)-[\\w.-]+\\b/giu\nconst bearerValue = /Bearer\\s+[^\\s,;]+/giu\nconst maxDepth = 4\nconst maxEntries = 50\nconst maxStringLength = 500\n\nfunction maskIdentifier(value: unknown): string {\n const text = String(value)\n return text.length <= 4 ? '[REDACTED]' : `\u2026${text.slice(-4)}`\n}\n\nfunction maskEmail(value: unknown): string {\n const text = String(value)\n const at = text.indexOf('@')\n if (at <= 0) return '[REDACTED]'\n return `${text.slice(0, 1)}***${text.slice(at)}`\n}\n\nfunction redactString(value: string): string {\n const bounded = value.length > maxStringLength ? `${value.slice(0, maxStringLength)}\u2026` : value\n return bounded.replace(tokenValue, '[REDACTED]').replace(bearerValue, 'Bearer [REDACTED]')\n}\n\n/** Redact credentials and bound arbitrary provider values before logging them. */\nexport function redactLogValue(value: unknown, depth = 0): unknown {\n if (typeof value === 'string') return redactString(value)\n if (value === null || typeof value !== 'object') return value\n if (depth >= maxDepth) return '[TRUNCATED]'\n if (value instanceof Error) {\n return {\n name: value.name,\n message: redactString(value.message),\n ...('code' in value ? { code: redactLogValue(value.code, depth + 1) } : {}),\n }\n }\n if (Array.isArray(value)) {\n return value.slice(0, maxEntries).map(item => redactLogValue(item, depth + 1))\n }\n\n return Object.fromEntries(Object.entries(value).slice(0, maxEntries).map(([key, item]) => {\n if (sensitiveKey.test(key)) return [key, '[REDACTED]']\n if (identifierKey.test(key)) return [key, maskIdentifier(item)]\n if (key.toLowerCase() === 'email') return [key, maskEmail(item)]\n return [key, redactLogValue(item, depth + 1)]\n }))\n}\n\n/** Parse JSON-shaped diagnostics when possible, then apply the same redaction boundary. */\nexport function redactLogPayload(text: string): unknown {\n try {\n return redactLogValue(JSON.parse(text))\n } catch {\n return redactLogValue(text)\n }\n}\n\n/** Log one successfully parsed non-stream response through the shared redaction policy. */\nexport function logParsedResponse(\n logger: QoderLogger | undefined,\n operation: string,\n result: unknown,\n): void {\n logger?.debug?.('[Qoder Response] Parsed', redactLogValue({ operation, result }))\n}\n", "/**\n * COSY authentication headers and signature algorithm for Qoder services.\n *\n * Implements RSA + AES + MD5 signature generation required by the upstream\n * Qoder gateway.\n *\n * @module dsh-provider-qoder/qoder/transport/wire/cosy\n */\n\nimport crypto from 'node:crypto'\nimport { getMachineId } from '../machine-id.ts'\n\nconst qoderRSAPublicKey = `-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDA8iMH5c02LilrsERw9t6Pv5Nc\n4k6Pz1EaDicBMpdpxKduSZu5OANqUq8er4GM95omAGIOPOh+Nx0spthYA2BqGz+l\n6HRkPJ7S236FZz73In/KVuLnwI8JJ2CbuJap8kvheCCZpmAWpb/cPx/3Vr/J6I17\nXcW+ML9FoCI6AOvOzwIDAQAB\n-----END PUBLIC KEY-----`\n\nexport const qoderIdeVersion = '1.1.47'\nexport const qoderClientType = '5'\n/**\n * The desktop client identifier the campaign endpoints require.\n *\n * Measured against the live upstream: `/sash/api/v1/me/campaigns` answers\n * HTTP 200 with an EMPTY `campaigns` array when the caller presents the\n * generic {@link qoderClientType} (`5`), and returns the real list only when\n * it presents the desktop identifier `10`. A check-in built on the wrong\n * identifier looks healthy at the transport layer \u2014 status 200, no error \u2014\n * while silently reporting \"no campaign today\" forever, so the campaign\n * paths must send this one explicitly.\n */\nexport const qoderDesktopClientType = '10'\nexport const defaultUserAgent = `qoder/${qoderIdeVersion}`\nconst qoderDataPolicy = 'disagree'\nconst qoderLoginVersion = 'v2'\nconst qoderMachineOs = process.platform === 'win32'\n ? process.arch === 'arm64'\n ? 'aarch64_windows'\n : 'x86_64_windows'\n : process.arch === 'arm64'\n ? 'aarch64_linux'\n : 'x86_64_linux'\nconst qoderMachineTypeMagic = '5'\n\nexport interface CosyCredentials {\n userID: string\n authToken: string\n name: string\n email: string\n machineID?: string\n}\n\ninterface UserInfo {\n uid: string\n security_oauth_token: string\n name: string\n aid: string\n email: string\n}\n\ninterface CosyPayload {\n version: string\n requestId: string\n info: string\n cosyVersion: string\n ideVersion: string\n}\n\nexport function computeSigPath(urlStr: string): string {\n const parsed = new URL(urlStr)\n let sigPath = parsed.pathname\n if (sigPath.startsWith('/algo')) {\n sigPath = sigPath.substring('/algo'.length)\n }\n return sigPath\n}\n\nfunction rsaEncryptBase64(data: Buffer | string): string {\n const key = {\n key: qoderRSAPublicKey,\n padding: crypto.constants.RSA_PKCS1_PADDING,\n }\n const encrypted = crypto.publicEncrypt(key, typeof data === 'string' ? Buffer.from(data) : data)\n return encrypted.toString('base64')\n}\n\nfunction aesEncryptCBCBase64(plaintext: string, keyStr: string): string {\n const cipher = crypto.createCipheriv('aes-128-cbc', Buffer.from(keyStr), Buffer.from(keyStr))\n let encrypted = cipher.update(plaintext, 'utf8', 'base64')\n encrypted += cipher.final('base64')\n return encrypted\n}\n\nexport function buildAuthHeaders(\n body: Buffer | string | null,\n requestURL: string,\n creds: CosyCredentials,\n): Record<string, string> {\n if (!creds.userID) {\n throw new Error('cosy: user id is empty')\n }\n if (!creds.authToken) {\n throw new Error('cosy: auth token is empty')\n }\n\n const aesKey = crypto.randomUUID().replace(/-/g, '').slice(0, 16)\n const userInfo: UserInfo = {\n uid: creds.userID,\n security_oauth_token: creds.authToken,\n name: creds.name || '',\n aid: '',\n email: creds.email || '',\n }\n\n const infoB64 = aesEncryptCBCBase64(JSON.stringify(userInfo), aesKey)\n const cosyKey = rsaEncryptBase64(aesKey)\n\n const timestamp = Math.floor(Date.now() / 1000).toString()\n const requestId = crypto.randomUUID()\n\n const cosyPayload: CosyPayload = {\n version: 'v1',\n requestId,\n info: infoB64,\n cosyVersion: qoderIdeVersion,\n ideVersion: '',\n }\n\n const payloadB64 = Buffer.from(JSON.stringify(cosyPayload)).toString('base64')\n const sigPath = computeSigPath(requestURL)\n\n const bodyStr = body ? (Buffer.isBuffer(body) ? body.toString('utf8') : body) : ''\n const sigInput = `${payloadB64}\\n${cosyKey}\\n${timestamp}\\n${bodyStr}\\n${sigPath}`\n const sig = crypto.createHash('md5').update(sigInput).digest('hex')\n\n const bodyHash = crypto\n .createHash('md5')\n .update(body || '')\n .digest('hex')\n const bodyLen = body ? (Buffer.isBuffer(body) ? body.length : Buffer.from(body).length).toString() : '0'\n\n // Only reached when a caller assembled credentials without an id: the\n // default chain reads Qoder's own file and otherwise creates the plugin's\n // seed inside its data directory \u2014 it no longer writes near $HOME.\n const machineID = creds.machineID || getMachineId()\n\n return {\n Authorization: `Bearer COSY.${payloadB64}.${sig}`,\n 'Cosy-Key': cosyKey,\n 'Cosy-User': creds.userID,\n 'Cosy-Date': timestamp,\n 'Cosy-Version': qoderIdeVersion,\n 'Cosy-Machineid': machineID,\n 'Cosy-Machinetoken': machineID,\n 'Cosy-Machinetype': qoderMachineTypeMagic,\n 'Cosy-Machineos': qoderMachineOs,\n 'Cosy-Clienttype': qoderClientType,\n 'Cosy-Clientip': '127.0.0.1',\n 'Cosy-Bodyhash': bodyHash,\n 'Cosy-Bodylength': bodyLen,\n 'Cosy-Sigpath': sigPath,\n 'Cosy-Data-Policy': qoderDataPolicy,\n 'Cosy-Organization-Id': '',\n 'Cosy-Organization-Tags': '',\n 'Login-Version': qoderLoginVersion,\n 'X-Request-Id': crypto.randomUUID(),\n }\n}\n", "/** PAT exchange and in-memory Qoder job-token lifecycle. */\r\n\r\nimport type { CosyCredentials } from './wire/cosy.ts'\r\nimport { getQoderExchangeUrl, getQoderUserInfoUrl, type QoderRegion } from './endpoints.ts'\r\nimport { QoderLlmError } from '../errors.ts'\r\nimport type { QoderLogger } from './logging.ts'\r\nimport { getMachineId } from './machine-id.ts'\r\nimport {\r\n opaqueCredentialKey,\r\n openApiJsonRequest,\r\n retryMetadataRead,\r\n} from './request.ts'\r\n\r\nconst expiryBufferMs = 5 * 60 * 1000\r\nconst defaultExpiryMs = 24 * 60 * 60 * 1000\r\nconst defaultAuthTimeoutMs = 15_000\r\n\r\ninterface CachedEntry {\r\n creds: CosyCredentials\r\n expiresAt: number\r\n}\r\n\r\ninterface InFlightEntry {\r\n promise: Promise<CosyCredentials>\r\n controller: AbortController\r\n waiters: number\r\n settled: boolean\r\n timeout: ReturnType<typeof setTimeout>\r\n}\r\n\r\ninterface HealFlightEntry {\r\n promise: Promise<CosyCredentials>\r\n settled: boolean\r\n}\r\n\r\nexport interface QoderAuthServiceOptions {\r\n fetch?: typeof fetch | undefined\r\n timeoutMs?: number | undefined\r\n resolveMachineId?: (() => string) | undefined\r\n region?: QoderRegion | undefined\r\n logger?: QoderLogger | undefined\r\n}\r\n\r\nfunction abortedError(): QoderLlmError {\r\n return new QoderLlmError('Qoder authentication was aborted.', 'ABORTED')\r\n}\r\n\r\nasync function waitForFlight(\r\n promise: Promise<CosyCredentials>,\r\n signal?: AbortSignal,\r\n): Promise<CosyCredentials> {\r\n if (signal === undefined) return promise\r\n if (signal.aborted) throw abortedError()\r\n\r\n return new Promise<CosyCredentials>((resolve, reject) => {\r\n const onAbort = (): void => reject(abortedError())\r\n signal.addEventListener('abort', onAbort, { once: true })\r\n promise.then(resolve, reject).finally(() => signal.removeEventListener('abort', onAbort))\r\n })\r\n}\r\n\r\nexport class QoderAuthService {\r\n private readonly cache = new Map<string, CachedEntry>()\r\n private readonly inFlight = new Map<string, InFlightEntry>()\r\n /**\r\n * Self-heal exchanges in flight, keyed like the cache. Deliberately separate\r\n * from {@link inFlight}: that flight may be aborted by a departing\r\n * concurrent waiter (a quota poll, a catalog sweep) whose abort has nothing\r\n * to do with the heal, so healers must not share its controller. Concurrent\r\n * heals instead share this flight \u2014 see {@link exchangeFresh}.\r\n */\r\n private readonly healFlights = new Map<string, HealFlightEntry>()\r\n private readonly fetchImpl: typeof fetch\r\n private readonly timeoutMs: number\r\n private readonly resolveMachineId: () => string\r\n private readonly region: QoderRegion\r\n private readonly logger: QoderLogger | undefined\r\n constructor(options: QoderAuthServiceOptions = {}) {\r\n this.fetchImpl = options.fetch ?? globalThis.fetch\r\n this.timeoutMs = options.timeoutMs ?? defaultAuthTimeoutMs\r\n // The same default chain every other caller gets: the official Qoder\r\n // CLI's id first, this plugin's own data-directory seed as the create\r\n // point \u2014 never a file under the OS home directory.\r\n this.resolveMachineId = options.resolveMachineId ?? getMachineId\r\n this.region = options.region ?? 'global'\r\n this.logger = options.logger\r\n }\r\n\r\n clear(pat?: string): void {\r\n if (pat) {\r\n this.cache.delete(`${this.region}:${opaqueCredentialKey(pat)}`)\r\n } else {\r\n this.cache.clear()\r\n }\r\n }\r\n\r\n /**\r\n * Exchange a fresh job token OUTSIDE the single-flight, for the self-heal\r\n * retry. The shared flight can be aborted by a departing concurrent waiter\r\n * (the quota poll, the catalog sweep), and a retry that joins it would then\r\n * be cancelled by a path that has nothing to do with the chat. The result\r\n * replaces the cache entry.\r\n *\r\n * Two heals for the same credential that overlap share one exchange instead\r\n * of racing: each racer's `clear` deleted what the previous one had just\r\n * cached, and its own `cache.set` overwrote the other's \u2014 so the cache could\r\n * end up naming a token the losing request was no longer using, and with an\r\n * upstream that retires the previous job token on a new exchange the racers\r\n * also invalidated each other's credentials (one chat recovering while a\r\n * concurrent one failed, exactly the 2026-09-26 22:36 observation). The\r\n * shared exchange runs on its own timeout signal, so one healer's abort \u2014\r\n * its chat request went away \u2014 cannot cancel an exchange other healers, and\r\n * the future `getCredentials` callers about to read the refreshed cache, are\r\n * waiting on.\r\n */\r\n async exchangeFresh(pat: string, signal?: AbortSignal): Promise<CosyCredentials> {\r\n const cacheKey = `${this.region}:${opaqueCredentialKey(pat)}`\r\n const existing = this.healFlights.get(cacheKey)\r\n if (existing !== undefined && !existing.settled) {\r\n return waitForFlight(existing.promise, signal)\r\n }\r\n this.clear(pat)\r\n const created = { settled: false } as HealFlightEntry\r\n created.promise = this.exchangeAndResolve(pat, AbortSignal.timeout(this.timeoutMs)).finally(() => {\r\n created.settled = true\r\n if (this.healFlights.get(cacheKey) === created) this.healFlights.delete(cacheKey)\r\n })\r\n this.healFlights.set(cacheKey, created)\r\n return waitForFlight(created.promise, signal)\r\n }\r\n\r\n async getCredentials(\r\n pat: string,\r\n signal?: AbortSignal,\r\n ): Promise<CosyCredentials> {\r\n if (!pat || typeof pat !== 'string') {\r\n throw new QoderLlmError(\r\n 'Qoder Personal Access Token is missing or invalid. Configure Qoder in the Qoder settings page.',\r\n 'MISSING_CREDENTIAL',\r\n )\r\n }\r\n if (signal?.aborted) throw abortedError()\r\n\r\n const cacheKey = `${this.region}:${opaqueCredentialKey(pat)}`\r\n\r\n const cached = this.cache.get(cacheKey)\r\n if (cached && cached.expiresAt > Date.now() + expiryBufferMs) return cached.creds\r\n\r\n let entry = this.inFlight.get(cacheKey)\r\n if (entry === undefined || entry.controller.signal.aborted) {\r\n const controller = new AbortController()\r\n const created = {} as InFlightEntry\r\n created.controller = controller\r\n created.waiters = 0\r\n created.settled = false\r\n created.timeout = setTimeout(() => controller.abort('authentication timeout'), this.timeoutMs)\r\n created.promise = this.exchangeAndResolve(pat, controller.signal).finally(() => {\r\n created.settled = true\r\n clearTimeout(created.timeout)\r\n if (this.inFlight.get(cacheKey) === created) this.inFlight.delete(cacheKey)\r\n })\r\n entry = created\r\n this.inFlight.set(cacheKey, entry)\r\n }\r\n\r\n entry.waiters++\r\n try {\r\n return await waitForFlight(entry.promise, signal)\r\n } finally {\r\n entry.waiters--\r\n if (entry.waiters === 0 && !entry.settled) {\r\n if (this.inFlight.get(cacheKey) === entry) this.inFlight.delete(cacheKey)\r\n entry.controller.abort('all callers aborted')\r\n }\r\n }\r\n }\r\n\r\n private async exchangeAndResolve(\r\n pat: string,\r\n signal: AbortSignal,\r\n ): Promise<CosyCredentials> {\r\n let jobToken: string\r\n let expiresAt = Date.now() + defaultExpiryMs\r\n\r\n const data = await openApiJsonRequest<{ token?: string; expires_at?: string; expires_in?: number }>(\r\n this.fetchImpl,\r\n {\r\n url: getQoderExchangeUrl(this.region),\r\n body: { personal_token: pat },\r\n signal,\r\n timeoutMs: this.timeoutMs,\r\n logger: this.logger,\r\n operation: 'Auth',\r\n logCategory: 'auth.exchange',\r\n },\r\n )\r\n if (!data.token) {\r\n throw new QoderLlmError('Qoder PAT exchange returned no job token.', 'AUTH')\r\n }\r\n jobToken = data.token\r\n if (data.expires_at) {\r\n const parsed = Date.parse(data.expires_at)\r\n if (!Number.isNaN(parsed)) expiresAt = parsed\r\n } else if (typeof data.expires_in === 'number' && data.expires_in > 0) {\r\n expiresAt = Date.now() + data.expires_in\r\n }\r\n\r\n const userInfo = await retryMetadataRead(signal, () => this.fetchUserInfo(jobToken, signal))\r\n const creds: CosyCredentials = {\r\n userID: userInfo.userID,\r\n authToken: jobToken,\r\n name: userInfo.name || 'Qoder User',\r\n email: userInfo.email,\r\n machineID: this.resolveMachineId(),\r\n }\r\n const cacheKey = `${this.region}:${opaqueCredentialKey(pat)}`\r\n this.cache.set(cacheKey, { creds, expiresAt })\r\n return creds\r\n }\r\n\r\n private async fetchUserInfo(\r\n jobToken: string,\r\n signal: AbortSignal,\r\n ): Promise<{ userID: string; email: string; name: string }> {\r\n const info = await openApiJsonRequest<{\r\n id?: string\r\n email?: string\r\n name?: string\r\n username?: string\r\n }>(this.fetchImpl, {\r\n url: getQoderUserInfoUrl(this.region),\r\n token: jobToken,\r\n signal,\r\n timeoutMs: this.timeoutMs,\r\n logger: this.logger,\r\n operation: 'UserInfo',\r\n logCategory: 'auth.user-info',\r\n })\r\n if (!info.id) {\r\n throw new QoderLlmError('Qoder identity lookup returned no user id.', 'AUTH')\r\n }\r\n return {\r\n userID: info.id,\r\n email: info.email ?? '',\r\n name: info.name ?? info.username ?? '',\r\n }\r\n }\r\n}\r\n", "/** Browser-safe Qoder model catalog types and built-in fallback entries. */\n\nexport interface QoderCatalogModel {\n id: string\n name: string\n description?: string\n /** Effective DSH input budget, which may be smaller than the provider default tier. */\n contextWindow?: number\n /** Largest known capacity, independent of the effective input budget. */\n maxContextWindow?: number\n maxTokens?: number\n source?: string\n isReasoning?: boolean\n supportsEffort?: boolean\n reasoningEfforts?: Array<{\n id: string\n name: string\n description?: string\n }>\n defaultReasoningEffort?: string\n priceFactor?: number\n contextOptions?: Record<string, { tokenCount?: number; isDefault?: boolean }>\n supportsImages?: boolean\n}\n\ninterface QoderModelEntry {\n key?: unknown\n enable?: unknown\n display_name?: unknown\n max_input_tokens?: unknown\n max_output_tokens?: unknown\n context_config?: unknown\n is_reasoning?: unknown\n thinking_config?: unknown\n source?: unknown\n price_factor?: unknown\n is_vl?: unknown\n}\n\nconst discoveredMetadataKeys = [\n 'description',\n 'source',\n 'isReasoning',\n 'supportsEffort',\n 'reasoningEfforts',\n 'defaultReasoningEffort',\n 'priceFactor',\n 'contextOptions',\n 'maxContextWindow',\n 'supportsImages',\n] as const satisfies readonly (keyof QoderCatalogModel)[]\n\nconst reasoningEffortOrder = new Map([\n ['low', 0],\n ['medium', 1],\n ['high', 2],\n ['xhigh', 3],\n ['max', 4],\n])\n\nfunction positiveNumber(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : undefined\n}\n\nfunction contextOptionsOf(value: unknown): QoderCatalogModel['contextOptions'] {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined\n const options: NonNullable<QoderCatalogModel['contextOptions']> = {}\n for (const [key, raw] of Object.entries(value)) {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) continue\n const entry = raw as { token_count?: unknown; is_default?: unknown }\n const tokenCount = positiveNumber(entry.token_count)\n const isDefault = typeof entry.is_default === 'boolean' ? entry.is_default : undefined\n if (tokenCount === undefined) continue\n options[key] = {\n ...tokenCount === undefined ? {} : { tokenCount },\n ...isDefault === undefined ? {} : { isDefault },\n }\n }\n if (Object.keys(options).length === 0) return undefined\n return options\n}\n\nfunction reasoningEffortsOf(value: unknown): {\n efforts?: NonNullable<QoderCatalogModel['reasoningEfforts']>\n defaultEffort?: string\n} {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return {}\n const enabled = (value as { enabled?: unknown }).enabled\n if (typeof enabled !== 'object' || enabled === null || Array.isArray(enabled)) return {}\n const rawEfforts = (enabled as { efforts?: unknown }).efforts\n if (typeof rawEfforts !== 'object' || rawEfforts === null || Array.isArray(rawEfforts)) return {}\n const efforts: NonNullable<QoderCatalogModel['reasoningEfforts']> = []\n let defaultEffort: string | undefined\n for (const [id, raw] of Object.entries(rawEfforts)) {\n if (!id.trim() || typeof raw !== 'object' || raw === null || Array.isArray(raw)) continue\n const entry = raw as { description?: unknown; is_default?: unknown }\n efforts.push({\n id,\n name: id,\n ...typeof entry.description === 'string' && entry.description.trim()\n ? { description: entry.description.trim() }\n : {},\n })\n if (entry.is_default === true) defaultEffort = id\n }\n return {\n ...efforts.length === 0\n ? {}\n : {\n efforts: efforts.sort((left, right) =>\n (reasoningEffortOrder.get(left.id) ?? Number.MAX_SAFE_INTEGER)\n - (reasoningEffortOrder.get(right.id) ?? Number.MAX_SAFE_INTEGER)),\n },\n ...defaultEffort === undefined ? {} : { defaultEffort },\n }\n}\n\ntype CatalogConflict = 'context-defaults' | 'thinking-defaults'\n\nfunction thinkingDefault(value: unknown, fallback: boolean, onConflict?: (conflict: CatalogConflict) => void): boolean {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return fallback\n const config = value as Record<string, unknown>\n const isDefault = (entry: unknown): boolean => typeof entry === 'object' && entry !== null\n && !Array.isArray(entry) && (entry as { is_default?: unknown }).is_default === true\n const enabled = isDefault(config.enabled)\n const disabled = isDefault(config.disabled)\n if (enabled && disabled) onConflict?.('thinking-defaults')\n return enabled === disabled ? fallback : enabled\n}\n\nexport function normalizeQoderModels(\n payload: unknown,\n onConflict?: (conflict: CatalogConflict) => void,\n): QoderCatalogModel[] {\n if (typeof payload !== 'object' || payload === null || !Array.isArray((payload as { assistant?: unknown }).assistant)) return []\n const models: QoderCatalogModel[] = []\n const seen = new Set<string>()\n for (const raw of (payload as { assistant: QoderModelEntry[] }).assistant) {\n if (typeof raw !== 'object' || raw === null || raw.enable !== true) continue\n const id = typeof raw.key === 'string' ? raw.key.trim() : ''\n if (!id || seen.has(id)) continue\n seen.add(id)\n const contextOptions = contextOptionsOf(raw.context_config)\n const defaultOptions = Object.values(contextOptions ?? {}).filter(option => option.isDefault && option.tokenCount !== undefined)\n if (defaultOptions.length > 1) onConflict?.('context-defaults')\n const contextWindow = (defaultOptions.length === 1 ? defaultOptions[0]?.tokenCount : undefined)\n ?? positiveNumber(raw.max_input_tokens) ?? 180_000\n const maxContextWindow = Math.max(\n positiveNumber(raw.max_input_tokens) ?? 0,\n contextWindow,\n ...Object.values(contextOptions ?? {}).map(option => option.tokenCount ?? 0),\n )\n const isReasoning = thinkingDefault(raw.thinking_config, raw.is_reasoning === true, onConflict)\n const priceFactor = typeof raw.price_factor === 'number' && Number.isFinite(raw.price_factor) && raw.price_factor >= 0\n ? raw.price_factor : undefined\n const reasoning = reasoningEffortsOf(raw.thinking_config)\n models.push({\n id,\n name: typeof raw.display_name === 'string' && raw.display_name.trim() ? raw.display_name.trim() : id,\n contextWindow,\n maxContextWindow,\n maxTokens: positiveNumber(raw.max_output_tokens) ?? 32_768,\n source: typeof raw.source === 'string' && raw.source.trim() ? raw.source.trim() : 'system',\n isReasoning,\n supportsEffort: reasoning.efforts !== undefined,\n supportsImages: raw.is_vl === true,\n ...reasoning.efforts === undefined ? {} : { reasoningEfforts: reasoning.efforts },\n ...reasoning.defaultEffort === undefined ? {} : { defaultReasoningEffort: reasoning.defaultEffort },\n ...priceFactor === undefined ? {} : { priceFactor },\n ...contextOptions === undefined ? {} : { contextOptions },\n })\n }\n return models\n}\n\nexport function mergeQoderDiscoveryMetadata(\n configured: readonly QoderCatalogModel[],\n discovered: readonly QoderCatalogModel[],\n): QoderCatalogModel[] {\n const catalog = new Map(discovered.map(model => [model.id, model]))\n return configured.map((model) => {\n const advertised = catalog.get(model.id)\n if (advertised === undefined) return { ...model }\n\n const merged = { ...model }\n if (advertised.contextWindow !== undefined) {\n merged.contextWindow = Math.min(model.contextWindow ?? advertised.contextWindow, advertised.contextWindow)\n }\n for (const key of discoveredMetadataKeys) delete merged[key]\n for (const key of discoveredMetadataKeys) {\n if (advertised[key] !== undefined) Object.assign(merged, { [key]: advertised[key] })\n }\n return merged\n })\n}\n\nexport function hasSameQoderDiscoveryMetadata(\n left: readonly QoderCatalogModel[] | undefined,\n right: readonly QoderCatalogModel[],\n): boolean {\n return left?.length === right.length && left.every((model, index) => {\n const candidate = right[index]\n return candidate?.id === model.id && candidate.contextWindow === model.contextWindow && discoveredMetadataKeys.every(key => (\n JSON.stringify(model[key]) === JSON.stringify(candidate[key])\n ))\n })\n}\n\nexport const defaultMaxTokens = 32_768\n\nexport const defaultModels: QoderCatalogModel[] = [\n {\n id: 'cmodel',\n name: 'Cantus (Qoder)',\n description: 'Default Global Qoder subscription model for quick validation',\n contextWindow: 1_000_000,\n maxTokens: defaultMaxTokens,\n supportsImages: true,\n },\n {\n id: 'auto',\n name: 'Qoder Auto',\n description: 'Server-routed Global Qoder model pool',\n contextWindow: 180_000,\n maxTokens: defaultMaxTokens,\n supportsImages: true,\n },\n {\n id: 'ultimate',\n name: 'Qoder Ultimate',\n description: 'Highest-capability Global Qoder model pool',\n contextWindow: 1_000_000,\n maxTokens: defaultMaxTokens,\n supportsImages: true,\n },\n {\n id: 'performance',\n name: 'Qoder Performance',\n description: 'Performance-oriented Global Qoder model pool',\n contextWindow: 1_000_000,\n maxTokens: defaultMaxTokens,\n supportsImages: true,\n },\n {\n id: 'efficient',\n name: 'Qoder Efficient',\n description: 'Efficiency-oriented Global Qoder model pool',\n contextWindow: 180_000,\n maxTokens: defaultMaxTokens,\n supportsImages: true,\n },\n {\n id: 'lite',\n name: 'Qoder Lite',\n description: 'Basic Global Qoder model pool',\n contextWindow: 180_000,\n maxTokens: defaultMaxTokens,\n },\n]\n", "/** Fetch and normalize the model catalog exposed to a Qoder subscriber. */\n\nimport type { CosyCredentials } from './wire/cosy.ts'\nimport { buildAuthHeaders } from './wire/cosy.ts'\nimport { getQoderModelListUrl, type QoderRegion } from './endpoints.ts'\nimport { QoderLlmError, qoderHttpError, qoderRequestId } from '../errors.ts'\nimport {\n redactLogPayload,\n redactLogValue,\n type QoderLogger,\n} from './logging.ts'\nimport { normalizeQoderModels, type QoderCatalogModel } from '../catalog.ts'\nimport {\n defaultMaxErrorBytes,\n defaultMaxJsonBytes,\n defaultMetadataTimeoutMs,\n readLimitedText,\n withDeadline,\n} from './request.ts'\n\nexport interface FetchQoderModelsOptions {\n fetch?: typeof fetch | undefined\n signal?: AbortSignal | undefined\n region?: QoderRegion | undefined\n logger?: QoderLogger | undefined\n timeoutMs?: number | undefined\n}\n\nexport async function fetchQoderModels(\n credentials: CosyCredentials,\n options: FetchQoderModelsOptions = {},\n): Promise<QoderCatalogModel[]> {\n const url = getQoderModelListUrl(options.region)\n const fetchImpl = options.fetch ?? globalThis.fetch\n const startedAt = performance.now()\n const deadline = withDeadline(options.signal, options.timeoutMs ?? defaultMetadataTimeoutMs)\n options.logger?.debug?.('[Qoder Models] Requesting model catalog', { url })\n try {\n const response = await fetchImpl(url, {\n method: 'GET',\n // `identity` keeps a host that does not decompress (the Electron desktop\n // host's fetch) from handing us a gzip byte stream that then fails\n // JSON.parse \u2014 the chat request in chat.ts declares it for the same\n // reason. readLimitedText additionally decodes a compressed body when a\n // proxy or middlebox ignores the header.\n headers: {\n accept: 'application/json',\n 'accept-encoding': 'identity',\n ...buildAuthHeaders(null, url, credentials),\n },\n signal: deadline.signal,\n })\n options.logger?.debug?.('[Qoder Models] Catalog request completed', {\n url,\n status: response.status,\n durationMs: Math.round(performance.now() - startedAt),\n ...qoderRequestId(response.headers) === undefined ? {} : { requestId: qoderRequestId(response.headers) },\n })\n const text = await readLimitedText(\n response,\n response.ok ? defaultMaxJsonBytes : defaultMaxErrorBytes,\n 'Qoder model discovery response',\n )\n if (!response.ok) {\n options.logger?.error?.('[Qoder Models] Catalog request failed', redactLogPayload(text))\n throw qoderHttpError(`Qoder model discovery failed with HTTP status ${response.status}.`, response)\n }\n let payload: unknown\n try {\n payload = JSON.parse(text)\n } catch {\n throw new QoderLlmError('Qoder model discovery returned invalid JSON.', 'MALFORMED_RESPONSE')\n }\n const models = normalizeQoderModels(payload, conflict => {\n options.logger?.warn?.('[Qoder Models] Conflicting catalog defaults; using fallback', { conflict })\n })\n if (models.length === 0) throw new QoderLlmError('Qoder model discovery returned no enabled models.', 'EMPTY_RESPONSE')\n return models\n } catch (error) {\n if (error instanceof QoderLlmError) throw error\n if (options.signal?.aborted) throw new QoderLlmError('Qoder model discovery was aborted.', 'ABORTED')\n if (deadline.timeoutSignal.aborted) throw new QoderLlmError('Qoder model discovery timed out.', 'TIMEOUT')\n options.logger?.error?.('[Qoder Models] Catalog network request failed', redactLogValue(error))\n throw new QoderLlmError('Qoder model discovery network request failed.', 'TRANSPORT', { cause: error })\n }\n}\n", "/** Build the minimum qodercli request envelope for a validated DSH request. */\n\nimport crypto from 'node:crypto'\nimport { contentHasImage, type GenerateOptions } from '@deepseek-ai/dsh-llm'\nimport { QoderLlmError } from '../../errors.ts'\nimport { translateTools, validateAndTranslateMessages, validateMessageShapes } from './translate.ts'\nimport type { QoderWireMessage, QoderWireRequest, QoderWireTool } from './wire-types.ts'\nimport type { QoderCatalogModel } from '../../catalog.ts'\nimport type { QoderImageAttachments, QoderImageResolver } from './translate.ts'\nimport type { CosyCredentials } from './cosy.ts'\n\nfunction stableHash(prefix: string, ...inputs: string[]): string {\n const hash = crypto.createHash('sha256')\n hash.update(prefix)\n for (const input of inputs) {\n hash.update('\\0')\n hash.update(input)\n }\n return hash.digest('hex').slice(0, 16)\n}\n\nfunction stableChatRecordId(\n model: string,\n messages: readonly QoderWireMessage[],\n tools: readonly QoderWireTool[],\n maxTokens: number,\n): string {\n const hash = crypto.createHash('sha256')\n hash.update('qoder-record')\n hash.update('\\0')\n hash.update(model)\n hash.update('\\0')\n hash.update(JSON.stringify(messages))\n hash.update('\\0')\n hash.update(JSON.stringify(tools))\n hash.update('\\0')\n hash.update(`mt=${maxTokens}`)\n return hash.digest('hex').slice(0, 16)\n}\n\n/**\n * Reject an unusable request before any credential resolution or provider I/O.\n *\n * Image publication needs credentials, so message translation now runs after\n * authentication. This static pass preserves the guarantee that a request the\n * provider cannot serve never reaches the network.\n */\nexport function validateQoderRequestShape(\n options: GenerateOptions,\n model?: QoderCatalogModel,\n): void {\n if (options.reasoningEffort !== undefined) {\n const effort = String(options.reasoningEffort)\n // Only a declaration can justify a local refusal. A row that declares no\n // efforts at all is not evidence that the model supports none: the upstream\n // accepts spellings its discovery catalog never lists, so refusing them here\n // misreports a supported value as unsupported. It also made detection\n // impossible \u2014 every probe candidate, sentinel included, was rejected before\n // the wire, which is why an undeclared model could only ever come back as\n // \"validating with no levels\". An undeclared row therefore goes to the\n // upstream for the answer; a declared set stays enforced exactly as before.\n const declared = model?.reasoningEfforts\n if (declared !== undefined && declared.length > 0 && !declared.some(candidate => candidate.id === effort)) {\n throw new QoderLlmError(\n `Qoder model \"${options.model}\" does not advertise reasoning effort \"${effort}\".`,\n 'UNSUPPORTED_REASONING_EFFORT',\n )\n }\n }\n if (options.messages.some(message => contentHasImage(message.content)) && model?.supportsImages !== true) {\n throw new QoderLlmError(\n `Qoder model \"${options.model}\" does not advertise image input.`,\n 'UNSUPPORTED_CONTENT',\n )\n }\n validateMessageShapes(options.messages)\n}\n\n/** Translate a request whose shape has already been validated. */\nexport function translateQoderMessages(\n options: GenerateOptions,\n attachments?: QoderImageAttachments,\n pipeline?: {\n uploader?: QoderImageResolver | undefined\n credentials?: CosyCredentials | undefined\n preserveThinking?: boolean | undefined\n },\n): Promise<QoderWireMessage[]> {\n return validateAndTranslateMessages(\n options.messages,\n options.system,\n attachments,\n options.signal,\n pipeline,\n )\n}\n\nexport async function validateQoderRequest(\n options: GenerateOptions,\n model?: QoderCatalogModel,\n attachments?: QoderImageAttachments,\n): Promise<QoderWireMessage[]> {\n validateQoderRequestShape(options, model)\n return validateAndTranslateMessages(options.messages, options.system, attachments, options.signal)\n}\n\nexport async function buildQoderRequestBody(\n options: GenerateOptions,\n userId: string,\n translatedMessages?: QoderWireMessage[],\n model?: QoderCatalogModel,\n attachments?: QoderImageAttachments,\n): Promise<QoderWireRequest> {\n if (!userId) {\n throw new QoderLlmError('Qoder request identity is missing.', 'AUTH')\n }\n const modelKey = options.model || 'cmodel'\n const messages = translatedMessages ?? await validateQoderRequest(options, model, attachments)\n const modelMaxTokens = model?.maxTokens ?? 32_768\n const maxTokens = Math.min(options.maxTokens ?? modelMaxTokens, modelMaxTokens)\n const isReasoning = options.reasoningEffort !== undefined || (model?.isReasoning ?? false)\n const tools = translateTools(options.tools)\n // Ambiguous defaults stay in discovery metadata, but must not select a request tier.\n const defaultContexts = Object.values(model?.contextOptions ?? {}).filter(option =>\n option.isDefault === true && typeof option.tokenCount === 'number'\n && Number.isFinite(option.tokenCount) && option.tokenCount > 0)\n const contextConfig = model?.contextOptions === undefined || defaultContexts.length !== 1\n ? undefined\n : Object.fromEntries(Object.entries(model.contextOptions).map(([key, value]) => [key, {\n ...value.tokenCount === undefined ? {} : { token_count: value.tokenCount },\n ...value.isDefault === undefined ? {} : { is_default: value.isDefault },\n }]))\n let lastUserText = ''\n for (let index = messages.length - 1; index >= 0; index--) {\n const message = messages[index]\n // index is bounded by messages.length; guard only satisfies noUncheckedIndexedAccess.\n if (message === undefined) continue\n if (message.role === 'user') {\n const content = message.content\n lastUserText = typeof content === 'string'\n ? content\n : Array.isArray(content)\n ? content.filter(part => part.type === 'text').map(part => part.text).join('')\n : ''\n break\n }\n }\n\n const stablePart = stableHash('qoder-session', userId, modelKey)\n const sessionId = options.sessionId === undefined\n ? `${stablePart}-${crypto.randomUUID()}`\n : `${stablePart}-${String(options.sessionId)}`\n const recordId = stableChatRecordId(modelKey, messages, tools, maxTokens)\n\n return {\n request_id: crypto.randomUUID(),\n request_set_id: recordId,\n chat_record_id: recordId,\n session_id: sessionId,\n stream: true,\n chat_task: 'FREE_INPUT',\n is_reply: true,\n is_retry: false,\n source: 1,\n version: '3',\n session_type: 'qodercli',\n agent_id: 'agent_common',\n task_id: 'common',\n code_language: '',\n chat_prompt: '',\n image_urls: null,\n aliyun_user_type: '',\n system: '',\n messages,\n tools,\n parameters: {\n max_tokens: maxTokens,\n ...options.reasoningEffort === undefined\n ? {}\n : { reasoning_effort: String(options.reasoningEffort) },\n },\n chat_context: {\n chatPrompt: '',\n imageUrls: null,\n extra: {\n context: [],\n modelConfig: { key: modelKey, is_reasoning: isReasoning },\n originalContent: lastUserText,\n },\n features: [],\n text: lastUserText,\n },\n model_config: {\n key: modelKey,\n is_reasoning: isReasoning,\n max_output_tokens: maxTokens,\n source: model?.source || 'system',\n ...contextConfig === undefined ? {} : { context_config: contextConfig },\n },\n business: {\n product: 'cli',\n version: '1.0.0',\n type: 'agent',\n stage: 'start',\n id: crypto.randomUUID(),\n name: lastUserText.substring(0, 30),\n begin_at: Date.now(),\n },\n }\n}\n", "/** Translate provider-neutral DSH messages and tools into Qoder wire values. */\n\nimport type { ContentBlock, ImageBlock, RequestMessage, ToolResultMessage, ToolSchema } from '@deepseek-ai/dsh-llm'\nimport type { AttachmentStore, RequestImageAttachment } from '@deepseek-ai/dsh-attachment'\nimport { requestImageDimensions } from '@deepseek-ai/dsh-attachment'\nimport { QoderLlmError } from '../../errors.ts'\nimport type { CosyCredentials } from './cosy.ts'\nimport type {\n QoderWireImagePart,\n QoderWireMessage,\n QoderWireTextPart,\n QoderWireTool,\n QoderWireToolCall,\n} from './wire-types.ts'\n\nexport type QoderImageAttachments = Pick<AttachmentStore, 'imageLimits' | 'readImageRequest'>\n\n/** Publishes a request image and returns the URL the wire message should carry. */\nexport interface QoderImageResolver {\n resolveImageUrl(\n image: RequestImageAttachment,\n credentials: CosyCredentials,\n signal?: AbortSignal,\n ): Promise<string>\n}\n\nexport interface QoderTranslateContext {\n attachments?: QoderImageAttachments | undefined\n uploader?: QoderImageResolver | undefined\n credentials?: CosyCredentials | undefined\n signal?: AbortSignal | undefined\n}\n\nfunction unsupported(message: string): QoderLlmError {\n return new QoderLlmError(message, 'UNSUPPORTED_CONTENT')\n}\n\n/**\n * Flatten one tool-result message's content to wire text.\n *\n * DSH 0.1.7 models a tool result as a first-class `role: 'tool'` message\n * (before 0.1.6 it was a `tool-result` block inside a user message); either\n * way the payload is a content array whose text/\u56FE\u50CF blocks this flattens.\n */\nfunction toolResultText(content: readonly ContentBlock[]): string {\n let text = ''\n for (const nested of content) {\n if (nested.type === 'image') continue\n if (nested.type !== 'text') {\n throw unsupported(`Qoder tool results support text only; received nested ${String(nested.type)} content.`)\n }\n text += nested.text\n }\n return text\n}\n\n/**\n * Check message shapes without performing any provider I/O.\n *\n * Callers run this before resolving credentials so an invalid request never\n * consumes a Qoder subscription. The input is DSH's request shape \u2014 durable\n * messages and one-shot user inputs alike; only `role` and `content` are read.\n */\nexport function validateMessageShapes(messages: readonly RequestMessage[]): void {\n for (const message of messages) {\n // DSH 0.1.7 carries a tool result as one `role: 'tool'` message; its\n // content is the result payload itself, with no sibling blocks.\n if (message.role === 'tool') {\n for (const block of message.content) {\n if (block.type === 'text' || block.type === 'image') continue\n throw unsupported(`Qoder tool results support text and image content only; received ${String(block.type)}.`)\n }\n continue\n }\n if (message.role === 'developer') {\n throw unsupported('Qoder transport does not support developer messages (dynamic tool addition/removal).')\n }\n\n for (const block of message.content) {\n if (block.type === 'text') continue\n if (block.type === 'image') {\n if (message.role !== 'user') throw unsupported('Qoder image content is valid only in user messages.')\n continue\n }\n if (block.type === 'tool-call') {\n if (message.role !== 'assistant') {\n throw unsupported('Qoder tool calls are valid only in assistant messages.')\n }\n continue\n }\n if (block.type === 'reasoning') {\n continue\n }\n throw unsupported(`Qoder transport encountered unsupported block type: ${String((block as ContentBlock).type)}`)\n }\n }\n}\n\n/** Reject a batch that exceeds the deployment image policy before any upload work starts. */\nfunction enforceImageLimits(\n images: readonly ImageBlock[],\n attachments: QoderImageAttachments,\n): void {\n const limits = attachments.imageLimits\n if (images.length > limits.maxImagesPerMessage) {\n throw unsupported(\n `Qoder accepts at most ${limits.maxImagesPerMessage} images per message; received ${images.length}.`,\n )\n }\n let total = 0\n for (const image of images) total += image.attachment.bytes\n if (total > limits.maxMessageImageBytes) {\n throw unsupported('Qoder message image content exceeds the configured total byte limit.')\n }\n}\n\nasync function resolveImagePart(\n block: ImageBlock,\n context: QoderTranslateContext,\n): Promise<QoderWireImagePart> {\n const { attachments, uploader, credentials, signal } = context\n if (attachments === undefined) {\n throw new QoderLlmError('Qoder image input requires the DSH attachment service.', 'ATTACHMENT')\n }\n let image: RequestImageAttachment\n try {\n // DSH \u2265 0.1.6-alpha.1 replaced the image-request policy `{maxPixels,\n // maxBytes}` with an explicit target `{width, height, maxBytes}`\n // (ImageRequestPolicy \u2192 ImageRequestTarget in @deepseek-ai/dsh-attachment):\n // the host now expects the caller to project the pixel budget into exact\n // dimensions with its own requestImageDimensions helper. Passing the\n // retired maxPixels field fails `validateTarget`'s checkedInteger on\n // width/height, which surfaces as a 400 \"could not prepare an image\n // attachment\" for every image.\n const { width: sourceWidth, height: sourceHeight } = block.attachment\n const projected = requestImageDimensions(\n sourceWidth,\n sourceHeight,\n attachments.imageLimits.maxImagePixels,\n )\n image = await attachments.readImageRequest(block.attachment, {\n width: projected.width,\n height: projected.height,\n maxBytes: attachments.imageLimits.maxImageBytes,\n }, signal)\n } catch (error) {\n if (signal?.aborted) throw new QoderLlmError('Qoder image preparation was aborted.', 'ABORTED', { cause: error })\n if (error instanceof QoderLlmError) throw error\n throw new QoderLlmError('Qoder could not prepare an image attachment.', 'ATTACHMENT', { cause: error })\n }\n\n // Publication degrades to an inline data URL on its own; only a missing\n // uploader or missing credentials skips the center exchange entirely.\n if (uploader !== undefined && credentials !== undefined) {\n const url = await uploader.resolveImageUrl(image, credentials, signal)\n return { type: 'image_url', image_url: { url } }\n }\n return {\n type: 'image_url',\n image_url: { url: `data:${image.mediaType};base64,${Buffer.from(image.data).toString('base64')}` },\n }\n}\n\nexport function translateTools(tools: readonly ToolSchema[] | undefined): QoderWireTool[] {\n return (tools ?? []).map(tool => ({\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters,\n },\n }))\n}\n\nexport async function validateAndTranslateMessages(\n messages: readonly RequestMessage[],\n systemPrompt?: string,\n attachments?: QoderImageAttachments,\n signal?: AbortSignal,\n pipeline?: Pick<QoderTranslateContext, 'uploader' | 'credentials'> & { preserveThinking?: boolean | undefined },\n): Promise<QoderWireMessage[]> {\n validateMessageShapes(messages)\n const context: QoderTranslateContext = {\n attachments,\n signal,\n uploader: pipeline?.uploader,\n credentials: pipeline?.credentials,\n }\n const preserveThinking = pipeline?.preserveThinking ?? true\n const output: QoderWireMessage[] = []\n\n if (typeof systemPrompt === 'string' && systemPrompt.trim().length > 0) {\n output.push({ role: 'system', content: systemPrompt })\n }\n\n for (const message of messages) {\n // A first-class tool-result message (DSH 0.1.7 shape): one wire tool\n // message, plus the result's images replayed as a following user turn.\n if (message.role === 'tool') {\n output.push({\n role: 'tool',\n tool_call_id: String(message.toolCallId),\n content: toolResultText(message.content),\n })\n const images = message.content.filter((block): block is ImageBlock => block.type === 'image')\n if (images.length > 0) {\n if (attachments !== undefined) enforceImageLimits(images, attachments)\n output.push({\n role: 'user',\n content: [\n {\n type: 'text',\n text: `[${images.length} image${images.length === 1 ? '' : 's'} returned by the previous tool call]`,\n },\n ...await Promise.all(images.map(image => resolveImagePart(image, context))),\n ],\n })\n }\n continue\n }\n\n let text = ''\n let reasoningText = ''\n const userContent: Array<QoderWireTextPart | QoderWireImagePart | undefined> = []\n const pendingImages: Array<{ slot: number; block: ImageBlock }> = []\n let hasImage = false\n const toolCalls: QoderWireToolCall[] = []\n for (const block of message.content) {\n if (block.type === 'text') {\n text += block.text\n if (message.role === 'user') userContent.push({ type: 'text', text: block.text })\n continue\n }\n if (block.type === 'image') {\n hasImage = true\n // Reserve the slot now so publication can proceed concurrently\n // without disturbing the author's content order.\n pendingImages.push({ slot: userContent.length, block })\n userContent.push(undefined)\n continue\n }\n if (block.type === 'tool-call') {\n toolCalls.push({\n id: String(block.id),\n type: 'function',\n function: { name: block.name, arguments: block.arguments },\n })\n continue\n }\n if (block.type === 'reasoning') {\n if (message.role === 'assistant') reasoningText += block.text\n continue\n }\n // 0.1.7's ContentBlock is merge-extensible (file / tool-addition /\n // tool-removal and plugin blocks); validateMessageShapes has already\n // rejected the ones Qoder cannot carry, so this is a defensive stop.\n throw unsupported(`Qoder transport encountered unsupported block type: ${String((block as ContentBlock).type)}`)\n }\n\n if (message.role === 'assistant') {\n const hasReasoning = preserveThinking && reasoningText.length > 0\n if (!text && toolCalls.length === 0 && !hasReasoning) continue\n output.push({\n role: 'assistant',\n content: text || ' ',\n ...toolCalls.length === 0 ? {} : { tool_calls: toolCalls },\n ...hasReasoning ? { reasoning_content: reasoningText } : {},\n })\n continue\n }\n\n if (pendingImages.length > 0) {\n if (attachments !== undefined) {\n enforceImageLimits(pendingImages.map(pending => pending.block), attachments)\n }\n await Promise.all(pendingImages.map(async (pending) => {\n userContent[pending.slot] = await resolveImagePart(pending.block, context)\n }))\n }\n // `developer` messages never reach here: validateMessageShapes rejects\n // them up front. The guard keeps the role union narrow for the wire shape.\n if (message.role === 'developer') continue\n output.push({\n role: message.role,\n content: hasImage\n ? userContent.filter((part): part is QoderWireTextPart | QoderWireImagePart => part !== undefined)\n : text,\n })\n }\n\n return output\n}\n", "/**\n * Center-hosted image upload pipeline for Qoder multimodal input.\n *\n * Qoder does not carry raster bytes inside a model request. It publishes each\n * request image to the center service once, then references the returned\n * durable URL. This module owns that exchange: deduplication, single-flight\n * sharing, bounded caching, and the degradation contract that keeps a model\n * request alive when publication fails.\n *\n * @module dsh-provider-qoder/qoder/transport/image-upload\n */\n\nimport crypto from 'node:crypto'\nimport type { RequestImageAttachment } from '@deepseek-ai/dsh-attachment'\nimport { QoderLlmError } from '../errors.ts'\nimport { getQoderImageUploadUrl, type QoderRegion } from './endpoints.ts'\nimport { redactLogValue, type QoderLogger } from './logging.ts'\nimport { defaultMaxJsonBytes, readLimitedText, SingleFlight } from './request.ts'\nimport { buildAuthHeaders, type CosyCredentials } from './wire/cosy.ts'\n\n/** Upstream deadline for one image publication attempt. */\nexport const defaultImageUploadTimeoutMs = 30_000\n/** Bounded number of remembered image URLs, matching the Qoder client. */\nexport const defaultImageUrlCacheCapacity = 512\n/**\n * Conservative lifetime for a remembered image URL.\n *\n * Whether the center service returns a permanently addressable object or a\n * pre-signed URL is not established. Remembering a pre-signed URL forever\n * would replay expiry failures for the rest of a long session with no way to\n * recover, so entries expire and are republished instead.\n */\nexport const defaultImageUrlCacheTtlMs = 30 * 60 * 1000\n/** Concurrent publications allowed while preparing one model request. */\nexport const defaultImageUploadConcurrency = 4\n\nconst mediaTypeExtensions: Record<string, string> = {\n 'image/png': 'png',\n 'image/jpeg': 'jpg',\n 'image/webp': 'webp',\n 'image/gif': 'gif',\n}\n\nexport interface QoderImageUploaderOptions {\n fetch?: typeof fetch | undefined\n region?: QoderRegion | undefined\n logger?: QoderLogger | undefined\n timeoutMs?: number | undefined\n cacheTtlMs?: number | undefined\n cacheCapacity?: number | undefined\n maxConcurrency?: number | undefined\n /** Re-resolve credentials after the center service rejects the current ones. */\n refreshCredentials?: ((signal?: AbortSignal) => Promise<CosyCredentials>) | undefined\n now?: (() => number) | undefined\n}\n\ninterface CacheEntry {\n url: string\n expiresAt: number\n}\n\nexport interface QoderMultipartBody {\n body: Buffer\n boundary: string\n}\n\nfunction aborted(): QoderLlmError {\n return new QoderLlmError('Qoder image upload was aborted.', 'ABORTED')\n}\n\n/** Encode one image as a single-field multipart payload using the Qoder boundary shape. */\nexport function buildQoderImageMultipart(\n data: Uint8Array,\n mediaType: string,\n boundaryId: string = crypto.randomUUID(),\n): QoderMultipartBody {\n const boundary = `----qodercli-${boundaryId}`\n const extension = mediaTypeExtensions[mediaType] ?? 'png'\n const header = Buffer.from(\n `--${boundary}\\r\\n`\n + `Content-Disposition: form-data; name=\"file\"; filename=\"image.${extension}\"\\r\\n`\n + `Content-Type: ${mediaType}\\r\\n\\r\\n`,\n 'utf8',\n )\n const footer = Buffer.from(`\\r\\n--${boundary}--\\r\\n`, 'utf8')\n return { body: Buffer.concat([header, Buffer.from(data), footer]), boundary }\n}\n\n/**\n * Extract the durable object URL from a center upload response.\n *\n * @param payload - parsed response body.\n * @returns the first usable absolute URL, or undefined when none is present.\n */\nexport function readQoderImageUrl(payload: unknown): string | undefined {\n if (payload === null || typeof payload !== 'object') return undefined\n const root = payload as Record<string, unknown>\n const result = root.result as Record<string, unknown> | undefined\n const data = root.data as Record<string, unknown> | undefined\n const candidates = [\n root.url,\n result?.url,\n result?.oss_url,\n data?.url,\n data?.oss_url,\n ]\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length === 0) continue\n if (!URL.canParse(trimmed)) continue\n return trimmed\n }\n return undefined\n}\n\nfunction dataUrl(image: Pick<RequestImageAttachment, 'data' | 'mediaType'>): string {\n return `data:${image.mediaType};base64,${Buffer.from(image.data).toString('base64')}`\n}\n\n/**\n * Publishes request images to the Qoder center service and remembers the result.\n *\n * Publication never fails a model request: any upstream problem degrades to an\n * inline data URL so the turn proceeds with the same content it would have\n * carried before the pipeline existed.\n */\nexport class QoderImageUploader {\n private readonly cache = new Map<string, CacheEntry>()\n private readonly flights = new SingleFlight<string>()\n private readonly fetchImpl: typeof fetch\n private readonly region: QoderRegion\n private readonly logger: QoderLogger | undefined\n private readonly timeoutMs: number\n private readonly cacheTtlMs: number\n private readonly cacheCapacity: number\n private readonly maxConcurrency: number\n private readonly refreshCredentials: ((signal?: AbortSignal) => Promise<CosyCredentials>) | undefined\n private readonly now: () => number\n private active = 0\n private readonly queue: Array<() => void> = []\n\n constructor(options: QoderImageUploaderOptions = {}) {\n this.fetchImpl = options.fetch ?? globalThis.fetch\n this.region = options.region ?? 'global'\n this.logger = options.logger\n this.timeoutMs = options.timeoutMs ?? defaultImageUploadTimeoutMs\n this.cacheTtlMs = options.cacheTtlMs ?? defaultImageUrlCacheTtlMs\n this.cacheCapacity = options.cacheCapacity ?? defaultImageUrlCacheCapacity\n this.maxConcurrency = options.maxConcurrency ?? defaultImageUploadConcurrency\n this.refreshCredentials = options.refreshCredentials\n this.now = options.now ?? Date.now\n }\n\n /**\n * Resolve the wire URL for one request image.\n *\n * @param image - request-encoded image produced by the DSH attachment store.\n * @param credentials - credentials authorizing the center exchange.\n * @param signal - optional caller cancellation.\n * @returns a center object URL, or an inline data URL when publication fails.\n * @throws QoderLlmError with code `ABORTED` only when the caller cancels.\n */\n async resolveImageUrl(\n image: RequestImageAttachment,\n credentials: CosyCredentials,\n signal?: AbortSignal,\n ): Promise<string> {\n if (signal?.aborted) throw aborted()\n\n const key = this.cacheKey(image, credentials)\n const cached = this.cache.get(key)\n if (cached !== undefined) {\n if (cached.expiresAt > this.now()) {\n // Refresh recency so the bounded cache evicts genuinely cold entries.\n this.cache.delete(key)\n this.cache.set(key, cached)\n this.logger?.debug?.('[image-upload] cache hit', {\n url: cached.url,\n region: this.region,\n mediaType: image.mediaType,\n bytes: image.data.byteLength,\n })\n return cached.url\n }\n this.cache.delete(key)\n }\n\n return this.flights.run(\n key,\n signal,\n async (sharedSignal) => {\n const url = await this.publish(image, credentials, sharedSignal)\n if (url !== undefined) {\n this.remember(key, url)\n return url\n }\n return dataUrl(image)\n },\n aborted,\n )\n }\n\n /**\n * Derive the deduplication identity for one request image.\n *\n * `variantId` is the attachment store's deterministic cache and upload index\n * over the attachment, the request policy, and the encoder parameters, so it\n * identifies these exact bytes without rehashing them. Region and subscriber\n * are included because a center object is never shared across either.\n */\n private cacheKey(image: RequestImageAttachment, credentials: CosyCredentials): string {\n const hash = crypto.createHash('sha256')\n hash.update(getQoderImageUploadUrl(this.region))\n hash.update('\\0')\n hash.update(credentials.userID)\n hash.update('\\0')\n hash.update(image.mediaType)\n hash.update('\\0')\n const variantId = typeof image.variantId === 'string' ? image.variantId : ''\n if (variantId.length > 0) {\n hash.update(variantId)\n } else {\n hash.update(crypto.createHash('sha256').update(Buffer.from(image.data)).digest('hex'))\n }\n return hash.digest('hex')\n }\n\n private remember(key: string, url: string): void {\n this.cache.delete(key)\n this.cache.set(key, { url, expiresAt: this.now() + this.cacheTtlMs })\n while (this.cache.size > this.cacheCapacity) {\n const oldest = this.cache.keys().next()\n if (oldest.done === true) break\n this.cache.delete(oldest.value)\n }\n }\n\n private async withSlot<T>(signal: AbortSignal, operation: () => Promise<T>): Promise<T> {\n if (signal.aborted) throw aborted()\n if (this.active >= this.maxConcurrency) {\n this.logger?.debug?.('[image-upload] queued', {\n region: this.region,\n active: this.active,\n queued: this.queue.length + 1,\n })\n await new Promise<void>((resolve, reject) => {\n const onAbort = (): void => {\n const index = this.queue.indexOf(release)\n if (index !== -1) this.queue.splice(index, 1)\n reject(aborted())\n }\n const release = (): void => {\n signal.removeEventListener('abort', onAbort)\n resolve()\n }\n signal.addEventListener('abort', onAbort, { once: true })\n this.queue.push(release)\n })\n } else {\n this.active++\n }\n try {\n if (signal.aborted) throw aborted()\n return await operation()\n } finally {\n const next = this.queue.shift()\n if (next !== undefined) next()\n else this.active--\n }\n }\n\n /** Attempt publication, returning undefined when the request must degrade. */\n private async publish(\n image: RequestImageAttachment,\n credentials: CosyCredentials,\n signal: AbortSignal,\n ): Promise<string | undefined> {\n return this.withSlot(signal, async () => {\n const first = await this.attempt(image, credentials, signal)\n if (first.url !== undefined) return first.url\n if (!first.retryable || this.refreshCredentials === undefined) {\n this.warnDegraded(first.reason)\n return undefined\n }\n\n let refreshed: CosyCredentials\n this.logger?.debug?.('[image-upload] refreshing credentials before retry', {\n region: this.region,\n reason: first.reason,\n })\n try {\n refreshed = await this.refreshCredentials(signal)\n } catch (error) {\n if (signal.aborted) throw aborted()\n this.warnDegraded('credential refresh failed', error)\n return undefined\n }\n const second = await this.attempt(image, refreshed, signal)\n if (second.url !== undefined) return second.url\n this.warnDegraded(second.reason)\n return undefined\n })\n }\n\n private warnDegraded(reason: string, cause?: unknown): void {\n this.logger?.warn?.(\n '[image-upload] upload failed, keeping base64 image',\n { region: this.region, reason },\n ...cause === undefined ? [] : [redactLogValue(cause)],\n )\n }\n\n private async attempt(\n image: RequestImageAttachment,\n credentials: CosyCredentials,\n signal: AbortSignal,\n ): Promise<{ url?: string; retryable: boolean; reason: string }> {\n const requestId = crypto.randomUUID()\n const url = getQoderImageUploadUrl(this.region, requestId)\n const multipart = buildQoderImageMultipart(image.data, image.mediaType)\n // The Qoder client signs the body *length*, not the body: prepareRequest\n // receives String(body.length). Signing raw multipart bytes would corrupt\n // them, because the signature input is assembled as text.\n const signedBody = Buffer.from(String(multipart.body.length), 'utf8')\n const timeout = AbortSignal.timeout(this.timeoutMs)\n const requestSignal = AbortSignal.any([signal, timeout])\n const startedAt = this.now()\n const details = {\n requestId,\n region: this.region,\n mediaType: image.mediaType,\n bytes: image.data.byteLength,\n timeoutMs: this.timeoutMs,\n }\n this.logger?.debug?.('[image-upload] started', details)\n\n try {\n const response = await this.fetchImpl(url, {\n method: 'PUT',\n headers: {\n ...buildAuthHeaders(signedBody, url, credentials),\n 'AI-CLIENT-TIMESTAMP': String(Math.floor(this.now() / 1000)),\n 'Content-Type': `multipart/form-data; boundary=${multipart.boundary}`,\n 'Content-Length': String(multipart.body.length),\n 'accept': 'application/json',\n },\n body: new Uint8Array(multipart.body),\n signal: requestSignal,\n })\n this.logger?.debug?.('[image-upload] response received', {\n requestId,\n status: response.status,\n elapsedMs: this.now() - startedAt,\n })\n const text = await readLimitedText(response, defaultMaxJsonBytes, 'Qoder image upload response')\n if (!response.ok) {\n return {\n retryable: response.status === 401 || response.status === 403,\n reason: `HTTP ${response.status}`,\n }\n }\n let payload: unknown\n try {\n payload = JSON.parse(text)\n } catch {\n return { retryable: false, reason: 'invalid JSON response' }\n }\n const resolved = readQoderImageUrl(payload)\n if (resolved === undefined) return { retryable: false, reason: 'response carried no image URL' }\n this.logger?.debug?.('[image-upload] succeeded', {\n ...details,\n status: response.status,\n elapsedMs: this.now() - startedAt,\n url: resolved\n })\n return { url: resolved, retryable: false, reason: '' }\n } catch (error) {\n const failureDetails = { requestId, region: this.region, elapsedMs: this.now() - startedAt }\n if (signal.aborted) {\n this.logger?.debug?.('[image-upload] aborted', failureDetails)\n throw aborted()\n }\n if (timeout.aborted) {\n this.logger?.debug?.('[image-upload] timed out', failureDetails)\n return { retryable: false, reason: 'upload timed out' }\n }\n this.logger?.debug?.('[image-upload] network failure', failureDetails, redactLogValue(error))\n return { retryable: false, reason: 'network failure' }\n }\n }\n}\n", "/** Qoder subscriber profile and quota usage querying. */\n\nimport type { QoderAuthService } from './auth.ts'\nimport {\n getQoderUsageUrl,\n getQoderUserPlanUrl,\n getQoderUserStatusUrl,\n type QoderRegion,\n} from './endpoints.ts'\nimport type {\n QoderAccountInfo,\n QoderQuota,\n QoderQuotaUsage,\n QoderSubscriberFeatureAllowed,\n QoderSubscriberOrganization,\n QoderSubscriberPlan,\n QoderSubscriberProfile,\n QoderSubscriberStatus,\n} from '../account.ts'\nimport { QoderLlmError, isQoderAuthRejection } from '../errors.ts'\nimport type { QoderLogger } from './logging.ts'\nimport {\n opaqueCredentialKey,\n openApiJsonRequest,\n retryMetadataRead,\n SingleFlight,\n} from './request.ts'\n\nconst defaultUsageTtlMs = 60_000\nconst defaultUsageTimeoutMs = 15_000\n\nexport interface QoderUsageReaderOptions {\n authService: QoderAuthService\n fetch?: typeof fetch | undefined\n ttlMs?: number | undefined\n timeoutMs?: number | undefined\n region?: QoderRegion | undefined\n logger?: QoderLogger | undefined\n}\n\n\ninterface RawQuota {\n total?: number\n cap?: number\n used?: number\n remaining?: number\n percentage?: number\n unit?: string\n available?: boolean\n}\n\ninterface RawUsageInfo {\n userQuota?: RawQuota\n orgResourcePackage?: RawQuota\n /** Bonus credits granted beside the plan (the daily campaign's 100). */\n addOnQuota?: RawQuota\n totalUsagePercentage?: number\n isQuotaExceeded?: boolean\n expiresAt?: number | string\n userType?: string\n upgradeUrl?: string\n}\n\nfunction normalizeQuota(raw?: RawQuota): QoderQuota | undefined {\n if (!raw || typeof raw !== 'object') return undefined\n const total = typeof raw.total === 'number' && Number.isFinite(raw.total)\n ? raw.total\n : (typeof raw.cap === 'number' && Number.isFinite(raw.cap)\n ? raw.cap\n : (typeof raw.remaining === 'number' && typeof raw.used === 'number'\n ? raw.used + raw.remaining\n : 0))\n const used = typeof raw.used === 'number' && Number.isFinite(raw.used) ? raw.used : 0\n const remaining = typeof raw.remaining === 'number' && Number.isFinite(raw.remaining)\n ? raw.remaining\n : Math.max(0, total - used)\n\n let percentage: number\n if (typeof raw.percentage === 'number' && Number.isFinite(raw.percentage)) {\n percentage = raw.percentage <= 1 && total > 1 ? raw.percentage * 100 : raw.percentage\n } else {\n percentage = total > 0 ? (used / total) * 100 : 0\n }\n\n const unit = typeof raw.unit === 'string' && raw.unit.length > 0 ? raw.unit : 'credits'\n\n return { total, used, remaining, percentage, unit }\n}\n\n\nfunction normalizeExpiresAt(rawExpires?: number | string): string | undefined {\n if (rawExpires === undefined || rawExpires === null) return undefined\n if (typeof rawExpires === 'number' && rawExpires > 0) {\n return new Date(rawExpires).toISOString()\n }\n if (typeof rawExpires === 'string' && rawExpires.length > 0) {\n const parsed = Date.parse(rawExpires)\n if (!Number.isNaN(parsed) && parsed > 0) return new Date(parsed).toISOString()\n }\n return undefined\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined\n}\n\nfunction asBoolean(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined\n}\n\nfunction asNumber(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim().length > 0) {\n const num = Number(value)\n if (Number.isFinite(num)) return num\n }\n return undefined\n}\n\nfunction normalizeOrganization(raw: unknown): QoderSubscriberOrganization | undefined {\n if (!raw || typeof raw !== 'object') return undefined\n const obj = raw as Record<string, unknown>\n const orgId = asString(obj.org_id) ?? asString(obj.orgId) ?? asString(obj.id)\n const orgName = asString(obj.org_name) ?? asString(obj.orgName) ?? asString(obj.name)\n if (!orgId || !orgName) return undefined\n return {\n orgId,\n orgName,\n ...asString(obj.role_name) ?? asString(obj.roleName) !== undefined\n ? { roleName: asString(obj.role_name) ?? asString(obj.roleName) }\n : {},\n isSuspended: asBoolean(obj.is_suspended) ?? asBoolean(obj.isSuspended) ?? false,\n canManageSubscriptions: asBoolean(obj.can_manage_subscriptions) ?? asBoolean(obj.canManageSubscriptions) ?? false,\n resourcePackageFeatureEnabled: asBoolean(obj.resource_package_feature_enabled) ?? asBoolean(obj.resourcePackageFeatureEnabled) ?? false,\n }\n}\n\nfunction normalizeFeatureAllowed(raw: unknown): QoderSubscriberFeatureAllowed | undefined {\n if (!raw || typeof raw !== 'object') return undefined\n const obj = raw as Record<string, unknown>\n return {\n quest: asBoolean(obj.quest) ?? false,\n wiki: asBoolean(obj.wiki) ?? false,\n codeReview: asBoolean(obj.code_review) ?? asBoolean(obj.codeReview) ?? false,\n }\n}\n\nfunction normalizePlan(raw: unknown): QoderSubscriberPlan | undefined {\n if (!raw || typeof raw !== 'object') return undefined\n const obj = raw as Record<string, unknown>\n const userType = asString(obj.user_type) ?? asString(obj.userType)\n const planTierName = asString(obj.plan_tier_name) ?? asString(obj.planTierName) ?? asString(obj.plan_name) ?? asString(obj.planName)\n if (!userType || !planTierName) return undefined\n\n const organization = normalizeOrganization(obj.organization)\n const isPersonalVersion = asBoolean(obj.is_personal_version) ?? asBoolean(obj.isPersonalVersion) ?? (organization === undefined)\n const startDate = normalizeExpiresAt(obj.start_date as number | string ?? obj.startDate as number | string)\n const endDate = normalizeExpiresAt(obj.end_date as number | string ?? obj.endDate as number | string)\n const planTier = asString(obj.plan_tier) ?? asString(obj.planTier)\n const isHighestTier = asBoolean(obj.is_highest_tier) ?? asBoolean(obj.isHighestTier)\n const isRenewed = asBoolean(obj.is_renewed) ?? asBoolean(obj.isRenewed)\n const featureAllowed = normalizeFeatureAllowed(obj.feature_allowed ?? obj.featureAllowed)\n\n return {\n userType,\n planTierName,\n ...planTier !== undefined ? { planTier } : {},\n isPersonalVersion,\n ...isHighestTier !== undefined ? { isHighestTier } : {},\n ...isRenewed !== undefined ? { isRenewed } : {},\n ...startDate !== undefined ? { startDate } : {},\n ...endDate !== undefined ? { endDate } : {},\n ...organization !== undefined ? { organization } : {},\n ...featureAllowed !== undefined ? { featureAllowed } : {},\n raw,\n }\n}\n\nfunction normalizeStatus(raw: unknown): QoderSubscriberStatus | undefined {\n if (!raw || typeof raw !== 'object') return undefined\n const obj = raw as Record<string, unknown>\n const featureSwitches = (obj.featureSwitches ?? obj.feature_switches) as Record<string, unknown> | undefined\n const teamSwitches = (obj.teamSwitches ?? obj.team_switches) as Record<string, unknown> | undefined\n const allowByok = asNumber(featureSwitches?.allow_byok ?? featureSwitches?.allowByok) ?? 0\n const teamAllowByok = asNumber(teamSwitches?.allow_byok ?? teamSwitches?.allowByok)\n const isPrivacyPolicyModifiable = asBoolean(obj.isPrivacyPolicyModifiable ?? obj.is_data_policy_modifiable)\n\n return {\n allowByok,\n ...teamAllowByok !== undefined ? { teamAllowByok } : {},\n ...isPrivacyPolicyModifiable !== undefined ? { isPrivacyPolicyModifiable } : {},\n raw,\n }\n}\n\nexport class QoderUsageReader {\n private readonly authService: QoderAuthService\n private readonly fetchImpl: typeof fetch\n private readonly ttlMs: number\n private readonly timeoutMs: number\n private readonly region: QoderRegion\n private readonly logger: QoderLogger | undefined\n private readonly cache = new Map<string, { info: QoderAccountInfo; expiresAt: number }>()\n private readonly flights = new SingleFlight<QoderAccountInfo>()\n\n constructor(options: QoderUsageReaderOptions) {\n this.authService = options.authService\n this.fetchImpl = options.fetch ?? globalThis.fetch\n this.ttlMs = options.ttlMs ?? defaultUsageTtlMs\n this.timeoutMs = options.timeoutMs ?? defaultUsageTimeoutMs\n this.region = options.region ?? 'global'\n this.logger = options.logger\n }\n\n async readAccount(\n pat: string,\n options?: { force?: boolean | undefined; signal?: AbortSignal | undefined },\n ): Promise<QoderAccountInfo> {\n if (!pat || typeof pat !== 'string') {\n throw new QoderLlmError(\n 'Qoder Personal Access Token is missing or invalid.',\n 'MISSING_CREDENTIAL',\n )\n }\n\n const cacheKey = `${this.region}:${opaqueCredentialKey(pat)}`\n\n if (!options?.force) {\n const cached = this.cache.get(cacheKey)\n if (cached && cached.expiresAt > Date.now()) {\n return cached.info\n }\n }\n\n return this.flights.run(\n cacheKey,\n options?.signal,\n sharedSignal => this.loadAccount(pat, sharedSignal, cacheKey),\n () => new QoderLlmError('Qoder account request was aborted.', 'ABORTED'),\n )\n }\n\n private async loadAccount(\n pat: string,\n signal: AbortSignal,\n cacheKey: string,\n ): Promise<QoderAccountInfo> {\n try {\n return await this.loadAccountWith(pat, signal, cacheKey)\n } catch (error) {\n // The cached job token can outlive the upstream's acceptance of it; one\n // fresh exchange self-heals that window instead of surfacing the card's\n // quota read as an auth failure until the next credential save.\n if (!isQoderAuthRejection(error) || signal.aborted) throw error\n this.logger?.warn?.('[Qoder Account] Usage read rejected as unauthorized; exchanging a fresh job token and retrying once')\n }\n this.authService.clear(pat)\n return this.loadAccountWith(pat, signal, cacheKey)\n }\n\n private async loadAccountWith(\n pat: string,\n signal: AbortSignal,\n cacheKey: string,\n ): Promise<QoderAccountInfo> {\n const creds = await this.authService.getCredentials(pat, signal)\n const profile: QoderSubscriberProfile = {\n id: creds.userID,\n name: creds.name || 'Qoder User',\n email: creds.email || '',\n }\n\n const [usage, plan, status] = await Promise.all([\n retryMetadataRead(signal, () => this.fetchUsage(creds.authToken, signal)),\n this.safeFetchPlan(creds.authToken, signal),\n this.safeFetchStatus(creds.authToken, creds.machineID, signal),\n ])\n\n const accountInfo: QoderAccountInfo = {\n profile,\n usage,\n ...plan !== undefined ? { plan } : {},\n ...status !== undefined ? { status } : {},\n updatedAt: new Date().toISOString(),\n }\n\n this.cache.set(cacheKey, {\n info: accountInfo,\n expiresAt: Date.now() + this.ttlMs,\n })\n\n return accountInfo\n }\n\n clear(pat?: string): void {\n if (pat) {\n this.cache.delete(`${this.region}:${opaqueCredentialKey(pat)}`)\n } else {\n this.cache.clear()\n }\n }\n\n private async fetchUsage(jobToken: string, signal?: AbortSignal): Promise<QoderQuotaUsage> {\n const data = await openApiJsonRequest<RawUsageInfo>(this.fetchImpl, {\n url: getQoderUsageUrl(this.region),\n token: jobToken,\n signal,\n timeoutMs: this.timeoutMs,\n logger: this.logger,\n operation: 'Usage',\n logCategory: 'account.usage',\n })\n\n return {\n userQuota: normalizeQuota(data.userQuota),\n orgResourcePackage: normalizeQuota(data.orgResourcePackage),\n addOnQuota: normalizeQuota(data.addOnQuota),\n totalUsagePercentage: typeof data.totalUsagePercentage === 'number' ? data.totalUsagePercentage : undefined,\n isQuotaExceeded: typeof data.isQuotaExceeded === 'boolean' ? data.isQuotaExceeded : false,\n expiresAt: normalizeExpiresAt(data.expiresAt),\n raw: data,\n }\n }\n\n private async fetchPlan(jobToken: string, signal?: AbortSignal): Promise<QoderSubscriberPlan | undefined> {\n const data = await openApiJsonRequest<unknown>(this.fetchImpl, {\n url: getQoderUserPlanUrl(this.region),\n token: jobToken,\n signal,\n timeoutMs: this.timeoutMs,\n logger: this.logger,\n operation: 'Plan',\n logCategory: 'account.plan',\n })\n return normalizePlan(data)\n }\n\n private async safeFetchPlan(jobToken: string, signal: AbortSignal): Promise<QoderSubscriberPlan | undefined> {\n try {\n return await this.fetchPlan(jobToken, signal)\n } catch (error) {\n if (signal.aborted) throw error\n this.logger?.warn?.('[Qoder Plan] Failed to load user plan (degraded)', error instanceof Error ? error.message : error)\n return undefined\n }\n }\n\n private async fetchStatus(\n jobToken: string,\n machineId?: string,\n signal?: AbortSignal,\n ): Promise<QoderSubscriberStatus | undefined> {\n const data = await openApiJsonRequest<unknown>(this.fetchImpl, {\n url: getQoderUserStatusUrl(this.region),\n token: jobToken,\n machineId,\n signal,\n timeoutMs: this.timeoutMs,\n logger: this.logger,\n operation: 'Status',\n logCategory: 'account.status',\n })\n return normalizeStatus(data)\n }\n\n private async safeFetchStatus(\n jobToken: string,\n machineId?: string,\n signal?: AbortSignal,\n ): Promise<QoderSubscriberStatus | undefined> {\n try {\n return await this.fetchStatus(jobToken, machineId, signal)\n } catch (error) {\n if (signal?.aborted) throw error\n this.logger?.warn?.('[Qoder Status] Failed to load user status (degraded)', error instanceof Error ? error.message : error)\n return undefined\n }\n }\n}\n", "/**\n * The one UTC+8 day calculation the check-in logic is allowed to use.\n *\n * Qoder opens the daily benefit at 10:00 Beijing time and closes it at 09:59\n * the next morning, so the unit that matters is a *window*, not a calendar\n * date \u2014 for the last ten hours of every window the two disagree. The\n * transport (which must say which window a campaign belongs to) and the\n * scheduler (which must decide whether today is settled) therefore have to name\n * that day identically, or one of them settles a day the other has not claimed.\n * That disagreement is exactly what silently cost a day's credits, so the\n * conversion lives here instead of being re-derived in each of them.\n *\n * @module dsh-qoder-connect/utc8\n */\n\n/** Beijing time's offset from UTC, in minutes. */\nexport const UTC8_OFFSET_MINUTES = 480\n\n/**\n * The UTC+8 wall clock of an instant, as a Date whose *local* fields hold it.\n *\n * Shifting by the host's own offset cancels the host timezone out, so the\n * result reads the same on a UTC+8 machine and on a UTC-5 one. Callers must\n * therefore use the local getters (`getHours`, `getFullYear`, \u2026) on it.\n */\nexport function utc8WallClock(atMs: number): Date {\n const d = new Date(atMs)\n return new Date(d.getTime() + (d.getTimezoneOffset() + UTC8_OFFSET_MINUTES) * 60_000)\n}\n\n/**\n * Format an epoch-ms instant as its UTC+8 calendar date, `YYYY-MM-DD`.\n */\nexport function formatUtc8Date(atMs: number): string {\n const utc8 = utc8WallClock(atMs)\n const y = utc8.getFullYear()\n const m = String(utc8.getMonth() + 1).padStart(2, '0')\n const day = String(utc8.getDate()).padStart(2, '0')\n return `${y}-${m}-${day}`\n}\n", "/** Qoder campaign inquiry and daily benefit check-in service. */\n\nimport { formatUtc8Date } from '../../utc8.ts'\nimport type { QoderAuthService } from './auth.ts'\nimport {\n getQoderCampaignsUrl,\n getQoderClaimCampaignUrl,\n resolveQoderEndpoints,\n type QoderRegion,\n} from './endpoints.ts'\nimport { isQoderAuthRejection, QoderLlmError } from '../errors.ts'\nimport type { QoderLogger } from './logging.ts'\nimport { openApiJsonRequest } from './request.ts'\nimport { qoderDesktopClientType } from './wire/cosy.ts'\n\nexport interface QoderCampaignBenefit {\n kind?: string\n amount?: number\n validity?: {\n mode?: string\n days?: number\n }\n}\n\nexport interface QoderCampaign {\n campaignId: string\n campaignKey?: string\n actionType: string\n claimStatus: string\n startAt?: number\n endAt?: number\n benefit?: QoderCampaignBenefit\n}\n\nexport interface QoderCampaignsResponse {\n uid?: string\n claimable?: boolean\n campaigns?: QoderCampaign[]\n}\n\nexport interface QoderClaimResponse {\n status?: string\n replayed?: boolean\n benefit?: {\n kind?: string\n amount?: number\n }\n expiresAt?: string\n}\n\nexport interface QoderCheckInResult {\n variantId: string\n date: string\n timestamp: number\n status: 'claimed' | 'already-claimed' | 'before-window' | 'no-campaign' | 'error'\n amount?: number | undefined\n campaignKey?: string | undefined\n message?: string | undefined\n}\n\nexport interface QoderCheckInServiceOptions {\n authService: QoderAuthService\n fetch?: typeof fetch | undefined\n region?: QoderRegion | undefined\n variantId?: string | undefined\n logger?: QoderLogger | undefined\n timeoutMs?: number | undefined\n}\n\nconst defaultCheckInTimeoutMs = 15_000\n\n/**\n * The longest span still recognised as one daily benefit window.\n *\n * Qoder's daily window runs 10:00 \u2192 09:59 the next morning (86_340 s). The\n * slack above 24h absorbs a clock or rounding difference; a genuinely longer\n * campaign is *not* a daily window, and its start day says nothing about which\n * day one claim of it belongs to, so it must fall back to the calendar day\n * rather than mislabel every day of its run.\n */\nconst DAILY_WINDOW_MAX_MS = 24 * 60 * 60_000\n\n/**\n * Which day's benefit the campaign the upstream is currently serving belongs to.\n *\n * Before 10:00 UTC+8 the upstream is still serving *yesterday's* window and its\n * `CLAIMED` describes yesterday, so \"the campaign says CLAIMED\" is not the same\n * statement as \"today is done\". Separating those two cases is the whole fix.\n */\ntype CampaignWindow =\n /** Today's window is open; `date` is the day it belongs to. */\n | { kind: 'open'; date: string }\n /** Today's window has not opened yet. */\n | { kind: 'not-open' }\n /** The served window belongs to an earlier day; `date` names it. */\n | { kind: 'earlier'; date: string }\n /** No usable window bounds; the calendar day is the only signal available. */\n | { kind: 'unknown' }\n\nexport class QoderCheckInService {\n private readonly authService: QoderAuthService\n private readonly fetchImpl: typeof fetch\n private readonly region: QoderRegion\n private readonly variantId: string\n private readonly logger: QoderLogger | undefined\n private readonly timeoutMs: number\n\n constructor(options: QoderCheckInServiceOptions) {\n this.authService = options.authService\n this.fetchImpl = options.fetch ?? globalThis.fetch\n this.region = options.region ?? 'china'\n this.variantId = options.variantId ?? 'qoder'\n this.logger = options.logger\n this.timeoutMs = options.timeoutMs ?? defaultCheckInTimeoutMs\n }\n\n async fetchCampaigns(token: string, signal?: AbortSignal): Promise<QoderCampaign[]> {\n const url = getQoderCampaignsUrl(this.region)\n const data = await openApiJsonRequest<QoderCampaignsResponse>(this.fetchImpl, {\n url,\n token,\n // The campaign family gates on the desktop identifier; the generic one\n // answers 200 with an empty list (see `qoderDesktopClientType`).\n headers: { 'cosy-clienttype': qoderDesktopClientType },\n signal,\n timeoutMs: this.timeoutMs,\n logger: this.logger,\n operation: 'Campaigns',\n logCategory: 'campaigns.list',\n })\n return Array.isArray(data?.campaigns) ? data.campaigns : []\n }\n\n async claimCampaign(token: string, campaignId: string, signal?: AbortSignal): Promise<QoderClaimResponse> {\n const url = getQoderClaimCampaignUrl(this.region, campaignId)\n const { openApiUrl } = resolveQoderEndpoints(this.region)\n return openApiJsonRequest<QoderClaimResponse>(this.fetchImpl, {\n url,\n method: 'POST',\n token,\n headers: { origin: openApiUrl, 'cosy-clienttype': qoderDesktopClientType },\n signal,\n timeoutMs: this.timeoutMs,\n logger: this.logger,\n operation: 'ClaimCampaign',\n logCategory: 'campaigns.claim',\n })\n }\n\n /**\n * Attribute the campaign the upstream is serving to a day, or say why it\n * cannot be attributed to today.\n *\n * The daily benefit window is 10:00 UTC+8 \u2192 09:59 the next morning, so a\n * calendar date and the window's own date agree for only fourteen hours of\n * every twenty-four. Treating them as the same thing is what recorded a\n * pre-10:00 read of the *previous* window's `CLAIMED` against today.\n */\n private classifyCampaignWindow(\n campaign: QoderCampaign,\n nowMs: number,\n today: string,\n ): CampaignWindow {\n const startAt = campaign.startAt\n if (typeof startAt !== 'number' || !Number.isFinite(startAt) || startAt <= 0) {\n // Nothing to attribute a status to: the calendar day is all there is.\n return { kind: 'unknown' }\n }\n const endAt = campaign.endAt\n if (typeof endAt === 'number' && Number.isFinite(endAt)) {\n const spanMs = (endAt - startAt) * 1000\n if (spanMs <= 0 || spanMs > DAILY_WINDOW_MAX_MS) return { kind: 'unknown' }\n }\n const startMs = startAt * 1000\n if (startMs > nowMs) return { kind: 'not-open' }\n const date = formatUtc8Date(startMs)\n return date === today ? { kind: 'open', date } : { kind: 'earlier', date }\n }\n\n async checkIn(pat: string, signal?: AbortSignal): Promise<QoderCheckInResult> {\n const nowMs = Date.now()\n // One instant decides both the calendar day and the window comparison, so\n // an attempt can never straddle the 10:00 boundary and mix two days.\n const today = formatUtc8Date(nowMs)\n\n if (!pat || typeof pat !== 'string' || pat.trim() === '') {\n return {\n variantId: this.variantId,\n date: today,\n timestamp: nowMs,\n status: 'error',\n message: 'No PAT available',\n }\n }\n\n const executeWithToken = async (authToken: string): Promise<QoderCheckInResult> => {\n const campaigns = await this.fetchCampaigns(authToken, signal)\n // Look for daily benefit campaign (actionType === 'CLAIM_BENEFIT')\n const benefitCampaign = campaigns.find(c => c.actionType === 'CLAIM_BENEFIT')\n if (!benefitCampaign) {\n return {\n variantId: this.variantId,\n date: today,\n timestamp: nowMs,\n status: 'no-campaign',\n message: 'No claimable benefit campaign found for this region',\n }\n }\n\n const campaignWindow = this.classifyCampaignWindow(benefitCampaign, nowMs, today)\n // Only today's own window may settle today, and which window the\n // upstream is serving is the only thing that can say so: a window that\n // has not opened yet, or one that is still yesterday's, is not today's\n // benefit however the upstream reports its status. This is also what\n // refuses a pre-window attempt (#13, a manual click at 09:58 that read\n // the previous window's `CLAIMED` and cost the day): nothing is claimed\n // and the day stays retryable, so the run after the window opens still\n // does the claiming.\n //\n // Deliberately driven by the campaign's own `startAt`/`endAt` rather than\n // any clock constant: the opening moment is the upstream's to state, and\n // the China and Global products need not share it. A local \"nothing can\n // be claimed before 10:00\" rule would have hard-coded the one product's\n // measured boundary onto both.\n //\n // `before-window` rather than `no-campaign`: the campaign exists and the\n // day is still claimable, only the window is not open. Sharing one status\n // with \"this account has no campaign at all\" (the Global shape, #6/#12)\n // made the card say the same sentence for both, which is how a user\n // reads \"nothing to claim\" while a claim is still owed to them.\n if (campaignWindow.kind === 'not-open' || campaignWindow.kind === 'earlier') {\n return {\n variantId: this.variantId,\n date: today,\n timestamp: nowMs,\n status: 'before-window',\n campaignKey: benefitCampaign.campaignKey,\n message: campaignWindow.kind === 'not-open'\n ? \"Today's benefit window has not opened yet\"\n : `Upstream is still serving the benefit window of ${campaignWindow.date}`,\n }\n }\n const windowDate = campaignWindow.kind === 'open' ? campaignWindow.date : today\n\n if (benefitCampaign.claimStatus === 'CLAIMED') {\n return {\n variantId: this.variantId,\n date: windowDate,\n timestamp: nowMs,\n status: 'already-claimed',\n campaignKey: benefitCampaign.campaignKey,\n amount: benefitCampaign.benefit?.amount ?? 100,\n message: 'Already claimed today',\n }\n }\n\n // Claim it\n const claimResult = await this.claimCampaign(authToken, benefitCampaign.campaignId, signal)\n const isClaimed = claimResult.status === 'CLAIMED'\n const replayed = Boolean(claimResult.replayed)\n const amount = claimResult.benefit?.amount ?? benefitCampaign.benefit?.amount ?? 100\n\n if (isClaimed) {\n return {\n variantId: this.variantId,\n date: windowDate,\n timestamp: nowMs,\n status: replayed ? 'already-claimed' : 'claimed',\n amount,\n campaignKey: benefitCampaign.campaignKey,\n message: replayed ? 'Already claimed today' : `Successfully claimed ${amount} credits`,\n }\n }\n\n return {\n variantId: this.variantId,\n date: today,\n timestamp: nowMs,\n status: 'error',\n campaignKey: benefitCampaign.campaignKey,\n message: `Claim returned status ${claimResult.status ?? 'unknown'}`,\n }\n }\n\n try {\n const creds = await this.authService.getCredentials(pat, signal)\n try {\n return await executeWithToken(creds.authToken)\n } catch (innerError) {\n // If 401 token rejection, attempt one fresh token rotation and retry\n if (isQoderAuthRejection(innerError)) {\n this.logger?.warn?.(`[Qoder CheckIn] Auth token rejected, retrying with fresh exchange`)\n const freshCreds = await this.authService.exchangeFresh(pat, signal)\n return await executeWithToken(freshCreds.authToken)\n }\n throw innerError\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n this.logger?.error?.(`[Qoder CheckIn] Check-in failed: ${message}`)\n return {\n variantId: this.variantId,\n date: today,\n timestamp: nowMs,\n status: 'error',\n message,\n }\n }\n }\n}\n", "/** Qoder chat request encoding, timeout lifecycle, and SSE streaming. */\r\n\r\nimport {\r\n attributionHeaders,\r\n type GenerateOptions,\r\n type StreamChunk,\r\n type TokenUsage,\r\n} from '@deepseek-ai/dsh-llm'\r\nimport type { QoderCatalogModel } from '../catalog.ts'\r\nimport { QoderLlmError, qoderHttpError, qoderRequestId } from '../errors.ts'\r\nimport type { QoderRegion } from '../region.ts'\r\nimport { getQoderChatUrl } from './endpoints.ts'\r\nimport { redactLogValue, type QoderLogger } from './logging.ts'\r\nimport { defaultMaxErrorBytes, readLimitedText } from './request.ts'\r\nimport { buildAuthHeaders, type CosyCredentials } from './wire/cosy.ts'\r\nimport { qoderEncodeBody } from './wire/encoding.ts'\r\nimport { buildQoderRequestBody } from './wire/serialize.ts'\r\nimport { parseQoderSse } from './wire/sse.ts'\r\nimport type { QoderWireMessage } from './wire/wire-types.ts'\r\n\r\nexport interface QoderChatDependencies {\r\n fetch: typeof fetch\r\n logger?: QoderLogger | undefined\r\n region: QoderRegion\r\n responseHeaderTimeoutMs: number\r\n streamIdleTimeoutMs: number\r\n}\r\n\r\nfunction aborted(message: string): QoderLlmError {\r\n return new QoderLlmError(message, 'ABORTED')\r\n}\r\n\r\nexport async function* streamQoderChat(\r\n options: GenerateOptions,\r\n model: QoderCatalogModel | undefined,\r\n credentials: CosyCredentials,\r\n messages: QoderWireMessage[],\r\n dependencies: QoderChatDependencies,\r\n): AsyncGenerator<StreamChunk> {\r\n const request = await buildQoderRequestBody(options, credentials.userID, messages, model)\r\n const encodedBody = qoderEncodeBody(JSON.stringify(request))\r\n const encodedBytes = Buffer.from(encodedBody, 'utf8')\r\n const chatUrl = getQoderChatUrl(dependencies.region)\r\n const requestController = new AbortController()\r\n let headerTimedOut = false\r\n let idleTimedOut = false\r\n let idleTimer: ReturnType<typeof setTimeout> | undefined\r\n let chunkCount = 0\r\n let reqId: ReturnType<typeof qoderRequestId> | undefined\r\n const startedAt = performance.now()\r\n let lastActivityAt = startedAt\r\n const onCallerAbort = (): void => requestController.abort(options.signal?.reason)\r\n options.signal?.addEventListener('abort', onCallerAbort, { once: true })\r\n const headerTimer = setTimeout(() => {\r\n headerTimedOut = true\r\n requestController.abort('response header timeout')\r\n }, dependencies.responseHeaderTimeoutMs)\r\n const resetIdleTimer = (): void => {\r\n lastActivityAt = performance.now()\r\n if (idleTimer !== undefined) clearTimeout(idleTimer)\r\n idleTimer = setTimeout(() => {\r\n idleTimedOut = true\r\n requestController.abort('stream idle timeout')\r\n }, dependencies.streamIdleTimeoutMs)\r\n }\r\n\r\n try {\r\n const response = await dependencies.fetch(chatUrl, {\r\n method: 'POST',\r\n headers: {\r\n 'content-type': 'application/json',\r\n 'accept': 'text/event-stream',\r\n 'cache-control': 'no-cache',\r\n 'accept-encoding': 'identity',\r\n 'x-model-key': options.model || 'cmodel',\r\n 'x-model-source': model?.source || 'system',\r\n ...attributionHeaders(),\r\n ...buildAuthHeaders(encodedBytes, chatUrl, credentials),\r\n },\r\n body: encodedBytes,\r\n signal: requestController.signal,\r\n })\r\n clearTimeout(headerTimer)\r\n reqId = qoderRequestId(response.headers)\r\n dependencies.logger?.debug?.('[Qoder Stream] Response headers received', {\r\n region: dependencies.region,\r\n status: response.status,\r\n durationMs: Math.round(performance.now() - startedAt),\r\n ...reqId === undefined ? {} : { requestId: reqId },\r\n })\r\n resetIdleTimer()\r\n if (!response.ok) {\r\n // Read the (bounded) error body before failing: a 401/403 the upstream\r\n // used to announce its queue carries code 10605 / isQueued /\r\n // retryAfterSeconds, and only the body separates a throttle from a real\r\n // authorization rejection. Without it every such answer looked like a\r\n // dead credential and triggered a job-token exchange that cannot jump\r\n // a queue.\r\n let errorBody: string | undefined\r\n try {\r\n errorBody = await readLimitedText(response, defaultMaxErrorBytes, 'Qoder chat error response')\r\n } catch {\r\n // A body that cannot be read (or that exceeds the cap) still fails the\r\n // request; it just classifies from status and headers alone.\r\n errorBody = undefined\r\n }\r\n throw qoderHttpError(`Qoder upstream service returned HTTP ${response.status}.`, response, errorBody)\r\n }\r\n if (!response.body) {\r\n throw new QoderLlmError('Qoder response contains no readable body stream.', 'EMPTY_RESPONSE')\r\n }\r\n\r\n let firstChunkDurationMs: number | undefined\r\n let tokenUsage: TokenUsage | undefined\r\n let finishReason: string | undefined\r\n const streamStartedAt = performance.now()\r\n\r\n for await (const chunk of parseQoderSse(response.body, { onActivity: resetIdleTimer })) {\r\n chunkCount++\r\n if (firstChunkDurationMs === undefined) {\r\n firstChunkDurationMs = Math.round(performance.now() - startedAt)\r\n dependencies.logger?.debug?.('[Qoder Stream] First chunk received', {\r\n durationMs: firstChunkDurationMs,\r\n ...reqId === undefined ? {} : { requestId: reqId },\r\n })\r\n }\r\n if (chunk.type === 'usage') {\r\n tokenUsage = chunk.usage\r\n }\r\n if (chunk.type === 'finish') {\r\n finishReason = chunk.reason.kind\r\n }\r\n yield chunk\r\n }\r\n\r\n dependencies.logger?.debug?.('[Qoder Stream] Stream completed', {\r\n durationMs: Math.round(performance.now() - startedAt),\r\n streamDurationMs: Math.round(performance.now() - streamStartedAt),\r\n chunkCount,\r\n ...finishReason === undefined ? {} : { finishReason },\r\n ...tokenUsage === undefined ? {} : { usage: tokenUsage },\r\n ...reqId === undefined ? {} : { requestId: reqId },\r\n })\r\n } catch (error: unknown) {\r\n if (options.signal?.aborted) throw aborted('Request was aborted.')\r\n const elapsedMs = Math.round(performance.now() - startedAt)\r\n if (headerTimedOut) {\r\n const failure = new QoderLlmError('Qoder model request exceeded its response header timeout.', 'TIMEOUT')\r\n dependencies.logger?.error?.('[Qoder Stream] Request failed', redactLogValue(failure), {\r\n phase: 'header',\r\n elapsedMs,\r\n timeoutMs: dependencies.responseHeaderTimeoutMs,\r\n })\r\n throw failure\r\n }\r\n if (idleTimedOut) {\r\n const failure = new QoderLlmError('Qoder model stream exceeded its idle timeout.', 'TIMEOUT')\r\n dependencies.logger?.error?.('[Qoder Stream] Request failed', redactLogValue(failure), {\r\n phase: 'stream-idle',\r\n chunkCount,\r\n idleDurationMs: Math.round(performance.now() - lastActivityAt),\r\n elapsedMs,\r\n ...reqId === undefined ? {} : { requestId: reqId },\r\n })\r\n throw failure\r\n }\r\n if (error instanceof QoderLlmError) {\r\n dependencies.logger?.error?.('[Qoder Stream] Request failed', redactLogValue(error), {\r\n chunkCount,\r\n elapsedMs,\r\n ...reqId === undefined ? {} : { requestId: reqId },\r\n })\r\n throw error\r\n }\r\n const failure = new QoderLlmError('Qoder transport request failed.', 'TRANSPORT', { cause: error })\r\n dependencies.logger?.error?.('[Qoder Stream] Request failed', redactLogValue(failure), {\r\n chunkCount,\r\n elapsedMs,\r\n ...reqId === undefined ? {} : { requestId: reqId },\r\n cause: redactLogValue(error),\r\n })\r\n throw failure\r\n } finally {\r\n clearTimeout(headerTimer)\r\n if (idleTimer !== undefined) clearTimeout(idleTimer)\r\n options.signal?.removeEventListener('abort', onCallerAbort)\r\n requestController.abort('request complete')\r\n }\r\n}\r\n", "/**\n * Qoder WAF Body encoding algorithm.\n *\n * Re-arranges standard Base64 chunks and translates characters against\n * a custom alphabet to satisfy Qoder upstream WAF requirements.\n *\n * The translation runs through a byte table applied to a Buffer instead of a\n * per-character string loop. The loop form (`out += char` plus\n * `alphabet.indexOf(char)`) costs ~800 ms on a 1 MB body and runs on the main\n * thread once per model request, which saturated the Harness event loop as\n * soon as a few large-context sessions were in flight. The table form is\n * byte-for-byte identical (the input is always Base64, i.e. ASCII) and about\n * 24x faster.\n *\n * @module dsh-provider-qoder/qoder/transport/wire/encoding\n */\n\nconst qoderCustomAlphabet = '_doRTgHZBKcGVjlvpC,@aFSx#DPuNJme&i*MzLOEn)sUrthbf%Y^w.(kIQyXqWA!'\nconst qoderStdAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\n\n/**\n * Byte translation table: every byte maps to itself unless it is a Base64\n * alphabet character (\u2192 the custom alphabet) or the `=` pad (\u2192 `$`).\n */\nconst encodeTable: Uint8Array = (() => {\n const table = new Uint8Array(256)\n for (let index = 0; index < 256; index++) table[index] = index\n for (let index = 0; index < qoderStdAlphabet.length; index++) {\n table[qoderStdAlphabet.charCodeAt(index)] = qoderCustomAlphabet.charCodeAt(index)\n }\n table['='.charCodeAt(0)] = '$'.charCodeAt(0)\n return table\n})()\n\nexport function qoderEncodeBody(plaintext: string | Buffer): string {\n const std = Buffer.isBuffer(plaintext) ? plaintext.toString('base64') : Buffer.from(plaintext).toString('base64')\n const n = std.length\n const a = Math.floor(n / 3)\n const rearranged = std.slice(n - a) + std.slice(a, n - a) + std.slice(0, a)\n // Base64 output is ASCII by construction, so a latin1 view is exact and the\n // table applies byte-wise.\n const source = Buffer.from(rearranged, 'latin1')\n const target = Buffer.allocUnsafe(n)\n for (let index = 0; index < n; index++) {\n // Both indexes are in range by construction; the fallbacks only satisfy\n // noUncheckedIndexedAccess.\n target[index] = encodeTable[source[index] ?? 0] ?? 0\n }\n return target.toString('latin1')\n}\n", "/** Decode Qoder's outer SSE envelope and inner model chunks. */\r\n\r\nimport {\r\n ToolCallId,\r\n EMPTY_RESPONSE_CODE,\r\n type StreamChunk,\r\n type TokenUsage,\r\n} from '@deepseek-ai/dsh-llm'\r\nimport { QoderLlmError, qoderHttpError } from '../../errors.ts'\r\nimport { QoderThinkingParser, type QoderContentSegment } from './thinking.ts'\r\nimport type { QoderInnerChunk, QoderSseEnvelope } from './wire-types.ts'\r\n\r\nconst doneMarker = '[DONE]'\r\nexport const defaultMaxSseBufferChars = 2 * 1024 * 1024\r\n\r\nexport interface QoderSseOptions {\r\n onActivity?: () => void\r\n maxBufferChars?: number\r\n}\r\n\r\ninterface TextualBlockState {\r\n type: 'text' | 'reasoning'\r\n index: number\r\n text: string\r\n}\r\n\r\ninterface ToolCallState {\r\n id: string\r\n name: string\r\n arguments: string\r\n emittedArguments: number\r\n blockIndex?: number\r\n}\r\n\r\ntype SuccessfulFinishKind = 'stop' | 'tool-calls' | 'max-tokens'\r\n\r\nfunction malformed(message: string): QoderLlmError {\r\n return new QoderLlmError(message, 'MALFORMED_RESPONSE')\r\n}\r\n\r\nfunction parseEnvelope(rawData: string): QoderSseEnvelope {\r\n let value: unknown\r\n try {\r\n value = JSON.parse(rawData)\r\n } catch {\r\n throw malformed('Malformed outer SSE JSON payload received from Qoder.')\r\n }\r\n if (value === null || typeof value !== 'object') throw malformed('Malformed outer SSE envelope received from Qoder.')\r\n const envelope = value as QoderSseEnvelope\r\n if (envelope.statusCodeValue !== undefined && typeof envelope.statusCodeValue !== 'number') {\r\n throw malformed('Qoder SSE envelope has an invalid status code.')\r\n }\r\n if (envelope.statusCodeValue !== undefined\r\n && (!Number.isInteger(envelope.statusCodeValue)\r\n || envelope.statusCodeValue < 100\r\n || envelope.statusCodeValue > 599)) {\r\n throw malformed('Qoder SSE envelope has an invalid status code.')\r\n }\r\n if (envelope.statusCodeValue !== undefined && envelope.statusCodeValue !== 200) {\r\n const status = envelope.statusCodeValue\r\n // Forward the envelope body into the reported message. Qoder answers a\r\n // rejected chat with a 200 SSE whose first envelope carries the failure,\r\n // and that body is where the real reason lives (quota exhausted, region\r\n // permission, risk control, ...). Dropping it left every such rejection\r\n // reading as a bare \"invalid API key\" with nothing to act on.\r\n //\r\n // The body is also handed to the classifier itself: a 401/403 envelope\r\n // whose body carries the queue markers (code 10605, isQueued,\r\n // queueCount, retryAfterSeconds) is a throttle, not an authorization\r\n // failure, and must not send the transport into a job-token exchange.\r\n throw qoderHttpError(\r\n envelope.body\r\n ? `Qoder service returned upstream error status ${status}: ${envelope.body}`\r\n : `Qoder service returned upstream error status ${status}.`,\r\n { status },\r\n envelope.body,\r\n )\r\n }\r\n if (envelope.body !== undefined && typeof envelope.body !== 'string') {\r\n throw malformed('Qoder SSE envelope has an invalid model body.')\r\n }\r\n return envelope\r\n}\r\n\r\nfunction parseInner(body: string): QoderInnerChunk {\r\n try {\r\n const value = JSON.parse(body) as unknown\r\n if (value === null || typeof value !== 'object') throw new Error('not an object')\r\n return value as QoderInnerChunk\r\n } catch {\r\n throw malformed('Malformed inner model payload received from Qoder.')\r\n }\r\n}\r\n\r\nfunction tokenUsage(innerChunk: QoderInnerChunk): TokenUsage | undefined {\r\n if (!innerChunk.usage) return undefined\r\n const usage = innerChunk.usage\r\n const promptTokens = usage.prompt_tokens ?? 0\r\n const cacheReadTokens = usage.prompt_tokens_details?.cached_tokens ?? 0\r\n const cacheWriteTokens = usage.prompt_tokens_details?.cache_write_tokens ?? 0\r\n const reasoningTokens = usage.completion_tokens_details?.reasoning_tokens\r\n return {\r\n inputTokens: Math.max(0, promptTokens - cacheReadTokens - cacheWriteTokens),\r\n outputTokens: usage.completion_tokens ?? 0,\r\n ...cacheReadTokens > 0 ? { cacheReadTokens } : {},\r\n ...cacheWriteTokens > 0 ? { cacheWriteTokens } : {},\r\n ...reasoningTokens === undefined ? {} : { reasoningTokens },\r\n }\r\n}\r\n\r\nfunction finishKind(value: string | null | undefined): SuccessfulFinishKind | undefined {\r\n if (value === undefined || value === null || value === '') return undefined\r\n if (value === 'stop') return 'stop'\r\n if (value === 'length') return 'max-tokens'\r\n if (value === 'tool_calls' || value === 'toolUse') return 'tool-calls'\r\n if (value === 'content_filter') {\r\n throw new QoderLlmError('Qoder blocked the response through its content filter.', 'PROVIDER_ERROR')\r\n }\r\n throw malformed(`Qoder returned unknown finish reason \"${value}\".`)\r\n}\r\n\r\nexport async function* parseQoderSse(\r\n stream: ReadableStream<Uint8Array>,\r\n options: QoderSseOptions = {},\r\n): AsyncGenerator<StreamChunk> {\r\n const reader = stream.getReader()\r\n const decoder = new TextDecoder()\r\n const thinkingParser = new QoderThinkingParser()\r\n const toolCalls = new Map<number, ToolCallState>()\r\n let buffer = ''\r\n let sourceEnded = false\r\n let sawDone = false\r\n let nextBlockIndex = 0\r\n let activeTextual: TextualBlockState | undefined\r\n let pendingUsage: TokenUsage | undefined\r\n let terminalKind: SuccessfulFinishKind = 'stop'\r\n let sawContent = false\r\n const maxBufferChars = options.maxBufferChars ?? defaultMaxSseBufferChars\r\n\r\n const closeTextual = (): StreamChunk[] => {\r\n if (activeTextual === undefined) return []\r\n const state = activeTextual\r\n activeTextual = undefined\r\n return [{\r\n type: 'block-end',\r\n index: state.index,\r\n block: state.type === 'text'\r\n ? { type: 'text', text: state.text }\r\n : { type: 'reasoning', text: state.text },\r\n }]\r\n }\r\n\r\n const appendSegment = (segment: QoderContentSegment): StreamChunk[] => {\r\n if (!segment.text) return []\r\n const chunks: StreamChunk[] = []\r\n sawContent = true\r\n if (activeTextual?.type !== segment.type) {\r\n chunks.push(...closeTextual())\r\n activeTextual = { type: segment.type, index: nextBlockIndex++, text: '' }\r\n chunks.push({ type: 'block-start', index: activeTextual.index, blockType: segment.type })\r\n }\r\n activeTextual.text += segment.text\r\n chunks.push(segment.type === 'text'\r\n ? { type: 'text-delta', index: activeTextual.index, text: segment.text }\r\n : { type: 'reasoning-delta', index: activeTextual.index, text: segment.text })\r\n return chunks\r\n }\r\n\r\n const openToolCall = (state: ToolCallState): StreamChunk[] => {\r\n if (!state.id || state.blockIndex !== undefined) return []\r\n const chunks = closeTextual()\r\n state.blockIndex = nextBlockIndex++\r\n sawContent = true\r\n chunks.push({ type: 'block-start', index: state.blockIndex, blockType: 'tool-call' })\r\n const argumentsDelta = state.arguments.slice(state.emittedArguments)\r\n state.emittedArguments = state.arguments.length\r\n chunks.push({\r\n type: 'tool-call-delta',\r\n index: state.blockIndex,\r\n id: ToolCallId(state.id),\r\n ...state.name ? { name: state.name } : {},\r\n argumentsDelta,\r\n })\r\n return chunks\r\n }\r\n\r\n try {\r\n while (!sourceEnded && !sawDone) {\r\n const { done, value } = await reader.read()\r\n if (done) {\r\n sourceEnded = true\r\n buffer += decoder.decode()\r\n if (buffer.length > 0 && !buffer.endsWith('\\n')) buffer += '\\n'\r\n } else {\r\n options.onActivity?.()\r\n buffer += decoder.decode(value, { stream: true })\r\n if (buffer.length > maxBufferChars) {\r\n throw malformed('Qoder SSE frame exceeded its size limit.')\r\n }\r\n }\r\n\r\n while (!sawDone) {\r\n const lineEnd = buffer.indexOf('\\n')\r\n if (lineEnd === -1) break\r\n let line = buffer.substring(0, lineEnd)\r\n buffer = buffer.substring(lineEnd + 1)\r\n if (line.endsWith('\\r')) line = line.slice(0, -1)\r\n line = line.trim()\r\n if (!line.startsWith('data:')) continue\r\n\r\n const rawData = line.substring(5).trim()\r\n if (!rawData) continue\r\n if (rawData === doneMarker) {\r\n sawDone = true\r\n break\r\n }\r\n\r\n const envelope = parseEnvelope(rawData)\r\n const body = envelope.body?.trim()\r\n if (!body) continue\r\n if (body === doneMarker) {\r\n sawDone = true\r\n break\r\n }\r\n const innerChunk = parseInner(body)\r\n pendingUsage = tokenUsage(innerChunk) ?? pendingUsage\r\n\r\n for (const choice of innerChunk.choices ?? []) {\r\n terminalKind = finishKind(choice.finish_reason) ?? terminalKind\r\n const delta = choice.delta\r\n if (!delta) continue\r\n\r\n if (typeof delta.reasoning_content === 'string' && delta.reasoning_content) {\r\n for (const segment of thinkingParser.pushReasoning(delta.reasoning_content)) {\r\n for (const chunk of appendSegment(segment)) yield chunk\r\n }\r\n }\r\n if (typeof delta.content === 'string' && delta.content) {\r\n for (const segment of thinkingParser.pushContent(delta.content)) {\r\n for (const chunk of appendSegment(segment)) yield chunk\r\n }\r\n }\r\n\r\n if (delta.tool_calls !== undefined) {\r\n if (!Array.isArray(delta.tool_calls)) throw malformed('Qoder tool-call delta is not an array.')\r\n for (const rawCall of delta.tool_calls) {\r\n if (typeof rawCall !== 'object' || rawCall === null || Array.isArray(rawCall)) {\r\n throw malformed('Qoder tool-call delta is not an object.')\r\n }\r\n const upstreamIndex = rawCall.index ?? 0\r\n if (!Number.isInteger(upstreamIndex) || upstreamIndex < 0) {\r\n throw malformed('Qoder tool-call delta has an invalid index.')\r\n }\r\n let state = toolCalls.get(upstreamIndex)\r\n if (state === undefined) {\r\n state = { id: '', name: '', arguments: '', emittedArguments: 0 }\r\n toolCalls.set(upstreamIndex, state)\r\n }\r\n if (rawCall.id !== undefined) {\r\n if (rawCall.id === '' || rawCall.id === null) {\r\n // Upstream models and gateways often emit empty or null IDs in parameter deltas.\r\n // Tolerate and ignore when an ID is already established, or wait for later chunks.\r\n } else if (typeof rawCall.id !== 'string') {\r\n throw malformed('Qoder tool call has an invalid id.')\r\n } else {\r\n if (state.id && state.id !== rawCall.id) throw malformed('Qoder changed a streamed tool-call id.')\r\n state.id = rawCall.id\r\n }\r\n }\r\n let hasNewName = false\r\n if (rawCall.function?.name !== undefined) {\r\n const name = rawCall.function.name\r\n if (name === '' || name === null) {\r\n // Upstream models and gateways often emit empty or null names in parameter deltas.\r\n // Tolerate and ignore when a name is already established, or wait for later chunks.\r\n } else if (typeof name !== 'string') {\r\n throw malformed('Qoder tool call has an invalid name.')\r\n } else {\r\n if (state.name && state.name !== name) throw malformed('Qoder changed a streamed tool-call name.')\r\n if (state.name !== name) {\r\n state.name = name\r\n hasNewName = true\r\n }\r\n }\r\n }\r\n if (rawCall.function?.arguments !== undefined) {\r\n if (typeof rawCall.function.arguments !== 'string') {\r\n throw malformed('Qoder tool-call arguments delta is not a string.')\r\n }\r\n state.arguments += rawCall.function.arguments\r\n }\r\n\r\n const wasOpen = state.blockIndex !== undefined\r\n for (const chunk of openToolCall(state)) yield chunk\r\n if (wasOpen && state.blockIndex !== undefined && state.emittedArguments < state.arguments.length) {\r\n const argumentsDelta = state.arguments.slice(state.emittedArguments)\r\n state.emittedArguments = state.arguments.length\r\n yield {\r\n type: 'tool-call-delta',\r\n index: state.blockIndex,\r\n id: ToolCallId(state.id),\r\n ...state.name ? { name: state.name } : {},\r\n argumentsDelta,\r\n }\r\n } else if (wasOpen && state.blockIndex !== undefined && hasNewName) {\r\n yield {\r\n type: 'tool-call-delta',\r\n index: state.blockIndex,\r\n id: ToolCallId(state.id),\r\n name: state.name,\r\n argumentsDelta: '',\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n } finally {\r\n await reader.cancel().catch(() => undefined)\r\n reader.releaseLock()\r\n }\r\n\r\n if (!sawDone) throw new QoderLlmError('SSE stream ended prematurely without [DONE].', 'TRANSPORT')\r\n\r\n for (const segment of thinkingParser.finish()) {\r\n for (const chunk of appendSegment(segment)) yield chunk\r\n }\r\n for (const chunk of closeTextual()) yield chunk\r\n\r\n for (const [, state] of [...toolCalls.entries()].sort(([left], [right]) => left - right)) {\r\n if (!state.id || !state.name) throw malformed('Qoder completed an unidentifiable tool call.')\r\n const normalizedArguments = state.arguments.trim() ? state.arguments : '{}'\r\n try {\r\n JSON.parse(normalizedArguments)\r\n } catch {\r\n throw malformed(`Qoder completed tool call \"${state.name}\" with malformed JSON arguments.`)\r\n }\r\n for (const chunk of openToolCall(state)) yield chunk\r\n if (state.blockIndex === undefined) throw malformed('Qoder failed to open a completed tool call.')\r\n if (state.emittedArguments === 0 && normalizedArguments === '{}') {\r\n yield {\r\n type: 'tool-call-delta',\r\n index: state.blockIndex,\r\n id: ToolCallId(state.id),\r\n name: state.name,\r\n argumentsDelta: '{}',\r\n }\r\n }\r\n yield {\r\n type: 'block-end',\r\n index: state.blockIndex,\r\n block: {\r\n type: 'tool-call',\r\n id: ToolCallId(state.id),\r\n name: state.name,\r\n arguments: normalizedArguments,\r\n },\r\n }\r\n }\r\n\r\n if (pendingUsage) yield { type: 'usage', usage: pendingUsage }\r\n if (!sawContent) {\r\n yield {\r\n type: 'finish',\r\n reason: {\r\n kind: 'error',\r\n failure: { message: 'Model returned a completed response with no content.', code: EMPTY_RESPONSE_CODE },\r\n },\r\n }\r\n return\r\n }\r\n yield { type: 'finish', reason: { kind: toolCalls.size > 0 ? 'tool-calls' : terminalKind } }\r\n}\r\n", "/** Split Qoder wire content into visible text and reasoning while removing tag artifacts. */\n\nexport interface QoderContentSegment {\n type: 'text' | 'reasoning'\n text: string\n}\n\nconst thinkingTags = [\n { open: '<thinking>', close: '</thinking>' },\n { open: '<think>', close: '</think>' },\n] as const\n\nconst allTags = thinkingTags.flatMap(tag => [tag.open, tag.close])\n\nfunction trailingPrefixLength(text: string, candidates: readonly string[]): number {\n let best = 0\n for (const candidate of candidates) {\n const limit = Math.min(text.length, candidate.length - 1)\n for (let length = limit; length > best; length--) {\n if (text.endsWith(candidate.slice(0, length))) {\n best = length\n break\n }\n }\n }\n return best\n}\n\nfunction earliestTag(\n text: string,\n kind: 'open' | 'close',\n): { position: number; tag: (typeof thinkingTags)[number] } | undefined {\n let found: { position: number; tag: (typeof thinkingTags)[number] } | undefined\n for (const tag of thinkingTags) {\n const position = text.indexOf(tag[kind])\n if (position !== -1 && (found === undefined || position < found.position)) found = { position, tag }\n }\n return found\n}\n\nfunction trimSeparator(text: string): string {\n if (text.startsWith('\\n\\n')) return text.slice(2)\n if (text.startsWith('\\n')) return text.slice(1)\n return text\n}\n\nclass NativeReasoningStripper {\n private buffer = ''\n\n push(chunk: string): string {\n this.buffer += chunk\n let output = ''\n while (this.buffer) {\n let firstPosition = -1\n let firstTag = ''\n for (const tag of allTags) {\n const position = this.buffer.indexOf(tag)\n if (position !== -1 && (firstPosition === -1 || position < firstPosition)) {\n firstPosition = position\n firstTag = tag\n }\n }\n if (firstPosition !== -1) {\n output += this.buffer.slice(0, firstPosition)\n this.buffer = this.buffer.slice(firstPosition + firstTag.length)\n continue\n }\n const held = trailingPrefixLength(this.buffer, allTags)\n output += this.buffer.slice(0, this.buffer.length - held)\n this.buffer = this.buffer.slice(this.buffer.length - held)\n break\n }\n return output\n }\n\n finish(): string {\n const output = allTags.some(tag => tag.startsWith(this.buffer)) ? '' : this.buffer\n this.buffer = ''\n return output\n }\n}\n\nexport class QoderThinkingParser {\n private buffer = ''\n private mode: 'text' | 'reasoning' = 'text'\n private closingTag: string = thinkingTags[0].close\n private readonly native = new NativeReasoningStripper()\n\n pushReasoning(chunk: string): QoderContentSegment[] {\n const text = this.native.push(chunk)\n return text ? [{ type: 'reasoning', text }] : []\n }\n\n pushContent(chunk: string): QoderContentSegment[] {\n const output: QoderContentSegment[] = []\n const pendingReasoning = this.native.finish()\n if (pendingReasoning) output.push({ type: 'reasoning', text: pendingReasoning })\n this.buffer += chunk\n\n while (this.buffer) {\n if (this.mode === 'reasoning') {\n const closeAt = this.buffer.indexOf(this.closingTag)\n if (closeAt !== -1) {\n if (closeAt > 0) output.push({ type: 'reasoning', text: this.buffer.slice(0, closeAt) })\n this.buffer = trimSeparator(this.buffer.slice(closeAt + this.closingTag.length))\n this.mode = 'text'\n continue\n }\n const held = trailingPrefixLength(this.buffer, [this.closingTag])\n const safeLength = this.buffer.length - held\n if (safeLength > 0) output.push({ type: 'reasoning', text: this.buffer.slice(0, safeLength) })\n this.buffer = this.buffer.slice(safeLength)\n break\n }\n\n const opener = earliestTag(this.buffer, 'open')\n const closer = earliestTag(this.buffer, 'close')\n if (opener !== undefined && (closer === undefined || opener.position < closer.position)) {\n if (opener.position > 0) output.push({ type: 'text', text: this.buffer.slice(0, opener.position) })\n this.buffer = this.buffer.slice(opener.position + opener.tag.open.length)\n this.closingTag = opener.tag.close\n this.mode = 'reasoning'\n continue\n }\n if (closer !== undefined) {\n if (closer.position > 0) output.push({ type: 'text', text: this.buffer.slice(0, closer.position) })\n this.buffer = trimSeparator(this.buffer.slice(closer.position + closer.tag.close.length))\n continue\n }\n\n const held = trailingPrefixLength(this.buffer, allTags)\n const safeLength = this.buffer.length - held\n if (safeLength > 0) output.push({ type: 'text', text: this.buffer.slice(0, safeLength) })\n this.buffer = this.buffer.slice(safeLength)\n break\n }\n return output\n }\n\n finish(): QoderContentSegment[] {\n const output: QoderContentSegment[] = []\n const pendingReasoning = this.native.finish()\n if (pendingReasoning) output.push({ type: 'reasoning', text: pendingReasoning })\n if (this.buffer) output.push({ type: this.mode, text: this.buffer })\n this.buffer = ''\n return output\n }\n}\n", "/** The only external seam for communication with Qoder. */\n\nimport type { GenerateOptions, StreamChunk } from '@deepseek-ai/dsh-llm'\nimport type { AttachmentStore } from '@deepseek-ai/dsh-attachment'\nimport type { QoderAccountInfo } from '../account.ts'\nimport type { QoderCatalogModel } from '../catalog.ts'\nimport type { QoderRegion } from '../region.ts'\nimport type { QoderCheckInResult } from './checkin.ts'\nimport { DefaultQoderTransport, defaultStreamIdleTimeoutMs } from './default-transport.ts'\nimport { defaultResponseHeaderTimeoutMs } from './request.ts'\nimport type { QoderLogger } from './logging.ts'\n\nexport { defaultResponseHeaderTimeoutMs, defaultStreamIdleTimeoutMs }\nexport type { QoderCheckInResult }\n\nexport interface QoderTransport {\n stream(options: GenerateOptions, model?: QoderCatalogModel): AsyncIterable<StreamChunk>\n discoverModels(signal?: AbortSignal): Promise<readonly QoderCatalogModel[]>\n readAccount(options?: { force?: boolean | undefined; signal?: AbortSignal | undefined }): Promise<QoderAccountInfo>\n checkIn(signal?: AbortSignal): Promise<QoderCheckInResult>\n}\n\nexport interface QoderTransportOptions {\n region: QoderRegion\n resolvePat: () => Promise<string>\n fetch?: typeof fetch\n logger?: QoderLogger\n streamIdleTimeoutMs?: number\n responseHeaderTimeoutMs?: number\n metadataTimeoutMs?: number\n resolveMachineId?: () => string\n attachments?: Pick<AttachmentStore, 'imageLimits' | 'readImageRequest'>\n /** Deadline for one center image publication attempt. */\n imageUploadTimeoutMs?: number\n /** Lifetime of a remembered center image URL. */\n imageUrlCacheTtlMs?: number\n /** Whether prior assistant reasoning content is preserved across turns. */\n preserveThinking?: boolean\n /**\n * Called once per successful re-auth refresh, right after a fresh job token\n * was exchanged and accepted following a 401 rejection. The plugin host\n * surfaces this as a visible \"token auto-refreshed\" notice on its card.\n */\n onJobTokenRefreshed?: (info: { region: QoderRegion; at: number }) => void\n /**\n * Called once per unresolved self-heal failure: the transport exchanged a\n * fresh job token, retried the chat, and the upstream rejected it anyway.\n *\n * The success notice alone left this case silent \u2014 the user saw only a bare\n * authorization failure with no sign that the plugin had already tried to\n * recover. Reported at most once per outage (reset when a later chat is\n * accepted), so a long rejection storm does not print a row per retry.\n */\n onJobTokenRefreshFailed?: (info: { region: QoderRegion; at: number; status?: number }) => void\n}\n\nexport function createQoderTransport(options: QoderTransportOptions): QoderTransport {\n return new DefaultQoderTransport(options)\n}\n", "import { createHash } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { setTimeout as delay } from 'node:timers/promises';\nimport { withFileLock } from '@deepseek-ai/dsh-atomic-write';\nimport { beijingDay, writePrivateJson } from './config.mjs';\n\nexport const supportsCheckin = provider => ['workbuddy', 'trae', 'qoder', 'qoder-global'].includes(provider);\nconst hash = value => createHash('sha256').update(value).digest('hex');\nconst nextDay = now => Date.parse(`${beijingDay(now)}T00:00:00+08:00`) + 86400000;\nconst evening = now => Date.parse(`${beijingDay(now)}T20:05:00+08:00`);\nconst windowAt = (a, now) => Date.parse(`${beijingDay(now)}T${a.provider.startsWith('qoder') ? '10:05' : '00:00'}:00+08:00`);\nexport function checkinFailure(error, submitted = false) {\n const status = error?.status ?? error?.failure?.status ?? Number(/\\bhttp\\s+(401|403|429)\\b/i.exec(error?.message || '')?.[1]);\n if (status === 401) return { status: 'auth-invalid' };\n if ([403, 429].includes(status)) return { status: 'paused' };\n if (/no valid refresh token is available|no refresh token is stored/.test(error?.message || '')) return { status: 'auth-invalid' };\n return { status: submitted ? 'uncertain' : 'retryable' };\n}\nconst canRetry = (record, now) => ['retryable', 'before-window'].includes(record.status)\n && record.retryAt <= now && (record.attempts || 1) < 2;\nexport const checkinMessages = {\n claimed: '\u7B7E\u5230\u6210\u529F', 'already-claimed': '\u4ECA\u65E5\u5DF2\u9886\u53D6', 'device-used': '\u6B64\u8BBE\u5907\u4ECA\u65E5\u5DF2\u53C2\u4E0E\u7B7E\u5230\uFF0C\u4E0D\u518D\u5207\u6362\u5176\u4ED6\u8D26\u53F7\u9886\u53D6',\n 'no-campaign': '\u5E73\u53F0\u672A\u5F00\u653E\u53EF\u9886\u53D6\u6D3B\u52A8', 'before-window': '\u7B7E\u5230\u7A97\u53E3\u5C1A\u672A\u5F00\u542F',\n paused: '\u5E73\u53F0\u9650\u5236\u6216\u9700\u8981\u9A8C\u8BC1\uFF0C\u5DF2\u6682\u505C\u6B64\u5E73\u53F0\u7B7E\u5230\uFF0C\u8BF7\u5728\u5B98\u65B9\u5BA2\u6237\u7AEF\u5904\u7406',\n uncertain: '\u8BF7\u6C42\u7ED3\u679C\u5F85\u786E\u8BA4\uFF0C\u4ECA\u65E5\u4E0D\u518D\u81EA\u52A8\u63D0\u4EA4\uFF0C\u8BF7\u5728\u5B98\u65B9\u5BA2\u6237\u7AEF\u6838\u5BF9',\n 'auth-invalid': '\u4EE4\u724C\u5931\u6548\uFF0C\u8BF7\u5230\u8D26\u53F7\u4E0E\u767B\u5F55\u66F4\u65B0\u51ED\u8BC1',\n retryable: '\u67E5\u8BE2\u5931\u8D25\uFF0C\u9886\u53D6\u5C1A\u672A\u63D0\u4EA4',\n error: '\u7B7E\u5230\u672A\u5B8C\u6210\uFF0C\u4ECA\u65E5\u4E0D\u518D\u91CD\u590D\u5C1D\u8BD5\uFF0C\u8BF7\u5728\u5B98\u65B9\u5BA2\u6237\u7AEF\u67E5\u770B',\n unsupported: '\u6682\u672A\u63A5\u5165\u53EF\u6838\u9A8C\u7684\u7B7E\u5230\u63A5\u53E3\uFF0C\u8BF7\u4F7F\u7528\u5B98\u65B9\u5BA2\u6237\u7AEF',\n};\n\n// One shared journal protects daily intent across processes, restarts and duplicate account copies.\n// A persisted intent precedes every request: a timeout/crash must never cause another claim.\nexport class Checkins {\n constructor(file, manager, { now = Date.now, spacingMs = 10000 } = {}) {\n this.file = file; this.manager = manager; this.now = now; this.spacingMs = spacingMs;\n this.data = { records: {}, devices: {}, pauses: {} }; this.abort = new AbortController();\n }\n async read() {\n try {\n const raw = JSON.parse(await readFile(this.file, 'utf8'));\n const object = value => value && typeof value === 'object' && !Array.isArray(value);\n if (!object(raw) || !['records', 'devices', 'pauses'].every(k => object(raw[k]))\n || Object.values(raw.records).some(r => !object(r) || !Array.isArray(r.ids) || !Number.isFinite(r.at) || typeof r.day !== 'string')) throw Error('Invalid check-in journal');\n this.data = raw;\n } catch (e) { if (e.code !== 'ENOENT') throw e; }\n }\n async load() {\n try { await this.read(); } catch { this.failed = true; }\n }\n get settings() { return this.manager.config.checkinSchedule ?? { mode: 'scheduled', time: '10:05' }; }\n last(account) { return Object.values(this.data.records).filter(r => r.ids?.includes(account.id)).sort((a, b) => b.at - a.at)[0]; }\n ready(account, now = this.now()) {\n const last = this.last(account);\n return account.enabled !== false && supportsCheckin(account.provider) && !this.data.pauses[account.provider]\n && last?.status !== 'auth-invalid' && now >= windowAt(account, now)\n && (last?.day !== beijingDay(now) || canRetry(last, now));\n }\n dueAt(account, now = this.now()) {\n const scheduled = this.settings.mode === 'startup' ? '00:00' : this.settings.time;\n return Math.max(windowAt(account, now), Date.parse(`${beijingDay(now)}T${scheduled}:00+08:00`));\n }\n tick() {\n if (this.failed || this.flight || this.abort.signal.aborted) return;\n const now = this.now();\n // Poll only local state. Completed accounts never enter the I/O or upstream queue again that day.\n const ids = this.manager.config.accounts.filter(a => a.autoCheckin === true && this.ready(a, now) && now >= this.dueAt(a, now)).map(a => a.id);\n if (ids.length) this.start(ids, true);\n }\n state() {\n return { running: !!this.flight, current: this.current, error: this.failed ? '\u7B7E\u5230\u8BB0\u5F55\u65E0\u6CD5\u8BFB\u53D6\uFF0C\u5DF2\u505C\u6B62\u7B7E\u5230\uFF1B\u8BF7\u4FEE\u590D\u8BB0\u5F55\u6587\u4EF6\u540E\u91CD\u542F\u63D2\u4EF6\u3002' : undefined,\n settings: this.settings,\n schedule: `${this.settings.mode === 'startup' ? '\u6BCF\u65E5\u9996\u6B21\u542F\u52A8\u65F6\u7B7E\u5230\uFF0C\u6301\u7EED\u8FD0\u884C\u5219\u65B0\u4E00\u5929\u81EA\u52A8\u6267\u884C' : `\u5317\u4EAC\u65F6\u95F4\u6BCF\u5929 ${this.settings.time} \u5B9A\u65F6\u7B7E\u5230\uFF0C\u9519\u8FC7\u65F6\u542F\u52A8\u8865\u67E5`}\uFF1B20:05 \u4EC5\u8865\u67E5\u672A\u63D0\u4EA4\u9886\u53D6\u7684\u5931\u8D25`,\n report: this.data.report,\n accounts: this.manager.config.accounts.map(a => {\n const last = this.last(a);\n const pause = this.data.pauses[a.provider];\n return { id: a.id, supported: supportsCheckin(a.provider), auto: a.autoCheckin === true,\n ready: this.ready(a), scheduledAt: this.dueAt(a),\n paused: !!pause, last: last ? { day: last.day, at: last.at, status: last.status, amount: last.amount, activity: last.activity, retryAt: last.retryAt,\n retryReady: canRetry(last, this.now()),\n message: checkinMessages[last.status] || checkinMessages.error } : undefined };\n }) };\n }\n start(ids, automatic = false) {\n if (this.failed || this.abort.signal.aborted || this.flight) return;\n if (!automatic && (!Array.isArray(ids) || !ids.length || ids.length > 200 || ids.some(id => !this.manager.config.accounts.some(a => a.id === id)))) throw Error('\u8BF7\u9009\u62E9\u6709\u6548\u7684\u7B7E\u5230\u8D26\u53F7');\n const selected = this.manager.config.accounts.filter(a => supportsCheckin(a.provider) && a.enabled !== false\n && (automatic ? a.autoCheckin === true && (!ids || ids.includes(a.id)) : ids.includes(a.id)) && this.ready(a)\n && (!automatic || this.now() >= this.dueAt(a))).map(a => a.id);\n if (!selected.length) return;\n this.flight = (async () => {\n let requested = false;\n const counts = {};\n for (const id of selected) {\n if (this.abort.signal.aborted) break;\n const account = this.manager.config.accounts.find(a => a.id === id && a.enabled !== false && (!automatic || a.autoCheckin === true));\n if (!account) continue;\n if (requested) { await delay(this.spacingMs, undefined, { signal: this.abort.signal }); requested = false; }\n this.current = id;\n requested = await this.run(account, automatic);\n if (requested) {\n const last = this.state().accounts.find(a => a.id === id)?.last;\n if (last) counts[last.status] = (counts[last.status] || 0) + 1;\n }\n }\n // No work means no new report, including the evening pass when everyone is done.\n if (Object.keys(counts).length) await withFileLock(this.file, async () => {\n await this.read(); this.data.report = { at: this.now(), counts }; await writePrivateJson(this.file, this.data);\n });\n })().catch(() => { if (!this.abort.signal.aborted) this.failed = true; }).finally(() => { this.flight = undefined; this.current = undefined; });\n }\n async resume(provider) {\n if (!supportsCheckin(provider) || this.failed || this.flight) throw Error('\u8BF7\u7B49\u5F85\u7B7E\u5230\u5B8C\u6210\uFF0C\u6216\u5148\u4FEE\u590D\u7B7E\u5230\u8BB0\u5F55');\n await withFileLock(this.file, async () => {\n await this.read(); delete this.data.pauses[provider]; await writePrivateJson(this.file, this.data);\n });\n // Today's intent/device fences remain intact; resuming cannot bypass a daily limit.\n }\n async credentialsUpdated(id) {\n // An explicit credential replacement may recover authentication, never a submitted/uncertain claim.\n await withFileLock(this.file, async () => {\n await this.read();\n for (const [key, row] of Object.entries(this.data.records)) if (row.status === 'auth-invalid' && row.ids.includes(id)) delete this.data.records[key];\n await writePrivateJson(this.file, this.data);\n }, { waitMs: 30000 });\n }\n async run(account, automatic = false) {\n const now = this.now(), day = beijingDay(now);\n if (now < windowAt(account, now) || automatic && now < this.dueAt(account, now)) return false;\n return withFileLock(this.file, async () => {\n await this.read();\n if (this.abort.signal.aborted || this.data.pauses[account.provider]) return false;\n if (this.last(account)?.status === 'auth-invalid') return false;\n const previousEntry = Object.entries(this.data.records).find(([, r]) => r.day === day && r.ids?.includes(account.id));\n const previous = previousEntry?.[1];\n if (previous && !canRetry(previous, now)) return false;\n if (this.data.lastRequestAt && now - this.data.lastRequestAt < this.spacingMs) return false;\n this.data.lastRequestAt = now;\n await writePrivateJson(this.file, this.data);\n const pendingKey = hash(`${account.provider}:local:${account.id}`);\n const pending = { day, at: now, status: 'retryable', ids: previous?.ids || [account.id], attempts: (previous?.attempts || (previous ? 1 : 0)) + 1,\n ...(now < evening(now) ? { retryAt: evening(now) } : {}) };\n if (previousEntry) delete this.data.records[previousEntry[0]];\n this.data.records[pendingKey] = pending;\n await writePrivateJson(this.file, this.data);\n let identity, client;\n try {\n client = await this.manager.router.client(account);\n if (!client.checkin) throw Error('Unsupported check-in');\n identity = await client.checkin.identity(AbortSignal.any([this.abort.signal, AbortSignal.timeout(30000)]));\n if (!identity?.account || (account.provider === 'trae' && !identity.device)) throw Error('Missing check-in identity');\n } catch (error) {\n pending.status = checkinFailure(error).status;\n if (pending.status !== 'retryable') delete pending.retryAt;\n if (pending.status === 'paused') this.data.pauses[account.provider] = { at: now };\n await writePrivateJson(this.file, this.data); return true;\n }\n if (this.abort.signal.aborted || !this.manager.config.accounts.some(a => a.id === account.id && a.enabled !== false\n && a.credentialFile === account.credentialFile && (!automatic || a.autoCheckin === true))) return true;\n const key = hash(`${account.provider}:${identity.account}`), device = identity.device ? hash(`${account.provider}:${identity.device}`) : undefined;\n const old = this.data.records[key];\n delete this.data.records[pendingKey];\n if (old?.day === day && !canRetry(old, now)) {\n if (!old.ids.includes(account.id)) { old.ids.push(account.id); await writePrivateJson(this.file, this.data); }\n else await writePrivateJson(this.file, this.data);\n return false;\n }\n const record = { ...pending, status: 'uncertain', ids: [...new Set([...pending.ids, ...(old?.ids || []), account.id])],\n attempts: Math.max(pending.attempts, old?.day === day ? (old.attempts || 1) + 1 : 1) };\n this.data.records[key] = record;\n // Expired journals are not a retry queue; keep only the last 30 days.\n for (const [k, row] of Object.entries(this.data.records)) if (row.at < now - 30 * 86400000) delete this.data.records[k];\n for (const [k, row] of Object.entries(this.data.devices)) if (row.until <= now) delete this.data.devices[k];\n if (device && this.data.devices[device]?.until > now) {\n record.status = 'device-used'; await writePrivateJson(this.file, this.data); return true;\n }\n // An ambiguous response also keeps the device fenced for the day.\n if (device) this.data.devices[device] = { until: nextDay(now) };\n await writePrivateJson(this.file, this.data);\n let result;\n try { result = await client.checkin.claim(AbortSignal.any([this.abort.signal, AbortSignal.timeout(30000)])); }\n catch { result = { status: 'uncertain' }; }\n record.status = Object.hasOwn(checkinMessages, result?.status) ? result.status : 'uncertain';\n if (device && ['already-claimed', 'no-campaign', 'retryable', 'before-window', 'auth-invalid'].includes(record.status)) delete this.data.devices[device];\n if (record.attempts >= 2 || !['retryable', 'before-window'].includes(record.status)) delete record.retryAt;\n if (['claimed', 'already-claimed'].includes(record.status) && Number.isFinite(result.amount) && result.amount >= 0) record.amount = result.amount;\n if (result?.activity) record.activity = Object.fromEntries(['streakDays', 'totalCredits', 'nextStreakDay', 'endsAt'].filter(k => Number.isFinite(result.activity[k]) && result.activity[k] >= 0).map(k => [k, result.activity[k]]));\n if (record.status === 'paused' || result?.paused === true) this.data.pauses[account.provider] = { at: now };\n await writePrivateJson(this.file, this.data);\n if (record.status === 'claimed') await this.manager.monitorAccount(account);\n return true;\n }, { waitMs: 1000 });\n }\n}\n", "// Inspect only the prelude. Once text, reasoning or a tool call exists, never replay.\nexport async function preflightStream(response, signal) {\n if (!response.body) return { ok: false, status: 502, kind: 'empty_stream' };\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n const buffered = [];\n let pending = '', size = 0;\n const abort = () => { void reader.cancel().catch(() => {}); };\n signal?.addEventListener('abort', abort, { once: true });\n const clean = () => signal?.removeEventListener('abort', abort);\n try {\n while (true) {\n signal?.throwIfAborted();\n const { value, done } = await reader.read();\n signal?.throwIfAborted();\n if (done) { clean(); return { ok: false, status: 502, kind: 'stream_ended_before_answer' }; }\n buffered.push(value); size += value.byteLength;\n pending += decoder.decode(value, { stream: true });\n let boundary;\n while ((boundary = /\\r?\\n\\r?\\n/.exec(pending))) {\n const frame = pending.slice(0, boundary.index);\n pending = pending.slice(boundary.index + boundary[0].length);\n const data = frame.split(/\\r?\\n/).filter(l => l.startsWith('data:')).map(l => l.slice(5).trimStart()).join('\\n');\n if (!data) continue;\n let payload;\n if (data === '[DONE]') return accepted();\n try { payload = JSON.parse(data); } catch { await reader.cancel(); clean(); return { ok: false, status: 502, kind: 'invalid_sse' }; }\n if (payload.error || /^event:\\s*error$/m.test(frame)) {\n const error = payload.error ?? payload;\n const status = Number(error.status ?? error.status_code ?? error.code);\n const kind = error.type ?? error.code;\n const mapped = ['soft_rate', 'RATE_LIMIT', 'rate_limit', 'rate_limit_exceeded'].includes(kind) ? 429\n : ['hard_credit', 'QUOTA', 'quota_exhausted'].includes(kind) ? 402\n : ['session_dead', 'authentication', 'AUTH', 'missing_credential'].includes(kind) ? 401 : 502;\n await reader.cancel(); clean();\n return { ok: false, status: status >= 400 && status <= 599 ? status : mapped, kind: 'early_stream_error' };\n }\n if (payload.choices?.some(choice => choice.finish_reason || choice.delta?.content || choice.delta?.reasoning_content || choice.delta?.tool_calls?.length || choice.delta?.function_call)) return accepted();\n }\n // A huge prelude is malformed; do not treat a partial JSON frame as an answer.\n if (size > 128 * 1024) { await reader.cancel(); clean(); return { ok: false, status: 502, kind: 'stream_prelude_too_large' }; }\n }\n } catch (error) { await reader.cancel().catch(() => {}); clean(); throw error; }\n function accepted() {\n let index = 0;\n const stream = new ReadableStream({\n async pull(controller) {\n try {\n signal?.throwIfAborted();\n if (index < buffered.length) { controller.enqueue(buffered[index++]); return; }\n const chunk = await reader.read();\n signal?.throwIfAborted();\n if (chunk.done) { clean(); controller.close(); } else controller.enqueue(chunk.value);\n } catch (error) { clean(); controller.error(error); await reader.cancel().catch(() => {}); }\n },\n async cancel(reason) { clean(); await reader.cancel(reason); },\n });\n return { ok: true, response: new Response(stream, { status: response.status, headers: response.headers }) };\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["readFile", "delay", "record", "record", "finitePositive", "randomUUID", "record", "record", "randomUUID", "randomBytes", "LlmError", "ToolCallId", "retryAfterMs", "delayMs", "LlmError", "readFileSync", "dirname", "join", "join", "readFileSync", "dirname", "crypto", "crypto", "abortedError", "crypto", "hash", "crypto", "crypto", "crypto", "hash", "asNumber", "table", "held", "safeLength", "aborted", "tokenUsage", "failure", "aborted", "LlmError", "ToolCallId", "randomBytes", "LlmError", "createHash", "createHash", "record", "readFile", "delay"]
|
|
7
|
-
}
|