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