@eddyskywalker/dsh-chatgpt-subscription 0.51.1 → 0.53.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 (44) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/lib/client.js +33 -14
  3. package/lib/client.js.map +1 -1
  4. package/lib/index.js +2335 -439
  5. package/lib/tool-result-pruner.js +8 -7
  6. package/lib/types/client/kimi-code/KimiCodeSection.d.ts.map +1 -1
  7. package/lib/types/compat.d.ts +1 -1
  8. package/lib/types/entry-tool-result-pruner.d.ts +7 -6
  9. package/lib/types/entry-tool-result-pruner.d.ts.map +1 -1
  10. package/lib/types/host/common/account-pool.d.ts +10 -0
  11. package/lib/types/host/common/account-pool.d.ts.map +1 -1
  12. package/lib/types/host/dispatch-ledger/guard.d.ts.map +1 -1
  13. package/lib/types/host/dispatch-ledger/header.d.ts +8 -0
  14. package/lib/types/host/dispatch-ledger/header.d.ts.map +1 -1
  15. package/lib/types/host/dispatch-ledger/protocol.d.ts +7 -0
  16. package/lib/types/host/dispatch-ledger/protocol.d.ts.map +1 -1
  17. package/lib/types/host/dispatch-ledger/tool.d.ts.map +1 -1
  18. package/lib/types/host/kimi-code/client.d.ts.map +1 -1
  19. package/lib/types/host/kimi-code/mapper.d.ts +19 -1
  20. package/lib/types/host/kimi-code/mapper.d.ts.map +1 -1
  21. package/lib/types/host/kimi-code/oauth.d.ts +43 -1
  22. package/lib/types/host/kimi-code/oauth.d.ts.map +1 -1
  23. package/lib/types/host/kimi-code/repeat-breaker.d.ts +220 -0
  24. package/lib/types/host/kimi-code/repeat-breaker.d.ts.map +1 -0
  25. package/lib/types/host/kimi-code/routes.d.ts.map +1 -1
  26. package/lib/types/host/kimi-code/types.d.ts +13 -0
  27. package/lib/types/host/kimi-code/types.d.ts.map +1 -1
  28. package/lib/types/host/minimax-code/adapter.d.ts.map +1 -1
  29. package/lib/types/host/minimax-code/client.d.ts +10 -1
  30. package/lib/types/host/minimax-code/client.d.ts.map +1 -1
  31. package/lib/types/host/minimax-code/mapper.d.ts +33 -4
  32. package/lib/types/host/minimax-code/mapper.d.ts.map +1 -1
  33. package/lib/types/host/minimax-code/model-catalog.d.ts +9 -2
  34. package/lib/types/host/minimax-code/model-catalog.d.ts.map +1 -1
  35. package/lib/types/host/minimax-code/runtime-enhancements.d.ts +313 -0
  36. package/lib/types/host/minimax-code/runtime-enhancements.d.ts.map +1 -0
  37. package/lib/types/host/minimax-code/types.d.ts +37 -4
  38. package/lib/types/host/minimax-code/types.d.ts.map +1 -1
  39. package/lib/types/host/ptc-sdk-cache-guard.d.ts +13 -4
  40. package/lib/types/host/ptc-sdk-cache-guard.d.ts.map +1 -1
  41. package/lib/types/host/tool-result-pruner-guard.d.ts +1 -1
  42. package/lib/types/index.d.ts.map +1 -1
  43. package/package.json +1 -1
  44. package/presets/dispatch/README.md +11 -3
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.53.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`;
@@ -2272,13 +2272,22 @@ var AccountPoolCore = class {
2272
2272
  return result;
2273
2273
  });
2274
2274
  }
2275
+ /**
2276
+ * Public summaries of a document the caller already read.
2277
+ *
2278
+ * A caller that needs both the rows and which one would serve the next
2279
+ * request must not read the pool twice: the two reads can straddle a write,
2280
+ * and the answer would then name one account while listing another
2281
+ * generation's state. Reading is not free either — an encrypted round trip,
2282
+ * a DPAPI unprotect on Windows.
2283
+ */
2284
+ summariesOf(data) {
2285
+ const now = Date.now();
2286
+ return data.accounts.map((account) => this.summarize(account, now));
2287
+ }
2275
2288
  /** Public summaries, with cooldowns that already expired reported as absent. */
2276
2289
  async listAccounts() {
2277
- const data = await this.read();
2278
- const now = Date.now();
2279
- return data.accounts.map((account) => {
2280
- return this.summarize(account, now);
2281
- });
2290
+ return this.summariesOf(await this.read());
2282
2291
  }
2283
2292
  summarize(account, now) {
2284
2293
  const expires = this.hooks.expiresAt?.(account.credentials);
@@ -2334,7 +2343,7 @@ var AccountPoolCore = class {
2334
2343
  };
2335
2344
  if (existingIndex >= 0) data.accounts[existingIndex] = account;
2336
2345
  else data.accounts.push(account);
2337
- if (!data.activeAccountId || account.isPrimary) data.activeAccountId = account.id;
2346
+ if (!data.activeAccountId) data.activeAccountId = account.id;
2338
2347
  return account;
2339
2348
  }
2340
2349
  setPrimary(accountId) {
@@ -3453,7 +3462,7 @@ var OAuthService = class {
3453
3462
  throw new OAuthServiceError("oauth-token-exchange-failed", `The ChatGPT device code could not be issued (${response.status}${detail === null ? "" : `, ${detail}`}).`, response.status);
3454
3463
  }
3455
3464
  const payload = await response.json().catch(() => null);
3456
- const record = isRecord$66(payload) ? payload : {};
3465
+ const record = isRecord$68(payload) ? payload : {};
3457
3466
  const authId = nonEmptyString$11(record.device_auth_id);
3458
3467
  const userCode = nonEmptyString$11(record.user_code) ?? nonEmptyString$11(record.usercode);
3459
3468
  if (authId === void 0 || userCode === void 0) throw new OAuthServiceError("oauth-token-exchange-failed", "ChatGPT returned no device code.");
@@ -3520,7 +3529,7 @@ var OAuthService = class {
3520
3529
  const detail = deviceErrorIdentifier(payload);
3521
3530
  throw new OAuthServiceError("oauth-token-exchange-failed", `The ChatGPT device confirmation was refused (${response.status}${detail === void 0 ? "" : `, ${detail}`}).`, response.status);
3522
3531
  }
3523
- const record = isRecord$66(payload) ? payload : {};
3532
+ const record = isRecord$68(payload) ? payload : {};
3524
3533
  const authorizationCode = nonEmptyString$11(record.authorization_code);
3525
3534
  const codeVerifier = nonEmptyString$11(record.code_verifier);
3526
3535
  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 +3876,11 @@ const DEVICE_PENDING_STATUSES = /* @__PURE__ */ new Set([
3867
3876
  function isPendingDeviceAnswer(response, payload) {
3868
3877
  if (response.status === 403 || response.status === 404) return true;
3869
3878
  if (!response.ok && response.status !== 400) return false;
3870
- if (!isRecord$66(payload)) return false;
3879
+ if (!isRecord$68(payload)) return false;
3871
3880
  const status = payload.status;
3872
3881
  if (typeof status === "string" && DEVICE_PENDING_STATUSES.has(status.toLowerCase())) return true;
3873
3882
  const error = payload.error;
3874
- if (isRecord$66(error)) {
3883
+ if (isRecord$68(error)) {
3875
3884
  const code = error.code;
3876
3885
  if (typeof code === "string" && DEVICE_PENDING_STATUSES.has(code.toLowerCase())) return true;
3877
3886
  }
@@ -3885,18 +3894,18 @@ function isPendingDeviceAnswer(response, payload) {
3885
3894
  * wrong.
3886
3895
  */
3887
3896
  function deviceErrorIdentifier(payload) {
3888
- if (!isRecord$66(payload)) return void 0;
3897
+ if (!isRecord$68(payload)) return void 0;
3889
3898
  const candidates = [payload.code];
3890
3899
  const error = payload.error;
3891
3900
  if (typeof error === "string") candidates.push(error);
3892
- else if (isRecord$66(error)) candidates.push(error.code, error.type);
3901
+ else if (isRecord$68(error)) candidates.push(error.code, error.type);
3893
3902
  candidates.push(payload.status);
3894
3903
  for (const candidate of candidates) if (typeof candidate === "string" && /^[a-z0-9_.-]{1,64}$/i.test(candidate)) return candidate;
3895
3904
  }
3896
3905
  function nonEmptyString$11(value) {
3897
3906
  return typeof value === "string" && value !== "" ? value : void 0;
3898
3907
  }
3899
- function isRecord$66(value) {
3908
+ function isRecord$68(value) {
3900
3909
  return typeof value === "object" && value !== null && !Array.isArray(value);
3901
3910
  }
3902
3911
  async function oauthErrorIdentifier(response) {
@@ -4079,7 +4088,7 @@ const CODEX_AUTH_CLAIMS_KEY = "https://api.openai.com/auth";
4079
4088
  * here, and the import has to be repeated afterwards.
4080
4089
  */
4081
4090
  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) {
4091
+ function isRecord$67(value) {
4083
4092
  return typeof value === "object" && value !== null && !Array.isArray(value);
4084
4093
  }
4085
4094
  /** A trimmed, non-empty string, or nothing. */
@@ -4181,7 +4190,7 @@ function decodeJwtClaims$1(token) {
4181
4190
  if (parts.length !== 3) return void 0;
4182
4191
  try {
4183
4192
  const value = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
4184
- return isRecord$65(value) ? value : void 0;
4193
+ return isRecord$67(value) ? value : void 0;
4185
4194
  } catch {
4186
4195
  return;
4187
4196
  }
@@ -4226,10 +4235,10 @@ function expiryFromAccessToken(accessToken) {
4226
4235
  * the file carries cannot reach the result.
4227
4236
  */
4228
4237
  function parseAdoptedCodexCredential(value, sourcePath) {
4229
- if (!isRecord$65(value)) return void 0;
4238
+ if (!isRecord$67(value)) return void 0;
4230
4239
  if (value.auth_mode !== "chatgpt") return void 0;
4231
4240
  const tokens = value[CODEX_CLI_TOKENS_KEY];
4232
- if (!isRecord$65(tokens)) return void 0;
4241
+ if (!isRecord$67(tokens)) return void 0;
4233
4242
  const accessToken = nonEmptyString$10(tokens.access_token);
4234
4243
  if (accessToken === void 0) return void 0;
4235
4244
  const refreshToken = nonEmptyString$10(tokens.refresh_token);
@@ -4248,7 +4257,7 @@ function parseAdoptedCodexCredential(value, sourcePath) {
4248
4257
  const email = claims === void 0 ? void 0 : nonEmptyString$10(claims.email);
4249
4258
  if (email !== void 0) credentials.email = email;
4250
4259
  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;
4260
+ const planType = isRecord$67(authClaims) ? nonEmptyString$10(authClaims.chatgpt_plan_type) : void 0;
4252
4261
  if (planType !== void 0) credentials.planType = planType;
4253
4262
  }
4254
4263
  const accountId = nonEmptyString$10(tokens.account_id);
@@ -5017,13 +5026,13 @@ function webServerOrigin(server) {
5017
5026
  //#region src/host/common/llm-compat.ts
5018
5027
  /** This package's kind in the harness message-source map. */
5019
5028
  const PLUGIN_MESSAGE_SOURCE_KIND = "dsh-chatgpt-subscription";
5020
- function isRecord$64(value) {
5029
+ function isRecord$66(value) {
5021
5030
  return typeof value === "object" && value !== null && !Array.isArray(value);
5022
5031
  }
5023
5032
  /** Read a message body's blocks, keeping every entry that carries a block tag. */
5024
5033
  function readBlocks(raw) {
5025
5034
  if (!Array.isArray(raw)) return [];
5026
- return raw.filter((block) => isRecord$64(block) && typeof block.type === "string");
5035
+ return raw.filter((block) => isRecord$66(block) && typeof block.type === "string");
5027
5036
  }
5028
5037
  /**
5029
5038
  * The first value that is a non-empty string.
@@ -5078,10 +5087,10 @@ function toolCallIdOf(raw, source, embedded) {
5078
5087
  function normalizeMessages(messages) {
5079
5088
  const normalized = [];
5080
5089
  for (const raw of messages ?? []) {
5081
- if (!isRecord$64(raw)) continue;
5090
+ if (!isRecord$66(raw)) continue;
5082
5091
  const content = readBlocks(raw.content);
5083
5092
  if (raw.role === "tool") {
5084
- const source = isRecord$64(raw.source) ? raw.source : void 0;
5093
+ const source = isRecord$66(raw.source) ? raw.source : void 0;
5085
5094
  const embedded = embeddedToolResult(content);
5086
5095
  const callId = toolCallIdOf(raw, source, embedded);
5087
5096
  const isError = raw.isError === true || embedded?.isError === true;
@@ -5105,7 +5114,7 @@ function normalizeMessages(messages) {
5105
5114
  id: raw.id,
5106
5115
  role: typeof raw.role === "string" ? raw.role : "user",
5107
5116
  content,
5108
- ...isRecord$64(raw.source) ? { source: raw.source } : {}
5117
+ ...isRecord$66(raw.source) ? { source: raw.source } : {}
5109
5118
  });
5110
5119
  }
5111
5120
  return normalized;
@@ -6809,7 +6818,7 @@ const schemaFields = /* @__PURE__ */ new Set([
6809
6818
  "required",
6810
6819
  "propertyOrdering"
6811
6820
  ]);
6812
- function isRecord$63(value) {
6821
+ function isRecord$65(value) {
6813
6822
  return typeof value === "object" && value !== null && !Array.isArray(value);
6814
6823
  }
6815
6824
  function mergeSchemas(left, right) {
@@ -6817,7 +6826,7 @@ function mergeSchemas(left, right) {
6817
6826
  ...left,
6818
6827
  ...right
6819
6828
  };
6820
- if (isRecord$63(left.properties) && isRecord$63(right.properties)) merged.properties = {
6829
+ if (isRecord$65(left.properties) && isRecord$65(right.properties)) merged.properties = {
6821
6830
  ...left.properties,
6822
6831
  ...right.properties
6823
6832
  };
@@ -6853,9 +6862,9 @@ const mergedTypeKeys = /* @__PURE__ */ new Set([
6853
6862
  * model with strictly less than the schema it started from.
6854
6863
  */
6855
6864
  function describeBranch(branch) {
6856
- const type = typeof branch.type === "string" ? branch.type : isRecord$63(branch.properties) ? "object" : isRecord$63(branch.items) ? "array" : "value";
6865
+ const type = typeof branch.type === "string" ? branch.type : isRecord$65(branch.properties) ? "object" : isRecord$65(branch.items) ? "array" : "value";
6857
6866
  const details = [];
6858
- if (isRecord$63(branch.properties)) {
6867
+ if (isRecord$65(branch.properties)) {
6859
6868
  const names = Object.keys(branch.properties);
6860
6869
  if (names.length > 0) details.push(`{${names.join(",")}}`);
6861
6870
  }
@@ -6869,7 +6878,7 @@ function describeBranch(branch) {
6869
6878
  }
6870
6879
  /** How well one branch can stand in for a whole union; a named object shape wins. */
6871
6880
  function branchRank(branch) {
6872
- if (isRecord$63(branch.properties)) return 3;
6881
+ if (isRecord$65(branch.properties)) return 3;
6873
6882
  if (branch.type === "object") return 2;
6874
6883
  if (branch.type === "array") return 1;
6875
6884
  return 0;
@@ -6898,7 +6907,7 @@ function unionShape(branches) {
6898
6907
  shape: branches[0],
6899
6908
  folded: false
6900
6909
  };
6901
- if (new Set(branches.map((branch) => branch.type)).size === 1 && branches.every((branch) => !isRecord$63(branch.properties) && !isRecord$63(branch.items))) {
6910
+ if (new Set(branches.map((branch) => branch.type)).size === 1 && branches.every((branch) => !isRecord$65(branch.properties) && !isRecord$65(branch.items))) {
6902
6911
  const shape = { type: branches[0].type };
6903
6912
  if (branches.every((branch) => Array.isArray(branch.enum))) {
6904
6913
  const values = [...new Set(branches.flatMap((branch) => branch.enum))];
@@ -6935,7 +6944,7 @@ function foldOwnFields(node) {
6935
6944
  const out = {};
6936
6945
  for (const [key, value] of Object.entries(node)) {
6937
6946
  if (key === "anyOf" || key === "oneOf" || key === "allOf") continue;
6938
- if (key === "properties" && isRecord$63(value)) {
6947
+ if (key === "properties" && isRecord$65(value)) {
6939
6948
  out.properties = Object.fromEntries(Object.entries(value).map(([name, child]) => [name, foldSchemaUnions(child)]));
6940
6949
  continue;
6941
6950
  }
@@ -6964,15 +6973,15 @@ function foldOwnFields(node) {
6964
6973
  * argument the model sends anyway fails there, naming the actual problem.
6965
6974
  */
6966
6975
  function foldSchemaUnions(node) {
6967
- if (!isRecord$63(node)) return node;
6976
+ if (!isRecord$65(node)) return node;
6968
6977
  let own = foldOwnFields(node);
6969
6978
  if (Array.isArray(node.allOf)) for (const branch of node.allOf) {
6970
6979
  const folded = foldSchemaUnions(branch);
6971
- if (isRecord$63(folded)) own = mergeSchemas(own, folded);
6980
+ if (isRecord$65(folded)) own = mergeSchemas(own, folded);
6972
6981
  }
6973
6982
  const alternatives = Array.isArray(node.anyOf) ? node.anyOf : Array.isArray(node.oneOf) ? node.oneOf : [];
6974
6983
  if (alternatives.length === 0) return own;
6975
- const branches = alternatives.map((branch) => foldSchemaUnions(branch)).filter(isRecord$63);
6984
+ const branches = alternatives.map((branch) => foldSchemaUnions(branch)).filter(isRecord$65);
6976
6985
  if (branches.length === 0) return own;
6977
6986
  const shapes = branches.filter((branch) => branch.type !== "null");
6978
6987
  const acceptsNull = branches.some((branch) => branch.type === "null");
@@ -6988,7 +6997,7 @@ function foldSchemaUnions(node) {
6988
6997
  return merged;
6989
6998
  }
6990
6999
  function toAntigravityToolSchema(schema, options = {}) {
6991
- if (!isRecord$63(schema)) return schema;
7000
+ if (!isRecord$65(schema)) return schema;
6992
7001
  const root = schema;
6993
7002
  function resolveReference(reference) {
6994
7003
  let target = root;
@@ -6996,13 +7005,13 @@ function toAntigravityToolSchema(schema, options = {}) {
6996
7005
  const path = reference === "#" ? [] : reference.slice(2).split("/");
6997
7006
  for (const segment of path) {
6998
7007
  const key = segment.replace(/~1/g, "/").replace(/~0/g, "~");
6999
- target = isRecord$63(target) && Object.hasOwn(target, key) ? target[key] : void 0;
7008
+ target = isRecord$65(target) && Object.hasOwn(target, key) ? target[key] : void 0;
7000
7009
  }
7001
- if (!isRecord$63(target)) throw new LlmError(`Antigravity tool schema reference was not found: ${reference}`, "PROVIDER_ERROR");
7010
+ if (!isRecord$65(target)) throw new LlmError(`Antigravity tool schema reference was not found: ${reference}`, "PROVIDER_ERROR");
7002
7011
  return target;
7003
7012
  }
7004
7013
  function convert(node, references) {
7005
- if (!isRecord$63(node)) return {};
7014
+ if (!isRecord$65(node)) return {};
7006
7015
  let inherited = {};
7007
7016
  if (typeof node.$ref === "string") {
7008
7017
  if (references.has(node.$ref)) throw new LlmError(`Antigravity tool schema contains a recursive reference: ${node.$ref}`, "PROVIDER_ERROR");
@@ -7011,8 +7020,8 @@ function toAntigravityToolSchema(schema, options = {}) {
7011
7020
  if (Array.isArray(node.allOf)) for (const branch of node.allOf) inherited = mergeSchemas(inherited, convert(branch, references));
7012
7021
  const out = {};
7013
7022
  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);
7023
+ if (isRecord$65(node.properties)) out.properties = Object.fromEntries(Object.entries(node.properties).map(([name, child]) => [name, convert(child, references)]));
7024
+ if (isRecord$65(node.items)) out.items = convert(node.items, references);
7016
7025
  const alternatives = Array.isArray(node.anyOf) ? node.anyOf : node.oneOf;
7017
7026
  if (Array.isArray(alternatives)) out.anyOf = alternatives.map((child) => convert(child, references));
7018
7027
  if (Array.isArray(node.type)) {
@@ -7048,7 +7057,7 @@ let toolCallCounter = 0;
7048
7057
  function sanitizeText$9(text) {
7049
7058
  return text.replace(/\0/g, "");
7050
7059
  }
7051
- function isRecord$62(value) {
7060
+ function isRecord$64(value) {
7052
7061
  return typeof value === "object" && value !== null && !Array.isArray(value);
7053
7062
  }
7054
7063
  function asString$29(value) {
@@ -7068,25 +7077,25 @@ function toolCallIdNeeded(modelId, runtimeModel) {
7068
7077
  return modelId.startsWith("claude-") || modelId.startsWith("gpt-oss-") || runtimeModel.startsWith("claude-") || runtimeModel.startsWith("gpt-oss-");
7069
7078
  }
7070
7079
  function parseArguments$1(raw) {
7071
- if (isRecord$62(raw)) return raw;
7080
+ if (isRecord$64(raw)) return raw;
7072
7081
  if (raw === void 0 || raw === null || raw === "") return {};
7073
7082
  const parsed = typeof raw === "string" ? safeJsonParse$9(raw) : raw;
7074
- return isRecord$62(parsed) ? parsed : {};
7083
+ return isRecord$64(parsed) ? parsed : {};
7075
7084
  }
7076
7085
  const NO_RESOLVED_IMAGES$5 = /* @__PURE__ */ new Map();
7077
7086
  function attachmentOf$5(block) {
7078
7087
  const attachment = block.attachment;
7079
- if (!isRecord$62(attachment)) return void 0;
7088
+ if (!isRecord$64(attachment)) return void 0;
7080
7089
  return typeof attachment.attachmentId === "string" ? attachment : void 0;
7081
7090
  }
7082
7091
  function attachmentLabel$6(block) {
7083
- const attachment = isRecord$62(block.attachment) ? block.attachment : void 0;
7092
+ const attachment = isRecord$64(block.attachment) ? block.attachment : void 0;
7084
7093
  return asString$29(attachment?.name) || asString$29(attachment?.attachmentId);
7085
7094
  }
7086
7095
  function collectImageRefs$3(content, refs) {
7087
7096
  if (!Array.isArray(content)) return;
7088
7097
  for (const block of content) {
7089
- if (!isRecord$62(block)) continue;
7098
+ if (!isRecord$64(block)) continue;
7090
7099
  if (block.type === "image") {
7091
7100
  const attachment = attachmentOf$5(block);
7092
7101
  if (attachment) refs.set(attachment.attachmentId, attachment);
@@ -7199,7 +7208,7 @@ function requestImageBytes$2(block) {
7199
7208
  function collectRequestImageBytes$2(content, lengths) {
7200
7209
  if (!Array.isArray(content)) return;
7201
7210
  for (const block of content) {
7202
- if (!isRecord$62(block)) continue;
7211
+ if (!isRecord$64(block)) continue;
7203
7212
  if (block.type === "tool-result") {
7204
7213
  collectRequestImageBytes$2(block.content, lengths);
7205
7214
  continue;
@@ -7249,7 +7258,7 @@ function offloadOldestRequestImages$3(options) {
7249
7258
  let replaced = false;
7250
7259
  return {
7251
7260
  content: content.map((block) => {
7252
- if (remaining.count === 0 || !isRecord$62(block)) return block;
7261
+ if (remaining.count === 0 || !isRecord$64(block)) return block;
7253
7262
  if (block.type === "image") {
7254
7263
  if (requestImageBytes$2(block) === void 0) return block;
7255
7264
  remaining.count -= 1;
@@ -7352,7 +7361,7 @@ function unavailableImageText$6(block) {
7352
7361
  }
7353
7362
  function imageBlockToPart(block, images) {
7354
7363
  let data = asString$29(block.data) || asString$29(block.base64);
7355
- const source = isRecord$62(block.source) ? block.source : void 0;
7364
+ const source = isRecord$64(block.source) ? block.source : void 0;
7356
7365
  if (!data && source) data = asString$29(source.data) || asString$29(source.base64);
7357
7366
  let mimeType = asString$29(block.mimeType) || asString$29(block.mediaType) || (source ? asString$29(source.mimeType) || asString$29(source.mediaType) : void 0) || "image/png";
7358
7367
  if (data?.startsWith("data:")) {
@@ -7377,8 +7386,8 @@ function contentToUserParts(content, images) {
7377
7386
  if (typeof content === "string") return [{ text: sanitizeText$9(content) }];
7378
7387
  if (!Array.isArray(content)) return [];
7379
7388
  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") {
7389
+ for (const block of content) if (isRecord$64(block) && block.type === "text" && typeof block.text === "string") parts.push({ text: sanitizeText$9(block.text) });
7390
+ else if (isRecord$64(block) && block.type === "image") {
7382
7391
  const img = imageBlockToPart(block, images);
7383
7392
  parts.push(img ?? { text: unavailableImageText$6(block) });
7384
7393
  }
@@ -7393,7 +7402,7 @@ function toolResultImageParts(blocks, images) {
7393
7402
  if (!Array.isArray(blocks)) return [];
7394
7403
  const parts = [];
7395
7404
  for (const block of blocks) {
7396
- if (!isRecord$62(block)) continue;
7405
+ if (!isRecord$64(block)) continue;
7397
7406
  if (block.type === "image") {
7398
7407
  parts.push(imageBlockToPart(block, images) ?? { text: unavailableImageText$6(block) });
7399
7408
  continue;
@@ -7405,7 +7414,7 @@ function toolResultImageParts(blocks, images) {
7405
7414
  function toolResultText$9(blocks) {
7406
7415
  if (!Array.isArray(blocks)) return "";
7407
7416
  return blocks.map((block) => {
7408
- if (!isRecord$62(block)) return "";
7417
+ if (!isRecord$64(block)) return "";
7409
7418
  if (block.type === "text" && typeof block.text === "string") return sanitizeText$9(block.text);
7410
7419
  if (block.type === "tool-result") return toolResultText$9(block.content);
7411
7420
  if (block.type === "image") {
@@ -7419,9 +7428,9 @@ function replayBlockFor$1(message, index) {
7419
7428
  const source = message.source;
7420
7429
  if (!source || source.kind !== "model" || source.provider !== "antigravity") return void 0;
7421
7430
  const state = source.replayState;
7422
- if (!isRecord$62(state)) return void 0;
7431
+ if (!isRecord$64(state)) return void 0;
7423
7432
  if (Array.isArray(state.blocks)) return state.blocks[index];
7424
- const resp = isRecord$62(state.response) ? state.response : void 0;
7433
+ const resp = isRecord$64(state.response) ? state.response : void 0;
7425
7434
  if (resp) {
7426
7435
  if (Array.isArray(resp.outputItems)) return resp.outputItems[index];
7427
7436
  if (Array.isArray(resp.blocks)) return resp.blocks[index];
@@ -7523,10 +7532,10 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
7523
7532
  if (!Array.isArray(message.content)) return parts;
7524
7533
  for (let index = 0; index < message.content.length; index++) {
7525
7534
  const block = message.content[index];
7526
- if (!isRecord$62(block)) continue;
7535
+ if (!isRecord$64(block)) continue;
7527
7536
  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
7537
  const replay = replayBlockFor$1(message, index);
7529
- const originalParts = Array.isArray(replay?.parts) ? replay.parts.filter(isRecord$62) : [];
7538
+ const originalParts = Array.isArray(replay?.parts) ? replay.parts.filter(isRecord$64) : [];
7530
7539
  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
7540
  parts.push(...originalParts.map(replayPart));
7532
7541
  continue;
@@ -7547,8 +7556,8 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
7547
7556
  } else if (block.type === "tool-call") {
7548
7557
  const toolId = String(block.id || "");
7549
7558
  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);
7559
+ const originalCall = originalParts.find((part) => isRecord$64(part.functionCall));
7560
+ 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
7561
  toolCalls.set(toolId, {
7553
7562
  name: toolName,
7554
7563
  id: wireId
@@ -7600,7 +7609,7 @@ function convertMessages(options, model, runtimeModel, images = NO_RESOLVED_IMAG
7600
7609
  continue;
7601
7610
  }
7602
7611
  const content = Array.isArray(message.content) ? message.content : [];
7603
- const userParts = contentToUserParts(content.filter((b) => !isRecord$62(b) || b.type !== "tool-result"), images);
7612
+ const userParts = contentToUserParts(content.filter((b) => !isRecord$64(b) || b.type !== "tool-result"), images);
7604
7613
  if (role === "system") {
7605
7614
  if (userParts.length) contents.push({
7606
7615
  role: GEMINI_ROLE.user,
@@ -7612,7 +7621,7 @@ function convertMessages(options, model, runtimeModel, images = NO_RESOLVED_IMAG
7612
7621
  role: GEMINI_ROLE.user,
7613
7622
  parts: userParts
7614
7623
  });
7615
- for (const b of content) if (isRecord$62(b) && b.type === "tool-result") pushToolResult(contents, b, toolCalls, model, runtimeModel, images);
7624
+ for (const b of content) if (isRecord$64(b) && b.type === "tool-result") pushToolResult(contents, b, toolCalls, model, runtimeModel, images);
7616
7625
  }
7617
7626
  return contents;
7618
7627
  }
@@ -7760,7 +7769,7 @@ const USAGE_FIELDS = [
7760
7769
  "totalTokenCount"
7761
7770
  ];
7762
7771
  function collectUsage(value, state) {
7763
- if (!isRecord$62(value)) return;
7772
+ if (!isRecord$64(value)) return;
7764
7773
  for (const key of USAGE_FIELDS) {
7765
7774
  const count = value[key];
7766
7775
  if (typeof count !== "number" || !Number.isSafeInteger(count) || count < 0) continue;
@@ -7790,17 +7799,17 @@ function processStreamLine$4(line, state) {
7790
7799
  }
7791
7800
  if (!json) return [];
7792
7801
  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;
7802
+ if (!isRecord$64(chunk)) return [];
7803
+ const responseData = isRecord$64(chunk.response) ? chunk.response : chunk;
7804
+ const error = isRecord$64(chunk.error) ? chunk.error : isRecord$64(responseData.error) ? responseData.error : void 0;
7796
7805
  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
7806
  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;
7807
+ const candidate = isRecord$64(candidates[0]) ? candidates[0] : void 0;
7808
+ const content = isRecord$64(candidate?.content) ? candidate.content : void 0;
7800
7809
  const parts = Array.isArray(content?.parts) ? content.parts : [];
7801
7810
  const out = [];
7802
7811
  for (const part of parts) {
7803
- if (!isRecord$62(part)) continue;
7812
+ if (!isRecord$64(part)) continue;
7804
7813
  if (typeof part.text === "string" && part.text !== "") {
7805
7814
  const isThinking = Boolean(part.thought);
7806
7815
  const blockType = isThinking ? "reasoning" : "text";
@@ -7832,7 +7841,7 @@ function processStreamLine$4(line, state) {
7832
7841
  index: state.currentBlock.index,
7833
7842
  text: delta
7834
7843
  });
7835
- } else if (!isRecord$62(part.functionCall) && thoughtSignature(part)) {
7844
+ } else if (!isRecord$64(part.functionCall) && thoughtSignature(part)) {
7836
7845
  if (state.replayBlocks.length === 0) {
7837
7846
  const type = part.thought ? "reasoning" : "text";
7838
7847
  state.blocks.push({
@@ -7856,12 +7865,12 @@ function processStreamLine$4(line, state) {
7856
7865
  }
7857
7866
  state.replayBlocks[state.replayBlocks.length - 1].parts.push(replayPart(part));
7858
7867
  }
7859
- if (isRecord$62(part.functionCall)) {
7868
+ if (isRecord$64(part.functionCall)) {
7860
7869
  out.push(...closeCurrentBlock(state));
7861
7870
  const fc = part.functionCall;
7862
7871
  const toolName = asString$29(fc.name) || "";
7863
7872
  const toolId = asString$29(fc.id) || sanitizeToolCallId("", toolName);
7864
- const argsText = JSON.stringify(isRecord$62(fc.args) ? fc.args : {});
7873
+ const argsText = JSON.stringify(isRecord$64(fc.args) ? fc.args : {});
7865
7874
  const index = state.blocks.length;
7866
7875
  const block = {
7867
7876
  type: "tool-call",
@@ -7900,7 +7909,7 @@ function processStreamLine$4(line, state) {
7900
7909
  if (responseData !== chunk) collectUsage(responseData.usageMetadata, state);
7901
7910
  const finishMessage = asString$29(candidate?.finishMessage);
7902
7911
  if (finishMessage) state.finishMessage = finishMessage;
7903
- const blockReason = asString$29((isRecord$62(responseData.promptFeedback) ? responseData.promptFeedback : void 0)?.blockReason);
7912
+ const blockReason = asString$29((isRecord$64(responseData.promptFeedback) ? responseData.promptFeedback : void 0)?.blockReason);
7904
7913
  const finishReason = asString$29(candidate?.finishReason) || asString$29(responseData.finishReason) || (blockReason ? `PROMPT_BLOCKED:${blockReason}` : void 0);
7905
7914
  if (finishReason) {
7906
7915
  state.finishReason = finishReason;
@@ -14084,7 +14093,7 @@ async function compactionCandidates(ctx) {
14084
14093
  };
14085
14094
  }))).filter((provider) => provider.models.length > 0) };
14086
14095
  }
14087
- function isRecord$61(value) {
14096
+ function isRecord$63(value) {
14088
14097
  return typeof value === "object" && value !== null && !Array.isArray(value);
14089
14098
  }
14090
14099
  function readPreferencesUpdate(value, current) {
@@ -14134,7 +14143,7 @@ function readPreferencesUpdate(value, current) {
14134
14143
  patch.subagentModelsByMainModel = value.subagentModelsByMainModel;
14135
14144
  }
14136
14145
  if ("contextWindowOverrides" in value) {
14137
- if (!isRecord$61(value.contextWindowOverrides)) throw new PreferenceError("contextWindowOverrides must be an object.");
14146
+ if (!isRecord$63(value.contextWindowOverrides)) throw new PreferenceError("contextWindowOverrides must be an object.");
14138
14147
  const overrides = {};
14139
14148
  for (const [model, contextWindow] of Object.entries(value.contextWindowOverrides)) {
14140
14149
  if (!isCodexModelId(model)) throw new PreferenceError("Unknown Codex model for a context window override.");
@@ -18634,11 +18643,11 @@ function commandCodeHeaders(apiKey, extra = {}) {
18634
18643
  function timeoutSignal$5(signal, ms) {
18635
18644
  return signal ? AbortSignal.any([signal, AbortSignal.timeout(ms)]) : AbortSignal.timeout(ms);
18636
18645
  }
18637
- function isRecord$60(value) {
18646
+ function isRecord$62(value) {
18638
18647
  return typeof value === "object" && value !== null && !Array.isArray(value);
18639
18648
  }
18640
18649
  function asRecord$16(value) {
18641
- return isRecord$60(value) ? value : void 0;
18650
+ return isRecord$62(value) ? value : void 0;
18642
18651
  }
18643
18652
  function asString$28(value) {
18644
18653
  if (typeof value === "string" && value.trim() !== "") return value;
@@ -18682,7 +18691,7 @@ function deepValue(value, keys, depth = 0) {
18682
18691
  }
18683
18692
  return;
18684
18693
  }
18685
- if (!isRecord$60(value)) return void 0;
18694
+ if (!isRecord$62(value)) return void 0;
18686
18695
  for (const key of keys) if (value[key] !== void 0 && value[key] !== null) return value[key];
18687
18696
  for (const nested of Object.values(value)) {
18688
18697
  const hit = deepValue(nested, keys, depth + 1);
@@ -18696,7 +18705,7 @@ function collectRecords(value, keys, depth = 0, out = []) {
18696
18705
  for (const entry of value) collectRecords(entry, keys, depth + 1, out);
18697
18706
  return out;
18698
18707
  }
18699
- if (!isRecord$60(value)) return out;
18708
+ if (!isRecord$62(value)) return out;
18700
18709
  if (keys.some((key) => value[key] !== void 0)) out.push(value);
18701
18710
  for (const nested of Object.values(value)) collectRecords(nested, keys, depth + 1, out);
18702
18711
  return out;
@@ -19506,7 +19515,7 @@ function buildModelOptions$2(catalog, enabledModelIds, overrides) {
19506
19515
  *
19507
19516
  * https://commandcode.ai/blog/command-code-provider-api
19508
19517
  */
19509
- function isRecord$59(value) {
19518
+ function isRecord$61(value) {
19510
19519
  return typeof value === "object" && value !== null && !Array.isArray(value);
19511
19520
  }
19512
19521
  function asString$27(value) {
@@ -19546,17 +19555,17 @@ const SUPPORTED_IMAGE_MEDIA_TYPES$4 = /* @__PURE__ */ new Set([
19546
19555
  ]);
19547
19556
  function attachmentOf$4(block) {
19548
19557
  const attachment = block.attachment;
19549
- if (!isRecord$59(attachment)) return void 0;
19558
+ if (!isRecord$61(attachment)) return void 0;
19550
19559
  return typeof attachment.attachmentId === "string" ? attachment : void 0;
19551
19560
  }
19552
19561
  function attachmentLabel$5(block) {
19553
- const attachment = isRecord$59(block.attachment) ? block.attachment : void 0;
19562
+ const attachment = isRecord$61(block.attachment) ? block.attachment : void 0;
19554
19563
  return asString$27(attachment?.name) || asString$27(attachment?.attachmentId);
19555
19564
  }
19556
19565
  function collectImageRefs$2(content, refs) {
19557
19566
  if (!Array.isArray(content)) return;
19558
19567
  for (const block of content) {
19559
- if (!isRecord$59(block)) continue;
19568
+ if (!isRecord$61(block)) continue;
19560
19569
  if (block.type === "image") {
19561
19570
  const attachment = attachmentOf$4(block);
19562
19571
  if (attachment) refs.set(attachment.attachmentId, attachment);
@@ -19577,7 +19586,7 @@ function requestImageBytes$1(block) {
19577
19586
  function collectRequestImageBytes$1(content, lengths) {
19578
19587
  if (!Array.isArray(content)) return;
19579
19588
  for (const block of content) {
19580
- if (!isRecord$59(block)) continue;
19589
+ if (!isRecord$61(block)) continue;
19581
19590
  if (block.type === "tool-result") {
19582
19591
  collectRequestImageBytes$1(block.content, lengths);
19583
19592
  continue;
@@ -19613,7 +19622,7 @@ function offloadOldestRequestImages$2(options) {
19613
19622
  let replaced = false;
19614
19623
  return {
19615
19624
  content: content.map((block) => {
19616
- if (remaining.count === 0 || !isRecord$59(block)) return block;
19625
+ if (remaining.count === 0 || !isRecord$61(block)) return block;
19617
19626
  if (block.type === "image") {
19618
19627
  if (requestImageBytes$1(block) === void 0) return block;
19619
19628
  remaining.count -= 1;
@@ -19685,7 +19694,7 @@ function unavailableImageText$5(block) {
19685
19694
  }
19686
19695
  function imageBlockToInline$3(block, images) {
19687
19696
  let data = asString$27(block.data) || asString$27(block.base64);
19688
- const source = isRecord$59(block.source) ? block.source : void 0;
19697
+ const source = isRecord$61(block.source) ? block.source : void 0;
19689
19698
  if (!data && source) data = asString$27(source.data) || asString$27(source.base64);
19690
19699
  let mediaType = asString$27(block.mimeType) || asString$27(block.mediaType) || (source ? asString$27(source.mimeType) || asString$27(source.mediaType) : void 0) || "image/png";
19691
19700
  if (data?.startsWith("data:")) {
@@ -19711,7 +19720,7 @@ function textOf$9(content) {
19711
19720
  if (!Array.isArray(content)) return "";
19712
19721
  const parts = [];
19713
19722
  for (const block of content) {
19714
- if (!isRecord$59(block)) continue;
19723
+ if (!isRecord$61(block)) continue;
19715
19724
  if (block.type === "text" && typeof block.text === "string") parts.push(sanitizeText$8(block.text));
19716
19725
  else if (block.type === "tool-result") parts.push(textOf$9(block.content));
19717
19726
  }
@@ -19720,7 +19729,7 @@ function textOf$9(content) {
19720
19729
  function toolResultText$8(blocks) {
19721
19730
  if (!Array.isArray(blocks)) return "";
19722
19731
  return blocks.map((block) => {
19723
- if (!isRecord$59(block)) return "";
19732
+ if (!isRecord$61(block)) return "";
19724
19733
  if (block.type === "text" && typeof block.text === "string") return sanitizeText$8(block.text);
19725
19734
  if (block.type === "tool-result") return toolResultText$8(block.content);
19726
19735
  if (block.type === "image") return `[image: ${attachmentLabel$5(block) ?? "attached image"}]`;
@@ -19738,7 +19747,7 @@ function toolResultBlocks$2(blocks, images) {
19738
19747
  const out = [];
19739
19748
  let hasImage = false;
19740
19749
  for (const block of blocks) {
19741
- if (!isRecord$59(block)) continue;
19750
+ if (!isRecord$61(block)) continue;
19742
19751
  if (block.type === "text" && typeof block.text === "string") {
19743
19752
  out.push({
19744
19753
  type: "text",
@@ -19787,7 +19796,7 @@ function toolResultImageBlocks$5(blocks, images) {
19787
19796
  if (!Array.isArray(blocks)) return [];
19788
19797
  const out = [];
19789
19798
  for (const block of blocks) {
19790
- if (!isRecord$59(block)) continue;
19799
+ if (!isRecord$61(block)) continue;
19791
19800
  if (block.type === "image") {
19792
19801
  const inline = imageBlockToInline$3(block, images);
19793
19802
  if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$4.has(inline.mediaType)) out.push({
@@ -19831,7 +19840,7 @@ function nonSystemMessages$8(options) {
19831
19840
  }
19832
19841
  /** Drop the JSON-Schema keywords provider gateways reject or ignore. */
19833
19842
  function stripMetaSchema$2(schema) {
19834
- if (!isRecord$59(schema)) return {
19843
+ if (!isRecord$61(schema)) return {
19835
19844
  type: "object",
19836
19845
  properties: {}
19837
19846
  };
@@ -19848,7 +19857,7 @@ function openAIUserContent$4(message, images) {
19848
19857
  const parts = [];
19849
19858
  let hasImage = false;
19850
19859
  for (const block of message.content) {
19851
- if (!isRecord$59(block)) continue;
19860
+ if (!isRecord$61(block)) continue;
19852
19861
  if (block.type === "text" && typeof block.text === "string") {
19853
19862
  const text = sanitizeText$8(block.text);
19854
19863
  if (text !== "") parts.push({
@@ -19876,7 +19885,7 @@ function openAIAssistantContent$4(message) {
19876
19885
  const textParts = [];
19877
19886
  const toolCalls = [];
19878
19887
  for (const block of message.content) {
19879
- if (!isRecord$59(block)) continue;
19888
+ if (!isRecord$61(block)) continue;
19880
19889
  if (block.type === "text" && typeof block.text === "string") textParts.push(sanitizeText$8(block.text));
19881
19890
  else if (block.type === "tool-call" && typeof block.name === "string") toolCalls.push({
19882
19891
  id: typeof block.id === "string" && block.id !== "" ? block.id : `call_${toolCalls.length}`,
@@ -19908,7 +19917,7 @@ function buildOpenAIRequest$1(options, images = NO_RESOLVED_IMAGES$4) {
19908
19917
  while (index < conversation.length && isToolResultMessage$8(conversation[index])) {
19909
19918
  const current = conversation[index];
19910
19919
  const block = current.content[0];
19911
- const callId = isRecord$59(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
19920
+ const callId = isRecord$61(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
19912
19921
  messages.push({
19913
19922
  role: "tool",
19914
19923
  tool_call_id: callId,
@@ -19969,7 +19978,7 @@ function anthropicUserContent$3(message, images) {
19969
19978
  if (!Array.isArray(message.content)) return [];
19970
19979
  const blocks = [];
19971
19980
  for (const block of message.content) {
19972
- if (!isRecord$59(block)) continue;
19981
+ if (!isRecord$61(block)) continue;
19973
19982
  if (block.type === "text" && typeof block.text === "string") {
19974
19983
  const text = sanitizeText$8(block.text);
19975
19984
  if (text !== "") blocks.push({
@@ -20006,7 +20015,7 @@ function anthropicUserContent$3(message, images) {
20006
20015
  function anthropicAssistantContent$3(message) {
20007
20016
  const blocks = [];
20008
20017
  for (const block of message.content) {
20009
- if (!isRecord$59(block)) continue;
20018
+ if (!isRecord$61(block)) continue;
20010
20019
  if (block.type === "text" && typeof block.text === "string") {
20011
20020
  const text = sanitizeText$8(block.text);
20012
20021
  if (text !== "") blocks.push({
@@ -20019,7 +20028,7 @@ function anthropicAssistantContent$3(message) {
20019
20028
  type: "tool_use",
20020
20029
  id: typeof block.id === "string" && block.id !== "" ? block.id : `toolu_${blocks.length}`,
20021
20030
  name: block.name,
20022
- input: isRecord$59(parsed) ? parsed : {}
20031
+ input: isRecord$61(parsed) ? parsed : {}
20023
20032
  });
20024
20033
  }
20025
20034
  }
@@ -20050,7 +20059,7 @@ function mergeAnthropicMessages$3(entries) {
20050
20059
  return merged;
20051
20060
  }
20052
20061
  /** Reasoning budget a thinking-enabled request may spend, given its output cap. */
20053
- function thinkingBudgetFor$1(effort, maxTokens) {
20062
+ function thinkingBudgetFor(effort, maxTokens) {
20054
20063
  if (effort === void 0 || effort === "") return void 0;
20055
20064
  const requested = anthropicThinkingBudget(effort);
20056
20065
  if (requested === void 0 || requested === null) return void 0;
@@ -20075,7 +20084,7 @@ function buildAnthropicRequest$1(options, images = NO_RESOLVED_IMAGES$4) {
20075
20084
  }
20076
20085
  const system = leadingSystemText$8(options);
20077
20086
  const maxTokens = options.maxTokens ?? maxOutputTokensFor$6(options.model);
20078
- const budget = thinkingBudgetFor$1(wireReasoningEffort(options.reasoningEffort === void 0 ? void 0 : String(options.reasoningEffort)), maxTokens);
20087
+ const budget = thinkingBudgetFor(wireReasoningEffort(options.reasoningEffort === void 0 ? void 0 : String(options.reasoningEffort)), maxTokens);
20079
20088
  return {
20080
20089
  model: options.model,
20081
20090
  max_tokens: maxTokens,
@@ -20113,7 +20122,7 @@ function responsesUserContent(message, images) {
20113
20122
  if (!Array.isArray(message.content)) return [];
20114
20123
  const parts = [];
20115
20124
  for (const block of message.content) {
20116
- if (!isRecord$59(block)) continue;
20125
+ if (!isRecord$61(block)) continue;
20117
20126
  if (block.type === "text" && typeof block.text === "string") {
20118
20127
  const text = sanitizeText$8(block.text);
20119
20128
  if (text !== "") parts.push({
@@ -20138,7 +20147,7 @@ function responsesToolResultImageBlocks(blocks, images) {
20138
20147
  if (!Array.isArray(blocks)) return [];
20139
20148
  const out = [];
20140
20149
  for (const block of blocks) {
20141
- if (!isRecord$59(block)) continue;
20150
+ if (!isRecord$61(block)) continue;
20142
20151
  if (block.type === "image") {
20143
20152
  const inline = imageBlockToInline$3(block, images);
20144
20153
  if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$4.has(inline.mediaType)) out.push({
@@ -20165,8 +20174,8 @@ function buildResponsesRequest(options, images = NO_RESOLVED_IMAGES$4) {
20165
20174
  const imageBlocks = [];
20166
20175
  while (index < conversation.length && isToolResultMessage$8(conversation[index])) {
20167
20176
  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 : "");
20177
+ const toolResult = Array.isArray(current.content) ? current.content.find((b) => isRecord$61(b) && b.type === "tool-result") : void 0;
20178
+ const callId = (isRecord$61(toolResult) && typeof toolResult.toolCallId === "string" ? toolResult.toolCallId : "") || (typeof current.source?.callId === "string" ? current.source.callId : "");
20170
20179
  input.push({
20171
20180
  type: "function_call_output",
20172
20181
  call_id: callId,
@@ -20189,7 +20198,7 @@ function buildResponsesRequest(options, images = NO_RESOLVED_IMAGES$4) {
20189
20198
  content
20190
20199
  });
20191
20200
  for (const call of toolCalls) {
20192
- const fn = isRecord$59(call.function) ? call.function : void 0;
20201
+ const fn = isRecord$61(call.function) ? call.function : void 0;
20193
20202
  input.push({
20194
20203
  type: "function_call",
20195
20204
  call_id: call.id,
@@ -20312,9 +20321,9 @@ function processOpenAIStreamLine$1(line, state) {
20312
20321
  }
20313
20322
  if (payload === "") return [];
20314
20323
  const chunk = safeJsonParse$8(payload);
20315
- if (!isRecord$59(chunk)) return [];
20324
+ if (!isRecord$61(chunk)) return [];
20316
20325
  const out = [];
20317
- if (isRecord$59(chunk.error)) {
20326
+ if (isRecord$61(chunk.error)) {
20318
20327
  const message = asString$27(chunk.error.message) ?? "unknown error";
20319
20328
  state.streamError = {
20320
20329
  vocabulary: "openai",
@@ -20323,20 +20332,20 @@ function processOpenAIStreamLine$1(line, state) {
20323
20332
  };
20324
20333
  throw new LlmError$1(`Command Code stream error: ${message}`, isContextOverflow(chunk.error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
20325
20334
  }
20326
- const usage = isRecord$59(chunk.usage) ? chunk.usage : void 0;
20335
+ const usage = isRecord$61(chunk.usage) ? chunk.usage : void 0;
20327
20336
  if (usage) {
20328
20337
  state.sawUsage = true;
20329
20338
  const prompt = numberOr$9(usage.prompt_tokens, 0);
20330
- const details = isRecord$59(usage.prompt_tokens_details) ? usage.prompt_tokens_details : void 0;
20339
+ const details = isRecord$61(usage.prompt_tokens_details) ? usage.prompt_tokens_details : void 0;
20331
20340
  const cached = details ? numberOr$9(details.cached_tokens, 0) : 0;
20332
20341
  state.inputTokens = Math.max(0, prompt - cached);
20333
20342
  state.cacheReadTokens = cached;
20334
20343
  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);
20344
+ if (isRecord$61(usage.completion_tokens_details)) state.reasoningTokens = numberOr$9(usage.completion_tokens_details.reasoning_tokens, state.reasoningTokens);
20336
20345
  }
20337
20346
  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;
20347
+ const choice = isRecord$61(choices[0]) ? choices[0] : void 0;
20348
+ const delta = isRecord$61(choice?.delta) ? choice.delta : void 0;
20340
20349
  if (delta) {
20341
20350
  const reasoning = asString$27(delta.reasoning_content) ?? asString$27(delta.reasoning);
20342
20351
  if (reasoning !== void 0 && reasoning !== "") {
@@ -20364,7 +20373,7 @@ function processOpenAIStreamLine$1(line, state) {
20364
20373
  }
20365
20374
  const toolDeltas = Array.isArray(delta.tool_calls) ? delta.tool_calls : [];
20366
20375
  for (const entry of toolDeltas) {
20367
- if (!isRecord$59(entry)) continue;
20376
+ if (!isRecord$61(entry)) continue;
20368
20377
  out.push(...applyOpenAIToolDelta$1(entry, state));
20369
20378
  }
20370
20379
  }
@@ -20378,7 +20387,7 @@ function processOpenAIStreamLine$1(line, state) {
20378
20387
  }
20379
20388
  function applyOpenAIToolDelta$1(entry, state) {
20380
20389
  const wireIndex = typeof entry.index === "number" ? entry.index : 0;
20381
- const fn = isRecord$59(entry.function) ? entry.function : {};
20390
+ const fn = isRecord$61(entry.function) ? entry.function : {};
20382
20391
  const out = [];
20383
20392
  let call = state.toolCalls.get(wireIndex);
20384
20393
  if (call === void 0) {
@@ -20436,12 +20445,12 @@ function processAnthropicStreamLine$1(line, state) {
20436
20445
  const payload = trimmed.slice(5).trim();
20437
20446
  if (payload === "" || payload === "[DONE]") return [];
20438
20447
  const event = safeJsonParse$8(payload);
20439
- if (!isRecord$59(event)) return [];
20448
+ if (!isRecord$61(event)) return [];
20440
20449
  const type = asString$27(event.type);
20441
20450
  const out = [];
20442
20451
  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;
20452
+ const message = isRecord$61(event.message) ? event.message : void 0;
20453
+ const usage = message && isRecord$61(message.usage) ? message.usage : void 0;
20445
20454
  if (usage) {
20446
20455
  state.sawUsage = true;
20447
20456
  state.inputTokens = numberOr$9(usage.input_tokens, 0);
@@ -20455,7 +20464,7 @@ function processAnthropicStreamLine$1(line, state) {
20455
20464
  }
20456
20465
  if (type === "content_block_start") {
20457
20466
  const contentIndex = numberOr$9(event.index, 0);
20458
- const block = isRecord$59(event.content_block) ? event.content_block : {};
20467
+ const block = isRecord$61(event.content_block) ? event.content_block : {};
20459
20468
  const blockType = asString$27(block.type);
20460
20469
  out.push(...closeCurrent$6(state));
20461
20470
  if (blockType === "tool_use") {
@@ -20505,7 +20514,7 @@ function processAnthropicStreamLine$1(line, state) {
20505
20514
  }
20506
20515
  if (type === "content_block_delta") {
20507
20516
  const contentIndex = numberOr$9(event.index, 0);
20508
- const delta = isRecord$59(event.delta) ? event.delta : {};
20517
+ const delta = isRecord$61(event.delta) ? event.delta : {};
20509
20518
  const deltaType = asString$27(delta.type);
20510
20519
  if (deltaType === "input_json_delta") {
20511
20520
  const pending = state.toolCalls.get(contentIndex);
@@ -20578,10 +20587,10 @@ function processAnthropicStreamLine$1(line, state) {
20578
20587
  return out;
20579
20588
  }
20580
20589
  if (type === "message_delta") {
20581
- const delta = isRecord$59(event.delta) ? event.delta : void 0;
20590
+ const delta = isRecord$61(event.delta) ? event.delta : void 0;
20582
20591
  const stop = delta ? asString$27(delta.stop_reason) : void 0;
20583
20592
  if (stop !== void 0 && stop !== "") state.finishReason = stop;
20584
- const usage = isRecord$59(event.usage) ? event.usage : void 0;
20593
+ const usage = isRecord$61(event.usage) ? event.usage : void 0;
20585
20594
  if (usage) {
20586
20595
  state.sawUsage = true;
20587
20596
  state.outputTokens = numberOr$9(usage.output_tokens, state.outputTokens);
@@ -20593,7 +20602,7 @@ function processAnthropicStreamLine$1(line, state) {
20593
20602
  return closeStream$6(state);
20594
20603
  }
20595
20604
  if (type === "error") {
20596
- const error = isRecord$59(event.error) ? event.error : {};
20605
+ const error = isRecord$61(event.error) ? event.error : {};
20597
20606
  const message = asString$27(error.message) ?? "unknown error";
20598
20607
  state.streamError = {
20599
20608
  vocabulary: "anthropic",
@@ -20639,7 +20648,7 @@ function processResponsesStreamLine(line, state) {
20639
20648
  } catch {
20640
20649
  return [];
20641
20650
  }
20642
- if (!isRecord$59(parsed)) return [];
20651
+ if (!isRecord$61(parsed)) return [];
20643
20652
  const type = typeof parsed.type === "string" ? parsed.type : "";
20644
20653
  if (type === "response.output_text.delta") {
20645
20654
  const delta = typeof parsed.delta === "string" ? parsed.delta : "";
@@ -20666,7 +20675,7 @@ function processResponsesStreamLine(line, state) {
20666
20675
  }];
20667
20676
  }
20668
20677
  if (type === "response.output_item.added") {
20669
- const item = isRecord$59(parsed.item) ? parsed.item : null;
20678
+ const item = isRecord$61(parsed.item) ? parsed.item : null;
20670
20679
  if (item === null || item.type !== "function_call") return [];
20671
20680
  return startResponsesToolCall(state, parsed, item);
20672
20681
  }
@@ -20690,11 +20699,11 @@ function processResponsesStreamLine(line, state) {
20690
20699
  return [];
20691
20700
  }
20692
20701
  if (type === "response.completed" || type === "response.incomplete") {
20693
- const response = isRecord$59(parsed.response) ? parsed.response : null;
20702
+ const response = isRecord$61(parsed.response) ? parsed.response : null;
20694
20703
  if (response !== null) {
20695
20704
  if (response.status === "failed") {
20696
20705
  state.done = true;
20697
- const errorObj = isRecord$59(response.error) ? response.error : null;
20706
+ const errorObj = isRecord$61(response.error) ? response.error : null;
20698
20707
  const detail = errorObj && typeof errorObj.message === "string" ? errorObj.message : typeof response.error === "string" ? response.error : "";
20699
20708
  state.streamError = {
20700
20709
  vocabulary: "responses",
@@ -20707,7 +20716,7 @@ function processResponsesStreamLine(line, state) {
20707
20716
  }
20708
20717
  state.done = true;
20709
20718
  if (type === "response.incomplete") {
20710
- const details = response && isRecord$59(response.incomplete_details) ? response.incomplete_details : null;
20719
+ const details = response && isRecord$61(response.incomplete_details) ? response.incomplete_details : null;
20711
20720
  const reason = details && typeof details.reason === "string" ? details.reason : "";
20712
20721
  state.finishReason = reason === "max_output_tokens" || reason === "length" || reason === "max_tokens" ? "length" : reason || "length";
20713
20722
  } else state.finishReason = "stop";
@@ -20715,8 +20724,8 @@ function processResponsesStreamLine(line, state) {
20715
20724
  }
20716
20725
  if (type === "response.failed" || type === "error") {
20717
20726
  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 : "");
20727
+ const errorObj = isRecord$61(parsed.error) ? parsed.error : isRecord$61(parsed.response) && isRecord$61(parsed.response.error) ? parsed.response.error : null;
20728
+ 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
20729
  state.streamError = {
20721
20730
  vocabulary: "responses",
20722
20731
  error: errorObj,
@@ -20804,15 +20813,15 @@ function responsesToolCall(state, key) {
20804
20813
  for (const call of state.toolCalls.values()) if (call.id === toToolCallId(key)) return call;
20805
20814
  }
20806
20815
  function readResponsesUsage(response, state) {
20807
- const usage = isRecord$59(response.usage) ? response.usage : null;
20816
+ const usage = isRecord$61(response.usage) ? response.usage : null;
20808
20817
  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;
20818
+ const cached = isRecord$61(usage.input_tokens_details) ? numberOrZero(usage.input_tokens_details.cached_tokens) : 0;
20819
+ const written = isRecord$61(usage.input_tokens_details) ? numberOrZero(usage.input_tokens_details.cache_write_tokens) : 0;
20811
20820
  state.inputTokens = Math.max(0, numberOrZero(usage.input_tokens) - cached - written);
20812
20821
  state.cacheReadTokens = cached;
20813
20822
  state.cacheWriteTokens = written;
20814
20823
  state.outputTokens = numberOrZero(usage.output_tokens);
20815
- const outputDetails = isRecord$59(usage.output_tokens_details) ? usage.output_tokens_details : null;
20824
+ const outputDetails = isRecord$61(usage.output_tokens_details) ? usage.output_tokens_details : null;
20816
20825
  if (outputDetails !== null) state.reasoningTokens = numberOrZero(outputDetails.reasoning_tokens);
20817
20826
  state.sawUsage = true;
20818
20827
  }
@@ -20900,7 +20909,7 @@ const ANTHROPIC_IN_BAND_STATUS = {
20900
20909
  * Anything not recognized keeps the mapper's verdict.
20901
20910
  */
20902
20911
  function inBandResponsesCode(error, message) {
20903
- const fields = isRecord$58(error) ? error : {};
20912
+ const fields = isRecord$60(error) ? error : {};
20904
20913
  const rawCode = (asString$26(fields.code) ?? asString$26(fields.type) ?? "").toLowerCase();
20905
20914
  const text = message.toLowerCase();
20906
20915
  if (text.includes("rate limit") || rawCode === "rate_limit" || rawCode === "rate_limit_exceeded") return "RATE_LIMIT";
@@ -20959,13 +20968,13 @@ function reclassifyInBandResponsesError(thrown, rawError, message, classify) {
20959
20968
  }
20960
20969
  /** The wire `error` object of an in-band event, read defensively. */
20961
20970
  function readErrorType(error) {
20962
- if (!isRecord$58(error)) return null;
20971
+ if (!isRecord$60(error)) return null;
20963
20972
  return typeof error.type === "string" ? error.type : null;
20964
20973
  }
20965
20974
  function asString$26(value) {
20966
20975
  return typeof value === "string" ? value : void 0;
20967
20976
  }
20968
- function isRecord$58(value) {
20977
+ function isRecord$60(value) {
20969
20978
  return typeof value === "object" && value !== null && !Array.isArray(value);
20970
20979
  }
20971
20980
  //#endregion
@@ -24190,14 +24199,14 @@ const IN_BAND_SERVER = [
24190
24199
  function isAbort$3(error, signal) {
24191
24200
  return signal?.aborted === true || error instanceof Error && error.name === "AbortError";
24192
24201
  }
24193
- function isRecord$57(value) {
24202
+ function isRecord$59(value) {
24194
24203
  return typeof value === "object" && value !== null && !Array.isArray(value);
24195
24204
  }
24196
24205
  function asString$25(value) {
24197
24206
  return typeof value === "string" && value !== "" ? value : void 0;
24198
24207
  }
24199
24208
  function attachmentLabel$4(block) {
24200
- const attachment = isRecord$57(block.attachment) ? block.attachment : void 0;
24209
+ const attachment = isRecord$59(block.attachment) ? block.attachment : void 0;
24201
24210
  return asString$25(attachment?.name) || asString$25(attachment?.attachmentId);
24202
24211
  }
24203
24212
  function unavailableImageText$4(block) {
@@ -24233,7 +24242,7 @@ async function processMessageContent(content, model, attachments, signal) {
24233
24242
  textParts.push(part);
24234
24243
  continue;
24235
24244
  }
24236
- if (!isRecord$57(part)) continue;
24245
+ if (!isRecord$59(part)) continue;
24237
24246
  if (part.type === "text") {
24238
24247
  if (typeof part.text === "string" && part.text !== "") textParts.push(part.text);
24239
24248
  continue;
@@ -24262,7 +24271,7 @@ async function processMessageContent(content, model, attachments, signal) {
24262
24271
  continue;
24263
24272
  }
24264
24273
  const inline = part.source;
24265
- if (isRecord$57(inline)) {
24274
+ if (isRecord$59(inline)) {
24266
24275
  const data = inline.data;
24267
24276
  if (typeof data === "string" && data !== "") {
24268
24277
  images.push(encodeImage(data, asMediaType(inline.mediaType)));
@@ -24303,7 +24312,7 @@ async function toOllamaRequest(options, attachments, signal, declared) {
24303
24312
  const toolResultBlocks = message.content.filter((b) => b.type === "tool-result");
24304
24313
  if (toolResultBlocks.length > 0) {
24305
24314
  for (const block of toolResultBlocks) {
24306
- const toolCallId = String(block.toolCallId ?? (isRecord$57(message.source) ? message.source.callId : "") ?? "");
24315
+ const toolCallId = String(block.toolCallId ?? (isRecord$59(message.source) ? message.source.callId : "") ?? "");
24307
24316
  const processed = await processMessageContent(block.content, options.model, attachments, signal);
24308
24317
  messages.push({
24309
24318
  role: "tool",
@@ -26394,7 +26403,7 @@ function planRetrievalOutline(text, toolName) {
26394
26403
  * @returns 读到的元数据;两者都没有时 undefined。
26395
26404
  */
26396
26405
  function shellMetadataOf(holder) {
26397
- const job = isPlainRecord(holder.job) ? holder.job : void 0;
26406
+ const job = isPlainRecord$2(holder.job) ? holder.job : void 0;
26398
26407
  let exitCode;
26399
26408
  if (typeof holder.exitCode === "number" && Number.isFinite(holder.exitCode)) exitCode = holder.exitCode;
26400
26409
  if (exitCode === void 0 && typeof job?.exitCode === "number" && Number.isFinite(job.exitCode)) exitCode = job.exitCode;
@@ -26499,7 +26508,7 @@ const JSON_ENVELOPE_LOG_KEYS = [
26499
26508
  /** JSON envelope 其余字段允许占用的最大序列化字符数(防止把含批量源码的混合 envelope 压掉)。 */
26500
26509
  const JSON_ENVELOPE_MAX_OTHER_CHARS = 800;
26501
26510
  /** 判断一个值是不是普通 JSON 对象(不是数组,也不是 null)。 */
26502
- function isPlainRecord(value) {
26511
+ function isPlainRecord$2(value) {
26503
26512
  return typeof value === "object" && value !== null && !Array.isArray(value);
26504
26513
  }
26505
26514
  /** 重建信封:只把预览写回被替换的键,其余字段原样保留。 */
@@ -26601,7 +26610,7 @@ function extractJsonEnvelopeLogField(text, toolName) {
26601
26610
  });
26602
26611
  }
26603
26612
  for (const [outerKey, outerValue] of Object.entries(record)) {
26604
- if (!isPlainRecord(outerValue)) continue;
26613
+ if (!isPlainRecord$2(outerValue)) continue;
26605
26614
  for (const key of JSON_ENVELOPE_LOG_KEYS) {
26606
26615
  const value = outerValue[key];
26607
26616
  if (typeof value === "string" && value.length > 0) candidates.push({
@@ -26691,7 +26700,7 @@ function canonicalGrepMatches(value) {
26691
26700
  if (!Array.isArray(value) || value.length === 0) return void 0;
26692
26701
  const matches = [];
26693
26702
  for (const entry of value) {
26694
- if (!isPlainRecord(entry)) return void 0;
26703
+ if (!isPlainRecord$2(entry)) return void 0;
26695
26704
  if (typeof entry.path !== "string") return void 0;
26696
26705
  if (!Number.isSafeInteger(entry.lineNumber)) return void 0;
26697
26706
  if (typeof entry.line !== "string") return void 0;
@@ -26705,12 +26714,12 @@ function canonicalGrepMatches(value) {
26705
26714
  }
26706
26715
  /** 规范读取结果。 */
26707
26716
  function canonicalReadResult(value) {
26708
- if (!isPlainRecord(value)) return void 0;
26717
+ if (!isPlainRecord$2(value)) return void 0;
26709
26718
  if (typeof value.path !== "string" || value.path.trim() === "") return void 0;
26710
26719
  if (!Array.isArray(value.lines) || value.lines.length === 0) return void 0;
26711
26720
  const lines = [];
26712
26721
  for (const entry of value.lines) {
26713
- if (!isPlainRecord(entry)) return void 0;
26722
+ if (!isPlainRecord$2(entry)) return void 0;
26714
26723
  if (!Number.isSafeInteger(entry.number)) return void 0;
26715
26724
  if (typeof entry.text !== "string") return void 0;
26716
26725
  lines.push({
@@ -26735,7 +26744,7 @@ function findGrepBinding(record) {
26735
26744
  matches: top
26736
26745
  };
26737
26746
  for (const [outerKey, outerValue] of Object.entries(record)) {
26738
- if (!isPlainRecord(outerValue)) continue;
26747
+ if (!isPlainRecord$2(outerValue)) continue;
26739
26748
  const nested = canonicalGrepMatches(outerValue.matches);
26740
26749
  if (nested !== void 0) return {
26741
26750
  binding: {
@@ -26762,7 +26771,7 @@ function findGlobBinding(record) {
26762
26771
  ...typeof record.root === "string" ? { root: record.root } : {}
26763
26772
  };
26764
26773
  for (const [outerKey, outerValue] of Object.entries(record)) {
26765
- if (!isPlainRecord(outerValue)) continue;
26774
+ if (!isPlainRecord$2(outerValue)) continue;
26766
26775
  const nested = canonicalGlobPaths(outerValue.paths);
26767
26776
  if (nested !== void 0) return {
26768
26777
  binding: {
@@ -26940,13 +26949,13 @@ function collectCompositeEntries(record) {
26940
26949
  for (const [key, value] of Object.entries(record)) {
26941
26950
  if (Array.isArray(value)) {
26942
26951
  value.forEach((item, index) => {
26943
- if (isPlainRecord(item)) push(`${key}[${index}]`, item);
26952
+ if (isPlainRecord$2(item)) push(`${key}[${index}]`, item);
26944
26953
  });
26945
26954
  continue;
26946
26955
  }
26947
- if (!isPlainRecord(value)) continue;
26956
+ if (!isPlainRecord$2(value)) continue;
26948
26957
  if (push(key, value)) continue;
26949
- for (const [subKey, subValue] of Object.entries(value)) if (isPlainRecord(subValue)) push(`${key}.${subKey}`, subValue);
26958
+ for (const [subKey, subValue] of Object.entries(value)) if (isPlainRecord$2(subValue)) push(`${key}.${subKey}`, subValue);
26950
26959
  }
26951
26960
  return entries;
26952
26961
  }
@@ -27382,7 +27391,7 @@ async function projectToolResult(input) {
27382
27391
  *
27383
27392
  * @module dsh-chatgpt-subscription/request-images
27384
27393
  */
27385
- function isRecord$56(value) {
27394
+ function isRecord$58(value) {
27386
27395
  return typeof value === "object" && value !== null && !Array.isArray(value);
27387
27396
  }
27388
27397
  function asString$24(value) {
@@ -27441,17 +27450,17 @@ const SUPPORTED_IMAGE_MEDIA_TYPES$3 = /* @__PURE__ */ new Set([
27441
27450
  ]);
27442
27451
  function attachmentOf$3(block) {
27443
27452
  const attachment = block.attachment;
27444
- if (!isRecord$56(attachment)) return void 0;
27453
+ if (!isRecord$58(attachment)) return void 0;
27445
27454
  return typeof attachment.attachmentId === "string" ? attachment : void 0;
27446
27455
  }
27447
27456
  function attachmentLabel$3(block) {
27448
- const attachment = isRecord$56(block.attachment) ? block.attachment : void 0;
27457
+ const attachment = isRecord$58(block.attachment) ? block.attachment : void 0;
27449
27458
  return asString$24(attachment?.name) || asString$24(attachment?.attachmentId);
27450
27459
  }
27451
27460
  function collectImageRefs$1(content, refs) {
27452
27461
  if (!Array.isArray(content)) return;
27453
27462
  for (const block of content) {
27454
- if (!isRecord$56(block)) continue;
27463
+ if (!isRecord$58(block)) continue;
27455
27464
  if (block.type === "image") {
27456
27465
  const attachment = attachmentOf$3(block);
27457
27466
  if (attachment) refs.set(attachment.attachmentId, attachment);
@@ -27481,7 +27490,7 @@ function base64Length$1(bytes) {
27481
27490
  */
27482
27491
  function inlinePayloadOf(block) {
27483
27492
  let data = asString$24(block.data) || asString$24(block.base64);
27484
- const source = isRecord$56(block.source) ? block.source : void 0;
27493
+ const source = isRecord$58(block.source) ? block.source : void 0;
27485
27494
  if (!data && source) data = asString$24(source.data) || asString$24(source.base64);
27486
27495
  if (data?.startsWith("data:")) {
27487
27496
  const matched = data.match(/^data:([^;,]+);base64,(.*)$/s);
@@ -27511,7 +27520,7 @@ function requestImagePayloadLength(block, images) {
27511
27520
  function collectRequestImagePayloads(content, images, lengths) {
27512
27521
  if (!Array.isArray(content)) return;
27513
27522
  for (const block of content) {
27514
- if (!isRecord$56(block)) continue;
27523
+ if (!isRecord$58(block)) continue;
27515
27524
  if (block.type === "image") {
27516
27525
  const bytes = requestImagePayloadLength(block, images);
27517
27526
  if (bytes !== void 0) lengths.push(bytes);
@@ -27565,7 +27574,7 @@ function replaceOldestRequestImages(options, count, images) {
27565
27574
  let replaced = false;
27566
27575
  return {
27567
27576
  content: content.map((block) => {
27568
- if (remaining.count === 0 || !isRecord$56(block)) return block;
27577
+ if (remaining.count === 0 || !isRecord$58(block)) return block;
27569
27578
  if (block.type === "image") {
27570
27579
  if (requestImagePayloadLength(block, images) === void 0) return block;
27571
27580
  remaining.count -= 1;
@@ -27707,7 +27716,7 @@ function collectImageOccurrences(options, images) {
27707
27716
  const walk = (content) => {
27708
27717
  if (!Array.isArray(content)) return;
27709
27718
  for (const block of content) {
27710
- if (!isRecord$56(block)) continue;
27719
+ if (!isRecord$58(block)) continue;
27711
27720
  if (block.type === "image") {
27712
27721
  const bytes = requestImagePayloadLength(block, images);
27713
27722
  const key = requestImageKey(block, images);
@@ -27761,7 +27770,7 @@ function replaceDroppedRequestImages(options, droppedKeys, images) {
27761
27770
  let replaced = false;
27762
27771
  return {
27763
27772
  content: content.map((block) => {
27764
- if (!isRecord$56(block)) return block;
27773
+ if (!isRecord$58(block)) return block;
27765
27774
  if (block.type === "image") {
27766
27775
  const key = requestImageKey(block, images);
27767
27776
  if (key === void 0 || !droppedKeys.has(key)) return block;
@@ -27946,7 +27955,7 @@ function unavailableImageText$3(block) {
27946
27955
  }
27947
27956
  function imageBlockToInline$2(block, images) {
27948
27957
  let data = asString$24(block.data) || asString$24(block.base64);
27949
- const source = isRecord$56(block.source) ? block.source : void 0;
27958
+ const source = isRecord$58(block.source) ? block.source : void 0;
27950
27959
  if (!data && source) data = asString$24(source.data) || asString$24(source.base64);
27951
27960
  let mediaType = asString$24(block.mimeType) || asString$24(block.mediaType) || (source ? asString$24(source.mimeType) || asString$24(source.mediaType) : void 0) || "image/png";
27952
27961
  if (data?.startsWith("data:")) {
@@ -28198,6 +28207,19 @@ const HEADER_MSH_DEVICE_NAME = "x-msh-device-name";
28198
28207
  const HEADER_MSH_DEVICE_MODEL = "x-msh-device-model";
28199
28208
  const HEADER_MSH_OS_VERSION = "x-msh-os-version";
28200
28209
  const HEADER_MSH_DEVICE_ID = "x-msh-device-id";
28210
+ /**
28211
+ * Environment variable carrying extra headers for every Kimi Code request.
28212
+ *
28213
+ * The official client reads newline-separated `Name: Value` lines from
28214
+ * `KIMI_CODE_CUSTOM_HEADERS` (it mirrors `ANTHROPIC_CUSTOM_HEADERS`) and
28215
+ * applies them to every outbound request, the `/models` listing included.
28216
+ *
28217
+ * These headers are the LOWEST-precedence layer: the Kimi device identity
28218
+ * headers and the caller's own headers both override them, so a deployment can
28219
+ * add a header for one gateway without being able to weaken the identity the
28220
+ * service attributes usage to.
28221
+ */
28222
+ const KIMI_CODE_CUSTOM_HEADERS_ENV = "KIMI_CODE_CUSTOM_HEADERS";
28201
28223
  /** Version the plugin reports to the managed service's telemetry headers. */
28202
28224
  const MSH_VERSION = "1.0.0";
28203
28225
  const REFRESH_THRESHOLD_RATIO = .5;
@@ -29052,6 +29074,51 @@ function asciiHeaderValue(value) {
29052
29074
  const printable = value.replace(/[^\x20-\x7E]/g, "").trim();
29053
29075
  return printable === "" ? void 0 : printable;
29054
29076
  }
29077
+ /**
29078
+ * Whether one header name is already set, ignoring case.
29079
+ *
29080
+ * HTTP header names are case-insensitive, so a custom `User-Agent` and the
29081
+ * identity `user-agent` are the same header. Keeping both in the map would
29082
+ * send one header twice with two values, which is exactly how a spoofed user
29083
+ * agent would survive the layer that was supposed to override it.
29084
+ */
29085
+ function hasHeaderName(headers, name) {
29086
+ const target = name.toLowerCase();
29087
+ return Object.keys(headers).some((key) => key.toLowerCase() === target);
29088
+ }
29089
+ /**
29090
+ * Extra headers the deployment supplies through KIMI_CODE_CUSTOM_HEADERS.
29091
+ *
29092
+ * The format is the official client's: newline-separated `Name: Value` lines,
29093
+ * exactly as `ANTHROPIC_CUSTOM_HEADERS` carries them. A line without a colon
29094
+ * is skipped, and both the name and the value are trimmed. The name keeps the
29095
+ * casing the deployment wrote, because that is the header the deployment
29096
+ * expects to see on the wire.
29097
+ *
29098
+ * The value is filtered through {@link asciiHeaderValue}, so a value with
29099
+ * nothing printable left in it is dropped instead of being sent as an empty
29100
+ * header.
29101
+ *
29102
+ * These headers form the LOWEST-precedence layer: the Kimi device identity
29103
+ * headers and the caller's own headers both override them.
29104
+ *
29105
+ * @param env environment the variable is read from, injectable for tests.
29106
+ */
29107
+ function parseKimiCodeCustomHeaders(env = process.env) {
29108
+ const raw = env[KIMI_CODE_CUSTOM_HEADERS_ENV]?.trim();
29109
+ if (raw === void 0 || raw === "") return {};
29110
+ const headers = {};
29111
+ for (const line of raw.split("\n")) {
29112
+ const colon = line.indexOf(":");
29113
+ if (colon < 0) continue;
29114
+ const name = line.slice(0, colon).trim();
29115
+ if (name === "") continue;
29116
+ const value = asciiHeaderValue(line.slice(colon + 1));
29117
+ if (value === void 0) continue;
29118
+ headers[name] = value;
29119
+ }
29120
+ return headers;
29121
+ }
29055
29122
  /** Best-effort human description of this machine, matching the official client. */
29056
29123
  function deviceModel() {
29057
29124
  const arch = os.arch();
@@ -29084,7 +29151,22 @@ async function getDeviceId() {
29084
29151
  } catch {}
29085
29152
  return created;
29086
29153
  }
29087
- /** Identity headers every Kimi Code OAuth and account request carries. */
29154
+ /**
29155
+ * Identity headers every Kimi Code OAuth and account request carries.
29156
+ *
29157
+ * Three layers, lowest precedence first:
29158
+ *
29159
+ * 1. the deployment's own `KIMI_CODE_CUSTOM_HEADERS`, so a gateway in front of
29160
+ * this route can ask for one extra header without a plugin release;
29161
+ * 2. the Kimi device identity, which the service uses to attribute usage to an
29162
+ * installation;
29163
+ * 3. the caller's own headers, which carry the credentials.
29164
+ *
29165
+ * A header name is matched across the layers without regard to case, so a
29166
+ * custom `User-Agent` cannot sit next to the identity `user-agent` and have
29167
+ * the last value win by accident: the higher layer replaces the lower one
29168
+ * outright instead of adding a second copy of the same header.
29169
+ */
29088
29170
  async function kimiIdentityHeaders(extra = {}) {
29089
29171
  const deviceId = await getDeviceId();
29090
29172
  const candidates = [
@@ -29102,6 +29184,10 @@ async function kimiIdentityHeaders(extra = {}) {
29102
29184
  const safe = asciiHeaderValue(value);
29103
29185
  if (safe !== void 0) headers[name] = safe;
29104
29186
  }
29187
+ for (const [name, value] of Object.entries(parseKimiCodeCustomHeaders())) {
29188
+ if (hasHeaderName(headers, name) || hasHeaderName(extra, name)) continue;
29189
+ headers[name] = value;
29190
+ }
29105
29191
  return {
29106
29192
  ...headers,
29107
29193
  ...extra
@@ -29479,6 +29565,8 @@ async function runDeviceLogin(options) {
29479
29565
  ...identity.nickname === void 0 ? {} : { nickname: identity.nickname }
29480
29566
  };
29481
29567
  const credentials = options.enrich === void 0 ? signedIn : await options.enrich(signedIn).catch(() => signedIn);
29568
+ const refusal = options.accept?.(credentials) ?? null;
29569
+ if (refusal !== null) throw new Error(refusal);
29482
29570
  await options.store.write(credentials);
29483
29571
  if (options.onSave) await options.onSave(credentials).catch(() => void 0);
29484
29572
  await persistRegion(options.region);
@@ -29528,7 +29616,8 @@ async function beginWebLogin(store, options = {}) {
29528
29616
  signal: controller.signal,
29529
29617
  open,
29530
29618
  ...options.onSave === void 0 ? {} : { onSave: options.onSave },
29531
- ...options.enrich === void 0 ? {} : { enrich: options.enrich }
29619
+ ...options.enrich === void 0 ? {} : { enrich: options.enrich },
29620
+ ...options.accept === void 0 ? {} : { accept: options.accept }
29532
29621
  });
29533
29622
  webLoginFlow = {
29534
29623
  ...webLoginFlow,
@@ -29561,11 +29650,11 @@ const MODELS_PATH$2 = "/models";
29561
29650
  const USAGES_PATH = "/usages";
29562
29651
  /** The service reports money in fixed-point units of 1e-6 cents. */
29563
29652
  const FIXED_POINT_CENTS = 1e6;
29564
- function isRecord$55(value) {
29653
+ function isRecord$57(value) {
29565
29654
  return typeof value === "object" && value !== null && !Array.isArray(value);
29566
29655
  }
29567
29656
  function asRecord$14(value) {
29568
- return isRecord$55(value) ? value : void 0;
29657
+ return isRecord$57(value) ? value : void 0;
29569
29658
  }
29570
29659
  function asString$23(value) {
29571
29660
  if (typeof value === "string" && value.trim() !== "") return value;
@@ -29591,6 +29680,19 @@ function firstNumber(record, keys) {
29591
29680
  if (value !== void 0) return value;
29592
29681
  }
29593
29682
  }
29683
+ /**
29684
+ * Non-empty strings from one array field.
29685
+ *
29686
+ * The service states its lists as JSON arrays. A field that is not an array, or
29687
+ * an array with nothing usable in it, reads as "the server said nothing" rather
29688
+ * than as an empty list, so the caller can fall back to the other dialect
29689
+ * instead of publishing an empty answer as the server's verdict.
29690
+ */
29691
+ function asStringList(value) {
29692
+ if (!Array.isArray(value)) return void 0;
29693
+ const entries = value.filter((entry) => typeof entry === "string" && entry.trim() !== "");
29694
+ return entries.length > 0 ? entries : void 0;
29695
+ }
29594
29696
  function clamp01$1(value) {
29595
29697
  return Math.min(1, Math.max(0, value));
29596
29698
  }
@@ -29698,14 +29800,48 @@ const RETIRED_MODEL_STATUSES = /* @__PURE__ */ new Set([
29698
29800
  * Read the three-state thinking declaration.
29699
29801
  *
29700
29802
  * 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.
29803
+ * ship `valid_efforts` that still contain `none` while the declaration says it
29804
+ * can only reason. When both are present the declaration wins, because it is
29805
+ * the field the service introduced to replace the older boolean.
29806
+ *
29807
+ * Two dialects state it. The unified schema nests it under `reasoning`:
29808
+ * `{ "type": "only" | "both" | "none" }`; the older listing states it flat as
29809
+ * `supports_thinking_type`. The unified object is read first, because it is
29810
+ * the newer field and the one that also carries the effort ladder; the flat
29811
+ * field remains the fallback for a server that still speaks the old shape.
29812
+ *
29813
+ * The unified schema spells the non-thinking state `none`; the internal
29814
+ * three-state keeps the legacy `no`.
29704
29815
  */
29705
29816
  function parseThinkingType(record) {
29817
+ const reasoning = asRecord$14(record.reasoning);
29818
+ if (reasoning !== void 0) {
29819
+ const rType = asString$23(reasoning.type);
29820
+ if (rType === "only" || rType === "both") return rType;
29821
+ if (rType === "none" || rType === "no") return "no";
29822
+ }
29706
29823
  const raw = asString$23(record.supports_thinking_type) ?? asString$23(record.supportsThinkingType);
29707
29824
  return raw === "only" || raw === "no" || raw === "both" ? raw : void 0;
29708
29825
  }
29826
+ /**
29827
+ * Read one model entry from the live listing.
29828
+ *
29829
+ * The service has published two shapes of the same listing and this parser
29830
+ * reads both:
29831
+ *
29832
+ * - the unified schema, which nests the window under `limit.context`, the
29833
+ * input cap under `limit.input`, the thinking declaration and the effort
29834
+ * ladder under `reasoning`, the accepted media under `modalities.input`
29835
+ * and the message-level tool flag under `tools.dynamic_load`;
29836
+ * - the older flat schema, which states the same facts as
29837
+ * `context_length`, `max_input_tokens`, `supports_thinking_type`,
29838
+ * `think_efforts`, `supports_image_in` / `supports_video_in` and
29839
+ * `supports_dynamic_tools`.
29840
+ *
29841
+ * A field the unified schema carries wins over its flat counterpart, because
29842
+ * that is the shape the service is moving towards; a field only the flat shape
29843
+ * carries is still read, so an older server keeps working.
29844
+ */
29709
29845
  function parseCatalogModel(value) {
29710
29846
  const record = asRecord$14(value);
29711
29847
  if (record === void 0) return void 0;
@@ -29713,30 +29849,41 @@ function parseCatalogModel(value) {
29713
29849
  if (id === void 0) return void 0;
29714
29850
  const status = asString$23(record.status)?.toLowerCase();
29715
29851
  if (status !== void 0 && RETIRED_MODEL_STATUSES.has(status)) return void 0;
29716
- const contextWindow = firstNumber(record, ["context_length", "contextLength"]);
29852
+ const limits = asRecord$14(record.limit) ?? asRecord$14(record.limits);
29853
+ const contextWindow = firstNumber(record, ["context_length", "contextLength"]) ?? firstNumber(limits ?? {}, ["context"]);
29717
29854
  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"]);
29855
+ const declaredInput = firstNumber(limits ?? {}, ["input"]) ?? firstNumber(record, ["max_input_tokens", "maxInputTokens"]);
29719
29856
  const maxInputTokens = declaredInput !== void 0 && declaredInput > 0 && declaredInput < contextWindow ? declaredInput : void 0;
29720
29857
  const thinkingType = parseThinkingType(record);
29858
+ const reasoningEffort = asRecord$14(asRecord$14(record.reasoning)?.effort);
29721
29859
  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;
29860
+ const usableEfforts = efforts !== void 0 && "support" in efforts && efforts.support !== true ? void 0 : efforts;
29861
+ const validEfforts = asStringList(reasoningEffort?.valid) ?? asStringList(usableEfforts?.valid_efforts) ?? asStringList(usableEfforts?.validEfforts);
29862
+ const rawDefaultEffort = asString$23(reasoningEffort?.default) ?? asString$23(usableEfforts?.default_effort ?? usableEfforts?.defaultEffort);
29863
+ const defaultReasoningEffort = rawDefaultEffort !== void 0 && validEfforts !== void 0 && validEfforts.length > 0 && !validEfforts.includes(rawDefaultEffort) ? void 0 : rawDefaultEffort;
29864
+ const rawModalities = asRecord$14(record.modalities);
29865
+ const modalityInputs = Array.isArray(rawModalities?.input) ? rawModalities.input.filter((entry) => typeof entry === "string") : [];
29866
+ const hasImage = record.supports_image_in === true || record.supportsImageIn === true || modalityInputs.includes("image");
29867
+ const hasVideo = record.supports_video_in === true || record.supportsVideoIn === true || modalityInputs.includes("video");
29723
29868
  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");
29869
+ if (hasImage) modalities.push("image");
29870
+ if (hasVideo) modalities.push("video");
29871
+ const toolsObj = asRecord$14(record.tools);
29872
+ const rawDynamicTools = typeof toolsObj?.dynamic_load === "boolean" ? toolsObj.dynamic_load : record.supports_dynamic_tools ?? record.supportsDynamicTools;
29726
29873
  const protocol = asString$23(record.protocol);
29727
29874
  return {
29728
29875
  id,
29729
29876
  name: asString$23(record.display_name) ?? asString$23(record.displayName) ?? void 0,
29730
29877
  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) },
29878
+ ...validEfforts === void 0 ? {} : { reasoningEfforts: validEfforts },
29879
+ ...defaultReasoningEffort === void 0 ? {} : { defaultReasoningEffort },
29733
29880
  inputModalities: modalities,
29734
29881
  protocol: protocol === "anthropic" ? "anthropic" : "openai",
29735
- ...record.supports_video_in === true || record.supportsVideoIn === true ? { supportsVideo: true } : {},
29882
+ ...hasVideo ? { supportsVideo: true } : {},
29736
29883
  ...maxInputTokens === void 0 ? {} : { maxInputTokens },
29737
29884
  ...thinkingType === void 0 ? {} : { thinkingType },
29738
29885
  ...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 } : {}
29886
+ ...typeof rawDynamicTools === "boolean" ? { supportsDynamicTools: rawDynamicTools } : {}
29740
29887
  };
29741
29888
  }
29742
29889
  /**
@@ -30622,12 +30769,12 @@ async function testConnection$1(store, options = {}) {
30622
30769
  *
30623
30770
  * @module dsh-chatgpt-subscription/tool-schema
30624
30771
  */
30625
- function isRecord$54(value) {
30772
+ function isRecord$56(value) {
30626
30773
  return typeof value === "object" && value !== null && !Array.isArray(value);
30627
30774
  }
30628
30775
  function cloneJsonValue(value) {
30629
30776
  if (Array.isArray(value)) return value.map(cloneJsonValue);
30630
- if (isRecord$54(value)) {
30777
+ if (isRecord$56(value)) {
30631
30778
  const res = {};
30632
30779
  for (const [k, v] of Object.entries(value)) res[k] = cloneJsonValue(v);
30633
30780
  return res;
@@ -30642,7 +30789,7 @@ function resolveLocalJsonPointer(root, ref) {
30642
30789
  let current = root;
30643
30790
  for (const rawPart of ref.slice(2).split("/")) {
30644
30791
  const part = rawPart.replaceAll("~1", "/").replaceAll("~0", "~");
30645
- if (isRecord$54(current)) {
30792
+ if (isRecord$56(current)) {
30646
30793
  if (!Object.prototype.hasOwnProperty.call(current, part)) return { found: false };
30647
30794
  current = current[part];
30648
30795
  } else if (Array.isArray(current)) {
@@ -30658,7 +30805,7 @@ function resolveLocalJsonPointer(root, ref) {
30658
30805
  }
30659
30806
  function derefNode(node, root, visited) {
30660
30807
  if (Array.isArray(node)) return node.map((item) => derefNode(item, root, visited));
30661
- if (isRecord$54(node)) {
30808
+ if (isRecord$56(node)) {
30662
30809
  if (typeof node["$ref"] === "string" && (node["$ref"] === "#" || node["$ref"].startsWith("#/"))) {
30663
30810
  const ref = node["$ref"];
30664
30811
  if (visited.has(ref)) return node;
@@ -30667,7 +30814,7 @@ function derefNode(node, root, visited) {
30667
30814
  visited.add(ref);
30668
30815
  const inlined = derefNode(resolved.value, root, visited);
30669
30816
  visited.delete(ref);
30670
- if (isRecord$54(inlined)) {
30817
+ if (isRecord$56(inlined)) {
30671
30818
  const merged = { ...inlined };
30672
30819
  for (const [k, v] of Object.entries(node)) {
30673
30820
  if (k === "$ref") continue;
@@ -30687,7 +30834,7 @@ function derefNode(node, root, visited) {
30687
30834
  }
30688
30835
  function hasUnresolvedDefinitionRef(node, bucketKey) {
30689
30836
  if (Array.isArray(node)) return node.some((child) => hasUnresolvedDefinitionRef(child, bucketKey));
30690
- if (isRecord$54(node)) {
30837
+ if (isRecord$56(node)) {
30691
30838
  const ref = node["$ref"];
30692
30839
  if (typeof ref === "string" && ref.startsWith(`#/${bucketKey}/`)) return true;
