@eddyskywalker/dsh-chatgpt-subscription 0.40.2 → 0.41.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 (37) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/lib/client.js +420 -15
  3. package/lib/client.js.map +1 -1
  4. package/lib/index.js +674 -229
  5. package/lib/types/client/common/AccountPoolSection.d.ts +19 -0
  6. package/lib/types/client/common/AccountPoolSection.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/KimiQuotaCard.d.ts +31 -0
  9. package/lib/types/client/kimi-code/KimiQuotaCard.d.ts.map +1 -0
  10. package/lib/types/client/kimi-code/locales.d.ts +74 -2
  11. package/lib/types/client/kimi-code/locales.d.ts.map +1 -1
  12. package/lib/types/client/kimi-code/staff-art.d.ts +19 -0
  13. package/lib/types/client/kimi-code/staff-art.d.ts.map +1 -0
  14. package/lib/types/client/kimi-code/styles.d.ts.map +1 -1
  15. package/lib/types/client/locales-ru/kimi-code.d.ts.map +1 -1
  16. package/lib/types/compat.d.ts +1 -1
  17. package/lib/types/host/agent-preset.d.ts.map +1 -1
  18. package/lib/types/host/kimi-code/adapter.d.ts +29 -0
  19. package/lib/types/host/kimi-code/adapter.d.ts.map +1 -1
  20. package/lib/types/host/kimi-code/cache-hint.d.ts +5 -5
  21. package/lib/types/host/kimi-code/client.d.ts.map +1 -1
  22. package/lib/types/host/kimi-code/mapper.d.ts.map +1 -1
  23. package/lib/types/host/kimi-code/routes.d.ts.map +1 -1
  24. package/lib/types/host/kimi-code/session-cache-state.d.ts +140 -0
  25. package/lib/types/host/kimi-code/session-cache-state.d.ts.map +1 -0
  26. package/lib/types/host/opendesign/adapter.d.ts.map +1 -1
  27. package/lib/types/host/opendesign/catalog.d.ts.map +1 -1
  28. package/lib/types/host/opendesign/types.d.ts +4 -0
  29. package/lib/types/host/opendesign/types.d.ts.map +1 -1
  30. package/lib/types/host/progress-updates/index.d.ts.map +1 -1
  31. package/lib/types/host/progress-updates/prompt.d.ts +6 -3
  32. package/lib/types/host/progress-updates/prompt.d.ts.map +1 -1
  33. package/lib/types/host/subagent-route-audit.d.ts +5 -0
  34. package/lib/types/host/subagent-route-audit.d.ts.map +1 -1
  35. package/lib/types/index.d.ts.map +1 -1
  36. package/package.json +1 -1
  37. package/presets/dispatch/agent.cordis.yml +7 -8
package/lib/index.js CHANGED
@@ -141,7 +141,7 @@ const ROUTE_PREFIX$4 = "/api/dsh-chatgpt-subscription";
141
141
  * `test/responses-client.test.ts` asserts the two agree, so a release that
142
142
  * forgets this constant fails the suite instead of shipping quietly.
143
143
  */
144
- const PLUGIN_VERSION = "0.40.2";
144
+ const PLUGIN_VERSION = "0.41.1";
145
145
  const CODEX_CHATGPT_PROVIDER_ID = "codex-chatgpt";
146
146
  const CODEX_API_BASE = "https://chatgpt.com/backend-api/codex";
147
147
  const CODEX_RESPONSES_URL = `${CODEX_API_BASE}/responses`;
@@ -3435,7 +3435,7 @@ var OAuthService = class {
3435
3435
  throw new OAuthServiceError("oauth-token-exchange-failed", `The ChatGPT device code could not be issued (${response.status}${detail === null ? "" : `, ${detail}`}).`, response.status);
3436
3436
  }
3437
3437
  const payload = await response.json().catch(() => null);
3438
- const record = isRecord$50(payload) ? payload : {};
3438
+ const record = isRecord$51(payload) ? payload : {};
3439
3439
  const authId = nonEmptyString$10(record.device_auth_id);
3440
3440
  const userCode = nonEmptyString$10(record.user_code) ?? nonEmptyString$10(record.usercode);
3441
3441
  if (authId === void 0 || userCode === void 0) throw new OAuthServiceError("oauth-token-exchange-failed", "ChatGPT returned no device code.");
@@ -3502,7 +3502,7 @@ var OAuthService = class {
3502
3502
  const detail = deviceErrorIdentifier(payload);
3503
3503
  throw new OAuthServiceError("oauth-token-exchange-failed", `The ChatGPT device confirmation was refused (${response.status}${detail === void 0 ? "" : `, ${detail}`}).`, response.status);
3504
3504
  }
3505
- const record = isRecord$50(payload) ? payload : {};
3505
+ const record = isRecord$51(payload) ? payload : {};
3506
3506
  const authorizationCode = nonEmptyString$10(record.authorization_code);
3507
3507
  const codeVerifier = nonEmptyString$10(record.code_verifier);
3508
3508
  if (authorizationCode === void 0 || codeVerifier === void 0) throw new OAuthServiceError("oauth-token-exchange-failed", "ChatGPT confirmed the device code but returned no authorization code.");
