@eddyskywalker/dsh-chatgpt-subscription 0.66.0 → 0.66.1

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 (34) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/lib/client.js +137 -9
  3. package/lib/client.js.map +1 -1
  4. package/lib/index.js +682 -77
  5. package/lib/types/client/antigravity/styles.d.ts.map +1 -1
  6. package/lib/types/client/glm-coding-plan/styles.d.ts.map +1 -1
  7. package/lib/types/client/kimi-code/KimiCodeSection.d.ts.map +1 -1
  8. package/lib/types/client/kimi-code/locales.d.ts +44 -2
  9. package/lib/types/client/kimi-code/locales.d.ts.map +1 -1
  10. package/lib/types/client/kimi-code/styles.d.ts.map +1 -1
  11. package/lib/types/client/locales-ru/kimi-code.d.ts.map +1 -1
  12. package/lib/types/client/workbuddy/styles.d.ts.map +1 -1
  13. package/lib/types/compat.d.ts +1 -1
  14. package/lib/types/host/cache-warmup/contracts.d.ts +1 -1
  15. package/lib/types/host/cache-warmup/contracts.d.ts.map +1 -1
  16. package/lib/types/host/cache-warmup/install.d.ts.map +1 -1
  17. package/lib/types/host/cache-warmup/projection.d.ts.map +1 -1
  18. package/lib/types/host/glm-coding-plan/adapter.d.ts +11 -0
  19. package/lib/types/host/glm-coding-plan/adapter.d.ts.map +1 -1
  20. package/lib/types/host/kimi-code/adapter.d.ts +4 -10
  21. package/lib/types/host/kimi-code/adapter.d.ts.map +1 -1
  22. package/lib/types/host/kimi-code/mapper.d.ts +11 -1
  23. package/lib/types/host/kimi-code/mapper.d.ts.map +1 -1
  24. package/lib/types/host/kimi-code/routes.d.ts.map +1 -1
  25. package/lib/types/host/kimi-code/session-cache-state.d.ts +19 -2
  26. package/lib/types/host/kimi-code/session-cache-state.d.ts.map +1 -1
  27. package/lib/types/host/kimi-code/tool-argument-guard.d.ts +36 -0
  28. package/lib/types/host/kimi-code/tool-argument-guard.d.ts.map +1 -0
  29. package/lib/types/host/kimi-code/tool-argument-recovery.d.ts +16 -0
  30. package/lib/types/host/kimi-code/tool-argument-recovery.d.ts.map +1 -0
  31. package/lib/types/index.d.ts.map +1 -1
  32. package/lib/types/shared/kimi-code-contracts.d.ts +63 -0
  33. package/lib/types/shared/kimi-code-contracts.d.ts.map +1 -1
  34. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -809,7 +809,7 @@ const ROUTE_PREFIX$5 = "/api/dsh-chatgpt-subscription";
809
809
  * `test/responses-client.test.ts` asserts the two agree, so a release that
810
810
  * forgets this constant fails the suite instead of shipping quietly.
811
811
  */
812
- const PLUGIN_VERSION = "0.66.0";
812
+ const PLUGIN_VERSION = "0.66.1";
813
813
  const CODEX_CHATGPT_PROVIDER_ID = "codex-chatgpt";
814
814
  const CODEX_API_BASE = "https://chatgpt.com/backend-api/codex";
815
815
  const CODEX_RESPONSES_URL = `${CODEX_API_BASE}/responses`;