30693
30840
  for (const [k, v] of Object.entries(node)) {
@@ -30718,19 +30865,19 @@ function inferTypeFromValues(values) {
30718
30865
  if (types.size === 1) return types.values().next().value;
30719
30866
  }
30720
30867
  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)) {
30868
+ if (!isRecord$56(node)) return;
30869
+ if (isRecord$56(node.properties)) {
30870
+ for (const propSchema of Object.values(node.properties)) if (isRecord$56(propSchema)) {
30724
30871
  if (!propSchema.type && !propSchema.$ref) {
30725
30872
  if (Array.isArray(propSchema.enum) && propSchema.enum.length > 0) propSchema.type = inferTypeFromValues(propSchema.enum) ?? "string";
30726
30873
  else if (propSchema.const !== void 0) propSchema.type = inferValueType(propSchema.const) ?? "string";
30727
- else if (isRecord$54(propSchema.properties)) propSchema.type = "object";
30874
+ else if (isRecord$56(propSchema.properties)) propSchema.type = "object";
30728
30875
  else if (propSchema.items) propSchema.type = "array";
30729
30876
  }
30730
30877
  normalizeSchemaProperties(propSchema);
30731
30878
  }
30732
30879
  }
30733
- if (isRecord$54(node.items)) normalizeSchemaProperties(node.items);
30880
+ if (isRecord$56(node.items)) normalizeSchemaProperties(node.items);
30734
30881
  else if (Array.isArray(node.items)) for (const item of node.items) normalizeSchemaProperties(item);
30735
30882
  }
