@eddyskywalker/dsh-chatgpt-subscription 0.19.1 → 0.21.0

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/lib/client.js +291 -20
  3. package/lib/client.js.map +1 -1
  4. package/lib/index.js +585 -177
  5. package/lib/types/client/minimax-code/MinimaxCodeSection.d.ts.map +1 -1
  6. package/lib/types/client/minimax-code/api.d.ts +30 -0
  7. package/lib/types/client/minimax-code/api.d.ts.map +1 -1
  8. package/lib/types/client/minimax-code/locales.d.ts +62 -2
  9. package/lib/types/client/minimax-code/locales.d.ts.map +1 -1
  10. package/lib/types/client/minimax-code/styles.d.ts.map +1 -1
  11. package/lib/types/client/minimax-code/useMinimaxCodeSection.d.ts +50 -1
  12. package/lib/types/client/minimax-code/useMinimaxCodeSection.d.ts.map +1 -1
  13. package/lib/types/client/ollama/OllamaSection.d.ts.map +1 -1
  14. package/lib/types/client/ollama/api.d.ts +2 -2
  15. package/lib/types/client/ollama/api.d.ts.map +1 -1
  16. package/lib/types/host/antigravity/adapter.d.ts.map +1 -1
  17. package/lib/types/host/claude/adapter.d.ts.map +1 -1
  18. package/lib/types/host/command-code/adapter.d.ts.map +1 -1
  19. package/lib/types/host/common/idle-watchdog.d.ts +13 -1
  20. package/lib/types/host/common/idle-watchdog.d.ts.map +1 -1
  21. package/lib/types/host/glm-coding-plan/adapter.d.ts.map +1 -1
  22. package/lib/types/host/kimi-code/adapter.d.ts.map +1 -1
  23. package/lib/types/host/minimax-code/adapter.d.ts.map +1 -1
  24. package/lib/types/host/minimax-code/reset-card.d.ts +136 -0
  25. package/lib/types/host/minimax-code/reset-card.d.ts.map +1 -0
  26. package/lib/types/host/minimax-code/routes.d.ts.map +1 -1
  27. package/lib/types/host/ollama/adapter.d.ts.map +1 -1
  28. package/lib/types/host/ollama/client.d.ts +8 -1
  29. package/lib/types/host/ollama/client.d.ts.map +1 -1
  30. package/lib/types/host/ollama/routes.d.ts.map +1 -1
  31. package/lib/types/host/ollama/token-store.d.ts +8 -3
  32. package/lib/types/host/ollama/token-store.d.ts.map +1 -1
  33. package/lib/types/host/responses-client.d.ts +11 -1
  34. package/lib/types/host/responses-client.d.ts.map +1 -1
  35. package/lib/types/host/workbuddy/adapter.d.ts.map +1 -1
  36. package/lib/types/index.d.ts +8 -0
  37. package/lib/types/index.d.ts.map +1 -1
  38. package/lib/types/shared/minimax-code-contracts.d.ts +35 -0
  39. package/lib/types/shared/minimax-code-contracts.d.ts.map +1 -1
  40. package/lib/types/shared/ollama-contracts.d.ts +8 -1
  41. package/lib/types/shared/ollama-contracts.d.ts.map +1 -1
  42. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -13,11 +13,11 @@ import http, { createServer } from "node:http";
13
13
  import { WebError } from "@deepseek-ai/dsh-web";
14
14
  import { lookup } from "node:dns/promises";
15
15
  import { isIP } from "node:net";
16
+ import { MAX_TIMER_DELAY_MS, idleWatchdog, timeoutOf } from "@deepseek-ai/dsh-timeout";
16
17
  import { boundContextSummary, createUserMessage } from "@deepseek-ai/dsh-llm/message";
17
18
  import { defineTool } from "@deepseek-ai/dsh-tools";
18
19
  import { ProxyAgent, fetch as fetch$1 } from "undici";
19
20
  import * as SettingsModule from "@deepseek-ai/dsh-settings";
20
- import { idleWatchdog, timeoutOf } from "@deepseek-ai/dsh-timeout";
21
21
  import { URL as URL$1, URLSearchParams as URLSearchParams$1, fileURLToPath } from "node:url";
22
22
  //#region src/host/common/output-reservation.ts
23
23
  /**
@@ -786,7 +786,7 @@ async function rehydrateSnapshot(key) {
786
786
  * so a backend that flattens the envelope does not read as an empty catalog.
787
787
  */