@@ -3849,11 +3849,11 @@ const DEVICE_PENDING_STATUSES = /* @__PURE__ */ new Set([
3849
3849
  function isPendingDeviceAnswer(response, payload) {
3850
3850
  if (response.status === 403 || response.status === 404) return true;
3851
3851
  if (!response.ok && response.status !== 400) return false;
3852
- if (!isRecord$50(payload)) return false;
3852
+ if (!isRecord$51(payload)) return false;
3853
3853
  const status = payload.status;
3854
3854
  if (typeof status === "string" && DEVICE_PENDING_STATUSES.has(status.toLowerCase())) return true;
3855
3855
  const error = payload.error;
3856
- if (isRecord$50(error)) {
3856
+ if (isRecord$51(error)) {
3857
3857
  const code = error.code;
3858
3858
  if (typeof code === "string" && DEVICE_PENDING_STATUSES.has(code.toLowerCase())) return true;
3859
3859
  }
@@ -3867,18 +3867,18 @@ function isPendingDeviceAnswer(response, payload) {
3867
3867
  * wrong.
3868
3868
  */
3869
3869
  function deviceErrorIdentifier(payload) {
3870
- if (!isRecord$50(payload)) return void 0;
3870
+ if (!isRecord$51(payload)) return void 0;
3871
3871
  const candidates = [payload.code];
3872
3872
  const error = payload.error;
3873
3873
  if (typeof error === "string") candidates.push(error);
3874
- else if (isRecord$50(error)) candidates.push(error.code, error.type);
3874
+ else if (isRecord$51(error)) candidates.push(error.code, error.type);
3875
3875
  candidates.push(payload.status);
3876
3876
  for (const candidate of candidates) if (typeof candidate === "string" && /^[a-z0-9_.-]{1,64}$/i.test(candidate)) return candidate;
3877
3877
  }
3878
3878
  function nonEmptyString$10(value) {
3879
3879
  return typeof value === "string" && value !== "" ? value : void 0;
3880
3880
  }
3881
- function isRecord$50(value) {
3881
+ function isRecord$51(value) {
3882
3882
  return typeof value === "object" && value !== null && !Array.isArray(value);
3883
3883
  }
3884
3884
  async function oauthErrorIdentifier(response) {
@@ -4061,7 +4061,7 @@ const CODEX_AUTH_CLAIMS_KEY = "https://api.openai.com/auth";
4061
4061
  * here, and the import has to be repeated afterwards.
4062
4062
  */
4063
4063
  const ADOPTED_CODEX_CREDENTIAL_EXPIRED_HINT = "The sign-in imported from the Codex CLI has expired. Sign in again in the Codex CLI, then import it again from this settings card.";
4064
- function isRecord$49(value) {
4064
+ function isRecord$50(value) {
4065
4065
  return typeof value === "object" && value !== null && !Array.isArray(value);
4066
4066
  }
4067
4067
  /** A trimmed, non-empty string, or nothing. */
@@ -4163,7 +4163,7 @@ function decodeJwtClaims$1(token) {
4163
4163
  if (parts.length !== 3) return void 0;
4164
4164
  try {
4165
4165
  const value = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
4166
- return isRecord$49(value) ? value : void 0;
4166
+ return isRecord$50(value) ? value : void 0;
4167
4167
  } catch {
4168
4168
  return;
4169
4169
  }
@@ -4208,10 +4208,10 @@ function expiryFromAccessToken(accessToken) {
4208
4208
  * the file carries cannot reach the result.
4209
4209
  */
4210
4210
  function parseAdoptedCodexCredential(value, sourcePath) {
4211
- if (!isRecord$49(value)) return void 0;
4211
+ if (!isRecord$50(value)) return void 0;
4212
4212
  if (value.auth_mode !== "chatgpt") return void 0;
4213
4213
  const tokens = value[CODEX_CLI_TOKENS_KEY];
4214
- if (!isRecord$49(tokens)) return void 0;
4214
+ if (!isRecord$50(tokens)) return void 0;
4215
4215
  const accessToken = nonEmptyString$9(tokens.access_token);
4216
4216
  if (accessToken === void 0) return void 0;
4217
4217
  const refreshToken = nonEmptyString$9(tokens.refresh_token);
@@ -4230,7 +4230,7 @@ function parseAdoptedCodexCredential(value, sourcePath) {
4230
4230
  const email = claims === void 0 ? void 0 : nonEmptyString$9(claims.email);
4231
4231
  if (email !== void 0) credentials.email = email;
4232
4232
  const authClaims = claims === void 0 ? void 0 : claims[CODEX_AUTH_CLAIMS_KEY];
4233
- const planType = isRecord$49(authClaims) ? nonEmptyString$9(authClaims.chatgpt_plan_type) : void 0;
4233
+ const planType = isRecord$50(authClaims) ? nonEmptyString$9(authClaims.chatgpt_plan_type) : void 0;
4234
4234
  if (planType !== void 0) credentials.planType = planType;
4235
4235
  }
4236
4236
  const accountId = nonEmptyString$9(tokens.account_id);
@@ -4999,13 +4999,13 @@ function webServerOrigin(server) {
4999
4999
  //#region src/host/common/llm-compat.ts
5000
5000
  /** This package's kind in the harness message-source map. */
5001
5001
  const PLUGIN_MESSAGE_SOURCE_KIND = "dsh-chatgpt-subscription";
5002
- function isRecord$48(value) {
5002
+ function isRecord$49(value) {
5003
5003
  return typeof value === "object" && value !== null && !Array.isArray(value);
5004
5004
  }
5005
5005
  /** Read a message body's blocks, keeping every entry that carries a block tag. */
5006
5006
  function readBlocks(raw) {
5007
5007
  if (!Array.isArray(raw)) return [];
5008
- return raw.filter((block) => isRecord$48(block) && typeof block.type === "string");
5008
+ return raw.filter((block) => isRecord$49(block) && typeof block.type === "string");
5009
5009
  }
5010
5010
  /**
5011
5011
  * Normalize one harness message list into {@link Message}.
@@ -5020,10 +5020,10 @@ function readBlocks(raw) {
5020
5020
  function normalizeMessages(messages) {
5021
5021
  const normalized = [];
5022
5022
  for (const raw of messages ?? []) {
5023
- if (!isRecord$48(raw)) continue;
5023
+ if (!isRecord$49(raw)) continue;
5024
5024
  const content = readBlocks(raw.content);
5025
5025
  if (raw.role === "tool") {
5026
- const source = isRecord$48(raw.source) ? raw.source : void 0;
5026
+ const source = isRecord$49(raw.source) ? raw.source : void 0;
5027
5027
  const callId = String(raw.toolCallId ?? source?.callId ?? "");
5028
5028
  normalized.push({
5029
5029
  id: raw.id,
@@ -5045,7 +5045,7 @@ function normalizeMessages(messages) {
5045
5045
  id: raw.id,
5046
5046
  role: typeof raw.role === "string" ? raw.role : "user",
5047
5047
  content,
5048
- ...isRecord$48(raw.source) ? { source: raw.source } : {}
5048
+ ...isRecord$49(raw.source) ? { source: raw.source } : {}
5049
5049
  });
5050
5050
  }
5051
5051
  return normalized;
@@ -6749,7 +6749,7 @@ const schemaFields = /* @__PURE__ */ new Set([
6749
6749
  "required",
6750
6750
  "propertyOrdering"
6751
6751
  ]);
6752
- function isRecord$47(value) {
6752
+ function isRecord$48(value) {
6753
6753
  return typeof value === "object" && value !== null && !Array.isArray(value);
6754
6754
  }
6755
6755
  function mergeSchemas(left, right) {
@@ -6757,7 +6757,7 @@ function mergeSchemas(left, right) {
6757
6757
  ...left,
6758
6758
  ...right
6759
6759
  };
6760
- if (isRecord$47(left.properties) && isRecord$47(right.properties)) merged.properties = {
6760
+ if (isRecord$48(left.properties) && isRecord$48(right.properties)) merged.properties = {
6761
6761
  ...left.properties,
6762
6762
  ...right.properties
6763
6763
  };
@@ -6793,9 +6793,9 @@ const mergedTypeKeys = /* @__PURE__ */ new Set([
6793
6793
  * model with strictly less than the schema it started from.
6794
6794
  */
6795
6795
  function describeBranch(branch) {
6796
- const type = typeof branch.type === "string" ? branch.type : isRecord$47(branch.properties) ? "object" : isRecord$47(branch.items) ? "array" : "value";
6796
+ const type = typeof branch.type === "string" ? branch.type : isRecord$48(branch.properties) ? "object" : isRecord$48(branch.items) ? "array" : "value";
6797
6797
  const details = [];
6798
- if (isRecord$47(branch.properties)) {
6798
+ if (isRecord$48(branch.properties)) {
6799
6799
  const names = Object.keys(branch.properties);
6800
6800
  if (names.length > 0) details.push(`{${names.join(",")}}`);
6801
6801
  }
@@ -6809,7 +6809,7 @@ function describeBranch(branch) {
6809
6809
  }
6810
6810
  /** How well one branch can stand in for a whole union; a named object shape wins. */
6811
6811
  function branchRank(branch) {
6812
- if (isRecord$47(branch.properties)) return 3;
6812
+ if (isRecord$48(branch.properties)) return 3;
6813
6813
  if (branch.type === "object") return 2;
6814
6814
  if (branch.type === "array") return 1;
6815
6815
  return 0;
@@ -6838,7 +6838,7 @@ function unionShape(branches) {
6838
6838
  shape: branches[0],
6839
6839
  folded: false
6840
6840
  };
6841
- if (new Set(branches.map((branch) => branch.type)).size === 1 && branches.every((branch) => !isRecord$47(branch.properties) && !isRecord$47(branch.items))) {
6841
+ if (new Set(branches.map((branch) => branch.type)).size === 1 && branches.every((branch) => !isRecord$48(branch.properties) && !isRecord$48(branch.items))) {
6842
6842
  const shape = { type: branches[0].type };
6843
6843
  if (branches.every((branch) => Array.isArray(branch.enum))) {
6844
6844
  const values = [...new Set(branches.flatMap((branch) => branch.enum))];
@@ -6875,7 +6875,7 @@ function foldOwnFields(node) {
6875
6875
  const out = {};
6876
6876
  for (const [key, value] of Object.entries(node)) {
6877
6877
  if (key === "anyOf" || key === "oneOf" || key === "allOf") continue;
6878
- if (key === "properties" && isRecord$47(value)) {
6878
+ if (key === "properties" && isRecord$48(value)) {
6879
6879
  out.properties = Object.fromEntries(Object.entries(value).map(([name, child]) => [name, foldSchemaUnions(child)]));
6880
6880
  continue;
6881
6881
  }
@@ -6904,15 +6904,15 @@ function foldOwnFields(node) {
6904
6904
  * argument the model sends anyway fails there, naming the actual problem.
6905
6905
  */
6906
6906
  function foldSchemaUnions(node) {
6907
- if (!isRecord$47(node)) return node;
6907
+ if (!isRecord$48(node)) return node;
6908
6908
  let own = foldOwnFields(node);
6909
6909
  if (Array.isArray(node.allOf)) for (const branch of node.allOf) {
6910
6910
  const folded = foldSchemaUnions(branch);
6911
- if (isRecord$47(folded)) own = mergeSchemas(own, folded);
6911
+ if (isRecord$48(folded)) own = mergeSchemas(own, folded);
6912
6912
  }
6913
6913
  const alternatives = Array.isArray(node.anyOf) ? node.anyOf : Array.isArray(node.oneOf) ? node.oneOf : [];
6914
6914
  if (alternatives.length === 0) return own;
6915
- const branches = alternatives.map((branch) => foldSchemaUnions(branch)).filter(isRecord$47);
6915
+ const branches = alternatives.map((branch) => foldSchemaUnions(branch)).filter(isRecord$48);
6916
6916
  if (branches.length === 0) return own;
6917
6917
  const shapes = branches.filter((branch) => branch.type !== "null");
6918
6918
  const acceptsNull = branches.some((branch) => branch.type === "null");
@@ -6928,7 +6928,7 @@ function foldSchemaUnions(node) {
6928
6928
  return merged;
6929
6929
  }
6930
6930
  function toAntigravityToolSchema(schema, options = {}) {
6931
- if (!isRecord$47(schema)) return schema;
6931
+ if (!isRecord$48(schema)) return schema;
6932
6932
  const root = schema;
6933
6933
  function resolveReference(reference) {
6934
6934
  let target = root;
@@ -6936,13 +6936,13 @@ function toAntigravityToolSchema(schema, options = {}) {
6936
6936
  const path = reference === "#" ? [] : reference.slice(2).split("/");
6937
6937
  for (const segment of path) {
6938
6938
  const key = segment.replace(/~1/g, "/").replace(/~0/g, "~");
6939
- target = isRecord$47(target) && Object.hasOwn(target, key) ? target[key] : void 0;
6939
+ target = isRecord$48(target) && Object.hasOwn(target, key) ? target[key] : void 0;
6940
6940
  }
6941
- if (!isRecord$47(target)) throw new LlmError(`Antigravity tool schema reference was not found: ${reference}`, "PROVIDER_ERROR");
6941
+ if (!isRecord$48(target)) throw new LlmError(`Antigravity tool schema reference was not found: ${reference}`, "PROVIDER_ERROR");
6942
6942
  return target;
6943
6943
  }
6944
6944
  function convert(node, references) {
6945
- if (!isRecord$47(node)) return {};
6945
+ if (!isRecord$48(node)) return {};
6946
6946
  let inherited = {};
6947
6947
  if (typeof node.$ref === "string") {
6948
6948
  if (references.has(node.$ref)) throw new LlmError(`Antigravity tool schema contains a recursive reference: ${node.$ref}`, "PROVIDER_ERROR");
@@ -6951,8 +6951,8 @@ function toAntigravityToolSchema(schema, options = {}) {
6951
6951
  if (Array.isArray(node.allOf)) for (const branch of node.allOf) inherited = mergeSchemas(inherited, convert(branch, references));
6952
6952
  const out = {};
6953
6953
  for (const [key, value] of Object.entries(node)) if (schemaFields.has(key)) out[key] = value;
6954
- if (isRecord$47(node.properties)) out.properties = Object.fromEntries(Object.entries(node.properties).map(([name, child]) => [name, convert(child, references)]));
6955
- if (isRecord$47(node.items)) out.items = convert(node.items, references);
6954
+ if (isRecord$48(node.properties)) out.properties = Object.fromEntries(Object.entries(node.properties).map(([name, child]) => [name, convert(child, references)]));
6955
+ if (isRecord$48(node.items)) out.items = convert(node.items, references);
6956
6956
  const alternatives = Array.isArray(node.anyOf) ? node.anyOf : node.oneOf;
6957
6957
  if (Array.isArray(alternatives)) out.anyOf = alternatives.map((child) => convert(child, references));
6958
6958
  if (Array.isArray(node.type)) {
@@ -6988,7 +6988,7 @@ let toolCallCounter = 0;
6988
6988
  function sanitizeText$8(text) {
6989
6989
  return text.replace(/\0/g, "");
6990
6990
  }
6991
- function isRecord$46(value) {
6991
+ function isRecord$47(value) {
6992
6992
  return typeof value === "object" && value !== null && !Array.isArray(value);
6993
6993
  }
6994
6994
  function asString$24(value) {
@@ -7008,25 +7008,25 @@ function toolCallIdNeeded(modelId, runtimeModel) {
7008
7008
  return modelId.startsWith("claude-") || modelId.startsWith("gpt-oss-") || runtimeModel.startsWith("claude-") || runtimeModel.startsWith("gpt-oss-");
7009
7009
  }
7010
7010
  function parseArguments$2(raw) {
7011
- if (isRecord$46(raw)) return raw;
7011
+ if (isRecord$47(raw)) return raw;
7012
7012
  if (raw === void 0 || raw === null || raw === "") return {};
7013
7013
  const parsed = typeof raw === "string" ? safeJsonParse$8(raw) : raw;
7014
- return isRecord$46(parsed) ? parsed : {};
7014
+ return isRecord$47(parsed) ? parsed : {};
7015
7015
  }
7016
7016
  const NO_RESOLVED_IMAGES$5 = /* @__PURE__ */ new Map();
7017
7017
  function attachmentOf$5(block) {
7018
7018
  const attachment = block.attachment;
7019
- if (!isRecord$46(attachment)) return void 0;
7019
+ if (!isRecord$47(attachment)) return void 0;
7020
7020
  return typeof attachment.attachmentId === "string" ? attachment : void 0;
7021
7021
  }
7022
7022
  function attachmentLabel$6(block) {
7023
- const attachment = isRecord$46(block.attachment) ? block.attachment : void 0;
7023
+ const attachment = isRecord$47(block.attachment) ? block.attachment : void 0;
7024
7024
  return asString$24(attachment?.name) || asString$24(attachment?.attachmentId);
7025
7025
  }
7026
7026
  function collectImageRefs$3(content, refs) {
7027
7027
  if (!Array.isArray(content)) return;
7028
7028
  for (const block of content) {
7029
- if (!isRecord$46(block)) continue;
7029
+ if (!isRecord$47(block)) continue;
7030
7030
  if (block.type === "image") {
7031
7031
  const attachment = attachmentOf$5(block);
7032
7032
  if (attachment) refs.set(attachment.attachmentId, attachment);
@@ -7139,7 +7139,7 @@ function requestImageBytes$2(block) {
7139
7139
  function collectRequestImageBytes$2(content, lengths) {
7140
7140
  if (!Array.isArray(content)) return;
7141
7141
  for (const block of content) {
7142
- if (!isRecord$46(block)) continue;
7142
+ if (!isRecord$47(block)) continue;
7143
7143
  if (block.type === "tool-result") {
7144
7144
  collectRequestImageBytes$2(block.content, lengths);
7145
7145
  continue;
@@ -7189,7 +7189,7 @@ function offloadOldestRequestImages$3(options) {
7189
7189
  let replaced = false;
7190
7190
  return {
7191
7191
  content: content.map((block) => {
7192
- if (remaining.count === 0 || !isRecord$46(block)) return block;
7192
+ if (remaining.count === 0 || !isRecord$47(block)) return block;
7193
7193
  if (block.type === "image") {
7194
7194
  if (requestImageBytes$2(block) === void 0) return block;
7195
7195
  remaining.count -= 1;
@@ -7292,7 +7292,7 @@ function unavailableImageText$6(block) {
7292
7292
  }
7293
7293
  function imageBlockToPart(block, images) {
7294
7294
  let data = asString$24(block.data) || asString$24(block.base64);
7295
- const source = isRecord$46(block.source) ? block.source : void 0;
7295
+ const source = isRecord$47(block.source) ? block.source : void 0;
7296
7296
  if (!data && source) data = asString$24(source.data) || asString$24(source.base64);
7297
7297
  let mimeType = asString$24(block.mimeType) || asString$24(block.mediaType) || (source ? asString$24(source.mimeType) || asString$24(source.mediaType) : void 0) || "image/png";
7298
7298
  if (data?.startsWith("data:")) {
@@ -7317,8 +7317,8 @@ function contentToUserParts(content, images) {
7317
7317
  if (typeof content === "string") return [{ text: sanitizeText$8(content) }];
7318
7318
  if (!Array.isArray(content)) return [];
7319
7319
  const parts = [];
7320
- for (const block of content) if (isRecord$46(block) && block.type === "text" && typeof block.text === "string") parts.push({ text: sanitizeText$8(block.text) });
7321
- else if (isRecord$46(block) && block.type === "image") {
7320
+ for (const block of content) if (isRecord$47(block) && block.type === "text" && typeof block.text === "string") parts.push({ text: sanitizeText$8(block.text) });
7321
+ else if (isRecord$47(block) && block.type === "image") {
7322
7322
  const img = imageBlockToPart(block, images);
7323
7323
  parts.push(img ?? { text: unavailableImageText$6(block) });
7324
7324
  }
@@ -7333,7 +7333,7 @@ function toolResultImageParts(blocks, images) {
7333
7333
  if (!Array.isArray(blocks)) return [];
7334
7334
  const parts = [];
7335
7335
  for (const block of blocks) {
7336
- if (!isRecord$46(block)) continue;
7336
+ if (!isRecord$47(block)) continue;
7337
7337
  if (block.type === "image") {
7338
7338
  parts.push(imageBlockToPart(block, images) ?? { text: unavailableImageText$6(block) });
7339
7339
  continue;
@@ -7345,7 +7345,7 @@ function toolResultImageParts(blocks, images) {
7345
7345
  function toolResultText$8(blocks) {
7346
7346
  if (!Array.isArray(blocks)) return "";
7347
7347
  return blocks.map((block) => {
7348
- if (!isRecord$46(block)) return "";
7348
+ if (!isRecord$47(block)) return "";
7349
7349
  if (block.type === "text" && typeof block.text === "string") return sanitizeText$8(block.text);
7350
7350
  if (block.type === "tool-result") return toolResultText$8(block.content);
7351
7351
  if (block.type === "image") {
@@ -7359,9 +7359,9 @@ function replayBlockFor$1(message, index) {
7359
7359
  const source = message.source;
7360
7360
  if (!source || source.kind !== "model" || source.provider !== "antigravity") return void 0;
7361
7361
  const state = source.replayState;
7362
- if (!isRecord$46(state)) return void 0;
7362
+ if (!isRecord$47(state)) return void 0;
7363
7363
  if (Array.isArray(state.blocks)) return state.blocks[index];
7364
- const resp = isRecord$46(state.response) ? state.response : void 0;
7364
+ const resp = isRecord$47(state.response) ? state.response : void 0;
7365
7365
  if (resp) {
7366
7366
  if (Array.isArray(resp.outputItems)) return resp.outputItems[index];
7367
7367
  if (Array.isArray(resp.blocks)) return resp.blocks[index];
@@ -7463,10 +7463,10 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
7463
7463
  if (!Array.isArray(message.content)) return parts;
7464
7464
  for (let index = 0; index < message.content.length; index++) {
7465
7465
  const block = message.content[index];
7466
- if (!isRecord$46(block)) continue;
7466
+ if (!isRecord$47(block)) continue;
7467
7467
  if (block.type === "reasoning" && runtimeModel.startsWith("claude-") && (message.source?.kind !== "model" || message.source.provider !== "antigravity" || !("model" in message.source) || message.source.model !== model.id)) continue;
7468
7468
  const replay = replayBlockFor$1(message, index);
7469
- const originalParts = Array.isArray(replay?.parts) ? replay.parts.filter(isRecord$46) : [];
7469
+ const originalParts = Array.isArray(replay?.parts) ? replay.parts.filter(isRecord$47) : [];
7470
7470
  if ((block.type === "text" || block.type === "reasoning") && originalParts.length > 0 && originalParts.every((part) => !part.functionCall) && originalParts.map((part) => asString$24(part.text) || "").join("") === sanitizeText$8(String(block.text || ""))) {
7471
7471
  parts.push(...originalParts.map(replayPart));
7472
7472
  continue;
@@ -7487,8 +7487,8 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
7487
7487
  } else if (block.type === "tool-call") {
7488
7488
  const toolId = String(block.id || "");
7489
7489
  const toolName = String(block.name || "");
7490
- const originalCall = originalParts.find((part) => isRecord$46(part.functionCall));
7491
- const wireId = asString$24((isRecord$46(originalCall?.functionCall) ? originalCall.functionCall : void 0)?.id) || (toolCallIdNeeded(model.id, runtimeModel) ? sanitizeToolCallId(toolId, toolName) : originalCall ? void 0 : toolId || void 0);
7490
+ const originalCall = originalParts.find((part) => isRecord$47(part.functionCall));
7491
+ const wireId = asString$24((isRecord$47(originalCall?.functionCall) ? originalCall.functionCall : void 0)?.id) || (toolCallIdNeeded(model.id, runtimeModel) ? sanitizeToolCallId(toolId, toolName) : originalCall ? void 0 : toolId || void 0);
7492
7492
  toolCalls.set(toolId, {
7493
7493
  name: toolName,
7494
7494
  id: wireId
@@ -7540,7 +7540,7 @@ function convertMessages(options, model, runtimeModel, images = NO_RESOLVED_IMAG
7540
7540
  continue;
7541
7541
  }
7542
7542
  const content = Array.isArray(message.content) ? message.content : [];
7543
- const userParts = contentToUserParts(content.filter((b) => !isRecord$46(b) || b.type !== "tool-result"), images);
7543
+ const userParts = contentToUserParts(content.filter((b) => !isRecord$47(b) || b.type !== "tool-result"), images);
7544
7544
  if (role === "system") {
7545
7545
  if (userParts.length) contents.push({
7546
7546
  role: GEMINI_ROLE.user,
@@ -7552,7 +7552,7 @@ function convertMessages(options, model, runtimeModel, images = NO_RESOLVED_IMAG
7552
7552
  role: GEMINI_ROLE.user,
7553
7553
  parts: userParts
7554
7554
  });
7555
- for (const b of content) if (isRecord$46(b) && b.type === "tool-result") pushToolResult(contents, b, toolCalls, model, runtimeModel, images);
7555
+ for (const b of content) if (isRecord$47(b) && b.type === "tool-result") pushToolResult(contents, b, toolCalls, model, runtimeModel, images);
7556
7556
  }
7557
7557
  return contents;
7558
7558
  }
@@ -7700,7 +7700,7 @@ const USAGE_FIELDS = [
7700
7700
  "totalTokenCount"
7701
7701
  ];
7702
7702
  function collectUsage(value, state) {
7703
- if (!isRecord$46(value)) return;
7703
+ if (!isRecord$47(value)) return;
7704
7704
  for (const key of USAGE_FIELDS) {
7705
7705
  const count = value[key];
7706
7706
  if (typeof count !== "number" || !Number.isSafeInteger(count) || count < 0) continue;
@@ -7730,17 +7730,17 @@ function processStreamLine$3(line, state) {
7730
7730
  }
7731
7731
  if (!json) return [];
7732
7732
  const chunk = safeJsonParse$8(json);
7733
- if (!isRecord$46(chunk)) return [];
7734
- const responseData = isRecord$46(chunk.response) ? chunk.response : chunk;
7735
- const error = isRecord$46(chunk.error) ? chunk.error : isRecord$46(responseData.error) ? responseData.error : void 0;
7733
+ if (!isRecord$47(chunk)) return [];
7734
+ const responseData = isRecord$47(chunk.response) ? chunk.response : chunk;
7735
+ const error = isRecord$47(chunk.error) ? chunk.error : isRecord$47(responseData.error) ? responseData.error : void 0;
7736
7736
  if (error !== void 0) throw new LlmError$1(`Antigravity stream error: ${asString$24(error.message) ?? "unknown error"}`, isContextOverflow(error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
7737
7737
  const candidates = Array.isArray(responseData.candidates) ? responseData.candidates : [];
7738
- const candidate = isRecord$46(candidates[0]) ? candidates[0] : void 0;
7739
- const content = isRecord$46(candidate?.content) ? candidate.content : void 0;
7738
+ const candidate = isRecord$47(candidates[0]) ? candidates[0] : void 0;
7739
+ const content = isRecord$47(candidate?.content) ? candidate.content : void 0;
7740
7740
  const parts = Array.isArray(content?.parts) ? content.parts : [];
7741
7741
  const out = [];
7742
7742
  for (const part of parts) {
7743
- if (!isRecord$46(part)) continue;
7743
+ if (!isRecord$47(part)) continue;
7744
7744
  if (typeof part.text === "string" && part.text !== "") {
7745
7745
  const isThinking = Boolean(part.thought);
7746
7746
  const blockType = isThinking ? "reasoning" : "text";
@@ -7772,7 +7772,7 @@ function processStreamLine$3(line, state) {
7772
7772
  index: state.currentBlock.index,
7773
7773
  text: delta
7774
7774
  });
7775
- } else if (!isRecord$46(part.functionCall) && thoughtSignature(part)) {
7775
+ } else if (!isRecord$47(part.functionCall) && thoughtSignature(part)) {
7776
7776
  if (state.replayBlocks.length === 0) {
7777
7777
  const type = part.thought ? "reasoning" : "text";
7778
7778
  state.blocks.push({
@@ -7796,12 +7796,12 @@ function processStreamLine$3(line, state) {
7796
7796
  }
7797
7797
  state.replayBlocks[state.replayBlocks.length - 1].parts.push(replayPart(part));
7798
7798
  }
7799
- if (isRecord$46(part.functionCall)) {
7799
+ if (isRecord$47(part.functionCall)) {
7800
7800
  out.push(...closeCurrentBlock(state));
7801
7801
  const fc = part.functionCall;
7802
7802
  const toolName = asString$24(fc.name) || "";
7803
7803
  const toolId = asString$24(fc.id) || sanitizeToolCallId("", toolName);
7804
- const argsText = JSON.stringify(isRecord$46(fc.args) ? fc.args : {});
7804
+ const argsText = JSON.stringify(isRecord$47(fc.args) ? fc.args : {});
7805
7805
  const index = state.blocks.length;
7806
7806
  const block = {
7807
7807
  type: "tool-call",
@@ -7840,7 +7840,7 @@ function processStreamLine$3(line, state) {
7840
7840
  if (responseData !== chunk) collectUsage(responseData.usageMetadata, state);
7841
7841
  const finishMessage = asString$24(candidate?.finishMessage);
7842
7842
  if (finishMessage) state.finishMessage = finishMessage;
7843
- const blockReason = asString$24((isRecord$46(responseData.promptFeedback) ? responseData.promptFeedback : void 0)?.blockReason);
7843
+ const blockReason = asString$24((isRecord$47(responseData.promptFeedback) ? responseData.promptFeedback : void 0)?.blockReason);
7844
7844
  const finishReason = asString$24(candidate?.finishReason) || asString$24(responseData.finishReason) || (blockReason ? `PROMPT_BLOCKED:${blockReason}` : void 0);
7845
7845
  if (finishReason) {
7846
7846
  state.finishReason = finishReason;
@@ -10554,7 +10554,7 @@ function preferencesPath() {
10554
10554
  return path.join(dshHomeDir(), "storages", "dsh-chatgpt-subscription-preferences.json");
10555
10555
  }
10556
10556
  /** Distinguishes concurrent temporary files written by one process. */
10557
- let writeSequence = 0;
10557
+ let writeSequence$1 = 0;
10558
10558
  /** One JSON document, validated and shaped by a schemastery schema. */
10559
10559
  var FilePreferencesStore = class {
10560
10560
  schema;
@@ -10656,8 +10656,8 @@ var FilePreferencesStore = class {
10656
10656
  }
10657
10657
  async write(value) {
10658
10658
  await fs.mkdir(path.dirname(this.filePath), { recursive: true });
10659
- writeSequence += 1;
10660
- const tmp = `${this.filePath}.tmp.${process.pid}.${writeSequence}`;
10659
+ writeSequence$1 += 1;
10660
+ const tmp = `${this.filePath}.tmp.${process.pid}.${writeSequence$1}`;
10661
10661
  try {
10662
10662
  await fs.writeFile(tmp, JSON.stringify(value, null, 2), {
10663
10663
  encoding: "utf8",
@@ -13856,7 +13856,7 @@ async function compactionCandidates(ctx) {
13856
13856
  };
13857
13857
  }))).filter((provider) => provider.models.length > 0) };
13858
13858
  }
13859
- function isRecord$45(value) {
13859
+ function isRecord$46(value) {
13860
13860
  return typeof value === "object" && value !== null && !Array.isArray(value);
13861
13861
  }
13862
13862
  function readPreferencesUpdate(value, current) {
@@ -13897,7 +13897,7 @@ function readPreferencesUpdate(value, current) {
13897
13897
  };
13898
13898
  }
13899
13899
  if ("contextWindowOverrides" in value) {
13900
- if (!isRecord$45(value.contextWindowOverrides)) throw new PreferenceError("contextWindowOverrides must be an object.");
13900
+ if (!isRecord$46(value.contextWindowOverrides)) throw new PreferenceError("contextWindowOverrides must be an object.");
13901
13901
  const overrides = {};
13902
13902
  for (const [model, contextWindow] of Object.entries(value.contextWindowOverrides)) {
13903
13903
  if (!isCodexModelId(model)) throw new PreferenceError("Unknown Codex model for a context window override.");
@@ -18397,11 +18397,11 @@ function commandCodeHeaders(apiKey, extra = {}) {
18397
18397
  function timeoutSignal$4(signal, ms) {
18398
18398
  return signal ? AbortSignal.any([signal, AbortSignal.timeout(ms)]) : AbortSignal.timeout(ms);
18399
18399
  }
18400
- function isRecord$44(value) {
18400
+ function isRecord$45(value) {
18401
18401
  return typeof value === "object" && value !== null && !Array.isArray(value);
18402
18402
  }
18403
18403
  function asRecord$15(value) {
18404
- return isRecord$44(value) ? value : void 0;
18404
+ return isRecord$45(value) ? value : void 0;
18405
18405
  }
18406
18406
  function asString$23(value) {
18407
18407
  if (typeof value === "string" && value.trim() !== "") return value;
@@ -18445,7 +18445,7 @@ function deepValue(value, keys, depth = 0) {
18445
18445
  }
18446
18446
  return;
18447
18447
  }
18448
- if (!isRecord$44(value)) return void 0;
18448
+ if (!isRecord$45(value)) return void 0;
18449
18449
  for (const key of keys) if (value[key] !== void 0 && value[key] !== null) return value[key];
18450
18450
  for (const nested of Object.values(value)) {
18451
18451
  const hit = deepValue(nested, keys, depth + 1);
@@ -18459,7 +18459,7 @@ function collectRecords(value, keys, depth = 0, out = []) {
18459
18459
  for (const entry of value) collectRecords(entry, keys, depth + 1, out);
18460
18460
  return out;
18461
18461
  }
18462
- if (!isRecord$44(value)) return out;
18462
+ if (!isRecord$45(value)) return out;
18463
18463
  if (keys.some((key) => value[key] !== void 0)) out.push(value);
18464
18464
  for (const nested of Object.values(value)) collectRecords(nested, keys, depth + 1, out);
18465
18465
  return out;
@@ -19269,7 +19269,7 @@ function buildModelOptions$1(catalog, enabledModelIds, overrides) {
19269
19269
  *
19270
19270
  * https://commandcode.ai/blog/command-code-provider-api
19271
19271
  */
19272
- function isRecord$43(value) {
19272
+ function isRecord$44(value) {
19273
19273
  return typeof value === "object" && value !== null && !Array.isArray(value);
19274
19274
  }
19275
19275
  function asString$22(value) {
@@ -19309,17 +19309,17 @@ const SUPPORTED_IMAGE_MEDIA_TYPES$4 = /* @__PURE__ */ new Set([
19309
19309
  ]);
19310
19310
  function attachmentOf$4(block) {
19311
19311
  const attachment = block.attachment;
19312
- if (!isRecord$43(attachment)) return void 0;
19312
+ if (!isRecord$44(attachment)) return void 0;
19313
19313
  return typeof attachment.attachmentId === "string" ? attachment : void 0;
19314
19314
  }
19315
19315
  function attachmentLabel$5(block) {
19316
- const attachment = isRecord$43(block.attachment) ? block.attachment : void 0;
19316
+ const attachment = isRecord$44(block.attachment) ? block.attachment : void 0;
19317
19317
  return asString$22(attachment?.name) || asString$22(attachment?.attachmentId);
19318
19318
  }
19319
19319
  function collectImageRefs$2(content, refs) {
19320
19320
  if (!Array.isArray(content)) return;
19321
19321
  for (const block of content) {
19322
- if (!isRecord$43(block)) continue;
19322
+ if (!isRecord$44(block)) continue;
19323
19323
  if (block.type === "image") {
19324
19324
  const attachment = attachmentOf$4(block);
19325
19325
  if (attachment) refs.set(attachment.attachmentId, attachment);
@@ -19340,7 +19340,7 @@ function requestImageBytes$1(block) {
19340
19340
  function collectRequestImageBytes$1(content, lengths) {
19341
19341
  if (!Array.isArray(content)) return;
19342
19342
  for (const block of content) {
19343
- if (!isRecord$43(block)) continue;
19343
+ if (!isRecord$44(block)) continue;
19344
19344
  if (block.type === "tool-result") {
19345
19345
  collectRequestImageBytes$1(block.content, lengths);
19346
19346
  continue;
@@ -19376,7 +19376,7 @@ function offloadOldestRequestImages$2(options) {
19376
19376
  let replaced = false;
19377
19377
  return {
19378
19378
  content: content.map((block) => {
19379
- if (remaining.count === 0 || !isRecord$43(block)) return block;
19379
+ if (remaining.count === 0 || !isRecord$44(block)) return block;
19380
19380
  if (block.type === "image") {
19381
19381
  if (requestImageBytes$1(block) === void 0) return block;
19382
19382
  remaining.count -= 1;
@@ -19448,7 +19448,7 @@ function unavailableImageText$5(block) {
19448
19448
  }
19449
19449
  function imageBlockToInline$3(block, images) {
19450
19450
  let data = asString$22(block.data) || asString$22(block.base64);
19451
- const source = isRecord$43(block.source) ? block.source : void 0;
19451
+ const source = isRecord$44(block.source) ? block.source : void 0;
19452
19452
  if (!data && source) data = asString$22(source.data) || asString$22(source.base64);
19453
19453
  let mediaType = asString$22(block.mimeType) || asString$22(block.mediaType) || (source ? asString$22(source.mimeType) || asString$22(source.mediaType) : void 0) || "image/png";
19454
19454
  if (data?.startsWith("data:")) {
@@ -19474,7 +19474,7 @@ function textOf$8(content) {
19474
19474
  if (!Array.isArray(content)) return "";
19475
19475
  const parts = [];
19476
19476
  for (const block of content) {
19477
- if (!isRecord$43(block)) continue;
19477
+ if (!isRecord$44(block)) continue;
19478
19478
  if (block.type === "text" && typeof block.text === "string") parts.push(sanitizeText$7(block.text));
19479
19479
  else if (block.type === "tool-result") parts.push(textOf$8(block.content));
19480
19480
  }
@@ -19483,7 +19483,7 @@ function textOf$8(content) {
19483
19483
  function toolResultText$7(blocks) {
19484
19484
  if (!Array.isArray(blocks)) return "";
19485
19485
  return blocks.map((block) => {
19486
- if (!isRecord$43(block)) return "";
19486
+ if (!isRecord$44(block)) return "";
19487
19487
  if (block.type === "text" && typeof block.text === "string") return sanitizeText$7(block.text);
19488
19488
  if (block.type === "tool-result") return toolResultText$7(block.content);
19489
19489
  if (block.type === "image") return `[image: ${attachmentLabel$5(block) ?? "attached image"}]`;
@@ -19501,7 +19501,7 @@ function toolResultBlocks$2(blocks, images) {
19501
19501
  const out = [];
19502
19502
  let hasImage = false;
19503
19503
  for (const block of blocks) {
19504
- if (!isRecord$43(block)) continue;
19504
+ if (!isRecord$44(block)) continue;
19505
19505
  if (block.type === "text" && typeof block.text === "string") {
19506
19506
  out.push({
19507
19507
  type: "text",
@@ -19550,7 +19550,7 @@ function toolResultImageBlocks$4(blocks, images) {
19550
19550
  if (!Array.isArray(blocks)) return [];
19551
19551
  const out = [];
19552
19552
  for (const block of blocks) {
19553
- if (!isRecord$43(block)) continue;
19553
+ if (!isRecord$44(block)) continue;
19554
19554
  if (block.type === "image") {
19555
19555
  const inline = imageBlockToInline$3(block, images);
19556
19556
  if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$4.has(inline.mediaType)) out.push({
@@ -19594,7 +19594,7 @@ function nonSystemMessages$7(options) {
19594
19594
  }
19595
19595
  /** Drop the JSON-Schema keywords provider gateways reject or ignore. */
19596
19596
  function stripMetaSchema$2(schema) {
19597
- if (!isRecord$43(schema)) return {
19597
+ if (!isRecord$44(schema)) return {
19598
19598
  type: "object",
19599
19599
  properties: {}
19600
19600
  };
@@ -19611,7 +19611,7 @@ function openAIUserContent$3(message, images) {
19611
19611
  const parts = [];
19612
19612
  let hasImage = false;
19613
19613
  for (const block of message.content) {
19614
- if (!isRecord$43(block)) continue;
19614
+ if (!isRecord$44(block)) continue;
19615
19615
  if (block.type === "text" && typeof block.text === "string") {
19616
19616
  const text = sanitizeText$7(block.text);
19617
19617
  if (text !== "") parts.push({
@@ -19639,7 +19639,7 @@ function openAIAssistantContent$3(message) {
19639
19639
  const textParts = [];
19640
19640
  const toolCalls = [];
19641
19641
  for (const block of message.content) {
19642
- if (!isRecord$43(block)) continue;
19642
+ if (!isRecord$44(block)) continue;
19643
19643
  if (block.type === "text" && typeof block.text === "string") textParts.push(sanitizeText$7(block.text));
19644
19644
  else if (block.type === "tool-call" && typeof block.name === "string") toolCalls.push({
19645
19645
  id: typeof block.id === "string" && block.id !== "" ? block.id : `call_${toolCalls.length}`,
@@ -19671,7 +19671,7 @@ function buildOpenAIRequest$1(options, images = NO_RESOLVED_IMAGES$4) {
19671
19671
  while (index < conversation.length && isToolResultMessage$7(conversation[index])) {
19672
19672
  const current = conversation[index];
19673
19673
  const block = current.content[0];
19674
- const callId = isRecord$43(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
19674
+ const callId = isRecord$44(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
19675
19675
  messages.push({
19676
19676
  role: "tool",
19677
19677
  tool_call_id: callId,
@@ -19732,7 +19732,7 @@ function anthropicUserContent$3(message, images) {
19732
19732
  if (!Array.isArray(message.content)) return [];
19733
19733
  const blocks = [];
19734
19734
  for (const block of message.content) {
19735
- if (!isRecord$43(block)) continue;
19735
+ if (!isRecord$44(block)) continue;
19736
19736
  if (block.type === "text" && typeof block.text === "string") {
19737
19737
  const text = sanitizeText$7(block.text);
19738
19738
  if (text !== "") blocks.push({
@@ -19769,7 +19769,7 @@ function anthropicUserContent$3(message, images) {
19769
19769
  function anthropicAssistantContent$3(message) {
19770
19770
  const blocks = [];
19771
19771
  for (const block of message.content) {
19772
- if (!isRecord$43(block)) continue;
19772
+ if (!isRecord$44(block)) continue;
19773
19773
  if (block.type === "text" && typeof block.text === "string") {
19774
19774
  const text = sanitizeText$7(block.text);
19775
19775
  if (text !== "") blocks.push({
@@ -19782,7 +19782,7 @@ function anthropicAssistantContent$3(message) {
19782
19782
  type: "tool_use",
19783
19783
  id: typeof block.id === "string" && block.id !== "" ? block.id : `toolu_${blocks.length}`,
19784
19784
  name: block.name,
19785
- input: isRecord$43(parsed) ? parsed : {}
19785
+ input: isRecord$44(parsed) ? parsed : {}
19786
19786
  });
19787
19787
  }
19788
19788
  }
@@ -19876,7 +19876,7 @@ function responsesUserContent(message, images) {
19876
19876
  if (!Array.isArray(message.content)) return [];
19877
19877
  const parts = [];
19878
19878
  for (const block of message.content) {
19879
- if (!isRecord$43(block)) continue;
19879
+ if (!isRecord$44(block)) continue;
19880
19880
  if (block.type === "text" && typeof block.text === "string") {
19881
19881
  const text = sanitizeText$7(block.text);
19882
19882
  if (text !== "") parts.push({
@@ -19901,7 +19901,7 @@ function responsesToolResultImageBlocks(blocks, images) {
19901
19901
  if (!Array.isArray(blocks)) return [];
19902
19902
  const out = [];
19903
19903
  for (const block of blocks) {
19904
- if (!isRecord$43(block)) continue;
19904
+ if (!isRecord$44(block)) continue;
19905
19905
  if (block.type === "image") {
19906
19906
  const inline = imageBlockToInline$3(block, images);
19907
19907
  if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$4.has(inline.mediaType)) out.push({
@@ -19928,8 +19928,8 @@ function buildResponsesRequest(options, images = NO_RESOLVED_IMAGES$4) {
19928
19928
  const imageBlocks = [];
19929
19929
  while (index < conversation.length && isToolResultMessage$7(conversation[index])) {
19930
19930
  const current = conversation[index];
19931
- const toolResult = Array.isArray(current.content) ? current.content.find((b) => isRecord$43(b) && b.type === "tool-result") : void 0;
19932
- const callId = (isRecord$43(toolResult) && typeof toolResult.toolCallId === "string" ? toolResult.toolCallId : "") || (typeof current.source?.callId === "string" ? current.source.callId : "");
19931
+ const toolResult = Array.isArray(current.content) ? current.content.find((b) => isRecord$44(b) && b.type === "tool-result") : void 0;
19932
+ const callId = (isRecord$44(toolResult) && typeof toolResult.toolCallId === "string" ? toolResult.toolCallId : "") || (typeof current.source?.callId === "string" ? current.source.callId : "");
19933
19933
  input.push({
19934
19934
  type: "function_call_output",
19935
19935
  call_id: callId,
@@ -19952,7 +19952,7 @@ function buildResponsesRequest(options, images = NO_RESOLVED_IMAGES$4) {
19952
19952
  content
19953
19953
  });
19954
19954
  for (const call of toolCalls) {
19955
- const fn = isRecord$43(call.function) ? call.function : void 0;
19955
+ const fn = isRecord$44(call.function) ? call.function : void 0;
19956
19956
  input.push({
19957
19957
  type: "function_call",
19958
19958
  call_id: call.id,
@@ -20075,9 +20075,9 @@ function processOpenAIStreamLine$1(line, state) {
20075
20075
  }
20076
20076
  if (payload === "") return [];
20077
20077
  const chunk = safeJsonParse$7(payload);
20078
- if (!isRecord$43(chunk)) return [];
20078
+ if (!isRecord$44(chunk)) return [];
20079
20079
  const out = [];
20080
- if (isRecord$43(chunk.error)) {
20080
+ if (isRecord$44(chunk.error)) {
20081
20081
  const message = asString$22(chunk.error.message) ?? "unknown error";
20082
20082
  state.streamError = {
20083
20083
  vocabulary: "openai",
@@ -20086,20 +20086,20 @@ function processOpenAIStreamLine$1(line, state) {
20086
20086
  };
20087
20087
  throw new LlmError$1(`Command Code stream error: ${message}`, isContextOverflow(chunk.error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
20088
20088
  }
20089
- const usage = isRecord$43(chunk.usage) ? chunk.usage : void 0;
20089
+ const usage = isRecord$44(chunk.usage) ? chunk.usage : void 0;
20090
20090
  if (usage) {
20091
20091
  state.sawUsage = true;
20092
20092
  const prompt = numberOr$8(usage.prompt_tokens, 0);
20093
- const details = isRecord$43(usage.prompt_tokens_details) ? usage.prompt_tokens_details : void 0;
20093
+ const details = isRecord$44(usage.prompt_tokens_details) ? usage.prompt_tokens_details : void 0;
20094
20094
  const cached = details ? numberOr$8(details.cached_tokens, 0) : 0;
20095
20095
  state.inputTokens = Math.max(0, prompt - cached);
20096
20096
  state.cacheReadTokens = cached;
20097
20097
  state.outputTokens = numberOr$8(usage.completion_tokens, state.outputTokens);
20098
- if (isRecord$43(usage.completion_tokens_details)) state.reasoningTokens = numberOr$8(usage.completion_tokens_details.reasoning_tokens, state.reasoningTokens);
20098
+ if (isRecord$44(usage.completion_tokens_details)) state.reasoningTokens = numberOr$8(usage.completion_tokens_details.reasoning_tokens, state.reasoningTokens);
20099
20099
  }
20100
20100
  const choices = Array.isArray(chunk.choices) ? chunk.choices : [];
20101
- const choice = isRecord$43(choices[0]) ? choices[0] : void 0;
20102
- const delta = isRecord$43(choice?.delta) ? choice.delta : void 0;
20101
+ const choice = isRecord$44(choices[0]) ? choices[0] : void 0;
20102
+ const delta = isRecord$44(choice?.delta) ? choice.delta : void 0;
20103
20103
  if (delta) {
20104
20104
  const reasoning = asString$22(delta.reasoning_content) ?? asString$22(delta.reasoning);
20105
20105
  if (reasoning !== void 0 && reasoning !== "") {
@@ -20127,7 +20127,7 @@ function processOpenAIStreamLine$1(line, state) {
20127
20127
  }
20128
20128
  const toolDeltas = Array.isArray(delta.tool_calls) ? delta.tool_calls : [];
20129
20129
  for (const entry of toolDeltas) {
20130
- if (!isRecord$43(entry)) continue;
20130
+ if (!isRecord$44(entry)) continue;
20131
20131
  out.push(...applyOpenAIToolDelta$1(entry, state));
20132
20132
  }
20133
20133
  }
@@ -20141,7 +20141,7 @@ function processOpenAIStreamLine$1(line, state) {
20141
20141
  }
20142
20142
  function applyOpenAIToolDelta$1(entry, state) {
20143
20143
  const wireIndex = typeof entry.index === "number" ? entry.index : 0;
20144
- const fn = isRecord$43(entry.function) ? entry.function : {};
20144
+ const fn = isRecord$44(entry.function) ? entry.function : {};
20145
20145
  const out = [];
20146
20146
  let call = state.toolCalls.get(wireIndex);
20147
20147
  if (call === void 0) {
@@ -20199,12 +20199,12 @@ function processAnthropicStreamLine$1(line, state) {
20199
20199
  const payload = trimmed.slice(5).trim();
20200
20200
  if (payload === "" || payload === "[DONE]") return [];
20201
20201
  const event = safeJsonParse$7(payload);
20202
- if (!isRecord$43(event)) return [];
20202
+ if (!isRecord$44(event)) return [];
20203
20203
  const type = asString$22(event.type);
20204
20204
  const out = [];
20205
20205
  if (type === "message_start") {
20206
- const message = isRecord$43(event.message) ? event.message : void 0;
20207
- const usage = message && isRecord$43(message.usage) ? message.usage : void 0;
20206
+ const message = isRecord$44(event.message) ? event.message : void 0;
20207
+ const usage = message && isRecord$44(message.usage) ? message.usage : void 0;
20208
20208
  if (usage) {
20209
20209
  state.sawUsage = true;
20210
20210
  state.inputTokens = numberOr$8(usage.input_tokens, 0);
@@ -20218,7 +20218,7 @@ function processAnthropicStreamLine$1(line, state) {
20218
20218
  }
20219
20219
  if (type === "content_block_start") {
20220
20220
  const contentIndex = numberOr$8(event.index, 0);
20221
- const block = isRecord$43(event.content_block) ? event.content_block : {};
20221
+ const block = isRecord$44(event.content_block) ? event.content_block : {};
20222
20222
  const blockType = asString$22(block.type);
20223
20223
  out.push(...closeCurrent$5(state));
20224
20224
  if (blockType === "tool_use") {
@@ -20268,7 +20268,7 @@ function processAnthropicStreamLine$1(line, state) {
20268
20268
  }
20269
20269
  if (type === "content_block_delta") {
20270
20270
  const contentIndex = numberOr$8(event.index, 0);
20271
- const delta = isRecord$43(event.delta) ? event.delta : {};
20271
+ const delta = isRecord$44(event.delta) ? event.delta : {};
20272
20272
  const deltaType = asString$22(delta.type);
20273
20273
  if (deltaType === "input_json_delta") {
20274
20274
  const pending = state.toolCalls.get(contentIndex);
@@ -20341,10 +20341,10 @@ function processAnthropicStreamLine$1(line, state) {
20341
20341
  return out;
20342
20342
  }
20343
20343
  if (type === "message_delta") {
20344
- const delta = isRecord$43(event.delta) ? event.delta : void 0;
20344
+ const delta = isRecord$44(event.delta) ? event.delta : void 0;
20345
20345
  const stop = delta ? asString$22(delta.stop_reason) : void 0;
20346
20346
  if (stop !== void 0 && stop !== "") state.finishReason = stop;
20347
- const usage = isRecord$43(event.usage) ? event.usage : void 0;
20347
+ const usage = isRecord$44(event.usage) ? event.usage : void 0;
20348
20348
  if (usage) {
20349
20349
  state.sawUsage = true;
20350
20350
  state.outputTokens = numberOr$8(usage.output_tokens, state.outputTokens);
@@ -20356,7 +20356,7 @@ function processAnthropicStreamLine$1(line, state) {
20356
20356
  return closeStream$5(state);
20357
20357
  }
20358
20358
  if (type === "error") {
20359
- const error = isRecord$43(event.error) ? event.error : {};
20359
+ const error = isRecord$44(event.error) ? event.error : {};
20360
20360
  const message = asString$22(error.message) ?? "unknown error";
20361
20361
  state.streamError = {
20362
20362
  vocabulary: "anthropic",
@@ -20402,7 +20402,7 @@ function processResponsesStreamLine(line, state) {
20402
20402
  } catch {
20403
20403
  return [];
20404
20404
  }
20405
- if (!isRecord$43(parsed)) return [];
20405
+ if (!isRecord$44(parsed)) return [];
20406
20406
  const type = typeof parsed.type === "string" ? parsed.type : "";
20407
20407
  if (type === "response.output_text.delta") {
20408
20408
  const delta = typeof parsed.delta === "string" ? parsed.delta : "";
@@ -20429,7 +20429,7 @@ function processResponsesStreamLine(line, state) {
20429
20429
  }];
20430
20430
  }
20431
20431
  if (type === "response.output_item.added") {
20432
- const item = isRecord$43(parsed.item) ? parsed.item : null;
20432
+ const item = isRecord$44(parsed.item) ? parsed.item : null;
20433
20433
  if (item === null || item.type !== "function_call") return [];
20434
20434
  return startResponsesToolCall(state, parsed, item);
20435
20435
  }
@@ -20453,11 +20453,11 @@ function processResponsesStreamLine(line, state) {
20453
20453
  return [];
20454
20454
  }
20455
20455
  if (type === "response.completed" || type === "response.incomplete") {
20456
- const response = isRecord$43(parsed.response) ? parsed.response : null;
20456
+ const response = isRecord$44(parsed.response) ? parsed.response : null;
20457
20457
  if (response !== null) {
20458
20458
  if (response.status === "failed") {
20459
20459
  state.done = true;
20460
- const errorObj = isRecord$43(response.error) ? response.error : null;
20460
+ const errorObj = isRecord$44(response.error) ? response.error : null;
20461
20461
  const detail = errorObj && typeof errorObj.message === "string" ? errorObj.message : typeof response.error === "string" ? response.error : "";
20462
20462
  state.streamError = {
20463
20463
  vocabulary: "responses",
@@ -20470,7 +20470,7 @@ function processResponsesStreamLine(line, state) {
20470
20470
  }
20471
20471
  state.done = true;
20472
20472
  if (type === "response.incomplete") {
20473
- const details = response && isRecord$43(response.incomplete_details) ? response.incomplete_details : null;
20473
+ const details = response && isRecord$44(response.incomplete_details) ? response.incomplete_details : null;
20474
20474
  const reason = details && typeof details.reason === "string" ? details.reason : "";
20475
20475
  state.finishReason = reason === "max_output_tokens" || reason === "length" || reason === "max_tokens" ? "length" : reason || "length";
20476
20476
  } else state.finishReason = "stop";
@@ -20478,8 +20478,8 @@ function processResponsesStreamLine(line, state) {
20478
20478
  }
20479
20479
  if (type === "response.failed" || type === "error") {
20480
20480
  state.done = true;
20481
- const errorObj = isRecord$43(parsed.error) ? parsed.error : isRecord$43(parsed.response) && isRecord$43(parsed.response.error) ? parsed.response.error : null;
20482
- const detail = (typeof parsed.message === "string" ? parsed.message : "") || (errorObj && typeof errorObj.message === "string" ? errorObj.message : "") || (isRecord$43(parsed.response) && typeof parsed.response.error === "string" ? parsed.response.error : typeof parsed.error === "string" ? parsed.error : "");
20481
+ const errorObj = isRecord$44(parsed.error) ? parsed.error : isRecord$44(parsed.response) && isRecord$44(parsed.response.error) ? parsed.response.error : null;
20482
+ const detail = (typeof parsed.message === "string" ? parsed.message : "") || (errorObj && typeof errorObj.message === "string" ? errorObj.message : "") || (isRecord$44(parsed.response) && typeof parsed.response.error === "string" ? parsed.response.error : typeof parsed.error === "string" ? parsed.error : "");
20483
20483
  state.streamError = {
20484
20484
  vocabulary: "responses",
20485
20485
  error: errorObj,
@@ -20567,15 +20567,15 @@ function responsesToolCall(state, key) {
20567
20567
  for (const call of state.toolCalls.values()) if (call.id === toToolCallId(key)) return call;
20568
20568
  }
20569
20569
  function readResponsesUsage(response, state) {
20570
- const usage = isRecord$43(response.usage) ? response.usage : null;
20570
+ const usage = isRecord$44(response.usage) ? response.usage : null;
20571
20571
  if (usage === null) return;
20572
- const cached = isRecord$43(usage.input_tokens_details) ? numberOrZero(usage.input_tokens_details.cached_tokens) : 0;
20573
- const written = isRecord$43(usage.input_tokens_details) ? numberOrZero(usage.input_tokens_details.cache_write_tokens) : 0;
20572
+ const cached = isRecord$44(usage.input_tokens_details) ? numberOrZero(usage.input_tokens_details.cached_tokens) : 0;
20573
+ const written = isRecord$44(usage.input_tokens_details) ? numberOrZero(usage.input_tokens_details.cache_write_tokens) : 0;
20574
20574
  state.inputTokens = Math.max(0, numberOrZero(usage.input_tokens) - cached - written);
20575
20575
  state.cacheReadTokens = cached;
20576
20576
  state.cacheWriteTokens = written;
20577
20577
  state.outputTokens = numberOrZero(usage.output_tokens);
20578
- const outputDetails = isRecord$43(usage.output_tokens_details) ? usage.output_tokens_details : null;
20578
+ const outputDetails = isRecord$44(usage.output_tokens_details) ? usage.output_tokens_details : null;
20579
20579
  if (outputDetails !== null) state.reasoningTokens = numberOrZero(outputDetails.reasoning_tokens);
20580
20580
  state.sawUsage = true;
20581
20581
  }
@@ -20663,7 +20663,7 @@ const ANTHROPIC_IN_BAND_STATUS = {
20663
20663
  * Anything not recognized keeps the mapper's verdict.
20664
20664
  */
20665
20665
  function inBandResponsesCode(error, message) {
20666
- const fields = isRecord$42(error) ? error : {};
20666
+ const fields = isRecord$43(error) ? error : {};
20667
20667
  const rawCode = (asString$21(fields.code) ?? asString$21(fields.type) ?? "").toLowerCase();
20668
20668
  const text = message.toLowerCase();
20669
20669
  if (text.includes("rate limit") || rawCode === "rate_limit" || rawCode === "rate_limit_exceeded") return "RATE_LIMIT";
@@ -20722,13 +20722,13 @@ function reclassifyInBandResponsesError(thrown, rawError, message, classify) {
20722
20722
  }
20723
20723
  /** The wire `error` object of an in-band event, read defensively. */
20724
20724
  function readErrorType(error) {
20725
- if (!isRecord$42(error)) return null;
20725
+ if (!isRecord$43(error)) return null;
20726
20726
  return typeof error.type === "string" ? error.type : null;
20727
20727
  }
20728
20728
  function asString$21(value) {
20729
20729
  return typeof value === "string" ? value : void 0;
20730
20730
  }
20731
- function isRecord$42(value) {
20731
+ function isRecord$43(value) {
20732
20732
  return typeof value === "object" && value !== null && !Array.isArray(value);
20733
20733
  }
20734
20734
  //#endregion
@@ -23923,14 +23923,14 @@ const IN_BAND_SERVER = [
23923
23923
  function isAbort$3(error, signal) {
23924
23924
  return signal?.aborted === true || error instanceof Error && error.name === "AbortError";
23925
23925
  }
23926
- function isRecord$41(value) {
23926
+ function isRecord$42(value) {
23927
23927
  return typeof value === "object" && value !== null && !Array.isArray(value);
23928
23928
  }
23929
23929
  function asString$20(value) {
23930
23930
  return typeof value === "string" && value !== "" ? value : void 0;
23931
23931
  }
23932
23932
  function attachmentLabel$4(block) {
23933
- const attachment = isRecord$41(block.attachment) ? block.attachment : void 0;
23933
+ const attachment = isRecord$42(block.attachment) ? block.attachment : void 0;
23934
23934
  return asString$20(attachment?.name) || asString$20(attachment?.attachmentId);
23935
23935
  }
23936
23936
  function unavailableImageText$4(block) {
@@ -23966,7 +23966,7 @@ async function processMessageContent(content, model, attachments, signal) {
23966
23966
  textParts.push(part);
23967
23967
  continue;
23968
23968
  }
23969
- if (!isRecord$41(part)) continue;
23969
+ if (!isRecord$42(part)) continue;
23970
23970
  if (part.type === "text") {
23971
23971
  if (typeof part.text === "string" && part.text !== "") textParts.push(part.text);
23972
23972
  continue;
@@ -23995,7 +23995,7 @@ async function processMessageContent(content, model, attachments, signal) {
23995
23995
  continue;
23996
23996
  }
23997
23997
  const inline = part.source;
23998
- if (isRecord$41(inline)) {
23998
+ if (isRecord$42(inline)) {
23999
23999
  const data = inline.data;
24000
24000
  if (typeof data === "string" && data !== "") {
24001
24001
  images.push(encodeImage(data, asMediaType(inline.mediaType)));
@@ -24036,7 +24036,7 @@ async function toOllamaRequest(options, attachments, signal, declared) {
24036
24036
  const toolResultBlocks = message.content.filter((b) => b.type === "tool-result");
24037
24037
  if (toolResultBlocks.length > 0) {
24038
24038
  for (const block of toolResultBlocks) {
24039
- const toolCallId = String(block.toolCallId ?? (isRecord$41(message.source) ? message.source.callId : "") ?? "");
24039
+ const toolCallId = String(block.toolCallId ?? (isRecord$42(message.source) ? message.source.callId : "") ?? "");
24040
24040
  const processed = await processMessageContent(block.content, options.model, attachments, signal);
24041
24041
  messages.push({
24042
24042
  role: "tool",
@@ -24647,7 +24647,7 @@ var OllamaAccountPool = class extends AccountPoolCore {
24647
24647
  };
24648
24648
  //#endregion
24649
24649
  //#region src/host/common/request-images.ts
24650
- function isRecord$40(value) {
24650
+ function isRecord$41(value) {
24651
24651
  return typeof value === "object" && value !== null && !Array.isArray(value);
24652
24652
  }
24653
24653
  function asString$19(value) {
@@ -24706,17 +24706,17 @@ const SUPPORTED_IMAGE_MEDIA_TYPES$3 = /* @__PURE__ */ new Set([
24706
24706
  ]);
24707
24707
  function attachmentOf$3(block) {
24708
24708
  const attachment = block.attachment;
24709
- if (!isRecord$40(attachment)) return void 0;
24709
+ if (!isRecord$41(attachment)) return void 0;
24710
24710
  return typeof attachment.attachmentId === "string" ? attachment : void 0;
24711
24711
  }
24712
24712
  function attachmentLabel$3(block) {
24713
- const attachment = isRecord$40(block.attachment) ? block.attachment : void 0;
24713
+ const attachment = isRecord$41(block.attachment) ? block.attachment : void 0;
24714
24714
  return asString$19(attachment?.name) || asString$19(attachment?.attachmentId);
24715
24715
  }
24716
24716
  function collectImageRefs$1(content, refs) {
24717
24717
  if (!Array.isArray(content)) return;
24718
24718
  for (const block of content) {
24719
- if (!isRecord$40(block)) continue;
24719
+ if (!isRecord$41(block)) continue;
24720
24720
  if (block.type === "image") {
24721
24721
  const attachment = attachmentOf$3(block);
24722
24722
  if (attachment) refs.set(attachment.attachmentId, attachment);
@@ -24746,7 +24746,7 @@ function base64Length$1(bytes) {
24746
24746
  */
24747
24747
  function requestImagePayloadLength(block, images) {
24748
24748
  let data = asString$19(block.data) || asString$19(block.base64);
24749
- const source = isRecord$40(block.source) ? block.source : void 0;
24749
+ const source = isRecord$41(block.source) ? block.source : void 0;
24750
24750
  if (!data && source) data = asString$19(source.data) || asString$19(source.base64);
24751
24751
  if (data?.startsWith("data:")) {
24752
24752
  const matched = data.match(/^data:([^;,]+);base64,(.*)$/s);
@@ -24772,7 +24772,7 @@ function requestImagePayloadLength(block, images) {
24772
24772
  function collectRequestImagePayloads(content, images, lengths) {
24773
24773
  if (!Array.isArray(content)) return;
24774
24774
  for (const block of content) {
24775
- if (!isRecord$40(block)) continue;
24775
+ if (!isRecord$41(block)) continue;
24776
24776
  if (block.type === "image") {
24777
24777
  const bytes = requestImagePayloadLength(block, images);
24778
24778
  if (bytes !== void 0) lengths.push(bytes);
@@ -24826,7 +24826,7 @@ function replaceOldestRequestImages(options, count, images) {
24826
24826
  let replaced = false;
24827
24827
  return {
24828
24828
  content: content.map((block) => {
24829
- if (remaining.count === 0 || !isRecord$40(block)) return block;
24829
+ if (remaining.count === 0 || !isRecord$41(block)) return block;
24830
24830
  if (block.type === "image") {
24831
24831
  if (requestImagePayloadLength(block, images) === void 0) return block;
24832
24832
  remaining.count -= 1;
@@ -25027,7 +25027,7 @@ function unavailableImageText$3(block) {
25027
25027
  }
25028
25028
  function imageBlockToInline$2(block, images) {
25029
25029
  let data = asString$19(block.data) || asString$19(block.base64);
25030
- const source = isRecord$40(block.source) ? block.source : void 0;
25030
+ const source = isRecord$41(block.source) ? block.source : void 0;
25031
25031
  if (!data && source) data = asString$19(source.data) || asString$19(source.base64);
25032
25032
  let mediaType = asString$19(block.mimeType) || asString$19(block.mediaType) || (source ? asString$19(source.mimeType) || asString$19(source.mediaType) : void 0) || "image/png";
25033
25033
  if (data?.startsWith("data:")) {
@@ -26015,7 +26015,7 @@ function evaluateCacheHint(input) {
26015
26015
  if (!Number.isFinite(lastActiveAt) || !Number.isFinite(totalTokens)) return { kind: "skip" };
26016
26016
  if (totalTokens < 1e5) return { kind: "skip" };
26017
26017
  const idleMs = now - lastActiveAt;
26018
- if (idleMs <= 18e5) return { kind: "skip" };
26018
+ if (idleMs <= 15e5) return { kind: "skip" };
26019
26019
  return {
26020
26020
  kind: "hint",
26021
26021
  idleMs,
@@ -26606,11 +26606,11 @@ const MODELS_PATH$2 = "/models";
26606
26606
  const USAGES_PATH = "/usages";
26607
26607
  /** The service reports money in fixed-point units of 1e-6 cents. */
26608
26608
  const FIXED_POINT_CENTS = 1e6;
26609
- function isRecord$39(value) {
26609
+ function isRecord$40(value) {
26610
26610
  return typeof value === "object" && value !== null && !Array.isArray(value);
26611
26611
  }
26612
26612
  function asRecord$13(value) {
26613
- return isRecord$39(value) ? value : void 0;
26613
+ return isRecord$40(value) ? value : void 0;
26614
26614
  }
26615
26615
  function asString$18(value) {
26616
26616
  if (typeof value === "string" && value.trim() !== "") return value;
@@ -27197,7 +27197,7 @@ function usageWindow(id, record, descriptor) {
27197
27197
  id,
27198
27198
  label: descriptor?.label ?? humanizeWindowKey(id),
27199
27199
  usedFraction,
27200
- usedPercent: Math.round(usedFraction * 100),
27200
+ usedPercent: Math.round(usedFraction * 1e4) / 100,
27201
27201
  windowDurationMins: descriptor?.minutes ?? null,
27202
27202
  resetsAt: parseTimestamp(record.reset_time ?? record.resetTime ?? record.resetsAt),
27203
27203
  limit: formatAmount(limit),
@@ -27582,12 +27582,12 @@ async function testConnection$1(store, options = {}) {
27582
27582
  *
27583
27583
  * @module dsh-chatgpt-subscription/tool-schema
27584
27584
  */
27585
- function isRecord$38(value) {
27585
+ function isRecord$39(value) {
27586
27586
  return typeof value === "object" && value !== null && !Array.isArray(value);
27587
27587
  }
27588
27588
  function cloneJsonValue(value) {
27589
27589
  if (Array.isArray(value)) return value.map(cloneJsonValue);
27590
- if (isRecord$38(value)) {
27590
+ if (isRecord$39(value)) {
27591
27591
  const res = {};
27592
27592
  for (const [k, v] of Object.entries(value)) res[k] = cloneJsonValue(v);
27593
27593
  return res;
@@ -27602,7 +27602,7 @@ function resolveLocalJsonPointer(root, ref) {
27602
27602
  let current = root;
27603
27603
  for (const rawPart of ref.slice(2).split("/")) {
27604
27604
  const part = rawPart.replaceAll("~1", "/").replaceAll("~0", "~");
27605
- if (isRecord$38(current)) {
27605
+ if (isRecord$39(current)) {
27606
27606
  if (!Object.prototype.hasOwnProperty.call(current, part)) return { found: false };
27607
27607
  current = current[part];
27608
27608
  } else if (Array.isArray(current)) {
@@ -27618,7 +27618,7 @@ function resolveLocalJsonPointer(root, ref) {
27618
27618
  }
27619
27619
  function derefNode(node, root, visited) {
27620
27620
  if (Array.isArray(node)) return node.map((item) => derefNode(item, root, visited));
27621
- if (isRecord$38(node)) {
27621
+ if (isRecord$39(node)) {
27622
27622
  if (typeof node["$ref"] === "string" && (node["$ref"] === "#" || node["$ref"].startsWith("#/"))) {
27623
27623
  const ref = node["$ref"];
27624
27624
  if (visited.has(ref)) return node;
@@ -27627,7 +27627,7 @@ function derefNode(node, root, visited) {
27627
27627
  visited.add(ref);
27628
27628
  const inlined = derefNode(resolved.value, root, visited);
27629
27629
  visited.delete(ref);
27630
- if (isRecord$38(inlined)) {
27630
+ if (isRecord$39(inlined)) {
27631
27631
  const merged = { ...inlined };
27632
27632
  for (const [k, v] of Object.entries(node)) {
27633
27633
  if (k === "$ref") continue;
@@ -27647,7 +27647,7 @@ function derefNode(node, root, visited) {
27647
27647
  }
27648
27648
  function hasUnresolvedDefinitionRef(node, bucketKey) {
27649
27649
  if (Array.isArray(node)) return node.some((child) => hasUnresolvedDefinitionRef(child, bucketKey));
27650
- if (isRecord$38(node)) {
27650
+ if (isRecord$39(node)) {
27651
27651
  const ref = node["$ref"];
27652
27652
  if (typeof ref === "string" && ref.startsWith(`#/${bucketKey}/`)) return true;
27653
27653
  for (const [k, v] of Object.entries(node)) {
@@ -27678,19 +27678,19 @@ function inferTypeFromValues(values) {
27678
27678
  if (types.size === 1) return types.values().next().value;
27679
27679
  }
27680
27680
  function normalizeSchemaProperties(node) {
27681
- if (!isRecord$38(node)) return;
27682
- if (isRecord$38(node.properties)) {
27683
- for (const propSchema of Object.values(node.properties)) if (isRecord$38(propSchema)) {
27681
+ if (!isRecord$39(node)) return;
27682
+ if (isRecord$39(node.properties)) {
27683
+ for (const propSchema of Object.values(node.properties)) if (isRecord$39(propSchema)) {
27684
27684
  if (!propSchema.type && !propSchema.$ref) {
27685
27685
  if (Array.isArray(propSchema.enum) && propSchema.enum.length > 0) propSchema.type = inferTypeFromValues(propSchema.enum) ?? "string";
27686
27686
  else if (propSchema.const !== void 0) propSchema.type = inferValueType(propSchema.const) ?? "string";
27687
- else if (isRecord$38(propSchema.properties)) propSchema.type = "object";
27687
+ else if (isRecord$39(propSchema.properties)) propSchema.type = "object";
27688
27688
  else if (propSchema.items) propSchema.type = "array";
27689
27689
  }
27690
27690
  normalizeSchemaProperties(propSchema);
27691
27691
  }
27692
27692
  }
27693
- if (isRecord$38(node.items)) normalizeSchemaProperties(node.items);
27693
+ if (isRecord$39(node.items)) normalizeSchemaProperties(node.items);
27694
27694
  else if (Array.isArray(node.items)) for (const item of node.items) normalizeSchemaProperties(item);
27695
27695
  }
27696
27696
  /**
@@ -27698,7 +27698,7 @@ function normalizeSchemaProperties(node) {
27698
27698
  * inlining definitions ($defs/definitions/$ref), and ensuring property types for enums/consts.
27699
27699
  */
27700
27700
  function normalizeKimiToolSchema(schema) {
27701
- if (!isRecord$38(schema)) return {
27701
+ if (!isRecord$39(schema)) return {
27702
27702
  type: "object",
27703
27703
  properties: {}
27704
27704
  };
@@ -27716,7 +27716,7 @@ function stripMetaSchema$1(schema) {
27716
27716
  }
27717
27717
  //#endregion
27718
27718
  //#region src/host/common/prompt-estimate.ts
27719
- function isRecord$37(value) {
27719
+ function isRecord$38(value) {
27720
27720
  return typeof value === "object" && value !== null && !Array.isArray(value);
27721
27721
  }
27722
27722
  /** Tool-call arguments as the JSON string a wire carries, whatever shape they arrived in. */
@@ -27749,7 +27749,7 @@ function estimatedInputTokens(options) {
27749
27749
  const contentCharacters = (content) => {
27750
27750
  if (!Array.isArray(content)) return typeof content === "string" ? content.length : 0;
27751
27751
  return content.reduce((total, block) => {
27752
- if (!isRecord$37(block)) return total;
27752
+ if (!isRecord$38(block)) return total;
27753
27753
  if ((block.type === "text" || block.type === "reasoning") && typeof block.text === "string") return total + block.text.length;
27754
27754
  if (block.type === "tool-result") return total + contentCharacters(block.content);
27755
27755
  if (block.type === "tool-call") {
@@ -27850,7 +27850,7 @@ function videoOmissionText$1(reason, label) {
27850
27850
  }
27851
27851
  //#endregion
27852
27852
  //#region src/host/common/video-request.ts
27853
- function isRecord$36(value) {
27853
+ function isRecord$37(value) {
27854
27854
  return typeof value === "object" && value !== null && !Array.isArray(value);
27855
27855
  }
27856
27856
  function asString$17(value) {
@@ -27858,14 +27858,14 @@ function asString$17(value) {
27858
27858
  }
27859
27859
  function videoAttachmentOf(block) {
27860
27860
  const attachment = block.attachment;
27861
- if (!isRecord$36(attachment)) return void 0;
27861
+ if (!isRecord$37(attachment)) return void 0;
27862
27862
  if (typeof attachment.attachmentId !== "string") return void 0;
27863
27863
  return attachment;
27864
27864
  }
27865
27865
  function collectVideoRefs(content, refs) {
27866
27866
  if (!Array.isArray(content)) return;
27867
27867
  for (const block of content) {
27868
- if (!isRecord$36(block) || block.type !== "video") continue;
27868
+ if (!isRecord$37(block) || block.type !== "video") continue;
27869
27869
  const attachment = videoAttachmentOf(block);
27870
27870
  if (attachment) refs.set(attachment.attachmentId, attachment);
27871
27871
  }
@@ -27880,7 +27880,7 @@ function requestVideoBytes(block) {
27880
27880
  function collectRequestVideoBytes(content, lengths) {
27881
27881
  if (!Array.isArray(content)) return;
27882
27882
  for (const block of content) {
27883
- if (!isRecord$36(block) || block.type !== "video") continue;
27883
+ if (!isRecord$37(block) || block.type !== "video") continue;
27884
27884
  const bytes = requestVideoBytes(block);
27885
27885
  if (bytes !== void 0) lengths.push(bytes);
27886
27886
  }
@@ -27924,7 +27924,7 @@ function isAbortLike(error, signal) {
27924
27924
  }
27925
27925
  /** True when the request carries any video occurrence at all. */
27926
27926
  function requestHasVideo(options) {
27927
- return options.messages.some((message) => Array.isArray(message.content) && message.content.some((block) => isRecord$36(block) && block.type === "video"));
27927
+ return options.messages.some((message) => Array.isArray(message.content) && message.content.some((block) => isRecord$37(block) && block.type === "video"));
27928
27928
  }
27929
27929
  function omittedVideoText(omit, block) {
27930
27930
  return omit("unreadable", videoBlockLabel(block));
@@ -27959,7 +27959,7 @@ function offloadOldestRequestVideos(options, maxBytes) {
27959
27959
  if (remaining.count === 0 || !Array.isArray(message.content)) return message;
27960
27960
  let replaced = false;
27961
27961
  const content = message.content.map((block) => {
27962
- if (remaining.count === 0 || !isRecord$36(block) || block.type !== "video") return block;
27962
+ if (remaining.count === 0 || !isRecord$37(block) || block.type !== "video") return block;
27963
27963
  if (requestVideoBytes(block) === void 0) return block;
27964
27964
  remaining.count -= 1;
27965
27965
  replaced = true;
@@ -28042,7 +28042,7 @@ function videoBlockToInline(block, videos, videoAccepted, omit) {
28042
28042
  *
28043
28043
  * See https://www.kimi.com/code/docs/en/kimi-code/error-reference.html
28044
28044
  */
28045
- function isRecord$35(value) {
28045
+ function isRecord$36(value) {
28046
28046
  return typeof value === "object" && value !== null && !Array.isArray(value);
28047
28047
  }
28048
28048
  function asString$16(value) {
@@ -28152,7 +28152,7 @@ function reasoningDetailFragments(value) {
28152
28152
  if (!Array.isArray(value)) return [];
28153
28153
  const fragments = [];
28154
28154
  value.forEach((entry, position) => {
28155
- if (!isRecord$35(entry)) return;
28155
+ if (!isRecord$36(entry)) return;
28156
28156
  fragments.push(...reasoningDetailElement(entry, position));
28157
28157
  });
28158
28158
  return fragments;
@@ -28399,7 +28399,7 @@ function textOf$6(content) {
28399
28399
  if (!Array.isArray(content)) return "";
28400
28400
  const parts = [];
28401
28401
  for (const block of content) {
28402
- if (!isRecord$35(block)) continue;
28402
+ if (!isRecord$36(block)) continue;
28403
28403
  if (block.type === "text" && typeof block.text === "string") parts.push(sanitizeText$6(block.text));
28404
28404
  else if (block.type === "tool-result") parts.push(textOf$6(block.content));
28405
28405
  }
@@ -28408,7 +28408,7 @@ function textOf$6(content) {
28408
28408
  function toolResultText$6(blocks) {
28409
28409
  if (!Array.isArray(blocks)) return "";
28410
28410
  return blocks.map((block) => {
28411
- if (!isRecord$35(block)) return "";
28411
+ if (!isRecord$36(block)) return "";
28412
28412
  if (block.type === "text" && typeof block.text === "string") return sanitizeText$6(block.text);
28413
28413
  if (block.type === "tool-result") return toolResultText$6(block.content);
28414
28414
  if (block.type === "image") return `[image: ${attachmentLabel$3(block) ?? "attached image"}]`;
@@ -28426,7 +28426,7 @@ function toolResultBlocks$1(blocks, images) {
28426
28426
  const out = [];
28427
28427
  let hasImage = false;
28428
28428
  for (const block of blocks) {
28429
- if (!isRecord$35(block)) continue;
28429
+ if (!isRecord$36(block)) continue;
28430
28430
  if (block.type === "text" && typeof block.text === "string") {
28431
28431
  out.push({
28432
28432
  type: "text",
@@ -28481,7 +28481,7 @@ function toolResultImageBlocks$3(blocks, images, media = {}) {
28481
28481
  if (!Array.isArray(blocks)) return [];
28482
28482
  const out = [];
28483
28483
  for (const block of blocks) {
28484
- if (!isRecord$35(block)) continue;
28484
+ if (!isRecord$36(block)) continue;
28485
28485
  if (block.type === "image") {
28486
28486
  const reference = hostedReference(media.imageReferences, block);
28487
28487
  if (reference !== void 0) {
@@ -28516,7 +28516,7 @@ const HOSTED_FILE_SCHEME = "ms://";
28516
28516
  * bytes.
28517
28517
  */
28518
28518
  function attachmentIdOf(block) {
28519
- const attachment = isRecord$35(block.attachment) ? block.attachment : void 0;
28519
+ const attachment = isRecord$36(block.attachment) ? block.attachment : void 0;
28520
28520
  const id = attachment === void 0 ? void 0 : asString$16(attachment.attachmentId);
28521
28521
  return id === void 0 || id === "" ? void 0 : id;
28522
28522
  }
@@ -28599,12 +28599,12 @@ function readReasoningForm(value) {
28599
28599
  */
28600
28600
  function reasoningRunsAt(message, blockIndex) {
28601
28601
  const state = message.source?.replayState;
28602
- if (!isRecord$35(state) || !Array.isArray(state.blocks)) return void 0;
28602
+ if (!isRecord$36(state) || !Array.isArray(state.blocks)) return void 0;
28603
28603
  const entry = state.blocks[blockIndex];
28604
- if (!isRecord$35(entry) || !Array.isArray(entry.reasoning)) return void 0;
28604
+ if (!isRecord$36(entry) || !Array.isArray(entry.reasoning)) return void 0;
28605
28605
  const runs = [];
28606
28606
  for (const raw of entry.reasoning) {
28607
- if (!isRecord$35(raw)) return void 0;
28607
+ if (!isRecord$36(raw)) return void 0;
28608
28608
  const key = asString$16(raw.key);
28609
28609
  const length = raw.length;
28610
28610
  if (key === void 0 || typeof length !== "number" || !Number.isInteger(length) || length < 0) return void 0;
@@ -28654,7 +28654,7 @@ function replayedReasoning(message, fallbackKey) {
28654
28654
  };
28655
28655
  for (let blockIndex = 0; blockIndex < message.content.length; blockIndex++) {
28656
28656
  const block = message.content[blockIndex];
28657
- if (!isRecord$35(block) || block.type !== "reasoning" || typeof block.text !== "string") continue;
28657
+ if (!isRecord$36(block) || block.type !== "reasoning" || typeof block.text !== "string") continue;
28658
28658
  const text = sanitizeText$6(block.text);
28659
28659
  joined += text;
28660
28660
  const runs = reasoningRunsAt(message, blockIndex);
@@ -28740,6 +28740,73 @@ function messageToolsOf(message) {
28740
28740
  if (Array.isArray(value) && value.length > 0) return value;
28741
28741
  }
28742
28742
  }
28743
+ /**
28744
+ * Names of the tools one developer message adds at its own history position.
28745
+ *
28746
+ * The harness states an addition as a name only; the definition it activates
28747
+ * lives in the request's declaration list, which is why the two are resolved
28748
+ * together rather than the block carrying a schema of its own.
28749
+ */
28750
+ function toolAdditionNames(message) {
28751
+ const names = [];
28752
+ for (const block of message.content) {
28753
+ if (block.type !== "tool-addition") continue;
28754
+ const name = block.toolName;
28755
+ if (typeof name !== "string" || name.trim() === "") continue;
28756
+ names.push(name.trim());
28757
+ }
28758
+ return names;
28759
+ }
28760
+ /**
28761
+ * Names of the tools one developer message revokes at its own history position.
28762
+ *
28763
+ * `in-history` is the only mode that emits these; a route declaring
28764
+ * `addition-only` never sees one, because the harness removes the declaration
28765
+ * from the list instead.
28766
+ */
28767
+ function toolRemovalNames(message) {
28768
+ const names = [];
28769
+ for (const block of message.content) {
28770
+ if (block.type !== "tool-removal") continue;
28771
+ const name = block.toolName;
28772
+ if (typeof name !== "string" || name.trim() === "") continue;
28773
+ names.push(name.trim());
28774
+ }
28775
+ return names;
28776
+ }
28777
+ /**
28778
+ * The model-facing note that revokes one or more tools.
28779
+ *
28780
+ * Imperative and unambiguous on purpose: the tool is still in the declaration
28781
+ * list (that is what keeps the prefix intact), so the only thing standing
28782
+ * between the model and a call that would fail is this sentence.
28783
+ */
28784
+ function removalNotice(names) {
28785
+ const list = names.map((name) => "\"" + name + "\"").join(", ");
28786
+ return names.length === 1 ? "[" + list + " is no longer available. Do not call it again: any call will fail.]" : "[" + list + " are no longer available. Do not call them again: any call will fail.]";
28787
+ }
28788
+ /**
28789
+ * Resolve additions against the declaration list the harness sent.
28790
+ *
28791
+ * A deferred definition keeps `deferLoading` for the top-level filter and loses
28792
+ * it here: a message-level declaration has no such field, and passing it on
28793
+ * would be a property the service documented a stricter shape for.
28794
+ */
28795
+ function declarationsFor(names, tools) {
28796
+ if (tools === void 0 || names.length === 0) return [];
28797
+ const byName = new Map(tools.map((tool) => [tool.name, tool]));
28798
+ const declarations = [];
28799
+ for (const name of names) {
28800
+ const tool = byName.get(name);
28801
+ if (tool === void 0) continue;
28802
+ declarations.push({
28803
+ name: tool.name,
28804
+ description: tool.description ?? "",
28805
+ parameters: stripMetaSchema$1(tool.parameters)
28806
+ });
28807
+ }
28808
+ return declarations;
28809
+ }
28743
28810
  /** One declaration in the wire shape Kimi documents for `messages[].tools`. */
28744
28811
  function openAIDynamicTool(tool) {
28745
28812
  return {
@@ -28756,7 +28823,7 @@ function openAIUserContent$2(message, images, media = {}) {
28756
28823
  const parts = [];
28757
28824
  let hasRichPart = false;
28758
28825
  for (const block of message.content) {
28759
- if (!isRecord$35(block)) continue;
28826
+ if (!isRecord$36(block)) continue;
28760
28827
  if (block.type === "text" && typeof block.text === "string") {
28761
28828
  const text = sanitizeText$6(block.text);
28762
28829
  if (text !== "") parts.push({
@@ -28814,7 +28881,7 @@ function openAIAssistantContent$2(message, toolCallIds, reasoningKey) {
28814
28881
  const textParts = [];
28815
28882
  const toolCalls = [];
28816
28883
  for (const block of message.content) {
28817
- if (!isRecord$35(block)) continue;
28884
+ if (!isRecord$36(block)) continue;
28818
28885
  if (block.type === "text" && typeof block.text === "string") textParts.push(sanitizeText$6(block.text));
28819
28886
  else if (block.type === "tool-call" && typeof block.name === "string") toolCalls.push({
28820
28887
  id: toolCallIds.normalize(typeof block.id === "string" && block.id !== "" ? block.id : `call_${toolCalls.length}`),
@@ -28857,6 +28924,28 @@ function declarationSlots(options, media) {
28857
28924
  const slots = [];
28858
28925
  let beforeIndex = 0;
28859
28926
  for (const message of options.messages) {
28927
+ if (message.role === "developer") {
28928
+ const additions = declarationsFor(toolAdditionNames(message), options.tools);
28929
+ const entries = [];
28930
+ if (additions.length > 0) entries.push(media.messageTools === true ? {
28931
+ role: "system",
28932
+ tools: additions.map(openAIDynamicTool)
28933
+ } : {
28934
+ role: "system",
28935
+ content: declarationNotice(options.model, additions.length, "capability")
28936
+ });
28937
+ const removals = toolRemovalNames(message);
28938
+ if (removals.length > 0) entries.push({
28939
+ role: "system",
28940
+ content: removalNotice(removals)
28941
+ });
28942
+ if (entries.length > 0) slots.push({
28943
+ beforeIndex,
28944
+ entries
28945
+ });
28946
+ beforeIndex += 1;
28947
+ continue;
28948
+ }
28860
28949
  if (message.role !== "system") {
28861
28950
  beforeIndex += 1;
28862
28951
  continue;
@@ -28977,7 +29066,7 @@ function buildOpenAIRequest(options, images = NO_RESOLVED_IMAGES$3, preserveThin
28977
29066
  nonSystemIndex += 1;
28978
29067
  }
28979
29068
  const block = current.content[0];
28980
- const callId = isRecord$35(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
29069
+ const callId = isRecord$36(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
28981
29070
  messages.push({
28982
29071
  role: "tool",
28983
29072
  tool_call_id: toolCallIds.normalize(callId),
@@ -29012,6 +29101,7 @@ function buildOpenAIRequest(options, images = NO_RESOLVED_IMAGES$3, preserveThin
29012
29101
  });
29013
29102
  }
29014
29103
  flushSlots(nonSystemIndex);
29104
+ const topLevelTools = (options.tools ?? []).filter((tool) => tool.deferLoading !== true);
29015
29105
  const maxTokens = options.maxTokens ?? maxOutputTokensFor$4(options.model);
29016
29106
  const body = {
29017
29107
  model: options.model,
@@ -29020,8 +29110,8 @@ function buildOpenAIRequest(options, images = NO_RESOLVED_IMAGES$3, preserveThin
29020
29110
  stream_options: { include_usage: true },
29021
29111
  max_completion_tokens: maxTokens,
29022
29112
  ...stopSequences(options.stop).length > 0 ? { stop: stopSequences(options.stop) } : {},
29023
- ...options.tools && options.tools.length > 0 ? {
29024
- tools: options.tools.map((tool) => ({
29113
+ ...topLevelTools.length > 0 ? {
29114
+ tools: topLevelTools.map((tool) => ({
29025
29115
  type: "function",
29026
29116
  function: {
29027
29117
  name: tool.name,
@@ -29064,7 +29154,7 @@ function anthropicUserContent$2(message, images, toolCallIds) {
29064
29154
  if (!Array.isArray(message.content)) return [];
29065
29155
  const blocks = [];
29066
29156
  for (const block of message.content) {
29067
- if (!isRecord$35(block)) continue;
29157
+ if (!isRecord$36(block)) continue;
29068
29158
  if (block.type === "video") {
29069
29159
  blocks.push({
29070
29160
  type: "text",
@@ -29108,7 +29198,7 @@ function anthropicUserContent$2(message, images, toolCallIds) {
29108
29198
  function anthropicAssistantContent$2(message, toolCallIds) {
29109
29199
  const blocks = [];
29110
29200
  for (const block of message.content) {
29111
- if (!isRecord$35(block)) continue;
29201
+ if (!isRecord$36(block)) continue;
29112
29202
  if (block.type === "text" && typeof block.text === "string") {
29113
29203
  const text = sanitizeText$6(block.text);
29114
29204
  if (text !== "") blocks.push({
@@ -29121,7 +29211,7 @@ function anthropicAssistantContent$2(message, toolCallIds) {
29121
29211
  type: "tool_use",
29122
29212
  id: toolCallIds.normalize(typeof block.id === "string" && block.id !== "" ? block.id : `toolu_${blocks.length}`),
29123
29213
  name: block.name,
29124
- input: isRecord$35(parsed) ? parsed : {}
29214
+ input: isRecord$36(parsed) ? parsed : {}
29125
29215
  });
29126
29216
  }
29127
29217
  }
@@ -29243,7 +29333,7 @@ function walkJson(value, visit) {
29243
29333
  for (const item of value) walkJson(item, visit);
29244
29334
  return;
29245
29335
  }
29246
- if (!isRecord$35(value)) return;
29336
+ if (!isRecord$36(value)) return;
29247
29337
  visit(value);
29248
29338
  for (const nested of Object.values(value)) walkJson(nested, visit);
29249
29339
  }
@@ -29259,12 +29349,12 @@ function requestBodyBreakdown(body, carriesVideo = false) {
29259
29349
  const totalBytes = Buffer.byteLength(serialized, "utf8");
29260
29350
  let imageBytes = 0;
29261
29351
  walkJson(body, (node) => {
29262
- const url = isRecord$35(node.image_url) ? asString$16(node.image_url.url) : void 0;
29352
+ const url = isRecord$36(node.image_url) ? asString$16(node.image_url.url) : void 0;
29263
29353
  if (url?.startsWith("data:")) {
29264
29354
  imageBytes += Buffer.byteLength(url, "utf8");
29265
29355
  return;
29266
29356
  }
29267
- const source = isRecord$35(node.source) ? node.source : void 0;
29357
+ const source = isRecord$36(node.source) ? node.source : void 0;
29268
29358
  if (source && asString$16(source.data) !== void 0 && asString$16(source.media_type) !== void 0) imageBytes += Buffer.byteLength(asString$16(source.data) ?? "", "utf8");
29269
29359
  });
29270
29360
  const toolSchemaBytes = Buffer.byteLength(JSON.stringify(body.tools ?? []), "utf8");
@@ -29390,9 +29480,9 @@ function processOpenAIStreamLine(line, state) {
29390
29480
  }
29391
29481
  if (payload === "") return [];
29392
29482
  const chunk = safeJsonParse$6(payload);
29393
- if (!isRecord$35(chunk)) return [];
29483
+ if (!isRecord$36(chunk)) return [];
29394
29484
  const out = [];
29395
- const errorPayload = isRecord$35(chunk.error) ? chunk.error : void 0;
29485
+ const errorPayload = isRecord$36(chunk.error) ? chunk.error : void 0;
29396
29486
  if (errorPayload !== void 0) {
29397
29487
  const message = asString$16(errorPayload.message) ?? "unknown error";
29398
29488
  state.streamError = {
@@ -29402,22 +29492,22 @@ function processOpenAIStreamLine(line, state) {
29402
29492
  };
29403
29493
  throw new LlmError$1(`Kimi Code stream error: ${message}`, isContextOverflow(errorPayload) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
29404
29494
  }
29405
- const usage = isRecord$35(chunk.usage) ? chunk.usage : void 0;
29495
+ const usage = isRecord$36(chunk.usage) ? chunk.usage : void 0;
29406
29496
  if (usage) {
29407
29497
  state.sawUsage = true;
29408
29498
  const prompt = numberOr$7(usage.prompt_tokens, 0);
29409
- const details = isRecord$35(usage.prompt_tokens_details) ? usage.prompt_tokens_details : void 0;
29499
+ const details = isRecord$36(usage.prompt_tokens_details) ? usage.prompt_tokens_details : void 0;
29410
29500
  const cached = details ? numberOr$7(details.cached_tokens, 0) : 0;
29411
29501
  const written = details ? numberOr$7(details.cache_write_tokens, 0) : 0;
29412
29502
  state.inputTokens = Math.max(0, prompt - cached - written);
29413
29503
  state.cacheReadTokens = cached;
29414
29504
  state.cacheWriteTokens = written;
29415
29505
  state.outputTokens = numberOr$7(usage.completion_tokens, state.outputTokens);
29416
- if (isRecord$35(usage.completion_tokens_details)) state.reasoningTokens = numberOr$7(usage.completion_tokens_details.reasoning_tokens, state.reasoningTokens);
29506
+ if (isRecord$36(usage.completion_tokens_details)) state.reasoningTokens = numberOr$7(usage.completion_tokens_details.reasoning_tokens, state.reasoningTokens);
29417
29507
  }
29418
29508
  const choices = Array.isArray(chunk.choices) ? chunk.choices : [];
29419
- const choice = isRecord$35(choices[0]) ? choices[0] : void 0;
29420
- const delta = isRecord$35(choice?.delta) ? choice.delta : void 0;
29509
+ const choice = isRecord$36(choices[0]) ? choices[0] : void 0;
29510
+ const delta = isRecord$36(choice?.delta) ? choice.delta : void 0;
29421
29511
  if (delta) {
29422
29512
  for (const fragment of reasoningDialect.observeAll(delta)) {
29423
29513
  const text = sanitizeText$6(fragment.text);
@@ -29458,7 +29548,7 @@ function processOpenAIStreamLine(line, state) {
29458
29548
  }
29459
29549
  const toolDeltas = Array.isArray(delta.tool_calls) ? delta.tool_calls : [];
29460
29550
  for (const entry of toolDeltas) {
29461
- if (!isRecord$35(entry)) continue;
29551
+ if (!isRecord$36(entry)) continue;
29462
29552
  out.push(...applyOpenAIToolDelta(entry, state));
29463
29553
  }
29464
29554
  }
@@ -29472,7 +29562,7 @@ function processOpenAIStreamLine(line, state) {
29472
29562
  }
29473
29563
  function applyOpenAIToolDelta(entry, state) {
29474
29564
  const wireIndex = typeof entry.index === "number" ? entry.index : 0;
29475
- const fn = isRecord$35(entry.function) ? entry.function : {};
29565
+ const fn = isRecord$36(entry.function) ? entry.function : {};
29476
29566
  const out = [];
29477
29567
  let call = state.toolCalls.get(wireIndex);
29478
29568
  if (call === void 0) {
@@ -29527,12 +29617,12 @@ function processAnthropicStreamLine(line, state) {
29527
29617
  const payload = trimmed.slice(5).trim();
29528
29618
  if (payload === "" || payload === "[DONE]") return [];
29529
29619
  const event = safeJsonParse$6(payload);
29530
- if (!isRecord$35(event)) return [];
29620
+ if (!isRecord$36(event)) return [];
29531
29621
  const type = asString$16(event.type);
29532
29622
  const out = [];
29533
29623
  if (type === "message_start") {
29534
- const message = isRecord$35(event.message) ? event.message : void 0;
29535
- const usage = message && isRecord$35(message.usage) ? message.usage : void 0;
29624
+ const message = isRecord$36(event.message) ? event.message : void 0;
29625
+ const usage = message && isRecord$36(message.usage) ? message.usage : void 0;
29536
29626
  if (usage) {
29537
29627
  state.sawUsage = true;
29538
29628
  state.inputTokens = numberOr$7(usage.input_tokens, 0);
@@ -29546,7 +29636,7 @@ function processAnthropicStreamLine(line, state) {
29546
29636
  }
29547
29637
  if (type === "content_block_start") {
29548
29638
  const contentIndex = numberOr$7(event.index, 0);
29549
- const block = isRecord$35(event.content_block) ? event.content_block : {};
29639
+ const block = isRecord$36(event.content_block) ? event.content_block : {};
29550
29640
  const blockType = asString$16(block.type);
29551
29641
  out.push(...closeCurrent$4(state));
29552
29642
  if (blockType === "tool_use") {
@@ -29596,7 +29686,7 @@ function processAnthropicStreamLine(line, state) {
29596
29686
  }
29597
29687
  if (type === "content_block_delta") {
29598
29688
  const contentIndex = numberOr$7(event.index, 0);
29599
- const delta = isRecord$35(event.delta) ? event.delta : {};
29689
+ const delta = isRecord$36(event.delta) ? event.delta : {};
29600
29690
  const deltaType = asString$16(delta.type);
29601
29691
  if (deltaType === "input_json_delta") {
29602
29692
  const pending = state.toolCalls.get(contentIndex);
@@ -29669,10 +29759,10 @@ function processAnthropicStreamLine(line, state) {
29669
29759
  return out;
29670
29760
  }
29671
29761
  if (type === "message_delta") {
29672
- const delta = isRecord$35(event.delta) ? event.delta : void 0;
29762
+ const delta = isRecord$36(event.delta) ? event.delta : void 0;
29673
29763
  const stop = delta ? asString$16(delta.stop_reason) : void 0;
29674
29764
  if (stop !== void 0 && stop !== "") state.finishReason = stop;
29675
- const usage = isRecord$35(event.usage) ? event.usage : void 0;
29765
+ const usage = isRecord$36(event.usage) ? event.usage : void 0;
29676
29766
  if (usage) {
29677
29767
  state.sawUsage = true;
29678
29768
  state.outputTokens = numberOr$7(usage.output_tokens, state.outputTokens);
@@ -29684,7 +29774,7 @@ function processAnthropicStreamLine(line, state) {
29684
29774
  return closeStream$3(state);
29685
29775
  }
29686
29776
  if (type === "error") {
29687
- const error = isRecord$35(event.error) ? event.error : {};
29777
+ const error = isRecord$36(event.error) ? event.error : {};
29688
29778
  const message = asString$16(error.message) ?? "unknown error";
29689
29779
  state.streamError = {
29690
29780
  vocabulary: "anthropic",
@@ -30007,6 +30097,211 @@ function closeStream$3(state, accountId) {
30007
30097
  function assertStreamComplete$4(state) {
30008
30098
  if (!state.done && state.finishReason === null) throw new LlmError$1("Kimi Code stream ended before its terminal event", "TRANSPORT");
30009
30099
  }
30100
+ /** Where the document lives; beside the other plugin-owned JSON. */
30101
+ function sessionCacheStatePath() {
30102
+ return path.join(dshHomeDir(), "storages", "dsh-chatgpt-subscription-kimi-cache.json");
30103
+ }
30104
+ /** Distinguishes concurrent temporary files written by one process. */
30105
+ let writeSequence = 0;
30106
+ /**
30107
+ * Whether a scheduled write should reach the disk.
30108
+ *
30109
+ * A unit test that exercises the request path must not overwrite the state file
30110
+ * of the machine running it; tests build their own store against a temporary
30111
+ * path (which always writes) and call {@link SessionCacheStateStore.flush}.
30112
+ */
30113
+ function persistenceEnabled() {
30114
+ return process.env.VITEST !== "true" && process.env.NODE_ENV !== "test";
30115
+ }
30116
+ /**
30117
+ * Per-session cache state held in one JSON document.
30118
+ *
30119
+ * Reads are synchronous because every caller is answering a status request or
30120
+ * closing a turn, both of which are allowed to block on a file this size. Writes
30121
+ * are debounced: a turn reports once, and several turns in flight must not
30122
+ * rewrite the document several times.
30123
+ */
30124
+ var SessionCacheStateStore = class {
30125
+ document;
30126
+ pending;
30127
+ /**
30128
+ * @param filePath - Document location; defaults to {@link sessionCacheStatePath}.
30129
+ * @param maxEntries - Conversations kept; the oldest are dropped first.
30130
+ */
30131
+ filePath;
30132
+ maxEntries;
30133
+ /**
30134
+ * Whether this store may write at all.
30135
+ *
30136
+ * A store built on an explicit path is someone's own file - a test's temporary
30137
+ * document - and always writes. The default-path store belongs to the user's
30138
+ * harness home, and a test that never named a path must not overwrite it.
30139
+ */
30140
+ allowWrite;
30141
+ constructor(filePath = sessionCacheStatePath(), maxEntries = 64) {
30142
+ this.filePath = filePath;
30143
+ this.maxEntries = maxEntries;
30144
+ this.allowWrite = filePath !== sessionCacheStatePath() || persistenceEnabled();
30145
+ }
30146
+ /**
30147
+ * The record for one conversation, or the most recently active one.
30148
+ *
30149
+ * The fallback is what makes the status card useful without a session named:
30150
+ * the card describes the line, and the only conversation it can honestly
30151
+ * describe in that case is the one that ran last.
30152
+ * @param sessionId - Conversation to read; omit for the most recent one.
30153
+ * @returns the record, or undefined when nothing has ever been recorded.
30154
+ */
30155
+ read(sessionId) {
30156
+ const sessions = this.load().sessions;
30157
+ const named = sessionId?.trim();
30158
+ if (named !== void 0 && named !== "") return sessions[named];
30159
+ let newest;
30160
+ for (const record of Object.values(sessions)) if (newest === void 0 || record.updatedAt > newest.updatedAt) newest = record;
30161
+ return newest;
30162
+ }
30163
+ /**
30164
+ * File one conversation's state and schedule the document write.
30165
+ * @param sessionId - Conversation the record belongs to; ignored when blank.
30166
+ * @param record - Complete record for that conversation.
30167
+ */
30168
+ write(sessionId, record) {
30169
+ const key = sessionId.trim();
30170
+ if (key === "") return;
30171
+ const document = this.load();
30172
+ document.sessions[key] = record;
30173
+ this.prune(document);
30174
+ this.schedule();
30175
+ }
30176
+ /**
30177
+ * Write the document now, synchronously.
30178
+ *
30179
+ * Exposed for tests and for a caller that is about to lose the process; the
30180
+ * debounced path is what normal turns use.
30181
+ */
30182
+ flush() {
30183
+ this.cancelPending();
30184
+ const document = this.document;
30185
+ if (document === void 0) return;
30186
+ this.persist(document);
30187
+ }
30188
+ /** Drop everything older than the newest maxEntries conversations. */
30189
+ prune(document) {
30190
+ const entries = Object.entries(document.sessions);
30191
+ if (entries.length <= this.maxEntries) return;
30192
+ entries.sort((a, b) => b[1].updatedAt - a[1].updatedAt);
30193
+ document.sessions = Object.fromEntries(entries.slice(0, this.maxEntries));
30194
+ }
30195
+ /** Read the document once; a missing or corrupt file reads as empty. */
30196
+ load() {
30197
+ if (this.document !== void 0) return this.document;
30198
+ try {
30199
+ const parsed = JSON.parse(fs$1.readFileSync(this.filePath, "utf8"));
30200
+ this.document = normalizeDocument(parsed);
30201
+ } catch {
30202
+ this.document = {
30203
+ version: 1,
30204
+ sessions: {}
30205
+ };
30206
+ }
30207
+ return this.document;
30208
+ }
30209
+ /** Coalesce the writes one turn's several fields would otherwise cause. */
30210
+ schedule() {
30211
+ if (!this.allowWrite || this.pending !== void 0) return;
30212
+ this.pending = setTimeout(() => {
30213
+ this.pending = void 0;
30214
+ const document = this.document;
30215
+ if (document !== void 0) this.persist(document);
30216
+ }, 250);
30217
+ this.pending.unref?.();
30218
+ }
30219
+ cancelPending() {
30220
+ if (this.pending === void 0) return;
30221
+ clearTimeout(this.pending);
30222
+ this.pending = void 0;
30223
+ }
30224
+ /** Write through a temporary file so a crash cannot leave half a document. */
30225
+ persist(document) {
30226
+ if (!this.allowWrite) return;
30227
+ try {
30228
+ fs$1.mkdirSync(path.dirname(this.filePath), { recursive: true });
30229
+ const temporary = this.filePath + "." + process.pid + "." + ++writeSequence + ".tmp";
30230
+ fs$1.writeFileSync(temporary, JSON.stringify(document), "utf8");
30231
+ fs$1.renameSync(temporary, this.filePath);
30232
+ } catch {}
30233
+ }
30234
+ };
30235
+ /** Validate one parsed document, dropping entries that do not describe a record. */
30236
+ function normalizeDocument(value) {
30237
+ const sessions = {};
30238
+ if (isRecord$35(value) && isRecord$35(value.sessions)) for (const [key, entry] of Object.entries(value.sessions)) {
30239
+ const record = normalizeRecord(entry);
30240
+ if (record !== void 0) sessions[key] = record;
30241
+ }
30242
+ return {
30243
+ version: 1,
30244
+ sessions
30245
+ };
30246
+ }
30247
+ function normalizeRecord(value) {
30248
+ if (!isRecord$35(value)) return void 0;
30249
+ const lastActiveAt = finite(value.lastActiveAt);
30250
+ const updatedAt = finite(value.updatedAt);
30251
+ if (lastActiveAt === void 0 || updatedAt === void 0) return void 0;
30252
+ const drift = typeof value.lastDrift === "string" && value.lastDrift !== "" ? value.lastDrift : void 0;
30253
+ return {
30254
+ lastActiveAt,
30255
+ updatedAt,
30256
+ totalTokens: count$1(value.totalTokens),
30257
+ requests: count$1(value.requests),
30258
+ cachedTokens: count$1(value.cachedTokens),
30259
+ freshTokens: count$1(value.freshTokens),
30260
+ outputTokens: count$1(value.outputTokens),
30261
+ cacheWriteTokens: count$1(value.cacheWriteTokens),
30262
+ cacheWrite5mTokens: count$1(value.cacheWrite5mTokens),
30263
+ cacheWrite1hTokens: count$1(value.cacheWrite1hTokens),
30264
+ ...drift === void 0 ? {} : { lastDrift: drift }
30265
+ };
30266
+ }
30267
+ /**
30268
+ * Combine process memory with the durable record into the hint's two inputs.
30269
+ *
30270
+ * The process supplies the idle baseline whenever it has served the conversation,
30271
+ * because only it knows about the turn that just ended. The prompt size comes
30272
+ * from the file when it has one: the record is rewritten at every turn close, so
30273
+ * it holds the LAST request's size, while the process only offers a sum across
30274
+ * every turn of the conversation - which can overstate the next turn's cost by
30275
+ * an order of magnitude. With no conversation named the file is the only source,
30276
+ * because a process aggregate spans several conversations and would make "this
30277
+ * conversation's prompt" a number no single conversation has.
30278
+ * @param sessionId - Conversation being described; omit for "the most recent".
30279
+ * @param memory - What this process knows about it.
30280
+ * @param durable - What the last run on this machine left behind.
30281
+ * @returns the idle baseline and prompt size the expiry rule needs.
30282
+ */
30283
+ function resolveSessionCacheView(sessionId, memory, durable) {
30284
+ if (sessionId === void 0 || sessionId.trim() === "") return {
30285
+ ...durable === void 0 ? {} : { lastActiveAt: durable.lastActiveAt },
30286
+ totalTokens: durable?.totalTokens ?? 0
30287
+ };
30288
+ return {
30289
+ lastActiveAt: memory.memoryLastActiveAt ?? durable?.lastActiveAt,
30290
+ totalTokens: durable?.totalTokens ?? memory.memoryTotalTokens
30291
+ };
30292
+ }
30293
+ /** The process-wide store the adapter writes and the routes read. */
30294
+ const sessionCacheState = new SessionCacheStateStore();
30295
+ function isRecord$35(value) {
30296
+ return typeof value === "object" && value !== null && !Array.isArray(value);
30297
+ }
30298
+ function finite(value) {
30299
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
30300
+ }
30301
+ function count$1(value) {
30302
+ const number = finite(value);
30303
+ return number === void 0 || number < 0 ? 0 : Math.floor(number);
30304
+ }
30010
30305
  //#endregion
30011
30306
  //#region src/host/kimi-code/media-files.ts
30012
30307
  /**
@@ -31038,6 +31333,86 @@ const MAX_ACCOUNT_LIMIT_COOLDOWN_MS = BILLING_CYCLE_COOLDOWN_MS;
31038
31333
  * without dimensions and the body-fit ceiling all behave exactly as before.
31039
31334
  */
31040
31335
  const KIMI_CODE_REQUEST_IMAGE_MAX_EDGE = 2e3;
31336
+ /**
31337
+ * Persist the cache facts a status card needs to survive a restart.
31338
+ *
31339
+ * Written at the end of every request, from the same numbers the in-memory
31340
+ * totals just recorded. The process forgets them at exit, and the expiry hint
31341
+ * depends on knowing how long a conversation sat idle before it was resumed —
31342
+ * the moment the hint matters is the moment memory no longer has the answer.
31343
+ *
31344
+ * The prompt size is this request's own (cache read + fresh input), not the
31345
+ * rolling sum: the hint describes what the NEXT turn would have to reprocess.
31346
+ */
31347
+ /**
31348
+ * How this route carries a mid-conversation tool change, or undefined for none.
31349
+ *
31350
+ * Three gates decide whether the route gets one at all: the model accepts
31351
+ * message-level declarations, the request travels the OpenAI-compatible surface
31352
+ * (the Anthropic one documents no such field), and no operator opted out. A
31353
+ * model that fails any gate keeps the old shape, in which every request carries
31354
+ * the complete tool list.
31355
+ *
31356
+ * The mode is `in-history`, not `addition-only`: both append an addition, but
31357
+ * only `in-history` also expresses a removal by appending a note. Under
31358
+ * `addition-only` a revoked tool is deleted from the declaration list, the
31359
+ * top-level `tools` array shrinks, and the prefix cache is thrown away.
31360
+ * @param modelId - exact model id.
31361
+ * @param catalog - live catalog, possibly empty when offline.
31362
+ * @returns the tool-update mode, or undefined when this route must resend everything.
31363
+ */
31364
+ function toolUpdateMode(modelId, catalog) {
31365
+ if (!dynamicToolsForEntry(modelId, catalog)) return void 0;
31366
+ if (wireForCatalogEntry(modelId, catalog) !== "openai") return void 0;
31367
+ const raw = (process.env.DSH_KIMI_CODE_TOOL_UPDATE ?? "").trim().toLowerCase();
31368
+ if (raw !== "" && [
31369
+ "0",
31370
+ "false",
31371
+ "no",
31372
+ "off",
31373
+ "none"
31374
+ ].includes(raw)) return void 0;
31375
+ return "in-history";
31376
+ }
31377
+ /** Sessions already told that their prefix broke, so the log stays readable. */
31378
+ const driftWarned = /* @__PURE__ */ new Set();
31379
+ /**
31380
+ * Say once per session when the prefix cache was rebuilt by a change we made.
31381
+ *
31382
+ * The cost of a rebuild is invisible in the transcript — it shows up as a
31383
+ * slower turn and a larger bill — so the one place it can be seen is here.
31384
+ * Deliberately not a per-request notice: a repeated warning is a warning people
31385
+ * stop reading.
31386
+ */
31387
+ function reportDriftCause(sessionId, cause) {
31388
+ if (cause !== "tools" && cause !== "system-prompt") return;
31389
+ const key = sessionId + ":" + cause;
31390
+ if (driftWarned.has(key)) return;
31391
+ driftWarned.add(key);
31392
+ if (driftWarned.size > 256) driftWarned.clear();
31393
+ console.warn("[kimi-code] prompt cache rebuilt for session " + sessionId + ": the " + cause + " changed mid-conversation, so the whole prompt was reprocessed once.");
31394
+ }
31395
+ function noteSessionCacheState(sessionId, state) {
31396
+ if (sessionId === void 0 || sessionId.trim() === "") return;
31397
+ const stats = getCacheStats(sessionId);
31398
+ if (stats.requests === 0) return;
31399
+ const lastDrift = getLastDriftCause(sessionId);
31400
+ reportDriftCause(sessionId, lastDrift);
31401
+ const now = Date.now();
31402
+ sessionCacheState.write(sessionId, {
31403
+ lastActiveAt: now,
31404
+ totalTokens: state.cacheReadTokens + state.inputTokens,
31405
+ requests: stats.requests,
31406
+ cachedTokens: stats.cachedTokens,
31407
+ freshTokens: stats.freshTokens,
31408
+ outputTokens: stats.outputTokens,
31409
+ cacheWriteTokens: stats.cacheWriteTokens,
31410
+ cacheWrite5mTokens: stats.cacheWrite5mTokens,
31411
+ cacheWrite1hTokens: stats.cacheWrite1hTokens,
31412
+ ...lastDrift === void 0 ? {} : { lastDrift },
31413
+ updatedAt: now
31414
+ });
31415
+ }
31041
31416
  var KimiCodeAdapter = class extends LlmAdapter {
31042
31417
  store;
31043
31418
  modelSettings;
@@ -31220,6 +31595,7 @@ var KimiCodeAdapter = class extends LlmAdapter {
31220
31595
  id: modelId,
31221
31596
  name: entry?.name ?? modelId,
31222
31597
  inputModalities: inputModalitiesForEntry(modelId, catalog),
31598
+ ...toolUpdateMode(modelId, catalog) === void 0 ? {} : { toolUpdate: toolUpdateMode(modelId, catalog) },
31223
31599
  context: { contextWindow: this.contextWindowFor(modelId, entry, settings.contextWindowOverrides) },
31224
31600
  ...efforts.length === 0 ? {} : { reasoning: {
31225
31601
  efforts: efforts.map((effort) => ({
@@ -31523,6 +31899,7 @@ var KimiCodeAdapter = class extends LlmAdapter {
31523
31899
  throw streamFailure(error, signal);
31524
31900
  }
31525
31901
  } finally {
31902
+ if (state.sawUsage) noteSessionCacheState(requestOptions.sessionId ?? state.sessionId, state);
31526
31903
  reader.cancel().catch(() => void 0);
31527
31904
  }
31528
31905
  }
@@ -31936,7 +32313,7 @@ async function getKimiCodeWebStatus(store, modelSettings, preferences, options =
31936
32313
  */
31937
32314
  function cacheStatsOrNull(sessionId) {
31938
32315
  const stats = getCacheStats(sessionId);
31939
- if (stats.requests === 0) return null;
32316
+ if (stats.requests === 0) return durableCacheStats(sessionId);
31940
32317
  const lastDrift = getLastDriftCause(sessionId);
31941
32318
  return {
31942
32319
  ...stats,
@@ -31955,11 +32332,15 @@ function cacheStatsOrNull(sessionId) {
31955
32332
  * some global figure.
31956
32333
  */
31957
32334
  function cacheHintOrNull(sessionId) {
31958
- const lastActiveAt = sessionLastActiveAt(sessionId);
32335
+ const stats = getCacheStats(sessionId);
32336
+ const view = resolveSessionCacheView(sessionId, {
32337
+ memoryLastActiveAt: sessionLastActiveAt(sessionId),
32338
+ memoryTotalTokens: stats.cachedTokens + stats.freshTokens
32339
+ }, sessionCacheState.read(sessionId));
31959
32340
  const decision = evaluateCacheHint({
31960
32341
  now: Date.now(),
31961
- lastActiveAt,
31962
- totalTokens: getCacheStats(sessionId).cachedTokens + getCacheStats(sessionId).freshTokens
32342
+ lastActiveAt: view.lastActiveAt,
32343
+ totalTokens: view.totalTokens
31963
32344
  });
31964
32345
  if (decision.kind !== "hint") return null;
31965
32346
  return {
@@ -31967,6 +32348,52 @@ function cacheHintOrNull(sessionId) {
31967
32348
  totalTokens: decision.totalTokens
31968
32349
  };
31969
32350
  }
32351
+ /**
32352
+ * The card built from the durable record, for a process that has served nothing.
32353
+ *
32354
+ * Only reached when the in-memory totals are empty, which after a restart is the
32355
+ * normal case rather than an error: the previous run wrote this record at every
32356
+ * turn close, so it still describes the conversation the card was showing.
32357
+ */
32358
+ function durableCacheStats(sessionId) {
32359
+ const durable = sessionCacheState.read(sessionId);
32360
+ if (durable === void 0 || durable.requests === 0) return null;
32361
+ const lastDrift = driftCauseOf(durable.lastDrift);
32362
+ return {
32363
+ requests: durable.requests,
32364
+ cachedTokens: durable.cachedTokens,
32365
+ freshTokens: durable.freshTokens,
32366
+ outputTokens: durable.outputTokens,
32367
+ hitRatio: hitRatioOf(durable.cachedTokens, durable.freshTokens),
32368
+ cacheWriteTokens: durable.cacheWriteTokens,
32369
+ cacheWrite5mTokens: durable.cacheWrite5mTokens,
32370
+ cacheWrite1hTokens: durable.cacheWrite1hTokens,
32371
+ ...lastDrift === void 0 ? {} : { lastDrift }
32372
+ };
32373
+ }
32374
+ /**
32375
+ * The drift cause a durable record names, when it is one the DTO can carry.
32376
+ *
32377
+ * The record stores the cause as a string because it outlives the module that
32378
+ * produced it; an unrecognized value is dropped rather than forwarded, so a
32379
+ * downgraded plugin cannot render a cause this build has no label for.
32380
+ */
32381
+ function driftCauseOf(value) {
32382
+ switch (value) {
32383
+ case "first-request":
32384
+ case "stable":
32385
+ case "system-prompt":
32386
+ case "tools":
32387
+ case "cache-key":
32388
+ case "cold-key": return value;
32389
+ default: return;
32390
+ }
32391
+ }
32392
+ /** Cached / (cached + fresh), or null before any prompt token was counted. */
32393
+ function hitRatioOf(cached, fresh) {
32394
+ const total = cached + fresh;
32395
+ return total > 0 ? cached / total : null;
32396
+ }
31970
32397
  /** Register the Kimi Code settings routes under `/kimi-code/api`. */
31971
32398
  function registerKimiCodeRoutes(ctx, store, modelSettings, preferences, options = {}, accountPool = options.accountPool) {
31972
32399
  const fetchFn = options.fetchFn ?? fetch;
@@ -72242,7 +72669,8 @@ const MODEL_CATALOG$1 = Object.freeze({
72242
72669
  "low",
72243
72670
  "high",
72244
72671
  "max"
72245
- ]
72672
+ ],
72673
+ defaultEffort: "high"
72246
72674
  },
72247
72675
  "deepseek-v4-flash": {
72248
72676
  name: "DeepSeek V4 Flash",
@@ -72258,7 +72686,8 @@ const MODEL_CATALOG$1 = Object.freeze({
72258
72686
  "low",
72259
72687
  "medium",
72260
72688
  "high"
72261
- ]
72689
+ ],
72690
+ defaultEffort: "high"
72262
72691
  },
72263
72692
  "deepseek-v4-flash-vision-exp": {
72264
72693
  name: "DeepSeek V4 Flash Vision Exp",
@@ -72272,7 +72701,8 @@ const MODEL_CATALOG$1 = Object.freeze({
72272
72701
  "none",
72273
72702
  "high",
72274
72703
  "max"
72275
- ]
72704
+ ],
72705
+ defaultEffort: "high"
72276
72706
  },
72277
72707
  "deepseek-v4-pro": {
72278
72708
  name: "DeepSeek V4 Pro",
@@ -72288,7 +72718,8 @@ const MODEL_CATALOG$1 = Object.freeze({
72288
72718
  "low",
72289
72719
  "high",
72290
72720
  "max"
72291
- ]
72721
+ ],
72722
+ defaultEffort: "high"
72292
72723
  },
72293
72724
  "gemini-3.7-flash": {
72294
72725
  name: "Gemini 3.7 Flash",
@@ -73149,6 +73580,7 @@ function resolveModelInfo(model, options) {
73149
73580
  const maxTokens = resolveOutputBudget(options.defaultMaxTokens ?? 64e3, published.maxTokens, contextWindow);
73150
73581
  const reasoning = published.reasoning ?? shipped?.reasoning ?? true;
73151
73582
  const efforts = (Array.isArray(published.efforts) && published.efforts.length > 0 ? published.efforts : void 0) ?? (shipped?.efforts !== void 0 && shipped.efforts.length > 0 ? [...shipped.efforts] : DEFAULT_EFFORTS);
73583
+ const defaultEffort = reasoning && shipped?.defaultEffort !== void 0 && efforts.includes(shipped.defaultEffort) ? shipped.defaultEffort : void 0;
73152
73584
  const input = (Array.isArray(published.input) && published.input.length > 0 ? published.input : shipped?.input ?? ["text"]).filter((entry) => SEAM_MODALITIES.has(entry));
73153
73585
  return {
73154
73586
  id: model,
@@ -73157,6 +73589,7 @@ function resolveModelInfo(model, options) {
73157
73589
  maxTokens: maxTokens ?? options.defaultMaxTokens ?? 64e3,
73158
73590
  reasoning,
73159
73591
  ...reasoning ? { efforts } : { efforts: [] },
73592
+ ...defaultEffort === void 0 ? {} : { defaultEffort },
73160
73593
  input: input.length > 0 ? input : ["text"],
73161
73594
  ...shipped?.pricing === void 0 ? {} : { pricing: shipped.pricing }
73162
73595
  };
@@ -74642,10 +75075,13 @@ var OpenDesignAdapter = class extends LlmAdapter {
74642
75075
  inputModalities: info.input,
74643
75076
  context: { contextWindow: info.contextWindow },
74644
75077
  ...outputReservation(info.contextWindow, info.maxTokens),
74645
- ...info.reasoning && info.efforts.length > 0 ? { reasoning: { efforts: info.efforts.map((effort) => ({
74646
- id: ReasoningEffortId(effort),
74647
- name: effort
74648
- })) } } : {}
75078
+ ...info.reasoning && info.efforts.length > 0 ? { reasoning: {
75079
+ efforts: info.efforts.map((effort) => ({
75080
+ id: ReasoningEffortId(effort),
75081
+ name: effort
75082
+ })),
75083
+ ...info.defaultEffort === void 0 ? {} : { defaultEffort: ReasoningEffortId(info.defaultEffort) }
75084
+ } } : {}
74649
75085
  };
74650
75086
  }
74651
75087
  async prepareCall(provider, model, signal) {
@@ -78189,6 +78625,7 @@ Reset: fallback applies only to the current task. When the next task begins, alw
78189
78625
  config: {
78190
78626
  provider: "spawn",
78191
78627
  toolName: "subagent",
78628
+ modelSelectionSettings: true,
78192
78629
  modelSelection: true,
78193
78630
  modelDiscovery: true,
78194
78631
  backgroundMode: "continuable"
@@ -78374,6 +78811,10 @@ function messageOf(error) {
78374
78811
  }
78375
78812
  //#endregion
78376
78813
  //#region src/host/subagent-route-audit.ts
78814
+ /** Read the ordered log from either a real Session or a lightweight fixture. */
78815
+ function eventsOf(session) {
78816
+ return session.events ?? session.snapshotEvents?.() ?? [];
78817
+ }
78377
78818
  /**
78378
78819
  * Read one field as a string.
78379
78820
  * @param value - Candidate value from a durable event or header.
@@ -78420,7 +78861,7 @@ function readChildDescriptor(data) {
78420
78861
  * @returns the authorized routes, or undefined when the session recorded none.
78421
78862
  */
78422
78863
  function auditedRoutesOf(session) {
78423
- for (const event of session.events ?? []) {
78864
+ for (const event of eventsOf(session)) {
78424
78865
  if (event.type !== "subagent/model-selection-policy") continue;
78425
78866
  const allowed = asRecord(event.data)?.["allowedModels"];
78426
78867
  if (!Array.isArray(allowed)) continue;
@@ -78454,7 +78895,7 @@ function childRoutesOf(parent, sessions) {
78454
78895
  const inspect = (child, childId) => {
78455
78896
  if (child === void 0 || seen.has(childId)) return;
78456
78897
  seen.add(childId);
78457
- const descriptor = child.events?.map((event) => event.type === "subagent/descriptor" ? readChildDescriptor(event.data) : void 0).find((entry) => entry !== void 0);
78898
+ const descriptor = eventsOf(child).map((event) => event.type === "subagent/descriptor" ? readChildDescriptor(event.data) : void 0).find((entry) => entry !== void 0);
78458
78899
  if (descriptor === void 0) return;
78459
78900
  const headerParent = asString(child.header?.parentSession);
78460
78901
  findings.push({
@@ -78463,7 +78904,7 @@ function childRoutesOf(parent, sessions) {
78463
78904
  ...descriptor
78464
78905
  });
78465
78906
  };
78466
- for (const event of parent.events ?? []) {
78907
+ for (const event of eventsOf(parent)) {
78467
78908
  if (event.type !== "subagent/catalog") continue;
78468
78909
  const childId = asString(asRecord(event.data)?.["childId"]);
78469
78910
  if (childId === void 0) continue;
@@ -80227,12 +80668,15 @@ function progressLanguageDirective(language) {
80227
80668
  }
80228
80669
  /**
80229
80670
  * 生成提示词分节的文本提供者。
80230
- * @param isEnabled - 读取当前开关状态的函数(每次装配重新求值)。
80671
+ *
80672
+ * 文本与开关无关,这是刻意的:系统提示是缓存前缀的第一段,会话中途改一个字
80673
+ * 就会让整段前缀失效、整段重新计费(Kimi 的缓存是内容前缀匹配)。开关的语义
80674
+ * 因此只留给工具自己——关闭时 `execute` 直接返回 `displayed:false`。
80231
80675
  * @param language - 读取当前输出语言的函数;缺省按 `auto` 处理。
80232
- * @returns 开关打开时返回引导词加语言指令,关闭时返回空串。
80676
+ * @returns 引导词加语言指令。
80233
80677
  */
80234
- function progressSectionText(isEnabled, language = () => "auto") {
80235
- return () => isEnabled() ? PROGRESS_GUIDANCE + "\n\n" + progressLanguageDirective(language()) : "";
80678
+ function progressSectionText(language = () => "auto") {
80679
+ return () => PROGRESS_GUIDANCE + "\n\n" + progressLanguageDirective(language());
80236
80680
  }
80237
80681
  //#endregion
80238
80682
  //#region src/host/progress-updates/projection.ts
@@ -80821,7 +81265,7 @@ function installProgressUpdates(ctx, options) {
80821
81265
  return systemPrompt.section({
80822
81266
  name: PROGRESS_SECTION_NAME,
80823
81267
  order: 220,
80824
- text: progressSectionText(() => options.settings().enabled, () => options.settings().language)
81268
+ text: progressSectionText(() => options.settings().language)
80825
81269
  });
80826
81270
  }, "dsh-chatgpt-subscription: progress update prompt section");
80827
81271
  track(() => {
@@ -81477,14 +81921,15 @@ function apply(ctx, pluginConfig = {}) {
81477
81921
  isEnabled: () => antigravityPreferences.status().enabled !== false
81478
81922
  }));
81479
81923
  const disposeVideoTool = ctx.tools.register(createKimiVideoTool(ctx, { fetchFn: proxyFetch }));
81480
- const disposeMinimaxUnderstandVideoTool = ctx.tools.register(createMinimaxUnderstandVideoTool(ctx, {
81924
+ const minimaxMediaToolsEnabled = minimaxCodePreferences.status().enabled;
81925
+ const disposeMinimaxUnderstandVideoTool = minimaxMediaToolsEnabled ? ctx.tools.register(createMinimaxUnderstandVideoTool(ctx, {
81481
81926
  fetchFn: proxyFetch,
81482
81927
  pool: minimaxCodeAccountPool
81483
- }));
81484
- const disposeMinimaxGenerateVideoTool = ctx.tools.register(createMinimaxGenerateVideoTool(ctx, {
81928
+ })) : () => void 0;
81929
+ const disposeMinimaxGenerateVideoTool = minimaxMediaToolsEnabled ? ctx.tools.register(createMinimaxGenerateVideoTool(ctx, {
81485
81930
  fetchFn: proxyFetch,
81486
81931
  pool: minimaxCodeAccountPool
81487
- }));
81932
+ })) : () => void 0;
81488
81933
  const disposeProgressUpdates = installProgressUpdates(ctx, { settings: () => resolveProgressUpdatesSettings(pluginConfig) });
81489
81934
  ctx.inject(["web"], (ctx) => {
81490
81935
  ctx.web.registerSearchProvider(createCodexSearchProvider(oauth, { fetchFn: proxyFetch }));