30736
30883
  /**
@@ -30738,7 +30885,7 @@ function normalizeSchemaProperties(node) {
30738
30885
  * inlining definitions ($defs/definitions/$ref), and ensuring property types for enums/consts.
30739
30886
  */
30740
30887
  function normalizeKimiToolSchema(schema) {
30741
- if (!isRecord$54(schema)) return {
30888
+ if (!isRecord$56(schema)) return {
30742
30889
  type: "object",
30743
30890
  properties: {}
30744
30891
  };
@@ -30756,7 +30903,7 @@ function stripMetaSchema$1(schema) {
30756
30903
  }
30757
30904
  //#endregion
30758
30905
  //#region src/host/common/prompt-estimate.ts
30759
- function isRecord$53(value) {
30906
+ function isRecord$55(value) {
30760
30907
  return typeof value === "object" && value !== null && !Array.isArray(value);
30761
30908
  }
30762
30909
  /** Tool-call arguments as the JSON string a wire carries, whatever shape they arrived in. */
@@ -30789,7 +30936,7 @@ function estimatedInputTokens(options) {
30789
30936
  const contentCharacters = (content) => {
30790
30937
  if (!Array.isArray(content)) return typeof content === "string" ? content.length : 0;
30791
30938
  return content.reduce((total, block) => {
30792
- if (!isRecord$53(block)) return total;
30939
+ if (!isRecord$55(block)) return total;
30793
30940
  if ((block.type === "text" || block.type === "reasoning") && typeof block.text === "string") return total + block.text.length;
30794
30941
  if (block.type === "tool-result") return total + contentCharacters(block.content);
30795
30942
  if (block.type === "tool-call") {
@@ -30890,7 +31037,7 @@ function videoOmissionText$1(reason, label) {
30890
31037
  }
30891
31038
  //#endregion
30892
31039
  //#region src/host/common/video-request.ts
30893
- function isRecord$52(value) {
31040
+ function isRecord$54(value) {
30894
31041
  return typeof value === "object" && value !== null && !Array.isArray(value);
30895
31042
  }
30896
31043
  function asString$22(value) {
@@ -30898,14 +31045,14 @@ function asString$22(value) {
30898
31045
  }
30899
31046
  function videoAttachmentOf(block) {
30900
31047
  const attachment = block.attachment;
30901
- if (!isRecord$52(attachment)) return void 0;
31048
+ if (!isRecord$54(attachment)) return void 0;
30902
31049
  if (typeof attachment.attachmentId !== "string") return void 0;
30903
31050
  return attachment;
30904
31051
  }
30905
31052
  function collectVideoRefs(content, refs) {
30906
31053
  if (!Array.isArray(content)) return;
30907
31054
  for (const block of content) {
30908
- if (!isRecord$52(block) || block.type !== "video") continue;
31055
+ if (!isRecord$54(block) || block.type !== "video") continue;
30909
31056
  const attachment = videoAttachmentOf(block);
30910
31057
  if (attachment) refs.set(attachment.attachmentId, attachment);
30911
31058
  }
@@ -30920,7 +31067,7 @@ function requestVideoBytes(block) {
30920
31067
  function collectRequestVideoBytes(content, lengths) {
30921
31068
  if (!Array.isArray(content)) return;
30922
31069
  for (const block of content) {
30923
- if (!isRecord$52(block) || block.type !== "video") continue;
31070
+ if (!isRecord$54(block) || block.type !== "video") continue;
30924
31071
  const bytes = requestVideoBytes(block);
30925
31072
  if (bytes !== void 0) lengths.push(bytes);
30926
31073
  }
@@ -30964,7 +31111,7 @@ function isAbortLike(error, signal) {
30964
31111
  }
30965
31112
  /** True when the request carries any video occurrence at all. */
30966
31113
  function requestHasVideo(options) {
30967
- return options.messages.some((message) => Array.isArray(message.content) && message.content.some((block) => isRecord$52(block) && block.type === "video"));
31114
+ return options.messages.some((message) => Array.isArray(message.content) && message.content.some((block) => isRecord$54(block) && block.type === "video"));
30968
31115
  }
30969
31116
  function omittedVideoText(omit, block) {
30970
31117
  return omit("unreadable", videoBlockLabel(block));
@@ -30999,7 +31146,7 @@ function offloadOldestRequestVideos(options, maxBytes) {
30999
31146
  if (remaining.count === 0 || !Array.isArray(message.content)) return message;
31000
31147
  let replaced = false;
31001
31148
  const content = message.content.map((block) => {
31002
- if (remaining.count === 0 || !isRecord$52(block) || block.type !== "video") return block;
31149
+ if (remaining.count === 0 || !isRecord$54(block) || block.type !== "video") return block;
31003
31150
  if (requestVideoBytes(block) === void 0) return block;
31004
31151
  remaining.count -= 1;
31005
31152
  replaced = true;
@@ -31082,7 +31229,7 @@ function videoBlockToInline(block, videos, videoAccepted, omit) {
31082
31229
  *
31083
31230
  * See https://www.kimi.com/code/docs/en/kimi-code/error-reference.html
31084
31231
  */
31085
- function isRecord$51(value) {
31232
+ function isRecord$53(value) {
31086
31233
  return typeof value === "object" && value !== null && !Array.isArray(value);
31087
31234
  }
31088
31235
  function asString$21(value) {
@@ -31192,7 +31339,7 @@ function reasoningDetailFragments(value) {
31192
31339
  if (!Array.isArray(value)) return [];
31193
31340
  const fragments = [];
31194
31341
  value.forEach((entry, position) => {
31195
- if (!isRecord$51(entry)) return;
31342
+ if (!isRecord$53(entry)) return;
31196
31343
  fragments.push(...reasoningDetailElement(entry, position));
31197
31344
  });
31198
31345
  return fragments;
@@ -31423,23 +31570,12 @@ function mapReasoningEffort(effort) {
31423
31570
  default: return;
31424
31571
  }
31425
31572
  }
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
31573
  function textOf$7(content) {
31438
31574
  if (typeof content === "string") return sanitizeText$7(content);
31439
31575
  if (!Array.isArray(content)) return "";
31440
31576
  const parts = [];
31441
31577
  for (const block of content) {
31442
- if (!isRecord$51(block)) continue;
31578
+ if (!isRecord$53(block)) continue;
31443
31579
  if (block.type === "text" && typeof block.text === "string") parts.push(sanitizeText$7(block.text));
31444
31580
  else if (block.type === "tool-result") parts.push(textOf$7(block.content));
31445
31581
  }
@@ -31448,7 +31584,7 @@ function textOf$7(content) {
31448
31584
  function toolResultText$7(blocks) {
31449
31585
  if (!Array.isArray(blocks)) return "";
31450
31586
  return blocks.map((block) => {
31451
- if (!isRecord$51(block)) return "";
31587
+ if (!isRecord$53(block)) return "";
31452
31588
  if (block.type === "text" && typeof block.text === "string") return sanitizeText$7(block.text);
31453
31589
  if (block.type === "tool-result") return toolResultText$7(block.content);
31454
31590
  if (block.type === "image") return `[image: ${attachmentLabel$3(block) ?? "attached image"}]`;
@@ -31466,7 +31602,7 @@ function toolResultBlocks$1(blocks, images) {
31466
31602
  const out = [];
31467
31603
  let hasImage = false;
31468
31604
  for (const block of blocks) {
31469
- if (!isRecord$51(block)) continue;
31605
+ if (!isRecord$53(block)) continue;
31470
31606
  if (block.type === "text" && typeof block.text === "string") {
31471
31607
  out.push({
31472
31608
  type: "text",
@@ -31521,7 +31657,7 @@ function toolResultImageBlocks$4(blocks, images, media = {}) {
31521
31657
  if (!Array.isArray(blocks)) return [];
31522
31658
  const out = [];
31523
31659
  for (const block of blocks) {
31524
- if (!isRecord$51(block)) continue;
31660
+ if (!isRecord$53(block)) continue;
31525
31661
  if (block.type === "image") {
31526
31662
  const reference = hostedReference(media.imageReferences, block);
31527
31663
  if (reference !== void 0) {
@@ -31556,7 +31692,7 @@ const HOSTED_FILE_SCHEME = "ms://";
31556
31692
  * bytes.
31557
31693
  */
31558
31694
  function attachmentIdOf(block) {
31559
- const attachment = isRecord$51(block.attachment) ? block.attachment : void 0;
31695
+ const attachment = isRecord$53(block.attachment) ? block.attachment : void 0;
31560
31696
  const id = attachment === void 0 ? void 0 : asString$21(attachment.attachmentId);
31561
31697
  return id === void 0 || id === "" ? void 0 : id;
31562
31698
  }
@@ -31639,12 +31775,12 @@ function readReasoningForm(value) {
31639
31775
  */
31640
31776
  function reasoningRunsAt(message, blockIndex) {
31641
31777
  const state = message.source?.replayState;
31642
- if (!isRecord$51(state) || !Array.isArray(state.blocks)) return void 0;
31778
+ if (!isRecord$53(state) || !Array.isArray(state.blocks)) return void 0;
31643
31779
  const entry = state.blocks[blockIndex];
31644
- if (!isRecord$51(entry) || !Array.isArray(entry.reasoning)) return void 0;
31780
+ if (!isRecord$53(entry) || !Array.isArray(entry.reasoning)) return void 0;
31645
31781
  const runs = [];
31646
31782
  for (const raw of entry.reasoning) {
31647
- if (!isRecord$51(raw)) return void 0;
31783
+ if (!isRecord$53(raw)) return void 0;
31648
31784
  const key = asString$21(raw.key);
31649
31785
  const length = raw.length;
31650
31786
  if (key === void 0 || typeof length !== "number" || !Number.isInteger(length) || length < 0) return void 0;
@@ -31694,7 +31830,7 @@ function replayedReasoning(message, fallbackKey) {
31694
31830
  };
31695
31831
  for (let blockIndex = 0; blockIndex < message.content.length; blockIndex++) {
31696
31832
  const block = message.content[blockIndex];
31697
- if (!isRecord$51(block) || block.type !== "reasoning" || typeof block.text !== "string") continue;
31833
+ if (!isRecord$53(block) || block.type !== "reasoning" || typeof block.text !== "string") continue;
31698
31834
  const text = sanitizeText$7(block.text);
31699
31835
  joined += text;
31700
31836
  const runs = reasoningRunsAt(message, blockIndex);
@@ -31863,7 +31999,7 @@ function openAIUserContent$3(message, images, media = {}) {
31863
31999
  const parts = [];
31864
32000
  let hasRichPart = false;
31865
32001
  for (const block of message.content) {
31866
- if (!isRecord$51(block)) continue;
32002
+ if (!isRecord$53(block)) continue;
31867
32003
  if (block.type === "text" && typeof block.text === "string") {
31868
32004
  const text = sanitizeText$7(block.text);
31869
32005
  if (text !== "") parts.push({
@@ -31921,16 +32057,20 @@ function openAIAssistantContent$3(message, toolCallIds, reasoningKey) {
31921
32057
  const textParts = [];
31922
32058
  const toolCalls = [];
31923
32059
  for (const block of message.content) {
31924
- if (!isRecord$51(block)) continue;
32060
+ if (!isRecord$53(block)) continue;
31925
32061
  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
- });
32062
+ else if (block.type === "tool-call" && typeof block.name === "string") {
32063
+ const call = {
32064
+ id: toolCallIds.normalize(typeof block.id === "string" && block.id !== "" ? block.id : `call_${toolCalls.length}`),
32065
+ type: "function",
32066
+ function: {
32067
+ name: block.name,
32068
+ arguments: toolCallArguments$6(block.arguments)
32069
+ }
32070
+ };
32071
+ if (isRecord$53(block.extras)) call.extras = block.extras;
32072
+ toolCalls.push(call);
32073
+ }
31934
32074
  }
31935
32075
  return {
31936
32076
  content: textParts.join(""),
@@ -32071,6 +32211,31 @@ function replayedDetailElement(detail) {
32071
32211
  ...index
32072
32212
  };
32073
32213
  }
32214
+ /**
32215
+ * Put one run of tool results back in the order the assistant declared its
32216
+ * calls in.
32217
+ *
32218
+ * A parallel tool call answers several calls at once, and the service reads
32219
+ * the `tool` messages as the answers to the `tool_calls` that precede them:
32220
+ * a result that arrives in the wrong order is answered against the wrong call.
32221
+ * DSH history can hold the results out of order (a resumed session, a tool
32222
+ * that answered late), so the run is sorted back into the declared order.
32223
+ *
32224
+ * A result whose id belongs to no declared call keeps its relative order
32225
+ * behind the answered ones: it answers something this turn did not declare,
32226
+ * so there is no declared position for it to be sorted into.
32227
+ */
32228
+ function pairToolExchanges(batch, declaredIds) {
32229
+ if (batch.length < 2 || declaredIds.length < 2) return [...batch];
32230
+ const rank = /* @__PURE__ */ new Map();
32231
+ for (const [position, id] of declaredIds.entries()) if (!rank.has(id)) rank.set(id, position);
32232
+ if (batch.filter((entry) => rank.has(entry.id)).length < 2) return [...batch];
32233
+ return batch.map((entry, position) => ({
32234
+ entry,
32235
+ position,
32236
+ key: rank.get(entry.id) ?? Number.MAX_SAFE_INTEGER
32237
+ })).sort((a, b) => a.key - b.key || a.position - b.position).map((ordered) => ordered.entry);
32238
+ }
32074
32239
  /** Build one `/chat/completions` body. */
32075
32240
  function buildOpenAIRequest(options, images = NO_RESOLVED_IMAGES$3, preserveThinking = preserveThinkingEnabled(), media = {}) {
32076
32241
  const effort = mapReasoningEffort(options.reasoningEffort === void 0 ? void 0 : String(options.reasoningEffort));
@@ -32132,21 +32297,16 @@ function buildOpenAIRequest(options, images = NO_RESOLVED_IMAGES$3, preserveThin
32132
32297
  flushSlots(nonSystemIndex);
32133
32298
  nonSystemIndex += 1;
32134
32299
  if (isToolResultMessage$7(message)) {
32300
+ const batch = [];
32135
32301
  while (index < conversation.length && isToolResultMessage$7(conversation[index])) {
32136
32302
  const current = conversation[index];
32137
32303
  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)
32304
+ const rawCallId = isRecord$53(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
32305
+ batch.push({
32306
+ id: toolCallIds.normalize(rawCallId),
32307
+ content: toolResultText$7(current.content),
32308
+ images: toolResultImageBlocks$4(current.content, images, media)
32144
32309
  });
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
32310
  if (index + 1 < conversation.length && isToolResultMessage$7(conversation[index + 1])) {
32151
32311
  flushSlots(nonSystemIndex);
32152
32312
  nonSystemIndex += 1;
@@ -32155,6 +32315,18 @@ function buildOpenAIRequest(options, images = NO_RESOLVED_IMAGES$3, preserveThin
32155
32315
  }
32156
32316
  break;
32157
32317
  }
32318
+ for (const entry of pairToolExchanges(batch, awaitingToolCallIds)) {
32319
+ messages.push({
32320
+ role: "tool",
32321
+ tool_call_id: entry.id,
32322
+ content: entry.content
32323
+ });
32324
+ pendingToolImages.push(...entry.images);
32325
+ if (awaitingToolCallIds.length > 0) {
32326
+ awaitingToolCallIds = awaitingToolCallIds.filter((id) => id !== entry.id);
32327
+ if (awaitingToolCallIds.length === 0) flushDeferred();
32328
+ }
32329
+ }
32158
32330
  if (awaitingToolCallIds.length === 0) flushToolImages();
32159
32331
  continue;
32160
32332
  }
@@ -32249,7 +32421,7 @@ function firstTextOf(content) {
32249
32421
  }
32250
32422
  if (!Array.isArray(content)) return void 0;
32251
32423
  for (const block of content) {
32252
- if (!isRecord$51(block)) continue;
32424
+ if (!isRecord$53(block)) continue;
32253
32425
  if (block.type === "text" && typeof block.text === "string") {
32254
32426
  const text = sanitizeText$7(block.text);
32255
32427
  if (text !== "") return text;
@@ -32307,7 +32479,7 @@ function isSideChannelTitleRequest(options) {
32307
32479
  const tools = options.tools;
32308
32480
  const toolLess = tools === void 0 || tools.length === 0;
32309
32481
  for (const message of messages) {
32310
- if (!isRecord$51(message)) continue;
32482
+ if (!isRecord$53(message)) continue;
32311
32483
  if (message.source?.kind === "dsh-session-title-llm") return true;
32312
32484
  const text = firstTextOf(message.content);
32313
32485
  if (toolLess && text !== void 0 && text.startsWith(TITLE_REQUEST_PROMPT_PREFIX)) return true;
@@ -32334,15 +32506,70 @@ function promptCacheKey(options) {
32334
32506
  if (isSideChannelTitleRequest(options)) return void 0;
32335
32507
  if (typeof options.sessionId === "string" && options.sessionId.trim() !== "") return `dsh-${options.sessionId.trim()}`;
32336
32508
  }
32337
- function anthropicUserContent$2(message, images, toolCallIds) {
32509
+ /**
32510
+ * The Anthropic beta that carries the context-management edit.
32511
+ *
32512
+ * `clear_thinking_20251015` is honoured only on the beta Messages API, so the
32513
+ * beta has to travel WITH the request; the official Kimi Anthropic protocol
32514
+ * asks for it on every thinking request (see the upstream
32515
+ * `kimiAnthropicProtocol`, which returns `betaFeatures: [CONTEXT_MANAGEMENT_BETA]`
32516
+ * for both the enabled and the disabled encoding).
32517
+ */
32518
+ const CONTEXT_MANAGEMENT_BETA = "context-management-2025-06-27";
32519
+ /**
32520
+ * The Anthropic context edit that clears stale thinking blocks.
32521
+ *
32522
+ * The edit is what "keep the thinking across turns" means on this wire: the
32523
+ * service clears the thinking it has already consumed instead of replaying it,
32524
+ * so a preserved thinking block stays affordable.
32525
+ */
32526
+ const CLEAR_THINKING_EDIT = "clear_thinking_20251015";
32527
+ /** The cache breakpoint the Anthropic wire marks with. */
32528
+ const ANTHROPIC_CACHE_CONTROL = { type: "ephemeral" };
32529
+ /**
32530
+ * The content block types that accept a cache breakpoint.
32531
+ *
32532
+ * The official provider injects the breakpoint on the last block of the last
32533
+ * message, and only when that block is one of the cacheable kinds; a block
32534
+ * that cannot carry the marker is left alone rather than given a field the
32535
+ * service would reject.
32536
+ */
32537
+ const ANTHROPIC_CACHEABLE_BLOCK_TYPES = /* @__PURE__ */ new Set([
32538
+ "text",
32539
+ "image",
32540
+ "document",
32541
+ "tool_use",
32542
+ "tool_result"
32543
+ ]);
32544
+ function anthropicUserContent$2(message, images, toolCallIds, media = {}) {
32338
32545
  if (!Array.isArray(message.content)) return [];
32339
32546
  const blocks = [];
32340
32547
  for (const block of message.content) {
32341
- if (!isRecord$51(block)) continue;
32548
+ if (!isRecord$53(block)) continue;
32342
32549
  if (block.type === "video") {
32343
- blocks.push({
32550
+ const reference = hostedReference(media.videoReferences, block);
32551
+ if (reference !== void 0) {
32552
+ blocks.push({
32553
+ type: "video",
32554
+ source: {
32555
+ type: "url",
32556
+ url: reference
32557
+ }
32558
+ });
32559
+ continue;
32560
+ }
32561
+ const outcome = videoBlockToInline(block, media.videos ?? /* @__PURE__ */ new Map(), media.videoAccepted === true, videoOmissionText$1);
32562
+ if ("inline" in outcome) blocks.push({
32563
+ type: "video",
32564
+ source: {
32565
+ type: "base64",
32566
+ media_type: outcome.inline.mediaType,
32567
+ data: outcome.inline.data
32568
+ }
32569
+ });
32570
+ else blocks.push({
32344
32571
  type: "text",
32345
- text: videoOmissionText$1("unsupported-wire", videoBlockLabel(block))
32572
+ text: outcome.omission
32346
32573
  });
32347
32574
  continue;
32348
32575
  }
@@ -32353,19 +32580,29 @@ function anthropicUserContent$2(message, images, toolCallIds) {
32353
32580
  text
32354
32581
  });
32355
32582
  } 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({
32583
+ const reference = hostedReference(media.imageReferences, block);
32584
+ if (reference !== void 0) blocks.push({
32358
32585
  type: "image",
32359
32586
  source: {
32360
- type: "base64",
32361
- media_type: inline.mediaType,
32362
- data: inline.data
32587
+ type: "url",
32588
+ url: reference
32363
32589
  }
32364
32590
  });
32365
- else blocks.push({
32366
- type: "text",
32367
- text: unavailableImageText$3(block)
32368
- });
32591
+ else {
32592
+ const inline = imageBlockToInline$2(block, images);
32593
+ if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$3.has(inline.mediaType)) blocks.push({
32594
+ type: "image",
32595
+ source: {
32596
+ type: "base64",
32597
+ media_type: inline.mediaType,
32598
+ data: inline.data
32599
+ }
32600
+ });
32601
+ else blocks.push({
32602
+ type: "text",
32603
+ text: unavailableImageText$3(block)
32604
+ });
32605
+ }
32369
32606
  } else if (block.type === "tool-result") {
32370
32607
  const callId = typeof block.toolCallId === "string" ? block.toolCallId : "";
32371
32608
  const resultBlocks = toolResultBlocks$1(block.content, images);
@@ -32382,20 +32619,28 @@ function anthropicUserContent$2(message, images, toolCallIds) {
32382
32619
  function anthropicAssistantContent$2(message, toolCallIds) {
32383
32620
  const blocks = [];
32384
32621
  for (const block of message.content) {
32385
- if (!isRecord$51(block)) continue;
32622
+ if (!isRecord$53(block)) continue;
32386
32623
  if (block.type === "text" && typeof block.text === "string") {
32387
32624
  const text = sanitizeText$7(block.text);
32388
32625
  if (text !== "") blocks.push({
32389
32626
  type: "text",
32390
32627
  text
32391
32628
  });
32629
+ } else if (block.type === "reasoning") {
32630
+ const thinkingText = typeof block.text === "string" ? sanitizeText$7(block.text) : "";
32631
+ const sig = typeof block.signature === "string" && block.signature.trim() !== "" ? block.signature : void 0;
32632
+ if (thinkingText !== "" || sig !== void 0) blocks.push({
32633
+ type: "thinking",
32634
+ thinking: thinkingText,
32635
+ ...sig === void 0 ? {} : { signature: sig }
32636
+ });
32392
32637
  } else if (block.type === "tool-call" && typeof block.name === "string") {
32393
32638
  const parsed = safeJsonParse$7(toolCallArguments$6(block.arguments));
32394
32639
  blocks.push({
32395
32640
  type: "tool_use",
32396
32641
  id: toolCallIds.normalize(typeof block.id === "string" && block.id !== "" ? block.id : `toolu_${blocks.length}`),
32397
32642
  name: block.name,
32398
- input: isRecord$51(parsed) ? parsed : {}
32643
+ input: isRecord$53(parsed) ? parsed : {}
32399
32644
  });
32400
32645
  }
32401
32646
  }
@@ -32426,7 +32671,7 @@ function mergeAnthropicMessages$2(entries) {
32426
32671
  return merged;
32427
32672
  }
32428
32673
  /** Build one `/v1/messages` body. */
32429
- function buildAnthropicRequest(options, images = NO_RESOLVED_IMAGES$3, media = {}) {
32674
+ function buildAnthropicRequest(options, images = NO_RESOLVED_IMAGES$3, media = {}, preserveThinking = preserveThinkingEnabled()) {
32430
32675
  const toolCallIds = new ToolCallIdNormalizer();
32431
32676
  const carriers = options.messages.filter((message) => message.role === "system" && messageToolsOf(message) !== void 0);
32432
32677
  const unsentDeclarations = carriers.reduce((total, message) => total + (messageToolsOf(message)?.length ?? 0), 0);
@@ -32436,13 +32681,13 @@ function buildAnthropicRequest(options, images = NO_RESOLVED_IMAGES$3, media = {
32436
32681
  if (isToolResultMessage$7(message)) {
32437
32682
  entries.push({
32438
32683
  role: "user",
32439
- content: anthropicUserContent$2(message, images, toolCallIds)
32684
+ content: anthropicUserContent$2(message, images, toolCallIds, media)
32440
32685
  });
32441
32686
  continue;
32442
32687
  }
32443
32688
  entries.push({
32444
32689
  role: message.role === "assistant" ? "assistant" : "user",
32445
- content: message.role === "assistant" ? anthropicAssistantContent$2(message, toolCallIds) : anthropicUserContent$2(message, images, toolCallIds)
32690
+ content: message.role === "assistant" ? anthropicAssistantContent$2(message, toolCallIds) : anthropicUserContent$2(message, images, toolCallIds, media)
32446
32691
  });
32447
32692
  }
32448
32693
  const systemParts = [
@@ -32453,31 +32698,54 @@ function buildAnthropicRequest(options, images = NO_RESOLVED_IMAGES$3, media = {
32453
32698
  const system = systemParts.length === 0 ? void 0 : systemParts.join("\n\n");
32454
32699
  const maxTokens = options.maxTokens ?? maxOutputTokensFor$5(options.model);
32455
32700
  const effort = mapReasoningEffort(options.reasoningEffort === void 0 ? void 0 : String(options.reasoningEffort));
32456
- const budget = thinkingBudgetFor(effort, maxTokens);
32701
+ const thinkingOff = effort === "none";
32702
+ const thinkingField = thinkingOff ? { type: "disabled" } : { type: "enabled" };
32703
+ const outputConfig = !thinkingOff && effort !== void 0 ? { effort } : void 0;
32704
+ const keepThinking = preserveThinking && !thinkingOff;
32705
+ const betas = [CONTEXT_MANAGEMENT_BETA];
32706
+ const contextManagement = keepThinking ? { edits: [{
32707
+ type: CLEAR_THINKING_EDIT,
32708
+ keep: "all"
32709
+ }] } : void 0;
32710
+ const messages = mergeAnthropicMessages$2(entries);
32711
+ const lastMessage = messages[messages.length - 1];
32712
+ if (lastMessage !== void 0 && Array.isArray(lastMessage.content) && lastMessage.content.length > 0) {
32713
+ const lastBlock = lastMessage.content[lastMessage.content.length - 1];
32714
+ if (lastBlock !== void 0 && ANTHROPIC_CACHEABLE_BLOCK_TYPES.has(String(lastBlock.type))) lastBlock.cache_control = { ...ANTHROPIC_CACHE_CONTROL };
32715
+ }
32716
+ const tools = options.tools && options.tools.length > 0 ? options.tools.map((tool) => ({
32717
+ name: tool.name,
32718
+ description: tool.description,
32719
+ input_schema: normalizeKimiToolSchema(tool.parameters)
32720
+ })) : [];
32721
+ if (tools.length > 0) tools[tools.length - 1] = {
32722
+ ...tools[tools.length - 1],
32723
+ cache_control: { ...ANTHROPIC_CACHE_CONTROL }
32724
+ };
32457
32725
  return {
32458
32726
  model: options.model,
32459
32727
  max_tokens: maxTokens,
32460
- messages: mergeAnthropicMessages$2(entries),
32461
- ...system === void 0 ? {} : { system },
32462
- ...options.temperature === void 0 || budget !== void 0 ? {} : { temperature: options.temperature },
32728
+ messages,
32729
+ ...system === void 0 ? {} : { system: [{
32730
+ type: "text",
32731
+ text: system,
32732
+ cache_control: { ...ANTHROPIC_CACHE_CONTROL }
32733
+ }] },
32734
+ ...options.temperature === void 0 || !thinkingOff ? {} : { temperature: options.temperature },
32463
32735
  ...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
- } }
32736
+ ...tools.length > 0 ? { tools } : {},
32737
+ thinking: thinkingField,
32738
+ ...outputConfig === void 0 ? {} : { output_config: outputConfig },
32739
+ ...contextManagement === void 0 ? {} : { context_management: contextManagement },
32740
+ betas
32473
32741
  };
32474
32742
  }
32475
32743
  /** Build the body for whichever endpoint serves `wire`. */
32476
32744
  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);
32745
+ if (isSideChannelTitleRequest(options)) return wire === "anthropic" ? buildAnthropicRequest(options, images, media, preserveThinking) : buildOpenAIRequest(options, images, preserveThinking, media);
32478
32746
  const cause = trackPrefixStability(options);
32479
32747
  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);
32748
+ return wire === "anthropic" ? buildAnthropicRequest(options, images, media, preserveThinking) : buildOpenAIRequest(options, images, preserveThinking, media);
32481
32749
  }
32482
32750
  /**
32483
32751
  * Reject a request the service would refuse for its size.
@@ -32519,7 +32787,7 @@ function walkJson(value, visit) {
32519
32787
  for (const item of value) walkJson(item, visit);
32520
32788
  return;
32521
32789
  }
32522
- if (!isRecord$51(value)) return;
32790
+ if (!isRecord$53(value)) return;
32523
32791
  visit(value);
32524
32792
  for (const nested of Object.values(value)) walkJson(nested, visit);
32525
32793
  }
@@ -32535,12 +32803,12 @@ function requestBodyBreakdown(body, carriesVideo = false) {
32535
32803
  const totalBytes = Buffer.byteLength(serialized, "utf8");
32536
32804
  let imageBytes = 0;
32537
32805
  walkJson(body, (node) => {
32538
- const url = isRecord$51(node.image_url) ? asString$21(node.image_url.url) : void 0;
32806
+ const url = isRecord$53(node.image_url) ? asString$21(node.image_url.url) : void 0;
32539
32807
  if (url?.startsWith("data:")) {
32540
32808
  imageBytes += Buffer.byteLength(url, "utf8");
32541
32809
  return;
32542
32810
  }
32543
- const source = isRecord$51(node.source) ? node.source : void 0;
32811
+ const source = isRecord$53(node.source) ? node.source : void 0;
32544
32812
  if (source && asString$21(source.data) !== void 0 && asString$21(source.media_type) !== void 0) imageBytes += Buffer.byteLength(asString$21(source.data) ?? "", "utf8");
32545
32813
  });
32546
32814
  const toolSchemaBytes = Buffer.byteLength(JSON.stringify(body.tools ?? []), "utf8");
@@ -32667,9 +32935,9 @@ function processOpenAIStreamLine(line, state) {
32667
32935
  }
32668
32936
  if (payload === "") return [];
32669
32937
  const chunk = safeJsonParse$7(payload);
32670
- if (!isRecord$51(chunk)) return [];
32938
+ if (!isRecord$53(chunk)) return [];
32671
32939
  const out = [];
32672
- const errorPayload = isRecord$51(chunk.error) ? chunk.error : void 0;
32940
+ const errorPayload = isRecord$53(chunk.error) ? chunk.error : void 0;
32673
32941
  if (errorPayload !== void 0) {
32674
32942
  const message = asString$21(errorPayload.message) ?? "unknown error";
32675
32943
  state.streamError = {
@@ -32679,22 +32947,22 @@ function processOpenAIStreamLine(line, state) {
32679
32947
  };
32680
32948
  throw new LlmError$1(`Kimi Code stream error: ${message}`, isContextOverflow(errorPayload) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
32681
32949
  }
32682
- const usage = isRecord$51(chunk.usage) ? chunk.usage : void 0;
32950
+ const usage = isRecord$53(chunk.usage) ? chunk.usage : void 0;
32683
32951
  if (usage) {
32684
32952
  state.sawUsage = true;
32685
32953
  const prompt = numberOr$8(usage.prompt_tokens, 0);
32686
- const details = isRecord$51(usage.prompt_tokens_details) ? usage.prompt_tokens_details : void 0;
32954
+ const details = isRecord$53(usage.prompt_tokens_details) ? usage.prompt_tokens_details : void 0;
32687
32955
  const cached = details ? numberOr$8(details.cached_tokens, 0) : 0;
32688
32956
  const written = details ? numberOr$8(details.cache_write_tokens, 0) : 0;
32689
32957
  state.inputTokens = Math.max(0, prompt - cached - written);
32690
32958
  state.cacheReadTokens = cached;
32691
32959
  state.cacheWriteTokens = written;
32692
32960
  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);
32961
+ if (isRecord$53(usage.completion_tokens_details)) state.reasoningTokens = numberOr$8(usage.completion_tokens_details.reasoning_tokens, state.reasoningTokens);
32694
32962
  }
32695
32963
  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;
32964
+ const choice = isRecord$53(choices[0]) ? choices[0] : void 0;
32965
+ const delta = isRecord$53(choice?.delta) ? choice.delta : void 0;
32698
32966
  if (delta) {
32699
32967
  for (const fragment of reasoningDialect.observeAll(delta)) {
32700
32968
  const text = sanitizeText$7(fragment.text);
@@ -32735,7 +33003,7 @@ function processOpenAIStreamLine(line, state) {
32735
33003
  }
32736
33004
  const toolDeltas = Array.isArray(delta.tool_calls) ? delta.tool_calls : [];
32737
33005
  for (const entry of toolDeltas) {
32738
- if (!isRecord$51(entry)) continue;
33006
+ if (!isRecord$53(entry)) continue;
32739
33007
  out.push(...applyOpenAIToolDelta(entry, state));
32740
33008
  }
32741
33009
  }
@@ -32749,7 +33017,7 @@ function processOpenAIStreamLine(line, state) {
32749
33017
  }
32750
33018
  function applyOpenAIToolDelta(entry, state) {
32751
33019
  const wireIndex = typeof entry.index === "number" ? entry.index : 0;
32752
- const fn = isRecord$51(entry.function) ? entry.function : {};
33020
+ const fn = isRecord$53(entry.function) ? entry.function : {};
32753
33021
  const out = [];
32754
33022
  let call = state.toolCalls.get(wireIndex);
32755
33023
  if (call === void 0) {
@@ -32804,12 +33072,12 @@ function processAnthropicStreamLine(line, state) {
32804
33072
  const payload = trimmed.slice(5).trim();
32805
33073
  if (payload === "" || payload === "[DONE]") return [];
32806
33074
  const event = safeJsonParse$7(payload);
32807
- if (!isRecord$51(event)) return [];
33075
+ if (!isRecord$53(event)) return [];
32808
33076
  const type = asString$21(event.type);
32809
33077
  const out = [];
32810
33078
  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;
33079
+ const message = isRecord$53(event.message) ? event.message : void 0;
33080
+ const usage = message && isRecord$53(message.usage) ? message.usage : void 0;
32813
33081
  if (usage) {
32814
33082
  state.sawUsage = true;
32815
33083
  state.inputTokens = numberOr$8(usage.input_tokens, 0);
@@ -32823,7 +33091,7 @@ function processAnthropicStreamLine(line, state) {
32823
33091
  }
32824
33092
  if (type === "content_block_start") {
32825
33093
  const contentIndex = numberOr$8(event.index, 0);
32826
- const block = isRecord$51(event.content_block) ? event.content_block : {};
33094
+ const block = isRecord$53(event.content_block) ? event.content_block : {};
32827
33095
  const blockType = asString$21(block.type);
32828
33096
  out.push(...closeCurrent$5(state));
32829
33097
  if (blockType === "tool_use") {
@@ -32873,7 +33141,7 @@ function processAnthropicStreamLine(line, state) {
32873
33141
  }
32874
33142
  if (type === "content_block_delta") {
32875
33143
  const contentIndex = numberOr$8(event.index, 0);
32876
- const delta = isRecord$51(event.delta) ? event.delta : {};
33144
+ const delta = isRecord$53(event.delta) ? event.delta : {};
32877
33145
  const deltaType = asString$21(delta.type);
32878
33146
  if (deltaType === "input_json_delta") {
32879
33147
  const pending = state.toolCalls.get(contentIndex);
@@ -32946,10 +33214,10 @@ function processAnthropicStreamLine(line, state) {
32946
33214
  return out;
32947
33215
  }
32948
33216
  if (type === "message_delta") {
32949
- const delta = isRecord$51(event.delta) ? event.delta : void 0;
33217
+ const delta = isRecord$53(event.delta) ? event.delta : void 0;
32950
33218
  const stop = delta ? asString$21(delta.stop_reason) : void 0;
32951
33219
  if (stop !== void 0 && stop !== "") state.finishReason = stop;
32952
- const usage = isRecord$51(event.usage) ? event.usage : void 0;
33220
+ const usage = isRecord$53(event.usage) ? event.usage : void 0;
32953
33221
  if (usage) {
32954
33222
  state.sawUsage = true;
32955
33223
  state.outputTokens = numberOr$8(usage.output_tokens, state.outputTokens);
@@ -32961,7 +33229,7 @@ function processAnthropicStreamLine(line, state) {
32961
33229
  return closeStream$4(state);
32962
33230
  }
32963
33231
  if (type === "error") {
32964
- const error = isRecord$51(event.error) ? event.error : {};
33232
+ const error = isRecord$53(event.error) ? event.error : {};
32965
33233
  const message = asString$21(error.message) ?? "unknown error";
32966
33234
  state.streamError = {
32967
33235
  vocabulary: "anthropic",
@@ -33552,7 +33820,7 @@ var SessionCacheStateStore = class {
33552
33820
  /** Validate one parsed document, dropping entries that do not describe a record. */
33553
33821
  function normalizeDocument(value) {
33554
33822
  const sessions = {};
33555
- if (isRecord$50(value) && isRecord$50(value.sessions)) for (const [key, entry] of Object.entries(value.sessions)) {
33823
+ if (isRecord$52(value) && isRecord$52(value.sessions)) for (const [key, entry] of Object.entries(value.sessions)) {
33556
33824
  const record = normalizeRecord(entry);
33557
33825
  if (record !== void 0) sessions[key] = record;
33558
33826
  }
@@ -33562,7 +33830,7 @@ function normalizeDocument(value) {
33562
33830
  };
33563
33831
  }
33564
33832
  function normalizeRecord(value) {
33565
- if (!isRecord$50(value)) return void 0;
33833
+ if (!isRecord$52(value)) return void 0;
33566
33834
  const lastActiveAt = finite(value.lastActiveAt);
33567
33835
  const updatedAt = finite(value.updatedAt);
33568
33836
  if (lastActiveAt === void 0 || updatedAt === void 0) return void 0;
@@ -33650,7 +33918,7 @@ function resolveSessionCacheView(sessionId, memory, durable) {
33650
33918
  }
33651
33919
  /** The process-wide store the adapter writes and the routes read. */
33652
33920
  const sessionCacheState = new SessionCacheStateStore();
33653
- function isRecord$50(value) {
33921
+ function isRecord$52(value) {
33654
33922
  return typeof value === "object" && value !== null && !Array.isArray(value);
33655
33923
  }
33656
33924
  function finite(value) {
@@ -33820,9 +34088,9 @@ function bodyDigest(raw, token) {
33820
34088
  const text = raw.trim();
33821
34089
  if (text === "") return "";
33822
34090
  const parsed = parseJson(text);
33823
- if (parsed.ok && isRecord$49(parsed.value)) {
34091
+ if (parsed.ok && isRecord$51(parsed.value)) {
33824
34092
  const root = parsed.value;
33825
- const nested = isRecord$49(root.error) ? root.error : void 0;
34093
+ const nested = isRecord$51(root.error) ? root.error : void 0;
33826
34094
  const code = firstString(nested?.code) ?? firstString(root.code) ?? firstString(root.error_code) ?? "";
33827
34095
  const message = nested !== void 0 ? firstString(nested.message) ?? firstString(nested.code) ?? "" : typeof root.error === "string" ? root.error : firstString(root.message) ?? firstString(root.detail) ?? "";
33828
34096
  const composed = [code === "" ? "" : "code=" + code, message].filter((part) => part !== "").join(" ");
@@ -33858,7 +34126,7 @@ function normalizeFileId(value) {
33858
34126
  */
33859
34127
  function readFileId$1(value, depth = 0) {
33860
34128
  if (depth > 3) return void 0;
33861
- if (!isRecord$49(value)) return void 0;
34129
+ if (!isRecord$51(value)) return void 0;
33862
34130
  const direct = normalizeFileId(value.id);
33863
34131
  if (direct !== void 0) return direct;
33864
34132
  for (const key of NESTED_ID_KEYS) {
@@ -33905,7 +34173,7 @@ function mediaFileCacheKey(input) {
33905
34173
  contentSha256(input.data)
33906
34174
  ].join("|");
33907
34175
  }
33908
- function isRecord$49(value) {
34176
+ function isRecord$51(value) {
33909
34177
  return typeof value === "object" && value !== null && !Array.isArray(value);
33910
34178
  }
33911
34179
  function firstString(value) {
@@ -35905,7 +36173,7 @@ async function getKimiCodeWebStatus(store, modelSettings, preferences, options =
35905
36173
  const credentials = await store.read();
35906
36174
  const settings = preferences ? preferences.status() : await modelSettings.read();
35907
36175
  const poolData = accountPool === void 0 ? null : await accountPool.read().catch(() => null);
35908
- const accounts = accountPool === void 0 ? [] : await accountPool.listAccounts().catch(() => []);
36176
+ const accounts = accountPool === void 0 || poolData === null ? [] : accountPool.summariesOf(poolData);
35909
36177
  const activeAccount = accounts.find((entry) => entry.id === poolData?.activeAccountId) ?? accounts.find((entry) => entry.isPrimary) ?? accounts[0];
35910
36178
  const activePoolAccount = poolData === null ? void 0 : poolData.accounts.find((entry) => entry.id === poolData.activeAccountId) ?? poolData.accounts.find((entry) => entry.isPrimary) ?? poolData.accounts[0];
35911
36179
  const active = (accountPool === void 0 || activePoolAccount === void 0 ? void 0 : await accountPool.getFreshCredential(activePoolAccount.id, options.fetchFn ?? fetch).catch(() => void 0)) ?? activePoolAccount?.credentials ?? credentials;
@@ -36083,6 +36351,31 @@ function hitRatioOf(cached, fresh) {
36083
36351
  const total = cached + fresh;
36084
36352
  return total > 0 ? cached / total : null;
36085
36353
  }
36354
+ /**
36355
+ * Name the account a re-authorization has to sign back in as.
36356
+ *
36357
+ * `relogin` on the card clears one row's failure marker and then runs an ordinary
36358
+ * device-code sign-in, which authorizes whichever account the browser already
36359
+ * is. Without this check the pool could accept a DIFFERENT account, replace that
36360
+ * account's row and move the rotation with it, while the row the user clicked
36361
+ * stayed broken — the card then looked like the pool had switched on its own.
36362
+ *
36363
+ * The comparison is over identity, never tokens: the account id the token
36364
+ * carries, and only when neither side carries one, the address.
36365
+ */
36366
+ async function signInGuard(pool, accountId) {
36367
+ const row = (await pool.read().catch(() => null))?.accounts.find((account) => account.id === accountId);
36368
+ if (row === void 0) return () => "要重新登录的账号已不在号池中,本次登录已取消,号池未改动。";
36369
+ const expectedUserId = row.userId ?? row.credentials.userId;
36370
+ const expectedEmail = (row.email ?? row.credentials.email)?.trim().toLowerCase() || void 0;
36371
+ return (credentials) => {
36372
+ const signedUserId = credentials.userId;
36373
+ const signedEmail = credentials.email?.trim().toLowerCase() || void 0;
36374
+ if (expectedUserId !== void 0 && signedUserId !== void 0 ? expectedUserId === signedUserId : expectedEmail !== void 0 && signedEmail !== void 0 ? expectedEmail === signedEmail : true) return null;
36375
+ const signedName = credentials.email ?? signedUserId ?? "未知账号";
36376
+ return `重新登录的是「${row.alias}」,本次登录的却是「${signedName}」,已取消,号池与凭据都没有改动。`;
36377
+ };
36378
+ }
36086
36379
  /** Register the Kimi Code settings routes under `/kimi-code/api`. */
36087
36380
  function registerKimiCodeRoutes(ctx, store, modelSettings, preferences, options = {}, accountPool = options.accountPool) {
36088
36381
  const fetchFn = options.fetchFn ?? fetch;
@@ -36234,12 +36527,15 @@ function registerKimiCodeRoutes(ctx, store, modelSettings, preferences, options
36234
36527
  });
36235
36528
  const body = await readRequestJson$9(request);
36236
36529
  const requested = isRegion$4(body.region) ? body.region : void 0;
36530
+ const expectAccountId = typeof body.accountId === "string" ? body.accountId : void 0;
36531
+ const accept = accountPool === void 0 || expectAccountId === void 0 ? void 0 : await signInGuard(accountPool, expectAccountId);
36237
36532
  return sendJson$9(response, 200, {
36238
36533
  ok: true,
36239
36534
  value: await beginWebLogin(store, {
36240
36535
  fetchFn,
36241
36536
  region: requested,
36242
36537
  openBrowser: options.openBrowser,
36538
+ ...accept === void 0 ? {} : { accept },
36243
36539
  enrich: async (credentials) => {
36244
36540
  const profile = await fetchProfile(store, {
36245
36541
  fetchFn,
@@ -36692,7 +36988,7 @@ const KIMI_VIDEO_TOOL_NAME = "kimi_attach_video";
36692
36988
  * routed provider is this one, which is the same contract `read_image` states
36693
36989
  * for a modality the active model does not declare.
36694
36990
  */
36695
- const KIMI_CODE_PROVIDER$1 = "kimi-code";
36991
+ const KIMI_CODE_PROVIDER$2 = "kimi-code";
36696
36992
  /**
36697
36993
  * Refuse when the session's routed model cannot accept video.
36698
36994
  *
@@ -36706,7 +37002,7 @@ async function assertVideoCapableRoute(ctx, exec, source) {
36706
37002
  const provider = routed?.provider ?? agent?.options?.provider;
36707
37003
  const model = routed?.model ?? agent?.options?.model;
36708
37004
  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");
37005
+ 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
37006
  const llm = ctx.get("llm");
36711
37007
  if (llm === void 0) throw new HarnessError(`cannot attach "${source}": the LLM service is unavailable`, "KIMI_VIDEO_NO_LLM");
36712
37008
  const active = await llm.resolveModelInfo(provider, model, exec.signal);
@@ -37015,6 +37311,18 @@ const MESSAGES_PATH$1 = "/messages";
37015
37311
  /** Anthropic protocol revision the endpoint documents. */
37016
37312
  const ANTHROPIC_VERSION$2 = "2023-06-01";
37017
37313
  /**
37314
+ * Beta marker the interleaved-thinking protocol needs.
37315
+ *
37316
+ * The Messages endpoint on this route accepts signed `thinking` blocks and
37317
+ * streams reasoning back in its own channel, and the Anthropic dialect gates
37318
+ * that on the interleaved-thinking beta. The official MiniMax agent sends the
37319
+ * marker on every Messages request (its `model-resolver-helpers.ts`), so a
37320
+ * request without it is shaped differently from the one the service is
37321
+ * documented against - and the replay path on this line has signed thinking
37322
+ * blocks to send.
37323
+ */
37324
+ const ANTHROPIC_INTERLEAVED_THINKING_BETA = "interleaved-thinking-2025-05-14";
37325
+ /**
37018
37326
  * Byte ceiling the guard enforces on one request body.
37019
37327
  *
37020
37328
  * WHY THIS IS NOT KIMI'S 2 MB FIGURE
@@ -37103,13 +37411,34 @@ function maxRequestImageBytes(env = process.env) {
37103
37411
  /**
37104
37412
  * Product token this plugin reports.
37105
37413
  *
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.
37414
+ * This is the plugin's own identity, and it stays honest. MiniMax Code's own
37415
+ * telemetry headers are deliberately NOT forged: this is a third-party client of
37416
+ * the subscription, and claiming to be the official app is both dishonest and,
37417
+ * per the app's own terms, grounds for suspending the subscription.
37418
+ *
37419
+ * The surfaces that carry this token are exactly the first-party ones (the
37420
+ * check-in call, the reset-card call, the usage read), and those are the ones
37421
+ * that must be able to say who is asking. The MODEL request carries
37422
+ * {@link MINIMAX_AGENT_USER_AGENT} instead - a different surface, a different
37423
+ * identifier.
37110
37424
  */
37111
37425
  const USER_AGENT$3 = "dsh-chatgpt-subscription (+https://github.com/Aa728848/dsh-chatgpt-subscription)";
37112
37426
  /**
37427
+ * Client identifier the managed agent's MODEL requests carry.
37428
+ *
37429
+ * The managed agent classifies a model request by this header, and the official
37430
+ * MiniMax agent sends exactly this value (`model-resolver-helpers.ts:11`, and
37431
+ * the same identifier the Matrix media face uses). A model request that names
37432
+ * something else is shaped differently from the one the service is documented
37433
+ * against - and the model request is the surface that has to speak the
37434
+ * protocol's own identifier.
37435
+ *
37436
+ * It is a separate constant from {@link USER_AGENT} on purpose: the first-party
37437
+ * surfaces keep identifying this plugin honestly, and only the model request
37438
+ * speaks as the agent the endpoint expects.
37439
+ */
37440
+ const MINIMAX_AGENT_USER_AGENT = "MiniMaxAgent";
37441
+ /**
37113
37442
  * How long before expiry a token is replaced.
37114
37443
  *
37115
37444
  * The measured MiniMax Code access token lives ONE HOUR, not the day an earlier
@@ -37238,6 +37567,937 @@ function computeMinimaxAuthOwner(credentials, accountId) {
37238
37567
  return hash.digest("hex").slice(0, 32);
37239
37568
  }
37240
37569
  //#endregion
37570
+ //#region src/host/minimax-code/runtime-enhancements.ts
37571
+ /** 本模块只对 MiniMax Code 这条线路生效。 */
37572
+ const MINIMAX_CODE_PROVIDER$1 = "minimax-code";
37573
+ /**
37574
+ * 判断一个值是不是普通对象(原型是 `Object.prototype` 或 `null`)。
37575
+ * @param value - 任意值。
37576
+ * @returns 是普通对象时为 true。
37577
+ */
37578
+ function isPlainRecord$1(value) {
37579
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
37580
+ const prototype = Object.getPrototypeOf(value);
37581
+ return prototype === Object.prototype || prototype === null;
37582
+ }
37583
+ /**
37584
+ * 判断一个值是不是普通对象(不要求原型,数组也算对象)。
37585
+ * @param value - 任意值。
37586
+ * @returns 是对象时为 true。
37587
+ */
37588
+ function isRecord$50(value) {
37589
+ return typeof value === "object" && value !== null;
37590
+ }
37591
+ /**
37592
+ * 读一个未知字段为非空字符串。
37593
+ * @param value - 候选值。
37594
+ * @returns 字符串,或任何其它类型的 undefined。
37595
+ */
37596
+ function stringOf$4(value) {
37597
+ return typeof value === "string" && value !== "" ? value : void 0;
37598
+ }
37599
+ /**
37600
+ * 读一次工具调用所属的线路。
37601
+ *
37602
+ * provider 的四个来源按可靠性排序:**请求头快照**(唯一反映「已经真的路由到
37603
+ * 哪个 provider」的那一份)→ **模型选择面**(首步还没有请求头时唯一还能说出
37604
+ * 这一场走哪条线路的地方)→ **agent 选项**(还没发出请求时唯一的意图)→
37605
+ * **agent 自身的 provider 字段**(最后的兜底)。
37606
+ *
37607
+ * 每一处读取都独立 try/catch:任何一处抛错都只是「这一处读不到」,不改变
37608
+ * 其余来源的行为,也不让整次读取失败。
37609
+ *
37610
+ * @param agent - 事件里的调用方 agent。
37611
+ * @returns 线路信息;读不到的字段省略。
37612
+ */
37613
+ function minimaxSessionRouteOf(agent) {
37614
+ const record = isRecord$50(agent) ? agent : void 0;
37615
+ const session = record?.session;
37616
+ let provider;
37617
+ try {
37618
+ provider = stringOf$4(session?.requestHeader?.()?.config?.provider);
37619
+ } catch {
37620
+ provider = void 0;
37621
+ }
37622
+ if (provider === void 0) try {
37623
+ provider = stringOf$4(record?.model?.current?.()?.provider);
37624
+ } catch {
37625
+ provider = void 0;
37626
+ }
37627
+ if (provider === void 0) provider = stringOf$4(record?.options?.provider);
37628
+ if (provider === void 0) provider = stringOf$4(record?.provider);
37629
+ const sessionId = stringOf$4(session?.header?.id) ?? stringOf$4(record?.id);
37630
+ return {
37631
+ ...provider === void 0 ? {} : { provider },
37632
+ ...sessionId === void 0 ? {} : { sessionId }
37633
+ };
37634
+ }
37635
+ /**
37636
+ * 判断一次工具调用是不是 MiniMax Code 这条线路上的。
37637
+ * @param agent - 事件里的调用方 agent。
37638
+ * @returns 是 MiniMax Code 时为 true。
37639
+ */
37640
+ function isMinimaxSession(agent) {
37641
+ return minimaxSessionRouteOf(agent).provider === MINIMAX_CODE_PROVIDER$1;
37642
+ }
37643
+ /** 无损的数字字符串:允许小数、指数、前导负号。 */
37644
+ const NUMERIC_STRING = /^-?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/u;
37645
+ /**
37646
+ * 顶层已知的数字字段(没有 schema 时按字段名强转)。
37647
+ *
37648
+ * 这些是本宿主工具面里**本来就该是数字**的字段:模型把它们写成字符串时,
37649
+ * schema 校验会直接失败,而它们强转回来是**无损**的。
37650
+ */
37651
+ const NUMERIC_TOOL_FIELDS = Object.freeze([
37652
+ "offset",
37653
+ "limit",
37654
+ "timeout",
37655
+ "timeoutMs",
37656
+ "timeout_ms",
37657
+ "line",
37658
+ "delta_x",
37659
+ "delta_y",
37660
+ "x",
37661
+ "y",
37662
+ "ref"
37663
+ ]);
37664
+ /**
37665
+ * 顶层已知的布尔字段(没有 schema 时按字段名强转)。
37666
+ *
37667
+ * 只有字面 `"true"` / `"false"` 才转:别的写法(`"1"`、`"yes"`)在布尔
37668
+ * 字段上是**有歧义**的,转过去等于替模型猜了一个开关的状态。
37669
+ */
37670
+ const BOOLEAN_TOOL_FIELDS = Object.freeze([
37671
+ "replace_all",
37672
+ "wait",
37673
+ "run_in_background",
37674
+ "new_tab",
37675
+ "multi_select"
37676
+ ]);
37677
+ /**
37678
+ * 按 schema 强转一个值,并把强转过程记进 `fixes`。
37679
+ *
37680
+ * 只认三种形状:
37681
+ *
37682
+ * - `type: 'array'`:值是单键对象 `{ item: X }` 时拆包(官方 Pi 的
37683
+ * `item_wrapper` 形状),然后按 `items` 递归每个元素;
37684
+ * - `type: 'number' | 'integer'`:值是**无损**数字字符串时转成数字
37685
+ * (`integer` 还要求转出来确实是整数,`"2.5"` 不转);
37686
+ * - `type: 'boolean'`:值是 `"true"` / `"false"` 时转成布尔。
37687
+ *
37688
+ * @param value - 当前值。
37689
+ * @param schema - 这一层的 JSON Schema。
37690
+ * @param fixes - 修复项累加器。
37691
+ * @returns 强转后的值。
37692
+ */
37693
+ function coerceBySchema(value, schema, fixes) {
37694
+ if (!isRecord$50(schema)) return value;
37695
+ const type = schema["type"];
37696
+ if (type === "array") {
37697
+ let current = value;
37698
+ if (isPlainRecord$1(current) && Object.keys(current).length === 1 && "item" in current) {
37699
+ const inner = current["item"];
37700
+ current = Array.isArray(inner) ? [...inner] : [inner];
37701
+ fixes.push("item_wrapper");
37702
+ }
37703
+ const items = schema["items"];
37704
+ if (Array.isArray(current) && items !== void 0) current = current.map((entry) => coerceBySchema(entry, items, fixes));
37705
+ return current;
37706
+ }
37707
+ if (type === "number" || type === "integer") {
37708
+ if (typeof value === "string" && NUMERIC_STRING.test(value)) {
37709
+ const parsed = Number(value);
37710
+ if (Number.isFinite(parsed) && (type !== "integer" || Number.isInteger(parsed))) {
37711
+ fixes.push("number_string");
37712
+ return parsed;
37713
+ }
37714
+ }
37715
+ return value;
37716
+ }
37717
+ if (type === "boolean") {
37718
+ if (value === "true") {
37719
+ fixes.push("boolean_string");
37720
+ return true;
37721
+ }
37722
+ if (value === "false") {
37723
+ fixes.push("boolean_string");
37724
+ return false;
37725
+ }
37726
+ return value;
37727
+ }
37728
+ if (type === "object") {
37729
+ const properties = schema["properties"];
37730
+ if (!isPlainRecord$1(value) || !isRecord$50(properties)) return value;
37731
+ const next = { ...value };
37732
+ for (const [key, subSchema] of Object.entries(properties)) {
37733
+ if (!(key in next)) continue;
37734
+ next[key] = coerceBySchema(next[key], subSchema, fixes);
37735
+ }
37736
+ return next;
37737
+ }
37738
+ const properties = schema["properties"];
37739
+ if (isPlainRecord$1(value) && isRecord$50(properties)) {
37740
+ const next = { ...value };
37741
+ for (const [key, subSchema] of Object.entries(properties)) {
37742
+ if (!(key in next)) continue;
37743
+ next[key] = coerceBySchema(next[key], subSchema, fixes);
37744
+ }
37745
+ return next;
37746
+ }
37747
+ const items = schema["items"];
37748
+ if (Array.isArray(value) && items !== void 0) return value.map((entry) => coerceBySchema(entry, items, fixes));
37749
+ return value;
37750
+ }
37751
+ /**
37752
+ * 没有 schema 时按字段名做的顶层强转。
37753
+ *
37754
+ * 只动**顶层**的已知字段:嵌套结构没有 schema 就没有依据,猜不得。
37755
+ * @param args - 参数副本。
37756
+ * @param fixes - 修复项累加器。
37757
+ */
37758
+ function coerceByKnownFields(args, fixes) {
37759
+ for (const field of NUMERIC_TOOL_FIELDS) {
37760
+ const current = args[field];
37761
+ if (typeof current !== "string" || !NUMERIC_STRING.test(current)) continue;
37762
+ const parsed = Number(current);
37763
+ if (!Number.isFinite(parsed)) continue;
37764
+ args[field] = parsed;
37765
+ fixes.push("number_string");
37766
+ }
37767
+ for (const field of BOOLEAN_TOOL_FIELDS) {
37768
+ const current = args[field];
37769
+ if (current === "true") {
37770
+ args[field] = true;
37771
+ fixes.push("boolean_string");
37772
+ } else if (current === "false") {
37773
+ args[field] = false;
37774
+ fixes.push("boolean_string");
37775
+ }
37776
+ }
37777
+ }
37778
+ /**
37779
+ * 修复一次工具调用的参数。
37780
+ *
37781
+ * 三步,顺序固定:
37782
+ *
37783
+ * 1. **`edits` 字符串解析**(官方 `edit-prepare-arguments.ts`):`edits` 是
37784
+ * JSON 字符串时解析回数组。解析失败就**原样留着**,让 schema 校验照常报错
37785
+ * ——在这里猜一个数组比不猜更糟。
37786
+ * 2. **按 schema 强转**(官方 `direct-call-arguments.ts` / `input-validation.ts`):
37787
+ * `item_wrapper` 拆包、数字字符串转数字、布尔字符串转布尔,并递归进
37788
+ * `properties` 与 `items`。
37789
+ * 3. **按字段名强转**:**没有传 schema** 时才做,因为那时唯一的依据就是字段名。
37790
+ *
37791
+ * 入参**不被修改**:返回值是一份新对象。
37792
+ *
37793
+ * @param toolName - 工具名(只用于日志与将来按工具定制规则)。
37794
+ * @param args - 原始参数。
37795
+ * @param schema - 该工具的 JSON Schema(参数面),可选。
37796
+ * @returns 修复后的参数与修复项列表。
37797
+ */
37798
+ function repairMinimaxToolArguments(toolName, args, schema) {
37799
+ if (!isPlainRecord$1(args)) return {
37800
+ value: args,
37801
+ fixes: []
37802
+ };
37803
+ const fixes = [];
37804
+ const working = { ...args };
37805
+ if (typeof working["edits"] === "string") {
37806
+ const parsed = tryParseJson(working["edits"]);
37807
+ if (Array.isArray(parsed)) {
37808
+ working["edits"] = parsed;
37809
+ fixes.push("edits_json_string");
37810
+ }
37811
+ }
37812
+ if (schema !== void 0) {
37813
+ const coerced = coerceBySchema(working, schema, fixes);
37814
+ if (isPlainRecord$1(coerced)) Object.assign(working, coerced);
37815
+ } else coerceByKnownFields(working, fixes);
37816
+ return {
37817
+ value: working,
37818
+ fixes
37819
+ };
37820
+ }
37821
+ /**
37822
+ * 解析一段 JSON,失败时返回 undefined(不抛)。
37823
+ * @param text - 待解析的文本。
37824
+ * @returns 解析结果,或 undefined。
37825
+ */
37826
+ function tryParseJson(text) {
37827
+ try {
37828
+ return JSON.parse(text);
37829
+ } catch {
37830
+ return;
37831
+ }
37832
+ }
37833
+ /**
37834
+ * 直接调用需要提醒的工具名。
37835
+ *
37836
+ * 这些是**原生**工具:在 PTC 模式里模型只能直接调 `run_code`,原生工具要
37837
+ * 从 `run_code` 程序里调。
37838
+ */
37839
+ const DIRECT_CALL_REMINDER_TOOLS = Object.freeze([
37840
+ "read",
37841
+ "edit",
37842
+ "write",
37843
+ "grep",
37844
+ "glob",
37845
+ "win_bash",
37846
+ "bash",
37847
+ "pwsh"
37848
+ ]);
37849
+ /**
37850
+ * 各个原生工具在 `run_code` 里的调用示例参数。
37851
+ *
37852
+ * 例子必须**真的能跑**:提醒里给一个跑不通的示例,比不给示例更糟。
37853
+ */
37854
+ const DIRECT_CALL_EXAMPLE_ARGS = Object.freeze({
37855
+ read: "{ file_path: \"README.md\" }",
37856
+ write: "{ file_path: \"README.md\", content: \"...\" }",
37857
+ edit: "{ file_path: \"README.md\", old_string: \"...\", new_string: \"...\" }",
37858
+ grep: "{ pattern: \"TODO\", path: \".\" }",
37859
+ glob: "{ pattern: \"src/**/*.ts\" }",
37860
+ bash: "{ command: \"ls -la\" }",
37861
+ win_bash: "{ command: \"ls -la\" }",
37862
+ pwsh: "{ command: \"Get-ChildItem\" }"
37863
+ });
37864
+ /**
37865
+ * 造一条 `run_code` 调用示例。
37866
+ * @param toolName - 工具名。
37867
+ * @returns 一句可读的调用示例。
37868
+ */
37869
+ function directCallExampleOf(toolName) {
37870
+ return `await tools.${toolName}(${DIRECT_CALL_EXAMPLE_ARGS[toolName] ?? "{ ... }"})`;
37871
+ }
37872
+ /**
37873
+ * 渲染 PTC 直调提醒。
37874
+ *
37875
+ * 文案与官方 `direct-call-reminder.ts` 同形:
37876
+ *
37877
+ * ```text
37878
+ * <system-reminder>
37879
+ * 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.
37880
+ * </system-reminder>
37881
+ * ```
37882
+ *
37883
+ * @param toolNames - 被直接调用的工具名。
37884
+ * @returns 提醒正文。
37885
+ */
37886
+ function renderDirectCallReminder(toolNames) {
37887
+ const names = [...new Set(toolNames.filter((name) => name !== ""))];
37888
+ if (names.length === 0) return [
37889
+ "<system-reminder>",
37890
+ "Do not call tools directly in this turn. Call them inside run_code. Put your next tool calls in one run_code program.",
37891
+ "</system-reminder>"
37892
+ ].join("\n");
37893
+ return [
37894
+ "<system-reminder>",
37895
+ `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.`,
37896
+ "</system-reminder>"
37897
+ ].join("\n");
37898
+ }
37899
+ /**
37900
+ * 官方提醒文案的后缀:提醒只对当前这一轮有效。
37901
+ * @returns 后缀正文。
37902
+ */
37903
+ 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.";
37904
+ /**
37905
+ * 渲染「同一个动作立刻重复」提醒。
37906
+ *
37907
+ * 与官方 `packages/agent-modules/runaway-guard/src/reminder.ts` 逐字一致。
37908
+ * @param occurrences - 连击次数。
37909
+ * @returns 提醒正文。
37910
+ */
37911
+ function renderExactActionRepeatReminder(occurrences) {
37912
+ 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}`;
37913
+ }
37914
+ /**
37915
+ * 渲染「同一族错误连续发生」提醒。
37916
+ *
37917
+ * 与官方 `packages/agent-modules/runaway-guard/src/reminder.ts` 逐字一致。
37918
+ * @param occurrences - 连击次数。
37919
+ * @returns 提醒正文。
37920
+ */
37921
+ function renderSameErrorFamilyReminder(occurrences) {
37922
+ 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}`;
37923
+ }
37924
+ /**
37925
+ * 渲染「反复轮询同一个后台任务」提醒。
37926
+ *
37927
+ * 与官方 `packages/agent-modules/runaway-guard/src/reminder.ts` 逐字一致:
37928
+ * 三次读同一个任务时写的是 `Three`,其它次数写数字。
37929
+ * @param occurrences - 连击次数。
37930
+ * @returns 提醒正文。
37931
+ */
37932
+ function renderPollingRepeatReminder(occurrences) {
37933
+ return [
37934
+ "<system-reminder>",
37935
+ `${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.`,
37936
+ "This reminder applies only to the current Turn. Do not save or generalize it into Memory, Skills, or other persistent instructions.",
37937
+ "</system-reminder>"
37938
+ ].join("\n");
37939
+ }
37940
+ /**
37941
+ * 轮询类工具名(后台任务的结果读取)。
37942
+ *
37943
+ * 这两个工具读的是后台任务的状态;反复读同一个任务而输出没变,就是官方说的
37944
+ * 「polling repeat」。
37945
+ */
37946
+ const POLLING_TOOL_NAMES = Object.freeze(["job_output", "task_output"]);
37947
+ /**
37948
+ * 规范化一段错误文本,取它的「族」。
37949
+ *
37950
+ * 族的作用是**把同一类错误认成同一类**:路径里的数字、id、时间戳都不该让
37951
+ * 两次一模一样的失败看起来是两回事。
37952
+ * @param text - 错误文本。
37953
+ * @returns 族标识。
37954
+ */
37955
+ function errorFamilyOf(text) {
37956
+ if (text === void 0 || text === "") return "unknown";
37957
+ return (text.split(/\r?\n/, 1)[0] ?? "").replace(/\d+/g, "#").slice(0, 200);
37958
+ }
37959
+ /**
37960
+ * 把参数规范化成可比较的字符串(键排序)。
37961
+ * @param value - 参数值。
37962
+ * @returns 规范化后的 JSON 文本。
37963
+ */
37964
+ function canonicalize(value) {
37965
+ return JSON.stringify(sortJsonValue$1(value));
37966
+ }
37967
+ /**
37968
+ * 深拷贝一份键排序后的 JSON 值。
37969
+ * @param value - 任意值。
37970
+ * @returns 排序后的副本。
37971
+ */
37972
+ function sortJsonValue$1(value) {
37973
+ if (Array.isArray(value)) return value.map(sortJsonValue$1);
37974
+ if (isPlainRecord$1(value)) {
37975
+ const sorted = {};
37976
+ for (const key of Object.keys(value).sort()) sorted[key] = sortJsonValue$1(value[key]);
37977
+ return sorted;
37978
+ }
37979
+ return value;
37980
+ }
37981
+ /**
37982
+ * 造一台工具级失控守卫。
37983
+ *
37984
+ * 三种可提醒信号(顺序即官方提醒优先级):
37985
+ *
37986
+ * 1. `same_error_family` —— 同一个工具连续报同一族错误;
37987
+ * 2. `exact_action_repeat` —— 同一次动作(同名 + 同参数)立刻重复;
37988
+ * 3. `polling_repeat` —— 连续轮询同一个后台任务而输出没变。
37989
+ *
37990
+ * `abab_action_cycle`(A B A B 的循环)**只记录不提醒**:官方把它排在提醒
37991
+ * 候选之外——模型在两个动作之间来回跳时,提醒它「别重复」是没有意义的。
37992
+ *
37993
+ * 每轮**至多一条**提醒:官方在发出第一条后就把本轮的提醒机会用掉了。
37994
+ *
37995
+ * @param options - 守卫选项。
37996
+ * @returns 守卫。
37997
+ */
37998
+ function createMinimaxRunawayGuard(options = {}) {
37999
+ const threshold = options.remindAfterOccurrences ?? 3;
38000
+ /** 同一次动作的连击。 */
38001
+ let actionStreak;
38002
+ /** 同一族错误的连击(键是工具名 + 错误族)。 */
38003
+ const errorStreaks = /* @__PURE__ */ new Map();
38004
+ /** 轮询连击(键是工具名)。 */
38005
+ const pollingStreaks = /* @__PURE__ */ new Map();
38006
+ /** 最近几次动作,用来认 A B A B 的循环。 */
38007
+ const recentActions = [];
38008
+ /** 当前正在计数的 A B 循环对。 */
38009
+ let activeAbabKey;
38010
+ /** 本轮是否已经提醒过。 */
38011
+ let reminderAttempted = false;
38012
+ /** 观察到的信号。 */
38013
+ const signals = [];
38014
+ /**
38015
+ * 记一条信号。
38016
+ * @param kind - 信号种类。
38017
+ * @param occurrences - 连击次数。
38018
+ * @param toolName - 工具名。
38019
+ */
38020
+ const record = (kind, occurrences, toolName) => {
38021
+ signals.push({
38022
+ kind,
38023
+ occurrences,
38024
+ toolName
38025
+ });
38026
+ };
38027
+ /**
38028
+ * 判断这次执行是不是一次「原地不动」的轮询。
38029
+ * @param observation - 观察事实。
38030
+ * @returns 是轮询时为 true。
38031
+ */
38032
+ const isPolling = (observation) => {
38033
+ if (!POLLING_TOOL_NAMES.includes(observation.toolName)) return false;
38034
+ return (isPlainRecord$1(observation.arguments) ? observation.arguments : void 0)?.["wait"] !== true;
38035
+ };
38036
+ return {
38037
+ observe(observation) {
38038
+ const toolName = observation.toolName;
38039
+ const actionKey = `${toolName}\u0000${canonicalize(observation.arguments)}`;
38040
+ const countsAsAction = !POLLING_TOOL_NAMES.includes(toolName);
38041
+ if (countsAsAction) {
38042
+ if (actionStreak?.key === actionKey) actionStreak = {
38043
+ key: actionKey,
38044
+ count: actionStreak.count + 1
38045
+ };
38046
+ else actionStreak = {
38047
+ key: actionKey,
38048
+ count: 1
38049
+ };
38050
+ record("exact_action_repeat", actionStreak.count, toolName);
38051
+ }
38052
+ if (countsAsAction) {
38053
+ recentActions.push(actionKey);
38054
+ if (recentActions.length > 4) recentActions.shift();
38055
+ if (recentActions.length === 4) {
38056
+ const [a, b, c, d] = recentActions;
38057
+ if (a !== void 0 && b !== void 0 && a !== b && a === c && b === d) {
38058
+ const episode = `${a}\u0000${b}`;
38059
+ if (activeAbabKey !== episode) {
38060
+ activeAbabKey = episode;
38061
+ record("abab_action_cycle", 2, toolName);
38062
+ }
38063
+ } else activeAbabKey = void 0;
38064
+ }
38065
+ }
38066
+ if (observation.isError === true) {
38067
+ const key = `${toolName}\u0000${observation.errorCode ?? errorFamilyOf(observation.errorText)}`;
38068
+ const previous = errorStreaks.get(key);
38069
+ const count = previous === void 0 ? 1 : previous.count + 1;
38070
+ errorStreaks.set(key, {
38071
+ toolName,
38072
+ count
38073
+ });
38074
+ record("same_error_family", count, toolName);
38075
+ } else for (const [key, entry] of [...errorStreaks]) if (entry.toolName === toolName) errorStreaks.delete(key);
38076
+ if (isPolling(observation)) {
38077
+ const key = `${toolName}\u0000${canonicalize(observation.arguments)}\u0000${observation.resultText ?? ""}`;
38078
+ const previous = pollingStreaks.get(toolName);
38079
+ const count = previous !== void 0 && previous.key === key ? previous.count + 1 : 1;
38080
+ pollingStreaks.set(toolName, {
38081
+ key,
38082
+ count
38083
+ });
38084
+ record("polling_repeat", count, toolName);
38085
+ } else pollingStreaks.delete(toolName);
38086
+ if (reminderAttempted) return void 0;
38087
+ const errorCandidate = [...errorStreaks.values()].find((entry) => entry.count >= threshold);
38088
+ if (errorCandidate !== void 0) {
38089
+ reminderAttempted = true;
38090
+ return {
38091
+ kind: "same_error_family",
38092
+ occurrences: errorCandidate.count,
38093
+ text: renderSameErrorFamilyReminder(errorCandidate.count)
38094
+ };
38095
+ }
38096
+ if (countsAsAction && actionStreak !== void 0 && actionStreak.count >= threshold) {
38097
+ reminderAttempted = true;
38098
+ return {
38099
+ kind: "exact_action_repeat",
38100
+ occurrences: actionStreak.count,
38101
+ text: renderExactActionRepeatReminder(actionStreak.count)
38102
+ };
38103
+ }
38104
+ const pollingCandidate = [...pollingStreaks.values()].find((entry) => entry.count >= threshold);
38105
+ if (pollingCandidate !== void 0) {
38106
+ reminderAttempted = true;
38107
+ return {
38108
+ kind: "polling_repeat",
38109
+ occurrences: pollingCandidate.count,
38110
+ text: renderPollingRepeatReminder(pollingCandidate.count)
38111
+ };
38112
+ }
38113
+ },
38114
+ reset() {
38115
+ actionStreak = void 0;
38116
+ errorStreaks.clear();
38117
+ pollingStreaks.clear();
38118
+ recentActions.length = 0;
38119
+ activeAbabKey = void 0;
38120
+ reminderAttempted = false;
38121
+ },
38122
+ get signals() {
38123
+ return signals;
38124
+ }
38125
+ };
38126
+ }
38127
+ /**
38128
+ * 读宿主上下文上的工具注册面。
38129
+ * @param ctx - 宿主上下文。
38130
+ * @returns 工具注册面;没有时为 undefined。
38131
+ */
38132
+ function toolsServiceOf$1(ctx) {
38133
+ const read = ctx.get;
38134
+ if (typeof read === "function") try {
38135
+ const found = read.call(ctx, "tools");
38136
+ if (found !== void 0) return found;
38137
+ } catch {}
38138
+ const direct = ctx.tools;
38139
+ return direct === void 0 ? void 0 : direct;
38140
+ }
38141
+ /**
38142
+ * 判断一个会话是不是处于 PTC 模式(模型只能直接调 `run_code`)。
38143
+ *
38144
+ * 三个来源,按可靠性排序:
38145
+ *
38146
+ * 1. **注册表自己的判定面**(结构探测 `modeFor`):这是宿主真正用来决定
38147
+ * 「这个作用域是 native 还是 ptc」的那一个函数,读到的就是事实。
38148
+ * 2. **保留通道的可见性**(公开 API `get('run_code', scope)`):`run_code` 这条
38149
+ * 传输通道只对 PTC 作用域可见,所以「能不能查到它」就是同一个问题的公开问法。
38150
+ * 3. **agent 自己声明的呈现模式**:宿主选项里直接写了 `ptc` 时的兜底。
38151
+ *
38152
+ * 读不出来时**当作不是 PTC**:提醒是加法,不是减法,宁可少提醒也不要在
38153
+ * native 会话里催模型去用 `run_code`。
38154
+ *
38155
+ * @param agent - 调用方 agent。
38156
+ * @param tools - 工具注册面。
38157
+ * @returns 处于 PTC 模式时为 true。
38158
+ */
38159
+ function isPtcSessionOf(agent, tools) {
38160
+ const mode = declaredModeOf(tools, agent);
38161
+ if (mode !== void 0) return mode;
38162
+ if (runCodeTransportVisible(tools, agent) === true) return true;
38163
+ return declaredPresentationOf(agent) === "ptc";
38164
+ }
38165
+ /**
38166
+ * 读注册表自己的呈现模式判定面。
38167
+ * @param tools - 工具注册面。
38168
+ * @param agent - 调用方 agent。
38169
+ * @returns true/false 表示读到了;undefined 表示这一代宿主没有这条接缝。
38170
+ */
38171
+ function declaredModeOf(tools, agent) {
38172
+ const modeFor = (isRecord$50(tools) ? tools : void 0)?.modeFor;
38173
+ if (typeof modeFor !== "function") return void 0;
38174
+ try {
38175
+ const mode = modeFor.call(tools, agent);
38176
+ if (mode === "ptc") return true;
38177
+ if (mode === "native") return false;
38178
+ } catch {}
38179
+ }
38180
+ /**
38181
+ * 看 `run_code` 这条保留通道对这个作用域是否可见。
38182
+ * @param tools - 工具注册面。
38183
+ * @param agent - 调用方 agent。
38184
+ * @returns true/false 表示读到了;undefined 表示这一代宿主没有这条接缝。
38185
+ */
38186
+ function runCodeTransportVisible(tools, agent) {
38187
+ const get = (isRecord$50(tools) ? tools : void 0)?.get;
38188
+ if (typeof get !== "function") return void 0;
38189
+ try {
38190
+ return get.call(tools, "run_code", agent) !== void 0;
38191
+ } catch {
38192
+ return;
38193
+ }
38194
+ }
38195
+ /**
38196
+ * 读 agent 自己声明的呈现模式。
38197
+ * @param agent - 调用方 agent。
38198
+ * @returns 'ptc' / 'native' / undefined。
38199
+ */
38200
+ function declaredPresentationOf(agent) {
38201
+ const record = isRecord$50(agent) ? agent : void 0;
38202
+ const options = isRecord$50(record?.["options"]) ? record?.["options"] : void 0;
38203
+ const agentOptions = isRecord$50(record?.["agentOptions"]) ? record?.["agentOptions"] : void 0;
38204
+ const preset = isRecord$50(record?.["preset"]) ? record?.["preset"] : void 0;
38205
+ const candidates = [
38206
+ options?.["presentation"],
38207
+ options?.["toolPresentation"],
38208
+ options?.["toolsMode"],
38209
+ options?.["mode"],
38210
+ agentOptions?.["presentation"],
38211
+ preset?.["presentation"]
38212
+ ];
38213
+ for (const candidate of candidates) {
38214
+ if (candidate === "ptc") return "ptc";
38215
+ if (candidate === "native") return "native";
38216
+ }
38217
+ }
38218
+ /**
38219
+ * 判断一次工具执行是不是「模型直接调了原生工具」。
38220
+ *
38221
+ * 直接调用的判据是**没有父调用**:嵌套调用(`run_code` 程序里的子调用)带
38222
+ * 父标记,直接调用不带。DSH 用 `parent` 这枚不透明令牌,官方 minimax-code
38223
+ * 用 `parentToolCallId`,两个都认。
38224
+ *
38225
+ * @param exec - 工具执行。
38226
+ * @returns 直接调用时为 true。
38227
+ */
38228
+ function isDirectToolCall(exec) {
38229
+ const record = isRecord$50(exec) ? exec : void 0;
38230
+ if (record?.["parent"] !== void 0) return false;
38231
+ if (record?.["parentToolCallId"] !== void 0) return false;
38232
+ return true;
38233
+ }
38234
+ /**
38235
+ * 读一次执行是不是「模型直接调了需要提醒的原生工具」。
38236
+ * @param exec - 工具执行。
38237
+ * @returns 工具名;不是这类调用时为 undefined。
38238
+ */
38239
+ function directCallToolNameOf(exec) {
38240
+ const name = stringOf$4((isRecord$50(exec) ? exec : void 0)?.["name"]);
38241
+ if (name === void 0 || !DIRECT_CALL_REMINDER_TOOLS.includes(name)) return void 0;
38242
+ if (!isDirectToolCall(exec)) return void 0;
38243
+ return name;
38244
+ }
38245
+ /**
38246
+ * 把一条 post-execute 决策接上附加上下文,保住它原有的形状。
38247
+ * @param decision - `next()` 交回来的决策。
38248
+ * @param contexts - 要追加的上下文。
38249
+ * @returns 追加后的决策。
38250
+ */
38251
+ function withAdditionalContexts$1(decision, contexts) {
38252
+ const additionalContexts = [...decision.additionalContexts ?? [], ...contexts];
38253
+ if (decision.kind === "block") return {
38254
+ kind: "block",
38255
+ feedback: decision.feedback,
38256
+ additionalContexts
38257
+ };
38258
+ if (decision.value !== void 0) return {
38259
+ kind: "accept",
38260
+ value: decision.value,
38261
+ additionalContexts
38262
+ };
38263
+ if (decision.content !== void 0) return {
38264
+ kind: "accept",
38265
+ content: decision.content,
38266
+ additionalContexts
38267
+ };
38268
+ return {
38269
+ kind: "accept",
38270
+ additionalContexts
38271
+ };
38272
+ }
38273
+ /**
38274
+ * 造一条 PTC 直调提醒上下文。
38275
+ * @param toolName - 被直接调用的工具名。
38276
+ * @returns 可直接放进 `additionalContexts` 的用户角色消息。
38277
+ */
38278
+ function createDirectCallReminder(toolName) {
38279
+ return createUserMessage({
38280
+ content: [{
38281
+ type: "text",
38282
+ text: renderDirectCallReminder([toolName])
38283
+ }],
38284
+ source: {
38285
+ kind: "minimax-direct-call-reminder",
38286
+ form: "notice",
38287
+ summary: `PTC direct call: ${toolName}`
38288
+ }
38289
+ });
38290
+ }
38291
+ /**
38292
+ * 造一条失控守卫提醒上下文。
38293
+ * @param reminder - 提醒。
38294
+ * @returns 可直接放进 `additionalContexts` 的用户角色消息。
38295
+ */
38296
+ function createRunawayReminder(reminder) {
38297
+ return createUserMessage({
38298
+ content: [{
38299
+ type: "text",
38300
+ text: reminder.text
38301
+ }],
38302
+ source: {
38303
+ kind: "minimax-runaway-guard",
38304
+ form: "notice",
38305
+ summary: `runaway guard: ${reminder.kind} x${reminder.occurrences}`
38306
+ }
38307
+ });
38308
+ }
38309
+ /**
38310
+ * 读一次执行的结果是不是失败。
38311
+ * @param result - 工具执行结果。
38312
+ * @returns 失败时为 true。
38313
+ */
38314
+ function isErrorResult(result) {
38315
+ return isRecord$50(result) && result["isError"] === true;
38316
+ }
38317
+ /**
38318
+ * 读一次执行的结构化错误码。
38319
+ * @param result - 工具执行结果。
38320
+ * @returns 错误码;没有时为 undefined。
38321
+ */
38322
+ function errorCodeOf$1(result) {
38323
+ if (!isRecord$50(result)) return void 0;
38324
+ const error = result["error"];
38325
+ if (!isRecord$50(error)) return void 0;
38326
+ const info = error["info"];
38327
+ if (!isRecord$50(info)) return void 0;
38328
+ return stringOf$4(info["code"]);
38329
+ }
38330
+ /**
38331
+ * 读一次执行的失败文本。
38332
+ * @param result - 工具执行结果。
38333
+ * @returns 失败文本;没有时为 undefined。
38334
+ */
38335
+ function errorTextOf(result) {
38336
+ if (!isRecord$50(result)) return void 0;
38337
+ const error = result["error"];
38338
+ if (!isRecord$50(error)) return void 0;
38339
+ return stringOf$4(error["message"]);
38340
+ }
38341
+ /**
38342
+ * 读一次执行的结果文本(轮询判定用)。
38343
+ * @param result - 工具执行结果。
38344
+ * @returns 结果文本;没有时是空串。
38345
+ */
38346
+ function resultTextOf(result) {
38347
+ if (!isRecord$50(result)) return "";
38348
+ const content = result["content"];
38349
+ if (!Array.isArray(content)) return "";
38350
+ const parts = [];
38351
+ for (const block of content) if (isRecord$50(block) && block["type"] === "text") parts.push(stringOf$4(block["text"]) ?? "");
38352
+ return parts.join("\n");
38353
+ }
38354
+ /**
38355
+ * 找一次工具调用的参数 schema。
38356
+ * @param tools - 工具注册面。
38357
+ * @param name - 工具名。
38358
+ * @param agent - 调用方 agent。
38359
+ * @returns JSON Schema;找不到时为 undefined。
38360
+ */
38361
+ function schemaOf(tools, name, agent) {
38362
+ const get = tools?.get;
38363
+ if (typeof get !== "function") return void 0;
38364
+ try {
38365
+ const definition = get.call(tools, name, agent);
38366
+ if (!isRecord$50(definition)) return void 0;
38367
+ return definition["parameters"];
38368
+ } catch {
38369
+ return;
38370
+ }
38371
+ }
38372
+ /**
38373
+ * 就地把一次执行的参数改成修复后的形状。
38374
+ *
38375
+ * **尽力而为**:新一代宿主把执行参数**冻结**了(`deepFreeze`),写回会抛,
38376
+ * 于是这次修复在那一代上落不了地 —— 但函数本身不抛,调用方也拿不到错误。
38377
+ * 老一代宿主不冻结参数时,写回是真正生效的。
38378
+ *
38379
+ * @param execution - 工具执行。
38380
+ * @param tools - 工具注册面。
38381
+ */
38382
+ function repairExecutionArguments(execution, tools) {
38383
+ const record = isRecord$50(execution) ? execution : void 0;
38384
+ const args = record?.["arguments"];
38385
+ if (!isPlainRecord$1(args)) return;
38386
+ const name = stringOf$4(record?.["name"]);
38387
+ if (name === void 0) return;
38388
+ const agent = record?.["agent"];
38389
+ const repaired = repairMinimaxToolArguments(name, args, schemaOf(tools, name, agent));
38390
+ if (repaired.fixes.length === 0) return;
38391
+ const target = repaired.value;
38392
+ if (!isPlainRecord$1(target)) return;
38393
+ try {
38394
+ for (const key of Object.keys(args)) if (!(key in target)) delete args[key];
38395
+ Object.assign(args, target);
38396
+ } catch {}
38397
+ }
38398
+ /**
38399
+ * 装上 MiniMax Code 的运行时增强。
38400
+ *
38401
+ * @param ctx - 宿主插件上下文。
38402
+ * @param options - 增强选项。
38403
+ * @returns 卸载函数。
38404
+ */
38405
+ function installMinimaxRuntimeEnhancements(ctx, options = {}) {
38406
+ /** 登记一个副作用;上下文没有 effect 时立即执行(测试用假上下文)。 */
38407
+ const track = (execute, label) => {
38408
+ if (typeof ctx.effect === "function") ctx.effect(execute, label);
38409
+ else execute();
38410
+ };
38411
+ const tools = toolsServiceOf$1(ctx);
38412
+ /** 每个 agent 一台守卫:连击是**这个会话**的事。 */
38413
+ const guards = /* @__PURE__ */ new WeakMap();
38414
+ /**
38415
+ * 没有 agent 的执行(有人绕过 agent-loop 直接调 `ctx.tools.execute`)共用这一台。
38416
+ *
38417
+ * 它是**一台**,不是每次新建:连击要跨调用累积,新建一台等于永远停在第一次。
38418
+ */
38419
+ const agentlessGuard = createMinimaxRunawayGuard(options);
38420
+ /**
38421
+ * 取一个 agent 的守卫。
38422
+ * @param agent - 调用方 agent。
38423
+ * @returns 守卫。
38424
+ */
38425
+ const guardOf = (agent) => {
38426
+ const key = isRecord$50(agent) ? agent : void 0;
38427
+ if (key === void 0) return agentlessGuard;
38428
+ const existing = guards.get(key);
38429
+ if (existing !== void 0) return existing;
38430
+ const created = createMinimaxRunawayGuard(options);
38431
+ guards.set(key, created);
38432
+ return created;
38433
+ };
38434
+ track(() => {
38435
+ if (typeof tools?.guard !== "function") return () => void 0;
38436
+ const dispose = tools.guard((execution) => {
38437
+ try {
38438
+ if (!isMinimaxSession(isRecord$50(execution) ? execution["agent"] : void 0)) return void 0;
38439
+ repairExecutionArguments(execution, tools);
38440
+ } catch {}
38441
+ });
38442
+ return () => {
38443
+ dispose?.();
38444
+ };
38445
+ }, "dsh-chatgpt-subscription: minimax argument repair guard");
38446
+ const disposePreExecute = ctx.on?.("tools/pre-execute", (async (exec, next) => {
38447
+ try {
38448
+ if (isMinimaxSession(exec.agent)) repairExecutionArguments(exec, tools);
38449
+ } catch {}
38450
+ return next();
38451
+ }));
38452
+ const disposePostExecute = ctx.on?.("tools/post-execute", (async (exec, result, next) => {
38453
+ const decision = await next();
38454
+ try {
38455
+ const agent = exec.agent;
38456
+ if (!isMinimaxSession(agent)) return decision;
38457
+ const contexts = [];
38458
+ const directName = directCallToolNameOf(exec);
38459
+ if (directName !== void 0 && isPtcSessionOf(agent, tools)) contexts.push(createDirectCallReminder(directName));
38460
+ const reminder = guardOf(agent).observe({
38461
+ toolName: exec.name,
38462
+ arguments: exec.arguments,
38463
+ isError: isErrorResult(result),
38464
+ errorCode: errorCodeOf$1(result),
38465
+ errorText: errorTextOf(result),
38466
+ resultText: resultTextOf(result)
38467
+ });
38468
+ if (reminder !== void 0) contexts.push(createRunawayReminder(reminder));
38469
+ if (contexts.length === 0) return decision;
38470
+ return withAdditionalContexts$1(decision, contexts);
38471
+ } catch {
38472
+ return decision;
38473
+ }
38474
+ }));
38475
+ const disposePreStep = ctx.on?.("agent/pre-step", (async (payload, next) => {
38476
+ const decision = await next();
38477
+ try {
38478
+ if (!(Array.isArray(payload?.messages) ? payload.messages : []).some((message) => {
38479
+ const source = isRecord$50(message) ? message["source"] : void 0;
38480
+ return isRecord$50(source) && source["kind"] === "user";
38481
+ })) return decision;
38482
+ const agent = payload?.agent;
38483
+ if (isRecord$50(agent)) guards.get(agent)?.reset();
38484
+ } catch {
38485
+ return decision;
38486
+ }
38487
+ return decision;
38488
+ }));
38489
+ const disposeDisposed = ctx.on?.("agent/disposed", ((payload) => {
38490
+ const agent = payload?.agent;
38491
+ if (isRecord$50(agent)) guards.delete(agent);
38492
+ }));
38493
+ return () => {
38494
+ disposePreExecute?.();
38495
+ disposePostExecute?.();
38496
+ disposePreStep?.();
38497
+ disposeDisposed?.();
38498
+ };
38499
+ }
38500
+ //#endregion
37241
38501
  //#region src/host/minimax-code/modalities.ts
37242
38502
  /**
37243
38503
  * MiniMax Code's video vocabulary.
@@ -37334,7 +38594,7 @@ function videoOmissionText(reason, label) {
37334
38594
  * a caller that opts out (MinimaxRequestOptions.cacheControl === false) gets
37335
38595
  * the original string body byte-for-byte.
37336
38596
  */
37337
- function isRecord$48(value) {
38597
+ function isRecord$49(value) {
37338
38598
  return typeof value === "object" && value !== null && !Array.isArray(value);
37339
38599
  }
37340
38600
  function asString$20(value) {
@@ -37387,7 +38647,7 @@ const SUPPORTED_IMAGE_MEDIA_TYPES$2 = /* @__PURE__ */ new Set([
37387
38647
  ]);
37388
38648
  function attachmentOf$2(block) {
37389
38649
  const attachment = block.attachment;
37390
- return isRecord$48(attachment) ? attachment : void 0;
38650
+ return isRecord$49(attachment) ? attachment : void 0;
37391
38651
  }
37392
38652
  function attachmentLabel$2(block) {
37393
38653
  const attachment = attachmentOf$2(block);
@@ -37423,7 +38683,7 @@ function textOf$6(content) {
37423
38683
  if (!Array.isArray(content)) return "";
37424
38684
  const parts = [];
37425
38685
  for (const block of content) {
37426
- if (!isRecord$48(block)) continue;
38686
+ if (!isRecord$49(block)) continue;
37427
38687
  if (block.type === "text" && typeof block.text === "string") parts.push(sanitizeText$6(block.text));
37428
38688
  else if (block.type === "tool-result") parts.push(textOf$6(block.content));
37429
38689
  }
@@ -37432,7 +38692,7 @@ function textOf$6(content) {
37432
38692
  function toolResultText$6(blocks) {
37433
38693
  if (!Array.isArray(blocks)) return "";
37434
38694
  return blocks.map((block) => {
37435
- if (!isRecord$48(block)) return "";
38695
+ if (!isRecord$49(block)) return "";
37436
38696
  if (block.type === "text" && typeof block.text === "string") return sanitizeText$6(block.text);
37437
38697
  if (block.type === "tool-result") return toolResultText$6(block.content);
37438
38698
  if (block.type === "image") return "[image: " + (attachmentLabel$2(block) ?? "attached image") + "]";
@@ -37451,7 +38711,7 @@ function toolResultBlocks(blocks, images) {
37451
38711
  const out = [];
37452
38712
  let hasImage = false;
37453
38713
  for (const block of blocks) {
37454
- if (!isRecord$48(block)) continue;
38714
+ if (!isRecord$49(block)) continue;
37455
38715
  if (block.type === "text" && typeof block.text === "string") {
37456
38716
  out.push({
37457
38717
  type: "text",
@@ -37502,12 +38762,31 @@ function isToolResultMessage$6(message) {
37502
38762
  return message.source?.kind === "tool";
37503
38763
  }
37504
38764
  /**
38765
+ * The rule a tool-enabled session must follow before it calls a tool.
38766
+ *
38767
+ * The official agent states it in the system prompt of every session that has
38768
+ * tools: a non-trivial tool step starts with a user-visible assistant text
38769
+ * block. Thinking does not count - a model that reasons and then calls the tool
38770
+ * without saying anything has produced a step the user cannot see, and the
38771
+ * official agent asks for that preamble explicitly.
38772
+ *
38773
+ * It is appended to the assembled system text rather than replacing it: the
38774
+ * caller's own prompt keeps its place at the head (which is the cached prefix),
38775
+ * and this rule lands after it.
38776
+ */
38777
+ 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.";
38778
+ /**
37505
38779
  * Concatenated system-prompt text.
37506
38780
  *
37507
38781
  * The system prompt is the head of the prefix the service caches, so this is a
37508
38782
  * pure, order-stable fold of its inputs: options.system always leads and message
37509
38783
  * text follows in history order. Nothing per-turn is added here, because one
37510
38784
  * changed byte at the head invalidates the whole cached prefix.
38785
+ *
38786
+ * The ONE addition is {@link TOOL_CALL_PREAMBLE_REMINDER}, and it is added only
38787
+ * to a session that has both tools and a system prompt - a request with no tools
38788
+ * has no tool-call step to remind the model about, and a request with no system
38789
+ * text at all keeps `system === undefined` rather than gaining one.
37511
38790
  */
37512
38791
  function leadingSystemText$6(options) {
37513
38792
  const parts = [];
@@ -37517,7 +38796,11 @@ function leadingSystemText$6(options) {
37517
38796
  const text = textOf$6(message.content);
37518
38797
  if (text !== "") parts.push(text);
37519
38798
  }
37520
- return parts.length === 0 ? void 0 : parts.join("\n\n");
38799
+ if (parts.length === 0) return void 0;
38800
+ if (options.tools && options.tools.length > 0) {
38801
+ 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);
38802
+ }
38803
+ return parts.join("\n\n");
37521
38804
  }
37522
38805
  function nonSystemMessages$6(options) {
37523
38806
  return options.messages.filter((message) => message.role !== "system");
@@ -37536,7 +38819,7 @@ function anthropicUserContent$1(message, images, videos, videoAccepted) {
37536
38819
  if (!Array.isArray(message.content)) return [];
37537
38820
  const blocks = [];
37538
38821
  for (const block of message.content) {
37539
- if (!isRecord$48(block)) continue;
38822
+ if (!isRecord$49(block)) continue;
37540
38823
  if (block.type === "text" && typeof block.text === "string") {
37541
38824
  const text = sanitizeText$6(block.text);
37542
38825
  if (text !== "") blocks.push({
@@ -37606,7 +38889,7 @@ function anthropicUserContent$1(message, images, videos, videoAccepted) {
37606
38889
  function computeVisibleContentHash(blocks) {
37607
38890
  if (!Array.isArray(blocks)) return "";
37608
38891
  const canonical = blocks.map((b) => {
37609
- if (!isRecord$48(b)) return null;
38892
+ if (!isRecord$49(b)) return null;
37610
38893
  const type = asString$20(b.type) ?? "";
37611
38894
  if (type === "text" || type === "reasoning") return [type, sanitizeText$6(asString$20(b.text) ?? "")];
37612
38895
  if (type === "tool-call") return [
@@ -37628,12 +38911,12 @@ function computeVisibleContentHash(blocks) {
37628
38911
  */
37629
38912
  function replayedThinkingBlock$1(message, index, expectedScope, block) {
37630
38913
  const source = message.source;
37631
- if (source === void 0 || source === null || !isRecord$48(source)) return void 0;
38914
+ if (source === void 0 || source === null || !isRecord$49(source)) return void 0;
37632
38915
  if (source.provider && source.provider !== PROVIDER_ID$8 && source.provider !== "dsh-chatgpt-subscription") return;
37633
38916
  if (source.model && expectedScope && source.model !== expectedScope.model) return;
37634
38917
  const state = source.replayState;
37635
- if (!isRecord$48(state)) return void 0;
37636
- const resp = isRecord$48(state.response) ? state.response : state;
38918
+ if (!isRecord$49(state)) return void 0;
38919
+ const resp = isRecord$49(state.response) ? state.response : state;
37637
38920
  const stateRoute = asString$20(resp.route) ?? asString$20(resp.provider);
37638
38921
  const stateModel = asString$20(resp.model);
37639
38922
  const stateAuthOwner = asString$20(resp.authOwner);
@@ -37641,19 +38924,19 @@ function replayedThinkingBlock$1(message, index, expectedScope, block) {
37641
38924
  if (expectedScope === void 0) return void 0;
37642
38925
  if (expectedScope.route && stateRoute !== expectedScope.route) return void 0;
37643
38926
  if (expectedScope.model && stateModel !== expectedScope.model) return void 0;
37644
- if (!expectedScope.authOwner || expectedScope.authOwner.trim() === "" || stateAuthOwner !== expectedScope.authOwner) return;
38927
+ if (!expectedScope.authOwner || expectedScope.authOwner.trim() === "") return void 0;
37645
38928
  let candidate;
37646
38929
  if (Array.isArray(state.blocks)) {
37647
38930
  const entry = state.blocks[index];
37648
- if (isRecord$48(entry)) candidate = entry;
38931
+ if (isRecord$49(entry)) candidate = entry;
37649
38932
  }
37650
38933
  if (candidate === void 0 && Array.isArray(resp.blocks)) {
37651
38934
  const entry = resp.blocks[index];
37652
- if (isRecord$48(entry)) candidate = entry;
38935
+ if (isRecord$49(entry)) candidate = entry;
37653
38936
  }
37654
38937
  if (candidate === void 0 && Array.isArray(resp.nativeBlocks)) {
37655
38938
  const entry = resp.nativeBlocks[index];
37656
- if (isRecord$48(entry)) candidate = entry;
38939
+ if (isRecord$49(entry)) candidate = entry;
37657
38940
  }
37658
38941
  if (candidate === void 0) return void 0;
37659
38942
  if (Array.isArray(state.blocks) && state.blocks.length !== message.content.length) return void 0;
@@ -37679,7 +38962,7 @@ function anthropicAssistantContent$1(message, expectedScope) {
37679
38962
  if (!Array.isArray(message.content)) return blocks;
37680
38963
  for (let index = 0; index < message.content.length; index++) {
37681
38964
  const block = message.content[index];
37682
- if (!isRecord$48(block)) continue;
38965
+ if (!isRecord$49(block)) continue;
37683
38966
  if (block.type === "text" && typeof block.text === "string") {
37684
38967
  const text = sanitizeText$6(block.text);
37685
38968
  if (text !== "") blocks.push({
@@ -37694,13 +38977,22 @@ function anthropicAssistantContent$1(message, expectedScope) {
37694
38977
  type: "tool_use",
37695
38978
  id: asString$20(block.id) ?? "toolu_" + blocks.length,
37696
38979
  name: block.name,
37697
- input: isRecord$48(parsed) ? parsed : {}
38980
+ input: isRecord$49(parsed) ? parsed : {}
37698
38981
  });
37699
38982
  continue;
37700
38983
  }
37701
38984
  if (block.type === "reasoning") {
37702
38985
  const replay = replayedThinkingBlock$1(message, index, expectedScope, block);
37703
- if (replay !== void 0) blocks.push(replay);
38986
+ if (replay !== void 0) {
38987
+ blocks.push(replay);
38988
+ continue;
38989
+ }
38990
+ const fallbackText = sanitizeText$6(typeof block.text === "string" ? block.text : "");
38991
+ const trimmed = fallbackText.trim();
38992
+ if (trimmed !== "" && trimmed !== "[Reasoning redacted]") blocks.push({
38993
+ type: "text",
38994
+ text: fallbackText
38995
+ });
37704
38996
  continue;
37705
38997
  }
37706
38998
  }
@@ -37777,15 +39069,17 @@ function thinkingFieldFor(modelId, requestedEffort) {
37777
39069
  * The level belongs at the TOP level - `output_config.effort` - and accepts
37778
39070
  * low, medium, high, xhigh and max. There is no `default` member: the page
37779
39071
  * 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.
39072
+ * reached the wire. This line no longer leans on that either: every model that
39073
+ * has levels states its default as NULL, so a request that asks for nothing
39074
+ * resolves to no `output_config` at all - which is what the official agent
39075
+ * sends when the conversation picked no level.
37783
39076
  *
37784
39077
  * The level is the DEPTH, not the channel: measured, low and max differ by
37785
39078
  * about 3x thinking and 4x latency, and it composes with the `thinking` object.
37786
39079
  *
37787
39080
  * @returns the value for `output_config`, or undefined when the request should
37788
- * carry no thinking control at all.
39081
+ * carry no thinking control at all - which is the case for an unset, empty or
39082
+ * unknown level.
37789
39083
  */
37790
39084
  function outputConfigFor(modelId, requestedEffort) {
37791
39085
  const model = catalogEntry$2(modelId);
@@ -37927,7 +39221,8 @@ function buildMinimaxRequest(options, images = NO_RESOLVED_IMAGES$2, request = {
37927
39221
  const requestedEffort = options.reasoningEffort === void 0 ? null : String(options.reasoningEffort);
37928
39222
  const outputConfig = outputConfigFor(options.model, requestedEffort);
37929
39223
  const thinking = thinkingFieldFor(options.model, requestedEffort);
37930
- const thinkingEngaged = outputConfig !== void 0 || thinking?.type === "adaptive";
39224
+ const modelDef = catalogEntry$2(options.model);
39225
+ const thinkingEngaged = outputConfig !== void 0 || thinking?.type === "adaptive" || modelDef?.thinking === "always-on" || modelDef?.thinking === "forced-effort";
37931
39226
  const caching = request.cacheControl !== false;
37932
39227
  const body = {
37933
39228
  model: options.model,
@@ -37943,6 +39238,7 @@ function buildMinimaxRequest(options, images = NO_RESOLVED_IMAGES$2, request = {
37943
39238
  ...options.tools && options.tools.length > 0 ? { tools: options.tools.map((tool) => ({
37944
39239
  name: tool.name,
37945
39240
  description: tool.description,
39241
+ eager_input_streaming: true,
37946
39242
  input_schema: stripMetaSchema$1(tool.parameters)
37947
39243
  })) } : {},
37948
39244
  ...thinking === void 0 ? {} : { thinking },
@@ -37979,6 +39275,7 @@ function createStreamState(options) {
37979
39275
  authOwner: options.authOwner,
37980
39276
  provider: options.provider ?? PROVIDER_ID$8
37981
39277
  } : void 0,
39278
+ toolSchemas: options?.tools && options.tools.length > 0 ? new Map(options.tools.map((tool) => [tool.name, tool.parameters])) : void 0,
37982
39279
  replayBlocks: [],
37983
39280
  pendingThinking: /* @__PURE__ */ new Map(),
37984
39281
  blocks: [],
@@ -38032,6 +39329,27 @@ function openTextBlock$4(state, type) {
38032
39329
  });
38033
39330
  return out;
38034
39331
  }
39332
+ /**
39333
+ * The argument string one finished tool call carries.
39334
+ *
39335
+ * The model writes tool arguments in shapes the schema does not accept: numbers
39336
+ * as strings, an `edits` array as a JSON string, an array wrapped in
39337
+ * `{"item": [...]}`. DSH's tool guard then refuses the call over a shape the
39338
+ * model had no way to know was wrong, so the arguments are repaired here - at
39339
+ * the end of the stream, where the whole argument string is finally known.
39340
+ *
39341
+ * The repair is LOSSLESS, and it only runs when it changes something:
39342
+ * arguments that need no repair come out byte-for-byte as they arrived, and
39343
+ * arguments that do not parse as an object are left exactly as they were.
39344
+ */
39345
+ function finalizeToolCallArguments(name, rawArguments, toolSchemas) {
39346
+ if (rawArguments === "") return "{}";
39347
+ const parsed = safeJsonParse$6(rawArguments);
39348
+ if (!isRecord$49(parsed)) return rawArguments;
39349
+ const repaired = repairMinimaxToolArguments(name, parsed, toolSchemas?.get(name));
39350
+ if (repaired.fixes.length === 0) return rawArguments;
39351
+ return JSON.stringify(repaired.value);
39352
+ }
38035
39353
  function closeToolCalls$4(state) {
38036
39354
  const out = [];
38037
39355
  for (const [wireIndex, call] of [...state.toolCalls.entries()].sort((a, b) => a[0] - b[0])) {
@@ -38039,7 +39357,7 @@ function closeToolCalls$4(state) {
38039
39357
  type: "tool-call",
38040
39358
  id: toToolCallId(call.id),
38041
39359
  name: call.name,
38042
- arguments: call.arguments === "" ? "{}" : call.arguments
39360
+ arguments: finalizeToolCallArguments(call.name, call.arguments, state.toolSchemas)
38043
39361
  };
38044
39362
  state.blocks[call.blockIndex] = block;
38045
39363
  state.replayBlocks[call.blockIndex] = null;
@@ -38152,12 +39470,12 @@ function processMinimaxStreamLine(line, state) {
38152
39470
  const payload = trimmed.slice(5).trim();
38153
39471
  if (payload === "" || payload === "[DONE]") return [];
38154
39472
  const event = safeJsonParse$6(payload);
38155
- if (!isRecord$48(event)) return [];
39473
+ if (!isRecord$49(event)) return [];
38156
39474
  const type = asString$20(event.type);
38157
39475
  const out = [];
38158
39476
  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;
39477
+ const message = isRecord$49(event.message) ? event.message : void 0;
39478
+ const usage = message !== void 0 && isRecord$49(message.usage) ? message.usage : void 0;
38161
39479
  if (usage !== void 0) {
38162
39480
  state.sawUsage = true;
38163
39481
  state.inputTokens = numberOr$7(usage.input_tokens, 0);
@@ -38173,7 +39491,7 @@ function processMinimaxStreamLine(line, state) {
38173
39491
  }
38174
39492
  if (type === "content_block_start") {
38175
39493
  const contentIndex = numberOr$7(event.index, 0);
38176
- const block = isRecord$48(event.content_block) ? event.content_block : {};
39494
+ const block = isRecord$49(event.content_block) ? event.content_block : {};
38177
39495
  const blockType = asString$20(block.type);
38178
39496
  out.push(...closeCurrent$4(state));
38179
39497
  if (blockType === "tool_use") {
@@ -38224,7 +39542,7 @@ function processMinimaxStreamLine(line, state) {
38224
39542
  type: "reasoning",
38225
39543
  text: state.current.text
38226
39544
  });
38227
- const initialReplay = isRecord$48(event.content_block) ? structuredClone(event.content_block) : { type: blockType };
39545
+ const initialReplay = isRecord$49(event.content_block) ? structuredClone(event.content_block) : { type: blockType };
38228
39546
  state.replayBlocks[index] = initialReplay;
38229
39547
  state.pendingThinking.set(contentIndex, {
38230
39548
  dshIndex: index,
@@ -38252,7 +39570,7 @@ function processMinimaxStreamLine(line, state) {
38252
39570
  }
38253
39571
  if (type === "content_block_delta") {
38254
39572
  const contentIndex = numberOr$7(event.index, 0);
38255
- const delta = isRecord$48(event.delta) ? event.delta : {};
39573
+ const delta = isRecord$49(event.delta) ? event.delta : {};
38256
39574
  const deltaType = asString$20(delta.type);
38257
39575
  if (deltaType === "input_json_delta") {
38258
39576
  const pending = state.toolCalls.get(contentIndex);
@@ -38341,7 +39659,7 @@ function processMinimaxStreamLine(line, state) {
38341
39659
  type: "tool-call",
38342
39660
  id: toToolCallId(pending.id),
38343
39661
  name: pending.name,
38344
- arguments: pending.arguments === "" ? "{}" : pending.arguments
39662
+ arguments: finalizeToolCallArguments(pending.name, pending.arguments, state.toolSchemas)
38345
39663
  };
38346
39664
  state.blocks[pending.blockIndex] = block;
38347
39665
  out.push({
@@ -38355,10 +39673,10 @@ function processMinimaxStreamLine(line, state) {
38355
39673
  return out;
38356
39674
  }
38357
39675
  if (type === "message_delta") {
38358
- const delta = isRecord$48(event.delta) ? event.delta : void 0;
39676
+ const delta = isRecord$49(event.delta) ? event.delta : void 0;
38359
39677
  const stop = delta === void 0 ? void 0 : asString$20(delta.stop_reason);
38360
39678
  if (stop !== void 0 && stop !== "") state.finishReason = stop;
38361
- const usage = isRecord$48(event.usage) ? event.usage : void 0;
39679
+ const usage = isRecord$49(event.usage) ? event.usage : void 0;
38362
39680
  if (usage !== void 0) {
38363
39681
  state.sawUsage = true;
38364
39682
  state.inputTokens = numberOr$7(usage.input_tokens, state.inputTokens);
@@ -38373,7 +39691,7 @@ function processMinimaxStreamLine(line, state) {
38373
39691
  return closeMinimaxStream(state);
38374
39692
  }
38375
39693
  if (type === "error") {
38376
- const error = isRecord$48(event.error) ? event.error : {};
39694
+ const error = isRecord$49(event.error) ? event.error : {};
38377
39695
  state.streamError = error;
38378
39696
  throw new LlmError$1("MiniMax Code(编程订阅) stream error: " + (asString$20(error.message) ?? "unknown error"), isContextOverflow(error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
38379
39697
  }
@@ -38446,7 +39764,7 @@ const MINIMAX_CODE_MODELS = [
38446
39764
  "xhigh",
38447
39765
  "max"
38448
39766
  ],
38449
- defaultReasoningEffort: "max",
39767
+ defaultReasoningEffort: null,
38450
39768
  maxAttachments: 9,
38451
39769
  maxImageBytes: 10 * 1024 * 1024,
38452
39770
  maxVideoBytes: 50 * 1024 * 1024,
@@ -38472,7 +39790,7 @@ const MINIMAX_CODE_MODELS = [
38472
39790
  "xhigh",
38473
39791
  "max"
38474
39792
  ],
38475
- defaultReasoningEffort: "max",
39793
+ defaultReasoningEffort: null,
38476
39794
  maxAttachments: 4,
38477
39795
  maxImageBytes: 10 * 1024 * 1024,
38478
39796
  maxVideoBytes: 50 * 1024 * 1024,
@@ -38539,14 +39857,22 @@ function isThinkingDisabledEffort(value) {
38539
39857
  /**
38540
39858
  * The effort level to put on the wire for one model.
38541
39859
  *
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.
39860
+ * NULL means "this request carries no `output_config.effort`", which is what
39861
+ * the official agent sends when the conversation picked no level. Every model in
39862
+ * this catalog states null as its default, so a request that names no effort
39863
+ * states no effort.
39864
+ *
39865
+ * An unknown value falls back to the model's documented default, so a caller
39866
+ * cannot talk this route into a level the model does not list - and with that
39867
+ * default being null, an unknown level now means no level rather than the most
39868
+ * expensive one.
38544
39869
  */
38545
39870
  function effortForModel(modelId, requested) {
38546
39871
  const model = minimaxCodeModelDef(modelId);
38547
39872
  if (model === void 0) return null;
38548
39873
  if (model.reasoningEfforts.length === 0) return null;
38549
- if (requested === void 0 || requested === null) return model.defaultReasoningEffort;
39874
+ if (isThinkingDisabledEffort(requested)) return null;
39875
+ if (requested === void 0 || requested === null || requested.trim() === "") return model.defaultReasoningEffort;
38550
39876
  const normalized = requested.trim().toLowerCase();
38551
39877
  return model.reasoningEfforts.find((effort) => effort === normalized) ?? model.defaultReasoningEffort;
38552
39878
  }
@@ -38676,7 +40002,7 @@ function authStateJsonPath(region, buildEnv = MINIMAX_CODE_BUILD_ENV) {
38676
40002
  function pluginCredentialPath() {
38677
40003
  return path.join(dshHomeDir(), "storages", "minimax-code-credentials.json");
38678
40004
  }
38679
- function isRecord$47(value) {
40005
+ function isRecord$48(value) {
38680
40006
  return typeof value === "object" && value !== null && !Array.isArray(value);
38681
40007
  }
38682
40008
  function asString$19(value) {
@@ -38698,7 +40024,7 @@ function asFiniteNumber$4(value) {
38698
40024
  * exists to prevent.
38699
40025
  */
38700
40026
  function parseMinimaxCodeCredentials(value, fallback) {
38701
- if (!isRecord$47(value)) throw new Error("MiniMax Code credential payload is invalid");
40027
+ if (!isRecord$48(value)) throw new Error("MiniMax Code credential payload is invalid");
38702
40028
  const accessToken = asString$19(value.accessToken);
38703
40029
  if (accessToken === void 0) throw new Error("MiniMax Code credential is missing its access token");
38704
40030
  const refreshToken = asString$19(value.refreshToken);
@@ -38984,10 +40310,10 @@ async function readNativeDocument(region) {
38984
40310
  } catch {
38985
40311
  return null;
38986
40312
  }
38987
- if (!isRecord$47(parsed) || !isRecord$47(parsed.records)) return null;
40313
+ if (!isRecord$48(parsed) || !isRecord$48(parsed.records)) return null;
38988
40314
  const records = parsed.records;
38989
40315
  for (const [recordKey, entry] of Object.entries(records)) {
38990
- if (!isRecord$47(entry)) continue;
40316
+ if (!isRecord$48(entry)) continue;
38991
40317
  if (asString$19(entry.clientId) !== "mcode-public") continue;
38992
40318
  if (asString$19(entry.accessToken) === void 0) continue;
38993
40319
  return {
@@ -39015,7 +40341,7 @@ async function syncAuthState(region, options) {
39015
40341
  } catch {
39016
40342
  return;
39017
40343
  }
39018
- if (!isRecord$47(parsed)) return;
40344
+ if (!isRecord$48(parsed)) return;
39019
40345
  const next = {
39020
40346
  ...parsed,
39021
40347
  generation: options.generation,
@@ -39938,14 +41264,25 @@ function withTimeout$8(signal, ms) {
39938
41264
  *
39939
41265
  * The token itself never appears in a log line or an error: callers that need to
39940
41266
  * name a credential do so through `redactToken`.
41267
+ *
41268
+ * @param context the session identity the managed agent expects on a request
41269
+ * that belongs to a session: the session id, the agent id inside it, and the
41270
+ * caller's timezone offset. They are sent only when there IS a session — a
41271
+ * request without one carries none of them.
39941
41272
  */
39942
- function modelRequestHeaders(accessToken) {
41273
+ function modelRequestHeaders(accessToken, context) {
39943
41274
  return {
39944
41275
  authorization: "Bearer " + accessToken,
39945
41276
  "anthropic-version": ANTHROPIC_VERSION$2,
41277
+ "anthropic-beta": ANTHROPIC_INTERLEAVED_THINKING_BETA,
39946
41278
  "content-type": "application/json",
39947
41279
  accept: "text/event-stream",
39948
- "user-agent": USER_AGENT$3
41280
+ "user-agent": MINIMAX_AGENT_USER_AGENT,
41281
+ ...context?.sessionId ? {
41282
+ "x-mavis-session-id": context.sessionId,
41283
+ "x-mavis-agent-id": context.agentId || "main",
41284
+ "x-mavis-timezone-offset": String(context.timezoneOffsetSec ?? (/* @__PURE__ */ new Date()).getTimezoneOffset() * -60)
41285
+ } : {}
39949
41286
  };
39950
41287
  }
39951
41288
  /** Headers for a non-streaming call (the probe). */
@@ -40529,7 +41866,7 @@ var FileIdStore = class FileIdStore {
40529
41866
  const raw = await (await import("node:fs/promises")).readFile(this.path, "utf8").catch(() => "");
40530
41867
  if (raw.trim() === "") return {};
40531
41868
  const parsed = JSON.parse(raw);
40532
- return isRecord$46(parsed) ? parsed : {};
41869
+ return isRecord$47(parsed) ? parsed : {};
40533
41870
  }
40534
41871
  async write(value) {
40535
41872
  if (this.path === void 0) {
@@ -40546,7 +41883,7 @@ var FileIdStore = class FileIdStore {
40546
41883
  /** Shared by every in-memory instance, so they see one cache. */
40547
41884
  static memory;
40548
41885
  };
40549
- function isRecord$46(value) {
41886
+ function isRecord$47(value) {
40550
41887
  return typeof value === "object" && value !== null && !Array.isArray(value);
40551
41888
  }
40552
41889
  /** Stable key for one (content, account) pair. */
@@ -40664,7 +42001,7 @@ function isAbort$1(error, signal) {
40664
42001
  }
40665
42002
  /** The file id from a successful upload body, or undefined. */
40666
42003
  function readFileId(payload) {
40667
- if (!isRecord$46(payload) || !isRecord$46(payload.base_resp) || !isRecord$46(payload.file)) return void 0;
42004
+ if (!isRecord$47(payload) || !isRecord$47(payload.base_resp) || !isRecord$47(payload.file)) return void 0;
40668
42005
  if (payload.base_resp["status_code"] !== 0) return void 0;
40669
42006
  const fileId = payload.file["file_id"];
40670
42007
  if (typeof fileId === "number") return Number.isSafeInteger(fileId) && fileId >= 0 ? String(fileId) : void 0;
@@ -40672,13 +42009,13 @@ function readFileId(payload) {
40672
42009
  }
40673
42010
  /** The service's own reason for a refusal, so the message names the cause. */
40674
42011
  function describeRejection(payload, raw) {
40675
- if (isRecord$46(payload) && isRecord$46(payload.base_resp)) {
42012
+ if (isRecord$47(payload) && isRecord$47(payload.base_resp)) {
40676
42013
  const status = payload.base_resp["status_code"];
40677
42014
  const reason = payload.base_resp["status_msg"];
40678
42015
  if (typeof reason === "string" && reason !== "") return "the Files API refused the upload (" + String(status) + "): " + reason;
40679
42016
  }
40680
42017
  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, " ");
42018
+ if (!isRecord$47(payload)) return "the Files API returned a non-JSON body: " + raw.slice(0, 120).replace(/\s+/g, " ");
40682
42019
  return "the Files API refused the upload without naming a reason";
40683
42020
  }
40684
42021
  /** Parse a response body without throwing on a non-JSON payload. */
@@ -41428,12 +42765,18 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
41428
42765
  return serialized;
41429
42766
  };
41430
42767
  let body = buildBodyForOwner(authOwner);
42768
+ const rawSessionId = options.sessionId;
42769
+ const rawAgentId = options.agentId;
42770
+ const requestContext = {
42771
+ sessionId: typeof rawSessionId === "string" && rawSessionId.trim() !== "" ? rawSessionId : void 0,
42772
+ agentId: typeof rawAgentId === "string" && rawAgentId.trim() !== "" ? rawAgentId : void 0
42773
+ };
41431
42774
  let refusedBody;
41432
42775
  for (let attempt = 0;; attempt += 1) {
41433
42776
  try {
41434
42777
  response = await fetchWithContextBudgetRecovery(fetchFn)(messagesUrl(credentials.region), {
41435
42778
  method: "POST",
41436
- headers: modelRequestHeaders(credentials.accessToken),
42779
+ headers: modelRequestHeaders(credentials.accessToken, requestContext),
41437
42780
  body,
41438
42781
  signal
41439
42782
  });
@@ -41480,7 +42823,8 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
41480
42823
  model: options.model,
41481
42824
  authOwner,
41482
42825
  route: PROVIDER_ID$8,
41483
- provider: PROVIDER_ID$8
42826
+ provider: PROVIDER_ID$8,
42827
+ tools: requestOptions.tools
41484
42828
  });
41485
42829
  let buffer = "";
41486
42830
  /**
@@ -42396,7 +43740,7 @@ const PROVIDER_ID$7 = "minimax-code";
42396
43740
  function videoHistoryPath() {
42397
43741
  return path.join(dshHomeDir(), "storages", "minimax-code-video-history.json");
42398
43742
  }
42399
- function isRecord$45(value) {
43743
+ function isRecord$46(value) {
42400
43744
  return typeof value === "object" && value !== null && !Array.isArray(value);
42401
43745
  }
42402
43746
  function asNonEmptyString(value) {
@@ -42418,7 +43762,7 @@ function asFiniteNumber$3(value) {
42418
43762
  * @returns the normalized entry, or undefined to drop it.
42419
43763
  */
42420
43764
  function parseHistoryEntry(value) {
42421
- if (!isRecord$45(value)) return void 0;
43765
+ if (!isRecord$46(value)) return void 0;
42422
43766
  const createdAtMs = asFiniteNumber$3(value.createdAtMs);
42423
43767
  const model = asNonEmptyString(value.model);
42424
43768
  const videoPath = asNonEmptyString(value.videoPath);
@@ -42450,7 +43794,7 @@ function parseHistoryEntry(value) {
42450
43794
  * @returns the normalized document.
42451
43795
  */
42452
43796
  function parseHistoryDocument(value) {
42453
- if (!isRecord$45(value) || !Array.isArray(value.entries)) return {
43797
+ if (!isRecord$46(value) || !Array.isArray(value.entries)) return {
42454
43798
  version: 1,
42455
43799
  entries: []
42456
43800
  };
@@ -44503,6 +45847,429 @@ function createMinimaxGenerateVideoTool(ctx, options) {
44503
45847
  }
44504
45848
  });
44505
45849
  }
45850
+ /** 官方重复刹车的开关环境变量。 */
45851
+ const REPEAT_BREAKER_ENV = "KIMI_CODE_REPEAT_BREAKER";
45852
+ /** 第一段提醒文案。 */
45853
+ 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>";
45854
+ /**
45855
+ * 造第二段提醒文案(连击 5-7 次时用)。
45856
+ *
45857
+ * @param repeatCount - 当前连击次数,原样写进文案。
45858
+ * @returns 提醒正文。
45859
+ */
45860
+ function makeReminderText2(repeatCount) {
45861
+ 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>";
45862
+ }
45863
+ /** 第三段提醒文案(连击 8 次起,以及强停那一轮)。 */
45864
+ 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>";
45865
+ /** 强停那一轮之后,守卫用来拒绝后续工具调用的文案。 */
45866
+ 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.";
45867
+ /**
45868
+ * 不计入连击的协调类工具。
45869
+ *
45870
+ * 这些工具**本来就会**被反复调用:报一次进展、更新一次待办、问一次用户。把它们
45871
+ * 算进连击等于让刹车对着正常的心跳乱响。
45872
+ */
45873
+ const REPEAT_BREAKER_EXEMPT_TOOLS = Object.freeze([
45874
+ "progress_update",
45875
+ "todo_write",
45876
+ "ask_user_question",
45877
+ "enter_plan_mode",
45878
+ "exit_plan_mode",
45879
+ "leave_plan_mode",
45880
+ "create_goal",
45881
+ "update_goal",
45882
+ "get_goal",
45883
+ "dispatch_ledger",
45884
+ "present"
45885
+ ]);
45886
+ /**
45887
+ * 判断一个工具是不是不计入连击的协调类工具。
45888
+ *
45889
+ * @param toolName - 工具名。
45890
+ * @returns 豁免时为 true。
45891
+ */
45892
+ function isRepeatBreakerExemptTool(toolName) {
45893
+ return REPEAT_BREAKER_EXEMPT_TOOLS.includes(toolName);
45894
+ }
45895
+ /** 明确表示「关掉」的环境变量取值。 */
45896
+ const DISABLED_ENV_VALUES = /* @__PURE__ */ new Set([
45897
+ "0",
45898
+ "false",
45899
+ "no",
45900
+ "off"
45901
+ ]);
45902
+ /**
45903
+ * 读重复刹车当前是否启用。
45904
+ *
45905
+ * **默认开启**:刹车是保护,不是功能开关。只有环境变量明确写成
45906
+ * 0 / false / no / off(大小写不敏感)才关掉它。
45907
+ *
45908
+ * @param env - 环境变量视图;默认读 process.env。
45909
+ * @returns 启用时为 true。
45910
+ */
45911
+ function isKimiRepeatBreakerEnabled(env = process.env) {
45912
+ const raw = env[REPEAT_BREAKER_ENV];
45913
+ if (typeof raw !== "string") return true;
45914
+ return !DISABLED_ENV_VALUES.has(raw.trim().toLowerCase());
45915
+ }
45916
+ /**
45917
+ * 判断一个值是不是普通对象(原型是 Object.prototype 或 null)。
45918
+ *
45919
+ * @param value - 任意值。
45920
+ * @returns 是普通对象时为 true。
45921
+ */
45922
+ function isPlainRecord(value) {
45923
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
45924
+ const prototype = Object.getPrototypeOf(value);
45925
+ return prototype === Object.prototype || prototype === null;
45926
+ }
45927
+ /**
45928
+ * 判断一个值是不是对象(数组也算)。
45929
+ *
45930
+ * @param value - 任意值。
45931
+ * @returns 是对象时为 true。
45932
+ */
45933
+ function isRecord$45(value) {
45934
+ return typeof value === "object" && value !== null;
45935
+ }
45936
+ /**
45937
+ * 读一个未知字段为非空字符串。
45938
+ *
45939
+ * @param value - 候选值。
45940
+ * @returns 字符串,或任何其它类型的 undefined。
45941
+ */
45942
+ function stringOf$3(value) {
45943
+ return typeof value === "string" && value !== "" ? value : void 0;
45944
+ }
45945
+ /**
45946
+ * 读一次工具调用所属的线路。
45947
+ *
45948
+ * provider 的四个来源按可靠性排序:**请求头快照**(唯一反映「已经真的路由到
45949
+ * 哪个 provider」的那一份)→ **模型选择面**(首步还没有请求头时唯一还能说出
45950
+ * 这一场走哪条线路的地方)→ **agent 选项**(还没发出请求时唯一的意图)→
45951
+ * **agent 自身的 provider 字段**(最后的兜底)。
45952
+ *
45953
+ * 每一处读取都独立 try/catch:任何一处抛错都只是「这一处读不到」,不改变
45954
+ * 其余来源的行为,也不让整次读取失败。
45955
+ *
45956
+ * @param agent - 事件里的调用方 agent。
45957
+ * @returns 线路信息;读不到的字段省略。
45958
+ */
45959
+ function kimiSessionRouteOf(agent) {
45960
+ const record = isRecord$45(agent) ? agent : void 0;
45961
+ const session = record?.session;
45962
+ let provider;
45963
+ try {
45964
+ provider = stringOf$3(session?.requestHeader?.()?.config?.provider);
45965
+ } catch {
45966
+ provider = void 0;
45967
+ }
45968
+ if (provider === void 0) try {
45969
+ provider = stringOf$3(record?.model?.current?.()?.provider);
45970
+ } catch {
45971
+ provider = void 0;
45972
+ }
45973
+ if (provider === void 0) provider = stringOf$3(record?.options?.provider);
45974
+ if (provider === void 0) provider = stringOf$3(record?.provider);
45975
+ const sessionId = stringOf$3(session?.header?.id) ?? stringOf$3(record?.id);
45976
+ return {
45977
+ ...provider === void 0 ? {} : { provider },
45978
+ ...sessionId === void 0 ? {} : { sessionId }
45979
+ };
45980
+ }
45981
+ /**
45982
+ * 递归把一个值重排成「键名有序」的形状。
45983
+ *
45984
+ * 数组**保持原序**:数组元素的顺序本身就是语义([1, 2] 与 [2, 1] 不是同一件事),
45985
+ * 只有对象的键名顺序没有语义。
45986
+ *
45987
+ * @param value - 当前值。
45988
+ * @returns 重排后的值。
45989
+ */
45990
+ function sortJsonValue(value) {
45991
+ if (Array.isArray(value)) return value.map(sortJsonValue);
45992
+ if (!isPlainRecord(value)) return value;
45993
+ const out = {};
45994
+ for (const key of Object.keys(value).sort()) out[key] = sortJsonValue(value[key]);
45995
+ return out;
45996
+ }
45997
+ /**
45998
+ * 造一次工具调用的**规范键**。
45999
+ *
46000
+ * 键 = 工具名 + 参数的规范 JSON。参数先递归重排键名再序列化,于是
46001
+ * { a: 1, b: 2 } 与 { b: 2, a: 1 } 得到**完全相同**的键 —— 否则模型只是把参数
46002
+ * 的书写顺序换了一下,刹车就看不见这是一个连击。
46003
+ *
46004
+ * @param toolName - 工具名。
46005
+ * @param args - 工具参数。
46006
+ * @returns 规范键。
46007
+ */
46008
+ function canonicalKimiToolCallKey(toolName, args) {
46009
+ let json;
46010
+ try {
46011
+ json = JSON.stringify(sortJsonValue(args));
46012
+ } catch {
46013
+ json = void 0;
46014
+ }
46015
+ return toolName + " " + (json ?? String(args));
46016
+ }
46017
+ /**
46018
+ * 造一台重复刹车。
46019
+ *
46020
+ * 状态**按会话**分开:连击是「这场对话里的同一件事重复了多少次」,两个会话
46021
+ * 互不相干。
46022
+ *
46023
+ * @returns 一台重复刹车。
46024
+ */
46025
+ function createKimiRepeatBreaker() {
46026
+ const sessions = /* @__PURE__ */ new Map();
46027
+ /** 取一个会话的状态;没有就新建一个。 */
46028
+ const stateOf = (sessionId) => {
46029
+ const existing = sessions.get(sessionId);
46030
+ if (existing !== void 0) return existing;
46031
+ const created = {
46032
+ consecutiveKey: null,
46033
+ consecutiveCount: 0,
46034
+ handoffActive: false
46035
+ };
46036
+ sessions.set(sessionId, created);
46037
+ return created;
46038
+ };
46039
+ return {
46040
+ checkBeforeExecute(sessionId, toolName, args) {
46041
+ const state = stateOf(sessionId);
46042
+ if (state.handoffActive) return HANDOFF_VETO_TEXT;
46043
+ const key = canonicalKimiToolCallKey(toolName, args);
46044
+ if (state.consecutiveKey === key && state.consecutiveCount + 1 >= 12) {
46045
+ state.consecutiveCount += 1;
46046
+ state.handoffActive = true;
46047
+ return HANDOFF_VETO_TEXT;
46048
+ }
46049
+ },
46050
+ recordAfterExecute(sessionId, toolName, args) {
46051
+ if (isRepeatBreakerExemptTool(toolName)) return void 0;
46052
+ const state = stateOf(sessionId);
46053
+ if (state.handoffActive) return REMINDER_TEXT_3;
46054
+ const key = canonicalKimiToolCallKey(toolName, args);
46055
+ if (state.consecutiveKey === key) state.consecutiveCount += 1;
46056
+ else {
46057
+ state.consecutiveKey = key;
46058
+ state.consecutiveCount = 1;
46059
+ }
46060
+ if (state.consecutiveCount >= 12) {
46061
+ state.handoffActive = true;
46062
+ return REMINDER_TEXT_3;
46063
+ }
46064
+ if (state.consecutiveCount >= 8) return REMINDER_TEXT_3;
46065
+ if (state.consecutiveCount >= 5) return makeReminderText2(state.consecutiveCount);
46066
+ if (state.consecutiveCount >= 3) return REMINDER_TEXT_1;
46067
+ },
46068
+ resetSession(sessionId) {
46069
+ sessions.delete(sessionId);
46070
+ }
46071
+ };
46072
+ }
46073
+ /**
46074
+ * 读宿主上下文上的工具注册面。
46075
+ *
46076
+ * @param ctx - 宿主上下文。
46077
+ * @returns 工具注册面;没有时为 undefined。
46078
+ */
46079
+ function toolsServiceOf(ctx) {
46080
+ const read = ctx.get;
46081
+ if (typeof read === "function") try {
46082
+ const found = read.call(ctx, "tools");
46083
+ if (found !== void 0) return found;
46084
+ } catch {}
46085
+ const direct = ctx.tools;
46086
+ return direct === void 0 ? void 0 : direct;
46087
+ }
46088
+ /**
46089
+ * 已挂载的模块登记表,走一个 global symbol:同一个包的两份模块实例(npm 拷贝与
46090
+ * 仓库 link)仍然共享一次判定,而重复装两台刹车会让同一次调用被记两遍。
46091
+ */
46092
+ const MOUNTED$1 = Symbol.for("dsh-chatgpt-subscription.mounted-modules");
46093
+ /** 本模块在登记表里的名字。 */
46094
+ const MODULE_ID$1 = "kimi-repeat-breaker";
46095
+ /**
46096
+ * 单实例守卫:本模块已挂载时放弃本次安装。
46097
+ *
46098
+ * @param ctx - 宿主上下文。
46099
+ * @returns 释放函数(交出挂载权);已经挂载过时返回 undefined。
46100
+ */
46101
+ function claimMount$1(ctx) {
46102
+ const registry = globalThis;
46103
+ const existing = registry[MOUNTED$1];
46104
+ const mounted = existing instanceof Set ? existing : /* @__PURE__ */ new Set();
46105
+ if (existing !== mounted) registry[MOUNTED$1] = mounted;
46106
+ if (mounted.has(MODULE_ID$1)) return void 0;
46107
+ mounted.add(MODULE_ID$1);
46108
+ const release = () => {
46109
+ mounted.delete(MODULE_ID$1);
46110
+ };
46111
+ if (typeof ctx.effect === "function") ctx.effect(() => release, "dsh-chatgpt-subscription: kimi repeat breaker mount");
46112
+ return release;
46113
+ }
46114
+ /**
46115
+ * 把一条 post-execute 决策接上附加上下文,保住它原有的形状。
46116
+ *
46117
+ * @param decision - next() 交回来的决策。
46118
+ * @param contexts - 要追加的上下文。
46119
+ * @returns 追加后的决策。
46120
+ */
46121
+ function withAdditionalContexts(decision, contexts) {
46122
+ const additionalContexts = [...decision.additionalContexts ?? [], ...contexts];
46123
+ if (decision.kind === "block") return {
46124
+ kind: "block",
46125
+ feedback: decision.feedback,
46126
+ additionalContexts
46127
+ };
46128
+ if (decision.value !== void 0) return {
46129
+ kind: "accept",
46130
+ value: decision.value,
46131
+ additionalContexts
46132
+ };
46133
+ if (decision.content !== void 0) return {
46134
+ kind: "accept",
46135
+ content: decision.content,
46136
+ additionalContexts
46137
+ };
46138
+ return {
46139
+ kind: "accept",
46140
+ additionalContexts
46141
+ };
46142
+ }
46143
+ /**
46144
+ * 造一条重复刹车的提醒上下文。
46145
+ *
46146
+ * @param text - 提醒正文。
46147
+ * @returns 可直接放进 additionalContexts 的用户角色消息。
46148
+ */
46149
+ function createRepeatBreakerReminder(text) {
46150
+ return createUserMessage({
46151
+ content: [{
46152
+ type: "text",
46153
+ text
46154
+ }],
46155
+ source: {
46156
+ kind: "kimi-repeat-breaker",
46157
+ form: "notice",
46158
+ summary: "repeat breaker reminder"
46159
+ }
46160
+ });
46161
+ }
46162
+ /**
46163
+ * 判断一条消息是不是**真的**用户发言。
46164
+ *
46165
+ * 本模块自己追加的提醒也是 user 角色的消息(宿主要求附加上下文走 user 角色),
46166
+ * 所以判定不能只看角色:得看来源是不是 user。
46167
+ *
46168
+ * @param message - 候选消息。
46169
+ * @returns 是真人用户发言时为 true。
46170
+ */
46171
+ function isRealUserTurn(message) {
46172
+ if (!isRecord$45(message)) return false;
46173
+ const role = message["role"];
46174
+ if (role !== void 0 && role !== "user") return false;
46175
+ const source = message["source"];
46176
+ if (!isRecord$45(source)) return false;
46177
+ return source["kind"] === "user";
46178
+ }
46179
+ /**
46180
+ * 装上 Kimi Code 的重复刹车。
46181
+ *
46182
+ * 四条接缝:ctx.tools.guard()(强停时拦下调用)、tools/post-execute(三段提醒)、
46183
+ * agent/pre-step(新一轮用户输入重置连击)、agent/disposed(会话拆除时清状态)。
46184
+ * 工具声明面一个字节都不改。
46185
+ *
46186
+ * @param ctx - 宿主插件上下文。
46187
+ * @param options - 安装选项。
46188
+ * @returns 卸载函数。
46189
+ */
46190
+ function installKimiRepeatBreaker(ctx, options = {}) {
46191
+ const releaseMount = claimMount$1(ctx);
46192
+ if (releaseMount === void 0) return () => void 0;
46193
+ const breaker = createKimiRepeatBreaker();
46194
+ const enabled = options.enabled ?? (() => isKimiRepeatBreakerEnabled());
46195
+ /** 读一次开关。读失败按**开启**处理:保护不该因为一次读失败而失效。 */
46196
+ const isEnabled = () => {
46197
+ try {
46198
+ return enabled() !== false;
46199
+ } catch {
46200
+ return true;
46201
+ }
46202
+ };
46203
+ /**
46204
+ * 取一次执行所属的会话;不是 Kimi Code 这条线路时是 undefined。
46205
+ *
46206
+ * @param agent - 调用方 agent。
46207
+ * @returns 会话标识;不该管时是 undefined。
46208
+ */
46209
+ const kimiSessionIdOf = (agent) => {
46210
+ const route = kimiSessionRouteOf(agent);
46211
+ if (route.provider !== "kimi-code") return void 0;
46212
+ return route.sessionId;
46213
+ };
46214
+ const disposeGuard = toolsServiceOf(ctx)?.guard?.((execution) => {
46215
+ try {
46216
+ if (!isEnabled()) return void 0;
46217
+ const record = isRecord$45(execution) ? execution : void 0;
46218
+ const agent = record?.["agent"];
46219
+ const sessionId = kimiSessionIdOf(agent);
46220
+ if (sessionId === void 0) return void 0;
46221
+ const toolName = stringOf$3(record?.["name"]);
46222
+ if (toolName === void 0) return void 0;
46223
+ const veto = breaker.checkBeforeExecute(sessionId, toolName, record?.["arguments"]);
46224
+ if (veto === HANDOFF_VETO_TEXT) return HANDOFF_VETO_TEXT;
46225
+ return veto;
46226
+ } catch {
46227
+ return;
46228
+ }
46229
+ });
46230
+ const disposePostExecute = ctx.on?.("tools/post-execute", (async (exec, result, next) => {
46231
+ const decision = await next();
46232
+ try {
46233
+ if (!isEnabled()) return decision;
46234
+ const agent = exec.agent;
46235
+ const sessionId = kimiSessionIdOf(agent);
46236
+ if (sessionId === void 0) return decision;
46237
+ const toolName = stringOf$3(exec.name);
46238
+ if (toolName === void 0) return decision;
46239
+ const reminder = breaker.recordAfterExecute(sessionId, toolName, exec.arguments);
46240
+ if (reminder === void 0) return decision;
46241
+ return withAdditionalContexts(decision, [createRepeatBreakerReminder(reminder)]);
46242
+ } catch {
46243
+ return decision;
46244
+ }
46245
+ }));
46246
+ const disposePreStep = ctx.on?.("agent/pre-step", (async (payload, next) => {
46247
+ const decision = await next();
46248
+ try {
46249
+ if (!isRealUserTurn((Array.isArray(payload?.messages) ? payload.messages : []).at(-1))) return decision;
46250
+ const sessionId = kimiSessionIdOf(payload?.agent);
46251
+ if (sessionId === void 0) return decision;
46252
+ breaker.resetSession(sessionId);
46253
+ } catch {
46254
+ return decision;
46255
+ }
46256
+ return decision;
46257
+ }));
46258
+ const disposeDisposed = ctx.on?.("agent/disposed", ((payload) => {
46259
+ try {
46260
+ const sessionId = kimiSessionIdOf(payload?.agent);
46261
+ if (sessionId === void 0) return;
46262
+ breaker.resetSession(sessionId);
46263
+ } catch {}
46264
+ }));
46265
+ return () => {
46266
+ disposeGuard?.();
46267
+ disposePostExecute?.();
46268
+ disposePreStep?.();
46269
+ disposeDisposed?.();
46270
+ releaseMount();
46271
+ };
46272
+ }
44506
46273
  //#endregion
44507
46274
  //#region src/host/minimax-code/account-pool.ts
44508
46275
  /**
@@ -83486,6 +85253,13 @@ function markPatched$2(patched, holder, name) {
83486
85253
  if (names === void 0) patched.set(holder, /* @__PURE__ */ new Set([name]));
83487
85254
  else names.add(name);
83488
85255
  }
85256
+ /**
85257
+ * 默认受保护的 provider 名单。
85258
+ *
85259
+ * `kimi-code` 与 `minimax-code` 都按前缀缓存计费:`tools:sdk` 段一旦被改写,
85260
+ * 前缀缓存从改写处起全部作废,所以这两条线路默认都要冻结 SDK 段。
85261
+ */
85262
+ const DEFAULT_PTC_SDK_CACHE_PROVIDERS = Object.freeze(["kimi-code", "minimax-code"]);
83489
85263
  /** PTC 生成的 SDK 段名。 */
83490
85264
  const PTC_SDK_SECTION_NAME = "tools:sdk";
83491
85265
  /** 没有 scope 的装配(会话标题之类)用的桶键。 */
@@ -83565,7 +85339,7 @@ function readScopeProvider(scope) {
83565
85339
  */
83566
85340
  function installPtcSdkCacheGuard(ctx, options = {}) {
83567
85341
  const host = isRecord$13(ctx) ? ctx : void 0;
83568
- const providers = new Set(options.providers ?? ["kimi-code"]);
85342
+ const providers = new Set(options.providers ?? DEFAULT_PTC_SDK_CACHE_PROVIDERS);
83569
85343
  /** 已包装过的实例(幂等标记)。 */
83570
85344
  const alreadyWrapped = /* @__PURE__ */ new WeakSet();
83571
85345
  /** 已包装过的「方法宿主 + 方法名」:同一个原型不叠第二层包装。 */
@@ -84986,39 +86760,68 @@ const HEADER_SCHEMA = z.strictObject({
84986
86760
  ]).optional()
84987
86761
  });
84988
86762
  /**
86763
+ * 每种角色**允许携带**的字段集。
86764
+ *
86765
+ * 同一个字段集只写一次:它既出现在 kind 违规的拒绝文案尾部(模型被拒时当场
86766
+ * 唯一的纠错入口),也出现在守卫的两条 `MANDATE_KIND` 拒绝里。文案与 schema
86767
+ * 各写一套,迟早会重演"样板自己非法"那类事故。
86768
+ */
86769
+ const MANDATE_KIND_FIELDS = {
86770
+ dispatch: "v, kind, brief_id, run_id, idem, mandate_version, prompt_ref, policy, task, boundary, followup, parent_mandate",
86771
+ report: "v, kind, brief_id, run_id, idem, mandate_version, prompt_ref, policy, status",
86772
+ steer: "v, kind, brief_id, run_id, idem, mandate_version, prompt_ref, policy, grant"
86773
+ };
86774
+ /**
86775
+ * 拼出"这个方向到底该带什么"的纠错尾巴。
86776
+ *
86777
+ * 拒绝文案只说"不许带 X"时,模型只能逐个字段试错——它反复写不对的原因正在这里。
86778
+ * 把该方向的字段集直接贴在违规说明后面,一次往返就能改对。
86779
+ * @param kind - 声明了角色、却用错了字段的那种角色。
86780
+ * @returns 追加在违规说明之后的纠错尾巴。
86781
+ */
86782
+ function kindRepairHint(kind) {
86783
+ return " (a " + kind + " header carries exactly: " + MANDATE_KIND_FIELDS[kind] + "; copy the ready-to-send block from dispatch_ledger {action:\"self\"})";
86784
+ }
86785
+ /**
84989
86786
  * 校验 kind 与字段的组合。
84990
86787
  *
84991
86788
  * 字段是"按角色出现"的:dispatch 带 task/boundary/followup/parent_mandate,
84992
86789
  * report 带 status,steer 带 grant。组合不合法 = 头部损坏,而不是"忽略
84993
86790
  * 多余字段"——多带字段往往意味着模型抄错了角色。
86791
+ *
86792
+ * `null` 与"没写"同义:schema 把 parent_mandate / grant 声明成 nullable,模型
86793
+ * 也习惯把用不到的字段写成 null。把 null 当成"携带了这个字段",等于拒绝一个
86794
+ * 语义上完全正确、只是写法啰嗦的头部。
84994
86795
  * @param header - 已通过 schema 的头部。
84995
86796
  * @returns 违规说明;合法时 undefined。
84996
86797
  */
84997
86798
  function kindViolation(header) {
86799
+ const carriedParent = header.parent_mandate !== void 0 && header.parent_mandate !== null;
86800
+ const carriedGrant = header.grant !== void 0 && header.grant !== null;
84998
86801
  if (header.kind === "dispatch") {
84999
- if (header.task === void 0) return "a dispatch header must carry task";
85000
- if (header.boundary === void 0) return "a dispatch header must carry boundary";
85001
- if (header.followup === void 0) return "a dispatch header must carry followup";
85002
- if (header.parent_mandate === void 0) return "a dispatch header must carry parent_mandate";
85003
- if (header.grant !== void 0) return "a dispatch header must not carry grant";
85004
- if (header.status !== void 0) return "a dispatch header must not carry status";
86802
+ if (header.task === void 0) return "a dispatch header must carry task" + kindRepairHint("dispatch");
86803
+ if (header.boundary === void 0) return "a dispatch header must carry boundary" + kindRepairHint("dispatch");
86804
+ if (header.followup === void 0) return "a dispatch header must carry followup" + kindRepairHint("dispatch");
86805
+ if (header.parent_mandate === void 0) return "a dispatch header must carry parent_mandate" + kindRepairHint("dispatch");
86806
+ if (carriedGrant) return "a dispatch header must not carry grant" + kindRepairHint("dispatch");
86807
+ if (header.status !== void 0) return "a dispatch header must not carry status" + kindRepairHint("dispatch");
85005
86808
  return;
85006
86809
  }
85007
86810
  if (header.kind === "report") {
85008
- if (header.status === void 0) return "a report header must carry status";
85009
- if (header.task !== void 0) return "a report header must not carry task";
85010
- if (header.boundary !== void 0) return "a report header must not carry boundary";
85011
- if (header.followup !== void 0) return "a report header must not carry followup";
85012
- if (header.parent_mandate !== void 0) return "a report header must not carry parent_mandate";
85013
- if (header.grant !== void 0) return "a report header must not carry grant";
86811
+ if (header.status === void 0) return "a report header must carry status" + kindRepairHint("report");
86812
+ if (header.task !== void 0) return "a report header must not carry task" + kindRepairHint("report");
86813
+ if (header.boundary !== void 0) return "a report header must not carry boundary" + kindRepairHint("report");
86814
+ if (header.followup !== void 0) return "a report header must not carry followup" + kindRepairHint("report");
86815
+ if (carriedParent) return "a report header must not carry parent_mandate" + kindRepairHint("report");
86816
+ if (carriedGrant) return "a report header must not carry grant" + kindRepairHint("report");
85014
86817
  return;
85015
86818
  }
85016
- if (header.grant === void 0) return "a steer header must carry grant";
85017
- if (header.status !== void 0) return "a steer header must not carry status";
85018
- if (header.task !== void 0) return "a steer header must not carry task";
85019
- if (header.boundary !== void 0) return "a steer header must not carry boundary";
85020
- if (header.followup !== void 0) return "a steer header must not carry followup";
85021
- if (header.parent_mandate !== void 0) return "a steer header must not carry parent_mandate";
86819
+ if (header.grant === void 0) return "a steer header must carry grant" + kindRepairHint("steer");
86820
+ if (header.status !== void 0) return "a steer header must not carry status" + kindRepairHint("steer");
86821
+ if (header.task !== void 0) return "a steer header must not carry task" + kindRepairHint("steer");
86822
+ if (header.boundary !== void 0) return "a steer header must not carry boundary" + kindRepairHint("steer");
86823
+ if (header.followup !== void 0) return "a steer header must not carry followup" + kindRepairHint("steer");
86824
+ if (carriedParent) return "a steer header must not carry parent_mandate" + kindRepairHint("steer");
85022
86825
  }
85023
86826
  /**
85024
86827
  * 解析一段文本里的 Mandate v2 头部。
@@ -86882,7 +88685,7 @@ function createDispatchLedgerGuard(options) {
86882
88685
  if (parsed.state === "invalid" || parsed.header === void 0) return dispatchDenial("MANDATE_MALFORMED", "the mandate header could not be parsed (" + (parsed.reason ?? "unknown reason") + ").");
86883
88686
  const header = parsed.header;
86884
88687
  if (isDispatch) {
86885
- if (header.kind !== "dispatch") return dispatchDenial("MANDATE_KIND", "a dispatch call must carry a kind \"dispatch\" header.");
88688
+ if (header.kind !== "dispatch") return dispatchDenial("MANDATE_KIND", "a dispatch call must carry a kind \"dispatch\" header. A dispatch header carries exactly: " + MANDATE_KIND_FIELDS.dispatch + " (copy the ready-to-send block from dispatch_ledger {action:\"self\"}).");
86886
88689
  const session = sessionOfAgent$1(execution?.agent);
86887
88690
  const state = session === void 0 ? initialDispatchLedgerState() : cache.fold(session);
86888
88691
  const policy = options.policyFor?.(session ?? { id: "" });
@@ -86893,7 +88696,7 @@ function createDispatchLedgerGuard(options) {
86893
88696
  if (denial === void 0 && issuer !== void 0 && callId !== void 0) reservations.reserve(issuer, ns, callId);
86894
88697
  return denial;
86895
88698
  }
86896
- if (header.kind === "dispatch") return dispatchDenial("MANDATE_KIND", "a dispatch header belongs to the delegation tool, not send_message.");
88699
+ if (header.kind === "dispatch") return dispatchDenial("MANDATE_KIND", "a dispatch header belongs to the delegation tool, not send_message. A report header carries exactly: " + MANDATE_KIND_FIELDS.report + "; a steer header exactly: " + MANDATE_KIND_FIELDS.steer + ".");
86897
88700
  const targetId = asString$2(args["agent_id"]);
86898
88701
  if (targetId === void 0) return void 0;
86899
88702
  const sessions = sessionsOf();
@@ -86952,64 +88755,60 @@ function installDispatchLedgerGuard(ctx, options = {}) {
86952
88755
  const DISPATCH_MANDATE_PROTOCOL = [
86953
88756
  "Dispatch Ledger - Mandate protocol v2",
86954
88757
  "",
86955
- "1. HEADER. Put the fenced block below at the VERY START of the text you pass to",
86956
- "`subagent.prompt` (dispatch) or to `send_message.message` (report/steer).",
86957
- "Nothing may precede it. The task text follows the closing fence.",
88758
+ "1. HEADER. Put ONE fenced block at the VERY START of the text you pass to",
88759
+ "`subagent.prompt` (dispatch) or `send_message.message` (report/steer). Nothing",
88760
+ "may precede it; the body follows the closing fence.",
86958
88761
  "",
86959
88762
  "```dsh-mandate-v2",
86960
- "{\"v\":2,\"kind\":\"dispatch\",\"brief_id\":\"b-7f\",\"run_id\":\"r-1\",\"idem\":\"i-1\",\"mandate_version\":1,\"prompt_ref\":\"plan-v3\",\"policy\":{\"id\":\"dsh-dispatch-ledger\",\"version\":\"1\",\"sha256\":\"3f9a1c2b3c4d5e6f\"},\"task\":[\"task://req-42\"],\"boundary\":[\"src/host/dispatch-ledger/**\"],\"followup\":[\"ctx://plan-v3\"],\"parent_mandate\":null,\"grant\":null}",
88763
+ "{\"v\":2,\"kind\":\"dispatch\",\"brief_id\":\"b-7f\",\"run_id\":\"r-1\",\"idem\":\"i-1\",\"mandate_version\":1,\"prompt_ref\":\"plan-v3\",\"policy\":{\"id\":\"dsh-dispatch-ledger\",\"version\":\"1\",\"sha256\":\"3f9a1c2b3c4d5e6f\"},\"task\":[\"task://req-42\"],\"boundary\":[\"src/host/dispatch-ledger/**\"],\"followup\":[\"ctx://plan-v3\"],\"parent_mandate\":null}",
86961
88764
  "```",
86962
88765
  "",
86963
- "2. FIELDS.",
86964
- "v = 2 (anything else is malformed).",
86965
- "kind: \"dispatch\" (new delegation), \"report\" (child -> owner), \"steer\" (owner -> child).",
86966
- "brief_id: the work item. Stable across runs. <=64 chars, [A-Za-z0-9._:-].",
86967
- "run_id: one dispatch attempt. Use a NEW value after a hand_back.",
86968
- "idem: idempotency key inside one run. Use a NEW value after a hand_back.",
86969
- "mandate_version: 1 (the authorization snapshot version).",
86970
- "prompt_ref: copy it verbatim from dispatch_ledger {action:\"self\"} (the prompt_ref field of",
86971
- " that result). Never invent one. A report or a steer MUST echo the mandate's own",
86972
- " prompt_ref unchanged.",
86973
- "policy: {id, version, sha256} copied verbatim from dispatch_ledger {action:\"self\"}.",
86974
- " sha256 is the first 12 or more hex characters the tool printed.",
86975
- "task: <=4 references (<=160 chars each) naming the original request. NOT the request text.",
86976
- "boundary: <=16 structured boundary entries (<=120 chars each), e.g. \"src/host/dispatch-ledger/**\".",
86977
- "followup: <=8 references (<=120 chars each) naming the context this delegation may later ask for.",
86978
- "parent_mandate: null on the first run of a brief; a later run must set {brief_id, run_id, idem}",
86979
- " of the run it replaces.",
86980
- "grant (steer only): null, or {context:[...]} where every entry is already in that run followup.",
86981
- "status (report only): ready | hand_back | blocked | failed | dropped.",
86982
- "The body after the closing fence is sealed by the host: it computes the sha256 and",
86983
- " stores it in the ledger. Do NOT put a hash in the header: an unknown field makes",
86984
- " the header malformed.",
88766
+ "2. PER KIND. Each kind carries its own fields and NO others: one foreign field",
88767
+ "makes the whole header malformed.",
88768
+ "- dispatch: the block above. task: <=4 references (<=160 chars) naming the",
88769
+ " request, NOT its text. boundary: <=16 entries (<=120 chars). followup: <=8",
88770
+ " references (<=120 chars). parent_mandate: null on the first run of a brief,",
88771
+ " else the {brief_id, run_id, idem} of the run this one replaces.",
88772
+ "- report: the same block MINUS task, boundary, followup and parent_mandate, PLUS",
88773
+ " \"status\":\"ready\"|\"hand_back\"|\"blocked\"|\"failed\"|\"dropped\". Take brief_id,",
88774
+ " run_id, idem, prompt_ref and policy from YOUR OWN mandate - read them with",
88775
+ " dispatch_ledger {action:\"self\"} - never from the message you received.",
88776
+ "- steer: the same block MINUS task, boundary, followup and parent_mandate, PLUS",
88777
+ " \"grant\": {\"context\":[\"...\"]} (entries already in that run followup) or null.",
88778
+ "",
88779
+ "3. FIELDS. v = 2, mandate_version = 1. brief_id: the work item, stable across",
88780
+ "runs, <=64 chars from [A-Za-z0-9._:-]. run_id: one dispatch attempt. idem: the",
88781
+ "idempotency key inside one run; both are NEW after a hand_back. prompt_ref and",
88782
+ "policy: copy verbatim from dispatch_ledger {action:\"self\"}; never invent them.",
88783
+ "The host seals the body by hashing it, so never put a hash in the header: an",
88784
+ "unknown field makes the header malformed.",
86985
88785
  "",
86986
- "3. FLOW.",
86987
- "a. Call dispatch_ledger {action:\"self\"} ONCE. Copy policy from the result. This protocol is",
86988
- " printed at the TAIL of that result.",
86989
- "b. Dispatch: header (kind=dispatch) then the task text, in `subagent.prompt`.",
88786
+ "4. FLOW.",
88787
+ "a. Call dispatch_ledger {action:\"self\"} ONCE. Copy policy and prompt_ref from it;",
88788
+ " this protocol is printed at the TAIL of that result.",
88789
+ "b. Dispatch: dispatch header + task text, in `subagent.prompt`.",
86990
88790
  "c. The child reads its own mandate with dispatch_ledger {action:\"self\"}.",
86991
- "d. Report: header (kind=report, status=...) then the result, in `send_message` to your parent agent id.",
86992
- "e. Steer: header (kind=steer, grant=...) in `send_message` to the child.",
88791
+ "d. Report: report header + result, in `send_message` to your parent agent id.",
88792
+ "e. Steer: steer header, in `send_message` to the child.",
86993
88793
  "",
86994
- "4. REJECTION CODES. The guard denies only these.",
86995
- "MANDATE_MALFORMED: the header does not parse, or a field is out of range.",
88794
+ "5. REJECTION CODES. These are the only denials; each one names its fix.",
88795
+ "MANDATE_MALFORMED: the header does not parse, or carries a field its kind does",
88796
+ " not allow. Re-send with exactly the fields of that kind.",
86996
88797
  "MANDATE_KIND: the kind does not match the tool.",
86997
- "MANDATE_DUPLICATE: the namespace (brief_id, run_id, idem) is already claimed. A namespace is",
86998
- " never reusable, not even after a release. Use a NEW run_id AND a NEW idem, and set parent_mandate.",
86999
- "MANDATE_BRIEF_BUSY: another run of this brief is still booked. Wait for it, or use a new brief_id.",
87000
- "MANDATE_LINEAGE_REQUIRED: this brief already has a run, but parent_mandate is missing.",
87001
- "MANDATE_LINEAGE: parent_mandate does not point at the latest released run of this brief.",
87002
- "MANDATE_POLICY_STALE: the policy block does not match the current one. Re-read",
87003
- " dispatch_ledger {action:\"self\"} and copy it again.",
88798
+ "MANDATE_DUPLICATE: the namespace (brief_id, run_id, idem) is claimed and never",
88799
+ " reusable. Use a NEW run_id AND a NEW idem, and set parent_mandate.",
88800
+ "MANDATE_BRIEF_BUSY: another run of this brief is still booked. Wait, or use a new brief_id.",
88801
+ "MANDATE_LINEAGE_REQUIRED: the brief already has a run, but parent_mandate is missing.",
88802
+ "MANDATE_LINEAGE: parent_mandate does not point at the latest settled run of the brief.",
88803
+ "MANDATE_POLICY_STALE: the policy block is not current. Copy it from self again.",
87004
88804
  "MANDATE_VERSION: mandate_version or prompt_ref does not match the recorded run.",
87005
- "MANDATE_NOT_PARENT / MANDATE_NOT_CHILD: the other side is not your parent / not your child.",
88805
+ "MANDATE_NOT_PARENT: the agent you report to is not your parent.",
88806
+ "MANDATE_NOT_CHILD: the agent you steer is not your child.",
87006
88807
  "MANDATE_GRANT_EXCEEDS: grant.context asks for context outside followup.",
87007
88808
  "MANDATE_NOT_HELD: you do not hold this mandate.",
87008
- "MANDATE_LEDGER_FULL: the ledger reached its run or brief limit. Report it; never",
87009
- " reuse an old namespace to get around it.",
88809
+ "MANDATE_LEDGER_FULL: the ledger is full. Report it; never reuse an old namespace.",
87010
88810
  "",
87011
- "5. A dispatch without a header is allowed but audited, and it cannot be de-duplicated.",
87012
- " After a hand_back the new run needs a NEW run_id and a NEW idem: never reuse the old ones."
88811
+ "6. A dispatch with no header is allowed but audited, and cannot be de-duplicated."
87013
88812
  ].join("\n");
87014
88813
  //#endregion
87015
88814
  //#region src/host/dispatch-ledger/tool.ts
@@ -87166,6 +88965,98 @@ function matchesFilters(row, args) {
87166
88965
  return true;
87167
88966
  }
87168
88967
  /**
88968
+ * 造一个本次渲染专用的 id。
88969
+ *
88970
+ * 骨架里的 brief_id / run_id / idem 必须是"抄下来就能用"的真 id,所以每渲染
88971
+ * 一次就现造一组:模型原样照抄也不会撞上别处的命名空间。
88972
+ * @param prefix - id 前缀(b / r / i)。
88973
+ * @returns 符合头部 id 字符集 `[A-Za-z0-9._:-]` 的 id。
88974
+ */
88975
+ function skeletonId(prefix) {
88976
+ const stamp = Date.now().toString(36);
88977
+ const noise = Math.random().toString(36).slice(2, 8);
88978
+ return prefix + "-" + (stamp + noise).slice(-8);
88979
+ }
88980
+ /**
88981
+ * 把一段头部值包成"可复制"的围栏块,并**先用真解析器自检**。
88982
+ *
88983
+ * 宁可少给一段骨架,也不给一个模型抄了就被拒的头部——这段文本是它唯一的依据。
88984
+ * @param lead - 引导语:说清哪些字段要改、哪些一个都不能动。
88985
+ * @param header - 头部值。
88986
+ * @returns 引导语 + 围栏块;判不出 `ok` 时 undefined。
88987
+ */
88988
+ function readyToSendBlock(lead, header) {
88989
+ const block = "```dsh-mandate-v2\n" + JSON.stringify(header) + "\n```";
88990
+ if (parseMandateHeader(block).state !== "ok") return void 0;
88991
+ return lead + "\n" + block;
88992
+ }
88993
+ /**
88994
+ * 读一个策略块的三个字段。
88995
+ * @param value - value 里的 policy(或 mandate.policy)。
88996
+ * @returns 策略块;形状不对时 undefined。
88997
+ */
88998
+ function policyBlockOf(value) {
88999
+ if (!isRecord$7(value)) return void 0;
89000
+ return {
89001
+ id: value["id"],
89002
+ version: value["version"],
89003
+ sha256: value["sha256"]
89004
+ };
89005
+ }
89006
+ /**
89007
+ * 子代理的 **report 骨架**。
89008
+ *
89009
+ * brief_id / run_id / idem / prompt_ref / policy 全部来自它**自己持有的**那份
89010
+ * mandate(也就是它收到的派发头),所以它只需要改 status——把"自己拼 JSON"换成
89011
+ * "照着抄一行"。
89012
+ * @param mandate - `self` 结果里的 mandate。
89013
+ * @returns 可复制块;没有 mandate 或自检不过时 undefined。
89014
+ */
89015
+ function reportSkeletonOf(mandate) {
89016
+ if (mandate === void 0) return void 0;
89017
+ const policy = policyBlockOf(mandate["policy"]);
89018
+ if (policy === void 0) return void 0;
89019
+ return readyToSendBlock("report header - copy this block into send_message and change ONLY status (ready | hand_back | blocked | failed | dropped); every other field is yours already:", {
89020
+ v: 2,
89021
+ kind: "report",
89022
+ brief_id: mandate["brief_id"],
89023
+ run_id: mandate["run_id"],
89024
+ idem: mandate["idem"],
89025
+ mandate_version: mandate["mandate_version"],
89026
+ prompt_ref: mandate["prompt_ref"],
89027
+ policy,
89028
+ status: "ready"
89029
+ });
89030
+ }
89031
+ /**
89032
+ * 协调者的 **dispatch 骨架**。
89033
+ *
89034
+ * policy 与 prompt_ref 由宿主填好(模型不能自拟),三个 id 现造(每次派发都要
89035
+ * 换新的),task / boundary / followup 留成一眼就该改掉的占位符。
89036
+ * @param policy - `self` 结果里的 policy。
89037
+ * @param promptRef - `self` 结果里的 prompt_ref。
89038
+ * @returns 可复制块;宿主没给 policy / prompt_ref 时 undefined。
89039
+ */
89040
+ function dispatchSkeletonOf(policy, promptRef) {
89041
+ const block = policyBlockOf(policy);
89042
+ if (block === void 0) return void 0;
89043
+ if (typeof promptRef !== "string" || promptRef === "") return void 0;
89044
+ return readyToSendBlock("dispatch header - give every dispatch NEW brief_id / run_id / idem, make task, boundary and followup name your own work, and write the task text after the closing fence:", {
89045
+ v: 2,
89046
+ kind: "dispatch",
89047
+ brief_id: skeletonId("b"),
89048
+ run_id: skeletonId("r"),
89049
+ idem: skeletonId("i"),
89050
+ mandate_version: 1,
89051
+ prompt_ref: promptRef,
89052
+ policy: block,
89053
+ task: ["task://what-this-dispatch-delivers"],
89054
+ boundary: ["files or module this child may touch"],
89055
+ followup: ["ctx://context-it-may-ask-for-later"],
89056
+ parent_mandate: null
89057
+ });
89058
+ }
89059
+ /**
87169
89060
  * 构造 `dispatch_ledger` 工具。
87170
89061
  * @param deps - 依赖。
87171
89062
  * @returns 可注册的工具定义。
@@ -87380,15 +89271,18 @@ function createDispatchLedgerTool(deps) {
87380
89271
  if (record["action"] === "self") {
87381
89272
  const mandate = record["mandate"];
87382
89273
  const policy = record["policy"];
89274
+ const head = [
89275
+ "session " + String(record["sessionId"]) + (record["parentSessionId"] === void 0 ? "" : " (parent " + String(record["parentSessionId"]) + ")"),
89276
+ "policy " + String(policy?.["id"] ?? "none") + " " + String(policy?.["version"] ?? "") + " sha256 " + String(policy?.["sha256"] ?? ""),
89277
+ "prompt_ref (copy into a dispatch header): " + String(record["prompt_ref"] ?? "not provided by this host"),
89278
+ mandate === void 0 ? "mandate: none held by this session" : "mandate: brief " + String(mandate["brief_id"]) + " run " + String(mandate["run_id"]) + " idem " + String(mandate["idem"]) + " prompt_ref " + String(mandate["prompt_ref"]),
89279
+ "open: " + JSON.stringify(record["open"] ?? {})
89280
+ ].join("\n");
89281
+ const held = record["mandate"];
89282
+ const skeleton = (held === void 0 ? void 0 : reportSkeletonOf(held)) ?? dispatchSkeletonOf(policy, record["prompt_ref"]);
87383
89283
  return [{
87384
89284
  type: "text",
87385
- text: [
87386
- "session " + String(record["sessionId"]) + (record["parentSessionId"] === void 0 ? "" : " (parent " + String(record["parentSessionId"]) + ")"),
87387
- "policy " + String(policy?.["id"] ?? "none") + " " + String(policy?.["version"] ?? "") + " sha256 " + String(policy?.["sha256"] ?? ""),
87388
- "prompt_ref (copy into a dispatch header): " + String(record["prompt_ref"] ?? "not provided by this host"),
87389
- mandate === void 0 ? "mandate: none held by this session" : "mandate: brief " + String(mandate["brief_id"]) + " run " + String(mandate["run_id"]) + " idem " + String(mandate["idem"]) + " prompt_ref " + String(mandate["prompt_ref"]),
87390
- "open: " + JSON.stringify(record["open"] ?? {})
87391
- ].join("\n") + "\n\n" + DISPATCH_MANDATE_PROTOCOL
89285
+ text: skeleton === void 0 ? head + "\n\n" + DISPATCH_MANDATE_PROTOCOL : head + "\n\n" + skeleton + "\n\n" + DISPATCH_MANDATE_PROTOCOL
87392
89286
  }];
87393
89287
  }
87394
89288
  const lines = (record["entries"] ?? []).map((entry) => [
@@ -98965,6 +100859,8 @@ function apply(ctx, pluginConfig = {}) {
98965
100859
  const guard = installCompactionPolicyGuard(ctx);
98966
100860
  return () => guard.dispose();
98967
100861
  }, "dsh-chatgpt-subscription: compaction policy guard");
100862
+ ctx.effect(() => installMinimaxRuntimeEnhancements(ctx), "dsh-chatgpt-subscription: MiniMax runtime enhancements");
100863
+ ctx.effect(() => installKimiRepeatBreaker(ctx), "dsh-chatgpt-subscription: Kimi repeat breaker");
98968
100864
  ctx.effect(() => installDispatchExecutionGuard(ctx, { enabled: () => resolveDispatchExecutionGuardEnabled(pluginConfig) }), "dsh-chatgpt-subscription: dispatch execution guard");
98969
100865
  ctx.effect(() => installDispatchLedger(ctx, {
98970
100866
  enabled: () => resolveDispatchExecutionGuardEnabled(pluginConfig),