@@ -15092,7 +15092,7 @@ async function* parseResponsesStream(response, signal, _legacyHiddenSandboxContr
15092
15092
  const tools = /* @__PURE__ */ new Map();
15093
15093
  const toolFor = (event, item) => {
15094
15094
  const itemId = string(event.item_id) ?? string(item?.id);
15095
- const outputIndex = number(event.output_index);
15095
+ const outputIndex = number$1(event.output_index);
15096
15096
  const key = itemId ?? (outputIndex === void 0 ? `tool-${tools.size}` : `index-${outputIndex}`);
15097
15097
  let tool = tools.get(key);
15098
15098
  if (tool === void 0) {
@@ -15421,12 +15421,12 @@ function visibleReasoningDelta(delta, currentVisibleChars, alreadyTruncated) {
15421
15421
  */
15422
15422
  function mapUsage$2(value) {
15423
15423
  if (value === null) return null;
15424
- const totalInput = number(value.input_tokens) ?? 0;
15425
- const outputTokens = number(value.output_tokens) ?? 0;
15424
+ const totalInput = number$1(value.input_tokens) ?? 0;
15425
+ const outputTokens = number$1(value.output_tokens) ?? 0;
15426
15426
  const details = record$3(value.input_tokens_details);
15427
- const cached = number(details?.cached_tokens);
15428
- const written = number(details?.cache_write_tokens);
15429
- const reasoning = number(record$3(value.output_tokens_details)?.reasoning_tokens);
15427
+ const cached = number$1(details?.cached_tokens);
15428
+ const written = number$1(details?.cache_write_tokens);
15429
+ const reasoning = number$1(record$3(value.output_tokens_details)?.reasoning_tokens);
15430
15430
  return {
15431
15431
  inputTokens: Math.max(0, totalInput - (cached ?? 0) - (written ?? 0)),
15432
15432
  outputTokens,
@@ -15481,7 +15481,7 @@ function record$3(value) {
15481
15481
  function string(value) {
15482
15482
  return typeof value === "string" ? value : void 0;
15483
15483
  }
15484
- function number(value) {
15484
+ function number$1(value) {
15485
15485
  const parsed = Number(value);
15486
15486
  return Number.isFinite(parsed) ? parsed : void 0;
15487
15487
  }
@@ -16579,8 +16579,8 @@ function parseCodexUsage(value) {
16579
16579
  for (const [index, value] of additional.entries()) {
16580
16580
  const limit = record$2(value);
16581
16581
  if (limit === null) continue;
16582
- const idSource = text$4(limit.limit_name) ?? text$4(limit.metered_feature) ?? `additional-${index + 1}`;
16583
- addBucket(buckets, usedIds, uniqueId(slug(idSource), usedIds), readableLimitName(text$4(limit.limit_name) ?? text$4(limit.metered_feature) ?? idSource), planType, limit.rate_limit);
16582
+ const idSource = text$5(limit.limit_name) ?? text$5(limit.metered_feature) ?? `additional-${index + 1}`;
16583
+ addBucket(buckets, usedIds, uniqueId(slug(idSource), usedIds), readableLimitName(text$5(limit.limit_name) ?? text$5(limit.metered_feature) ?? idSource), planType, limit.rate_limit);
16584
16584
  }
16585
16585
  return {
16586
16586
  buckets,
@@ -16665,7 +16665,7 @@ function parseResetCredits(value) {
16665
16665
  availableCreditIds: []
16666
16666
  };
16667
16667
  const available = (Array.isArray(data.credits) ? data.credits : []).map(record$2).filter((credit) => credit !== null && credit.status === "available").map((credit) => ({
16668
- id: text$4(credit.id),
16668
+ id: text$5(credit.id),
16669
16669
  expiresAt: timestamp(credit.expires_at)
16670
16670
  })).filter((credit) => credit.id !== null).sort((left, right) => (left.expiresAt ?? Number.MAX_SAFE_INTEGER) - (right.expiresAt ?? Number.MAX_SAFE_INTEGER));
16671
16671
  const reported = numeric(data.available_count);
@@ -16699,7 +16699,7 @@ function decimalText(value) {
16699
16699
  const trimmed = value.trim();
16700
16700
  return trimmed !== "" ? trimmed : null;
16701
16701
  }
16702
- function text$4(value) {
16702
+ function text$5(value) {
16703
16703
  return typeof value === "string" && value.trim() !== "" ? value.trim() : null;
16704
16704
  }
16705
16705
  function slug(value) {
@@ -24922,7 +24922,7 @@ function classifyCommandCodeFailure(status, detail) {
24922
24922
  };
24923
24923
  }
24924
24924
  /** Cooldown one rate-limited key takes when the provider states no delay. */
24925
- const POOL_COOLDOWN_MS$7 = 15 * 6e4;
24925
+ const POOL_COOLDOWN_MS$6 = 15 * 6e4;
24926
24926
  var CommandCodeAdapter = class extends LlmAdapter {
24927
24927
  store;
24928
24928
  modelSettings;
@@ -25110,7 +25110,7 @@ var CommandCodeAdapter = class extends LlmAdapter {
25110
25110
  }
25111
25111
  if (response.status === 429) {
25112
25112
  const after = retryAfterMs$1(response.headers);
25113
- await pool.markCooldown(accountId, after ?? POOL_COOLDOWN_MS$7, `${PROVIDER_NAME$10} 429`).catch(() => void 0);
25113
+ await pool.markCooldown(accountId, after ?? POOL_COOLDOWN_MS$6, `${PROVIDER_NAME$10} 429`).catch(() => void 0);
25114
25114
  if (await pool.hasAnotherAvailableAccount(tried)) continue;
25115
25115
  break;
25116
25116
  }
@@ -25185,7 +25185,7 @@ var CommandCodeAdapter = class extends LlmAdapter {
25185
25185
  const reclassified = reclassifyInBandStreamError(error, inBand);
25186
25186
  if (reclassified.code === "RATE_LIMIT" && pool !== null && accountId !== void 0) {
25187
25187
  const after = retryAfterMs$1(response.headers);
25188
- await pool.markCooldown(accountId, after ?? POOL_COOLDOWN_MS$7, `${PROVIDER_NAME$10} in-stream 429`).catch(() => void 0);
25188
+ await pool.markCooldown(accountId, after ?? POOL_COOLDOWN_MS$6, `${PROVIDER_NAME$10} in-stream 429`).catch(() => void 0);
25189
25189
  }
25190
25190
  throw reclassified;
25191
25191
  }
@@ -26371,7 +26371,7 @@ const STREAM_IDLE_TIMEOUT_MS$5 = 3e5;
26371
26371
  * A 429 here is a real quota or rate limit, not a blip, so the account is parked
26372
26372
  * for long enough that the next request goes to a different one.
26373
26373
  */
26374
- const POOL_COOLDOWN_MS$6 = 15 * 6e4;
26374
+ const POOL_COOLDOWN_MS$5 = 15 * 6e4;
26375
26375
  /**
26376
26376
  * NO fallback model names.
26377
26377
  *
@@ -27766,7 +27766,7 @@ var OllamaAdapter = class extends LlmAdapter {
27766
27766
  break;
27767
27767
  }
27768
27768
  if (lastStatus === 429) {
27769
- await pool.markCooldown(accountId, POOL_COOLDOWN_MS$6, `${PROVIDER_NAME$9} 429`).catch(() => void 0);
27769
+ await pool.markCooldown(accountId, POOL_COOLDOWN_MS$5, `${PROVIDER_NAME$9} 429`).catch(() => void 0);
27770
27770
  if (await pool.hasAnotherAvailableAccount(tried)) continue;
27771
27771
  break;
27772
27772
  }
@@ -29294,7 +29294,7 @@ function consecutiveWarmupHits(reports) {
29294
29294
  }
29295
29295
  }
29296
29296
  /** 把任意输入归一成一条用量报告;形状不对返回 undefined(绝不抛)。 */
29297
- function normalizeUsage(input) {
29297
+ function normalizeUsage$1(input) {
29298
29298
  if (input === null || input === void 0 || typeof input !== "object") return void 0;
29299
29299
  const sessionId = input.sessionId;
29300
29300
  if (typeof sessionId !== "string" || sessionId.trim() === "") return void 0;
@@ -29335,7 +29335,7 @@ function recordCacheWarmupUsage(input) {
29335
29335
  let sessionId = "";
29336
29336
  let provider;
29337
29337
  try {
29338
- const usage = normalizeUsage(input);
29338
+ const usage = normalizeUsage$1(input);
29339
29339
  if (usage === void 0) return neutralState("");
29340
29340
  sessionId = usage.sessionId;
29341
29341
  provider = usage.provider;
@@ -30799,6 +30799,57 @@ function planMultiSectionProjection(text) {
30799
30799
  sections
30800
30800
  };
30801
30801
  }
30802
+ /**
30803
+ * PTC 工具目录:保留完整的 namespace/name 索引,重 schema 由原文 ref 补读。
30804
+ *
30805
+ * 只认 code_tools_list / code_tools_search 的根对象形状。任意字段缺失、额外根成员
30806
+ * 或非 PTC 调用都回退原文,避免把业务 JSON 里的 tools 数组误当成工具发现结果。
30807
+ */
30808
+ function planToolCatalogProjection(text, toolName) {
30809
+ if (!isPtcTransportName(toolName)) return void 0;
30810
+ const candidate = parseJsonCandidate(text);
30811
+ if (candidate?.kind !== "object") return void 0;
30812
+ const record = candidate.record;
30813
+ if (Object.keys(record).some((key) => key !== "tools" && key !== "fallback")) return void 0;
30814
+ if (!Array.isArray(record.tools) || record.tools.length === 0) return void 0;
30815
+ const lines = [];
30816
+ for (const entry of record.tools) {
30817
+ if (!isPlainRecord$1(entry)) return void 0;
30818
+ if (typeof entry.name !== "string" || entry.name.trim() === "") return void 0;
30819
+ if (typeof entry.namespace !== "string" || entry.namespace.trim() === "") return void 0;
30820
+ if (typeof entry.description !== "string") return void 0;
30821
+ const name = entry.name.trim();
30822
+ const namespace = entry.namespace.trim();
30823
+ const description = entry.description.replace(/\s+/g, " ").trim();
30824
+ lines.push(` ${namespace}/${name}: ${clip(description, 180)}`);
30825
+ }
30826
+ const header = [`tools: ${record.tools.length} (complete name index; descriptions clipped)`];
30827
+ if (typeof record.fallback === "string" && record.fallback.trim() !== "") header.push("fallback: " + clip(record.fallback.replace(/\s+/g, " ").trim(), 240));
30828
+ return {
30829
+ kind: "preview",
30830
+ strategy: "tool-catalog",
30831
+ sections: [{ lines: header }, { lines }]
30832
+ };
30833
+ }
30834
+ /** 成功测试日志必须有明确通过汇总,且没有任何可识别的失败证据。 */
30835
+ function isSuccessfulTestEvidence(text, evidence) {
30836
+ if (evidence.failures.length > 0 || evidence.summary.length === 0) return false;
30837
+ if (!evidence.summary.some((line) => /\b\d+\s+passed\b/i.test(line))) return false;
30838
+ if (/(?:^|\s)[1-9]\d*\s+failed\b/i.test(text)) return false;
30839
+ const exitMatch = /(?:exit code|exited with code|process exited with code)[:=\s]+(-?\d+)/i.exec(text) ?? /\[exit code: (-?\d+)\]/i.exec(text);
30840
+ if (exitMatch !== null && Number(exitMatch[1]) !== 0) return false;
30841
+ for (const raw of text.split("\n")) {
30842
+ const trimmed = raw.trim();
30843
+ if (trimmed === "" || /^npm notice\b/i.test(trimmed)) continue;
30844
+ if (/^(?:PASS\b|[✓✔]|ok\s+\d+)/i.test(trimmed)) continue;
30845
+ if (/^(?:stdout|stderr)\s*\|/i.test(trimmed)) continue;
30846
+ if (/^\(node:\d+\).*Warning:/i.test(trimmed)) continue;
30847
+ if (/^\s*(?:0|no)\s+(?:errors?|failures?|failed)\b/i.test(trimmed)) continue;
30848
+ if (/\b\d+\s+passed\b/i.test(trimmed)) continue;
30849
+ if (SHELL_ERROR_LINE.test(trimmed)) return false;
30850
+ }
30851
+ return true;
30852
+ }
30802
30853
  /** 对一段纯文本(非 JSON 文档)做投影计划判定。 */
30803
30854
  function planPlainTextProjection(rawText, toolName) {
30804
30855
  const text = stripAnsi(rawText);
@@ -30816,6 +30867,11 @@ function planPlainTextProjection(rawText, toolName) {
30816
30867
  strategy: "test-failure",
30817
30868
  sections: buildTestSections(test)
30818
30869
  };
30870
+ if (test !== void 0 && isSuccessfulTestEvidence(text, test)) return {
30871
+ kind: "preview",
30872
+ strategy: "test-success",
30873
+ sections: buildTestSections(test)
30874
+ };
30819
30875
  const grep = extractGrepEvidence(text);
30820
30876
  if (grep !== void 0) return {
30821
30877
  kind: "preview",
@@ -30886,6 +30942,10 @@ function planProjection(text, toolName, navigation, retrievalOnly, spilled = fal
30886
30942
  const multiSection = planMultiSectionProjection(text);
30887
30943
  if (multiSection !== void 0) return multiSection;
30888
30944
  }
30945
+ if (isJsonDocument(text)) {
30946
+ const toolCatalog = planToolCatalogProjection(text, toolName);
30947
+ if (toolCatalog !== void 0) return toolCatalog;
30948
+ }
30889
30949
  if (looksLikeContract(text)) return {
30890
30950
  kind: "verbatim",
30891
30951
  strategy: "verbatim-contract"
@@ -34470,6 +34530,150 @@ function videoBlockToInline(block, videos, videoAccepted, omit) {
34470
34530
  } } : { omission: omit("unsupported-container", label) };
34471
34531
  }
34472
34532
  //#endregion
34533
+ //#region src/host/kimi-code/tool-argument-guard.ts
34534
+ const TOOL_ARGUMENT_BYTES_EXCEEDED_CODE = "KIMI_TOOL_ARGUMENT_BYTES_EXCEEDED";
34535
+ const TOOL_ARGUMENT_REPEATED_KEY_CODE = "KIMI_TOOL_ARGUMENT_REPEATED_KEY";
34536
+ /** Whether one adapter failure belongs to the recoverable argument guard. */
34537
+ function isKimiToolArgumentGuardCode(code) {
34538
+ return code === "KIMI_TOOL_ARGUMENT_BYTES_EXCEEDED" || code === "KIMI_TOOL_ARGUMENT_REPEATED_KEY";
34539
+ }
34540
+ const ASK_USER_ARGUMENT_LIMIT = 32 * 1024;
34541
+ const LARGE_PROGRAM_ARGUMENT_LIMIT = 1024 * 1024;
34542
+ const DEFAULT_ARGUMENT_LIMIT = 256 * 1024;
34543
+ const REPEATED_KEY_LIMIT = 8;
34544
+ const MAX_TRACKED_KEY_GROUPS = 64;
34545
+ const MAX_SCANNED_KEY_CHARS = 1024;
34546
+ /** Large source/file payloads need a different ceiling from coordination cards. */
34547
+ function toolArgumentLimit(toolName) {
34548
+ if (toolName === "ask_user_question") return ASK_USER_ARGUMENT_LIMIT;
34549
+ if (toolName === "write" || toolName === "edit" || toolName === "code_run" || toolName === "run_code") return LARGE_PROGRAM_ARGUMENT_LIMIT;
34550
+ return DEFAULT_ARGUMENT_LIMIT;
34551
+ }
34552
+ /** Split `header_comment`, `header_unused`, and `header___` into one family. */
34553
+ function keyFamily(key) {
34554
+ const suffix = /_(?:comment|unused)$|_+$/.exec(key);
34555
+ if (suffix === null || suffix.index === 0) return {
34556
+ stem: key,
34557
+ variant: false
34558
+ };
34559
+ return {
34560
+ stem: key.slice(0, suffix.index),
34561
+ variant: true
34562
+ };
34563
+ }
34564
+ var KimiToolArgumentGuard = class {
34565
+ toolName;
34566
+ bytes = 0;
34567
+ inString = false;
34568
+ escaped = false;
34569
+ afterString = false;
34570
+ stringRaw = "";
34571
+ stringTooLong = false;
34572
+ highSurrogate = "";
34573
+ keyGroups = /* @__PURE__ */ new Map();
34574
+ violation;
34575
+ constructor(toolName) {
34576
+ this.toolName = toolName;
34577
+ }
34578
+ observe(delta) {
34579
+ if (this.violation !== void 0) return this.violation;
34580
+ const text = this.highSurrogate + delta;
34581
+ this.highSurrogate = "";
34582
+ if (text === "") return void 0;
34583
+ const last = text.charCodeAt(text.length - 1);
34584
+ const complete = last >= 55296 && last <= 56319 ? text.slice(0, -1) : text;
34585
+ if (complete.length !== text.length) this.highSurrogate = text.at(-1) ?? "";
34586
+ this.bytes += Buffer.byteLength(complete, "utf8");
34587
+ if (this.bytes > toolArgumentLimit(this.toolName)) return this.fail("argument-bytes");
34588
+ for (const char of complete) {
34589
+ const violation = this.observeChar(char);
34590
+ if (violation !== void 0) return violation;
34591
+ }
34592
+ }
34593
+ /** Account for a trailing unmatched surrogate without leaving it unbudgeted. */
34594
+ finish() {
34595
+ if (this.highSurrogate !== "") {
34596
+ this.highSurrogate = "";
34597
+ this.bytes += Buffer.byteLength("\ud800", "utf8");
34598
+ if (this.bytes > toolArgumentLimit(this.toolName)) return this.fail("argument-bytes");
34599
+ }
34600
+ return this.violation;
34601
+ }
34602
+ fail(rule) {
34603
+ this.violation = {
34604
+ toolName: this.toolName || "unknown",
34605
+ rule,
34606
+ bytes: this.bytes
34607
+ };
34608
+ return this.violation;
34609
+ }
34610
+ observeChar(char) {
34611
+ if (this.inString) {
34612
+ if (this.escaped) {
34613
+ this.escaped = false;
34614
+ if (!this.stringTooLong) this.stringRaw += char;
34615
+ return;
34616
+ }
34617
+ if (char === "\\") {
34618
+ this.escaped = true;
34619
+ if (!this.stringTooLong) this.stringRaw += char;
34620
+ return;
34621
+ }
34622
+ if (char === "\"") {
34623
+ this.inString = false;
34624
+ this.afterString = true;
34625
+ return;
34626
+ }
34627
+ if (!this.stringTooLong) {
34628
+ this.stringRaw += char;
34629
+ if (this.stringRaw.length > MAX_SCANNED_KEY_CHARS) {
34630
+ this.stringTooLong = true;
34631
+ this.stringRaw = "";
34632
+ }
34633
+ }
34634
+ return;
34635
+ }
34636
+ if (this.afterString) {
34637
+ if (/\s/.test(char)) return void 0;
34638
+ this.afterString = false;
34639
+ if (char === ":") {
34640
+ this.observeKey();
34641
+ return this.violation;
34642
+ }
34643
+ this.stringRaw = "";
34644
+ this.stringTooLong = false;
34645
+ }
34646
+ if (char === "\"") {
34647
+ this.inString = true;
34648
+ this.escaped = false;
34649
+ this.stringRaw = "";
34650
+ this.stringTooLong = false;
34651
+ }
34652
+ }
34653
+ observeKey() {
34654
+ if (this.stringTooLong || this.stringRaw === "") return;
34655
+ try {
34656
+ const key = JSON.parse("\"" + this.stringRaw + "\"");
34657
+ if (typeof key !== "string" || key === "") return;
34658
+ const family = keyFamily(key);
34659
+ if (family.stem === "") return;
34660
+ const group = this.keyGroups.get(family.stem) ?? {
34661
+ count: 0,
34662
+ sawVariant: false
34663
+ };
34664
+ group.count += 1;
34665
+ group.sawVariant ||= family.variant;
34666
+ this.keyGroups.delete(family.stem);
34667
+ this.keyGroups.set(family.stem, group);
34668
+ while (this.keyGroups.size > MAX_TRACKED_KEY_GROUPS) {
34669
+ const oldest = this.keyGroups.keys().next();
34670
+ if (oldest.done !== true) this.keyGroups.delete(oldest.value);
34671
+ }
34672
+ if (group.sawVariant && group.count >= REPEATED_KEY_LIMIT) this.fail("repeated-key");
34673
+ } catch {}
34674
+ }
34675
+ };
34676
+ //#endregion
34473
34677
  //#region src/host/kimi-code/mapper.ts
34474
34678
  /**
34475
34679
  * Provider-wire mapping for the Kimi Code coding endpoints.
@@ -36154,6 +36358,9 @@ function createStreamState$5(wire, sessionId, sideChannel = false) {
36154
36358
  cacheWrite5mTokens: 0,
36155
36359
  cacheWrite1hTokens: 0,
36156
36360
  reasoningTokens: 0,
36361
+ cacheReadReported: false,
36362
+ cacheWriteReported: false,
36363
+ reasoningReported: false,
36157
36364
  sawUsage: false,
36158
36365
  toolCallIds: new ToolCallIdNormalizer()
36159
36366
  };
@@ -36176,9 +36383,22 @@ function closeCurrent$5(state) {
36176
36383
  block
36177
36384
  }];
36178
36385
  }
36386
+ function throwToolGuardViolation(state, call, violation) {
36387
+ if (violation === void 0) return;
36388
+ state.toolGuard = violation;
36389
+ const reason = violation.rule === "argument-bytes" ? `arguments exceeded the ${violation.rule} safety budget` : "arguments contained a runaway repeated-key family";
36390
+ throw new LlmError$1(`Kimi Code stopped tool call "${violation.toolName}": ${reason} at ${violation.bytes} bytes. The tool was not executed.`, violation.rule === "argument-bytes" ? TOOL_ARGUMENT_BYTES_EXCEEDED_CODE : TOOL_ARGUMENT_REPEATED_KEY_CODE);
36391
+ }
36392
+ function appendGuardedArguments(state, call, delta) {
36393
+ if (delta === "") return;
36394
+ call.arguments += delta;
36395
+ call.guard ??= new KimiToolArgumentGuard(call.name);
36396
+ throwToolGuardViolation(state, call, call.guard.observe(delta));
36397
+ }
36179
36398
  function closeToolCalls$5(state) {
36180
36399
  const out = [];
36181
36400
  for (const [wireIndex, call] of [...state.toolCalls.entries()].sort((a, b) => a[0] - b[0])) {
36401
+ throwToolGuardViolation(state, call, call.guard?.finish());
36182
36402
  const block = {
36183
36403
  type: "tool-call",
36184
36404
  id: toToolCallId(state.toolCallIds.normalize(call.id)),
@@ -36247,8 +36467,14 @@ function processOpenAIStreamLine(line, state) {
36247
36467
  state.inputTokens = Math.max(0, prompt - cached - written);
36248
36468
  state.cacheReadTokens = cached;
36249
36469
  state.cacheWriteTokens = written;
36470
+ state.cacheReadReported = details !== void 0 && typeof details.cached_tokens === "number" && Number.isFinite(details.cached_tokens);
36471
+ state.cacheWriteReported = details !== void 0 && typeof details.cache_write_tokens === "number" && Number.isFinite(details.cache_write_tokens);
36250
36472
  state.outputTokens = numberOr$8(usage.completion_tokens, state.outputTokens);
36251
- if (isRecord$53(usage.completion_tokens_details)) state.reasoningTokens = numberOr$8(usage.completion_tokens_details.reasoning_tokens, state.reasoningTokens);
36473
+ if (isRecord$53(usage.completion_tokens_details)) {
36474
+ const reasoning = usage.completion_tokens_details.reasoning_tokens;
36475
+ state.reasoningReported = typeof reasoning === "number" && Number.isFinite(reasoning);
36476
+ state.reasoningTokens = numberOr$8(reasoning, state.reasoningTokens);
36477
+ } else state.reasoningReported = false;
36252
36478
  }
36253
36479
  const choices = Array.isArray(chunk.choices) ? chunk.choices : [];
36254
36480
  const choice = isRecord$53(choices[0]) ? choices[0] : void 0;
@@ -36352,7 +36578,7 @@ function applyOpenAIToolDelta(entry, state) {
36352
36578
  if (name !== void 0 && name !== "") call.name = name;
36353
36579
  }
36354
36580
  const argsDelta = asString$21(fn.arguments) ?? "";
36355
- if (argsDelta !== "") call.arguments += argsDelta;
36581
+ appendGuardedArguments(state, call, argsDelta);
36356
36582
  if (!call.started) {
36357
36583
  call.started = true;
36358
36584
  state.hasToolCall = true;
@@ -36390,7 +36616,13 @@ function processAnthropicStreamLine(line, state) {
36390
36616
  state.inputTokens = numberOr$8(usage.input_tokens, 0);
36391
36617
  state.cacheReadTokens = numberOr$8(usage.cache_read_input_tokens, 0);
36392
36618
  state.cacheWriteTokens = numberOr$8(usage.cache_creation_input_tokens, 0);
36619
+ state.cacheReadReported = typeof usage.cache_read_input_tokens === "number" && Number.isFinite(usage.cache_read_input_tokens);
36620
+ state.cacheWriteReported = typeof usage.cache_creation_input_tokens === "number" && Number.isFinite(usage.cache_creation_input_tokens);
36393
36621
  state.outputTokens = numberOr$8(usage.output_tokens, 0);
36622
+ const reasoningDetails = isRecord$53(usage.output_tokens_details) ? usage.output_tokens_details : void 0;
36623
+ const reasoning = usage.reasoning_tokens ?? reasoningDetails?.reasoning_tokens;
36624
+ state.reasoningReported = typeof reasoning === "number" && Number.isFinite(reasoning);
36625
+ state.reasoningTokens = numberOr$8(reasoning, state.reasoningTokens);
36394
36626
  }
36395
36627
  const stop = message ? asString$21(message.stop_reason) : void 0;
36396
36628
  if (stop !== void 0) state.finishReason = stop;
@@ -36454,7 +36686,7 @@ function processAnthropicStreamLine(line, state) {
36454
36686
  const pending = state.toolCalls.get(contentIndex);
36455
36687
  const partial = asString$21(delta.partial_json) ?? "";
36456
36688
  if (pending !== void 0) {
36457
- pending.arguments += partial;
36689
+ appendGuardedArguments(state, pending, partial);
36458
36690
  out.push({
36459
36691
  type: "tool-call-delta",
36460
36692
  index: pending.blockIndex,
@@ -36502,6 +36734,7 @@ function processAnthropicStreamLine(line, state) {
36502
36734
  const contentIndex = numberOr$8(event.index, 0);
36503
36735
  const pending = state.toolCalls.get(contentIndex);
36504
36736
  if (pending !== void 0) {
36737
+ throwToolGuardViolation(state, pending, pending.guard?.finish());
36505
36738
  state.toolCalls.delete(contentIndex);
36506
36739
  const block = {
36507
36740
  type: "tool-call",
@@ -36528,6 +36761,12 @@ function processAnthropicStreamLine(line, state) {
36528
36761
  if (usage) {
36529
36762
  state.sawUsage = true;
36530
36763
  state.outputTokens = numberOr$8(usage.output_tokens, state.outputTokens);
36764
+ const reasoningDetails = isRecord$53(usage.output_tokens_details) ? usage.output_tokens_details : void 0;
36765
+ const reasoning = usage.reasoning_tokens ?? reasoningDetails?.reasoning_tokens;
36766
+ if (typeof reasoning === "number" && Number.isFinite(reasoning)) {
36767
+ state.reasoningReported = true;
36768
+ state.reasoningTokens = reasoning;
36769
+ }
36531
36770
  }
36532
36771
  return out;
36533
36772
  }
@@ -36971,7 +37210,7 @@ function closeStream$4(state, accountId) {
36971
37210
  state.finished = true;
36972
37211
  const out = [...closeCurrent$5(state), ...closeToolCalls$5(state)];
36973
37212
  if (state.sawUsage) {
36974
- recordCacheStats(state, state.sessionId, accountId);
37213
+ recordCacheStats(state, state.sessionId, accountId ?? state.accountId);
36975
37214
  out.push({
36976
37215
  type: "usage",
36977
37216
  usage: tokenUsage$5(state)
@@ -37119,6 +37358,27 @@ var SessionCacheStateStore = class extends CommonSessionCacheStateStore {
37119
37358
  normalizeRecord: normalizeRecord$2
37120
37359
  });
37121
37360
  }
37361
+ /** Append bounded request evidence, including a first request that failed before usage. */
37362
+ noteRequest(sessionId, request) {
37363
+ const base = this.read(sessionId) ?? {
37364
+ lastActiveAt: request.startedAt,
37365
+ totalTokens: 0,
37366
+ requests: 0,
37367
+ cachedTokens: 0,
37368
+ freshTokens: 0,
37369
+ outputTokens: 0,
37370
+ cacheWriteTokens: 0,
37371
+ cacheWrite5mTokens: 0,
37372
+ cacheWrite1hTokens: 0,
37373
+ updatedAt: request.endedAt
37374
+ };
37375
+ this.write(sessionId, {
37376
+ ...base,
37377
+ lastActiveAt: Math.max(base.lastActiveAt, request.endedAt),
37378
+ recentRequests: [...base.recentRequests ?? [], request].slice(-20),
37379
+ updatedAt: request.endedAt
37380
+ });
37381
+ }
37122
37382
  /** Update the warmup streak without creating a record for an unknown session. */
37123
37383
  noteWarmupStreak(sessionId, consecutiveHits) {
37124
37384
  this.update(sessionId, (existing) => {
@@ -37133,6 +37393,94 @@ var SessionCacheStateStore = class extends CommonSessionCacheStateStore {
37133
37393
  });
37134
37394
  }
37135
37395
  };
37396
+ function optionalText(value, maxLength = 256) {
37397
+ return typeof value === "string" && value.trim() !== "" ? value.trim().slice(0, maxLength) : void 0;
37398
+ }
37399
+ function nullableCount(value) {
37400
+ return value === null ? null : nonNegative(value);
37401
+ }
37402
+ function normalizeAttempt(value) {
37403
+ if (!isRecord$52(value)) return void 0;
37404
+ const startedAt = finite(value.startedAt);
37405
+ if (startedAt === void 0) return void 0;
37406
+ const poolAction = value.poolAction === "retry-same-account" || value.poolAction === "cooldown-and-rotate" || value.poolAction === "mark-auth-failed" || value.poolAction === "none" ? value.poolAction : void 0;
37407
+ const status = nonNegative(value.status);
37408
+ const endedAt = finite(value.endedAt);
37409
+ const retryAfterMs = nonNegative(value.retryAfterMs);
37410
+ const accountId = optionalText(value.accountId);
37411
+ const code = optionalText(value.code);
37412
+ const providerRequestId = optionalText(value.providerRequestId, 128);
37413
+ return {
37414
+ startedAt,
37415
+ ...accountId === void 0 ? {} : { accountId },
37416
+ ...endedAt === void 0 ? {} : { endedAt },
37417
+ ...status === void 0 ? {} : { status },
37418
+ ...code === void 0 ? {} : { code },
37419
+ ...poolAction === void 0 ? {} : { poolAction },
37420
+ ...retryAfterMs === void 0 ? {} : { retryAfterMs },
37421
+ ...providerRequestId === void 0 ? {} : { providerRequestId }
37422
+ };
37423
+ }
37424
+ function normalizeUsage(value) {
37425
+ if (!isRecord$52(value)) return void 0;
37426
+ const freshTokens = nonNegative(value.freshTokens);
37427
+ const outputTokens = nonNegative(value.outputTokens);
37428
+ const cacheReadTokens = nullableCount(value.cacheReadTokens);
37429
+ const cacheWriteTokens = nullableCount(value.cacheWriteTokens);
37430
+ const reasoningTokens = nullableCount(value.reasoningTokens);
37431
+ if (freshTokens === void 0 || outputTokens === void 0 || cacheReadTokens === void 0 || cacheWriteTokens === void 0 || reasoningTokens === void 0) return void 0;
37432
+ return {
37433
+ freshTokens,
37434
+ cacheReadTokens,
37435
+ cacheWriteTokens,
37436
+ outputTokens,
37437
+ reasoningTokens
37438
+ };
37439
+ }
37440
+ function normalizeRequestDiagnostic(value) {
37441
+ if (!isRecord$52(value)) return void 0;
37442
+ const id = optionalText(value.id, 128);
37443
+ const model = optionalText(value.model, 256);
37444
+ const startedAt = finite(value.startedAt);
37445
+ const endedAt = finite(value.endedAt);
37446
+ const wire = value.wire === "openai" || value.wire === "anthropic" ? value.wire : void 0;
37447
+ const outcome = value.outcome === "success" || value.outcome === "error" || value.outcome === "aborted" ? value.outcome : void 0;
37448
+ if (id === void 0 || model === void 0 || startedAt === void 0 || endedAt === void 0 || wire === void 0 || outcome === void 0) return void 0;
37449
+ const usage = normalizeUsage(value.usage);
37450
+ const attempts = (Array.isArray(value.attempts) ? value.attempts : []).map(normalizeAttempt).filter((attempt) => attempt !== void 0);
37451
+ const accountId = optionalText(value.accountId);
37452
+ const previousAccountId = optionalText(value.previousAccountId);
37453
+ const code = optionalText(value.code);
37454
+ const finishReason = optionalText(value.finishReason);
37455
+ const guard = isRecord$52(value.toolGuard) ? value.toolGuard : void 0;
37456
+ const guardName = optionalText(guard?.toolName);
37457
+ const guardBytes = nonNegative(guard?.bytes);
37458
+ const guardRule = guard?.rule === "argument-bytes" || guard?.rule === "repeated-key" ? guard.rule : void 0;
37459
+ return {
37460
+ id,
37461
+ startedAt,
37462
+ endedAt,
37463
+ model,
37464
+ wire,
37465
+ accountChanged: value.accountChanged === true,
37466
+ outcome,
37467
+ attempts,
37468
+ ...accountId === void 0 ? {} : { accountId },
37469
+ ...previousAccountId === void 0 ? {} : { previousAccountId },
37470
+ ...code === void 0 ? {} : { code },
37471
+ ...finishReason === void 0 ? {} : { finishReason },
37472
+ ...usage === void 0 ? {} : { usage },
37473
+ ...guardName === void 0 || guardBytes === void 0 || guardRule === void 0 ? {} : { toolGuard: {
37474
+ toolName: guardName,
37475
+ bytes: guardBytes,
37476
+ rule: guardRule
37477
+ } }
37478
+ };
37479
+ }
37480
+ function normalizeRecentRequests(value) {
37481
+ if (!Array.isArray(value)) return [];
37482
+ return value.map(normalizeRequestDiagnostic).filter((request) => request !== void 0).slice(-20);
37483
+ }
37136
37484
  function normalizeRecord$2(value) {
37137
37485
  if (!isRecord$52(value)) return void 0;
37138
37486
  const lastActiveAt = finite(value.lastActiveAt);
@@ -37141,10 +37489,16 @@ function normalizeRecord$2(value) {
37141
37489
  const drift = typeof value.lastDrift === "string" && value.lastDrift !== "" ? value.lastDrift : void 0;
37142
37490
  const firstRequestCachedTokens = nonNegative(value.firstRequestCachedTokens);
37143
37491
  const firstRequestPromptTokens = nonNegative(value.firstRequestPromptTokens);
37492
+ const lastRequestCachedTokens = nonNegative(value.lastRequestCachedTokens);
37493
+ const lastRequestFreshTokens = nonNegative(value.lastRequestFreshTokens);
37494
+ const previousRequestPromptTokens = nonNegative(value.previousRequestPromptTokens);
37495
+ const lastAccountId = typeof value.lastAccountId === "string" && value.lastAccountId.trim() !== "" ? value.lastAccountId.trim() : void 0;
37496
+ const lastAccountAt = nonNegative(value.lastAccountAt);
37144
37497
  const warmupStreak = count$1(value.warmupConsecutiveHits);
37145
37498
  const budgetDropped = droppedImageKeys(value.budgetDropped);
37146
37499
  const lastRequestImageBytes = nonNegative(value.lastRequestImageBytes);
37147
37500
  const lastDroppedImages = nonNegative(value.lastDroppedImages);
37501
+ const recentRequests = normalizeRecentRequests(value.recentRequests);
37148
37502
  return {
37149
37503
  lastActiveAt,
37150
37504
  updatedAt,
@@ -37159,6 +37513,12 @@ function normalizeRecord$2(value) {
37159
37513
  ...drift === void 0 ? {} : { lastDrift: drift },
37160
37514
  ...firstRequestCachedTokens === void 0 ? {} : { firstRequestCachedTokens },
37161
37515
  ...firstRequestPromptTokens === void 0 ? {} : { firstRequestPromptTokens },
37516
+ ...lastRequestCachedTokens === void 0 ? {} : { lastRequestCachedTokens },
37517
+ ...lastRequestFreshTokens === void 0 ? {} : { lastRequestFreshTokens },
37518
+ ...previousRequestPromptTokens === void 0 ? {} : { previousRequestPromptTokens },
37519
+ ...lastAccountId === void 0 ? {} : { lastAccountId },
37520
+ ...lastAccountAt === void 0 ? {} : { lastAccountAt },
37521
+ ...recentRequests.length > 0 ? { recentRequests } : {},
37162
37522
  ...warmupStreak > 0 ? { warmupConsecutiveHits: warmupStreak } : {},
37163
37523
  ...budgetDropped.length > 0 ? { budgetDropped } : {},
37164
37524
  ...lastRequestImageBytes === void 0 ? {} : { lastRequestImageBytes },
@@ -38259,6 +38619,7 @@ function classifyKimiFailure(status, bodyText) {
38259
38619
  const detail = summarizeFailureBody$1(bodyText);
38260
38620
  if (isHttpContextOverflow(status, bodyText)) return {
38261
38621
  code: CONTEXT_OVERFLOW_CODE,
38622
+ poolAction: "none",
38262
38623
  retryable: false,
38263
38624
  accountScoped: false,
38264
38625
  upstreamOverload: false,
@@ -38266,6 +38627,7 @@ function classifyKimiFailure(status, bodyText) {
38266
38627
  };
38267
38628
  if (status === 400 && isKimiBodySizeRefusal(detail)) return {
38268
38629
  code: CONTEXT_OVERFLOW_CODE,
38630
+ poolAction: "none",
38269
38631
  retryable: false,
38270
38632
  accountScoped: false,
38271
38633
  upstreamOverload: false,
@@ -38273,6 +38635,7 @@ function classifyKimiFailure(status, bodyText) {
38273
38635
  };
38274
38636
  if (status === 402) return {
38275
38637
  code: "SERVER",
38638
+ poolAction: "retry-same-account",
38276
38639
  retryable: true,
38277
38640
  accountScoped: false,
38278
38641
  upstreamOverload: false,
@@ -38281,6 +38644,7 @@ function classifyKimiFailure(status, bodyText) {
38281
38644
  if (status === 401 || status === 403) {
38282
38645
  if (matchesAny$1(detail, ENTITLEMENT_PATTERNS)) return {
38283
38646
  code: "PROVIDER_ERROR",
38647
+ poolAction: "none",
38284
38648
  retryable: false,
38285
38649
  accountScoped: false,
38286
38650
  upstreamOverload: false,
@@ -38290,6 +38654,7 @@ function classifyKimiFailure(status, bodyText) {
38290
38654
  const limitReached = matchesAny$1(detail, ACCOUNT_LIMIT_PATTERNS);
38291
38655
  return {
38292
38656
  code: "PROVIDER_ERROR",
38657
+ poolAction: "cooldown-and-rotate",
38293
38658
  retryable: false,
38294
38659
  accountScoped: true,
38295
38660
  upstreamOverload: false,
@@ -38298,6 +38663,7 @@ function classifyKimiFailure(status, bodyText) {
38298
38663
  }
38299
38664
  return {
38300
38665
  code: "INVALID_CREDENTIAL",
38666
+ poolAction: "mark-auth-failed",
38301
38667
  retryable: false,
38302
38668
  accountScoped: false,
38303
38669
  upstreamOverload: false,
@@ -38307,6 +38673,7 @@ function classifyKimiFailure(status, bodyText) {
38307
38673
  if (status === 429) {
38308
38674
  if (matchesAny$1(detail, QUOTA_EXHAUSTED_PATTERNS$1)) return {
38309
38675
  code: "PROVIDER_ERROR",
38676
+ poolAction: "cooldown-and-rotate",
38310
38677
  retryable: false,
38311
38678
  accountScoped: true,
38312
38679
  upstreamOverload: false,
@@ -38314,6 +38681,7 @@ function classifyKimiFailure(status, bodyText) {
38314
38681
  };
38315
38682
  if (matchesAny$1(detail, UPSTREAM_OVERLOAD_PATTERNS)) return {
38316
38683
  code: "SERVER",
38684
+ poolAction: "retry-same-account",
38317
38685
  retryable: true,
38318
38686
  accountScoped: false,
38319
38687
  upstreamOverload: true,
@@ -38321,6 +38689,7 @@ function classifyKimiFailure(status, bodyText) {
38321
38689
  };
38322
38690
  return {
38323
38691
  code: "RATE_LIMIT",
38692
+ poolAction: "retry-same-account",
38324
38693
  retryable: true,
38325
38694
  accountScoped: false,
38326
38695
  upstreamOverload: false,
@@ -38329,6 +38698,7 @@ function classifyKimiFailure(status, bodyText) {
38329
38698
  }
38330
38699
  if (status >= 500) return {
38331
38700
  code: "SERVER",
38701
+ poolAction: "retry-same-account",
38332
38702
  retryable: true,
38333
38703
  accountScoped: false,
38334
38704
  upstreamOverload: matchesAny$1(detail, UPSTREAM_OVERLOAD_PATTERNS),
@@ -38336,6 +38706,7 @@ function classifyKimiFailure(status, bodyText) {
38336
38706
  };
38337
38707
  if (status === 400) return {
38338
38708
  code: "PROVIDER_ERROR",
38709
+ poolAction: "none",
38339
38710
  retryable: false,
38340
38711
  accountScoped: false,
38341
38712
  upstreamOverload: false,
@@ -38343,6 +38714,7 @@ function classifyKimiFailure(status, bodyText) {
38343
38714
  };
38344
38715
  return {
38345
38716
  code: "PROVIDER_ERROR",
38717
+ poolAction: "none",
38346
38718
  retryable: false,
38347
38719
  accountScoped: false,
38348
38720
  upstreamOverload: false,
@@ -38378,18 +38750,33 @@ function accountLimitCooldownMs(bodyText, now = Date.now()) {
38378
38750
  resetAtMs: field !== null ? parseTimestamp(Number(field[1])) : instant !== null ? Date.parse(instant[0].replace(" ", "T")) : null,
38379
38751
  now,
38380
38752
  fallbackMs: BILLING_CYCLE_PATTERN.test(bodyText) ? BILLING_CYCLE_COOLDOWN_MS : ACCOUNT_LIMIT_COOLDOWN_MS,
38381
- minimumMs: POOL_COOLDOWN_MS$5,
38753
+ minimumMs: MIN_ACCOUNT_LIMIT_COOLDOWN_MS,
38382
38754
  maximumMs: MAX_ACCOUNT_LIMIT_COOLDOWN_MS
38383
38755
  });
38384
38756
  }
38757
+ /** Minimum cooldown for a proven account-owned usage limit near its reset. */
38758
+ const MIN_ACCOUNT_LIMIT_COOLDOWN_MS = 15 * 6e4;
38385
38759
  /**
38386
- * Cooldown one rate-limited account takes when the provider states no delay.
38760
+ * The account a shared/transient failure should use on the harness's next attempt.
38387
38761
  *
38388
- * 只在**真正的**限流上使用:上游引擎过载走 SERVER,既不落这条窗口,也不消耗轮转
38389
- * 名额。它是 15 分钟而不是服务自己说的时长,正是因为拿不准——拿不准的那次猜测
38390
- * 落在一个只有单个账号的号池上,代价是整个号池在 15 分钟里彻底不可用。
38762
+ * DSH rebuilds GenerateOptions for a retry, but keeps the step's original abort
38763
+ * signal. Keying by that signal avoids a process-global session latch: concurrent
38764
+ * sessions cannot affect one another, and an abandoned retry chain disappears by GC.
38391
38765
  */
38392
- const POOL_COOLDOWN_MS$5 = 15 * 6e4;
38766
+ const sameAccountRetryBySignal = /* @__PURE__ */ new WeakMap();
38767
+ function rememberSameAccountRetry(signal, accountId) {
38768
+ if (signal !== void 0 && accountId !== void 0 && !signal.aborted) sameAccountRetryBySignal.set(signal, accountId);
38769
+ }
38770
+ function clearSameAccountRetry(signal) {
38771
+ if (signal !== void 0) sameAccountRetryBySignal.delete(signal);
38772
+ }
38773
+ /** Only these non-secret, bounded upstream identities may enter durable diagnostics. */
38774
+ function upstreamRequestId(headers) {
38775
+ for (const name of ["x-request-id", "msh-request-id"]) {
38776
+ const value = headers.get(name)?.trim() ?? "";
38777
+ if (/^[A-Za-z0-9._:-]{1,128}$/.test(value)) return value;
38778
+ }
38779
+ }
38393
38780
  /**
38394
38781
  * Fallback cooldown for an account whose usage window is spent.
38395
38782
  *
@@ -38525,30 +38912,39 @@ function reportDriftCause(sessionId, cause) {
38525
38912
  if (driftWarned.size > 256) driftWarned.clear();
38526
38913
  console.warn("[kimi-code] prompt cache rebuilt for session " + sessionId + ": the " + cause + " changed mid-conversation, so the whole prompt was reprocessed once.");
38527
38914
  }
38528
- function noteSessionCacheState(sessionId, state) {
38915
+ function noteSessionCacheState(sessionId, state, successful, requestDiagnostic) {
38529
38916
  if (sessionId === void 0 || sessionId.trim() === "") return;
38530
38917
  const stats = getCacheStats(sessionId);
38531
- if (stats.requests === 0) return;
38918
+ if (stats.requests === 0 && requestDiagnostic === void 0) return;
38532
38919
  const lastDrift = getLastDriftCause(sessionId);
38533
38920
  reportDriftCause(sessionId, lastDrift);
38534
38921
  const now = Date.now();
38535
38922
  const imageBudget = getSessionImageBudgetStats(sessionId);
38536
38923
  const priorRecord = sessionCacheState.read(sessionId);
38924
+ const previousRequestPromptTokens = priorRecord?.totalTokens;
38537
38925
  const budgetDropped = imageBudget !== void 0 && imageBudget.droppedKeys.length > 0 ? imageBudget.droppedKeys : priorRecord?.budgetDropped;
38538
38926
  const liveBytes = imageBudget?.requestImageBytes ?? 0;
38539
38927
  const liveDropped = imageBudget?.droppedImages ?? 0;
38540
38928
  const lastRequestImageBytes = liveBytes > 0 ? liveBytes : priorRecord?.lastRequestImageBytes;
38541
38929
  const lastDroppedImages = liveDropped > 0 ? liveDropped : priorRecord?.lastDroppedImages;
38930
+ const recentRequests = requestDiagnostic === void 0 ? priorRecord?.recentRequests : [...priorRecord?.recentRequests ?? [], requestDiagnostic].slice(-20);
38931
+ const accountObservation = successful && state.accountId !== void 0 ? {
38932
+ lastAccountId: state.accountId,
38933
+ lastAccountAt: now
38934
+ } : {
38935
+ ...priorRecord?.lastAccountId === void 0 ? {} : { lastAccountId: priorRecord.lastAccountId },
38936
+ ...priorRecord?.lastAccountAt === void 0 ? {} : { lastAccountAt: priorRecord.lastAccountAt }
38937
+ };
38542
38938
  const firstRequest = stats.requests === 1 ? {
38543
38939
  firstRequestCachedTokens: state.cacheReadTokens,
38544
- firstRequestPromptTokens: state.cacheReadTokens + state.inputTokens
38940
+ firstRequestPromptTokens: state.cacheReadTokens + state.inputTokens + state.cacheWriteTokens
38545
38941
  } : {
38546
38942
  ...priorRecord?.firstRequestCachedTokens === void 0 ? {} : { firstRequestCachedTokens: priorRecord.firstRequestCachedTokens },
38547
38943
  ...priorRecord?.firstRequestPromptTokens === void 0 ? {} : { firstRequestPromptTokens: priorRecord.firstRequestPromptTokens }
38548
38944
  };
38549
38945
  sessionCacheState.write(sessionId, {
38550
38946
  lastActiveAt: now,
38551
- totalTokens: state.cacheReadTokens + state.inputTokens,
38947
+ totalTokens: state.cacheReadTokens + state.inputTokens + state.cacheWriteTokens,
38552
38948
  requests: stats.requests,
38553
38949
  cachedTokens: stats.cachedTokens,
38554
38950
  freshTokens: stats.freshTokens,
@@ -38556,6 +38952,11 @@ function noteSessionCacheState(sessionId, state) {
38556
38952
  cacheWriteTokens: stats.cacheWriteTokens,
38557
38953
  cacheWrite5mTokens: stats.cacheWrite5mTokens,
38558
38954
  cacheWrite1hTokens: stats.cacheWrite1hTokens,
38955
+ lastRequestCachedTokens: state.cacheReadTokens,
38956
+ lastRequestFreshTokens: state.inputTokens,
38957
+ ...accountObservation,
38958
+ ...recentRequests === void 0 ? {} : { recentRequests },
38959
+ ...previousRequestPromptTokens === void 0 ? {} : { previousRequestPromptTokens },
38559
38960
  ...lastDrift === void 0 ? {} : { lastDrift },
38560
38961
  ...budgetDropped === void 0 ? {} : { budgetDropped },
38561
38962
  ...lastRequestImageBytes === void 0 ? {} : { lastRequestImageBytes },
@@ -38569,7 +38970,7 @@ function noteSessionCacheState(sessionId, state) {
38569
38970
  inputTokens: state.inputTokens,
38570
38971
  cacheReadTokens: state.cacheReadTokens,
38571
38972
  outputTokens: state.outputTokens,
38572
- totalTokens: state.cacheReadTokens + state.inputTokens,
38973
+ totalTokens: state.cacheReadTokens + state.inputTokens + state.cacheWriteTokens,
38573
38974
  at: now,
38574
38975
  ...lastDrift === void 0 ? {} : { driftCause: lastDrift }
38575
38976
  });
@@ -38737,13 +39138,18 @@ var KimiCodeAdapter = class extends LlmAdapter {
38737
39138
  warm: true
38738
39139
  });
38739
39140
  }
38740
- if (candidates.length === 0) return void 0;
38741
39141
  const remainingShareById = {};
38742
39142
  for (const candidate of candidates) remainingShareById[candidate.id] = remainingQuotaShare(cachedQuotaFor$1(candidate.id));
38743
- const preferAccountIds = orderAffinityCandidates({
39143
+ const warmAccountIds = orderAffinityCandidates({
38744
39144
  candidates,
38745
39145
  remainingShareById
38746
39146
  });
39147
+ const sessionId = typeof options.sessionId === "string" ? options.sessionId.trim() : "";
39148
+ const durable = sessionId === "" ? void 0 : sessionCacheState.read(sessionId);
39149
+ const previousAccountId = durable?.lastAccountId;
39150
+ const previousAge = durable?.lastAccountAt === void 0 ? Infinity : Date.now() - durable.lastAccountAt;
39151
+ const previousIsWarm = previousAccountId !== void 0 && scopes.some((scope) => scope.id === previousAccountId) && previousAge >= 0 && previousAge < 15e5;
39152
+ const preferAccountIds = [.../* @__PURE__ */ new Set([...previousIsWarm ? [previousAccountId] : [], ...warmAccountIds])];
38747
39153
  return preferAccountIds.length === 0 ? void 0 : { preferAccountIds };
38748
39154
  }
38749
39155
  /**
@@ -38852,10 +39258,27 @@ var KimiCodeAdapter = class extends LlmAdapter {
38852
39258
  const normalized = normalizeGenerateOptions(options);
38853
39259
  const sideChannel = isAuxiliaryRequest(normalized) || isSideChannelTitleRequest(normalized);
38854
39260
  const sessionKey = typeof options.sessionId === "string" ? options.sessionId.trim() : "";
39261
+ const retrySignal = options.signal;
39262
+ const sameAccountRetryId = sideChannel || retrySignal === void 0 ? void 0 : sameAccountRetryBySignal.get(retrySignal);
39263
+ const previousAccountId = sideChannel || sessionKey === "" ? void 0 : sessionCacheState.read(sessionKey)?.lastAccountId;
39264
+ const requestDiagnostic = {
39265
+ id: randomUUID(),
39266
+ startedAt: Date.now(),
39267
+ endedAt: Date.now(),
39268
+ model: options.model,
39269
+ wire: "openai",
39270
+ ...previousAccountId === void 0 ? {} : { previousAccountId },
39271
+ accountChanged: false,
39272
+ outcome: "error",
39273
+ attempts: []
39274
+ };
39275
+ let diagnosticState;
39276
+ let requestError;
38855
39277
  const mainHeaderRelease = !sideChannel && sessionKey !== "" ? registerInFlightMainSessionHeader(sessionKey) : () => void 0;
38856
39278
  try {
38857
39279
  const catalog = await this.catalog().catch(() => []);
38858
39280
  const wire = wireForCatalogEntry(options.model, catalog);
39281
+ requestDiagnostic.wire = wire;
38859
39282
  const entry = catalog.find((model) => model.id === options.model);
38860
39283
  const images = await resolveRequestImages$2(normalized, this.options.attachments, signal, KIMI_CODE_REQUEST_IMAGE_MAX_EDGE);
38861
39284
  const priorDroppedKeys = getSessionDroppedImageKeys(options.sessionId, options.sessionId === void 0 ? void 0 : sessionCacheState.read(options.sessionId)?.budgetDropped);
@@ -38967,7 +39390,8 @@ var KimiCodeAdapter = class extends LlmAdapter {
38967
39390
  let sentBuild;
38968
39391
  const pool = this.accountPool;
38969
39392
  const tried = /* @__PURE__ */ new Set();
38970
- const affinity = sideChannel ? void 0 : await this.cacheAffinityHint(pool, requestOptions);
39393
+ const cacheAffinity = sideChannel ? void 0 : await this.cacheAffinityHint(pool, requestOptions);
39394
+ const affinity = sameAccountRetryId === void 0 ? cacheAffinity : { preferAccountIds: [.../* @__PURE__ */ new Set([sameAccountRetryId, ...cacheAffinity?.preferAccountIds ?? []])] };
38971
39395
  let servedByAccountId;
38972
39396
  let response;
38973
39397
  while (true) {
@@ -38994,6 +39418,11 @@ var KimiCodeAdapter = class extends LlmAdapter {
38994
39418
  tried.add(accountId);
38995
39419
  apiCredentials = effective.credentials;
38996
39420
  }
39421
+ const attemptDiagnostic = {
39422
+ startedAt: Date.now(),
39423
+ ...accountId === void 0 ? {} : { accountId }
39424
+ };
39425
+ if (!sideChannel) requestDiagnostic.attempts.push(attemptDiagnostic);
38997
39426
  const region = apiCredentials.region ?? await resolveRegion();
38998
39427
  const base = (apiCredentials.baseUrl ?? codingBaseUrl(region)).replace(/\/+$/, "");
38999
39428
  const endpoint = wire === "anthropic" ? `${base}/v1/messages?beta=true` : `${base}/v1/chat/completions`;
@@ -39088,21 +39517,30 @@ var KimiCodeAdapter = class extends LlmAdapter {
39088
39517
  detail = response.ok ? "" : (await response.text().catch(() => "")).slice(0, 2e3);
39089
39518
  }
39090
39519
  }
39091
- if (response.ok) break;
39520
+ attemptDiagnostic.status = response.status;
39521
+ const providerRequestId = upstreamRequestId(response.headers);
39522
+ if (providerRequestId !== void 0) attemptDiagnostic.providerRequestId = providerRequestId;
39523
+ if (response.ok) {
39524
+ attemptDiagnostic.endedAt = Date.now();
39525
+ if (accountId !== void 0) requestDiagnostic.accountId = accountId;
39526
+ clearSameAccountRetry(retrySignal);
39527
+ break;
39528
+ }
39092
39529
  const failure = classifyKimiFailure(response.status, detail);
39530
+ attemptDiagnostic.code = failure.code;
39531
+ attemptDiagnostic.poolAction = failure.poolAction;
39532
+ attemptDiagnostic.endedAt = Date.now();
39093
39533
  const after = response.status === 429 ? retryAfterMs$1(response.headers) : void 0;
39534
+ if (after !== void 0) attemptDiagnostic.retryAfterMs = after;
39535
+ if (failure.poolAction === "retry-same-account") rememberSameAccountRetry(retrySignal, accountId);
39536
+ else clearSameAccountRetry(retrySignal);
39094
39537
  if (pool !== null && accountId !== void 0) {
39095
- const planScoped = response.status === 429 && matchesAny$1(detail, ENTITLEMENT_PATTERNS);
39096
- if (response.status === 429 && !planScoped && !failure.upstreamOverload) {
39097
- const cooldownMs = failure.accountScoped ? accountLimitCooldownMs(detail) : after ?? POOL_COOLDOWN_MS$5;
39098
- await pool.markCooldown(accountId, cooldownMs, `${PROVIDER_NAME$8} 429`).catch(() => void 0);
39538
+ if (failure.poolAction === "cooldown-and-rotate") {
39539
+ await pool.markCooldown(accountId, accountLimitCooldownMs(detail), `${PROVIDER_NAME$8} ${response.status}`).catch(() => void 0);
39099
39540
  if (await pool.hasAnotherAvailableAccount(tried)) continue;
39100
- } else if (failure.code === "INVALID_CREDENTIAL") {
39541
+ } else if (failure.poolAction === "mark-auth-failed") {
39101
39542
  await pool.markAuthFailed(accountId, failure.message).catch(() => void 0);
39102
39543
  if (await pool.hasAnotherAvailableAccount(tried)) continue;
39103
- } else if (failure.accountScoped) {
39104
- await pool.markCooldown(accountId, accountLimitCooldownMs(detail), `${PROVIDER_NAME$8} 403`).catch(() => void 0);
39105
- if (await pool.hasAnotherAvailableAccount(tried)) continue;
39106
39544
  }
39107
39545
  }
39108
39546
  throw new LlmError(failure.message, failure.code, {
@@ -39127,6 +39565,8 @@ var KimiCodeAdapter = class extends LlmAdapter {
39127
39565
  const reader = response.body.getReader();
39128
39566
  const decoder = new TextDecoder();
39129
39567
  const state = createStreamState$5(wire, requestOptions.sessionId, sideChannel);
39568
+ state.accountId = servedByAccountId;
39569
+ diagnosticState = state;
39130
39570
  applyCacheWriteTiers(state, response.headers);
39131
39571
  if (!sideChannel) markSessionActive(requestOptions.sessionId);
39132
39572
  let buffer = "";
@@ -39170,14 +39610,42 @@ var KimiCodeAdapter = class extends LlmAdapter {
39170
39610
  }
39171
39611
  } catch (error) {
39172
39612
  const inBand = state.streamError;
39173
- if (error instanceof LlmError && !outputStarted && error.code === "PROVIDER_ERROR" && inBand !== void 0) throw await this.inBandStreamFailure(error, inBand, servedByAccountId);
39613
+ if (error instanceof LlmError && !outputStarted && error.code === "PROVIDER_ERROR" && inBand !== void 0) throw await this.inBandStreamFailure(error, inBand, servedByAccountId, retrySignal, requestDiagnostic.attempts.at(-1));
39174
39614
  throw streamFailure(error, signal);
39175
39615
  }
39176
39616
  } finally {
39177
- if (state.sawUsage && !sideChannel) noteSessionCacheState(requestOptions.sessionId ?? state.sessionId, state);
39178
39617
  reader.cancel().catch(() => void 0);
39179
39618
  }
39619
+ } catch (error) {
39620
+ if (error instanceof LlmError && isKimiToolArgumentGuardCode(error.code)) rememberSameAccountRetry(retrySignal, diagnosticState?.accountId);
39621
+ requestError = error;
39622
+ throw error;
39180
39623
  } finally {
39624
+ const endedAt = Date.now();
39625
+ const finalAccountId = diagnosticState?.accountId ?? requestDiagnostic.accountId ?? requestDiagnostic.attempts.at(-1)?.accountId;
39626
+ const errorCode = requestError instanceof LlmError ? requestError.code : requestError === void 0 ? void 0 : "UNKNOWN";
39627
+ const lastAttempt = requestDiagnostic.attempts.at(-1);
39628
+ if (lastAttempt !== void 0 && errorCode !== void 0) {
39629
+ lastAttempt.code = errorCode;
39630
+ lastAttempt.endedAt ??= endedAt;
39631
+ }
39632
+ requestDiagnostic.endedAt = endedAt;
39633
+ if (finalAccountId !== void 0) requestDiagnostic.accountId = finalAccountId;
39634
+ requestDiagnostic.accountChanged = previousAccountId !== void 0 && finalAccountId !== void 0 && previousAccountId !== finalAccountId;
39635
+ requestDiagnostic.outcome = retrySignal?.aborted === true || errorCode === "ABORTED" ? "aborted" : requestError === void 0 && diagnosticState?.finished === true ? "success" : "error";
39636
+ if (errorCode !== void 0) requestDiagnostic.code = errorCode;
39637
+ else if (requestDiagnostic.outcome === "error") requestDiagnostic.code = "INCOMPLETE_STREAM";
39638
+ if (diagnosticState?.finishReason !== null && diagnosticState?.finishReason !== void 0) requestDiagnostic.finishReason = diagnosticState.finishReason;
39639
+ if (diagnosticState?.sawUsage === true) requestDiagnostic.usage = {
39640
+ freshTokens: diagnosticState.inputTokens,
39641
+ cacheReadTokens: diagnosticState.cacheReadReported ? diagnosticState.cacheReadTokens : null,
39642
+ cacheWriteTokens: diagnosticState.cacheWriteReported ? diagnosticState.cacheWriteTokens : null,
39643
+ outputTokens: diagnosticState.outputTokens,
39644
+ reasoningTokens: diagnosticState.reasoningReported ? diagnosticState.reasoningTokens : null
39645
+ };
39646
+ if (diagnosticState?.toolGuard !== void 0) requestDiagnostic.toolGuard = diagnosticState.toolGuard;
39647
+ if (!sideChannel && sessionKey !== "") if (diagnosticState?.sawUsage === true) noteSessionCacheState(diagnosticState.sessionId, diagnosticState, requestError === void 0 && diagnosticState.finished, requestDiagnostic);
39648
+ else sessionCacheState.noteRequest(sessionKey, requestDiagnostic);
39181
39649
  mainHeaderRelease();
39182
39650
  }
39183
39651
  }
@@ -39197,37 +39665,32 @@ var KimiCodeAdapter = class extends LlmAdapter {
39197
39665
  * re-issued: its body is already open and part-read, and the harness retry
39198
39666
  * policy owns the repeat.
39199
39667
  */
39200
- async inBandStreamFailure(thrown, inBand, accountId) {
39668
+ async inBandStreamFailure(thrown, inBand, accountId, retrySignal, attemptDiagnostic) {
39201
39669
  const bodyText = JSON.stringify({ error: inBand.error });
39202
39670
  const reclassified = inBand.vocabulary === "anthropic" ? reclassifyInBandError(thrown, inBand.error, classifyKimiFailure) : reclassifyInBandResponsesError(thrown, inBand.error, inBand.message, classifyKimiFailure);
39203
39671
  const pool = this.accountPool;
39204
39672
  if (pool === null || accountId === void 0) return reclassified;
39673
+ let action = "none";
39205
39674
  if (inBand.vocabulary === "anthropic") {
39206
39675
  const status = inBandAnthropicStatus(inBand.error);
39207
39676
  if (status === null) return reclassified;
39208
- const failure = classifyKimiFailure(status, bodyText);
39209
- const planScoped = status === 429 && matchesAny$1(bodyText, ENTITLEMENT_PATTERNS);
39210
- if (status === 429 && !planScoped && !failure.upstreamOverload) await this.coolInBandRateLimit(pool, accountId, failure.accountScoped, bodyText);
39211
- else if (failure.code === "INVALID_CREDENTIAL") await pool.markAuthFailed(accountId, failure.message).catch(() => void 0);
39212
- else if (failure.accountScoped) await pool.markCooldown(accountId, accountLimitCooldownMs(bodyText), `${PROVIDER_NAME$8} in-stream 403`).catch(() => void 0);
39677
+ action = classifyKimiFailure(status, bodyText).poolAction;
39678
+ } else if (reclassified.code === "RATE_LIMIT" || matchesAny$1(bodyText, QUOTA_EXHAUSTED_PATTERNS$1)) action = classifyKimiFailure(429, bodyText).poolAction;
39679
+ else if (reclassified.code === "SERVER") action = "retry-same-account";
39680
+ if (attemptDiagnostic !== void 0) {
39681
+ attemptDiagnostic.code = reclassified.code;
39682
+ attemptDiagnostic.poolAction = action;
39683
+ attemptDiagnostic.endedAt = Date.now();
39684
+ }
39685
+ if (action === "retry-same-account") {
39686
+ rememberSameAccountRetry(retrySignal, accountId);
39213
39687
  return reclassified;
39214
39688
  }
39215
- if (reclassified.code === "RATE_LIMIT" && !matchesAny$1(bodyText, ENTITLEMENT_PATTERNS)) await this.coolInBandRateLimit(pool, accountId, classifyKimiFailure(429, bodyText).accountScoped, bodyText);
39689
+ clearSameAccountRetry(retrySignal);
39690
+ if (action === "cooldown-and-rotate") await pool.markCooldown(accountId, accountLimitCooldownMs(bodyText), `${PROVIDER_NAME$8} in-stream limit`).catch(() => void 0);
39691
+ else if (action === "mark-auth-failed") await pool.markAuthFailed(accountId, reclassified.message).catch(() => void 0);
39216
39692
  return reclassified;
39217
39693
  }
39218
- /**
39219
- * Cool the account whose own rate limit the stream reported.
39220
- *
39221
- * The window this route already defaults to, never a Retry-After: there is no
39222
- * 429 response to read one from, and a delay stated on the 200 belongs to a
39223
- * different message. An account-scoped verdict takes its own window instead,
39224
- * because a spent balance is not back-pressure and 15 minutes would put the
39225
- * account back into rotation four times inside the window that refused it.
39226
- */
39227
- async coolInBandRateLimit(pool, accountId, accountScoped, bodyText) {
39228
- const cooldownMs = accountScoped ? accountLimitCooldownMs(bodyText) : POOL_COOLDOWN_MS$5;
39229
- await pool.markCooldown(accountId, cooldownMs, `${PROVIDER_NAME$8} in-stream 429`).catch(() => void 0);
39230
- }
39231
39694
  };
39232
39695
  function isRefreshTimeout(error) {
39233
39696
  const seen = /* @__PURE__ */ new Set();
@@ -39756,17 +40219,45 @@ function openingInheritanceOf(sessionId) {
39756
40219
  hitRatio: Math.min(1, Math.max(0, cachedTokens / promptTokens))
39757
40220
  };
39758
40221
  }
40222
+ /**
40223
+ * Latest request's continuity against the previous prompt's observed 256-token
40224
+ * alignment baseline. Raw counts travel with the ratio so an above-baseline
40225
+ * reading stays visible instead of being hidden by clamping.
40226
+ */
40227
+ function continuationOf(sessionId) {
40228
+ const durable = sessionCacheState.read(sessionId);
40229
+ const cachedTokens = durable?.lastRequestCachedTokens;
40230
+ const freshTokens = durable?.lastRequestFreshTokens;
40231
+ const previousPromptTokens = durable?.previousRequestPromptTokens;
40232
+ if (cachedTokens === void 0 || freshTokens === void 0 || previousPromptTokens === void 0) return void 0;
40233
+ const expectedCachedTokens = Math.floor(previousPromptTokens / 256) * 256;
40234
+ if (expectedCachedTokens <= 0) return void 0;
40235
+ return {
40236
+ cachedTokens,
40237
+ freshTokens,
40238
+ previousPromptTokens,
40239
+ expectedCachedTokens,
40240
+ retentionRatio: Math.min(1, Math.max(0, cachedTokens / expectedCachedTokens))
40241
+ };
40242
+ }
40243
+ function lastRequestDiagnosticOf(sessionId) {
40244
+ return sessionCacheState.read(sessionId)?.recentRequests?.at(-1);
40245
+ }
39759
40246
  function cacheStatsOrNull(sessionId) {
39760
40247
  const stats = getCacheStats(sessionId);
39761
40248
  if (stats.requests === 0) return durableCacheStats(sessionId);
39762
40249
  const lastDrift = getLastDriftCause(sessionId);
39763
40250
  const warmup = warmupStatusOf(sessionId);
39764
40251
  const opening = openingInheritanceOf(sessionId);
40252
+ const continuation = continuationOf(sessionId);
40253
+ const lastRequest = lastRequestDiagnosticOf(sessionId);
39765
40254
  return {
39766
40255
  ...stats,
39767
40256
  ...lastDrift === void 0 ? {} : { lastDrift },
39768
40257
  ...warmup === void 0 ? {} : { warmup },
39769
40258
  ...opening === void 0 ? {} : { opening },
40259
+ ...continuation === void 0 ? {} : { continuation },
40260
+ ...lastRequest === void 0 ? {} : { lastRequest },
39770
40261
  imageBudget: imageBudgetOf(sessionId),
39771
40262
  cacheWriteTokens: stats.cacheWriteTokens,
39772
40263
  cacheWrite5mTokens: stats.cacheWrite5mTokens,
@@ -39807,10 +40298,12 @@ function cacheHintOrNull(sessionId) {
39807
40298
  */
39808
40299
  function durableCacheStats(sessionId) {
39809
40300
  const durable = sessionCacheState.read(sessionId);
39810
- if (durable === void 0 || durable.requests === 0) return null;
40301
+ if (durable === void 0 || durable.requests === 0 && durable.recentRequests === void 0) return null;
39811
40302
  const lastDrift = driftCauseOf(durable.lastDrift);
39812
40303
  const warmup = warmupStatusOf(sessionId);
39813
40304
  const opening = openingInheritanceOf(sessionId);
40305
+ const continuation = continuationOf(sessionId);
40306
+ const lastRequest = lastRequestDiagnosticOf(sessionId);
39814
40307
  return {
39815
40308
  requests: durable.requests,
39816
40309
  cachedTokens: durable.cachedTokens,
@@ -39823,6 +40316,8 @@ function durableCacheStats(sessionId) {
39823
40316
  ...lastDrift === void 0 ? {} : { lastDrift },
39824
40317
  ...warmup === void 0 ? {} : { warmup },
39825
40318
  ...opening === void 0 ? {} : { opening },
40319
+ ...continuation === void 0 ? {} : { continuation },
40320
+ ...lastRequest === void 0 ? {} : { lastRequest },
39826
40321
  imageBudget: imageBudgetOf(sessionId)
39827
40322
  };
39828
40323
  }
@@ -49761,6 +50256,83 @@ function installKimiRepeatBreaker(ctx, options = {}) {
49761
50256
  };
49762
50257
  }
49763
50258
  //#endregion
50259
+ //#region src/host/kimi-code/tool-argument-recovery.ts
50260
+ /**
50261
+ * One guided retry after a Kimi tool-argument stream enters a runaway shape.
50262
+ *
50263
+ * The failed attempt is already settled before `agent/request-error` runs. The
50264
+ * recovery notice is appended AFTER it, so the next same-step deriveMessages()
50265
+ * sees the instruction without changing the system prompt or tool declarations.
50266
+ * `agent.steer()` is deliberately not used: it targets a later step boundary.
50267
+ */
50268
+ const MAX_RECOVERY_STEPS = 256;
50269
+ function text$4(value) {
50270
+ return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
50271
+ }
50272
+ function number(value) {
50273
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
50274
+ }
50275
+ /** The model-facing recovery instruction; raw tool arguments never enter it. */
50276
+ function createKimiToolArgumentRecoveryMessage(code) {
50277
+ const repeated = code === TOOL_ARGUMENT_REPEATED_KEY_CODE;
50278
+ return createUserMessage$1({
50279
+ content: [{
50280
+ type: "text",
50281
+ text: repeated ? "The previous tool call was stopped because its JSON arguments contained a runaway repeated-key family. Do not resume, reuse, or repair that payload. If you still need a tool, make one fresh call with minimal valid JSON and only the exact property names in its schema. For ask_user_question, use only questions, id, question, header, options, label, description, and multi_select as applicable; never append documentation annotations or underscores to property names. If no tool call is necessary, continue with the evidence already available or explain the blocker in text." : "The previous tool call was stopped because its arguments exceeded the route byte budget. Do not resend the same payload. If the existing evidence is sufficient, finish in text. Otherwise make one fresh call with the smallest sufficient arguments; for a large file or program, use a legal smaller/chunked approach instead of repeating the oversized content."
50282
+ }],
50283
+ source: {
50284
+ kind: PLUGIN_MESSAGE_SOURCE_KIND,
50285
+ form: "notice",
50286
+ summary: boundContextSummary(repeated ? "Runaway tool arguments: retry once with fresh minimal JSON." : "Oversized tool arguments: retry once with a smaller payload.")
50287
+ }
50288
+ });
50289
+ }
50290
+ /** Install the one-per-step request recovery hook. */
50291
+ function installKimiToolArgumentRecovery(ctx) {
50292
+ const attempted = /* @__PURE__ */ new Set();
50293
+ const clearAgent = (raw) => {
50294
+ const agent = raw;
50295
+ const sessionId = text$4(agent?.session?.id) ?? text$4(agent?.id);
50296
+ if (sessionId === void 0) return;
50297
+ const prefix = sessionId + ":";
50298
+ for (const key of [...attempted]) if (key.startsWith(prefix)) attempted.delete(key);
50299
+ };
50300
+ const disposeRequestError = ctx.on?.("agent/request-error", (async (payload, next) => {
50301
+ const code = payload.failure?.code;
50302
+ if (payload.provider !== "kimi-code" || !isKimiToolArgumentGuardCode(code)) return await next();
50303
+ if (payload.signal?.aborted === true) return await next();
50304
+ const agent = payload.agent;
50305
+ const sessionId = text$4(agent?.session?.id) ?? text$4(agent?.id);
50306
+ const turn = number(payload.turn);
50307
+ const step = number(payload.step);
50308
+ const session = agent?.session;
50309
+ const append = session?.append;
50310
+ if (sessionId === void 0 || turn === void 0 || step === void 0 || session === void 0 || append === void 0) return await next();
50311
+ const key = `${sessionId}:${turn}:${step}`;
50312
+ if (attempted.has(key)) return await next();
50313
+ const message = createKimiToolArgumentRecoveryMessage(code);
50314
+ try {
50315
+ append.call(session, "user/message", message, { surfaceOp: "append" });
50316
+ } catch {
50317
+ return await next();
50318
+ }
50319
+ attempted.add(key);
50320
+ while (attempted.size > MAX_RECOVERY_STEPS) {
50321
+ const oldest = attempted.keys().next();
50322
+ if (oldest.done !== true) attempted.delete(oldest.value);
50323
+ }
50324
+ return { kind: "retry" };
50325
+ }));
50326
+ const disposeDisposed = ctx.on?.("agent/disposed", ((payload) => {
50327
+ clearAgent(payload?.agent);
50328
+ }));
50329
+ return () => {
50330
+ disposeRequestError?.();
50331
+ disposeDisposed?.();
50332
+ attempted.clear();
50333
+ };
50334
+ }
50335
+ //#endregion
49764
50336
  //#region src/host/minimax-code/account-pool.ts
49765
50337
  /**
49766
50338
  * MiniMax Code 号池:the account pool for the MiniMax Code (编程订阅) line.
@@ -64533,6 +65105,7 @@ var GlmCodingPlanAdapter = class extends LlmAdapter {
64533
65105
  preferences;
64534
65106
  accountPool;
64535
65107
  options;
65108
+ catalogRegionSnapshot;
64536
65109
  constructor(store = new GlmCodingPlanCredentialStore(), modelSettings = new GlmCodingPlanModelSettingsStore(), preferences, options = {}) {
64537
65110
  super();
64538
65111
  this.store = store;
@@ -64565,6 +65138,38 @@ var GlmCodingPlanAdapter = class extends LlmAdapter {
64565
65138
  return cached.length > 0 ? cached : modelsForRegion(region, GLM_MODEL_CATALOG);
64566
65139
  }
64567
65140
  /**
65141
+ * 模型目录只需要区域,不需要一把可发请求的凭据。
65142
+ *
65143
+ * 这里刻意不调用 credentialFor:那是真实请求的选号入口,会重复解密号池并回写
65144
+ * lastUsedAt。目录构建会为每个模型并发调用 resolveModel,把它放在这里会让一次
65145
+ * 选择器刷新放大成一串 DPAPI 读写。区域快照按号池 revision 与指定账号失效,
65146
+ * 同一代的并发调用共享同一次只读;读不到或尚未登录时不缓存,登录后即可重试。
65147
+ */
65148
+ catalogRegion(settings) {
65149
+ const pool = this.accountPool;
65150
+ if (pool === null) return this.readCatalogRegion(settings).catch(() => null);
65151
+ const revision = pool.currentIdentityRevision();
65152
+ const selectedAccountId = settings.selectedAccountId;
65153
+ const cached = this.catalogRegionSnapshot;
65154
+ if (cached !== void 0 && cached.revision === revision && cached.selectedAccountId === selectedAccountId) return cached.region;
65155
+ const snapshot = {
65156
+ revision,
65157
+ selectedAccountId,
65158
+ region: this.readCatalogRegion(settings).catch(() => null)
65159
+ };
65160
+ this.catalogRegionSnapshot = snapshot;
65161
+ snapshot.region.then((region) => {
65162
+ if (region === null && this.catalogRegionSnapshot === snapshot) this.catalogRegionSnapshot = void 0;
65163
+ });
65164
+ return snapshot.region;
65165
+ }
65166
+ async readCatalogRegion(settings) {
65167
+ if (this.accountPool === null) return (await this.store.read())?.codingPlan.region ?? null;
65168
+ const data = await this.accountPool.read();
65169
+ const usable = data.accounts.filter((account) => account.authStatus === void 0 || account.authStatus === "ok");
65170
+ return (usable.find((account) => account.id === settings.selectedAccountId) ?? usable.find((account) => account.id === data.activeAccountId) ?? usable.find((account) => account.isPrimary) ?? usable[0])?.credentials.codingPlan.region ?? null;
65171
+ }
65172
+ /**
64568
65173
  * 这一行请求用哪份凭据。
64569
65174
  *
64570
65175
  * 有池时轮转;没有池时读单凭据存储(无头 host 与测试的形态)。
@@ -64589,10 +65194,9 @@ var GlmCodingPlanAdapter = class extends LlmAdapter {
64589
65194
  async listModels(provider) {
64590
65195
  const prov = provider || PROVIDER_ID$1;
64591
65196
  const settings = await this.settings();
64592
- if (settings.enabled === false) return [];
64593
- const pick = await this.credentialFor().catch(() => null);
64594
- if (pick === null) return [];
64595
- const region = pick.credentials.codingPlan.region;
65197
+ if (settings.enabled === false || settings.enabledModelIds.length === 0) return [];
65198
+ const region = await this.catalogRegion(settings);
65199
+ if (region === null) return [];
64596
65200
  const available = this.catalog(region);
64597
65201
  const enabled = new Set(settings.enabledModelIds);
64598
65202
  return available.filter((model) => model.wire !== null && enabled.has(model.id)).map((model) => ({
@@ -64605,7 +65209,7 @@ var GlmCodingPlanAdapter = class extends LlmAdapter {
64605
65209
  async resolveModel(provider, model, signal) {
64606
65210
  if (signal?.aborted) throw new LlmError(t("glm.modelResolveAborted", { provider: PROVIDER_NAME$1 }), "ABORTED");
64607
65211
  const settings = await this.settings();
64608
- const region = (await this.credentialFor().catch(() => null))?.credentials.codingPlan.region ?? "intl";
65212
+ const region = await this.catalogRegion(settings) ?? "intl";
64609
65213
  const entry = resolveGlmModel(model, this.catalog(region));
64610
65214
  const override = settings.contextWindowOverrides[model];
64611
65215
  const contextWindow = typeof override === "number" && Number.isFinite(override) && override > 0 ? override : entry.defaultContextWindow;
@@ -97338,10 +97942,10 @@ function installCacheWarmup(ctx, options) {
97338
97942
  const blocks = decision.content ?? result.content;
97339
97943
  if (blocks.length === 0) return decision;
97340
97944
  const baseNavigation = retrievalTool || ptcRetrieval ? cacheWarmupNavigationIntentOf(exec.agent) : void 0;
97341
- const isOversizedSearchDump = (exec.name === "grep" || exec.name === "glob") && blocks.reduce((sum, block) => {
97945
+ const isSearchPreviewCandidate = (exec.name === "grep" || exec.name === "glob") && blocks.reduce((sum, block) => {
97342
97946
  return sum + (typeof block === "object" && block !== null && typeof block.text === "string" ? block.text : "").length;
97343
- }, 0) >= 2e4;
97344
- const navigation = baseNavigation === true || isOversizedSearchDump ? true : baseNavigation;
97947
+ }, 0) >= CACHE_WARMUP_DEFAULTS.warmupMaxChars;
97948
+ const navigation = baseNavigation === true || isSearchPreviewCandidate ? true : baseNavigation;
97345
97949
  if (retrievalTool && navigation !== true) return decision;
97346
97950
  if (sourceTool && !settings.enabled && navigation !== true) return decision;
97347
97951
  const route = cacheWarmupRouteOf(exec.agent);
@@ -105967,6 +106571,7 @@ function apply(ctx, pluginConfig = {}) {
105967
106571
  providers: CONTROLLED_PROVIDERS.filter((provider) => provider !== "minimax-code"),
105968
106572
  globalEnabled: () => resolveToolRunawayGuardEnabled(pluginConfig)
105969
106573
  }), "dsh-chatgpt-subscription: shared tool runaway guard");
106574
+ ctx.effect(() => installKimiToolArgumentRecovery(ctx), "dsh-chatgpt-subscription: Kimi tool argument recovery");
105970
106575
  ctx.effect(() => installDispatchExecutionGuard(ctx, { enabled: () => resolveDispatchExecutionGuardEnabled(pluginConfig) }), "dsh-chatgpt-subscription: dispatch execution guard");
105971
106576
  ctx.effect(() => installDispatchLedger(ctx, {
105972
106577
  enabled: () => resolveDispatchExecutionGuardEnabled(pluginConfig),