788
788
  function parseListing(payload) {
789
- const record = asRecord$13(payload);
789
+ const record = asRecord$14(payload);
790
790
  const models = Array.isArray(payload) ? payload : record?.models;
791
791
  if (!Array.isArray(models)) return [];
792
792
  return models.flatMap((item) => parseListingEntry$1(item));
@@ -800,7 +800,7 @@ function parseListing(payload) {
800
800
  * back to a conservative answer rather than to a guess.
801
801
  */
802
802
  function parseListingEntry$1(value) {
803
- const record = asRecord$13(value);
803
+ const record = asRecord$14(value);
804
804
  if (record === void 0) return [];
805
805
  const id = asString$23(record.slug) ?? asString$23(record.id);
806
806
  if (id === void 0) return [];
@@ -836,7 +836,7 @@ function parseEfforts(value) {
836
836
  if (!Array.isArray(value)) return null;
837
837
  const out = [];
838
838
  for (const item of value) {
839
- const effort = asString$23(item) ?? asString$23(asRecord$13(item)?.effort);
839
+ const effort = asString$23(item) ?? asString$23(asRecord$14(item)?.effort);
840
840
  if (effort !== void 0 && !out.includes(effort)) out.push(effort);
841
841
  }
842
842
  return out.length > 0 ? out : null;
@@ -851,7 +851,7 @@ function parseEfforts(value) {
851
851
  function accountKeyFor$1(credentials) {
852
852
  return credentials.accountId || "default";
853
853
  }
854
- function asRecord$13(value) {
854
+ function asRecord$14(value) {
855
855
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
856
856
  }
857
857
  function asString$23(value) {
@@ -3915,6 +3915,53 @@ function createCodexFetchProvider(options = {}) {
3915
3915
  };
3916
3916
  }
3917
3917
  //#endregion
3918
+ //#region src/host/common/idle-watchdog.ts
3919
+ const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 3e5;
3920
+ const STREAM_IDLE_TIMEOUT_CODE$7 = "LLM_STREAM_IDLE_TIMEOUT";
3921
+ /**
3922
+ * The same budget under the name every provider adapter passes it by.
3923
+ *
3924
+ * Six provider `types.ts` files each declared their own
3925
+ * `STREAM_IDLE_TIMEOUT_MS = 300_000`, so one line ended up importing a sibling
3926
+ * line's copy just to name the same number. This alias is the single home: the
3927
+ * value is unchanged, and an adapter that took the constant from another line
3928
+ * can now take it from here without renaming its local usage.
3929
+ */
3930
+ const STREAM_IDLE_TIMEOUT_MS$7 = DEFAULT_STREAM_IDLE_TIMEOUT_MS;
3931
+ /**
3932
+ * 为异步流包裹可复位的空闲超时看门狗。
3933
+ * 当流式 chunk 产出之间的间隔超过指定阈值时,主动终止并抛出带有 TIMEOUT 的 LlmError。
3934
+ */
3935
+ async function* wrapStreamWithWatchdog(source, upstreamSignal, timeoutMs = DEFAULT_STREAM_IDLE_TIMEOUT_MS, timeoutCode = STREAM_IDLE_TIMEOUT_CODE$7, providerTag = "llm") {
3936
+ const consumer = new AbortController();
3937
+ const watchdog = idleWatchdog(upstreamSignal === void 0 ? consumer.signal : AbortSignal.any([upstreamSignal, consumer.signal]), timeoutMs, timeoutCode);
3938
+ const iterator = source(watchdog.signal, { pulse: () => {
3939
+ watchdog.pulse();
3940
+ } })[Symbol.asyncIterator]();
3941
+ let exhausted = false;
3942
+ try {
3943
+ while (true) {
3944
+ const result = await watchdog.next(iterator);
3945
+ if (timeoutOf(watchdog.signal, timeoutCode) !== void 0) throw new LlmError(`${providerTag} stream idle timeout after ${timeoutMs}ms`, "TIMEOUT");
3946
+ if (result.done) {
3947
+ exhausted = true;
3948
+ return;
3949
+ }
3950
+ yield result.value;
3951
+ }
3952
+ } catch (error) {
3953
+ if (timeoutOf(watchdog.signal, timeoutCode) !== void 0) throw new LlmError(`${providerTag} stream idle timeout after ${timeoutMs}ms`, "TIMEOUT", { cause: error });
3954
+ if (upstreamSignal?.aborted) throw new LlmError(`${providerTag} request aborted by caller`, "ABORTED", { cause: error });
3955
+ throw error;
3956
+ } finally {
3957
+ consumer.abort(`${providerTag} stream consumer stopped`);
3958
+ if (!exhausted) try {
3959
+ await iterator.return?.(void 0);
3960
+ } catch {}
3961
+ watchdog[Symbol.dispose]();
3962
+ }
3963
+ }
3964
+ //#endregion
3918
3965
  //#region src/host/common/llm-compat.ts
3919
3966
  /** This package's kind in the harness message-source map. */
3920
3967
  const PLUGIN_MESSAGE_SOURCE_KIND = "dsh-chatgpt-subscription";
@@ -5725,51 +5772,6 @@ const toToolCallId = (id) => {
5725
5772
  return (mod.ToolCallId ?? mod.CallId ?? ((x) => x))(id);
5726
5773
  };
5727
5774
  //#endregion
5728
- //#region src/host/common/idle-watchdog.ts
5729
- const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 3e5;
5730
- const STREAM_IDLE_TIMEOUT_CODE$7 = "LLM_STREAM_IDLE_TIMEOUT";
5731
- /**
5732
- * The same budget under the name every provider adapter passes it by.
5733
- *
5734
- * Six provider `types.ts` files each declared their own
5735
- * `STREAM_IDLE_TIMEOUT_MS = 300_000`, so one line ended up importing a sibling
5736
- * line's copy just to name the same number. This alias is the single home: the
5737
- * value is unchanged, and an adapter that took the constant from another line
5738
- * can now take it from here without renaming its local usage.
5739
- */
5740
- const STREAM_IDLE_TIMEOUT_MS$7 = DEFAULT_STREAM_IDLE_TIMEOUT_MS;
5741
- /**
5742
- * 为异步流包裹可复位的空闲超时看门狗。
5743
- * 当流式 chunk 产出之间的间隔超过指定阈值时,主动终止并抛出带有 TIMEOUT 的 LlmError。
5744
- */
5745
- async function* wrapStreamWithWatchdog(source, upstreamSignal, timeoutMs = DEFAULT_STREAM_IDLE_TIMEOUT_MS, timeoutCode = STREAM_IDLE_TIMEOUT_CODE$7, providerTag = "llm") {
5746
- const consumer = new AbortController();
5747
- const watchdog = idleWatchdog(upstreamSignal === void 0 ? consumer.signal : AbortSignal.any([upstreamSignal, consumer.signal]), timeoutMs, timeoutCode);
5748
- const iterator = source(watchdog.signal)[Symbol.asyncIterator]();
5749
- let exhausted = false;
5750
- try {
5751
- while (true) {
5752
- const result = await watchdog.next(iterator);
5753
- if (timeoutOf(watchdog.signal, timeoutCode) !== void 0) throw new LlmError(`${providerTag} stream idle timeout after ${timeoutMs}ms`, "TIMEOUT");
5754
- if (result.done) {
5755
- exhausted = true;
5756
- return;
5757
- }
5758
- yield result.value;
5759
- }
5760
- } catch (error) {
5761
- if (timeoutOf(watchdog.signal, timeoutCode) !== void 0) throw new LlmError(`${providerTag} stream idle timeout after ${timeoutMs}ms`, "TIMEOUT", { cause: error });
5762
- if (upstreamSignal?.aborted) throw new LlmError(`${providerTag} request aborted by caller`, "ABORTED", { cause: error });
5763
- throw error;
5764
- } finally {
5765
- consumer.abort(`${providerTag} stream consumer stopped`);
5766
- if (!exhausted) try {
5767
- await iterator.return?.(void 0);
5768
- } catch {}
5769
- watchdog[Symbol.dispose]();
5770
- }
5771
- }
5772
- //#endregion
5773
5775
  //#region src/host/responses-mapper.ts
5774
5776
  /**
5775
5777
  * Base64 image payload one Codex request may carry.
@@ -6314,6 +6316,7 @@ var ResponsesClient = class {
6314
6316
  fastMode;
6315
6317
  reasoningSummary;
6316
6318
  accountPool;
6319
+ codexStreamIdleTimeoutMs;
6317
6320
  /**
6318
6321
  * Opaque backend routing state, keyed by a unique model-request nonce.
6319
6322
  * The host does not expose a reliable human-turn identity, so this is the
@@ -6341,6 +6344,7 @@ var ResponsesClient = class {
6341
6344
  this.fastMode = options.fastMode ?? (() => false);
6342
6345
  this.reasoningSummary = options.reasoningSummary ?? (() => null);
6343
6346
  this.accountPool = options.accountPool ?? null;
6347
+ this.codexStreamIdleTimeoutMs = options.codexStreamIdleTimeoutMs ?? 3e5;
6344
6348
  }
6345
6349
  localRawImages;
6346
6350
  async *stream(rawOptions) {
@@ -6375,7 +6379,7 @@ var ResponsesClient = class {
6375
6379
  }
6376
6380
  }
6377
6381
  try {
6378
- yield* wrapStreamWithWatchdog((watchdogSignal) => parseResponsesStream(response, watchdogSignal, hiddenSandboxControls), options.signal, 3e5, "LLM_STREAM_IDLE_TIMEOUT", "Codex");
6382
+ yield* wrapStreamWithWatchdog((watchdogSignal, activity) => parseResponsesStream(response, watchdogSignal, hiddenSandboxControls, activity), options.signal, this.codexStreamIdleTimeoutMs, "LLM_STREAM_IDLE_TIMEOUT", "Codex");
6379
6383
  } catch (error) {
6380
6384
  throw streamFailure(error, options.signal);
6381
6385
  } finally {
@@ -6582,7 +6586,7 @@ function perRequestNonce() {
6582
6586
  requestCounter += 1;
6583
6587
  return requestCounter;
6584
6588
  }
6585
- async function* parseResponsesStream(response, signal, hiddenSandboxControls = /* @__PURE__ */ new Set()) {
6589
+ async function* parseResponsesStream(response, signal, hiddenSandboxControls = /* @__PURE__ */ new Set(), activity) {
6586
6590
  if (response.body === null) throw new LlmError("Codex returned no response stream.", "PROVIDER_ERROR");
6587
6591
  const reader = response.body.getReader();
6588
6592
  const abortReader = () => {
@@ -6782,10 +6786,12 @@ async function* parseResponsesStream(response, signal, hiddenSandboxControls = /
6782
6786
  if (signal?.aborted) throw signal.reason ?? new DOMException("Aborted", "AbortError");
6783
6787
  const { done, value } = await reader.read();
6784
6788
  if (done) break;
6789
+ if (value !== void 0 && value.byteLength > 0) activity?.pulse();
6785
6790
  buffer += decoder.decode(value, { stream: true });
6786
6791
  const frames = buffer.split(/\r?\n\r?\n/);
6787
6792
  buffer = frames.pop() ?? "";
6788
6793
  for (const frame of frames) {
6794
+ activity?.pulse();
6789
6795
  const data = frame.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
6790
6796
  if (data === "" || data === "[DONE]") continue;
6791
6797
  let event;
@@ -7487,8 +7493,8 @@ function parseCodexUsage(value) {
7487
7493
  for (const [index, value] of additional.entries()) {
7488
7494
  const limit = record$1(value);
7489
7495
  if (limit === null) continue;
7490
- const idSource = text$1(limit.limit_name) ?? text$1(limit.metered_feature) ?? `additional-${index + 1}`;
7491
- addBucket(buckets, usedIds, uniqueId(slug(idSource), usedIds), readableLimitName(text$1(limit.limit_name) ?? text$1(limit.metered_feature) ?? idSource), planType, limit.rate_limit);
7496
+ const idSource = text$2(limit.limit_name) ?? text$2(limit.metered_feature) ?? `additional-${index + 1}`;
7497
+ addBucket(buckets, usedIds, uniqueId(slug(idSource), usedIds), readableLimitName(text$2(limit.limit_name) ?? text$2(limit.metered_feature) ?? idSource), planType, limit.rate_limit);
7492
7498
  }
7493
7499
  return {
7494
7500
  buckets,
@@ -7573,7 +7579,7 @@ function parseResetCredits(value) {
7573
7579
  availableCreditIds: []
7574
7580
  };
7575
7581
  const available = (Array.isArray(data.credits) ? data.credits : []).map(record$1).filter((credit) => credit !== null && credit.status === "available").map((credit) => ({
7576
- id: text$1(credit.id),
7582
+ id: text$2(credit.id),
7577
7583
  expiresAt: timestamp(credit.expires_at)
7578
7584
  })).filter((credit) => credit.id !== null).sort((left, right) => (left.expiresAt ?? Number.MAX_SAFE_INTEGER) - (right.expiresAt ?? Number.MAX_SAFE_INTEGER));
7579
7585
  const reported = numeric(data.available_count);
@@ -7607,7 +7613,7 @@ function decimalText(value) {
7607
7613
  const trimmed = value.trim();
7608
7614
  return trimmed !== "" ? trimmed : null;
7609
7615
  }
7610
- function text$1(value) {
7616
+ function text$2(value) {
7611
7617
  return typeof value === "string" && value.trim() !== "" ? value.trim() : null;
7612
7618
  }
7613
7619
  function slug(value) {
@@ -11217,12 +11223,12 @@ var AntigravityAdapter = class extends LlmAdapter {
11217
11223
  ...options,
11218
11224
  reasoningEffort: effectiveEffort
11219
11225
  } : options;
11220
- yield* wrapStreamWithWatchdog((watchdogSignal) => this.requestStream({
11226
+ yield* wrapStreamWithWatchdog((watchdogSignal, activity) => this.requestStream({
11221
11227
  ...effectiveOptions,
11222
11228
  maxTokens: options.maxTokens ?? model.maxTokens
11223
- }, model, watchdogSignal), options.signal, STREAM_IDLE_TIMEOUT_MS$6, STREAM_IDLE_TIMEOUT_CODE$6, "Antigravity");
11229
+ }, model, watchdogSignal, activity), options.signal, STREAM_IDLE_TIMEOUT_MS$6, STREAM_IDLE_TIMEOUT_CODE$6, "Antigravity");
11224
11230
  }
11225
- async *requestStream(options, model, signal) {
11231
+ async *requestStream(options, model, signal, activity) {
11226
11232
  const fetchFn = this.options.fetchFn ?? fetch;
11227
11233
  const effort = String(options.reasoningEffort || "medium").toLowerCase();
11228
11234
  const routing = ROUTING[model.id];
@@ -11346,12 +11352,14 @@ var AntigravityAdapter = class extends LlmAdapter {
11346
11352
  while (true) {
11347
11353
  const { done, value } = await reader.read();
11348
11354
  if (done) break;
11355
+ if (value !== void 0 && value.byteLength > 0) activity?.pulse();
11349
11356
  buffer += decoder.decode(value, { stream: true });
11350
11357
  const lines = buffer.split("\n");
11351
11358
  buffer = lines.pop() || "";
11352
11359
  for (const line of lines) {
11353
11360
  const trimmed = line.trim();
11354
11361
  if (!trimmed) continue;
11362
+ activity?.pulse();
11355
11363
  const chunks = processStreamLine$3(trimmed, state);
11356
11364
  for (const chunk of chunks) {
11357
11365
  recordUsageChunk(chunk, statsSessionId, statsAccountId);
@@ -13305,7 +13313,7 @@ function timeoutSignal$3(signal, ms) {
13305
13313
  function isRecord$31(value) {
13306
13314
  return typeof value === "object" && value !== null && !Array.isArray(value);
13307
13315
  }
13308
- function asRecord$12(value) {
13316
+ function asRecord$13(value) {
13309
13317
  return isRecord$31(value) ? value : void 0;
13310
13318
  }
13311
13319
  function asString$21(value) {
@@ -13384,16 +13392,16 @@ const ORG_KEYS = [
13384
13392
  ];
13385
13393
  /** Map `/alpha/whoami` (or a stored key's own facts) onto the public account DTO. */
13386
13394
  function parseWhoami(payload, fallback = {}) {
13387
- const root = asRecord$12(payload) ?? {};
13388
- const data = asRecord$12(root.data) ?? root;
13389
- const user = asRecord$12(deepValue(data, USER_KEYS)) ?? {};
13390
- const org = asRecord$12(deepValue(data, ORG_KEYS)) ?? {};
13391
- const key = asRecord$12(deepValue(data, [
13395
+ const root = asRecord$13(payload) ?? {};
13396
+ const data = asRecord$13(root.data) ?? root;
13397
+ const user = asRecord$13(deepValue(data, USER_KEYS)) ?? {};
13398
+ const org = asRecord$13(deepValue(data, ORG_KEYS)) ?? {};
13399
+ const key = asRecord$13(deepValue(data, [
13392
13400
  "apiKey",
13393
13401
  "key",
13394
13402
  "credential"
13395
13403
  ])) ?? {};
13396
- const subscription = asRecord$12(deepValue(data, [
13404
+ const subscription = asRecord$13(deepValue(data, [
13397
13405
  "subscription",
13398
13406
  "plan",
13399
13407
  "tier"
@@ -13497,14 +13505,14 @@ function humanizeWindowKey$1(key) {
13497
13505
  * — so they are read here first, by name.
13498
13506
  */
13499
13507
  function parseWindowLimits(payload, consumed = []) {
13500
- const root = asRecord$12(payload) ?? {};
13501
- const limits = asRecord$12(deepValue(asRecord$12(root.data) ?? root, ["windowLimits", "window_limits"]));
13508
+ const root = asRecord$13(payload) ?? {};
13509
+ const limits = asRecord$13(deepValue(asRecord$13(root.data) ?? root, ["windowLimits", "window_limits"]));
13502
13510
  if (limits === void 0) return [];
13503
13511
  const keys = [...WINDOW_ORDER$1.filter((key) => limits[key] !== void 0), ...Object.keys(limits).filter((key) => !WINDOW_ORDER$1.includes(key))];
13504
13512
  const meters = [];
13505
13513
  for (const key of keys) {
13506
13514
  if (key === "limited" || key === "exceeded") continue;
13507
- const record = asRecord$12(limits[key]);
13515
+ const record = asRecord$13(limits[key]);
13508
13516
  if (record === void 0) continue;
13509
13517
  const cap = firstNumber$2(record, [
13510
13518
  "cap",
@@ -13538,8 +13546,8 @@ function parseWindowLimits(payload, consumed = []) {
13538
13546
  * source for a remaining balance.
13539
13547
  */
13540
13548
  function parseCreditBalances(payload, consumed = []) {
13541
- const root = asRecord$12(payload) ?? {};
13542
- const credits = asRecord$12(deepValue(asRecord$12(root.data) ?? root, ["credits"]));
13549
+ const root = asRecord$13(payload) ?? {};
13550
+ const credits = asRecord$13(deepValue(asRecord$13(root.data) ?? root, ["credits"]));
13543
13551
  if (credits === void 0) return [];
13544
13552
  const monthly = firstNumber$2(credits, ["monthlyCredits", "monthly_credits"]);
13545
13553
  const purchased = firstNumber$2(credits, ["purchasedCredits", "purchased_credits"]);
@@ -13586,13 +13594,13 @@ function parsePlanId(payloads) {
13586
13594
  * subscription's remaining credits as usable would be worse than showing none.
13587
13595
  */
13588
13596
  function parseSubscriptionStatus(payload) {
13589
- const root = asRecord$12(payload) ?? {};
13590
- return asString$21(deepValue(asRecord$12(root.data) ?? root, ["status"])) ?? null;
13597
+ const root = asRecord$13(payload) ?? {};
13598
+ return asString$21(deepValue(asRecord$13(root.data) ?? root, ["status"])) ?? null;
13591
13599
  }
13592
13600
  /** End of the current billing period, in Unix milliseconds. */
13593
13601
  function parseSubscriptionPeriodEnd(payload) {
13594
- const root = asRecord$12(payload) ?? {};
13595
- return parseTimestamp$1(deepValue(asRecord$12(root.data) ?? root, ["currentPeriodEnd", "current_period_end"]));
13602
+ const root = asRecord$13(payload) ?? {};
13603
+ return parseTimestamp$1(deepValue(asRecord$13(root.data) ?? root, ["currentPeriodEnd", "current_period_end"]));
13596
13604
  }
13597
13605
  /**
13598
13606
  * Turn one billing/usage payload into meters.
@@ -13809,9 +13817,9 @@ function parseUsageWindows$1(payload) {
13809
13817
  return windows;
13810
13818
  }
13811
13819
  function extractCreditsBalance(payload) {
13812
- const root = asRecord$12(payload) ?? {};
13813
- const data = asRecord$12(root.data) ?? root;
13814
- const credits = asRecord$12(data.credits);
13820
+ const root = asRecord$13(payload) ?? {};
13821
+ const data = asRecord$13(root.data) ?? root;
13822
+ const credits = asRecord$13(data.credits);
13815
13823
  if (credits !== void 0) {
13816
13824
  const pools = [
13817
13825
  "monthlyCredits",
@@ -13855,11 +13863,11 @@ let catalogInFlight$3 = null;
13855
13863
  const catalogSnapshotScopesLoaded$2 = /* @__PURE__ */ new Set();
13856
13864
  /** Parse the public `/provider/v1/models` payload. */
13857
13865
  function parseProviderModels(payload) {
13858
- const root = asRecord$12(payload) ?? {};
13866
+ const root = asRecord$13(payload) ?? {};
13859
13867
  const list = Array.isArray(root.data) ? root.data : Array.isArray(payload) ? payload : [];
13860
13868
  const models = [];
13861
13869
  for (const entry of list) {
13862
- const record = asRecord$12(entry);
13870
+ const record = asRecord$13(entry);
13863
13871
  if (!record) continue;
13864
13872
  const id = firstString$1(record, [
13865
13873
  "id",
@@ -16053,9 +16061,9 @@ var CommandCodeAdapter = class extends LlmAdapter {
16053
16061
  ...effectiveOptions,
16054
16062
  reasoningEffort: void 0
16055
16063
  };
16056
- yield* wrapStreamWithWatchdog((watchdogSignal) => this.requestStream(resolvedOptions, watchdogSignal), options.signal, STREAM_IDLE_TIMEOUT_MS$5, STREAM_IDLE_TIMEOUT_CODE$5, PROVIDER_NAME$6);
16064
+ yield* wrapStreamWithWatchdog((watchdogSignal, activity) => this.requestStream(resolvedOptions, watchdogSignal, activity), options.signal, STREAM_IDLE_TIMEOUT_MS$5, STREAM_IDLE_TIMEOUT_CODE$5, PROVIDER_NAME$6);
16057
16065
  }
16058
- async *requestStream(options, signal) {
16066
+ async *requestStream(options, signal, activity) {
16059
16067
  const fetchFn = this.options.fetchFn ?? fetch;
16060
16068
  const catalogEntry = (await this.catalog()).find((entry) => entry.id === options.model);
16061
16069
  const wire = (catalogEntry === void 0 ? void 0 : wireForCatalogEntry$1(catalogEntry)) ?? wireForModel$2(options.model);
@@ -16172,10 +16180,12 @@ var CommandCodeAdapter = class extends LlmAdapter {
16172
16180
  while (true) {
16173
16181
  const { done, value } = await reader.read();
16174
16182
  if (done) break;
16183
+ if (value !== void 0 && value.byteLength > 0) activity?.pulse();
16175
16184
  buffer += decoder.decode(value, { stream: true });
16176
16185
  const lines = buffer.split("\n");
16177
16186
  buffer = lines.pop() ?? "";
16178
16187
  for (const line of lines) {
16188
+ if (line.trim() !== "") activity?.pulse();
16179
16189
  for (const chunk of processLine$1(line, state, wire)) {
16180
16190
  outputStarted = true;
16181
16191
  yield chunk;
@@ -17493,6 +17503,21 @@ var FileCredentialStore$5 = class {
17493
17503
  }
17494
17504
  };
17495
17505
  /**
17506
+ * The selection as one settings file means it. Version 2 stores the tri-state
17507
+ * as-is; a file from before then could not say "none" at all — its empty array
17508
+ * was the untouched default, so it is read as "no filter", the behaviour it
17509
+ * always had.
17510
+ */
17511
+ function readEnabledModelIds(record) {
17512
+ const value = record.enabledModelIds;
17513
+ if (record.version === 2) {
17514
+ if (!Array.isArray(value)) return null;
17515
+ return value.filter((id) => typeof id === "string");
17516
+ }
17517
+ if (!Array.isArray(value) || value.length === 0) return null;
17518
+ return value.filter((id) => typeof id === "string");
17519
+ }
17520
+ /**
17496
17521
  * Model settings, bound to the DSH settings document when the harness offers one
17497
17522
  * and to a JSON file beside it otherwise.
17498
17523
  */
@@ -17509,7 +17534,7 @@ var FileModelSettingsStore$5 = class {
17509
17534
  status() {
17510
17535
  return this.cached ?? {
17511
17536
  enabled: true,
17512
- enabledModelIds: [],
17537
+ enabledModelIds: null,
17513
17538
  catalogModels: [],
17514
17539
  defaultReasoningEffort: null
17515
17540
  };
@@ -17528,7 +17553,7 @@ var FileModelSettingsStore$5 = class {
17528
17553
  const parsed = JSON.parse(content);
17529
17554
  if (typeof parsed === "object" && parsed !== null) {
17530
17555
  const record = parsed;
17531
- const enabledModels = Array.isArray(record.enabledModelIds) ? record.enabledModelIds.filter((id) => typeof id === "string") : [];
17556
+ const enabledModels = readEnabledModelIds(record);
17532
17557
  const catalogModels = Array.isArray(record.catalogModels) ? record.catalogModels.filter((entry) => typeof entry === "object" && entry !== null && typeof entry.id === "string") : [];
17533
17558
  this.cached = {
17534
17559
  enabled: record.enabled !== false,
@@ -17541,7 +17566,7 @@ var FileModelSettingsStore$5 = class {
17541
17566
  } catch {}
17542
17567
  this.cached = {
17543
17568
  enabled: true,
17544
- enabledModelIds: [],
17569
+ enabledModelIds: null,
17545
17570
  catalogModels: [],
17546
17571
  defaultReasoningEffort: null
17547
17572
  };
@@ -17550,7 +17575,10 @@ var FileModelSettingsStore$5 = class {
17550
17575
  async write(settings) {
17551
17576
  await fs.mkdir(path.dirname(this.filePath), { recursive: true });
17552
17577
  const tmp = `${this.filePath}.tmp.${Date.now()}`;
17553
- await fs.writeFile(tmp, JSON.stringify(settings, null, 2), "utf8");
17578
+ await fs.writeFile(tmp, JSON.stringify({
17579
+ version: 2,
17580
+ ...settings
17581
+ }, null, 2), "utf8");
17554
17582
  await fs.rename(tmp, this.filePath);
17555
17583
  this.cached = settings;
17556
17584
  }
@@ -17558,7 +17586,7 @@ var FileModelSettingsStore$5 = class {
17558
17586
  const current = await this.read();
17559
17587
  const next = {
17560
17588
  enabled: patch.enabled ?? current.enabled,
17561
- enabledModelIds: patch.enabledModelIds ?? current.enabledModelIds,
17589
+ enabledModelIds: patch.enabledModelIds !== void 0 ? patch.enabledModelIds : current.enabledModelIds,
17562
17590
  catalogModels: current.catalogModels,
17563
17591
  defaultReasoningEffort: patch.defaultReasoningEffort === void 0 ? current.defaultReasoningEffort : patch.defaultReasoningEffort
17564
17592
  };
@@ -17768,7 +17796,7 @@ function chatUrl(wire) {
17768
17796
  * Response, because the caller has to decide between retrying this account and
17769
17797
  * failing the turn, and both need the status before any body is read.
17770
17798
  */
17771
- function startChat(fetchFn, credentials, wire, request) {
17799
+ function startChat(fetchFn, credentials, wire, request, activity) {
17772
17800
  let resolveStatus = () => void 0;
17773
17801
  let rejectStatus = () => void 0;
17774
17802
  const status = new Promise((resolve, reject) => {
@@ -17798,7 +17826,7 @@ function startChat(fetchFn, credentials, wire, request) {
17798
17826
  };
17799
17827
  return;
17800
17828
  }
17801
- yield* readStream(response, wire);
17829
+ yield* readStream(response, wire, activity);
17802
17830
  })(),
17803
17831
  status
17804
17832
  };
@@ -17811,7 +17839,7 @@ async function safeErrorText(response) {
17811
17839
  }
17812
17840
  }
17813
17841
  /** Parse the SSE stream of either surface. */
17814
- async function* readStream(response, wire) {
17842
+ async function* readStream(response, wire, activity) {
17815
17843
  const body = response.body;
17816
17844
  if (body === null) return;
17817
17845
  const decoder = new TextDecoder();
@@ -17822,12 +17850,14 @@ async function* readStream(response, wire) {
17822
17850
  for (;;) {
17823
17851
  const { done, value } = await reader.read();
17824
17852
  if (done) break;
17853
+ if (value !== void 0 && value.byteLength > 0) activity?.pulse();
17825
17854
  buffer += decoder.decode(value, { stream: true });
17826
17855
  let newline = buffer.indexOf("\n");
17827
17856
  while (newline !== -1) {
17828
17857
  const line = buffer.slice(0, newline).trim();
17829
17858
  buffer = buffer.slice(newline + 1);
17830
17859
  newline = buffer.indexOf("\n");
17860
+ if (line !== "") activity?.pulse();
17831
17861
  if (line === "" || !line.startsWith("data:")) continue;
17832
17862
  const payload = line.slice(5).trim();
17833
17863
  if (payload === "" || payload === "[DONE]") continue;
@@ -18341,8 +18371,8 @@ var OllamaAdapter = class extends LlmAdapter {
18341
18371
  const settings = await this.settings();
18342
18372
  if (settings.enabled === false) return [];
18343
18373
  const catalog = await this.catalog();
18344
- const enabled = new Set(settings.enabledModelIds);
18345
- return (settings.enabledModelIds.length === 0 ? catalog : catalog.filter((model) => enabled.has(model.id))).map((model) => ({
18374
+ const enabled = settings.enabledModelIds === null ? null : new Set(settings.enabledModelIds);
18375
+ return (enabled === null ? catalog : catalog.filter((model) => enabled.has(model.id))).map((model) => ({
18346
18376
  provider: prov,
18347
18377
  id: model.id,
18348
18378
  name: model.name ?? model.id,
@@ -18368,9 +18398,9 @@ var OllamaAdapter = class extends LlmAdapter {
18368
18398
  };
18369
18399
  }
18370
18400
  async *stream(options) {
18371
- yield* wrapStreamWithWatchdog((watchdogSignal) => this.requestStream(options, watchdogSignal), options.signal, STREAM_IDLE_TIMEOUT_MS$7, STREAM_IDLE_TIMEOUT_CODE$7, PROVIDER_NAME$5);
18401
+ yield* wrapStreamWithWatchdog((watchdogSignal, activity) => this.requestStream(options, watchdogSignal, activity), options.signal, STREAM_IDLE_TIMEOUT_MS$7, STREAM_IDLE_TIMEOUT_CODE$7, PROVIDER_NAME$5);
18372
18402
  }
18373
- async *requestStream(rawOptions, signal) {
18403
+ async *requestStream(rawOptions, signal, activity) {
18374
18404
  const fetchFn = this.options.fetchFn ?? fetch;
18375
18405
  const options = normalizeGenerateOptions(rawOptions);
18376
18406
  const wire = wireForModel$1(options.model);
@@ -18412,7 +18442,7 @@ var OllamaAdapter = class extends LlmAdapter {
18412
18442
  const call = startChat(fetchFn, credentials, wire, {
18413
18443
  ...request,
18414
18444
  signal
18415
- });
18445
+ }, activity);
18416
18446
  const state = createStreamState$5();
18417
18447
  let openedStatus;
18418
18448
  call.status.then((value) => {
@@ -18826,7 +18856,7 @@ async function getOllamaWebStatus(options) {
18826
18856
  };
18827
18857
  const settings = await modelSettings.read().catch(() => ({
18828
18858
  enabled: true,
18829
- enabledModelIds: [],
18859
+ enabledModelIds: null,
18830
18860
  catalogModels: [],
18831
18861
  defaultReasoningEffort: null
18832
18862
  }));
@@ -18862,6 +18892,22 @@ function registerOllamaRoutes(ctx, options) {
18862
18892
  ok: true,
18863
18893
  value: await getOllamaWebStatus(options)
18864
18894
  });
18895
+ if (path === "settings") {
18896
+ if (method !== "POST") return sendMethodNotAllowed$5(response);
18897
+ if (!isSameOriginMutation(request)) return sendJson$6(response, 403, {
18898
+ ok: false,
18899
+ error: "Cross-origin request rejected."
18900
+ });
18901
+ const body = await readRequestJson$6(request).catch(() => ({}));
18902
+ if (typeof body.enabled === "boolean") {
18903
+ await modelSettings.update({ enabled: body.enabled });
18904
+ ctx.emit?.("llm/adapters-updated");
18905
+ }
18906
+ return sendJson$6(response, 200, {
18907
+ ok: true,
18908
+ value: await modelSettings.read()
18909
+ });
18910
+ }
18865
18911
  if (path === "accounts") {
18866
18912
  if (method === "GET") return sendJson$6(response, 200, {
18867
18913
  ok: true,
@@ -18896,16 +18942,12 @@ function registerOllamaRoutes(ctx, options) {
18896
18942
  addedAt: Date.now()
18897
18943
  };
18898
18944
  if (alias !== void 0) credentials.alias = alias;
18899
- return sendJson$6(response, 200, {
18900
- ok: true,
18901
- value: { id: (await accountPool.addAccount(credentials, alias)).id }
18902
- });
18903
- }
18904
- if (accountId === void 0) return sendJson$6(response, 400, {
18945
+ await accountPool.addAccount(credentials, alias);
18946
+ } else if (accountId === void 0) return sendJson$6(response, 400, {
18905
18947
  ok: false,
18906
18948
  error: "accountId is required."
18907
18949
  });
18908
- if (action === "set-primary") await accountPool.setPrimary(accountId);
18950
+ else if (action === "set-primary") await accountPool.setPrimary(accountId);
18909
18951
  else if (action === "set-alias" && typeof body.alias === "string") await accountPool.setAlias(accountId, body.alias);
18910
18952
  else if (action === "delete") await accountPool.deleteAccount(accountId);
18911
18953
  else if (action === "clear-cooldown") await accountPool.clearCooldown(accountId);
@@ -18943,8 +18985,16 @@ function registerOllamaRoutes(ctx, options) {
18943
18985
  error: "Cross-origin request rejected."
18944
18986
  });
18945
18987
  const body = await readRequestJson$6(request).catch(() => ({}));
18946
- if (typeof body.enabled === "boolean") await modelSettings.update({ enabled: body.enabled });
18947
- if (Array.isArray(body.enabledModelIds)) await modelSettings.update({ enabledModelIds: body.enabledModelIds.filter((id) => typeof id === "string") });
18988
+ let touched = false;
18989
+ if (typeof body.enabled === "boolean") {
18990
+ await modelSettings.update({ enabled: body.enabled });
18991
+ touched = true;
18992
+ }
18993
+ if (Array.isArray(body.enabledModelIds) || body.enabledModelIds === null) {
18994
+ await modelSettings.update({ enabledModelIds: Array.isArray(body.enabledModelIds) ? body.enabledModelIds.filter((id) => typeof id === "string") : null });
18995
+ touched = true;
18996
+ }
18997
+ if (touched) ctx.emit?.("llm/adapters-updated");
18948
18998
  return sendJson$6(response, 200, {
18949
18999
  ok: true,
18950
19000
  value: await modelSettings.read()
@@ -20406,14 +20456,14 @@ async function kimiIdentityHeaders(extra = {}) {
20406
20456
  * `AbortSignal.any` keeps whichever fires first, so an abandoned login stops
20407
20457
  * promptly while a hung endpoint still cannot hold the request forever.
20408
20458
  */
20409
- function withTimeout$7(signal, ms) {
20459
+ function withTimeout$8(signal, ms) {
20410
20460
  const timeout = AbortSignal.timeout(ms);
20411
20461
  return signal === void 0 ? timeout : AbortSignal.any([signal, timeout]);
20412
20462
  }
20413
20463
  function oauthEndpoint(host, endpoint) {
20414
20464
  return `${host.replace(/\/+$/, "")}${endpoint}`;
20415
20465
  }
20416
- function asRecord$11(value) {
20466
+ function asRecord$12(value) {
20417
20467
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
20418
20468
  }
20419
20469
  /**
@@ -20424,8 +20474,8 @@ function asRecord$11(value) {
20424
20474
  * caller decides whether the flow continues.
20425
20475
  */
20426
20476
  function oauthErrorFields$2(payload) {
20427
- const root = asRecord$11(payload) ?? {};
20428
- const nested = asRecord$11(root.error);
20477
+ const root = asRecord$12(payload) ?? {};
20478
+ const nested = asRecord$12(root.error);
20429
20479
  if (nested !== void 0) return {
20430
20480
  code: typeof nested.code === "string" ? nested.code : "",
20431
20481
  description: String(nested.message ?? nested.error_description ?? nested.detail ?? nested.type ?? "")
@@ -20450,14 +20500,14 @@ async function requestDeviceAuthorization(options = {}) {
20450
20500
  accept: "application/json"
20451
20501
  }),
20452
20502
  body: new URLSearchParams$1({ client_id: KIMI_CODE_CLIENT_ID }).toString(),
20453
- signal: withTimeout$7(options.signal, OAUTH_TIMEOUT_MS$2)
20503
+ signal: withTimeout$8(options.signal, OAUTH_TIMEOUT_MS$2)
20454
20504
  });
20455
20505
  const payload = await response.json().catch(() => void 0);
20456
20506
  if (!response.ok) {
20457
20507
  const { description } = oauthErrorFields$2(payload);
20458
20508
  throw new Error(`Device authorization failed (${response.status})${description ? `: ${description}` : ""}`);
20459
20509
  }
20460
- const record = asRecord$11(payload) ?? {};
20510
+ const record = asRecord$12(payload) ?? {};
20461
20511
  const userCode = typeof record.user_code === "string" ? record.user_code : "";
20462
20512
  const deviceCode = typeof record.device_code === "string" ? record.device_code : "";
20463
20513
  const complete = typeof record.verification_uri_complete === "string" ? record.verification_uri_complete : "";
@@ -20496,10 +20546,10 @@ async function pollDeviceToken$1(host, deviceCode, options) {
20496
20546
  device_code: deviceCode,
20497
20547
  grant_type: DEVICE_CODE_GRANT_TYPE$1
20498
20548
  }).toString(),
20499
- signal: withTimeout$7(options.signal, OAUTH_TIMEOUT_MS$2)
20549
+ signal: withTimeout$8(options.signal, OAUTH_TIMEOUT_MS$2)
20500
20550
  });
20501
20551
  const payload = await response.json().catch(() => void 0);
20502
- const record = asRecord$11(payload) ?? {};
20552
+ const record = asRecord$12(payload) ?? {};
20503
20553
  if (response.status === 200 && typeof record.access_token === "string" && record.access_token !== "") return {
20504
20554
  kind: "success",
20505
20555
  token: parseTokenResponse$2(record)
@@ -20620,12 +20670,12 @@ async function refreshAccessToken$1(refreshToken, options = {}) {
20620
20670
  grant_type: "refresh_token",
20621
20671
  refresh_token: refreshToken
20622
20672
  }).toString(),
20623
- signal: withTimeout$7(options.signal, OAUTH_TIMEOUT_MS$2)
20673
+ signal: withTimeout$8(options.signal, OAUTH_TIMEOUT_MS$2)
20624
20674
  });
20625
20675
  const payload = await response.json().catch(() => void 0);
20626
20676
  const { code, description } = oauthErrorFields$2(payload);
20627
20677
  if (response.status === 401 || response.status === 403 || code === "invalid_grant") throw new KimiCodeUnauthorizedError(description || "Token refresh was rejected; sign in again.");
20628
- if (response.ok) return parseTokenResponse$2(asRecord$11(payload) ?? {});
20678
+ if (response.ok) return parseTokenResponse$2(asRecord$12(payload) ?? {});
20629
20679
  if (!RETRYABLE_REFRESH_STATUSES$1.has(response.status)) throw new Error(description || `Token refresh failed (HTTP ${response.status}).`);
20630
20680
  lastError = new KimiCodeRetryableError(description || `Token refresh failed (HTTP ${response.status}).`);
20631
20681
  } catch (error) {
@@ -20852,7 +20902,7 @@ const FIXED_POINT_CENTS = 1e6;
20852
20902
  function isRecord$26(value) {
20853
20903
  return typeof value === "object" && value !== null && !Array.isArray(value);
20854
20904
  }
20855
- function asRecord$10(value) {
20905
+ function asRecord$11(value) {
20856
20906
  return isRecord$26(value) ? value : void 0;
20857
20907
  }
20858
20908
  function asString$16(value) {
@@ -20995,7 +21045,7 @@ function parseThinkingType(record) {
20995
21045
  return raw === "only" || raw === "no" || raw === "both" ? raw : void 0;
20996
21046
  }
20997
21047
  function parseCatalogModel(value) {
20998
- const record = asRecord$10(value);
21048
+ const record = asRecord$11(value);
20999
21049
  if (record === void 0) return void 0;
21000
21050
  const id = asString$16(record.id);
21001
21051
  if (id === void 0) return void 0;
@@ -21003,10 +21053,10 @@ function parseCatalogModel(value) {
21003
21053
  if (status !== void 0 && RETIRED_MODEL_STATUSES.has(status)) return void 0;
21004
21054
  const contextWindow = firstNumber(record, ["context_length", "contextLength"]);
21005
21055
  if (contextWindow === void 0 || contextWindow <= 0) return void 0;
21006
- const declaredInput = firstNumber(asRecord$10(record.limit) ?? asRecord$10(record.limits) ?? {}, ["input"]) ?? firstNumber(record, ["max_input_tokens", "maxInputTokens"]);
21056
+ const declaredInput = firstNumber(asRecord$11(record.limit) ?? asRecord$11(record.limits) ?? {}, ["input"]) ?? firstNumber(record, ["max_input_tokens", "maxInputTokens"]);
21007
21057
  const maxInputTokens = declaredInput !== void 0 && declaredInput > 0 && declaredInput < contextWindow ? declaredInput : void 0;
21008
21058
  const thinkingType = parseThinkingType(record);
21009
- const efforts = asRecord$10(record.think_efforts) ?? asRecord$10(record.thinkEfforts);
21059
+ const efforts = asRecord$11(record.think_efforts) ?? asRecord$11(record.thinkEfforts);
21010
21060
  const validEfforts = Array.isArray(efforts?.valid_efforts) ? efforts.valid_efforts.filter((entry) => typeof entry === "string") : Array.isArray(efforts?.validEfforts) ? efforts.validEfforts.filter((entry) => typeof entry === "string") : void 0;
21011
21061
  const modalities = ["text"];
21012
21062
  if (record.supports_image_in === true || record.supportsImageIn === true) modalities.push("image");
@@ -21121,7 +21171,7 @@ async function performListing(options) {
21121
21171
  });
21122
21172
  if (!response.ok) throw new Error(`Kimi Code model listing failed (${response.status}).`);
21123
21173
  const payload = await response.json().catch(() => void 0);
21124
- const data = Array.isArray(payload) ? payload : asRecord$10(payload)?.data;
21174
+ const data = Array.isArray(payload) ? payload : asRecord$11(payload)?.data;
21125
21175
  if (!Array.isArray(data)) throw new Error("Kimi Code model listing was not in the documented shape.");
21126
21176
  const models = data.map(parseCatalogModel).filter((model) => model !== void 0);
21127
21177
  if (epoch !== catalogCacheEpoch$1) return models;
@@ -21455,7 +21505,7 @@ function usageWindow(id, record, descriptor) {
21455
21505
  * than a fabricated 0%.
21456
21506
  */
21457
21507
  function parseUsageWindows(payload) {
21458
- const root = asRecord$10(payload) ?? {};
21508
+ const root = asRecord$11(payload) ?? {};
21459
21509
  const windows = [];
21460
21510
  const seen = /* @__PURE__ */ new Set();
21461
21511
  const push = (id, record, descriptor) => {
@@ -21465,23 +21515,23 @@ function parseUsageWindows(payload) {
21465
21515
  seen.add(id);
21466
21516
  windows.push(parsed);
21467
21517
  };
21468
- const usages = asRecord$10(root.usages) ?? asRecord$10(root.usageWindows);
21518
+ const usages = asRecord$11(root.usages) ?? asRecord$11(root.usageWindows);
21469
21519
  if (usages !== void 0) {
21470
21520
  const keys = [...WINDOW_ORDER.filter((key) => usages[key] !== void 0), ...Object.keys(usages).filter((key) => !WINDOW_ORDER.includes(key))];
21471
21521
  for (const key of keys) {
21472
- const record = asRecord$10(usages[key]);
21522
+ const record = asRecord$11(usages[key]);
21473
21523
  if (record === void 0) continue;
21474
21524
  push(key, record, WINDOW_DESCRIPTORS[key]);
21475
21525
  }
21476
21526
  }
21477
- const topLevel = asRecord$10(root.usage);
21527
+ const topLevel = asRecord$11(root.usage);
21478
21528
  if (topLevel !== void 0 && seen.size === 0) push("limit_7d", topLevel, WINDOW_DESCRIPTORS.limit_7d);
21479
21529
  const limits = Array.isArray(root.limits) ? root.limits : [];
21480
21530
  for (const entry of limits) {
21481
- const record = asRecord$10(entry);
21531
+ const record = asRecord$11(entry);
21482
21532
  if (record === void 0) continue;
21483
- const detail = asRecord$10(record.detail) ?? record;
21484
- const window = asRecord$10(record.window);
21533
+ const detail = asRecord$11(record.detail) ?? record;
21534
+ const window = asRecord$11(record.window);
21485
21535
  const duration = firstNumber(window ?? {}, ["duration"]);
21486
21536
  const unit = asString$16(window?.timeUnit ?? window?.time_unit);
21487
21537
  const minutes = duration === void 0 ? null : unit === "TIME_UNIT_HOUR" ? duration * 60 : duration;
@@ -21514,13 +21564,13 @@ function fixedPointToCents(value) {
21514
21564
  * under-report a charge limit by six orders of magnitude.
21515
21565
  */
21516
21566
  function moneyCents(value) {
21517
- const record = asRecord$10(value);
21567
+ const record = asRecord$11(value);
21518
21568
  if (record === void 0) return null;
21519
21569
  const cents = asNumber$4(record.priceInCents ?? record.price_in_cents);
21520
21570
  return cents === void 0 || !Number.isFinite(cents) ? null : Math.round(cents);
21521
21571
  }
21522
21572
  function moneyCurrency(value) {
21523
- const record = asRecord$10(value);
21573
+ const record = asRecord$11(value);
21524
21574
  return record === void 0 ? void 0 : asString$16(record.currency);
21525
21575
  }
21526
21576
  /**
@@ -21531,10 +21581,10 @@ function moneyCurrency(value) {
21531
21581
  * cannot spend.
21532
21582
  */
21533
21583
  function parseExtraUsage(payload) {
21534
- const root = asRecord$10(payload) ?? {};
21535
- const wallet = asRecord$10(root.boosterWallet) ?? asRecord$10(root.booster_wallet) ?? asRecord$10(root.extraUsage);
21584
+ const root = asRecord$11(payload) ?? {};
21585
+ const wallet = asRecord$11(root.boosterWallet) ?? asRecord$11(root.booster_wallet) ?? asRecord$11(root.extraUsage);
21536
21586
  if (wallet === void 0) return null;
21537
- const balance = asRecord$10(wallet.balance);
21587
+ const balance = asRecord$11(wallet.balance);
21538
21588
  const balanceType = asString$16(balance?.type);
21539
21589
  const amount = asNumber$4(balance?.amount);
21540
21590
  if (balance === void 0 || balanceType !== "BOOSTER" || amount === void 0 || amount <= 0) return null;
@@ -21583,7 +21633,7 @@ function membershipLevelName(level) {
21583
21633
  * `user_level_name` still yields a readable tier instead of a raw enum.
21584
21634
  */
21585
21635
  function parsePlanName(payload) {
21586
- const root = asRecord$10(payload) ?? {};
21636
+ const root = asRecord$11(payload) ?? {};
21587
21637
  const direct = firstString(root, [
21588
21638
  "user_level_name",
21589
21639
  "userLevelName",
@@ -21591,17 +21641,17 @@ function parsePlanName(payload) {
21591
21641
  "plan_name"
21592
21642
  ]);
21593
21643
  if (direct !== void 0) return direct;
21594
- const membership = asRecord$10(asRecord$10(root.user)?.membership);
21644
+ const membership = asRecord$11(asRecord$11(root.user)?.membership);
21595
21645
  const named = asString$16(membership?.level_name ?? membership?.levelName);
21596
21646
  if (named !== void 0) return named;
21597
21647
  return membershipLevelName(asString$16(membership?.level) ?? null);
21598
21648
  }
21599
21649
  /** Machine tier level when the service reports one. */
21600
21650
  function parsePlanLevel(payload) {
21601
- const root = asRecord$10(payload) ?? {};
21651
+ const root = asRecord$11(payload) ?? {};
21602
21652
  const direct = firstNumber(root, ["user_level", "userLevel"]);
21603
21653
  if (direct !== void 0) return String(direct);
21604
- const membership = asRecord$10(asRecord$10(root.user)?.membership);
21654
+ const membership = asRecord$11(asRecord$11(root.user)?.membership);
21605
21655
  return asString$16(membership?.level ?? membership?.levelId ?? membership?.level_id) ?? null;
21606
21656
  }
21607
21657
  /**
@@ -21708,7 +21758,7 @@ function accountFromCredentials$2(credentials, payload, profile) {
21708
21758
  const planLevel = (profile === void 0 ? null : parsePlanLevel(profile)) ?? (payload === void 0 ? null : parsePlanLevel(payload));
21709
21759
  return {
21710
21760
  userId: credentials.userId ?? identity.userId ?? null,
21711
- nickname: (profile === void 0 ? null : firstString(asRecord$10(profile) ?? {}, [
21761
+ nickname: (profile === void 0 ? null : firstString(asRecord$11(profile) ?? {}, [
21712
21762
  "nickname",
21713
21763
  "username",
21714
21764
  "name"
@@ -24138,9 +24188,9 @@ var KimiCodeAdapter = class extends LlmAdapter {
24138
24188
  ...options,
24139
24189
  reasoningEffort: ReasoningEffortId(String(effort))
24140
24190
  };
24141
- yield* wrapStreamWithWatchdog((watchdogSignal) => this.requestStream(effectiveOptions, watchdogSignal), options.signal, STREAM_IDLE_TIMEOUT_MS$4, STREAM_IDLE_TIMEOUT_CODE$4, PROVIDER_NAME$4);
24191
+ yield* wrapStreamWithWatchdog((watchdogSignal, activity) => this.requestStream(effectiveOptions, watchdogSignal, activity), options.signal, STREAM_IDLE_TIMEOUT_MS$4, STREAM_IDLE_TIMEOUT_CODE$4, PROVIDER_NAME$4);
24142
24192
  }
24143
- async *requestStream(options, signal) {
24193
+ async *requestStream(options, signal, activity) {
24144
24194
  const fetchFn = this.options.fetchFn ?? fetch;
24145
24195
  const catalog = await this.catalog().catch(() => []);
24146
24196
  const wire = wireForCatalogEntry(options.model, catalog);
@@ -24276,10 +24326,12 @@ var KimiCodeAdapter = class extends LlmAdapter {
24276
24326
  while (true) {
24277
24327
  const { done, value } = await reader.read();
24278
24328
  if (done) break;
24329
+ if (value !== void 0 && value.byteLength > 0) activity?.pulse();
24279
24330
  buffer += decoder.decode(value, { stream: true });
24280
24331
  const lines = buffer.split("\n");
24281
24332
  buffer = lines.pop() ?? "";
24282
24333
  for (const line of lines) {
24334
+ activity?.pulse();
24283
24335
  for (const chunk of processLine(line, state, wire)) {
24284
24336
  outputStarted = true;
24285
24337
  yield chunk;
@@ -27891,11 +27943,11 @@ const OAUTH_HEADERS = {
27891
27943
  accept: "application/json",
27892
27944
  "content-type": "application/x-www-form-urlencoded"
27893
27945
  };
27894
- function withTimeout$6(signal, ms) {
27946
+ function withTimeout$7(signal, ms) {
27895
27947
  const timeout = AbortSignal.timeout(ms);
27896
27948
  return signal === void 0 ? timeout : AbortSignal.any([signal, timeout]);
27897
27949
  }
27898
- function asRecord$9(value) {
27950
+ function asRecord$10(value) {
27899
27951
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
27900
27952
  }
27901
27953
  function asString$11(value) {
@@ -27909,8 +27961,8 @@ function asString$11(value) {
27909
27961
  * both are unwrapped before the caller decides what the failure means.
27910
27962
  */
27911
27963
  function oauthErrorFields$1(payload) {
27912
- const root = asRecord$9(payload) ?? {};
27913
- const nested = asRecord$9(root.error);
27964
+ const root = asRecord$10(payload) ?? {};
27965
+ const nested = asRecord$10(root.error);
27914
27966
  if (nested !== void 0) return {
27915
27967
  code: asString$11(nested.code) ?? "",
27916
27968
  description: String(nested.message ?? nested.error_description ?? nested.detail ?? nested.type ?? "")
@@ -27959,14 +28011,14 @@ async function requestDeviceAuthorization$1(options = {}) {
27959
28011
  code_challenge: pkce.challenge,
27960
28012
  code_challenge_method: PKCE_CHALLENGE_METHOD
27961
28013
  }).toString(),
27962
- signal: withTimeout$6(options.signal, OAUTH_TIMEOUT_MS$1)
28014
+ signal: withTimeout$7(options.signal, OAUTH_TIMEOUT_MS$1)
27963
28015
  });
27964
28016
  const payload = await response.json().catch(() => void 0);
27965
28017
  if (!response.ok) {
27966
28018
  const { description } = oauthErrorFields$1(payload);
27967
28019
  throw new Error("MiniMax Code device authorization failed (" + response.status + ")" + (description === "" ? "" : ": " + description));
27968
28020
  }
27969
- const record = asRecord$9(payload) ?? {};
28021
+ const record = asRecord$10(payload) ?? {};
27970
28022
  const userCode = asString$11(record.user_code);
27971
28023
  const deviceCode = asString$11(record.device_code);
27972
28024
  if (userCode === void 0 || deviceCode === void 0) throw new Error("MiniMax Code device authorization response carried no device code or user code");
@@ -28017,10 +28069,10 @@ async function pollDeviceToken(authorization, options = {}) {
28017
28069
  code_verifier: authorization.codeVerifier,
28018
28070
  grant_type: DEVICE_CODE_GRANT_TYPE
28019
28071
  }).toString(),
28020
- signal: withTimeout$6(options.signal, OAUTH_TIMEOUT_MS$1)
28072
+ signal: withTimeout$7(options.signal, OAUTH_TIMEOUT_MS$1)
28021
28073
  });
28022
28074
  const payload = await response.json().catch(() => void 0);
28023
- const record = asRecord$9(payload) ?? {};
28075
+ const record = asRecord$10(payload) ?? {};
28024
28076
  if (response.ok && asString$11(record.access_token) !== void 0) return {
28025
28077
  kind: "success",
28026
28078
  token: parseTokenResponse$1(record)
@@ -28079,12 +28131,12 @@ async function refreshAccessToken$2(refreshToken, options) {
28079
28131
  scope: MINIMAX_CODE_SCOPE,
28080
28132
  audience: MINIMAX_CODE_AUDIENCE
28081
28133
  }).toString(),
28082
- signal: withTimeout$6(options.signal, OAUTH_TIMEOUT_MS$1)
28134
+ signal: withTimeout$7(options.signal, OAUTH_TIMEOUT_MS$1)
28083
28135
  });
28084
28136
  const payload = await response.json().catch(() => void 0);
28085
28137
  const { code, description } = oauthErrorFields$1(payload);
28086
28138
  if (response.status === 400 || response.status === 401 || response.status === 403 || code === "invalid_grant" || code === "invalid_client") throw new MinimaxCodeUnauthorizedError("MiniMax Code rejected the stored refresh token " + redactToken(refreshToken) + ". Sign in again in MiniMax Code, then reopen this card.");
28087
- if (response.ok) return parseTokenResponse$1(asRecord$9(payload) ?? {});
28139
+ if (response.ok) return parseTokenResponse$1(asRecord$10(payload) ?? {});
28088
28140
  if (!RETRYABLE_REFRESH_STATUSES.has(response.status)) throw new MinimaxCodeRetryableError(description || "MiniMax Code token refresh failed (HTTP " + response.status + ").");
28089
28141
  lastError = new MinimaxCodeRetryableError(description || "MiniMax Code token refresh failed (HTTP " + response.status + ").");
28090
28142
  } catch (error) {
@@ -28112,7 +28164,7 @@ async function revokeToken(token, options) {
28112
28164
  token,
28113
28165
  token_type_hint: "refresh_token"
28114
28166
  }).toString(),
28115
- signal: withTimeout$6(options.signal, OAUTH_TIMEOUT_MS$1)
28167
+ signal: withTimeout$7(options.signal, OAUTH_TIMEOUT_MS$1)
28116
28168
  })).ok;
28117
28169
  } catch {
28118
28170
  return false;
@@ -28384,7 +28436,7 @@ async function pollWebLogin(store, loginId, options = {}) {
28384
28436
  */
28385
28437
  /** Timeout for the connection probe and any other one-shot call. */
28386
28438
  const PROBE_TIMEOUT_MS = 3e4;
28387
- function withTimeout$5(signal, ms) {
28439
+ function withTimeout$6(signal, ms) {
28388
28440
  const timeout = AbortSignal.timeout(ms);
28389
28441
  return signal === void 0 ? timeout : AbortSignal.any([signal, timeout]);
28390
28442
  }
@@ -28414,7 +28466,7 @@ function probeRequestHeaders(accessToken) {
28414
28466
  accept: "application/json"
28415
28467
  };
28416
28468
  }
28417
- function asRecord$8(value) {
28469
+ function asRecord$9(value) {
28418
28470
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
28419
28471
  }
28420
28472
  function numberOr$4(value, fallback) {
@@ -28422,7 +28474,7 @@ function numberOr$4(value, fallback) {
28422
28474
  }
28423
28475
  /** Read the four token counters the Messages response reports. */
28424
28476
  function parseAnthropicUsage(payload) {
28425
- const usage = asRecord$8(asRecord$8(payload)?.usage);
28477
+ const usage = asRecord$9(asRecord$9(payload)?.usage);
28426
28478
  if (usage === void 0) return null;
28427
28479
  return {
28428
28480
  inputTokens: numberOr$4(usage.input_tokens, 0),
@@ -28436,13 +28488,13 @@ function summarizeFailureBody(raw) {
28436
28488
  const text = raw.replace(/[\r\n\t]+/g, " ").trim();
28437
28489
  if (text === "") return "";
28438
28490
  try {
28439
- const record = asRecord$8(JSON.parse(text));
28491
+ const record = asRecord$9(JSON.parse(text));
28440
28492
  if (record !== void 0) {
28441
28493
  const message = record.message ?? record.error_description ?? record.errorReason ?? record.error;
28442
28494
  if (typeof message === "string") return message.slice(0, 400);
28443
- const nestedMessage = asRecord$8(record.error)?.message;
28495
+ const nestedMessage = asRecord$9(record.error)?.message;
28444
28496
  if (typeof nestedMessage === "string") return nestedMessage.slice(0, 400);
28445
- const baseResp = asRecord$8(record.base_resp)?.status_msg;
28497
+ const baseResp = asRecord$9(record.base_resp)?.status_msg;
28446
28498
  if (typeof baseResp === "string") return baseResp.slice(0, 400);
28447
28499
  }
28448
28500
  } catch {}
@@ -28494,7 +28546,7 @@ async function testConnection(store, options = {}) {
28494
28546
  content: "ping"
28495
28547
  }]
28496
28548
  }),
28497
- signal: withTimeout$5(options.signal, PROBE_TIMEOUT_MS)
28549
+ signal: withTimeout$6(options.signal, PROBE_TIMEOUT_MS)
28498
28550
  });
28499
28551
  const latencyMs = Date.now() - startedAt;
28500
28552
  if (!response.ok) {
@@ -28559,7 +28611,7 @@ async function createMessage(store, request, options = {}) {
28559
28611
  content: request.prompt
28560
28612
  }]
28561
28613
  }),
28562
- signal: withTimeout$5(options.signal, PROBE_TIMEOUT_MS)
28614
+ signal: withTimeout$6(options.signal, PROBE_TIMEOUT_MS)
28563
28615
  });
28564
28616
  const payload = await response.json().catch(() => void 0);
28565
28617
  return {
@@ -28761,11 +28813,11 @@ function quotaWindow(input) {
28761
28813
  * card's graceful degradation.
28762
28814
  */
28763
28815
  function parseTokenPlanQuota(payload, now = Date.now()) {
28764
- const rows = asRecord$8(payload)?.model_remains;
28816
+ const rows = asRecord$9(payload)?.model_remains;
28765
28817
  if (!Array.isArray(rows)) return null;
28766
28818
  const entries = [];
28767
28819
  for (const raw of rows) {
28768
- const row = asRecord$8(raw);
28820
+ const row = asRecord$9(raw);
28769
28821
  if (row === void 0) continue;
28770
28822
  const name = typeof row.model_name === "string" && row.model_name !== "" ? row.model_name : "quota";
28771
28823
  const intervalTotal = numberOr$4(row.current_interval_total_count, 0);
@@ -28832,7 +28884,7 @@ async function fetchTokenPlanQuota(credentials, options = {}) {
28832
28884
  const response = await fetchFn(tokenPlanRemainsUrl(host), {
28833
28885
  method: "GET",
28834
28886
  headers: quotaRequestHeaders(credentials.accessToken, remainsPath),
28835
- signal: withTimeout$5(options.signal, QUOTA_TIMEOUT_MS)
28887
+ signal: withTimeout$6(options.signal, QUOTA_TIMEOUT_MS)
28836
28888
  });
28837
28889
  if (response.status === 401 || response.status === 403) {
28838
28890
  if (await options.isCredentialStale?.() === true) return null;
@@ -28841,7 +28893,7 @@ async function fetchTokenPlanQuota(credentials, options = {}) {
28841
28893
  }
28842
28894
  if (!response.ok) continue;
28843
28895
  const payload = await response.json().catch(() => void 0);
28844
- if (numberOr$4(asRecord$8(asRecord$8(payload)?.base_resp)?.status_code, 0) !== 0) {
28896
+ if (numberOr$4(asRecord$9(asRecord$9(payload)?.base_resp)?.status_code, 0) !== 0) {
28845
28897
  reason = "credential-not-accepted";
28846
28898
  break;
28847
28899
  }
@@ -29662,9 +29714,9 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
29662
29714
  ...options,
29663
29715
  reasoningEffort: ReasoningEffortId(String(effort))
29664
29716
  };
29665
- yield* wrapStreamWithWatchdog((watchdogSignal) => this.requestStream(effectiveOptions, watchdogSignal), options.signal, STREAM_IDLE_TIMEOUT_MS$3, STREAM_IDLE_TIMEOUT_CODE$3, PROVIDER_NAME$3);
29717
+ yield* wrapStreamWithWatchdog((watchdogSignal, activity) => this.requestStream(effectiveOptions, watchdogSignal, activity), options.signal, STREAM_IDLE_TIMEOUT_MS$3, STREAM_IDLE_TIMEOUT_CODE$3, PROVIDER_NAME$3);
29666
29718
  }
29667
- async *requestStream(options, signal) {
29719
+ async *requestStream(options, signal, activity) {
29668
29720
  const fetchFn = this.options.fetchFn ?? fetch;
29669
29721
  const settings = await this.settings();
29670
29722
  minimaxCodeModelDef(options.model);
@@ -29772,10 +29824,12 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
29772
29824
  while (true) {
29773
29825
  const { done, value } = await reader.read();
29774
29826
  if (done) break;
29827
+ if (value !== void 0 && value.byteLength > 0) activity?.pulse();
29775
29828
  buffer += decoder.decode(value, { stream: true });
29776
29829
  const lines = buffer.split("\n");
29777
29830
  buffer = lines.pop() ?? "";
29778
29831
  for (const line of lines) {
29832
+ activity?.pulse();
29779
29833
  for (const chunk of processMinimaxStreamLine(line, state)) {
29780
29834
  outputStarted = true;
29781
29835
  yield chunk;
@@ -30466,6 +30520,287 @@ function createMinimaxCodeAccountsHandler(pool, options = {}) {
30466
30520
  };
30467
30521
  }
30468
30522
  //#endregion
30523
+ //#region src/host/minimax-code/reset-card.ts
30524
+ /** Path that spends a card. */
30525
+ const RESET_CARD_USE_PATH = "/backend/account/reset_card/use";
30526
+ /** The flow window the panel shows, and the start `flows` is asked from. */
30527
+ const RESET_CARD_FLOW_WINDOW_MS = 720 * 60 * 60 * 1e3;
30528
+ /** Local timeout for one reset-card call. */
30529
+ const RESET_CARD_TIMEOUT_MS = 15e3;
30530
+ /** The outcomes the service reports, exactly. */
30531
+ const RESET_OUTCOMES = /* @__PURE__ */ new Set([
30532
+ "SUCCESS",
30533
+ "REPLAYED",
30534
+ "EXPIRED",
30535
+ "NOT_FOUND",
30536
+ "RETRYABLE_FAIL",
30537
+ "LOCK_BUSY"
30538
+ ]);
30539
+ /**
30540
+ * A reset-card call that failed.
30541
+ *
30542
+ * `statusCode` is the envelope's `base_resp.status_code` (the platform answers
30543
+ * HTTP 200 for a refusal), `httpStatus` the status line when the transport
30544
+ * itself refused. Both are kept so the route can answer 401 for an expired token
30545
+ * rather than the generic 502 it would otherwise send for an upstream refusal.
30546
+ */
30547
+ var MinimaxCodeResetCardError = class extends Error {
30548
+ httpStatus;
30549
+ statusCode;
30550
+ constructor(message, httpStatus, statusCode) {
30551
+ super(message);
30552
+ this.httpStatus = httpStatus;
30553
+ this.statusCode = statusCode;
30554
+ this.name = "MinimaxCodeResetCardError";
30555
+ }
30556
+ };
30557
+ /**
30558
+ * Status line one failure should be reported to the browser with.
30559
+ *
30560
+ * The envelope codes are mapped rather than flattened, because "rate limited"
30561
+ * and "your sign-in expired" ask the user for opposite things: one is a
30562
+ * "try in a minute", the other is a refresh this line performs on its own.
30563
+ */
30564
+ function resetCardHttpStatus(error) {
30565
+ if (!(error instanceof MinimaxCodeResetCardError)) return 502;
30566
+ if (error.httpStatus === 401 || error.httpStatus === 403) return 401;
30567
+ if (error.statusCode === 1002) return 429;
30568
+ if (error.statusCode === 1004) return 401;
30569
+ if (error.statusCode === 2013) return 404;
30570
+ return error.httpStatus !== null && error.httpStatus >= 400 ? 502 : 502;
30571
+ }
30572
+ function asRecord$8(value) {
30573
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
30574
+ }
30575
+ /** A finite number, or undefined. The service's epoch fields are milliseconds. */
30576
+ function ms(value) {
30577
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
30578
+ }
30579
+ /** A non-empty string, or undefined. */
30580
+ function text$1(value) {
30581
+ return typeof value === "string" && value !== "" ? value : void 0;
30582
+ }
30583
+ function withTimeout$5(signal, ms_) {
30584
+ const timeout = AbortSignal.timeout(ms_);
30585
+ return signal === void 0 ? timeout : AbortSignal.any([signal, timeout]);
30586
+ }
30587
+ /**
30588
+ * Headers for one reset-card call.
30589
+ *
30590
+ * The bearer is the only credential field: measured, the desktop client's
30591
+ * literal `token:` header is refused with 401 by these routes. Nothing derived
30592
+ * from the token is ever logged, so a failure sentence can name the surface
30593
+ * without naming the credential.
30594
+ */
30595
+ function resetCardRequestHeaders(accessToken) {
30596
+ return {
30597
+ authorization: "Bearer " + accessToken,
30598
+ accept: "application/json",
30599
+ "content-type": "application/json",
30600
+ "user-agent": USER_AGENT$1
30601
+ };
30602
+ }
30603
+ /**
30604
+ * The host that last answered a reset-card call.
30605
+ *
30606
+ * Mirrors the usage read's own habit: only a live call settles which candidate
30607
+ * serves this subscription, so the winner is tried first from then on and the
30608
+ * remaining uncertainty stays in one place.
30609
+ */
30610
+ let resetCardHostInForce = null;
30611
+ /** Candidates for one region, the remembered winner first. */
30612
+ function orderedHosts(region) {
30613
+ const candidates = quotaHostCandidates(region);
30614
+ return resetCardHostInForce === null ? candidates : [resetCardHostInForce, ...candidates.filter((host) => host !== resetCardHostInForce)];
30615
+ }
30616
+ /** The envelope's verdict: 0 means the call did what it was asked. */
30617
+ function readStatusCode(payload) {
30618
+ return asRecord$8(asRecord$8(payload)?.base_resp)?.status_code === void 0 ? 0 : Number(asRecord$8(asRecord$8(payload)?.base_resp)?.status_code);
30619
+ }
30620
+ function statusMessage(payload, fallback) {
30621
+ const message = asRecord$8(asRecord$8(payload)?.base_resp)?.status_msg;
30622
+ return typeof message === "string" && message !== "" ? message : fallback;
30623
+ }
30624
+ /**
30625
+ * One JSON call, walking the host candidates.
30626
+ *
30627
+ * Every candidate is tried for a TRANSPORT or business failure alike: a 401 on
30628
+ * one host is a host that does not serve this route, not a verdict on the
30629
+ * credential — and the task this read serves (which card the user still holds)
30630
+ * is worth finding on the next candidate rather than failing over.
30631
+ */
30632
+ async function resetCardCall(input) {
30633
+ let response;
30634
+ try {
30635
+ response = await input.fetchFn(input.url, {
30636
+ method: input.method,
30637
+ headers: resetCardRequestHeaders(input.accessToken),
30638
+ ...input.body === void 0 ? {} : { body: input.body },
30639
+ signal: withTimeout$5(input.signal, RESET_CARD_TIMEOUT_MS)
30640
+ });
30641
+ } catch (error) {
30642
+ throw new MinimaxCodeResetCardError("reset-card call could not be reached: " + (error instanceof Error ? error.message : String(error)), null, null);
30643
+ }
30644
+ if (!response.ok) throw new MinimaxCodeResetCardError("reset-card call failed with HTTP " + response.status, response.status, null);
30645
+ const payload = await response.json().catch(() => void 0);
30646
+ const statusCode = readStatusCode(payload);
30647
+ if (statusCode !== 0) throw new MinimaxCodeResetCardError(statusMessage(payload, "reset-card call rejected with base_resp " + statusCode), response.status, statusCode);
30648
+ resetCardHostInForce = input.host;
30649
+ return payload;
30650
+ }
30651
+ /** Run one call against the candidate list, keeping the last failure to report. */
30652
+ async function callAcrossHosts(input) {
30653
+ const fetchFn = input.options.fetchFn ?? fetch;
30654
+ let lastError = null;
30655
+ for (const host of orderedHosts(input.credentials.region)) try {
30656
+ return await resetCardCall({
30657
+ url: host.replace(/\/+$/, "") + input.path,
30658
+ method: input.method,
30659
+ accessToken: input.credentials.accessToken,
30660
+ host,
30661
+ fetchFn,
30662
+ ...input.body === void 0 ? {} : { body: input.body },
30663
+ ...input.options.signal === void 0 ? {} : { signal: input.options.signal }
30664
+ });
30665
+ } catch (error) {
30666
+ lastError = error;
30667
+ }
30668
+ if (lastError instanceof MinimaxCodeResetCardError) throw lastError;
30669
+ throw new MinimaxCodeResetCardError("reset-card call had no usable host", null, null);
30670
+ }
30671
+ /** One card, or undefined when a required field is missing or mistyped. */
30672
+ function parseResetCard(raw) {
30673
+ const row = asRecord$8(raw);
30674
+ if (row === void 0) return void 0;
30675
+ const cardId = text$1(row.card_id);
30676
+ const sourceType = text$1(row.source_type);
30677
+ const outBizNo = text$1(row.out_biz_no);
30678
+ const expiresAtMs = ms(row.expire_time);
30679
+ const createdAtMs = ms(row.create_time);
30680
+ if (cardId === void 0 || sourceType === void 0 || outBizNo === void 0) return void 0;
30681
+ if (expiresAtMs === void 0 || createdAtMs === void 0) return void 0;
30682
+ return {
30683
+ cardId,
30684
+ sourceType,
30685
+ expiresAtMs,
30686
+ createdAtMs,
30687
+ outBizNo
30688
+ };
30689
+ }
30690
+ /**
30691
+ * One flow row.
30692
+ *
30693
+ * `event_type` is a closed vocabulary, and an unknown value is dropped rather
30694
+ * than passed through: the contract says GRANT | USE, and a card rendered with a
30695
+ * third value would be showing this plugin an assumption it cannot back.
30696
+ */
30697
+ function parseResetCardFlow(raw) {
30698
+ const row = asRecord$8(raw);
30699
+ if (row === void 0) return void 0;
30700
+ const cardId = text$1(row.card_id);
30701
+ const eventType = text$1(row.event_type);
30702
+ const createdAtMs = ms(row.create_time);
30703
+ if (cardId === void 0 || createdAtMs === void 0) return void 0;
30704
+ if (eventType !== "GRANT" && eventType !== "USE") return void 0;
30705
+ return {
30706
+ cardId,
30707
+ eventType,
30708
+ createdAtMs
30709
+ };
30710
+ }
30711
+ /** The available cards from one `list` document. */
30712
+ function parseResetCardList(payload) {
30713
+ const rows = asRecord$8(payload)?.cards;
30714
+ if (!Array.isArray(rows)) return [];
30715
+ const cards = [];
30716
+ for (const raw of rows) {
30717
+ const card = parseResetCard(raw);
30718
+ if (card !== void 0) cards.push(card);
30719
+ }
30720
+ return cards;
30721
+ }
30722
+ /** The flow rows from one `flows` document. */
30723
+ function parseResetCardFlows(payload) {
30724
+ const rows = asRecord$8(payload)?.flows;
30725
+ if (!Array.isArray(rows)) return [];
30726
+ const flows = [];
30727
+ for (const raw of rows) {
30728
+ const flow = parseResetCardFlow(raw);
30729
+ if (flow !== void 0) flows.push(flow);
30730
+ }
30731
+ return flows;
30732
+ }
30733
+ /** The query the flow read is sent with. `create_time` is mandatory. */
30734
+ function resetCardFlowsQuery(sinceMs, page = 1, size = 20) {
30735
+ return new URLSearchParams({
30736
+ create_time: String(Math.floor(sinceMs)),
30737
+ page: String(page),
30738
+ size: String(size)
30739
+ }).toString();
30740
+ }
30741
+ /** The query the list read is sent with. */
30742
+ function resetCardListQuery(page = 1, size = 20) {
30743
+ return new URLSearchParams({
30744
+ page: String(page),
30745
+ size: String(size)
30746
+ }).toString();
30747
+ }
30748
+ /**
30749
+ * The reset-card panel: the cards still held, plus the recent flow.
30750
+ *
30751
+ * Two requests, and the asymmetry between them is the point: the LIST is the
30752
+ * panel's substance, so a failure of it is reported; the FLOW is context, so its
30753
+ * failure degrades to an empty list and the cards still render. A user whose
30754
+ * flow read is refused loses a history row, not the button they came to press.
30755
+ */
30756
+ async function fetchResetCards(credentials, options = {}) {
30757
+ const now = (options.nowMs ?? Date.now)();
30758
+ return {
30759
+ cards: parseResetCardList(await callAcrossHosts({
30760
+ path: "/backend/account/reset_card/list?" + resetCardListQuery(),
30761
+ method: "GET",
30762
+ credentials,
30763
+ options
30764
+ })),
30765
+ flows: parseResetCardFlows(await callAcrossHosts({
30766
+ path: "/backend/account/reset_card/flows?" + resetCardFlowsQuery(now - RESET_CARD_FLOW_WINDOW_MS),
30767
+ method: "GET",
30768
+ credentials,
30769
+ options
30770
+ }).catch(() => null)),
30771
+ fetchedAtMs: now
30772
+ };
30773
+ }
30774
+ /**
30775
+ * Spend one card.
30776
+ *
30777
+ * The body is exactly two fields, both copied off the card. There is deliberately
30778
+ * no request id here: de-duplication is the service's, keyed on `out_biz_no`,
30779
+ * and a self-minted id would make a second click spend a second card — the exact
30780
+ * harm this line's contract warns about.
30781
+ *
30782
+ * The returned outcome is passed through rather than collapsed into a boolean,
30783
+ * because three of the six values mean "possibly spent, confirm with THIS card"
30784
+ * (REPLAYED, LOCK_BUSY, RETRYABLE_FAIL) and the caller has to be able to tell the
30785
+ * user to retry the same card instead of another one.
30786
+ */
30787
+ async function useResetCard(credentials, card, options = {}) {
30788
+ if (card.sourceType === "" || card.outBizNo === "") throw new MinimaxCodeResetCardError("the reset card is missing its source type or idempotency key", null, null);
30789
+ const payload = await callAcrossHosts({
30790
+ path: RESET_CARD_USE_PATH,
30791
+ method: "POST",
30792
+ credentials,
30793
+ body: JSON.stringify({
30794
+ source_type: card.sourceType,
30795
+ out_biz_no: card.outBizNo
30796
+ }),
30797
+ options
30798
+ });
30799
+ const outcome = text$1(asRecord$8(payload)?.outcome);
30800
+ if (outcome === void 0 || !RESET_OUTCOMES.has(outcome)) throw new MinimaxCodeResetCardError("reset-card use answered without a usable outcome", null, readStatusCode(payload));
30801
+ return outcome;
30802
+ }
30803
+ //#endregion
30469
30804
  //#region src/host/minimax-code/routes.ts
30470
30805
  /** Path the sibling lines register (\`/kimi-code/api\`, \`/workbuddy/api\`). */
30471
30806
  const MAX_BODY_BYTES$3 = 64 * 1024;
@@ -30624,6 +30959,20 @@ function registerMinimaxCodeRoutes(ctx, store = new MinimaxCodeCredentialStore()
30624
30959
  * had neither half.
30625
30960
  */
30626
30961
  const quotaRefresh = new QuotaRefresh();
30962
+ /**
30963
+ * The credential a reset-card call presents, read the same way `refreshQuota`
30964
+ * reads one.
30965
+ *
30966
+ * The pool is the rotation authority when it is installed, so the reset-card
30967
+ * surface must take its credential from the same place a model request would:
30968
+ * a second, independent reader would be a second refresh-token authority, and
30969
+ * two of them presenting the same rotating token is how a healthy account ends
30970
+ * up reported as needing a new sign-in.
30971
+ */
30972
+ const readResetCardCredential = async () => {
30973
+ if (options.accountPool !== void 0) return (await options.accountPool.getQuotaReadTarget(fetchFn).catch(() => null))?.credentials ?? null;
30974
+ return await ensureAccessToken$2(store, { fetchFn }).catch(() => null);
30975
+ };
30627
30976
  const handler = async (request, response) => {
30628
30977
  const path = subPathOf(request.url ?? "/");
30629
30978
  const method = request.method ?? "GET";
@@ -30685,6 +31034,51 @@ function registerMinimaxCodeRoutes(ctx, store = new MinimaxCodeCredentialStore()
30685
31034
  value: await getMinimaxCodeWebStatus(store, options, settings)
30686
31035
  });
30687
31036
  }
31037
+ if (path === "reset-cards") {
31038
+ if (method !== "GET") return sendMethodNotAllowed$3(response);
31039
+ const credentials = await readResetCardCredential();
31040
+ if (credentials === null) return sendJson$3(response, 401, {
31041
+ ok: false,
31042
+ error: "Not signed in."
31043
+ });
31044
+ return sendJson$3(response, 200, {
31045
+ ok: true,
31046
+ value: await fetchResetCards(credentials, { fetchFn })
31047
+ });
31048
+ }
31049
+ if (path === "reset-cards/use") {
31050
+ if (method !== "POST") return sendMethodNotAllowed$3(response);
31051
+ if (!isSameOriginMutation(request)) return sendCrossOrigin$1(response);
31052
+ const body = await readRequestJson$3(request);
31053
+ const cardId = typeof body.cardId === "string" ? body.cardId : "";
31054
+ if (cardId === "") return sendJson$3(response, 400, {
31055
+ ok: false,
31056
+ error: "cardId is required."
31057
+ });
31058
+ const credentials = await readResetCardCredential();
31059
+ if (credentials === null) return sendJson$3(response, 401, {
31060
+ ok: false,
31061
+ error: "Not signed in."
31062
+ });
31063
+ const before = await fetchResetCards(credentials, { fetchFn });
31064
+ const card = before.cards.find((entry) => entry.cardId === cardId);
31065
+ if (card === void 0) return sendJson$3(response, 404, {
31066
+ ok: false,
31067
+ error: "No reset card with that id is currently available."
31068
+ });
31069
+ const value = {
31070
+ outcome: await useResetCard(credentials, {
31071
+ sourceType: card.sourceType,
31072
+ outBizNo: card.outBizNo
31073
+ }, { fetchFn }),
31074
+ cards: await fetchResetCards(credentials, { fetchFn }).catch(() => before)
31075
+ };
31076
+ return sendJson$3(response, 200, {
31077
+ ok: true,
31078
+ value,
31079
+ ...value
31080
+ });
31081
+ }
30688
31082
  if (path === "checkin/now") {
30689
31083
  if (method !== "POST") return sendMethodNotAllowed$3(response);
30690
31084
  if (!isSameOriginMutation(request)) return sendCrossOrigin$1(response);
@@ -30811,6 +31205,10 @@ function registerMinimaxCodeRoutes(ctx, store = new MinimaxCodeCredentialStore()
30811
31205
  ok: false,
30812
31206
  error: error.message
30813
31207
  });
31208
+ if (error instanceof MinimaxCodeResetCardError) return sendJson$3(response, resetCardHttpStatus(error), {
31209
+ ok: false,
31210
+ error: error.message
31211
+ });
30814
31212
  return sendJson$3(response, 500, {
30815
31213
  ok: false,
30816
31214
  error: error instanceof Error ? error.message : String(error)
@@ -34928,7 +35326,7 @@ var WorkBuddyAdapter = class extends LlmAdapter {
34928
35326
  ...options,
34929
35327
  reasoningEffort: ReasoningEffortId(effort)
34930
35328
  };
34931
- yield* wrapStreamWithWatchdog((watchdogSignal) => this.requestStream(effectiveOptions, watchdogSignal), options.signal, STREAM_IDLE_TIMEOUT_MS$2, STREAM_IDLE_TIMEOUT_CODE$2, PROVIDER_NAME$2);
35329
+ yield* wrapStreamWithWatchdog((watchdogSignal, activity) => this.requestStream(effectiveOptions, watchdogSignal, activity), options.signal, STREAM_IDLE_TIMEOUT_MS$2, STREAM_IDLE_TIMEOUT_CODE$2, PROVIDER_NAME$2);
34932
35330
  }
34933
35331
  /**
34934
35332
  * Effort this request should carry, or `undefined` to send none.
@@ -34957,7 +35355,7 @@ var WorkBuddyAdapter = class extends LlmAdapter {
34957
35355
  resolveWorkBuddyModel(options.model, catalog).defaultReasoningEffort ?? void 0
34958
35356
  ].find((candidate) => candidate !== void 0 && efforts.includes(candidate));
34959
35357
  }
34960
- async *requestStream(options, signal) {
35358
+ async *requestStream(options, signal, activity) {
34961
35359
  const fetchFn = this.options.fetchFn ?? fetch;
34962
35360
  const requestOptions = offloadOldestRequestImages$1(normalizeGenerateOptions(options));
34963
35361
  const images = await resolveRequestImages$1(requestOptions, this.options.attachments, signal);
@@ -35027,10 +35425,12 @@ var WorkBuddyAdapter = class extends LlmAdapter {
35027
35425
  while (true) {
35028
35426
  const { done, value } = await reader.read();
35029
35427
  if (done) break;
35428
+ if (value !== void 0 && value.byteLength > 0) activity?.pulse();
35030
35429
  buffer += decoder.decode(value, { stream: true });
35031
35430
  const lines = buffer.split("\n");
35032
35431
  buffer = lines.pop() ?? "";
35033
35432
  for (const line of lines) {
35433
+ activity?.pulse();
35034
35434
  for (const chunk of processStreamLine$2(line, state)) yield chunk;
35035
35435
  if (state.finished) return;
35036
35436
  }
@@ -41370,7 +41770,7 @@ var ClaudeAdapter = class ClaudeAdapter extends LlmAdapter {
41370
41770
  };
41371
41771
  }
41372
41772
  async *stream(options) {
41373
- yield* wrapStreamWithWatchdog((watchdogSignal) => this.requestStream(options, watchdogSignal), options.signal, STREAM_IDLE_TIMEOUT_MS$1, STREAM_IDLE_TIMEOUT_CODE$1, PROVIDER_NAME);
41773
+ yield* wrapStreamWithWatchdog((watchdogSignal, activity) => this.requestStream(options, watchdogSignal, activity), options.signal, STREAM_IDLE_TIMEOUT_MS$1, STREAM_IDLE_TIMEOUT_CODE$1, PROVIDER_NAME);
41374
41774
  }
41375
41775
  /**
41376
41776
  * Read one credential for this attempt.
@@ -41463,7 +41863,7 @@ var ClaudeAdapter = class ClaudeAdapter extends LlmAdapter {
41463
41863
  throw toLlmError(networkFailure(error));
41464
41864
  }
41465
41865
  }
41466
- async *requestStream(options, signal) {
41866
+ async *requestStream(options, signal, activity) {
41467
41867
  const fetchFn = this.options.fetchFn ?? fetch;
41468
41868
  const requestOptions = offloadOldestRequestImages(normalizeGenerateOptions(options));
41469
41869
  const images = await resolveRequestImages(requestOptions, this.options.attachments, signal);
@@ -41524,10 +41924,12 @@ var ClaudeAdapter = class ClaudeAdapter extends LlmAdapter {
41524
41924
  while (true) {
41525
41925
  const { done, value } = await reader.read();
41526
41926
  if (done) break;
41927
+ if (value !== void 0 && value.byteLength > 0) activity?.pulse();
41527
41928
  buffer += decoder.decode(value, { stream: true });
41528
41929
  const lines = buffer.split("\n");
41529
41930
  buffer = lines.pop() ?? "";
41530
41931
  for (const line of lines) {
41932
+ if (line.trim() !== "") activity?.pulse();
41531
41933
  for (const chunk of processStreamLine$1(line, state)) {
41532
41934
  outputStarted = true;
41533
41935
  yield chunk;
@@ -48737,7 +49139,7 @@ var GlmCodingPlanAdapter = class extends LlmAdapter {
48737
49139
  };
48738
49140
  }
48739
49141
  async *stream(options) {
48740
- yield* wrapStreamWithWatchdog((watchdogSignal) => this.requestStream(options, watchdogSignal), options.signal, STREAM_IDLE_TIMEOUT_MS, STREAM_IDLE_TIMEOUT_CODE, PROVIDER_NAME$1);
49142
+ yield* wrapStreamWithWatchdog((watchdogSignal, activity) => this.requestStream(options, watchdogSignal, activity), options.signal, STREAM_IDLE_TIMEOUT_MS, STREAM_IDLE_TIMEOUT_CODE, PROVIDER_NAME$1);
48741
49143
  }
48742
49144
  /**
48743
49145
  * 一次请求的完整往返:选账号 → 定协议面 → 发 → 解析流。
@@ -48745,7 +49147,7 @@ var GlmCodingPlanAdapter = class extends LlmAdapter {
48745
49147
  * 账号轮转的循环只有一处:一次 429 或一次 AUTH 会把那个账号移出本次请求,
48746
49148
  * 由另一个账号来发**同一份**请求体。没有池时这个循环只跑一次。
48747
49149
  */
48748
- async *requestStream(options, signal) {
49150
+ async *requestStream(options, signal, activity) {
48749
49151
  const fetchFn = this.options.fetchFn ?? fetch;
48750
49152
  await this.settings();
48751
49153
  const requestOptions = offloadOldestRequestImages$2(normalizeGenerateOptions(options));
@@ -48830,10 +49232,12 @@ var GlmCodingPlanAdapter = class extends LlmAdapter {
48830
49232
  while (true) {
48831
49233
  const { done, value } = await reader.read();
48832
49234
  if (done) break;
49235
+ if (value !== void 0 && value.byteLength > 0) activity?.pulse();
48833
49236
  buffer += decoder.decode(value, { stream: true });
48834
49237
  const lines = buffer.split("\n");
48835
49238
  buffer = lines.pop() ?? "";
48836
49239
  for (const line of lines) {
49240
+ activity?.pulse();
48837
49241
  for (const chunk of processGlmAnthropicStreamLine(line, state)) yield chunk;
48838
49242
  if (state.finished) return;
48839
49243
  }
@@ -48854,10 +49258,12 @@ var GlmCodingPlanAdapter = class extends LlmAdapter {
48854
49258
  while (true) {
48855
49259
  const { done, value } = await reader.read();
48856
49260
  if (done) break;
49261
+ if (value !== void 0 && value.byteLength > 0) activity?.pulse();
48857
49262
  buffer += decoder.decode(value, { stream: true });
48858
49263
  const lines = buffer.split("\n");
48859
49264
  buffer = lines.pop() ?? "";
48860
49265
  for (const line of lines) {
49266
+ activity?.pulse();
48861
49267
  for (const chunk of processStreamLine(line, state)) yield chunk;
48862
49268
  if (state.finished) return;
48863
49269
  }
@@ -53686,7 +54092,8 @@ const Config = z.object({
53686
54092
  subagentModelTools: z.array(z.string()).default([]),
53687
54093
  subagentModelInheritTools: z.array(z.string()).default(DEFAULT_SUBAGENT_INHERIT_TOOLS),
53688
54094
  subagentModelScope: z.union([z.const("session"), z.const("preference")]).default("session"),
53689
- reasoningCollapseGuard: z.union([z.object({}), z.const(false)]).default({})
54095
+ reasoningCollapseGuard: z.union([z.object({}), z.const(false)]).default({}),
54096
+ codexStreamIdleTimeoutMs: z.number().min(1).max(MAX_TIMER_DELAY_MS).step(1).default(DEFAULT_STREAM_IDLE_TIMEOUT_MS)
53690
54097
  });
53691
54098
  const inject = [
53692
54099
  "webServer",
@@ -53969,7 +54376,8 @@ function apply(ctx, pluginConfig = {}) {
53969
54376
  onGenerationFinished: () => usage.invalidate(),
53970
54377
  outputVerbosity: () => preferences.status().outputVerbosity,
53971
54378
  fastMode: () => preferences.status().fastMode,
53972
- reasoningSummary: () => preferences.status().reasoningSummary
54379
+ reasoningSummary: () => preferences.status().reasoningSummary,
54380
+ codexStreamIdleTimeoutMs: pluginConfig.codexStreamIdleTimeoutMs
53973
54381
  }), preferences, (options) => oauth.credentials(void 0, { purpose: "tool" }).then((credentials) => loadCodexCatalog(credentials, {
53974
54382
  fetchFn: proxyFetch,
53975
54383
  signal: options?.signal
@@ -54157,17 +54565,17 @@ function apply(ctx, pluginConfig = {}) {
54157
54565
  {
54158
54566
  id: "ollama",
54159
54567
  providerId: PROVIDER_ID$5,
54160
- canToggle: false,
54568
+ canToggle: true,
54161
54569
  read: async () => {
54162
54570
  const accounts = await ollamaAccountPool.listAccounts().catch(() => []);
54163
- const current = ollamaModelSettings.status();
54571
+ const current = await ollamaModelSettings.read();
54164
54572
  const total = catalogTotal(current.catalogModels.length);
54165
- const enabled = current.enabledModelIds.length === 0 ? total : current.enabledModelIds.length;
54573
+ const selected = current.enabledModelIds === null ? total : current.enabledModelIds.length;
54166
54574
  return {
54167
- enabled: true,
54575
+ enabled: current.enabled !== false,
54168
54576
  accountCount: accounts.length,
54169
54577
  authenticated: routable(accounts),
54170
- enabledModelCount: total === null ? null : Math.min(enabled ?? 0, total),
54578
+ enabledModelCount: total === null || selected === null ? null : Math.min(selected, total),
54171
54579
  totalModelCount: total
54172
54580
  };
54173
54581
  }