@xiaoso/dsh-tool-plus 0.1.16 → 0.1.17-beta.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/lib/{abort-DZ54CaKU.mjs → abort-BTblp0Rt.mjs} +2 -2
- package/lib/{alibaba-coding-plan-DODpkcqi.mjs → alibaba-coding-plan-t3R4YKCB.mjs} +3 -3
- package/lib/{alibaba-token-plan-C6lpKCda.mjs → alibaba-token-plan-CO4djG1y.mjs} +4 -4
- package/lib/{alibaba-token-plan-CHGyWOfX.mjs → alibaba-token-plan-CUjYJX0-.mjs} +1 -1
- package/lib/{anthropic-Dv_GGX6g.mjs → anthropic-nf7w6so1.mjs} +48 -21
- package/lib/{api-key-validation-MnMf_ihX.mjs → api-key-validation-C_tZ7Y9a.mjs} +2 -2
- package/lib/behavior-BwvTUtag.mjs +111 -0
- package/lib/{browser-render-BZXt548F.mjs → browser-render-BQaEVK_n.mjs} +4 -4
- package/lib/{reference-CtvM4zLU.mjs → bundled-references-CrQ4dQcT.mjs} +57 -4
- package/lib/cascade-BWjRTD1q.mjs +30265 -0
- package/lib/{cline-pass-BT9CBEOj.mjs → cline-pass-Bjm-O8GG.mjs} +2 -2
- package/lib/cloudflare-CKXRJ0l9.mjs +37 -0
- package/lib/{cloudflare-ai-gateway-DReN6ohJ.mjs → cloudflare-ai-gateway-BpnBSjwV.mjs} +8 -4
- package/lib/cloudflare-workers-ai-odj9XswL.mjs +32 -0
- package/lib/collapse-_nkb2dn7.mjs +1945 -0
- package/lib/{coreweave-C82HrLpb.mjs → coreweave-CGDZOD8-.mjs} +1 -1
- package/lib/{coreweave-C68UgRQO.mjs → coreweave-DwffcgW5.mjs} +4 -4
- package/lib/cursor-BgOuV7Qf.mjs +794 -0
- package/lib/{cursor-_gHHq-Dq.mjs → cursor-CF1iHHbv.mjs} +68 -19
- package/lib/{cursor-proto-Cr_WEMuv.mjs → cursor-proto-BuNTjX3L.mjs} +823 -23
- package/lib/{devin-QpfTSl9H.mjs → devin-7OEeEb80.mjs} +112 -31
- package/lib/{devin-proto-DYhp4Ty6.mjs → devin-proto-C-QreeAv.mjs} +71 -5
- package/lib/{dom-DG3sPESc.mjs → dom-BmbZv4v9.mjs} +598 -182
- package/lib/{error-O63pC8zg.mjs → error-8LVo7tug.mjs} +725 -104
- package/lib/factory-droid-ChhmsGWb.mjs +71 -0
- package/lib/{fs-promises-shim-B2YFWkcd.mjs → fs-promises-shim-CANAxFWh.mjs} +10 -1
- package/lib/{github-copilot-BMEcw8N1.mjs → github-copilot-QwevdT30.mjs} +4 -4
- package/lib/{github-copilot-headers-DnjGEbko.mjs → github-copilot-headers-CAUZ0rUD.mjs} +138 -26
- package/lib/{gitlab-duo-DnHqJjFY.mjs → gitlab-duo-DigV7k_o.mjs} +2 -2
- package/lib/{google-antigravity-B1mSckrK.mjs → google-antigravity-D-oe0r8A.mjs} +6 -7
- package/lib/{google-gemini-cli-DJwThCCn.mjs → google-gemini-cli-CQBHgGJT.mjs} +5 -6
- package/lib/{google-oauth-shared-BctLpVUN.mjs → google-oauth-shared-CvgVIUwJ.mjs} +2 -2
- package/lib/google-validation-CdvRj4ec.mjs +126 -0
- package/lib/id-EJwVLDHE.mjs +2548 -0
- package/lib/index.mjs +248 -258
- package/lib/{kilo-BEgEwMJQ.mjs → kilo-5r6OffCa.mjs} +2 -2
- package/lib/{kimi-T9NldEIJ.mjs → kimi-DOOtbXmm.mjs} +9 -10
- package/lib/{launch-BIWNyrBB.mjs → launch-DkAjib7h.mjs} +1 -1
- package/lib/{markit-Dvp2JPdT.mjs → markit-CCcyeAds.mjs} +359 -140
- package/lib/{models-DnXMYGcJ.mjs → models-DCpDT_im.mjs} +199203 -112275
- package/lib/{muse-code-CNvqqAp6.mjs → muse-code-CYf8zj_B.mjs} +5 -5
- package/lib/{openai-codex-D5-CyTxa.mjs → openai-codex-Cj-TvSFh.mjs} +13 -10
- package/lib/{perplexity-A2PEoGaC.mjs → perplexity-Dh_Qgsmx.mjs} +68 -25
- package/lib/{pkce-BYjmugmw.mjs → pkce-DO-jBJLV.mjs} +1 -1
- package/lib/pricing-DusBEhwm.mjs +593 -0
- package/lib/{readability-uGhqb4GC.mjs → readability-XHK0o3bv.mjs} +287 -27
- package/lib/{scrapers-C1ujjV8k.mjs → scrapers-B6PADOVm.mjs} +13 -13
- package/lib/slugify-ynYWBIA5.mjs +11 -0
- package/lib/snowflake-B_jap6lz.mjs +666 -0
- package/lib/snowflake-Cu1ZyOp6.mjs +151 -0
- package/lib/{src-AELUUb5U.mjs → src-BhinCSpi.mjs} +1172 -458
- package/lib/{stream-AVOoe5Hj.mjs → stream-D2ivg3GH.mjs} +3740 -5311
- package/lib/{turndown-D6fof1OX.mjs → turndown-Vya8SavL.mjs} +82 -30
- package/lib/types/tools/hashline/native/index.d.ts +2 -2
- package/lib/types/tools/hashline/native/policy.d.ts +19 -21
- package/lib/types/tools/omp/session/agent-storage.d.ts +3 -3
- package/lib/types/tools/shared/bun-named-shim.d.ts +5 -0
- package/lib/{types-BLrLohwK.mjs → types-tH1v9uRm.mjs} +2 -2
- package/lib/{utils-cZX3f_Ls.mjs → utils-C_Ncya1r.mjs} +1737 -509
- package/lib/utils-D2tK38xq.mjs +34006 -0
- package/lib/{utils-I4I8azHN.mjs → utils-DrDwmNtu.mjs} +8 -3
- package/lib/{xai-oauth-CbeldUSV.mjs → xai-oauth-DLLzX6my.mjs} +4 -4
- package/lib/{xiaomi-Dl3VSs04.mjs → xiaomi-CqK-KivK.mjs} +2 -2
- package/lib/{zai-FyjGSypr.mjs → zai-DoJ2xPIH.mjs} +2 -2
- package/lib/{zip-DRrycScC.mjs → zip-DG1mUV6X.mjs} +1 -1
- package/package.json +8 -8
- package/lib/amazon-bedrock-Dx0rr9dY.mjs +0 -996
- package/lib/anthropic-ClCw0PV_.mjs +0 -3624
- package/lib/anthropic-wire-lbGAFzYb.mjs +0 -927
- package/lib/azure-openai-responses-WE_bgFWp.mjs +0 -285
- package/lib/bundled-references-DY3EJxZV.mjs +0 -56
- package/lib/cloudflare-ai-gateway-CrMa97Ap.mjs +0 -44
- package/lib/collapse-CkMNRNr7.mjs +0 -2304
- package/lib/cursor-C6jaIJDg.mjs +0 -283
- package/lib/cursor-D-XZYDf_.mjs +0 -4544
- package/lib/deterministic-id-CUEIMSqR.mjs +0 -17
- package/lib/devin-ExGIghmx.mjs +0 -69
- package/lib/devin-u0ljw5P6.mjs +0 -628
- package/lib/effort-BdtQMN-_.mjs +0 -23
- package/lib/event-stream-BKEtb45Y.mjs +0 -167
- package/lib/gemini-headers-Co9cVvex.mjs +0 -54
- package/lib/google-auth-qAN-6DMW.mjs +0 -232
- package/lib/google-gemini-cli-B2Aw1S5w.mjs +0 -844
- package/lib/google-lTxuq28n.mjs +0 -38
- package/lib/google-shared-Y01j9xOr.mjs +0 -856
- package/lib/google-validation-BEkNs-Bx.mjs +0 -18
- package/lib/google-vertex-DcM-FRC5.mjs +0 -99
- package/lib/hosts-00rjRzUD.mjs +0 -203
- package/lib/id-AL5obQzR.mjs +0 -71
- package/lib/idle-iterator-D0ZXEcUq.mjs +0 -366
- package/lib/ollama-6R0oXZks.mjs +0 -574
- package/lib/openai-codex-responses-C8bnBWOe.mjs +0 -3232
- package/lib/openai-completions-DNr3mUsn.mjs +0 -1430
- package/lib/openai-configuration-update-xMYUjaK_.mjs +0 -150
- package/lib/openai-reasoning-fallback-Ju-5pSR8.mjs +0 -380
- package/lib/openai-responses-CjpafAEr.mjs +0 -861
- package/lib/protobuf-BMgDYu_U.mjs +0 -717
- package/lib/provider-response-SqKSkkUc.mjs +0 -22
- package/lib/proxy-DxvCQOCA.mjs +0 -230
- package/lib/request-debug-BwPOqN_j.mjs +0 -183
- package/lib/sanitize-text-BCf5KmCf.mjs +0 -33
- package/lib/sse-debug-B-tkLCPW.mjs +0 -11
- package/lib/stream-markup-healing-CN3RsqG9.mjs +0 -267
- package/lib/strict-tool-validation-CBTz1dAA.mjs +0 -105
- package/lib/taxonomy-DSIM99rS.mjs +0 -15392
- package/lib/thinking-ngMwf_1Y.mjs +0 -336
- package/lib/type-guards-CttAANEx.mjs +0 -11
- package/lib/utils-CE3DSebh.mjs +0 -11763
- package/lib/vision-guard-BCpXWUj3.mjs +0 -77
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { installBunShim as __installBunShim } from "./bun-shim.mjs";
|
|
2
2
|
__installBunShim();
|
|
3
|
-
import {
|
|
4
|
-
import { r as ValidationError } from "./error-
|
|
5
|
-
import {
|
|
6
|
-
import { i as
|
|
7
|
-
import {
|
|
8
|
-
|
|
3
|
+
import { E as debug, H as $env, S as parseJsonWithRepair, W as $flag, n as structuredCloneJSON, x as classifyJsonPrefix } from "./src-BhinCSpi.mjs";
|
|
4
|
+
import { r as ValidationError } from "./error-8LVo7tug.mjs";
|
|
5
|
+
import { h as isRecord, r as resolveCascade } from "./cascade-BWjRTD1q.mjs";
|
|
6
|
+
import { i as isBareIdReferenceProvider } from "./behavior-BwvTUtag.mjs";
|
|
7
|
+
import { o as resolveCatalogAxes } from "./id-EJwVLDHE.mjs";
|
|
8
|
+
import { l as classifyModel } from "./pricing-DusBEhwm.mjs";
|
|
9
|
+
import { i as buildModelReferenceIndex, r as toModelSpec } from "./bundled-references-CrQ4dQcT.mjs";
|
|
10
|
+
import { i as getBundledProviders, r as getBundledModels } from "./models-DCpDT_im.mjs";
|
|
11
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
12
|
+
import { formatLocalRefPointer, parseLocalRefPointer } from "@oh-my-pi/omptype";
|
|
13
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-utils@18.12.6/node_modules/@oh-my-pi/pi-utils/src/json.ts
|
|
9
14
|
/**
|
|
10
15
|
* Try to parse JSON, returning null on failure.
|
|
11
16
|
*/
|
|
@@ -26,10 +31,139 @@ function tryParseJson(content) {
|
|
|
26
31
|
* only lossless JSON representation.
|
|
27
32
|
*/
|
|
28
33
|
function stringifyJson$1(value, space) {
|
|
29
|
-
|
|
34
|
+
try {
|
|
35
|
+
return JSON.stringify(value, void 0, space);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
if (!(error instanceof TypeError)) throw error;
|
|
38
|
+
return JSON.stringify(value, (_key, item) => typeof item === "bigint" ? item.toString() : item, space);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-utils@18.12.6/node_modules/@oh-my-pi/pi-utils/src/sanitize-text.ts
|
|
43
|
+
const ESC_CHAR = "\x1B";
|
|
44
|
+
const CONTROL_RE = /[\x00-\x08\x0B-\x1F\x7F-\x9F]/g;
|
|
45
|
+
const REPLACEMENT_CHAR = "�";
|
|
46
|
+
function sanitizeText(text) {
|
|
47
|
+
const wellFormed = text.toWellFormed();
|
|
48
|
+
if (wellFormed !== text) return sanitizeWellFormedText(wellFormed.replaceAll(REPLACEMENT_CHAR, ""));
|
|
49
|
+
return sanitizeWellFormedText(text);
|
|
50
|
+
}
|
|
51
|
+
function sanitizeWellFormedText(text) {
|
|
52
|
+
CONTROL_RE.lastIndex = 0;
|
|
53
|
+
if (CONTROL_RE.exec(text) === null) return text;
|
|
54
|
+
const stripped = text.indexOf(ESC_CHAR) === -1 ? text : Bun.stripANSI(text);
|
|
55
|
+
CONTROL_RE.lastIndex = 0;
|
|
56
|
+
return stripped.replace(CONTROL_RE, "");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Escape the three XML-significant characters (`&`, `<`, `>`) in text destined
|
|
60
|
+
* for an XML/markup element body. Allocation-conscious: returns the input
|
|
61
|
+
* unchanged (same reference) when nothing needs escaping. Quotes are left as-is
|
|
62
|
+
* — use it for element text, not attribute values.
|
|
63
|
+
*/
|
|
64
|
+
function escapeXmlText(input) {
|
|
65
|
+
let firstEscapable = -1;
|
|
66
|
+
for (let index = 0; index < input.length; index++) {
|
|
67
|
+
const char = input.charCodeAt(index);
|
|
68
|
+
if (char === 38 || char === 60 || char === 62) {
|
|
69
|
+
firstEscapable = index;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (firstEscapable === -1) return input;
|
|
74
|
+
let output = input.slice(0, firstEscapable);
|
|
75
|
+
for (let index = firstEscapable; index < input.length; index++) {
|
|
76
|
+
const char = input[index];
|
|
77
|
+
if (char === "&") output += "&";
|
|
78
|
+
else if (char === "<") output += "<";
|
|
79
|
+
else if (char === ">") output += ">";
|
|
80
|
+
else output += char;
|
|
81
|
+
}
|
|
82
|
+
return output;
|
|
83
|
+
}
|
|
84
|
+
//#endregion
|
|
85
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/compat/catalog-policy.ts
|
|
86
|
+
/**
|
|
87
|
+
* Rule-owned catalog-axis policy by model. Resolve once per process rather
|
|
88
|
+
* than walking the static policy cascade on every accessor call. The key
|
|
89
|
+
* mirrors the cascade target inputs — `providerType ?? provider`, api, model
|
|
90
|
+
* id, and the reasoning flag; identity-derived class/family/revision facts are
|
|
91
|
+
* a pure function of provider + id. Bounded: one entry per distinct model.
|
|
92
|
+
*/
|
|
93
|
+
const catalogPolicyCache = /* @__PURE__ */ new Map();
|
|
94
|
+
const CATALOG_POLICY_CACHE_MAX = 8192;
|
|
95
|
+
/**
|
|
96
|
+
* The `catalog` axis bag authored in the KDL cascade rules for a model,
|
|
97
|
+
* memoized per distinct model. Frozen: the bag is shared across callers, so it
|
|
98
|
+
* must stay read-only — extract the value you need rather than handing it on.
|
|
99
|
+
*/
|
|
100
|
+
function resolveCatalogPolicy(model) {
|
|
101
|
+
const key = `${model.provider}\u0000${model.providerType ?? ""}\u0000${model.api}\u0000${model.id}\u0000${model.reasoning ? 1 : 0}`;
|
|
102
|
+
const cached = catalogPolicyCache.get(key);
|
|
103
|
+
if (cached !== void 0) return cached;
|
|
104
|
+
const policy = Object.freeze({ ...resolveCatalogAxes(toModelSpec(model)) });
|
|
105
|
+
if (catalogPolicyCache.size >= CATALOG_POLICY_CACHE_MAX) catalogPolicyCache.clear();
|
|
106
|
+
catalogPolicyCache.set(key, policy);
|
|
107
|
+
return policy;
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/compat/reasoning-carry.ts
|
|
111
|
+
/**
|
|
112
|
+
* Reasoning carry: whether reasoning a model produced on one host may replay
|
|
113
|
+
* natively on another host serving the same model.
|
|
114
|
+
*
|
|
115
|
+
* The model-side half is declared with the `portable-reasoning` catalog axis
|
|
116
|
+
* per family in `rules/classes/*.kdl`: the family's stored reasoning is its own
|
|
117
|
+
* full plaintext trace, and its identity pins one set of weights. A host whose
|
|
118
|
+
* reasoning must neither be carried in nor out overrides it to `#false` in its
|
|
119
|
+
* `rules/providers/*.kdl`. Whether the target host has a native slot for
|
|
120
|
+
* earlier reasoning is derived by the request encoders in `@oh-my-pi/pi-ai`,
|
|
121
|
+
* not declared here.
|
|
122
|
+
*
|
|
123
|
+
* Resolved through the cascade on demand (like delegation bias) because
|
|
124
|
+
* bundled rows are frozen by the generator; results are memoized per
|
|
125
|
+
* deployment.
|
|
126
|
+
*/
|
|
127
|
+
/** `null` records a deployment that does not carry reasoning. */
|
|
128
|
+
const portableIdentityMemo = /* @__PURE__ */ new Map();
|
|
129
|
+
/**
|
|
130
|
+
* The identity a deployment's reasoning is carried under, or `undefined` when
|
|
131
|
+
* the deployment's model family is not declared portable there. Class-only
|
|
132
|
+
* identities never qualify: they name a lineage, not a set of weights.
|
|
133
|
+
*/
|
|
134
|
+
function portableReasoningIdentity(provider, api, modelId) {
|
|
135
|
+
const key = `${provider}\0${api}\0${modelId}`;
|
|
136
|
+
const memo = portableIdentityMemo.get(key);
|
|
137
|
+
if (memo !== void 0) return memo ?? void 0;
|
|
138
|
+
const identity = classifyModel(provider, modelId, { lenient: true });
|
|
139
|
+
let portable = null;
|
|
140
|
+
if (identity.family !== void 0 || identity.revision !== void 0) {
|
|
141
|
+
if (resolveCascade({
|
|
142
|
+
provider,
|
|
143
|
+
api,
|
|
144
|
+
class: identity.class,
|
|
145
|
+
model: modelId,
|
|
146
|
+
reasoning: true,
|
|
147
|
+
...identity.family !== void 0 && { family: identity.family },
|
|
148
|
+
...identity.revision !== void 0 && { revision: identity.revision }
|
|
149
|
+
}).catalog.portableReasoning === true) portable = identity;
|
|
150
|
+
}
|
|
151
|
+
portableIdentityMemo.set(key, portable);
|
|
152
|
+
return portable ?? void 0;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Whether reasoning recorded on `source` may replay natively on `target`:
|
|
156
|
+
* both deployments declare the family portable and classify to the same
|
|
157
|
+
* class, family, and revision.
|
|
158
|
+
*/
|
|
159
|
+
function carriesReasoning(source, target) {
|
|
160
|
+
const to = portableReasoningIdentity(target.provider, target.api, target.id);
|
|
161
|
+
if (!to) return false;
|
|
162
|
+
const from = portableReasoningIdentity(source.provider, source.api, source.model);
|
|
163
|
+
return from !== void 0 && from.class === to.class && from.family === to.family && from.revision === to.revision;
|
|
30
164
|
}
|
|
31
165
|
//#endregion
|
|
32
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.
|
|
166
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/identity/bundled.ts
|
|
33
167
|
/**
|
|
34
168
|
* Memoized proxy-reference index over the bundled model catalog.
|
|
35
169
|
*
|
|
@@ -40,7 +174,7 @@ function stringifyJson$1(value, space) {
|
|
|
40
174
|
*/
|
|
41
175
|
let bundledModels;
|
|
42
176
|
function getBundledModelList() {
|
|
43
|
-
bundledModels ??= getBundledProviders().flatMap((provider) => getBundledModels(provider));
|
|
177
|
+
bundledModels ??= getBundledProviders().filter(isBareIdReferenceProvider).flatMap((provider) => getBundledModels(provider));
|
|
44
178
|
return bundledModels;
|
|
45
179
|
}
|
|
46
180
|
let referenceIndex;
|
|
@@ -65,10 +199,10 @@ function preferredDialect(modelId) {
|
|
|
65
199
|
}
|
|
66
200
|
}
|
|
67
201
|
//#endregion
|
|
68
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
202
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/anthropic.md
|
|
69
203
|
var anthropic_default = "## Format guide\n\nA call is a `<function_calls>` block wrapping one or more `<invoke>` blocks, each holding `<parameter>` children:\n\n```text\n<function_calls>\n<invoke name=\"tool_name\"><parameter name=\"arg_name\">arg value</parameter></invoke>\n</function_calls>\n```\n\nResults arrive later in a `<function_results>` block, one `<result>` per call (failures use `<error>` with `<stderr>` in place of `<result>` with `<stdout>`):\n\n```text\n<function_results>\n<result>\n<tool_name>tool_name</tool_name>\n<stdout>verbatim tool result</stdout>\n</result>\n</function_results>\n```\n\n## Rules\n\n- `name` MUST match a listed function.\n- String/scalar parameters: exact text, spaces preserved — bodies are read by regex (delimiter matching), NOT a real XML parser, so never HTML-escape them (emit `a & b`, not `a & b`; `<`/`>` stay literal); only the body's own `</parameter>` closing tag is reserved. Lists/objects: JSON.\n- Multiple calls: multiple `<invoke>` blocks in one `<function_calls>`.\n- You MAY write visible text before the calls.\n- NEVER emit `tool_calls` JSON.\n- NEVER use the legacy `<tool_name>`/`<parameters>` call syntax.\n- Read each `<result>`/`<error>` in call order. NEVER emit `<function_results>` yourself.\n- Emit the stop sequence ONLY after the call is fully written — NEVER announce a tool then stop (e.g. halting at \"Let's run `cargo clippy`\" with no `<invoke>` emitted). Write the complete call, THEN the stop sequence, THEN halt.\n";
|
|
70
204
|
//#endregion
|
|
71
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
205
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/utils/schema/types.ts
|
|
72
206
|
function isJsonObject(value) {
|
|
73
207
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
74
208
|
}
|
|
@@ -77,7 +211,7 @@ function isJsonObjectEmpty(value) {
|
|
|
77
211
|
return Object.keys(value).length === 0;
|
|
78
212
|
}
|
|
79
213
|
//#endregion
|
|
80
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
214
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/utils/schema/equality.ts
|
|
81
215
|
function areJsonValuesEqual(left, right) {
|
|
82
216
|
if (Object.is(left, right)) return true;
|
|
83
217
|
if (Array.isArray(left) || Array.isArray(right)) {
|
|
@@ -130,43 +264,41 @@ function mergePropertySchemas(existing, incoming) {
|
|
|
130
264
|
return mergedAnyOf.length === 1 ? mergedAnyOf[0] : { anyOf: mergedAnyOf };
|
|
131
265
|
}
|
|
132
266
|
//#endregion
|
|
133
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
267
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/utils/schema/stamps.ts
|
|
134
268
|
/**
|
|
135
|
-
*
|
|
269
|
+
* Lazy memoization keyed by host object identity, held in a module-level
|
|
270
|
+
* weak side table.
|
|
136
271
|
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
272
|
+
* The bookkeeping deliberately lives outside the host rather than in a
|
|
273
|
+
* non-enumerable symbol property: schema objects are caller-owned and may be
|
|
274
|
+
* sealed, frozen, or deep-frozen after their first traversal. A recursive
|
|
275
|
+
* freeze that enumerates with `Reflect.ownKeys` reaches symbol slots, so an
|
|
276
|
+
* on-host slot would be frozen along with the schema and every later write
|
|
277
|
+
* would throw. A side table is also invisible to `{...spread}`,
|
|
278
|
+
* `Object.keys`, `JSON.stringify`, and `toEqual`-style deep equality.
|
|
142
279
|
*
|
|
143
|
-
* Caveats:
|
|
280
|
+
* Caveats: an entry lives as long as the host object, even after callers
|
|
144
281
|
* release their references to the cached value — only use this for caches
|
|
145
|
-
* whose lifetime should match the host.
|
|
146
|
-
* `define` silently skips them, so memoization/visit-tracking degrades to
|
|
147
|
-
* best-effort (recompute on every call, no cycle protection) instead of
|
|
148
|
-
* throwing.
|
|
282
|
+
* whose lifetime should match the host.
|
|
149
283
|
*/
|
|
150
|
-
|
|
151
|
-
if (Object.isFrozen(target)) return;
|
|
152
|
-
Object.defineProperty(target, key, {
|
|
153
|
-
value,
|
|
154
|
-
writable: true,
|
|
155
|
-
configurable: true
|
|
156
|
-
});
|
|
157
|
-
}
|
|
284
|
+
const memos = /* @__PURE__ */ new WeakMap();
|
|
158
285
|
function stamp(target, key, compute) {
|
|
159
|
-
|
|
286
|
+
let slots = memos.get(target);
|
|
287
|
+
if (!slots) {
|
|
288
|
+
slots = /* @__PURE__ */ new Map();
|
|
289
|
+
memos.set(target, slots);
|
|
290
|
+
}
|
|
291
|
+
const existing = slots.get(key);
|
|
160
292
|
if (existing !== void 0) return existing;
|
|
161
293
|
const value = compute(target);
|
|
162
|
-
|
|
294
|
+
slots.set(key, value);
|
|
163
295
|
return value;
|
|
164
296
|
}
|
|
165
297
|
/**
|
|
166
|
-
* Epoch-keyed cycle guard. Cheaper than `WeakSet` for recursive
|
|
167
|
-
* because the marker is a single
|
|
168
|
-
* once and overwritten in place on every subsequent traversal —
|
|
169
|
-
*
|
|
298
|
+
* Epoch-keyed cycle guard. Cheaper than a per-call `WeakSet` for recursive
|
|
299
|
+
* traversal because the marker is a single side-table entry per host object,
|
|
300
|
+
* written once and overwritten in place on every subsequent traversal — no
|
|
301
|
+
* per-walk allocation.
|
|
170
302
|
*
|
|
171
303
|
* Usage:
|
|
172
304
|
* function walk(node, epoch = epochNext()) {
|
|
@@ -174,7 +306,7 @@ function stamp(target, key, compute) {
|
|
|
174
306
|
* for (const child of node.children) walk(child, epoch);
|
|
175
307
|
* }
|
|
176
308
|
*/
|
|
177
|
-
const
|
|
309
|
+
const epochs = /* @__PURE__ */ new WeakMap();
|
|
178
310
|
let __epoch = 0;
|
|
179
311
|
function epochNext() {
|
|
180
312
|
return ++__epoch;
|
|
@@ -185,24 +317,18 @@ function epochNext() {
|
|
|
185
317
|
* subsequent call within the same epoch.
|
|
186
318
|
*/
|
|
187
319
|
function once(target, epoch) {
|
|
188
|
-
const
|
|
189
|
-
const cur = slot[kEpoch];
|
|
320
|
+
const cur = epochs.get(target);
|
|
190
321
|
if (cur !== void 0 && cur >= epoch) return false;
|
|
191
|
-
|
|
192
|
-
else slot[kEpoch] = epoch;
|
|
322
|
+
epochs.set(target, epoch);
|
|
193
323
|
return true;
|
|
194
324
|
}
|
|
195
325
|
/**
|
|
196
326
|
* Counter-based path tracker. Use when a traversal needs to distinguish
|
|
197
327
|
* "currently on the recursion path" from "previously visited" — i.e. cycle
|
|
198
328
|
* detection that throws while still allowing DAG sharing. Increment on
|
|
199
|
-
* entry, decrement on exit; the
|
|
329
|
+
* entry, decrement on exit; the counter returns to 0 after a balanced walk so
|
|
200
330
|
* subsequent top-level calls see a fresh state without any reset.
|
|
201
331
|
*
|
|
202
|
-
* Unlike a `WeakSet` with `seen.delete(...)`, the property is never deleted
|
|
203
|
-
* — only incremented and decremented — so the host object's hidden class
|
|
204
|
-
* is never invalidated.
|
|
205
|
-
*
|
|
206
332
|
* Usage:
|
|
207
333
|
* function walk(node) {
|
|
208
334
|
* if (!enter(node)) throw new Error("cycle");
|
|
@@ -210,7 +336,7 @@ function once(target, epoch) {
|
|
|
210
336
|
* finally { exit(node); }
|
|
211
337
|
* }
|
|
212
338
|
*/
|
|
213
|
-
const
|
|
339
|
+
const depths = /* @__PURE__ */ new WeakMap();
|
|
214
340
|
/**
|
|
215
341
|
* Returns `true` on first entry, `false` if `target` is already on the
|
|
216
342
|
* current path. A `false` return does NOT deepen the counter — callers pair
|
|
@@ -219,24 +345,18 @@ const kDepth = Symbol("pi.schema.depth");
|
|
|
219
345
|
* make every later top-level walk of the same object misreport a cycle.
|
|
220
346
|
*/
|
|
221
347
|
function enter(target) {
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
define(target, kDepth, 1);
|
|
226
|
-
return true;
|
|
227
|
-
}
|
|
228
|
-
if (cur !== 0) return false;
|
|
229
|
-
slot[kDepth] = 1;
|
|
348
|
+
const cur = depths.get(target);
|
|
349
|
+
if (cur !== void 0 && cur !== 0) return false;
|
|
350
|
+
depths.set(target, 1);
|
|
230
351
|
return true;
|
|
231
352
|
}
|
|
232
353
|
function exit(target) {
|
|
233
|
-
const
|
|
234
|
-
const cur = slot[kDepth];
|
|
354
|
+
const cur = depths.get(target);
|
|
235
355
|
if (cur === void 0) return;
|
|
236
|
-
|
|
356
|
+
depths.set(target, cur - 1);
|
|
237
357
|
}
|
|
238
358
|
//#endregion
|
|
239
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
359
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/utils/schema/draft.ts
|
|
240
360
|
const JSON_SCHEMA_DRAFT_2020_12_URI = "https://json-schema.org/draft/2020-12/schema";
|
|
241
361
|
/** Draft-07 schema URIs we recognise as needing an upgrade. The trailing `#` is the canonical form in the JSON Schema spec, but providers (and Zod) emit both. */
|
|
242
362
|
const DRAFT_07_SCHEMA_URIS = {
|
|
@@ -250,7 +370,7 @@ const DRAFT_07_SCHEMA_URIS = {
|
|
|
250
370
|
* entry rather than the map object itself so legacy `definitions`-style refs
|
|
251
371
|
* inside property schemas get rewritten.
|
|
252
372
|
*/
|
|
253
|
-
const SCHEMA_MAP_KEYS$
|
|
373
|
+
const SCHEMA_MAP_KEYS$2 = {
|
|
254
374
|
properties: true,
|
|
255
375
|
patternProperties: true,
|
|
256
376
|
dependentSchemas: true
|
|
@@ -270,9 +390,16 @@ const NON_SCHEMA_VALUE_KEYS = {
|
|
|
270
390
|
dependentRequired: true,
|
|
271
391
|
type: true
|
|
272
392
|
};
|
|
273
|
-
/**
|
|
393
|
+
/**
|
|
394
|
+
* Rewrite draft-07's `#/definitions/Foo` ref form to draft 2020-12's
|
|
395
|
+
* `#/$defs/Foo`, decoding URI-fragment spellings such as
|
|
396
|
+
* `#%2Fdefinitions%2Ffoo` with the shared pointer parser first. External
|
|
397
|
+
* refs (`http://…`) pass through.
|
|
398
|
+
*/
|
|
274
399
|
function convertRef(value) {
|
|
275
|
-
|
|
400
|
+
const pointer = parseLocalRefPointer(value);
|
|
401
|
+
if (pointer === void 0 || pointer[0] !== "definitions") return value;
|
|
402
|
+
return formatLocalRefPointer(["$defs", ...pointer.slice(1)]);
|
|
276
403
|
}
|
|
277
404
|
/** Get-or-create a child object map on `target[key]`. Used to lazily build up `$defs`/`dependentRequired`/`dependentSchemas` during conversion. */
|
|
278
405
|
function getObjectMap(target, key) {
|
|
@@ -421,7 +548,7 @@ function schemaNeedsDraft202012UpgradeImpl(value, epoch) {
|
|
|
421
548
|
continue;
|
|
422
549
|
}
|
|
423
550
|
if (key === "items" && Array.isArray(entry)) return true;
|
|
424
|
-
if (key === "$defs" || key in SCHEMA_MAP_KEYS$
|
|
551
|
+
if (key === "$defs" || key in SCHEMA_MAP_KEYS$2) {
|
|
425
552
|
if (schemaMapNeedsDraft202012Upgrade(entry, epoch)) return true;
|
|
426
553
|
continue;
|
|
427
554
|
}
|
|
@@ -456,7 +583,7 @@ function upgradeJsonSchemaTo202012Impl(value, cache) {
|
|
|
456
583
|
if (isJsonObject(entry)) mergeSchemaMap(result, "$defs", entry, cache);
|
|
457
584
|
continue;
|
|
458
585
|
}
|
|
459
|
-
if (key in SCHEMA_MAP_KEYS$
|
|
586
|
+
if (key in SCHEMA_MAP_KEYS$2) {
|
|
460
587
|
copySchemaMap(result, key, entry, cache);
|
|
461
588
|
continue;
|
|
462
589
|
}
|
|
@@ -505,7 +632,7 @@ function upgradeJsonSchemaTo202012(schema) {
|
|
|
505
632
|
return upgradeJsonSchemaTo202012Impl(schema, /* @__PURE__ */ new WeakMap());
|
|
506
633
|
}
|
|
507
634
|
//#endregion
|
|
508
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
635
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/utils/schema/dereference.ts
|
|
509
636
|
/**
|
|
510
637
|
* Inline `$ref` / `$defs` in a JSON Schema so every consumer sees
|
|
511
638
|
* the full definition without needing a resolver.
|
|
@@ -517,17 +644,54 @@ function upgradeJsonSchemaTo202012(schema) {
|
|
|
517
644
|
*
|
|
518
645
|
* After dereferencing, `$defs` and `definitions` are stripped from the root.
|
|
519
646
|
*/
|
|
647
|
+
const SCHEMA_MAP_KEYS$1 = {
|
|
648
|
+
properties: true,
|
|
649
|
+
patternProperties: true,
|
|
650
|
+
dependencies: true,
|
|
651
|
+
dependentSchemas: true
|
|
652
|
+
};
|
|
653
|
+
const SCHEMA_ARRAY_KEYS$1 = {
|
|
654
|
+
anyOf: true,
|
|
655
|
+
oneOf: true,
|
|
656
|
+
allOf: true,
|
|
657
|
+
prefixItems: true
|
|
658
|
+
};
|
|
659
|
+
const SCHEMA_VALUE_KEYS$1 = {
|
|
660
|
+
items: true,
|
|
661
|
+
additionalItems: true,
|
|
662
|
+
contains: true,
|
|
663
|
+
contentSchema: true,
|
|
664
|
+
propertyNames: true,
|
|
665
|
+
if: true,
|
|
666
|
+
then: true,
|
|
667
|
+
else: true,
|
|
668
|
+
not: true,
|
|
669
|
+
additionalProperties: true,
|
|
670
|
+
unevaluatedItems: true,
|
|
671
|
+
unevaluatedProperties: true
|
|
672
|
+
};
|
|
673
|
+
function dereferenceKeyword(key, value, root, visiting) {
|
|
674
|
+
if (Object.hasOwn(SCHEMA_MAP_KEYS$1, key) && isJsonObject(value)) {
|
|
675
|
+
const result = {};
|
|
676
|
+
for (const name in value) result[name] = dereferenceNode(value[name], root, visiting);
|
|
677
|
+
return result;
|
|
678
|
+
}
|
|
679
|
+
if ((Object.hasOwn(SCHEMA_ARRAY_KEYS$1, key) || key === "items") && Array.isArray(value)) return value.map((item) => dereferenceNode(item, root, visiting));
|
|
680
|
+
if (Object.hasOwn(SCHEMA_VALUE_KEYS$1, key)) return dereferenceNode(value, root, visiting);
|
|
681
|
+
return value;
|
|
682
|
+
}
|
|
520
683
|
/**
|
|
521
684
|
* Resolve a JSON-pointer-style `$ref` against the root schema's `$defs`
|
|
522
685
|
* or `definitions` block. Returns `undefined` for external or unresolvable refs.
|
|
523
686
|
*/
|
|
524
687
|
function resolveLocalRef(ref, root) {
|
|
525
|
-
const
|
|
526
|
-
if (
|
|
527
|
-
const
|
|
688
|
+
const pointer = parseLocalRefPointer(ref);
|
|
689
|
+
if (pointer === void 0 || pointer.length !== 2) return void 0;
|
|
690
|
+
const defsKey = pointer[0];
|
|
691
|
+
if (defsKey !== "$defs" && defsKey !== "definitions") return void 0;
|
|
528
692
|
const defs = root[defsKey];
|
|
529
693
|
if (!isJsonObject(defs)) return void 0;
|
|
530
|
-
const resolved = defs[
|
|
694
|
+
const resolved = defs[pointer[1]];
|
|
531
695
|
return isJsonObject(resolved) ? resolved : void 0;
|
|
532
696
|
}
|
|
533
697
|
/**
|
|
@@ -535,7 +699,6 @@ function resolveLocalRef(ref, root) {
|
|
|
535
699
|
*/
|
|
536
700
|
function dereferenceNode(node, root, visiting) {
|
|
537
701
|
if (!isJsonObject(node)) return node;
|
|
538
|
-
if (Array.isArray(node)) return node.map((item) => dereferenceNode(item, root, visiting));
|
|
539
702
|
const ref = node.$ref;
|
|
540
703
|
if (typeof ref === "string") {
|
|
541
704
|
if (visiting.has(ref)) return {};
|
|
@@ -545,25 +708,23 @@ function dereferenceNode(node, root, visiting) {
|
|
|
545
708
|
const inlined = dereferenceNode(resolved, root, visiting);
|
|
546
709
|
visiting.delete(ref);
|
|
547
710
|
let hasSiblings = false;
|
|
548
|
-
for (const k in node) if (k !== "$ref") {
|
|
711
|
+
for (const k in node) if (k !== "$ref" && k !== "$defs" && k !== "definitions") {
|
|
549
712
|
hasSiblings = true;
|
|
550
713
|
break;
|
|
551
714
|
}
|
|
552
715
|
if (!hasSiblings || !isJsonObject(inlined)) return inlined;
|
|
553
|
-
const merged = {
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
716
|
+
const merged = { ...inlined };
|
|
717
|
+
for (const key in node) {
|
|
718
|
+
if (key === "$ref" || key === "$defs" || key === "definitions") continue;
|
|
719
|
+
merged[key] = dereferenceKeyword(key, node[key], root, visiting);
|
|
720
|
+
}
|
|
558
721
|
return merged;
|
|
559
722
|
}
|
|
560
723
|
const result = {};
|
|
561
724
|
for (const key in node) {
|
|
562
725
|
const value = node[key];
|
|
563
726
|
if (key === "$defs" || key === "definitions") continue;
|
|
564
|
-
|
|
565
|
-
else if (isJsonObject(value)) result[key] = dereferenceNode(value, root, visiting);
|
|
566
|
-
else result[key] = value;
|
|
727
|
+
result[key] = dereferenceKeyword(key, value, root, visiting);
|
|
567
728
|
}
|
|
568
729
|
return result;
|
|
569
730
|
}
|
|
@@ -583,7 +744,7 @@ function dereferenceJsonSchema(schema) {
|
|
|
583
744
|
return dereferenceNode(schema, schema, /* @__PURE__ */ new Set());
|
|
584
745
|
}
|
|
585
746
|
//#endregion
|
|
586
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
747
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/utils/schema/fields.ts
|
|
587
748
|
/**
|
|
588
749
|
* Field classification sets for JSON Schema sanitization across providers.
|
|
589
750
|
*
|
|
@@ -600,6 +761,8 @@ function dereferenceJsonSchema(schema) {
|
|
|
600
761
|
*/
|
|
601
762
|
const UNSUPPORTED_SCHEMA_FIELDS = {
|
|
602
763
|
$schema: true,
|
|
764
|
+
$id: true,
|
|
765
|
+
$anchor: true,
|
|
603
766
|
$ref: true,
|
|
604
767
|
$defs: true,
|
|
605
768
|
$dynamicRef: true,
|
|
@@ -613,6 +776,11 @@ const UNSUPPORTED_SCHEMA_FIELDS = {
|
|
|
613
776
|
propertyNames: true,
|
|
614
777
|
minItems: true,
|
|
615
778
|
maxItems: true,
|
|
779
|
+
uniqueItems: true,
|
|
780
|
+
contains: true,
|
|
781
|
+
minContains: true,
|
|
782
|
+
maxContains: true,
|
|
783
|
+
additionalItems: true,
|
|
616
784
|
minLength: true,
|
|
617
785
|
maxLength: true,
|
|
618
786
|
minimum: true,
|
|
@@ -622,6 +790,9 @@ const UNSUPPORTED_SCHEMA_FIELDS = {
|
|
|
622
790
|
multipleOf: true,
|
|
623
791
|
pattern: true,
|
|
624
792
|
format: true,
|
|
793
|
+
contentEncoding: true,
|
|
794
|
+
contentMediaType: true,
|
|
795
|
+
contentSchema: true,
|
|
625
796
|
dependencies: true,
|
|
626
797
|
dependentSchemas: true,
|
|
627
798
|
dependentRequired: true,
|
|
@@ -791,6 +962,8 @@ const COMBINATOR_KEYS = [
|
|
|
791
962
|
*/
|
|
792
963
|
const CCA_UNSUPPORTED_SCHEMA_FIELDS = {
|
|
793
964
|
$schema: true,
|
|
965
|
+
$id: true,
|
|
966
|
+
$anchor: true,
|
|
794
967
|
$ref: true,
|
|
795
968
|
$defs: true,
|
|
796
969
|
$dynamicRef: true,
|
|
@@ -799,13 +972,18 @@ const CCA_UNSUPPORTED_SCHEMA_FIELDS = {
|
|
|
799
972
|
deprecated: true,
|
|
800
973
|
readOnly: true,
|
|
801
974
|
writeOnly: true,
|
|
802
|
-
$comment: true
|
|
975
|
+
$comment: true,
|
|
976
|
+
uniqueItems: true,
|
|
977
|
+
contains: true,
|
|
978
|
+
minContains: true,
|
|
979
|
+
maxContains: true,
|
|
980
|
+
additionalItems: true,
|
|
981
|
+
contentEncoding: true,
|
|
982
|
+
contentMediaType: true,
|
|
983
|
+
contentSchema: true
|
|
803
984
|
};
|
|
804
985
|
//#endregion
|
|
805
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
806
|
-
function isPlainObject(value) {
|
|
807
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
808
|
-
}
|
|
986
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/utils/schema/meta-validator.ts
|
|
809
987
|
const TYPE_NAMES = {
|
|
810
988
|
string: true,
|
|
811
989
|
number: true,
|
|
@@ -836,14 +1014,14 @@ function checkSchemaArray(value, epoch) {
|
|
|
836
1014
|
return Array.isArray(value) && value.every((entry) => checkNode(entry, epoch));
|
|
837
1015
|
}
|
|
838
1016
|
function checkSchemaMap(value, epoch) {
|
|
839
|
-
if (!
|
|
1017
|
+
if (!isRecord(value)) return false;
|
|
840
1018
|
for (const k in value) if (!checkNode(value[k], epoch)) return false;
|
|
841
1019
|
return true;
|
|
842
1020
|
}
|
|
843
1021
|
/** Validate a single sub-schema node. */
|
|
844
1022
|
function checkNode(node, epoch) {
|
|
845
1023
|
if (node === true || node === false) return true;
|
|
846
|
-
if (!
|
|
1024
|
+
if (!isRecord(node)) return false;
|
|
847
1025
|
if (!once(node, epoch)) return true;
|
|
848
1026
|
if ("type" in node && !checkTypeKeyword(node.type)) return false;
|
|
849
1027
|
for (const key of [
|
|
@@ -893,7 +1071,7 @@ function checkNode(node, epoch) {
|
|
|
893
1071
|
if ("dependentSchemas" in node && !checkSchemaMap(node.dependentSchemas, epoch)) return false;
|
|
894
1072
|
if ("dependentRequired" in node) {
|
|
895
1073
|
const value = node.dependentRequired;
|
|
896
|
-
if (!
|
|
1074
|
+
if (!isRecord(value)) return false;
|
|
897
1075
|
for (const k in value) {
|
|
898
1076
|
const entry = value[k];
|
|
899
1077
|
if (!Array.isArray(entry) || !entry.every((item) => typeof item === "string")) return false;
|
|
@@ -943,7 +1121,7 @@ function isValidJsonSchema(schema) {
|
|
|
943
1121
|
}
|
|
944
1122
|
}
|
|
945
1123
|
//#endregion
|
|
946
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
1124
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/utils/schema/spill.ts
|
|
947
1125
|
function formatSpillValue(value) {
|
|
948
1126
|
return JSON.stringify(value);
|
|
949
1127
|
}
|
|
@@ -974,7 +1152,7 @@ function spillToDescription(node, entries, format = "spill") {
|
|
|
974
1152
|
node.description = existing ? `${existing}\n\n${formatted}` : formatted;
|
|
975
1153
|
}
|
|
976
1154
|
//#endregion
|
|
977
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
1155
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/utils/schema/normalize.ts
|
|
978
1156
|
/**
|
|
979
1157
|
* Provider-specific JSON Schema normalization used in the request path.
|
|
980
1158
|
*
|
|
@@ -1144,6 +1322,45 @@ function preHandleNullFields(obj) {
|
|
|
1144
1322
|
} else out.anyOf = kept;
|
|
1145
1323
|
return out;
|
|
1146
1324
|
}
|
|
1325
|
+
/**
|
|
1326
|
+
* Rewrites a multi-type `type` array (`["string", "array"]`) as one `anyOf`
|
|
1327
|
+
* branch per non-null type, each carrying only the keywords that constrain its
|
|
1328
|
+
* type. Collapsing to the first type instead narrows what the tool accepts and
|
|
1329
|
+
* strands the other types' keywords: Gemini rejects `items` beside
|
|
1330
|
+
* `type: "string"` with HTTP 400. A `null` member becomes `nullable: true`, as
|
|
1331
|
+
* in the scalar collapse. Returns `obj` itself when it has fewer than two
|
|
1332
|
+
* non-null types or already carries `anyOf`.
|
|
1333
|
+
*/
|
|
1334
|
+
function splitTypeArrayIntoAnyOf(obj) {
|
|
1335
|
+
if (!Array.isArray(obj.type) || Array.isArray(obj.anyOf)) return obj;
|
|
1336
|
+
const types = [];
|
|
1337
|
+
for (const type of obj.type) if (typeof type === "string" && type !== "null" && !types.includes(type)) types.push(type);
|
|
1338
|
+
if (types.length < 2) return obj;
|
|
1339
|
+
const branches = types.map((type) => {
|
|
1340
|
+
return {
|
|
1341
|
+
schema: { type },
|
|
1342
|
+
keys: CLOUD_CODE_ASSIST_TYPE_SPECIFIC_KEYS[type] ?? {}
|
|
1343
|
+
};
|
|
1344
|
+
});
|
|
1345
|
+
const out = {};
|
|
1346
|
+
for (const key in obj) {
|
|
1347
|
+
if (!Object.hasOwn(obj, key) || key === "type") continue;
|
|
1348
|
+
const value = obj[key];
|
|
1349
|
+
if (!Object.hasOwn(ALL_CCA_TYPE_SPECIFIC_KEYS, key)) {
|
|
1350
|
+
out[key] = value;
|
|
1351
|
+
continue;
|
|
1352
|
+
}
|
|
1353
|
+
for (const branch of branches) if (Object.hasOwn(branch.keys, key)) branch.schema[key] = value;
|
|
1354
|
+
}
|
|
1355
|
+
if (obj.type.includes("null")) out.nullable = true;
|
|
1356
|
+
out.anyOf = branches.map((branch) => branch.schema);
|
|
1357
|
+
return out;
|
|
1358
|
+
}
|
|
1359
|
+
/** Deletes keywords that constrain a JSON type other than `type`, e.g. `items` on a string node. */
|
|
1360
|
+
function dropForeignTypeKeywords(schema, type) {
|
|
1361
|
+
const allowed = CLOUD_CODE_ASSIST_TYPE_SPECIFIC_KEYS[type] ?? {};
|
|
1362
|
+
for (const key in schema) if (Object.hasOwn(ALL_CCA_TYPE_SPECIFIC_KEYS, key) && !Object.hasOwn(allowed, key)) delete schema[key];
|
|
1363
|
+
}
|
|
1147
1364
|
function outHasOwn(obj, key) {
|
|
1148
1365
|
return Object.hasOwn(obj, key);
|
|
1149
1366
|
}
|
|
@@ -1198,6 +1415,7 @@ function normalizeSchemaNode(value, options) {
|
|
|
1198
1415
|
}
|
|
1199
1416
|
function normalizeSchemaObjectNode(value, options) {
|
|
1200
1417
|
let obj = options.normalizeFieldNames && !options.insideSchemaMap ? applySnakeCaseRenames(value) : value;
|
|
1418
|
+
if (options.scalarizeTypeArrays && !options.insideSchemaMap) obj = splitTypeArrayIntoAnyOf(obj);
|
|
1201
1419
|
if (options.collapseNullFields && !options.insideSchemaMap) obj = preHandleNullFields(obj);
|
|
1202
1420
|
const result = {};
|
|
1203
1421
|
let spill;
|
|
@@ -1262,11 +1480,12 @@ function normalizeSchemaObjectNode(value, options) {
|
|
|
1262
1480
|
booleanIsSubschema: childKind === "schema"
|
|
1263
1481
|
}) : entry;
|
|
1264
1482
|
}
|
|
1265
|
-
if (options.
|
|
1483
|
+
if (options.scalarizeTypeArrays && Array.isArray(result.type)) {
|
|
1266
1484
|
const types = result.type.filter((t) => typeof t === "string");
|
|
1267
1485
|
const nonNull = types.filter((t) => t !== "null");
|
|
1268
1486
|
if (types.includes("null") && !options.stripNullableKeyword) result.nullable = true;
|
|
1269
1487
|
result.type = nonNull[0] ?? types[0];
|
|
1488
|
+
if (typeof result.type === "string") dropForeignTypeKeywords(result, result.type);
|
|
1270
1489
|
}
|
|
1271
1490
|
if (constValue !== void 0) {
|
|
1272
1491
|
const existingEnum = Array.isArray(result.enum) ? result.enum : [];
|
|
@@ -1414,11 +1633,7 @@ function collapseMixedTypeCombinerVariants(schema, combiner) {
|
|
|
1414
1633
|
const chosenType = variantTypes.filter((t) => t !== "null")[0] ?? variantTypes[0];
|
|
1415
1634
|
nextSchema.type = chosenType;
|
|
1416
1635
|
const chosenTypeAllowedKeys = CLOUD_CODE_ASSIST_TYPE_SPECIFIC_KEYS[chosenType] ?? {};
|
|
1417
|
-
|
|
1418
|
-
if (!Object.hasOwn(nextSchema, key)) continue;
|
|
1419
|
-
if (key === "type") continue;
|
|
1420
|
-
if (Object.hasOwn(ALL_CCA_TYPE_SPECIFIC_KEYS, key) && !Object.hasOwn(chosenTypeAllowedKeys, key) && !Object.hasOwn(CLOUD_CODE_ASSIST_SHARED_SCHEMA_KEYS, key)) delete nextSchema[key];
|
|
1421
|
-
}
|
|
1636
|
+
dropForeignTypeKeywords(nextSchema, chosenType);
|
|
1422
1637
|
for (const key in mergedVariantFields) {
|
|
1423
1638
|
if (!Object.hasOwn(mergedVariantFields, key)) continue;
|
|
1424
1639
|
if (!Object.hasOwn(chosenTypeAllowedKeys, key) && !Object.hasOwn(CLOUD_CODE_ASSIST_SHARED_SCHEMA_KEYS, key)) continue;
|
|
@@ -1811,7 +2026,7 @@ function normalizeSchemaForGoogle(value) {
|
|
|
1811
2026
|
unsupportedFields: isGoogleUnsupportedSchemaField,
|
|
1812
2027
|
normalizeFieldNames: true,
|
|
1813
2028
|
collapseNullFields: true,
|
|
1814
|
-
|
|
2029
|
+
scalarizeTypeArrays: true,
|
|
1815
2030
|
stripNullableKeyword: false,
|
|
1816
2031
|
autoPropertyOrdering: true,
|
|
1817
2032
|
ensureObjectProperties: true,
|
|
@@ -1833,7 +2048,7 @@ function normalizeSchemaForCCA(value) {
|
|
|
1833
2048
|
unsupportedFields: isGoogleUnsupportedSchemaField,
|
|
1834
2049
|
normalizeFieldNames: true,
|
|
1835
2050
|
collapseNullFields: false,
|
|
1836
|
-
|
|
2051
|
+
scalarizeTypeArrays: true,
|
|
1837
2052
|
stripNullableKeyword: true,
|
|
1838
2053
|
autoPropertyOrdering: false,
|
|
1839
2054
|
ensureObjectProperties: true,
|
|
@@ -1868,8 +2083,9 @@ function normalizeSchemaForCCA(value) {
|
|
|
1868
2083
|
* rejected; collapse to `enum` with an inferred scalar `type`.
|
|
1869
2084
|
* - `oneOf` is not an MFJS combinator (only `anyOf` is); residual `oneOf` is
|
|
1870
2085
|
* folded into `anyOf`.
|
|
1871
|
-
* - `type` must be a scalar string; `
|
|
1872
|
-
*
|
|
2086
|
+
* - `type` must be a scalar string; `["T", "null"]` reduces to `T` (the
|
|
2087
|
+
* `null` member is dropped — `nullable` is unsupported) and a multi-type
|
|
2088
|
+
* array becomes one typed `anyOf` branch per type.
|
|
1873
2089
|
* - Enum-bearing nodes get an inferred `type` (the idiomatic MFJS form; a bare
|
|
1874
2090
|
* `enum` is valid too) so `anyOf` branches always carry a `type`.
|
|
1875
2091
|
* - Validation/decorative keywords (`minItems`, `maxItems`, `maxLength`,
|
|
@@ -1892,7 +2108,7 @@ function normalizeSchemaForMoonshot(value) {
|
|
|
1892
2108
|
unsupportedFields: isMoonshotUnsupportedSchemaField,
|
|
1893
2109
|
normalizeFieldNames: false,
|
|
1894
2110
|
collapseNullFields: false,
|
|
1895
|
-
|
|
2111
|
+
scalarizeTypeArrays: true,
|
|
1896
2112
|
stripNullableKeyword: true,
|
|
1897
2113
|
autoPropertyOrdering: false,
|
|
1898
2114
|
ensureObjectProperties: false,
|
|
@@ -2295,12 +2511,12 @@ function inferStrictPrimitiveTypeFromEnumOrConst(node) {
|
|
|
2295
2511
|
return inferred;
|
|
2296
2512
|
}
|
|
2297
2513
|
/**
|
|
2298
|
-
* Per-schema-object memoization
|
|
2299
|
-
* is
|
|
2300
|
-
*
|
|
2514
|
+
* Per-schema-object memoization key. The result of `tryEnforceStrictSchema`
|
|
2515
|
+
* is memoized against the input via `stamp(target, kStrictSchema, …)` so
|
|
2516
|
+
* repeated calls (different providers, retries, batching) reuse the same
|
|
2301
2517
|
* computed pair without re-walking the tree.
|
|
2302
2518
|
*/
|
|
2303
|
-
const kStrictSchema = Symbol("
|
|
2519
|
+
const kStrictSchema = Symbol("omp.schema.strict");
|
|
2304
2520
|
/**
|
|
2305
2521
|
* A boolean schema (`true`/`false`) or the empty object schema `{}`: an
|
|
2306
2522
|
* unconstrained branch with no declared type. Strict providers (OpenAI/Codex)
|
|
@@ -2671,24 +2887,21 @@ function tryEnforceStrictSchema(schema) {
|
|
|
2671
2887
|
});
|
|
2672
2888
|
}
|
|
2673
2889
|
/**
|
|
2674
|
-
* Resolve a
|
|
2675
|
-
* OpenAI SDK's `resolve_ref` helper
|
|
2676
|
-
* supported, and each segment must dereference to a dictionary.
|
|
2677
|
-
* Cite: openai-python/src/openai/lib/_pydantic.py:118-129
|
|
2890
|
+
* Resolve a URI-fragment JSON Pointer against the root schema. Each segment
|
|
2891
|
+
* must dereference to a dictionary, as in the OpenAI SDK's `resolve_ref` helper.
|
|
2678
2892
|
*/
|
|
2679
2893
|
function resolveStrictRef(root, ref) {
|
|
2680
|
-
|
|
2681
|
-
|
|
2894
|
+
const pointer = parseLocalRefPointer(ref);
|
|
2895
|
+
if (pointer === void 0 || pointer.length === 0) return void 0;
|
|
2682
2896
|
let cursor = root;
|
|
2683
|
-
for (const
|
|
2897
|
+
for (const segment of pointer) {
|
|
2684
2898
|
if (!isJsonObject(cursor)) return void 0;
|
|
2685
|
-
const segment = raw.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
2686
2899
|
cursor = cursor[segment];
|
|
2687
2900
|
}
|
|
2688
2901
|
return isJsonObject(cursor) ? cursor : void 0;
|
|
2689
2902
|
}
|
|
2690
2903
|
//#endregion
|
|
2691
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
2904
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/utils/schema/adapt.ts
|
|
2692
2905
|
/**
|
|
2693
2906
|
* Set when callers want to globally bypass OpenAI strict-mode enforcement
|
|
2694
2907
|
* (e.g. for debugging a provider that misreports strict support, or when
|
|
@@ -2721,7 +2934,212 @@ function adaptSchemaForStrict(schema, strict) {
|
|
|
2721
2934
|
({ ...UNSUPPORTED_SCHEMA_FIELDS });
|
|
2722
2935
|
({ ...CCA_UNSUPPORTED_SCHEMA_FIELDS });
|
|
2723
2936
|
//#endregion
|
|
2724
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
2937
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/utils/schema/foundation-models.ts
|
|
2938
|
+
/**
|
|
2939
|
+
* Lowers tool JSON Schemas into the dialect Apple's `GenerationSchema` Codable
|
|
2940
|
+
* decoder accepts (Foundation Models, `apple-fm` provider).
|
|
2941
|
+
*
|
|
2942
|
+
* The decoder is strict: every object needs `title`, `x-order` (which also
|
|
2943
|
+
* selects the generated properties), `required`, and
|
|
2944
|
+
* `additionalProperties: false`; `anyOf` needs a `title`; a node must carry
|
|
2945
|
+
* `type`, `const`, `$ref`, or `anyOf`. Constructs it cannot express — free-form
|
|
2946
|
+
* maps, open `{}` subschemas, tuples, mixed-type enums, `allOf` — are generated
|
|
2947
|
+
* as JSON-encoded strings instead, and {@link decodeFoundationModelsArguments}
|
|
2948
|
+
* parses those back so tools receive the arguments their schema describes.
|
|
2949
|
+
*
|
|
2950
|
+
* @example
|
|
2951
|
+
* const { schema, encodedPaths } = toFoundationModelsSchema(toolWireSchema(tool), tool.name);
|
|
2952
|
+
* // …model responds with arguments…
|
|
2953
|
+
* const args = decodeFoundationModelsArguments(rawArgs, encodedPaths);
|
|
2954
|
+
*/
|
|
2955
|
+
const ENCODED_SUFFIX = "(JSON-encoded value)";
|
|
2956
|
+
/** Converts a tool's wire JSON Schema into Foundation Models' dialect. */
|
|
2957
|
+
function toFoundationModelsSchema(schema, name) {
|
|
2958
|
+
const encodedPaths = [];
|
|
2959
|
+
const root = dereferenceJsonSchema(schema);
|
|
2960
|
+
const lowered = lower(root, titleOf(name), [], encodedPaths);
|
|
2961
|
+
if (lowered?.type === "object") return {
|
|
2962
|
+
schema: lowered,
|
|
2963
|
+
encodedPaths
|
|
2964
|
+
};
|
|
2965
|
+
return {
|
|
2966
|
+
schema: object(titleOf(name), {}, [], describe(root)),
|
|
2967
|
+
encodedPaths: []
|
|
2968
|
+
};
|
|
2969
|
+
}
|
|
2970
|
+
/** Parses the JSON-encoded argument values produced for {@link FoundationModelsSchema.encodedPaths}. */
|
|
2971
|
+
function decodeFoundationModelsArguments(args, encodedPaths) {
|
|
2972
|
+
for (const path of encodedPaths) decodeAt(args, path, 0);
|
|
2973
|
+
return args;
|
|
2974
|
+
}
|
|
2975
|
+
function decodeAt(container, path, index) {
|
|
2976
|
+
const key = path[index];
|
|
2977
|
+
const last = index === path.length - 1;
|
|
2978
|
+
if (key === "*") {
|
|
2979
|
+
if (!Array.isArray(container)) return;
|
|
2980
|
+
for (let i = 0; i < container.length; i++) if (last) container[i] = parseEncoded(container[i]);
|
|
2981
|
+
else decodeAt(container[i], path, index + 1);
|
|
2982
|
+
return;
|
|
2983
|
+
}
|
|
2984
|
+
if (!isJsonObject(container) || !Object.hasOwn(container, key)) return;
|
|
2985
|
+
if (last) container[key] = parseEncoded(container[key]);
|
|
2986
|
+
else decodeAt(container[key], path, index + 1);
|
|
2987
|
+
}
|
|
2988
|
+
function parseEncoded(value) {
|
|
2989
|
+
if (typeof value !== "string") return value;
|
|
2990
|
+
try {
|
|
2991
|
+
return JSON.parse(value);
|
|
2992
|
+
} catch {
|
|
2993
|
+
return value;
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
/**
|
|
2997
|
+
* Lowers one subschema. Returns `undefined` when the node is not expressible;
|
|
2998
|
+
* the caller then encodes it as a JSON string when `encoded` is non-null, or
|
|
2999
|
+
* propagates the failure (inside `anyOf`, where an encoded branch would make
|
|
3000
|
+
* decoding ambiguous).
|
|
3001
|
+
*/
|
|
3002
|
+
function lower(node, title, path, encoded) {
|
|
3003
|
+
if (!isJsonObject(node)) return void 0;
|
|
3004
|
+
const description = describe(node);
|
|
3005
|
+
const lowered = lowerShape(node, title, path, encoded);
|
|
3006
|
+
if (lowered && description !== void 0 && lowered.description === void 0) lowered.description = description;
|
|
3007
|
+
return lowered;
|
|
3008
|
+
}
|
|
3009
|
+
function lowerShape(node, title, path, encoded) {
|
|
3010
|
+
if (Object.hasOwn(node, "const")) return typeof node.const === "string" ? { const: node.const } : void 0;
|
|
3011
|
+
if (Array.isArray(node.enum)) return node.enum.length > 0 && node.enum.every((value) => typeof value === "string") ? {
|
|
3012
|
+
type: "string",
|
|
3013
|
+
enum: node.enum
|
|
3014
|
+
} : void 0;
|
|
3015
|
+
const branches = [...Array.isArray(node.anyOf) ? node.anyOf : [], ...Array.isArray(node.oneOf) ? node.oneOf : []];
|
|
3016
|
+
if (branches.length > 0) return lowerUnion(node, branches, title, path, encoded);
|
|
3017
|
+
if (Array.isArray(node.allOf)) {
|
|
3018
|
+
if (node.allOf.length !== 1 || !isJsonObject(node.allOf[0])) return void 0;
|
|
3019
|
+
const { allOf: _, ...rest } = node;
|
|
3020
|
+
return lower({
|
|
3021
|
+
...rest,
|
|
3022
|
+
...node.allOf[0]
|
|
3023
|
+
}, title, path, encoded);
|
|
3024
|
+
}
|
|
3025
|
+
if (Array.isArray(node.type)) {
|
|
3026
|
+
const types = [...new Set(node.type.filter((type) => type !== "null"))];
|
|
3027
|
+
if (types.length === 0) return { type: "null" };
|
|
3028
|
+
if (types.length === 1) return lowerShape({
|
|
3029
|
+
...node,
|
|
3030
|
+
type: types[0]
|
|
3031
|
+
}, title, path, encoded);
|
|
3032
|
+
return lowerUnion(node, types.map((type) => ({
|
|
3033
|
+
...node,
|
|
3034
|
+
type
|
|
3035
|
+
})), title, path, encoded);
|
|
3036
|
+
}
|
|
3037
|
+
const type = node.type ?? (isJsonObject(node.properties) ? "object" : void 0);
|
|
3038
|
+
switch (type) {
|
|
3039
|
+
case "string":
|
|
3040
|
+
case "boolean":
|
|
3041
|
+
case "null": return { type };
|
|
3042
|
+
case "integer":
|
|
3043
|
+
case "number": {
|
|
3044
|
+
const out = { type };
|
|
3045
|
+
if (typeof node.minimum === "number") out.minimum = node.minimum;
|
|
3046
|
+
if (typeof node.maximum === "number") out.maximum = node.maximum;
|
|
3047
|
+
return out;
|
|
3048
|
+
}
|
|
3049
|
+
case "array": return lowerArray(node, title, path, encoded);
|
|
3050
|
+
case "object": return lowerObject(node, title, path, encoded);
|
|
3051
|
+
default: return;
|
|
3052
|
+
}
|
|
3053
|
+
}
|
|
3054
|
+
function lowerUnion(node, branches, title, path, encoded) {
|
|
3055
|
+
const { anyOf: _a, oneOf: _o, type: _t, ...shared } = node;
|
|
3056
|
+
const options = branches.filter((branch) => !(isJsonObject(branch) && branch.type === "null"));
|
|
3057
|
+
if (options.length === 0) return { type: "null" };
|
|
3058
|
+
if (options.length === 1) return isJsonObject(options[0]) ? lower({
|
|
3059
|
+
...shared,
|
|
3060
|
+
...options[0]
|
|
3061
|
+
}, title, path, encoded) : void 0;
|
|
3062
|
+
const literals = options.flatMap((option) => stringLiterals(option) ?? [null]);
|
|
3063
|
+
if (!literals.includes(null)) return {
|
|
3064
|
+
type: "string",
|
|
3065
|
+
enum: [...new Set(literals)]
|
|
3066
|
+
};
|
|
3067
|
+
const anyOf = [];
|
|
3068
|
+
for (let i = 0; i < options.length; i++) {
|
|
3069
|
+
const option = options[i];
|
|
3070
|
+
const lowered = lower(isJsonObject(option) ? {
|
|
3071
|
+
...shared,
|
|
3072
|
+
...option
|
|
3073
|
+
} : option, `${title}_${i}`, path, null);
|
|
3074
|
+
if (!lowered) return void 0;
|
|
3075
|
+
delete lowered.description;
|
|
3076
|
+
anyOf.push(lowered);
|
|
3077
|
+
}
|
|
3078
|
+
return {
|
|
3079
|
+
title,
|
|
3080
|
+
anyOf
|
|
3081
|
+
};
|
|
3082
|
+
}
|
|
3083
|
+
function stringLiterals(node) {
|
|
3084
|
+
if (!isJsonObject(node)) return void 0;
|
|
3085
|
+
if (typeof node.const === "string") return [node.const];
|
|
3086
|
+
if (Array.isArray(node.enum) && node.enum.every((value) => typeof value === "string")) return node.enum;
|
|
3087
|
+
}
|
|
3088
|
+
function lowerArray(node, title, path, encoded) {
|
|
3089
|
+
if (Array.isArray(node.items) || Array.isArray(node.prefixItems)) return void 0;
|
|
3090
|
+
const items = child(node.items ?? true, `${title}_item`, [...path, "*"], encoded);
|
|
3091
|
+
if (!items) return void 0;
|
|
3092
|
+
const out = {
|
|
3093
|
+
type: "array",
|
|
3094
|
+
items
|
|
3095
|
+
};
|
|
3096
|
+
if (typeof node.minItems === "number") out.minItems = node.minItems;
|
|
3097
|
+
if (typeof node.maxItems === "number") out.maxItems = node.maxItems;
|
|
3098
|
+
return out;
|
|
3099
|
+
}
|
|
3100
|
+
function lowerObject(node, title, path, encoded) {
|
|
3101
|
+
const properties = isJsonObject(node.properties) ? node.properties : {};
|
|
3102
|
+
const keys = Object.keys(properties);
|
|
3103
|
+
if (keys.length === 0 && node.additionalProperties !== false) return void 0;
|
|
3104
|
+
const lowered = {};
|
|
3105
|
+
for (const key of keys) {
|
|
3106
|
+
const property = child(properties[key], `${title}_${titleOf(key)}`, [...path, key], encoded);
|
|
3107
|
+
if (!property) return void 0;
|
|
3108
|
+
lowered[key] = property;
|
|
3109
|
+
}
|
|
3110
|
+
return object(title, lowered, Array.isArray(node.required) ? node.required.filter((key) => typeof key === "string" && Object.hasOwn(lowered, key)) : [], void 0);
|
|
3111
|
+
}
|
|
3112
|
+
/** Lowers a nested subschema, falling back to a JSON-encoded string when allowed. */
|
|
3113
|
+
function child(node, title, path, encoded) {
|
|
3114
|
+
const lowered = lower(node, title, path, encoded);
|
|
3115
|
+
if (lowered || !encoded) return lowered;
|
|
3116
|
+
encoded.push(path);
|
|
3117
|
+
const description = isJsonObject(node) ? describe(node) : void 0;
|
|
3118
|
+
return {
|
|
3119
|
+
type: "string",
|
|
3120
|
+
description: description ? `${description} ${ENCODED_SUFFIX}` : ENCODED_SUFFIX
|
|
3121
|
+
};
|
|
3122
|
+
}
|
|
3123
|
+
function object(title, properties, required, description) {
|
|
3124
|
+
const out = {
|
|
3125
|
+
type: "object",
|
|
3126
|
+
title,
|
|
3127
|
+
properties,
|
|
3128
|
+
required,
|
|
3129
|
+
"x-order": Object.keys(properties),
|
|
3130
|
+
additionalProperties: false
|
|
3131
|
+
};
|
|
3132
|
+
if (description !== void 0) out.description = description;
|
|
3133
|
+
return out;
|
|
3134
|
+
}
|
|
3135
|
+
function describe(node) {
|
|
3136
|
+
return isJsonObject(node) && typeof node.description === "string" ? node.description : void 0;
|
|
3137
|
+
}
|
|
3138
|
+
function titleOf(name) {
|
|
3139
|
+
return name.replace(/[^A-Za-z0-9_]/g, "_");
|
|
3140
|
+
}
|
|
3141
|
+
//#endregion
|
|
3142
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/utils/schema/wire.ts
|
|
2725
3143
|
/**
|
|
2726
3144
|
* True when `value` is a live ArkType schema instance.
|
|
2727
3145
|
*
|
|
@@ -2733,11 +3151,11 @@ function isArkSchema(value) {
|
|
|
2733
3151
|
}
|
|
2734
3152
|
function isArkJsonAst(value) {
|
|
2735
3153
|
if (Array.isArray(value)) return value.some(isArkJsonAst);
|
|
2736
|
-
if (!
|
|
3154
|
+
if (!isRecord(value)) return false;
|
|
2737
3155
|
if (typeof value.domain === "string" || Object.hasOwn(value, "unit")) return true;
|
|
2738
3156
|
if (value.proto === "Array" && Object.hasOwn(value, "sequence")) return true;
|
|
2739
3157
|
const required = value.required;
|
|
2740
|
-
return Array.isArray(required) && required.some((entry) =>
|
|
3158
|
+
return Array.isArray(required) && required.some((entry) => isRecord(entry) && typeof entry.key === "string" && "value" in entry);
|
|
2741
3159
|
}
|
|
2742
3160
|
function parseArkObjectKey(key) {
|
|
2743
3161
|
const match = /^(.*?)\s*\/\*\*\s*([\s\S]*?)\s*\*\/\s*$/.exec(key);
|
|
@@ -2749,7 +3167,7 @@ function parseArkObjectKey(key) {
|
|
|
2749
3167
|
}
|
|
2750
3168
|
function withArkKeyDescription(schema, description) {
|
|
2751
3169
|
if (!description) return schema;
|
|
2752
|
-
if (
|
|
3170
|
+
if (isRecord(schema)) {
|
|
2753
3171
|
if (typeof schema.description !== "string") schema.description = description;
|
|
2754
3172
|
return schema;
|
|
2755
3173
|
}
|
|
@@ -2769,10 +3187,10 @@ function arkJsonAstToWire(value) {
|
|
|
2769
3187
|
default: return {};
|
|
2770
3188
|
}
|
|
2771
3189
|
if (Array.isArray(value)) {
|
|
2772
|
-
if (value.every((item) =>
|
|
3190
|
+
if (value.every((item) => isRecord(item) && Object.hasOwn(item, "unit"))) return { enum: value.map((item) => item.unit) };
|
|
2773
3191
|
return { anyOf: value.map(arkJsonAstToWire) };
|
|
2774
3192
|
}
|
|
2775
|
-
if (!
|
|
3193
|
+
if (!isRecord(value)) return {};
|
|
2776
3194
|
if (Object.hasOwn(value, "unit")) return { const: value.unit };
|
|
2777
3195
|
if (value.proto === "Array" && Object.hasOwn(value, "sequence")) return {
|
|
2778
3196
|
type: "array",
|
|
@@ -2782,7 +3200,7 @@ function arkJsonAstToWire(value) {
|
|
|
2782
3200
|
const properties = {};
|
|
2783
3201
|
const required = [];
|
|
2784
3202
|
const addEntry = (entry, isRequired) => {
|
|
2785
|
-
if (!
|
|
3203
|
+
if (!isRecord(entry) || typeof entry.key !== "string" || !("value" in entry)) return;
|
|
2786
3204
|
const key = parseArkObjectKey(entry.key);
|
|
2787
3205
|
properties[key.name] = withArkKeyDescription(arkJsonAstToWire(entry.value), key.description);
|
|
2788
3206
|
if (isRequired) required.push(key.name);
|
|
@@ -2799,9 +3217,9 @@ function arkJsonAstToWire(value) {
|
|
|
2799
3217
|
if (typeof value.domain === "string") return { type: value.domain };
|
|
2800
3218
|
return {};
|
|
2801
3219
|
}
|
|
2802
|
-
/**
|
|
2803
|
-
const kJsonWireSchema = Symbol("
|
|
2804
|
-
const kArkWireSchema = Symbol("
|
|
3220
|
+
/** `stamp` cache keys; the entries themselves live in a weak side table keyed by schema identity. */
|
|
3221
|
+
const kJsonWireSchema = Symbol("omp.schema.json.wire");
|
|
3222
|
+
const kArkWireSchema = Symbol("omp.schema.ark.wire");
|
|
2805
3223
|
function postProcessJsonSchema(schema) {
|
|
2806
3224
|
walk(schema);
|
|
2807
3225
|
normalizeArkPropertyComments(schema);
|
|
@@ -2835,9 +3253,6 @@ const SCHEMA_DEFINING_SIBLING_KEYS = /* @__PURE__ */ new Set([
|
|
|
2835
3253
|
"unevaluatedItems",
|
|
2836
3254
|
"unevaluatedProperties"
|
|
2837
3255
|
]);
|
|
2838
|
-
function isSchemaRecord(value) {
|
|
2839
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2840
|
-
}
|
|
2841
3256
|
function hasSchemaDefiningSibling(schema) {
|
|
2842
3257
|
for (const key in schema) if (key !== "anyOf" && SCHEMA_DEFINING_SIBLING_KEYS.has(key)) return true;
|
|
2843
3258
|
return false;
|
|
@@ -2868,7 +3283,7 @@ function rewriteNullableScalarAnyOf(schema) {
|
|
|
2868
3283
|
let scalarType;
|
|
2869
3284
|
let sawNull = false;
|
|
2870
3285
|
for (const variant of variants) {
|
|
2871
|
-
if (!
|
|
3286
|
+
if (!isRecord(variant)) return;
|
|
2872
3287
|
if (isNullVariant(variant)) {
|
|
2873
3288
|
if (sawNull) return;
|
|
2874
3289
|
sawNull = true;
|
|
@@ -2884,7 +3299,7 @@ function rewriteNullableScalarAnyOf(schema) {
|
|
|
2884
3299
|
schema.type = [scalarType, "null"];
|
|
2885
3300
|
}
|
|
2886
3301
|
function isExclusiveRequiredBranch(branch) {
|
|
2887
|
-
if (!
|
|
3302
|
+
if (!isRecord(branch)) return false;
|
|
2888
3303
|
if (Object.hasOwn(branch, "type")) return false;
|
|
2889
3304
|
if (!Array.isArray(branch.required) || branch.required.length === 0) return false;
|
|
2890
3305
|
if (!branch.required.every((name) => typeof name === "string" && name.length > 0)) return false;
|
|
@@ -2905,7 +3320,7 @@ function flattenExclusiveRequiredRootUnion(schema) {
|
|
|
2905
3320
|
if (!unionKey) return schema;
|
|
2906
3321
|
const union = schema[unionKey];
|
|
2907
3322
|
if (!Array.isArray(union) || union.length === 0) return schema;
|
|
2908
|
-
if (!(schema.type === "object" || Array.isArray(schema.type) && schema.type.includes("object")) && !
|
|
3323
|
+
if (!(schema.type === "object" || Array.isArray(schema.type) && schema.type.includes("object")) && !isRecord(schema.properties)) return schema;
|
|
2909
3324
|
if (!union.every(isExclusiveRequiredBranch)) return schema;
|
|
2910
3325
|
const flattened = { ...schema };
|
|
2911
3326
|
delete flattened[unionKey];
|
|
@@ -2943,10 +3358,10 @@ function normalizeArkPropertyComments(node) {
|
|
|
2943
3358
|
for (const child of node) normalizeArkPropertyComments(child);
|
|
2944
3359
|
return;
|
|
2945
3360
|
}
|
|
2946
|
-
if (!
|
|
3361
|
+
if (!isRecord(node)) return;
|
|
2947
3362
|
const obj = node;
|
|
2948
3363
|
const properties = obj.properties;
|
|
2949
|
-
if (
|
|
3364
|
+
if (isRecord(properties)) {
|
|
2950
3365
|
const required = Array.isArray(obj.required) ? obj.required : void 0;
|
|
2951
3366
|
if (required) obj.required = required.map((key) => typeof key === "string" ? parseArkObjectKey(key).name : key);
|
|
2952
3367
|
for (const key of Object.keys(properties)) {
|
|
@@ -2965,7 +3380,7 @@ function normalizeArkPropertyComments(node) {
|
|
|
2965
3380
|
for (const mapKey of SCHEMA_MAP_KEYS) {
|
|
2966
3381
|
if (mapKey === "properties") continue;
|
|
2967
3382
|
const map = obj[mapKey];
|
|
2968
|
-
if (
|
|
3383
|
+
if (isRecord(map)) for (const key in map) normalizeArkPropertyComments(map[key]);
|
|
2969
3384
|
}
|
|
2970
3385
|
for (const arrayKey of SCHEMA_ARRAY_KEYS) {
|
|
2971
3386
|
const array = obj[arrayKey];
|
|
@@ -3045,7 +3460,7 @@ function collapseConstUnionAnyOf(obj) {
|
|
|
3045
3460
|
let branchDescription;
|
|
3046
3461
|
let describedCount = 0;
|
|
3047
3462
|
for (const variant of variants) {
|
|
3048
|
-
if (!
|
|
3463
|
+
if (!isRecord(variant) || !Object.hasOwn(variant, "const")) return;
|
|
3049
3464
|
for (const key in variant) if (key !== "const" && key !== "description") return;
|
|
3050
3465
|
const desc = variant.description;
|
|
3051
3466
|
if (typeof desc === "string") {
|
|
@@ -3173,7 +3588,7 @@ function pruneArkUndefinedUnionBranches(node) {
|
|
|
3173
3588
|
const concrete = branches.filter((branch) => !isUnconstrainedSchema(branch));
|
|
3174
3589
|
if (concrete.length === branches.length || concrete.length === 0) continue;
|
|
3175
3590
|
const only = concrete.length === 1 ? concrete[0] : void 0;
|
|
3176
|
-
if (only !== void 0 &&
|
|
3591
|
+
if (only !== void 0 && isRecord(only)) {
|
|
3177
3592
|
delete obj[unionKey];
|
|
3178
3593
|
for (const key in only) if (!(key in obj)) obj[key] = only[key];
|
|
3179
3594
|
} else obj[unionKey] = concrete;
|
|
@@ -3213,11 +3628,11 @@ function toolWireSchema(tool) {
|
|
|
3213
3628
|
const params = tool.parameters;
|
|
3214
3629
|
if (isArkSchema(params)) return arkToWireSchema(params);
|
|
3215
3630
|
return stamp(params, kJsonWireSchema, (p) => {
|
|
3216
|
-
return postProcessJsonSchema(upgradeJsonSchemaTo202012(isArkJsonAst(p) ? arkJsonAstToWire(p) : p));
|
|
3631
|
+
return postProcessJsonSchema(upgradeJsonSchemaTo202012(isArkJsonAst(p) ? arkJsonAstToWire(p) : structuredCloneJSON(p)));
|
|
3217
3632
|
});
|
|
3218
3633
|
}
|
|
3219
3634
|
//#endregion
|
|
3220
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
3635
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/coercion.ts
|
|
3221
3636
|
function buildArgShapes(tools = []) {
|
|
3222
3637
|
const shapes = /* @__PURE__ */ new Map();
|
|
3223
3638
|
for (const tool of tools) {
|
|
@@ -3315,8 +3730,23 @@ function normalizeKimiFunctionName(rawId) {
|
|
|
3315
3730
|
function asRecord(value) {
|
|
3316
3731
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
3317
3732
|
}
|
|
3733
|
+
/**
|
|
3734
|
+
* Extract a COMPLETE tool name from a partial in-band JSON body.
|
|
3735
|
+
* Returns undefined until the name string is fully closed, so streaming
|
|
3736
|
+
* scanners never start a tool call under a truncated name.
|
|
3737
|
+
*/
|
|
3738
|
+
function parseCompleteToolName(body) {
|
|
3739
|
+
const match = /^\s*\{\s*"name"\s*:\s*("(?:\\.|[^"\\])*")/.exec(body);
|
|
3740
|
+
if (!match) return void 0;
|
|
3741
|
+
try {
|
|
3742
|
+
const name = JSON.parse(match[1]);
|
|
3743
|
+
return typeof name === "string" && name.length > 0 ? name : void 0;
|
|
3744
|
+
} catch {
|
|
3745
|
+
return;
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3318
3748
|
//#endregion
|
|
3319
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
3749
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/rendering.ts
|
|
3320
3750
|
function renderToolResponseResults(results) {
|
|
3321
3751
|
return results.map((result) => `<tool_response>\n${result.text}\n</tool_response>`).join("\n");
|
|
3322
3752
|
}
|
|
@@ -3347,8 +3777,19 @@ function pyString(value) {
|
|
|
3347
3777
|
function escapeXmlAttr(value) {
|
|
3348
3778
|
return value.replaceAll("&", "&").replaceAll("\"", """).replaceAll("<", "<").replaceAll(">", ">");
|
|
3349
3779
|
}
|
|
3350
|
-
|
|
3351
|
-
|
|
3780
|
+
/** Render one Anthropic-style `<invoke>`; declared string args stay raw, everything else is JSON. */
|
|
3781
|
+
function renderInvoke(call, shape) {
|
|
3782
|
+
let body = `<invoke name="${escapeXmlAttr(call.name)}">`;
|
|
3783
|
+
for (const key in call.arguments) {
|
|
3784
|
+
const value = call.arguments[key];
|
|
3785
|
+
const rendered = shape?.stringArgs.has(key) === true && typeof value === "string" ? value : stringifyJson(value);
|
|
3786
|
+
body += `<parameter name="${escapeXmlAttr(key)}">${rendered}</parameter>`;
|
|
3787
|
+
}
|
|
3788
|
+
return `${body}</invoke>`;
|
|
3789
|
+
}
|
|
3790
|
+
function renderInvokes(calls, tools) {
|
|
3791
|
+
const shapes = buildArgShapes(tools);
|
|
3792
|
+
return calls.map((call) => renderInvoke(call, shapes.get(call.name))).join("\n");
|
|
3352
3793
|
}
|
|
3353
3794
|
function renderChatMlTranscript(messages, options, config) {
|
|
3354
3795
|
if (messages.length === 0) return "";
|
|
@@ -3504,7 +3945,7 @@ function appendLegacySegment(out, segment) {
|
|
|
3504
3945
|
return `${out}\n\n${segment}`;
|
|
3505
3946
|
}
|
|
3506
3947
|
//#endregion
|
|
3507
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
3948
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/anthropic.ts
|
|
3508
3949
|
const MAX_PARTIAL_TAG_LENGTH = 256;
|
|
3509
3950
|
const MAX_PARAMETER_VALUE_LENGTH = 1e6;
|
|
3510
3951
|
const WRAPPER_TAGS = {
|
|
@@ -3976,11 +4417,11 @@ function couldBeTagPrefix(buffer, prefixes) {
|
|
|
3976
4417
|
return false;
|
|
3977
4418
|
}
|
|
3978
4419
|
function renderToolCall$10(call, options = {}) {
|
|
3979
|
-
return renderInvoke
|
|
4420
|
+
return renderInvoke(call, buildArgShapes(options.tools).get(call.name));
|
|
3980
4421
|
}
|
|
3981
4422
|
function renderAssistantToolCalls$10(calls, options = {}) {
|
|
3982
4423
|
if (calls.length === 0) return "";
|
|
3983
|
-
return `<function_calls>\n${renderInvokes
|
|
4424
|
+
return `<function_calls>\n${renderInvokes(calls, options.tools ?? [])}\n</function_calls>`;
|
|
3984
4425
|
}
|
|
3985
4426
|
function renderToolResults$10(results) {
|
|
3986
4427
|
return `<function_results>\n${results.map((result) => {
|
|
@@ -3999,19 +4440,6 @@ function renderTranscript$10(messages, options = {}) {
|
|
|
3999
4440
|
renderResults: renderToolResults$10
|
|
4000
4441
|
});
|
|
4001
4442
|
}
|
|
4002
|
-
function renderInvoke$2(call, shape) {
|
|
4003
|
-
let body = `<invoke name="${escapeXmlAttr(call.name)}">`;
|
|
4004
|
-
for (const key in call.arguments) {
|
|
4005
|
-
const value = call.arguments[key];
|
|
4006
|
-
const rendered = shape?.stringArgs.has(key) === true && typeof value === "string" ? value : stringifyJson(value);
|
|
4007
|
-
body += `<parameter name="${escapeXmlAttr(key)}">${rendered}</parameter>`;
|
|
4008
|
-
}
|
|
4009
|
-
return `${body}</invoke>`;
|
|
4010
|
-
}
|
|
4011
|
-
function renderInvokes$2(calls, tools) {
|
|
4012
|
-
const shapes = buildArgShapes(tools);
|
|
4013
|
-
return calls.map((call) => renderInvoke$2(call, shapes.get(call.name))).join("\n");
|
|
4014
|
-
}
|
|
4015
4443
|
const definition$10 = {
|
|
4016
4444
|
dialect: "anthropic",
|
|
4017
4445
|
prompt: anthropic_default,
|
|
@@ -4023,10 +4451,92 @@ const definition$10 = {
|
|
|
4023
4451
|
renderTranscript: renderTranscript$10
|
|
4024
4452
|
};
|
|
4025
4453
|
//#endregion
|
|
4026
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
4454
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/utils/tool-call-arguments.ts
|
|
4455
|
+
/** Final arguments must not reuse the streaming parser's auto-closed preview. */
|
|
4456
|
+
function parseToolCallArguments(json) {
|
|
4457
|
+
if (!json?.trim()) return {};
|
|
4458
|
+
try {
|
|
4459
|
+
return parseJsonWithRepair(json);
|
|
4460
|
+
} catch (error) {
|
|
4461
|
+
return invalidToolCallArguments(json, error);
|
|
4462
|
+
}
|
|
4463
|
+
}
|
|
4464
|
+
/**
|
|
4465
|
+
* Native Responses `function_call.arguments` to persist for replay.
|
|
4466
|
+
*
|
|
4467
|
+
* {@link parseToolCallArguments} repairs some invalid JSON (e.g. `"name": ,`) and the tool runs with the
|
|
4468
|
+
* repaired value; replay must carry what was executed (#14155), not the {@link invalidToolCallArguments}
|
|
4469
|
+
* diagnostic it substitutes for stored arguments that do not parse (#15568).
|
|
4470
|
+
* Returns `raw` when it already parses or the arguments were unrepairable, else the executed arguments.
|
|
4471
|
+
*/
|
|
4472
|
+
function replayableToolCallArguments(raw, executed) {
|
|
4473
|
+
try {
|
|
4474
|
+
JSON.parse(raw);
|
|
4475
|
+
return raw;
|
|
4476
|
+
} catch {
|
|
4477
|
+
return executed && typeof executed === "object" && "__parseError" in executed ? raw : JSON.stringify(executed);
|
|
4478
|
+
}
|
|
4479
|
+
}
|
|
4480
|
+
const TRUNCATED_SUFFIX = /… \[truncated \d+ chars\]$/;
|
|
4481
|
+
/** Bound raw argument text for a diagnostic. Text this function already bounded is returned unchanged. */
|
|
4482
|
+
function boundRawToolArguments(raw) {
|
|
4483
|
+
if (raw.length <= 512) return raw;
|
|
4484
|
+
if (TRUNCATED_SUFFIX.exec(raw)?.index === 512) return raw;
|
|
4485
|
+
return `${raw.slice(0, 512)}… [truncated ${raw.length - 512} chars]`;
|
|
4486
|
+
}
|
|
4487
|
+
/** Preserve a bounded diagnostic, never any partially recovered executable keys. */
|
|
4488
|
+
function invalidToolCallArguments(raw, error) {
|
|
4489
|
+
return {
|
|
4490
|
+
__parseError: error instanceof Error ? error.message : String(error),
|
|
4491
|
+
__rawJson: boundRawToolArguments(raw)
|
|
4492
|
+
};
|
|
4493
|
+
}
|
|
4494
|
+
//#endregion
|
|
4495
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/deepseek.md
|
|
4027
4496
|
var deepseek_default = "## Format guide\n\nA tool call wraps the function name, a separator, and one JSON object of arguments in fixed tokens. Emit them exactly:\n\n```text\n<|tool▁calls▁begin|><|tool▁call▁begin|>tool_name<|tool▁sep|>{\"arg\":\"value\"}<|tool▁call▁end|><|tool▁calls▁end|>\n```\n\nResults arrive as output tokens:\n\n```text\n<|tool▁output▁begin|>verbatim tool result<|tool▁output▁end|>\n```\n\n## Rules\n\n- Use `|` (U+FF5C) and `▁` (U+2581) exactly.\n- Tool name MUST match an available function; arguments are one valid JSON object.\n- Argument string values use only normal JSON string escaping (`\\\"`, `\\\\`, `\\n`); never HTML-escape their contents — write `a & b`, not `a & b`.\n- NEVER wrap arguments in Markdown fences; NEVER emit a `type` field or `function` prefix.\n- Multiple calls chain `<|tool▁call▁begin|>...<|tool▁call▁end|>` directly — no separators, spaces, or newlines between them.\n- Private reasoning, when needed, goes in `<think>...</think>` before the tokens.\n- Read each output token in call order. NEVER emit output tokens yourself.\n- Emit the stop sequence ONLY after the call is fully written — NEVER announce a tool then stop (e.g. halting at \"Let's run `cargo clippy`\" with no `<|tool▁call▁begin|>` emitted). Write the complete call, THEN the stop sequence, THEN halt.\n";
|
|
4028
4497
|
//#endregion
|
|
4029
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
4498
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/terminator-wait.ts
|
|
4499
|
+
/**
|
|
4500
|
+
* Fast path for in-band scanners that sit inside a body waiting for one fixed
|
|
4501
|
+
* terminator (a tool-call close tag) and emit nothing until it arrives.
|
|
4502
|
+
*
|
|
4503
|
+
* Appending each delta to the scanner's string buffer and calling `indexOf` on
|
|
4504
|
+
* it flattens the growing rope on every delta, so a long in-band tool call cost
|
|
4505
|
+
* O(n²) copying and scanning. While armed, deltas are set aside and only the new
|
|
4506
|
+
* text plus the terminator-length overlap with what came before is searched;
|
|
4507
|
+
* the buffer is rebuilt once, when the terminator shows up or the stream ends.
|
|
4508
|
+
*/
|
|
4509
|
+
var TerminatorWait = class {
|
|
4510
|
+
#terminator = "";
|
|
4511
|
+
#tail = "";
|
|
4512
|
+
#parts = [];
|
|
4513
|
+
/** Start deferring; `buffered` is the scanner's pending body, known not to contain `terminator`. */
|
|
4514
|
+
arm(terminator, buffered) {
|
|
4515
|
+
this.#terminator = terminator;
|
|
4516
|
+
this.#tail = buffered.slice(Math.max(0, buffered.length - (terminator.length - 1)));
|
|
4517
|
+
this.#parts.length = 0;
|
|
4518
|
+
}
|
|
4519
|
+
/** Take `text` while the terminator is still absent; false means the caller must {@link release} and scan. */
|
|
4520
|
+
absorb(text) {
|
|
4521
|
+
if (this.#terminator.length === 0) return false;
|
|
4522
|
+
const window = this.#tail + text;
|
|
4523
|
+
if (window.includes(this.#terminator)) return false;
|
|
4524
|
+
this.#parts.push(text);
|
|
4525
|
+
this.#tail = window.slice(Math.max(0, window.length - (this.#terminator.length - 1)));
|
|
4526
|
+
return true;
|
|
4527
|
+
}
|
|
4528
|
+
/** Stop deferring and return `buffered` with every absorbed delta appended. */
|
|
4529
|
+
release(buffered) {
|
|
4530
|
+
this.#terminator = "";
|
|
4531
|
+
this.#tail = "";
|
|
4532
|
+
if (this.#parts.length === 0) return buffered;
|
|
4533
|
+
const joined = buffered + this.#parts.join("");
|
|
4534
|
+
this.#parts.length = 0;
|
|
4535
|
+
return joined;
|
|
4536
|
+
}
|
|
4537
|
+
};
|
|
4538
|
+
//#endregion
|
|
4539
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/deepseek.ts
|
|
4030
4540
|
const DEEPSEEK_TOOL_CALLS_BEGIN = "<|tool▁calls▁begin|>";
|
|
4031
4541
|
const DEEPSEEK_TOOL_CALLS_END = "<|tool▁calls▁end|>";
|
|
4032
4542
|
const DEEPSEEK_TOOL_CALL_BEGIN = "<|tool▁call▁begin|>";
|
|
@@ -4087,7 +4597,90 @@ const OUTSIDE_TOKENS = [
|
|
|
4087
4597
|
...DSML_ORPHAN_CLOSE_TOKENS,
|
|
4088
4598
|
...CONTROL_TOKENS
|
|
4089
4599
|
];
|
|
4090
|
-
|
|
4600
|
+
/** Outside-state tokens dropped from visible text (closers with nothing open, template control tokens). */
|
|
4601
|
+
const OUTSIDE_DROPPED_TOKENS = Object.fromEntries([
|
|
4602
|
+
DEEPSEEK_TOOL_CALLS_END,
|
|
4603
|
+
THINK_CLOSE$4,
|
|
4604
|
+
DSML_TOOL_CALLS_CLOSE_FULLWIDTH,
|
|
4605
|
+
DSML_TOOL_CALLS_CLOSE_ASCII,
|
|
4606
|
+
...CONTROL_TOKENS
|
|
4607
|
+
].map((token) => [token, true]));
|
|
4608
|
+
const TEMPLATE_TOKEN_SPELLING = /<(|?)([A-Za-z]+(?:[▁_][A-Za-z]+)*)(|?)>/gu;
|
|
4609
|
+
const TEMPLATE_TOKEN_SPELLING_AT_START = new RegExp(TEMPLATE_TOKEN_SPELLING.source, "uy");
|
|
4610
|
+
const TEMPLATE_TOKEN_PARTIAL = /^<|?([A-Za-z▁_]*)(|?)$/u;
|
|
4611
|
+
const TEMPLATE_TOKEN_BAR = "|";
|
|
4612
|
+
/**
|
|
4613
|
+
* Canonical template token by spelling-independent key (`tool_calls_begin`).
|
|
4614
|
+
* A Map, not a Record: keys come from model output, so `constructor` and friends
|
|
4615
|
+
* must not resolve through the prototype.
|
|
4616
|
+
*/
|
|
4617
|
+
const TEMPLATE_TOKEN_BY_KEY = new Map([
|
|
4618
|
+
DEEPSEEK_TOOL_CALLS_BEGIN,
|
|
4619
|
+
DEEPSEEK_TOOL_CALLS_END,
|
|
4620
|
+
DEEPSEEK_TOOL_CALL_BEGIN,
|
|
4621
|
+
DEEPSEEK_TOOL_CALL_END,
|
|
4622
|
+
DEEPSEEK_TOOL_SEPARATOR,
|
|
4623
|
+
...CONTROL_TOKENS
|
|
4624
|
+
].flatMap((token) => {
|
|
4625
|
+
const name = /^<|([A-Za-z]+(?:▁[A-Za-z]+)*)|>$/u.exec(token)?.[1];
|
|
4626
|
+
return name === void 0 ? [] : [[templateTokenKey(name), token]];
|
|
4627
|
+
}));
|
|
4628
|
+
const TEMPLATE_TOKEN_KEYS = [...TEMPLATE_TOKEN_BY_KEY.keys()];
|
|
4629
|
+
const TEMPLATE_TOKEN_MAX_SPELLING = Math.max(...TEMPLATE_TOKEN_KEYS.map((key) => key.length)) + 4;
|
|
4630
|
+
const OUTSIDE_TEMPLATE_TOKENS = Object.fromEntries([
|
|
4631
|
+
DEEPSEEK_TOOL_CALLS_BEGIN,
|
|
4632
|
+
DEEPSEEK_TOOL_CALLS_END,
|
|
4633
|
+
DEEPSEEK_TOOL_CALL_BEGIN,
|
|
4634
|
+
...CONTROL_TOKENS
|
|
4635
|
+
].map((token) => [token, true]));
|
|
4636
|
+
const SEPARATOR_TOKENS = { [DEEPSEEK_TOOL_SEPARATOR]: true };
|
|
4637
|
+
const ARGS_TERMINATOR_TOKENS = {
|
|
4638
|
+
[DEEPSEEK_TOOL_CALL_END]: true,
|
|
4639
|
+
[DEEPSEEK_TOOL_CALLS_END]: true,
|
|
4640
|
+
[DEEPSEEK_TOOL_CALL_BEGIN]: true
|
|
4641
|
+
};
|
|
4642
|
+
function templateTokenKey(name) {
|
|
4643
|
+
return name.replaceAll("▁", "_");
|
|
4644
|
+
}
|
|
4645
|
+
function resolveTemplateSpelling(match) {
|
|
4646
|
+
if (match[1].length === 0 && match[3].length === 0) return void 0;
|
|
4647
|
+
return TEMPLATE_TOKEN_BY_KEY.get(templateTokenKey(match[2]));
|
|
4648
|
+
}
|
|
4649
|
+
/**
|
|
4650
|
+
* Find the earliest of `tokens` in `text` at or after `from`, in its canonical
|
|
4651
|
+
* spelling or any re-spelling described at {@link TEMPLATE_TOKEN_SPELLING}.
|
|
4652
|
+
*/
|
|
4653
|
+
function findDeepSeekTemplateToken(text, tokens, from = 0) {
|
|
4654
|
+
TEMPLATE_TOKEN_SPELLING.lastIndex = from;
|
|
4655
|
+
for (let match = TEMPLATE_TOKEN_SPELLING.exec(text); match; match = TEMPLATE_TOKEN_SPELLING.exec(text)) {
|
|
4656
|
+
const token = resolveTemplateSpelling(match);
|
|
4657
|
+
if (token !== void 0 && tokens[token]) return {
|
|
4658
|
+
token,
|
|
4659
|
+
raw: match[0],
|
|
4660
|
+
index: match.index
|
|
4661
|
+
};
|
|
4662
|
+
}
|
|
4663
|
+
}
|
|
4664
|
+
function templateTokenAtStart(text) {
|
|
4665
|
+
TEMPLATE_TOKEN_SPELLING_AT_START.lastIndex = 0;
|
|
4666
|
+
const match = TEMPLATE_TOKEN_SPELLING_AT_START.exec(text);
|
|
4667
|
+
if (!match) return void 0;
|
|
4668
|
+
const token = resolveTemplateSpelling(match);
|
|
4669
|
+
return token === void 0 ? void 0 : {
|
|
4670
|
+
token,
|
|
4671
|
+
raw: match[0],
|
|
4672
|
+
index: 0
|
|
4673
|
+
};
|
|
4674
|
+
}
|
|
4675
|
+
/** Length of a trailing fragment of `text` that could still complete into a template token spelling. */
|
|
4676
|
+
function templateTokenPartialLength(text) {
|
|
4677
|
+
const start = text.lastIndexOf("<");
|
|
4678
|
+
if (start === -1 || text.length - start >= TEMPLATE_TOKEN_MAX_SPELLING) return 0;
|
|
4679
|
+
const match = TEMPLATE_TOKEN_PARTIAL.exec(text.slice(start));
|
|
4680
|
+
if (!match) return 0;
|
|
4681
|
+
const key = templateTokenKey(match[1]);
|
|
4682
|
+
return (match[2].length > 0 ? TEMPLATE_TOKEN_BY_KEY.has(key) : TEMPLATE_TOKEN_KEYS.some((known) => known.startsWith(key))) ? text.length - start : 0;
|
|
4683
|
+
}
|
|
4091
4684
|
const DSML_SECTION_TOKENS = [
|
|
4092
4685
|
DSML_TOOL_CALLS_CLOSE_FULLWIDTH,
|
|
4093
4686
|
DSML_TOOL_CALLS_CLOSE_ASCII,
|
|
@@ -4101,6 +4694,67 @@ const DSML_INVOKE_TOKENS = [
|
|
|
4101
4694
|
"<|DSML|parameter"
|
|
4102
4695
|
];
|
|
4103
4696
|
const DSML_PARAMETER_CLOSE_TOKENS = [DSML_PARAMETER_CLOSE_FULLWIDTH, DSML_PARAMETER_CLOSE_ASCII];
|
|
4697
|
+
const BARE_DSML_OPEN = /<[||]DSML[||](?:invoke|parameter)\b/u;
|
|
4698
|
+
const OUTSIDE_CODE = {
|
|
4699
|
+
fence: 0,
|
|
4700
|
+
run: 0,
|
|
4701
|
+
newline: false
|
|
4702
|
+
};
|
|
4703
|
+
const BACKTICK = 96;
|
|
4704
|
+
const LINE_FEED = 10;
|
|
4705
|
+
/** A finished backtick run opens code, or closes it when it matches the opening run. */
|
|
4706
|
+
function settleBacktickRun(fence, run) {
|
|
4707
|
+
if (run === 0) return fence;
|
|
4708
|
+
if (fence === 0) return run;
|
|
4709
|
+
return run === fence ? 0 : fence;
|
|
4710
|
+
}
|
|
4711
|
+
function advanceCodeState(state, text) {
|
|
4712
|
+
let { fence, run, newline } = state;
|
|
4713
|
+
for (let i = 0; i < text.length; i++) {
|
|
4714
|
+
const c = text.charCodeAt(i);
|
|
4715
|
+
if (c === BACKTICK) {
|
|
4716
|
+
run++;
|
|
4717
|
+
newline = false;
|
|
4718
|
+
continue;
|
|
4719
|
+
}
|
|
4720
|
+
fence = settleBacktickRun(fence, run);
|
|
4721
|
+
run = 0;
|
|
4722
|
+
if (c === LINE_FEED) {
|
|
4723
|
+
if (newline && fence < 3) fence = 0;
|
|
4724
|
+
newline = true;
|
|
4725
|
+
} else if (!/\s/.test(text[i])) newline = false;
|
|
4726
|
+
}
|
|
4727
|
+
return {
|
|
4728
|
+
fence,
|
|
4729
|
+
run,
|
|
4730
|
+
newline
|
|
4731
|
+
};
|
|
4732
|
+
}
|
|
4733
|
+
/**
|
|
4734
|
+
* Whether an inline span opened by a `fence`-long backtick run closes in
|
|
4735
|
+
* `text` before its paragraph ends. Markdown renders an unmatched run as plain
|
|
4736
|
+
* text, so only a closed span is code. `undefined` until the stream decides.
|
|
4737
|
+
*/
|
|
4738
|
+
function inlineSpanCloses(text, fence, final) {
|
|
4739
|
+
let run = 0;
|
|
4740
|
+
let newline = false;
|
|
4741
|
+
for (let i = 0; i < text.length; i++) {
|
|
4742
|
+
const c = text.charCodeAt(i);
|
|
4743
|
+
if (c === BACKTICK) {
|
|
4744
|
+
run++;
|
|
4745
|
+
newline = false;
|
|
4746
|
+
continue;
|
|
4747
|
+
}
|
|
4748
|
+
if (run === fence) return true;
|
|
4749
|
+
run = 0;
|
|
4750
|
+
if (c === LINE_FEED) {
|
|
4751
|
+
if (newline) return false;
|
|
4752
|
+
newline = true;
|
|
4753
|
+
} else if (!/\s/.test(text[i])) newline = false;
|
|
4754
|
+
}
|
|
4755
|
+
if (!final) return void 0;
|
|
4756
|
+
return run === fence;
|
|
4757
|
+
}
|
|
4104
4758
|
var DeepSeekInbandScanner = class {
|
|
4105
4759
|
#buffer = "";
|
|
4106
4760
|
#state = "outside";
|
|
@@ -4113,17 +4767,35 @@ var DeepSeekInbandScanner = class {
|
|
|
4113
4767
|
#dsmlParamName = "";
|
|
4114
4768
|
#dsmlParamIsString = true;
|
|
4115
4769
|
#dsmlParamRaw = "";
|
|
4770
|
+
/** Unclassified wrapper text is kept until an invoke proves it is a tool call. */
|
|
4771
|
+
#pendingDsmlSection;
|
|
4116
4772
|
#rawBlock = "";
|
|
4117
4773
|
#stripLeadingWhitespace = false;
|
|
4774
|
+
/**
|
|
4775
|
+
* Visible text already carries a bare DSML `invoke`/`parameter` opener (a
|
|
4776
|
+
* malformed call missing its `tool_calls` wrapper). Its closers are then kept
|
|
4777
|
+
* verbatim instead of stripped as orphans, so the agent loop can find where
|
|
4778
|
+
* the broken call ends and remove exactly that span, keeping prose after it.
|
|
4779
|
+
*/
|
|
4780
|
+
#bareDsmlOpenVisible = false;
|
|
4781
|
+
/** Last few visible characters, so a bare opener split across chunks is still seen. */
|
|
4782
|
+
#visibleTail = "";
|
|
4783
|
+
/** Markdown code state of the visible text emitted so far. */
|
|
4784
|
+
#code = OUTSIDE_CODE;
|
|
4785
|
+
#closeWait = new TerminatorWait();
|
|
4118
4786
|
constructor(options = {}) {
|
|
4119
4787
|
this.#parseThinking = options.parseThinking ?? true;
|
|
4120
4788
|
}
|
|
4121
4789
|
feed(text) {
|
|
4122
4790
|
if (text.length === 0) return [];
|
|
4123
|
-
this.#
|
|
4124
|
-
|
|
4791
|
+
if (this.#closeWait.absorb(text)) return [];
|
|
4792
|
+
this.#buffer = this.#closeWait.release(this.#buffer) + text;
|
|
4793
|
+
const events = this.#consume(false);
|
|
4794
|
+
if ((this.#state === "args" || this.#state === "legacyArgs") && templateTokenPartialLength(this.#buffer) === 0) this.#closeWait.arm(TEMPLATE_TOKEN_BAR, this.#buffer);
|
|
4795
|
+
return events;
|
|
4125
4796
|
}
|
|
4126
4797
|
flush() {
|
|
4798
|
+
this.#buffer = this.#closeWait.release(this.#buffer);
|
|
4127
4799
|
return this.#consume(true);
|
|
4128
4800
|
}
|
|
4129
4801
|
#consume(final) {
|
|
@@ -4140,7 +4812,7 @@ var DeepSeekInbandScanner = class {
|
|
|
4140
4812
|
continue;
|
|
4141
4813
|
}
|
|
4142
4814
|
if (this.#state === "section") {
|
|
4143
|
-
if (!this.#consumeSection(final)) break;
|
|
4815
|
+
if (!this.#consumeSection(final, events)) break;
|
|
4144
4816
|
continue;
|
|
4145
4817
|
}
|
|
4146
4818
|
if (this.#state === "header") {
|
|
@@ -4166,6 +4838,12 @@ var DeepSeekInbandScanner = class {
|
|
|
4166
4838
|
if (!this.#consumeDsmlParam(final, events)) break;
|
|
4167
4839
|
}
|
|
4168
4840
|
if (final && this.#state === "thinking") this.#endThinking(events);
|
|
4841
|
+
if (final && this.#pendingDsmlSection !== void 0) {
|
|
4842
|
+
this.#emitText(this.#pendingDsmlSection + this.#buffer, events);
|
|
4843
|
+
this.#pendingDsmlSection = void 0;
|
|
4844
|
+
this.#buffer = "";
|
|
4845
|
+
this.#state = "outside";
|
|
4846
|
+
}
|
|
4169
4847
|
if (final && this.#buffer.length === 0 && this.#rawBlock.length > 0) this.#rawBlock = "";
|
|
4170
4848
|
return events;
|
|
4171
4849
|
}
|
|
@@ -4180,62 +4858,68 @@ var DeepSeekInbandScanner = class {
|
|
|
4180
4858
|
this.#buffer = trimmed;
|
|
4181
4859
|
this.#stripLeadingWhitespace = false;
|
|
4182
4860
|
}
|
|
4183
|
-
const match =
|
|
4861
|
+
const match = this.#findOutsideToken(final);
|
|
4862
|
+
if (typeof match === "number") {
|
|
4863
|
+
this.#emitText(this.#buffer.slice(0, match), events);
|
|
4864
|
+
this.#buffer = this.#buffer.slice(match);
|
|
4865
|
+
return;
|
|
4866
|
+
}
|
|
4184
4867
|
if (!match) {
|
|
4185
|
-
const hold = final ? 0 : partialSuffixOverlapAny(this.#buffer, OUTSIDE_TOKENS);
|
|
4186
|
-
|
|
4187
|
-
if (emit.length > 0) events.push({
|
|
4188
|
-
type: "text",
|
|
4189
|
-
text: emit
|
|
4190
|
-
});
|
|
4868
|
+
const hold = final ? 0 : Math.max(partialSuffixOverlapAny(this.#buffer, OUTSIDE_TOKENS), templateTokenPartialLength(this.#buffer));
|
|
4869
|
+
this.#emitText(this.#buffer.slice(0, this.#buffer.length - hold), events);
|
|
4191
4870
|
this.#buffer = this.#buffer.slice(this.#buffer.length - hold);
|
|
4192
4871
|
return;
|
|
4193
4872
|
}
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4873
|
+
this.#emitText(this.#buffer.slice(0, match.index), events);
|
|
4874
|
+
this.#buffer = this.#buffer.slice(match.index + match.raw.length);
|
|
4875
|
+
if (match.raw !== match.token) {
|
|
4876
|
+
const fence = settleBacktickRun(this.#code.fence, this.#code.run);
|
|
4877
|
+
if (fence > 0 && fence < 3) this.#code = OUTSIDE_CODE;
|
|
4878
|
+
}
|
|
4879
|
+
if (match.token === "<|tool▁calls▁begin|>") {
|
|
4201
4880
|
this.#inToolSection = true;
|
|
4202
4881
|
this.#state = "section";
|
|
4203
4882
|
return;
|
|
4204
4883
|
}
|
|
4205
|
-
if (
|
|
4206
|
-
this.#
|
|
4207
|
-
this.#rawBlock = DEEPSEEK_TOOL_CALL_BEGIN;
|
|
4884
|
+
if (match.token === "<|tool▁call▁begin|>") {
|
|
4885
|
+
this.#rawBlock = match.raw;
|
|
4208
4886
|
this.#inToolSection = false;
|
|
4209
4887
|
this.#state = "header";
|
|
4210
4888
|
return;
|
|
4211
4889
|
}
|
|
4212
|
-
if (
|
|
4213
|
-
this.#buffer = this.#buffer.slice(7);
|
|
4890
|
+
if (match.token === THINK_OPEN$5) {
|
|
4214
4891
|
this.#state = "thinking";
|
|
4215
4892
|
this.#thinking = "";
|
|
4216
4893
|
if (this.#parseThinking) events.push({ type: "thinkingStart" });
|
|
4217
4894
|
return;
|
|
4218
4895
|
}
|
|
4219
|
-
if (
|
|
4220
|
-
|
|
4221
|
-
this.#buffer = this.#buffer.slice(openToken.length);
|
|
4896
|
+
if (match.token === DSML_TOOL_CALLS_OPEN_FULLWIDTH || match.token === DSML_TOOL_CALLS_OPEN_ASCII) {
|
|
4897
|
+
this.#pendingDsmlSection = match.raw;
|
|
4222
4898
|
this.#state = "dsmlSection";
|
|
4223
4899
|
return;
|
|
4224
4900
|
}
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
this.#buffer = this.#buffer.slice(orphanClose.length);
|
|
4901
|
+
if (DSML_ORPHAN_CLOSE_TOKENS.includes(match.token)) {
|
|
4902
|
+
if (this.#bareDsmlOpenVisible) this.#emitText(match.raw, events);
|
|
4228
4903
|
continue;
|
|
4229
4904
|
}
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
this.#
|
|
4233
|
-
this.#stripLeadingWhitespace = true;
|
|
4905
|
+
if (this.#bareDsmlOpenVisible && (match.token === DSML_TOOL_CALLS_CLOSE_FULLWIDTH || match.token === DSML_TOOL_CALLS_CLOSE_ASCII)) {
|
|
4906
|
+
this.#emitText(match.raw, events);
|
|
4907
|
+
this.#bareDsmlOpenVisible = false;
|
|
4234
4908
|
continue;
|
|
4235
4909
|
}
|
|
4236
|
-
|
|
4910
|
+
if (OUTSIDE_DROPPED_TOKENS[match.token]) this.#stripLeadingWhitespace = true;
|
|
4237
4911
|
}
|
|
4238
4912
|
}
|
|
4913
|
+
#emitText(text, events) {
|
|
4914
|
+
if (text.length === 0) return;
|
|
4915
|
+
events.push({
|
|
4916
|
+
type: "text",
|
|
4917
|
+
text
|
|
4918
|
+
});
|
|
4919
|
+
this.#visibleTail = (this.#visibleTail + text).slice(-48);
|
|
4920
|
+
this.#code = advanceCodeState(this.#code, text);
|
|
4921
|
+
if (!this.#bareDsmlOpenVisible && BARE_DSML_OPEN.test(this.#visibleTail)) this.#bareDsmlOpenVisible = true;
|
|
4922
|
+
}
|
|
4239
4923
|
#consumeThinking(final, events) {
|
|
4240
4924
|
const close = this.#buffer.indexOf(THINK_CLOSE$4);
|
|
4241
4925
|
if (close === -1) {
|
|
@@ -4249,35 +4933,47 @@ var DeepSeekInbandScanner = class {
|
|
|
4249
4933
|
this.#buffer = this.#buffer.slice(close + 8);
|
|
4250
4934
|
this.#endThinking(events);
|
|
4251
4935
|
}
|
|
4252
|
-
#consumeSection(final) {
|
|
4936
|
+
#consumeSection(final, events) {
|
|
4253
4937
|
while (this.#buffer.length > 0) {
|
|
4254
|
-
this.#
|
|
4255
|
-
|
|
4256
|
-
|
|
4938
|
+
const indent = this.#buffer.length - this.#buffer.trimStart().length;
|
|
4939
|
+
const rest = this.#buffer.slice(indent);
|
|
4940
|
+
const lead = templateTokenAtStart(rest);
|
|
4941
|
+
if (lead?.token === "<|tool▁calls▁end|>") {
|
|
4942
|
+
this.#buffer = rest.slice(lead.raw.length);
|
|
4257
4943
|
this.#inToolSection = false;
|
|
4258
4944
|
this.#state = "outside";
|
|
4259
4945
|
return true;
|
|
4260
4946
|
}
|
|
4261
|
-
if (
|
|
4262
|
-
this.#buffer =
|
|
4263
|
-
this.#rawBlock =
|
|
4947
|
+
if (lead?.token === "<|tool▁call▁begin|>") {
|
|
4948
|
+
this.#buffer = rest.slice(lead.raw.length);
|
|
4949
|
+
this.#rawBlock = lead.raw;
|
|
4264
4950
|
this.#state = "header";
|
|
4265
4951
|
return true;
|
|
4266
4952
|
}
|
|
4267
|
-
if (
|
|
4268
|
-
|
|
4269
|
-
|
|
4953
|
+
if (lead) {
|
|
4954
|
+
this.#buffer = rest.slice(lead.raw.length);
|
|
4955
|
+
continue;
|
|
4956
|
+
}
|
|
4957
|
+
if (rest.length === 0 || templateTokenPartialLength(rest) === rest.length) {
|
|
4958
|
+
if (!final) return false;
|
|
4959
|
+
this.#buffer = "";
|
|
4960
|
+
return true;
|
|
4961
|
+
}
|
|
4962
|
+
const next = rest.indexOf("<", 1);
|
|
4963
|
+
const prose = this.#buffer.slice(0, next === -1 ? this.#buffer.length : indent + next).trimEnd();
|
|
4964
|
+
this.#emitText(prose, events);
|
|
4965
|
+
this.#buffer = this.#buffer.slice(prose.length);
|
|
4270
4966
|
}
|
|
4271
4967
|
return final;
|
|
4272
4968
|
}
|
|
4273
4969
|
#consumeHeader(final, events) {
|
|
4274
|
-
const sep = this.#buffer
|
|
4275
|
-
if (sep
|
|
4970
|
+
const sep = findDeepSeekTemplateToken(this.#buffer, SEPARATOR_TOKENS);
|
|
4971
|
+
if (!sep) {
|
|
4276
4972
|
if (final) this.#resetTool();
|
|
4277
4973
|
return false;
|
|
4278
4974
|
}
|
|
4279
|
-
const rawHead = this.#buffer.slice(0, sep +
|
|
4280
|
-
const head = this.#buffer.slice(0, sep).trim();
|
|
4975
|
+
const rawHead = this.#buffer.slice(0, sep.index + sep.raw.length);
|
|
4976
|
+
const head = this.#buffer.slice(0, sep.index).trim();
|
|
4281
4977
|
this.#rawBlock += rawHead;
|
|
4282
4978
|
this.#buffer = this.#buffer.slice(rawHead.length);
|
|
4283
4979
|
if (head === LEGACY_TOOL_TYPE) {
|
|
@@ -4304,18 +5000,26 @@ var DeepSeekInbandScanner = class {
|
|
|
4304
5000
|
return true;
|
|
4305
5001
|
}
|
|
4306
5002
|
#consumeArgs(final, events) {
|
|
4307
|
-
|
|
4308
|
-
|
|
5003
|
+
let end;
|
|
5004
|
+
let rawArgs = "";
|
|
5005
|
+
for (let candidate = findDeepSeekTemplateToken(this.#buffer, ARGS_TERMINATOR_TOKENS); candidate; candidate = findDeepSeekTemplateToken(this.#buffer, ARGS_TERMINATOR_TOKENS, candidate.index + candidate.raw.length)) {
|
|
5006
|
+
rawArgs = this.#buffer.slice(0, candidate.index);
|
|
5007
|
+
if (this.#state === "legacyArgs") {
|
|
5008
|
+
const fence = rawArgs.lastIndexOf(CODE_FENCE);
|
|
5009
|
+
if (fence !== -1) rawArgs = rawArgs.slice(0, fence);
|
|
5010
|
+
}
|
|
5011
|
+
const trimmed = rawArgs.trim();
|
|
5012
|
+
if (candidate.raw === "<|tool▁call▁end|>" || trimmed.length === 0 || classifyJsonPrefix(trimmed) !== "prefix") {
|
|
5013
|
+
end = candidate;
|
|
5014
|
+
break;
|
|
5015
|
+
}
|
|
5016
|
+
}
|
|
5017
|
+
if (!end) {
|
|
4309
5018
|
if (final) this.#resetTool();
|
|
4310
5019
|
return false;
|
|
4311
5020
|
}
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
const fence = rawArgs.lastIndexOf(CODE_FENCE);
|
|
4315
|
-
if (fence !== -1) rawArgs = rawArgs.slice(0, fence);
|
|
4316
|
-
}
|
|
4317
|
-
const rawTail = this.#buffer.slice(0, end + 17);
|
|
4318
|
-
this.#rawBlock += rawTail;
|
|
5021
|
+
const consumed = end.index + (end.token === "<|tool▁call▁end|>" ? end.raw.length : 0);
|
|
5022
|
+
this.#rawBlock += this.#buffer.slice(0, consumed);
|
|
4319
5023
|
events.push({
|
|
4320
5024
|
type: "toolEnd",
|
|
4321
5025
|
id: this.#id,
|
|
@@ -4323,21 +5027,27 @@ var DeepSeekInbandScanner = class {
|
|
|
4323
5027
|
arguments: this.#parseArgs(rawArgs),
|
|
4324
5028
|
rawBlock: this.#rawBlock
|
|
4325
5029
|
});
|
|
4326
|
-
this.#buffer = this.#buffer.slice(
|
|
5030
|
+
this.#buffer = this.#buffer.slice(consumed);
|
|
4327
5031
|
this.#resetTool(this.#inToolSection ? "section" : "outside");
|
|
4328
5032
|
return true;
|
|
4329
5033
|
}
|
|
4330
5034
|
#consumeDsmlSection(final, events) {
|
|
5035
|
+
const initial = this.#buffer;
|
|
4331
5036
|
while (this.#buffer.length > 0) {
|
|
4332
5037
|
this.#skipWhitespace();
|
|
4333
5038
|
const close = this.#matchingDsmlClose(DSML_TOOL_CALLS_CLOSE_FULLWIDTH, DSML_TOOL_CALLS_CLOSE_ASCII);
|
|
4334
5039
|
if (close) {
|
|
5040
|
+
if (this.#pendingDsmlSection !== void 0) {
|
|
5041
|
+
this.#emitText(this.#pendingDsmlSection + initial.slice(0, initial.length - this.#buffer.length) + close, events);
|
|
5042
|
+
this.#pendingDsmlSection = void 0;
|
|
5043
|
+
}
|
|
4335
5044
|
this.#buffer = this.#buffer.slice(close.length);
|
|
4336
5045
|
this.#state = "outside";
|
|
4337
5046
|
return true;
|
|
4338
5047
|
}
|
|
4339
5048
|
const invoke = this.#matchDsmlOpen("invoke");
|
|
4340
5049
|
if (invoke) {
|
|
5050
|
+
this.#pendingDsmlSection = void 0;
|
|
4341
5051
|
this.#rawBlock = invoke.raw;
|
|
4342
5052
|
this.#name = invoke.name;
|
|
4343
5053
|
this.#id = mintToolCallId();
|
|
@@ -4351,12 +5061,13 @@ var DeepSeekInbandScanner = class {
|
|
|
4351
5061
|
return true;
|
|
4352
5062
|
}
|
|
4353
5063
|
if (!final) {
|
|
4354
|
-
if ((this.#buffer.startsWith("<|DSML|invoke") || this.#buffer.startsWith("<|DSML|invoke")) && !this.#buffer.includes(">"))
|
|
4355
|
-
if (partialSuffixOverlapAny(this.#buffer, DSML_SECTION_TOKENS) === this.#buffer.length)
|
|
5064
|
+
if ((this.#buffer.startsWith("<|DSML|invoke") || this.#buffer.startsWith("<|DSML|invoke")) && !this.#buffer.includes(">")) break;
|
|
5065
|
+
if (partialSuffixOverlapAny(this.#buffer, DSML_SECTION_TOKENS) === this.#buffer.length) break;
|
|
4356
5066
|
}
|
|
4357
|
-
if (this.#buffer.length === 0)
|
|
5067
|
+
if (this.#buffer.length === 0) break;
|
|
4358
5068
|
this.#buffer = this.#buffer.slice(1);
|
|
4359
5069
|
}
|
|
5070
|
+
if (this.#pendingDsmlSection !== void 0) this.#pendingDsmlSection += initial.slice(0, initial.length - this.#buffer.length);
|
|
4360
5071
|
return final;
|
|
4361
5072
|
}
|
|
4362
5073
|
#consumeDsmlInvoke(final, events) {
|
|
@@ -4461,11 +5172,7 @@ var DeepSeekInbandScanner = class {
|
|
|
4461
5172
|
#parseArgs(rawArgs) {
|
|
4462
5173
|
const trimmed = rawArgs.trim();
|
|
4463
5174
|
if (trimmed.length === 0) return {};
|
|
4464
|
-
|
|
4465
|
-
return asRecord(parseJsonWithRepair(trimmed));
|
|
4466
|
-
} catch {
|
|
4467
|
-
return {};
|
|
4468
|
-
}
|
|
5175
|
+
return asRecord(parseToolCallArguments(trimmed));
|
|
4469
5176
|
}
|
|
4470
5177
|
#skipWhitespace() {
|
|
4471
5178
|
let i = 0;
|
|
@@ -4486,15 +5193,34 @@ var DeepSeekInbandScanner = class {
|
|
|
4486
5193
|
}
|
|
4487
5194
|
return "";
|
|
4488
5195
|
}
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
5196
|
+
/**
|
|
5197
|
+
* Earliest outside-state token: a literal (`<think>`, DSML tags, canonical
|
|
5198
|
+
* template tokens) or a re-spelled template token. Ties keep the literal.
|
|
5199
|
+
* A re-spelled token inside code the model quoted is prose about the token,
|
|
5200
|
+
* not markup; canonical spellings keep their long-standing handling. An
|
|
5201
|
+
* inline span is code only once its closing run arrives, so a token after an
|
|
5202
|
+
* unclosed run returns its index to hold from until the paragraph decides.
|
|
5203
|
+
*/
|
|
5204
|
+
#findOutsideToken(final) {
|
|
5205
|
+
const literal = findEarliestToken(this.#buffer, OUTSIDE_TOKENS);
|
|
5206
|
+
let template = findDeepSeekTemplateToken(this.#buffer, OUTSIDE_TEMPLATE_TOKENS);
|
|
5207
|
+
while (template && template.raw !== template.token && (!literal || template.index < literal.index)) {
|
|
5208
|
+
const code = advanceCodeState(this.#code, this.#buffer.slice(0, template.index));
|
|
5209
|
+
const fence = settleBacktickRun(code.fence, code.run);
|
|
5210
|
+
if (fence === 0) break;
|
|
5211
|
+
if (fence < 3) {
|
|
5212
|
+
const closes = inlineSpanCloses(this.#buffer.slice(template.index + template.raw.length), fence, final);
|
|
5213
|
+
if (closes === void 0) return template.index;
|
|
5214
|
+
if (!closes) break;
|
|
5215
|
+
}
|
|
5216
|
+
template = findDeepSeekTemplateToken(this.#buffer, OUTSIDE_TEMPLATE_TOKENS, template.index + template.raw.length);
|
|
5217
|
+
}
|
|
5218
|
+
if (template && (!literal || template.index < literal.index)) return template;
|
|
5219
|
+
return literal && {
|
|
5220
|
+
token: literal.token,
|
|
5221
|
+
raw: literal.token,
|
|
5222
|
+
index: literal.index
|
|
5223
|
+
};
|
|
4498
5224
|
}
|
|
4499
5225
|
#matchingDsmlClose(fullwidth, ascii) {
|
|
4500
5226
|
if (this.#buffer.startsWith(fullwidth)) return fullwidth;
|
|
@@ -4606,7 +5332,7 @@ const definition$9 = {
|
|
|
4606
5332
|
renderTranscript: renderTranscript$9
|
|
4607
5333
|
};
|
|
4608
5334
|
//#endregion
|
|
4609
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
5335
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/fenced-thinking.ts
|
|
4610
5336
|
/**
|
|
4611
5337
|
* Close-matcher for a ` ```thinking ` block that respects nested Markdown code
|
|
4612
5338
|
* fences. A naive `indexOf("```")` closes the thinking section at the FIRST
|
|
@@ -4781,10 +5507,10 @@ var FencedThinkingScanner = class {
|
|
|
4781
5507
|
}
|
|
4782
5508
|
};
|
|
4783
5509
|
//#endregion
|
|
4784
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
5510
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/gemini.md
|
|
4785
5511
|
var gemini_default = "## Format guide\n\nEmit tool calls as Python inside a fenced ` ```tool_code ` block. Call each function as a method on `default_api`:\n\n````text\n```tool_code\ndefault_api.function_name(arg=\"value\", count=2)\n```\n````\n\nArgument values are Python literals: `\"strings\"`, numbers, `True`/`False`, `None`, `[lists]`, `{\"dicts\": 1}`.\n\nCall several functions in parallel as a Python list:\n\n````text\n```tool_code\n[default_api.first(x=\"a\"), default_api.second(y=\"b\")]\n```\n````\n\nTool results arrive later in a ` ```tool_outputs ` block:\n\n````text\n```tool_outputs\nverbatim tool result\n```\n````\n\nPut any private reasoning in a fenced ` ```thinking ` block before the ` ```tool_code ` block:\n\n````text\n```thinking\nbrief reasoning\n```\n````\n\n## Rules\n\n- The function name MUST match a listed function; arguments are keyword form (`name=value`).\n- Argument string values use only normal Python string escaping; never HTML-escape their contents — write `\"a & b\"`, not `\"a & b\"`.\n- Multiple calls = a single `[...]` list (or one `default_api...` call per line) inside one ` ```tool_code ` block.\n- Put private reasoning in a ` ```thinking ` block before the ` ```tool_code ` block, never inside ` ```tool_code `.\n- Read each ` ```tool_outputs ` block in call order. NEVER write a ` ```tool_outputs ` block yourself.\n- Emit the ` ```tool_code ` block in full, THEN stop and halt — NEVER announce a tool then stop (e.g. halting at \"Let's run `cargo clippy`\" with no ` ```tool_code ` block emitted).\n";
|
|
4786
5512
|
//#endregion
|
|
4787
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
5513
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/gemini.ts
|
|
4788
5514
|
const CODE_OPEN = "```tool_code";
|
|
4789
5515
|
const OUTPUT_OPEN = "```tool_outputs";
|
|
4790
5516
|
const FENCE = "```";
|
|
@@ -4806,15 +5532,20 @@ var GeminiInbandScanner = class {
|
|
|
4806
5532
|
/** Fence-aware close-matcher while {@link #state} is "thinking"; undefined otherwise. */
|
|
4807
5533
|
#fenced;
|
|
4808
5534
|
#parseThinking;
|
|
5535
|
+
#closeWait = new TerminatorWait();
|
|
4809
5536
|
constructor(options = {}) {
|
|
4810
5537
|
this.#parseThinking = options.parseThinking !== false;
|
|
4811
5538
|
}
|
|
4812
5539
|
feed(text) {
|
|
4813
5540
|
if (text.length === 0) return [];
|
|
4814
|
-
this.#
|
|
4815
|
-
|
|
5541
|
+
if (this.#closeWait.absorb(text)) return [];
|
|
5542
|
+
this.#buffer = this.#closeWait.release(this.#buffer) + text;
|
|
5543
|
+
const events = this.#consume(false);
|
|
5544
|
+
if (this.#state === "tool") this.#closeWait.arm(FENCE, this.#buffer);
|
|
5545
|
+
return events;
|
|
4816
5546
|
}
|
|
4817
5547
|
flush() {
|
|
5548
|
+
this.#buffer = this.#closeWait.release(this.#buffer);
|
|
4818
5549
|
return this.#consume(true);
|
|
4819
5550
|
}
|
|
4820
5551
|
#consume(final) {
|
|
@@ -5312,10 +6043,10 @@ const definition$8 = {
|
|
|
5312
6043
|
renderTranscript: renderTranscript$8
|
|
5313
6044
|
};
|
|
5314
6045
|
//#endregion
|
|
5315
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
6046
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/gemma.md
|
|
5316
6047
|
var gemma_default = "## Format guide\n\nEmit each tool call as one `<|tool_call>` block. The body is `call:NAME{key:value,...}`; wrap every string value in the `<|\"|>` token:\n\n```text\n<|tool_call>call:function_name{path:<|\"|>src/a.ts<|\"|>,count:2}<tool_call|>\n```\n\nNon-string values are bare: numbers (`2`), `true`/`false`, `null`, lists `[<|\"|>a<|\"|>,<|\"|>b<|\"|>]`, and nested objects `{k:<|\"|>v<|\"|>}`.\n\nTool results arrive later in matching `<|tool_response>` blocks:\n\n```text\n<|tool_response>response:function_name{output:<|\"|>verbatim result<|\"|>}<tool_response|>\n```\n\nOptionally precede tool calls with private reasoning in a `<|channel>thought` block, closed by `<channel|>`:\n\n```text\n<|channel>thought\nbrief reasoning\n<channel|>\n```\n\n## Rules\n\n- `NAME` MUST match a listed function; arguments are `key:value` pairs separated by commas.\n- String values between `<|\"|>` tokens are raw literal text (no escaping); never HTML-escape them — write `a & b`, not `a & b`.\n- Multiple calls = consecutive `<|tool_call>...<tool_call|>` blocks; keep prose outside them.\n- The closer is `<tool_call|>` (pipe on the right), not `</tool_call>` or `<|tool_call>`.\n- Private reasoning goes in a `<|channel>thought…<channel|>` block before any call; NEVER put tool calls inside it.\n- Read each `<|tool_response>` block in call order. NEVER write a `<|tool_response>` block yourself.\n- Write each call in full, THEN stop and halt — NEVER announce a tool then stop (e.g. halting at \"Let's run `cargo clippy`\" with no `<|tool_call>` block emitted).\n";
|
|
5317
6048
|
//#endregion
|
|
5318
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
6049
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/gemma.ts
|
|
5319
6050
|
const CALL_OPEN = "<|tool_call>";
|
|
5320
6051
|
const CALL_CLOSE = "<tool_call|>";
|
|
5321
6052
|
const STRING = "<|\"|>";
|
|
@@ -5660,10 +6391,10 @@ const definition$7 = {
|
|
|
5660
6391
|
renderTranscript: renderTranscript$7
|
|
5661
6392
|
};
|
|
5662
6393
|
//#endregion
|
|
5663
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
6394
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/glm.md
|
|
5664
6395
|
var glm_default = "## Format guide\n\nEmit each call as a `<tool_call>` block. The function name goes on the same line as the opening tag, followed by one `<arg_key>`/`<arg_value>` pair per argument, closed by `</tool_call>`:\n\n```text\n<tool_call>get_weather\n<arg_key>location</arg_key>\n<arg_value>Beijing</arg_value>\n<arg_key>days</arg_key>\n<arg_value>3</arg_value>\n</tool_call>\n```\n\nTool results return in an observation block:\n\n```text\n<observation>\n<tool_response>\nverbatim tool result\n</tool_response>\n</observation>\n```\n\n## Rules\n\n- The name after `<tool_call>` must match a listed function and sit on the same line.\n- Emit one `<arg_key>name</arg_key>` + `<arg_value>value</arg_value>` pair per argument; omit unset optional args.\n- `<arg_value>` bodies are read by regex (delimiter matching), NOT a real XML parser: write string values as raw literal text and never HTML-escape them (emit `a & b`, not `a & b`; `<`/`>` stay literal); only the body's own `</arg_value>` closing tag is reserved. Non-string values are valid JSON.\n- Multiple calls are consecutive `<tool_call>…</tool_call>` blocks.\n- Private reasoning goes in `<think>…</think>`; NEVER put tool calls inside `<think>`.\n- Read each `<tool_response>` in call order. NEVER emit `<tool_response>` yourself.\n- Emit the stop sequence ONLY after the call is fully written — NEVER announce a tool then stop (e.g. halting at \"Let's run `cargo clippy`\" with no `<tool_call>` emitted). Write the complete call, THEN the stop sequence, THEN halt.\n";
|
|
5665
6396
|
//#endregion
|
|
5666
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
6397
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/glm.ts
|
|
5667
6398
|
const TOOL_OPEN$2 = "<tool_call>";
|
|
5668
6399
|
const TOOL_CLOSE$2 = "</tool_call>";
|
|
5669
6400
|
const ARG_KEY_OPEN = "<arg_key>";
|
|
@@ -6188,10 +6919,10 @@ const definition$6 = {
|
|
|
6188
6919
|
renderTranscript: renderTranscript$6
|
|
6189
6920
|
};
|
|
6190
6921
|
//#endregion
|
|
6191
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
6922
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/harmony.md
|
|
6192
6923
|
var harmony_default = "## Format guide\n\nEach function call is one assistant message on the `commentary` channel addressed to the function, emitted as text:\n\n```text\n<|start|>assistant<|channel|>commentary to=functions.function_name<|message|>{\"arg\":\"value\"}<|call|>\n```\n\nPut private reasoning in an `analysis` message:\n\n```text\n<|start|>assistant<|channel|>analysis<|message|>private reasoning<|end|>\n```\n\nTool results arrive as messages authored by the function, addressed back to the assistant:\n\n```text\n<|start|>functions.function_name to=assistant<|channel|>commentary<|message|>verbatim tool result<|end|>\n```\n\n## Rules\n\n- Recipient is `functions.` + a listed function name.\n- Body is one JSON object matching the schema; omit optional arguments you are not setting.\n- Argument string values use only normal JSON string escaping (`\\\"`, `\\\\`, `\\n`); never HTML-escape their contents — write `a & b`, not `a & b`.\n- Multiple calls = consecutive call messages.\n- An optional visible preamble is a `commentary` message ending `<|end|>`.\n- NEVER put tool calls in `analysis`.\n- NEVER wrap calls in Markdown/code fences.\n- Read each tool-result message in call order. NEVER emit tool-result messages yourself.\n- Emit the stop sequence ONLY after the call is fully written — NEVER announce a tool then stop (e.g. halting at \"Let's run `cargo clippy`\" with no `<|call|>` message emitted). Write the complete call, THEN the stop sequence, THEN halt.\n";
|
|
6193
6924
|
//#endregion
|
|
6194
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
6925
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/harmony.ts
|
|
6195
6926
|
const START = "<|start|>";
|
|
6196
6927
|
const END = "<|end|>";
|
|
6197
6928
|
const MESSAGE = "<|message|>";
|
|
@@ -6393,11 +7124,7 @@ var HarmonyInbandScanner = class {
|
|
|
6393
7124
|
#parseArgs() {
|
|
6394
7125
|
const raw = this.#toolArgs.trim();
|
|
6395
7126
|
if (raw.length === 0) return {};
|
|
6396
|
-
|
|
6397
|
-
return asRecord(parseJsonWithRepair(raw));
|
|
6398
|
-
} catch {
|
|
6399
|
-
return {};
|
|
6400
|
-
}
|
|
7127
|
+
return asRecord(parseToolCallArguments(raw));
|
|
6401
7128
|
}
|
|
6402
7129
|
#clearBody(resetRawBlock = true) {
|
|
6403
7130
|
this.#mode = "skip";
|
|
@@ -6499,10 +7226,10 @@ const definition$5 = {
|
|
|
6499
7226
|
renderTranscript: renderTranscript$5
|
|
6500
7227
|
};
|
|
6501
7228
|
//#endregion
|
|
6502
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
7229
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/hermes.md
|
|
6503
7230
|
var hermes_default = "## Format guide\n\nEmit each call as a `<tool_call>` block wrapping a single-line JSON object with `name` and `arguments`:\n\n```text\n<tool_call>\n{\"name\":\"function_name\",\"arguments\":{\"arg\":\"value\"}}\n</tool_call>\n```\n\nResults arrive later as `<tool_response>` blocks:\n\n```text\n<tool_response>\nverbatim tool result\n</tool_response>\n```\n\n## Rules\n\n- `name` MUST match a listed function; `arguments` is a JSON object, never a stringified JSON.\n- Argument string values use only normal JSON string escaping (`\\\"`, `\\\\`, `\\n`); never HTML-escape their contents — write `a & b`, not `a & b`.\n- Emit multiple calls as consecutive `<tool_call>` blocks; keep any prose outside them.\n- Read each `<tool_response>` in call order. NEVER emit `<tool_response>` yourself.\n- Emit the stop sequence ONLY after the call is fully written — NEVER announce a tool then stop (e.g. halting at \"Let's run `cargo clippy`\" with no `<tool_call>` emitted). Write the complete call, THEN the stop sequence, THEN halt.\n";
|
|
6504
7231
|
//#endregion
|
|
6505
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
7232
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/hermes.ts
|
|
6506
7233
|
const TOOL_OPEN$1 = "<tool_call>";
|
|
6507
7234
|
const TOOL_CLOSE$1 = "</tool_call>";
|
|
6508
7235
|
const THINK_OPEN$2 = "<think>";
|
|
@@ -6522,15 +7249,20 @@ var HermesInbandScanner = class {
|
|
|
6522
7249
|
#parseThinking;
|
|
6523
7250
|
#inThinking = false;
|
|
6524
7251
|
#thinking = "";
|
|
7252
|
+
#closeWait = new TerminatorWait();
|
|
6525
7253
|
constructor(options = {}) {
|
|
6526
7254
|
this.#parseThinking = options.parseThinking === true;
|
|
6527
7255
|
}
|
|
6528
7256
|
feed(text) {
|
|
6529
7257
|
if (text.length === 0) return [];
|
|
6530
|
-
this.#
|
|
6531
|
-
|
|
7258
|
+
if (this.#closeWait.absorb(text)) return [];
|
|
7259
|
+
this.#buffer = this.#closeWait.release(this.#buffer) + text;
|
|
7260
|
+
const events = this.#consume(false);
|
|
7261
|
+
if (this.#inside && this.#started && !this.#inThinking) this.#closeWait.arm(TOOL_CLOSE$1, this.#buffer);
|
|
7262
|
+
return events;
|
|
6532
7263
|
}
|
|
6533
7264
|
flush() {
|
|
7265
|
+
this.#buffer = this.#closeWait.release(this.#buffer);
|
|
6534
7266
|
return this.#consume(true);
|
|
6535
7267
|
}
|
|
6536
7268
|
#consume(final) {
|
|
@@ -6639,28 +7371,22 @@ var HermesInbandScanner = class {
|
|
|
6639
7371
|
return events;
|
|
6640
7372
|
}
|
|
6641
7373
|
#tryStart(body, events) {
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
});
|
|
6652
|
-
} catch {}
|
|
7374
|
+
const name = parseCompleteToolName(body);
|
|
7375
|
+
if (!name) return;
|
|
7376
|
+
this.#name = name;
|
|
7377
|
+
this.#started = true;
|
|
7378
|
+
events.push({
|
|
7379
|
+
type: "toolStart",
|
|
7380
|
+
id: this.#id,
|
|
7381
|
+
name: this.#name
|
|
7382
|
+
});
|
|
6653
7383
|
}
|
|
6654
7384
|
#parseCall(body) {
|
|
6655
7385
|
try {
|
|
6656
7386
|
const parsed = parseJsonWithRepair(body.trim());
|
|
6657
7387
|
if (typeof parsed.name !== "string" || parsed.name.length === 0) return void 0;
|
|
6658
7388
|
let args = parsed.arguments;
|
|
6659
|
-
if (typeof args === "string")
|
|
6660
|
-
args = parseJsonWithRepair(args);
|
|
6661
|
-
} catch {
|
|
6662
|
-
args = {};
|
|
6663
|
-
}
|
|
7389
|
+
if (typeof args === "string") args = parseToolCallArguments(args);
|
|
6664
7390
|
return {
|
|
6665
7391
|
name: parsed.name,
|
|
6666
7392
|
arguments: asRecord(args)
|
|
@@ -6710,10 +7436,10 @@ const definition$4 = {
|
|
|
6710
7436
|
renderTranscript: renderTranscript$4
|
|
6711
7437
|
};
|
|
6712
7438
|
//#endregion
|
|
6713
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
7439
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/kimi.md
|
|
6714
7440
|
var kimi_default = "## Format guide\n\nEmit every call of a turn inside one section. Each call is an id of the fixed form `functions.NAME:INDEX` followed by one JSON arguments object:\n\n```text\n<|tool_calls_section_begin|><|tool_call_begin|>functions.NAME:INDEX<|tool_call_argument_begin|>{\"arg\":\"value\"}<|tool_call_end|><|tool_calls_section_end|>\n```\n\nTool results arrive later as turns whose body is a `## Return of functions.NAME:INDEX` header then the verbatim result:\n\n```text\n<|im_system|>NAME<|im_middle|>## Return of functions.NAME:INDEX\nverbatim tool result<|im_end|>\n```\n\n## Rules\n\n- `NAME` MUST match a listed function exactly.\n- Arguments MUST be one JSON object with double-quoted keys.\n- Argument string values use only normal JSON string escaping (`\\\"`, `\\\\`, `\\n`); never HTML-escape their contents — write `a & b`, not `a & b`.\n- Multiple calls = consecutive `<|tool_call_begin|>…<|tool_call_end|>` blocks in the same section; `INDEX` increments from `0`.\n- Private reasoning, when supported, goes in `<think>…</think>` before the tool-call section; NEVER put tool calls inside `<think>`.\n- Read each result turn in call order. NEVER emit result turns yourself.\n- Emit the stop sequence ONLY after the call is fully written — NEVER announce a tool then stop (e.g. halting at \"Let's run `cargo clippy`\" with no `<|tool_call_begin|>` emitted). Write the complete call, THEN the stop sequence, THEN halt.\n";
|
|
6715
7441
|
//#endregion
|
|
6716
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
7442
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/kimi.ts
|
|
6717
7443
|
const KIMI_SECTION_BEGIN = "<|tool_calls_section_begin|>";
|
|
6718
7444
|
const KIMI_SECTION_END = "<|tool_calls_section_end|>";
|
|
6719
7445
|
const KIMI_CALL_BEGIN = "<|tool_call_begin|>";
|
|
@@ -6743,16 +7469,21 @@ var KimiInbandScanner = class {
|
|
|
6743
7469
|
#name = "";
|
|
6744
7470
|
#rawBlock = "";
|
|
6745
7471
|
#thinking = "";
|
|
7472
|
+
#closeWait = new TerminatorWait();
|
|
6746
7473
|
#parseThinking;
|
|
6747
7474
|
constructor(options = {}) {
|
|
6748
7475
|
this.#parseThinking = options.parseThinking !== false;
|
|
6749
7476
|
}
|
|
6750
7477
|
feed(text) {
|
|
6751
7478
|
if (text.length === 0) return [];
|
|
6752
|
-
this.#
|
|
6753
|
-
|
|
7479
|
+
if (this.#closeWait.absorb(text)) return [];
|
|
7480
|
+
this.#buffer = this.#closeWait.release(this.#buffer) + text;
|
|
7481
|
+
const events = this.#consume(false);
|
|
7482
|
+
if (this.#state === "args") this.#closeWait.arm(KIMI_CALL_END, this.#buffer);
|
|
7483
|
+
return events;
|
|
6754
7484
|
}
|
|
6755
7485
|
flush() {
|
|
7486
|
+
this.#buffer = this.#closeWait.release(this.#buffer);
|
|
6756
7487
|
return this.#consume(true);
|
|
6757
7488
|
}
|
|
6758
7489
|
#consume(final) {
|
|
@@ -6914,11 +7645,7 @@ var KimiInbandScanner = class {
|
|
|
6914
7645
|
}
|
|
6915
7646
|
#parseArgs(rawArgs) {
|
|
6916
7647
|
if (rawArgs.length === 0) return {};
|
|
6917
|
-
|
|
6918
|
-
return asRecord(parseJsonWithRepair(rawArgs));
|
|
6919
|
-
} catch {
|
|
6920
|
-
return {};
|
|
6921
|
-
}
|
|
7648
|
+
return asRecord(parseToolCallArguments(rawArgs));
|
|
6922
7649
|
}
|
|
6923
7650
|
#nextTokenIndex() {
|
|
6924
7651
|
let best = -1;
|
|
@@ -7009,10 +7736,10 @@ const definition$3 = {
|
|
|
7009
7736
|
renderTranscript: renderTranscript$3
|
|
7010
7737
|
};
|
|
7011
7738
|
//#endregion
|
|
7012
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
7739
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/minimax.md
|
|
7013
7740
|
var minimax_default = "## Format guide\n\nA call is a `<minimax:tool_call>` block wrapping one or more `<invoke>` blocks, each holding `<parameter>` children:\n\n```text\n<minimax:tool_call>\n<invoke name=\"tool_name\"><parameter name=\"arg_name\">arg value</parameter></invoke>\n</minimax:tool_call>\n```\n\nResults arrive later in a `<function_results>` block, one `<result>` per call (failures use `<error>` with `<stderr>` in place of `<result>` with `<stdout>`):\n\n```text\n<function_results>\n<result>\n<tool_name>tool_name</tool_name>\n<stdout>verbatim tool result</stdout>\n</result>\n</function_results>\n```\n\n## Rules\n\n- `name` MUST match a listed function.\n- String/scalar parameters: exact text, spaces preserved — bodies are read by regex (delimiter matching), NOT a real XML parser, so never HTML-escape them (emit `a & b`, not `a & b`; `<`/`>` stay literal); only the body's own `</parameter>` closing tag is reserved. Lists/objects: JSON.\n- Multiple calls: multiple `<invoke>` blocks in one `<minimax:tool_call>`.\n- You MAY write visible text before the calls.\n- NEVER emit `tool_calls` JSON.\n- NEVER use `<function_calls>` or the legacy `<tool_name>`/`<parameters>` call syntax.\n- Read each `<result>`/`<error>` in call order. NEVER emit `<function_results>` yourself.\n- Emit the stop sequence ONLY after the call is fully written — NEVER announce a tool then stop (e.g. halting at \"Let's run `cargo clippy`\" with no `<invoke>` emitted). Write the complete call, THEN the stop sequence, THEN halt.\n";
|
|
7014
7741
|
//#endregion
|
|
7015
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
7742
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/minimax.ts
|
|
7016
7743
|
const MINIMAX_WRAPPER_TAGS = { tool_call: true };
|
|
7017
7744
|
const MINIMAX_BASE_TAG_PREFIXES = [
|
|
7018
7745
|
"<minimax:tool_call",
|
|
@@ -7030,11 +7757,11 @@ const MINIMAX_SCANNER_CONFIG = {
|
|
|
7030
7757
|
allTagPrefixes: [...MINIMAX_BASE_TAG_PREFIXES, ...ANTHROPIC_THINKING_TAG_PREFIXES]
|
|
7031
7758
|
};
|
|
7032
7759
|
function renderToolCall$2(call, options = {}) {
|
|
7033
|
-
return renderInvoke
|
|
7760
|
+
return renderInvoke(call, buildArgShapes(options.tools).get(call.name));
|
|
7034
7761
|
}
|
|
7035
7762
|
function renderAssistantToolCalls$2(calls, options = {}) {
|
|
7036
7763
|
if (calls.length === 0) return "";
|
|
7037
|
-
return `<minimax:tool_call>\n${renderInvokes
|
|
7764
|
+
return `<minimax:tool_call>\n${renderInvokes(calls, options.tools ?? [])}\n</minimax:tool_call>`;
|
|
7038
7765
|
}
|
|
7039
7766
|
function renderToolResults$2(results) {
|
|
7040
7767
|
return `<function_results>\n${results.map((result) => {
|
|
@@ -7053,19 +7780,6 @@ function renderTranscript$2(messages, options = {}) {
|
|
|
7053
7780
|
renderResults: renderToolResults$2
|
|
7054
7781
|
});
|
|
7055
7782
|
}
|
|
7056
|
-
function renderInvoke$1(call, shape) {
|
|
7057
|
-
let body = `<invoke name="${escapeXmlAttr(call.name)}">`;
|
|
7058
|
-
for (const key in call.arguments) {
|
|
7059
|
-
const value = call.arguments[key];
|
|
7060
|
-
const rendered = shape?.stringArgs.has(key) === true && typeof value === "string" ? value : stringifyJson(value);
|
|
7061
|
-
body += `<parameter name="${escapeXmlAttr(key)}">${rendered}</parameter>`;
|
|
7062
|
-
}
|
|
7063
|
-
return `${body}</invoke>`;
|
|
7064
|
-
}
|
|
7065
|
-
function renderInvokes$1(calls, tools) {
|
|
7066
|
-
const shapes = buildArgShapes(tools);
|
|
7067
|
-
return calls.map((call) => renderInvoke$1(call, shapes.get(call.name))).join("\n");
|
|
7068
|
-
}
|
|
7069
7783
|
const definition$2 = {
|
|
7070
7784
|
dialect: "minimax",
|
|
7071
7785
|
prompt: minimax_default,
|
|
@@ -7077,10 +7791,10 @@ const definition$2 = {
|
|
|
7077
7791
|
renderTranscript: renderTranscript$2
|
|
7078
7792
|
};
|
|
7079
7793
|
//#endregion
|
|
7080
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
7794
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/qwen3.md
|
|
7081
7795
|
var qwen3_default = "## Format guide\n\nEmit each tool call as one `<tool_call>` block wrapping a single-line JSON object with `name` and a nested `arguments` object:\n\n```text\n<tool_call>\n{\"name\":\"function_name\",\"arguments\":{\"arg\":\"value\"}}\n</tool_call>\n```\n\nDo any private reasoning in `<think>...</think>` before your tool calls.\n\nTool results arrive later in a user turn:\n\n```text\n<tool_response>\nverbatim tool result\n</tool_response>\n```\n\n## Rules\n\n- `name` MUST match a listed function; `arguments` is a JSON object, never a JSON string.\n- Argument string values use only normal JSON string escaping (`\\\"`, `\\\\`, `\\n`); never HTML-escape their contents — write `a & b`, not `a & b`.\n- Multiple calls = consecutive `<tool_call>...</tool_call>` blocks; keep prose outside them.\n- NEVER put tool calls inside `<think>`.\n- Read each `<tool_response>` in call order. NEVER emit `<tool_response>` yourself.\n- Emit the stop sequence ONLY after the call is fully written — NEVER announce a tool then stop (e.g. halting at \"Let's run `cargo clippy`\" with no `<tool_call>` emitted). Write the complete call, THEN the stop sequence, THEN halt.\n";
|
|
7082
7796
|
//#endregion
|
|
7083
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
7797
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/qwen3.ts
|
|
7084
7798
|
const TOOL_OPEN = "<tool_call>";
|
|
7085
7799
|
const TOOL_CLOSE = "</tool_call>";
|
|
7086
7800
|
const THINK_OPEN = "<think>";
|
|
@@ -7088,7 +7802,6 @@ const THINK_CLOSE = "</think>";
|
|
|
7088
7802
|
const TOOL_START_TAGS = [TOOL_OPEN];
|
|
7089
7803
|
const START_TAGS = [TOOL_OPEN, THINK_OPEN];
|
|
7090
7804
|
const THINK_CLOSE_TAGS = [THINK_CLOSE];
|
|
7091
|
-
const COMPLETE_NAME = /^\s*\{\s*"name"\s*:\s*("(?:\\.|[^"\\])*")/;
|
|
7092
7805
|
var Qwen3InbandScanner = class {
|
|
7093
7806
|
#buffer = "";
|
|
7094
7807
|
#state = "outside";
|
|
@@ -7096,16 +7809,21 @@ var Qwen3InbandScanner = class {
|
|
|
7096
7809
|
#name = "";
|
|
7097
7810
|
#started = false;
|
|
7098
7811
|
#thinking = "";
|
|
7812
|
+
#closeWait = new TerminatorWait();
|
|
7099
7813
|
#parseThinking;
|
|
7100
7814
|
constructor(options = {}) {
|
|
7101
7815
|
this.#parseThinking = options.parseThinking !== false;
|
|
7102
7816
|
}
|
|
7103
7817
|
feed(text) {
|
|
7104
7818
|
if (text.length === 0) return [];
|
|
7105
|
-
this.#
|
|
7106
|
-
|
|
7819
|
+
if (this.#closeWait.absorb(text)) return [];
|
|
7820
|
+
this.#buffer = this.#closeWait.release(this.#buffer) + text;
|
|
7821
|
+
const events = this.#consume(false);
|
|
7822
|
+
if (this.#state === "tool" && this.#started) this.#closeWait.arm(TOOL_CLOSE, this.#buffer);
|
|
7823
|
+
return events;
|
|
7107
7824
|
}
|
|
7108
7825
|
flush() {
|
|
7826
|
+
this.#buffer = this.#closeWait.release(this.#buffer);
|
|
7109
7827
|
return this.#consume(true);
|
|
7110
7828
|
}
|
|
7111
7829
|
#consume(final) {
|
|
@@ -7224,15 +7942,8 @@ var Qwen3InbandScanner = class {
|
|
|
7224
7942
|
this.#state = "outside";
|
|
7225
7943
|
}
|
|
7226
7944
|
#tryStart(body, events) {
|
|
7227
|
-
const
|
|
7228
|
-
if (!
|
|
7229
|
-
let name;
|
|
7230
|
-
try {
|
|
7231
|
-
name = JSON.parse(nameMatch[1]);
|
|
7232
|
-
} catch {
|
|
7233
|
-
return;
|
|
7234
|
-
}
|
|
7235
|
-
if (typeof name !== "string" || name.length === 0) return;
|
|
7945
|
+
const name = parseCompleteToolName(body);
|
|
7946
|
+
if (!name) return;
|
|
7236
7947
|
this.#name = name;
|
|
7237
7948
|
this.#started = true;
|
|
7238
7949
|
events.push({
|
|
@@ -7246,11 +7957,7 @@ var Qwen3InbandScanner = class {
|
|
|
7246
7957
|
const parsed = parseJsonWithRepair(body.trim());
|
|
7247
7958
|
if (typeof parsed.name !== "string" || parsed.name.length === 0) return void 0;
|
|
7248
7959
|
let args = parsed.arguments;
|
|
7249
|
-
if (typeof args === "string")
|
|
7250
|
-
args = parseJsonWithRepair(args);
|
|
7251
|
-
} catch {
|
|
7252
|
-
args = {};
|
|
7253
|
-
}
|
|
7960
|
+
if (typeof args === "string") args = parseToolCallArguments(args);
|
|
7254
7961
|
return {
|
|
7255
7962
|
name: parsed.name,
|
|
7256
7963
|
arguments: asRecord(args)
|
|
@@ -7301,10 +8008,10 @@ const definition$1 = {
|
|
|
7301
8008
|
renderTranscript: renderTranscript$1
|
|
7302
8009
|
};
|
|
7303
8010
|
//#endregion
|
|
7304
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
8011
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/xml.md
|
|
7305
8012
|
var xml_default = "## Format guide\n\nA call is one `<invoke>` element whose `<parameter>` children carry its arguments:\n\n```text\n<invoke name=\"fn\"><parameter name=\"arg\">value</parameter></invoke>\n```\n\nEmit consecutive `<invoke>…</invoke>` blocks for multiple calls; you MAY wrap them in `<tool_calls>…</tool_calls>`. Each call's result arrives as a response block:\n\n```text\n<tool_response>\nverbatim tool result\n</tool_response>\n```\n\n## Rules\n\n- `name` MUST match a listed function.\n- Parameter values are read literally by regex (delimiter matching), NOT a real XML parser: write them verbatim and never HTML-escape (emit `a & b`, never `a & b`; `<`/`>` stay literal too). Only the body's own `</parameter>` closing tag is reserved. Non-string values are JSON; add `string=\"false\"` to a parameter only to force JSON parsing of a value the schema treats as a string.\n- Read each `<tool_response>` in call order. NEVER emit `<tool_response>` yourself.\n- Emit the stop sequence ONLY after the call is fully written — NEVER announce a tool then stop (e.g. halting at \"Let's run `cargo clippy`\" with no `<invoke>` emitted). Write the complete call, THEN the stop sequence, THEN halt.\n";
|
|
7306
8013
|
//#endregion
|
|
7307
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
8014
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/xml.ts
|
|
7308
8015
|
var XmlInbandScanner = class {
|
|
7309
8016
|
#inner;
|
|
7310
8017
|
constructor(options = {}) {
|
|
@@ -7336,21 +8043,8 @@ function renderTranscript(messages, options = {}) {
|
|
|
7336
8043
|
renderResults: renderToolResults
|
|
7337
8044
|
});
|
|
7338
8045
|
}
|
|
7339
|
-
function renderInvoke(call, shape) {
|
|
7340
|
-
let body = `<invoke name="${escapeXmlAttr(call.name)}">`;
|
|
7341
|
-
for (const key in call.arguments) {
|
|
7342
|
-
const value = call.arguments[key];
|
|
7343
|
-
const rendered = shape?.stringArgs.has(key) === true && typeof value === "string" ? value : stringifyJson(value);
|
|
7344
|
-
body += `<parameter name="${escapeXmlAttr(key)}">${rendered}</parameter>`;
|
|
7345
|
-
}
|
|
7346
|
-
return `${body}</invoke>`;
|
|
7347
|
-
}
|
|
7348
|
-
function renderInvokes(calls, tools) {
|
|
7349
|
-
const shapes = buildArgShapes(tools);
|
|
7350
|
-
return calls.map((call) => renderInvoke(call, shapes.get(call.name))).join("\n");
|
|
7351
|
-
}
|
|
7352
8046
|
//#endregion
|
|
7353
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
8047
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/factory.ts
|
|
7354
8048
|
const DIALECT_DEFINITIONS = {
|
|
7355
8049
|
glm: definition$6,
|
|
7356
8050
|
hermes: definition$4,
|
|
@@ -7380,7 +8074,7 @@ function createInbandScanner(dialect, options = {}) {
|
|
|
7380
8074
|
return getDialectDefinition(dialect).createScanner(options);
|
|
7381
8075
|
}
|
|
7382
8076
|
//#endregion
|
|
7383
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
8077
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/dialect/demotion.ts
|
|
7384
8078
|
/**
|
|
7385
8079
|
* Wrap a prior-turn reasoning string for demotion into native conversation
|
|
7386
8080
|
* history — the cross-provider / cross-model case where the target cannot
|
|
@@ -7419,7 +8113,7 @@ function renderDemotedThinking(modelId, text) {
|
|
|
7419
8113
|
return getDialectDefinition(dialect).renderThinking(text);
|
|
7420
8114
|
}
|
|
7421
8115
|
//#endregion
|
|
7422
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
8116
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/utils/block-symbols.ts
|
|
7423
8117
|
/** Stores streamed tool-call argument JSON for live renderers and parser recovery. */
|
|
7424
8118
|
const kStreamingPartialJson = Symbol("provider.block.partialJson");
|
|
7425
8119
|
/** Clears streamed tool-call argument JSON without deleting or changing object shape. */
|
|
@@ -7470,8 +8164,74 @@ const kDemotedThinking = Symbol("provider.block.demotedThinking");
|
|
|
7470
8164
|
function isDemotedThinking(block) {
|
|
7471
8165
|
return block?.[kDemotedThinking] === true;
|
|
7472
8166
|
}
|
|
8167
|
+
/**
|
|
8168
|
+
* Marks a thinking block that `transformMessages` carried natively from
|
|
8169
|
+
* another host serving the same model (see `compat/reasoning-carry` in the
|
|
8170
|
+
* catalog). Its host-bound signature and item id are gone, so encoders that
|
|
8171
|
+
* replay reasoning from stored payloads (Responses) emit a plaintext item for
|
|
8172
|
+
* it instead. Symbol-keyed so the marker never persists or reaches the wire.
|
|
8173
|
+
*/
|
|
8174
|
+
const kCarriedReasoning = Symbol("provider.block.carriedReasoning");
|
|
8175
|
+
/** True for thinking blocks carried natively from another host of the same model. */
|
|
8176
|
+
function isCarriedReasoning(block) {
|
|
8177
|
+
return block?.[kCarriedReasoning] === true;
|
|
8178
|
+
}
|
|
8179
|
+
/**
|
|
8180
|
+
* Marks an Anthropic wire message that was serialized from a source
|
|
8181
|
+
* `role: "user"` message.
|
|
8182
|
+
*
|
|
8183
|
+
* The wire role alone cannot answer this. `convertAnthropicMessages` emits
|
|
8184
|
+
* `role: "user"` for several things that are not a conversational turn:
|
|
8185
|
+
* `developer` messages on models without mid-conversation `system` support,
|
|
8186
|
+
* `tool_result` runs, and the synthetic `Continue.` pads inserted between
|
|
8187
|
+
* adjacent assistants. Prompt-cache decimation counts conversational turns,
|
|
8188
|
+
* so it reads this marker instead of guessing from wire content.
|
|
8189
|
+
*
|
|
8190
|
+
* Symbol-keyed so the marker never persists across the JSONL round-trip and
|
|
8191
|
+
* never reaches the wire.
|
|
8192
|
+
*/
|
|
8193
|
+
const kConversationalUser = Symbol("provider.message.conversationalUser");
|
|
8194
|
+
/** True for wire messages serialized from a source `role: "user"` message. */
|
|
8195
|
+
function isConversationalUser(message) {
|
|
8196
|
+
return message?.[kConversationalUser] === true;
|
|
8197
|
+
}
|
|
8198
|
+
/**
|
|
8199
|
+
* Marks a `role: "user"` message that `transformMessages` synthesized rather
|
|
8200
|
+
* than one the user sent.
|
|
8201
|
+
*
|
|
8202
|
+
* The stale-tool-result note is deliberately emitted as `user` so no provider
|
|
8203
|
+
* elevates untrusted tool output to instruction priority, which leaves it
|
|
8204
|
+
* indistinguishable from a real turn by role alone. Prompt-cache decimation
|
|
8205
|
+
* must not count it, or an orphan result appearing or disappearing in a
|
|
8206
|
+
* compacted history shifts every later checkpoint.
|
|
8207
|
+
*
|
|
8208
|
+
* Symbol-keyed so the marker never persists across the JSONL round-trip and
|
|
8209
|
+
* never reaches the wire.
|
|
8210
|
+
*/
|
|
8211
|
+
const kSyntheticUser = Symbol("provider.message.syntheticUser");
|
|
8212
|
+
/** True for `user` messages synthesized by message transformation. */
|
|
8213
|
+
function isSyntheticUser(message) {
|
|
8214
|
+
return message?.[kSyntheticUser] === true;
|
|
8215
|
+
}
|
|
8216
|
+
/**
|
|
8217
|
+
* Marks a message synthesized by a per-call context transform rather than
|
|
8218
|
+
* loaded from persisted conversation history.
|
|
8219
|
+
*
|
|
8220
|
+
* Prompt-cache boundaries must skip these messages: their content is rebuilt
|
|
8221
|
+
* for each request and cannot anchor a prefix reused by the next turn.
|
|
8222
|
+
* Symbol-keyed so the marker never persists or reaches the provider wire.
|
|
8223
|
+
*/
|
|
8224
|
+
const kPerCallContextMessage = Symbol("agent.message.perCallContext");
|
|
8225
|
+
/** Copies per-call context provenance to a converted or projected message. */
|
|
8226
|
+
function copyPerCallContextMessage(target, source) {
|
|
8227
|
+
if (source[kPerCallContextMessage] === true) target[kPerCallContextMessage] = true;
|
|
8228
|
+
}
|
|
8229
|
+
/** True when a message was synthesized for the current provider call. */
|
|
8230
|
+
function isPerCallContextMessage(message) {
|
|
8231
|
+
return message?.[kPerCallContextMessage] === true;
|
|
8232
|
+
}
|
|
7473
8233
|
//#endregion
|
|
7474
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
8234
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/providers/transform-messages.ts
|
|
7475
8235
|
var ToolCallStatus = /* @__PURE__ */ function(ToolCallStatus) {
|
|
7476
8236
|
/** A tool result has already been emitted for this tool call; later duplicates must be skipped. */
|
|
7477
8237
|
ToolCallStatus[ToolCallStatus["Resolved"] = 1] = "Resolved";
|
|
@@ -7479,16 +8239,15 @@ var ToolCallStatus = /* @__PURE__ */ function(ToolCallStatus) {
|
|
|
7479
8239
|
ToolCallStatus[ToolCallStatus["Aborted"] = 2] = "Aborted";
|
|
7480
8240
|
return ToolCallStatus;
|
|
7481
8241
|
}(ToolCallStatus || {});
|
|
7482
|
-
/**
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
|
|
7486
|
-
|
|
7487
|
-
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
const MAX_TOOL_CALL_ID_LENGTH = 64;
|
|
8242
|
+
/** Replace unsupported tool-call ID characters and cap the result for strict replay providers. */
|
|
8243
|
+
function normalizeToolCallId(id, maxLength = 64) {
|
|
8244
|
+
return id.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, maxLength);
|
|
8245
|
+
}
|
|
8246
|
+
const TOOL_CALL_ID_PATTERN = new RegExp(`^[a-zA-Z0-9_-]{1,64}$`);
|
|
8247
|
+
/** Whether `id` already satisfies the strict 1–64 `[a-zA-Z0-9_-]` tool-call ID contract. */
|
|
8248
|
+
function isValidToolCallId(id) {
|
|
8249
|
+
return TOOL_CALL_ID_PATTERN.test(id);
|
|
8250
|
+
}
|
|
7492
8251
|
/**
|
|
7493
8252
|
* OpenAI Responses-family APIs mint composite tool ids (`call_id|item_id`);
|
|
7494
8253
|
* opaque Chat Completions ids do not (openai-completions preserves same-model
|
|
@@ -7508,22 +8267,22 @@ function responsesCallComponent(id) {
|
|
|
7508
8267
|
const pipe = id.indexOf("|");
|
|
7509
8268
|
return pipe <= 0 ? id : id.slice(0, pipe);
|
|
7510
8269
|
}
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
8270
|
+
/**
|
|
8271
|
+
* Record one assistant turn's tool-call ids into the origin-scope sets.
|
|
8272
|
+
*
|
|
8273
|
+
* Called from the normalization map (`transformMessages`) in document order, on
|
|
8274
|
+
* the SAME post-transform content that message emits, so the two sets cover
|
|
8275
|
+
* every assistant turn exactly once and hold its post-normalization, pre-dedup
|
|
8276
|
+
* ids (`_dupN` replacements minted later by dedup are never scope members).
|
|
8277
|
+
* Both sets are only read via `.has`, so ordering is inert.
|
|
8278
|
+
*/
|
|
8279
|
+
function recordToolCallOriginScope(msg, content, responsesComponents, opaqueCompositeCallIds) {
|
|
8280
|
+
const responsesOrigin = isResponsesFamilyApi(msg.api);
|
|
8281
|
+
for (const block of content) {
|
|
8282
|
+
if (block.type !== "toolCall") continue;
|
|
8283
|
+
if (responsesOrigin) responsesComponents.add(responsesCallComponent(block.id));
|
|
8284
|
+
else if (block.id.includes("|")) opaqueCompositeCallIds.add(block.id);
|
|
7522
8285
|
}
|
|
7523
|
-
return {
|
|
7524
|
-
responsesComponents,
|
|
7525
|
-
opaqueCompositeCallIds
|
|
7526
|
-
};
|
|
7527
8286
|
}
|
|
7528
8287
|
/**
|
|
7529
8288
|
* Canonical key for pairing a tool result with its assistant tool call.
|
|
@@ -7571,70 +8330,146 @@ function appendSegmentDuplicateSuffix(segment, suffix, maxLength) {
|
|
|
7571
8330
|
const prefixBudget = Math.max(0, maxLength - suffix.length);
|
|
7572
8331
|
return `${segment.slice(0, prefixBudget)}${suffix}`;
|
|
7573
8332
|
}
|
|
7574
|
-
|
|
8333
|
+
/**
|
|
8334
|
+
* File a SURVIVING (post-dedup) tool result into the request-wide index.
|
|
8335
|
+
*
|
|
8336
|
+
* Called from the dedup pass, once per tool result message, at the position the
|
|
8337
|
+
* message occupies in that pass's output array — so the entries and their order
|
|
8338
|
+
* describe the transcript the request will actually carry.
|
|
8339
|
+
* The caller passes the pairing key for the id that survived the pass (a `_dup`
|
|
8340
|
+
* rewrite changes it), which is what the consumers downstream must pair against.
|
|
8341
|
+
*/
|
|
8342
|
+
function indexToolResult(msg, index, key, realToolResultsById) {
|
|
8343
|
+
const entry = {
|
|
8344
|
+
index,
|
|
8345
|
+
msg,
|
|
8346
|
+
consumed: false
|
|
8347
|
+
};
|
|
8348
|
+
const entries = realToolResultsById.get(key);
|
|
8349
|
+
if (entries) entries.push(entry);
|
|
8350
|
+
else realToolResultsById.set(key, [entry]);
|
|
8351
|
+
}
|
|
8352
|
+
function deduplicateToolCallIds(messages, originScope, maxToolCallIdLength, duplicateSuffixPrefix) {
|
|
7575
8353
|
const seenToolCallIds = /* @__PURE__ */ new Map();
|
|
7576
8354
|
const pendingToolResultRewrites = /* @__PURE__ */ new Map();
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
if (rewrite) return {
|
|
7585
|
-
...msg,
|
|
7586
|
-
toolCallId: rewrite.replacementId
|
|
7587
|
-
};
|
|
7588
|
-
return msg;
|
|
8355
|
+
const realToolResultsById = /* @__PURE__ */ new Map();
|
|
8356
|
+
const validToolUseIds = /* @__PURE__ */ new Set();
|
|
8357
|
+
const enqueueToolResultRewrite = (id, rewrite) => {
|
|
8358
|
+
const rewrites = pendingToolResultRewrites.get(id);
|
|
8359
|
+
if (rewrites) {
|
|
8360
|
+
rewrites.push(rewrite);
|
|
8361
|
+
return;
|
|
7589
8362
|
}
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
return
|
|
8363
|
+
pendingToolResultRewrites.set(id, [rewrite]);
|
|
8364
|
+
};
|
|
8365
|
+
return {
|
|
8366
|
+
messages: messages.map((msg, index) => {
|
|
8367
|
+
if (msg.role === "toolResult") {
|
|
8368
|
+
const key = toolCallPairingKey(msg.toolCallId, originScope);
|
|
8369
|
+
const rewrites = pendingToolResultRewrites.get(key);
|
|
8370
|
+
if (!rewrites || rewrites.length === 0) {
|
|
8371
|
+
indexToolResult(msg, index, key, realToolResultsById);
|
|
8372
|
+
return msg;
|
|
8373
|
+
}
|
|
8374
|
+
const rewrite = rewrites.shift();
|
|
8375
|
+
if (rewrites.length === 0) pendingToolResultRewrites.delete(key);
|
|
8376
|
+
if (rewrite) {
|
|
8377
|
+
const rewritten = {
|
|
8378
|
+
...msg,
|
|
8379
|
+
toolCallId: rewrite.replacementId
|
|
8380
|
+
};
|
|
8381
|
+
indexToolResult(rewritten, index, toolCallPairingKey(rewritten.toolCallId, originScope), realToolResultsById);
|
|
8382
|
+
return rewritten;
|
|
8383
|
+
}
|
|
8384
|
+
indexToolResult(msg, index, key, realToolResultsById);
|
|
8385
|
+
return msg;
|
|
7613
8386
|
}
|
|
7614
|
-
|
|
7615
|
-
let
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
8387
|
+
if (msg.role !== "assistant") return msg;
|
|
8388
|
+
let idsTouchedInTurn;
|
|
8389
|
+
let contentChanged = false;
|
|
8390
|
+
const content = msg.content.map((block) => {
|
|
8391
|
+
if (block.type !== "toolCall") return block;
|
|
8392
|
+
const blockKey = toolCallPairingKey(block.id, originScope);
|
|
8393
|
+
if (!idsTouchedInTurn?.has(blockKey)) {
|
|
8394
|
+
(idsTouchedInTurn ??= /* @__PURE__ */ new Set()).add(blockKey);
|
|
8395
|
+
pendingToolResultRewrites.delete(blockKey);
|
|
8396
|
+
}
|
|
8397
|
+
const previousCount = seenToolCallIds.get(blockKey) ?? 0;
|
|
8398
|
+
if (previousCount === 0) {
|
|
8399
|
+
seenToolCallIds.set(blockKey, 1);
|
|
8400
|
+
enqueueToolResultRewrite(blockKey, void 0);
|
|
8401
|
+
return block;
|
|
8402
|
+
}
|
|
8403
|
+
let duplicateIndex = previousCount;
|
|
8404
|
+
let replacementId = appendDuplicateSuffix(block.id, `${duplicateSuffixPrefix}${duplicateIndex}`, maxToolCallIdLength);
|
|
8405
|
+
while (seenToolCallIds.has(toolCallPairingKey(replacementId, originScope))) {
|
|
8406
|
+
duplicateIndex += 1;
|
|
8407
|
+
replacementId = appendDuplicateSuffix(block.id, `${duplicateSuffixPrefix}${duplicateIndex}`, maxToolCallIdLength);
|
|
8408
|
+
}
|
|
8409
|
+
seenToolCallIds.set(blockKey, duplicateIndex + 1);
|
|
8410
|
+
seenToolCallIds.set(toolCallPairingKey(replacementId, originScope), 1);
|
|
8411
|
+
enqueueToolResultRewrite(blockKey, { replacementId });
|
|
8412
|
+
contentChanged = true;
|
|
8413
|
+
return {
|
|
8414
|
+
...block,
|
|
8415
|
+
id: replacementId
|
|
8416
|
+
};
|
|
8417
|
+
});
|
|
8418
|
+
for (const block of content) {
|
|
8419
|
+
if (block.type !== "toolCall") continue;
|
|
8420
|
+
validToolUseIds.add(toolCallPairingKey(block.id, originScope));
|
|
7619
8421
|
}
|
|
7620
|
-
|
|
7621
|
-
seenToolCallIds.set(toolCallPairingKey(replacementId, originScope), 1);
|
|
7622
|
-
enqueueToolResultRewrite(blockKey, { replacementId });
|
|
7623
|
-
contentChanged = true;
|
|
8422
|
+
if (!contentChanged) return msg;
|
|
7624
8423
|
return {
|
|
7625
|
-
...
|
|
7626
|
-
|
|
8424
|
+
...msg,
|
|
8425
|
+
content
|
|
7627
8426
|
};
|
|
7628
|
-
})
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
content
|
|
7633
|
-
};
|
|
7634
|
-
});
|
|
8427
|
+
}),
|
|
8428
|
+
realToolResultsById,
|
|
8429
|
+
validToolUseIds
|
|
8430
|
+
};
|
|
7635
8431
|
}
|
|
8432
|
+
/** Default for providers without an authored tool-name policy and native OpenAI Responses history. */
|
|
8433
|
+
const MAX_TOOL_CALL_NAME_LENGTH = 128;
|
|
8434
|
+
const STRICT_TOOL_CALL_NAME_RE = /^[a-zA-Z0-9_-]+$/;
|
|
8435
|
+
const GOOGLE_TOOL_CALL_NAME_RE = /^[a-zA-Z_][a-zA-Z0-9_.:-]*$/;
|
|
8436
|
+
/** Any character some provider accepts in a declared tool name, for checks with no target. */
|
|
8437
|
+
const ANY_PROVIDER_TOOL_CALL_NAME_RE = /^[a-zA-Z0-9_.:-]+$/;
|
|
7636
8438
|
/**
|
|
7637
|
-
*
|
|
8439
|
+
* Charset and length a tool-call name must meet to replay to `model`. Without a
|
|
8440
|
+
* target, a name passes when any provider could declare it.
|
|
8441
|
+
*/
|
|
8442
|
+
function toolCallNameLimits(model) {
|
|
8443
|
+
if (!model) return {
|
|
8444
|
+
allowedName: ANY_PROVIDER_TOOL_CALL_NAME_RE,
|
|
8445
|
+
maxLength: MAX_TOOL_CALL_NAME_LENGTH
|
|
8446
|
+
};
|
|
8447
|
+
const policy = resolveCatalogPolicy(model);
|
|
8448
|
+
return {
|
|
8449
|
+
allowedName: policy.toolCallNameCharset === "google" ? GOOGLE_TOOL_CALL_NAME_RE : STRICT_TOOL_CALL_NAME_RE,
|
|
8450
|
+
maxLength: typeof policy.toolCallNameMaxLength === "number" ? policy.toolCallNameMaxLength : MAX_TOOL_CALL_NAME_LENGTH
|
|
8451
|
+
};
|
|
8452
|
+
}
|
|
8453
|
+
/**
|
|
8454
|
+
* Whether a tool-call name cannot be replayed to the target: missing, empty,
|
|
8455
|
+
* longer than its declaration limit, or containing a character outside its
|
|
8456
|
+
* declaration charset. Models emit such names when the name slot carries
|
|
8457
|
+
* invocation text (whitespace, NULs) or an invented internal URL (`proc://*`).
|
|
8458
|
+
*
|
|
8459
|
+
* Without a target, use the OpenAI Responses native-history constraints.
|
|
8460
|
+
*/
|
|
8461
|
+
function isMalformedToolCallName(name, allowedName = STRICT_TOOL_CALL_NAME_RE, maxLength = MAX_TOOL_CALL_NAME_LENGTH) {
|
|
8462
|
+
return typeof name !== "string" || name.length > maxLength || !allowedName.test(name);
|
|
8463
|
+
}
|
|
8464
|
+
function isMalformedToolCallId(id) {
|
|
8465
|
+
return !id || id.trim().length === 0;
|
|
8466
|
+
}
|
|
8467
|
+
function isMalformedToolCall(block, allowedName, maxLength) {
|
|
8468
|
+
return isMalformedToolCallId(block.id) || isMalformedToolCallName(block.name, allowedName, maxLength);
|
|
8469
|
+
}
|
|
8470
|
+
/**
|
|
8471
|
+
* Drop assistant `toolCall` blocks with an empty / whitespace-only `id` or a `name`
|
|
8472
|
+
* the target provider cannot declare (see {@link isMalformedToolCallName}),
|
|
7638
8473
|
* the `toolResult` messages they point at, and any assistant turn that has no
|
|
7639
8474
|
* replayable content left.
|
|
7640
8475
|
*
|
|
@@ -7647,26 +8482,21 @@ function deduplicateToolCallIds(messages, originScope, maxToolCallIdLength = MAX
|
|
|
7647
8482
|
* Anthropic 400s on `tool_use.name` / `tool_use.id` (alongside an orphan
|
|
7648
8483
|
* `tool_result`), OpenAI Chat Completions 400s on malformed
|
|
7649
8484
|
* `tool_calls[i].function.*` — wedging the session in a 400 loop until manual
|
|
7650
|
-
* `/clear`.
|
|
8485
|
+
* `/clear`. Gateways also hand back the model's whole invocation text as the
|
|
8486
|
+
* name (observed: a 9654-char script and a NUL-separated `bash\0arg\0…` string
|
|
8487
|
+
* from GLM-5.3); OpenAI Responses rejects any replayed `input[N].name` over
|
|
8488
|
+
* 128 characters with `string_above_max_length`.
|
|
7651
8489
|
*
|
|
7652
8490
|
* Run before any other transform so the rest of the pipeline never sees a
|
|
7653
|
-
* malformed call. Idempotent: a re-run on an already-sanitized
|
|
7654
|
-
* the input untouched.
|
|
8491
|
+
* malformed call. Idempotent for the same target: a re-run on an already-sanitized
|
|
8492
|
+
* list returns the input untouched.
|
|
7655
8493
|
*/
|
|
7656
|
-
function
|
|
7657
|
-
|
|
7658
|
-
}
|
|
7659
|
-
function isMalformedToolCallId(id) {
|
|
7660
|
-
return !id || id.trim().length === 0;
|
|
7661
|
-
}
|
|
7662
|
-
function isMalformedToolCall(block) {
|
|
7663
|
-
return isMalformedToolCallId(block.id) || isMalformedToolCallName(block.name);
|
|
7664
|
-
}
|
|
7665
|
-
function sanitizeMalformedToolCalls(messages) {
|
|
8494
|
+
function sanitizeMalformedToolCalls(messages, model) {
|
|
8495
|
+
const { allowedName, maxLength } = toolCallNameLimits(model);
|
|
7666
8496
|
let hasMalformed = false;
|
|
7667
8497
|
outer: for (const msg of messages) {
|
|
7668
8498
|
if (msg.role !== "assistant") continue;
|
|
7669
|
-
for (const block of msg.content) if (block.type === "toolCall" && isMalformedToolCall(block)) {
|
|
8499
|
+
for (const block of msg.content) if (block.type === "toolCall" && isMalformedToolCall(block, allowedName, maxLength)) {
|
|
7670
8500
|
hasMalformed = true;
|
|
7671
8501
|
break outer;
|
|
7672
8502
|
}
|
|
@@ -7680,7 +8510,7 @@ function sanitizeMalformedToolCalls(messages) {
|
|
|
7680
8510
|
const filtered = [];
|
|
7681
8511
|
for (const block of msg.content) {
|
|
7682
8512
|
if (block.type === "toolCall") {
|
|
7683
|
-
const malformed = isMalformedToolCall(block);
|
|
8513
|
+
const malformed = isMalformedToolCall(block, allowedName, maxLength);
|
|
7684
8514
|
const queue = dropQueues.get(block.id);
|
|
7685
8515
|
if (queue) queue.push(malformed);
|
|
7686
8516
|
else dropQueues.set(block.id, [malformed]);
|
|
@@ -7710,19 +8540,41 @@ function sanitizeMalformedToolCalls(messages) {
|
|
|
7710
8540
|
}
|
|
7711
8541
|
return result;
|
|
7712
8542
|
}
|
|
8543
|
+
/**
|
|
8544
|
+
* Whether {@link transformMessages} drops `msg` from every replay: a turn cut
|
|
8545
|
+
* off by `length` / `error` / `aborted` that carries no text and no tool call.
|
|
8546
|
+
*/
|
|
7713
8547
|
function shouldDropTruncatedThinkingOnlyAssistant(msg) {
|
|
7714
8548
|
return (msg.stopReason === "length" || msg.stopReason === "error" || msg.stopReason === "aborted") && !msg.content.some((block) => block.type === "toolCall" || block.type === "text");
|
|
7715
8549
|
}
|
|
7716
|
-
|
|
8550
|
+
/**
|
|
8551
|
+
* Whether `msg` reaches a replay as an assistant turn, so it can be the latest
|
|
8552
|
+
* surviving one: {@link sanitizeMalformedToolCalls} drops its malformed tool
|
|
8553
|
+
* calls, then {@link shouldDropTruncatedThinkingOnlyAssistant} a truncated
|
|
8554
|
+
* turn left with no text and no tool call. On an already sanitized list this
|
|
8555
|
+
* is `!shouldDropTruncatedThinkingOnlyAssistant(msg)`. Pass the target `model`
|
|
8556
|
+
* to apply its tool-name limits; without one, any provider-declarable name survives.
|
|
8557
|
+
*/
|
|
8558
|
+
function isSurvivingAssistant(msg, model) {
|
|
8559
|
+
const isTruncatedStop = msg.stopReason === "length" || msg.stopReason === "error" || msg.stopReason === "aborted";
|
|
8560
|
+
if (msg.content.length === 0) return !isTruncatedStop;
|
|
8561
|
+
const { allowedName, maxLength } = toolCallNameLimits(model);
|
|
8562
|
+
return msg.content.some((block) => block.type === "toolCall" ? !isMalformedToolCall(block, allowedName, maxLength) : !isTruncatedStop || block.type === "text");
|
|
8563
|
+
}
|
|
8564
|
+
function getLatestSurvivingAssistantIndex(messages, model) {
|
|
7717
8565
|
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
7718
8566
|
const msg = messages[index];
|
|
7719
|
-
if (msg.role === "assistant" &&
|
|
8567
|
+
if (msg.role === "assistant" && isSurvivingAssistant(msg, model)) return index;
|
|
7720
8568
|
}
|
|
7721
8569
|
return -1;
|
|
7722
8570
|
}
|
|
7723
8571
|
function isAnthropicMessagesModel(model) {
|
|
7724
8572
|
return model.api === "anthropic-messages";
|
|
7725
8573
|
}
|
|
8574
|
+
/** Whether `turn` came from `model` itself: its own turns replay their native reasoning unchanged. */
|
|
8575
|
+
function isSameModelTurn(turn, model) {
|
|
8576
|
+
return turn.provider === model.provider && turn.api === model.api && turn.model === model.id;
|
|
8577
|
+
}
|
|
7726
8578
|
/**
|
|
7727
8579
|
* Targets that have proven they read unsigned foreign thinking when replayed
|
|
7728
8580
|
* natively. This is a semantic-carry allowlist only: OpenAI-compatible
|
|
@@ -7737,37 +8589,253 @@ function targetReadsForeignThinking(model, compat) {
|
|
|
7737
8589
|
if (compat.requiresThinkingAsText) return false;
|
|
7738
8590
|
return model.reasoning && compat.thinkingFormat === "zai";
|
|
7739
8591
|
}
|
|
7740
|
-
|
|
7741
|
-
|
|
7742
|
-
|
|
8592
|
+
/**
|
|
8593
|
+
* Whether the target's encoder already replays the target's own plaintext
|
|
8594
|
+
* reasoning in a native slot. Reasoning carried from another host of the same
|
|
8595
|
+
* model (`carriesReasoning`) takes exactly that path, so this is derived from
|
|
8596
|
+
* the flags the encoders branch on rather than declared per host:
|
|
8597
|
+
* - chat completions writes a reasoning field or content part for thinking
|
|
8598
|
+
* blocks only under these flags; otherwise it drops them.
|
|
8599
|
+
* - the Responses wire replays reasoning items unless history is filtered, and
|
|
8600
|
+
* hosts that require reasoning replay already receive id-less plaintext
|
|
8601
|
+
* items from omp (the `requiresReasoningContent*` safety net). OpenRouter's
|
|
8602
|
+
* chat fallback shares the tool-call flag.
|
|
8603
|
+
* - Devin sends every turn's thinking in the prompt's `thinking` field.
|
|
8604
|
+
* Anthropic-format targets that accept unsigned thinking already read it via
|
|
8605
|
+
* `targetReadsForeignThinking`; Bedrock and Google reject or ignore unsigned
|
|
8606
|
+
* reasoning, and Codex hosts no portable family.
|
|
8607
|
+
*/
|
|
8608
|
+
function targetReplaysPlaintextReasoning(model, compat) {
|
|
8609
|
+
if (!model.reasoning || compat === void 0) return false;
|
|
8610
|
+
if (model.api === "devin-agent") return true;
|
|
8611
|
+
if (!("requiresReasoningContentForToolCalls" in compat)) return false;
|
|
8612
|
+
switch (model.api) {
|
|
8613
|
+
case "openai-completions": return !compat.requiresThinkingAsText && (compat.mistralReasoningContentParts === true || compat.requiresReasoningContentForToolCalls || compat.thinkingFormat === "zai" || compat.replayReasoningContent);
|
|
8614
|
+
case "openrouter": return !compat.filterReasoningHistory && compat.requiresReasoningContentForToolCalls;
|
|
8615
|
+
case "openai-responses": return !compat.filterReasoningHistory && (compat.requiresReasoningContentForToolCalls || compat.requiresReasoningContentForAllAssistantTurns);
|
|
8616
|
+
default: return false;
|
|
8617
|
+
}
|
|
7743
8618
|
}
|
|
7744
8619
|
function fallbackAnthropicToolCallId(originalId) {
|
|
7745
8620
|
return `toolu_${Bun.hash(originalId).toString(36)}`;
|
|
7746
8621
|
}
|
|
7747
|
-
function normalizeAnthropicTargetToolCallId(id, model, source,
|
|
7748
|
-
if (
|
|
7749
|
-
const normalized =
|
|
7750
|
-
if (
|
|
8622
|
+
function normalizeAnthropicTargetToolCallId(id, model, source, normalizeId) {
|
|
8623
|
+
if (isValidToolCallId(id)) return id;
|
|
8624
|
+
const normalized = normalizeId?.(id, model, source) ?? normalizeToolCallId(id);
|
|
8625
|
+
if (isValidToolCallId(normalized)) return normalized;
|
|
7751
8626
|
return fallbackAnthropicToolCallId(id);
|
|
7752
8627
|
}
|
|
8628
|
+
/**
|
|
8629
|
+
* Normalize tool call ID for cross-provider compatibility.
|
|
8630
|
+
* OpenAI Responses API generates IDs that are 450+ chars with special characters like `|`.
|
|
8631
|
+
* Anthropic APIs require IDs matching ^[a-zA-Z0-9_-]+$ (max 64 chars).
|
|
8632
|
+
*
|
|
8633
|
+
* For aborted/errored turns, this function:
|
|
8634
|
+
* - Preserves tool call structure (unlike converting to text summaries)
|
|
8635
|
+
* - Injects synthetic "aborted" tool results
|
|
8636
|
+
*/
|
|
8637
|
+
/**
|
|
8638
|
+
* Credential-shaped token patterns scrubbed from outbound provider traffic when
|
|
8639
|
+
* credential redaction is enabled. Exported so hosts can route the same shapes
|
|
8640
|
+
* through reversible obfuscation (keyed placeholders restored before local tool
|
|
8641
|
+
* execution) instead of the irreversible `[*_token_redacted]` rewrite below —
|
|
8642
|
+
* an irreversible placeholder echoed back in edit-tool `old_string` can never
|
|
8643
|
+
* match the real bytes on disk.
|
|
8644
|
+
*/
|
|
8645
|
+
const SENSITIVE_TOKEN_RE = /(?<![a-zA-Z0-9_*-])(gh[opusr]_[a-zA-Z0-9_*]{36,}|github_pat_[a-zA-Z0-9_*]{36,}|glpat-[a-zA-Z0-9_*-]{20,}|sk-proj-[a-zA-Z0-9_*-]{36,}|sk-ant-[a-zA-Z0-9_*-]{36,}|sk-[a-zA-Z0-9_*-]{48,})(?![a-zA-Z0-9_*-])/gi;
|
|
8646
|
+
function hasPlausibleCredentialEntropy(token) {
|
|
8647
|
+
const lower = token.toLowerCase();
|
|
8648
|
+
const prefixLength = lower.startsWith("github_pat_") ? 11 : lower.startsWith("glpat-") ? 6 : lower.startsWith("sk-proj-") ? 8 : lower.startsWith("sk-ant-") ? 7 : lower.startsWith("gh") ? 4 : 3;
|
|
8649
|
+
const secret = token.slice(prefixLength);
|
|
8650
|
+
if (/^\*+$/.test(secret)) return true;
|
|
8651
|
+
return [
|
|
8652
|
+
/[a-z]/,
|
|
8653
|
+
/[A-Z]/,
|
|
8654
|
+
/\d/,
|
|
8655
|
+
/[_-]/
|
|
8656
|
+
].filter((pattern) => pattern.test(secret)).length >= 2;
|
|
8657
|
+
}
|
|
8658
|
+
/**
|
|
8659
|
+
* Whether outbound credential-pattern redaction is active outside any
|
|
8660
|
+
* {@link withCredentialRedaction} scope. Off by default; hosts opt in
|
|
8661
|
+
* explicitly (the coding agent wires this to the `secrets.enabled` setting).
|
|
8662
|
+
*/
|
|
8663
|
+
let credentialRedactionEnabled = false;
|
|
8664
|
+
/** Per-request override of {@link credentialRedactionEnabled}; see {@link withCredentialRedaction}. */
|
|
8665
|
+
const credentialRedactionScope = new AsyncLocalStorage();
|
|
8666
|
+
/** Redaction policy for the request being built: its scope's, else the process-wide switch. */
|
|
8667
|
+
function isCredentialRedactionActive() {
|
|
8668
|
+
return credentialRedactionScope.getStore() ?? credentialRedactionEnabled;
|
|
8669
|
+
}
|
|
7753
8670
|
function redactSensitiveCredentials(text) {
|
|
7754
|
-
return text;
|
|
8671
|
+
if (!isCredentialRedactionActive()) return text;
|
|
8672
|
+
return text.replace(SENSITIVE_TOKEN_RE, (match) => {
|
|
8673
|
+
if (!hasPlausibleCredentialEntropy(match)) return match;
|
|
8674
|
+
const lower = match.toLowerCase();
|
|
8675
|
+
if (lower.startsWith("gh")) return "[github_token_redacted]";
|
|
8676
|
+
if (lower.startsWith("gl")) return "[gitlab_token_redacted]";
|
|
8677
|
+
if (lower.startsWith("sk-ant-")) return "[anthropic_token_redacted]";
|
|
8678
|
+
if (lower.startsWith("sk")) return "[openai_token_redacted]";
|
|
8679
|
+
return "[token_redacted]";
|
|
8680
|
+
});
|
|
7755
8681
|
}
|
|
7756
8682
|
function redactSensitiveInObject(val) {
|
|
8683
|
+
if (!isCredentialRedactionActive()) return {
|
|
8684
|
+
result: val,
|
|
8685
|
+
changed: false
|
|
8686
|
+
};
|
|
8687
|
+
if (typeof val === "string") {
|
|
8688
|
+
const redacted = redactSensitiveCredentials(val);
|
|
8689
|
+
return {
|
|
8690
|
+
result: redacted,
|
|
8691
|
+
changed: redacted !== val
|
|
8692
|
+
};
|
|
8693
|
+
}
|
|
8694
|
+
if (Array.isArray(val)) {
|
|
8695
|
+
let result;
|
|
8696
|
+
for (let i = 0; i < val.length; i++) {
|
|
8697
|
+
const sub = redactSensitiveInObject(val[i]);
|
|
8698
|
+
if (!sub.changed) continue;
|
|
8699
|
+
result ??= val.slice();
|
|
8700
|
+
result[i] = sub.result;
|
|
8701
|
+
}
|
|
8702
|
+
return result ? {
|
|
8703
|
+
result,
|
|
8704
|
+
changed: true
|
|
8705
|
+
} : {
|
|
8706
|
+
result: val,
|
|
8707
|
+
changed: false
|
|
8708
|
+
};
|
|
8709
|
+
}
|
|
8710
|
+
if (val !== null && typeof val === "object") {
|
|
8711
|
+
const entries = Object.entries(val);
|
|
8712
|
+
let result;
|
|
8713
|
+
for (const [k, v] of entries) {
|
|
8714
|
+
const sub = redactSensitiveInObject(v);
|
|
8715
|
+
if (!sub.changed) continue;
|
|
8716
|
+
result ??= Object.fromEntries(entries);
|
|
8717
|
+
result[k] = sub.result;
|
|
8718
|
+
}
|
|
8719
|
+
return result ? {
|
|
8720
|
+
result,
|
|
8721
|
+
changed: true
|
|
8722
|
+
} : {
|
|
8723
|
+
result: val,
|
|
8724
|
+
changed: false
|
|
8725
|
+
};
|
|
8726
|
+
}
|
|
7757
8727
|
return {
|
|
7758
8728
|
result: val,
|
|
7759
8729
|
changed: false
|
|
7760
8730
|
};
|
|
7761
8731
|
}
|
|
7762
8732
|
function redactSensitiveCredentialsInMessages(messages) {
|
|
7763
|
-
return messages;
|
|
8733
|
+
if (!isCredentialRedactionActive()) return messages;
|
|
8734
|
+
return messages.map((msg) => {
|
|
8735
|
+
if (msg.role === "user" || msg.role === "developer") {
|
|
8736
|
+
const userMsg = msg;
|
|
8737
|
+
if (typeof userMsg.content === "string") {
|
|
8738
|
+
const redacted = redactSensitiveCredentials(userMsg.content);
|
|
8739
|
+
if (redacted === userMsg.content) return msg;
|
|
8740
|
+
return {
|
|
8741
|
+
...userMsg,
|
|
8742
|
+
content: redacted
|
|
8743
|
+
};
|
|
8744
|
+
}
|
|
8745
|
+
const contentArray = userMsg.content;
|
|
8746
|
+
let changed = false;
|
|
8747
|
+
const content = contentArray.map((block) => {
|
|
8748
|
+
if (block.type === "text") {
|
|
8749
|
+
const redacted = redactSensitiveCredentials(block.text);
|
|
8750
|
+
if (redacted !== block.text) {
|
|
8751
|
+
changed = true;
|
|
8752
|
+
return {
|
|
8753
|
+
...block,
|
|
8754
|
+
text: redacted
|
|
8755
|
+
};
|
|
8756
|
+
}
|
|
8757
|
+
}
|
|
8758
|
+
return block;
|
|
8759
|
+
});
|
|
8760
|
+
return changed ? {
|
|
8761
|
+
...userMsg,
|
|
8762
|
+
content
|
|
8763
|
+
} : userMsg;
|
|
8764
|
+
}
|
|
8765
|
+
if (msg.role === "toolResult") {
|
|
8766
|
+
const toolResultMsg = msg;
|
|
8767
|
+
let changed = false;
|
|
8768
|
+
const content = toolResultMsg.content.map((block) => {
|
|
8769
|
+
if (block.type === "text") {
|
|
8770
|
+
const redacted = redactSensitiveCredentials(block.text);
|
|
8771
|
+
if (redacted !== block.text) {
|
|
8772
|
+
changed = true;
|
|
8773
|
+
return {
|
|
8774
|
+
...block,
|
|
8775
|
+
text: redacted
|
|
8776
|
+
};
|
|
8777
|
+
}
|
|
8778
|
+
}
|
|
8779
|
+
return block;
|
|
8780
|
+
});
|
|
8781
|
+
return changed ? {
|
|
8782
|
+
...toolResultMsg,
|
|
8783
|
+
content
|
|
8784
|
+
} : toolResultMsg;
|
|
8785
|
+
}
|
|
8786
|
+
if (msg.role === "assistant") {
|
|
8787
|
+
const assistantMsg = msg;
|
|
8788
|
+
let changed = false;
|
|
8789
|
+
const content = assistantMsg.content.map((block) => {
|
|
8790
|
+
if (block.type === "text") {
|
|
8791
|
+
const redacted = redactSensitiveCredentials(block.text);
|
|
8792
|
+
if (redacted !== block.text) {
|
|
8793
|
+
changed = true;
|
|
8794
|
+
return {
|
|
8795
|
+
...block,
|
|
8796
|
+
text: redacted
|
|
8797
|
+
};
|
|
8798
|
+
}
|
|
8799
|
+
} else if (block.type === "thinking") {
|
|
8800
|
+
const redacted = redactSensitiveCredentials(block.thinking);
|
|
8801
|
+
if (redacted !== block.thinking) {
|
|
8802
|
+
changed = true;
|
|
8803
|
+
return {
|
|
8804
|
+
...block,
|
|
8805
|
+
thinking: redacted,
|
|
8806
|
+
thinkingSignature: void 0
|
|
8807
|
+
};
|
|
8808
|
+
}
|
|
8809
|
+
} else if (block.type === "toolCall") {
|
|
8810
|
+
if (block.arguments) {
|
|
8811
|
+
const { result: redactedArgs, changed: argsChanged } = redactSensitiveInObject(block.arguments);
|
|
8812
|
+
if (argsChanged) {
|
|
8813
|
+
changed = true;
|
|
8814
|
+
const castArgs = redactedArgs && typeof redactedArgs === "object" && !Array.isArray(redactedArgs) ? redactedArgs : void 0;
|
|
8815
|
+
return {
|
|
8816
|
+
...block,
|
|
8817
|
+
arguments: castArgs,
|
|
8818
|
+
thoughtSignature: void 0
|
|
8819
|
+
};
|
|
8820
|
+
}
|
|
8821
|
+
}
|
|
8822
|
+
}
|
|
8823
|
+
return block;
|
|
8824
|
+
});
|
|
8825
|
+
return changed ? {
|
|
8826
|
+
...assistantMsg,
|
|
8827
|
+
content
|
|
8828
|
+
} : assistantMsg;
|
|
8829
|
+
}
|
|
8830
|
+
return msg;
|
|
8831
|
+
});
|
|
7764
8832
|
}
|
|
7765
|
-
function transformMessages(messages, model, normalizeToolCallId, maxNormalizedToolCallIdLength =
|
|
8833
|
+
function transformMessages(messages, model, normalizeToolCallId, maxNormalizedToolCallIdLength = 64, duplicateToolCallIdSuffixPrefix = "_dup", targetCompat = model.compat, targetCredentialId) {
|
|
7766
8834
|
messages = redactSensitiveCredentialsInMessages(messages);
|
|
7767
|
-
messages = sanitizeMalformedToolCalls(messages);
|
|
8835
|
+
messages = sanitizeMalformedToolCalls(messages, model);
|
|
7768
8836
|
const toolCallIdMap = /* @__PURE__ */ new Map();
|
|
7769
8837
|
const responsesCompositeIdMap = /* @__PURE__ */ new Map();
|
|
7770
|
-
const latestSurvivingAssistantIndex = getLatestSurvivingAssistantIndex(messages);
|
|
8838
|
+
const latestSurvivingAssistantIndex = getLatestSurvivingAssistantIndex(messages, model);
|
|
7771
8839
|
const invalidBoundThinkingAssistantIndexes = /* @__PURE__ */ new Set();
|
|
7772
8840
|
if (model.thinking?.prefixBinding) {
|
|
7773
8841
|
let latestRewriteAt;
|
|
@@ -7778,6 +8846,9 @@ function transformMessages(messages, model, normalizeToolCallId, maxNormalizedTo
|
|
|
7778
8846
|
else if (message.role === "assistant" && latestRewriteAt !== void 0 && message.timestamp <= latestRewriteAt) invalidBoundThinkingAssistantIndexes.add(index);
|
|
7779
8847
|
}
|
|
7780
8848
|
}
|
|
8849
|
+
const targetHasReasoningSlot = targetReplaysPlaintextReasoning(model, targetCompat);
|
|
8850
|
+
const responsesComponents = /* @__PURE__ */ new Set();
|
|
8851
|
+
const opaqueCompositeCallIds = /* @__PURE__ */ new Set();
|
|
7781
8852
|
const normalizedMessages = messages.map((msg, index) => {
|
|
7782
8853
|
if (msg.role === "user" || msg.role === "developer") return msg;
|
|
7783
8854
|
if (msg.role === "toolResult") {
|
|
@@ -7790,13 +8861,19 @@ function transformMessages(messages, model, normalizeToolCallId, maxNormalizedTo
|
|
|
7790
8861
|
}
|
|
7791
8862
|
if (msg.role === "assistant") {
|
|
7792
8863
|
const assistantMsg = msg;
|
|
7793
|
-
const isSameModel = assistantMsg
|
|
8864
|
+
const isSameModel = isSameModelTurn(assistantMsg, model);
|
|
8865
|
+
const carriesSameModelReasoning = !isSameModel && assistantMsg.stopReason !== "error" && targetHasReasoningSlot && carriesReasoning({
|
|
8866
|
+
provider: assistantMsg.provider,
|
|
8867
|
+
api: assistantMsg.api,
|
|
8868
|
+
model: assistantMsg.upstreamModel ?? assistantMsg.model
|
|
8869
|
+
}, model);
|
|
7794
8870
|
const isAnthropicTarget = isAnthropicMessagesModel(model);
|
|
7795
8871
|
const isAnthropicReplay = isAnthropicTarget && assistantMsg.api === "anthropic-messages";
|
|
7796
8872
|
const sameAnthropicDeployment = isAnthropicReplay && assistantMsg.provider === model.provider && (model.compat.officialEndpoint || model.thinking?.prefixBinding === true);
|
|
7797
8873
|
const isLatestSurvivingAssistant = index === latestSurvivingAssistantIndex;
|
|
7798
8874
|
const isOfficialAnthropicSource = isAnthropicReplay && assistantMsg.provider === "anthropic";
|
|
7799
8875
|
const isSigningAnthropicTarget = isAnthropicTarget && model.compat.signingEndpoint;
|
|
8876
|
+
const foreignCredential = isSigningAnthropicTarget && assistantMsg.credentialId !== void 0 && targetCredentialId !== void 0 && assistantMsg.credentialId !== targetCredentialId;
|
|
7800
8877
|
const signingAnthropicInvolved = isOfficialAnthropicSource || isSigningAnthropicTarget;
|
|
7801
8878
|
const replaysUnsignedAnthropicThinking = isAnthropicTarget && model.compat.replayUnsignedThinking;
|
|
7802
8879
|
const invalidStopReason = assistantMsg.stopReason === "aborted" || assistantMsg.stopReason === "error";
|
|
@@ -7814,6 +8891,7 @@ function transformMessages(messages, model, normalizeToolCallId, maxNormalizedTo
|
|
|
7814
8891
|
const hasVisibleAnthropicThinking = assistantMsg.content.some((candidate) => candidate.type === "thinking");
|
|
7815
8892
|
const dropsAllSameModelVisibleThinking = isAnthropicReplay && isSameModel && isSigningAnthropicTarget && hasVisibleAnthropicThinking && !assistantMsg.content.some(anthropicVisibleThinkingSurvivesReplay);
|
|
7816
8893
|
const transformedContent = assistantMsg.content.flatMap((block, blockIndex) => {
|
|
8894
|
+
if (foreignCredential && (block.type === "thinking" || block.type === "redactedThinking")) return [];
|
|
7817
8895
|
if (invalidBoundThinkingAssistantIndexes.has(index) && (block.type === "thinking" || block.type === "redactedThinking")) return [];
|
|
7818
8896
|
if (block.type === "thinking") {
|
|
7819
8897
|
let sanitized = (abandonedToolUse || invalidStopReason && blockIndex === lastBlockIndex) && block.thinkingSignature ? {
|
|
@@ -7838,6 +8916,11 @@ function transformMessages(messages, model, normalizeToolCallId, maxNormalizedTo
|
|
|
7838
8916
|
...sanitized,
|
|
7839
8917
|
thinkingSignature: void 0
|
|
7840
8918
|
} : sanitized;
|
|
8919
|
+
if (carriesSameModelReasoning && sanitized.summary === false) return {
|
|
8920
|
+
type: "thinking",
|
|
8921
|
+
thinking: sanitized.thinking,
|
|
8922
|
+
[kCarriedReasoning]: true
|
|
8923
|
+
};
|
|
7841
8924
|
return {
|
|
7842
8925
|
type: "text",
|
|
7843
8926
|
text: renderDemotedThinking(model.id, sanitized.thinking),
|
|
@@ -7858,7 +8941,7 @@ function transformMessages(messages, model, normalizeToolCallId, maxNormalizedTo
|
|
|
7858
8941
|
return [];
|
|
7859
8942
|
}
|
|
7860
8943
|
if (block.type === "fallback") {
|
|
7861
|
-
if (isAnthropicTarget
|
|
8944
|
+
if (isAnthropicTarget) return block;
|
|
7862
8945
|
return [];
|
|
7863
8946
|
}
|
|
7864
8947
|
if (block.type === "image") return [];
|
|
@@ -7899,6 +8982,7 @@ function transformMessages(messages, model, normalizeToolCallId, maxNormalizedTo
|
|
|
7899
8982
|
...finalBlock,
|
|
7900
8983
|
text: finalBlock.text.trimEnd()
|
|
7901
8984
|
};
|
|
8985
|
+
recordToolCallOriginScope(assistantMsg, transformedContent, responsesComponents, opaqueCompositeCallIds);
|
|
7902
8986
|
return {
|
|
7903
8987
|
...assistantMsg,
|
|
7904
8988
|
content: transformedContent
|
|
@@ -7906,23 +8990,11 @@ function transformMessages(messages, model, normalizeToolCallId, maxNormalizedTo
|
|
|
7906
8990
|
}
|
|
7907
8991
|
return msg;
|
|
7908
8992
|
});
|
|
7909
|
-
const originScope =
|
|
7910
|
-
|
|
7911
|
-
|
|
7912
|
-
|
|
7913
|
-
|
|
7914
|
-
if (msg.role === "toolResult") {
|
|
7915
|
-
const entry = {
|
|
7916
|
-
index,
|
|
7917
|
-
msg,
|
|
7918
|
-
consumed: false
|
|
7919
|
-
};
|
|
7920
|
-
const key = toolCallPairingKey(msg.toolCallId, originScope);
|
|
7921
|
-
const entries = realToolResultsById.get(key);
|
|
7922
|
-
if (entries) entries.push(entry);
|
|
7923
|
-
else realToolResultsById.set(key, [entry]);
|
|
7924
|
-
}
|
|
7925
|
-
}
|
|
8993
|
+
const originScope = {
|
|
8994
|
+
responsesComponents,
|
|
8995
|
+
opaqueCompositeCallIds
|
|
8996
|
+
};
|
|
8997
|
+
const { messages: transformed, realToolResultsById, validToolUseIds } = deduplicateToolCallIds(normalizedMessages, originScope, maxNormalizedToolCallIdLength, duplicateToolCallIdSuffixPrefix);
|
|
7926
8998
|
const takeRealToolResult = (id, afterIndex) => {
|
|
7927
8999
|
const entries = realToolResultsById.get(toolCallPairingKey(id, originScope));
|
|
7928
9000
|
if (!entries) return void 0;
|
|
@@ -7932,11 +9004,6 @@ function transformMessages(messages, model, normalizeToolCallId, maxNormalizedTo
|
|
|
7932
9004
|
return entry.msg;
|
|
7933
9005
|
}
|
|
7934
9006
|
};
|
|
7935
|
-
const validToolUseIds = /* @__PURE__ */ new Set();
|
|
7936
|
-
for (const msg of transformed) {
|
|
7937
|
-
if (msg.role !== "assistant") continue;
|
|
7938
|
-
for (const block of msg.content) if (block.type === "toolCall") validToolUseIds.add(toolCallPairingKey(block.id, originScope));
|
|
7939
|
-
}
|
|
7940
9007
|
const result = [];
|
|
7941
9008
|
let pendingToolCalls = [];
|
|
7942
9009
|
let pendingToolCallsStartIndex = -1;
|
|
@@ -8039,11 +9106,13 @@ function transformMessages(messages, model, normalizeToolCallId, maxNormalizedTo
|
|
|
8039
9106
|
for (const part of msg.content) if (part.type === "text" && part.text.trim() !== "") textParts.push(part.text);
|
|
8040
9107
|
if (textParts.length > 0) {
|
|
8041
9108
|
const errorAttr = msg.isError ? " is-error=\"true\"" : "";
|
|
8042
|
-
|
|
9109
|
+
const note = {
|
|
8043
9110
|
role: "user",
|
|
8044
9111
|
content: `<stale-tool-result tool="${msg.toolName}" id="${msg.toolCallId}"${errorAttr}>\n${textParts.join("\n")}\n</stale-tool-result>`,
|
|
8045
9112
|
timestamp: messageTimestamp
|
|
8046
|
-
}
|
|
9113
|
+
};
|
|
9114
|
+
note[kSyntheticUser] = true;
|
|
9115
|
+
result.push(note);
|
|
8047
9116
|
}
|
|
8048
9117
|
}
|
|
8049
9118
|
} else if (msg.role === "user" || msg.role === "developer") {
|
|
@@ -8061,7 +9130,7 @@ function transformMessages(messages, model, normalizeToolCallId, maxNormalizedTo
|
|
|
8061
9130
|
return result;
|
|
8062
9131
|
}
|
|
8063
9132
|
//#endregion
|
|
8064
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
9133
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/utils.ts
|
|
8065
9134
|
const NON_WHITESPACE_RE = /\S/;
|
|
8066
9135
|
/**
|
|
8067
9136
|
* Read a header value ignoring key casing. HTTP header names are
|
|
@@ -8078,16 +9147,12 @@ function normalizeSystemPrompts(systemPrompt) {
|
|
|
8078
9147
|
if (systemPrompt === void 0 || systemPrompt === null) return [];
|
|
8079
9148
|
return (Array.isArray(systemPrompt) ? systemPrompt : typeof systemPrompt === "string" ? [systemPrompt] : []).map((prompt) => redactSensitiveCredentials(prompt.toWellFormed())).filter((prompt) => prompt.trim().length > 0);
|
|
8080
9149
|
}
|
|
8081
|
-
function normalizeToolCallId(id) {
|
|
8082
|
-
const sanitized = id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8083
|
-
return sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized;
|
|
8084
|
-
}
|
|
8085
9150
|
/** Preserve opaque call IDs for Responses replay while normalizing or generating the separate item ID. */
|
|
8086
9151
|
function normalizeResponsesToolCallId(id, itemPrefix = "fc") {
|
|
8087
|
-
const
|
|
8088
|
-
if (
|
|
8089
|
-
callId,
|
|
8090
|
-
itemId: normalizeResponsesItemId(
|
|
9152
|
+
const sep = id.search(/[\n|]/);
|
|
9153
|
+
if (sep > 0) return {
|
|
9154
|
+
callId: id.slice(0, sep),
|
|
9155
|
+
itemId: normalizeResponsesItemId(id.slice(sep + 1), itemPrefix)
|
|
8091
9156
|
};
|
|
8092
9157
|
return {
|
|
8093
9158
|
callId: id,
|
|
@@ -8158,6 +9223,18 @@ function clampReplayItemImageDetail(item, supportsImageDetailOriginal) {
|
|
|
8158
9223
|
content
|
|
8159
9224
|
} : item;
|
|
8160
9225
|
}
|
|
9226
|
+
/** Clamp replayed images without changing item identities or other native replay fields. */
|
|
9227
|
+
function clampOpenAIResponsesImageDetailForReplay(items, supportsImageDetailOriginal) {
|
|
9228
|
+
if (supportsImageDetailOriginal) return items;
|
|
9229
|
+
let clamped;
|
|
9230
|
+
for (let index = 0; index < items.length; index++) {
|
|
9231
|
+
const item = items[index];
|
|
9232
|
+
const clampedItem = clampReplayItemImageDetail(item, supportsImageDetailOriginal);
|
|
9233
|
+
if (clampedItem !== item && !clamped) clamped = items.slice(0, index);
|
|
9234
|
+
clamped?.push(clampedItem);
|
|
9235
|
+
}
|
|
9236
|
+
return clamped ?? items;
|
|
9237
|
+
}
|
|
8161
9238
|
function isOpenAIResponsesClientInputBoundary(item) {
|
|
8162
9239
|
if (item.type === "message") return item.role !== "assistant";
|
|
8163
9240
|
if (item.type === void 0 && typeof item.role === "string") return item.role !== "assistant";
|
|
@@ -8202,9 +9279,10 @@ function collectOpenAIResponsesComputerLinkedReasoningItems(items, requireLaterO
|
|
|
8202
9279
|
}
|
|
8203
9280
|
const provisionalOpenAIResponsesComputerReasoningItems = /* @__PURE__ */ new WeakSet();
|
|
8204
9281
|
function sanitizeOpenAIResponsesHistoryItemsForReplay(items, options = {}) {
|
|
8205
|
-
const
|
|
8206
|
-
const
|
|
8207
|
-
|
|
9282
|
+
const replayItems = dropMalformedOpenAIResponsesToolCalls(items);
|
|
9283
|
+
const supportsImageDetailOriginal = options.supportsImageDetailOriginal === true;
|
|
9284
|
+
const computerLinkedReasoningItems = options.supportsComputerUse === false ? void 0 : collectOpenAIResponsesComputerLinkedReasoningItems(replayItems, false);
|
|
9285
|
+
return stripOpenAIResponsesOutputOnlyStatusesForReplay(replayItems.flatMap((item) => {
|
|
8208
9286
|
const preserveForComputer = computerLinkedReasoningItems?.has(item) === true;
|
|
8209
9287
|
const sanitizedItem = sanitizeOpenAIResponsesHistoryItemForReplay(item, supportsImageDetailOriginal, preserveForComputer);
|
|
8210
9288
|
if (preserveForComputer && sanitizedItem?.type === "reasoning") provisionalOpenAIResponsesComputerReasoningItems.add(sanitizedItem);
|
|
@@ -8272,36 +9350,77 @@ function stripUnpairedOpenAIResponsesComputerReasoningIdsForReplay(items) {
|
|
|
8272
9350
|
* Returns `undefined` for hidden-empty turns that only contain reasoning and an
|
|
8273
9351
|
* empty assistant message, allowing callers to rebuild visible transcript
|
|
8274
9352
|
* history instead of replaying stale native state.
|
|
9353
|
+
*
|
|
9354
|
+
* When the turn does carry replayable output, whitespace-only assistant
|
|
9355
|
+
* messages are dropped rather than replayed. gpt-5.6 Codex ends a turn whose
|
|
9356
|
+
* text all landed in the `commentary` phase with an empty `final_answer`
|
|
9357
|
+
* message; replaying that item verbatim seeds the next turn with an empty slot
|
|
9358
|
+
* the model then fills - `""` → `"\n\n"` → stray words → non-Latin residue -
|
|
9359
|
+
* and each contaminated item is replayed in turn, so the drift compounds until
|
|
9360
|
+
* the visible answer collapses. Codex CLI replays the empty item too
|
|
9361
|
+
* (openai/codex#32389); this is the layer where omp can refuse to.
|
|
8275
9362
|
*/
|
|
8276
9363
|
function sanitizeOpenAIResponsesAssistantHistoryItemsForReplay(items, options = {}) {
|
|
8277
9364
|
const sanitized = sanitizeOpenAIResponsesHistoryItemsForReplay(items, options);
|
|
8278
9365
|
let hasReplayableAssistantOutput = false;
|
|
9366
|
+
let hasEmptyAssistantMessage = false;
|
|
8279
9367
|
for (const item of sanitized) {
|
|
8280
9368
|
if (item.type === "reasoning") continue;
|
|
8281
|
-
if (item
|
|
8282
|
-
|
|
8283
|
-
|
|
9369
|
+
if (isEmptyAssistantMessage(item)) {
|
|
9370
|
+
hasEmptyAssistantMessage = true;
|
|
9371
|
+
continue;
|
|
8284
9372
|
}
|
|
8285
|
-
|
|
8286
|
-
|
|
8287
|
-
|
|
8288
|
-
|
|
8289
|
-
|
|
9373
|
+
hasReplayableAssistantOutput = true;
|
|
9374
|
+
}
|
|
9375
|
+
if (!hasReplayableAssistantOutput) return void 0;
|
|
9376
|
+
if (!hasEmptyAssistantMessage) return sanitized;
|
|
9377
|
+
return dropEmptyAssistantMessagesForReplay(sanitized);
|
|
9378
|
+
}
|
|
9379
|
+
function isEmptyAssistantMessage(item) {
|
|
9380
|
+
if (item.type !== "message" || item.role !== "assistant") return false;
|
|
9381
|
+
if (typeof item.content === "string") return !NON_WHITESPACE_RE.test(item.content);
|
|
9382
|
+
for (const part of item.content) {
|
|
9383
|
+
if (part.type === "output_text" && NON_WHITESPACE_RE.test(part.text)) return false;
|
|
9384
|
+
if (part.type === "refusal" && NON_WHITESPACE_RE.test(part.refusal)) return false;
|
|
9385
|
+
}
|
|
9386
|
+
return true;
|
|
9387
|
+
}
|
|
9388
|
+
/**
|
|
9389
|
+
* Remove whitespace-only assistant messages plus any reasoning item left with
|
|
9390
|
+
* no output to introduce: a reasoning item is only meaningful ahead of the
|
|
9391
|
+
* output it produced, and a dangling one is rejected by the Responses API when
|
|
9392
|
+
* it carries an id.
|
|
9393
|
+
*/
|
|
9394
|
+
function dropEmptyAssistantMessagesForReplay(items) {
|
|
9395
|
+
const kept = [];
|
|
9396
|
+
let pendingReasoning = [];
|
|
9397
|
+
let removedAssistantMessage = false;
|
|
9398
|
+
const flushReasoning = () => {
|
|
9399
|
+
kept.push(...pendingReasoning);
|
|
9400
|
+
pendingReasoning = [];
|
|
9401
|
+
};
|
|
9402
|
+
for (const item of items) {
|
|
9403
|
+
if (isOpenAIResponsesClientInputBoundary(item)) {
|
|
9404
|
+
pendingReasoning = [];
|
|
9405
|
+
removedAssistantMessage = false;
|
|
9406
|
+
kept.push(item);
|
|
8290
9407
|
continue;
|
|
8291
9408
|
}
|
|
8292
|
-
|
|
8293
|
-
if (
|
|
8294
|
-
|
|
8295
|
-
|
|
8296
|
-
|
|
8297
|
-
if (part.type === "refusal" && NON_WHITESPACE_RE.test(part.refusal)) {
|
|
8298
|
-
hasReplayableAssistantOutput = true;
|
|
8299
|
-
break;
|
|
8300
|
-
}
|
|
9409
|
+
if (item.type === "reasoning") {
|
|
9410
|
+
if (removedAssistantMessage) pendingReasoning = [];
|
|
9411
|
+
removedAssistantMessage = false;
|
|
9412
|
+
pendingReasoning.push(item);
|
|
9413
|
+
continue;
|
|
8301
9414
|
}
|
|
8302
|
-
if (
|
|
9415
|
+
if (isEmptyAssistantMessage(item)) {
|
|
9416
|
+
removedAssistantMessage = true;
|
|
9417
|
+
continue;
|
|
9418
|
+
}
|
|
9419
|
+
flushReasoning();
|
|
9420
|
+
removedAssistantMessage = false;
|
|
9421
|
+
kept.push(item);
|
|
8303
9422
|
}
|
|
8304
|
-
return
|
|
9423
|
+
return kept;
|
|
8305
9424
|
}
|
|
8306
9425
|
/**
|
|
8307
9426
|
* Drop hidden-only fallback assistant replay after a native Responses snapshot is rejected.
|
|
@@ -8330,20 +9449,129 @@ function sanitizeOpenAIResponsesAssistantFallbackItemsForReplay(items) {
|
|
|
8330
9449
|
}
|
|
8331
9450
|
return sanitized;
|
|
8332
9451
|
}
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
9452
|
+
/** Native tool call whose name {@link isMalformedToolCallName} rejects. */
|
|
9453
|
+
function isMalformedOpenAIResponsesToolCall(item) {
|
|
9454
|
+
return (item.type === "function_call" || item.type === "custom_tool_call") && isMalformedToolCallName(item.name);
|
|
9455
|
+
}
|
|
9456
|
+
function malformedResponsesCallKind(type) {
|
|
9457
|
+
if (type === "function_call") return "function";
|
|
9458
|
+
if (type === "custom_tool_call") return "custom";
|
|
9459
|
+
}
|
|
9460
|
+
function malformedResponsesOutputKind(type) {
|
|
9461
|
+
if (type === "function_call_output") return "function";
|
|
9462
|
+
if (type === "custom_tool_call_output") return "custom";
|
|
9463
|
+
}
|
|
9464
|
+
/** Tool results stay inside the pairing window; other client input starts a new one. */
|
|
9465
|
+
function isResponsesToolResultItem(type) {
|
|
9466
|
+
return type === "function_call_output" || type === "custom_tool_call_output" || type === "computer_call_output" || type === "local_shell_call_output" || type === "shell_call_output" || type === "apply_patch_call_output";
|
|
9467
|
+
}
|
|
9468
|
+
/**
|
|
9469
|
+
* User/developer messages and other non-result client input end the current
|
|
9470
|
+
* call/output window. A malformed call whose output never arrived must not
|
|
9471
|
+
* consume a later valid call that reuses the same `call_id`.
|
|
9472
|
+
*/
|
|
9473
|
+
function breaksMalformedResponsesPairingWindow(item) {
|
|
9474
|
+
if (isResponsesToolResultItem(item.type)) return false;
|
|
9475
|
+
return isOpenAIResponsesClientInputBoundary(item);
|
|
9476
|
+
}
|
|
9477
|
+
/**
|
|
9478
|
+
* Drop each native tool call with a malformed name and only the matching
|
|
9479
|
+
* `function_call_output` / `custom_tool_call_output` in the same window.
|
|
9480
|
+
*
|
|
9481
|
+
* `call_id` is not unique across a snapshot. Pair the same way
|
|
9482
|
+
* `sanitizeMalformedToolCalls` does for transcript messages: a per-id FIFO of
|
|
9483
|
+
* malformed-ness, keyed by function vs custom, cleared at user/developer and
|
|
9484
|
+
* other non-result client boundaries so a missing result cannot eat the next
|
|
9485
|
+
* window's output. Returns `items` itself when nothing is malformed.
|
|
9486
|
+
*/
|
|
9487
|
+
function dropMalformedOpenAIResponsesToolCalls(items) {
|
|
9488
|
+
let hasMalformed = false;
|
|
9489
|
+
for (const item of items) if (isMalformedOpenAIResponsesToolCall(item)) {
|
|
9490
|
+
hasMalformed = true;
|
|
9491
|
+
break;
|
|
9492
|
+
}
|
|
9493
|
+
if (!hasMalformed) return items;
|
|
9494
|
+
const dropQueues = /* @__PURE__ */ new Map();
|
|
9495
|
+
const kept = [];
|
|
9496
|
+
for (const item of items) {
|
|
9497
|
+
const callKind = malformedResponsesCallKind(item.type);
|
|
9498
|
+
if (callKind) {
|
|
9499
|
+
const malformed = isMalformedOpenAIResponsesToolCall(item);
|
|
9500
|
+
const callId = typeof item.call_id === "string" ? item.call_id : void 0;
|
|
9501
|
+
if (callId !== void 0) {
|
|
9502
|
+
const key = `${callKind}\0${callId}`;
|
|
9503
|
+
const queue = dropQueues.get(key);
|
|
9504
|
+
if (queue) queue.push(malformed);
|
|
9505
|
+
else dropQueues.set(key, [malformed]);
|
|
9506
|
+
}
|
|
9507
|
+
if (malformed) continue;
|
|
9508
|
+
kept.push(item);
|
|
9509
|
+
continue;
|
|
8340
9510
|
}
|
|
9511
|
+
const outputKind = malformedResponsesOutputKind(item.type);
|
|
9512
|
+
if (outputKind) {
|
|
9513
|
+
const callId = typeof item.call_id === "string" ? item.call_id : void 0;
|
|
9514
|
+
if (callId !== void 0) {
|
|
9515
|
+
const key = `${outputKind}\0${callId}`;
|
|
9516
|
+
const queue = dropQueues.get(key);
|
|
9517
|
+
if (queue && queue.length > 0) {
|
|
9518
|
+
const drop = queue.shift() === true;
|
|
9519
|
+
if (queue.length === 0) dropQueues.delete(key);
|
|
9520
|
+
if (drop) continue;
|
|
9521
|
+
}
|
|
9522
|
+
}
|
|
9523
|
+
kept.push(item);
|
|
9524
|
+
continue;
|
|
9525
|
+
}
|
|
9526
|
+
if (breaksMalformedResponsesPairingWindow(item)) dropQueues.clear();
|
|
9527
|
+
kept.push(item);
|
|
8341
9528
|
}
|
|
9529
|
+
return kept;
|
|
9530
|
+
}
|
|
9531
|
+
/**
|
|
9532
|
+
* Replay history is immutable and re-sanitized on every request, so each item
|
|
9533
|
+
* remembers the replay `arguments` derived from its stored value instead of
|
|
9534
|
+
* re-parsing every historical call (large write/edit payloads) per request.
|
|
9535
|
+
* Frozen/sealed caller-owned items are never mutated; they re-parse instead.
|
|
9536
|
+
*/
|
|
9537
|
+
const kReplayArguments = Symbol("openaiResponses.replayArguments");
|
|
9538
|
+
/**
|
|
9539
|
+
* `arguments` to replay for a native `function_call`: the stored string when it
|
|
9540
|
+
* parses, `{}` when absent/blank, else the bounded `{__parseError, __rawJson}`
|
|
9541
|
+
* diagnostic the transcript (and the cold replay path) already carries.
|
|
9542
|
+
*
|
|
9543
|
+
* Unparsable text (stream cut off mid-JSON) 400s the whole request, but dropping
|
|
9544
|
+
* the call orphans its recorded tool result into an assistant note that can end
|
|
9545
|
+
* the request and 400 it again (#15568).
|
|
9546
|
+
*/
|
|
9547
|
+
function replayFunctionCallArguments(item) {
|
|
9548
|
+
const raw = item.arguments;
|
|
9549
|
+
const cached = item[kReplayArguments];
|
|
9550
|
+
if (cached && cached.raw === raw) return cached.replay;
|
|
9551
|
+
let replay = "{}";
|
|
9552
|
+
if (typeof raw === "string" && raw.trim().length > 0) try {
|
|
9553
|
+
JSON.parse(raw);
|
|
9554
|
+
replay = raw;
|
|
9555
|
+
} catch (error) {
|
|
9556
|
+
replay = JSON.stringify(invalidToolCallArguments(raw, error));
|
|
9557
|
+
}
|
|
9558
|
+
if (Object.isExtensible(item)) Object.defineProperty(item, kReplayArguments, {
|
|
9559
|
+
value: {
|
|
9560
|
+
raw,
|
|
9561
|
+
replay
|
|
9562
|
+
},
|
|
9563
|
+
writable: true
|
|
9564
|
+
});
|
|
9565
|
+
return replay;
|
|
9566
|
+
}
|
|
9567
|
+
function sanitizeOpenAIResponsesHistoryItemForReplay(item, supportsImageDetailOriginal, preserveReasoningItemIds) {
|
|
9568
|
+
if (isMalformedOpenAIResponsesToolCall(item)) return;
|
|
8342
9569
|
if (item.type === "item_reference") return void 0;
|
|
8343
9570
|
if (item.type === "image_generation_call") return sanitizeOpenAIResponsesImageGenerationCallForReplay(item);
|
|
8344
9571
|
if (item.type === "reasoning") return sanitizeOpenAIResponsesReasoningItemForReplay(item, preserveReasoningItemIds);
|
|
8345
9572
|
const { id: _id, ...sanitizedItem } = item;
|
|
8346
9573
|
if (item.type === "computer_call" && typeof item.id === "string") sanitizedItem.id = item.id;
|
|
9574
|
+
if (item.type === "function_call") sanitizedItem.arguments = replayFunctionCallArguments(item);
|
|
8347
9575
|
return clampReplayItemImageDetail(sanitizedItem, supportsImageDetailOriginal);
|
|
8348
9576
|
}
|
|
8349
9577
|
function sanitizeOpenAIResponsesReasoningItemForReplay(item, preserveItemId) {
|
|
@@ -8395,4 +9623,4 @@ function resolveCacheRetention(cacheRetention, fallback = "short") {
|
|
|
8395
9623
|
return fallback;
|
|
8396
9624
|
}
|
|
8397
9625
|
//#endregion
|
|
8398
|
-
export {
|
|
9626
|
+
export { normalizeSchemaForMoonshot as $, kConversationalUser as A, FencedThinkingScanner as B, clearStreamingPartialJson as C, isDemotedThinking as D, isConversationalUser as E, kStreamingEnvelopeId as F, flattenExclusiveRequiredRootUnion as G, parseToolCallArguments as H, kStreamingLastParseLen as I, toFoundationModelsSchema as J, toolWireSchema as K, kStreamingPartialJson as L, kStreamingArgumentsDone as M, kStreamingBlockIndex as N, isPerCallContextMessage as O, kStreamingBlockKind as P, normalizeSchemaForGoogle as Q, renderDemotedThinking as R, transformMessages as S, isCarriedReasoning as T, replayableToolCallArguments as U, TerminatorWait as V, partialSuffixOverlapAny as W, adaptSchemaForStrict as X, NO_STRICT as Y, normalizeSchemaForCCA as Z, isValidToolCallId as _, getOpenAIResponsesHistoryItems as a, COMBINATOR_KEYS as at, redactSensitiveInObject as b, normalizeSystemPrompts as c, sanitizeText as ct, sanitizeOpenAIResponsesAssistantHistoryItemsForReplay as d, sanitizeSchemaForCursor as et, sanitizeOpenAIResponsesHistoryItemsForReplay as f, isResponsesFamilyApi as g, truncateResponseItemId as h, getHeaderCaseInsensitive as i, spillToDescription as it, kCursorExecResolved as j, isSyntheticUser as k, resolveCacheRetention as l, stringifyJson$1 as lt, stripUnpairedOpenAIResponsesComputerReasoningIdsForReplay as m, createOpenAIResponsesHistoryPayload as n, sanitizeSchemaForOllama as nt, getOpenAIResponsesHistoryPayload as o, getBundledModelReferenceIndex as ot, stripOpenAIResponsesComputerLinkedReasoningIdsForReplay as p, decodeFoundationModelsArguments as q, dropMalformedOpenAIResponsesToolCalls as r, sanitizeSchemaForOpenAIResponses as rt, normalizeResponsesToolCallId as s, resolveCatalogPolicy as st, clampOpenAIResponsesImageDetailForReplay as t, sanitizeSchemaForGrammar as tt, sanitizeOpenAIResponsesAssistantFallbackItemsForReplay as u, tryParseJson as ut, normalizeToolCallId as v, copyPerCallContextMessage as w, responsesCallComponent as x, redactSensitiveCredentials as y, createInbandScanner as z };
|