@eddyskywalker/dsh-chatgpt-subscription 0.60.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 +26 -0
- package/lib/client.js.map +1 -1
- package/lib/codemode.js +319 -89
- 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 +905 -574
- package/lib/plan-mode.js +2 -779
- package/lib/progress-updates.js +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/rules.d.ts.map +1 -1
- package/lib/types/host/codemode/transport.d.ts +38 -0
- 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/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/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 +7 -10
- package/presets/dispatch/agent.cordis.yml +4 -11
package/lib/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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
3
|
import { n as PLUGIN_MESSAGE_SOURCE_KIND, r as normalizeGenerateOptions, t as LlmError$1 } from "./llm-compat-u9mor0uu.js";
|
|
4
4
|
import { DEFAULT_SKIP_PROVIDERS, PRUNER_SERVICE_NAME, resolveSkipProviders, shouldSkipPruningForSession } from "./tool-result-pruner.js";
|
|
5
|
-
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";
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
import * as LlmModule from "@deepseek-ai/dsh-llm";
|
|
8
8
|
import { EMPTY_RESPONSE_CODE, HarnessError, LlmAdapter, LlmError, ProviderRequestId, ReasoningEffortId, ToolCallId, attributionHeaders, createUserMessage, errorChain, resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
|
|
@@ -808,7 +808,7 @@ const ROUTE_PREFIX$5 = "/api/dsh-chatgpt-subscription";
|
|
|
808
808
|
* `test/responses-client.test.ts` asserts the two agree, so a release that
|
|
809
809
|
* forgets this constant fails the suite instead of shipping quietly.
|
|
810
810
|
*/
|
|
811
|
-
const PLUGIN_VERSION = "0.
|
|
811
|
+
const PLUGIN_VERSION = "0.61.0";
|
|
812
812
|
const CODEX_CHATGPT_PROVIDER_ID = "codex-chatgpt";
|
|
813
813
|
const CODEX_API_BASE = "https://chatgpt.com/backend-api/codex";
|
|
814
814
|
const CODEX_RESPONSES_URL = `${CODEX_API_BASE}/responses`;
|
|
@@ -1193,6 +1193,7 @@ function resolveCodexModel(model, preferences, live) {
|
|
|
1193
1193
|
inputModalities: [...liveEntry?.inputModalities ?? entry.inputModalities],
|
|
1194
1194
|
context: { contextWindow: configuredContextWindow ?? liveEntry?.contextWindow ?? entry.contextWindow },
|
|
1195
1195
|
...outputReservation(configuredContextWindow ?? liveEntry?.contextWindow ?? entry.contextWindow, codexModelMaxTokens(model)),
|
|
1196
|
+
...codexToolUpdateMode() === void 0 ? {} : { toolUpdate: codexToolUpdateMode() },
|
|
1196
1197
|
reasoning: {
|
|
1197
1198
|
efforts: orderReasoningEfforts(efforts, GPT_56_REASONING_EFFORTS).map((effort) => ({
|
|
1198
1199
|
id: ReasoningEffortId(effort),
|
|
@@ -1203,6 +1204,46 @@ function resolveCodexModel(model, preferences, live) {
|
|
|
1203
1204
|
};
|
|
1204
1205
|
}
|
|
1205
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
|
+
/**
|
|
1206
1247
|
* Resolve the wire capabilities of one model.
|
|
1207
1248
|
*
|
|
1208
1249
|
* The live listing outranks the shipped table, because the backend is the
|
|
@@ -1753,7 +1794,7 @@ function parseListing(payload) {
|
|
|
1753
1794
|
function parseListingEntry$1(value) {
|
|
1754
1795
|
const record = asRecord$20(value);
|
|
1755
1796
|
if (record === void 0) return [];
|
|
1756
|
-
const id = asString$
|
|
1797
|
+
const id = asString$31(record.slug) ?? asString$31(record.id);
|
|
1757
1798
|
if (id === void 0) return [];
|
|
1758
1799
|
const contextWindow = asNumber$8(record.context_window) ?? asNumber$8(record.contextWindow);
|
|
1759
1800
|
const modalities = parseModalities(record.input_modalities);
|
|
@@ -1762,11 +1803,11 @@ function parseListingEntry$1(value) {
|
|
|
1762
1803
|
const fallback = CODEX_MODEL_CATALOG.find((entry) => entry.id === id);
|
|
1763
1804
|
return [{
|
|
1764
1805
|
id,
|
|
1765
|
-
name: asString$
|
|
1806
|
+
name: asString$31(record.display_name) ?? asString$31(record.displayName) ?? fallback?.name ?? id,
|
|
1766
1807
|
contextWindow: contextWindow !== void 0 && contextWindow > 0 ? contextWindow : null,
|
|
1767
1808
|
inputModalities: modalities ?? (fallback ? [...fallback.inputModalities] : ["text"]),
|
|
1768
1809
|
...efforts !== null ? { reasoningEfforts: efforts } : {},
|
|
1769
|
-
defaultReasoningEffort: asString$
|
|
1810
|
+
defaultReasoningEffort: asString$31(record.default_reasoning_level) ?? fallback?.defaultReasoningEffort ?? null,
|
|
1770
1811
|
...useResponsesLite !== void 0 ? { useResponsesLite } : {}
|
|
1771
1812
|
}];
|
|
1772
1813
|
}
|
|
@@ -1774,7 +1815,7 @@ function parseModalities(value) {
|
|
|
1774
1815
|
if (!Array.isArray(value)) return null;
|
|
1775
1816
|
const out = [];
|
|
1776
1817
|
for (const item of value) {
|
|
1777
|
-
const name = asString$
|
|
1818
|
+
const name = asString$31(item);
|
|
1778
1819
|
if (name === "text" || name === "image") out.push(name);
|
|
1779
1820
|
}
|
|
1780
1821
|
return out.length > 0 ? out : null;
|
|
@@ -1789,7 +1830,7 @@ function parseEfforts(value) {
|
|
|
1789
1830
|
if (!Array.isArray(value)) return null;
|
|
1790
1831
|
const out = [];
|
|
1791
1832
|
for (const item of value) {
|
|
1792
|
-
const effort = asString$
|
|
1833
|
+
const effort = asString$31(item) ?? asString$31(asRecord$20(item)?.effort);
|
|
1793
1834
|
if (effort !== void 0 && !out.includes(effort)) out.push(effort);
|
|
1794
1835
|
}
|
|
1795
1836
|
return out.length > 0 ? out : null;
|
|
@@ -1814,7 +1855,7 @@ function accountKeyFor$1(credentials) {
|
|
|
1814
1855
|
function asRecord$20(value) {
|
|
1815
1856
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
1816
1857
|
}
|
|
1817
|
-
function asString$
|
|
1858
|
+
function asString$31(value) {
|
|
1818
1859
|
return typeof value === "string" && value !== "" ? value : void 0;
|
|
1819
1860
|
}
|
|
1820
1861
|
function asNumber$8(value) {
|
|
@@ -8178,7 +8219,7 @@ function sanitizeText$9(text) {
|
|
|
8178
8219
|
function isRecord$64(value) {
|
|
8179
8220
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8180
8221
|
}
|
|
8181
|
-
function asString$
|
|
8222
|
+
function asString$30(value) {
|
|
8182
8223
|
return typeof value === "string" ? value : void 0;
|
|
8183
8224
|
}
|
|
8184
8225
|
function safeJsonParse$9(text) {
|
|
@@ -8208,7 +8249,7 @@ function attachmentOf$5(block) {
|
|
|
8208
8249
|
}
|
|
8209
8250
|
function attachmentLabel$6(block) {
|
|
8210
8251
|
const attachment = isRecord$64(block.attachment) ? block.attachment : void 0;
|
|
8211
|
-
return asString$
|
|
8252
|
+
return asString$30(attachment?.name) || asString$30(attachment?.attachmentId);
|
|
8212
8253
|
}
|
|
8213
8254
|
function collectImageRefs$3(content, refs) {
|
|
8214
8255
|
if (!Array.isArray(content)) return;
|
|
@@ -8345,10 +8386,10 @@ function unavailableImageText$6(block) {
|
|
|
8345
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]`;
|
|
8346
8387
|
}
|
|
8347
8388
|
function imageBlockToPart(block, images) {
|
|
8348
|
-
let data = asString$
|
|
8389
|
+
let data = asString$30(block.data) || asString$30(block.base64);
|
|
8349
8390
|
const source = isRecord$64(block.source) ? block.source : void 0;
|
|
8350
|
-
if (!data && source) data = asString$
|
|
8351
|
-
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";
|
|
8352
8393
|
if (data?.startsWith("data:")) {
|
|
8353
8394
|
const match = data.match(/^data:([^;,]+);base64,(.*)$/s);
|
|
8354
8395
|
if (match) {
|
|
@@ -8422,7 +8463,7 @@ function replayBlockFor$1(message, index) {
|
|
|
8422
8463
|
}
|
|
8423
8464
|
}
|
|
8424
8465
|
function thoughtSignature(part) {
|
|
8425
|
-
return asString$
|
|
8466
|
+
return asString$30(part?.thoughtSignature) || asString$30(part?.thought_signature) || asString$30(part?.thinkingSignature) || asString$30(part?.textSignature);
|
|
8426
8467
|
}
|
|
8427
8468
|
function replayPart(part) {
|
|
8428
8469
|
const copy = { ...part };
|
|
@@ -8521,7 +8562,7 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
|
|
|
8521
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;
|
|
8522
8563
|
const replay = replayBlockFor$1(message, index);
|
|
8523
8564
|
const originalParts = Array.isArray(replay?.parts) ? replay.parts.filter(isRecord$64) : [];
|
|
8524
|
-
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 || ""))) {
|
|
8525
8566
|
parts.push(...originalParts.map(replayPart));
|
|
8526
8567
|
continue;
|
|
8527
8568
|
}
|
|
@@ -8542,7 +8583,7 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
|
|
|
8542
8583
|
const toolId = String(block.id || "");
|
|
8543
8584
|
const toolName = String(block.name || "");
|
|
8544
8585
|
const originalCall = originalParts.find((part) => isRecord$64(part.functionCall));
|
|
8545
|
-
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);
|
|
8546
8587
|
toolCalls.set(toolId, {
|
|
8547
8588
|
name: toolName,
|
|
8548
8589
|
id: wireId
|
|
@@ -8787,7 +8828,7 @@ function processStreamLine$4(line, state) {
|
|
|
8787
8828
|
if (!isRecord$64(chunk)) return [];
|
|
8788
8829
|
const responseData = isRecord$64(chunk.response) ? chunk.response : chunk;
|
|
8789
8830
|
const error = isRecord$64(chunk.error) ? chunk.error : isRecord$64(responseData.error) ? responseData.error : void 0;
|
|
8790
|
-
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");
|
|
8791
8832
|
const candidates = Array.isArray(responseData.candidates) ? responseData.candidates : [];
|
|
8792
8833
|
const candidate = isRecord$64(candidates[0]) ? candidates[0] : void 0;
|
|
8793
8834
|
const content = isRecord$64(candidate?.content) ? candidate.content : void 0;
|
|
@@ -8853,8 +8894,8 @@ function processStreamLine$4(line, state) {
|
|
|
8853
8894
|
if (isRecord$64(part.functionCall)) {
|
|
8854
8895
|
out.push(...closeCurrentBlock(state));
|
|
8855
8896
|
const fc = part.functionCall;
|
|
8856
|
-
const toolName = asString$
|
|
8857
|
-
const toolId = asString$
|
|
8897
|
+
const toolName = asString$30(fc.name) || "";
|
|
8898
|
+
const toolId = asString$30(fc.id) || sanitizeToolCallId("", toolName);
|
|
8858
8899
|
const argsText = JSON.stringify(isRecord$64(fc.args) ? fc.args : {});
|
|
8859
8900
|
const index = state.blocks.length;
|
|
8860
8901
|
const block = {
|
|
@@ -8892,10 +8933,10 @@ function processStreamLine$4(line, state) {
|
|
|
8892
8933
|
}
|
|
8893
8934
|
collectUsage(chunk.usageMetadata, state);
|
|
8894
8935
|
if (responseData !== chunk) collectUsage(responseData.usageMetadata, state);
|
|
8895
|
-
const finishMessage = asString$
|
|
8936
|
+
const finishMessage = asString$30(candidate?.finishMessage);
|
|
8896
8937
|
if (finishMessage) state.finishMessage = finishMessage;
|
|
8897
|
-
const blockReason = asString$
|
|
8898
|
-
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);
|
|
8899
8940
|
if (finishReason) {
|
|
8900
8941
|
state.finishReason = finishReason;
|
|
8901
8942
|
out.push(...closeCurrentBlock(state));
|
|
@@ -8970,7 +9011,7 @@ function closeStream$7(state) {
|
|
|
8970
9011
|
function isRecord$63(value) {
|
|
8971
9012
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8972
9013
|
}
|
|
8973
|
-
function asString$
|
|
9014
|
+
function asString$29(value) {
|
|
8974
9015
|
return typeof value === "string" ? value : void 0;
|
|
8975
9016
|
}
|
|
8976
9017
|
/**
|
|
@@ -9031,7 +9072,7 @@ function attachmentOf$4(block) {
|
|
|
9031
9072
|
}
|
|
9032
9073
|
function attachmentLabel$5(block) {
|
|
9033
9074
|
const attachment = isRecord$63(block.attachment) ? block.attachment : void 0;
|
|
9034
|
-
return asString$
|
|
9075
|
+
return asString$29(attachment?.name) || asString$29(attachment?.attachmentId);
|
|
9035
9076
|
}
|
|
9036
9077
|
function collectImageRefs$2(content, refs) {
|
|
9037
9078
|
if (!Array.isArray(content)) return;
|
|
@@ -9065,9 +9106,9 @@ function base64Length$2(bytes) {
|
|
|
9065
9106
|
* has no resolved map behaves exactly as before.
|
|
9066
9107
|
*/
|
|
9067
9108
|
function inlinePayloadOf$1(block) {
|
|
9068
|
-
let data = asString$
|
|
9109
|
+
let data = asString$29(block.data) || asString$29(block.base64);
|
|
9069
9110
|
const source = isRecord$63(block.source) ? block.source : void 0;
|
|
9070
|
-
if (!data && source) data = asString$
|
|
9111
|
+
if (!data && source) data = asString$29(source.data) || asString$29(source.base64);
|
|
9071
9112
|
if (data?.startsWith("data:")) {
|
|
9072
9113
|
const matched = data.match(/^data:([^;,]+);base64,(.*)$/s);
|
|
9073
9114
|
if (matched) data = matched[2] ?? "";
|
|
@@ -9530,10 +9571,10 @@ function unavailableImageText$5(block) {
|
|
|
9530
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]`;
|
|
9531
9572
|
}
|
|
9532
9573
|
function imageBlockToInline$3(block, images) {
|
|
9533
|
-
let data = asString$
|
|
9574
|
+
let data = asString$29(block.data) || asString$29(block.base64);
|
|
9534
9575
|
const source = isRecord$63(block.source) ? block.source : void 0;
|
|
9535
|
-
if (!data && source) data = asString$
|
|
9536
|
-
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";
|
|
9537
9578
|
if (data?.startsWith("data:")) {
|
|
9538
9579
|
const matched = data.match(/^data:([^;,]+);base64,(.*)$/s);
|
|
9539
9580
|
if (matched) {
|
|
@@ -13110,6 +13151,21 @@ async function buildResponsesPayload(options, attachments, localRawImages = {},
|
|
|
13110
13151
|
});
|
|
13111
13152
|
continue;
|
|
13112
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
|
+
}
|
|
13113
13169
|
const content = await mapContent(message, attachments, options.signal, localRawImages, localImageStats, resolveLocalRawImages);
|
|
13114
13170
|
if (content.length > 0) input.push({
|
|
13115
13171
|
role: message.role,
|
|
@@ -13120,8 +13176,9 @@ async function buildResponsesPayload(options, attachments, localRawImages = {},
|
|
|
13120
13176
|
offloadOldestInputImages(input);
|
|
13121
13177
|
const instructionText = [...instructionParts, localRawImageInstruction(localImageStats)].filter((value) => Boolean(value)).join("\n\n");
|
|
13122
13178
|
const prefix = [];
|
|
13123
|
-
const
|
|
13124
|
-
|
|
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));
|
|
13125
13182
|
if (instructionText !== "") prefix.push(developerMessageItem(instructionText, wire.idNamespace, useResponsesLite));
|
|
13126
13183
|
input.unshift(...prefix);
|
|
13127
13184
|
const toolDeclarations = tools.length > 0 ? tools.map(toolDeclaration) : void 0;
|
|
@@ -13193,6 +13250,87 @@ function additionalToolsItem(tools, idNamespace) {
|
|
|
13193
13250
|
};
|
|
13194
13251
|
}
|
|
13195
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
|
+
/**
|
|
13196
13334
|
* The base instructions as a developer message.
|
|
13197
13335
|
*
|
|
13198
13336
|
* The official client marks the item with the `model.base_instructions` kind, so
|
|
@@ -13579,6 +13717,8 @@ var ResponsesClient = class {
|
|
|
13579
13717
|
const turnKey = turnKeyFor(sessionId);
|
|
13580
13718
|
let currentModel = options.model;
|
|
13581
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"));
|
|
13582
13722
|
let response;
|
|
13583
13723
|
let release;
|
|
13584
13724
|
while (true) {
|
|
@@ -13604,6 +13744,12 @@ var ResponsesClient = class {
|
|
|
13604
13744
|
continue;
|
|
13605
13745
|
}
|
|
13606
13746
|
}
|
|
13747
|
+
if (!strippedToolChanges && statesToolChange(attemptOptions) && error.status === 400) {
|
|
13748
|
+
disableCodexToolUpdate();
|
|
13749
|
+
attemptOptions = withoutCodexToolChanges(attemptOptions);
|
|
13750
|
+
strippedToolChanges = true;
|
|
13751
|
+
continue;
|
|
13752
|
+
}
|
|
13607
13753
|
throw error;
|
|
13608
13754
|
}
|
|
13609
13755
|
}
|
|
@@ -20868,7 +21014,7 @@ function isRecord$61(value) {
|
|
|
20868
21014
|
function asRecord$16(value) {
|
|
20869
21015
|
return isRecord$61(value) ? value : void 0;
|
|
20870
21016
|
}
|
|
20871
|
-
function asString$
|
|
21017
|
+
function asString$28(value) {
|
|
20872
21018
|
if (typeof value === "string" && value.trim() !== "") return value;
|
|
20873
21019
|
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
20874
21020
|
}
|
|
@@ -20881,7 +21027,7 @@ function asNumber$6(value) {
|
|
|
20881
21027
|
}
|
|
20882
21028
|
function firstString$2(record, keys) {
|
|
20883
21029
|
for (const key of keys) {
|
|
20884
|
-
const value = asString$
|
|
21030
|
+
const value = asString$28(record[key]);
|
|
20885
21031
|
if (value !== void 0) return value;
|
|
20886
21032
|
}
|
|
20887
21033
|
}
|
|
@@ -21128,7 +21274,7 @@ function parseCreditBalances(payload, consumed = []) {
|
|
|
21128
21274
|
/** Resolve the plan id the subscription or credits payload reports, when either does. */
|
|
21129
21275
|
function parsePlanId(payloads) {
|
|
21130
21276
|
for (const payload of payloads) {
|
|
21131
|
-
const id = asString$
|
|
21277
|
+
const id = asString$28(deepValue(payload, [
|
|
21132
21278
|
"planId",
|
|
21133
21279
|
"plan_id",
|
|
21134
21280
|
"priceId",
|
|
@@ -21147,7 +21293,7 @@ function parsePlanId(payloads) {
|
|
|
21147
21293
|
*/
|
|
21148
21294
|
function parseSubscriptionStatus(payload) {
|
|
21149
21295
|
const root = asRecord$16(payload) ?? {};
|
|
21150
|
-
return asString$
|
|
21296
|
+
return asString$28(deepValue(asRecord$16(root.data) ?? root, ["status"])) ?? null;
|
|
21151
21297
|
}
|
|
21152
21298
|
/** End of the current billing period, in Unix milliseconds. */
|
|
21153
21299
|
function parseSubscriptionPeriodEnd(payload) {
|
|
@@ -21723,6 +21869,92 @@ function buildModelOptions$2(catalog, enabledModelIds, overrides) {
|
|
|
21723
21869
|
});
|
|
21724
21870
|
}
|
|
21725
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
|
|
21726
21958
|
//#region src/host/command-code/mapper.ts
|
|
21727
21959
|
/**
|
|
21728
21960
|
* Provider-wire mapping for the two Command Code provider endpoints.
|
|
@@ -22279,7 +22511,7 @@ function anthropicAssistantContent$3(message) {
|
|
|
22279
22511
|
* the Messages wire wants one user turn, so consecutive turns of one role are
|
|
22280
22512
|
* folded together in order.
|
|
22281
22513
|
*/
|
|
22282
|
-
function mergeAnthropicMessages$
|
|
22514
|
+
function mergeAnthropicMessages$4(entries) {
|
|
22283
22515
|
const merged = [];
|
|
22284
22516
|
for (const entry of entries) {
|
|
22285
22517
|
if (entry.content.length === 0) continue;
|
|
@@ -22370,7 +22602,7 @@ function buildAnthropicRequest$1(options, images = NO_RESOLVED_IMAGES$3) {
|
|
|
22370
22602
|
return {
|
|
22371
22603
|
model: options.model,
|
|
22372
22604
|
max_tokens: maxTokens,
|
|
22373
|
-
messages: mergeAnthropicMessages$
|
|
22605
|
+
messages: cleanOrphanedToolCalls(mergeAnthropicMessages$4(entries), mergeAnthropicMessages$4),
|
|
22374
22606
|
...system === void 0 ? {} : { system: anthropicSystemBlocks(system) },
|
|
22375
22607
|
...options.temperature === void 0 || budget !== void 0 ? {} : { temperature: options.temperature },
|
|
22376
22608
|
...options.stop && options.stop.length > 0 ? { stop_sequences: options.stop } : {},
|
|
@@ -22672,6 +22904,23 @@ function applyOpenAIToolDelta$1(entry, state) {
|
|
|
22672
22904
|
const fn = isRecord$60(entry.function) ? entry.function : {};
|
|
22673
22905
|
const out = [];
|
|
22674
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
|
+
}
|
|
22675
22924
|
if (call === void 0) {
|
|
22676
22925
|
out.push(...closeCurrent$6(state));
|
|
22677
22926
|
call = {
|
|
@@ -34457,7 +34706,7 @@ function anthropicAssistantContent$2(message, toolCallIds) {
|
|
|
34457
34706
|
* the Messages wire wants one user turn, so consecutive turns of one role are
|
|
34458
34707
|
* folded together in order.
|
|
34459
34708
|
*/
|
|
34460
|
-
function mergeAnthropicMessages$
|
|
34709
|
+
function mergeAnthropicMessages$3(entries) {
|
|
34461
34710
|
const merged = [];
|
|
34462
34711
|
for (const entry of entries) {
|
|
34463
34712
|
if (entry.content.length === 0) continue;
|
|
@@ -34510,7 +34759,7 @@ function buildAnthropicRequest(options, images = NO_RESOLVED_IMAGES$4, media = {
|
|
|
34510
34759
|
type: CLEAR_THINKING_EDIT,
|
|
34511
34760
|
keep: "all"
|
|
34512
34761
|
}] } : void 0;
|
|
34513
|
-
const messages = mergeAnthropicMessages$
|
|
34762
|
+
const messages = cleanOrphanedToolCalls(mergeAnthropicMessages$3(entries), mergeAnthropicMessages$3);
|
|
34514
34763
|
const lastMessage = messages[messages.length - 1];
|
|
34515
34764
|
if (lastMessage !== void 0 && Array.isArray(lastMessage.content) && lastMessage.content.length > 0) {
|
|
34516
34765
|
const lastBlock = lastMessage.content[lastMessage.content.length - 1];
|
|
@@ -34823,6 +35072,23 @@ function applyOpenAIToolDelta(entry, state) {
|
|
|
34823
35072
|
const fn = isRecord$53(entry.function) ? entry.function : {};
|
|
34824
35073
|
const out = [];
|
|
34825
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
|
+
}
|
|
34826
35092
|
if (call === void 0) {
|
|
34827
35093
|
out.push(...closeCurrent$5(state));
|
|
34828
35094
|
call = {
|
|
@@ -36809,7 +37075,7 @@ const KIMI_CODE_REQUEST_IMAGE_MAX_EDGE = 2e3;
|
|
|
36809
37075
|
* @param catalog - live catalog, possibly empty when offline.
|
|
36810
37076
|
* @returns the tool-update mode, or undefined when this route must resend everything.
|
|
36811
37077
|
*/
|
|
36812
|
-
function toolUpdateMode$
|
|
37078
|
+
function toolUpdateMode$2(modelId, catalog) {
|
|
36813
37079
|
if (!dynamicToolsForEntry(modelId, catalog)) return void 0;
|
|
36814
37080
|
if (wireForCatalogEntry(modelId, catalog) !== "openai") return void 0;
|
|
36815
37081
|
const raw = (process.env.DSH_KIMI_CODE_TOOL_UPDATE ?? "").trim().toLowerCase();
|
|
@@ -37212,7 +37478,7 @@ var KimiCodeAdapter = class extends LlmAdapter {
|
|
|
37212
37478
|
id: modelId,
|
|
37213
37479
|
name: entry?.name ?? modelId,
|
|
37214
37480
|
inputModalities: inputModalitiesForEntry(modelId, catalog),
|
|
37215
|
-
...toolUpdateMode$
|
|
37481
|
+
...toolUpdateMode$2(modelId, catalog) === void 0 ? {} : { toolUpdate: toolUpdateMode$2(modelId, catalog) },
|
|
37216
37482
|
context: { contextWindow: this.contextWindowFor(modelId, entry, settings.contextWindowOverrides) },
|
|
37217
37483
|
...efforts.length === 0 ? {} : { reasoning: {
|
|
37218
37484
|
efforts: efforts.map((effort) => ({
|
|
@@ -40865,7 +41131,7 @@ function anthropicAssistantContent$1(message, expectedScope) {
|
|
|
40865
41131
|
* Messages wire wants one user turn, so consecutive turns of one role are folded
|
|
40866
41132
|
* together in order.
|
|
40867
41133
|
*/
|
|
40868
|
-
function mergeAnthropicMessages$
|
|
41134
|
+
function mergeAnthropicMessages$2(entries) {
|
|
40869
41135
|
const merged = [];
|
|
40870
41136
|
for (const entry of entries) {
|
|
40871
41137
|
if (entry.content.length === 0) continue;
|
|
@@ -41087,7 +41353,7 @@ function buildMinimaxRequest(options, images = NO_RESOLVED_IMAGES$2, request = {
|
|
|
41087
41353
|
model: options.model,
|
|
41088
41354
|
max_tokens: maxTokens,
|
|
41089
41355
|
stream: true,
|
|
41090
|
-
messages: mergeAnthropicMessages$
|
|
41356
|
+
messages: cleanOrphanedToolCalls(mergeAnthropicMessages$2(entries), mergeAnthropicMessages$2),
|
|
41091
41357
|
...system === void 0 ? {} : { system: caching ? [{
|
|
41092
41358
|
type: "text",
|
|
41093
41359
|
text: system
|
|
@@ -49630,6 +49896,16 @@ function isClaudeCacheTtl$1(value) {
|
|
|
49630
49896
|
* models (`THINKING_BINDING_CONTROLS_BETA`, pushed when `supportsMidConvoEffort`).
|
|
49631
49897
|
*/
|
|
49632
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";
|
|
49633
49909
|
/** Anthropic protocol revision sent as `anthropic-version`. */
|
|
49634
49910
|
const ANTHROPIC_VERSION$1 = "2023-06-01";
|
|
49635
49911
|
/**
|
|
@@ -51256,6 +51532,7 @@ function claudeBetas(options = {}) {
|
|
|
51256
51532
|
if (options.thinking === true) betas.push(INTERLEAVED_THINKING_BETA);
|
|
51257
51533
|
if (options.thinkingBinding === true) betas.push(THINKING_BINDING_CONTROLS_BETA);
|
|
51258
51534
|
if (options.cacheTtl === "1h") betas.push(EXTENDED_CACHE_TTL_BETA);
|
|
51535
|
+
if (options.toolChanges === true) betas.push(INLINE_TOOLS_BETA);
|
|
51259
51536
|
return betas;
|
|
51260
51537
|
}
|
|
51261
51538
|
/** The `User-Agent` value this line reports for one surface. */
|
|
@@ -53356,10 +53633,85 @@ function wireTool(tool, names) {
|
|
|
53356
53633
|
return {
|
|
53357
53634
|
name: claudeWireToolName(tool.name, names),
|
|
53358
53635
|
description: tool.description ?? "",
|
|
53359
|
-
input_schema: schema
|
|
53636
|
+
input_schema: schema,
|
|
53637
|
+
...tool.deferLoading === true ? { defer_loading: true } : {}
|
|
53360
53638
|
};
|
|
53361
53639
|
}
|
|
53362
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
|
+
/**
|
|
53363
53715
|
* One system-role turn's blocks.
|
|
53364
53716
|
*
|
|
53365
53717
|
* The vendor documents a mid-conversation system message as carrying "a plain
|
|
@@ -53385,6 +53737,17 @@ function claudeSystemContent(message, images) {
|
|
|
53385
53737
|
continue;
|
|
53386
53738
|
}
|
|
53387
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
|
+
}
|
|
53388
53751
|
}
|
|
53389
53752
|
return blocks;
|
|
53390
53753
|
}
|
|
@@ -53588,7 +53951,9 @@ function buildClaudeRequestBody(options, images = NO_RESOLVED_IMAGES$1, request
|
|
|
53588
53951
|
const maxTokens = claudeRequestThinks(options.model, effort, catalog) ? adjustMaxTokensForThinking(baseMax, modelMax, level, request.thinkingBudgets).maxTokens : baseMax;
|
|
53589
53952
|
const { thinking, outputConfig } = claudeThinking(options.model, effort, level, maxTokens, request.thinkingBudgets, catalog);
|
|
53590
53953
|
const entries = [];
|
|
53591
|
-
|
|
53954
|
+
const wire = messagesForTheWire(options);
|
|
53955
|
+
for (let index = 0; index < wire.length; index += 1) {
|
|
53956
|
+
const message = wire[index];
|
|
53592
53957
|
if (message.role === "system") {
|
|
53593
53958
|
entries.push({
|
|
53594
53959
|
role: "system",
|
|
@@ -53596,6 +53961,26 @@ function buildClaudeRequestBody(options, images = NO_RESOLVED_IMAGES$1, request
|
|
|
53596
53961
|
});
|
|
53597
53962
|
continue;
|
|
53598
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
|
+
}
|
|
53599
53984
|
if (isToolResultMessage$5(message)) {
|
|
53600
53985
|
entries.push({
|
|
53601
53986
|
role: "user",
|
|
@@ -53617,8 +54002,8 @@ function buildClaudeRequestBody(options, images = NO_RESOLVED_IMAGES$1, request
|
|
|
53617
54002
|
max_tokens: maxTokens,
|
|
53618
54003
|
stream: true,
|
|
53619
54004
|
system: buildClaudeSystemBlocks(options, caching, cacheTtl),
|
|
53620
|
-
messages: mergeClaudeMessages(entries),
|
|
53621
|
-
...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) } : {},
|
|
53622
54007
|
...thinking === void 0 ? {} : { thinking },
|
|
53623
54008
|
...outputConfig === void 0 ? {} : { output_config: outputConfig },
|
|
53624
54009
|
...temperatureAllowed && options.temperature !== void 0 ? { temperature: options.temperature } : {},
|
|
@@ -55444,6 +55829,33 @@ var ClaudeAccountTokenStore = class {
|
|
|
55444
55829
|
await this.store.saveAccount(credentials, { internalId: this.internalId });
|
|
55445
55830
|
}
|
|
55446
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
|
+
}
|
|
55447
55859
|
var ClaudeAdapter = class ClaudeAdapter extends LlmAdapter {
|
|
55448
55860
|
store;
|
|
55449
55861
|
modelSettings;
|
|
@@ -55559,6 +55971,7 @@ var ClaudeAdapter = class ClaudeAdapter extends LlmAdapter {
|
|
|
55559
55971
|
inputModalities: entry.supportsImage ? ["text", "image"] : ["text"],
|
|
55560
55972
|
context: { contextWindow: contextWindow || 2e5 },
|
|
55561
55973
|
...outputReservation(contextWindow || 2e5, maxOutputTokensFor(modelId, catalog)),
|
|
55974
|
+
...toolUpdateMode$1(modelId) === void 0 ? {} : { toolUpdate: toolUpdateMode$1(modelId) },
|
|
55562
55975
|
...efforts.length === 0 ? {} : { reasoning: {
|
|
55563
55976
|
efforts: efforts.map((effort) => ({
|
|
55564
55977
|
id: ReasoningEffortId(effort),
|
|
@@ -55657,6 +56070,7 @@ var ClaudeAdapter = class ClaudeAdapter extends LlmAdapter {
|
|
|
55657
56070
|
model: requestOptions.model,
|
|
55658
56071
|
thinking,
|
|
55659
56072
|
thinkingBinding: claudeBodyBindsThinking(payload),
|
|
56073
|
+
toolChanges: claudeBodyHasToolChanges(payload),
|
|
55660
56074
|
cacheTtl,
|
|
55661
56075
|
method: "POST"
|
|
55662
56076
|
}),
|
|
@@ -59161,7 +59575,7 @@ function safeStringify(value) {
|
|
|
59161
59575
|
* DSH 历史里可能连续两条 user(注入的上下文提示 + 真正的用户轮),而工具结果本身就是
|
|
59162
59576
|
* user 角色消息;Messages 线要的是一个 user 轮,所以同角色的连续轮按顺序折叠。
|
|
59163
59577
|
*/
|
|
59164
|
-
function mergeAnthropicMessages(entries) {
|
|
59578
|
+
function mergeAnthropicMessages$1(entries) {
|
|
59165
59579
|
const merged = [];
|
|
59166
59580
|
for (const entry of entries) {
|
|
59167
59581
|
if (entry.content.length === 0) continue;
|
|
@@ -59310,7 +59724,7 @@ function buildGlmAnthropicRequest(options, request = {}) {
|
|
|
59310
59724
|
}
|
|
59311
59725
|
const system = glmAnthropicSystemBlocks(options);
|
|
59312
59726
|
const maxTokens = options.maxTokens ?? request.defaultMaxTokens ?? 32768;
|
|
59313
|
-
const merged = mergeAnthropicMessages(entries);
|
|
59727
|
+
const merged = cleanOrphanedToolCalls(mergeAnthropicMessages$1(entries), mergeAnthropicMessages$1);
|
|
59314
59728
|
const lastMessageIndex = merged.length - 1;
|
|
59315
59729
|
const messages = lastMessageIndex < 0 ? merged : merged.map((message, index) => index === lastMessageIndex ? {
|
|
59316
59730
|
...message,
|
|
@@ -60637,6 +61051,23 @@ function applyToolDelta$3(entry, state) {
|
|
|
60637
61051
|
const fn = isRecord$37(entry.function) ? entry.function : {};
|
|
60638
61052
|
const out = [];
|
|
60639
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
|
+
}
|
|
60640
61071
|
if (call === void 0) {
|
|
60641
61072
|
out.push(...closeCurrent$3(state));
|
|
60642
61073
|
call = {
|
|
@@ -65470,6 +65901,23 @@ function applyToolDelta$2(entry, state) {
|
|
|
65470
65901
|
const fn = isRecord$33(entry.function) ? entry.function : void 0;
|
|
65471
65902
|
const out = [];
|
|
65472
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
|
+
}
|
|
65473
65921
|
if (call === void 0) {
|
|
65474
65922
|
const opened = openToolCall$1(state, entry, wireIndex);
|
|
65475
65923
|
out.push(...opened.chunks);
|
|
@@ -71734,6 +72182,7 @@ async function* translate(payloads) {
|
|
|
71734
72182
|
if (!isRecord$26(call)) continue;
|
|
71735
72183
|
const index = Number(call.index ?? 0);
|
|
71736
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;
|
|
71737
72186
|
if (block === void 0) {
|
|
71738
72187
|
block = open("tool-call");
|
|
71739
72188
|
toolBlocks.set(index, block);
|
|
@@ -71745,7 +72194,7 @@ async function* translate(payloads) {
|
|
|
71745
72194
|
}
|
|
71746
72195
|
const fn = isRecord$26(call.function) ? call.function : {};
|
|
71747
72196
|
block.callId = acceptIdentity$1(block.callId, call.id);
|
|
71748
|
-
block.name = acceptIdentity$1(block.name, fn.name);
|
|
72197
|
+
if (block.name === void 0 || block.name === "") block.name = acceptIdentity$1(block.name, fn.name);
|
|
71749
72198
|
const fragment = typeof fn.arguments === "string" ? fn.arguments : "";
|
|
71750
72199
|
block.text += fragment;
|
|
71751
72200
|
yield {
|
|
@@ -78472,6 +78921,23 @@ function applyToolDelta$1(entry, state) {
|
|
|
78472
78921
|
const fn = isRecord$21(entry.function) ? entry.function : void 0;
|
|
78473
78922
|
const out = [];
|
|
78474
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
|
+
}
|
|
78475
78941
|
if (call === void 0) {
|
|
78476
78942
|
const opened = openToolCall(state, entry, wireIndex);
|
|
78477
78943
|
out.push(...opened.chunks);
|
|
@@ -83690,6 +84156,7 @@ async function* translate$1(payloads) {
|
|
|
83690
84156
|
if (!isRecord$17(call)) continue;
|
|
83691
84157
|
const index = Number(call.index ?? 0);
|
|
83692
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;
|
|
83693
84160
|
if (block === void 0) {
|
|
83694
84161
|
block = open("tool-call");
|
|
83695
84162
|
toolBlocks.set(index, block);
|
|
@@ -83701,7 +84168,7 @@ async function* translate$1(payloads) {
|
|
|
83701
84168
|
}
|
|
83702
84169
|
const fn = isRecord$17(call.function) ? call.function : {};
|
|
83703
84170
|
block.callId = acceptIdentity(block.callId, call.id);
|
|
83704
|
-
block.name = acceptIdentity(block.name, fn.name);
|
|
84171
|
+
if (block.name === void 0 || block.name === "") block.name = acceptIdentity(block.name, fn.name);
|
|
83705
84172
|
const fragment = typeof fn.arguments === "string" ? fn.arguments : "";
|
|
83706
84173
|
block.text += fragment;
|
|
83707
84174
|
yield {
|
|
@@ -87228,9 +87695,9 @@ function installToolResultPrunerGuard(ctx, options = {}) {
|
|
|
87228
87695
|
const wrapPruner = (pruner) => {
|
|
87229
87696
|
if (disposed || !isRecord$14(pruner)) return false;
|
|
87230
87697
|
if (alreadyWrapped.has(pruner)) return false;
|
|
87231
|
-
const target = resolveMethodTarget$
|
|
87698
|
+
const target = resolveMethodTarget$4(pruner, "pruneSession");
|
|
87232
87699
|
if (target === void 0) return false;
|
|
87233
|
-
if (alreadyPatched$
|
|
87700
|
+
if (alreadyPatched$4(patchedMethods, target.holder, target.name)) {
|
|
87234
87701
|
alreadyWrapped.add(pruner);
|
|
87235
87702
|
return false;
|
|
87236
87703
|
}
|
|
@@ -87242,11 +87709,11 @@ function installToolResultPrunerGuard(ctx, options = {}) {
|
|
|
87242
87709
|
};
|
|
87243
87710
|
return original.call(this ?? pruner, session);
|
|
87244
87711
|
};
|
|
87245
|
-
if (!installMethod$
|
|
87246
|
-
markPatched$
|
|
87712
|
+
if (!installMethod$4(target, replacement)) return false;
|
|
87713
|
+
markPatched$4(patchedMethods, target.holder, target.name);
|
|
87247
87714
|
alreadyWrapped.add(pruner);
|
|
87248
87715
|
restores.push(() => {
|
|
87249
|
-
restoreMethod$
|
|
87716
|
+
restoreMethod$4(target);
|
|
87250
87717
|
});
|
|
87251
87718
|
return true;
|
|
87252
87719
|
};
|
|
@@ -87466,7 +87933,7 @@ function isRecord$14(value) {
|
|
|
87466
87933
|
* @param name - 方法名。
|
|
87467
87934
|
* @returns 目标;方法不存在时为 `undefined`。
|
|
87468
87935
|
*/
|
|
87469
|
-
function resolveMethodTarget$
|
|
87936
|
+
function resolveMethodTarget$4(service, name) {
|
|
87470
87937
|
if (typeof service !== "object" || service === null) return void 0;
|
|
87471
87938
|
const own = service;
|
|
87472
87939
|
if (Object.prototype.hasOwnProperty.call(own, name)) {
|
|
@@ -87498,7 +87965,7 @@ function resolveMethodTarget$3(service, name) {
|
|
|
87498
87965
|
* @param replacement - 包装实现。
|
|
87499
87966
|
* @returns 是否装上了。
|
|
87500
87967
|
*/
|
|
87501
|
-
function installMethod$
|
|
87968
|
+
function installMethod$4(target, replacement) {
|
|
87502
87969
|
try {
|
|
87503
87970
|
Object.defineProperty(target.holder, target.name, {
|
|
87504
87971
|
value: replacement,
|
|
@@ -87516,7 +87983,7 @@ function installMethod$3(target, replacement) {
|
|
|
87516
87983
|
*
|
|
87517
87984
|
* @param target - 目标。
|
|
87518
87985
|
*/
|
|
87519
|
-
function restoreMethod$
|
|
87986
|
+
function restoreMethod$4(target) {
|
|
87520
87987
|
try {
|
|
87521
87988
|
if (target.descriptor === void 0) Reflect.deleteProperty(target.holder, target.name);
|
|
87522
87989
|
else Object.defineProperty(target.holder, target.name, target.descriptor);
|
|
@@ -87530,7 +87997,7 @@ function restoreMethod$3(target) {
|
|
|
87530
87997
|
* @param name - 方法名。
|
|
87531
87998
|
* @returns 是否已经包过。
|
|
87532
87999
|
*/
|
|
87533
|
-
function alreadyPatched$
|
|
88000
|
+
function alreadyPatched$4(patched, holder, name) {
|
|
87534
88001
|
return patched.get(holder)?.has(name) === true;
|
|
87535
88002
|
}
|
|
87536
88003
|
/**
|
|
@@ -87540,7 +88007,7 @@ function alreadyPatched$3(patched, holder, name) {
|
|
|
87540
88007
|
* @param holder - 方法宿主。
|
|
87541
88008
|
* @param name - 方法名。
|
|
87542
88009
|
*/
|
|
87543
|
-
function markPatched$
|
|
88010
|
+
function markPatched$4(patched, holder, name) {
|
|
87544
88011
|
const names = patched.get(holder);
|
|
87545
88012
|
if (names === void 0) patched.set(holder, /* @__PURE__ */ new Set([name]));
|
|
87546
88013
|
else names.add(name);
|
|
@@ -87555,7 +88022,7 @@ const GLOBAL_KEY$2 = Object.freeze({});
|
|
|
87555
88022
|
* @param service - 服务名。
|
|
87556
88023
|
* @returns 服务实例或 undefined。
|
|
87557
88024
|
*/
|
|
87558
|
-
function serviceOf$
|
|
88025
|
+
function serviceOf$2(ctx, service) {
|
|
87559
88026
|
const read = ctx?.get;
|
|
87560
88027
|
if (typeof read !== "function") return void 0;
|
|
87561
88028
|
try {
|
|
@@ -87577,11 +88044,15 @@ function bucketOf$1(value) {
|
|
|
87577
88044
|
* @param ctx - 宿主上下文。
|
|
87578
88045
|
* @param event - 事件名。
|
|
87579
88046
|
* @param listener - 监听器。
|
|
88047
|
+
* @param options - cordis 订阅选项;省略时按两参数订阅。
|
|
87580
88048
|
* @returns 解绑函数或 undefined。
|
|
87581
88049
|
*/
|
|
87582
|
-
function subscribe$3(ctx, event, listener) {
|
|
88050
|
+
function subscribe$3(ctx, event, listener, options) {
|
|
87583
88051
|
const on = ctx?.on;
|
|
87584
88052
|
if (typeof on !== "function") return void 0;
|
|
88053
|
+
if (options !== void 0) try {
|
|
88054
|
+
return on.call(ctx, event, listener, options);
|
|
88055
|
+
} catch {}
|
|
87585
88056
|
try {
|
|
87586
88057
|
return on.call(ctx, event, listener);
|
|
87587
88058
|
} catch {
|
|
@@ -87674,11 +88145,15 @@ function installPlanModeCacheGuard(ctx) {
|
|
|
87674
88145
|
if (offPreStep !== void 0) restores.push(() => {
|
|
87675
88146
|
offPreStep();
|
|
87676
88147
|
});
|
|
88148
|
+
const offReminder = installPlanModeExitReminder(ctx, { isActive: (agent) => planActiveOfAgent(ctx, agent) });
|
|
88149
|
+
if (offReminder !== void 0) restores.push(() => {
|
|
88150
|
+
offReminder();
|
|
88151
|
+
});
|
|
87677
88152
|
const wrap = (tools) => {
|
|
87678
88153
|
if (tools === void 0) return;
|
|
87679
|
-
const target = resolveMethodTarget$
|
|
88154
|
+
const target = resolveMethodTarget$3(tools, "register");
|
|
87680
88155
|
if (target === void 0) return;
|
|
87681
|
-
if (alreadyPatched$
|
|
88156
|
+
if (alreadyPatched$3(patchedMethods, target.holder, target.name)) return;
|
|
87682
88157
|
const original = target.original;
|
|
87683
88158
|
const wrapped = function(...args) {
|
|
87684
88159
|
const receiver = this ?? tools;
|
|
@@ -87690,16 +88165,16 @@ function installPlanModeCacheGuard(ctx) {
|
|
|
87690
88165
|
}
|
|
87691
88166
|
return original.call(receiver, definition, options);
|
|
87692
88167
|
};
|
|
87693
|
-
if (!installMethod$
|
|
87694
|
-
markPatched$
|
|
88168
|
+
if (!installMethod$3(target, wrapped)) return;
|
|
88169
|
+
markPatched$3(patchedMethods, target.holder, target.name);
|
|
87695
88170
|
restores.push(() => {
|
|
87696
|
-
restoreMethod$
|
|
88171
|
+
restoreMethod$3(target);
|
|
87697
88172
|
});
|
|
87698
88173
|
if (typeof tools.get === "function") try {
|
|
87699
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");
|
|
87700
88175
|
} catch {}
|
|
87701
88176
|
};
|
|
87702
|
-
const tools = serviceOf$
|
|
88177
|
+
const tools = serviceOf$2(ctx, "tools");
|
|
87703
88178
|
if (tools !== void 0) wrap(tools);
|
|
87704
88179
|
else {
|
|
87705
88180
|
const inject = ctx?.inject;
|
|
@@ -87709,7 +88184,7 @@ function installPlanModeCacheGuard(ctx) {
|
|
|
87709
88184
|
inject.call(ctx, ["tools"], (scope) => {
|
|
87710
88185
|
if (wrapped || closed) return;
|
|
87711
88186
|
wrapped = true;
|
|
87712
|
-
wrap(serviceOf$
|
|
88187
|
+
wrap(serviceOf$2(scope, "tools"));
|
|
87713
88188
|
});
|
|
87714
88189
|
} catch {}
|
|
87715
88190
|
}
|
|
@@ -87729,7 +88204,7 @@ function installPlanModeCacheGuard(ctx) {
|
|
|
87729
88204
|
* @returns true / false;读不到时 undefined。
|
|
87730
88205
|
*/
|
|
87731
88206
|
function planActiveOf(ctx, session) {
|
|
87732
|
-
const projections = serviceOf$
|
|
88207
|
+
const projections = serviceOf$2(ctx, "sessionProjections");
|
|
87733
88208
|
if (typeof projections?.stateOf !== "function") return void 0;
|
|
87734
88209
|
try {
|
|
87735
88210
|
const state = projections.stateOf(session, PLAN_PROJECTION_KEY);
|
|
@@ -87739,6 +88214,35 @@ function planActiveOf(ctx, session) {
|
|
|
87739
88214
|
}
|
|
87740
88215
|
}
|
|
87741
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
|
+
/**
|
|
87742
88246
|
* 记一条警告。
|
|
87743
88247
|
* @param ctx - 宿主上下文。
|
|
87744
88248
|
* @param message - 正文。
|
|
@@ -87767,7 +88271,7 @@ function logWarn$1(ctx, message) {
|
|
|
87767
88271
|
* @param name - 方法名。
|
|
87768
88272
|
* @returns 目标;方法不存在时为 `undefined`。
|
|
87769
88273
|
*/
|
|
87770
|
-
function resolveMethodTarget$
|
|
88274
|
+
function resolveMethodTarget$3(service, name) {
|
|
87771
88275
|
if (typeof service !== "object" || service === null) return void 0;
|
|
87772
88276
|
const own = service;
|
|
87773
88277
|
if (Object.prototype.hasOwnProperty.call(own, name)) {
|
|
@@ -87799,7 +88303,7 @@ function resolveMethodTarget$2(service, name) {
|
|
|
87799
88303
|
* @param replacement - 包装实现。
|
|
87800
88304
|
* @returns 是否装上了。
|
|
87801
88305
|
*/
|
|
87802
|
-
function installMethod$
|
|
88306
|
+
function installMethod$3(target, replacement) {
|
|
87803
88307
|
try {
|
|
87804
88308
|
Object.defineProperty(target.holder, target.name, {
|
|
87805
88309
|
value: replacement,
|
|
@@ -87817,7 +88321,7 @@ function installMethod$2(target, replacement) {
|
|
|
87817
88321
|
*
|
|
87818
88322
|
* @param target - 目标。
|
|
87819
88323
|
*/
|
|
87820
|
-
function restoreMethod$
|
|
88324
|
+
function restoreMethod$3(target) {
|
|
87821
88325
|
try {
|
|
87822
88326
|
if (target.descriptor === void 0) Reflect.deleteProperty(target.holder, target.name);
|
|
87823
88327
|
else Object.defineProperty(target.holder, target.name, target.descriptor);
|
|
@@ -87831,7 +88335,7 @@ function restoreMethod$2(target) {
|
|
|
87831
88335
|
* @param name - 方法名。
|
|
87832
88336
|
* @returns 是否已经包过。
|
|
87833
88337
|
*/
|
|
87834
|
-
function alreadyPatched$
|
|
88338
|
+
function alreadyPatched$3(patched, holder, name) {
|
|
87835
88339
|
return patched.get(holder)?.has(name) === true;
|
|
87836
88340
|
}
|
|
87837
88341
|
/**
|
|
@@ -87841,7 +88345,7 @@ function alreadyPatched$2(patched, holder, name) {
|
|
|
87841
88345
|
* @param holder - 方法宿主。
|
|
87842
88346
|
* @param name - 方法名。
|
|
87843
88347
|
*/
|
|
87844
|
-
function markPatched$
|
|
88348
|
+
function markPatched$3(patched, holder, name) {
|
|
87845
88349
|
const names = patched.get(holder);
|
|
87846
88350
|
if (names === void 0) patched.set(holder, /* @__PURE__ */ new Set([name]));
|
|
87847
88351
|
else names.add(name);
|
|
@@ -87963,7 +88467,7 @@ function installPtcSdkCacheGuard(ctx, options = {}) {
|
|
|
87963
88467
|
*/
|
|
87964
88468
|
const toolFingerprint = (tools, scope) => {
|
|
87965
88469
|
if (!isRecord$13(tools)) return "";
|
|
87966
|
-
const target = resolveMethodTarget$
|
|
88470
|
+
const target = resolveMethodTarget$2(tools, "definitions");
|
|
87967
88471
|
if (target === void 0) return "";
|
|
87968
88472
|
let list;
|
|
87969
88473
|
try {
|
|
@@ -87983,9 +88487,9 @@ function installPtcSdkCacheGuard(ctx, options = {}) {
|
|
|
87983
88487
|
const wrapToolsService = (tools) => {
|
|
87984
88488
|
if (disposed || !isRecord$13(tools)) return false;
|
|
87985
88489
|
if (alreadyWrapped.has(tools)) return false;
|
|
87986
|
-
const target = resolveMethodTarget$
|
|
88490
|
+
const target = resolveMethodTarget$2(tools, "definitions");
|
|
87987
88491
|
if (target === void 0) return false;
|
|
87988
|
-
if (alreadyPatched$
|
|
88492
|
+
if (alreadyPatched$2(patchedMethods, target.holder, target.name)) {
|
|
87989
88493
|
alreadyWrapped.add(tools);
|
|
87990
88494
|
return false;
|
|
87991
88495
|
}
|
|
@@ -87998,11 +88502,11 @@ function installPtcSdkCacheGuard(ctx, options = {}) {
|
|
|
87998
88502
|
}
|
|
87999
88503
|
return original.call(receiver, scope, toolSet);
|
|
88000
88504
|
};
|
|
88001
|
-
if (!installMethod$
|
|
88002
|
-
markPatched$
|
|
88505
|
+
if (!installMethod$2(target, replacement)) return false;
|
|
88506
|
+
markPatched$2(patchedMethods, target.holder, target.name);
|
|
88003
88507
|
alreadyWrapped.add(tools);
|
|
88004
88508
|
restores.push(() => {
|
|
88005
|
-
restoreMethod$
|
|
88509
|
+
restoreMethod$2(target);
|
|
88006
88510
|
});
|
|
88007
88511
|
return true;
|
|
88008
88512
|
};
|
|
@@ -88042,7 +88546,7 @@ function installPtcSdkCacheGuard(ctx, options = {}) {
|
|
|
88042
88546
|
};
|
|
88043
88547
|
const offAssemble = subscribe$2(host, "system-prompt/assemble", onAssemble);
|
|
88044
88548
|
if (offAssemble !== void 0) disposers.push(offAssemble);
|
|
88045
|
-
const initialTools = serviceOf(host, "tools");
|
|
88549
|
+
const initialTools = serviceOf$1(host, "tools");
|
|
88046
88550
|
if (initialTools !== void 0) {
|
|
88047
88551
|
currentTools = initialTools;
|
|
88048
88552
|
wrapToolsService(initialTools);
|
|
@@ -88051,7 +88555,7 @@ function installPtcSdkCacheGuard(ctx, options = {}) {
|
|
|
88051
88555
|
if (typeof inject === "function") try {
|
|
88052
88556
|
inject.call(host, ["tools"], (scope) => {
|
|
88053
88557
|
if (disposed) return;
|
|
88054
|
-
const tools = serviceOf(scope, "tools");
|
|
88558
|
+
const tools = serviceOf$1(scope, "tools");
|
|
88055
88559
|
if (tools === void 0) return;
|
|
88056
88560
|
currentTools = tools;
|
|
88057
88561
|
wrapToolsService(tools);
|
|
@@ -88079,7 +88583,7 @@ function installPtcSdkCacheGuard(ctx, options = {}) {
|
|
|
88079
88583
|
* @param service - 服务名。
|
|
88080
88584
|
* @returns 服务实例;读不到时为 `undefined`。
|
|
88081
88585
|
*/
|
|
88082
|
-
function serviceOf(ctx, service) {
|
|
88586
|
+
function serviceOf$1(ctx, service) {
|
|
88083
88587
|
if (!isRecord$13(ctx)) return void 0;
|
|
88084
88588
|
const read = ctx["get"];
|
|
88085
88589
|
if (typeof read !== "function") return void 0;
|
|
@@ -88148,7 +88652,7 @@ function isRecord$13(value) {
|
|
|
88148
88652
|
* @param name - 方法名。
|
|
88149
88653
|
* @returns 目标;方法不存在时为 `undefined`。
|
|
88150
88654
|
*/
|
|
88151
|
-
function resolveMethodTarget$
|
|
88655
|
+
function resolveMethodTarget$2(service, name) {
|
|
88152
88656
|
if (typeof service !== "object" || service === null) return void 0;
|
|
88153
88657
|
const own = service;
|
|
88154
88658
|
if (Object.prototype.hasOwnProperty.call(own, name)) {
|
|
@@ -88180,7 +88684,7 @@ function resolveMethodTarget$1(service, name) {
|
|
|
88180
88684
|
* @param replacement - 包装实现。
|
|
88181
88685
|
* @returns 是否装上了。
|
|
88182
88686
|
*/
|
|
88183
|
-
function installMethod$
|
|
88687
|
+
function installMethod$2(target, replacement) {
|
|
88184
88688
|
try {
|
|
88185
88689
|
Object.defineProperty(target.holder, target.name, {
|
|
88186
88690
|
value: replacement,
|
|
@@ -88198,7 +88702,7 @@ function installMethod$1(target, replacement) {
|
|
|
88198
88702
|
*
|
|
88199
88703
|
* @param target - 目标。
|
|
88200
88704
|
*/
|
|
88201
|
-
function restoreMethod$
|
|
88705
|
+
function restoreMethod$2(target) {
|
|
88202
88706
|
try {
|
|
88203
88707
|
if (target.descriptor === void 0) Reflect.deleteProperty(target.holder, target.name);
|
|
88204
88708
|
else Object.defineProperty(target.holder, target.name, target.descriptor);
|
|
@@ -88212,7 +88716,7 @@ function restoreMethod$1(target) {
|
|
|
88212
88716
|
* @param name - 方法名。
|
|
88213
88717
|
* @returns 是否已经包过。
|
|
88214
88718
|
*/
|
|
88215
|
-
function alreadyPatched$
|
|
88719
|
+
function alreadyPatched$2(patched, holder, name) {
|
|
88216
88720
|
return patched.get(holder)?.has(name) === true;
|
|
88217
88721
|
}
|
|
88218
88722
|
/**
|
|
@@ -88222,12 +88726,245 @@ function alreadyPatched$1(patched, holder, name) {
|
|
|
88222
88726
|
* @param holder - 方法宿主。
|
|
88223
88727
|
* @param name - 方法名。
|
|
88224
88728
|
*/
|
|
88225
|
-
function markPatched$
|
|
88729
|
+
function markPatched$2(patched, holder, name) {
|
|
88226
88730
|
const names = patched.get(holder);
|
|
88227
88731
|
if (names === void 0) patched.set(holder, /* @__PURE__ */ new Set([name]));
|
|
88228
88732
|
else names.add(name);
|
|
88229
88733
|
}
|
|
88230
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
|
|
88231
88968
|
//#region src/host/team-policy-cache-guard.ts
|
|
88232
88969
|
/**
|
|
88233
88970
|
* 「Agent Teams 策略段前缀缓存守卫」—— 把内置 `team:policy` 段从 system 里摘掉,
|
|
@@ -88567,7 +89304,7 @@ const GUARDED_EVENTS = [
|
|
|
88567
89304
|
* @returns 可销毁的句柄。
|
|
88568
89305
|
*/
|
|
88569
89306
|
function installCompactionPolicyGuard(ctx, options = {}) {
|
|
88570
|
-
const host = isRecord$
|
|
89307
|
+
const host = isRecord$11(ctx) ? ctx : void 0;
|
|
88571
89308
|
const provider = options.provider ?? "kimi-code";
|
|
88572
89309
|
const defaults = {
|
|
88573
89310
|
provider,
|
|
@@ -88642,9 +89379,9 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88642
89379
|
* @param source - agent、header 或配置对象。
|
|
88643
89380
|
*/
|
|
88644
89381
|
const observeFrom = (source) => {
|
|
88645
|
-
if (!isRecord$
|
|
89382
|
+
if (!isRecord$11(source)) return;
|
|
88646
89383
|
const session = source["session"];
|
|
88647
|
-
if (isRecord$
|
|
89384
|
+
if (isRecord$11(session)) {
|
|
88648
89385
|
const requestHeader = session["requestHeader"];
|
|
88649
89386
|
if (typeof requestHeader === "function") {
|
|
88650
89387
|
let header;
|
|
@@ -88653,16 +89390,16 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88653
89390
|
} catch {
|
|
88654
89391
|
header = void 0;
|
|
88655
89392
|
}
|
|
88656
|
-
if (isRecord$
|
|
89393
|
+
if (isRecord$11(header)) {
|
|
88657
89394
|
const config = header["config"];
|
|
88658
|
-
if (isRecord$
|
|
89395
|
+
if (isRecord$11(config)) observe(readString(config["provider"]), readString(config["model"]));
|
|
88659
89396
|
}
|
|
88660
89397
|
}
|
|
88661
89398
|
}
|
|
88662
89399
|
const optionsField = source["options"];
|
|
88663
|
-
if (isRecord$
|
|
89400
|
+
if (isRecord$11(optionsField)) observe(readString(optionsField["provider"]), readString(optionsField["model"]));
|
|
88664
89401
|
const config = source["config"];
|
|
88665
|
-
if (isRecord$
|
|
89402
|
+
if (isRecord$11(config)) observe(readString(config["provider"]), readString(config["model"]));
|
|
88666
89403
|
};
|
|
88667
89404
|
/**
|
|
88668
89405
|
* 读一个字符串字段。
|
|
@@ -88692,10 +89429,10 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88692
89429
|
* @returns 是否真的改写了。
|
|
88693
89430
|
*/
|
|
88694
89431
|
const patchEngine = (engine) => {
|
|
88695
|
-
if (disposed || !isRecord$
|
|
89432
|
+
if (disposed || !isRecord$11(engine)) return false;
|
|
88696
89433
|
if (patched.has(engine)) return false;
|
|
88697
89434
|
const config = engine["config"];
|
|
88698
|
-
if (!isRecord$
|
|
89435
|
+
if (!isRecord$11(config)) return false;
|
|
88699
89436
|
const originalPolicies = config["modelPolicies"];
|
|
88700
89437
|
if (!Array.isArray(originalPolicies)) return false;
|
|
88701
89438
|
const originalConfig = config;
|
|
@@ -88765,7 +89502,7 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88765
89502
|
let nextArgs = args;
|
|
88766
89503
|
if (name === "summarize") {
|
|
88767
89504
|
const input = args[0];
|
|
88768
|
-
if (isRecord$
|
|
89505
|
+
if (isRecord$11(input)) {
|
|
88769
89506
|
const messages = input["messages"];
|
|
88770
89507
|
if (Array.isArray(messages)) {
|
|
88771
89508
|
const replaced = replaceCompactionInstruction(messages);
|
|
@@ -88800,12 +89537,12 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88800
89537
|
* @returns 是否改写了新引擎。
|
|
88801
89538
|
*/
|
|
88802
89539
|
const patchStoreEntry = (entry) => {
|
|
88803
|
-
if (!isRecord$
|
|
89540
|
+
if (!isRecord$11(entry)) return false;
|
|
88804
89541
|
const record = entry;
|
|
88805
89542
|
const name = readServiceName(record);
|
|
88806
89543
|
if (name !== void 0 && name !== "compaction") return false;
|
|
88807
89544
|
const value = record.value ?? record.impl;
|
|
88808
|
-
if (isRecord$
|
|
89545
|
+
if (isRecord$11(value)) {
|
|
88809
89546
|
if (patchEngine(value)) return true;
|
|
88810
89547
|
const nested = value["engine"];
|
|
88811
89548
|
if (nested !== void 0) return patchEngine(nested);
|
|
@@ -88820,11 +89557,11 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88820
89557
|
* @returns 本次新改写的引擎数。
|
|
88821
89558
|
*/
|
|
88822
89559
|
const scanStore = (target) => {
|
|
88823
|
-
if (!isRecord$
|
|
89560
|
+
if (!isRecord$11(target)) return 0;
|
|
88824
89561
|
const reflect = target["reflect"];
|
|
88825
|
-
if (!isRecord$
|
|
89562
|
+
if (!isRecord$11(reflect)) return 0;
|
|
88826
89563
|
const store = reflect["store"];
|
|
88827
|
-
if (!isRecord$
|
|
89564
|
+
if (!isRecord$11(store)) return 0;
|
|
88828
89565
|
const services = store;
|
|
88829
89566
|
let count = 0;
|
|
88830
89567
|
for (const key of Object.getOwnPropertySymbols(services)) if (patchStoreEntry(services[key])) count += 1;
|
|
@@ -88838,12 +89575,12 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88838
89575
|
* @returns 是否改写了新引擎。
|
|
88839
89576
|
*/
|
|
88840
89577
|
const patchServiceFrom = (target, name) => {
|
|
88841
|
-
if (!isRecord$
|
|
89578
|
+
if (!isRecord$11(target)) return false;
|
|
88842
89579
|
const get = target["get"];
|
|
88843
89580
|
if (typeof get !== "function") return false;
|
|
88844
89581
|
try {
|
|
88845
89582
|
const service = get.call(target, name);
|
|
88846
|
-
if (!isRecord$
|
|
89583
|
+
if (!isRecord$11(service)) return false;
|
|
88847
89584
|
if (patchEngine(service)) return true;
|
|
88848
89585
|
const nested = service["engine"];
|
|
88849
89586
|
return nested === void 0 ? false : patchEngine(nested);
|
|
@@ -88886,7 +89623,7 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88886
89623
|
try {
|
|
88887
89624
|
for (const arg of args) {
|
|
88888
89625
|
observeFrom(arg);
|
|
88889
|
-
if (isRecord$
|
|
89626
|
+
if (isRecord$11(arg)) observeFrom(arg["agent"]);
|
|
88890
89627
|
}
|
|
88891
89628
|
scanAndPatch();
|
|
88892
89629
|
const agentCtx = findAgentContext(args);
|
|
@@ -88925,9 +89662,9 @@ function installCompactionPolicyGuard(ctx, options = {}) {
|
|
|
88925
89662
|
function readServiceName(record) {
|
|
88926
89663
|
if (typeof record.name === "string") return record.name;
|
|
88927
89664
|
const impl = record.impl;
|
|
88928
|
-
if (isRecord$
|
|
89665
|
+
if (isRecord$11(impl) && typeof impl["name"] === "string") return impl["name"];
|
|
88929
89666
|
const value = record.value;
|
|
88930
|
-
if (isRecord$
|
|
89667
|
+
if (isRecord$11(value) && typeof value["name"] === "string") return value["name"];
|
|
88931
89668
|
}
|
|
88932
89669
|
/**
|
|
88933
89670
|
* 从一次事件派发的参数里找出 agent 的上下文。
|
|
@@ -88939,7 +89676,7 @@ function findAgentContext(args) {
|
|
|
88939
89676
|
for (const arg of args) {
|
|
88940
89677
|
const direct = readContext(arg);
|
|
88941
89678
|
if (direct !== void 0) return direct;
|
|
88942
|
-
if (isRecord$
|
|
89679
|
+
if (isRecord$11(arg)) {
|
|
88943
89680
|
const nested = readContext(arg["agent"]);
|
|
88944
89681
|
if (nested !== void 0) return nested;
|
|
88945
89682
|
}
|
|
@@ -88952,10 +89689,10 @@ function findAgentContext(args) {
|
|
|
88952
89689
|
* @returns 上下文;不像时返回 `undefined`。
|
|
88953
89690
|
*/
|
|
88954
89691
|
function readContext(value) {
|
|
88955
|
-
if (!isRecord$
|
|
89692
|
+
if (!isRecord$11(value)) return void 0;
|
|
88956
89693
|
const ctx = value["ctx"];
|
|
88957
|
-
if (!isRecord$
|
|
88958
|
-
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;
|
|
88959
89696
|
}
|
|
88960
89697
|
/**
|
|
88961
89698
|
* 订阅一个事件,优先用 `prepend: true`。
|
|
@@ -88995,7 +89732,7 @@ function subscribe(host, event, listener) {
|
|
|
88995
89732
|
* @param value - 任意值。
|
|
88996
89733
|
* @returns 是非 null 的对象时为 `true`。
|
|
88997
89734
|
*/
|
|
88998
|
-
function isRecord$
|
|
89735
|
+
function isRecord$11(value) {
|
|
88999
89736
|
return typeof value === "object" && value !== null;
|
|
89000
89737
|
}
|
|
89001
89738
|
/**
|
|
@@ -89095,449 +89832,6 @@ function markPatched(patched, holder, name) {
|
|
|
89095
89832
|
if (names === void 0) patched.set(holder, /* @__PURE__ */ new Set([name]));
|
|
89096
89833
|
else names.add(name);
|
|
89097
89834
|
}
|
|
89098
|
-
//#endregion
|
|
89099
|
-
//#region src/host/dispatch-execution-guard.ts
|
|
89100
|
-
/**
|
|
89101
|
-
* 「调度执行守卫」——在**执行期**拦住两类越界调用。
|
|
89102
|
-
*
|
|
89103
|
-
* ## 为什么需要它
|
|
89104
|
-
*
|
|
89105
|
-
* 调度模式(dispatch preset)里主控与子代理跑在同一进程、同一套工具注册面上,
|
|
89106
|
-
* 于是有两件事会悄悄坏掉:
|
|
89107
|
-
*
|
|
89108
|
-
* 1. **子代理越权调用主控专用工具**。`ask_user_question`、`exit_plan_mode`、
|
|
89109
|
-
* `create_goal` 这些是**主控的**决定口:让子代理自己问用户、自己进/出计划模式、
|
|
89110
|
-
* 自己建目标,都会把「一个决定」拆成两个决定——子代理问完,用户答了,主控却
|
|
89111
|
-
* 不知道问过什么。子代理本来就该把未决问题**带回**主控,而不是自己去问。
|
|
89112
|
-
* 2. **等待子代理期间空等**。子代理还在跑的时候,主控用 `sleep` 空转,既烧 token
|
|
89113
|
-
* 又错过通知到达的那一刻。正确做法是**结束这一轮**,让内置的子代理完成通知把
|
|
89114
|
-
* 它叫醒(R-W)。
|
|
89115
|
-
*
|
|
89116
|
-
* ## 零 Kimi Code 缓存漂移
|
|
89117
|
-
*
|
|
89118
|
-
* 守卫**只**用 `ctx.tools.guard(exec => …)` 这一条执行期接缝:
|
|
89119
|
-
*
|
|
89120
|
-
* - 不包 `tools.definitions`,不包 `tools.register`,不听
|
|
89121
|
-
* `system-prompt/assemble`——工具声明面(`tools:sdk` 段与顶层工具 schema)
|
|
89122
|
-
* 保持逐字节恒定,Kimi Code 的前缀缓存不会因为这个守卫重建一次。
|
|
89123
|
-
* - 拦截发生在**调用执行时**,模型看到的工具表完全没变,所以「看得见」与
|
|
89124
|
-
* 「叫得动」仍然被拆开:工具照常出现在表里,只是越界的调用被拒。
|
|
89125
|
-
*
|
|
89126
|
-
* ## 判定从哪来
|
|
89127
|
-
*
|
|
89128
|
-
* 两条判定都走**结构探测**,不 import 任何 harness 代次专属的类型:
|
|
89129
|
-
*
|
|
89130
|
-
* - 「你是不是子代理」:先看**持久会话血缘**(`session.header.origin ===
|
|
89131
|
-
* 'subagent'`),再看宿主活着的**存活根**(`agents.roots()`)。两条都是
|
|
89132
|
-
* 读得着的既有事实,不新增任何状态。
|
|
89133
|
-
* - 「你还有没有在跑的子代理」:依次问 `subagents.list` 与 `agents.list`,
|
|
89134
|
-
* 看有没有 `status === 'running'` 的直接子代。
|
|
89135
|
-
*
|
|
89136
|
-
* @module @eddyskywalker/dsh-chatgpt-subscription/host/dispatch-execution-guard
|
|
89137
|
-
*/
|
|
89138
|
-
/**
|
|
89139
|
-
* 子代理**不得**直接调用的主控专用工具。
|
|
89140
|
-
*
|
|
89141
|
-
* 这七个都是「决定口」或「交付口」,不是「干活口」:
|
|
89142
|
-
*
|
|
89143
|
-
* - `ask_user_question` / `exit_plan_mode` / `enter_plan_mode` /
|
|
89144
|
-
* `leave_plan_mode`:计划与提问的决定权在主控;
|
|
89145
|
-
* - `create_goal` / `update_goal`:目标由主控持有;
|
|
89146
|
-
* - `present`:交付口由主控掌握。
|
|
89147
|
-
*
|
|
89148
|
-
* 子代理遇到需要决定的地方,正确动作是**把问题带回主控**,让主控去调这些工具。
|
|
89149
|
-
*/
|
|
89150
|
-
const DEFAULT_DELEGATED_BLOCKED_TOOLS = Object.freeze([
|
|
89151
|
-
"ask_user_question",
|
|
89152
|
-
"exit_plan_mode",
|
|
89153
|
-
"enter_plan_mode",
|
|
89154
|
-
"leave_plan_mode",
|
|
89155
|
-
"create_goal",
|
|
89156
|
-
"update_goal",
|
|
89157
|
-
"present"
|
|
89158
|
-
]);
|
|
89159
|
-
/**
|
|
89160
|
-
* 承载「等待」语义的 shell 工具。
|
|
89161
|
-
*
|
|
89162
|
-
* 这三个是本包与宿主都会用到的 shell 入口:它们的 `command` 参数里可能藏着
|
|
89163
|
-
* `sleep`。空等只在**确实有在跑的子代理**时才是问题(有子代理时应当结束这一
|
|
89164
|
-
* 轮等通知),没有子代理时 `sleep 1` 只是普通命令,不该拦。
|
|
89165
|
-
*/
|
|
89166
|
-
const DEFAULT_SHELL_TOOLS = Object.freeze([
|
|
89167
|
-
"bash",
|
|
89168
|
-
"pwsh",
|
|
89169
|
-
"win_bash"
|
|
89170
|
-
]);
|
|
89171
|
-
/** 一次执行里被判定为「纯等待」的命令形态。 */
|
|
89172
|
-
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;
|
|
89173
|
-
/** 无害的空转语句(回显、真、冒号)。 */
|
|
89174
|
-
const NOOP_COMMAND_PATTERN = /^(?:echo\b.*|Write-Host\b.*|Write-Output\b.*|true|:)$/;
|
|
89175
|
-
/** 注释行。 */
|
|
89176
|
-
const COMMENT_COMMAND_PATTERN = /^#/;
|
|
89177
|
-
/**
|
|
89178
|
-
* 读宿主上下文上「直接注入」的 running-child 判定回调。
|
|
89179
|
-
*
|
|
89180
|
-
* 这一步必须**try/catch**:真实 Cordis 的上下文代理对任何没有 inject 的属性直读
|
|
89181
|
-
* 都当场抛 `cannot get property "..." without inject`,一次读失败不该让守卫在
|
|
89182
|
-
* 每次工具调用上抛错。
|
|
89183
|
-
*
|
|
89184
|
-
* @param ctx - 宿主上下文。
|
|
89185
|
-
* @returns 注入的回调;没有时为 undefined。
|
|
89186
|
-
*/
|
|
89187
|
-
function injectedHasRunningChildren(ctx) {
|
|
89188
|
-
if (!isRecord$11(ctx)) return void 0;
|
|
89189
|
-
let injected;
|
|
89190
|
-
try {
|
|
89191
|
-
injected = ctx["hasRunningChildren"];
|
|
89192
|
-
} catch {
|
|
89193
|
-
return;
|
|
89194
|
-
}
|
|
89195
|
-
return typeof injected === "function" ? injected : void 0;
|
|
89196
|
-
}
|
|
89197
|
-
/**
|
|
89198
|
-
* 判断一个值是不是可读的记录对象。
|
|
89199
|
-
*
|
|
89200
|
-
* @param value - 候选值。
|
|
89201
|
-
* @returns 是记录对象时为 true。
|
|
89202
|
-
*/
|
|
89203
|
-
function isRecord$11(value) {
|
|
89204
|
-
return typeof value === "object" && value !== null;
|
|
89205
|
-
}
|
|
89206
|
-
/**
|
|
89207
|
-
* 从宿主上下文里读一个**可选**服务。
|
|
89208
|
-
*
|
|
89209
|
-
* 一律走 `ctx.get()`:没写进 `inject` 的服务名不能当属性读,真实 Cordis 会当场
|
|
89210
|
-
* 抛 `cannot get property "..." without inject`,整个插件降级。读不到就是读不到,
|
|
89211
|
-
* 守卫据此放行,绝不因此让插件挂不上。
|
|
89212
|
-
*
|
|
89213
|
-
* @param ctx - 宿主上下文。
|
|
89214
|
-
* @param name - 服务名。
|
|
89215
|
-
* @returns 服务实例;不存在或读取抛错时为 undefined。
|
|
89216
|
-
*/
|
|
89217
|
-
function readService(ctx, name) {
|
|
89218
|
-
const reader = ctx?.get;
|
|
89219
|
-
if (typeof reader !== "function") return void 0;
|
|
89220
|
-
try {
|
|
89221
|
-
return reader.call(ctx, name);
|
|
89222
|
-
} catch {
|
|
89223
|
-
return;
|
|
89224
|
-
}
|
|
89225
|
-
}
|
|
89226
|
-
/**
|
|
89227
|
-
* 读一个宿主上下文里的工具注册面。
|
|
89228
|
-
*
|
|
89229
|
-
* @param ctx - 宿主上下文。
|
|
89230
|
-
* @returns 带 `guard` 接缝的注册面;没有时为 undefined。
|
|
89231
|
-
*/
|
|
89232
|
-
function toolsOf$2(ctx) {
|
|
89233
|
-
if (!isRecord$11(ctx)) return void 0;
|
|
89234
|
-
let tools;
|
|
89235
|
-
try {
|
|
89236
|
-
tools = ctx["tools"];
|
|
89237
|
-
} catch {
|
|
89238
|
-
tools = void 0;
|
|
89239
|
-
}
|
|
89240
|
-
if (!isRecord$11(tools)) tools = readService(ctx, "tools");
|
|
89241
|
-
return isRecord$11(tools) ? tools : void 0;
|
|
89242
|
-
}
|
|
89243
|
-
/**
|
|
89244
|
-
* 读一条记录的 `id`。
|
|
89245
|
-
*
|
|
89246
|
-
* @param value - 候选记录。
|
|
89247
|
-
* @returns id 字符串;没有时为 undefined。
|
|
89248
|
-
*/
|
|
89249
|
-
function idOf(value) {
|
|
89250
|
-
if (!isRecord$11(value)) return void 0;
|
|
89251
|
-
const id = value["id"];
|
|
89252
|
-
return typeof id === "string" ? id : void 0;
|
|
89253
|
-
}
|
|
89254
|
-
/**
|
|
89255
|
-
* 读一条会话记录头里的 `id`。
|
|
89256
|
-
*
|
|
89257
|
-
* @param agent - 候选 agent。
|
|
89258
|
-
* @returns 会话 id;没有时为 undefined。
|
|
89259
|
-
*/
|
|
89260
|
-
function sessionIdOf$1(agent) {
|
|
89261
|
-
if (!isRecord$11(agent)) return void 0;
|
|
89262
|
-
const session = agent["session"];
|
|
89263
|
-
if (!isRecord$11(session)) return void 0;
|
|
89264
|
-
const header = session["header"];
|
|
89265
|
-
return idOf(header);
|
|
89266
|
-
}
|
|
89267
|
-
/**
|
|
89268
|
-
* 这个调用方是不是**子代理**。
|
|
89269
|
-
*
|
|
89270
|
-
* 判定分两级,先看能独立成立的持久事实,再看宿主当前活着的存活根:
|
|
89271
|
-
*
|
|
89272
|
-
* 1. **持久会话血缘**:`session.header.origin === 'subagent'`。这是子代理会话
|
|
89273
|
-
* 创建时就写下的血缘,跨宿主代次都在,不依赖任何服务是否挂载。
|
|
89274
|
-
* 2. **存活根判定**:宿主提供 `agents.roots()` 时,一个**不在**存活根集合里的
|
|
89275
|
-
* agent 就是别人的孩子。先核对**存活**(`agents.get(id) === agent`):不是
|
|
89276
|
-
* 那个 id 当前登记的存活 agent,说明这个调用方已经过期或已被顶替——判它是不是
|
|
89277
|
-
* 子代理没有意义,放行。
|
|
89278
|
-
*
|
|
89279
|
-
* 宿主没有 `agents` 服务(或老代没有 `roots`)时,判不了就**放行**:把一个
|
|
89280
|
-
* 读不出来的身份当成子代理去拦,会拦掉主控自己的正常调用。
|
|
89281
|
-
*
|
|
89282
|
-
* @param agent - 调用方 agent。
|
|
89283
|
-
* @param ctx - 宿主上下文(可选;用于读 `agents` 服务)。
|
|
89284
|
-
* @returns 是子代理时为 true。
|
|
89285
|
-
*/
|
|
89286
|
-
function isDelegatedCaller(agent, ctx) {
|
|
89287
|
-
if (!isRecord$11(agent)) return false;
|
|
89288
|
-
const session = agent["session"];
|
|
89289
|
-
if (isRecord$11(session)) {
|
|
89290
|
-
const header = session["header"];
|
|
89291
|
-
if (isRecord$11(header) && header["origin"] === "subagent") return true;
|
|
89292
|
-
}
|
|
89293
|
-
const agents = readService(ctx, "agents");
|
|
89294
|
-
if (!isRecord$11(agents)) return false;
|
|
89295
|
-
const roots = rootsOf(agents);
|
|
89296
|
-
if (roots === void 0) return false;
|
|
89297
|
-
const id = idOf(agent);
|
|
89298
|
-
if (typeof id === "string" && typeof agents["get"] === "function") {
|
|
89299
|
-
let live;
|
|
89300
|
-
try {
|
|
89301
|
-
live = agents["get"].call(agents, id);
|
|
89302
|
-
} catch {
|
|
89303
|
-
live = void 0;
|
|
89304
|
-
}
|
|
89305
|
-
if (live !== agent) return false;
|
|
89306
|
-
}
|
|
89307
|
-
return !roots.includes(agent);
|
|
89308
|
-
}
|
|
89309
|
-
/**
|
|
89310
|
-
* 读宿主存活根集合。
|
|
89311
|
-
*
|
|
89312
|
-
* @param agents - `agents` 服务。
|
|
89313
|
-
* @returns 存活根数组;服务没有 `roots` 或读取抛错时为 undefined。
|
|
89314
|
-
*/
|
|
89315
|
-
function rootsOf(agents) {
|
|
89316
|
-
const roots = agents["roots"];
|
|
89317
|
-
if (typeof roots !== "function") return void 0;
|
|
89318
|
-
try {
|
|
89319
|
-
const listed = roots.call(agents);
|
|
89320
|
-
return Array.isArray(listed) ? listed : void 0;
|
|
89321
|
-
} catch {
|
|
89322
|
-
return;
|
|
89323
|
-
}
|
|
89324
|
-
}
|
|
89325
|
-
/**
|
|
89326
|
-
* 判断一条命令是不是**纯等待**。
|
|
89327
|
-
*
|
|
89328
|
-
* 判据:整条命令**按分隔符切开后**,至少有一条是 sleep/wait,而**每一条**都是
|
|
89329
|
-
* sleep/wait 或者无害的空转(回显、真、冒号、注释)。只要有一条在做真事
|
|
89330
|
-
* (`sleep 1 && npm test`、`git status`、`node …`),整条命令就不是纯等待——
|
|
89331
|
-
* 这类命令**必须放行**,否则守卫会拦掉正当的后台工作。
|
|
89332
|
-
*
|
|
89333
|
-
* @param command - 候选命令。
|
|
89334
|
-
* @returns 是纯等待时为 true。
|
|
89335
|
-
*/
|
|
89336
|
-
function isPureSleepCommand(command) {
|
|
89337
|
-
if (typeof command !== "string") return false;
|
|
89338
|
-
const trimmed = command.trim();
|
|
89339
|
-
if (trimmed.length === 0) return false;
|
|
89340
|
-
const statements = trimmed.split(/;|&&|\n/).map((statement) => statement.trim()).filter((statement) => statement.length > 0);
|
|
89341
|
-
if (statements.length === 0) return false;
|
|
89342
|
-
let sawWait = false;
|
|
89343
|
-
for (const statement of statements) {
|
|
89344
|
-
if (SLEEP_COMMAND_PATTERN.test(statement)) {
|
|
89345
|
-
sawWait = true;
|
|
89346
|
-
continue;
|
|
89347
|
-
}
|
|
89348
|
-
if (!isNoopStatement(statement)) return false;
|
|
89349
|
-
}
|
|
89350
|
-
return sawWait;
|
|
89351
|
-
}
|
|
89352
|
-
/**
|
|
89353
|
-
* 判断一条语句是不是无害的空转。
|
|
89354
|
-
*
|
|
89355
|
-
* @param statement - 候选语句。
|
|
89356
|
-
* @returns 是空转时为 true。
|
|
89357
|
-
*/
|
|
89358
|
-
function isNoopStatement(statement) {
|
|
89359
|
-
return NOOP_COMMAND_PATTERN.test(statement) || COMMENT_COMMAND_PATTERN.test(statement);
|
|
89360
|
-
}
|
|
89361
|
-
/**
|
|
89362
|
-
* 这个调用方当前**还有没有在跑的子代理**。
|
|
89363
|
-
*
|
|
89364
|
-
* 两条宿主探测,任何一条给出答案就算数:
|
|
89365
|
-
*
|
|
89366
|
-
* 1. `subagents.list(agent, 'children')`(老代退化成 `subagents.list(agent)`):
|
|
89367
|
-
* 直接子代里有没有 `status === 'running'` 的。
|
|
89368
|
-
* 2. `agents.list()`:活着且 `status === 'running'`、并且 `parent` 就是这个
|
|
89369
|
-
* 调用方的那些 agent。
|
|
89370
|
-
*
|
|
89371
|
-
* 宿主提供 `hasRunningChildren` 回调时以它为准(直接注入口,见
|
|
89372
|
-
* {@link DispatchExecutionGuardOptions.hasRunningChildren})。
|
|
89373
|
-
*
|
|
89374
|
-
* @param agent - 调用方 agent。
|
|
89375
|
-
* @param ctx - 宿主上下文(可选;用于读 `subagents` / `agents` 服务)。
|
|
89376
|
-
* @returns 有在跑的子代理时为 true。
|
|
89377
|
-
*/
|
|
89378
|
-
function hasRunningChildSubagent(agent, ctx) {
|
|
89379
|
-
if (!isRecord$11(agent)) return false;
|
|
89380
|
-
const injected = injectedHasRunningChildren(ctx);
|
|
89381
|
-
if (injected !== void 0) try {
|
|
89382
|
-
return injected(agent) === true;
|
|
89383
|
-
} catch {
|
|
89384
|
-
return false;
|
|
89385
|
-
}
|
|
89386
|
-
const subagents = readService(ctx, "subagents");
|
|
89387
|
-
if (isRecord$11(subagents) && typeof subagents["list"] === "function") {
|
|
89388
|
-
if (entriesOf(callList(subagents["list"], subagents, agent)).some((entry) => entry["status"] === "running")) return true;
|
|
89389
|
-
}
|
|
89390
|
-
const agents = readService(ctx, "agents");
|
|
89391
|
-
if (isRecord$11(agents) && typeof agents["list"] === "function") {
|
|
89392
|
-
const listed = callList(agents["list"], agents, agent, false);
|
|
89393
|
-
const parentIds = /* @__PURE__ */ new Set();
|
|
89394
|
-
const ownId = idOf(agent);
|
|
89395
|
-
if (ownId !== void 0) parentIds.add(ownId);
|
|
89396
|
-
const headerId = sessionIdOf$1(agent);
|
|
89397
|
-
if (headerId !== void 0) parentIds.add(headerId);
|
|
89398
|
-
if (entriesOf(listed).some((entry) => entry["status"] === "running" && typeof entry["parent"] === "string" && parentIds.has(entry["parent"]))) return true;
|
|
89399
|
-
}
|
|
89400
|
-
return false;
|
|
89401
|
-
}
|
|
89402
|
-
/**
|
|
89403
|
-
* 调用一个「列出子代」的宿主方法。
|
|
89404
|
-
*
|
|
89405
|
-
* 先试带 scope 的形态(`list(agent, 'children')`),老代只认 `list(agent)`,
|
|
89406
|
-
* 再老一代的 `agents.list()` 不接参数——三种都试,谁先成功用谁。
|
|
89407
|
-
*
|
|
89408
|
-
* @param fn - 宿主方法。
|
|
89409
|
-
* @param self - 调用宿主。
|
|
89410
|
-
* @param agent - 调用方 agent。
|
|
89411
|
-
* @param scoped - 是否先试带 scope 的形态。
|
|
89412
|
-
* @returns 宿主返回值;全部失败时为 undefined。
|
|
89413
|
-
*/
|
|
89414
|
-
function callList(fn, self, agent, scoped = true) {
|
|
89415
|
-
if (typeof fn !== "function") return void 0;
|
|
89416
|
-
const call = fn;
|
|
89417
|
-
const attempts = scoped ? [
|
|
89418
|
-
[agent, "children"],
|
|
89419
|
-
[agent],
|
|
89420
|
-
[]
|
|
89421
|
-
] : [
|
|
89422
|
-
[],
|
|
89423
|
-
[agent],
|
|
89424
|
-
[agent, "children"]
|
|
89425
|
-
];
|
|
89426
|
-
for (const args of attempts) try {
|
|
89427
|
-
const listed = call.apply(self, args);
|
|
89428
|
-
if (listed !== void 0) return listed;
|
|
89429
|
-
} catch {}
|
|
89430
|
-
}
|
|
89431
|
-
/**
|
|
89432
|
-
* 从宿主返回值里取出「条目数组」。
|
|
89433
|
-
*
|
|
89434
|
-
* 宿主可能直接给数组,也可能给一个包着数组的记录(`children` / `agents`)。
|
|
89435
|
-
*
|
|
89436
|
-
* @param listed - 宿主返回值。
|
|
89437
|
-
* @returns 条目数组;取不到时是空数组。
|
|
89438
|
-
*/
|
|
89439
|
-
function entriesOf(listed) {
|
|
89440
|
-
if (Array.isArray(listed)) return listed.filter(isRecord$11);
|
|
89441
|
-
if (!isRecord$11(listed)) return [];
|
|
89442
|
-
const entries = [];
|
|
89443
|
-
for (const key of [
|
|
89444
|
-
"children",
|
|
89445
|
-
"agents",
|
|
89446
|
-
"entries",
|
|
89447
|
-
"list"
|
|
89448
|
-
]) {
|
|
89449
|
-
const candidate = listed[key];
|
|
89450
|
-
if (!Array.isArray(candidate)) continue;
|
|
89451
|
-
for (const entry of candidate) if (isRecord$11(entry)) entries.push(entry);
|
|
89452
|
-
}
|
|
89453
|
-
return entries;
|
|
89454
|
-
}
|
|
89455
|
-
/**
|
|
89456
|
-
* 解析「调度执行守卫」当前是否启用。
|
|
89457
|
-
*
|
|
89458
|
-
* 沿 volatile 活引用取当前值,所以设置保存后立刻生效。缺省、非法值、读取抛错都
|
|
89459
|
-
* 按**开启**处理:守卫是保护,不是功能开关,读失败不该把保护关掉。
|
|
89460
|
-
*
|
|
89461
|
-
* @param config - 插件配置(活引用或普通值)。
|
|
89462
|
-
* @returns 是否启用。
|
|
89463
|
-
*/
|
|
89464
|
-
function resolveDispatchExecutionGuardEnabled(config) {
|
|
89465
|
-
const field = config?.dispatchExecutionGuard;
|
|
89466
|
-
if (field === void 0 || field === null) return true;
|
|
89467
|
-
if (typeof field === "object" && typeof field.get === "function") try {
|
|
89468
|
-
return field.get() !== false;
|
|
89469
|
-
} catch {
|
|
89470
|
-
return true;
|
|
89471
|
-
}
|
|
89472
|
-
return field !== false;
|
|
89473
|
-
}
|
|
89474
|
-
/**
|
|
89475
|
-
* 子代理越权调用时的拒绝文案。
|
|
89476
|
-
*
|
|
89477
|
-
* 文案要**可执行**:光说「不许调」模型只会换个花样再试一次,所以这里写清楚
|
|
89478
|
-
* 它该做什么——把未决问题带回主控,并带上报告状态。
|
|
89479
|
-
*
|
|
89480
|
-
* @param toolName - 被拦下的工具名。
|
|
89481
|
-
* @returns 拒绝理由。
|
|
89482
|
-
*/
|
|
89483
|
-
function delegatedDenial(toolName) {
|
|
89484
|
-
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.`;
|
|
89485
|
-
}
|
|
89486
|
-
/**
|
|
89487
|
-
* 子代理还在跑时用 sleep 空等的拒绝文案。
|
|
89488
|
-
*
|
|
89489
|
-
* @returns 拒绝理由。
|
|
89490
|
-
*/
|
|
89491
|
-
function activeChildSleepDenial() {
|
|
89492
|
-
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.";
|
|
89493
|
-
}
|
|
89494
|
-
/**
|
|
89495
|
-
* 装一台「调度执行守卫」。
|
|
89496
|
-
*
|
|
89497
|
-
* 只用 `ctx.tools.guard()` 这一条执行期接缝:工具声明面(`tools:sdk` 段与顶层
|
|
89498
|
-
* 工具 schema)一个字节都不改,Kimi Code 的前缀缓存不会因为这个守卫重建。
|
|
89499
|
-
*
|
|
89500
|
-
* @param ctx - 宿主上下文。
|
|
89501
|
-
* @param options - 守卫选项。
|
|
89502
|
-
* @returns 注销守卫的函数;宿主没有 `guard` 接缝时是一个空操作。
|
|
89503
|
-
*/
|
|
89504
|
-
function installDispatchExecutionGuard(ctx, options = {}) {
|
|
89505
|
-
const tools = toolsOf$2(ctx);
|
|
89506
|
-
const register = tools?.guard;
|
|
89507
|
-
if (typeof register !== "function") return () => void 0;
|
|
89508
|
-
const enabled = options.enabled ?? (() => true);
|
|
89509
|
-
const delegatedBlocked = new Set(DEFAULT_DELEGATED_BLOCKED_TOOLS);
|
|
89510
|
-
const shellTools = new Set(DEFAULT_SHELL_TOOLS);
|
|
89511
|
-
const hasRunningChildren = options.hasRunningChildren;
|
|
89512
|
-
const guard = (execution) => {
|
|
89513
|
-
if (!isEnabled(enabled)) return void 0;
|
|
89514
|
-
const toolName = typeof execution?.name === "string" ? execution.name : void 0;
|
|
89515
|
-
if (toolName === void 0) return void 0;
|
|
89516
|
-
const agent = execution?.agent;
|
|
89517
|
-
if (delegatedBlocked.has(toolName) && isDelegatedCaller(agent, ctx)) return delegatedDenial(toolName);
|
|
89518
|
-
if (shellTools.has(toolName)) {
|
|
89519
|
-
const args = isRecord$11(execution?.arguments) ? execution.arguments : void 0;
|
|
89520
|
-
if (!(args?.["run_in_background"] === true) && isPureSleepCommand(args?.["command"])) {
|
|
89521
|
-
if (hasRunningChildren !== void 0 ? hasRunningChildren(agent) === true : hasRunningChildSubagent(agent, ctx)) return activeChildSleepDenial();
|
|
89522
|
-
}
|
|
89523
|
-
}
|
|
89524
|
-
};
|
|
89525
|
-
const dispose = register.call(tools, guard);
|
|
89526
|
-
return typeof dispose === "function" ? dispose : () => void 0;
|
|
89527
|
-
}
|
|
89528
|
-
/**
|
|
89529
|
-
* 读一次开关。读失败按**开启**处理:保护不该因为一次读失败而失效。
|
|
89530
|
-
*
|
|
89531
|
-
* @param enabled - 开关读取函数。
|
|
89532
|
-
* @returns 是否启用。
|
|
89533
|
-
*/
|
|
89534
|
-
function isEnabled(enabled) {
|
|
89535
|
-
try {
|
|
89536
|
-
return enabled() !== false;
|
|
89537
|
-
} catch {
|
|
89538
|
-
return true;
|
|
89539
|
-
}
|
|
89540
|
-
}
|
|
89541
89835
|
const ID_SCHEMA = z.string().min(1).max(64).regex(/^[A-Za-z0-9._:-]+$/);
|
|
89542
89836
|
const TASK_REFERENCE_SCHEMA = z.string().min(1).max(160);
|
|
89543
89837
|
const BOUNDARY_SCHEMA = z.string().min(1).max(120);
|
|
@@ -92883,23 +93177,16 @@ const DISPATCH_PRESET = {
|
|
|
92883
93177
|
name: "@deepseek-ai/dsh-persona",
|
|
92884
93178
|
config: {
|
|
92885
93179
|
suffix: "Your working directory is {{cwd}}.",
|
|
92886
|
-
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.
|
|
92887
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).
|
|
92888
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.
|
|
92889
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.
|
|
92890
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.
|
|
92891
93185
|
|
|
92892
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.
|
|
92893
|
-
[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.
|
|
92894
93188
|
|
|
92895
|
-
|
|
92896
|
-
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.
|
|
92897
|
-
Criterion: whether spawn_teammate exists (check via code_run). Never gate on wait_agent, send_message, list_agents, or interrupt_agent: this mode mounts those itself.
|
|
92898
|
-
- Absent -> Write "Orchestration ready: subagent" and proceed to R0. 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 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.
|
|
92899
|
-
- Present -> This session runs the legacy runtime and is **not orchestratable**. In order, and nothing else:
|
|
92900
|
-
1. State in one sentence that the legacy runtime shadows the coordination tools and this mode has no degraded path.
|
|
92901
|
-
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.
|
|
92902
|
-
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.
|
|
92903
93190
|
|
|
92904
93191
|
## R0 · Complexity Triage (Triage First, Then Choose the Workflow)
|
|
92905
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:
|
|
@@ -92970,7 +93257,7 @@ Fallback is a task-scoped, non-session-wide exception for delegated briefs: it c
|
|
|
92970
93257
|
|
|
92971
93258
|
## Anti-Patterns (Any Occurrence Is a Violation)
|
|
92972
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).
|
|
92973
|
-
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).
|
|
92974
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).
|
|
92975
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).
|
|
92976
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).
|
|
@@ -99769,6 +100056,23 @@ function applyToolDelta(entry, state) {
|
|
|
99769
100056
|
const fn = isRecord$3(entry.function) ? entry.function : {};
|
|
99770
100057
|
const out = [];
|
|
99771
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
|
+
}
|
|
99772
100076
|
if (call === void 0) {
|
|
99773
100077
|
out.push(...closeCurrent(state));
|
|
99774
100078
|
call = {
|
|
@@ -100138,6 +100442,30 @@ function messagesAssistantContent(message) {
|
|
|
100138
100442
|
return blocks;
|
|
100139
100443
|
}
|
|
100140
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
|
+
/**
|
|
100141
100469
|
* Build one `/v1/messages` body.
|
|
100142
100470
|
*
|
|
100143
100471
|
* `stream: true` is mandatory: the adapter reads every response as SSE, and a
|
|
@@ -100155,13 +100483,12 @@ function buildMessagesRequest(options, request = {}) {
|
|
|
100155
100483
|
const role = isToolResultMessage(message) || message.role !== "assistant" ? "user" : "assistant";
|
|
100156
100484
|
const content = role === "user" ? messagesUserContent(message, images) : messagesAssistantContent(message);
|
|
100157
100485
|
if (content.length === 0) continue;
|
|
100158
|
-
|
|
100159
|
-
if (previous !== void 0 && previous.role === role) previous.content.push(...content);
|
|
100160
|
-
else entries.push({
|
|
100486
|
+
entries.push({
|
|
100161
100487
|
role,
|
|
100162
100488
|
content
|
|
100163
100489
|
});
|
|
100164
100490
|
}
|
|
100491
|
+
const messages = cleanOrphanedToolCalls(mergeAnthropicMessages(entries), mergeAnthropicMessages);
|
|
100165
100492
|
const system = leadingSystemTextRaw(options);
|
|
100166
100493
|
const tools = options.tools ?? [];
|
|
100167
100494
|
const effort = request.effort !== void 0 && (request.efforts ?? []).length > 0 ? request.effort : void 0;
|
|
@@ -100170,7 +100497,7 @@ function buildMessagesRequest(options, request = {}) {
|
|
|
100170
100497
|
model: options.model,
|
|
100171
100498
|
max_tokens: maxTokens,
|
|
100172
100499
|
stream: true,
|
|
100173
|
-
messages
|
|
100500
|
+
messages,
|
|
100174
100501
|
...system === void 0 ? {} : { system },
|
|
100175
100502
|
...tools.length > 0 ? { tools: tools.map((tool) => ({
|
|
100176
100503
|
name: tool.name,
|
|
@@ -103920,6 +104247,10 @@ function apply(ctx, pluginConfig = {}) {
|
|
|
103920
104247
|
const guard = installPtcSdkCacheGuard(ctx);
|
|
103921
104248
|
return () => guard.dispose();
|
|
103922
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");
|
|
103923
104254
|
ctx.effect(() => {
|
|
103924
104255
|
const guard = installTeamPolicyCacheGuard(ctx, { enabled: () => resolveTeamPolicyCacheGuardEnabled(pluginConfig) });
|
|
103925
104256
|
return () => guard.dispose();
|