@eddyskywalker/dsh-chatgpt-subscription 0.59.0 → 0.61.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 +42 -0
- package/README.md +1 -1
- package/lib/client.js +1578 -232
- package/lib/client.js.map +1 -1
- package/lib/codemode.js +795 -178
- package/lib/entry-plan-mode-CLRKkgYG.js +1787 -0
- package/lib/{entry-progress-updates-CxQewio9.js → entry-progress-updates-DZ0ZRus4.js} +14 -1
- package/lib/index.js +1079 -754
- package/lib/llm-compat-u9mor0uu.js +110 -0
- package/lib/plan-mode.js +2 -779
- package/lib/progress-updates.js +1 -1
- package/lib/types/client/codemode/CodeRunToolView.d.ts +68 -0
- package/lib/types/client/codemode/CodeRunToolView.d.ts.map +1 -0
- package/lib/types/client/codemode/highlight.d.ts +25 -0
- package/lib/types/client/codemode/highlight.d.ts.map +1 -0
- package/lib/types/client/codemode/styles.d.ts +11 -0
- package/lib/types/client/codemode/styles.d.ts.map +1 -0
- package/lib/types/client/codemode/tool-name.d.ts +10 -0
- package/lib/types/client/codemode/tool-name.d.ts.map +1 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/locales-ru/hub.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +23 -1
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/compat.d.ts +1 -1
- package/lib/types/entry-codemode.d.ts.map +1 -1
- package/lib/types/entry-plan-mode.d.ts +136 -0
- package/lib/types/entry-plan-mode.d.ts.map +1 -1
- package/lib/types/host/agent-preset.d.ts.map +1 -1
- package/lib/types/host/claude/adapter.d.ts +16 -0
- package/lib/types/host/claude/adapter.d.ts.map +1 -1
- package/lib/types/host/claude/client.d.ts +7 -1
- package/lib/types/host/claude/client.d.ts.map +1 -1
- package/lib/types/host/claude/mapper.d.ts +9 -0
- package/lib/types/host/claude/mapper.d.ts.map +1 -1
- package/lib/types/host/claude/types.d.ts +10 -0
- package/lib/types/host/claude/types.d.ts.map +1 -1
- package/lib/types/host/cline-pass/mapper.d.ts.map +1 -1
- package/lib/types/host/codemode/discovery.d.ts.map +1 -1
- package/lib/types/host/codemode/executor.d.ts.map +1 -1
- package/lib/types/host/codemode/rules.d.ts +16 -6
- package/lib/types/host/codemode/rules.d.ts.map +1 -1
- package/lib/types/host/codemode/transport.d.ts +120 -41
- package/lib/types/host/codemode/transport.d.ts.map +1 -1
- package/lib/types/host/command-code/mapper.d.ts.map +1 -1
- package/lib/types/host/command-code/model-catalog.d.ts +14 -14
- package/lib/types/host/command-code/model-catalog.d.ts.map +1 -1
- package/lib/types/host/command-code/routes.d.ts.map +1 -1
- package/lib/types/host/common/orphan-tool-calls.d.ts +48 -0
- package/lib/types/host/common/orphan-tool-calls.d.ts.map +1 -0
- package/lib/types/host/dispatch-execution-guard.d.ts +32 -2
- package/lib/types/host/dispatch-execution-guard.d.ts.map +1 -1
- package/lib/types/host/glm-coding-plan/mapper-anthropic.d.ts.map +1 -1
- package/lib/types/host/glm-coding-plan/mapper-openai.d.ts.map +1 -1
- package/lib/types/host/kimi-code/mapper.d.ts.map +1 -1
- package/lib/types/host/minimax-code/mapper.d.ts.map +1 -1
- package/lib/types/host/model-catalog.d.ts +21 -0
- package/lib/types/host/model-catalog.d.ts.map +1 -1
- package/lib/types/host/opendesign/mapper.d.ts.map +1 -1
- package/lib/types/host/plan-mode-cache-guard.d.ts.map +1 -1
- package/lib/types/host/preset-sync.d.ts +19 -4
- package/lib/types/host/preset-sync.d.ts.map +1 -1
- package/lib/types/host/progress-updates/nudge.d.ts +13 -1
- package/lib/types/host/progress-updates/nudge.d.ts.map +1 -1
- package/lib/types/host/qoder/mapper.d.ts.map +1 -1
- package/lib/types/host/responses-client.d.ts.map +1 -1
- package/lib/types/host/responses-mapper.d.ts +12 -0
- package/lib/types/host/responses-mapper.d.ts.map +1 -1
- package/lib/types/host/settled-job-guard.d.ts +77 -0
- package/lib/types/host/settled-job-guard.d.ts.map +1 -0
- package/lib/types/host/step-code/mapper.d.ts.map +1 -1
- package/lib/types/host/workbuddy/mapper.d.ts.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/presets/dispatch/README.md +8 -13
- package/presets/dispatch/agent.cordis.yml +11 -16
package/lib/index.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { a as resolveProgressUpdatesSettings, n as attachProgressSettings } from "./entry-progress-updates-
|
|
1
|
+
import { a as resolveProgressUpdatesSettings, n as attachProgressSettings } from "./entry-progress-updates-DZ0ZRus4.js";
|
|
2
2
|
import { attachPlanModePipelineSettings, resolvePlanModePipelineEnabled } from "./plan-mode-pipeline.js";
|
|
3
|
+
import { n as PLUGIN_MESSAGE_SOURCE_KIND, r as normalizeGenerateOptions, t as LlmError$1 } from "./llm-compat-u9mor0uu.js";
|
|
3
4
|
import { DEFAULT_SKIP_PROVIDERS, PRUNER_SERVICE_NAME, resolveSkipProviders, shouldSkipPruningForSession } from "./tool-result-pruner.js";
|
|
4
|
-
import { PLAN_PROJECTION_KEY, createPlanNotice } from "./plan-mode.js";
|
|
5
|
+
import { b as installDispatchExecutionGuard, h as installPlanModeExitReminder, l as PLAN_PROJECTION_KEY, p as createPlanNotice, v as registeredPlanControllerActive, x as resolveDispatchExecutionGuardEnabled } from "./entry-plan-mode-CLRKkgYG.js";
|
|
5
6
|
import { createRequire } from "node:module";
|
|
6
7
|
import * as LlmModule from "@deepseek-ai/dsh-llm";
|
|
7
|
-
import { EMPTY_RESPONSE_CODE, HarnessError, LlmAdapter, LlmError,
|
|
8
|
+
import { EMPTY_RESPONSE_CODE, HarnessError, LlmAdapter, LlmError, ProviderRequestId, ReasoningEffortId, ToolCallId, attributionHeaders, createUserMessage, errorChain, resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
|
|
8
9
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
9
10
|
import { z } from "zod";
|
|
10
11
|
import z$1 from "@deepseek-ai/schemastery";
|
|
11
12
|
import fs, { chmod, lstat, mkdir, open, readFile, realpath, rename, stat, unlink, writeFile } from "node:fs/promises";
|
|
12
|
-
import path, { basename, dirname, extname, join, relative, resolve } from "node:path";
|
|
13
|
+
import path, { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
13
14
|
import os, { homedir, platform, userInfo } from "node:os";
|
|
14
15
|
import { constants, createCipheriv, createDecipheriv, createHash, createHmac, publicEncrypt, randomBytes, randomUUID } from "node:crypto";
|
|
15
16
|
import { isDeepStrictEqual } from "node:util";
|
|
@@ -807,7 +808,7 @@ const ROUTE_PREFIX$5 = "/api/dsh-chatgpt-subscription";
|
|
|
807
808
|
* `test/responses-client.test.ts` asserts the two agree, so a release that
|
|
808
809
|
* forgets this constant fails the suite instead of shipping quietly.
|
|
809
810
|
*/
|
|
810
|
-
const PLUGIN_VERSION = "0.
|
|
811
|
+
const PLUGIN_VERSION = "0.61.0";
|
|
811
812
|
const CODEX_CHATGPT_PROVIDER_ID = "codex-chatgpt";
|
|
812
813
|
const CODEX_API_BASE = "https://chatgpt.com/backend-api/codex";
|
|
813
814
|
const CODEX_RESPONSES_URL = `${CODEX_API_BASE}/responses`;
|
|
@@ -1192,6 +1193,7 @@ function resolveCodexModel(model, preferences, live) {
|
|
|
1192
1193
|
inputModalities: [...liveEntry?.inputModalities ?? entry.inputModalities],
|
|
1193
1194
|
context: { contextWindow: configuredContextWindow ?? liveEntry?.contextWindow ?? entry.contextWindow },
|
|
1194
1195
|
...outputReservation(configuredContextWindow ?? liveEntry?.contextWindow ?? entry.contextWindow, codexModelMaxTokens(model)),
|
|
1196
|
+
...codexToolUpdateMode() === void 0 ? {} : { toolUpdate: codexToolUpdateMode() },
|
|
1195
1197
|
reasoning: {
|
|
1196
1198
|
efforts: orderReasoningEfforts(efforts, GPT_56_REASONING_EFFORTS).map((effort) => ({
|
|
1197
1199
|
id: ReasoningEffortId(effort),
|
|
@@ -1202,6 +1204,46 @@ function resolveCodexModel(model, preferences, live) {
|
|
|
1202
1204
|
};
|
|
1203
1205
|
}
|
|
1204
1206
|
/**
|
|
1207
|
+
* Whether this line may state a tool change in the history instead of rewriting
|
|
1208
|
+
* the head.
|
|
1209
|
+
*
|
|
1210
|
+
* `in-history` rather than `addition-only`: this wire has an `additional_tools`
|
|
1211
|
+
* item to add a tool but nothing to withdraw one, so a removal has to keep its
|
|
1212
|
+
* declaration and travel as a note. Deleting the declaration would shorten the
|
|
1213
|
+
* head and throw the cached prefix away, which is the cost this mode exists to
|
|
1214
|
+
* avoid.
|
|
1215
|
+
*
|
|
1216
|
+
* `DSH_CODEX_TOOL_UPDATE=0` turns it off for one account without a code change,
|
|
1217
|
+
* the same escape hatch kimi-code carries for its own gate.
|
|
1218
|
+
*
|
|
1219
|
+
* @returns the mode to declare, or undefined when every request must restate the
|
|
1220
|
+
* complete tool list.
|
|
1221
|
+
*/
|
|
1222
|
+
function codexToolUpdateMode() {
|
|
1223
|
+
if (toolUpdateRejected) return void 0;
|
|
1224
|
+
const raw = (process.env.DSH_CODEX_TOOL_UPDATE ?? "").trim().toLowerCase();
|
|
1225
|
+
if (raw !== "" && [
|
|
1226
|
+
"0",
|
|
1227
|
+
"false",
|
|
1228
|
+
"no",
|
|
1229
|
+
"off",
|
|
1230
|
+
"none"
|
|
1231
|
+
].includes(raw)) return void 0;
|
|
1232
|
+
return "in-history";
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* Set when a request that carried a tool change was refused with a 400.
|
|
1236
|
+
*
|
|
1237
|
+
* Process-wide and one-way: the failure mode of a stale probe is a lost cache
|
|
1238
|
+
* optimisation, and the failure mode of NOT latching is the same 400 on every
|
|
1239
|
+
* later turn. The asymmetry decides it.
|
|
1240
|
+
*/
|
|
1241
|
+
let toolUpdateRejected = false;
|
|
1242
|
+
/** Record a refusal, so every later request restates the complete tool list. */
|
|
1243
|
+
function disableCodexToolUpdate() {
|
|
1244
|
+
toolUpdateRejected = true;
|
|
1245
|
+
}
|
|
1246
|
+
/**
|
|
1205
1247
|
* Resolve the wire capabilities of one model.
|
|
1206
1248
|
*
|
|
1207
1249
|
* The live listing outranks the shipped table, because the backend is the
|
|
@@ -1752,7 +1794,7 @@ function parseListing(payload) {
|
|
|
1752
1794
|
function parseListingEntry$1(value) {
|
|
1753
1795
|
const record = asRecord$20(value);
|
|
1754
1796
|
if (record === void 0) return [];
|
|
1755
|
-
const id = asString$
|
|
1797
|
+
const id = asString$31(record.slug) ?? asString$31(record.id);
|
|
1756
1798
|
if (id === void 0) return [];
|
|
1757
1799
|
const contextWindow = asNumber$8(record.context_window) ?? asNumber$8(record.contextWindow);
|
|
1758
1800
|
const modalities = parseModalities(record.input_modalities);
|
|
@@ -1761,11 +1803,11 @@ function parseListingEntry$1(value) {
|
|
|
1761
1803
|
const fallback = CODEX_MODEL_CATALOG.find((entry) => entry.id === id);
|
|
1762
1804
|
return [{
|
|
1763
1805
|
id,
|
|
1764
|
-
name: asString$
|
|
1806
|
+
name: asString$31(record.display_name) ?? asString$31(record.displayName) ?? fallback?.name ?? id,
|
|
1765
1807
|
contextWindow: contextWindow !== void 0 && contextWindow > 0 ? contextWindow : null,
|
|
1766
1808
|
inputModalities: modalities ?? (fallback ? [...fallback.inputModalities] : ["text"]),
|
|
1767
1809
|
...efforts !== null ? { reasoningEfforts: efforts } : {},
|
|
1768
|
-
defaultReasoningEffort: asString$
|
|
1810
|
+
defaultReasoningEffort: asString$31(record.default_reasoning_level) ?? fallback?.defaultReasoningEffort ?? null,
|
|
1769
1811
|
...useResponsesLite !== void 0 ? { useResponsesLite } : {}
|
|
1770
1812
|
}];
|
|
1771
1813
|
}
|
|
@@ -1773,7 +1815,7 @@ function parseModalities(value) {
|
|
|
1773
1815
|
if (!Array.isArray(value)) return null;
|
|
1774
1816
|
const out = [];
|
|
1775
1817
|
for (const item of value) {
|
|
1776
|
-
const name = asString$
|
|
1818
|
+
const name = asString$31(item);
|
|
1777
1819
|
if (name === "text" || name === "image") out.push(name);
|
|
1778
1820
|
}
|
|
1779
1821
|
return out.length > 0 ? out : null;
|
|
@@ -1788,7 +1830,7 @@ function parseEfforts(value) {
|
|
|
1788
1830
|
if (!Array.isArray(value)) return null;
|
|
1789
1831
|
const out = [];
|
|
1790
1832
|
for (const item of value) {
|
|
1791
|
-
const effort = asString$
|
|
1833
|
+
const effort = asString$31(item) ?? asString$31(asRecord$20(item)?.effort);
|
|
1792
1834
|
if (effort !== void 0 && !out.includes(effort)) out.push(effort);
|
|
1793
1835
|
}
|
|
1794
1836
|
return out.length > 0 ? out : null;
|
|
@@ -1813,7 +1855,7 @@ function accountKeyFor$1(credentials) {
|
|
|
1813
1855
|
function asRecord$20(value) {
|
|
1814
1856
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
1815
1857
|
}
|
|
1816
|
-
function asString$
|
|
1858
|
+
function asString$31(value) {
|
|
1817
1859
|
return typeof value === "string" && value !== "" ? value : void 0;
|
|
1818
1860
|
}
|
|
1819
1861
|
function asNumber$8(value) {
|
|
@@ -4434,7 +4476,7 @@ var OAuthService = class {
|
|
|
4434
4476
|
throw new OAuthServiceError("oauth-token-exchange-failed", `The ChatGPT device code could not be issued (${response.status}${detail === null ? "" : `, ${detail}`}).`, response.status);
|
|
4435
4477
|
}
|
|
4436
4478
|
const payload = await response.json().catch(() => null);
|
|
4437
|
-
const record = isRecord$
|
|
4479
|
+
const record = isRecord$67(payload) ? payload : {};
|
|
4438
4480
|
const authId = nonEmptyString$11(record.device_auth_id);
|
|
4439
4481
|
const userCode = nonEmptyString$11(record.user_code) ?? nonEmptyString$11(record.usercode);
|
|
4440
4482
|
if (authId === void 0 || userCode === void 0) throw new OAuthServiceError("oauth-token-exchange-failed", "ChatGPT returned no device code.");
|
|
@@ -4501,7 +4543,7 @@ var OAuthService = class {
|
|
|
4501
4543
|
const detail = deviceErrorIdentifier(payload);
|
|
4502
4544
|
throw new OAuthServiceError("oauth-token-exchange-failed", `The ChatGPT device confirmation was refused (${response.status}${detail === void 0 ? "" : `, ${detail}`}).`, response.status);
|
|
4503
4545
|
}
|
|
4504
|
-
const record = isRecord$
|
|
4546
|
+
const record = isRecord$67(payload) ? payload : {};
|
|
4505
4547
|
const authorizationCode = nonEmptyString$11(record.authorization_code);
|
|
4506
4548
|
const codeVerifier = nonEmptyString$11(record.code_verifier);
|
|
4507
4549
|
if (authorizationCode === void 0 || codeVerifier === void 0) throw new OAuthServiceError("oauth-token-exchange-failed", "ChatGPT confirmed the device code but returned no authorization code.");
|
|
@@ -4834,11 +4876,11 @@ const DEVICE_PENDING_STATUSES = /* @__PURE__ */ new Set([
|
|
|
4834
4876
|
function isPendingDeviceAnswer(response, payload) {
|
|
4835
4877
|
if (response.status === 403 || response.status === 404) return true;
|
|
4836
4878
|
if (!response.ok && response.status !== 400) return false;
|
|
4837
|
-
if (!isRecord$
|
|
4879
|
+
if (!isRecord$67(payload)) return false;
|
|
4838
4880
|
const status = payload.status;
|
|
4839
4881
|
if (typeof status === "string" && DEVICE_PENDING_STATUSES.has(status.toLowerCase())) return true;
|
|
4840
4882
|
const error = payload.error;
|
|
4841
|
-
if (isRecord$
|
|
4883
|
+
if (isRecord$67(error)) {
|
|
4842
4884
|
const code = error.code;
|
|
4843
4885
|
if (typeof code === "string" && DEVICE_PENDING_STATUSES.has(code.toLowerCase())) return true;
|
|
4844
4886
|
}
|
|
@@ -4852,18 +4894,18 @@ function isPendingDeviceAnswer(response, payload) {
|
|
|
4852
4894
|
* wrong.
|
|
4853
4895
|
*/
|
|
4854
4896
|
function deviceErrorIdentifier(payload) {
|
|
4855
|
-
if (!isRecord$
|
|
4897
|
+
if (!isRecord$67(payload)) return void 0;
|
|
4856
4898
|
const candidates = [payload.code];
|
|
4857
4899
|
const error = payload.error;
|
|
4858
4900
|
if (typeof error === "string") candidates.push(error);
|
|
4859
|
-
else if (isRecord$
|
|
4901
|
+
else if (isRecord$67(error)) candidates.push(error.code, error.type);
|
|
4860
4902
|
candidates.push(payload.status);
|
|
4861
4903
|
for (const candidate of candidates) if (typeof candidate === "string" && /^[a-z0-9_.-]{1,64}$/i.test(candidate)) return candidate;
|
|
4862
4904
|
}
|
|
4863
4905
|
function nonEmptyString$11(value) {
|
|
4864
4906
|
return typeof value === "string" && value !== "" ? value : void 0;
|
|
4865
4907
|
}
|
|
4866
|
-
function isRecord$
|
|
4908
|
+
function isRecord$67(value) {
|
|
4867
4909
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4868
4910
|
}
|
|
4869
4911
|
async function oauthErrorIdentifier(response) {
|
|
@@ -5044,7 +5086,7 @@ const CODEX_CLI_CREDENTIAL_SOURCE = "codex";
|
|
|
5044
5086
|
* here, and the import has to be repeated afterwards.
|
|
5045
5087
|
*/
|
|
5046
5088
|
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.";
|
|
5047
|
-
function isRecord$
|
|
5089
|
+
function isRecord$66(value) {
|
|
5048
5090
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5049
5091
|
}
|
|
5050
5092
|
/** A trimmed, non-empty string, or nothing. */
|
|
@@ -5146,7 +5188,7 @@ function decodeJwtClaims$1(token) {
|
|
|
5146
5188
|
if (parts.length !== 3) return void 0;
|
|
5147
5189
|
try {
|
|
5148
5190
|
const value = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
|
|
5149
|
-
return isRecord$
|
|
5191
|
+
return isRecord$66(value) ? value : void 0;
|
|
5150
5192
|
} catch {
|
|
5151
5193
|
return;
|
|
5152
5194
|
}
|
|
@@ -5191,10 +5233,10 @@ function expiryFromAccessToken(accessToken) {
|
|
|
5191
5233
|
* the file carries cannot reach the result.
|
|
5192
5234
|
*/
|
|
5193
5235
|
function parseAdoptedCodexCredential(value, sourcePath) {
|
|
5194
|
-
if (!isRecord$
|
|
5236
|
+
if (!isRecord$66(value)) return void 0;
|
|
5195
5237
|
if (value.auth_mode !== "chatgpt") return void 0;
|
|
5196
5238
|
const tokens = value[CODEX_CLI_TOKENS_KEY];
|
|
5197
|
-
if (!isRecord$
|
|
5239
|
+
if (!isRecord$66(tokens)) return void 0;
|
|
5198
5240
|
const accessToken = nonEmptyString$10(tokens.access_token);
|
|
5199
5241
|
if (accessToken === void 0) return void 0;
|
|
5200
5242
|
const refreshToken = nonEmptyString$10(tokens.refresh_token);
|
|
@@ -5213,7 +5255,7 @@ function parseAdoptedCodexCredential(value, sourcePath) {
|
|
|
5213
5255
|
const email = claims === void 0 ? void 0 : nonEmptyString$10(claims.email);
|
|
5214
5256
|
if (email !== void 0) credentials.email = email;
|
|
5215
5257
|
const authClaims = claims === void 0 ? void 0 : claims[CODEX_AUTH_CLAIMS_KEY];
|
|
5216
|
-
const planType = isRecord$
|
|
5258
|
+
const planType = isRecord$66(authClaims) ? nonEmptyString$10(authClaims.chatgpt_plan_type) : void 0;
|
|
5217
5259
|
if (planType !== void 0) credentials.planType = planType;
|
|
5218
5260
|
}
|
|
5219
5261
|
const accountId = nonEmptyString$10(tokens.account_id);
|
|
@@ -5999,114 +6041,6 @@ function webServerOrigin(server) {
|
|
|
5999
6041
|
return `http://${server.host === "0.0.0.0" ? "127.0.0.1" : server.host}:${server.port}`;
|
|
6000
6042
|
}
|
|
6001
6043
|
//#endregion
|
|
6002
|
-
//#region src/host/common/llm-compat.ts
|
|
6003
|
-
/** This package's kind in the harness message-source map. */
|
|
6004
|
-
const PLUGIN_MESSAGE_SOURCE_KIND = "dsh-chatgpt-subscription";
|
|
6005
|
-
function isRecord$66(value) {
|
|
6006
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6007
|
-
}
|
|
6008
|
-
/** Read a message body's blocks, keeping every entry that carries a block tag. */
|
|
6009
|
-
function readBlocks(raw) {
|
|
6010
|
-
if (!Array.isArray(raw)) return [];
|
|
6011
|
-
return raw.filter((block) => isRecord$66(block) && typeof block.type === "string");
|
|
6012
|
-
}
|
|
6013
|
-
/**
|
|
6014
|
-
* The first value that is a non-empty string.
|
|
6015
|
-
*
|
|
6016
|
-
* Used for fields the two generations spell in different places: a value that
|
|
6017
|
-
* is present but empty must not shadow a real one further down the chain, which
|
|
6018
|
-
* is what `??` alone does.
|
|
6019
|
-
*/
|
|
6020
|
-
function firstNonEmptyString(...values) {
|
|
6021
|
-
for (const value of values) if (typeof value === "string" && value !== "") return value;
|
|
6022
|
-
return "";
|
|
6023
|
-
}
|
|
6024
|
-
/**
|
|
6025
|
-
* The result block a `role: 'tool'` message already carries inside its body.
|
|
6026
|
-
*
|
|
6027
|
-
* Some harness generations deliver the call id inside the result block rather
|
|
6028
|
-
* than on the message, and one shape carries both: `role: 'tool'` with a
|
|
6029
|
-
* `tool-result` block holding the id. Reading only the message-level fields
|
|
6030
|
-
* leaves {@link toolCallIdOf} nothing to find.
|
|
6031
|
-
*/
|
|
6032
|
-
function embeddedToolResult(content) {
|
|
6033
|
-
if (content.length !== 1) return void 0;
|
|
6034
|
-
const [block] = content;
|
|
6035
|
-
return block?.type === "tool-result" ? block : void 0;
|
|
6036
|
-
}
|
|
6037
|
-
/**
|
|
6038
|
-
* The call id one `role: 'tool'` message associates with its `tool-call`.
|
|
6039
|
-
*
|
|
6040
|
-
* The id is the only thing tying a result to the call it answers: a mapper that
|
|
6041
|
-
* sends it empty makes every result an orphan and tells the repair pass that no
|
|
6042
|
-
* call was answered, which some gateways reject outright (WorkBuddy answers
|
|
6043
|
-
* `11148`, "tool calls and tool results do not match"). It therefore has to be
|
|
6044
|
-
* read from every place the harness generations put it — the message, the
|
|
6045
|
-
* message's source, and the result block inside the body — and an empty string
|
|
6046
|
-
* must not shadow a later, real one.
|
|
6047
|
-
*/
|
|
6048
|
-
function toolCallIdOf(raw, source, embedded) {
|
|
6049
|
-
return firstNonEmptyString(raw.toolCallId, raw.callId, source?.callId, embedded?.toolCallId);
|
|
6050
|
-
}
|
|
6051
|
-
/**
|
|
6052
|
-
* Normalize one harness message list into {@link Message}.
|
|
6053
|
-
*
|
|
6054
|
-
* A 0.1.7 `role: 'tool'` message is re-wrapped as the user-role message holding
|
|
6055
|
-
* one {@link ToolResultBlock} that the mappers expect, keeping the tool
|
|
6056
|
-
* provenance (`kind: 'tool'`) they use to tell a real tool result from a user
|
|
6057
|
-
* turn. A message that already carries that block keeps its own body instead of
|
|
6058
|
-
* nesting a second `tool-result` around it. Everything a newer harness adds
|
|
6059
|
-
* beside that keeps its own shape.
|
|
6060
|
-
* @param messages - Messages straight off the request options, in either generation's shape.
|
|
6061
|
-
* @returns The same conversation in the pre-0.1.7 vocabulary.
|
|
6062
|
-
*/
|
|
6063
|
-
function normalizeMessages(messages) {
|
|
6064
|
-
const normalized = [];
|
|
6065
|
-
for (const raw of messages ?? []) {
|
|
6066
|
-
if (!isRecord$66(raw)) continue;
|
|
6067
|
-
const content = readBlocks(raw.content);
|
|
6068
|
-
if (raw.role === "tool") {
|
|
6069
|
-
const source = isRecord$66(raw.source) ? raw.source : void 0;
|
|
6070
|
-
const embedded = embeddedToolResult(content);
|
|
6071
|
-
const callId = toolCallIdOf(raw, source, embedded);
|
|
6072
|
-
const isError = raw.isError === true || embedded?.isError === true;
|
|
6073
|
-
normalized.push({
|
|
6074
|
-
id: raw.id,
|
|
6075
|
-
role: "user",
|
|
6076
|
-
content: [{
|
|
6077
|
-
type: "tool-result",
|
|
6078
|
-
toolCallId: callId,
|
|
6079
|
-
content: embedded === void 0 ? content : embedded.content,
|
|
6080
|
-
...isError ? { isError: true } : {}
|
|
6081
|
-
}],
|
|
6082
|
-
source: {
|
|
6083
|
-
kind: "tool",
|
|
6084
|
-
callId
|
|
6085
|
-
}
|
|
6086
|
-
});
|
|
6087
|
-
continue;
|
|
6088
|
-
}
|
|
6089
|
-
normalized.push({
|
|
6090
|
-
id: raw.id,
|
|
6091
|
-
role: typeof raw.role === "string" ? raw.role : "user",
|
|
6092
|
-
content,
|
|
6093
|
-
...isRecord$66(raw.source) ? { source: raw.source } : {}
|
|
6094
|
-
});
|
|
6095
|
-
}
|
|
6096
|
-
return normalized;
|
|
6097
|
-
}
|
|
6098
|
-
/**
|
|
6099
|
-
* Normalize request options for the mappers.
|
|
6100
|
-
* @param options - Request options the harness handed the adapter.
|
|
6101
|
-
* @returns The same options with {@link Message} history.
|
|
6102
|
-
*/
|
|
6103
|
-
function normalizeGenerateOptions(options) {
|
|
6104
|
-
return {
|
|
6105
|
-
...options,
|
|
6106
|
-
messages: normalizeMessages(options.messages)
|
|
6107
|
-
};
|
|
6108
|
-
}
|
|
6109
|
-
//#endregion
|
|
6110
6044
|
//#region src/host/codex-images.ts
|
|
6111
6045
|
/**
|
|
6112
6046
|
* Output canvases the Codex image endpoint accepts in `size`.
|
|
@@ -8285,7 +8219,7 @@ function sanitizeText$9(text) {
|
|
|
8285
8219
|
function isRecord$64(value) {
|
|
8286
8220
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8287
8221
|
}
|
|
8288
|
-
function asString$
|
|
8222
|
+
function asString$30(value) {
|
|
8289
8223
|
return typeof value === "string" ? value : void 0;
|
|
8290
8224
|
}
|
|
8291
8225
|
function safeJsonParse$9(text) {
|
|
@@ -8315,7 +8249,7 @@ function attachmentOf$5(block) {
|
|
|
8315
8249
|
}
|
|
8316
8250
|
function attachmentLabel$6(block) {
|
|
8317
8251
|
const attachment = isRecord$64(block.attachment) ? block.attachment : void 0;
|
|
8318
|
-
return asString$
|
|
8252
|
+
return asString$30(attachment?.name) || asString$30(attachment?.attachmentId);
|
|
8319
8253
|
}
|
|
8320
8254
|
function collectImageRefs$3(content, refs) {
|
|
8321
8255
|
if (!Array.isArray(content)) return;
|
|
@@ -8452,10 +8386,10 @@ function unavailableImageText$6(block) {
|
|
|
8452
8386
|
return `[image unavailable: ${label ? `${label} could not be read` : "the image could not be read"}; ask the user to attach it again if the image is needed]`;
|
|
8453
8387
|
}
|
|
8454
8388
|
function imageBlockToPart(block, images) {
|
|
8455
|
-
let data = asString$
|
|
8389
|
+
let data = asString$30(block.data) || asString$30(block.base64);
|
|
8456
8390
|
const source = isRecord$64(block.source) ? block.source : void 0;
|
|
8457
|
-
if (!data && source) data = asString$
|
|
8458
|
-
let mimeType = asString$
|
|
8391
|
+
if (!data && source) data = asString$30(source.data) || asString$30(source.base64);
|
|
8392
|
+
let mimeType = asString$30(block.mimeType) || asString$30(block.mediaType) || (source ? asString$30(source.mimeType) || asString$30(source.mediaType) : void 0) || "image/png";
|
|
8459
8393
|
if (data?.startsWith("data:")) {
|
|
8460
8394
|
const match = data.match(/^data:([^;,]+);base64,(.*)$/s);
|
|
8461
8395
|
if (match) {
|
|
@@ -8529,7 +8463,7 @@ function replayBlockFor$1(message, index) {
|
|
|
8529
8463
|
}
|
|
8530
8464
|
}
|
|
8531
8465
|
function thoughtSignature(part) {
|
|
8532
|
-
return asString$
|
|
8466
|
+
return asString$30(part?.thoughtSignature) || asString$30(part?.thought_signature) || asString$30(part?.thinkingSignature) || asString$30(part?.textSignature);
|
|
8533
8467
|
}
|
|
8534
8468
|
function replayPart(part) {
|
|
8535
8469
|
const copy = { ...part };
|
|
@@ -8628,7 +8562,7 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
|
|
|
8628
8562
|
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;
|
|
8629
8563
|
const replay = replayBlockFor$1(message, index);
|
|
8630
8564
|
const originalParts = Array.isArray(replay?.parts) ? replay.parts.filter(isRecord$64) : [];
|
|
8631
|
-
if ((block.type === "text" || block.type === "reasoning") && originalParts.length > 0 && originalParts.every((part) => !part.functionCall) && originalParts.map((part) => asString$
|
|
8565
|
+
if ((block.type === "text" || block.type === "reasoning") && originalParts.length > 0 && originalParts.every((part) => !part.functionCall) && originalParts.map((part) => asString$30(part.text) || "").join("") === sanitizeText$9(String(block.text || ""))) {
|
|
8632
8566
|
parts.push(...originalParts.map(replayPart));
|
|
8633
8567
|
continue;
|
|
8634
8568
|
}
|
|
@@ -8649,7 +8583,7 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
|
|
|
8649
8583
|
const toolId = String(block.id || "");
|
|
8650
8584
|
const toolName = String(block.name || "");
|
|
8651
8585
|
const originalCall = originalParts.find((part) => isRecord$64(part.functionCall));
|
|
8652
|
-
const wireId = asString$
|
|
8586
|
+
const wireId = asString$30((isRecord$64(originalCall?.functionCall) ? originalCall.functionCall : void 0)?.id) || (toolCallIdNeeded(model.id, runtimeModel) ? sanitizeToolCallId(toolId, toolName) : originalCall ? void 0 : toolId || void 0);
|
|
8653
8587
|
toolCalls.set(toolId, {
|
|
8654
8588
|
name: toolName,
|
|
8655
8589
|
id: wireId
|
|
@@ -8894,7 +8828,7 @@ function processStreamLine$4(line, state) {
|
|
|
8894
8828
|
if (!isRecord$64(chunk)) return [];
|
|
8895
8829
|
const responseData = isRecord$64(chunk.response) ? chunk.response : chunk;
|
|
8896
8830
|
const error = isRecord$64(chunk.error) ? chunk.error : isRecord$64(responseData.error) ? responseData.error : void 0;
|
|
8897
|
-
if (error !== void 0) throw new LlmError$1(`Antigravity stream error: ${asString$
|
|
8831
|
+
if (error !== void 0) throw new LlmError$1(`Antigravity stream error: ${asString$30(error.message) ?? "unknown error"}`, isContextOverflow(error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
8898
8832
|
const candidates = Array.isArray(responseData.candidates) ? responseData.candidates : [];
|
|
8899
8833
|
const candidate = isRecord$64(candidates[0]) ? candidates[0] : void 0;
|
|
8900
8834
|
const content = isRecord$64(candidate?.content) ? candidate.content : void 0;
|
|
@@ -8960,8 +8894,8 @@ function processStreamLine$4(line, state) {
|
|
|
8960
8894
|
if (isRecord$64(part.functionCall)) {
|
|
8961
8895
|
out.push(...closeCurrentBlock(state));
|
|
8962
8896
|
const fc = part.functionCall;
|
|
8963
|
-
const toolName = asString$
|
|
8964
|
-
const toolId = asString$
|
|
8897
|
+
const toolName = asString$30(fc.name) || "";
|
|
8898
|
+
const toolId = asString$30(fc.id) || sanitizeToolCallId("", toolName);
|
|
8965
8899
|
const argsText = JSON.stringify(isRecord$64(fc.args) ? fc.args : {});
|
|
8966
8900
|
const index = state.blocks.length;
|
|
8967
8901
|
const block = {
|
|
@@ -8999,10 +8933,10 @@ function processStreamLine$4(line, state) {
|
|
|
8999
8933
|
}
|
|
9000
8934
|
collectUsage(chunk.usageMetadata, state);
|
|
9001
8935
|
if (responseData !== chunk) collectUsage(responseData.usageMetadata, state);
|
|
9002
|
-
const finishMessage = asString$
|
|
8936
|
+
const finishMessage = asString$30(candidate?.finishMessage);
|
|
9003
8937
|
if (finishMessage) state.finishMessage = finishMessage;
|
|
9004
|
-
const blockReason = asString$
|
|
9005
|
-
const finishReason = asString$
|
|
8938
|
+
const blockReason = asString$30((isRecord$64(responseData.promptFeedback) ? responseData.promptFeedback : void 0)?.blockReason);
|
|
8939
|
+
const finishReason = asString$30(candidate?.finishReason) || asString$30(responseData.finishReason) || (blockReason ? `PROMPT_BLOCKED:${blockReason}` : void 0);
|
|
9006
8940
|
if (finishReason) {
|
|
9007
8941
|
state.finishReason = finishReason;
|
|
9008
8942
|
out.push(...closeCurrentBlock(state));
|
|
@@ -9077,7 +9011,7 @@ function closeStream$7(state) {
|
|
|
9077
9011
|
function isRecord$63(value) {
|
|
9078
9012
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9079
9013
|
}
|
|
9080
|
-
function asString$
|
|
9014
|
+
function asString$29(value) {
|
|
9081
9015
|
return typeof value === "string" ? value : void 0;
|
|
9082
9016
|
}
|
|
9083
9017
|
/**
|
|
@@ -9138,7 +9072,7 @@ function attachmentOf$4(block) {
|
|
|
9138
9072
|
}
|
|
9139
9073
|
function attachmentLabel$5(block) {
|
|
9140
9074
|
const attachment = isRecord$63(block.attachment) ? block.attachment : void 0;
|
|
9141
|
-
return asString$
|
|
9075
|
+
return asString$29(attachment?.name) || asString$29(attachment?.attachmentId);
|
|
9142
9076
|
}
|
|
9143
9077
|
function collectImageRefs$2(content, refs) {
|
|
9144
9078
|
if (!Array.isArray(content)) return;
|
|
@@ -9172,9 +9106,9 @@ function base64Length$2(bytes) {
|
|
|
9172
9106
|
* has no resolved map behaves exactly as before.
|
|
9173
9107
|
*/
|
|
9174
9108
|
function inlinePayloadOf$1(block) {
|
|
9175
|
-
let data = asString$
|
|
9109
|
+
let data = asString$29(block.data) || asString$29(block.base64);
|
|
9176
9110
|
const source = isRecord$63(block.source) ? block.source : void 0;
|
|
9177
|
-
if (!data && source) data = asString$
|
|
9111
|
+
if (!data && source) data = asString$29(source.data) || asString$29(source.base64);
|
|
9178
9112
|
if (data?.startsWith("data:")) {
|
|
9179
9113
|
const matched = data.match(/^data:([^;,]+);base64,(.*)$/s);
|
|
9180
9114
|
if (matched) data = matched[2] ?? "";
|
|
@@ -9637,10 +9571,10 @@ function unavailableImageText$5(block) {
|
|
|
9637
9571
|
return `[image unavailable: ${label ? `${label} could not be read` : "the image could not be read"}; ask the user to attach it again if the image is needed]`;
|
|
9638
9572
|
}
|
|
9639
9573
|
function imageBlockToInline$3(block, images) {
|
|
9640
|
-
let data = asString$
|
|
9574
|
+
let data = asString$29(block.data) || asString$29(block.base64);
|
|
9641
9575
|
const source = isRecord$63(block.source) ? block.source : void 0;
|
|
9642
|
-
if (!data && source) data = asString$
|
|
9643
|
-
let mediaType = asString$
|
|
9576
|
+
if (!data && source) data = asString$29(source.data) || asString$29(source.base64);
|
|
9577
|
+
let mediaType = asString$29(block.mimeType) || asString$29(block.mediaType) || (source ? asString$29(source.mimeType) || asString$29(source.mediaType) : void 0) || "image/png";
|
|
9644
9578
|
if (data?.startsWith("data:")) {
|
|
9645
9579
|
const matched = data.match(/^data:([^;,]+);base64,(.*)$/s);
|
|
9646
9580
|
if (matched) {
|
|
@@ -13217,6 +13151,21 @@ async function buildResponsesPayload(options, attachments, localRawImages = {},
|
|
|
13217
13151
|
});
|
|
13218
13152
|
continue;
|
|
13219
13153
|
}
|
|
13154
|
+
if (message.role === "developer") {
|
|
13155
|
+
input.push(...toolChangeItems(message, options.tools, wire.idNamespace));
|
|
13156
|
+
const rest = message.content.filter((block) => block.type !== "tool-addition" && block.type !== "tool-removal");
|
|
13157
|
+
if (rest.length > 0) {
|
|
13158
|
+
const content = await mapContent({
|
|
13159
|
+
...message,
|
|
13160
|
+
content: rest
|
|
13161
|
+
}, attachments, options.signal, localRawImages, localImageStats, resolveLocalRawImages);
|
|
13162
|
+
if (content.length > 0) input.push({
|
|
13163
|
+
role: "developer",
|
|
13164
|
+
content
|
|
13165
|
+
});
|
|
13166
|
+
}
|
|
13167
|
+
continue;
|
|
13168
|
+
}
|
|
13220
13169
|
const content = await mapContent(message, attachments, options.signal, localRawImages, localImageStats, resolveLocalRawImages);
|
|
13221
13170
|
if (content.length > 0) input.push({
|
|
13222
13171
|
role: message.role,
|
|
@@ -13227,8 +13176,9 @@ async function buildResponsesPayload(options, attachments, localRawImages = {},
|
|
|
13227
13176
|
offloadOldestInputImages(input);
|
|
13228
13177
|
const instructionText = [...instructionParts, localRawImageInstruction(localImageStats)].filter((value) => Boolean(value)).join("\n\n");
|
|
13229
13178
|
const prefix = [];
|
|
13230
|
-
const
|
|
13231
|
-
|
|
13179
|
+
const allTools = options.tools ?? [];
|
|
13180
|
+
const tools = allTools.filter((tool) => tool.deferLoading !== true);
|
|
13181
|
+
if (useResponsesLite && allTools.length > 0) prefix.push(additionalToolsItem(allTools, wire.idNamespace));
|
|
13232
13182
|
if (instructionText !== "") prefix.push(developerMessageItem(instructionText, wire.idNamespace, useResponsesLite));
|
|
13233
13183
|
input.unshift(...prefix);
|
|
13234
13184
|
const toolDeclarations = tools.length > 0 ? tools.map(toolDeclaration) : void 0;
|
|
@@ -13300,6 +13250,87 @@ function additionalToolsItem(tools, idNamespace) {
|
|
|
13300
13250
|
};
|
|
13301
13251
|
}
|
|
13302
13252
|
/**
|
|
13253
|
+
* The input items one mid-conversation tool change becomes.
|
|
13254
|
+
*
|
|
13255
|
+
* An addition travels as an `additional_tools` item at the point in the history
|
|
13256
|
+
* where it happened. The item carries the full definition, so the head never has
|
|
13257
|
+
* to grow it: everything before this position keeps its cached prefix and the
|
|
13258
|
+
* backend reads the new tool from here onward.
|
|
13259
|
+
*
|
|
13260
|
+
* A removal has no wire form of its own — there is no `tool_removal` item — so
|
|
13261
|
+
* the declaration stays exactly where it is and this note tells the model the
|
|
13262
|
+
* tool is gone. Dropping the declaration instead would shorten the head and
|
|
13263
|
+
* throw the prefix away, which is the cost `in-history` exists to avoid.
|
|
13264
|
+
*
|
|
13265
|
+
* Measured on the subscription backend by
|
|
13266
|
+
* `scripts/probe-codex-tool-updates.probe.ts`: the item is accepted, the model
|
|
13267
|
+
* calls a tool that only ever appeared in it, and a padded prefix stays cached
|
|
13268
|
+
* across the addition.
|
|
13269
|
+
*
|
|
13270
|
+
* @param message - the developer message carrying the change.
|
|
13271
|
+
* @param tools - the active declaration set the change resolves against.
|
|
13272
|
+
* @param idNamespace - the conversation identity, for stable item ids.
|
|
13273
|
+
* @returns the items to append at this position, in order.
|
|
13274
|
+
*/
|
|
13275
|
+
function toolChangeItems(message, tools, idNamespace) {
|
|
13276
|
+
const byName = new Map((tools ?? []).map((tool) => [tool.name, tool]));
|
|
13277
|
+
const added = [];
|
|
13278
|
+
const removed = [];
|
|
13279
|
+
for (const block of message.content) {
|
|
13280
|
+
const name = typeof block["toolName"] === "string" ? block["toolName"] : "";
|
|
13281
|
+
if (name === "") continue;
|
|
13282
|
+
if (block["type"] === "tool-addition") {
|
|
13283
|
+
const tool = byName.get(name);
|
|
13284
|
+
if (tool !== void 0) added.push(toolDeclaration(tool));
|
|
13285
|
+
} else if (block["type"] === "tool-removal") removed.push(name);
|
|
13286
|
+
}
|
|
13287
|
+
const items = [];
|
|
13288
|
+
if (added.length > 0) items.push({
|
|
13289
|
+
type: "additional_tools",
|
|
13290
|
+
id: stableItemId("at", idNamespace, JSON.stringify(added)),
|
|
13291
|
+
role: "developer",
|
|
13292
|
+
tools: added
|
|
13293
|
+
});
|
|
13294
|
+
if (removed.length > 0) {
|
|
13295
|
+
const text = toolRemovalNotice(removed);
|
|
13296
|
+
items.push({
|
|
13297
|
+
type: "message",
|
|
13298
|
+
id: stableItemId("msg", idNamespace, text),
|
|
13299
|
+
role: "developer",
|
|
13300
|
+
content: [{
|
|
13301
|
+
type: "input_text",
|
|
13302
|
+
text
|
|
13303
|
+
}]
|
|
13304
|
+
});
|
|
13305
|
+
}
|
|
13306
|
+
return items;
|
|
13307
|
+
}
|
|
13308
|
+
/**
|
|
13309
|
+
* The same request with every tool change taken back out.
|
|
13310
|
+
*
|
|
13311
|
+
* This is the shape a backend that refuses the update channel gets: the complete
|
|
13312
|
+
* current declaration list at the head, no change messages, no deferred markers.
|
|
13313
|
+
* It is exactly what the line sent before the capability existed, so the fallback
|
|
13314
|
+
* costs a cache miss and nothing else.
|
|
13315
|
+
*
|
|
13316
|
+
* @param options - the request that was refused.
|
|
13317
|
+
* @returns a request the line can always send.
|
|
13318
|
+
*/
|
|
13319
|
+
function withoutCodexToolChanges(options) {
|
|
13320
|
+
const messages = options.messages.filter((message) => !(message.role === "developer" && Array.isArray(message.content) && message.content.some((block) => block.type === "tool-addition" || block.type === "tool-removal")));
|
|
13321
|
+
const tools = options.tools?.map(({ deferLoading: _deferred, ...tool }) => tool);
|
|
13322
|
+
return {
|
|
13323
|
+
...options,
|
|
13324
|
+
messages,
|
|
13325
|
+
...tools === void 0 ? {} : { tools }
|
|
13326
|
+
};
|
|
13327
|
+
}
|
|
13328
|
+
/** How a withdrawn tool is stated to the model, imperatively. */
|
|
13329
|
+
function toolRemovalNotice(names) {
|
|
13330
|
+
const list = names.map((name) => `"${name}"`).join(", ");
|
|
13331
|
+
return names.length === 1 ? `[The tool ${list} is no longer available. Do not call it again: any call will fail.]` : `[The tools ${list} are no longer available. Do not call them again: any call will fail.]`;
|
|
13332
|
+
}
|
|
13333
|
+
/**
|
|
13303
13334
|
* The base instructions as a developer message.
|
|
13304
13335
|
*
|
|
13305
13336
|
* The official client marks the item with the `model.base_instructions` kind, so
|
|
@@ -13686,6 +13717,8 @@ var ResponsesClient = class {
|
|
|
13686
13717
|
const turnKey = turnKeyFor(sessionId);
|
|
13687
13718
|
let currentModel = options.model;
|
|
13688
13719
|
let attemptOptions = options;
|
|
13720
|
+
let strippedToolChanges = false;
|
|
13721
|
+
const statesToolChange = (candidate) => candidate.messages.some((message) => message.role === "developer" && Array.isArray(message.content) && message.content.some((block) => block["type"] === "tool-addition" || block["type"] === "tool-removal"));
|
|
13689
13722
|
let response;
|
|
13690
13723
|
let release;
|
|
13691
13724
|
while (true) {
|
|
@@ -13711,6 +13744,12 @@ var ResponsesClient = class {
|
|
|
13711
13744
|
continue;
|
|
13712
13745
|
}
|
|
13713
13746
|
}
|
|
13747
|
+
if (!strippedToolChanges && statesToolChange(attemptOptions) && error.status === 400) {
|
|
13748
|
+
disableCodexToolUpdate();
|
|
13749
|
+
attemptOptions = withoutCodexToolChanges(attemptOptions);
|
|
13750
|
+
strippedToolChanges = true;
|
|
13751
|
+
continue;
|
|
13752
|
+
}
|
|
13714
13753
|
throw error;
|
|
13715
13754
|
}
|
|
13716
13755
|
}
|
|
@@ -20079,6 +20118,21 @@ const COMMAND_CODE_MODELS = [
|
|
|
20079
20118
|
maxTokens: 256e3,
|
|
20080
20119
|
hidden: false
|
|
20081
20120
|
},
|
|
20121
|
+
{
|
|
20122
|
+
id: "stealth/crouton-alpha",
|
|
20123
|
+
name: "Crouton Alpha",
|
|
20124
|
+
inputModalities: ["text", "image"],
|
|
20125
|
+
reasoningEfforts: [
|
|
20126
|
+
"low",
|
|
20127
|
+
"medium",
|
|
20128
|
+
"high",
|
|
20129
|
+
"xhigh",
|
|
20130
|
+
"max"
|
|
20131
|
+
],
|
|
20132
|
+
contextWindow: 1048576,
|
|
20133
|
+
maxTokens: 943718,
|
|
20134
|
+
hidden: false
|
|
20135
|
+
},
|
|
20082
20136
|
{
|
|
20083
20137
|
id: "reflection/beam:free",
|
|
20084
20138
|
name: "Beam 1.0",
|
|
@@ -20096,7 +20150,7 @@ const COMMAND_CODE_MODELS = [
|
|
|
20096
20150
|
},
|
|
20097
20151
|
{
|
|
20098
20152
|
id: "poolside/laguna-s-2.1-free",
|
|
20099
|
-
name: "Laguna S 2.1",
|
|
20153
|
+
name: "Laguna S 2.1 (Free)",
|
|
20100
20154
|
inputModalities: ["text"],
|
|
20101
20155
|
reasoningEfforts: [],
|
|
20102
20156
|
contextWindow: 256e3,
|
|
@@ -20125,6 +20179,32 @@ const COMMAND_CODE_MODELS = [
|
|
|
20125
20179
|
maxTokens: 32768,
|
|
20126
20180
|
hidden: false
|
|
20127
20181
|
},
|
|
20182
|
+
{
|
|
20183
|
+
id: "inclusionai/ling-3.1-flash-1019",
|
|
20184
|
+
name: "Ling 3.1 Flash 1019",
|
|
20185
|
+
inputModalities: ["text"],
|
|
20186
|
+
reasoningEfforts: [
|
|
20187
|
+
"low",
|
|
20188
|
+
"medium",
|
|
20189
|
+
"high"
|
|
20190
|
+
],
|
|
20191
|
+
contextWindow: 1e6,
|
|
20192
|
+
maxTokens: 262144,
|
|
20193
|
+
hidden: false
|
|
20194
|
+
},
|
|
20195
|
+
{
|
|
20196
|
+
id: "inclusionai/ling-3.1-flash-1019:free",
|
|
20197
|
+
name: "Ling 3.1 Flash 1019",
|
|
20198
|
+
inputModalities: ["text"],
|
|
20199
|
+
reasoningEfforts: [
|
|
20200
|
+
"low",
|
|
20201
|
+
"medium",
|
|
20202
|
+
"high"
|
|
20203
|
+
],
|
|
20204
|
+
contextWindow: 1e6,
|
|
20205
|
+
maxTokens: 262144,
|
|
20206
|
+
hidden: true
|
|
20207
|
+
},
|
|
20128
20208
|
{
|
|
20129
20209
|
id: "meta/muse-spark-1.1",
|
|
20130
20210
|
name: "Muse Spark 1.1",
|
|
@@ -20286,42 +20366,37 @@ const COMMAND_CODE_MODELS = [
|
|
|
20286
20366
|
function commandCodeModelDef(modelId) {
|
|
20287
20367
|
return COMMAND_CODE_MODELS.find((model) => model.id === modelId);
|
|
20288
20368
|
}
|
|
20289
|
-
/**
|
|
20290
|
-
|
|
20291
|
-
|
|
20292
|
-
|
|
20293
|
-
|
|
20294
|
-
|
|
20295
|
-
|
|
20296
|
-
|
|
20297
|
-
|
|
20298
|
-
|
|
20299
|
-
|
|
20300
|
-
|
|
20301
|
-
|
|
20302
|
-
|
|
20303
|
-
|
|
20304
|
-
|
|
20305
|
-
|
|
20306
|
-
|
|
20307
|
-
|
|
20308
|
-
|
|
20309
|
-
|
|
20310
|
-
|
|
20311
|
-
|
|
20312
|
-
|
|
20313
|
-
|
|
20314
|
-
|
|
20315
|
-
|
|
20316
|
-
|
|
20317
|
-
|
|
20318
|
-
|
|
20319
|
-
|
|
20320
|
-
"xiaomi/mimo-v2.5",
|
|
20321
|
-
"stealth/space-bunny-alpha",
|
|
20322
|
-
"inclusionai/ling-3.0-flash-sante:free",
|
|
20323
|
-
"inclusionai/ling-3.1-flash:free"
|
|
20324
|
-
];
|
|
20369
|
+
/** Default-selection deltas recognized by `resolveEnabledModelIds` in `./routes.ts`. */
|
|
20370
|
+
const SHIPPED_DEFAULT_MIGRATIONS = [{
|
|
20371
|
+
version: "1.88.4",
|
|
20372
|
+
added: ["stealth/crouton-alpha", "inclusionai/ling-3.1-flash-1019"],
|
|
20373
|
+
retired: []
|
|
20374
|
+
}, {
|
|
20375
|
+
version: "1.88.2",
|
|
20376
|
+
added: [
|
|
20377
|
+
"claude-haiku-5-5",
|
|
20378
|
+
"gpt-6.1-terra",
|
|
20379
|
+
"moonshotai/Kimi-K3.1-Pro",
|
|
20380
|
+
"minimax/minimax-m3.1-flash",
|
|
20381
|
+
"ornith/ornith-1.5-122b",
|
|
20382
|
+
"Qwen/Qwen3.8-Max-Prime",
|
|
20383
|
+
"google/gemini-4-argon",
|
|
20384
|
+
"nvidia/nemotron-3.5-super-vl",
|
|
20385
|
+
"stealth/glyph-cluster:free",
|
|
20386
|
+
"reflection/beam:free",
|
|
20387
|
+
"inclusionai/ling-3.1-flash",
|
|
20388
|
+
"meta/muse-spark-open",
|
|
20389
|
+
"meta/muse-wonder-1.0",
|
|
20390
|
+
"mistral/mistral-large-4"
|
|
20391
|
+
],
|
|
20392
|
+
retired: [
|
|
20393
|
+
"xiaomi/mimo-v2.5-pro",
|
|
20394
|
+
"xiaomi/mimo-v2.5",
|
|
20395
|
+
"stealth/space-bunny-alpha",
|
|
20396
|
+
"inclusionai/ling-3.0-flash-sante:free",
|
|
20397
|
+
"inclusionai/ling-3.1-flash:free"
|
|
20398
|
+
]
|
|
20399
|
+
}];
|
|
20325
20400
|
//#endregion
|
|
20326
20401
|
//#region src/host/command-code/types.ts
|
|
20327
20402
|
const PROVIDER_ID$11 = "command-code";
|
|
@@ -20939,7 +21014,7 @@ function isRecord$61(value) {
|
|
|
20939
21014
|
function asRecord$16(value) {
|
|
20940
21015
|
return isRecord$61(value) ? value : void 0;
|
|
20941
21016
|
}
|
|
20942
|
-
function asString$
|
|
21017
|
+
function asString$28(value) {
|
|
20943
21018
|
if (typeof value === "string" && value.trim() !== "") return value;
|
|
20944
21019
|
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
20945
21020
|
}
|
|
@@ -20952,7 +21027,7 @@ function asNumber$6(value) {
|
|
|
20952
21027
|
}
|
|
20953
21028
|
function firstString$2(record, keys) {
|
|
20954
21029
|
for (const key of keys) {
|
|
20955
|
-
const value = asString$
|
|
21030
|
+
const value = asString$28(record[key]);
|
|
20956
21031
|
if (value !== void 0) return value;
|
|
20957
21032
|
}
|
|
20958
21033
|
}
|
|
@@ -21199,7 +21274,7 @@ function parseCreditBalances(payload, consumed = []) {
|
|
|
21199
21274
|
/** Resolve the plan id the subscription or credits payload reports, when either does. */
|
|
21200
21275
|
function parsePlanId(payloads) {
|
|
21201
21276
|
for (const payload of payloads) {
|
|
21202
|
-
const id = asString$
|
|
21277
|
+
const id = asString$28(deepValue(payload, [
|
|
21203
21278
|
"planId",
|
|
21204
21279
|
"plan_id",
|
|
21205
21280
|
"priceId",
|
|
@@ -21218,7 +21293,7 @@ function parsePlanId(payloads) {
|
|
|
21218
21293
|
*/
|
|
21219
21294
|
function parseSubscriptionStatus(payload) {
|
|
21220
21295
|
const root = asRecord$16(payload) ?? {};
|
|
21221
|
-
return asString$
|
|
21296
|
+
return asString$28(deepValue(asRecord$16(root.data) ?? root, ["status"])) ?? null;
|
|
21222
21297
|
}
|
|
21223
21298
|
/** End of the current billing period, in Unix milliseconds. */
|
|
21224
21299
|
function parseSubscriptionPeriodEnd(payload) {
|
|
@@ -21794,6 +21869,92 @@ function buildModelOptions$2(catalog, enabledModelIds, overrides) {
|
|
|
21794
21869
|
});
|
|
21795
21870
|
}
|
|
21796
21871
|
//#endregion
|
|
21872
|
+
//#region src/host/common/orphan-tool-calls.ts
|
|
21873
|
+
/**
|
|
21874
|
+
* 读一个未知字段为字符串。
|
|
21875
|
+
* @param value - 候选值。
|
|
21876
|
+
* @returns 字符串,或任何其它类型的 undefined。
|
|
21877
|
+
*/
|
|
21878
|
+
function asString$27(value) {
|
|
21879
|
+
return typeof value === "string" ? value : void 0;
|
|
21880
|
+
}
|
|
21881
|
+
/**
|
|
21882
|
+
* 清掉没有配对的工具调用。
|
|
21883
|
+
*
|
|
21884
|
+
* 配对规则只有一条:`tool_use` 必须被**后面第一条** user 轮里的同名 `tool_result` 应答;
|
|
21885
|
+
* 到了下一条 assistant 轮还没被应答,它就是孤儿。反向也一样——`tool_result` 找不到仍在
|
|
21886
|
+
* 等待的同名调用,它就是无主结果(线上报的是「tool call result does not follow tool call」)。
|
|
21887
|
+
*
|
|
21888
|
+
* @param messages - 已折叠过的消息列表。
|
|
21889
|
+
* @param refold - 调用方自己的相邻同角色折叠,清理后需要再折一次。
|
|
21890
|
+
* @returns 配对完整、且没有空消息的消息列表;清理会把整段历史清空时原样返回。
|
|
21891
|
+
*/
|
|
21892
|
+
function cleanOrphanedToolCalls(messages, refold) {
|
|
21893
|
+
const result = [];
|
|
21894
|
+
let pending = [];
|
|
21895
|
+
/**
|
|
21896
|
+
* 丢掉没有被结果应答的调用。
|
|
21897
|
+
* @param answered - 已经被结果应答的 id 集合。
|
|
21898
|
+
*/
|
|
21899
|
+
const dropUnanswered = (answered) => {
|
|
21900
|
+
const byMessage = /* @__PURE__ */ new Map();
|
|
21901
|
+
for (const call of pending) {
|
|
21902
|
+
if (answered.has(call.id)) continue;
|
|
21903
|
+
const indices = byMessage.get(call.messageIndex);
|
|
21904
|
+
if (indices === void 0) byMessage.set(call.messageIndex, [call.blockIndex]);
|
|
21905
|
+
else indices.push(call.blockIndex);
|
|
21906
|
+
}
|
|
21907
|
+
for (const [messageIndex, indices] of byMessage) {
|
|
21908
|
+
const message = result[messageIndex];
|
|
21909
|
+
if (message === void 0) continue;
|
|
21910
|
+
message.content = message.content.filter((_block, index) => !indices.includes(index));
|
|
21911
|
+
}
|
|
21912
|
+
pending = [];
|
|
21913
|
+
};
|
|
21914
|
+
for (const message of messages) {
|
|
21915
|
+
if (message.role === "assistant") {
|
|
21916
|
+
dropUnanswered(/* @__PURE__ */ new Set());
|
|
21917
|
+
const messageIndex = result.length;
|
|
21918
|
+
for (let blockIndex = 0; blockIndex < message.content.length; blockIndex += 1) {
|
|
21919
|
+
const block = message.content[blockIndex];
|
|
21920
|
+
if (block.type !== "tool_use") continue;
|
|
21921
|
+
const id = asString$27(block.id);
|
|
21922
|
+
if (id === void 0) continue;
|
|
21923
|
+
pending.push({
|
|
21924
|
+
messageIndex,
|
|
21925
|
+
blockIndex,
|
|
21926
|
+
id
|
|
21927
|
+
});
|
|
21928
|
+
}
|
|
21929
|
+
result.push({
|
|
21930
|
+
...message,
|
|
21931
|
+
content: [...message.content]
|
|
21932
|
+
});
|
|
21933
|
+
continue;
|
|
21934
|
+
}
|
|
21935
|
+
const answered = /* @__PURE__ */ new Set();
|
|
21936
|
+
const content = [];
|
|
21937
|
+
for (const block of message.content) {
|
|
21938
|
+
if (block.type === "tool_result") {
|
|
21939
|
+
const id = asString$27(block.tool_use_id);
|
|
21940
|
+
if (id === void 0 || !pending.some((call) => call.id === id)) continue;
|
|
21941
|
+
answered.add(id);
|
|
21942
|
+
content.push(block);
|
|
21943
|
+
continue;
|
|
21944
|
+
}
|
|
21945
|
+
content.push(block);
|
|
21946
|
+
}
|
|
21947
|
+
dropUnanswered(answered);
|
|
21948
|
+
result.push({
|
|
21949
|
+
...message,
|
|
21950
|
+
content
|
|
21951
|
+
});
|
|
21952
|
+
}
|
|
21953
|
+
dropUnanswered(/* @__PURE__ */ new Set());
|
|
21954
|
+
const nonEmpty = result.filter((message) => message.content.length > 0);
|
|
21955
|
+
return nonEmpty.length === 0 ? messages : refold(nonEmpty);
|
|
21956
|
+
}
|
|
21957
|
+
//#endregion
|
|
21797
21958
|
//#region src/host/command-code/mapper.ts
|
|
21798
21959
|
/**
|
|
21799
21960
|
* Provider-wire mapping for the two Command Code provider endpoints.
|
|
@@ -22350,7 +22511,7 @@ function anthropicAssistantContent$3(message) {
|
|
|
22350
22511
|
* the Messages wire wants one user turn, so consecutive turns of one role are
|
|
22351
22512
|
* folded together in order.
|
|
22352
22513
|
*/
|
|
22353
|
-
function mergeAnthropicMessages$
|
|
22514
|
+
function mergeAnthropicMessages$4(entries) {
|
|
22354
22515
|
const merged = [];
|
|
22355
22516
|
for (const entry of entries) {
|
|
22356
22517
|
if (entry.content.length === 0) continue;
|
|
@@ -22441,7 +22602,7 @@ function buildAnthropicRequest$1(options, images = NO_RESOLVED_IMAGES$3) {
|
|
|
22441
22602
|
return {
|
|
22442
22603
|
model: options.model,
|
|
22443
22604
|
max_tokens: maxTokens,
|
|
22444
|
-
messages: mergeAnthropicMessages$
|
|
22605
|
+
messages: cleanOrphanedToolCalls(mergeAnthropicMessages$4(entries), mergeAnthropicMessages$4),
|
|
22445
22606
|
...system === void 0 ? {} : { system: anthropicSystemBlocks(system) },
|
|
22446
22607
|
...options.temperature === void 0 || budget !== void 0 ? {} : { temperature: options.temperature },
|
|
22447
22608
|
...options.stop && options.stop.length > 0 ? { stop_sequences: options.stop } : {},
|
|
@@ -22743,6 +22904,23 @@ function applyOpenAIToolDelta$1(entry, state) {
|
|
|
22743
22904
|
const fn = isRecord$60(entry.function) ? entry.function : {};
|
|
22744
22905
|
const out = [];
|
|
22745
22906
|
let call = state.toolCalls.get(wireIndex);
|
|
22907
|
+
const incomingId = asString$26(entry.id);
|
|
22908
|
+
if (call !== void 0 && incomingId !== void 0 && call.id !== `call_${wireIndex}` && incomingId !== call.id) {
|
|
22909
|
+
const closedBlock = {
|
|
22910
|
+
type: "tool-call",
|
|
22911
|
+
id: toToolCallId(call.id),
|
|
22912
|
+
name: call.name,
|
|
22913
|
+
arguments: call.arguments === "" ? "{}" : call.arguments
|
|
22914
|
+
};
|
|
22915
|
+
state.blocks[call.blockIndex] = closedBlock;
|
|
22916
|
+
out.push({
|
|
22917
|
+
type: "block-end",
|
|
22918
|
+
index: call.blockIndex,
|
|
22919
|
+
block: closedBlock
|
|
22920
|
+
});
|
|
22921
|
+
state.toolCalls.delete(wireIndex);
|
|
22922
|
+
call = void 0;
|
|
22923
|
+
}
|
|
22746
22924
|
if (call === void 0) {
|
|
22747
22925
|
out.push(...closeCurrent$6(state));
|
|
22748
22926
|
call = {
|
|
@@ -24692,16 +24870,20 @@ function resolveEnabledModelIds$5(stored, catalog, enabled = true) {
|
|
|
24692
24870
|
/**
|
|
24693
24871
|
* Whether a stored selection still is a shipped default.
|
|
24694
24872
|
*
|
|
24695
|
-
*
|
|
24696
|
-
*
|
|
24697
|
-
*
|
|
24873
|
+
* Walk the recorded catalog refreshes newest-first. Each step reconstructs one
|
|
24874
|
+
* earlier default, so users who never edited either the immediate previous
|
|
24875
|
+
* release or an older recorded release still receive the current catalog.
|
|
24698
24876
|
*/
|
|
24699
24877
|
function isUneditedSelection(stored, shipped) {
|
|
24700
24878
|
if (stored.length === 0) return false;
|
|
24701
24879
|
if (sameSelection(stored, shipped)) return true;
|
|
24702
|
-
|
|
24703
|
-
for (const
|
|
24704
|
-
|
|
24880
|
+
let previous = new Set(shipped);
|
|
24881
|
+
for (const migration of SHIPPED_DEFAULT_MIGRATIONS) {
|
|
24882
|
+
previous = new Set([...previous].filter((id) => !migration.added.includes(id)));
|
|
24883
|
+
for (const id of migration.retired) previous.add(id);
|
|
24884
|
+
if (sameSelection(stored, previous)) return true;
|
|
24885
|
+
}
|
|
24886
|
+
return false;
|
|
24705
24887
|
}
|
|
24706
24888
|
/** Whether two id lists name exactly the same models, in any order. */
|
|
24707
24889
|
function sameSelection(stored, other) {
|
|
@@ -34524,7 +34706,7 @@ function anthropicAssistantContent$2(message, toolCallIds) {
|
|
|
34524
34706
|
* the Messages wire wants one user turn, so consecutive turns of one role are
|
|
34525
34707
|
* folded together in order.
|
|
34526
34708
|
*/
|
|
34527
|
-
function mergeAnthropicMessages$
|
|
34709
|
+
function mergeAnthropicMessages$3(entries) {
|
|
34528
34710
|
const merged = [];
|
|
34529
34711
|
for (const entry of entries) {
|
|
34530
34712
|
if (entry.content.length === 0) continue;
|
|
@@ -34577,7 +34759,7 @@ function buildAnthropicRequest(options, images = NO_RESOLVED_IMAGES$4, media = {
|
|
|
34577
34759
|
type: CLEAR_THINKING_EDIT,
|
|
34578
34760
|
keep: "all"
|
|
34579
34761
|
}] } : void 0;
|
|
34580
|
-
const messages = mergeAnthropicMessages$
|
|
34762
|
+
const messages = cleanOrphanedToolCalls(mergeAnthropicMessages$3(entries), mergeAnthropicMessages$3);
|
|
34581
34763
|
const lastMessage = messages[messages.length - 1];
|
|
34582
34764
|
if (lastMessage !== void 0 && Array.isArray(lastMessage.content) && lastMessage.content.length > 0) {
|
|
34583
34765
|
const lastBlock = lastMessage.content[lastMessage.content.length - 1];
|
|
@@ -34890,6 +35072,23 @@ function applyOpenAIToolDelta(entry, state) {
|
|
|
34890
35072
|
const fn = isRecord$53(entry.function) ? entry.function : {};
|
|
34891
35073
|
const out = [];
|
|
34892
35074
|
let call = state.toolCalls.get(wireIndex);
|
|
35075
|
+
const incomingId = asString$21(entry.id);
|
|
35076
|
+
if (call !== void 0 && incomingId !== void 0 && call.id !== `call_${wireIndex}` && incomingId !== call.id) {
|
|
35077
|
+
const closedBlock = {
|
|
35078
|
+
type: "tool-call",
|
|
35079
|
+
id: toToolCallId(state.toolCallIds.normalize(call.id)),
|
|
35080
|
+
name: call.name,
|
|
35081
|
+
arguments: call.arguments === "" ? "{}" : call.arguments
|
|
35082
|
+
};
|
|
35083
|
+
state.blocks[call.blockIndex] = closedBlock;
|
|
35084
|
+
out.push({
|
|
35085
|
+
type: "block-end",
|
|
35086
|
+
index: call.blockIndex,
|
|
35087
|
+
block: closedBlock
|
|
35088
|
+
});
|
|
35089
|
+
state.toolCalls.delete(wireIndex);
|
|
35090
|
+
call = void 0;
|
|
35091
|
+
}
|
|
34893
35092
|
if (call === void 0) {
|
|
34894
35093
|
out.push(...closeCurrent$5(state));
|
|
34895
35094
|
call = {
|
|
@@ -36876,7 +37075,7 @@ const KIMI_CODE_REQUEST_IMAGE_MAX_EDGE = 2e3;
|
|
|
36876
37075
|
* @param catalog - live catalog, possibly empty when offline.
|
|
36877
37076
|
* @returns the tool-update mode, or undefined when this route must resend everything.
|
|
36878
37077
|
*/
|
|
36879
|
-
function toolUpdateMode$
|
|
37078
|
+
function toolUpdateMode$2(modelId, catalog) {
|
|
36880
37079
|
if (!dynamicToolsForEntry(modelId, catalog)) return void 0;
|
|
36881
37080
|
if (wireForCatalogEntry(modelId, catalog) !== "openai") return void 0;
|
|
36882
37081
|
const raw = (process.env.DSH_KIMI_CODE_TOOL_UPDATE ?? "").trim().toLowerCase();
|
|
@@ -37279,7 +37478,7 @@ var KimiCodeAdapter = class extends LlmAdapter {
|
|
|
37279
37478
|
id: modelId,
|
|
37280
37479
|
name: entry?.name ?? modelId,
|
|
37281
37480
|
inputModalities: inputModalitiesForEntry(modelId, catalog),
|
|
37282
|
-
...toolUpdateMode$
|
|
37481
|
+
...toolUpdateMode$2(modelId, catalog) === void 0 ? {} : { toolUpdate: toolUpdateMode$2(modelId, catalog) },
|
|
37283
37482
|
context: { contextWindow: this.contextWindowFor(modelId, entry, settings.contextWindowOverrides) },
|
|
37284
37483
|
...efforts.length === 0 ? {} : { reasoning: {
|
|
37285
37484
|
efforts: efforts.map((effort) => ({
|
|
@@ -40932,7 +41131,7 @@ function anthropicAssistantContent$1(message, expectedScope) {
|
|
|
40932
41131
|
* Messages wire wants one user turn, so consecutive turns of one role are folded
|
|
40933
41132
|
* together in order.
|
|
40934
41133
|
*/
|
|
40935
|
-
function mergeAnthropicMessages$
|
|
41134
|
+
function mergeAnthropicMessages$2(entries) {
|
|
40936
41135
|
const merged = [];
|
|
40937
41136
|
for (const entry of entries) {
|
|
40938
41137
|
if (entry.content.length === 0) continue;
|
|
@@ -41154,7 +41353,7 @@ function buildMinimaxRequest(options, images = NO_RESOLVED_IMAGES$2, request = {
|
|
|
41154
41353
|
model: options.model,
|
|
41155
41354
|
max_tokens: maxTokens,
|
|
41156
41355
|
stream: true,
|
|
41157
|
-
messages: mergeAnthropicMessages$
|
|
41356
|
+
messages: cleanOrphanedToolCalls(mergeAnthropicMessages$2(entries), mergeAnthropicMessages$2),
|
|
41158
41357
|
...system === void 0 ? {} : { system: caching ? [{
|
|
41159
41358
|
type: "text",
|
|
41160
41359
|
text: system
|
|
@@ -49697,6 +49896,16 @@ function isClaudeCacheTtl$1(value) {
|
|
|
49697
49896
|
* models (`THINKING_BINDING_CONTROLS_BETA`, pushed when `supportsMidConvoEffort`).
|
|
49698
49897
|
*/
|
|
49699
49898
|
const THINKING_BINDING_CONTROLS_BETA = "thinking-binding-controls-2026-08-01";
|
|
49899
|
+
/**
|
|
49900
|
+
* Licenses a mid-conversation `tool_addition` / `tool_removal` block.
|
|
49901
|
+
*
|
|
49902
|
+
* A tool change stated inside a `role: "system"` message is a beta shape: without
|
|
49903
|
+
* this marker the blocks are an unknown content type and the request is refused.
|
|
49904
|
+
* The name carries its own date because the vendor versions the shape, so a
|
|
49905
|
+
* future revision arrives as a new constant rather than as a silent behaviour
|
|
49906
|
+
* change under the old one.
|
|
49907
|
+
*/
|
|
49908
|
+
const INLINE_TOOLS_BETA = "inline-tools-2026-09-15";
|
|
49700
49909
|
/** Anthropic protocol revision sent as `anthropic-version`. */
|
|
49701
49910
|
const ANTHROPIC_VERSION$1 = "2023-06-01";
|
|
49702
49911
|
/**
|
|
@@ -51323,6 +51532,7 @@ function claudeBetas(options = {}) {
|
|
|
51323
51532
|
if (options.thinking === true) betas.push(INTERLEAVED_THINKING_BETA);
|
|
51324
51533
|
if (options.thinkingBinding === true) betas.push(THINKING_BINDING_CONTROLS_BETA);
|
|
51325
51534
|
if (options.cacheTtl === "1h") betas.push(EXTENDED_CACHE_TTL_BETA);
|
|
51535
|
+
if (options.toolChanges === true) betas.push(INLINE_TOOLS_BETA);
|
|
51326
51536
|
return betas;
|
|
51327
51537
|
}
|
|
51328
51538
|
/** The `User-Agent` value this line reports for one surface. */
|
|
@@ -53423,10 +53633,85 @@ function wireTool(tool, names) {
|
|
|
53423
53633
|
return {
|
|
53424
53634
|
name: claudeWireToolName(tool.name, names),
|
|
53425
53635
|
description: tool.description ?? "",
|
|
53426
|
-
input_schema: schema
|
|
53636
|
+
input_schema: schema,
|
|
53637
|
+
...tool.deferLoading === true ? { defer_loading: true } : {}
|
|
53427
53638
|
};
|
|
53428
53639
|
}
|
|
53429
53640
|
/**
|
|
53641
|
+
* The stand-in declaration a request needs when every real tool is deferred.
|
|
53642
|
+
*
|
|
53643
|
+
* The vendor's rule is that at least one tool must stay active: a request whose
|
|
53644
|
+
* declarations are all deferred has no active declaration, and a tool change
|
|
53645
|
+
* stated in that state would move the start of the rendered prompt. Transcribed
|
|
53646
|
+
* from the harness's own anthropic-messages adapter, which inserts the same
|
|
53647
|
+
* placeholder for the same reason.
|
|
53648
|
+
*/
|
|
53649
|
+
const CLAUDE_TOOL_UPDATE_PLACEHOLDER = {
|
|
53650
|
+
name: "tool_update_placeholder",
|
|
53651
|
+
description: "Reserved. Keeps one tool declaration active so a mid-conversation tool change stays in the history. Never call it.",
|
|
53652
|
+
parameters: {
|
|
53653
|
+
type: "object",
|
|
53654
|
+
properties: {}
|
|
53655
|
+
}
|
|
53656
|
+
};
|
|
53657
|
+
/** Whether one message states a tool change this wire can carry. */
|
|
53658
|
+
function claudeMessageStatesToolChange(message) {
|
|
53659
|
+
return Array.isArray(message.content) && message.content.some((block) => isRecord$41(block) && (block.type === "tool-addition" || block.type === "tool-removal"));
|
|
53660
|
+
}
|
|
53661
|
+
/**
|
|
53662
|
+
* The fallback statement of one tool change, for a history position the vendor
|
|
53663
|
+
* will not accept a mid-conversation system message in.
|
|
53664
|
+
*
|
|
53665
|
+
* The declarations are untouched in both shapes: this only tells the model what
|
|
53666
|
+
* changed, and it is deliberately imperative for a removal because the
|
|
53667
|
+
* declaration is still there and could otherwise still be called.
|
|
53668
|
+
*/
|
|
53669
|
+
function claudeToolChangeNote(message) {
|
|
53670
|
+
const added = [];
|
|
53671
|
+
const removed = [];
|
|
53672
|
+
for (const block of message.content) {
|
|
53673
|
+
if (!isRecord$41(block)) continue;
|
|
53674
|
+
const name = typeof block.toolName === "string" ? block.toolName.trim() : "";
|
|
53675
|
+
if (name === "") continue;
|
|
53676
|
+
if (block.type === "tool-addition") added.push(name);
|
|
53677
|
+
else if (block.type === "tool-removal") removed.push(name);
|
|
53678
|
+
}
|
|
53679
|
+
const notes = [];
|
|
53680
|
+
if (added.length > 0) notes.push(`[The tool(s) ${added.map((name) => `"${name}"`).join(", ")} are now available.]`);
|
|
53681
|
+
if (removed.length > 0) notes.push(`[The tool(s) ${removed.map((name) => `"${name}"`).join(", ")} are no longer available. Do not call them again: any call will fail.]`);
|
|
53682
|
+
return notes.join("\n");
|
|
53683
|
+
}
|
|
53684
|
+
/** Whether any message states a tool change that this wire can carry. */
|
|
53685
|
+
function claudeHasToolChanges(options) {
|
|
53686
|
+
return options.messages.some((message) => message.role === "developer" && Array.isArray(message.content) && message.content.some((block) => isRecord$41(block) && (block.type === "tool-addition" || block.type === "tool-removal")));
|
|
53687
|
+
}
|
|
53688
|
+
/**
|
|
53689
|
+
* Whether a BUILT payload carries a `tool_addition` / `tool_removal` block.
|
|
53690
|
+
*
|
|
53691
|
+
* Read off the body rather than from the request, so the beta header and the
|
|
53692
|
+
* blocks it licenses cannot disagree about one request.
|
|
53693
|
+
*/
|
|
53694
|
+
function claudeBodyHasToolChanges(payload) {
|
|
53695
|
+
const messages = payload["messages"];
|
|
53696
|
+
if (!Array.isArray(messages)) return false;
|
|
53697
|
+
return messages.some((message) => {
|
|
53698
|
+
const content = message["content"];
|
|
53699
|
+
return Array.isArray(content) && content.some((block) => block["type"] === "tool_addition" || block["type"] === "tool_removal");
|
|
53700
|
+
});
|
|
53701
|
+
}
|
|
53702
|
+
/**
|
|
53703
|
+
* The wire tool list for one request.
|
|
53704
|
+
*
|
|
53705
|
+
* Deferred declarations travel with `defer_loading` so they stay out of the
|
|
53706
|
+
* prefix. When EVERY declaration is deferred and the history states a change,
|
|
53707
|
+
* one placeholder is prepended: the vendor refuses a tool change on a request
|
|
53708
|
+
* that has no active declaration at all.
|
|
53709
|
+
*/
|
|
53710
|
+
function claudeWireTools(options, names) {
|
|
53711
|
+
const tools = options.tools ?? [];
|
|
53712
|
+
return (tools.length > 0 && tools.every((tool) => tool.deferLoading === true) && claudeHasToolChanges(options) ? [CLAUDE_TOOL_UPDATE_PLACEHOLDER, ...tools] : tools).map((tool) => wireTool(tool, names));
|
|
53713
|
+
}
|
|
53714
|
+
/**
|
|
53430
53715
|
* One system-role turn's blocks.
|
|
53431
53716
|
*
|
|
53432
53717
|
* The vendor documents a mid-conversation system message as carrying "a plain
|
|
@@ -53452,6 +53737,17 @@ function claudeSystemContent(message, images) {
|
|
|
53452
53737
|
continue;
|
|
53453
53738
|
}
|
|
53454
53739
|
if (block.type === "image") blocks.push(imageBlockFor(block, images));
|
|
53740
|
+
if (block.type === "tool-addition" || block.type === "tool-removal") {
|
|
53741
|
+
const name = typeof block.toolName === "string" ? block.toolName.trim() : "";
|
|
53742
|
+
if (name === "") continue;
|
|
53743
|
+
blocks.push({
|
|
53744
|
+
type: block.type === "tool-addition" ? "tool_addition" : "tool_removal",
|
|
53745
|
+
tool: {
|
|
53746
|
+
type: "tool_reference",
|
|
53747
|
+
name: claudeWireToolName(name)
|
|
53748
|
+
}
|
|
53749
|
+
});
|
|
53750
|
+
}
|
|
53455
53751
|
}
|
|
53456
53752
|
return blocks;
|
|
53457
53753
|
}
|
|
@@ -53655,7 +53951,9 @@ function buildClaudeRequestBody(options, images = NO_RESOLVED_IMAGES$1, request
|
|
|
53655
53951
|
const maxTokens = claudeRequestThinks(options.model, effort, catalog) ? adjustMaxTokensForThinking(baseMax, modelMax, level, request.thinkingBudgets).maxTokens : baseMax;
|
|
53656
53952
|
const { thinking, outputConfig } = claudeThinking(options.model, effort, level, maxTokens, request.thinkingBudgets, catalog);
|
|
53657
53953
|
const entries = [];
|
|
53658
|
-
|
|
53954
|
+
const wire = messagesForTheWire(options);
|
|
53955
|
+
for (let index = 0; index < wire.length; index += 1) {
|
|
53956
|
+
const message = wire[index];
|
|
53659
53957
|
if (message.role === "system") {
|
|
53660
53958
|
entries.push({
|
|
53661
53959
|
role: "system",
|
|
@@ -53663,6 +53961,26 @@ function buildClaudeRequestBody(options, images = NO_RESOLVED_IMAGES$1, request
|
|
|
53663
53961
|
});
|
|
53664
53962
|
continue;
|
|
53665
53963
|
}
|
|
53964
|
+
if (message.role === "developer" && claudeMessageStatesToolChange(message)) {
|
|
53965
|
+
const previous = wire[index - 1];
|
|
53966
|
+
const next = wire[index + 1];
|
|
53967
|
+
if (previous !== void 0 && wireRoleOf(previous) === "user" && (next === void 0 || wireRoleOf(next) === "assistant")) {
|
|
53968
|
+
entries.push({
|
|
53969
|
+
role: "system",
|
|
53970
|
+
content: claudeSystemContent(message, images)
|
|
53971
|
+
});
|
|
53972
|
+
continue;
|
|
53973
|
+
}
|
|
53974
|
+
const note = claudeToolChangeNote(message);
|
|
53975
|
+
if (note !== "") entries.push({
|
|
53976
|
+
role: "user",
|
|
53977
|
+
content: [{
|
|
53978
|
+
type: "text",
|
|
53979
|
+
text: note
|
|
53980
|
+
}]
|
|
53981
|
+
});
|
|
53982
|
+
continue;
|
|
53983
|
+
}
|
|
53666
53984
|
if (isToolResultMessage$5(message)) {
|
|
53667
53985
|
entries.push({
|
|
53668
53986
|
role: "user",
|
|
@@ -53684,8 +54002,8 @@ function buildClaudeRequestBody(options, images = NO_RESOLVED_IMAGES$1, request
|
|
|
53684
54002
|
max_tokens: maxTokens,
|
|
53685
54003
|
stream: true,
|
|
53686
54004
|
system: buildClaudeSystemBlocks(options, caching, cacheTtl),
|
|
53687
|
-
messages: mergeClaudeMessages(entries),
|
|
53688
|
-
...options.tools !== void 0 && options.tools.length > 0 ? { tools: options
|
|
54005
|
+
messages: cleanOrphanedToolCalls(mergeClaudeMessages(entries), mergeClaudeMessages),
|
|
54006
|
+
...options.tools !== void 0 && options.tools.length > 0 ? { tools: claudeWireTools(options, names) } : {},
|
|
53689
54007
|
...thinking === void 0 ? {} : { thinking },
|
|
53690
54008
|
...outputConfig === void 0 ? {} : { output_config: outputConfig },
|
|
53691
54009
|
...temperatureAllowed && options.temperature !== void 0 ? { temperature: options.temperature } : {},
|
|
@@ -55511,6 +55829,33 @@ var ClaudeAccountTokenStore = class {
|
|
|
55511
55829
|
await this.store.saveAccount(credentials, { internalId: this.internalId });
|
|
55512
55830
|
}
|
|
55513
55831
|
};
|
|
55832
|
+
/**
|
|
55833
|
+
* Whether this model may state a tool change in the history.
|
|
55834
|
+
*
|
|
55835
|
+
* Gated on the same capability that licenses a mid-conversation system message,
|
|
55836
|
+
* because that message is what carries the change: a model that folds those
|
|
55837
|
+
* messages back into the top-level `system` field cannot take a tool change
|
|
55838
|
+
* without moving the head, which is the cost the capability exists to avoid.
|
|
55839
|
+
*
|
|
55840
|
+
* `DSH_CLAUDE_TOOL_UPDATE=0` turns it off for one account without a code change,
|
|
55841
|
+
* mirroring the escape hatch kimi-code and the codex line carry.
|
|
55842
|
+
*
|
|
55843
|
+
* @param modelId - exact model id.
|
|
55844
|
+
* @returns the mode to declare, or undefined when every request must restate the
|
|
55845
|
+
* complete tool list.
|
|
55846
|
+
*/
|
|
55847
|
+
function toolUpdateMode$1(modelId) {
|
|
55848
|
+
if (!claudeSupportsMidConversationSystemMessages(modelId)) return void 0;
|
|
55849
|
+
const raw = (process.env.DSH_CLAUDE_TOOL_UPDATE ?? "").trim().toLowerCase();
|
|
55850
|
+
if (raw !== "" && [
|
|
55851
|
+
"0",
|
|
55852
|
+
"false",
|
|
55853
|
+
"no",
|
|
55854
|
+
"off",
|
|
55855
|
+
"none"
|
|
55856
|
+
].includes(raw)) return void 0;
|
|
55857
|
+
return "in-history";
|
|
55858
|
+
}
|
|
55514
55859
|
var ClaudeAdapter = class ClaudeAdapter extends LlmAdapter {
|
|
55515
55860
|
store;
|
|
55516
55861
|
modelSettings;
|
|
@@ -55626,6 +55971,7 @@ var ClaudeAdapter = class ClaudeAdapter extends LlmAdapter {
|
|
|
55626
55971
|
inputModalities: entry.supportsImage ? ["text", "image"] : ["text"],
|
|
55627
55972
|
context: { contextWindow: contextWindow || 2e5 },
|
|
55628
55973
|
...outputReservation(contextWindow || 2e5, maxOutputTokensFor(modelId, catalog)),
|
|
55974
|
+
...toolUpdateMode$1(modelId) === void 0 ? {} : { toolUpdate: toolUpdateMode$1(modelId) },
|
|
55629
55975
|
...efforts.length === 0 ? {} : { reasoning: {
|
|
55630
55976
|
efforts: efforts.map((effort) => ({
|
|
55631
55977
|
id: ReasoningEffortId(effort),
|
|
@@ -55724,6 +56070,7 @@ var ClaudeAdapter = class ClaudeAdapter extends LlmAdapter {
|
|
|
55724
56070
|
model: requestOptions.model,
|
|
55725
56071
|
thinking,
|
|
55726
56072
|
thinkingBinding: claudeBodyBindsThinking(payload),
|
|
56073
|
+
toolChanges: claudeBodyHasToolChanges(payload),
|
|
55727
56074
|
cacheTtl,
|
|
55728
56075
|
method: "POST"
|
|
55729
56076
|
}),
|
|
@@ -59228,7 +59575,7 @@ function safeStringify(value) {
|
|
|
59228
59575
|
* DSH 历史里可能连续两条 user(注入的上下文提示 + 真正的用户轮),而工具结果本身就是
|
|
59229
59576
|
* user 角色消息;Messages 线要的是一个 user 轮,所以同角色的连续轮按顺序折叠。
|
|
59230
59577
|
*/
|
|
59231
|
-
function mergeAnthropicMessages(entries) {
|
|
59578
|
+
function mergeAnthropicMessages$1(entries) {
|
|
59232
59579
|
const merged = [];
|
|
59233
59580
|
for (const entry of entries) {
|
|
59234
59581
|
if (entry.content.length === 0) continue;
|
|
@@ -59377,7 +59724,7 @@ function buildGlmAnthropicRequest(options, request = {}) {
|
|
|
59377
59724
|
}
|
|
59378
59725
|
const system = glmAnthropicSystemBlocks(options);
|
|
59379
59726
|
const maxTokens = options.maxTokens ?? request.defaultMaxTokens ?? 32768;
|
|
59380
|
-
const merged = mergeAnthropicMessages(entries);
|
|
59727
|
+
const merged = cleanOrphanedToolCalls(mergeAnthropicMessages$1(entries), mergeAnthropicMessages$1);
|
|
59381
59728
|
const lastMessageIndex = merged.length - 1;
|
|
59382
59729
|
const messages = lastMessageIndex < 0 ? merged : merged.map((message, index) => index === lastMessageIndex ? {
|
|
59383
59730
|
...message,
|
|
@@ -60704,6 +61051,23 @@ function applyToolDelta$3(entry, state) {
|
|
|
60704
61051
|
const fn = isRecord$37(entry.function) ? entry.function : {};
|
|
60705
61052
|
const out = [];
|
|
60706
61053
|
let call = state.toolCalls.get(wireIndex);
|
|
61054
|
+
const incomingId = asString$14(entry.id);
|
|
61055
|
+
if (call !== void 0 && incomingId !== void 0 && call.id !== `call_${wireIndex}` && incomingId !== call.id) {
|
|
61056
|
+
const closedBlock = {
|
|
61057
|
+
type: "tool-call",
|
|
61058
|
+
id: toToolCallId(call.id),
|
|
61059
|
+
name: call.name,
|
|
61060
|
+
arguments: call.arguments === "" ? "{}" : call.arguments
|
|
61061
|
+
};
|
|
61062
|
+
state.blocks[call.blockIndex] = closedBlock;
|
|
61063
|
+
out.push({
|
|
61064
|
+
type: "block-end",
|
|
61065
|
+
index: call.blockIndex,
|
|
61066
|
+
block: closedBlock
|
|
61067
|
+
});
|
|
61068
|
+
state.toolCalls.delete(wireIndex);
|
|
61069
|
+
call = void 0;
|
|
61070
|
+
}
|
|
60707
61071
|
if (call === void 0) {
|
|
60708
61072
|
out.push(...closeCurrent$3(state));
|
|
60709
61073
|
call = {
|
|
@@ -65537,6 +65901,23 @@ function applyToolDelta$2(entry, state) {
|
|
|
65537
65901
|
const fn = isRecord$33(entry.function) ? entry.function : void 0;
|
|
65538
65902
|
const out = [];
|
|
65539
65903
|
let call = state.toolCalls.get(wireIndex);
|
|
65904
|
+
const incomingId = asString$10(entry.id);
|
|
65905
|
+
if (call !== void 0 && incomingId !== void 0 && call.id !== `call_${wireIndex}` && incomingId !== call.id) {
|
|
65906
|
+
const closedBlock = {
|
|
65907
|
+
type: "tool-call",
|
|
65908
|
+
id: toToolCallId(call.id),
|
|
65909
|
+
name: call.name,
|
|
65910
|
+
arguments: call.arguments === "" ? "{}" : call.arguments
|
|
65911
|
+
};
|
|
65912
|
+
state.blocks[call.blockIndex] = closedBlock;
|
|
65913
|
+
out.push({
|
|
65914
|
+
type: "block-end",
|
|
65915
|
+
index: call.blockIndex,
|
|
65916
|
+
block: closedBlock
|
|
65917
|
+
});
|
|
65918
|
+
state.toolCalls.delete(wireIndex);
|
|
65919
|
+
call = void 0;
|
|
65920
|
+
}
|
|
65540
65921
|
if (call === void 0) {
|
|
65541
65922
|
const opened = openToolCall$1(state, entry, wireIndex);
|
|
65542
65923
|
out.push(...opened.chunks);
|
|
@@ -71801,6 +72182,7 @@ async function* translate(payloads) {
|
|
|
71801
72182
|
if (!isRecord$26(call)) continue;
|
|
71802
72183
|
const index = Number(call.index ?? 0);
|
|
71803
72184
|
let block = toolBlocks.get(index);
|
|
72185
|
+
if (block !== void 0 && typeof call.id === "string" && call.id.length > 0 && block.callId !== void 0 && block.callId.length > 0 && block.callId !== call.id) block = void 0;
|
|
71804
72186
|
if (block === void 0) {
|
|
71805
72187
|
block = open("tool-call");
|
|
71806
72188
|
toolBlocks.set(index, block);
|
|
@@ -71812,7 +72194,7 @@ async function* translate(payloads) {
|
|
|
71812
72194
|
}
|
|
71813
72195
|
const fn = isRecord$26(call.function) ? call.function : {};
|
|
71814
72196
|
block.callId = acceptIdentity$1(block.callId, call.id);
|
|
71815
|
-
block.name = acceptIdentity$1(block.name, fn.name);
|
|
72197
|
+
if (block.name === void 0 || block.name === "") block.name = acceptIdentity$1(block.name, fn.name);
|
|
71816
72198
|
const fragment = typeof fn.arguments === "string" ? fn.arguments : "";
|
|
71817
72199
|
block.text += fragment;
|
|
71818
72200
|
yield {
|
|
@@ -78539,6 +78921,23 @@ function applyToolDelta$1(entry, state) {
|
|
|
78539
78921
|
const fn = isRecord$21(entry.function) ? entry.function : void 0;
|
|
78540
78922
|
const out = [];
|
|
78541
78923
|
let call = state.toolCalls.get(wireIndex);
|
|
78924
|
+
const incomingId = asString$7(entry.id);
|
|
78925
|
+
if (call !== void 0 && incomingId !== void 0 && call.id !== "call_" + wireIndex && incomingId !== call.id) {
|
|
78926
|
+
const closedBlock = {
|
|
78927
|
+
type: "tool-call",
|
|
78928
|
+
id: toToolCallId(call.id),
|
|
78929
|
+
name: call.name,
|
|
78930
|
+
arguments: call.arguments === "" ? "{}" : call.arguments
|
|
78931
|
+
};
|
|
78932
|
+
state.blocks[call.blockIndex] = closedBlock;
|
|
78933
|
+
out.push({
|
|
78934
|
+
type: "block-end",
|
|
78935
|
+
index: call.blockIndex,
|
|
78936
|
+
block: closedBlock
|
|
78937
|
+
});
|
|
78938
|
+
state.toolCalls.delete(wireIndex);
|
|
78939
|
+
call = void 0;
|
|
78940
|
+
}
|
|
78542
78941
|
if (call === void 0) {
|
|
78543
78942
|
const opened = openToolCall(state, entry, wireIndex);
|
|
78544
78943
|
out.push(...opened.chunks);
|
|
@@ -83757,6 +84156,7 @@ async function* translate$1(payloads) {
|
|
|
83757
84156
|
if (!isRecord$17(call)) continue;
|
|
83758
84157
|
const index = Number(call.index ?? 0);
|
|
83759
84158
|
let block = toolBlocks.get(index);
|
|
84159
|
+
if (block !== void 0 && typeof call.id === "string" && call.id.length > 0 && block.callId !== void 0 && block.callId.length > 0 && block.callId !== call.id) block = void 0;
|
|
83760
84160
|
if (block === void 0) {
|
|
83761
84161
|
block = open("tool-call");
|
|
83762
84162
|
toolBlocks.set(index, block);
|
|
@@ -83768,7 +84168,7 @@ async function* translate$1(payloads) {
|
|
|
83768
84168
|
}
|
|
83769
84169
|
const fn = isRecord$17(call.function) ? call.function : {};
|
|
83770
84170
|
block.callId = acceptIdentity(block.callId, call.id);
|
|
83771
|
-
block.name = acceptIdentity(block.name, fn.name);
|
|
84171
|
+
if (block.name === void 0 || block.name === "") block.name = acceptIdentity(block.name, fn.name);
|
|
83772
84172
|
const fragment = typeof fn.arguments === "string" ? fn.arguments : "";
|
|
83773
84173
|
block.text += fragment;
|
|
83774
84174
|
yield {
|
|
@@ -87295,9 +87695,9 @@ function installToolResultPrunerGuard(ctx, options = {}) {
|
|
|
87295
87695
|
const wrapPruner = (pruner) => {
|
|
87296
87696
|
if (disposed || !isRecord$14(pruner)) return false;
|
|
87297
87697
|
if (alreadyWrapped.has(pruner)) return false;
|
|
87298
|
-
const target = resolveMethodTarget$
|
|
87698
|
+
const target = resolveMethodTarget$4(pruner, "pruneSession");
|
|
87299
87699
|
if (target === void 0) return false;
|
|
87300
|
-
if (alreadyPatched$
|
|
87700
|
+
if (alreadyPatched$4(patchedMethods, target.holder, target.name)) {
|
|
87301
87701
|
alreadyWrapped.add(pruner);
|
|
87302
87702
|
return false;
|
|
87303
87703
|
}
|
|
@@ -87309,11 +87709,11 @@ function installToolResultPrunerGuard(ctx, options = {}) {
|
|
|
87309
87709
|
};
|
|
87310
87710
|
return original.call(this ?? pruner, session);
|
|
87311
87711
|
};
|
|
87312
|
-
if (!installMethod$
|
|
87313
|
-
markPatched$
|
|
87712
|
+
if (!installMethod$4(target, replacement)) return false;
|
|
87713
|
+
markPatched$4(patchedMethods, target.holder, target.name);
|
|
87314
87714
|
alreadyWrapped.add(pruner);
|
|
87315
87715
|
restores.push(() => {
|
|
87316
|
-
restoreMethod$
|
|
87716
|
+
restoreMethod$4(target);
|
|
87317
87717
|
});
|
|
87318
87718
|
return true;
|
|
87319
87719
|
};
|
|
@@ -87533,7 +87933,7 @@ function isRecord$14(value) {
|
|
|
87533
87933
|
* @param name - 方法名。
|
|
87534
87934
|
* @returns 目标;方法不存在时为 `undefined`。
|
|
87535
87935
|
*/
|
|
87536
|
-
function resolveMethodTarget$
|
|
87936
|
+
function resolveMethodTarget$4(service, name) {
|
|
87537
87937
|
if (typeof service !== "object" || service === null) return void 0;
|
|
87538
87938
|
const own = service;
|
|
87539
87939
|
if (Object.prototype.hasOwnProperty.call(own, name)) {
|
|
@@ -87565,7 +87965,7 @@ function resolveMethodTarget$3(service, name) {
|
|
|
87565
87965
|
* @param replacement - 包装实现。
|
|
87566
87966
|
* @returns 是否装上了。
|
|
87567
87967
|
*/
|
|
87568
|
-
function installMethod$
|
|
87968
|
+
function installMethod$4(target, replacement) {
|
|
87569
87969
|
try {
|
|
87570
87970
|
Object.defineProperty(target.holder, target.name, {
|
|
87571
87971
|
value: replacement,
|
|
@@ -87583,7 +87983,7 @@ function installMethod$3(target, replacement) {
|
|
|
87583
87983
|
*
|
|
87584
87984
|
* @param target - 目标。
|
|
87585
87985
|
*/
|
|
87586
|
-
function restoreMethod$
|
|
87986
|
+
function restoreMethod$4(target) {
|
|
87587
87987
|
try {
|
|
87588
87988
|
if (target.descriptor === void 0) Reflect.deleteProperty(target.holder, target.name);
|
|
87589
87989
|
else Object.defineProperty(target.holder, target.name, target.descriptor);
|
|
@@ -87597,7 +87997,7 @@ function restoreMethod$3(target) {
|
|
|
87597
87997
|
* @param name - 方法名。
|
|
87598
87998
|
* @returns 是否已经包过。
|
|
87599
87999
|
*/
|
|
87600
|
-
function alreadyPatched$
|
|
88000
|
+
function alreadyPatched$4(patched, holder, name) {
|
|
87601
88001
|
return patched.get(holder)?.has(name) === true;
|
|
87602
88002
|
}
|
|
87603
88003
|
/**
|
|
@@ -87607,7 +88007,7 @@ function alreadyPatched$3(patched, holder, name) {
|
|
|
87607
88007
|
* @param holder - 方法宿主。
|
|
87608
88008
|
* @param name - 方法名。
|
|
87609
88009
|
*/
|
|
87610
|
-
function markPatched$
|
|
88010
|
+
function markPatched$4(patched, holder, name) {
|
|
87611
88011
|
const names = patched.get(holder);
|
|
87612
88012
|
if (names === void 0) patched.set(holder, /* @__PURE__ */ new Set([name]));
|
|
87613
88013
|
else names.add(name);
|
|
@@ -87622,7 +88022,7 @@ const GLOBAL_KEY$2 = Object.freeze({});
|
|
|
87622
88022
|
* @param service - 服务名。
|
|
87623
88023
|
* @returns 服务实例或 undefined。
|
|
87624
88024
|
*/
|
|
87625
|
-
function serviceOf$
|
|
88025
|
+
function serviceOf$2(ctx, service) {
|
|
87626
88026
|
const read = ctx?.get;
|
|
87627
88027
|
if (typeof read !== "function") return void 0;
|
|
87628
88028
|
try {
|
|
@@ -87644,11 +88044,15 @@ function bucketOf$1(value) {
|
|
|
87644
88044
|
* @param ctx - 宿主上下文。
|
|
87645
88045
|
* @param event - 事件名。
|
|
87646
88046
|
* @param listener - 监听器。
|
|
88047
|
+
* @param options - cordis 订阅选项;省略时按两参数订阅。
|
|
87647
88048
|
* @returns 解绑函数或 undefined。
|
|
87648
88049
|
*/
|
|
87649
|
-
function subscribe$3(ctx, event, listener) {
|
|
88050
|
+
function subscribe$3(ctx, event, listener, options) {
|
|
87650
88051
|
const on = ctx?.on;
|
|
87651
88052
|
if (typeof on !== "function") return void 0;
|
|
88053
|
+
if (options !== void 0) try {
|
|
88054
|
+
return on.call(ctx, event, listener, options);
|
|
88055
|
+
} catch {}
|
|
87652
88056
|
try {
|
|
87653
88057
|
return on.call(ctx, event, listener);
|
|
87654
88058
|
} catch {
|
|
@@ -87741,11 +88145,15 @@ function installPlanModeCacheGuard(ctx) {
|
|
|
87741
88145
|
if (offPreStep !== void 0) restores.push(() => {
|
|
87742
88146
|
offPreStep();
|
|
87743
88147
|
});
|
|
88148
|
+
const offReminder = installPlanModeExitReminder(ctx, { isActive: (agent) => planActiveOfAgent(ctx, agent) });
|
|
88149
|
+
if (offReminder !== void 0) restores.push(() => {
|
|
88150
|
+
offReminder();
|
|
88151
|
+
});
|
|
87744
88152
|
const wrap = (tools) => {
|
|
87745
88153
|
if (tools === void 0) return;
|
|
87746
|
-
const target = resolveMethodTarget$
|
|
88154
|
+
const target = resolveMethodTarget$3(tools, "register");
|
|
87747
88155
|
if (target === void 0) return;
|
|
87748
|
-
if (alreadyPatched$
|
|
88156
|
+
if (alreadyPatched$3(patchedMethods, target.holder, target.name)) return;
|
|
87749
88157
|
const original = target.original;
|
|
87750
88158
|
const wrapped = function(...args) {
|
|
87751
88159
|
const receiver = this ?? tools;
|
|
@@ -87757,16 +88165,16 @@ function installPlanModeCacheGuard(ctx) {
|
|
|
87757
88165
|
}
|
|
87758
88166
|
return original.call(receiver, definition, options);
|
|
87759
88167
|
};
|
|
87760
|
-
if (!installMethod$
|
|
87761
|
-
markPatched$
|
|
88168
|
+
if (!installMethod$3(target, wrapped)) return;
|
|
88169
|
+
markPatched$3(patchedMethods, target.holder, target.name);
|
|
87762
88170
|
restores.push(() => {
|
|
87763
|
-
restoreMethod$
|
|
88171
|
+
restoreMethod$3(target);
|
|
87764
88172
|
});
|
|
87765
88173
|
if (typeof tools.get === "function") try {
|
|
87766
88174
|
if (tools.get("exit_plan_mode") !== void 0) logWarn$1(ctx, "[dsh-chatgpt-subscription] plan-mode cache guard was installed after exit_plan_mode was already registered; this session keeps the conditional admission");
|
|
87767
88175
|
} catch {}
|
|
87768
88176
|
};
|
|
87769
|
-
const tools = serviceOf$
|
|
88177
|
+
const tools = serviceOf$2(ctx, "tools");
|
|
87770
88178
|
if (tools !== void 0) wrap(tools);
|
|
87771
88179
|
else {
|
|
87772
88180
|
const inject = ctx?.inject;
|
|
@@ -87776,7 +88184,7 @@ function installPlanModeCacheGuard(ctx) {
|
|
|
87776
88184
|
inject.call(ctx, ["tools"], (scope) => {
|
|
87777
88185
|
if (wrapped || closed) return;
|
|
87778
88186
|
wrapped = true;
|
|
87779
|
-
wrap(serviceOf$
|
|
88187
|
+
wrap(serviceOf$2(scope, "tools"));
|
|
87780
88188
|
});
|
|
87781
88189
|
} catch {}
|
|
87782
88190
|
}
|
|
@@ -87796,7 +88204,7 @@ function installPlanModeCacheGuard(ctx) {
|
|
|
87796
88204
|
* @returns true / false;读不到时 undefined。
|
|
87797
88205
|
*/
|
|
87798
88206
|
function planActiveOf(ctx, session) {
|
|
87799
|
-
const projections = serviceOf$
|
|
88207
|
+
const projections = serviceOf$2(ctx, "sessionProjections");
|
|
87800
88208
|
if (typeof projections?.stateOf !== "function") return void 0;
|
|
87801
88209
|
try {
|
|
87802
88210
|
const state = projections.stateOf(session, PLAN_PROJECTION_KEY);
|
|
@@ -87806,6 +88214,35 @@ function planActiveOf(ctx, session) {
|
|
|
87806
88214
|
}
|
|
87807
88215
|
}
|
|
87808
88216
|
/**
|
|
88217
|
+
* 读一个 agent 此刻是否在计划模式。
|
|
88218
|
+
*
|
|
88219
|
+
* 三级降级,顺序不可颠倒:
|
|
88220
|
+
*
|
|
88221
|
+
* 1. 进程级登记册({@link registeredPlanControllerActive}):本包的 fork 会把每个
|
|
88222
|
+
* 会话登记进去,**跨 realm 可见**。`ctx.get()` 看不见 `isolate: { planMode: true }`
|
|
88223
|
+
* 的子 realm,而隔离正是宿主守卫最常见的部署(守卫在根作用域、控制器在 preset 里),
|
|
88224
|
+
* 所以这一级必须先问。
|
|
88225
|
+
* 2. 同一作用域里的 `planMode` 服务:本包的 fork 有 `selectedActive`(含未决选择),
|
|
88226
|
+
* 所以 `exit_plan_mode` 刚排队 `{ active: false }`、日志还没落进投影的那一刻不会被
|
|
88227
|
+
* 误判成「还在计划模式」。
|
|
88228
|
+
* 3. plan 投影:内置 preset 挂的是官方服务,它的 `/plan` 只写日志,投影是那边唯一的
|
|
88229
|
+
* 事实来源。
|
|
88230
|
+
* @param ctx - 宿主上下文。
|
|
88231
|
+
* @param agent - 调用方 agent。
|
|
88232
|
+
* @returns true / false;读不到时 undefined。
|
|
88233
|
+
*/
|
|
88234
|
+
function planActiveOfAgent(ctx, agent) {
|
|
88235
|
+
const session = agent?.session;
|
|
88236
|
+
const registered = registeredPlanControllerActive(session);
|
|
88237
|
+
if (registered !== void 0) return registered;
|
|
88238
|
+
const controller = serviceOf$2(ctx, "planMode");
|
|
88239
|
+
if (typeof controller?.selectedActive === "function") try {
|
|
88240
|
+
const active = controller.selectedActive(session);
|
|
88241
|
+
if (typeof active === "boolean") return active;
|
|
88242
|
+
} catch {}
|
|
88243
|
+
return planActiveOf(ctx, session);
|
|
88244
|
+
}
|
|
88245
|
+
/**
|
|
87809
88246
|
* 记一条警告。
|
|
87810
88247
|
* @param ctx - 宿主上下文。
|
|
87811
88248
|
* @param message - 正文。
|
|
@@ -87834,7 +88271,7 @@ function logWarn$1(ctx, message) {
|
|
|
87834
88271
|
* @param name - 方法名。
|
|
87835
88272
|
* @returns 目标;方法不存在时为 `undefined`。
|
|
87836
88273
|
*/
|
|
87837
|
-
function resolveMethodTarget$
|
|
88274
|
+
function resolveMethodTarget$3(service, name) {
|
|
87838
88275
|
if (typeof service !== "object" || service === null) return void 0;
|
|
87839
88276
|
const own = service;
|
|
87840
88277
|
if (Object.prototype.hasOwnProperty.call(own, name)) {
|
|
@@ -87866,7 +88303,7 @@ function resolveMethodTarget$2(service, name) {
|
|
|
87866
88303
|
* @param replacement - 包装实现。
|
|
87867
88304
|
* @returns 是否装上了。
|
|
87868
88305
|
*/
|
|
87869
|
-
function installMethod$
|
|
88306
|
+
function installMethod$3(target, replacement) {
|
|
87870
88307
|
try {
|
|
87871
88308
|
Object.defineProperty(target.holder, target.name, {
|
|
87872
88309
|
value: replacement,
|
|
@@ -87884,7 +88321,7 @@ function installMethod$2(target, replacement) {
|
|
|
87884
88321
|
*
|
|
87885
88322
|
* @param target - 目标。
|
|
87886
88323
|
*/
|
|
87887
|
-
function restoreMethod$
|
|
88324
|
+
function restoreMethod$3(target) {
|
|
87888
88325
|
try {
|
|
87889
88326
|
if (target.descriptor === void 0) Reflect.deleteProperty(target.holder, target.name);
|
|
87890
88327
|
else Object.defineProperty(target.holder, target.name, target.descriptor);
|
|
@@ -87898,7 +88335,7 @@ function restoreMethod$2(target) {
|
|
|
87898
88335
|
* @param name - 方法名。
|
|
87899
88336
|
* @returns 是否已经包过。
|
|
87900
88337
|
*/
|
|
87901
|
-
function alreadyPatched$
|
|
88338
|
+
function alreadyPatched$3(patched, holder, name) {
|
|
87902
88339
|
return patched.get(holder)?.has(name) === true;
|
|
87903
88340
|
}
|
|
87904
88341
|
/**
|
|
@@ -87908,7 +88345,7 @@ function alreadyPatched$2(patched, holder, name) {
|
|
|
87908
88345
|
* @param holder - 方法宿主。
|
|
87909
88346
|
* @param name - 方法名。
|
|
87910
88347
|
*/
|
|
87911
|
-
function markPatched$
|
|
88348
|
+
function markPatched$3(patched, holder, name) {
|
|
87912
88349
|
const names = patched.get(holder);
|
|
87913
88350
|
if (names === void 0) patched.set(holder, /* @__PURE__ */ new Set([name]));
|
|
87914
88351
|
else names.add(name);
|
|
@@ -88030,7 +88467,7 @@ function installPtcSdkCacheGuard(ctx, options = {}) {
|
|
|
88030
88467
|
*/
|
|
88031
88468
|
const toolFingerprint = (tools, scope) => {
|
|
88032
88469
|
if (!isRecord$13(tools)) return "";
|
|
88033
|
-
const target = resolveMethodTarget$
|
|
88470
|
+
const target = resolveMethodTarget$2(tools, "definitions");
|
|
88034
88471
|
if (target === void 0) return "";
|
|
88035
88472
|
let list;
|
|
88036
88473
|
try {
|
|
@@ -88050,9 +88487,9 @@ function installPtcSdkCacheGuard(ctx, options = {}) {
|
|
|
88050
88487
|
const wrapToolsService = (tools) => {
|
|
88051
88488
|
if (disposed || !isRecord$13(tools)) return false;
|
|
88052
88489
|
if (alreadyWrapped.has(tools)) return false;
|
|
88053
|
-
const target = resolveMethodTarget$
|
|
88490
|
+
const target = resolveMethodTarget$2(tools, "definitions");
|
|
88054
88491
|
if (target === void 0) return false;
|
|
88055
|
-
if (alreadyPatched$
|
|
88492
|
+
if (alreadyPatched$2(patchedMethods, target.holder, target.name)) {
|
|
88056
88493
|
alreadyWrapped.add(tools);
|
|
88057
88494
|
return false;
|
|
88058
88495
|
}
|
|
@@ -88065,11 +88502,11 @@ function installPtcSdkCacheGuard(ctx, options = {}) {
|
|
|
88065
88502
|
}
|
|
88066
88503
|
return original.call(receiver, scope, toolSet);
|
|
88067
88504
|
};
|
|
88068
|
-
if (!installMethod$
|
|
88069
|
-
markPatched$
|
|
88505
|
+
if (!installMethod$2(target, replacement)) return false;
|
|
88506
|
+
markPatched$2(patchedMethods, target.holder, target.name);
|
|
88070
88507
|
alreadyWrapped.add(tools);
|
|
88071
88508
|
restores.push(() => {
|
|
88072
|
-
restoreMethod$
|
|
88509
|
+
restoreMethod$2(target);
|
|
88073
88510
|
});
|
|
88074
88511
|
return true;
|
|
88075
88512
|
};
|
|
@@ -88109,7 +88546,7 @@ function installPtcSdkCacheGuard(ctx, options = {}) {
|
|
|
88109
88546
|
};
|
|
88110
88547
|
const offAssemble = subscribe$2(host, "system-prompt/assemble", onAssemble);
|
|
88111
88548
|
if (offAssemble !== void 0) disposers.push(offAssemble);
|
|
88112
|
-
const initialTools = serviceOf(host, "tools");
|
|
88549
|
+
const initialTools = serviceOf$1(host, "tools");
|
|
88113
88550
|
if (initialTools !== void 0) {
|
|
88114
88551
|
currentTools = initialTools;
|
|
88115
88552
|
wrapToolsService(initialTools);
|
|
@@ -88118,7 +88555,7 @@ function installPtcSdkCacheGuard(ctx, options = {}) {
|
|
|
88118
88555
|
if (typeof inject === "function") try {
|
|
88119
88556
|
inject.call(host, ["tools"], (scope) => {
|
|
88120
88557
|
if (disposed) return;
|
|
88121
|
-
const tools = serviceOf(scope, "tools");
|
|
88558
|
+
const tools = serviceOf$1(scope, "tools");
|
|
88122
88559
|
if (tools === void 0) return;
|
|
88123
88560
|
currentTools = tools;
|
|
88124
88561
|
wrapToolsService(tools);
|
|
@@ -88146,7 +88583,7 @@ function installPtcSdkCacheGuard(ctx, options = {}) {
|
|
|
88146
88583
|
* @param service - 服务名。
|
|
88147
88584
|
* @returns 服务实例;读不到时为 `undefined`。
|
|
88148
88585
|
*/
|
|
88149
|
-
function serviceOf(ctx, service) {
|
|
88586
|
+
function serviceOf$1(ctx, service) {
|
|
88150
88587
|
if (!isRecord$13(ctx)) return void 0;
|
|
88151
88588
|
const read = ctx["get"];
|
|
88152
88589
|
if (typeof read !== "function") return void 0;
|
|
@@ -88215,7 +88652,7 @@ function isRecord$13(value) {
|
|
|
88215
88652
|
* @param name - 方法名。
|
|
88216
88653
|
* @returns 目标;方法不存在时为 `undefined`。
|
|
88217
88654
|
*/
|
|
88218
|
-
function resolveMethodTarget$
|
|
88655
|
+
function resolveMethodTarget$2(service, name) {
|
|
88219
88656
|
if (typeof service !== "object" || service === null) return void 0;
|
|
88220
88657
|
const own = service;
|
|
88221
88658
|
if (Object.prototype.hasOwnProperty.call(own, name)) {
|
|
@@ -88247,7 +88684,7 @@ function resolveMethodTarget$1(service, name) {
|
|
|
88247
88684
|
* @param replacement - 包装实现。
|
|
88248
88685
|
* @returns 是否装上了。
|
|
88249
88686
|
*/
|
|
88250
|
-
function installMethod$
|
|
88687
|
+
function installMethod$2(target, replacement) {
|
|
88251
88688
|
try {
|
|
88252
88689
|
Object.defineProperty(target.holder, target.name, {
|
|
88253
88690
|
value: replacement,
|
|
@@ -88265,7 +88702,7 @@ function installMethod$1(target, replacement) {
|
|
|
88265
88702
|
*
|
|
88266
88703
|
* @param target - 目标。
|
|
88267
88704
|
*/
|
|
88268
|
-
function restoreMethod$
|
|
88705
|
+
function restoreMethod$2(target) {
|
|
88269
88706
|
try {
|
|
88270
88707
|
if (target.descriptor === void 0) Reflect.deleteProperty(target.holder, target.name);
|
|
88271
88708
|
else Object.defineProperty(target.holder, target.name, target.descriptor);
|
|
@@ -88279,7 +88716,7 @@ function restoreMethod$1(target) {
|
|
|
88279
88716
|
* @param name - 方法名。
|
|
88280
88717
|
* @returns 是否已经包过。
|
|
88281
88718
|
*/
|
|
88282
|
-
function alreadyPatched$
|
|
88719
|
+
function alreadyPatched$2(patched, holder, name) {
|
|
88283
88720
|
return patched.get(holder)?.has(name) === true;
|
|
88284
88721
|
}
|
|
88285
88722
|
/**
|
|
@@ -88289,12 +88726,245 @@ function alreadyPatched$1(patched, holder, name) {
|
|
|
88289
88726
|
* @param holder - 方法宿主。
|
|
88290
88727
|
* @param name - 方法名。
|
|
88291
88728
|
*/
|
|
88292
|
-
function markPatched$
|
|
88729
|
+
function markPatched$2(patched, holder, name) {
|
|
88293
88730
|
const names = patched.get(holder);
|
|
88294
88731
|
if (names === void 0) patched.set(holder, /* @__PURE__ */ new Set([name]));
|
|
88295
88732
|
else names.add(name);
|
|
88296
88733
|
}
|
|
88297
88734
|
//#endregion
|
|
88735
|
+
//#region src/host/settled-job-guard.ts
|
|
88736
|
+
function isRecord$12(value) {
|
|
88737
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
88738
|
+
}
|
|
88739
|
+
function serviceOf(ctx, name) {
|
|
88740
|
+
const get = ctx?.get;
|
|
88741
|
+
if (typeof get !== "function") return void 0;
|
|
88742
|
+
try {
|
|
88743
|
+
return get.call(ctx, name);
|
|
88744
|
+
} catch {
|
|
88745
|
+
return;
|
|
88746
|
+
}
|
|
88747
|
+
}
|
|
88748
|
+
function isTerminalStatus(value) {
|
|
88749
|
+
return value === "completed" || value === "failed" || value === "killed";
|
|
88750
|
+
}
|
|
88751
|
+
function isUnknownJobError(error, id) {
|
|
88752
|
+
if (!(error instanceof Error)) return false;
|
|
88753
|
+
return error.message === `unknown job ${id}`;
|
|
88754
|
+
}
|
|
88755
|
+
/**
|
|
88756
|
+
* 通过 `agents` 或 `sessions` 服务定位 `caller` 对应的会话对象。
|
|
88757
|
+
*/
|
|
88758
|
+
function resolveCallerSession(ctx, caller) {
|
|
88759
|
+
const agents = serviceOf(ctx, "agents");
|
|
88760
|
+
if (typeof agents?.get === "function") try {
|
|
88761
|
+
const agent = agents.get(caller);
|
|
88762
|
+
if (agent?.session !== void 0 && agent.session !== null) return agent.session;
|
|
88763
|
+
} catch {}
|
|
88764
|
+
const sessions = serviceOf(ctx, "sessions");
|
|
88765
|
+
if (typeof sessions?.get === "function") try {
|
|
88766
|
+
const session = sessions.get(caller);
|
|
88767
|
+
if (session !== void 0 && session !== null) return session;
|
|
88768
|
+
} catch {
|
|
88769
|
+
return;
|
|
88770
|
+
}
|
|
88771
|
+
}
|
|
88772
|
+
/**
|
|
88773
|
+
* 从调用方自己的持久会话日志里倒序查找已落盘的 `job/settled` 记录。
|
|
88774
|
+
*
|
|
88775
|
+
* 严格校验 `owner === caller`:无主或归属其它会话的任务绝不跨会话恢复。
|
|
88776
|
+
*/
|
|
88777
|
+
function findSettledJobInSession(session, jobId, caller) {
|
|
88778
|
+
if (!isRecord$12(session)) return void 0;
|
|
88779
|
+
const snapshot = session["snapshotEvents"];
|
|
88780
|
+
if (typeof snapshot !== "function") return void 0;
|
|
88781
|
+
let events;
|
|
88782
|
+
try {
|
|
88783
|
+
events = snapshot.call(session);
|
|
88784
|
+
} catch {
|
|
88785
|
+
return;
|
|
88786
|
+
}
|
|
88787
|
+
if (!Array.isArray(events)) return void 0;
|
|
88788
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
88789
|
+
const event = events[index];
|
|
88790
|
+
if (!isRecord$12(event) || event["type"] !== "job/settled") continue;
|
|
88791
|
+
const data = event["data"];
|
|
88792
|
+
if (!isRecord$12(data)) continue;
|
|
88793
|
+
if (data["jobId"] !== jobId) continue;
|
|
88794
|
+
if (data["owner"] !== caller) return void 0;
|
|
88795
|
+
const kind = typeof data["kind"] === "string" && data["kind"].length > 0 ? data["kind"] : "job";
|
|
88796
|
+
const label = typeof data["label"] === "string" && data["label"].length > 0 ? data["label"] : jobId;
|
|
88797
|
+
const status = isTerminalStatus(data["status"]) ? data["status"] : "killed";
|
|
88798
|
+
const detail = typeof data["detail"] === "string" && data["detail"].length > 0 ? data["detail"] : void 0;
|
|
88799
|
+
const startedAt = typeof data["startedAt"] === "number" && Number.isFinite(data["startedAt"]) ? data["startedAt"] : 0;
|
|
88800
|
+
const finishedAt = typeof data["finishedAt"] === "number" && Number.isFinite(data["finishedAt"]) ? data["finishedAt"] : void 0;
|
|
88801
|
+
return {
|
|
88802
|
+
id: jobId,
|
|
88803
|
+
kind,
|
|
88804
|
+
label,
|
|
88805
|
+
owner: caller,
|
|
88806
|
+
status,
|
|
88807
|
+
...detail === void 0 ? {} : { detail },
|
|
88808
|
+
startedAt,
|
|
88809
|
+
...finishedAt === void 0 ? {} : { finishedAt },
|
|
88810
|
+
output: {
|
|
88811
|
+
total: 0,
|
|
88812
|
+
earliest: 0
|
|
88813
|
+
}
|
|
88814
|
+
};
|
|
88815
|
+
}
|
|
88816
|
+
}
|
|
88817
|
+
function resolveMethodTarget$1(service, name) {
|
|
88818
|
+
if (typeof service !== "object" || service === null) return void 0;
|
|
88819
|
+
const own = service;
|
|
88820
|
+
if (Object.prototype.hasOwnProperty.call(own, name)) {
|
|
88821
|
+
const original = own[name];
|
|
88822
|
+
if (typeof original !== "function") return void 0;
|
|
88823
|
+
return {
|
|
88824
|
+
holder: own,
|
|
88825
|
+
name,
|
|
88826
|
+
original,
|
|
88827
|
+
descriptor: Object.getOwnPropertyDescriptor(own, name)
|
|
88828
|
+
};
|
|
88829
|
+
}
|
|
88830
|
+
const proto = Object.getPrototypeOf(service);
|
|
88831
|
+
if (proto === null || proto === Object.prototype || proto === Function.prototype) return void 0;
|
|
88832
|
+
const descriptor = Object.getOwnPropertyDescriptor(proto, name);
|
|
88833
|
+
if (descriptor === void 0 || typeof descriptor.value !== "function") return void 0;
|
|
88834
|
+
return {
|
|
88835
|
+
holder: proto,
|
|
88836
|
+
name,
|
|
88837
|
+
original: descriptor.value,
|
|
88838
|
+
descriptor
|
|
88839
|
+
};
|
|
88840
|
+
}
|
|
88841
|
+
function installMethod$1(target, replacement) {
|
|
88842
|
+
try {
|
|
88843
|
+
Object.defineProperty(target.holder, target.name, {
|
|
88844
|
+
configurable: target.descriptor?.configurable ?? true,
|
|
88845
|
+
enumerable: target.descriptor?.enumerable ?? false,
|
|
88846
|
+
writable: target.descriptor?.writable ?? true,
|
|
88847
|
+
value: replacement
|
|
88848
|
+
});
|
|
88849
|
+
return true;
|
|
88850
|
+
} catch {
|
|
88851
|
+
return false;
|
|
88852
|
+
}
|
|
88853
|
+
}
|
|
88854
|
+
function restoreMethod$1(target) {
|
|
88855
|
+
try {
|
|
88856
|
+
if (target.descriptor !== void 0) Object.defineProperty(target.holder, target.name, target.descriptor);
|
|
88857
|
+
else delete target.holder[target.name];
|
|
88858
|
+
} catch {}
|
|
88859
|
+
}
|
|
88860
|
+
function alreadyPatched$1(patched, holder, name) {
|
|
88861
|
+
return patched.get(holder)?.has(name) === true;
|
|
88862
|
+
}
|
|
88863
|
+
function markPatched$1(patched, holder, name) {
|
|
88864
|
+
let set = patched.get(holder);
|
|
88865
|
+
if (set === void 0) {
|
|
88866
|
+
set = /* @__PURE__ */ new Set();
|
|
88867
|
+
patched.set(holder, set);
|
|
88868
|
+
}
|
|
88869
|
+
set.add(name);
|
|
88870
|
+
}
|
|
88871
|
+
/**
|
|
88872
|
+
* 安装「已结算后台任务跨回合幂等守卫」。
|
|
88873
|
+
*
|
|
88874
|
+
* @param ctx - 宿主上下文。
|
|
88875
|
+
* @returns 守卫句柄。
|
|
88876
|
+
*/
|
|
88877
|
+
function installSettledJobGuard(ctx) {
|
|
88878
|
+
const restores = [];
|
|
88879
|
+
const patchedMethods = /* @__PURE__ */ new WeakMap();
|
|
88880
|
+
let closed = false;
|
|
88881
|
+
const recoverForCaller = (rawId, rawCaller) => {
|
|
88882
|
+
if (closed) return void 0;
|
|
88883
|
+
if (typeof rawId !== "string" || rawId.length === 0) return void 0;
|
|
88884
|
+
if (typeof rawCaller !== "string" || rawCaller.length === 0) return void 0;
|
|
88885
|
+
return findSettledJobInSession(resolveCallerSession(ctx, rawCaller), rawId, rawCaller);
|
|
88886
|
+
};
|
|
88887
|
+
const patchSync = (jobs, methodName, onRecovered) => {
|
|
88888
|
+
const target = resolveMethodTarget$1(jobs, methodName);
|
|
88889
|
+
if (target === void 0 || alreadyPatched$1(patchedMethods, target.holder, target.name)) return;
|
|
88890
|
+
const original = target.original;
|
|
88891
|
+
const wrapped = function(...args) {
|
|
88892
|
+
const receiver = this ?? jobs;
|
|
88893
|
+
try {
|
|
88894
|
+
return original.call(receiver, ...args);
|
|
88895
|
+
} catch (error) {
|
|
88896
|
+
const id = typeof args[0] === "string" ? args[0] : "";
|
|
88897
|
+
if (id !== "" && isUnknownJobError(error, id)) {
|
|
88898
|
+
const recovered = recoverForCaller(id, args[1]);
|
|
88899
|
+
if (recovered !== void 0) return onRecovered(recovered);
|
|
88900
|
+
}
|
|
88901
|
+
throw error;
|
|
88902
|
+
}
|
|
88903
|
+
};
|
|
88904
|
+
if (!installMethod$1(target, wrapped)) return;
|
|
88905
|
+
markPatched$1(patchedMethods, target.holder, target.name);
|
|
88906
|
+
restores.push(() => {
|
|
88907
|
+
restoreMethod$1(target);
|
|
88908
|
+
});
|
|
88909
|
+
};
|
|
88910
|
+
const patchWait = (jobs) => {
|
|
88911
|
+
const target = resolveMethodTarget$1(jobs, "wait");
|
|
88912
|
+
if (target === void 0 || alreadyPatched$1(patchedMethods, target.holder, target.name)) return;
|
|
88913
|
+
const original = target.original;
|
|
88914
|
+
const wrapped = async function(...args) {
|
|
88915
|
+
const receiver = this ?? jobs;
|
|
88916
|
+
try {
|
|
88917
|
+
return await original.call(receiver, ...args);
|
|
88918
|
+
} catch (error) {
|
|
88919
|
+
const id = typeof args[0] === "string" ? args[0] : "";
|
|
88920
|
+
if (id !== "" && isUnknownJobError(error, id)) {
|
|
88921
|
+
const recovered = recoverForCaller(id, args[2]);
|
|
88922
|
+
if (recovered !== void 0) return recovered;
|
|
88923
|
+
}
|
|
88924
|
+
throw error;
|
|
88925
|
+
}
|
|
88926
|
+
};
|
|
88927
|
+
if (!installMethod$1(target, wrapped)) return;
|
|
88928
|
+
markPatched$1(patchedMethods, target.holder, target.name);
|
|
88929
|
+
restores.push(() => {
|
|
88930
|
+
restoreMethod$1(target);
|
|
88931
|
+
});
|
|
88932
|
+
};
|
|
88933
|
+
const wrap = (jobs) => {
|
|
88934
|
+
if (jobs === void 0) return;
|
|
88935
|
+
patchSync(jobs, "kill", () => "already-finished");
|
|
88936
|
+
patchSync(jobs, "get", (view) => view);
|
|
88937
|
+
patchSync(jobs, "read", (view) => ({
|
|
88938
|
+
chunks: [],
|
|
88939
|
+
lossy: false,
|
|
88940
|
+
job: view
|
|
88941
|
+
}));
|
|
88942
|
+
patchWait(jobs);
|
|
88943
|
+
};
|
|
88944
|
+
const immediate = serviceOf(ctx, "jobs");
|
|
88945
|
+
if (immediate !== void 0) wrap(immediate);
|
|
88946
|
+
else {
|
|
88947
|
+
const inject = ctx?.inject;
|
|
88948
|
+
if (typeof inject === "function") {
|
|
88949
|
+
let wrapped = false;
|
|
88950
|
+
try {
|
|
88951
|
+
inject.call(ctx, ["jobs"], (scope) => {
|
|
88952
|
+
if (wrapped || closed) return;
|
|
88953
|
+
wrapped = true;
|
|
88954
|
+
wrap(serviceOf(scope, "jobs"));
|
|
88955
|
+
});
|
|
88956
|
+
} catch {}
|
|
88957
|
+
}
|
|
88958
|
+
}
|
|
88959
|
+
return { dispose() {
|
|
88960
|
+
if (closed) return;
|
|
88961
|
+
closed = true;
|
|
88962
|
+
for (const restore of restores.splice(0)) try {
|
|
88963
|
+
restore();
|
|
88964
|
+
} catch {}
|
|
88965
|
+
} };
|
|
88966
|
+
}
|
|
88967
|
+
//#endregion
|
|
88298
88968
|
//#region src/host/team-policy-cache-guard.ts
|
|
88299
88969
|
/**
|
|
88300
88970
|
* 「Agent Teams 策略段前缀缓存守卫」—— 把内置 `team:policy` 段从 system 里摘掉,
|
|
@@ -88634,7 +89304,7 @@ const GUARDED_EVENTS = [
|
|
|
88634
89304
|
* @returns 可销毁的句柄。
|
|
88635
89305
|
*/
|
|
88636
89306
|
function installCompactionPolicyGuard(ctx, options = {}) {
|
|
88637
|
-
const host = isRecord$
|
|
89307
|
+
const host = isRecord$11(ctx) ? ctx : void 0;
|
|
88638
89308
|
const provider = options.provider ?? "kimi-code";
|
|
88639
89309
|
const defaults = {
|
|
88640
89310
|
provider,
|
|
@@ -88709,9 +89379,9 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88709
89379
|
* @param source - agent、header 或配置对象。
|
|
88710
89380
|
*/
|
|
88711
89381
|
const observeFrom = (source) => {
|
|
88712
|
-
if (!isRecord$
|
|
89382
|
+
if (!isRecord$11(source)) return;
|
|
88713
89383
|
const session = source["session"];
|
|
88714
|
-
if (isRecord$
|
|
89384
|
+
if (isRecord$11(session)) {
|
|
88715
89385
|
const requestHeader = session["requestHeader"];
|
|
88716
89386
|
if (typeof requestHeader === "function") {
|
|
88717
89387
|
let header;
|
|
@@ -88720,16 +89390,16 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88720
89390
|
} catch {
|
|
88721
89391
|
header = void 0;
|
|
88722
89392
|
}
|
|
88723
|
-
if (isRecord$
|
|
89393
|
+
if (isRecord$11(header)) {
|
|
88724
89394
|
const config = header["config"];
|
|
88725
|
-
if (isRecord$
|
|
89395
|
+
if (isRecord$11(config)) observe(readString(config["provider"]), readString(config["model"]));
|
|
88726
89396
|
}
|
|
88727
89397
|
}
|
|
88728
89398
|
}
|
|
88729
89399
|
const optionsField = source["options"];
|
|
88730
|
-
if (isRecord$
|
|
89400
|
+
if (isRecord$11(optionsField)) observe(readString(optionsField["provider"]), readString(optionsField["model"]));
|
|
88731
89401
|
const config = source["config"];
|
|
88732
|
-
if (isRecord$
|
|
89402
|
+
if (isRecord$11(config)) observe(readString(config["provider"]), readString(config["model"]));
|
|
88733
89403
|
};
|
|
88734
89404
|
/**
|
|
88735
89405
|
* 读一个字符串字段。
|
|
@@ -88759,10 +89429,10 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88759
89429
|
* @returns 是否真的改写了。
|
|
88760
89430
|
*/
|
|
88761
89431
|
const patchEngine = (engine) => {
|
|
88762
|
-
if (disposed || !isRecord$
|
|
89432
|
+
if (disposed || !isRecord$11(engine)) return false;
|
|
88763
89433
|
if (patched.has(engine)) return false;
|
|
88764
89434
|
const config = engine["config"];
|
|
88765
|
-
if (!isRecord$
|
|
89435
|
+
if (!isRecord$11(config)) return false;
|
|
88766
89436
|
const originalPolicies = config["modelPolicies"];
|
|
88767
89437
|
if (!Array.isArray(originalPolicies)) return false;
|
|
88768
89438
|
const originalConfig = config;
|
|
@@ -88832,7 +89502,7 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88832
89502
|
let nextArgs = args;
|
|
88833
89503
|
if (name === "summarize") {
|
|
88834
89504
|
const input = args[0];
|
|
88835
|
-
if (isRecord$
|
|
89505
|
+
if (isRecord$11(input)) {
|
|
88836
89506
|
const messages = input["messages"];
|
|
88837
89507
|
if (Array.isArray(messages)) {
|
|
88838
89508
|
const replaced = replaceCompactionInstruction(messages);
|
|
@@ -88867,12 +89537,12 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88867
89537
|
* @returns 是否改写了新引擎。
|
|
88868
89538
|
*/
|
|
88869
89539
|
const patchStoreEntry = (entry) => {
|
|
88870
|
-
if (!isRecord$
|
|
89540
|
+
if (!isRecord$11(entry)) return false;
|
|
88871
89541
|
const record = entry;
|
|
88872
89542
|
const name = readServiceName(record);
|
|
88873
89543
|
if (name !== void 0 && name !== "compaction") return false;
|
|
88874
89544
|
const value = record.value ?? record.impl;
|
|
88875
|
-
if (isRecord$
|
|
89545
|
+
if (isRecord$11(value)) {
|
|
88876
89546
|
if (patchEngine(value)) return true;
|
|
88877
89547
|
const nested = value["engine"];
|
|
88878
89548
|
if (nested !== void 0) return patchEngine(nested);
|
|
@@ -88887,11 +89557,11 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88887
89557
|
* @returns 本次新改写的引擎数。
|
|
88888
89558
|
*/
|
|
88889
89559
|
const scanStore = (target) => {
|
|
88890
|
-
if (!isRecord$
|
|
89560
|
+
if (!isRecord$11(target)) return 0;
|
|
88891
89561
|
const reflect = target["reflect"];
|
|
88892
|
-
if (!isRecord$
|
|
89562
|
+
if (!isRecord$11(reflect)) return 0;
|
|
88893
89563
|
const store = reflect["store"];
|
|
88894
|
-
if (!isRecord$
|
|
89564
|
+
if (!isRecord$11(store)) return 0;
|
|
88895
89565
|
const services = store;
|
|
88896
89566
|
let count = 0;
|
|
88897
89567
|
for (const key of Object.getOwnPropertySymbols(services)) if (patchStoreEntry(services[key])) count += 1;
|
|
@@ -88905,12 +89575,12 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88905
89575
|
* @returns 是否改写了新引擎。
|
|
88906
89576
|
*/
|
|
88907
89577
|
const patchServiceFrom = (target, name) => {
|
|
88908
|
-
if (!isRecord$
|
|
89578
|
+
if (!isRecord$11(target)) return false;
|
|
88909
89579
|
const get = target["get"];
|
|
88910
89580
|
if (typeof get !== "function") return false;
|
|
88911
89581
|
try {
|
|
88912
89582
|
const service = get.call(target, name);
|
|
88913
|
-
if (!isRecord$
|
|
89583
|
+
if (!isRecord$11(service)) return false;
|
|
88914
89584
|
if (patchEngine(service)) return true;
|
|
88915
89585
|
const nested = service["engine"];
|
|
88916
89586
|
return nested === void 0 ? false : patchEngine(nested);
|
|
@@ -88953,7 +89623,7 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88953
89623
|
try {
|
|
88954
89624
|
for (const arg of args) {
|
|
88955
89625
|
observeFrom(arg);
|
|
88956
|
-
if (isRecord$
|
|
89626
|
+
if (isRecord$11(arg)) observeFrom(arg["agent"]);
|
|
88957
89627
|
}
|
|
88958
89628
|
scanAndPatch();
|
|
88959
89629
|
const agentCtx = findAgentContext(args);
|
|
@@ -88992,9 +89662,9 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88992
89662
|
function readServiceName(record) {
|
|
88993
89663
|
if (typeof record.name === "string") return record.name;
|
|
88994
89664
|
const impl = record.impl;
|
|
88995
|
-
if (isRecord$
|
|
89665
|
+
if (isRecord$11(impl) && typeof impl["name"] === "string") return impl["name"];
|
|
88996
89666
|
const value = record.value;
|
|
88997
|
-
if (isRecord$
|
|
89667
|
+
if (isRecord$11(value) && typeof value["name"] === "string") return value["name"];
|
|
88998
89668
|
}
|
|
88999
89669
|
/**
|
|
89000
89670
|
* 从一次事件派发的参数里找出 agent 的上下文。
|
|
@@ -89006,7 +89676,7 @@ function findAgentContext(args) {
|
|
|
89006
89676
|
for (const arg of args) {
|
|
89007
89677
|
const direct = readContext(arg);
|
|
89008
89678
|
if (direct !== void 0) return direct;
|
|
89009
|
-
if (isRecord$
|
|
89679
|
+
if (isRecord$11(arg)) {
|
|
89010
89680
|
const nested = readContext(arg["agent"]);
|
|
89011
89681
|
if (nested !== void 0) return nested;
|
|
89012
89682
|
}
|
|
@@ -89019,10 +89689,10 @@ function findAgentContext(args) {
|
|
|
89019
89689
|
* @returns 上下文;不像时返回 `undefined`。
|
|
89020
89690
|
*/
|
|
89021
89691
|
function readContext(value) {
|
|
89022
|
-
if (!isRecord$
|
|
89692
|
+
if (!isRecord$11(value)) return void 0;
|
|
89023
89693
|
const ctx = value["ctx"];
|
|
89024
|
-
if (!isRecord$
|
|
89025
|
-
if (typeof ctx["get"] === "function" || isRecord$
|
|
89694
|
+
if (!isRecord$11(ctx)) return void 0;
|
|
89695
|
+
if (typeof ctx["get"] === "function" || isRecord$11(ctx["reflect"])) return ctx;
|
|
89026
89696
|
}
|
|
89027
89697
|
/**
|
|
89028
89698
|
* 订阅一个事件,优先用 `prepend: true`。
|
|
@@ -89062,7 +89732,7 @@ function subscribe(host, event, listener) {
|
|
|
89062
89732
|
* @param value - 任意值。
|
|
89063
89733
|
* @returns 是非 null 的对象时为 `true`。
|
|
89064
89734
|
*/
|
|
89065
|
-
function isRecord$
|
|
89735
|
+
function isRecord$11(value) {
|
|
89066
89736
|
return typeof value === "object" && value !== null;
|
|
89067
89737
|
}
|
|
89068
89738
|
/**
|
|
@@ -89162,449 +89832,6 @@ function markPatched(patched, holder, name) {
|
|
|
89162
89832
|
if (names === void 0) patched.set(holder, /* @__PURE__ */ new Set([name]));
|
|
89163
89833
|
else names.add(name);
|
|
89164
89834
|
}
|
|
89165
|
-
//#endregion
|
|
89166
|
-
//#region src/host/dispatch-execution-guard.ts
|
|
89167
|
-
/**
|
|
89168
|
-
* 「调度执行守卫」——在**执行期**拦住两类越界调用。
|
|
89169
|
-
*
|
|
89170
|
-
* ## 为什么需要它
|
|
89171
|
-
*
|
|
89172
|
-
* 调度模式(dispatch preset)里主控与子代理跑在同一进程、同一套工具注册面上,
|
|
89173
|
-
* 于是有两件事会悄悄坏掉:
|
|
89174
|
-
*
|
|
89175
|
-
* 1. **子代理越权调用主控专用工具**。`ask_user_question`、`exit_plan_mode`、
|
|
89176
|
-
* `create_goal` 这些是**主控的**决定口:让子代理自己问用户、自己进/出计划模式、
|
|
89177
|
-
* 自己建目标,都会把「一个决定」拆成两个决定——子代理问完,用户答了,主控却
|
|
89178
|
-
* 不知道问过什么。子代理本来就该把未决问题**带回**主控,而不是自己去问。
|
|
89179
|
-
* 2. **等待子代理期间空等**。子代理还在跑的时候,主控用 `sleep` 空转,既烧 token
|
|
89180
|
-
* 又错过通知到达的那一刻。正确做法是**结束这一轮**,让内置的子代理完成通知把
|
|
89181
|
-
* 它叫醒(R-W)。
|
|
89182
|
-
*
|
|
89183
|
-
* ## 零 Kimi Code 缓存漂移
|
|
89184
|
-
*
|
|
89185
|
-
* 守卫**只**用 `ctx.tools.guard(exec => …)` 这一条执行期接缝:
|
|
89186
|
-
*
|
|
89187
|
-
* - 不包 `tools.definitions`,不包 `tools.register`,不听
|
|
89188
|
-
* `system-prompt/assemble`——工具声明面(`tools:sdk` 段与顶层工具 schema)
|
|
89189
|
-
* 保持逐字节恒定,Kimi Code 的前缀缓存不会因为这个守卫重建一次。
|
|
89190
|
-
* - 拦截发生在**调用执行时**,模型看到的工具表完全没变,所以「看得见」与
|
|
89191
|
-
* 「叫得动」仍然被拆开:工具照常出现在表里,只是越界的调用被拒。
|
|
89192
|
-
*
|
|
89193
|
-
* ## 判定从哪来
|
|
89194
|
-
*
|
|
89195
|
-
* 两条判定都走**结构探测**,不 import 任何 harness 代次专属的类型:
|
|
89196
|
-
*
|
|
89197
|
-
* - 「你是不是子代理」:先看**持久会话血缘**(`session.header.origin ===
|
|
89198
|
-
* 'subagent'`),再看宿主活着的**存活根**(`agents.roots()`)。两条都是
|
|
89199
|
-
* 读得着的既有事实,不新增任何状态。
|
|
89200
|
-
* - 「你还有没有在跑的子代理」:依次问 `subagents.list` 与 `agents.list`,
|
|
89201
|
-
* 看有没有 `status === 'running'` 的直接子代。
|
|
89202
|
-
*
|
|
89203
|
-
* @module @eddyskywalker/dsh-chatgpt-subscription/host/dispatch-execution-guard
|
|
89204
|
-
*/
|
|
89205
|
-
/**
|
|
89206
|
-
* 子代理**不得**直接调用的主控专用工具。
|
|
89207
|
-
*
|
|
89208
|
-
* 这七个都是「决定口」或「交付口」,不是「干活口」:
|
|
89209
|
-
*
|
|
89210
|
-
* - `ask_user_question` / `exit_plan_mode` / `enter_plan_mode` /
|
|
89211
|
-
* `leave_plan_mode`:计划与提问的决定权在主控;
|
|
89212
|
-
* - `create_goal` / `update_goal`:目标由主控持有;
|
|
89213
|
-
* - `present`:交付口由主控掌握。
|
|
89214
|
-
*
|
|
89215
|
-
* 子代理遇到需要决定的地方,正确动作是**把问题带回主控**,让主控去调这些工具。
|
|
89216
|
-
*/
|
|
89217
|
-
const DEFAULT_DELEGATED_BLOCKED_TOOLS = Object.freeze([
|
|
89218
|
-
"ask_user_question",
|
|
89219
|
-
"exit_plan_mode",
|
|
89220
|
-
"enter_plan_mode",
|
|
89221
|
-
"leave_plan_mode",
|
|
89222
|
-
"create_goal",
|
|
89223
|
-
"update_goal",
|
|
89224
|
-
"present"
|
|
89225
|
-
]);
|
|
89226
|
-
/**
|
|
89227
|
-
* 承载「等待」语义的 shell 工具。
|
|
89228
|
-
*
|
|
89229
|
-
* 这三个是本包与宿主都会用到的 shell 入口:它们的 `command` 参数里可能藏着
|
|
89230
|
-
* `sleep`。空等只在**确实有在跑的子代理**时才是问题(有子代理时应当结束这一
|
|
89231
|
-
* 轮等通知),没有子代理时 `sleep 1` 只是普通命令,不该拦。
|
|
89232
|
-
*/
|
|
89233
|
-
const DEFAULT_SHELL_TOOLS = Object.freeze([
|
|
89234
|
-
"bash",
|
|
89235
|
-
"pwsh",
|
|
89236
|
-
"win_bash"
|
|
89237
|
-
]);
|
|
89238
|
-
/** 一次执行里被判定为「纯等待」的命令形态。 */
|
|
89239
|
-
const SLEEP_COMMAND_PATTERN = /^(?:sleep\s+\d+(?:\.\d+)?[smhd]?|Start-Sleep\s+(?:-(?:Seconds|Milliseconds|s|m)\s+)?\d+(?:\.\d+)?|timeout(?:\.exe)?\s+(?:\/t\s+)?\d+(?:\s+\/nobreak)?|ping(?:\.exe)?\s+-(?:n|c)\s+\d+\s+(?:127\.0\.0\.1|localhost)(?:\s+>|\s*$).*)$/i;
|
|
89240
|
-
/** 无害的空转语句(回显、真、冒号)。 */
|
|
89241
|
-
const NOOP_COMMAND_PATTERN = /^(?:echo\b.*|Write-Host\b.*|Write-Output\b.*|true|:)$/;
|
|
89242
|
-
/** 注释行。 */
|
|
89243
|
-
const COMMENT_COMMAND_PATTERN = /^#/;
|
|
89244
|
-
/**
|
|
89245
|
-
* 读宿主上下文上「直接注入」的 running-child 判定回调。
|
|
89246
|
-
*
|
|
89247
|
-
* 这一步必须**try/catch**:真实 Cordis 的上下文代理对任何没有 inject 的属性直读
|
|
89248
|
-
* 都当场抛 `cannot get property "..." without inject`,一次读失败不该让守卫在
|
|
89249
|
-
* 每次工具调用上抛错。
|
|
89250
|
-
*
|
|
89251
|
-
* @param ctx - 宿主上下文。
|
|
89252
|
-
* @returns 注入的回调;没有时为 undefined。
|
|
89253
|
-
*/
|
|
89254
|
-
function injectedHasRunningChildren(ctx) {
|
|
89255
|
-
if (!isRecord$11(ctx)) return void 0;
|
|
89256
|
-
let injected;
|
|
89257
|
-
try {
|
|
89258
|
-
injected = ctx["hasRunningChildren"];
|
|
89259
|
-
} catch {
|
|
89260
|
-
return;
|
|
89261
|
-
}
|
|
89262
|
-
return typeof injected === "function" ? injected : void 0;
|
|
89263
|
-
}
|
|
89264
|
-
/**
|
|
89265
|
-
* 判断一个值是不是可读的记录对象。
|
|
89266
|
-
*
|
|
89267
|
-
* @param value - 候选值。
|
|
89268
|
-
* @returns 是记录对象时为 true。
|
|
89269
|
-
*/
|
|
89270
|
-
function isRecord$11(value) {
|
|
89271
|
-
return typeof value === "object" && value !== null;
|
|
89272
|
-
}
|
|
89273
|
-
/**
|
|
89274
|
-
* 从宿主上下文里读一个**可选**服务。
|
|
89275
|
-
*
|
|
89276
|
-
* 一律走 `ctx.get()`:没写进 `inject` 的服务名不能当属性读,真实 Cordis 会当场
|
|
89277
|
-
* 抛 `cannot get property "..." without inject`,整个插件降级。读不到就是读不到,
|
|
89278
|
-
* 守卫据此放行,绝不因此让插件挂不上。
|
|
89279
|
-
*
|
|
89280
|
-
* @param ctx - 宿主上下文。
|
|
89281
|
-
* @param name - 服务名。
|
|
89282
|
-
* @returns 服务实例;不存在或读取抛错时为 undefined。
|
|
89283
|
-
*/
|
|
89284
|
-
function readService(ctx, name) {
|
|
89285
|
-
const reader = ctx?.get;
|
|
89286
|
-
if (typeof reader !== "function") return void 0;
|
|
89287
|
-
try {
|
|
89288
|
-
return reader.call(ctx, name);
|
|
89289
|
-
} catch {
|
|
89290
|
-
return;
|
|
89291
|
-
}
|
|
89292
|
-
}
|
|
89293
|
-
/**
|
|
89294
|
-
* 读一个宿主上下文里的工具注册面。
|
|
89295
|
-
*
|
|
89296
|
-
* @param ctx - 宿主上下文。
|
|
89297
|
-
* @returns 带 `guard` 接缝的注册面;没有时为 undefined。
|
|
89298
|
-
*/
|
|
89299
|
-
function toolsOf$2(ctx) {
|
|
89300
|
-
if (!isRecord$11(ctx)) return void 0;
|
|
89301
|
-
let tools;
|
|
89302
|
-
try {
|
|
89303
|
-
tools = ctx["tools"];
|
|
89304
|
-
} catch {
|
|
89305
|
-
tools = void 0;
|
|
89306
|
-
}
|
|
89307
|
-
if (!isRecord$11(tools)) tools = readService(ctx, "tools");
|
|
89308
|
-
return isRecord$11(tools) ? tools : void 0;
|
|
89309
|
-
}
|
|
89310
|
-
/**
|
|
89311
|
-
* 读一条记录的 `id`。
|
|
89312
|
-
*
|
|
89313
|
-
* @param value - 候选记录。
|
|
89314
|
-
* @returns id 字符串;没有时为 undefined。
|
|
89315
|
-
*/
|
|
89316
|
-
function idOf(value) {
|
|
89317
|
-
if (!isRecord$11(value)) return void 0;
|
|
89318
|
-
const id = value["id"];
|
|
89319
|
-
return typeof id === "string" ? id : void 0;
|
|
89320
|
-
}
|
|
89321
|
-
/**
|
|
89322
|
-
* 读一条会话记录头里的 `id`。
|
|
89323
|
-
*
|
|
89324
|
-
* @param agent - 候选 agent。
|
|
89325
|
-
* @returns 会话 id;没有时为 undefined。
|
|
89326
|
-
*/
|
|
89327
|
-
function sessionIdOf$1(agent) {
|
|
89328
|
-
if (!isRecord$11(agent)) return void 0;
|
|
89329
|
-
const session = agent["session"];
|
|
89330
|
-
if (!isRecord$11(session)) return void 0;
|
|
89331
|
-
const header = session["header"];
|
|
89332
|
-
return idOf(header);
|
|
89333
|
-
}
|
|
89334
|
-
/**
|
|
89335
|
-
* 这个调用方是不是**子代理**。
|
|
89336
|
-
*
|
|
89337
|
-
* 判定分两级,先看能独立成立的持久事实,再看宿主当前活着的存活根:
|
|
89338
|
-
*
|
|
89339
|
-
* 1. **持久会话血缘**:`session.header.origin === 'subagent'`。这是子代理会话
|
|
89340
|
-
* 创建时就写下的血缘,跨宿主代次都在,不依赖任何服务是否挂载。
|
|
89341
|
-
* 2. **存活根判定**:宿主提供 `agents.roots()` 时,一个**不在**存活根集合里的
|
|
89342
|
-
* agent 就是别人的孩子。先核对**存活**(`agents.get(id) === agent`):不是
|
|
89343
|
-
* 那个 id 当前登记的存活 agent,说明这个调用方已经过期或已被顶替——判它是不是
|
|
89344
|
-
* 子代理没有意义,放行。
|
|
89345
|
-
*
|
|
89346
|
-
* 宿主没有 `agents` 服务(或老代没有 `roots`)时,判不了就**放行**:把一个
|
|
89347
|
-
* 读不出来的身份当成子代理去拦,会拦掉主控自己的正常调用。
|
|
89348
|
-
*
|
|
89349
|
-
* @param agent - 调用方 agent。
|
|
89350
|
-
* @param ctx - 宿主上下文(可选;用于读 `agents` 服务)。
|
|
89351
|
-
* @returns 是子代理时为 true。
|
|
89352
|
-
*/
|
|
89353
|
-
function isDelegatedCaller(agent, ctx) {
|
|
89354
|
-
if (!isRecord$11(agent)) return false;
|
|
89355
|
-
const session = agent["session"];
|
|
89356
|
-
if (isRecord$11(session)) {
|
|
89357
|
-
const header = session["header"];
|
|
89358
|
-
if (isRecord$11(header) && header["origin"] === "subagent") return true;
|
|
89359
|
-
}
|
|
89360
|
-
const agents = readService(ctx, "agents");
|
|
89361
|
-
if (!isRecord$11(agents)) return false;
|
|
89362
|
-
const roots = rootsOf(agents);
|
|
89363
|
-
if (roots === void 0) return false;
|
|
89364
|
-
const id = idOf(agent);
|
|
89365
|
-
if (typeof id === "string" && typeof agents["get"] === "function") {
|
|
89366
|
-
let live;
|
|
89367
|
-
try {
|
|
89368
|
-
live = agents["get"].call(agents, id);
|
|
89369
|
-
} catch {
|
|
89370
|
-
live = void 0;
|
|
89371
|
-
}
|
|
89372
|
-
if (live !== agent) return false;
|
|
89373
|
-
}
|
|
89374
|
-
return !roots.includes(agent);
|
|
89375
|
-
}
|
|
89376
|
-
/**
|
|
89377
|
-
* 读宿主存活根集合。
|
|
89378
|
-
*
|
|
89379
|
-
* @param agents - `agents` 服务。
|
|
89380
|
-
* @returns 存活根数组;服务没有 `roots` 或读取抛错时为 undefined。
|
|
89381
|
-
*/
|
|
89382
|
-
function rootsOf(agents) {
|
|
89383
|
-
const roots = agents["roots"];
|
|
89384
|
-
if (typeof roots !== "function") return void 0;
|
|
89385
|
-
try {
|
|
89386
|
-
const listed = roots.call(agents);
|
|
89387
|
-
return Array.isArray(listed) ? listed : void 0;
|
|
89388
|
-
} catch {
|
|
89389
|
-
return;
|
|
89390
|
-
}
|
|
89391
|
-
}
|
|
89392
|
-
/**
|
|
89393
|
-
* 判断一条命令是不是**纯等待**。
|
|
89394
|
-
*
|
|
89395
|
-
* 判据:整条命令**按分隔符切开后**,至少有一条是 sleep/wait,而**每一条**都是
|
|
89396
|
-
* sleep/wait 或者无害的空转(回显、真、冒号、注释)。只要有一条在做真事
|
|
89397
|
-
* (`sleep 1 && npm test`、`git status`、`node …`),整条命令就不是纯等待——
|
|
89398
|
-
* 这类命令**必须放行**,否则守卫会拦掉正当的后台工作。
|
|
89399
|
-
*
|
|
89400
|
-
* @param command - 候选命令。
|
|
89401
|
-
* @returns 是纯等待时为 true。
|
|
89402
|
-
*/
|
|
89403
|
-
function isPureSleepCommand(command) {
|
|
89404
|
-
if (typeof command !== "string") return false;
|
|
89405
|
-
const trimmed = command.trim();
|
|
89406
|
-
if (trimmed.length === 0) return false;
|
|
89407
|
-
const statements = trimmed.split(/;|&&|\n/).map((statement) => statement.trim()).filter((statement) => statement.length > 0);
|
|
89408
|
-
if (statements.length === 0) return false;
|
|
89409
|
-
let sawWait = false;
|
|
89410
|
-
for (const statement of statements) {
|
|
89411
|
-
if (SLEEP_COMMAND_PATTERN.test(statement)) {
|
|
89412
|
-
sawWait = true;
|
|
89413
|
-
continue;
|
|
89414
|
-
}
|
|
89415
|
-
if (!isNoopStatement(statement)) return false;
|
|
89416
|
-
}
|
|
89417
|
-
return sawWait;
|
|
89418
|
-
}
|
|
89419
|
-
/**
|
|
89420
|
-
* 判断一条语句是不是无害的空转。
|
|
89421
|
-
*
|
|
89422
|
-
* @param statement - 候选语句。
|
|
89423
|
-
* @returns 是空转时为 true。
|
|
89424
|
-
*/
|
|
89425
|
-
function isNoopStatement(statement) {
|
|
89426
|
-
return NOOP_COMMAND_PATTERN.test(statement) || COMMENT_COMMAND_PATTERN.test(statement);
|
|
89427
|
-
}
|
|
89428
|
-
/**
|
|
89429
|
-
* 这个调用方当前**还有没有在跑的子代理**。
|
|
89430
|
-
*
|
|
89431
|
-
* 两条宿主探测,任何一条给出答案就算数:
|
|
89432
|
-
*
|
|
89433
|
-
* 1. `subagents.list(agent, 'children')`(老代退化成 `subagents.list(agent)`):
|
|
89434
|
-
* 直接子代里有没有 `status === 'running'` 的。
|
|
89435
|
-
* 2. `agents.list()`:活着且 `status === 'running'`、并且 `parent` 就是这个
|
|
89436
|
-
* 调用方的那些 agent。
|
|
89437
|
-
*
|
|
89438
|
-
* 宿主提供 `hasRunningChildren` 回调时以它为准(直接注入口,见
|
|
89439
|
-
* {@link DispatchExecutionGuardOptions.hasRunningChildren})。
|
|
89440
|
-
*
|
|
89441
|
-
* @param agent - 调用方 agent。
|
|
89442
|
-
* @param ctx - 宿主上下文(可选;用于读 `subagents` / `agents` 服务)。
|
|
89443
|
-
* @returns 有在跑的子代理时为 true。
|
|
89444
|
-
*/
|
|
89445
|
-
function hasRunningChildSubagent(agent, ctx) {
|
|
89446
|
-
if (!isRecord$11(agent)) return false;
|
|
89447
|
-
const injected = injectedHasRunningChildren(ctx);
|
|
89448
|
-
if (injected !== void 0) try {
|
|
89449
|
-
return injected(agent) === true;
|
|
89450
|
-
} catch {
|
|
89451
|
-
return false;
|
|
89452
|
-
}
|
|
89453
|
-
const subagents = readService(ctx, "subagents");
|
|
89454
|
-
if (isRecord$11(subagents) && typeof subagents["list"] === "function") {
|
|
89455
|
-
if (entriesOf(callList(subagents["list"], subagents, agent)).some((entry) => entry["status"] === "running")) return true;
|
|
89456
|
-
}
|
|
89457
|
-
const agents = readService(ctx, "agents");
|
|
89458
|
-
if (isRecord$11(agents) && typeof agents["list"] === "function") {
|
|
89459
|
-
const listed = callList(agents["list"], agents, agent, false);
|
|
89460
|
-
const parentIds = /* @__PURE__ */ new Set();
|
|
89461
|
-
const ownId = idOf(agent);
|
|
89462
|
-
if (ownId !== void 0) parentIds.add(ownId);
|
|
89463
|
-
const headerId = sessionIdOf$1(agent);
|
|
89464
|
-
if (headerId !== void 0) parentIds.add(headerId);
|
|
89465
|
-
if (entriesOf(listed).some((entry) => entry["status"] === "running" && typeof entry["parent"] === "string" && parentIds.has(entry["parent"]))) return true;
|
|
89466
|
-
}
|
|
89467
|
-
return false;
|
|
89468
|
-
}
|
|
89469
|
-
/**
|
|
89470
|
-
* 调用一个「列出子代」的宿主方法。
|
|
89471
|
-
*
|
|
89472
|
-
* 先试带 scope 的形态(`list(agent, 'children')`),老代只认 `list(agent)`,
|
|
89473
|
-
* 再老一代的 `agents.list()` 不接参数——三种都试,谁先成功用谁。
|
|
89474
|
-
*
|
|
89475
|
-
* @param fn - 宿主方法。
|
|
89476
|
-
* @param self - 调用宿主。
|
|
89477
|
-
* @param agent - 调用方 agent。
|
|
89478
|
-
* @param scoped - 是否先试带 scope 的形态。
|
|
89479
|
-
* @returns 宿主返回值;全部失败时为 undefined。
|
|
89480
|
-
*/
|
|
89481
|
-
function callList(fn, self, agent, scoped = true) {
|
|
89482
|
-
if (typeof fn !== "function") return void 0;
|
|
89483
|
-
const call = fn;
|
|
89484
|
-
const attempts = scoped ? [
|
|
89485
|
-
[agent, "children"],
|
|
89486
|
-
[agent],
|
|
89487
|
-
[]
|
|
89488
|
-
] : [
|
|
89489
|
-
[],
|
|
89490
|
-
[agent],
|
|
89491
|
-
[agent, "children"]
|
|
89492
|
-
];
|
|
89493
|
-
for (const args of attempts) try {
|
|
89494
|
-
const listed = call.apply(self, args);
|
|
89495
|
-
if (listed !== void 0) return listed;
|
|
89496
|
-
} catch {}
|
|
89497
|
-
}
|
|
89498
|
-
/**
|
|
89499
|
-
* 从宿主返回值里取出「条目数组」。
|
|
89500
|
-
*
|
|
89501
|
-
* 宿主可能直接给数组,也可能给一个包着数组的记录(`children` / `agents`)。
|
|
89502
|
-
*
|
|
89503
|
-
* @param listed - 宿主返回值。
|
|
89504
|
-
* @returns 条目数组;取不到时是空数组。
|
|
89505
|
-
*/
|
|
89506
|
-
function entriesOf(listed) {
|
|
89507
|
-
if (Array.isArray(listed)) return listed.filter(isRecord$11);
|
|
89508
|
-
if (!isRecord$11(listed)) return [];
|
|
89509
|
-
const entries = [];
|
|
89510
|
-
for (const key of [
|
|
89511
|
-
"children",
|
|
89512
|
-
"agents",
|
|
89513
|
-
"entries",
|
|
89514
|
-
"list"
|
|
89515
|
-
]) {
|
|
89516
|
-
const candidate = listed[key];
|
|
89517
|
-
if (!Array.isArray(candidate)) continue;
|
|
89518
|
-
for (const entry of candidate) if (isRecord$11(entry)) entries.push(entry);
|
|
89519
|
-
}
|
|
89520
|
-
return entries;
|
|
89521
|
-
}
|
|
89522
|
-
/**
|
|
89523
|
-
* 解析「调度执行守卫」当前是否启用。
|
|
89524
|
-
*
|
|
89525
|
-
* 沿 volatile 活引用取当前值,所以设置保存后立刻生效。缺省、非法值、读取抛错都
|
|
89526
|
-
* 按**开启**处理:守卫是保护,不是功能开关,读失败不该把保护关掉。
|
|
89527
|
-
*
|
|
89528
|
-
* @param config - 插件配置(活引用或普通值)。
|
|
89529
|
-
* @returns 是否启用。
|
|
89530
|
-
*/
|
|
89531
|
-
function resolveDispatchExecutionGuardEnabled(config) {
|
|
89532
|
-
const field = config?.dispatchExecutionGuard;
|
|
89533
|
-
if (field === void 0 || field === null) return true;
|
|
89534
|
-
if (typeof field === "object" && typeof field.get === "function") try {
|
|
89535
|
-
return field.get() !== false;
|
|
89536
|
-
} catch {
|
|
89537
|
-
return true;
|
|
89538
|
-
}
|
|
89539
|
-
return field !== false;
|
|
89540
|
-
}
|
|
89541
|
-
/**
|
|
89542
|
-
* 子代理越权调用时的拒绝文案。
|
|
89543
|
-
*
|
|
89544
|
-
* 文案要**可执行**:光说「不许调」模型只会换个花样再试一次,所以这里写清楚
|
|
89545
|
-
* 它该做什么——把未决问题带回主控,并带上报告状态。
|
|
89546
|
-
*
|
|
89547
|
-
* @param toolName - 被拦下的工具名。
|
|
89548
|
-
* @returns 拒绝理由。
|
|
89549
|
-
*/
|
|
89550
|
-
function delegatedDenial(toolName) {
|
|
89551
|
-
return `DELEGATED_CALLER: "${toolName}" is a dispatch-level tool and a delegated subagent must not call it directly. Report back to the dispatcher instead: include status: "hand_back" or status: "blocked" and the unresolved question or decision in your report, and let the dispatcher act on it.`;
|
|
89552
|
-
}
|
|
89553
|
-
/**
|
|
89554
|
-
* 子代理还在跑时用 sleep 空等的拒绝文案。
|
|
89555
|
-
*
|
|
89556
|
-
* @returns 拒绝理由。
|
|
89557
|
-
*/
|
|
89558
|
-
function activeChildSleepDenial() {
|
|
89559
|
-
return "ACTIVE_CHILD_SLEEP_FORBIDDEN: a child subagent is still running, so sleeping to wait for it is not allowed. End your turn now and let the built-in subagent completion notification wake you.";
|
|
89560
|
-
}
|
|
89561
|
-
/**
|
|
89562
|
-
* 装一台「调度执行守卫」。
|
|
89563
|
-
*
|
|
89564
|
-
* 只用 `ctx.tools.guard()` 这一条执行期接缝:工具声明面(`tools:sdk` 段与顶层
|
|
89565
|
-
* 工具 schema)一个字节都不改,Kimi Code 的前缀缓存不会因为这个守卫重建。
|
|
89566
|
-
*
|
|
89567
|
-
* @param ctx - 宿主上下文。
|
|
89568
|
-
* @param options - 守卫选项。
|
|
89569
|
-
* @returns 注销守卫的函数;宿主没有 `guard` 接缝时是一个空操作。
|
|
89570
|
-
*/
|
|
89571
|
-
function installDispatchExecutionGuard(ctx, options = {}) {
|
|
89572
|
-
const tools = toolsOf$2(ctx);
|
|
89573
|
-
const register = tools?.guard;
|
|
89574
|
-
if (typeof register !== "function") return () => void 0;
|
|
89575
|
-
const enabled = options.enabled ?? (() => true);
|
|
89576
|
-
const delegatedBlocked = new Set(DEFAULT_DELEGATED_BLOCKED_TOOLS);
|
|
89577
|
-
const shellTools = new Set(DEFAULT_SHELL_TOOLS);
|
|
89578
|
-
const hasRunningChildren = options.hasRunningChildren;
|
|
89579
|
-
const guard = (execution) => {
|
|
89580
|
-
if (!isEnabled(enabled)) return void 0;
|
|
89581
|
-
const toolName = typeof execution?.name === "string" ? execution.name : void 0;
|
|
89582
|
-
if (toolName === void 0) return void 0;
|
|
89583
|
-
const agent = execution?.agent;
|
|
89584
|
-
if (delegatedBlocked.has(toolName) && isDelegatedCaller(agent, ctx)) return delegatedDenial(toolName);
|
|
89585
|
-
if (shellTools.has(toolName)) {
|
|
89586
|
-
const args = isRecord$11(execution?.arguments) ? execution.arguments : void 0;
|
|
89587
|
-
if (!(args?.["run_in_background"] === true) && isPureSleepCommand(args?.["command"])) {
|
|
89588
|
-
if (hasRunningChildren !== void 0 ? hasRunningChildren(agent) === true : hasRunningChildSubagent(agent, ctx)) return activeChildSleepDenial();
|
|
89589
|
-
}
|
|
89590
|
-
}
|
|
89591
|
-
};
|
|
89592
|
-
const dispose = register.call(tools, guard);
|
|
89593
|
-
return typeof dispose === "function" ? dispose : () => void 0;
|
|
89594
|
-
}
|
|
89595
|
-
/**
|
|
89596
|
-
* 读一次开关。读失败按**开启**处理:保护不该因为一次读失败而失效。
|
|
89597
|
-
*
|
|
89598
|
-
* @param enabled - 开关读取函数。
|
|
89599
|
-
* @returns 是否启用。
|
|
89600
|
-
*/
|
|
89601
|
-
function isEnabled(enabled) {
|
|
89602
|
-
try {
|
|
89603
|
-
return enabled() !== false;
|
|
89604
|
-
} catch {
|
|
89605
|
-
return true;
|
|
89606
|
-
}
|
|
89607
|
-
}
|
|
89608
89835
|
const ID_SCHEMA = z.string().min(1).max(64).regex(/^[A-Za-z0-9._:-]+$/);
|
|
89609
89836
|
const TASK_REFERENCE_SCHEMA = z.string().min(1).max(160);
|
|
89610
89837
|
const BOUNDARY_SCHEMA = z.string().min(1).max(120);
|
|
@@ -92408,6 +92635,7 @@ const RENAMED_PACKAGES = /* @__PURE__ */ new Map([["@deepseek-ai/dsh-workflow-wo
|
|
|
92408
92635
|
*/
|
|
92409
92636
|
const OPTIONALLY_ABSENT_PACKAGES = [
|
|
92410
92637
|
"@deepseek-ai/dsh-tool-present",
|
|
92638
|
+
"@deepseek-ai/dsh-tool-subagent-control/list-agents",
|
|
92411
92639
|
"@eddyskywalker/dsh-chatgpt-subscription/plan-mode-pipeline",
|
|
92412
92640
|
"@eddyskywalker/dsh-chatgpt-subscription/plan-mode",
|
|
92413
92641
|
"@eddyskywalker/dsh-chatgpt-subscription/tool-result-pruner"
|
|
@@ -92470,12 +92698,20 @@ function candidatePackageRoots(entryScript = process.argv[1]) {
|
|
|
92470
92698
|
} catch {}
|
|
92471
92699
|
return [...roots];
|
|
92472
92700
|
}
|
|
92701
|
+
/** The package-name portion of a bare package or package-subpath specifier. */
|
|
92702
|
+
function packageNameOf(specifier) {
|
|
92703
|
+
return specifier.split("/").slice(0, specifier.startsWith("@") ? 2 : 1).join("/");
|
|
92704
|
+
}
|
|
92473
92705
|
/**
|
|
92474
92706
|
* Whether a package or exported subpath is installed in any candidate node_modules tree.
|
|
92475
92707
|
* A subpath needs its own exact `exports` key; the package root alone is not enough.
|
|
92708
|
+
*
|
|
92709
|
+
* The nearest manifest on each Node resolution chain is authoritative. Looking
|
|
92710
|
+
* farther out after that manifest rejects a subpath would let an unrelated old
|
|
92711
|
+
* installation resurrect an export the running package deliberately removed.
|
|
92476
92712
|
*/
|
|
92477
92713
|
function packageInstalled(specifier, roots = candidatePackageRoots()) {
|
|
92478
|
-
const pkg =
|
|
92714
|
+
const pkg = packageNameOf(specifier);
|
|
92479
92715
|
const subpath = specifier.slice(pkg.length);
|
|
92480
92716
|
for (const root of roots) {
|
|
92481
92717
|
let dir = root;
|
|
@@ -92485,9 +92721,9 @@ function packageInstalled(specifier, roots = candidatePackageRoots()) {
|
|
|
92485
92721
|
if (subpath === "") return true;
|
|
92486
92722
|
try {
|
|
92487
92723
|
const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
92488
|
-
|
|
92724
|
+
return manifest.exports !== void 0 && Object.prototype.hasOwnProperty.call(manifest.exports, `.${subpath}`);
|
|
92489
92725
|
} catch {
|
|
92490
|
-
|
|
92726
|
+
return false;
|
|
92491
92727
|
}
|
|
92492
92728
|
}
|
|
92493
92729
|
const parent = dirname(dir);
|
|
@@ -92498,20 +92734,72 @@ function packageInstalled(specifier, roots = candidatePackageRoots()) {
|
|
|
92498
92734
|
return false;
|
|
92499
92735
|
}
|
|
92500
92736
|
/**
|
|
92501
|
-
*
|
|
92502
|
-
*
|
|
92503
|
-
*
|
|
92504
|
-
|
|
92737
|
+
* Packages the preset intentionally loads from the plugin's own dependency
|
|
92738
|
+
* closure rather than the harness installation. Every other harness row must
|
|
92739
|
+
* resolve where the registry mounts it, not merely beside this plugin.
|
|
92740
|
+
*/
|
|
92741
|
+
const PLUGIN_RESOLVED_PACKAGES = ["@eddyskywalker/dsh-chatgpt-subscription", "@deepseek-ai/dsh-tool-executor-native"];
|
|
92742
|
+
/** Whether `candidate` is `root` itself or one of its descendants. */
|
|
92743
|
+
function pathInside(root, candidate) {
|
|
92744
|
+
const rel = relative(root, candidate);
|
|
92745
|
+
return rel === "" || rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel);
|
|
92746
|
+
}
|
|
92747
|
+
/**
|
|
92748
|
+
* Whether a plugin-side resolution points into the package the harness's own
|
|
92749
|
+
* entry script reaches. Walking ancestors mirrors Node's node_modules lookup;
|
|
92750
|
+
* the CLI commonly sits in `bin/`, beside rather than inside node_modules.
|
|
92751
|
+
*/
|
|
92752
|
+
function resolvedFromHarness(resolved, entryDir, specifier) {
|
|
92753
|
+
if (typeof resolved !== "string") return false;
|
|
92754
|
+
let path;
|
|
92755
|
+
try {
|
|
92756
|
+
path = fileURLToPath(resolved);
|
|
92757
|
+
} catch {
|
|
92758
|
+
return false;
|
|
92759
|
+
}
|
|
92760
|
+
const pkg = packageNameOf(specifier);
|
|
92761
|
+
let dir = entryDir;
|
|
92762
|
+
for (;;) {
|
|
92763
|
+
if (pathInside(join(dir, "node_modules", pkg), path)) return true;
|
|
92764
|
+
const parent = dirname(dir);
|
|
92765
|
+
if (parent === dir) return false;
|
|
92766
|
+
dir = parent;
|
|
92767
|
+
}
|
|
92768
|
+
}
|
|
92769
|
+
/**
|
|
92770
|
+
* Resolve against the installation that will actually mount the preset.
|
|
92771
|
+
*
|
|
92772
|
+
* `import.meta.resolve` is based at this plugin, while the harness mounts
|
|
92773
|
+
* runtime-declared preset rows from its own context. A successful plugin-side
|
|
92774
|
+
* resolution is therefore not sufficient for a harness package: an old copy in
|
|
92775
|
+
* the profile tree must not override the running harness's missing export.
|
|
92776
|
+
* Plugin-owned rows and the plugin-borne native executor are the deliberate
|
|
92777
|
+
* exceptions. With no harness entry, retain the legacy local probe behavior.
|
|
92778
|
+
*/
|
|
92779
|
+
function resolvesFromInstallation(specifier, entryScript, resolveFromPlugin) {
|
|
92780
|
+
const entryDir = harnessEntryDir(entryScript);
|
|
92781
|
+
if (entryDir !== void 0 && packageInstalled(specifier, [entryDir])) return true;
|
|
92782
|
+
let resolved;
|
|
92783
|
+
let didResolve = false;
|
|
92784
|
+
if (resolveFromPlugin !== void 0) try {
|
|
92785
|
+
resolved = resolveFromPlugin(specifier);
|
|
92786
|
+
didResolve = true;
|
|
92787
|
+
} catch {}
|
|
92788
|
+
if (entryDir === void 0) {
|
|
92789
|
+
if (didResolve) return true;
|
|
92790
|
+
return packageInstalled(specifier, candidatePackageRoots(entryScript));
|
|
92791
|
+
}
|
|
92792
|
+
if (didResolve && PLUGIN_RESOLVED_PACKAGES.includes(packageNameOf(specifier))) return true;
|
|
92793
|
+
return didResolve && resolvedFromHarness(resolved, entryDir, specifier);
|
|
92794
|
+
}
|
|
92795
|
+
/**
|
|
92796
|
+
* Whether a bare specifier resolves in the installation that mounts presets.
|
|
92505
92797
|
* @param specifier - bare package specifier.
|
|
92506
92798
|
* @returns whether the specifier resolves.
|
|
92507
92799
|
*/
|
|
92508
92800
|
function resolvesFromHere(specifier) {
|
|
92509
|
-
const
|
|
92510
|
-
|
|
92511
|
-
resolve(specifier);
|
|
92512
|
-
return true;
|
|
92513
|
-
} catch {}
|
|
92514
|
-
return packageInstalled(specifier);
|
|
92801
|
+
const resolveFromPlugin = import.meta.resolve;
|
|
92802
|
+
return resolvesFromInstallation(specifier, process.argv[1], resolveFromPlugin);
|
|
92515
92803
|
}
|
|
92516
92804
|
/**
|
|
92517
92805
|
* Point every renamed package name at the spelling this installation ships.
|
|
@@ -92889,23 +93177,16 @@ const DISPATCH_PRESET = {
|
|
|
92889
93177
|
name: "@deepseek-ai/dsh-persona",
|
|
92890
93178
|
config: {
|
|
92891
93179
|
suffix: "Your working directory is {{cwd}}.",
|
|
92892
|
-
prefix: `[Role Identification] If your first user message is a task brief (rather than a direct request from the human user), you are a subagent: the coordinator-facing rules in R0,
|
|
93180
|
+
prefix: `[Role Identification] If your first user message is a task brief (rather than a direct request from the human user), you are a subagent: the coordinator-facing rules in R0, R-G, R1, R2, R4, R5, and R-W do not apply to you. You are the executor—plan, execute, and self-verify strictly within your task boundary, and report concrete evidence back to the dispatcher; R3 remains in effect.
|
|
92893
93181
|
- [Standing Subagent Contract] Unless overridden by the brief, every subagent inherits these standing limits: retry attempts at most 3 total per brief; file edits bounded strictly to the declared Boundary module or files; read, search, verification, and test commands unlimited within that boundary; no per-cycle banking (all limits are single-run task totals, and unused allowance is not banked).
|
|
92894
93182
|
- [Subagent Report Protocol] Every subagent completion report states status: ready | hand_back | blocked | failed | dropped, a summary, and evidence (diffs, test commands and outputs, before/after captures for UI). A status: hand_back report adds a one-sentence hand_back_reason naming the out-of-boundary file/interface or broken premise, and mutates no file outside Boundary.
|
|
92895
93183
|
- [Coordinator-Only Tools] ask_user_question, enter_plan_mode, leave_plan_mode, exit_plan_mode, create_goal, update_goal, and present are coordinator-only: a subagent call is hard-blocked at execution time (DELEGATED_CALLER), while declarations remain visible to preserve the provider’s content-prefix cache. Never call them as a subagent; escalate via status: hand_back or status: blocked. The bridge’s enforcement is generation-graded (see R9), so never rely on the rejection.
|
|
92896
93184
|
- [Dispatch Ledger] Call dispatch_ledger {action:"self"} once before your first delegation — it prints the v2 mandate protocol at the tail of its result — and follow that protocol verbatim for every dispatch, report, and steer.
|
|
92897
93185
|
|
|
92898
93186
|
[Coordinator Identity] You are the Lead & Dispatch Agent: converge requirements, plan architecture, select R1 topology (Lead-Core / Hybrid / Fan-out), orchestrate subagents where ROI is positive, and own final acceptance.
|
|
92899
|
-
[Execution Pipeline] R0
|
|
93187
|
+
[Execution Pipeline] R0 Triage -> (L2) R-G Interview -> R9 Plan -> R1 Topology -> (if delegating: R2 Routing -> R5 Brief -> R-W Wait) -> R6 Acceptance.
|
|
92900
93188
|
|
|
92901
|
-
|
|
92902
|
-
A legacy Agent Teams runtime (pre-#7519) registers spawn_teammate and replaces send_message / list_agents / interrupt_agent with team-scoped variants, leaving spawned subagents unreachable. The current runtime only adds a shared task board (team_task_create and its list/get/update siblings) and reuses this mode's tools.
|
|
92903
|
-
Criterion: whether spawn_teammate exists (PTC: tools.spawn_teammate). Never gate on wait_agent, send_message, list_agents, or interrupt_agent: this mode mounts those itself.
|
|
92904
|
-
- Absent -> Write "Orchestration ready: subagent" and proceed to R0. The board tools stay visible in the PTC SDK whether or not the board is on - frozen declaration, not availability - so confirm with team_task_list before relying on it. When the board is on it is bookkeeping, not a second dispatcher: the dispatch ledger stays the dispatch authority and R5 briefs stay the task contract; publish cross-agent dependencies (blocked_by) and write scopes on one team task per brief, claimed and completed by the child that owns it; never start work because a task is ready, and never reassign a task to skip R6.
|
|
92905
|
-
- Present -> This session runs the legacy runtime and is **not orchestratable**. In order, and nothing else:
|
|
92906
|
-
1. State in one sentence that the legacy runtime shadows the coordination tools and this mode has no degraded path.
|
|
92907
|
-
2. Call ask_user_question once (see R-W) offering: disable the legacy runtime, restart Host, **start a new session**; switch preset; or execute this task directly.
|
|
92908
|
-
3. **Do nothing else** until the user replies: no triage, plan, dispatch, file edits, or workarounds.
|
|
93189
|
+
[Agent Teams Board] A current harness adds exactly one Agent Teams surface beside this mode: the shared task board (team_task_create and its list/get/update siblings). It is bookkeeping, not a second dispatcher. The board tools stay declared whether or not the board is on - frozen declaration, not availability - so confirm with team_task_list before relying on it. When it is on, the dispatch ledger stays the dispatch authority and R5 briefs stay the task contract; publish cross-agent dependencies (blocked_by) and write scopes on one team task per brief, claimed and completed by the child that owns it; never start work because a task is ready, and never reassign a task to skip R6.
|
|
92909
93190
|
|
|
92910
93191
|
## R0 · Complexity Triage (Triage First, Then Choose the Workflow)
|
|
92911
93192
|
Upon receiving a task, determine its tier by semantic impact and uncertainty first, write one line stating "Tier + Rationale", and run the matching workflow:
|
|
@@ -92931,7 +93212,7 @@ L0/L1: execute directly (or 1 subagent for L1). L2: R-G, R9, and R6 are mandator
|
|
|
92931
93212
|
- [Media generation] Generate/revise/retry images directly; delegate complex creative work, never a bare call.
|
|
92932
93213
|
|
|
92933
93214
|
## R2 · Model Routing (Check Availability First, Then Decide How to Dispatch)
|
|
92934
|
-
Check whether list_subagent_models exists
|
|
93215
|
+
Check whether list_subagent_models exists. The tool row and provider/model/reasoning_effort parameters are mounted statically, so they are present even in a session that authorized no route at all. Read that fact instead of inferring it from the tool's output:
|
|
92935
93216
|
- If the output says neither—no authorized-routes block and no "No allowlist is in force" sentence—the annotation is absent and you cannot read the posture. Treat it as [State: Unlisted] for behaviour, but say "unconfirmed" rather than claiming either posture, and never report a route as authorized.
|
|
92936
93217
|
- [State: Listed] Output ends with "Authorized child routes for this Session": enforcement is active.
|
|
92937
93218
|
- The sole source of truth for the allowlist is list_subagent_models: call list_subagent_models({}) to list authorized providers, and call list_subagent_models({ provider }) to list authorized models under that provider; trust its output directly without cross-checking local config files or workspace code (even if upstream tool text says "Catalog membership is advisory", the runtime output is already filtered to this session's allowlist).
|
|
@@ -92947,7 +93228,7 @@ A subagent has full authority to plan, execute, and self-verify within its assig
|
|
|
92947
93228
|
Every task brief covers six elements: Goal / Boundary (which files or modules may be touched) / Constraints / Limits (see below) / Acceptance Criteria / Required Evidence to Report.
|
|
92948
93229
|
- [Compact Delta Brief] Standing default limits and the report schema already live in [Role Identification], so use a Compact Delta Brief by default: state Goal, original file/line Source Pointers (do not paraphrase code into long prose), Module-Interface Boundary, Constraints, Acceptance Criteria, and Required Evidence, and omit repeating standing limits unless overriding them.
|
|
92949
93230
|
- [Limits] When overriding any standing limit, write one line per limit spelling out four things: **what it bounds, in what unit, the cap, and whether it accumulates**. Write explicit caps ("at most 3 attempts", "edits at most 5 files", "test runs: unlimited"), never ranges ("2–5 files"); where an override dimension is left unstated, silence is read as a limit of zero, and a quota that resets per cycle is lost, not banked.
|
|
92950
|
-
- Do not ask the child to restate your rules back as a correctness check; if a limit is genuinely unclear, instruct the child to spend one minimal tool call to verify it. Dispatch independent tasks concurrently in one message (
|
|
93231
|
+
- Do not ask the child to restate your rules back as a correctness check; if a limit is genuinely unclear, instruct the child to spend one minimal tool call to verify it. Dispatch independent tasks concurrently in one message (native calls; use code_run Promise.all for batch filter/MCP) only after the interview has converged.
|
|
92951
93232
|
|
|
92952
93233
|
## R6 · Review & Acceptance
|
|
92953
93234
|
Two layers: subagent self-check -> your independent review (reading diffs, running tests, checking each criterion). The completion notification is a post-hoc signal: it tells you a child stopped, not that the work passed.
|
|
@@ -92976,7 +93257,7 @@ Fallback is a task-scoped, non-session-wide exception for delegated briefs: it c
|
|
|
92976
93257
|
|
|
92977
93258
|
## Anti-Patterns (Any Occurrence Is a Violation)
|
|
92978
93259
|
1. Orchestrating or opening Plan Mode for an L0/L1 task, or before the R-G interview has converged (21. Entering Plan Mode for an L0/L1 task, or before the R-G interview has converged; 22. Using leave_plan_mode to bypass exit_plan_mode approval).
|
|
92979
|
-
2. Switching to teammate vocabulary to keep orchestrating
|
|
93260
|
+
2. Switching to teammate vocabulary to keep orchestrating, or Treating the team task board as a substitute for R1 topology, R2 routing, R5 briefs, R6 acceptance, or R-W waiting (R1, R6).
|
|
92980
93261
|
3. Omitting provider/model under [State: Listed], Second-guessing list_subagent_models output by hunting through local config or source files just to check which subagent models are allowed, or Reporting a route as "authorized", or claiming per-task routing is in force, when the session recorded no allowlist (R2).
|
|
92981
93262
|
4. Writing a task brief with a range where a cap belongs ("2–5 files", "a few attempts"), or Asking a subagent to restate its rules as a correctness check (R0, R5).
|
|
92982
93263
|
5. Running sleep, polling loops, or placeholder long commands to wait, Proactively creating a goal at the start of a task, or Ending with a paragraph of prose to wait for user sign-off instead of calling ask_user_question (R-W).
|
|
@@ -99775,6 +100056,23 @@ function applyToolDelta(entry, state) {
|
|
|
99775
100056
|
const fn = isRecord$3(entry.function) ? entry.function : {};
|
|
99776
100057
|
const out = [];
|
|
99777
100058
|
let call = state.toolCalls.get(wireIndex);
|
|
100059
|
+
const incomingId = asString$1(entry.id);
|
|
100060
|
+
if (call !== void 0 && incomingId !== void 0 && call.id !== `call_${wireIndex}` && incomingId !== call.id) {
|
|
100061
|
+
const closedBlock = {
|
|
100062
|
+
type: "tool-call",
|
|
100063
|
+
id: toToolCallId(call.id),
|
|
100064
|
+
name: call.name,
|
|
100065
|
+
arguments: call.arguments === "" ? "{}" : call.arguments
|
|
100066
|
+
};
|
|
100067
|
+
state.blocks[call.blockIndex] = closedBlock;
|
|
100068
|
+
out.push({
|
|
100069
|
+
type: "block-end",
|
|
100070
|
+
index: call.blockIndex,
|
|
100071
|
+
block: closedBlock
|
|
100072
|
+
});
|
|
100073
|
+
state.toolCalls.delete(wireIndex);
|
|
100074
|
+
call = void 0;
|
|
100075
|
+
}
|
|
99778
100076
|
if (call === void 0) {
|
|
99779
100077
|
out.push(...closeCurrent(state));
|
|
99780
100078
|
call = {
|
|
@@ -100144,6 +100442,30 @@ function messagesAssistantContent(message) {
|
|
|
100144
100442
|
return blocks;
|
|
100145
100443
|
}
|
|
100146
100444
|
/**
|
|
100445
|
+
* Merge neighbouring same-role turns.
|
|
100446
|
+
*
|
|
100447
|
+
* DSH history can hold two user messages in a row (an injected context notice
|
|
100448
|
+
* followed by the real turn) and a tool result is itself a user-role message;
|
|
100449
|
+
* the Messages wire wants one user turn, so consecutive turns of one role are
|
|
100450
|
+
* folded together in order.
|
|
100451
|
+
*/
|
|
100452
|
+
function mergeAnthropicMessages(entries) {
|
|
100453
|
+
const merged = [];
|
|
100454
|
+
for (const entry of entries) {
|
|
100455
|
+
if (entry.content.length === 0) continue;
|
|
100456
|
+
const last = merged[merged.length - 1];
|
|
100457
|
+
if (last !== void 0 && last.role === entry.role) {
|
|
100458
|
+
last.content = [...last.content, ...entry.content];
|
|
100459
|
+
continue;
|
|
100460
|
+
}
|
|
100461
|
+
merged.push({
|
|
100462
|
+
role: entry.role,
|
|
100463
|
+
content: [...entry.content]
|
|
100464
|
+
});
|
|
100465
|
+
}
|
|
100466
|
+
return merged;
|
|
100467
|
+
}
|
|
100468
|
+
/**
|
|
100147
100469
|
* Build one `/v1/messages` body.
|
|
100148
100470
|
*
|
|
100149
100471
|
* `stream: true` is mandatory: the adapter reads every response as SSE, and a
|
|
@@ -100161,13 +100483,12 @@ function buildMessagesRequest(options, request = {}) {
|
|
|
100161
100483
|
const role = isToolResultMessage(message) || message.role !== "assistant" ? "user" : "assistant";
|
|
100162
100484
|
const content = role === "user" ? messagesUserContent(message, images) : messagesAssistantContent(message);
|
|
100163
100485
|
if (content.length === 0) continue;
|
|
100164
|
-
|
|
100165
|
-
if (previous !== void 0 && previous.role === role) previous.content.push(...content);
|
|
100166
|
-
else entries.push({
|
|
100486
|
+
entries.push({
|
|
100167
100487
|
role,
|
|
100168
100488
|
content
|
|
100169
100489
|
});
|
|
100170
100490
|
}
|
|
100491
|
+
const messages = cleanOrphanedToolCalls(mergeAnthropicMessages(entries), mergeAnthropicMessages);
|
|
100171
100492
|
const system = leadingSystemTextRaw(options);
|
|
100172
100493
|
const tools = options.tools ?? [];
|
|
100173
100494
|
const effort = request.effort !== void 0 && (request.efforts ?? []).length > 0 ? request.effort : void 0;
|
|
@@ -100176,7 +100497,7 @@ function buildMessagesRequest(options, request = {}) {
|
|
|
100176
100497
|
model: options.model,
|
|
100177
100498
|
max_tokens: maxTokens,
|
|
100178
100499
|
stream: true,
|
|
100179
|
-
messages
|
|
100500
|
+
messages,
|
|
100180
100501
|
...system === void 0 ? {} : { system },
|
|
100181
100502
|
...tools.length > 0 ? { tools: tools.map((tool) => ({
|
|
100182
100503
|
name: tool.name,
|
|
@@ -103926,6 +104247,10 @@ function apply(ctx, pluginConfig = {}) {
|
|
|
103926
104247
|
const guard = installPtcSdkCacheGuard(ctx);
|
|
103927
104248
|
return () => guard.dispose();
|
|
103928
104249
|
}, "dsh-chatgpt-subscription: PTC SDK cache guard");
|
|
104250
|
+
ctx.effect(() => {
|
|
104251
|
+
const guard = installSettledJobGuard(ctx);
|
|
104252
|
+
return () => guard.dispose();
|
|
104253
|
+
}, "dsh-chatgpt-subscription: settled job guard");
|
|
103929
104254
|
ctx.effect(() => {
|
|
103930
104255
|
const guard = installTeamPolicyCacheGuard(ctx, { enabled: () => resolveTeamPolicyCacheGuardEnabled(pluginConfig) });
|
|
103931
104256
|
return () => guard.dispose();
|