@eddyskywalker/dsh-chatgpt-subscription 0.51.1 → 0.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/lib/client.js.map +1 -1
  3. package/lib/index.js +2094 -358
  4. package/lib/tool-result-pruner.js +8 -7
  5. package/lib/types/compat.d.ts +1 -1
  6. package/lib/types/entry-tool-result-pruner.d.ts +7 -6
  7. package/lib/types/entry-tool-result-pruner.d.ts.map +1 -1
  8. package/lib/types/host/kimi-code/client.d.ts.map +1 -1
  9. package/lib/types/host/kimi-code/mapper.d.ts +19 -1
  10. package/lib/types/host/kimi-code/mapper.d.ts.map +1 -1
  11. package/lib/types/host/kimi-code/oauth.d.ts +35 -1
  12. package/lib/types/host/kimi-code/oauth.d.ts.map +1 -1
  13. package/lib/types/host/kimi-code/repeat-breaker.d.ts +220 -0
  14. package/lib/types/host/kimi-code/repeat-breaker.d.ts.map +1 -0
  15. package/lib/types/host/kimi-code/types.d.ts +13 -0
  16. package/lib/types/host/kimi-code/types.d.ts.map +1 -1
  17. package/lib/types/host/minimax-code/adapter.d.ts.map +1 -1
  18. package/lib/types/host/minimax-code/client.d.ts +10 -1
  19. package/lib/types/host/minimax-code/client.d.ts.map +1 -1
  20. package/lib/types/host/minimax-code/mapper.d.ts +33 -4
  21. package/lib/types/host/minimax-code/mapper.d.ts.map +1 -1
  22. package/lib/types/host/minimax-code/model-catalog.d.ts +9 -2
  23. package/lib/types/host/minimax-code/model-catalog.d.ts.map +1 -1
  24. package/lib/types/host/minimax-code/runtime-enhancements.d.ts +313 -0
  25. package/lib/types/host/minimax-code/runtime-enhancements.d.ts.map +1 -0
  26. package/lib/types/host/minimax-code/types.d.ts +37 -4
  27. package/lib/types/host/minimax-code/types.d.ts.map +1 -1
  28. package/lib/types/host/ptc-sdk-cache-guard.d.ts +13 -4
  29. package/lib/types/host/ptc-sdk-cache-guard.d.ts.map +1 -1
  30. package/lib/types/host/tool-result-pruner-guard.d.ts +1 -1
  31. package/lib/types/index.d.ts.map +1 -1
  32. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -4,7 +4,7 @@ import { DEFAULT_SKIP_PROVIDERS, PRUNER_SERVICE_NAME, resolveSkipProviders, shou
4
4
  import { PLAN_PROJECTION_KEY, createPlanNotice } from "./plan-mode.js";
5
5
  import { createRequire } from "node:module";
6
6
  import * as LlmModule from "@deepseek-ai/dsh-llm";
7
- import { EMPTY_RESPONSE_CODE, HarnessError, LlmAdapter, LlmError, LlmError as LlmError$1, ProviderRequestId, ReasoningEffortId, ToolCallId, attributionHeaders, errorChain, resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
7
+ import { EMPTY_RESPONSE_CODE, HarnessError, LlmAdapter, LlmError, LlmError as LlmError$1, ProviderRequestId, ReasoningEffortId, ToolCallId, attributionHeaders, createUserMessage, errorChain, resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
8
8
  import { defineTool } from "@deepseek-ai/dsh-tools";
9
9
  import { z } from "zod";
10
10
  import z$1 from "@deepseek-ai/schemastery";
@@ -146,7 +146,7 @@ const ROUTE_PREFIX$5 = "/api/dsh-chatgpt-subscription";
146
146
  * `test/responses-client.test.ts` asserts the two agree, so a release that
147
147
  * forgets this constant fails the suite instead of shipping quietly.
148
148
  */
149
- const PLUGIN_VERSION = "0.51.1";
149
+ const PLUGIN_VERSION = "0.52.0";
150
150
  const CODEX_CHATGPT_PROVIDER_ID = "codex-chatgpt";
151
151
  const CODEX_API_BASE = "https://chatgpt.com/backend-api/codex";
152
152
  const CODEX_RESPONSES_URL = `${CODEX_API_BASE}/responses`;
@@ -3453,7 +3453,7 @@ var OAuthService = class {
3453
3453
  throw new OAuthServiceError("oauth-token-exchange-failed", `The ChatGPT device code could not be issued (${response.status}${detail === null ? "" : `, ${detail}`}).`, response.status);
3454
3454
  }
3455
3455
  const payload = await response.json().catch(() => null);
3456
- const record = isRecord$66(payload) ? payload : {};
3456
+ const record = isRecord$68(payload) ? payload : {};
3457
3457
  const authId = nonEmptyString$11(record.device_auth_id);
3458
3458
  const userCode = nonEmptyString$11(record.user_code) ?? nonEmptyString$11(record.usercode);
3459
3459
  if (authId === void 0 || userCode === void 0) throw new OAuthServiceError("oauth-token-exchange-failed", "ChatGPT returned no device code.");
@@ -3520,7 +3520,7 @@ var OAuthService = class {
3520
3520
  const detail = deviceErrorIdentifier(payload);
3521
3521
  throw new OAuthServiceError("oauth-token-exchange-failed", `The ChatGPT device confirmation was refused (${response.status}${detail === void 0 ? "" : `, ${detail}`}).`, response.status);
3522
3522
  }
3523
- const record = isRecord$66(payload) ? payload : {};
3523
+ const record = isRecord$68(payload) ? payload : {};
3524
3524
  const authorizationCode = nonEmptyString$11(record.authorization_code);
3525
3525
  const codeVerifier = nonEmptyString$11(record.code_verifier);
3526
3526
  if (authorizationCode === void 0 || codeVerifier === void 0) throw new OAuthServiceError("oauth-token-exchange-failed", "ChatGPT confirmed the device code but returned no authorization code.");
@@ -3867,11 +3867,11 @@ const DEVICE_PENDING_STATUSES = /* @__PURE__ */ new Set([
3867
3867
  function isPendingDeviceAnswer(response, payload) {
3868
3868
  if (response.status === 403 || response.status === 404) return true;
3869
3869
  if (!response.ok && response.status !== 400) return false;
3870
- if (!isRecord$66(payload)) return false;
3870
+ if (!isRecord$68(payload)) return false;
3871
3871
  const status = payload.status;
3872
3872
  if (typeof status === "string" && DEVICE_PENDING_STATUSES.has(status.toLowerCase())) return true;
3873
3873
  const error = payload.error;
3874
- if (isRecord$66(error)) {
3874
+ if (isRecord$68(error)) {
3875
3875
  const code = error.code;
3876
3876
  if (typeof code === "string" && DEVICE_PENDING_STATUSES.has(code.toLowerCase())) return true;
3877
3877
  }
@@ -3885,18 +3885,18 @@ function isPendingDeviceAnswer(response, payload) {
3885
3885
  * wrong.
3886
3886
  */
3887
3887
  function deviceErrorIdentifier(payload) {
3888
- if (!isRecord$66(payload)) return void 0;
3888
+ if (!isRecord$68(payload)) return void 0;
3889
3889
  const candidates = [payload.code];
3890
3890
  const error = payload.error;
3891
3891
  if (typeof error === "string") candidates.push(error);
3892
- else if (isRecord$66(error)) candidates.push(error.code, error.type);
3892
+ else if (isRecord$68(error)) candidates.push(error.code, error.type);
3893
3893
  candidates.push(payload.status);
3894
3894
  for (const candidate of candidates) if (typeof candidate === "string" && /^[a-z0-9_.-]{1,64}$/i.test(candidate)) return candidate;
3895
3895
  }
3896
3896
  function nonEmptyString$11(value) {
3897
3897
  return typeof value === "string" && value !== "" ? value : void 0;
3898
3898
  }
3899
- function isRecord$66(value) {
3899
+ function isRecord$68(value) {
3900
3900
  return typeof value === "object" && value !== null && !Array.isArray(value);
3901
3901
  }
3902
3902
  async function oauthErrorIdentifier(response) {
@@ -4079,7 +4079,7 @@ const CODEX_AUTH_CLAIMS_KEY = "https://api.openai.com/auth";
4079
4079
  * here, and the import has to be repeated afterwards.
4080
4080
  */
4081
4081
  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.";
4082
- function isRecord$65(value) {
4082
+ function isRecord$67(value) {
4083
4083
  return typeof value === "object" && value !== null && !Array.isArray(value);
4084
4084
  }
4085
4085
  /** A trimmed, non-empty string, or nothing. */
@@ -4181,7 +4181,7 @@ function decodeJwtClaims$1(token) {
4181
4181
  if (parts.length !== 3) return void 0;
4182
4182
  try {
4183
4183
  const value = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
4184
- return isRecord$65(value) ? value : void 0;
4184
+ return isRecord$67(value) ? value : void 0;
4185
4185
  } catch {
4186
4186
  return;
4187
4187
  }
@@ -4226,10 +4226,10 @@ function expiryFromAccessToken(accessToken) {
4226
4226
  * the file carries cannot reach the result.
4227
4227
  */
4228
4228
  function parseAdoptedCodexCredential(value, sourcePath) {
4229
- if (!isRecord$65(value)) return void 0;
4229
+ if (!isRecord$67(value)) return void 0;
4230
4230
  if (value.auth_mode !== "chatgpt") return void 0;
4231
4231
  const tokens = value[CODEX_CLI_TOKENS_KEY];
4232
- if (!isRecord$65(tokens)) return void 0;
4232
+ if (!isRecord$67(tokens)) return void 0;
4233
4233
  const accessToken = nonEmptyString$10(tokens.access_token);
4234
4234
  if (accessToken === void 0) return void 0;
4235
4235
  const refreshToken = nonEmptyString$10(tokens.refresh_token);
@@ -4248,7 +4248,7 @@ function parseAdoptedCodexCredential(value, sourcePath) {
4248
4248
  const email = claims === void 0 ? void 0 : nonEmptyString$10(claims.email);
4249
4249
  if (email !== void 0) credentials.email = email;
4250
4250
  const authClaims = claims === void 0 ? void 0 : claims[CODEX_AUTH_CLAIMS_KEY];
4251
- const planType = isRecord$65(authClaims) ? nonEmptyString$10(authClaims.chatgpt_plan_type) : void 0;
4251
+ const planType = isRecord$67(authClaims) ? nonEmptyString$10(authClaims.chatgpt_plan_type) : void 0;
4252
4252
  if (planType !== void 0) credentials.planType = planType;
4253
4253
  }
4254
4254
  const accountId = nonEmptyString$10(tokens.account_id);
@@ -5017,13 +5017,13 @@ function webServerOrigin(server) {
5017
5017
  //#region src/host/common/llm-compat.ts
5018
5018
  /** This package's kind in the harness message-source map. */
5019
5019
  const PLUGIN_MESSAGE_SOURCE_KIND = "dsh-chatgpt-subscription";
5020
- function isRecord$64(value) {
5020
+ function isRecord$66(value) {
5021
5021
  return typeof value === "object" && value !== null && !Array.isArray(value);
5022
5022
  }
5023
5023
  /** Read a message body's blocks, keeping every entry that carries a block tag. */
5024
5024
  function readBlocks(raw) {
5025
5025
  if (!Array.isArray(raw)) return [];
5026
- return raw.filter((block) => isRecord$64(block) && typeof block.type === "string");
5026
+ return raw.filter((block) => isRecord$66(block) && typeof block.type === "string");
5027
5027
  }
5028
5028
  /**
5029
5029
  * The first value that is a non-empty string.
@@ -5078,10 +5078,10 @@ function toolCallIdOf(raw, source, embedded) {
5078
5078
  function normalizeMessages(messages) {
5079
5079
  const normalized = [];
5080
5080
  for (const raw of messages ?? []) {
5081
- if (!isRecord$64(raw)) continue;
5081
+ if (!isRecord$66(raw)) continue;
5082
5082
  const content = readBlocks(raw.content);
5083
5083
  if (raw.role === "tool") {
5084
- const source = isRecord$64(raw.source) ? raw.source : void 0;
5084
+ const source = isRecord$66(raw.source) ? raw.source : void 0;
5085
5085
  const embedded = embeddedToolResult(content);
5086
5086
  const callId = toolCallIdOf(raw, source, embedded);
5087
5087
  const isError = raw.isError === true || embedded?.isError === true;
@@ -5105,7 +5105,7 @@ function normalizeMessages(messages) {
5105
5105
  id: raw.id,
5106
5106
  role: typeof raw.role === "string" ? raw.role : "user",
5107
5107
  content,
5108
- ...isRecord$64(raw.source) ? { source: raw.source } : {}
5108
+ ...isRecord$66(raw.source) ? { source: raw.source } : {}
5109
5109
  });
5110
5110
  }
5111
5111
  return normalized;
@@ -6809,7 +6809,7 @@ const schemaFields = /* @__PURE__ */ new Set([
6809
6809
  "required",
6810
6810
  "propertyOrdering"
6811
6811
  ]);
6812
- function isRecord$63(value) {
6812
+ function isRecord$65(value) {
6813
6813
  return typeof value === "object" && value !== null && !Array.isArray(value);
6814
6814
  }
6815
6815
  function mergeSchemas(left, right) {
@@ -6817,7 +6817,7 @@ function mergeSchemas(left, right) {
6817
6817
  ...left,
6818
6818
  ...right
6819
6819
  };
6820
- if (isRecord$63(left.properties) && isRecord$63(right.properties)) merged.properties = {
6820
+ if (isRecord$65(left.properties) && isRecord$65(right.properties)) merged.properties = {
6821
6821
  ...left.properties,
6822
6822
  ...right.properties
6823
6823
  };
@@ -6853,9 +6853,9 @@ const mergedTypeKeys = /* @__PURE__ */ new Set([
6853
6853
  * model with strictly less than the schema it started from.
6854
6854
  */
6855
6855
  function describeBranch(branch) {
6856
- const type = typeof branch.type === "string" ? branch.type : isRecord$63(branch.properties) ? "object" : isRecord$63(branch.items) ? "array" : "value";
6856
+ const type = typeof branch.type === "string" ? branch.type : isRecord$65(branch.properties) ? "object" : isRecord$65(branch.items) ? "array" : "value";
6857
6857
  const details = [];
6858
- if (isRecord$63(branch.properties)) {
6858
+ if (isRecord$65(branch.properties)) {
6859
6859
  const names = Object.keys(branch.properties);
6860
6860
  if (names.length > 0) details.push(`{${names.join(",")}}`);
6861
6861
  }
@@ -6869,7 +6869,7 @@ function describeBranch(branch) {
6869
6869
  }
6870
6870
  /** How well one branch can stand in for a whole union; a named object shape wins. */
6871
6871
  function branchRank(branch) {
6872
- if (isRecord$63(branch.properties)) return 3;
6872
+ if (isRecord$65(branch.properties)) return 3;
6873
6873
  if (branch.type === "object") return 2;
6874
6874
  if (branch.type === "array") return 1;
6875
6875
  return 0;
@@ -6898,7 +6898,7 @@ function unionShape(branches) {
6898
6898
  shape: branches[0],
6899
6899
  folded: false
6900
6900
  };
6901
- if (new Set(branches.map((branch) => branch.type)).size === 1 && branches.every((branch) => !isRecord$63(branch.properties) && !isRecord$63(branch.items))) {
6901
+ if (new Set(branches.map((branch) => branch.type)).size === 1 && branches.every((branch) => !isRecord$65(branch.properties) && !isRecord$65(branch.items))) {
6902
6902
  const shape = { type: branches[0].type };
6903
6903
  if (branches.every((branch) => Array.isArray(branch.enum))) {
6904
6904
  const values = [...new Set(branches.flatMap((branch) => branch.enum))];
@@ -6935,7 +6935,7 @@ function foldOwnFields(node) {
6935
6935
  const out = {};
6936
6936
  for (const [key, value] of Object.entries(node)) {
6937
6937
  if (key === "anyOf" || key === "oneOf" || key === "allOf") continue;
6938
- if (key === "properties" && isRecord$63(value)) {
6938
+ if (key === "properties" && isRecord$65(value)) {
6939
6939
  out.properties = Object.fromEntries(Object.entries(value).map(([name, child]) => [name, foldSchemaUnions(child)]));
6940
6940
  continue;
6941
6941
  }
@@ -6964,15 +6964,15 @@ function foldOwnFields(node) {
6964
6964
  * argument the model sends anyway fails there, naming the actual problem.
6965
6965
  */
6966
6966
  function foldSchemaUnions(node) {
6967
- if (!isRecord$63(node)) return node;
6967
+ if (!isRecord$65(node)) return node;
6968
6968
  let own = foldOwnFields(node);
6969
6969
  if (Array.isArray(node.allOf)) for (const branch of node.allOf) {
6970
6970
  const folded = foldSchemaUnions(branch);
6971
- if (isRecord$63(folded)) own = mergeSchemas(own, folded);
6971
+ if (isRecord$65(folded)) own = mergeSchemas(own, folded);
6972
6972
  }
6973
6973
  const alternatives = Array.isArray(node.anyOf) ? node.anyOf : Array.isArray(node.oneOf) ? node.oneOf : [];
6974
6974
  if (alternatives.length === 0) return own;
6975
- const branches = alternatives.map((branch) => foldSchemaUnions(branch)).filter(isRecord$63);
6975
+ const branches = alternatives.map((branch) => foldSchemaUnions(branch)).filter(isRecord$65);
6976
6976
  if (branches.length === 0) return own;
6977
6977
  const shapes = branches.filter((branch) => branch.type !== "null");
6978
6978
  const acceptsNull = branches.some((branch) => branch.type === "null");
@@ -6988,7 +6988,7 @@ function foldSchemaUnions(node) {
6988
6988
  return merged;
6989
6989
  }
6990
6990
  function toAntigravityToolSchema(schema, options = {}) {
6991
- if (!isRecord$63(schema)) return schema;
6991
+ if (!isRecord$65(schema)) return schema;
6992
6992
  const root = schema;
6993
6993
  function resolveReference(reference) {
6994
6994
  let target = root;
@@ -6996,13 +6996,13 @@ function toAntigravityToolSchema(schema, options = {}) {
6996
6996
  const path = reference === "#" ? [] : reference.slice(2).split("/");
6997
6997
  for (const segment of path) {
6998
6998
  const key = segment.replace(/~1/g, "/").replace(/~0/g, "~");
6999
- target = isRecord$63(target) && Object.hasOwn(target, key) ? target[key] : void 0;
6999
+ target = isRecord$65(target) && Object.hasOwn(target, key) ? target[key] : void 0;
7000
7000
  }
7001
- if (!isRecord$63(target)) throw new LlmError(`Antigravity tool schema reference was not found: ${reference}`, "PROVIDER_ERROR");
7001
+ if (!isRecord$65(target)) throw new LlmError(`Antigravity tool schema reference was not found: ${reference}`, "PROVIDER_ERROR");
7002
7002
  return target;
7003
7003
  }
7004
7004
  function convert(node, references) {
7005
- if (!isRecord$63(node)) return {};
7005
+ if (!isRecord$65(node)) return {};
7006
7006
  let inherited = {};
7007
7007
  if (typeof node.$ref === "string") {
7008
7008
  if (references.has(node.$ref)) throw new LlmError(`Antigravity tool schema contains a recursive reference: ${node.$ref}`, "PROVIDER_ERROR");
@@ -7011,8 +7011,8 @@ function toAntigravityToolSchema(schema, options = {}) {
7011
7011
  if (Array.isArray(node.allOf)) for (const branch of node.allOf) inherited = mergeSchemas(inherited, convert(branch, references));
7012
7012
  const out = {};
7013
7013
  for (const [key, value] of Object.entries(node)) if (schemaFields.has(key)) out[key] = value;
7014
- if (isRecord$63(node.properties)) out.properties = Object.fromEntries(Object.entries(node.properties).map(([name, child]) => [name, convert(child, references)]));
7015
- if (isRecord$63(node.items)) out.items = convert(node.items, references);
7014
+ if (isRecord$65(node.properties)) out.properties = Object.fromEntries(Object.entries(node.properties).map(([name, child]) => [name, convert(child, references)]));
7015
+ if (isRecord$65(node.items)) out.items = convert(node.items, references);
7016
7016
  const alternatives = Array.isArray(node.anyOf) ? node.anyOf : node.oneOf;
7017
7017
  if (Array.isArray(alternatives)) out.anyOf = alternatives.map((child) => convert(child, references));
7018
7018
  if (Array.isArray(node.type)) {
@@ -7048,7 +7048,7 @@ let toolCallCounter = 0;
7048
7048
  function sanitizeText$9(text) {
7049
7049
  return text.replace(/\0/g, "");
7050
7050
  }
7051
- function isRecord$62(value) {
7051
+ function isRecord$64(value) {
7052
7052
  return typeof value === "object" && value !== null && !Array.isArray(value);
7053
7053
  }
7054
7054
  function asString$29(value) {
@@ -7068,25 +7068,25 @@ function toolCallIdNeeded(modelId, runtimeModel) {
7068
7068
  return modelId.startsWith("claude-") || modelId.startsWith("gpt-oss-") || runtimeModel.startsWith("claude-") || runtimeModel.startsWith("gpt-oss-");
7069
7069
  }
7070
7070
  function parseArguments$1(raw) {
7071
- if (isRecord$62(raw)) return raw;
7071
+ if (isRecord$64(raw)) return raw;
7072
7072
  if (raw === void 0 || raw === null || raw === "") return {};
7073
7073
  const parsed = typeof raw === "string" ? safeJsonParse$9(raw) : raw;
7074
- return isRecord$62(parsed) ? parsed : {};
7074
+ return isRecord$64(parsed) ? parsed : {};
7075
7075
  }
7076
7076
  const NO_RESOLVED_IMAGES$5 = /* @__PURE__ */ new Map();
7077
7077
  function attachmentOf$5(block) {
7078
7078
  const attachment = block.attachment;
7079
- if (!isRecord$62(attachment)) return void 0;
7079
+ if (!isRecord$64(attachment)) return void 0;
7080
7080
  return typeof attachment.attachmentId === "string" ? attachment : void 0;
7081
7081
  }
7082
7082
  function attachmentLabel$6(block) {
7083
- const attachment = isRecord$62(block.attachment) ? block.attachment : void 0;
7083
+ const attachment = isRecord$64(block.attachment) ? block.attachment : void 0;
7084
7084
  return asString$29(attachment?.name) || asString$29(attachment?.attachmentId);
7085
7085
  }
7086
7086
  function collectImageRefs$3(content, refs) {
7087
7087
  if (!Array.isArray(content)) return;
7088
7088
  for (const block of content) {
7089
- if (!isRecord$62(block)) continue;
7089
+ if (!isRecord$64(block)) continue;
7090
7090
  if (block.type === "image") {
7091
7091
  const attachment = attachmentOf$5(block);
7092
7092
  if (attachment) refs.set(attachment.attachmentId, attachment);
@@ -7199,7 +7199,7 @@ function requestImageBytes$2(block) {
7199
7199
  function collectRequestImageBytes$2(content, lengths) {
7200
7200
  if (!Array.isArray(content)) return;
7201
7201
  for (const block of content) {
7202
- if (!isRecord$62(block)) continue;
7202
+ if (!isRecord$64(block)) continue;
7203
7203
  if (block.type === "tool-result") {
7204
7204
  collectRequestImageBytes$2(block.content, lengths);
7205
7205
  continue;
@@ -7249,7 +7249,7 @@ function offloadOldestRequestImages$3(options) {
7249
7249
  let replaced = false;
7250
7250
  return {
7251
7251
  content: content.map((block) => {
7252
- if (remaining.count === 0 || !isRecord$62(block)) return block;
7252
+ if (remaining.count === 0 || !isRecord$64(block)) return block;
7253
7253
  if (block.type === "image") {
7254
7254
  if (requestImageBytes$2(block) === void 0) return block;
7255
7255
  remaining.count -= 1;
@@ -7352,7 +7352,7 @@ function unavailableImageText$6(block) {
7352
7352
  }
7353
7353
  function imageBlockToPart(block, images) {
7354
7354
  let data = asString$29(block.data) || asString$29(block.base64);
7355
- const source = isRecord$62(block.source) ? block.source : void 0;
7355
+ const source = isRecord$64(block.source) ? block.source : void 0;
7356
7356
  if (!data && source) data = asString$29(source.data) || asString$29(source.base64);
7357
7357
  let mimeType = asString$29(block.mimeType) || asString$29(block.mediaType) || (source ? asString$29(source.mimeType) || asString$29(source.mediaType) : void 0) || "image/png";
7358
7358
  if (data?.startsWith("data:")) {
@@ -7377,8 +7377,8 @@ function contentToUserParts(content, images) {
7377
7377
  if (typeof content === "string") return [{ text: sanitizeText$9(content) }];
7378
7378
  if (!Array.isArray(content)) return [];
7379
7379
  const parts = [];
7380
- for (const block of content) if (isRecord$62(block) && block.type === "text" && typeof block.text === "string") parts.push({ text: sanitizeText$9(block.text) });
7381
- else if (isRecord$62(block) && block.type === "image") {
7380
+ for (const block of content) if (isRecord$64(block) && block.type === "text" && typeof block.text === "string") parts.push({ text: sanitizeText$9(block.text) });
7381
+ else if (isRecord$64(block) && block.type === "image") {
7382
7382
  const img = imageBlockToPart(block, images);
7383
7383
  parts.push(img ?? { text: unavailableImageText$6(block) });
7384
7384
  }
@@ -7393,7 +7393,7 @@ function toolResultImageParts(blocks, images) {
7393
7393
  if (!Array.isArray(blocks)) return [];
7394
7394
  const parts = [];
7395
7395
  for (const block of blocks) {
7396
- if (!isRecord$62(block)) continue;
7396
+ if (!isRecord$64(block)) continue;
7397
7397
  if (block.type === "image") {
7398
7398
  parts.push(imageBlockToPart(block, images) ?? { text: unavailableImageText$6(block) });
7399
7399
  continue;
@@ -7405,7 +7405,7 @@ function toolResultImageParts(blocks, images) {
7405
7405
  function toolResultText$9(blocks) {
7406
7406
  if (!Array.isArray(blocks)) return "";
7407
7407
  return blocks.map((block) => {
7408
- if (!isRecord$62(block)) return "";
7408
+ if (!isRecord$64(block)) return "";
7409
7409
  if (block.type === "text" && typeof block.text === "string") return sanitizeText$9(block.text);
7410
7410
  if (block.type === "tool-result") return toolResultText$9(block.content);
7411
7411
  if (block.type === "image") {
@@ -7419,9 +7419,9 @@ function replayBlockFor$1(message, index) {
7419
7419
  const source = message.source;
7420
7420
  if (!source || source.kind !== "model" || source.provider !== "antigravity") return void 0;
7421
7421
  const state = source.replayState;
7422
- if (!isRecord$62(state)) return void 0;
7422
+ if (!isRecord$64(state)) return void 0;
7423
7423
  if (Array.isArray(state.blocks)) return state.blocks[index];
7424
- const resp = isRecord$62(state.response) ? state.response : void 0;
7424
+ const resp = isRecord$64(state.response) ? state.response : void 0;
7425
7425
  if (resp) {
7426
7426
  if (Array.isArray(resp.outputItems)) return resp.outputItems[index];
7427
7427
  if (Array.isArray(resp.blocks)) return resp.blocks[index];
@@ -7523,10 +7523,10 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
7523
7523
  if (!Array.isArray(message.content)) return parts;
7524
7524
  for (let index = 0; index < message.content.length; index++) {
7525
7525
  const block = message.content[index];
7526
- if (!isRecord$62(block)) continue;
7526
+ if (!isRecord$64(block)) continue;
7527
7527
  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;
7528
7528
  const replay = replayBlockFor$1(message, index);
7529
- const originalParts = Array.isArray(replay?.parts) ? replay.parts.filter(isRecord$62) : [];
7529
+ const originalParts = Array.isArray(replay?.parts) ? replay.parts.filter(isRecord$64) : [];
7530
7530
  if ((block.type === "text" || block.type === "reasoning") && originalParts.length > 0 && originalParts.every((part) => !part.functionCall) && originalParts.map((part) => asString$29(part.text) || "").join("") === sanitizeText$9(String(block.text || ""))) {
7531
7531
  parts.push(...originalParts.map(replayPart));
7532
7532
  continue;
@@ -7547,8 +7547,8 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
7547
7547
  } else if (block.type === "tool-call") {
7548
7548
  const toolId = String(block.id || "");
7549
7549
  const toolName = String(block.name || "");
7550
- const originalCall = originalParts.find((part) => isRecord$62(part.functionCall));
7551
- const wireId = asString$29((isRecord$62(originalCall?.functionCall) ? originalCall.functionCall : void 0)?.id) || (toolCallIdNeeded(model.id, runtimeModel) ? sanitizeToolCallId(toolId, toolName) : originalCall ? void 0 : toolId || void 0);
7550
+ const originalCall = originalParts.find((part) => isRecord$64(part.functionCall));
7551
+ const wireId = asString$29((isRecord$64(originalCall?.functionCall) ? originalCall.functionCall : void 0)?.id) || (toolCallIdNeeded(model.id, runtimeModel) ? sanitizeToolCallId(toolId, toolName) : originalCall ? void 0 : toolId || void 0);
7552
7552
  toolCalls.set(toolId, {
7553
7553
  name: toolName,
7554
7554
  id: wireId
@@ -7600,7 +7600,7 @@ function convertMessages(options, model, runtimeModel, images = NO_RESOLVED_IMAG
7600
7600
  continue;
7601
7601
  }
7602
7602
  const content = Array.isArray(message.content) ? message.content : [];
7603
- const userParts = contentToUserParts(content.filter((b) => !isRecord$62(b) || b.type !== "tool-result"), images);
7603
+ const userParts = contentToUserParts(content.filter((b) => !isRecord$64(b) || b.type !== "tool-result"), images);
7604
7604
  if (role === "system") {
7605
7605
  if (userParts.length) contents.push({
7606
7606
  role: GEMINI_ROLE.user,
@@ -7612,7 +7612,7 @@ function convertMessages(options, model, runtimeModel, images = NO_RESOLVED_IMAG
7612
7612
  role: GEMINI_ROLE.user,
7613
7613
  parts: userParts
7614
7614
  });
7615
- for (const b of content) if (isRecord$62(b) && b.type === "tool-result") pushToolResult(contents, b, toolCalls, model, runtimeModel, images);
7615
+ for (const b of content) if (isRecord$64(b) && b.type === "tool-result") pushToolResult(contents, b, toolCalls, model, runtimeModel, images);
7616
7616
  }
7617
7617
  return contents;
7618
7618
  }
@@ -7760,7 +7760,7 @@ const USAGE_FIELDS = [
7760
7760
  "totalTokenCount"
7761
7761
  ];
7762
7762
  function collectUsage(value, state) {
7763
- if (!isRecord$62(value)) return;
7763
+ if (!isRecord$64(value)) return;
7764
7764
  for (const key of USAGE_FIELDS) {
7765
7765
  const count = value[key];
7766
7766
  if (typeof count !== "number" || !Number.isSafeInteger(count) || count < 0) continue;
@@ -7790,17 +7790,17 @@ function processStreamLine$4(line, state) {
7790
7790
  }
7791
7791
  if (!json) return [];
7792
7792
  const chunk = safeJsonParse$9(json);
7793
- if (!isRecord$62(chunk)) return [];
7794
- const responseData = isRecord$62(chunk.response) ? chunk.response : chunk;
7795
- const error = isRecord$62(chunk.error) ? chunk.error : isRecord$62(responseData.error) ? responseData.error : void 0;
7793
+ if (!isRecord$64(chunk)) return [];
7794
+ const responseData = isRecord$64(chunk.response) ? chunk.response : chunk;
7795
+ const error = isRecord$64(chunk.error) ? chunk.error : isRecord$64(responseData.error) ? responseData.error : void 0;
7796
7796
  if (error !== void 0) throw new LlmError$1(`Antigravity stream error: ${asString$29(error.message) ?? "unknown error"}`, isContextOverflow(error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
7797
7797
  const candidates = Array.isArray(responseData.candidates) ? responseData.candidates : [];
7798
- const candidate = isRecord$62(candidates[0]) ? candidates[0] : void 0;
7799
- const content = isRecord$62(candidate?.content) ? candidate.content : void 0;
7798
+ const candidate = isRecord$64(candidates[0]) ? candidates[0] : void 0;
7799
+ const content = isRecord$64(candidate?.content) ? candidate.content : void 0;
7800
7800
  const parts = Array.isArray(content?.parts) ? content.parts : [];
7801
7801
  const out = [];
7802
7802
  for (const part of parts) {
7803
- if (!isRecord$62(part)) continue;
7803
+ if (!isRecord$64(part)) continue;
7804
7804
  if (typeof part.text === "string" && part.text !== "") {
7805
7805
  const isThinking = Boolean(part.thought);
7806
7806
  const blockType = isThinking ? "reasoning" : "text";
@@ -7832,7 +7832,7 @@ function processStreamLine$4(line, state) {
7832
7832
  index: state.currentBlock.index,
7833
7833
  text: delta
7834
7834
  });
7835
- } else if (!isRecord$62(part.functionCall) && thoughtSignature(part)) {
7835
+ } else if (!isRecord$64(part.functionCall) && thoughtSignature(part)) {
7836
7836
  if (state.replayBlocks.length === 0) {
7837
7837
  const type = part.thought ? "reasoning" : "text";
7838
7838
  state.blocks.push({
@@ -7856,12 +7856,12 @@ function processStreamLine$4(line, state) {
7856
7856
  }
7857
7857
  state.replayBlocks[state.replayBlocks.length - 1].parts.push(replayPart(part));
7858
7858
  }
7859
- if (isRecord$62(part.functionCall)) {
7859
+ if (isRecord$64(part.functionCall)) {
7860
7860
  out.push(...closeCurrentBlock(state));
7861
7861
  const fc = part.functionCall;
7862
7862
  const toolName = asString$29(fc.name) || "";
7863
7863
  const toolId = asString$29(fc.id) || sanitizeToolCallId("", toolName);
7864
- const argsText = JSON.stringify(isRecord$62(fc.args) ? fc.args : {});
7864
+ const argsText = JSON.stringify(isRecord$64(fc.args) ? fc.args : {});
7865
7865
  const index = state.blocks.length;
7866
7866
  const block = {
7867
7867
  type: "tool-call",
@@ -7900,7 +7900,7 @@ function processStreamLine$4(line, state) {
7900
7900
  if (responseData !== chunk) collectUsage(responseData.usageMetadata, state);
7901
7901
  const finishMessage = asString$29(candidate?.finishMessage);
7902
7902
  if (finishMessage) state.finishMessage = finishMessage;
7903
- const blockReason = asString$29((isRecord$62(responseData.promptFeedback) ? responseData.promptFeedback : void 0)?.blockReason);
7903
+ const blockReason = asString$29((isRecord$64(responseData.promptFeedback) ? responseData.promptFeedback : void 0)?.blockReason);
7904
7904
  const finishReason = asString$29(candidate?.finishReason) || asString$29(responseData.finishReason) || (blockReason ? `PROMPT_BLOCKED:${blockReason}` : void 0);
7905
7905
  if (finishReason) {
7906
7906
  state.finishReason = finishReason;
@@ -14084,7 +14084,7 @@ async function compactionCandidates(ctx) {
14084
14084
  };
14085
14085
  }))).filter((provider) => provider.models.length > 0) };
14086
14086
  }
14087
- function isRecord$61(value) {
14087
+ function isRecord$63(value) {
14088
14088
  return typeof value === "object" && value !== null && !Array.isArray(value);
14089
14089
  }
14090
14090
  function readPreferencesUpdate(value, current) {
@@ -14134,7 +14134,7 @@ function readPreferencesUpdate(value, current) {
14134
14134
  patch.subagentModelsByMainModel = value.subagentModelsByMainModel;
14135
14135
  }
14136
14136
  if ("contextWindowOverrides" in value) {
14137
- if (!isRecord$61(value.contextWindowOverrides)) throw new PreferenceError("contextWindowOverrides must be an object.");
14137
+ if (!isRecord$63(value.contextWindowOverrides)) throw new PreferenceError("contextWindowOverrides must be an object.");
14138
14138
  const overrides = {};
14139
14139
  for (const [model, contextWindow] of Object.entries(value.contextWindowOverrides)) {
14140
14140
  if (!isCodexModelId(model)) throw new PreferenceError("Unknown Codex model for a context window override.");
@@ -18634,11 +18634,11 @@ function commandCodeHeaders(apiKey, extra = {}) {
18634
18634
  function timeoutSignal$5(signal, ms) {
18635
18635
  return signal ? AbortSignal.any([signal, AbortSignal.timeout(ms)]) : AbortSignal.timeout(ms);
18636
18636
  }
18637
- function isRecord$60(value) {
18637
+ function isRecord$62(value) {
18638
18638
  return typeof value === "object" && value !== null && !Array.isArray(value);
18639
18639
  }
18640
18640
  function asRecord$16(value) {
18641
- return isRecord$60(value) ? value : void 0;
18641
+ return isRecord$62(value) ? value : void 0;
18642
18642
  }
18643
18643
  function asString$28(value) {
18644
18644
  if (typeof value === "string" && value.trim() !== "") return value;
@@ -18682,7 +18682,7 @@ function deepValue(value, keys, depth = 0) {
18682
18682
  }
18683
18683
  return;
18684
18684
  }
18685
- if (!isRecord$60(value)) return void 0;
18685
+ if (!isRecord$62(value)) return void 0;
18686
18686
  for (const key of keys) if (value[key] !== void 0 && value[key] !== null) return value[key];
18687
18687
  for (const nested of Object.values(value)) {
18688
18688
  const hit = deepValue(nested, keys, depth + 1);
@@ -18696,7 +18696,7 @@ function collectRecords(value, keys, depth = 0, out = []) {
18696
18696
  for (const entry of value) collectRecords(entry, keys, depth + 1, out);
18697
18697
  return out;
18698
18698
  }
18699
- if (!isRecord$60(value)) return out;
18699
+ if (!isRecord$62(value)) return out;
18700
18700
  if (keys.some((key) => value[key] !== void 0)) out.push(value);
18701
18701
  for (const nested of Object.values(value)) collectRecords(nested, keys, depth + 1, out);
18702
18702
  return out;
@@ -19506,7 +19506,7 @@ function buildModelOptions$2(catalog, enabledModelIds, overrides) {
19506
19506
  *
19507
19507
  * https://commandcode.ai/blog/command-code-provider-api
19508
19508
  */
19509
- function isRecord$59(value) {
19509
+ function isRecord$61(value) {
19510
19510
  return typeof value === "object" && value !== null && !Array.isArray(value);
19511
19511
  }
19512
19512
  function asString$27(value) {
@@ -19546,17 +19546,17 @@ const SUPPORTED_IMAGE_MEDIA_TYPES$4 = /* @__PURE__ */ new Set([
19546
19546
  ]);
19547
19547
  function attachmentOf$4(block) {
19548
19548
  const attachment = block.attachment;
19549
- if (!isRecord$59(attachment)) return void 0;
19549
+ if (!isRecord$61(attachment)) return void 0;
19550
19550
  return typeof attachment.attachmentId === "string" ? attachment : void 0;
19551
19551
  }
19552
19552
  function attachmentLabel$5(block) {
19553
- const attachment = isRecord$59(block.attachment) ? block.attachment : void 0;
19553
+ const attachment = isRecord$61(block.attachment) ? block.attachment : void 0;
19554
19554
  return asString$27(attachment?.name) || asString$27(attachment?.attachmentId);
19555
19555
  }
19556
19556
  function collectImageRefs$2(content, refs) {
19557
19557
  if (!Array.isArray(content)) return;
19558
19558
  for (const block of content) {
19559
- if (!isRecord$59(block)) continue;
19559
+ if (!isRecord$61(block)) continue;
19560
19560
  if (block.type === "image") {
19561
19561
  const attachment = attachmentOf$4(block);
19562
19562
  if (attachment) refs.set(attachment.attachmentId, attachment);
@@ -19577,7 +19577,7 @@ function requestImageBytes$1(block) {
19577
19577
  function collectRequestImageBytes$1(content, lengths) {
19578
19578
  if (!Array.isArray(content)) return;
19579
19579
  for (const block of content) {
19580
- if (!isRecord$59(block)) continue;
19580
+ if (!isRecord$61(block)) continue;
19581
19581
  if (block.type === "tool-result") {
19582
19582
  collectRequestImageBytes$1(block.content, lengths);
19583
19583
  continue;
@@ -19613,7 +19613,7 @@ function offloadOldestRequestImages$2(options) {
19613
19613
  let replaced = false;
19614
19614
  return {
19615
19615
  content: content.map((block) => {
19616
- if (remaining.count === 0 || !isRecord$59(block)) return block;
19616
+ if (remaining.count === 0 || !isRecord$61(block)) return block;
19617
19617
  if (block.type === "image") {
19618
19618
  if (requestImageBytes$1(block) === void 0) return block;
19619
19619
  remaining.count -= 1;
@@ -19685,7 +19685,7 @@ function unavailableImageText$5(block) {
19685
19685
  }
19686
19686
  function imageBlockToInline$3(block, images) {
19687
19687
  let data = asString$27(block.data) || asString$27(block.base64);
19688
- const source = isRecord$59(block.source) ? block.source : void 0;
19688
+ const source = isRecord$61(block.source) ? block.source : void 0;
19689
19689
  if (!data && source) data = asString$27(source.data) || asString$27(source.base64);
19690
19690
  let mediaType = asString$27(block.mimeType) || asString$27(block.mediaType) || (source ? asString$27(source.mimeType) || asString$27(source.mediaType) : void 0) || "image/png";
19691
19691
  if (data?.startsWith("data:")) {
@@ -19711,7 +19711,7 @@ function textOf$9(content) {
19711
19711
  if (!Array.isArray(content)) return "";
19712
19712
  const parts = [];
19713
19713
  for (const block of content) {
19714
- if (!isRecord$59(block)) continue;
19714
+ if (!isRecord$61(block)) continue;
19715
19715
  if (block.type === "text" && typeof block.text === "string") parts.push(sanitizeText$8(block.text));
19716
19716
  else if (block.type === "tool-result") parts.push(textOf$9(block.content));
19717
19717
  }
@@ -19720,7 +19720,7 @@ function textOf$9(content) {
19720
19720
  function toolResultText$8(blocks) {
19721
19721
  if (!Array.isArray(blocks)) return "";
19722
19722
  return blocks.map((block) => {
19723
- if (!isRecord$59(block)) return "";
19723
+ if (!isRecord$61(block)) return "";
19724
19724
  if (block.type === "text" && typeof block.text === "string") return sanitizeText$8(block.text);
19725
19725
  if (block.type === "tool-result") return toolResultText$8(block.content);
19726
19726
  if (block.type === "image") return `[image: ${attachmentLabel$5(block) ?? "attached image"}]`;
@@ -19738,7 +19738,7 @@ function toolResultBlocks$2(blocks, images) {
19738
19738
  const out = [];
19739
19739
  let hasImage = false;
19740
19740
  for (const block of blocks) {
19741
- if (!isRecord$59(block)) continue;
19741
+ if (!isRecord$61(block)) continue;
19742
19742
  if (block.type === "text" && typeof block.text === "string") {
19743
19743
  out.push({
19744
19744
  type: "text",
@@ -19787,7 +19787,7 @@ function toolResultImageBlocks$5(blocks, images) {
19787
19787
  if (!Array.isArray(blocks)) return [];
19788
19788
  const out = [];
19789
19789
  for (const block of blocks) {
19790
- if (!isRecord$59(block)) continue;
19790
+ if (!isRecord$61(block)) continue;
19791
19791
  if (block.type === "image") {
19792
19792
  const inline = imageBlockToInline$3(block, images);
19793
19793
  if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$4.has(inline.mediaType)) out.push({
@@ -19831,7 +19831,7 @@ function nonSystemMessages$8(options) {
19831
19831
  }
19832
19832
  /** Drop the JSON-Schema keywords provider gateways reject or ignore. */
19833
19833
  function stripMetaSchema$2(schema) {
19834
- if (!isRecord$59(schema)) return {
19834
+ if (!isRecord$61(schema)) return {
19835
19835
  type: "object",
19836
19836
  properties: {}
19837
19837
  };
@@ -19848,7 +19848,7 @@ function openAIUserContent$4(message, images) {
19848
19848
  const parts = [];
19849
19849
  let hasImage = false;
19850
19850
  for (const block of message.content) {
19851
- if (!isRecord$59(block)) continue;
19851
+ if (!isRecord$61(block)) continue;
19852
19852
  if (block.type === "text" && typeof block.text === "string") {
19853
19853
  const text = sanitizeText$8(block.text);
19854
19854
  if (text !== "") parts.push({
@@ -19876,7 +19876,7 @@ function openAIAssistantContent$4(message) {
19876
19876
  const textParts = [];
19877
19877
  const toolCalls = [];
19878
19878
  for (const block of message.content) {
19879
- if (!isRecord$59(block)) continue;
19879
+ if (!isRecord$61(block)) continue;
19880
19880
  if (block.type === "text" && typeof block.text === "string") textParts.push(sanitizeText$8(block.text));
19881
19881
  else if (block.type === "tool-call" && typeof block.name === "string") toolCalls.push({
19882
19882
  id: typeof block.id === "string" && block.id !== "" ? block.id : `call_${toolCalls.length}`,
@@ -19908,7 +19908,7 @@ function buildOpenAIRequest$1(options, images = NO_RESOLVED_IMAGES$4) {
19908
19908
  while (index < conversation.length && isToolResultMessage$8(conversation[index])) {
19909
19909
  const current = conversation[index];
19910
19910
  const block = current.content[0];
19911
- const callId = isRecord$59(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
19911
+ const callId = isRecord$61(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
19912
19912
  messages.push({
19913
19913
  role: "tool",
19914
19914
  tool_call_id: callId,
@@ -19969,7 +19969,7 @@ function anthropicUserContent$3(message, images) {
19969
19969
  if (!Array.isArray(message.content)) return [];
19970
19970
  const blocks = [];
19971
19971
  for (const block of message.content) {
19972
- if (!isRecord$59(block)) continue;
19972
+ if (!isRecord$61(block)) continue;
19973
19973
  if (block.type === "text" && typeof block.text === "string") {
19974
19974
  const text = sanitizeText$8(block.text);
19975
19975
  if (text !== "") blocks.push({
@@ -20006,7 +20006,7 @@ function anthropicUserContent$3(message, images) {
20006
20006
  function anthropicAssistantContent$3(message) {
20007
20007
  const blocks = [];
20008
20008
  for (const block of message.content) {
20009
- if (!isRecord$59(block)) continue;
20009
+ if (!isRecord$61(block)) continue;
20010
20010
  if (block.type === "text" && typeof block.text === "string") {
20011
20011
  const text = sanitizeText$8(block.text);
20012
20012
  if (text !== "") blocks.push({
@@ -20019,7 +20019,7 @@ function anthropicAssistantContent$3(message) {
20019
20019
  type: "tool_use",
20020
20020
  id: typeof block.id === "string" && block.id !== "" ? block.id : `toolu_${blocks.length}`,
20021
20021
  name: block.name,
20022
- input: isRecord$59(parsed) ? parsed : {}
20022
+ input: isRecord$61(parsed) ? parsed : {}
20023
20023
  });
20024
20024
  }
20025
20025
  }
@@ -20050,7 +20050,7 @@ function mergeAnthropicMessages$3(entries) {
20050
20050
  return merged;
20051
20051
  }
20052
20052
  /** Reasoning budget a thinking-enabled request may spend, given its output cap. */
20053
- function thinkingBudgetFor$1(effort, maxTokens) {
20053
+ function thinkingBudgetFor(effort, maxTokens) {
20054
20054
  if (effort === void 0 || effort === "") return void 0;
20055
20055
  const requested = anthropicThinkingBudget(effort);
20056
20056
  if (requested === void 0 || requested === null) return void 0;
@@ -20075,7 +20075,7 @@ function buildAnthropicRequest$1(options, images = NO_RESOLVED_IMAGES$4) {
20075
20075
  }
20076
20076
  const system = leadingSystemText$8(options);
20077
20077
  const maxTokens = options.maxTokens ?? maxOutputTokensFor$6(options.model);
20078
- const budget = thinkingBudgetFor$1(wireReasoningEffort(options.reasoningEffort === void 0 ? void 0 : String(options.reasoningEffort)), maxTokens);
20078
+ const budget = thinkingBudgetFor(wireReasoningEffort(options.reasoningEffort === void 0 ? void 0 : String(options.reasoningEffort)), maxTokens);
20079
20079
  return {
20080
20080
  model: options.model,
20081
20081
  max_tokens: maxTokens,
@@ -20113,7 +20113,7 @@ function responsesUserContent(message, images) {
20113
20113
  if (!Array.isArray(message.content)) return [];
20114
20114
  const parts = [];
20115
20115
  for (const block of message.content) {
20116
- if (!isRecord$59(block)) continue;
20116
+ if (!isRecord$61(block)) continue;
20117
20117
  if (block.type === "text" && typeof block.text === "string") {
20118
20118
  const text = sanitizeText$8(block.text);
20119
20119
  if (text !== "") parts.push({
@@ -20138,7 +20138,7 @@ function responsesToolResultImageBlocks(blocks, images) {
20138
20138
  if (!Array.isArray(blocks)) return [];
20139
20139
  const out = [];
20140
20140
  for (const block of blocks) {
20141
- if (!isRecord$59(block)) continue;
20141
+ if (!isRecord$61(block)) continue;
20142
20142
  if (block.type === "image") {
20143
20143
  const inline = imageBlockToInline$3(block, images);
20144
20144
  if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$4.has(inline.mediaType)) out.push({
@@ -20165,8 +20165,8 @@ function buildResponsesRequest(options, images = NO_RESOLVED_IMAGES$4) {
20165
20165
  const imageBlocks = [];
20166
20166
  while (index < conversation.length && isToolResultMessage$8(conversation[index])) {
20167
20167
  const current = conversation[index];
20168
- const toolResult = Array.isArray(current.content) ? current.content.find((b) => isRecord$59(b) && b.type === "tool-result") : void 0;
20169
- const callId = (isRecord$59(toolResult) && typeof toolResult.toolCallId === "string" ? toolResult.toolCallId : "") || (typeof current.source?.callId === "string" ? current.source.callId : "");
20168
+ const toolResult = Array.isArray(current.content) ? current.content.find((b) => isRecord$61(b) && b.type === "tool-result") : void 0;
20169
+ const callId = (isRecord$61(toolResult) && typeof toolResult.toolCallId === "string" ? toolResult.toolCallId : "") || (typeof current.source?.callId === "string" ? current.source.callId : "");
20170
20170
  input.push({
20171
20171
  type: "function_call_output",
20172
20172
  call_id: callId,
@@ -20189,7 +20189,7 @@ function buildResponsesRequest(options, images = NO_RESOLVED_IMAGES$4) {
20189
20189
  content
20190
20190
  });
20191
20191
  for (const call of toolCalls) {
20192
- const fn = isRecord$59(call.function) ? call.function : void 0;
20192
+ const fn = isRecord$61(call.function) ? call.function : void 0;
20193
20193
  input.push({
20194
20194
  type: "function_call",
20195
20195
  call_id: call.id,
@@ -20312,9 +20312,9 @@ function processOpenAIStreamLine$1(line, state) {
20312
20312
  }
20313
20313
  if (payload === "") return [];
20314
20314
  const chunk = safeJsonParse$8(payload);
20315
- if (!isRecord$59(chunk)) return [];
20315
+ if (!isRecord$61(chunk)) return [];
20316
20316
  const out = [];
20317
- if (isRecord$59(chunk.error)) {
20317
+ if (isRecord$61(chunk.error)) {
20318
20318
  const message = asString$27(chunk.error.message) ?? "unknown error";
20319
20319
  state.streamError = {
20320
20320
  vocabulary: "openai",
@@ -20323,20 +20323,20 @@ function processOpenAIStreamLine$1(line, state) {
20323
20323
  };
20324
20324
  throw new LlmError$1(`Command Code stream error: ${message}`, isContextOverflow(chunk.error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
20325
20325
  }
20326
- const usage = isRecord$59(chunk.usage) ? chunk.usage : void 0;
20326
+ const usage = isRecord$61(chunk.usage) ? chunk.usage : void 0;
20327
20327
  if (usage) {
20328
20328
  state.sawUsage = true;
20329
20329
  const prompt = numberOr$9(usage.prompt_tokens, 0);
20330
- const details = isRecord$59(usage.prompt_tokens_details) ? usage.prompt_tokens_details : void 0;
20330
+ const details = isRecord$61(usage.prompt_tokens_details) ? usage.prompt_tokens_details : void 0;
20331
20331
  const cached = details ? numberOr$9(details.cached_tokens, 0) : 0;
20332
20332
  state.inputTokens = Math.max(0, prompt - cached);
20333
20333
  state.cacheReadTokens = cached;
20334
20334
  state.outputTokens = numberOr$9(usage.completion_tokens, state.outputTokens);
20335
- if (isRecord$59(usage.completion_tokens_details)) state.reasoningTokens = numberOr$9(usage.completion_tokens_details.reasoning_tokens, state.reasoningTokens);
20335
+ if (isRecord$61(usage.completion_tokens_details)) state.reasoningTokens = numberOr$9(usage.completion_tokens_details.reasoning_tokens, state.reasoningTokens);
20336
20336
  }
20337
20337
  const choices = Array.isArray(chunk.choices) ? chunk.choices : [];
20338
- const choice = isRecord$59(choices[0]) ? choices[0] : void 0;
20339
- const delta = isRecord$59(choice?.delta) ? choice.delta : void 0;
20338
+ const choice = isRecord$61(choices[0]) ? choices[0] : void 0;
20339
+ const delta = isRecord$61(choice?.delta) ? choice.delta : void 0;
20340
20340
  if (delta) {
20341
20341
  const reasoning = asString$27(delta.reasoning_content) ?? asString$27(delta.reasoning);
20342
20342
  if (reasoning !== void 0 && reasoning !== "") {
@@ -20364,7 +20364,7 @@ function processOpenAIStreamLine$1(line, state) {
20364
20364
  }
20365
20365
  const toolDeltas = Array.isArray(delta.tool_calls) ? delta.tool_calls : [];
20366
20366
  for (const entry of toolDeltas) {
20367
- if (!isRecord$59(entry)) continue;
20367
+ if (!isRecord$61(entry)) continue;
20368
20368
  out.push(...applyOpenAIToolDelta$1(entry, state));
20369
20369
  }
20370
20370
  }
@@ -20378,7 +20378,7 @@ function processOpenAIStreamLine$1(line, state) {
20378
20378
  }
20379
20379
  function applyOpenAIToolDelta$1(entry, state) {
20380
20380
  const wireIndex = typeof entry.index === "number" ? entry.index : 0;
20381
- const fn = isRecord$59(entry.function) ? entry.function : {};
20381
+ const fn = isRecord$61(entry.function) ? entry.function : {};
20382
20382
  const out = [];
20383
20383
  let call = state.toolCalls.get(wireIndex);
20384
20384
  if (call === void 0) {
@@ -20436,12 +20436,12 @@ function processAnthropicStreamLine$1(line, state) {
20436
20436
  const payload = trimmed.slice(5).trim();
20437
20437
  if (payload === "" || payload === "[DONE]") return [];
20438
20438
  const event = safeJsonParse$8(payload);
20439
- if (!isRecord$59(event)) return [];
20439
+ if (!isRecord$61(event)) return [];
20440
20440
  const type = asString$27(event.type);
20441
20441
  const out = [];
20442
20442
  if (type === "message_start") {
20443
- const message = isRecord$59(event.message) ? event.message : void 0;
20444
- const usage = message && isRecord$59(message.usage) ? message.usage : void 0;
20443
+ const message = isRecord$61(event.message) ? event.message : void 0;
20444
+ const usage = message && isRecord$61(message.usage) ? message.usage : void 0;
20445
20445
  if (usage) {
20446
20446
  state.sawUsage = true;
20447
20447
  state.inputTokens = numberOr$9(usage.input_tokens, 0);
@@ -20455,7 +20455,7 @@ function processAnthropicStreamLine$1(line, state) {
20455
20455
  }
20456
20456
  if (type === "content_block_start") {
20457
20457
  const contentIndex = numberOr$9(event.index, 0);
20458
- const block = isRecord$59(event.content_block) ? event.content_block : {};
20458
+ const block = isRecord$61(event.content_block) ? event.content_block : {};
20459
20459
  const blockType = asString$27(block.type);
20460
20460
  out.push(...closeCurrent$6(state));
20461
20461
  if (blockType === "tool_use") {
@@ -20505,7 +20505,7 @@ function processAnthropicStreamLine$1(line, state) {
20505
20505
  }
20506
20506
  if (type === "content_block_delta") {
20507
20507
  const contentIndex = numberOr$9(event.index, 0);
20508
- const delta = isRecord$59(event.delta) ? event.delta : {};
20508
+ const delta = isRecord$61(event.delta) ? event.delta : {};
20509
20509
  const deltaType = asString$27(delta.type);
20510
20510
  if (deltaType === "input_json_delta") {
20511
20511
  const pending = state.toolCalls.get(contentIndex);
@@ -20578,10 +20578,10 @@ function processAnthropicStreamLine$1(line, state) {
20578
20578
  return out;
20579
20579
  }
20580
20580
  if (type === "message_delta") {
20581
- const delta = isRecord$59(event.delta) ? event.delta : void 0;
20581
+ const delta = isRecord$61(event.delta) ? event.delta : void 0;
20582
20582
  const stop = delta ? asString$27(delta.stop_reason) : void 0;
20583
20583
  if (stop !== void 0 && stop !== "") state.finishReason = stop;
20584
- const usage = isRecord$59(event.usage) ? event.usage : void 0;
20584
+ const usage = isRecord$61(event.usage) ? event.usage : void 0;
20585
20585
  if (usage) {
20586
20586
  state.sawUsage = true;
20587
20587
  state.outputTokens = numberOr$9(usage.output_tokens, state.outputTokens);
@@ -20593,7 +20593,7 @@ function processAnthropicStreamLine$1(line, state) {
20593
20593
  return closeStream$6(state);
20594
20594
  }
20595
20595
  if (type === "error") {
20596
- const error = isRecord$59(event.error) ? event.error : {};
20596
+ const error = isRecord$61(event.error) ? event.error : {};
20597
20597
  const message = asString$27(error.message) ?? "unknown error";
20598
20598
  state.streamError = {
20599
20599
  vocabulary: "anthropic",
@@ -20639,7 +20639,7 @@ function processResponsesStreamLine(line, state) {
20639
20639
  } catch {
20640
20640
  return [];
20641
20641
  }
20642
- if (!isRecord$59(parsed)) return [];
20642
+ if (!isRecord$61(parsed)) return [];
20643
20643
  const type = typeof parsed.type === "string" ? parsed.type : "";
20644
20644
  if (type === "response.output_text.delta") {
20645
20645
  const delta = typeof parsed.delta === "string" ? parsed.delta : "";
@@ -20666,7 +20666,7 @@ function processResponsesStreamLine(line, state) {
20666
20666
  }];
20667
20667
  }
20668
20668
  if (type === "response.output_item.added") {
20669
- const item = isRecord$59(parsed.item) ? parsed.item : null;
20669
+ const item = isRecord$61(parsed.item) ? parsed.item : null;
20670
20670
  if (item === null || item.type !== "function_call") return [];
20671
20671
  return startResponsesToolCall(state, parsed, item);
20672
20672
  }
@@ -20690,11 +20690,11 @@ function processResponsesStreamLine(line, state) {
20690
20690
  return [];
20691
20691
  }
20692
20692
  if (type === "response.completed" || type === "response.incomplete") {
20693
- const response = isRecord$59(parsed.response) ? parsed.response : null;
20693
+ const response = isRecord$61(parsed.response) ? parsed.response : null;
20694
20694
  if (response !== null) {
20695
20695
  if (response.status === "failed") {
20696
20696
  state.done = true;
20697
- const errorObj = isRecord$59(response.error) ? response.error : null;
20697
+ const errorObj = isRecord$61(response.error) ? response.error : null;
20698
20698
  const detail = errorObj && typeof errorObj.message === "string" ? errorObj.message : typeof response.error === "string" ? response.error : "";
20699
20699
  state.streamError = {
20700
20700
  vocabulary: "responses",
@@ -20707,7 +20707,7 @@ function processResponsesStreamLine(line, state) {
20707
20707
  }
20708
20708
  state.done = true;
20709
20709
  if (type === "response.incomplete") {
20710
- const details = response && isRecord$59(response.incomplete_details) ? response.incomplete_details : null;
20710
+ const details = response && isRecord$61(response.incomplete_details) ? response.incomplete_details : null;
20711
20711
  const reason = details && typeof details.reason === "string" ? details.reason : "";
20712
20712
  state.finishReason = reason === "max_output_tokens" || reason === "length" || reason === "max_tokens" ? "length" : reason || "length";
20713
20713
  } else state.finishReason = "stop";
@@ -20715,8 +20715,8 @@ function processResponsesStreamLine(line, state) {
20715
20715
  }
20716
20716
  if (type === "response.failed" || type === "error") {
20717
20717
  state.done = true;
20718
- const errorObj = isRecord$59(parsed.error) ? parsed.error : isRecord$59(parsed.response) && isRecord$59(parsed.response.error) ? parsed.response.error : null;
20719
- const detail = (typeof parsed.message === "string" ? parsed.message : "") || (errorObj && typeof errorObj.message === "string" ? errorObj.message : "") || (isRecord$59(parsed.response) && typeof parsed.response.error === "string" ? parsed.response.error : typeof parsed.error === "string" ? parsed.error : "");
20718
+ const errorObj = isRecord$61(parsed.error) ? parsed.error : isRecord$61(parsed.response) && isRecord$61(parsed.response.error) ? parsed.response.error : null;
20719
+ const detail = (typeof parsed.message === "string" ? parsed.message : "") || (errorObj && typeof errorObj.message === "string" ? errorObj.message : "") || (isRecord$61(parsed.response) && typeof parsed.response.error === "string" ? parsed.response.error : typeof parsed.error === "string" ? parsed.error : "");
20720
20720
  state.streamError = {
20721
20721
  vocabulary: "responses",
20722
20722
  error: errorObj,
@@ -20804,15 +20804,15 @@ function responsesToolCall(state, key) {
20804
20804
  for (const call of state.toolCalls.values()) if (call.id === toToolCallId(key)) return call;
20805
20805
  }
20806
20806
  function readResponsesUsage(response, state) {
20807
- const usage = isRecord$59(response.usage) ? response.usage : null;
20807
+ const usage = isRecord$61(response.usage) ? response.usage : null;
20808
20808
  if (usage === null) return;
20809
- const cached = isRecord$59(usage.input_tokens_details) ? numberOrZero(usage.input_tokens_details.cached_tokens) : 0;
20810
- const written = isRecord$59(usage.input_tokens_details) ? numberOrZero(usage.input_tokens_details.cache_write_tokens) : 0;
20809
+ const cached = isRecord$61(usage.input_tokens_details) ? numberOrZero(usage.input_tokens_details.cached_tokens) : 0;
20810
+ const written = isRecord$61(usage.input_tokens_details) ? numberOrZero(usage.input_tokens_details.cache_write_tokens) : 0;
20811
20811
  state.inputTokens = Math.max(0, numberOrZero(usage.input_tokens) - cached - written);
20812
20812
  state.cacheReadTokens = cached;
20813
20813
  state.cacheWriteTokens = written;
20814
20814
  state.outputTokens = numberOrZero(usage.output_tokens);
20815
- const outputDetails = isRecord$59(usage.output_tokens_details) ? usage.output_tokens_details : null;
20815
+ const outputDetails = isRecord$61(usage.output_tokens_details) ? usage.output_tokens_details : null;
20816
20816
  if (outputDetails !== null) state.reasoningTokens = numberOrZero(outputDetails.reasoning_tokens);
20817
20817
  state.sawUsage = true;
20818
20818
  }
@@ -20900,7 +20900,7 @@ const ANTHROPIC_IN_BAND_STATUS = {
20900
20900
  * Anything not recognized keeps the mapper's verdict.
20901
20901
  */
20902
20902
  function inBandResponsesCode(error, message) {
20903
- const fields = isRecord$58(error) ? error : {};
20903
+ const fields = isRecord$60(error) ? error : {};
20904
20904
  const rawCode = (asString$26(fields.code) ?? asString$26(fields.type) ?? "").toLowerCase();
20905
20905
  const text = message.toLowerCase();
20906
20906
  if (text.includes("rate limit") || rawCode === "rate_limit" || rawCode === "rate_limit_exceeded") return "RATE_LIMIT";
@@ -20959,13 +20959,13 @@ function reclassifyInBandResponsesError(thrown, rawError, message, classify) {
20959
20959
  }
20960
20960
  /** The wire `error` object of an in-band event, read defensively. */
20961
20961
  function readErrorType(error) {
20962
- if (!isRecord$58(error)) return null;
20962
+ if (!isRecord$60(error)) return null;
20963
20963
  return typeof error.type === "string" ? error.type : null;
20964
20964
  }
20965
20965
  function asString$26(value) {
20966
20966
  return typeof value === "string" ? value : void 0;
20967
20967
  }
20968
- function isRecord$58(value) {
20968
+ function isRecord$60(value) {
20969
20969
  return typeof value === "object" && value !== null && !Array.isArray(value);
20970
20970
  }
20971
20971
  //#endregion
@@ -24190,14 +24190,14 @@ const IN_BAND_SERVER = [
24190
24190
  function isAbort$3(error, signal) {
24191
24191
  return signal?.aborted === true || error instanceof Error && error.name === "AbortError";
24192
24192
  }
24193
- function isRecord$57(value) {
24193
+ function isRecord$59(value) {
24194
24194
  return typeof value === "object" && value !== null && !Array.isArray(value);
24195
24195
  }
24196
24196
  function asString$25(value) {
24197
24197
  return typeof value === "string" && value !== "" ? value : void 0;
24198
24198
  }
24199
24199
  function attachmentLabel$4(block) {
24200
- const attachment = isRecord$57(block.attachment) ? block.attachment : void 0;
24200
+ const attachment = isRecord$59(block.attachment) ? block.attachment : void 0;
24201
24201
  return asString$25(attachment?.name) || asString$25(attachment?.attachmentId);
24202
24202
  }
24203
24203
  function unavailableImageText$4(block) {
@@ -24233,7 +24233,7 @@ async function processMessageContent(content, model, attachments, signal) {
24233
24233
  textParts.push(part);
24234
24234
  continue;
24235
24235
  }
24236
- if (!isRecord$57(part)) continue;
24236
+ if (!isRecord$59(part)) continue;
24237
24237
  if (part.type === "text") {
24238
24238
  if (typeof part.text === "string" && part.text !== "") textParts.push(part.text);
24239
24239
  continue;
@@ -24262,7 +24262,7 @@ async function processMessageContent(content, model, attachments, signal) {
24262
24262
  continue;
24263
24263
  }
24264
24264
  const inline = part.source;
24265
- if (isRecord$57(inline)) {
24265
+ if (isRecord$59(inline)) {
24266
24266
  const data = inline.data;
24267
24267
  if (typeof data === "string" && data !== "") {
24268
24268
  images.push(encodeImage(data, asMediaType(inline.mediaType)));
@@ -24303,7 +24303,7 @@ async function toOllamaRequest(options, attachments, signal, declared) {
24303
24303
  const toolResultBlocks = message.content.filter((b) => b.type === "tool-result");
24304
24304
  if (toolResultBlocks.length > 0) {
24305
24305
  for (const block of toolResultBlocks) {
24306
- const toolCallId = String(block.toolCallId ?? (isRecord$57(message.source) ? message.source.callId : "") ?? "");
24306
+ const toolCallId = String(block.toolCallId ?? (isRecord$59(message.source) ? message.source.callId : "") ?? "");
24307
24307
  const processed = await processMessageContent(block.content, options.model, attachments, signal);
24308
24308
  messages.push({
24309
24309
  role: "tool",
@@ -26394,7 +26394,7 @@ function planRetrievalOutline(text, toolName) {
26394
26394
  * @returns 读到的元数据;两者都没有时 undefined。
26395
26395
  */
26396
26396
  function shellMetadataOf(holder) {
26397
- const job = isPlainRecord(holder.job) ? holder.job : void 0;
26397
+ const job = isPlainRecord$2(holder.job) ? holder.job : void 0;
26398
26398
  let exitCode;
26399
26399
  if (typeof holder.exitCode === "number" && Number.isFinite(holder.exitCode)) exitCode = holder.exitCode;
26400
26400
  if (exitCode === void 0 && typeof job?.exitCode === "number" && Number.isFinite(job.exitCode)) exitCode = job.exitCode;
@@ -26499,7 +26499,7 @@ const JSON_ENVELOPE_LOG_KEYS = [
26499
26499
  /** JSON envelope 其余字段允许占用的最大序列化字符数(防止把含批量源码的混合 envelope 压掉)。 */
26500
26500
  const JSON_ENVELOPE_MAX_OTHER_CHARS = 800;
26501
26501
  /** 判断一个值是不是普通 JSON 对象(不是数组,也不是 null)。 */
26502
- function isPlainRecord(value) {
26502
+ function isPlainRecord$2(value) {
26503
26503
  return typeof value === "object" && value !== null && !Array.isArray(value);
26504
26504
  }
26505
26505
  /** 重建信封:只把预览写回被替换的键,其余字段原样保留。 */
@@ -26601,7 +26601,7 @@ function extractJsonEnvelopeLogField(text, toolName) {
26601
26601
  });
26602
26602
  }
26603
26603
  for (const [outerKey, outerValue] of Object.entries(record)) {
26604
- if (!isPlainRecord(outerValue)) continue;
26604
+ if (!isPlainRecord$2(outerValue)) continue;
26605
26605
  for (const key of JSON_ENVELOPE_LOG_KEYS) {
26606
26606
  const value = outerValue[key];
26607
26607
  if (typeof value === "string" && value.length > 0) candidates.push({
@@ -26691,7 +26691,7 @@ function canonicalGrepMatches(value) {
26691
26691
  if (!Array.isArray(value) || value.length === 0) return void 0;
26692
26692
  const matches = [];
26693
26693
  for (const entry of value) {
26694
- if (!isPlainRecord(entry)) return void 0;
26694
+ if (!isPlainRecord$2(entry)) return void 0;
26695
26695
  if (typeof entry.path !== "string") return void 0;
26696
26696
  if (!Number.isSafeInteger(entry.lineNumber)) return void 0;
26697
26697
  if (typeof entry.line !== "string") return void 0;
@@ -26705,12 +26705,12 @@ function canonicalGrepMatches(value) {
26705
26705
  }
26706
26706
  /** 规范读取结果。 */
26707
26707
  function canonicalReadResult(value) {
26708
- if (!isPlainRecord(value)) return void 0;
26708
+ if (!isPlainRecord$2(value)) return void 0;
26709
26709
  if (typeof value.path !== "string" || value.path.trim() === "") return void 0;
26710
26710
  if (!Array.isArray(value.lines) || value.lines.length === 0) return void 0;
26711
26711
  const lines = [];
26712
26712
  for (const entry of value.lines) {
26713
- if (!isPlainRecord(entry)) return void 0;
26713
+ if (!isPlainRecord$2(entry)) return void 0;
26714
26714
  if (!Number.isSafeInteger(entry.number)) return void 0;
26715
26715
  if (typeof entry.text !== "string") return void 0;
26716
26716
  lines.push({
@@ -26735,7 +26735,7 @@ function findGrepBinding(record) {
26735
26735
  matches: top
26736
26736
  };
26737
26737
  for (const [outerKey, outerValue] of Object.entries(record)) {
26738
- if (!isPlainRecord(outerValue)) continue;
26738
+ if (!isPlainRecord$2(outerValue)) continue;
26739
26739
  const nested = canonicalGrepMatches(outerValue.matches);
26740
26740
  if (nested !== void 0) return {
26741
26741
  binding: {
@@ -26762,7 +26762,7 @@ function findGlobBinding(record) {
26762
26762
  ...typeof record.root === "string" ? { root: record.root } : {}
26763
26763
  };
26764
26764
  for (const [outerKey, outerValue] of Object.entries(record)) {
26765
- if (!isPlainRecord(outerValue)) continue;
26765
+ if (!isPlainRecord$2(outerValue)) continue;
26766
26766
  const nested = canonicalGlobPaths(outerValue.paths);
26767
26767
  if (nested !== void 0) return {
26768
26768
  binding: {
@@ -26940,13 +26940,13 @@ function collectCompositeEntries(record) {
26940
26940
  for (const [key, value] of Object.entries(record)) {
26941
26941
  if (Array.isArray(value)) {
26942
26942
  value.forEach((item, index) => {
26943
- if (isPlainRecord(item)) push(`${key}[${index}]`, item);
26943
+ if (isPlainRecord$2(item)) push(`${key}[${index}]`, item);
26944
26944
  });
26945
26945
  continue;
26946
26946
  }
26947
- if (!isPlainRecord(value)) continue;
26947
+ if (!isPlainRecord$2(value)) continue;
26948
26948
  if (push(key, value)) continue;
26949
- for (const [subKey, subValue] of Object.entries(value)) if (isPlainRecord(subValue)) push(`${key}.${subKey}`, subValue);
26949
+ for (const [subKey, subValue] of Object.entries(value)) if (isPlainRecord$2(subValue)) push(`${key}.${subKey}`, subValue);
26950
26950
  }
26951
26951
  return entries;
26952
26952
  }
@@ -27382,7 +27382,7 @@ async function projectToolResult(input) {
27382
27382
  *
27383
27383
  * @module dsh-chatgpt-subscription/request-images
27384
27384
  */
27385
- function isRecord$56(value) {
27385
+ function isRecord$58(value) {
27386
27386
  return typeof value === "object" && value !== null && !Array.isArray(value);
27387
27387
  }
27388
27388
  function asString$24(value) {
@@ -27441,17 +27441,17 @@ const SUPPORTED_IMAGE_MEDIA_TYPES$3 = /* @__PURE__ */ new Set([
27441
27441
  ]);
27442
27442
  function attachmentOf$3(block) {
27443
27443
  const attachment = block.attachment;
27444
- if (!isRecord$56(attachment)) return void 0;
27444
+ if (!isRecord$58(attachment)) return void 0;
27445
27445
  return typeof attachment.attachmentId === "string" ? attachment : void 0;
27446
27446
  }
27447
27447
  function attachmentLabel$3(block) {
27448
- const attachment = isRecord$56(block.attachment) ? block.attachment : void 0;
27448
+ const attachment = isRecord$58(block.attachment) ? block.attachment : void 0;
27449
27449
  return asString$24(attachment?.name) || asString$24(attachment?.attachmentId);
27450
27450
  }
27451
27451
  function collectImageRefs$1(content, refs) {
27452
27452
  if (!Array.isArray(content)) return;
27453
27453
  for (const block of content) {
27454
- if (!isRecord$56(block)) continue;
27454
+ if (!isRecord$58(block)) continue;
27455
27455
  if (block.type === "image") {
27456
27456
  const attachment = attachmentOf$3(block);
27457
27457
  if (attachment) refs.set(attachment.attachmentId, attachment);
@@ -27481,7 +27481,7 @@ function base64Length$1(bytes) {
27481
27481
  */
27482
27482
  function inlinePayloadOf(block) {
27483
27483
  let data = asString$24(block.data) || asString$24(block.base64);
27484
- const source = isRecord$56(block.source) ? block.source : void 0;
27484
+ const source = isRecord$58(block.source) ? block.source : void 0;
27485
27485
  if (!data && source) data = asString$24(source.data) || asString$24(source.base64);
27486
27486
  if (data?.startsWith("data:")) {
27487
27487
  const matched = data.match(/^data:([^;,]+);base64,(.*)$/s);
@@ -27511,7 +27511,7 @@ function requestImagePayloadLength(block, images) {
27511
27511
  function collectRequestImagePayloads(content, images, lengths) {
27512
27512
  if (!Array.isArray(content)) return;
27513
27513
  for (const block of content) {
27514
- if (!isRecord$56(block)) continue;
27514
+ if (!isRecord$58(block)) continue;
27515
27515
  if (block.type === "image") {
27516
27516
  const bytes = requestImagePayloadLength(block, images);
27517
27517
  if (bytes !== void 0) lengths.push(bytes);
@@ -27565,7 +27565,7 @@ function replaceOldestRequestImages(options, count, images) {
27565
27565
  let replaced = false;
27566
27566
  return {
27567
27567
  content: content.map((block) => {
27568
- if (remaining.count === 0 || !isRecord$56(block)) return block;
27568
+ if (remaining.count === 0 || !isRecord$58(block)) return block;
27569
27569
  if (block.type === "image") {
27570
27570
  if (requestImagePayloadLength(block, images) === void 0) return block;
27571
27571
  remaining.count -= 1;
@@ -27707,7 +27707,7 @@ function collectImageOccurrences(options, images) {
27707
27707
  const walk = (content) => {
27708
27708
  if (!Array.isArray(content)) return;
27709
27709
  for (const block of content) {
27710
- if (!isRecord$56(block)) continue;
27710
+ if (!isRecord$58(block)) continue;
27711
27711
  if (block.type === "image") {
27712
27712
  const bytes = requestImagePayloadLength(block, images);
27713
27713
  const key = requestImageKey(block, images);
@@ -27761,7 +27761,7 @@ function replaceDroppedRequestImages(options, droppedKeys, images) {
27761
27761
  let replaced = false;
27762
27762
  return {
27763
27763
  content: content.map((block) => {
27764
- if (!isRecord$56(block)) return block;
27764
+ if (!isRecord$58(block)) return block;
27765
27765
  if (block.type === "image") {
27766
27766
  const key = requestImageKey(block, images);
27767
27767
  if (key === void 0 || !droppedKeys.has(key)) return block;
@@ -27946,7 +27946,7 @@ function unavailableImageText$3(block) {
27946
27946
  }
27947
27947
  function imageBlockToInline$2(block, images) {
27948
27948
  let data = asString$24(block.data) || asString$24(block.base64);
27949
- const source = isRecord$56(block.source) ? block.source : void 0;
27949
+ const source = isRecord$58(block.source) ? block.source : void 0;
27950
27950
  if (!data && source) data = asString$24(source.data) || asString$24(source.base64);
27951
27951
  let mediaType = asString$24(block.mimeType) || asString$24(block.mediaType) || (source ? asString$24(source.mimeType) || asString$24(source.mediaType) : void 0) || "image/png";
27952
27952
  if (data?.startsWith("data:")) {
@@ -28198,6 +28198,19 @@ const HEADER_MSH_DEVICE_NAME = "x-msh-device-name";
28198
28198
  const HEADER_MSH_DEVICE_MODEL = "x-msh-device-model";
28199
28199
  const HEADER_MSH_OS_VERSION = "x-msh-os-version";
28200
28200
  const HEADER_MSH_DEVICE_ID = "x-msh-device-id";
28201
+ /**
28202
+ * Environment variable carrying extra headers for every Kimi Code request.
28203
+ *
28204
+ * The official client reads newline-separated `Name: Value` lines from
28205
+ * `KIMI_CODE_CUSTOM_HEADERS` (it mirrors `ANTHROPIC_CUSTOM_HEADERS`) and
28206
+ * applies them to every outbound request, the `/models` listing included.
28207
+ *
28208
+ * These headers are the LOWEST-precedence layer: the Kimi device identity
28209
+ * headers and the caller's own headers both override them, so a deployment can
28210
+ * add a header for one gateway without being able to weaken the identity the
28211
+ * service attributes usage to.
28212
+ */
28213
+ const KIMI_CODE_CUSTOM_HEADERS_ENV = "KIMI_CODE_CUSTOM_HEADERS";
28201
28214
  /** Version the plugin reports to the managed service's telemetry headers. */
28202
28215
  const MSH_VERSION = "1.0.0";
28203
28216
  const REFRESH_THRESHOLD_RATIO = .5;
@@ -29052,6 +29065,51 @@ function asciiHeaderValue(value) {
29052
29065
  const printable = value.replace(/[^\x20-\x7E]/g, "").trim();
29053
29066
  return printable === "" ? void 0 : printable;
29054
29067
  }
29068
+ /**
29069
+ * Whether one header name is already set, ignoring case.
29070
+ *
29071
+ * HTTP header names are case-insensitive, so a custom `User-Agent` and the
29072
+ * identity `user-agent` are the same header. Keeping both in the map would
29073
+ * send one header twice with two values, which is exactly how a spoofed user
29074
+ * agent would survive the layer that was supposed to override it.
29075
+ */
29076
+ function hasHeaderName(headers, name) {
29077
+ const target = name.toLowerCase();
29078
+ return Object.keys(headers).some((key) => key.toLowerCase() === target);
29079
+ }
29080
+ /**
29081
+ * Extra headers the deployment supplies through KIMI_CODE_CUSTOM_HEADERS.
29082
+ *
29083
+ * The format is the official client's: newline-separated `Name: Value` lines,
29084
+ * exactly as `ANTHROPIC_CUSTOM_HEADERS` carries them. A line without a colon
29085
+ * is skipped, and both the name and the value are trimmed. The name keeps the
29086
+ * casing the deployment wrote, because that is the header the deployment
29087
+ * expects to see on the wire.
29088
+ *
29089
+ * The value is filtered through {@link asciiHeaderValue}, so a value with
29090
+ * nothing printable left in it is dropped instead of being sent as an empty
29091
+ * header.
29092
+ *
29093
+ * These headers form the LOWEST-precedence layer: the Kimi device identity
29094
+ * headers and the caller's own headers both override them.
29095
+ *
29096
+ * @param env environment the variable is read from, injectable for tests.
29097
+ */
29098
+ function parseKimiCodeCustomHeaders(env = process.env) {
29099
+ const raw = env[KIMI_CODE_CUSTOM_HEADERS_ENV]?.trim();
29100
+ if (raw === void 0 || raw === "") return {};
29101
+ const headers = {};
29102
+ for (const line of raw.split("\n")) {
29103
+ const colon = line.indexOf(":");
29104
+ if (colon < 0) continue;
29105
+ const name = line.slice(0, colon).trim();
29106
+ if (name === "") continue;
29107
+ const value = asciiHeaderValue(line.slice(colon + 1));
29108
+ if (value === void 0) continue;
29109
+ headers[name] = value;
29110
+ }
29111
+ return headers;
29112
+ }
29055
29113
  /** Best-effort human description of this machine, matching the official client. */
29056
29114
  function deviceModel() {
29057
29115
  const arch = os.arch();
@@ -29084,7 +29142,22 @@ async function getDeviceId() {
29084
29142
  } catch {}
29085
29143
  return created;
29086
29144
  }
29087
- /** Identity headers every Kimi Code OAuth and account request carries. */
29145
+ /**
29146
+ * Identity headers every Kimi Code OAuth and account request carries.
29147
+ *
29148
+ * Three layers, lowest precedence first:
29149
+ *
29150
+ * 1. the deployment's own `KIMI_CODE_CUSTOM_HEADERS`, so a gateway in front of
29151
+ * this route can ask for one extra header without a plugin release;
29152
+ * 2. the Kimi device identity, which the service uses to attribute usage to an
29153
+ * installation;
29154
+ * 3. the caller's own headers, which carry the credentials.
29155
+ *
29156
+ * A header name is matched across the layers without regard to case, so a
29157
+ * custom `User-Agent` cannot sit next to the identity `user-agent` and have
29158
+ * the last value win by accident: the higher layer replaces the lower one
29159
+ * outright instead of adding a second copy of the same header.
29160
+ */
29088
29161
  async function kimiIdentityHeaders(extra = {}) {
29089
29162
  const deviceId = await getDeviceId();
29090
29163
  const candidates = [
@@ -29102,6 +29175,10 @@ async function kimiIdentityHeaders(extra = {}) {
29102
29175
  const safe = asciiHeaderValue(value);
29103
29176
  if (safe !== void 0) headers[name] = safe;
29104
29177
  }
29178
+ for (const [name, value] of Object.entries(parseKimiCodeCustomHeaders())) {
29179
+ if (hasHeaderName(headers, name) || hasHeaderName(extra, name)) continue;
29180
+ headers[name] = value;
29181
+ }
29105
29182
  return {
29106
29183
  ...headers,
29107
29184
  ...extra
@@ -29561,11 +29638,11 @@ const MODELS_PATH$2 = "/models";
29561
29638
  const USAGES_PATH = "/usages";
29562
29639
  /** The service reports money in fixed-point units of 1e-6 cents. */
29563
29640
  const FIXED_POINT_CENTS = 1e6;
29564
- function isRecord$55(value) {
29641
+ function isRecord$57(value) {
29565
29642
  return typeof value === "object" && value !== null && !Array.isArray(value);
29566
29643
  }
29567
29644
  function asRecord$14(value) {
29568
- return isRecord$55(value) ? value : void 0;
29645
+ return isRecord$57(value) ? value : void 0;
29569
29646
  }
29570
29647
  function asString$23(value) {
29571
29648
  if (typeof value === "string" && value.trim() !== "") return value;
@@ -29591,6 +29668,19 @@ function firstNumber(record, keys) {
29591
29668
  if (value !== void 0) return value;
29592
29669
  }
29593
29670
  }
29671
+ /**
29672
+ * Non-empty strings from one array field.
29673
+ *
29674
+ * The service states its lists as JSON arrays. A field that is not an array, or
29675
+ * an array with nothing usable in it, reads as "the server said nothing" rather
29676
+ * than as an empty list, so the caller can fall back to the other dialect
29677
+ * instead of publishing an empty answer as the server's verdict.
29678
+ */
29679
+ function asStringList(value) {
29680
+ if (!Array.isArray(value)) return void 0;
29681
+ const entries = value.filter((entry) => typeof entry === "string" && entry.trim() !== "");
29682
+ return entries.length > 0 ? entries : void 0;
29683
+ }
29594
29684
  function clamp01$1(value) {
29595
29685
  return Math.min(1, Math.max(0, value));
29596
29686
  }
@@ -29698,14 +29788,48 @@ const RETIRED_MODEL_STATUSES = /* @__PURE__ */ new Set([
29698
29788
  * Read the three-state thinking declaration.
29699
29789
  *
29700
29790
  * Kept separate from the effort list because it can contradict it: a model may
29701
- * ship `valid_efforts` that still contain `none` while `supports_thinking_type`
29702
- * says it can only reason. When both are present the declaration wins, because
29703
- * it is the field the service introduced to replace the older boolean.
29791
+ * ship `valid_efforts` that still contain `none` while the declaration says it
29792
+ * can only reason. When both are present the declaration wins, because it is
29793
+ * the field the service introduced to replace the older boolean.
29794
+ *
29795
+ * Two dialects state it. The unified schema nests it under `reasoning`:
29796
+ * `{ "type": "only" | "both" | "none" }`; the older listing states it flat as
29797
+ * `supports_thinking_type`. The unified object is read first, because it is
29798
+ * the newer field and the one that also carries the effort ladder; the flat
29799
+ * field remains the fallback for a server that still speaks the old shape.
29800
+ *
29801
+ * The unified schema spells the non-thinking state `none`; the internal
29802
+ * three-state keeps the legacy `no`.
29704
29803
  */
29705
29804
  function parseThinkingType(record) {
29805
+ const reasoning = asRecord$14(record.reasoning);
29806
+ if (reasoning !== void 0) {
29807
+ const rType = asString$23(reasoning.type);
29808
+ if (rType === "only" || rType === "both") return rType;
29809
+ if (rType === "none" || rType === "no") return "no";
29810
+ }
29706
29811
  const raw = asString$23(record.supports_thinking_type) ?? asString$23(record.supportsThinkingType);
29707
29812
  return raw === "only" || raw === "no" || raw === "both" ? raw : void 0;
29708
29813
  }
29814
+ /**
29815
+ * Read one model entry from the live listing.
29816
+ *
29817
+ * The service has published two shapes of the same listing and this parser
29818
+ * reads both:
29819
+ *
29820
+ * - the unified schema, which nests the window under `limit.context`, the
29821
+ * input cap under `limit.input`, the thinking declaration and the effort
29822
+ * ladder under `reasoning`, the accepted media under `modalities.input`
29823
+ * and the message-level tool flag under `tools.dynamic_load`;
29824
+ * - the older flat schema, which states the same facts as
29825
+ * `context_length`, `max_input_tokens`, `supports_thinking_type`,
29826
+ * `think_efforts`, `supports_image_in` / `supports_video_in` and
29827
+ * `supports_dynamic_tools`.
29828
+ *
29829
+ * A field the unified schema carries wins over its flat counterpart, because
29830
+ * that is the shape the service is moving towards; a field only the flat shape
29831
+ * carries is still read, so an older server keeps working.
29832
+ */
29709
29833
  function parseCatalogModel(value) {
29710
29834
  const record = asRecord$14(value);
29711
29835
  if (record === void 0) return void 0;
@@ -29713,30 +29837,41 @@ function parseCatalogModel(value) {
29713
29837
  if (id === void 0) return void 0;
29714
29838
  const status = asString$23(record.status)?.toLowerCase();
29715
29839
  if (status !== void 0 && RETIRED_MODEL_STATUSES.has(status)) return void 0;
29716
- const contextWindow = firstNumber(record, ["context_length", "contextLength"]);
29840
+ const limits = asRecord$14(record.limit) ?? asRecord$14(record.limits);
29841
+ const contextWindow = firstNumber(record, ["context_length", "contextLength"]) ?? firstNumber(limits ?? {}, ["context"]);
29717
29842
  if (contextWindow === void 0 || contextWindow <= 0) return void 0;
29718
- const declaredInput = firstNumber(asRecord$14(record.limit) ?? asRecord$14(record.limits) ?? {}, ["input"]) ?? firstNumber(record, ["max_input_tokens", "maxInputTokens"]);
29843
+ const declaredInput = firstNumber(limits ?? {}, ["input"]) ?? firstNumber(record, ["max_input_tokens", "maxInputTokens"]);
29719
29844
  const maxInputTokens = declaredInput !== void 0 && declaredInput > 0 && declaredInput < contextWindow ? declaredInput : void 0;
29720
29845
  const thinkingType = parseThinkingType(record);
29846
+ const reasoningEffort = asRecord$14(asRecord$14(record.reasoning)?.effort);
29721
29847
  const efforts = asRecord$14(record.think_efforts) ?? asRecord$14(record.thinkEfforts);
29722
- const validEfforts = Array.isArray(efforts?.valid_efforts) ? efforts.valid_efforts.filter((entry) => typeof entry === "string") : Array.isArray(efforts?.validEfforts) ? efforts.validEfforts.filter((entry) => typeof entry === "string") : void 0;
29848
+ const usableEfforts = efforts !== void 0 && "support" in efforts && efforts.support !== true ? void 0 : efforts;
29849
+ const validEfforts = asStringList(reasoningEffort?.valid) ?? asStringList(usableEfforts?.valid_efforts) ?? asStringList(usableEfforts?.validEfforts);
29850
+ const rawDefaultEffort = asString$23(reasoningEffort?.default) ?? asString$23(usableEfforts?.default_effort ?? usableEfforts?.defaultEffort);
29851
+ const defaultReasoningEffort = rawDefaultEffort !== void 0 && validEfforts !== void 0 && validEfforts.length > 0 && !validEfforts.includes(rawDefaultEffort) ? void 0 : rawDefaultEffort;
29852
+ const rawModalities = asRecord$14(record.modalities);
29853
+ const modalityInputs = Array.isArray(rawModalities?.input) ? rawModalities.input.filter((entry) => typeof entry === "string") : [];
29854
+ const hasImage = record.supports_image_in === true || record.supportsImageIn === true || modalityInputs.includes("image");
29855
+ const hasVideo = record.supports_video_in === true || record.supportsVideoIn === true || modalityInputs.includes("video");
29723
29856
  const modalities = ["text"];
29724
- if (record.supports_image_in === true || record.supportsImageIn === true) modalities.push("image");
29725
- if (record.supports_video_in === true || record.supportsVideoIn === true) modalities.push("video");
29857
+ if (hasImage) modalities.push("image");
29858
+ if (hasVideo) modalities.push("video");
29859
+ const toolsObj = asRecord$14(record.tools);
29860
+ const rawDynamicTools = typeof toolsObj?.dynamic_load === "boolean" ? toolsObj.dynamic_load : record.supports_dynamic_tools ?? record.supportsDynamicTools;
29726
29861
  const protocol = asString$23(record.protocol);
29727
29862
  return {
29728
29863
  id,
29729
29864
  name: asString$23(record.display_name) ?? asString$23(record.displayName) ?? void 0,
29730
29865
  contextWindow,
29731
- ...validEfforts === void 0 || validEfforts.length === 0 ? {} : { reasoningEfforts: validEfforts },
29732
- ...asString$23(efforts?.default_effort ?? efforts?.defaultEffort) === void 0 ? {} : { defaultReasoningEffort: asString$23(efforts?.default_effort ?? efforts?.defaultEffort) },
29866
+ ...validEfforts === void 0 ? {} : { reasoningEfforts: validEfforts },
29867
+ ...defaultReasoningEffort === void 0 ? {} : { defaultReasoningEffort },
29733
29868
  inputModalities: modalities,
29734
29869
  protocol: protocol === "anthropic" ? "anthropic" : "openai",
29735
- ...record.supports_video_in === true || record.supportsVideoIn === true ? { supportsVideo: true } : {},
29870
+ ...hasVideo ? { supportsVideo: true } : {},
29736
29871
  ...maxInputTokens === void 0 ? {} : { maxInputTokens },
29737
29872
  ...thinkingType === void 0 ? {} : { thinkingType },
29738
29873
  ...typeof (record.supports_tool_use ?? record.supportsToolUse) === "boolean" ? { supportsToolUse: record.supports_tool_use ?? record.supportsToolUse } : {},
29739
- ...typeof (record.supports_dynamic_tools ?? record.supportsDynamicTools) === "boolean" ? { supportsDynamicTools: record.supports_dynamic_tools ?? record.supportsDynamicTools } : {}
29874
+ ...typeof rawDynamicTools === "boolean" ? { supportsDynamicTools: rawDynamicTools } : {}
29740
29875
  };
29741
29876
  }
29742
29877
  /**
@@ -30622,12 +30757,12 @@ async function testConnection$1(store, options = {}) {
30622
30757
  *
30623
30758
  * @module dsh-chatgpt-subscription/tool-schema
30624
30759
  */
30625
- function isRecord$54(value) {
30760
+ function isRecord$56(value) {
30626
30761
  return typeof value === "object" && value !== null && !Array.isArray(value);
30627
30762
  }
30628
30763
  function cloneJsonValue(value) {
30629
30764
  if (Array.isArray(value)) return value.map(cloneJsonValue);
30630
- if (isRecord$54(value)) {
30765
+ if (isRecord$56(value)) {
30631
30766
  const res = {};
30632
30767
  for (const [k, v] of Object.entries(value)) res[k] = cloneJsonValue(v);
30633
30768
  return res;
@@ -30642,7 +30777,7 @@ function resolveLocalJsonPointer(root, ref) {
30642
30777
  let current = root;
30643
30778
  for (const rawPart of ref.slice(2).split("/")) {
30644
30779
  const part = rawPart.replaceAll("~1", "/").replaceAll("~0", "~");
30645
- if (isRecord$54(current)) {
30780
+ if (isRecord$56(current)) {
30646
30781
  if (!Object.prototype.hasOwnProperty.call(current, part)) return { found: false };
30647
30782
  current = current[part];
30648
30783
  } else if (Array.isArray(current)) {
@@ -30658,7 +30793,7 @@ function resolveLocalJsonPointer(root, ref) {
30658
30793
  }
30659
30794
  function derefNode(node, root, visited) {
30660
30795
  if (Array.isArray(node)) return node.map((item) => derefNode(item, root, visited));
30661
- if (isRecord$54(node)) {
30796
+ if (isRecord$56(node)) {
30662
30797
  if (typeof node["$ref"] === "string" && (node["$ref"] === "#" || node["$ref"].startsWith("#/"))) {
30663
30798
  const ref = node["$ref"];
30664
30799
  if (visited.has(ref)) return node;
@@ -30667,7 +30802,7 @@ function derefNode(node, root, visited) {
30667
30802
  visited.add(ref);
30668
30803
  const inlined = derefNode(resolved.value, root, visited);
30669
30804
  visited.delete(ref);
30670
- if (isRecord$54(inlined)) {
30805
+ if (isRecord$56(inlined)) {
30671
30806
  const merged = { ...inlined };
30672
30807
  for (const [k, v] of Object.entries(node)) {
30673
30808
  if (k === "$ref") continue;
@@ -30687,7 +30822,7 @@ function derefNode(node, root, visited) {
30687
30822
  }
30688
30823
  function hasUnresolvedDefinitionRef(node, bucketKey) {
30689
30824
  if (Array.isArray(node)) return node.some((child) => hasUnresolvedDefinitionRef(child, bucketKey));
30690
- if (isRecord$54(node)) {
30825
+ if (isRecord$56(node)) {
30691
30826
  const ref = node["$ref"];
30692
30827
  if (typeof ref === "string" && ref.startsWith(`#/${bucketKey}/`)) return true;
30693
30828
  for (const [k, v] of Object.entries(node)) {
@@ -30718,19 +30853,19 @@ function inferTypeFromValues(values) {
30718
30853
  if (types.size === 1) return types.values().next().value;
30719
30854
  }
30720
30855
  function normalizeSchemaProperties(node) {
30721
- if (!isRecord$54(node)) return;
30722
- if (isRecord$54(node.properties)) {
30723
- for (const propSchema of Object.values(node.properties)) if (isRecord$54(propSchema)) {
30856
+ if (!isRecord$56(node)) return;
30857
+ if (isRecord$56(node.properties)) {
30858
+ for (const propSchema of Object.values(node.properties)) if (isRecord$56(propSchema)) {
30724
30859
  if (!propSchema.type && !propSchema.$ref) {
30725
30860
  if (Array.isArray(propSchema.enum) && propSchema.enum.length > 0) propSchema.type = inferTypeFromValues(propSchema.enum) ?? "string";
30726
30861
  else if (propSchema.const !== void 0) propSchema.type = inferValueType(propSchema.const) ?? "string";
30727
- else if (isRecord$54(propSchema.properties)) propSchema.type = "object";
30862
+ else if (isRecord$56(propSchema.properties)) propSchema.type = "object";
30728
30863
  else if (propSchema.items) propSchema.type = "array";
30729
30864
  }
30730
30865
  normalizeSchemaProperties(propSchema);
30731
30866
  }
30732
30867
  }
30733
- if (isRecord$54(node.items)) normalizeSchemaProperties(node.items);
30868
+ if (isRecord$56(node.items)) normalizeSchemaProperties(node.items);
30734
30869
  else if (Array.isArray(node.items)) for (const item of node.items) normalizeSchemaProperties(item);
30735
30870
  }
30736
30871
  /**
@@ -30738,7 +30873,7 @@ function normalizeSchemaProperties(node) {
30738
30873
  * inlining definitions ($defs/definitions/$ref), and ensuring property types for enums/consts.
30739
30874
  */
30740
30875
  function normalizeKimiToolSchema(schema) {
30741
- if (!isRecord$54(schema)) return {
30876
+ if (!isRecord$56(schema)) return {
30742
30877
  type: "object",
30743
30878
  properties: {}
30744
30879
  };
@@ -30756,7 +30891,7 @@ function stripMetaSchema$1(schema) {
30756
30891
  }
30757
30892
  //#endregion
30758
30893
  //#region src/host/common/prompt-estimate.ts
30759
- function isRecord$53(value) {
30894
+ function isRecord$55(value) {
30760
30895
  return typeof value === "object" && value !== null && !Array.isArray(value);
30761
30896
  }
30762
30897
  /** Tool-call arguments as the JSON string a wire carries, whatever shape they arrived in. */
@@ -30789,7 +30924,7 @@ function estimatedInputTokens(options) {
30789
30924
  const contentCharacters = (content) => {
30790
30925
  if (!Array.isArray(content)) return typeof content === "string" ? content.length : 0;
30791
30926
  return content.reduce((total, block) => {
30792
- if (!isRecord$53(block)) return total;
30927
+ if (!isRecord$55(block)) return total;
30793
30928
  if ((block.type === "text" || block.type === "reasoning") && typeof block.text === "string") return total + block.text.length;
30794
30929
  if (block.type === "tool-result") return total + contentCharacters(block.content);
30795
30930
  if (block.type === "tool-call") {
@@ -30890,7 +31025,7 @@ function videoOmissionText$1(reason, label) {
30890
31025
  }
30891
31026
  //#endregion
30892
31027
  //#region src/host/common/video-request.ts
30893
- function isRecord$52(value) {
31028
+ function isRecord$54(value) {
30894
31029
  return typeof value === "object" && value !== null && !Array.isArray(value);
30895
31030
  }
30896
31031
  function asString$22(value) {
@@ -30898,14 +31033,14 @@ function asString$22(value) {
30898
31033
  }
30899
31034
  function videoAttachmentOf(block) {
30900
31035
  const attachment = block.attachment;
30901
- if (!isRecord$52(attachment)) return void 0;
31036
+ if (!isRecord$54(attachment)) return void 0;
30902
31037
  if (typeof attachment.attachmentId !== "string") return void 0;
30903
31038
  return attachment;
30904
31039
  }
30905
31040
  function collectVideoRefs(content, refs) {
30906
31041
  if (!Array.isArray(content)) return;
30907
31042
  for (const block of content) {
30908
- if (!isRecord$52(block) || block.type !== "video") continue;
31043
+ if (!isRecord$54(block) || block.type !== "video") continue;
30909
31044
  const attachment = videoAttachmentOf(block);
30910
31045
  if (attachment) refs.set(attachment.attachmentId, attachment);
30911
31046
  }
@@ -30920,7 +31055,7 @@ function requestVideoBytes(block) {
30920
31055
  function collectRequestVideoBytes(content, lengths) {
30921
31056
  if (!Array.isArray(content)) return;
30922
31057
  for (const block of content) {
30923
- if (!isRecord$52(block) || block.type !== "video") continue;
31058
+ if (!isRecord$54(block) || block.type !== "video") continue;
30924
31059
  const bytes = requestVideoBytes(block);
30925
31060
  if (bytes !== void 0) lengths.push(bytes);
30926
31061
  }
@@ -30964,7 +31099,7 @@ function isAbortLike(error, signal) {
30964
31099
  }
30965
31100
  /** True when the request carries any video occurrence at all. */
30966
31101
  function requestHasVideo(options) {
30967
- return options.messages.some((message) => Array.isArray(message.content) && message.content.some((block) => isRecord$52(block) && block.type === "video"));
31102
+ return options.messages.some((message) => Array.isArray(message.content) && message.content.some((block) => isRecord$54(block) && block.type === "video"));
30968
31103
  }
30969
31104
  function omittedVideoText(omit, block) {
30970
31105
  return omit("unreadable", videoBlockLabel(block));
@@ -30999,7 +31134,7 @@ function offloadOldestRequestVideos(options, maxBytes) {
30999
31134
  if (remaining.count === 0 || !Array.isArray(message.content)) return message;
31000
31135
  let replaced = false;
31001
31136
  const content = message.content.map((block) => {
31002
- if (remaining.count === 0 || !isRecord$52(block) || block.type !== "video") return block;
31137
+ if (remaining.count === 0 || !isRecord$54(block) || block.type !== "video") return block;
31003
31138
  if (requestVideoBytes(block) === void 0) return block;
31004
31139
  remaining.count -= 1;
31005
31140
  replaced = true;
@@ -31082,7 +31217,7 @@ function videoBlockToInline(block, videos, videoAccepted, omit) {
31082
31217
  *
31083
31218
  * See https://www.kimi.com/code/docs/en/kimi-code/error-reference.html
31084
31219
  */
31085
- function isRecord$51(value) {
31220
+ function isRecord$53(value) {
31086
31221
  return typeof value === "object" && value !== null && !Array.isArray(value);
31087
31222
  }
31088
31223
  function asString$21(value) {
@@ -31192,7 +31327,7 @@ function reasoningDetailFragments(value) {
31192
31327
  if (!Array.isArray(value)) return [];
31193
31328
  const fragments = [];
31194
31329
  value.forEach((entry, position) => {
31195
- if (!isRecord$51(entry)) return;
31330
+ if (!isRecord$53(entry)) return;
31196
31331
  fragments.push(...reasoningDetailElement(entry, position));
31197
31332
  });
31198
31333
  return fragments;
@@ -31423,23 +31558,12 @@ function mapReasoningEffort(effort) {
31423
31558
  default: return;
31424
31559
  }
31425
31560
  }
31426
- /**
31427
- * Thinking-token budget one Anthropic-route level asks for.
31428
- *
31429
- * Kimi's Anthropic surface takes the standard `thinking` block, so the budget is
31430
- * derived from the same three levels the OpenAI surface uses.
31431
- */
31432
- function thinkingBudgetFor(effort, maxTokens) {
31433
- if (effort === void 0 || effort === "none") return void 0;
31434
- const budget = Math.min(effort === "low" ? 2048 : effort === "high" ? 8192 : 16384, maxTokens - 1024);
31435
- return budget >= 1024 ? budget : void 0;
31436
- }
31437
31561
  function textOf$7(content) {
31438
31562
  if (typeof content === "string") return sanitizeText$7(content);
31439
31563
  if (!Array.isArray(content)) return "";
31440
31564
  const parts = [];
31441
31565
  for (const block of content) {
31442
- if (!isRecord$51(block)) continue;
31566
+ if (!isRecord$53(block)) continue;
31443
31567
  if (block.type === "text" && typeof block.text === "string") parts.push(sanitizeText$7(block.text));
31444
31568
  else if (block.type === "tool-result") parts.push(textOf$7(block.content));
31445
31569
  }
@@ -31448,7 +31572,7 @@ function textOf$7(content) {
31448
31572
  function toolResultText$7(blocks) {
31449
31573
  if (!Array.isArray(blocks)) return "";
31450
31574
  return blocks.map((block) => {
31451
- if (!isRecord$51(block)) return "";
31575
+ if (!isRecord$53(block)) return "";
31452
31576
  if (block.type === "text" && typeof block.text === "string") return sanitizeText$7(block.text);
31453
31577
  if (block.type === "tool-result") return toolResultText$7(block.content);
31454
31578
  if (block.type === "image") return `[image: ${attachmentLabel$3(block) ?? "attached image"}]`;
@@ -31466,7 +31590,7 @@ function toolResultBlocks$1(blocks, images) {
31466
31590
  const out = [];
31467
31591
  let hasImage = false;
31468
31592
  for (const block of blocks) {
31469
- if (!isRecord$51(block)) continue;
31593
+ if (!isRecord$53(block)) continue;
31470
31594
  if (block.type === "text" && typeof block.text === "string") {
31471
31595
  out.push({
31472
31596
  type: "text",
@@ -31521,7 +31645,7 @@ function toolResultImageBlocks$4(blocks, images, media = {}) {
31521
31645
  if (!Array.isArray(blocks)) return [];
31522
31646
  const out = [];
31523
31647
  for (const block of blocks) {
31524
- if (!isRecord$51(block)) continue;
31648
+ if (!isRecord$53(block)) continue;
31525
31649
  if (block.type === "image") {
31526
31650
  const reference = hostedReference(media.imageReferences, block);
31527
31651
  if (reference !== void 0) {
@@ -31556,7 +31680,7 @@ const HOSTED_FILE_SCHEME = "ms://";
31556
31680
  * bytes.
31557
31681
  */
31558
31682
  function attachmentIdOf(block) {
31559
- const attachment = isRecord$51(block.attachment) ? block.attachment : void 0;
31683
+ const attachment = isRecord$53(block.attachment) ? block.attachment : void 0;
31560
31684
  const id = attachment === void 0 ? void 0 : asString$21(attachment.attachmentId);
31561
31685
  return id === void 0 || id === "" ? void 0 : id;
31562
31686
  }
@@ -31639,12 +31763,12 @@ function readReasoningForm(value) {
31639
31763
  */
31640
31764
  function reasoningRunsAt(message, blockIndex) {
31641
31765
  const state = message.source?.replayState;
31642
- if (!isRecord$51(state) || !Array.isArray(state.blocks)) return void 0;
31766
+ if (!isRecord$53(state) || !Array.isArray(state.blocks)) return void 0;
31643
31767
  const entry = state.blocks[blockIndex];
31644
- if (!isRecord$51(entry) || !Array.isArray(entry.reasoning)) return void 0;
31768
+ if (!isRecord$53(entry) || !Array.isArray(entry.reasoning)) return void 0;
31645
31769
  const runs = [];
31646
31770
  for (const raw of entry.reasoning) {
31647
- if (!isRecord$51(raw)) return void 0;
31771
+ if (!isRecord$53(raw)) return void 0;
31648
31772
  const key = asString$21(raw.key);
31649
31773
  const length = raw.length;
31650
31774
  if (key === void 0 || typeof length !== "number" || !Number.isInteger(length) || length < 0) return void 0;
@@ -31694,7 +31818,7 @@ function replayedReasoning(message, fallbackKey) {
31694
31818
  };
31695
31819
  for (let blockIndex = 0; blockIndex < message.content.length; blockIndex++) {
31696
31820
  const block = message.content[blockIndex];
31697
- if (!isRecord$51(block) || block.type !== "reasoning" || typeof block.text !== "string") continue;
31821
+ if (!isRecord$53(block) || block.type !== "reasoning" || typeof block.text !== "string") continue;
31698
31822
  const text = sanitizeText$7(block.text);
31699
31823
  joined += text;
31700
31824
  const runs = reasoningRunsAt(message, blockIndex);
@@ -31863,7 +31987,7 @@ function openAIUserContent$3(message, images, media = {}) {
31863
31987
  const parts = [];
31864
31988
  let hasRichPart = false;
31865
31989
  for (const block of message.content) {
31866
- if (!isRecord$51(block)) continue;
31990
+ if (!isRecord$53(block)) continue;
31867
31991
  if (block.type === "text" && typeof block.text === "string") {
31868
31992
  const text = sanitizeText$7(block.text);
31869
31993
  if (text !== "") parts.push({
@@ -31921,16 +32045,20 @@ function openAIAssistantContent$3(message, toolCallIds, reasoningKey) {
31921
32045
  const textParts = [];
31922
32046
  const toolCalls = [];
31923
32047
  for (const block of message.content) {
31924
- if (!isRecord$51(block)) continue;
32048
+ if (!isRecord$53(block)) continue;
31925
32049
  if (block.type === "text" && typeof block.text === "string") textParts.push(sanitizeText$7(block.text));
31926
- else if (block.type === "tool-call" && typeof block.name === "string") toolCalls.push({
31927
- id: toolCallIds.normalize(typeof block.id === "string" && block.id !== "" ? block.id : `call_${toolCalls.length}`),
31928
- type: "function",
31929
- function: {
31930
- name: block.name,
31931
- arguments: toolCallArguments$6(block.arguments)
31932
- }
31933
- });
32050
+ else if (block.type === "tool-call" && typeof block.name === "string") {
32051
+ const call = {
32052
+ id: toolCallIds.normalize(typeof block.id === "string" && block.id !== "" ? block.id : `call_${toolCalls.length}`),
32053
+ type: "function",
32054
+ function: {
32055
+ name: block.name,
32056
+ arguments: toolCallArguments$6(block.arguments)
32057
+ }
32058
+ };
32059
+ if (isRecord$53(block.extras)) call.extras = block.extras;
32060
+ toolCalls.push(call);
32061
+ }
31934
32062
  }
31935
32063
  return {
31936
32064
  content: textParts.join(""),
@@ -32071,6 +32199,31 @@ function replayedDetailElement(detail) {
32071
32199
  ...index
32072
32200
  };
32073
32201
  }
32202
+ /**
32203
+ * Put one run of tool results back in the order the assistant declared its
32204
+ * calls in.
32205
+ *
32206
+ * A parallel tool call answers several calls at once, and the service reads
32207
+ * the `tool` messages as the answers to the `tool_calls` that precede them:
32208
+ * a result that arrives in the wrong order is answered against the wrong call.
32209
+ * DSH history can hold the results out of order (a resumed session, a tool
32210
+ * that answered late), so the run is sorted back into the declared order.
32211
+ *
32212
+ * A result whose id belongs to no declared call keeps its relative order
32213
+ * behind the answered ones: it answers something this turn did not declare,
32214
+ * so there is no declared position for it to be sorted into.
32215
+ */
32216
+ function pairToolExchanges(batch, declaredIds) {
32217
+ if (batch.length < 2 || declaredIds.length < 2) return [...batch];
32218
+ const rank = /* @__PURE__ */ new Map();
32219
+ for (const [position, id] of declaredIds.entries()) if (!rank.has(id)) rank.set(id, position);
32220
+ if (batch.filter((entry) => rank.has(entry.id)).length < 2) return [...batch];
32221
+ return batch.map((entry, position) => ({
32222
+ entry,
32223
+ position,
32224
+ key: rank.get(entry.id) ?? Number.MAX_SAFE_INTEGER
32225
+ })).sort((a, b) => a.key - b.key || a.position - b.position).map((ordered) => ordered.entry);
32226
+ }
32074
32227
  /** Build one `/chat/completions` body. */
32075
32228
  function buildOpenAIRequest(options, images = NO_RESOLVED_IMAGES$3, preserveThinking = preserveThinkingEnabled(), media = {}) {
32076
32229
  const effort = mapReasoningEffort(options.reasoningEffort === void 0 ? void 0 : String(options.reasoningEffort));
@@ -32132,21 +32285,16 @@ function buildOpenAIRequest(options, images = NO_RESOLVED_IMAGES$3, preserveThin
32132
32285
  flushSlots(nonSystemIndex);
32133
32286
  nonSystemIndex += 1;
32134
32287
  if (isToolResultMessage$7(message)) {
32288
+ const batch = [];
32135
32289
  while (index < conversation.length && isToolResultMessage$7(conversation[index])) {
32136
32290
  const current = conversation[index];
32137
32291
  const block = current.content[0];
32138
- const rawCallId = isRecord$51(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
32139
- const normalizedCallId = toolCallIds.normalize(rawCallId);
32140
- messages.push({
32141
- role: "tool",
32142
- tool_call_id: normalizedCallId,
32143
- content: toolResultText$7(current.content)
32292
+ const rawCallId = isRecord$53(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
32293
+ batch.push({
32294
+ id: toolCallIds.normalize(rawCallId),
32295
+ content: toolResultText$7(current.content),
32296
+ images: toolResultImageBlocks$4(current.content, images, media)
32144
32297
  });
32145
- pendingToolImages.push(...toolResultImageBlocks$4(current.content, images, media));
32146
- if (awaitingToolCallIds.length > 0) {
32147
- awaitingToolCallIds = awaitingToolCallIds.filter((id) => id !== normalizedCallId);
32148
- if (awaitingToolCallIds.length === 0) flushDeferred();
32149
- }
32150
32298
  if (index + 1 < conversation.length && isToolResultMessage$7(conversation[index + 1])) {
32151
32299
  flushSlots(nonSystemIndex);
32152
32300
  nonSystemIndex += 1;
@@ -32155,6 +32303,18 @@ function buildOpenAIRequest(options, images = NO_RESOLVED_IMAGES$3, preserveThin
32155
32303
  }
32156
32304
  break;
32157
32305
  }
32306
+ for (const entry of pairToolExchanges(batch, awaitingToolCallIds)) {
32307
+ messages.push({
32308
+ role: "tool",
32309
+ tool_call_id: entry.id,
32310
+ content: entry.content
32311
+ });
32312
+ pendingToolImages.push(...entry.images);
32313
+ if (awaitingToolCallIds.length > 0) {
32314
+ awaitingToolCallIds = awaitingToolCallIds.filter((id) => id !== entry.id);
32315
+ if (awaitingToolCallIds.length === 0) flushDeferred();
32316
+ }
32317
+ }
32158
32318
  if (awaitingToolCallIds.length === 0) flushToolImages();
32159
32319
  continue;
32160
32320
  }
@@ -32249,7 +32409,7 @@ function firstTextOf(content) {
32249
32409
  }
32250
32410
  if (!Array.isArray(content)) return void 0;
32251
32411
  for (const block of content) {
32252
- if (!isRecord$51(block)) continue;
32412
+ if (!isRecord$53(block)) continue;
32253
32413
  if (block.type === "text" && typeof block.text === "string") {
32254
32414
  const text = sanitizeText$7(block.text);
32255
32415
  if (text !== "") return text;
@@ -32307,7 +32467,7 @@ function isSideChannelTitleRequest(options) {
32307
32467
  const tools = options.tools;
32308
32468
  const toolLess = tools === void 0 || tools.length === 0;
32309
32469
  for (const message of messages) {
32310
- if (!isRecord$51(message)) continue;
32470
+ if (!isRecord$53(message)) continue;
32311
32471
  if (message.source?.kind === "dsh-session-title-llm") return true;
32312
32472
  const text = firstTextOf(message.content);
32313
32473
  if (toolLess && text !== void 0 && text.startsWith(TITLE_REQUEST_PROMPT_PREFIX)) return true;
@@ -32334,15 +32494,70 @@ function promptCacheKey(options) {
32334
32494
  if (isSideChannelTitleRequest(options)) return void 0;
32335
32495
  if (typeof options.sessionId === "string" && options.sessionId.trim() !== "") return `dsh-${options.sessionId.trim()}`;
32336
32496
  }
32337
- function anthropicUserContent$2(message, images, toolCallIds) {
32497
+ /**
32498
+ * The Anthropic beta that carries the context-management edit.
32499
+ *
32500
+ * `clear_thinking_20251015` is honoured only on the beta Messages API, so the
32501
+ * beta has to travel WITH the request; the official Kimi Anthropic protocol
32502
+ * asks for it on every thinking request (see the upstream
32503
+ * `kimiAnthropicProtocol`, which returns `betaFeatures: [CONTEXT_MANAGEMENT_BETA]`
32504
+ * for both the enabled and the disabled encoding).
32505
+ */
32506
+ const CONTEXT_MANAGEMENT_BETA = "context-management-2025-06-27";
32507
+ /**
32508
+ * The Anthropic context edit that clears stale thinking blocks.
32509
+ *
32510
+ * The edit is what "keep the thinking across turns" means on this wire: the
32511
+ * service clears the thinking it has already consumed instead of replaying it,
32512
+ * so a preserved thinking block stays affordable.
32513
+ */
32514
+ const CLEAR_THINKING_EDIT = "clear_thinking_20251015";
32515
+ /** The cache breakpoint the Anthropic wire marks with. */
32516
+ const ANTHROPIC_CACHE_CONTROL = { type: "ephemeral" };
32517
+ /**
32518
+ * The content block types that accept a cache breakpoint.
32519
+ *
32520
+ * The official provider injects the breakpoint on the last block of the last
32521
+ * message, and only when that block is one of the cacheable kinds; a block
32522
+ * that cannot carry the marker is left alone rather than given a field the
32523
+ * service would reject.
32524
+ */
32525
+ const ANTHROPIC_CACHEABLE_BLOCK_TYPES = /* @__PURE__ */ new Set([
32526
+ "text",
32527
+ "image",
32528
+ "document",
32529
+ "tool_use",
32530
+ "tool_result"
32531
+ ]);
32532
+ function anthropicUserContent$2(message, images, toolCallIds, media = {}) {
32338
32533
  if (!Array.isArray(message.content)) return [];
32339
32534
  const blocks = [];
32340
32535
  for (const block of message.content) {
32341
- if (!isRecord$51(block)) continue;
32536
+ if (!isRecord$53(block)) continue;
32342
32537
  if (block.type === "video") {
32343
- blocks.push({
32538
+ const reference = hostedReference(media.videoReferences, block);
32539
+ if (reference !== void 0) {
32540
+ blocks.push({
32541
+ type: "video",
32542
+ source: {
32543
+ type: "url",
32544
+ url: reference
32545
+ }
32546
+ });
32547
+ continue;
32548
+ }
32549
+ const outcome = videoBlockToInline(block, media.videos ?? /* @__PURE__ */ new Map(), media.videoAccepted === true, videoOmissionText$1);
32550
+ if ("inline" in outcome) blocks.push({
32551
+ type: "video",
32552
+ source: {
32553
+ type: "base64",
32554
+ media_type: outcome.inline.mediaType,
32555
+ data: outcome.inline.data
32556
+ }
32557
+ });
32558
+ else blocks.push({
32344
32559
  type: "text",
32345
- text: videoOmissionText$1("unsupported-wire", videoBlockLabel(block))
32560
+ text: outcome.omission
32346
32561
  });
32347
32562
  continue;
32348
32563
  }
@@ -32353,19 +32568,29 @@ function anthropicUserContent$2(message, images, toolCallIds) {
32353
32568
  text
32354
32569
  });
32355
32570
  } else if (block.type === "image") {
32356
- const inline = imageBlockToInline$2(block, images);
32357
- if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$3.has(inline.mediaType)) blocks.push({
32571
+ const reference = hostedReference(media.imageReferences, block);
32572
+ if (reference !== void 0) blocks.push({
32358
32573
  type: "image",
32359
32574
  source: {
32360
- type: "base64",
32361
- media_type: inline.mediaType,
32362
- data: inline.data
32575
+ type: "url",
32576
+ url: reference
32363
32577
  }
32364
32578
  });
32365
- else blocks.push({
32366
- type: "text",
32367
- text: unavailableImageText$3(block)
32368
- });
32579
+ else {
32580
+ const inline = imageBlockToInline$2(block, images);
32581
+ if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$3.has(inline.mediaType)) blocks.push({
32582
+ type: "image",
32583
+ source: {
32584
+ type: "base64",
32585
+ media_type: inline.mediaType,
32586
+ data: inline.data
32587
+ }
32588
+ });
32589
+ else blocks.push({
32590
+ type: "text",
32591
+ text: unavailableImageText$3(block)
32592
+ });
32593
+ }
32369
32594
  } else if (block.type === "tool-result") {
32370
32595
  const callId = typeof block.toolCallId === "string" ? block.toolCallId : "";
32371
32596
  const resultBlocks = toolResultBlocks$1(block.content, images);
@@ -32382,20 +32607,28 @@ function anthropicUserContent$2(message, images, toolCallIds) {
32382
32607
  function anthropicAssistantContent$2(message, toolCallIds) {
32383
32608
  const blocks = [];
32384
32609
  for (const block of message.content) {
32385
- if (!isRecord$51(block)) continue;
32610
+ if (!isRecord$53(block)) continue;
32386
32611
  if (block.type === "text" && typeof block.text === "string") {
32387
32612
  const text = sanitizeText$7(block.text);
32388
32613
  if (text !== "") blocks.push({
32389
32614
  type: "text",
32390
32615
  text
32391
32616
  });
32617
+ } else if (block.type === "reasoning") {
32618
+ const thinkingText = typeof block.text === "string" ? sanitizeText$7(block.text) : "";
32619
+ const sig = typeof block.signature === "string" && block.signature.trim() !== "" ? block.signature : void 0;
32620
+ if (thinkingText !== "" || sig !== void 0) blocks.push({
32621
+ type: "thinking",
32622
+ thinking: thinkingText,
32623
+ ...sig === void 0 ? {} : { signature: sig }
32624
+ });
32392
32625
  } else if (block.type === "tool-call" && typeof block.name === "string") {
32393
32626
  const parsed = safeJsonParse$7(toolCallArguments$6(block.arguments));
32394
32627
  blocks.push({
32395
32628
  type: "tool_use",
32396
32629
  id: toolCallIds.normalize(typeof block.id === "string" && block.id !== "" ? block.id : `toolu_${blocks.length}`),
32397
32630
  name: block.name,
32398
- input: isRecord$51(parsed) ? parsed : {}
32631
+ input: isRecord$53(parsed) ? parsed : {}
32399
32632
  });
32400
32633
  }
32401
32634
  }
@@ -32426,7 +32659,7 @@ function mergeAnthropicMessages$2(entries) {
32426
32659
  return merged;
32427
32660
  }
32428
32661
  /** Build one `/v1/messages` body. */
32429
- function buildAnthropicRequest(options, images = NO_RESOLVED_IMAGES$3, media = {}) {
32662
+ function buildAnthropicRequest(options, images = NO_RESOLVED_IMAGES$3, media = {}, preserveThinking = preserveThinkingEnabled()) {
32430
32663
  const toolCallIds = new ToolCallIdNormalizer();
32431
32664
  const carriers = options.messages.filter((message) => message.role === "system" && messageToolsOf(message) !== void 0);
32432
32665
  const unsentDeclarations = carriers.reduce((total, message) => total + (messageToolsOf(message)?.length ?? 0), 0);
@@ -32436,13 +32669,13 @@ function buildAnthropicRequest(options, images = NO_RESOLVED_IMAGES$3, media = {
32436
32669
  if (isToolResultMessage$7(message)) {
32437
32670
  entries.push({
32438
32671
  role: "user",
32439
- content: anthropicUserContent$2(message, images, toolCallIds)
32672
+ content: anthropicUserContent$2(message, images, toolCallIds, media)
32440
32673
  });
32441
32674
  continue;
32442
32675
  }
32443
32676
  entries.push({
32444
32677
  role: message.role === "assistant" ? "assistant" : "user",
32445
- content: message.role === "assistant" ? anthropicAssistantContent$2(message, toolCallIds) : anthropicUserContent$2(message, images, toolCallIds)
32678
+ content: message.role === "assistant" ? anthropicAssistantContent$2(message, toolCallIds) : anthropicUserContent$2(message, images, toolCallIds, media)
32446
32679
  });
32447
32680
  }
32448
32681
  const systemParts = [
@@ -32453,31 +32686,54 @@ function buildAnthropicRequest(options, images = NO_RESOLVED_IMAGES$3, media = {
32453
32686
  const system = systemParts.length === 0 ? void 0 : systemParts.join("\n\n");
32454
32687
  const maxTokens = options.maxTokens ?? maxOutputTokensFor$5(options.model);
32455
32688
  const effort = mapReasoningEffort(options.reasoningEffort === void 0 ? void 0 : String(options.reasoningEffort));
32456
- const budget = thinkingBudgetFor(effort, maxTokens);
32689
+ const thinkingOff = effort === "none";
32690
+ const thinkingField = thinkingOff ? { type: "disabled" } : { type: "enabled" };
32691
+ const outputConfig = !thinkingOff && effort !== void 0 ? { effort } : void 0;
32692
+ const keepThinking = preserveThinking && !thinkingOff;
32693
+ const betas = [CONTEXT_MANAGEMENT_BETA];
32694
+ const contextManagement = keepThinking ? { edits: [{
32695
+ type: CLEAR_THINKING_EDIT,
32696
+ keep: "all"
32697
+ }] } : void 0;
32698
+ const messages = mergeAnthropicMessages$2(entries);
32699
+ const lastMessage = messages[messages.length - 1];
32700
+ if (lastMessage !== void 0 && Array.isArray(lastMessage.content) && lastMessage.content.length > 0) {
32701
+ const lastBlock = lastMessage.content[lastMessage.content.length - 1];
32702
+ if (lastBlock !== void 0 && ANTHROPIC_CACHEABLE_BLOCK_TYPES.has(String(lastBlock.type))) lastBlock.cache_control = { ...ANTHROPIC_CACHE_CONTROL };
32703
+ }
32704
+ const tools = options.tools && options.tools.length > 0 ? options.tools.map((tool) => ({
32705
+ name: tool.name,
32706
+ description: tool.description,
32707
+ input_schema: normalizeKimiToolSchema(tool.parameters)
32708
+ })) : [];
32709
+ if (tools.length > 0) tools[tools.length - 1] = {
32710
+ ...tools[tools.length - 1],
32711
+ cache_control: { ...ANTHROPIC_CACHE_CONTROL }
32712
+ };
32457
32713
  return {
32458
32714
  model: options.model,
32459
32715
  max_tokens: maxTokens,
32460
- messages: mergeAnthropicMessages$2(entries),
32461
- ...system === void 0 ? {} : { system },
32462
- ...options.temperature === void 0 || budget !== void 0 ? {} : { temperature: options.temperature },
32716
+ messages,
32717
+ ...system === void 0 ? {} : { system: [{
32718
+ type: "text",
32719
+ text: system,
32720
+ cache_control: { ...ANTHROPIC_CACHE_CONTROL }
32721
+ }] },
32722
+ ...options.temperature === void 0 || !thinkingOff ? {} : { temperature: options.temperature },
32463
32723
  ...options.stop && options.stop.length > 0 ? { stop_sequences: options.stop } : {},
32464
- ...options.tools && options.tools.length > 0 ? { tools: options.tools.map((tool) => ({
32465
- name: tool.name,
32466
- description: tool.description,
32467
- input_schema: stripMetaSchema$1(tool.parameters)
32468
- })) } : {},
32469
- ...effort === void 0 ? {} : budget === void 0 ? { thinking: { type: "disabled" } } : { thinking: {
32470
- type: "enabled",
32471
- budget_tokens: budget
32472
- } }
32724
+ ...tools.length > 0 ? { tools } : {},
32725
+ thinking: thinkingField,
32726
+ ...outputConfig === void 0 ? {} : { output_config: outputConfig },
32727
+ ...contextManagement === void 0 ? {} : { context_management: contextManagement },
32728
+ betas
32473
32729
  };
32474
32730
  }
32475
32731
  /** Build the body for whichever endpoint serves `wire`. */
32476
32732
  function buildRequest(options, wire, images = NO_RESOLVED_IMAGES$3, preserveThinking = preserveThinkingEnabled(), media = {}) {
32477
- if (isSideChannelTitleRequest(options)) return wire === "anthropic" ? buildAnthropicRequest(options, images, media) : buildOpenAIRequest(options, images, preserveThinking, media);
32733
+ if (isSideChannelTitleRequest(options)) return wire === "anthropic" ? buildAnthropicRequest(options, images, media, preserveThinking) : buildOpenAIRequest(options, images, preserveThinking, media);
32478
32734
  const cause = trackPrefixStability(options);
32479
32735
  recordDriftCause(cause === "stable" && (pendingImageOffloads.get(cacheScopeKey(options.sessionId)) ?? 0) > 0 ? "image-offload" : cause, options.sessionId, options);
32480
- return wire === "anthropic" ? buildAnthropicRequest(options, images, media) : buildOpenAIRequest(options, images, preserveThinking, media);
32736
+ return wire === "anthropic" ? buildAnthropicRequest(options, images, media, preserveThinking) : buildOpenAIRequest(options, images, preserveThinking, media);
32481
32737
  }
32482
32738
  /**
32483
32739
  * Reject a request the service would refuse for its size.
@@ -32519,7 +32775,7 @@ function walkJson(value, visit) {
32519
32775
  for (const item of value) walkJson(item, visit);
32520
32776
  return;
32521
32777
  }
32522
- if (!isRecord$51(value)) return;
32778
+ if (!isRecord$53(value)) return;
32523
32779
  visit(value);
32524
32780
  for (const nested of Object.values(value)) walkJson(nested, visit);
32525
32781
  }
@@ -32535,12 +32791,12 @@ function requestBodyBreakdown(body, carriesVideo = false) {
32535
32791
  const totalBytes = Buffer.byteLength(serialized, "utf8");
32536
32792
  let imageBytes = 0;
32537
32793
  walkJson(body, (node) => {
32538
- const url = isRecord$51(node.image_url) ? asString$21(node.image_url.url) : void 0;
32794
+ const url = isRecord$53(node.image_url) ? asString$21(node.image_url.url) : void 0;
32539
32795
  if (url?.startsWith("data:")) {
32540
32796
  imageBytes += Buffer.byteLength(url, "utf8");
32541
32797
  return;
32542
32798
  }
32543
- const source = isRecord$51(node.source) ? node.source : void 0;
32799
+ const source = isRecord$53(node.source) ? node.source : void 0;
32544
32800
  if (source && asString$21(source.data) !== void 0 && asString$21(source.media_type) !== void 0) imageBytes += Buffer.byteLength(asString$21(source.data) ?? "", "utf8");
32545
32801
  });
32546
32802
  const toolSchemaBytes = Buffer.byteLength(JSON.stringify(body.tools ?? []), "utf8");
@@ -32667,9 +32923,9 @@ function processOpenAIStreamLine(line, state) {
32667
32923
  }
32668
32924
  if (payload === "") return [];
32669
32925
  const chunk = safeJsonParse$7(payload);
32670
- if (!isRecord$51(chunk)) return [];
32926
+ if (!isRecord$53(chunk)) return [];
32671
32927
  const out = [];
32672
- const errorPayload = isRecord$51(chunk.error) ? chunk.error : void 0;
32928
+ const errorPayload = isRecord$53(chunk.error) ? chunk.error : void 0;
32673
32929
  if (errorPayload !== void 0) {
32674
32930
  const message = asString$21(errorPayload.message) ?? "unknown error";
32675
32931
  state.streamError = {
@@ -32679,22 +32935,22 @@ function processOpenAIStreamLine(line, state) {
32679
32935
  };
32680
32936
  throw new LlmError$1(`Kimi Code stream error: ${message}`, isContextOverflow(errorPayload) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
32681
32937
  }
32682
- const usage = isRecord$51(chunk.usage) ? chunk.usage : void 0;
32938
+ const usage = isRecord$53(chunk.usage) ? chunk.usage : void 0;
32683
32939
  if (usage) {
32684
32940
  state.sawUsage = true;
32685
32941
  const prompt = numberOr$8(usage.prompt_tokens, 0);
32686
- const details = isRecord$51(usage.prompt_tokens_details) ? usage.prompt_tokens_details : void 0;
32942
+ const details = isRecord$53(usage.prompt_tokens_details) ? usage.prompt_tokens_details : void 0;
32687
32943
  const cached = details ? numberOr$8(details.cached_tokens, 0) : 0;
32688
32944
  const written = details ? numberOr$8(details.cache_write_tokens, 0) : 0;
32689
32945
  state.inputTokens = Math.max(0, prompt - cached - written);
32690
32946
  state.cacheReadTokens = cached;
32691
32947
  state.cacheWriteTokens = written;
32692
32948
  state.outputTokens = numberOr$8(usage.completion_tokens, state.outputTokens);
32693
- if (isRecord$51(usage.completion_tokens_details)) state.reasoningTokens = numberOr$8(usage.completion_tokens_details.reasoning_tokens, state.reasoningTokens);
32949
+ if (isRecord$53(usage.completion_tokens_details)) state.reasoningTokens = numberOr$8(usage.completion_tokens_details.reasoning_tokens, state.reasoningTokens);
32694
32950
  }
32695
32951
  const choices = Array.isArray(chunk.choices) ? chunk.choices : [];
32696
- const choice = isRecord$51(choices[0]) ? choices[0] : void 0;
32697
- const delta = isRecord$51(choice?.delta) ? choice.delta : void 0;
32952
+ const choice = isRecord$53(choices[0]) ? choices[0] : void 0;
32953
+ const delta = isRecord$53(choice?.delta) ? choice.delta : void 0;
32698
32954
  if (delta) {
32699
32955
  for (const fragment of reasoningDialect.observeAll(delta)) {
32700
32956
  const text = sanitizeText$7(fragment.text);
@@ -32735,7 +32991,7 @@ function processOpenAIStreamLine(line, state) {
32735
32991
  }
32736
32992
  const toolDeltas = Array.isArray(delta.tool_calls) ? delta.tool_calls : [];
32737
32993
  for (const entry of toolDeltas) {
32738
- if (!isRecord$51(entry)) continue;
32994
+ if (!isRecord$53(entry)) continue;
32739
32995
  out.push(...applyOpenAIToolDelta(entry, state));
32740
32996
  }
32741
32997
  }
@@ -32749,7 +33005,7 @@ function processOpenAIStreamLine(line, state) {
32749
33005
  }
32750
33006
  function applyOpenAIToolDelta(entry, state) {
32751
33007
  const wireIndex = typeof entry.index === "number" ? entry.index : 0;
32752
- const fn = isRecord$51(entry.function) ? entry.function : {};
33008
+ const fn = isRecord$53(entry.function) ? entry.function : {};
32753
33009
  const out = [];
32754
33010
  let call = state.toolCalls.get(wireIndex);
32755
33011
  if (call === void 0) {
@@ -32804,12 +33060,12 @@ function processAnthropicStreamLine(line, state) {
32804
33060
  const payload = trimmed.slice(5).trim();
32805
33061
  if (payload === "" || payload === "[DONE]") return [];
32806
33062
  const event = safeJsonParse$7(payload);
32807
- if (!isRecord$51(event)) return [];
33063
+ if (!isRecord$53(event)) return [];
32808
33064
  const type = asString$21(event.type);
32809
33065
  const out = [];
32810
33066
  if (type === "message_start") {
32811
- const message = isRecord$51(event.message) ? event.message : void 0;
32812
- const usage = message && isRecord$51(message.usage) ? message.usage : void 0;
33067
+ const message = isRecord$53(event.message) ? event.message : void 0;
33068
+ const usage = message && isRecord$53(message.usage) ? message.usage : void 0;
32813
33069
  if (usage) {
32814
33070
  state.sawUsage = true;
32815
33071
  state.inputTokens = numberOr$8(usage.input_tokens, 0);
@@ -32823,7 +33079,7 @@ function processAnthropicStreamLine(line, state) {
32823
33079
  }
32824
33080
  if (type === "content_block_start") {
32825
33081
  const contentIndex = numberOr$8(event.index, 0);
32826
- const block = isRecord$51(event.content_block) ? event.content_block : {};
33082
+ const block = isRecord$53(event.content_block) ? event.content_block : {};
32827
33083
  const blockType = asString$21(block.type);
32828
33084
  out.push(...closeCurrent$5(state));
32829
33085
  if (blockType === "tool_use") {
@@ -32873,7 +33129,7 @@ function processAnthropicStreamLine(line, state) {
32873
33129
  }
32874
33130
  if (type === "content_block_delta") {
32875
33131
  const contentIndex = numberOr$8(event.index, 0);
32876
- const delta = isRecord$51(event.delta) ? event.delta : {};
33132
+ const delta = isRecord$53(event.delta) ? event.delta : {};
32877
33133
  const deltaType = asString$21(delta.type);
32878
33134
  if (deltaType === "input_json_delta") {
32879
33135
  const pending = state.toolCalls.get(contentIndex);
@@ -32946,10 +33202,10 @@ function processAnthropicStreamLine(line, state) {
32946
33202
  return out;
32947
33203
  }
32948
33204
  if (type === "message_delta") {
32949
- const delta = isRecord$51(event.delta) ? event.delta : void 0;
33205
+ const delta = isRecord$53(event.delta) ? event.delta : void 0;
32950
33206
  const stop = delta ? asString$21(delta.stop_reason) : void 0;
32951
33207
  if (stop !== void 0 && stop !== "") state.finishReason = stop;
32952
- const usage = isRecord$51(event.usage) ? event.usage : void 0;
33208
+ const usage = isRecord$53(event.usage) ? event.usage : void 0;
32953
33209
  if (usage) {
32954
33210
  state.sawUsage = true;
32955
33211
  state.outputTokens = numberOr$8(usage.output_tokens, state.outputTokens);
@@ -32961,7 +33217,7 @@ function processAnthropicStreamLine(line, state) {
32961
33217
  return closeStream$4(state);
32962
33218
  }
32963
33219
  if (type === "error") {
32964
- const error = isRecord$51(event.error) ? event.error : {};
33220
+ const error = isRecord$53(event.error) ? event.error : {};
32965
33221
  const message = asString$21(error.message) ?? "unknown error";
32966
33222
  state.streamError = {
32967
33223
  vocabulary: "anthropic",
@@ -33552,7 +33808,7 @@ var SessionCacheStateStore = class {
33552
33808
  /** Validate one parsed document, dropping entries that do not describe a record. */
33553
33809
  function normalizeDocument(value) {
33554
33810
  const sessions = {};
33555
- if (isRecord$50(value) && isRecord$50(value.sessions)) for (const [key, entry] of Object.entries(value.sessions)) {
33811
+ if (isRecord$52(value) && isRecord$52(value.sessions)) for (const [key, entry] of Object.entries(value.sessions)) {
33556
33812
  const record = normalizeRecord(entry);
33557
33813
  if (record !== void 0) sessions[key] = record;
33558
33814
  }
@@ -33562,7 +33818,7 @@ function normalizeDocument(value) {
33562
33818
  };
33563
33819
  }
33564
33820
  function normalizeRecord(value) {
33565
- if (!isRecord$50(value)) return void 0;
33821
+ if (!isRecord$52(value)) return void 0;
33566
33822
  const lastActiveAt = finite(value.lastActiveAt);
33567
33823
  const updatedAt = finite(value.updatedAt);
33568
33824
  if (lastActiveAt === void 0 || updatedAt === void 0) return void 0;
@@ -33650,7 +33906,7 @@ function resolveSessionCacheView(sessionId, memory, durable) {
33650
33906
  }
33651
33907
  /** The process-wide store the adapter writes and the routes read. */
33652
33908
  const sessionCacheState = new SessionCacheStateStore();
33653
- function isRecord$50(value) {
33909
+ function isRecord$52(value) {
33654
33910
  return typeof value === "object" && value !== null && !Array.isArray(value);
33655
33911
  }
33656
33912
  function finite(value) {
@@ -33820,9 +34076,9 @@ function bodyDigest(raw, token) {
33820
34076
  const text = raw.trim();
33821
34077
  if (text === "") return "";
33822
34078
  const parsed = parseJson(text);
33823
- if (parsed.ok && isRecord$49(parsed.value)) {
34079
+ if (parsed.ok && isRecord$51(parsed.value)) {
33824
34080
  const root = parsed.value;
33825
- const nested = isRecord$49(root.error) ? root.error : void 0;
34081
+ const nested = isRecord$51(root.error) ? root.error : void 0;
33826
34082
  const code = firstString(nested?.code) ?? firstString(root.code) ?? firstString(root.error_code) ?? "";
33827
34083
  const message = nested !== void 0 ? firstString(nested.message) ?? firstString(nested.code) ?? "" : typeof root.error === "string" ? root.error : firstString(root.message) ?? firstString(root.detail) ?? "";
33828
34084
  const composed = [code === "" ? "" : "code=" + code, message].filter((part) => part !== "").join(" ");
@@ -33858,7 +34114,7 @@ function normalizeFileId(value) {
33858
34114
  */
33859
34115
  function readFileId$1(value, depth = 0) {
33860
34116
  if (depth > 3) return void 0;
33861
- if (!isRecord$49(value)) return void 0;
34117
+ if (!isRecord$51(value)) return void 0;
33862
34118
  const direct = normalizeFileId(value.id);
33863
34119
  if (direct !== void 0) return direct;
33864
34120
  for (const key of NESTED_ID_KEYS) {
@@ -33905,7 +34161,7 @@ function mediaFileCacheKey(input) {
33905
34161
  contentSha256(input.data)
33906
34162
  ].join("|");
33907
34163
  }
33908
- function isRecord$49(value) {
34164
+ function isRecord$51(value) {
33909
34165
  return typeof value === "object" && value !== null && !Array.isArray(value);
33910
34166
  }
33911
34167
  function firstString(value) {
@@ -36692,7 +36948,7 @@ const KIMI_VIDEO_TOOL_NAME = "kimi_attach_video";
36692
36948
  * routed provider is this one, which is the same contract `read_image` states
36693
36949
  * for a modality the active model does not declare.
36694
36950
  */
36695
- const KIMI_CODE_PROVIDER$1 = "kimi-code";
36951
+ const KIMI_CODE_PROVIDER$2 = "kimi-code";
36696
36952
  /**
36697
36953
  * Refuse when the session's routed model cannot accept video.
36698
36954
  *
@@ -36706,7 +36962,7 @@ async function assertVideoCapableRoute(ctx, exec, source) {
36706
36962
  const provider = routed?.provider ?? agent?.options?.provider;
36707
36963
  const model = routed?.model ?? agent?.options?.model;
36708
36964
  if (provider === void 0 || model === void 0) throw new HarnessError(`cannot attach "${source}": the current model route could not be resolved`, "KIMI_VIDEO_ROUTE_UNRESOLVED");
36709
- if (provider !== KIMI_CODE_PROVIDER$1) throw new HarnessError(`cannot attach "${source}": video input is only wired for the ${KIMI_CODE_PROVIDER$1} provider, and this session is routed to "${provider}"`, "KIMI_VIDEO_WRONG_PROVIDER");
36965
+ if (provider !== KIMI_CODE_PROVIDER$2) throw new HarnessError(`cannot attach "${source}": video input is only wired for the ${KIMI_CODE_PROVIDER$2} provider, and this session is routed to "${provider}"`, "KIMI_VIDEO_WRONG_PROVIDER");
36710
36966
  const llm = ctx.get("llm");
36711
36967
  if (llm === void 0) throw new HarnessError(`cannot attach "${source}": the LLM service is unavailable`, "KIMI_VIDEO_NO_LLM");
36712
36968
  const active = await llm.resolveModelInfo(provider, model, exec.signal);
@@ -37015,6 +37271,18 @@ const MESSAGES_PATH$1 = "/messages";
37015
37271
  /** Anthropic protocol revision the endpoint documents. */
37016
37272
  const ANTHROPIC_VERSION$2 = "2023-06-01";
37017
37273
  /**
37274
+ * Beta marker the interleaved-thinking protocol needs.
37275
+ *
37276
+ * The Messages endpoint on this route accepts signed `thinking` blocks and
37277
+ * streams reasoning back in its own channel, and the Anthropic dialect gates
37278
+ * that on the interleaved-thinking beta. The official MiniMax agent sends the
37279
+ * marker on every Messages request (its `model-resolver-helpers.ts`), so a
37280
+ * request without it is shaped differently from the one the service is
37281
+ * documented against - and the replay path on this line has signed thinking
37282
+ * blocks to send.
37283
+ */
37284
+ const ANTHROPIC_INTERLEAVED_THINKING_BETA = "interleaved-thinking-2025-05-14";
37285
+ /**
37018
37286
  * Byte ceiling the guard enforces on one request body.
37019
37287
  *
37020
37288
  * WHY THIS IS NOT KIMI'S 2 MB FIGURE
@@ -37103,13 +37371,34 @@ function maxRequestImageBytes(env = process.env) {
37103
37371
  /**
37104
37372
  * Product token this plugin reports.
37105
37373
  *
37106
- * MiniMax Code's own telemetry headers are deliberately NOT forged: this is a
37107
- * third-party client of the subscription, and claiming to be the official app is
37108
- * both dishonest and, per the app's own terms, grounds for suspending the
37109
- * subscription.
37374
+ * This is the plugin's own identity, and it stays honest. MiniMax Code's own
37375
+ * telemetry headers are deliberately NOT forged: this is a third-party client of
37376
+ * the subscription, and claiming to be the official app is both dishonest and,
37377
+ * per the app's own terms, grounds for suspending the subscription.
37378
+ *
37379
+ * The surfaces that carry this token are exactly the first-party ones (the
37380
+ * check-in call, the reset-card call, the usage read), and those are the ones
37381
+ * that must be able to say who is asking. The MODEL request carries
37382
+ * {@link MINIMAX_AGENT_USER_AGENT} instead - a different surface, a different
37383
+ * identifier.
37110
37384
  */
37111
37385
  const USER_AGENT$3 = "dsh-chatgpt-subscription (+https://github.com/Aa728848/dsh-chatgpt-subscription)";
37112
37386
  /**
37387
+ * Client identifier the managed agent's MODEL requests carry.
37388
+ *
37389
+ * The managed agent classifies a model request by this header, and the official
37390
+ * MiniMax agent sends exactly this value (`model-resolver-helpers.ts:11`, and
37391
+ * the same identifier the Matrix media face uses). A model request that names
37392
+ * something else is shaped differently from the one the service is documented
37393
+ * against - and the model request is the surface that has to speak the
37394
+ * protocol's own identifier.
37395
+ *
37396
+ * It is a separate constant from {@link USER_AGENT} on purpose: the first-party
37397
+ * surfaces keep identifying this plugin honestly, and only the model request
37398
+ * speaks as the agent the endpoint expects.
37399
+ */
37400
+ const MINIMAX_AGENT_USER_AGENT = "MiniMaxAgent";
37401
+ /**
37113
37402
  * How long before expiry a token is replaced.
37114
37403
  *
37115
37404
  * The measured MiniMax Code access token lives ONE HOUR, not the day an earlier
@@ -37238,6 +37527,937 @@ function computeMinimaxAuthOwner(credentials, accountId) {
37238
37527
  return hash.digest("hex").slice(0, 32);
37239
37528
  }
37240
37529
  //#endregion
37530
+ //#region src/host/minimax-code/runtime-enhancements.ts
37531
+ /** 本模块只对 MiniMax Code 这条线路生效。 */
37532
+ const MINIMAX_CODE_PROVIDER$1 = "minimax-code";
37533
+ /**
37534
+ * 判断一个值是不是普通对象(原型是 `Object.prototype` 或 `null`)。
37535
+ * @param value - 任意值。
37536
+ * @returns 是普通对象时为 true。
37537
+ */
37538
+ function isPlainRecord$1(value) {
37539
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
37540
+ const prototype = Object.getPrototypeOf(value);
37541
+ return prototype === Object.prototype || prototype === null;
37542
+ }
37543
+ /**
37544
+ * 判断一个值是不是普通对象(不要求原型,数组也算对象)。
37545
+ * @param value - 任意值。
37546
+ * @returns 是对象时为 true。
37547
+ */
37548
+ function isRecord$50(value) {
37549
+ return typeof value === "object" && value !== null;
37550
+ }
37551
+ /**
37552
+ * 读一个未知字段为非空字符串。
37553
+ * @param value - 候选值。
37554
+ * @returns 字符串,或任何其它类型的 undefined。
37555
+ */
37556
+ function stringOf$4(value) {
37557
+ return typeof value === "string" && value !== "" ? value : void 0;
37558
+ }
37559
+ /**
37560
+ * 读一次工具调用所属的线路。
37561
+ *
37562
+ * provider 的四个来源按可靠性排序:**请求头快照**(唯一反映「已经真的路由到
37563
+ * 哪个 provider」的那一份)→ **模型选择面**(首步还没有请求头时唯一还能说出
37564
+ * 这一场走哪条线路的地方)→ **agent 选项**(还没发出请求时唯一的意图)→
37565
+ * **agent 自身的 provider 字段**(最后的兜底)。
37566
+ *
37567
+ * 每一处读取都独立 try/catch:任何一处抛错都只是「这一处读不到」,不改变
37568
+ * 其余来源的行为,也不让整次读取失败。
37569
+ *
37570
+ * @param agent - 事件里的调用方 agent。
37571
+ * @returns 线路信息;读不到的字段省略。
37572
+ */
37573
+ function minimaxSessionRouteOf(agent) {
37574
+ const record = isRecord$50(agent) ? agent : void 0;
37575
+ const session = record?.session;
37576
+ let provider;
37577
+ try {
37578
+ provider = stringOf$4(session?.requestHeader?.()?.config?.provider);
37579
+ } catch {
37580
+ provider = void 0;
37581
+ }
37582
+ if (provider === void 0) try {
37583
+ provider = stringOf$4(record?.model?.current?.()?.provider);
37584
+ } catch {
37585
+ provider = void 0;
37586
+ }
37587
+ if (provider === void 0) provider = stringOf$4(record?.options?.provider);
37588
+ if (provider === void 0) provider = stringOf$4(record?.provider);
37589
+ const sessionId = stringOf$4(session?.header?.id) ?? stringOf$4(record?.id);
37590
+ return {
37591
+ ...provider === void 0 ? {} : { provider },
37592
+ ...sessionId === void 0 ? {} : { sessionId }
37593
+ };
37594
+ }
37595
+ /**
37596
+ * 判断一次工具调用是不是 MiniMax Code 这条线路上的。
37597
+ * @param agent - 事件里的调用方 agent。
37598
+ * @returns 是 MiniMax Code 时为 true。
37599
+ */
37600
+ function isMinimaxSession(agent) {
37601
+ return minimaxSessionRouteOf(agent).provider === MINIMAX_CODE_PROVIDER$1;
37602
+ }
37603
+ /** 无损的数字字符串:允许小数、指数、前导负号。 */
37604
+ const NUMERIC_STRING = /^-?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/u;
37605
+ /**
37606
+ * 顶层已知的数字字段(没有 schema 时按字段名强转)。
37607
+ *
37608
+ * 这些是本宿主工具面里**本来就该是数字**的字段:模型把它们写成字符串时,
37609
+ * schema 校验会直接失败,而它们强转回来是**无损**的。
37610
+ */
37611
+ const NUMERIC_TOOL_FIELDS = Object.freeze([
37612
+ "offset",
37613
+ "limit",
37614
+ "timeout",
37615
+ "timeoutMs",
37616
+ "timeout_ms",
37617
+ "line",
37618
+ "delta_x",
37619
+ "delta_y",
37620
+ "x",
37621
+ "y",
37622
+ "ref"
37623
+ ]);
37624
+ /**
37625
+ * 顶层已知的布尔字段(没有 schema 时按字段名强转)。
37626
+ *
37627
+ * 只有字面 `"true"` / `"false"` 才转:别的写法(`"1"`、`"yes"`)在布尔
37628
+ * 字段上是**有歧义**的,转过去等于替模型猜了一个开关的状态。
37629
+ */
37630
+ const BOOLEAN_TOOL_FIELDS = Object.freeze([
37631
+ "replace_all",
37632
+ "wait",
37633
+ "run_in_background",
37634
+ "new_tab",
37635
+ "multi_select"
37636
+ ]);
37637
+ /**
37638
+ * 按 schema 强转一个值,并把强转过程记进 `fixes`。
37639
+ *
37640
+ * 只认三种形状:
37641
+ *
37642
+ * - `type: 'array'`:值是单键对象 `{ item: X }` 时拆包(官方 Pi 的
37643
+ * `item_wrapper` 形状),然后按 `items` 递归每个元素;
37644
+ * - `type: 'number' | 'integer'`:值是**无损**数字字符串时转成数字
37645
+ * (`integer` 还要求转出来确实是整数,`"2.5"` 不转);
37646
+ * - `type: 'boolean'`:值是 `"true"` / `"false"` 时转成布尔。
37647
+ *
37648
+ * @param value - 当前值。
37649
+ * @param schema - 这一层的 JSON Schema。
37650
+ * @param fixes - 修复项累加器。
37651
+ * @returns 强转后的值。
37652
+ */
37653
+ function coerceBySchema(value, schema, fixes) {
37654
+ if (!isRecord$50(schema)) return value;
37655
+ const type = schema["type"];
37656
+ if (type === "array") {
37657
+ let current = value;
37658
+ if (isPlainRecord$1(current) && Object.keys(current).length === 1 && "item" in current) {
37659
+ const inner = current["item"];
37660
+ current = Array.isArray(inner) ? [...inner] : [inner];
37661
+ fixes.push("item_wrapper");
37662
+ }
37663
+ const items = schema["items"];
37664
+ if (Array.isArray(current) && items !== void 0) current = current.map((entry) => coerceBySchema(entry, items, fixes));
37665
+ return current;
37666
+ }
37667
+ if (type === "number" || type === "integer") {
37668
+ if (typeof value === "string" && NUMERIC_STRING.test(value)) {
37669
+ const parsed = Number(value);
37670
+ if (Number.isFinite(parsed) && (type !== "integer" || Number.isInteger(parsed))) {
37671
+ fixes.push("number_string");
37672
+ return parsed;
37673
+ }
37674
+ }
37675
+ return value;
37676
+ }
37677
+ if (type === "boolean") {
37678
+ if (value === "true") {
37679
+ fixes.push("boolean_string");
37680
+ return true;
37681
+ }
37682
+ if (value === "false") {
37683
+ fixes.push("boolean_string");
37684
+ return false;
37685
+ }
37686
+ return value;
37687
+ }
37688
+ if (type === "object") {
37689
+ const properties = schema["properties"];
37690
+ if (!isPlainRecord$1(value) || !isRecord$50(properties)) return value;
37691
+ const next = { ...value };
37692
+ for (const [key, subSchema] of Object.entries(properties)) {
37693
+ if (!(key in next)) continue;
37694
+ next[key] = coerceBySchema(next[key], subSchema, fixes);
37695
+ }
37696
+ return next;
37697
+ }
37698
+ const properties = schema["properties"];
37699
+ if (isPlainRecord$1(value) && isRecord$50(properties)) {
37700
+ const next = { ...value };
37701
+ for (const [key, subSchema] of Object.entries(properties)) {
37702
+ if (!(key in next)) continue;
37703
+ next[key] = coerceBySchema(next[key], subSchema, fixes);
37704
+ }
37705
+ return next;
37706
+ }
37707
+ const items = schema["items"];
37708
+ if (Array.isArray(value) && items !== void 0) return value.map((entry) => coerceBySchema(entry, items, fixes));
37709
+ return value;
37710
+ }
37711
+ /**
37712
+ * 没有 schema 时按字段名做的顶层强转。
37713
+ *
37714
+ * 只动**顶层**的已知字段:嵌套结构没有 schema 就没有依据,猜不得。
37715
+ * @param args - 参数副本。
37716
+ * @param fixes - 修复项累加器。
37717
+ */
37718
+ function coerceByKnownFields(args, fixes) {
37719
+ for (const field of NUMERIC_TOOL_FIELDS) {
37720
+ const current = args[field];
37721
+ if (typeof current !== "string" || !NUMERIC_STRING.test(current)) continue;
37722
+ const parsed = Number(current);
37723
+ if (!Number.isFinite(parsed)) continue;
37724
+ args[field] = parsed;
37725
+ fixes.push("number_string");
37726
+ }
37727
+ for (const field of BOOLEAN_TOOL_FIELDS) {
37728
+ const current = args[field];
37729
+ if (current === "true") {
37730
+ args[field] = true;
37731
+ fixes.push("boolean_string");
37732
+ } else if (current === "false") {
37733
+ args[field] = false;
37734
+ fixes.push("boolean_string");
37735
+ }
37736
+ }
37737
+ }
37738
+ /**
37739
+ * 修复一次工具调用的参数。
37740
+ *
37741
+ * 三步,顺序固定:
37742
+ *
37743
+ * 1. **`edits` 字符串解析**(官方 `edit-prepare-arguments.ts`):`edits` 是
37744
+ * JSON 字符串时解析回数组。解析失败就**原样留着**,让 schema 校验照常报错
37745
+ * ——在这里猜一个数组比不猜更糟。
37746
+ * 2. **按 schema 强转**(官方 `direct-call-arguments.ts` / `input-validation.ts`):
37747
+ * `item_wrapper` 拆包、数字字符串转数字、布尔字符串转布尔,并递归进
37748
+ * `properties` 与 `items`。
37749
+ * 3. **按字段名强转**:**没有传 schema** 时才做,因为那时唯一的依据就是字段名。
37750
+ *
37751
+ * 入参**不被修改**:返回值是一份新对象。
37752
+ *
37753
+ * @param toolName - 工具名(只用于日志与将来按工具定制规则)。
37754
+ * @param args - 原始参数。
37755
+ * @param schema - 该工具的 JSON Schema(参数面),可选。
37756
+ * @returns 修复后的参数与修复项列表。
37757
+ */
37758
+ function repairMinimaxToolArguments(toolName, args, schema) {
37759
+ if (!isPlainRecord$1(args)) return {
37760
+ value: args,
37761
+ fixes: []
37762
+ };
37763
+ const fixes = [];
37764
+ const working = { ...args };
37765
+ if (typeof working["edits"] === "string") {
37766
+ const parsed = tryParseJson(working["edits"]);
37767
+ if (Array.isArray(parsed)) {
37768
+ working["edits"] = parsed;
37769
+ fixes.push("edits_json_string");
37770
+ }
37771
+ }
37772
+ if (schema !== void 0) {
37773
+ const coerced = coerceBySchema(working, schema, fixes);
37774
+ if (isPlainRecord$1(coerced)) Object.assign(working, coerced);
37775
+ } else coerceByKnownFields(working, fixes);
37776
+ return {
37777
+ value: working,
37778
+ fixes
37779
+ };
37780
+ }
37781
+ /**
37782
+ * 解析一段 JSON,失败时返回 undefined(不抛)。
37783
+ * @param text - 待解析的文本。
37784
+ * @returns 解析结果,或 undefined。
37785
+ */
37786
+ function tryParseJson(text) {
37787
+ try {
37788
+ return JSON.parse(text);
37789
+ } catch {
37790
+ return;
37791
+ }
37792
+ }
37793
+ /**
37794
+ * 直接调用需要提醒的工具名。
37795
+ *
37796
+ * 这些是**原生**工具:在 PTC 模式里模型只能直接调 `run_code`,原生工具要
37797
+ * 从 `run_code` 程序里调。
37798
+ */
37799
+ const DIRECT_CALL_REMINDER_TOOLS = Object.freeze([
37800
+ "read",
37801
+ "edit",
37802
+ "write",
37803
+ "grep",
37804
+ "glob",
37805
+ "win_bash",
37806
+ "bash",
37807
+ "pwsh"
37808
+ ]);
37809
+ /**
37810
+ * 各个原生工具在 `run_code` 里的调用示例参数。
37811
+ *
37812
+ * 例子必须**真的能跑**:提醒里给一个跑不通的示例,比不给示例更糟。
37813
+ */
37814
+ const DIRECT_CALL_EXAMPLE_ARGS = Object.freeze({
37815
+ read: "{ file_path: \"README.md\" }",
37816
+ write: "{ file_path: \"README.md\", content: \"...\" }",
37817
+ edit: "{ file_path: \"README.md\", old_string: \"...\", new_string: \"...\" }",
37818
+ grep: "{ pattern: \"TODO\", path: \".\" }",
37819
+ glob: "{ pattern: \"src/**/*.ts\" }",
37820
+ bash: "{ command: \"ls -la\" }",
37821
+ win_bash: "{ command: \"ls -la\" }",
37822
+ pwsh: "{ command: \"Get-ChildItem\" }"
37823
+ });
37824
+ /**
37825
+ * 造一条 `run_code` 调用示例。
37826
+ * @param toolName - 工具名。
37827
+ * @returns 一句可读的调用示例。
37828
+ */
37829
+ function directCallExampleOf(toolName) {
37830
+ return `await tools.${toolName}(${DIRECT_CALL_EXAMPLE_ARGS[toolName] ?? "{ ... }"})`;
37831
+ }
37832
+ /**
37833
+ * 渲染 PTC 直调提醒。
37834
+ *
37835
+ * 文案与官方 `direct-call-reminder.ts` 同形:
37836
+ *
37837
+ * ```text
37838
+ * <system-reminder>
37839
+ * Do not call read directly in this turn. Call it inside run_code: await tools.read({ file_path: "README.md" }). Put your next tool calls in one run_code program.
37840
+ * </system-reminder>
37841
+ * ```
37842
+ *
37843
+ * @param toolNames - 被直接调用的工具名。
37844
+ * @returns 提醒正文。
37845
+ */
37846
+ function renderDirectCallReminder(toolNames) {
37847
+ const names = [...new Set(toolNames.filter((name) => name !== ""))];
37848
+ if (names.length === 0) return [
37849
+ "<system-reminder>",
37850
+ "Do not call tools directly in this turn. Call them inside run_code. Put your next tool calls in one run_code program.",
37851
+ "</system-reminder>"
37852
+ ].join("\n");
37853
+ return [
37854
+ "<system-reminder>",
37855
+ `Do not call ${names.join(", ")} directly in this turn. Call ${names.length === 1 ? "it" : "them"} inside run_code: ${names.slice(0, 2).map((name) => directCallExampleOf(name)).join("; ")}. Put your next tool calls in one run_code program.`,
37856
+ "</system-reminder>"
37857
+ ].join("\n");
37858
+ }
37859
+ /**
37860
+ * 官方提醒文案的后缀:提醒只对当前这一轮有效。
37861
+ * @returns 后缀正文。
37862
+ */
37863
+ const TURN_ONLY_SUFFIX = " This is a temporary runtime reminder for the current Turn only, not a user preference or a durable rule; do not save this reminder or generalize it into Memory, Skills, or other persistent instruction files for future Turns or sessions.";
37864
+ /**
37865
+ * 渲染「同一个动作立刻重复」提醒。
37866
+ *
37867
+ * 与官方 `packages/agent-modules/runaway-guard/src/reminder.ts` 逐字一致。
37868
+ * @param occurrences - 连击次数。
37869
+ * @returns 提醒正文。
37870
+ */
37871
+ function renderExactActionRepeatReminder(occurrences) {
37872
+ return `[runaway guard] The immediately repeated tool action has now occurred ${occurrences} times with the same arguments. Do not repeat it unchanged. Inspect the results already available, then either change strategy with a concrete expected state change, or report the blocker. Repetition alone does not establish that the task is complete or impossible.${TURN_ONLY_SUFFIX}`;
37873
+ }
37874
+ /**
37875
+ * 渲染「同一族错误连续发生」提醒。
37876
+ *
37877
+ * 与官方 `packages/agent-modules/runaway-guard/src/reminder.ts` 逐字一致。
37878
+ * @param occurrences - 连击次数。
37879
+ * @returns 提醒正文。
37880
+ */
37881
+ function renderSameErrorFamilyReminder(occurrences) {
37882
+ return `[runaway guard] The same tool error family has now occurred ${occurrences} times in a row. Do not retry the same route unchanged. Diagnose the cause, change one controlled variable or switch route. Do not infer that the entire task has failed from this signal.${TURN_ONLY_SUFFIX}`;
37883
+ }
37884
+ /**
37885
+ * 渲染「反复轮询同一个后台任务」提醒。
37886
+ *
37887
+ * 与官方 `packages/agent-modules/runaway-guard/src/reminder.ts` 逐字一致:
37888
+ * 三次读同一个任务时写的是 `Three`,其它次数写数字。
37889
+ * @param occurrences - 连击次数。
37890
+ * @returns 提醒正文。
37891
+ */
37892
+ function renderPollingRepeatReminder(occurrences) {
37893
+ return [
37894
+ "<system-reminder>",
37895
+ `${occurrences === 3 ? "Three" : String(occurrences)} task_output reads for the same task have returned an unchanged status and output cursor. Avoid repeated polling; you will be notified automatically and this conversation will resume when the background task completes.`,
37896
+ "This reminder applies only to the current Turn. Do not save or generalize it into Memory, Skills, or other persistent instructions.",
37897
+ "</system-reminder>"
37898
+ ].join("\n");
37899
+ }
37900
+ /**
37901
+ * 轮询类工具名(后台任务的结果读取)。
37902
+ *
37903
+ * 这两个工具读的是后台任务的状态;反复读同一个任务而输出没变,就是官方说的
37904
+ * 「polling repeat」。
37905
+ */
37906
+ const POLLING_TOOL_NAMES = Object.freeze(["job_output", "task_output"]);
37907
+ /**
37908
+ * 规范化一段错误文本,取它的「族」。
37909
+ *
37910
+ * 族的作用是**把同一类错误认成同一类**:路径里的数字、id、时间戳都不该让
37911
+ * 两次一模一样的失败看起来是两回事。
37912
+ * @param text - 错误文本。
37913
+ * @returns 族标识。
37914
+ */
37915
+ function errorFamilyOf(text) {
37916
+ if (text === void 0 || text === "") return "unknown";
37917
+ return (text.split(/\r?\n/, 1)[0] ?? "").replace(/\d+/g, "#").slice(0, 200);
37918
+ }
37919
+ /**
37920
+ * 把参数规范化成可比较的字符串(键排序)。
37921
+ * @param value - 参数值。
37922
+ * @returns 规范化后的 JSON 文本。
37923
+ */
37924
+ function canonicalize(value) {
37925
+ return JSON.stringify(sortJsonValue$1(value));
37926
+ }
37927
+ /**
37928
+ * 深拷贝一份键排序后的 JSON 值。
37929
+ * @param value - 任意值。
37930
+ * @returns 排序后的副本。
37931
+ */
37932
+ function sortJsonValue$1(value) {
37933
+ if (Array.isArray(value)) return value.map(sortJsonValue$1);
37934
+ if (isPlainRecord$1(value)) {
37935
+ const sorted = {};
37936
+ for (const key of Object.keys(value).sort()) sorted[key] = sortJsonValue$1(value[key]);
37937
+ return sorted;
37938
+ }
37939
+ return value;
37940
+ }
37941
+ /**
37942
+ * 造一台工具级失控守卫。
37943
+ *
37944
+ * 三种可提醒信号(顺序即官方提醒优先级):
37945
+ *
37946
+ * 1. `same_error_family` —— 同一个工具连续报同一族错误;
37947
+ * 2. `exact_action_repeat` —— 同一次动作(同名 + 同参数)立刻重复;
37948
+ * 3. `polling_repeat` —— 连续轮询同一个后台任务而输出没变。
37949
+ *
37950
+ * `abab_action_cycle`(A B A B 的循环)**只记录不提醒**:官方把它排在提醒
37951
+ * 候选之外——模型在两个动作之间来回跳时,提醒它「别重复」是没有意义的。
37952
+ *
37953
+ * 每轮**至多一条**提醒:官方在发出第一条后就把本轮的提醒机会用掉了。
37954
+ *
37955
+ * @param options - 守卫选项。
37956
+ * @returns 守卫。
37957
+ */
37958
+ function createMinimaxRunawayGuard(options = {}) {
37959
+ const threshold = options.remindAfterOccurrences ?? 3;
37960
+ /** 同一次动作的连击。 */
37961
+ let actionStreak;
37962
+ /** 同一族错误的连击(键是工具名 + 错误族)。 */
37963
+ const errorStreaks = /* @__PURE__ */ new Map();
37964
+ /** 轮询连击(键是工具名)。 */
37965
+ const pollingStreaks = /* @__PURE__ */ new Map();
37966
+ /** 最近几次动作,用来认 A B A B 的循环。 */
37967
+ const recentActions = [];
37968
+ /** 当前正在计数的 A B 循环对。 */
37969
+ let activeAbabKey;
37970
+ /** 本轮是否已经提醒过。 */
37971
+ let reminderAttempted = false;
37972
+ /** 观察到的信号。 */
37973
+ const signals = [];
37974
+ /**
37975
+ * 记一条信号。
37976
+ * @param kind - 信号种类。
37977
+ * @param occurrences - 连击次数。
37978
+ * @param toolName - 工具名。
37979
+ */
37980
+ const record = (kind, occurrences, toolName) => {
37981
+ signals.push({
37982
+ kind,
37983
+ occurrences,
37984
+ toolName
37985
+ });
37986
+ };
37987
+ /**
37988
+ * 判断这次执行是不是一次「原地不动」的轮询。
37989
+ * @param observation - 观察事实。
37990
+ * @returns 是轮询时为 true。
37991
+ */
37992
+ const isPolling = (observation) => {
37993
+ if (!POLLING_TOOL_NAMES.includes(observation.toolName)) return false;
37994
+ return (isPlainRecord$1(observation.arguments) ? observation.arguments : void 0)?.["wait"] !== true;
37995
+ };
37996
+ return {
37997
+ observe(observation) {
37998
+ const toolName = observation.toolName;
37999
+ const actionKey = `${toolName}\u0000${canonicalize(observation.arguments)}`;
38000
+ const countsAsAction = !POLLING_TOOL_NAMES.includes(toolName);
38001
+ if (countsAsAction) {
38002
+ if (actionStreak?.key === actionKey) actionStreak = {
38003
+ key: actionKey,
38004
+ count: actionStreak.count + 1
38005
+ };
38006
+ else actionStreak = {
38007
+ key: actionKey,
38008
+ count: 1
38009
+ };
38010
+ record("exact_action_repeat", actionStreak.count, toolName);
38011
+ }
38012
+ if (countsAsAction) {
38013
+ recentActions.push(actionKey);
38014
+ if (recentActions.length > 4) recentActions.shift();
38015
+ if (recentActions.length === 4) {
38016
+ const [a, b, c, d] = recentActions;
38017
+ if (a !== void 0 && b !== void 0 && a !== b && a === c && b === d) {
38018
+ const episode = `${a}\u0000${b}`;
38019
+ if (activeAbabKey !== episode) {
38020
+ activeAbabKey = episode;
38021
+ record("abab_action_cycle", 2, toolName);
38022
+ }
38023
+ } else activeAbabKey = void 0;
38024
+ }
38025
+ }
38026
+ if (observation.isError === true) {
38027
+ const key = `${toolName}\u0000${observation.errorCode ?? errorFamilyOf(observation.errorText)}`;
38028
+ const previous = errorStreaks.get(key);
38029
+ const count = previous === void 0 ? 1 : previous.count + 1;
38030
+ errorStreaks.set(key, {
38031
+ toolName,
38032
+ count
38033
+ });
38034
+ record("same_error_family", count, toolName);
38035
+ } else for (const [key, entry] of [...errorStreaks]) if (entry.toolName === toolName) errorStreaks.delete(key);
38036
+ if (isPolling(observation)) {
38037
+ const key = `${toolName}\u0000${canonicalize(observation.arguments)}\u0000${observation.resultText ?? ""}`;
38038
+ const previous = pollingStreaks.get(toolName);
38039
+ const count = previous !== void 0 && previous.key === key ? previous.count + 1 : 1;
38040
+ pollingStreaks.set(toolName, {
38041
+ key,
38042
+ count
38043
+ });
38044
+ record("polling_repeat", count, toolName);
38045
+ } else pollingStreaks.delete(toolName);
38046
+ if (reminderAttempted) return void 0;
38047
+ const errorCandidate = [...errorStreaks.values()].find((entry) => entry.count >= threshold);
38048
+ if (errorCandidate !== void 0) {
38049
+ reminderAttempted = true;
38050
+ return {
38051
+ kind: "same_error_family",
38052
+ occurrences: errorCandidate.count,
38053
+ text: renderSameErrorFamilyReminder(errorCandidate.count)
38054
+ };
38055
+ }
38056
+ if (countsAsAction && actionStreak !== void 0 && actionStreak.count >= threshold) {
38057
+ reminderAttempted = true;
38058
+ return {
38059
+ kind: "exact_action_repeat",
38060
+ occurrences: actionStreak.count,
38061
+ text: renderExactActionRepeatReminder(actionStreak.count)
38062
+ };
38063
+ }
38064
+ const pollingCandidate = [...pollingStreaks.values()].find((entry) => entry.count >= threshold);
38065
+ if (pollingCandidate !== void 0) {
38066
+ reminderAttempted = true;
38067
+ return {
38068
+ kind: "polling_repeat",
38069
+ occurrences: pollingCandidate.count,
38070
+ text: renderPollingRepeatReminder(pollingCandidate.count)
38071
+ };
38072
+ }
38073
+ },
38074
+ reset() {
38075
+ actionStreak = void 0;
38076
+ errorStreaks.clear();
38077
+ pollingStreaks.clear();
38078
+ recentActions.length = 0;
38079
+ activeAbabKey = void 0;
38080
+ reminderAttempted = false;
38081
+ },
38082
+ get signals() {
38083
+ return signals;
38084
+ }
38085
+ };
38086
+ }
38087
+ /**
38088
+ * 读宿主上下文上的工具注册面。
38089
+ * @param ctx - 宿主上下文。
38090
+ * @returns 工具注册面;没有时为 undefined。
38091
+ */
38092
+ function toolsServiceOf$1(ctx) {
38093
+ const read = ctx.get;
38094
+ if (typeof read === "function") try {
38095
+ const found = read.call(ctx, "tools");
38096
+ if (found !== void 0) return found;
38097
+ } catch {}
38098
+ const direct = ctx.tools;
38099
+ return direct === void 0 ? void 0 : direct;
38100
+ }
38101
+ /**
38102
+ * 判断一个会话是不是处于 PTC 模式(模型只能直接调 `run_code`)。
38103
+ *
38104
+ * 三个来源,按可靠性排序:
38105
+ *
38106
+ * 1. **注册表自己的判定面**(结构探测 `modeFor`):这是宿主真正用来决定
38107
+ * 「这个作用域是 native 还是 ptc」的那一个函数,读到的就是事实。
38108
+ * 2. **保留通道的可见性**(公开 API `get('run_code', scope)`):`run_code` 这条
38109
+ * 传输通道只对 PTC 作用域可见,所以「能不能查到它」就是同一个问题的公开问法。
38110
+ * 3. **agent 自己声明的呈现模式**:宿主选项里直接写了 `ptc` 时的兜底。
38111
+ *
38112
+ * 读不出来时**当作不是 PTC**:提醒是加法,不是减法,宁可少提醒也不要在
38113
+ * native 会话里催模型去用 `run_code`。
38114
+ *
38115
+ * @param agent - 调用方 agent。
38116
+ * @param tools - 工具注册面。
38117
+ * @returns 处于 PTC 模式时为 true。
38118
+ */
38119
+ function isPtcSessionOf(agent, tools) {
38120
+ const mode = declaredModeOf(tools, agent);
38121
+ if (mode !== void 0) return mode;
38122
+ if (runCodeTransportVisible(tools, agent) === true) return true;
38123
+ return declaredPresentationOf(agent) === "ptc";
38124
+ }
38125
+ /**
38126
+ * 读注册表自己的呈现模式判定面。
38127
+ * @param tools - 工具注册面。
38128
+ * @param agent - 调用方 agent。
38129
+ * @returns true/false 表示读到了;undefined 表示这一代宿主没有这条接缝。
38130
+ */
38131
+ function declaredModeOf(tools, agent) {
38132
+ const modeFor = (isRecord$50(tools) ? tools : void 0)?.modeFor;
38133
+ if (typeof modeFor !== "function") return void 0;
38134
+ try {
38135
+ const mode = modeFor.call(tools, agent);
38136
+ if (mode === "ptc") return true;
38137
+ if (mode === "native") return false;
38138
+ } catch {}
38139
+ }
38140
+ /**
38141
+ * 看 `run_code` 这条保留通道对这个作用域是否可见。
38142
+ * @param tools - 工具注册面。
38143
+ * @param agent - 调用方 agent。
38144
+ * @returns true/false 表示读到了;undefined 表示这一代宿主没有这条接缝。
38145
+ */
38146
+ function runCodeTransportVisible(tools, agent) {
38147
+ const get = (isRecord$50(tools) ? tools : void 0)?.get;
38148
+ if (typeof get !== "function") return void 0;
38149
+ try {
38150
+ return get.call(tools, "run_code", agent) !== void 0;
38151
+ } catch {
38152
+ return;
38153
+ }
38154
+ }
38155
+ /**
38156
+ * 读 agent 自己声明的呈现模式。
38157
+ * @param agent - 调用方 agent。
38158
+ * @returns 'ptc' / 'native' / undefined。
38159
+ */
38160
+ function declaredPresentationOf(agent) {
38161
+ const record = isRecord$50(agent) ? agent : void 0;
38162
+ const options = isRecord$50(record?.["options"]) ? record?.["options"] : void 0;
38163
+ const agentOptions = isRecord$50(record?.["agentOptions"]) ? record?.["agentOptions"] : void 0;
38164
+ const preset = isRecord$50(record?.["preset"]) ? record?.["preset"] : void 0;
38165
+ const candidates = [
38166
+ options?.["presentation"],
38167
+ options?.["toolPresentation"],
38168
+ options?.["toolsMode"],
38169
+ options?.["mode"],
38170
+ agentOptions?.["presentation"],
38171
+ preset?.["presentation"]
38172
+ ];
38173
+ for (const candidate of candidates) {
38174
+ if (candidate === "ptc") return "ptc";
38175
+ if (candidate === "native") return "native";
38176
+ }
38177
+ }
38178
+ /**
38179
+ * 判断一次工具执行是不是「模型直接调了原生工具」。
38180
+ *
38181
+ * 直接调用的判据是**没有父调用**:嵌套调用(`run_code` 程序里的子调用)带
38182
+ * 父标记,直接调用不带。DSH 用 `parent` 这枚不透明令牌,官方 minimax-code
38183
+ * 用 `parentToolCallId`,两个都认。
38184
+ *
38185
+ * @param exec - 工具执行。
38186
+ * @returns 直接调用时为 true。
38187
+ */
38188
+ function isDirectToolCall(exec) {
38189
+ const record = isRecord$50(exec) ? exec : void 0;
38190
+ if (record?.["parent"] !== void 0) return false;
38191
+ if (record?.["parentToolCallId"] !== void 0) return false;
38192
+ return true;
38193
+ }
38194
+ /**
38195
+ * 读一次执行是不是「模型直接调了需要提醒的原生工具」。
38196
+ * @param exec - 工具执行。
38197
+ * @returns 工具名;不是这类调用时为 undefined。
38198
+ */
38199
+ function directCallToolNameOf(exec) {
38200
+ const name = stringOf$4((isRecord$50(exec) ? exec : void 0)?.["name"]);
38201
+ if (name === void 0 || !DIRECT_CALL_REMINDER_TOOLS.includes(name)) return void 0;
38202
+ if (!isDirectToolCall(exec)) return void 0;
38203
+ return name;
38204
+ }
38205
+ /**
38206
+ * 把一条 post-execute 决策接上附加上下文,保住它原有的形状。
38207
+ * @param decision - `next()` 交回来的决策。
38208
+ * @param contexts - 要追加的上下文。
38209
+ * @returns 追加后的决策。
38210
+ */
38211
+ function withAdditionalContexts$1(decision, contexts) {
38212
+ const additionalContexts = [...decision.additionalContexts ?? [], ...contexts];
38213
+ if (decision.kind === "block") return {
38214
+ kind: "block",
38215
+ feedback: decision.feedback,
38216
+ additionalContexts
38217
+ };
38218
+ if (decision.value !== void 0) return {
38219
+ kind: "accept",
38220
+ value: decision.value,
38221
+ additionalContexts
38222
+ };
38223
+ if (decision.content !== void 0) return {
38224
+ kind: "accept",
38225
+ content: decision.content,
38226
+ additionalContexts
38227
+ };
38228
+ return {
38229
+ kind: "accept",
38230
+ additionalContexts
38231
+ };
38232
+ }
38233
+ /**
38234
+ * 造一条 PTC 直调提醒上下文。
38235
+ * @param toolName - 被直接调用的工具名。
38236
+ * @returns 可直接放进 `additionalContexts` 的用户角色消息。
38237
+ */
38238
+ function createDirectCallReminder(toolName) {
38239
+ return createUserMessage({
38240
+ content: [{
38241
+ type: "text",
38242
+ text: renderDirectCallReminder([toolName])
38243
+ }],
38244
+ source: {
38245
+ kind: "minimax-direct-call-reminder",
38246
+ form: "notice",
38247
+ summary: `PTC direct call: ${toolName}`
38248
+ }
38249
+ });
38250
+ }
38251
+ /**
38252
+ * 造一条失控守卫提醒上下文。
38253
+ * @param reminder - 提醒。
38254
+ * @returns 可直接放进 `additionalContexts` 的用户角色消息。
38255
+ */
38256
+ function createRunawayReminder(reminder) {
38257
+ return createUserMessage({
38258
+ content: [{
38259
+ type: "text",
38260
+ text: reminder.text
38261
+ }],
38262
+ source: {
38263
+ kind: "minimax-runaway-guard",
38264
+ form: "notice",
38265
+ summary: `runaway guard: ${reminder.kind} x${reminder.occurrences}`
38266
+ }
38267
+ });
38268
+ }
38269
+ /**
38270
+ * 读一次执行的结果是不是失败。
38271
+ * @param result - 工具执行结果。
38272
+ * @returns 失败时为 true。
38273
+ */
38274
+ function isErrorResult(result) {
38275
+ return isRecord$50(result) && result["isError"] === true;
38276
+ }
38277
+ /**
38278
+ * 读一次执行的结构化错误码。
38279
+ * @param result - 工具执行结果。
38280
+ * @returns 错误码;没有时为 undefined。
38281
+ */
38282
+ function errorCodeOf$1(result) {
38283
+ if (!isRecord$50(result)) return void 0;
38284
+ const error = result["error"];
38285
+ if (!isRecord$50(error)) return void 0;
38286
+ const info = error["info"];
38287
+ if (!isRecord$50(info)) return void 0;
38288
+ return stringOf$4(info["code"]);
38289
+ }
38290
+ /**
38291
+ * 读一次执行的失败文本。
38292
+ * @param result - 工具执行结果。
38293
+ * @returns 失败文本;没有时为 undefined。
38294
+ */
38295
+ function errorTextOf(result) {
38296
+ if (!isRecord$50(result)) return void 0;
38297
+ const error = result["error"];
38298
+ if (!isRecord$50(error)) return void 0;
38299
+ return stringOf$4(error["message"]);
38300
+ }
38301
+ /**
38302
+ * 读一次执行的结果文本(轮询判定用)。
38303
+ * @param result - 工具执行结果。
38304
+ * @returns 结果文本;没有时是空串。
38305
+ */
38306
+ function resultTextOf(result) {
38307
+ if (!isRecord$50(result)) return "";
38308
+ const content = result["content"];
38309
+ if (!Array.isArray(content)) return "";
38310
+ const parts = [];
38311
+ for (const block of content) if (isRecord$50(block) && block["type"] === "text") parts.push(stringOf$4(block["text"]) ?? "");
38312
+ return parts.join("\n");
38313
+ }
38314
+ /**
38315
+ * 找一次工具调用的参数 schema。
38316
+ * @param tools - 工具注册面。
38317
+ * @param name - 工具名。
38318
+ * @param agent - 调用方 agent。
38319
+ * @returns JSON Schema;找不到时为 undefined。
38320
+ */
38321
+ function schemaOf(tools, name, agent) {
38322
+ const get = tools?.get;
38323
+ if (typeof get !== "function") return void 0;
38324
+ try {
38325
+ const definition = get.call(tools, name, agent);
38326
+ if (!isRecord$50(definition)) return void 0;
38327
+ return definition["parameters"];
38328
+ } catch {
38329
+ return;
38330
+ }
38331
+ }
38332
+ /**
38333
+ * 就地把一次执行的参数改成修复后的形状。
38334
+ *
38335
+ * **尽力而为**:新一代宿主把执行参数**冻结**了(`deepFreeze`),写回会抛,
38336
+ * 于是这次修复在那一代上落不了地 —— 但函数本身不抛,调用方也拿不到错误。
38337
+ * 老一代宿主不冻结参数时,写回是真正生效的。
38338
+ *
38339
+ * @param execution - 工具执行。
38340
+ * @param tools - 工具注册面。
38341
+ */
38342
+ function repairExecutionArguments(execution, tools) {
38343
+ const record = isRecord$50(execution) ? execution : void 0;
38344
+ const args = record?.["arguments"];
38345
+ if (!isPlainRecord$1(args)) return;
38346
+ const name = stringOf$4(record?.["name"]);
38347
+ if (name === void 0) return;
38348
+ const agent = record?.["agent"];
38349
+ const repaired = repairMinimaxToolArguments(name, args, schemaOf(tools, name, agent));
38350
+ if (repaired.fixes.length === 0) return;
38351
+ const target = repaired.value;
38352
+ if (!isPlainRecord$1(target)) return;
38353
+ try {
38354
+ for (const key of Object.keys(args)) if (!(key in target)) delete args[key];
38355
+ Object.assign(args, target);
38356
+ } catch {}
38357
+ }
38358
+ /**
38359
+ * 装上 MiniMax Code 的运行时增强。
38360
+ *
38361
+ * @param ctx - 宿主插件上下文。
38362
+ * @param options - 增强选项。
38363
+ * @returns 卸载函数。
38364
+ */
38365
+ function installMinimaxRuntimeEnhancements(ctx, options = {}) {
38366
+ /** 登记一个副作用;上下文没有 effect 时立即执行(测试用假上下文)。 */
38367
+ const track = (execute, label) => {
38368
+ if (typeof ctx.effect === "function") ctx.effect(execute, label);
38369
+ else execute();
38370
+ };
38371
+ const tools = toolsServiceOf$1(ctx);
38372
+ /** 每个 agent 一台守卫:连击是**这个会话**的事。 */
38373
+ const guards = /* @__PURE__ */ new WeakMap();
38374
+ /**
38375
+ * 没有 agent 的执行(有人绕过 agent-loop 直接调 `ctx.tools.execute`)共用这一台。
38376
+ *
38377
+ * 它是**一台**,不是每次新建:连击要跨调用累积,新建一台等于永远停在第一次。
38378
+ */
38379
+ const agentlessGuard = createMinimaxRunawayGuard(options);
38380
+ /**
38381
+ * 取一个 agent 的守卫。
38382
+ * @param agent - 调用方 agent。
38383
+ * @returns 守卫。
38384
+ */
38385
+ const guardOf = (agent) => {
38386
+ const key = isRecord$50(agent) ? agent : void 0;
38387
+ if (key === void 0) return agentlessGuard;
38388
+ const existing = guards.get(key);
38389
+ if (existing !== void 0) return existing;
38390
+ const created = createMinimaxRunawayGuard(options);
38391
+ guards.set(key, created);
38392
+ return created;
38393
+ };
38394
+ track(() => {
38395
+ if (typeof tools?.guard !== "function") return () => void 0;
38396
+ const dispose = tools.guard((execution) => {
38397
+ try {
38398
+ if (!isMinimaxSession(isRecord$50(execution) ? execution["agent"] : void 0)) return void 0;
38399
+ repairExecutionArguments(execution, tools);
38400
+ } catch {}
38401
+ });
38402
+ return () => {
38403
+ dispose?.();
38404
+ };
38405
+ }, "dsh-chatgpt-subscription: minimax argument repair guard");
38406
+ const disposePreExecute = ctx.on?.("tools/pre-execute", (async (exec, next) => {
38407
+ try {
38408
+ if (isMinimaxSession(exec.agent)) repairExecutionArguments(exec, tools);
38409
+ } catch {}
38410
+ return next();
38411
+ }));
38412
+ const disposePostExecute = ctx.on?.("tools/post-execute", (async (exec, result, next) => {
38413
+ const decision = await next();
38414
+ try {
38415
+ const agent = exec.agent;
38416
+ if (!isMinimaxSession(agent)) return decision;
38417
+ const contexts = [];
38418
+ const directName = directCallToolNameOf(exec);
38419
+ if (directName !== void 0 && isPtcSessionOf(agent, tools)) contexts.push(createDirectCallReminder(directName));
38420
+ const reminder = guardOf(agent).observe({
38421
+ toolName: exec.name,
38422
+ arguments: exec.arguments,
38423
+ isError: isErrorResult(result),
38424
+ errorCode: errorCodeOf$1(result),
38425
+ errorText: errorTextOf(result),
38426
+ resultText: resultTextOf(result)
38427
+ });
38428
+ if (reminder !== void 0) contexts.push(createRunawayReminder(reminder));
38429
+ if (contexts.length === 0) return decision;
38430
+ return withAdditionalContexts$1(decision, contexts);
38431
+ } catch {
38432
+ return decision;
38433
+ }
38434
+ }));
38435
+ const disposePreStep = ctx.on?.("agent/pre-step", (async (payload, next) => {
38436
+ const decision = await next();
38437
+ try {
38438
+ if (!(Array.isArray(payload?.messages) ? payload.messages : []).some((message) => {
38439
+ const source = isRecord$50(message) ? message["source"] : void 0;
38440
+ return isRecord$50(source) && source["kind"] === "user";
38441
+ })) return decision;
38442
+ const agent = payload?.agent;
38443
+ if (isRecord$50(agent)) guards.get(agent)?.reset();
38444
+ } catch {
38445
+ return decision;
38446
+ }
38447
+ return decision;
38448
+ }));
38449
+ const disposeDisposed = ctx.on?.("agent/disposed", ((payload) => {
38450
+ const agent = payload?.agent;
38451
+ if (isRecord$50(agent)) guards.delete(agent);
38452
+ }));
38453
+ return () => {
38454
+ disposePreExecute?.();
38455
+ disposePostExecute?.();
38456
+ disposePreStep?.();
38457
+ disposeDisposed?.();
38458
+ };
38459
+ }
38460
+ //#endregion
37241
38461
  //#region src/host/minimax-code/modalities.ts
37242
38462
  /**
37243
38463
  * MiniMax Code's video vocabulary.
@@ -37334,7 +38554,7 @@ function videoOmissionText(reason, label) {
37334
38554
  * a caller that opts out (MinimaxRequestOptions.cacheControl === false) gets
37335
38555
  * the original string body byte-for-byte.
37336
38556
  */
37337
- function isRecord$48(value) {
38557
+ function isRecord$49(value) {
37338
38558
  return typeof value === "object" && value !== null && !Array.isArray(value);
37339
38559
  }
37340
38560
  function asString$20(value) {
@@ -37387,7 +38607,7 @@ const SUPPORTED_IMAGE_MEDIA_TYPES$2 = /* @__PURE__ */ new Set([
37387
38607
  ]);
37388
38608
  function attachmentOf$2(block) {
37389
38609
  const attachment = block.attachment;
37390
- return isRecord$48(attachment) ? attachment : void 0;
38610
+ return isRecord$49(attachment) ? attachment : void 0;
37391
38611
  }
37392
38612
  function attachmentLabel$2(block) {
37393
38613
  const attachment = attachmentOf$2(block);
@@ -37423,7 +38643,7 @@ function textOf$6(content) {
37423
38643
  if (!Array.isArray(content)) return "";
37424
38644
  const parts = [];
37425
38645
  for (const block of content) {
37426
- if (!isRecord$48(block)) continue;
38646
+ if (!isRecord$49(block)) continue;
37427
38647
  if (block.type === "text" && typeof block.text === "string") parts.push(sanitizeText$6(block.text));
37428
38648
  else if (block.type === "tool-result") parts.push(textOf$6(block.content));
37429
38649
  }
@@ -37432,7 +38652,7 @@ function textOf$6(content) {
37432
38652
  function toolResultText$6(blocks) {
37433
38653
  if (!Array.isArray(blocks)) return "";
37434
38654
  return blocks.map((block) => {
37435
- if (!isRecord$48(block)) return "";
38655
+ if (!isRecord$49(block)) return "";
37436
38656
  if (block.type === "text" && typeof block.text === "string") return sanitizeText$6(block.text);
37437
38657
  if (block.type === "tool-result") return toolResultText$6(block.content);
37438
38658
  if (block.type === "image") return "[image: " + (attachmentLabel$2(block) ?? "attached image") + "]";
@@ -37451,7 +38671,7 @@ function toolResultBlocks(blocks, images) {
37451
38671
  const out = [];
37452
38672
  let hasImage = false;
37453
38673
  for (const block of blocks) {
37454
- if (!isRecord$48(block)) continue;
38674
+ if (!isRecord$49(block)) continue;
37455
38675
  if (block.type === "text" && typeof block.text === "string") {
37456
38676
  out.push({
37457
38677
  type: "text",
@@ -37502,12 +38722,31 @@ function isToolResultMessage$6(message) {
37502
38722
  return message.source?.kind === "tool";
37503
38723
  }
37504
38724
  /**
38725
+ * The rule a tool-enabled session must follow before it calls a tool.
38726
+ *
38727
+ * The official agent states it in the system prompt of every session that has
38728
+ * tools: a non-trivial tool step starts with a user-visible assistant text
38729
+ * block. Thinking does not count - a model that reasons and then calls the tool
38730
+ * without saying anything has produced a step the user cannot see, and the
38731
+ * official agent asks for that preamble explicitly.
38732
+ *
38733
+ * It is appended to the assembled system text rather than replacing it: the
38734
+ * caller's own prompt keeps its place at the head (which is the cached prefix),
38735
+ * and this rule lands after it.
38736
+ */
38737
+ const TOOL_CALL_PREAMBLE_REMINDER = "For any non-trivial tool-call step, you MUST first send a non-empty, user-visible assistant text block. Thinking or reasoning content does not count as the preamble.";
38738
+ /**
37505
38739
  * Concatenated system-prompt text.
37506
38740
  *
37507
38741
  * The system prompt is the head of the prefix the service caches, so this is a
37508
38742
  * pure, order-stable fold of its inputs: options.system always leads and message
37509
38743
  * text follows in history order. Nothing per-turn is added here, because one
37510
38744
  * changed byte at the head invalidates the whole cached prefix.
38745
+ *
38746
+ * The ONE addition is {@link TOOL_CALL_PREAMBLE_REMINDER}, and it is added only
38747
+ * to a session that has both tools and a system prompt - a request with no tools
38748
+ * has no tool-call step to remind the model about, and a request with no system
38749
+ * text at all keeps `system === undefined` rather than gaining one.
37511
38750
  */
37512
38751
  function leadingSystemText$6(options) {
37513
38752
  const parts = [];
@@ -37517,7 +38756,11 @@ function leadingSystemText$6(options) {
37517
38756
  const text = textOf$6(message.content);
37518
38757
  if (text !== "") parts.push(text);
37519
38758
  }
37520
- return parts.length === 0 ? void 0 : parts.join("\n\n");
38759
+ if (parts.length === 0) return void 0;
38760
+ if (options.tools && options.tools.length > 0) {
38761
+ if (!parts.join("\n\n").includes("For any non-trivial tool-call step, you MUST first send a non-empty, user-visible assistant text block. Thinking or reasoning content does not count as the preamble.")) parts.push(TOOL_CALL_PREAMBLE_REMINDER);
38762
+ }
38763
+ return parts.join("\n\n");
37521
38764
  }
37522
38765
  function nonSystemMessages$6(options) {
37523
38766
  return options.messages.filter((message) => message.role !== "system");
@@ -37536,7 +38779,7 @@ function anthropicUserContent$1(message, images, videos, videoAccepted) {
37536
38779
  if (!Array.isArray(message.content)) return [];
37537
38780
  const blocks = [];
37538
38781
  for (const block of message.content) {
37539
- if (!isRecord$48(block)) continue;
38782
+ if (!isRecord$49(block)) continue;
37540
38783
  if (block.type === "text" && typeof block.text === "string") {
37541
38784
  const text = sanitizeText$6(block.text);
37542
38785
  if (text !== "") blocks.push({
@@ -37606,7 +38849,7 @@ function anthropicUserContent$1(message, images, videos, videoAccepted) {
37606
38849
  function computeVisibleContentHash(blocks) {
37607
38850
  if (!Array.isArray(blocks)) return "";
37608
38851
  const canonical = blocks.map((b) => {
37609
- if (!isRecord$48(b)) return null;
38852
+ if (!isRecord$49(b)) return null;
37610
38853
  const type = asString$20(b.type) ?? "";
37611
38854
  if (type === "text" || type === "reasoning") return [type, sanitizeText$6(asString$20(b.text) ?? "")];
37612
38855
  if (type === "tool-call") return [
@@ -37628,12 +38871,12 @@ function computeVisibleContentHash(blocks) {
37628
38871
  */
37629
38872
  function replayedThinkingBlock$1(message, index, expectedScope, block) {
37630
38873
  const source = message.source;
37631
- if (source === void 0 || source === null || !isRecord$48(source)) return void 0;
38874
+ if (source === void 0 || source === null || !isRecord$49(source)) return void 0;
37632
38875
  if (source.provider && source.provider !== PROVIDER_ID$8 && source.provider !== "dsh-chatgpt-subscription") return;
37633
38876
  if (source.model && expectedScope && source.model !== expectedScope.model) return;
37634
38877
  const state = source.replayState;
37635
- if (!isRecord$48(state)) return void 0;
37636
- const resp = isRecord$48(state.response) ? state.response : state;
38878
+ if (!isRecord$49(state)) return void 0;
38879
+ const resp = isRecord$49(state.response) ? state.response : state;
37637
38880
  const stateRoute = asString$20(resp.route) ?? asString$20(resp.provider);
37638
38881
  const stateModel = asString$20(resp.model);
37639
38882
  const stateAuthOwner = asString$20(resp.authOwner);
@@ -37641,19 +38884,19 @@ function replayedThinkingBlock$1(message, index, expectedScope, block) {
37641
38884
  if (expectedScope === void 0) return void 0;
37642
38885
  if (expectedScope.route && stateRoute !== expectedScope.route) return void 0;
37643
38886
  if (expectedScope.model && stateModel !== expectedScope.model) return void 0;
37644
- if (!expectedScope.authOwner || expectedScope.authOwner.trim() === "" || stateAuthOwner !== expectedScope.authOwner) return;
38887
+ if (!expectedScope.authOwner || expectedScope.authOwner.trim() === "") return void 0;
37645
38888
  let candidate;
37646
38889
  if (Array.isArray(state.blocks)) {
37647
38890
  const entry = state.blocks[index];
37648
- if (isRecord$48(entry)) candidate = entry;
38891
+ if (isRecord$49(entry)) candidate = entry;
37649
38892
  }
37650
38893
  if (candidate === void 0 && Array.isArray(resp.blocks)) {
37651
38894
  const entry = resp.blocks[index];
37652
- if (isRecord$48(entry)) candidate = entry;
38895
+ if (isRecord$49(entry)) candidate = entry;
37653
38896
  }
37654
38897
  if (candidate === void 0 && Array.isArray(resp.nativeBlocks)) {
37655
38898
  const entry = resp.nativeBlocks[index];
37656
- if (isRecord$48(entry)) candidate = entry;
38899
+ if (isRecord$49(entry)) candidate = entry;
37657
38900
  }
37658
38901
  if (candidate === void 0) return void 0;
37659
38902
  if (Array.isArray(state.blocks) && state.blocks.length !== message.content.length) return void 0;
@@ -37679,7 +38922,7 @@ function anthropicAssistantContent$1(message, expectedScope) {
37679
38922
  if (!Array.isArray(message.content)) return blocks;
37680
38923
  for (let index = 0; index < message.content.length; index++) {
37681
38924
  const block = message.content[index];
37682
- if (!isRecord$48(block)) continue;
38925
+ if (!isRecord$49(block)) continue;
37683
38926
  if (block.type === "text" && typeof block.text === "string") {
37684
38927
  const text = sanitizeText$6(block.text);
37685
38928
  if (text !== "") blocks.push({
@@ -37694,13 +38937,22 @@ function anthropicAssistantContent$1(message, expectedScope) {
37694
38937
  type: "tool_use",
37695
38938
  id: asString$20(block.id) ?? "toolu_" + blocks.length,
37696
38939
  name: block.name,
37697
- input: isRecord$48(parsed) ? parsed : {}
38940
+ input: isRecord$49(parsed) ? parsed : {}
37698
38941
  });
37699
38942
  continue;
37700
38943
  }
37701
38944
  if (block.type === "reasoning") {
37702
38945
  const replay = replayedThinkingBlock$1(message, index, expectedScope, block);
37703
- if (replay !== void 0) blocks.push(replay);
38946
+ if (replay !== void 0) {
38947
+ blocks.push(replay);
38948
+ continue;
38949
+ }
38950
+ const fallbackText = sanitizeText$6(typeof block.text === "string" ? block.text : "");
38951
+ const trimmed = fallbackText.trim();
38952
+ if (trimmed !== "" && trimmed !== "[Reasoning redacted]") blocks.push({
38953
+ type: "text",
38954
+ text: fallbackText
38955
+ });
37704
38956
  continue;
37705
38957
  }
37706
38958
  }
@@ -37777,15 +39029,17 @@ function thinkingFieldFor(modelId, requestedEffort) {
37777
39029
  * The level belongs at the TOP level - `output_config.effort` - and accepts
37778
39030
  * low, medium, high, xhigh and max. There is no `default` member: the page
37779
39031
  * says omitting the field means max, so the old local `default` spelling never
37780
- * reached the wire. This line no longer leans on that: every model that has
37781
- * levels states its default out loud, and a request that asks for nothing
37782
- * resolves to that default instead of to an omission.
39032
+ * reached the wire. This line no longer leans on that either: every model that
39033
+ * has levels states its default as NULL, so a request that asks for nothing
39034
+ * resolves to no `output_config` at all - which is what the official agent
39035
+ * sends when the conversation picked no level.
37783
39036
  *
37784
39037
  * The level is the DEPTH, not the channel: measured, low and max differ by
37785
39038
  * about 3x thinking and 4x latency, and it composes with the `thinking` object.
37786
39039
  *
37787
39040
  * @returns the value for `output_config`, or undefined when the request should
37788
- * carry no thinking control at all.
39041
+ * carry no thinking control at all - which is the case for an unset, empty or
39042
+ * unknown level.
37789
39043
  */
37790
39044
  function outputConfigFor(modelId, requestedEffort) {
37791
39045
  const model = catalogEntry$2(modelId);
@@ -37927,7 +39181,8 @@ function buildMinimaxRequest(options, images = NO_RESOLVED_IMAGES$2, request = {
37927
39181
  const requestedEffort = options.reasoningEffort === void 0 ? null : String(options.reasoningEffort);
37928
39182
  const outputConfig = outputConfigFor(options.model, requestedEffort);
37929
39183
  const thinking = thinkingFieldFor(options.model, requestedEffort);
37930
- const thinkingEngaged = outputConfig !== void 0 || thinking?.type === "adaptive";
39184
+ const modelDef = catalogEntry$2(options.model);
39185
+ const thinkingEngaged = outputConfig !== void 0 || thinking?.type === "adaptive" || modelDef?.thinking === "always-on" || modelDef?.thinking === "forced-effort";
37931
39186
  const caching = request.cacheControl !== false;
37932
39187
  const body = {
37933
39188
  model: options.model,
@@ -37943,6 +39198,7 @@ function buildMinimaxRequest(options, images = NO_RESOLVED_IMAGES$2, request = {
37943
39198
  ...options.tools && options.tools.length > 0 ? { tools: options.tools.map((tool) => ({
37944
39199
  name: tool.name,
37945
39200
  description: tool.description,
39201
+ eager_input_streaming: true,
37946
39202
  input_schema: stripMetaSchema$1(tool.parameters)
37947
39203
  })) } : {},
37948
39204
  ...thinking === void 0 ? {} : { thinking },
@@ -37979,6 +39235,7 @@ function createStreamState(options) {
37979
39235
  authOwner: options.authOwner,
37980
39236
  provider: options.provider ?? PROVIDER_ID$8
37981
39237
  } : void 0,
39238
+ toolSchemas: options?.tools && options.tools.length > 0 ? new Map(options.tools.map((tool) => [tool.name, tool.parameters])) : void 0,
37982
39239
  replayBlocks: [],
37983
39240
  pendingThinking: /* @__PURE__ */ new Map(),
37984
39241
  blocks: [],
@@ -38032,6 +39289,27 @@ function openTextBlock$4(state, type) {
38032
39289
  });
38033
39290
  return out;
38034
39291
  }
39292
+ /**
39293
+ * The argument string one finished tool call carries.
39294
+ *
39295
+ * The model writes tool arguments in shapes the schema does not accept: numbers
39296
+ * as strings, an `edits` array as a JSON string, an array wrapped in
39297
+ * `{"item": [...]}`. DSH's tool guard then refuses the call over a shape the
39298
+ * model had no way to know was wrong, so the arguments are repaired here - at
39299
+ * the end of the stream, where the whole argument string is finally known.
39300
+ *
39301
+ * The repair is LOSSLESS, and it only runs when it changes something:
39302
+ * arguments that need no repair come out byte-for-byte as they arrived, and
39303
+ * arguments that do not parse as an object are left exactly as they were.
39304
+ */
39305
+ function finalizeToolCallArguments(name, rawArguments, toolSchemas) {
39306
+ if (rawArguments === "") return "{}";
39307
+ const parsed = safeJsonParse$6(rawArguments);
39308
+ if (!isRecord$49(parsed)) return rawArguments;
39309
+ const repaired = repairMinimaxToolArguments(name, parsed, toolSchemas?.get(name));
39310
+ if (repaired.fixes.length === 0) return rawArguments;
39311
+ return JSON.stringify(repaired.value);
39312
+ }
38035
39313
  function closeToolCalls$4(state) {
38036
39314
  const out = [];
38037
39315
  for (const [wireIndex, call] of [...state.toolCalls.entries()].sort((a, b) => a[0] - b[0])) {
@@ -38039,7 +39317,7 @@ function closeToolCalls$4(state) {
38039
39317
  type: "tool-call",
38040
39318
  id: toToolCallId(call.id),
38041
39319
  name: call.name,
38042
- arguments: call.arguments === "" ? "{}" : call.arguments
39320
+ arguments: finalizeToolCallArguments(call.name, call.arguments, state.toolSchemas)
38043
39321
  };
38044
39322
  state.blocks[call.blockIndex] = block;
38045
39323
  state.replayBlocks[call.blockIndex] = null;
@@ -38152,12 +39430,12 @@ function processMinimaxStreamLine(line, state) {
38152
39430
  const payload = trimmed.slice(5).trim();
38153
39431
  if (payload === "" || payload === "[DONE]") return [];
38154
39432
  const event = safeJsonParse$6(payload);
38155
- if (!isRecord$48(event)) return [];
39433
+ if (!isRecord$49(event)) return [];
38156
39434
  const type = asString$20(event.type);
38157
39435
  const out = [];
38158
39436
  if (type === "message_start") {
38159
- const message = isRecord$48(event.message) ? event.message : void 0;
38160
- const usage = message !== void 0 && isRecord$48(message.usage) ? message.usage : void 0;
39437
+ const message = isRecord$49(event.message) ? event.message : void 0;
39438
+ const usage = message !== void 0 && isRecord$49(message.usage) ? message.usage : void 0;
38161
39439
  if (usage !== void 0) {
38162
39440
  state.sawUsage = true;
38163
39441
  state.inputTokens = numberOr$7(usage.input_tokens, 0);
@@ -38173,7 +39451,7 @@ function processMinimaxStreamLine(line, state) {
38173
39451
  }
38174
39452
  if (type === "content_block_start") {
38175
39453
  const contentIndex = numberOr$7(event.index, 0);
38176
- const block = isRecord$48(event.content_block) ? event.content_block : {};
39454
+ const block = isRecord$49(event.content_block) ? event.content_block : {};
38177
39455
  const blockType = asString$20(block.type);
38178
39456
  out.push(...closeCurrent$4(state));
38179
39457
  if (blockType === "tool_use") {
@@ -38224,7 +39502,7 @@ function processMinimaxStreamLine(line, state) {
38224
39502
  type: "reasoning",
38225
39503
  text: state.current.text
38226
39504
  });
38227
- const initialReplay = isRecord$48(event.content_block) ? structuredClone(event.content_block) : { type: blockType };
39505
+ const initialReplay = isRecord$49(event.content_block) ? structuredClone(event.content_block) : { type: blockType };
38228
39506
  state.replayBlocks[index] = initialReplay;
38229
39507
  state.pendingThinking.set(contentIndex, {
38230
39508
  dshIndex: index,
@@ -38252,7 +39530,7 @@ function processMinimaxStreamLine(line, state) {
38252
39530
  }
38253
39531
  if (type === "content_block_delta") {
38254
39532
  const contentIndex = numberOr$7(event.index, 0);
38255
- const delta = isRecord$48(event.delta) ? event.delta : {};
39533
+ const delta = isRecord$49(event.delta) ? event.delta : {};
38256
39534
  const deltaType = asString$20(delta.type);
38257
39535
  if (deltaType === "input_json_delta") {
38258
39536
  const pending = state.toolCalls.get(contentIndex);
@@ -38341,7 +39619,7 @@ function processMinimaxStreamLine(line, state) {
38341
39619
  type: "tool-call",
38342
39620
  id: toToolCallId(pending.id),
38343
39621
  name: pending.name,
38344
- arguments: pending.arguments === "" ? "{}" : pending.arguments
39622
+ arguments: finalizeToolCallArguments(pending.name, pending.arguments, state.toolSchemas)
38345
39623
  };
38346
39624
  state.blocks[pending.blockIndex] = block;
38347
39625
  out.push({
@@ -38355,10 +39633,10 @@ function processMinimaxStreamLine(line, state) {
38355
39633
  return out;
38356
39634
  }
38357
39635
  if (type === "message_delta") {
38358
- const delta = isRecord$48(event.delta) ? event.delta : void 0;
39636
+ const delta = isRecord$49(event.delta) ? event.delta : void 0;
38359
39637
  const stop = delta === void 0 ? void 0 : asString$20(delta.stop_reason);
38360
39638
  if (stop !== void 0 && stop !== "") state.finishReason = stop;
38361
- const usage = isRecord$48(event.usage) ? event.usage : void 0;
39639
+ const usage = isRecord$49(event.usage) ? event.usage : void 0;
38362
39640
  if (usage !== void 0) {
38363
39641
  state.sawUsage = true;
38364
39642
  state.inputTokens = numberOr$7(usage.input_tokens, state.inputTokens);
@@ -38373,7 +39651,7 @@ function processMinimaxStreamLine(line, state) {
38373
39651
  return closeMinimaxStream(state);
38374
39652
  }
38375
39653
  if (type === "error") {
38376
- const error = isRecord$48(event.error) ? event.error : {};
39654
+ const error = isRecord$49(event.error) ? event.error : {};
38377
39655
  state.streamError = error;
38378
39656
  throw new LlmError$1("MiniMax Code(编程订阅) stream error: " + (asString$20(error.message) ?? "unknown error"), isContextOverflow(error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
38379
39657
  }
@@ -38446,7 +39724,7 @@ const MINIMAX_CODE_MODELS = [
38446
39724
  "xhigh",
38447
39725
  "max"
38448
39726
  ],
38449
- defaultReasoningEffort: "max",
39727
+ defaultReasoningEffort: null,
38450
39728
  maxAttachments: 9,
38451
39729
  maxImageBytes: 10 * 1024 * 1024,
38452
39730
  maxVideoBytes: 50 * 1024 * 1024,
@@ -38472,7 +39750,7 @@ const MINIMAX_CODE_MODELS = [
38472
39750
  "xhigh",
38473
39751
  "max"
38474
39752
  ],
38475
- defaultReasoningEffort: "max",
39753
+ defaultReasoningEffort: null,
38476
39754
  maxAttachments: 4,
38477
39755
  maxImageBytes: 10 * 1024 * 1024,
38478
39756
  maxVideoBytes: 50 * 1024 * 1024,
@@ -38539,14 +39817,22 @@ function isThinkingDisabledEffort(value) {
38539
39817
  /**
38540
39818
  * The effort level to put on the wire for one model.
38541
39819
  *
38542
- * An unknown or off value falls back to the model's documented default, so a
38543
- * caller cannot talk this route into a level the model does not list.
39820
+ * NULL means "this request carries no `output_config.effort`", which is what
39821
+ * the official agent sends when the conversation picked no level. Every model in
39822
+ * this catalog states null as its default, so a request that names no effort
39823
+ * states no effort.
39824
+ *
39825
+ * An unknown value falls back to the model's documented default, so a caller
39826
+ * cannot talk this route into a level the model does not list - and with that
39827
+ * default being null, an unknown level now means no level rather than the most
39828
+ * expensive one.
38544
39829
  */
38545
39830
  function effortForModel(modelId, requested) {
38546
39831
  const model = minimaxCodeModelDef(modelId);
38547
39832
  if (model === void 0) return null;
38548
39833
  if (model.reasoningEfforts.length === 0) return null;
38549
- if (requested === void 0 || requested === null) return model.defaultReasoningEffort;
39834
+ if (isThinkingDisabledEffort(requested)) return null;
39835
+ if (requested === void 0 || requested === null || requested.trim() === "") return model.defaultReasoningEffort;
38550
39836
  const normalized = requested.trim().toLowerCase();
38551
39837
  return model.reasoningEfforts.find((effort) => effort === normalized) ?? model.defaultReasoningEffort;
38552
39838
  }
@@ -38676,7 +39962,7 @@ function authStateJsonPath(region, buildEnv = MINIMAX_CODE_BUILD_ENV) {
38676
39962
  function pluginCredentialPath() {
38677
39963
  return path.join(dshHomeDir(), "storages", "minimax-code-credentials.json");
38678
39964
  }
38679
- function isRecord$47(value) {
39965
+ function isRecord$48(value) {
38680
39966
  return typeof value === "object" && value !== null && !Array.isArray(value);
38681
39967
  }
38682
39968
  function asString$19(value) {
@@ -38698,7 +39984,7 @@ function asFiniteNumber$4(value) {
38698
39984
  * exists to prevent.
38699
39985
  */
38700
39986
  function parseMinimaxCodeCredentials(value, fallback) {
38701
- if (!isRecord$47(value)) throw new Error("MiniMax Code credential payload is invalid");
39987
+ if (!isRecord$48(value)) throw new Error("MiniMax Code credential payload is invalid");
38702
39988
  const accessToken = asString$19(value.accessToken);
38703
39989
  if (accessToken === void 0) throw new Error("MiniMax Code credential is missing its access token");
38704
39990
  const refreshToken = asString$19(value.refreshToken);
@@ -38984,10 +40270,10 @@ async function readNativeDocument(region) {
38984
40270
  } catch {
38985
40271
  return null;
38986
40272
  }
38987
- if (!isRecord$47(parsed) || !isRecord$47(parsed.records)) return null;
40273
+ if (!isRecord$48(parsed) || !isRecord$48(parsed.records)) return null;
38988
40274
  const records = parsed.records;
38989
40275
  for (const [recordKey, entry] of Object.entries(records)) {
38990
- if (!isRecord$47(entry)) continue;
40276
+ if (!isRecord$48(entry)) continue;
38991
40277
  if (asString$19(entry.clientId) !== "mcode-public") continue;
38992
40278
  if (asString$19(entry.accessToken) === void 0) continue;
38993
40279
  return {
@@ -39015,7 +40301,7 @@ async function syncAuthState(region, options) {
39015
40301
  } catch {
39016
40302
  return;
39017
40303
  }
39018
- if (!isRecord$47(parsed)) return;
40304
+ if (!isRecord$48(parsed)) return;
39019
40305
  const next = {
39020
40306
  ...parsed,
39021
40307
  generation: options.generation,
@@ -39938,14 +41224,25 @@ function withTimeout$8(signal, ms) {
39938
41224
  *
39939
41225
  * The token itself never appears in a log line or an error: callers that need to
39940
41226
  * name a credential do so through `redactToken`.
41227
+ *
41228
+ * @param context the session identity the managed agent expects on a request
41229
+ * that belongs to a session: the session id, the agent id inside it, and the
41230
+ * caller's timezone offset. They are sent only when there IS a session — a
41231
+ * request without one carries none of them.
39941
41232
  */
39942
- function modelRequestHeaders(accessToken) {
41233
+ function modelRequestHeaders(accessToken, context) {
39943
41234
  return {
39944
41235
  authorization: "Bearer " + accessToken,
39945
41236
  "anthropic-version": ANTHROPIC_VERSION$2,
41237
+ "anthropic-beta": ANTHROPIC_INTERLEAVED_THINKING_BETA,
39946
41238
  "content-type": "application/json",
39947
41239
  accept: "text/event-stream",
39948
- "user-agent": USER_AGENT$3
41240
+ "user-agent": MINIMAX_AGENT_USER_AGENT,
41241
+ ...context?.sessionId ? {
41242
+ "x-mavis-session-id": context.sessionId,
41243
+ "x-mavis-agent-id": context.agentId || "main",
41244
+ "x-mavis-timezone-offset": String(context.timezoneOffsetSec ?? (/* @__PURE__ */ new Date()).getTimezoneOffset() * -60)
41245
+ } : {}
39949
41246
  };
39950
41247
  }
39951
41248
  /** Headers for a non-streaming call (the probe). */
@@ -40529,7 +41826,7 @@ var FileIdStore = class FileIdStore {
40529
41826
  const raw = await (await import("node:fs/promises")).readFile(this.path, "utf8").catch(() => "");
40530
41827
  if (raw.trim() === "") return {};
40531
41828
  const parsed = JSON.parse(raw);
40532
- return isRecord$46(parsed) ? parsed : {};
41829
+ return isRecord$47(parsed) ? parsed : {};
40533
41830
  }
40534
41831
  async write(value) {
40535
41832
  if (this.path === void 0) {
@@ -40546,7 +41843,7 @@ var FileIdStore = class FileIdStore {
40546
41843
  /** Shared by every in-memory instance, so they see one cache. */
40547
41844
  static memory;
40548
41845
  };
40549
- function isRecord$46(value) {
41846
+ function isRecord$47(value) {
40550
41847
  return typeof value === "object" && value !== null && !Array.isArray(value);
40551
41848
  }
40552
41849
  /** Stable key for one (content, account) pair. */
@@ -40664,7 +41961,7 @@ function isAbort$1(error, signal) {
40664
41961
  }
40665
41962
  /** The file id from a successful upload body, or undefined. */
40666
41963
  function readFileId(payload) {
40667
- if (!isRecord$46(payload) || !isRecord$46(payload.base_resp) || !isRecord$46(payload.file)) return void 0;
41964
+ if (!isRecord$47(payload) || !isRecord$47(payload.base_resp) || !isRecord$47(payload.file)) return void 0;
40668
41965
  if (payload.base_resp["status_code"] !== 0) return void 0;
40669
41966
  const fileId = payload.file["file_id"];
40670
41967
  if (typeof fileId === "number") return Number.isSafeInteger(fileId) && fileId >= 0 ? String(fileId) : void 0;
@@ -40672,13 +41969,13 @@ function readFileId(payload) {
40672
41969
  }
40673
41970
  /** The service's own reason for a refusal, so the message names the cause. */
40674
41971
  function describeRejection(payload, raw) {
40675
- if (isRecord$46(payload) && isRecord$46(payload.base_resp)) {
41972
+ if (isRecord$47(payload) && isRecord$47(payload.base_resp)) {
40676
41973
  const status = payload.base_resp["status_code"];
40677
41974
  const reason = payload.base_resp["status_msg"];
40678
41975
  if (typeof reason === "string" && reason !== "") return "the Files API refused the upload (" + String(status) + "): " + reason;
40679
41976
  }
40680
41977
  if (raw.trim() === "") return "the Files API returned an empty body";
40681
- if (!isRecord$46(payload)) return "the Files API returned a non-JSON body: " + raw.slice(0, 120).replace(/\s+/g, " ");
41978
+ if (!isRecord$47(payload)) return "the Files API returned a non-JSON body: " + raw.slice(0, 120).replace(/\s+/g, " ");
40682
41979
  return "the Files API refused the upload without naming a reason";
40683
41980
  }
40684
41981
  /** Parse a response body without throwing on a non-JSON payload. */
@@ -41428,12 +42725,18 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
41428
42725
  return serialized;
41429
42726
  };
41430
42727
  let body = buildBodyForOwner(authOwner);
42728
+ const rawSessionId = options.sessionId;
42729
+ const rawAgentId = options.agentId;
42730
+ const requestContext = {
42731
+ sessionId: typeof rawSessionId === "string" && rawSessionId.trim() !== "" ? rawSessionId : void 0,
42732
+ agentId: typeof rawAgentId === "string" && rawAgentId.trim() !== "" ? rawAgentId : void 0
42733
+ };
41431
42734
  let refusedBody;
41432
42735
  for (let attempt = 0;; attempt += 1) {
41433
42736
  try {
41434
42737
  response = await fetchWithContextBudgetRecovery(fetchFn)(messagesUrl(credentials.region), {
41435
42738
  method: "POST",
41436
- headers: modelRequestHeaders(credentials.accessToken),
42739
+ headers: modelRequestHeaders(credentials.accessToken, requestContext),
41437
42740
  body,
41438
42741
  signal
41439
42742
  });
@@ -41480,7 +42783,8 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
41480
42783
  model: options.model,
41481
42784
  authOwner,
41482
42785
  route: PROVIDER_ID$8,
41483
- provider: PROVIDER_ID$8
42786
+ provider: PROVIDER_ID$8,
42787
+ tools: requestOptions.tools
41484
42788
  });
41485
42789
  let buffer = "";
41486
42790
  /**
@@ -42396,7 +43700,7 @@ const PROVIDER_ID$7 = "minimax-code";
42396
43700
  function videoHistoryPath() {
42397
43701
  return path.join(dshHomeDir(), "storages", "minimax-code-video-history.json");
42398
43702
  }
42399
- function isRecord$45(value) {
43703
+ function isRecord$46(value) {
42400
43704
  return typeof value === "object" && value !== null && !Array.isArray(value);
42401
43705
  }
42402
43706
  function asNonEmptyString(value) {
@@ -42418,7 +43722,7 @@ function asFiniteNumber$3(value) {
42418
43722
  * @returns the normalized entry, or undefined to drop it.
42419
43723
  */
42420
43724
  function parseHistoryEntry(value) {
42421
- if (!isRecord$45(value)) return void 0;
43725
+ if (!isRecord$46(value)) return void 0;
42422
43726
  const createdAtMs = asFiniteNumber$3(value.createdAtMs);
42423
43727
  const model = asNonEmptyString(value.model);
42424
43728
  const videoPath = asNonEmptyString(value.videoPath);
@@ -42450,7 +43754,7 @@ function parseHistoryEntry(value) {
42450
43754
  * @returns the normalized document.
42451
43755
  */
42452
43756
  function parseHistoryDocument(value) {
42453
- if (!isRecord$45(value) || !Array.isArray(value.entries)) return {
43757
+ if (!isRecord$46(value) || !Array.isArray(value.entries)) return {
42454
43758
  version: 1,
42455
43759
  entries: []
42456
43760
  };
@@ -44503,6 +45807,429 @@ function createMinimaxGenerateVideoTool(ctx, options) {
44503
45807
  }
44504
45808
  });
44505
45809
  }
45810
+ /** 官方重复刹车的开关环境变量。 */
45811
+ const REPEAT_BREAKER_ENV = "KIMI_CODE_REPEAT_BREAKER";
45812
+ /** 第一段提醒文案。 */
45813
+ const REMINDER_TEXT_1 = "<system-reminder>\nThe same tool call has been repeated several times in a row. Before making your next call, write one sentence stating what new information you expect it to produce. Then act on that sentence: if it names something this result does not already give you, choose the action that best provides it; otherwise, continue with the evidence you already have.\n</system-reminder>";
45814
+ /**
45815
+ * 造第二段提醒文案(连击 5-7 次时用)。
45816
+ *
45817
+ * @param repeatCount - 当前连击次数,原样写进文案。
45818
+ * @returns 提醒正文。
45819
+ */
45820
+ function makeReminderText2(repeatCount) {
45821
+ return "<system-reminder>\nThe same tool call has now been issued " + String(repeatCount) + " times in a row. Choose exactly one of the following and state your choice before acting:\n(1) Falsification check: run the cheapest test that could conclusively disprove your current approach, if such a test exists.\n(2) Missing input: tell the user precisely what information or decision you need to proceed, and ask for it.\n(3) Conclude: deliver your best result based on the evidence already gathered, listing anything that remains uncertain.\n</system-reminder>";
45822
+ }
45823
+ /** 第三段提醒文案(连击 8 次起,以及强停那一轮)。 */
45824
+ const REMINDER_TEXT_3 = "<system-reminder>\nWrite your final response now, without any further tool calls. Cover: the current blocker, each approach you have tried and what it established, and the specific information or decision you need from the user to unblock progress. Text only.\n</system-reminder>";
45825
+ /** 强停那一轮之后,守卫用来拒绝后续工具调用的文案。 */
45826
+ const HANDOFF_VETO_TEXT = "This turn was ended by the repeat breaker after the same tool call was issued " + String(12) + " times in a row. This step accepts a text response only, so the tool call was not executed. Reply in text: the current blocker, what you tried, and what you need next.";
45827
+ /**
45828
+ * 不计入连击的协调类工具。
45829
+ *
45830
+ * 这些工具**本来就会**被反复调用:报一次进展、更新一次待办、问一次用户。把它们
45831
+ * 算进连击等于让刹车对着正常的心跳乱响。
45832
+ */
45833
+ const REPEAT_BREAKER_EXEMPT_TOOLS = Object.freeze([
45834
+ "progress_update",
45835
+ "todo_write",
45836
+ "ask_user_question",
45837
+ "enter_plan_mode",
45838
+ "exit_plan_mode",
45839
+ "leave_plan_mode",
45840
+ "create_goal",
45841
+ "update_goal",
45842
+ "get_goal",
45843
+ "dispatch_ledger",
45844
+ "present"
45845
+ ]);
45846
+ /**
45847
+ * 判断一个工具是不是不计入连击的协调类工具。
45848
+ *
45849
+ * @param toolName - 工具名。
45850
+ * @returns 豁免时为 true。
45851
+ */
45852
+ function isRepeatBreakerExemptTool(toolName) {
45853
+ return REPEAT_BREAKER_EXEMPT_TOOLS.includes(toolName);
45854
+ }
45855
+ /** 明确表示「关掉」的环境变量取值。 */
45856
+ const DISABLED_ENV_VALUES = /* @__PURE__ */ new Set([
45857
+ "0",
45858
+ "false",
45859
+ "no",
45860
+ "off"
45861
+ ]);
45862
+ /**
45863
+ * 读重复刹车当前是否启用。
45864
+ *
45865
+ * **默认开启**:刹车是保护,不是功能开关。只有环境变量明确写成
45866
+ * 0 / false / no / off(大小写不敏感)才关掉它。
45867
+ *
45868
+ * @param env - 环境变量视图;默认读 process.env。
45869
+ * @returns 启用时为 true。
45870
+ */
45871
+ function isKimiRepeatBreakerEnabled(env = process.env) {
45872
+ const raw = env[REPEAT_BREAKER_ENV];
45873
+ if (typeof raw !== "string") return true;
45874
+ return !DISABLED_ENV_VALUES.has(raw.trim().toLowerCase());
45875
+ }
45876
+ /**
45877
+ * 判断一个值是不是普通对象(原型是 Object.prototype 或 null)。
45878
+ *
45879
+ * @param value - 任意值。
45880
+ * @returns 是普通对象时为 true。
45881
+ */
45882
+ function isPlainRecord(value) {
45883
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
45884
+ const prototype = Object.getPrototypeOf(value);
45885
+ return prototype === Object.prototype || prototype === null;
45886
+ }
45887
+ /**
45888
+ * 判断一个值是不是对象(数组也算)。
45889
+ *
45890
+ * @param value - 任意值。
45891
+ * @returns 是对象时为 true。
45892
+ */
45893
+ function isRecord$45(value) {
45894
+ return typeof value === "object" && value !== null;
45895
+ }
45896
+ /**
45897
+ * 读一个未知字段为非空字符串。
45898
+ *
45899
+ * @param value - 候选值。
45900
+ * @returns 字符串,或任何其它类型的 undefined。
45901
+ */
45902
+ function stringOf$3(value) {
45903
+ return typeof value === "string" && value !== "" ? value : void 0;
45904
+ }
45905
+ /**
45906
+ * 读一次工具调用所属的线路。
45907
+ *
45908
+ * provider 的四个来源按可靠性排序:**请求头快照**(唯一反映「已经真的路由到
45909
+ * 哪个 provider」的那一份)→ **模型选择面**(首步还没有请求头时唯一还能说出
45910
+ * 这一场走哪条线路的地方)→ **agent 选项**(还没发出请求时唯一的意图)→
45911
+ * **agent 自身的 provider 字段**(最后的兜底)。
45912
+ *
45913
+ * 每一处读取都独立 try/catch:任何一处抛错都只是「这一处读不到」,不改变
45914
+ * 其余来源的行为,也不让整次读取失败。
45915
+ *
45916
+ * @param agent - 事件里的调用方 agent。
45917
+ * @returns 线路信息;读不到的字段省略。
45918
+ */
45919
+ function kimiSessionRouteOf(agent) {
45920
+ const record = isRecord$45(agent) ? agent : void 0;
45921
+ const session = record?.session;
45922
+ let provider;
45923
+ try {
45924
+ provider = stringOf$3(session?.requestHeader?.()?.config?.provider);
45925
+ } catch {
45926
+ provider = void 0;
45927
+ }
45928
+ if (provider === void 0) try {
45929
+ provider = stringOf$3(record?.model?.current?.()?.provider);
45930
+ } catch {
45931
+ provider = void 0;
45932
+ }
45933
+ if (provider === void 0) provider = stringOf$3(record?.options?.provider);
45934
+ if (provider === void 0) provider = stringOf$3(record?.provider);
45935
+ const sessionId = stringOf$3(session?.header?.id) ?? stringOf$3(record?.id);
45936
+ return {
45937
+ ...provider === void 0 ? {} : { provider },
45938
+ ...sessionId === void 0 ? {} : { sessionId }
45939
+ };
45940
+ }
45941
+ /**
45942
+ * 递归把一个值重排成「键名有序」的形状。
45943
+ *
45944
+ * 数组**保持原序**:数组元素的顺序本身就是语义([1, 2] 与 [2, 1] 不是同一件事),
45945
+ * 只有对象的键名顺序没有语义。
45946
+ *
45947
+ * @param value - 当前值。
45948
+ * @returns 重排后的值。
45949
+ */
45950
+ function sortJsonValue(value) {
45951
+ if (Array.isArray(value)) return value.map(sortJsonValue);
45952
+ if (!isPlainRecord(value)) return value;
45953
+ const out = {};
45954
+ for (const key of Object.keys(value).sort()) out[key] = sortJsonValue(value[key]);
45955
+ return out;
45956
+ }
45957
+ /**
45958
+ * 造一次工具调用的**规范键**。
45959
+ *
45960
+ * 键 = 工具名 + 参数的规范 JSON。参数先递归重排键名再序列化,于是
45961
+ * { a: 1, b: 2 } 与 { b: 2, a: 1 } 得到**完全相同**的键 —— 否则模型只是把参数
45962
+ * 的书写顺序换了一下,刹车就看不见这是一个连击。
45963
+ *
45964
+ * @param toolName - 工具名。
45965
+ * @param args - 工具参数。
45966
+ * @returns 规范键。
45967
+ */
45968
+ function canonicalKimiToolCallKey(toolName, args) {
45969
+ let json;
45970
+ try {
45971
+ json = JSON.stringify(sortJsonValue(args));
45972
+ } catch {
45973
+ json = void 0;
45974
+ }
45975
+ return toolName + " " + (json ?? String(args));
45976
+ }
45977
+ /**
45978
+ * 造一台重复刹车。
45979
+ *
45980
+ * 状态**按会话**分开:连击是「这场对话里的同一件事重复了多少次」,两个会话
45981
+ * 互不相干。
45982
+ *
45983
+ * @returns 一台重复刹车。
45984
+ */
45985
+ function createKimiRepeatBreaker() {
45986
+ const sessions = /* @__PURE__ */ new Map();
45987
+ /** 取一个会话的状态;没有就新建一个。 */
45988
+ const stateOf = (sessionId) => {
45989
+ const existing = sessions.get(sessionId);
45990
+ if (existing !== void 0) return existing;
45991
+ const created = {
45992
+ consecutiveKey: null,
45993
+ consecutiveCount: 0,
45994
+ handoffActive: false
45995
+ };
45996
+ sessions.set(sessionId, created);
45997
+ return created;
45998
+ };
45999
+ return {
46000
+ checkBeforeExecute(sessionId, toolName, args) {
46001
+ const state = stateOf(sessionId);
46002
+ if (state.handoffActive) return HANDOFF_VETO_TEXT;
46003
+ const key = canonicalKimiToolCallKey(toolName, args);
46004
+ if (state.consecutiveKey === key && state.consecutiveCount + 1 >= 12) {
46005
+ state.consecutiveCount += 1;
46006
+ state.handoffActive = true;
46007
+ return HANDOFF_VETO_TEXT;
46008
+ }
46009
+ },
46010
+ recordAfterExecute(sessionId, toolName, args) {
46011
+ if (isRepeatBreakerExemptTool(toolName)) return void 0;
46012
+ const state = stateOf(sessionId);
46013
+ if (state.handoffActive) return REMINDER_TEXT_3;
46014
+ const key = canonicalKimiToolCallKey(toolName, args);
46015
+ if (state.consecutiveKey === key) state.consecutiveCount += 1;
46016
+ else {
46017
+ state.consecutiveKey = key;
46018
+ state.consecutiveCount = 1;
46019
+ }
46020
+ if (state.consecutiveCount >= 12) {
46021
+ state.handoffActive = true;
46022
+ return REMINDER_TEXT_3;
46023
+ }
46024
+ if (state.consecutiveCount >= 8) return REMINDER_TEXT_3;
46025
+ if (state.consecutiveCount >= 5) return makeReminderText2(state.consecutiveCount);
46026
+ if (state.consecutiveCount >= 3) return REMINDER_TEXT_1;
46027
+ },
46028
+ resetSession(sessionId) {
46029
+ sessions.delete(sessionId);
46030
+ }
46031
+ };
46032
+ }
46033
+ /**
46034
+ * 读宿主上下文上的工具注册面。
46035
+ *
46036
+ * @param ctx - 宿主上下文。
46037
+ * @returns 工具注册面;没有时为 undefined。
46038
+ */
46039
+ function toolsServiceOf(ctx) {
46040
+ const read = ctx.get;
46041
+ if (typeof read === "function") try {
46042
+ const found = read.call(ctx, "tools");
46043
+ if (found !== void 0) return found;
46044
+ } catch {}
46045
+ const direct = ctx.tools;
46046
+ return direct === void 0 ? void 0 : direct;
46047
+ }
46048
+ /**
46049
+ * 已挂载的模块登记表,走一个 global symbol:同一个包的两份模块实例(npm 拷贝与
46050
+ * 仓库 link)仍然共享一次判定,而重复装两台刹车会让同一次调用被记两遍。
46051
+ */
46052
+ const MOUNTED$1 = Symbol.for("dsh-chatgpt-subscription.mounted-modules");
46053
+ /** 本模块在登记表里的名字。 */
46054
+ const MODULE_ID$1 = "kimi-repeat-breaker";
46055
+ /**
46056
+ * 单实例守卫:本模块已挂载时放弃本次安装。
46057
+ *
46058
+ * @param ctx - 宿主上下文。
46059
+ * @returns 释放函数(交出挂载权);已经挂载过时返回 undefined。
46060
+ */
46061
+ function claimMount$1(ctx) {
46062
+ const registry = globalThis;
46063
+ const existing = registry[MOUNTED$1];
46064
+ const mounted = existing instanceof Set ? existing : /* @__PURE__ */ new Set();
46065
+ if (existing !== mounted) registry[MOUNTED$1] = mounted;
46066
+ if (mounted.has(MODULE_ID$1)) return void 0;
46067
+ mounted.add(MODULE_ID$1);
46068
+ const release = () => {
46069
+ mounted.delete(MODULE_ID$1);
46070
+ };
46071
+ if (typeof ctx.effect === "function") ctx.effect(() => release, "dsh-chatgpt-subscription: kimi repeat breaker mount");
46072
+ return release;
46073
+ }
46074
+ /**
46075
+ * 把一条 post-execute 决策接上附加上下文,保住它原有的形状。
46076
+ *
46077
+ * @param decision - next() 交回来的决策。
46078
+ * @param contexts - 要追加的上下文。
46079
+ * @returns 追加后的决策。
46080
+ */
46081
+ function withAdditionalContexts(decision, contexts) {
46082
+ const additionalContexts = [...decision.additionalContexts ?? [], ...contexts];
46083
+ if (decision.kind === "block") return {
46084
+ kind: "block",
46085
+ feedback: decision.feedback,
46086
+ additionalContexts
46087
+ };
46088
+ if (decision.value !== void 0) return {
46089
+ kind: "accept",
46090
+ value: decision.value,
46091
+ additionalContexts
46092
+ };
46093
+ if (decision.content !== void 0) return {
46094
+ kind: "accept",
46095
+ content: decision.content,
46096
+ additionalContexts
46097
+ };
46098
+ return {
46099
+ kind: "accept",
46100
+ additionalContexts
46101
+ };
46102
+ }
46103
+ /**
46104
+ * 造一条重复刹车的提醒上下文。
46105
+ *
46106
+ * @param text - 提醒正文。
46107
+ * @returns 可直接放进 additionalContexts 的用户角色消息。
46108
+ */
46109
+ function createRepeatBreakerReminder(text) {
46110
+ return createUserMessage({
46111
+ content: [{
46112
+ type: "text",
46113
+ text
46114
+ }],
46115
+ source: {
46116
+ kind: "kimi-repeat-breaker",
46117
+ form: "notice",
46118
+ summary: "repeat breaker reminder"
46119
+ }
46120
+ });
46121
+ }
46122
+ /**
46123
+ * 判断一条消息是不是**真的**用户发言。
46124
+ *
46125
+ * 本模块自己追加的提醒也是 user 角色的消息(宿主要求附加上下文走 user 角色),
46126
+ * 所以判定不能只看角色:得看来源是不是 user。
46127
+ *
46128
+ * @param message - 候选消息。
46129
+ * @returns 是真人用户发言时为 true。
46130
+ */
46131
+ function isRealUserTurn(message) {
46132
+ if (!isRecord$45(message)) return false;
46133
+ const role = message["role"];
46134
+ if (role !== void 0 && role !== "user") return false;
46135
+ const source = message["source"];
46136
+ if (!isRecord$45(source)) return false;
46137
+ return source["kind"] === "user";
46138
+ }
46139
+ /**
46140
+ * 装上 Kimi Code 的重复刹车。
46141
+ *
46142
+ * 四条接缝:ctx.tools.guard()(强停时拦下调用)、tools/post-execute(三段提醒)、
46143
+ * agent/pre-step(新一轮用户输入重置连击)、agent/disposed(会话拆除时清状态)。
46144
+ * 工具声明面一个字节都不改。
46145
+ *
46146
+ * @param ctx - 宿主插件上下文。
46147
+ * @param options - 安装选项。
46148
+ * @returns 卸载函数。
46149
+ */
46150
+ function installKimiRepeatBreaker(ctx, options = {}) {
46151
+ const releaseMount = claimMount$1(ctx);
46152
+ if (releaseMount === void 0) return () => void 0;
46153
+ const breaker = createKimiRepeatBreaker();
46154
+ const enabled = options.enabled ?? (() => isKimiRepeatBreakerEnabled());
46155
+ /** 读一次开关。读失败按**开启**处理:保护不该因为一次读失败而失效。 */
46156
+ const isEnabled = () => {
46157
+ try {
46158
+ return enabled() !== false;
46159
+ } catch {
46160
+ return true;
46161
+ }
46162
+ };
46163
+ /**
46164
+ * 取一次执行所属的会话;不是 Kimi Code 这条线路时是 undefined。
46165
+ *
46166
+ * @param agent - 调用方 agent。
46167
+ * @returns 会话标识;不该管时是 undefined。
46168
+ */
46169
+ const kimiSessionIdOf = (agent) => {
46170
+ const route = kimiSessionRouteOf(agent);
46171
+ if (route.provider !== "kimi-code") return void 0;
46172
+ return route.sessionId;
46173
+ };
46174
+ const disposeGuard = toolsServiceOf(ctx)?.guard?.((execution) => {
46175
+ try {
46176
+ if (!isEnabled()) return void 0;
46177
+ const record = isRecord$45(execution) ? execution : void 0;
46178
+ const agent = record?.["agent"];
46179
+ const sessionId = kimiSessionIdOf(agent);
46180
+ if (sessionId === void 0) return void 0;
46181
+ const toolName = stringOf$3(record?.["name"]);
46182
+ if (toolName === void 0) return void 0;
46183
+ const veto = breaker.checkBeforeExecute(sessionId, toolName, record?.["arguments"]);
46184
+ if (veto === HANDOFF_VETO_TEXT) return HANDOFF_VETO_TEXT;
46185
+ return veto;
46186
+ } catch {
46187
+ return;
46188
+ }
46189
+ });
46190
+ const disposePostExecute = ctx.on?.("tools/post-execute", (async (exec, result, next) => {
46191
+ const decision = await next();
46192
+ try {
46193
+ if (!isEnabled()) return decision;
46194
+ const agent = exec.agent;
46195
+ const sessionId = kimiSessionIdOf(agent);
46196
+ if (sessionId === void 0) return decision;
46197
+ const toolName = stringOf$3(exec.name);
46198
+ if (toolName === void 0) return decision;
46199
+ const reminder = breaker.recordAfterExecute(sessionId, toolName, exec.arguments);
46200
+ if (reminder === void 0) return decision;
46201
+ return withAdditionalContexts(decision, [createRepeatBreakerReminder(reminder)]);
46202
+ } catch {
46203
+ return decision;
46204
+ }
46205
+ }));
46206
+ const disposePreStep = ctx.on?.("agent/pre-step", (async (payload, next) => {
46207
+ const decision = await next();
46208
+ try {
46209
+ if (!isRealUserTurn((Array.isArray(payload?.messages) ? payload.messages : []).at(-1))) return decision;
46210
+ const sessionId = kimiSessionIdOf(payload?.agent);
46211
+ if (sessionId === void 0) return decision;
46212
+ breaker.resetSession(sessionId);
46213
+ } catch {
46214
+ return decision;
46215
+ }
46216
+ return decision;
46217
+ }));
46218
+ const disposeDisposed = ctx.on?.("agent/disposed", ((payload) => {
46219
+ try {
46220
+ const sessionId = kimiSessionIdOf(payload?.agent);
46221
+ if (sessionId === void 0) return;
46222
+ breaker.resetSession(sessionId);
46223
+ } catch {}
46224
+ }));
46225
+ return () => {
46226
+ disposeGuard?.();
46227
+ disposePostExecute?.();
46228
+ disposePreStep?.();
46229
+ disposeDisposed?.();
46230
+ releaseMount();
46231
+ };
46232
+ }
44506
46233
  //#endregion
44507
46234
  //#region src/host/minimax-code/account-pool.ts
44508
46235
  /**
@@ -83486,6 +85213,13 @@ function markPatched$2(patched, holder, name) {
83486
85213
  if (names === void 0) patched.set(holder, /* @__PURE__ */ new Set([name]));
83487
85214
  else names.add(name);
83488
85215
  }
85216
+ /**
85217
+ * 默认受保护的 provider 名单。
85218
+ *
85219
+ * `kimi-code` 与 `minimax-code` 都按前缀缓存计费:`tools:sdk` 段一旦被改写,
85220
+ * 前缀缓存从改写处起全部作废,所以这两条线路默认都要冻结 SDK 段。
85221
+ */
85222
+ const DEFAULT_PTC_SDK_CACHE_PROVIDERS = Object.freeze(["kimi-code", "minimax-code"]);
83489
85223
  /** PTC 生成的 SDK 段名。 */
83490
85224
  const PTC_SDK_SECTION_NAME = "tools:sdk";
83491
85225
  /** 没有 scope 的装配(会话标题之类)用的桶键。 */
@@ -83565,7 +85299,7 @@ function readScopeProvider(scope) {
83565
85299
  */
83566
85300
  function installPtcSdkCacheGuard(ctx, options = {}) {
83567
85301
  const host = isRecord$13(ctx) ? ctx : void 0;
83568
- const providers = new Set(options.providers ?? ["kimi-code"]);
85302
+ const providers = new Set(options.providers ?? DEFAULT_PTC_SDK_CACHE_PROVIDERS);
83569
85303
  /** 已包装过的实例(幂等标记)。 */
83570
85304
  const alreadyWrapped = /* @__PURE__ */ new WeakSet();
83571
85305
  /** 已包装过的「方法宿主 + 方法名」:同一个原型不叠第二层包装。 */
@@ -98965,6 +100699,8 @@ function apply(ctx, pluginConfig = {}) {
98965
100699
  const guard = installCompactionPolicyGuard(ctx);
98966
100700
  return () => guard.dispose();
98967
100701
  }, "dsh-chatgpt-subscription: compaction policy guard");
100702
+ ctx.effect(() => installMinimaxRuntimeEnhancements(ctx), "dsh-chatgpt-subscription: MiniMax runtime enhancements");
100703
+ ctx.effect(() => installKimiRepeatBreaker(ctx), "dsh-chatgpt-subscription: Kimi repeat breaker");
98968
100704
  ctx.effect(() => installDispatchExecutionGuard(ctx, { enabled: () => resolveDispatchExecutionGuardEnabled(pluginConfig) }), "dsh-chatgpt-subscription: dispatch execution guard");
98969
100705
  ctx.effect(() => installDispatchLedger(ctx, {
98970
100706
  enabled: () => resolveDispatchExecutionGuardEnabled(pluginConfig),