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