@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.
Files changed (109) hide show
  1. package/lib/{abort-DZ54CaKU.mjs → abort-BTblp0Rt.mjs} +2 -2
  2. package/lib/{alibaba-coding-plan-DODpkcqi.mjs → alibaba-coding-plan-t3R4YKCB.mjs} +3 -3
  3. package/lib/{alibaba-token-plan-C6lpKCda.mjs → alibaba-token-plan-CO4djG1y.mjs} +4 -4
  4. package/lib/{alibaba-token-plan-CHGyWOfX.mjs → alibaba-token-plan-CUjYJX0-.mjs} +1 -1
  5. package/lib/{anthropic-Dv_GGX6g.mjs → anthropic-nf7w6so1.mjs} +48 -21
  6. package/lib/{api-key-validation-MnMf_ihX.mjs → api-key-validation-C_tZ7Y9a.mjs} +2 -2
  7. package/lib/behavior-BwvTUtag.mjs +111 -0
  8. package/lib/{browser-render-BZXt548F.mjs → browser-render-BQaEVK_n.mjs} +4 -4
  9. package/lib/{reference-CtvM4zLU.mjs → bundled-references-CrQ4dQcT.mjs} +57 -4
  10. package/lib/cascade-BWjRTD1q.mjs +30265 -0
  11. package/lib/{cline-pass-BT9CBEOj.mjs → cline-pass-Bjm-O8GG.mjs} +2 -2
  12. package/lib/cloudflare-CKXRJ0l9.mjs +37 -0
  13. package/lib/{cloudflare-ai-gateway-DReN6ohJ.mjs → cloudflare-ai-gateway-BpnBSjwV.mjs} +8 -4
  14. package/lib/cloudflare-workers-ai-odj9XswL.mjs +32 -0
  15. package/lib/collapse-_nkb2dn7.mjs +1945 -0
  16. package/lib/{coreweave-C82HrLpb.mjs → coreweave-CGDZOD8-.mjs} +1 -1
  17. package/lib/{coreweave-C68UgRQO.mjs → coreweave-DwffcgW5.mjs} +4 -4
  18. package/lib/cursor-BgOuV7Qf.mjs +794 -0
  19. package/lib/{cursor-_gHHq-Dq.mjs → cursor-CF1iHHbv.mjs} +68 -19
  20. package/lib/{cursor-proto-Cr_WEMuv.mjs → cursor-proto-BuNTjX3L.mjs} +823 -23
  21. package/lib/{devin-QpfTSl9H.mjs → devin-7OEeEb80.mjs} +112 -31
  22. package/lib/{devin-proto-DYhp4Ty6.mjs → devin-proto-C-QreeAv.mjs} +71 -5
  23. package/lib/{dom-DG3sPESc.mjs → dom-BmbZv4v9.mjs} +598 -182
  24. package/lib/{error-O63pC8zg.mjs → error-8LVo7tug.mjs} +725 -104
  25. package/lib/factory-droid-ChhmsGWb.mjs +71 -0
  26. package/lib/{fs-promises-shim-B2YFWkcd.mjs → fs-promises-shim-CANAxFWh.mjs} +10 -1
  27. package/lib/{github-copilot-BMEcw8N1.mjs → github-copilot-QwevdT30.mjs} +4 -4
  28. package/lib/{github-copilot-headers-DnjGEbko.mjs → github-copilot-headers-CAUZ0rUD.mjs} +138 -26
  29. package/lib/{gitlab-duo-DnHqJjFY.mjs → gitlab-duo-DigV7k_o.mjs} +2 -2
  30. package/lib/{google-antigravity-B1mSckrK.mjs → google-antigravity-D-oe0r8A.mjs} +6 -7
  31. package/lib/{google-gemini-cli-DJwThCCn.mjs → google-gemini-cli-CQBHgGJT.mjs} +5 -6
  32. package/lib/{google-oauth-shared-BctLpVUN.mjs → google-oauth-shared-CvgVIUwJ.mjs} +2 -2
  33. package/lib/google-validation-CdvRj4ec.mjs +126 -0
  34. package/lib/id-EJwVLDHE.mjs +2548 -0
  35. package/lib/index.mjs +248 -258
  36. package/lib/{kilo-BEgEwMJQ.mjs → kilo-5r6OffCa.mjs} +2 -2
  37. package/lib/{kimi-T9NldEIJ.mjs → kimi-DOOtbXmm.mjs} +9 -10
  38. package/lib/{launch-BIWNyrBB.mjs → launch-DkAjib7h.mjs} +1 -1
  39. package/lib/{markit-Dvp2JPdT.mjs → markit-CCcyeAds.mjs} +359 -140
  40. package/lib/{models-DnXMYGcJ.mjs → models-DCpDT_im.mjs} +199203 -112275
  41. package/lib/{muse-code-CNvqqAp6.mjs → muse-code-CYf8zj_B.mjs} +5 -5
  42. package/lib/{openai-codex-D5-CyTxa.mjs → openai-codex-Cj-TvSFh.mjs} +13 -10
  43. package/lib/{perplexity-A2PEoGaC.mjs → perplexity-Dh_Qgsmx.mjs} +68 -25
  44. package/lib/{pkce-BYjmugmw.mjs → pkce-DO-jBJLV.mjs} +1 -1
  45. package/lib/pricing-DusBEhwm.mjs +593 -0
  46. package/lib/{readability-uGhqb4GC.mjs → readability-XHK0o3bv.mjs} +287 -27
  47. package/lib/{scrapers-C1ujjV8k.mjs → scrapers-B6PADOVm.mjs} +13 -13
  48. package/lib/slugify-ynYWBIA5.mjs +11 -0
  49. package/lib/snowflake-B_jap6lz.mjs +666 -0
  50. package/lib/snowflake-Cu1ZyOp6.mjs +151 -0
  51. package/lib/{src-AELUUb5U.mjs → src-BhinCSpi.mjs} +1172 -458
  52. package/lib/{stream-AVOoe5Hj.mjs → stream-D2ivg3GH.mjs} +3740 -5311
  53. package/lib/{turndown-D6fof1OX.mjs → turndown-Vya8SavL.mjs} +82 -30
  54. package/lib/types/tools/hashline/native/index.d.ts +2 -2
  55. package/lib/types/tools/hashline/native/policy.d.ts +19 -21
  56. package/lib/types/tools/omp/session/agent-storage.d.ts +3 -3
  57. package/lib/types/tools/shared/bun-named-shim.d.ts +5 -0
  58. package/lib/{types-BLrLohwK.mjs → types-tH1v9uRm.mjs} +2 -2
  59. package/lib/{utils-cZX3f_Ls.mjs → utils-C_Ncya1r.mjs} +1737 -509
  60. package/lib/utils-D2tK38xq.mjs +34006 -0
  61. package/lib/{utils-I4I8azHN.mjs → utils-DrDwmNtu.mjs} +8 -3
  62. package/lib/{xai-oauth-CbeldUSV.mjs → xai-oauth-DLLzX6my.mjs} +4 -4
  63. package/lib/{xiaomi-Dl3VSs04.mjs → xiaomi-CqK-KivK.mjs} +2 -2
  64. package/lib/{zai-FyjGSypr.mjs → zai-DoJ2xPIH.mjs} +2 -2
  65. package/lib/{zip-DRrycScC.mjs → zip-DG1mUV6X.mjs} +1 -1
  66. package/package.json +8 -8
  67. package/lib/amazon-bedrock-Dx0rr9dY.mjs +0 -996
  68. package/lib/anthropic-ClCw0PV_.mjs +0 -3624
  69. package/lib/anthropic-wire-lbGAFzYb.mjs +0 -927
  70. package/lib/azure-openai-responses-WE_bgFWp.mjs +0 -285
  71. package/lib/bundled-references-DY3EJxZV.mjs +0 -56
  72. package/lib/cloudflare-ai-gateway-CrMa97Ap.mjs +0 -44
  73. package/lib/collapse-CkMNRNr7.mjs +0 -2304
  74. package/lib/cursor-C6jaIJDg.mjs +0 -283
  75. package/lib/cursor-D-XZYDf_.mjs +0 -4544
  76. package/lib/deterministic-id-CUEIMSqR.mjs +0 -17
  77. package/lib/devin-ExGIghmx.mjs +0 -69
  78. package/lib/devin-u0ljw5P6.mjs +0 -628
  79. package/lib/effort-BdtQMN-_.mjs +0 -23
  80. package/lib/event-stream-BKEtb45Y.mjs +0 -167
  81. package/lib/gemini-headers-Co9cVvex.mjs +0 -54
  82. package/lib/google-auth-qAN-6DMW.mjs +0 -232
  83. package/lib/google-gemini-cli-B2Aw1S5w.mjs +0 -844
  84. package/lib/google-lTxuq28n.mjs +0 -38
  85. package/lib/google-shared-Y01j9xOr.mjs +0 -856
  86. package/lib/google-validation-BEkNs-Bx.mjs +0 -18
  87. package/lib/google-vertex-DcM-FRC5.mjs +0 -99
  88. package/lib/hosts-00rjRzUD.mjs +0 -203
  89. package/lib/id-AL5obQzR.mjs +0 -71
  90. package/lib/idle-iterator-D0ZXEcUq.mjs +0 -366
  91. package/lib/ollama-6R0oXZks.mjs +0 -574
  92. package/lib/openai-codex-responses-C8bnBWOe.mjs +0 -3232
  93. package/lib/openai-completions-DNr3mUsn.mjs +0 -1430
  94. package/lib/openai-configuration-update-xMYUjaK_.mjs +0 -150
  95. package/lib/openai-reasoning-fallback-Ju-5pSR8.mjs +0 -380
  96. package/lib/openai-responses-CjpafAEr.mjs +0 -861
  97. package/lib/protobuf-BMgDYu_U.mjs +0 -717
  98. package/lib/provider-response-SqKSkkUc.mjs +0 -22
  99. package/lib/proxy-DxvCQOCA.mjs +0 -230
  100. package/lib/request-debug-BwPOqN_j.mjs +0 -183
  101. package/lib/sanitize-text-BCf5KmCf.mjs +0 -33
  102. package/lib/sse-debug-B-tkLCPW.mjs +0 -11
  103. package/lib/stream-markup-healing-CN3RsqG9.mjs +0 -267
  104. package/lib/strict-tool-validation-CBTz1dAA.mjs +0 -105
  105. package/lib/taxonomy-DSIM99rS.mjs +0 -15392
  106. package/lib/thinking-ngMwf_1Y.mjs +0 -336
  107. package/lib/type-guards-CttAANEx.mjs +0 -11
  108. package/lib/utils-CE3DSebh.mjs +0 -11763
  109. 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 { F as $flag, N as $env, _ as parseStreamingJson, b as debug, g as parseJsonWithRepair } from "./src-AELUUb5U.mjs";
4
- import { r as ValidationError } from "./error-O63pC8zg.mjs";
5
- import { n as classifyModel } from "./taxonomy-DSIM99rS.mjs";
6
- import { i as getBundledProviders, r as getBundledModels } from "./models-DnXMYGcJ.mjs";
7
- import { t as buildModelReferenceIndex } from "./reference-CtvM4zLU.mjs";
8
- //#region node_modules/.pnpm/@oh-my-pi+pi-utils@18.1.17/node_modules/@oh-my-pi/pi-utils/src/json.ts
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
- return JSON.stringify(value, (_key, item) => typeof item === "bigint" ? item.toString() : item, space);
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 += "&amp;";
78
+ else if (char === "<") output += "&lt;";
79
+ else if (char === ">") output += "&gt;";
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.1.17/node_modules/@oh-my-pi/pi-catalog/src/identity/bundled.ts
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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/anthropic.md
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 &amp; 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.1.17/node_modules/@oh-my-pi/pi-ai/src/utils/schema/types.ts
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.1.17/node_modules/@oh-my-pi/pi-ai/src/utils/schema/equality.ts
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.1.17/node_modules/@oh-my-pi/pi-ai/src/utils/schema/stamps.ts
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
- * Symbol-keyed lazy memoization stamped directly onto the host object.
269
+ * Lazy memoization keyed by host object identity, held in a module-level
270
+ * weak side table.
136
271
  *
137
- * Faster than a module-level `WeakMap` in V8/JSC because the symbol slot is
138
- * resolved through the object's hidden class instead of a side-table hash
139
- * lookup. The slot is defined as a non-enumerable property so the stamp
140
- * does not leak through `{...spread}`, `Object.keys`, `JSON.stringify`, or
141
- * `toEqual`-style deep equality.
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: the stamp lives as long as the host object, even after callers
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. Frozen hosts cannot be stamped;
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
- function define(target, key, value) {
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
- const existing = target[key];
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
- define(target, key, value);
294
+ slots.set(key, value);
163
295
  return value;
164
296
  }
165
297
  /**
166
- * Epoch-keyed cycle guard. Cheaper than `WeakSet` for recursive traversal
167
- * because the marker is a single property slot on the host object, written
168
- * once and overwritten in place on every subsequent traversal — the hidden
169
- * class transitions once per object lifetime, not per traversal.
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 kEpoch = Symbol("pi.schema.epoch");
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 slot = target;
189
- const cur = slot[kEpoch];
320
+ const cur = epochs.get(target);
190
321
  if (cur !== void 0 && cur >= epoch) return false;
191
- if (cur === void 0) define(target, kEpoch, epoch);
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 slot returns to 0 after a balanced walk so
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 kDepth = Symbol("pi.schema.depth");
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 slot = target;
223
- const cur = slot[kDepth];
224
- if (cur === void 0) {
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 slot = target;
234
- const cur = slot[kDepth];
354
+ const cur = depths.get(target);
235
355
  if (cur === void 0) return;
236
- slot[kDepth] = cur - 1;
356
+ depths.set(target, cur - 1);
237
357
  }
238
358
  //#endregion
239
- //#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.1.17/node_modules/@oh-my-pi/pi-ai/src/utils/schema/draft.ts
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$1 = {
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
- /** Rewrite draft-07's `#/definitions/Foo` ref form to draft 2020-12's `#/$defs/Foo`. External refs (`http://…`) pass through. */
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
- return value.startsWith("#/definitions/") ? `#/$defs/${value.slice(14)}` : value;
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$1) {
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$1) {
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.1.17/node_modules/@oh-my-pi/pi-ai/src/utils/schema/dereference.ts
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 match = /^#\/(\$defs|definitions)\/(.+)$/.exec(ref);
526
- if (!match) return void 0;
527
- const [, defsKey, name] = match;
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[name];
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
- ...inlined,
555
- ...node
556
- };
557
- delete merged.$ref;
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
- if (Array.isArray(value)) result[key] = value.map((item) => dereferenceNode(item, root, visiting));
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.1.17/node_modules/@oh-my-pi/pi-ai/src/utils/schema/fields.ts
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.1.17/node_modules/@oh-my-pi/pi-ai/src/utils/schema/meta-validator.ts
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 (!isPlainObject(value)) return false;
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 (!isPlainObject(node)) return false;
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 (!isPlainObject(value)) return false;
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.1.17/node_modules/@oh-my-pi/pi-ai/src/utils/schema/spill.ts
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.1.17/node_modules/@oh-my-pi/pi-ai/src/utils/schema/normalize.ts
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.normalizeTypeArrayToNullable && Array.isArray(result.type)) {
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
- for (const key in nextSchema) {
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
- normalizeTypeArrayToNullable: true,
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
- normalizeTypeArrayToNullable: true,
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; `type: [...]` arrays are reduced to a
1872
- * single scalar (the `null` branch is dropped — `nullable` is unsupported).
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
- normalizeTypeArrayToNullable: true,
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 slot. The result of `tryEnforceStrictSchema`
2299
- * is stamped directly onto the input via `stamp(target, kStrictSchema, …)`
2300
- * so repeated calls (different providers, retries, batching) reuse the same
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("pi.schema.strict");
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 JSON-pointer-style `$ref` against the root schema. Mirrors the
2675
- * OpenAI SDK's `resolve_ref` helper: only local refs starting with `#/` are
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
- if (!ref.startsWith("#/")) return void 0;
2681
- const segments = ref.slice(2).split("/");
2894
+ const pointer = parseLocalRefPointer(ref);
2895
+ if (pointer === void 0 || pointer.length === 0) return void 0;
2682
2896
  let cursor = root;
2683
- for (const raw of segments) {
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.1.17/node_modules/@oh-my-pi/pi-ai/src/utils/schema/adapt.ts
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.1.17/node_modules/@oh-my-pi/pi-ai/src/utils/schema/wire.ts
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 (!isSchemaRecord(value)) return false;
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) => isSchemaRecord(entry) && typeof entry.key === "string" && "value" in 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 (isSchemaRecord(schema)) {
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) => isSchemaRecord(item) && Object.hasOwn(item, "unit"))) return { enum: value.map((item) => item.unit) };
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 (!isSchemaRecord(value)) return {};
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 (!isSchemaRecord(entry) || typeof entry.key !== "string" || !("value" in entry)) return;
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
- /** Symbol-stamped caches keyed by schema object identity. */
2803
- const kJsonWireSchema = Symbol("pi.schema.json.wire");
2804
- const kArkWireSchema = Symbol("pi.schema.ark.wire");
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 (!isSchemaRecord(variant)) return;
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 (!isSchemaRecord(branch)) return false;
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")) && !isSchemaRecord(schema.properties)) return schema;
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 (!isSchemaRecord(node)) return;
3361
+ if (!isRecord(node)) return;
2947
3362
  const obj = node;
2948
3363
  const properties = obj.properties;
2949
- if (isSchemaRecord(properties)) {
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 (isSchemaRecord(map)) for (const key in map) normalizeArkPropertyComments(map[key]);
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 (!isSchemaRecord(variant) || !Object.hasOwn(variant, "const")) return;
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 && isSchemaRecord(only)) {
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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/coercion.ts
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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/rendering.ts
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("&", "&amp;").replaceAll("\"", "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
3349
3779
  }
3350
- function escapeXmlText(value) {
3351
- return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/anthropic.ts
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$2(call, buildArgShapes(options.tools).get(call.name));
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$2(calls, options.tools ?? [])}\n</function_calls>`;
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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/deepseek.md
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 &amp; 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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/deepseek.ts
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
- const SECTION_TOKENS = [DEEPSEEK_TOOL_CALL_BEGIN, DEEPSEEK_TOOL_CALLS_END];
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.#buffer += text;
4124
- return this.#consume(false);
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 = findEarliestToken(this.#buffer, OUTSIDE_TOKENS);
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
- const emit = this.#buffer.slice(0, this.#buffer.length - hold);
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
- if (match.index > 0) events.push({
4195
- type: "text",
4196
- text: this.#buffer.slice(0, match.index)
4197
- });
4198
- this.#buffer = this.#buffer.slice(match.index);
4199
- if (this.#buffer.startsWith("<|tool▁calls▁begin|>")) {
4200
- this.#buffer = this.#buffer.slice(20);
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 (this.#buffer.startsWith("<|tool▁call▁begin|>")) {
4206
- this.#buffer = this.#buffer.slice(19);
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 (this.#buffer.startsWith(THINK_OPEN$5)) {
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 (this.#buffer.startsWith(DSML_TOOL_CALLS_OPEN_FULLWIDTH) || this.#buffer.startsWith(DSML_TOOL_CALLS_OPEN_ASCII)) {
4220
- const openToken = this.#buffer.startsWith(DSML_TOOL_CALLS_OPEN_FULLWIDTH) ? DSML_TOOL_CALLS_OPEN_FULLWIDTH : DSML_TOOL_CALLS_OPEN_ASCII;
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
- const orphanClose = this.#matchingOrphanDsmlClose();
4226
- if (orphanClose) {
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
- const control = this.#matchingControlToken();
4231
- if (control) {
4232
- this.#buffer = this.#buffer.slice(control.length);
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
- this.#buffer = this.#buffer.slice(match.token.length);
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.#skipWhitespace();
4255
- if (this.#buffer.startsWith("<|tool▁calls▁end|>")) {
4256
- this.#buffer = this.#buffer.slice(18);
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 (this.#buffer.startsWith("<|tool▁call▁begin|>")) {
4262
- this.#buffer = this.#buffer.slice(19);
4263
- this.#rawBlock = DEEPSEEK_TOOL_CALL_BEGIN;
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 (!final && partialSuffixOverlapAny(this.#buffer, SECTION_TOKENS) === this.#buffer.length) return false;
4268
- if (this.#buffer.length === 0) return false;
4269
- this.#buffer = this.#buffer.slice(1);
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.indexOf(DEEPSEEK_TOOL_SEPARATOR);
4275
- if (sep === -1) {
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 + 12);
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
- const end = this.#buffer.indexOf(DEEPSEEK_TOOL_CALL_END);
4308
- if (end === -1) {
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
- let rawArgs = this.#buffer.slice(0, end);
4313
- if (this.#state === "legacyArgs") {
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(rawTail.length);
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(">")) return false;
4355
- if (partialSuffixOverlapAny(this.#buffer, DSML_SECTION_TOKENS) === this.#buffer.length) return false;
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) return false;
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
- try {
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
- #matchingOrphanDsmlClose() {
4490
- for (const token of DSML_ORPHAN_CLOSE_TOKENS) if (this.#buffer.startsWith(token)) return token;
4491
- }
4492
- #matchingControlToken() {
4493
- if (this.#buffer.startsWith("<|tool▁calls▁end|>")) return DEEPSEEK_TOOL_CALLS_END;
4494
- if (this.#buffer.startsWith(THINK_CLOSE$4)) return THINK_CLOSE$4;
4495
- if (this.#buffer.startsWith(DSML_TOOL_CALLS_CLOSE_FULLWIDTH)) return DSML_TOOL_CALLS_CLOSE_FULLWIDTH;
4496
- if (this.#buffer.startsWith(DSML_TOOL_CALLS_CLOSE_ASCII)) return DSML_TOOL_CALLS_CLOSE_ASCII;
4497
- for (const token of CONTROL_TOKENS) if (this.#buffer.startsWith(token)) return token;
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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/fenced-thinking.ts
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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/gemini.md
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 &amp; 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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/gemini.ts
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.#buffer += text;
4815
- return this.#consume(false);
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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/gemma.md
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 &amp; 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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/gemma.ts
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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/glm.md
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 &amp; 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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/glm.ts
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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/harmony.md
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 &amp; 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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/harmony.ts
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
- try {
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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/hermes.md
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 &amp; 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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/hermes.ts
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.#buffer += text;
6531
- return this.#consume(false);
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
- try {
6643
- const partial = parseStreamingJson(body);
6644
- if (typeof partial.name !== "string" || partial.name.length === 0) return;
6645
- this.#name = partial.name;
6646
- this.#started = true;
6647
- events.push({
6648
- type: "toolStart",
6649
- id: this.#id,
6650
- name: this.#name
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") try {
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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/kimi.md
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 &amp; 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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/kimi.ts
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.#buffer += text;
6753
- return this.#consume(false);
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
- try {
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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/minimax.md
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 &amp; 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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/minimax.ts
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$1(call, buildArgShapes(options.tools).get(call.name));
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$1(calls, options.tools ?? [])}\n</minimax:tool_call>`;
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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/qwen3.md
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 &amp; 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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/qwen3.ts
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.#buffer += text;
7106
- return this.#consume(false);
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 nameMatch = COMPLETE_NAME.exec(body);
7228
- if (!nameMatch) return;
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") try {
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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/xml.md
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 &amp; 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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/xml.ts
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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/factory.ts
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.1.17/node_modules/@oh-my-pi/pi-ai/src/dialect/demotion.ts
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.1.17/node_modules/@oh-my-pi/pi-ai/src/utils/block-symbols.ts
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.1.17/node_modules/@oh-my-pi/pi-ai/src/providers/transform-messages.ts
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
- * Maximum tool-call id length the strictest replay provider accepts.
7484
- *
7485
- * Anthropic requires `^[a-zA-Z0-9_-]+$` with a 64-char cap; Google and Codex
7486
- * `normalizeToolCallId` implementations cap individual id segments to the same
7487
- * 64-char ceiling. Replacement ids minted here flow back through
7488
- * `convertAnthropicMessages` (and friends) unchanged, so the `_dupN` suffix
7489
- * MUST not push a normalized id past this bound.
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
- function collectToolCallOriginScope(messages) {
7512
- const responsesComponents = /* @__PURE__ */ new Set();
7513
- const opaqueCompositeCallIds = /* @__PURE__ */ new Set();
7514
- for (const msg of messages) {
7515
- if (msg.role !== "assistant") continue;
7516
- const responsesOrigin = isResponsesFamilyApi(msg.api);
7517
- for (const block of msg.content) {
7518
- if (block.type !== "toolCall") continue;
7519
- if (responsesOrigin) responsesComponents.add(responsesCallComponent(block.id));
7520
- else if (block.id.includes("|")) opaqueCompositeCallIds.add(block.id);
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
- function deduplicateToolCallIds(messages, originScope, maxToolCallIdLength = MAX_TOOL_CALL_ID_LENGTH, duplicateSuffixPrefix = "_dup") {
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
- return messages.map((msg) => {
7578
- if (msg.role === "toolResult") {
7579
- const key = toolCallPairingKey(msg.toolCallId, originScope);
7580
- const rewrites = pendingToolResultRewrites.get(key);
7581
- if (!rewrites || rewrites.length === 0) return msg;
7582
- const rewrite = rewrites.shift();
7583
- if (rewrites.length === 0) pendingToolResultRewrites.delete(key);
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
- if (msg.role !== "assistant") return msg;
7591
- const enqueueToolResultRewrite = (id, rewrite) => {
7592
- const rewrites = pendingToolResultRewrites.get(id);
7593
- if (rewrites) {
7594
- rewrites.push(rewrite);
7595
- return;
7596
- }
7597
- pendingToolResultRewrites.set(id, [rewrite]);
7598
- };
7599
- const idsTouchedInTurn = /* @__PURE__ */ new Set();
7600
- let contentChanged = false;
7601
- const content = msg.content.map((block) => {
7602
- if (block.type !== "toolCall") return block;
7603
- const blockKey = toolCallPairingKey(block.id, originScope);
7604
- if (!idsTouchedInTurn.has(blockKey)) {
7605
- pendingToolResultRewrites.delete(blockKey);
7606
- idsTouchedInTurn.add(blockKey);
7607
- }
7608
- const previousCount = seenToolCallIds.get(blockKey) ?? 0;
7609
- if (previousCount === 0) {
7610
- seenToolCallIds.set(blockKey, 1);
7611
- enqueueToolResultRewrite(blockKey, void 0);
7612
- return block;
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
- let duplicateIndex = previousCount;
7615
- let replacementId = appendDuplicateSuffix(block.id, `${duplicateSuffixPrefix}${duplicateIndex}`, maxToolCallIdLength);
7616
- while (seenToolCallIds.has(toolCallPairingKey(replacementId, originScope))) {
7617
- duplicateIndex += 1;
7618
- replacementId = appendDuplicateSuffix(block.id, `${duplicateSuffixPrefix}${duplicateIndex}`, maxToolCallIdLength);
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
- seenToolCallIds.set(blockKey, duplicateIndex + 1);
7621
- seenToolCallIds.set(toolCallPairingKey(replacementId, originScope), 1);
7622
- enqueueToolResultRewrite(blockKey, { replacementId });
7623
- contentChanged = true;
8422
+ if (!contentChanged) return msg;
7624
8423
  return {
7625
- ...block,
7626
- id: replacementId
8424
+ ...msg,
8425
+ content
7627
8426
  };
7628
- });
7629
- if (!contentChanged) return msg;
7630
- return {
7631
- ...msg,
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
- * Drop assistant `toolCall` blocks whose `id` or `name` is empty / whitespace-only,
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 list returns
7654
- * the input untouched. Provider-agnostic — any wire model could surface this.
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 isMalformedToolCallName(name) {
7657
- return !name || name.trim().length === 0;
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
- function getLatestSurvivingAssistantIndex(messages) {
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" && !shouldDropTruncatedThinkingOnlyAssistant(msg)) return index;
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
- const ANTHROPIC_TOOL_CALL_ID_PATTERN = /^[a-zA-Z0-9_-]{1,64}$/;
7741
- function isValidAnthropicToolCallId(id) {
7742
- return ANTHROPIC_TOOL_CALL_ID_PATTERN.test(id);
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, normalizeToolCallId) {
7748
- if (isValidAnthropicToolCallId(id)) return id;
7749
- const normalized = normalizeToolCallId?.(id, model, source) ?? id.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, MAX_TOOL_CALL_ID_LENGTH);
7750
- if (isValidAnthropicToolCallId(normalized)) return normalized;
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 = MAX_TOOL_CALL_ID_LENGTH, duplicateToolCallIdSuffixPrefix = "_dup", targetCompat = model.compat) {
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.provider === model.provider && assistantMsg.api === model.api && assistantMsg.model === model.id;
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 && model.compat.officialEndpoint) return block;
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 = collectToolCallOriginScope(normalizedMessages);
7910
- const transformed = deduplicateToolCallIds(normalizedMessages, originScope, maxNormalizedToolCallIdLength, duplicateToolCallIdSuffixPrefix);
7911
- const realToolResultsById = /* @__PURE__ */ new Map();
7912
- for (let index = 0; index < transformed.length; index++) {
7913
- const msg = transformed[index];
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
- result.push({
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.1.17/node_modules/@oh-my-pi/pi-ai/src/utils.ts
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 [callId, itemId] = id.split("|");
8088
- if (callId && itemId) return {
8089
- callId,
8090
- itemId: normalizeResponsesItemId(itemId, itemPrefix)
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 supportsImageDetailOriginal = options.supportsImageDetailOriginal !== false;
8206
- const computerLinkedReasoningItems = options.supportsComputerUse === false ? void 0 : collectOpenAIResponsesComputerLinkedReasoningItems(items, false);
8207
- return stripOpenAIResponsesOutputOnlyStatusesForReplay(items.flatMap((item) => {
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.type !== "message" || item.role !== "assistant") {
8282
- hasReplayableAssistantOutput = true;
8283
- break;
9369
+ if (isEmptyAssistantMessage(item)) {
9370
+ hasEmptyAssistantMessage = true;
9371
+ continue;
8284
9372
  }
8285
- if (typeof item.content === "string") {
8286
- if (NON_WHITESPACE_RE.test(item.content)) {
8287
- hasReplayableAssistantOutput = true;
8288
- break;
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
- for (const part of item.content) {
8293
- if (part.type === "output_text" && NON_WHITESPACE_RE.test(part.text)) {
8294
- hasReplayableAssistantOutput = true;
8295
- break;
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 (hasReplayableAssistantOutput) break;
9415
+ if (isEmptyAssistantMessage(item)) {
9416
+ removedAssistantMessage = true;
9417
+ continue;
9418
+ }
9419
+ flushReasoning();
9420
+ removedAssistantMessage = false;
9421
+ kept.push(item);
8303
9422
  }
8304
- return hasReplayableAssistantOutput ? sanitized : void 0;
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
- function sanitizeOpenAIResponsesHistoryItemForReplay(item, supportsImageDetailOriginal, preserveReasoningItemIds) {
8334
- if (item.type === "function_call") {
8335
- if (typeof item.arguments !== "string" || item.arguments.trim().length === 0) return void 0;
8336
- try {
8337
- JSON.parse(item.arguments);
8338
- } catch {
8339
- return;
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 { toolWireSchema as A, spillToDescription as B, kStreamingLastParseLen as C, FencedThinkingScanner as D, createInbandScanner as E, normalizeSchemaForMoonshot as F, getBundledModelReferenceIndex as H, sanitizeSchemaForCursor as I, sanitizeSchemaForGrammar as L, adaptSchemaForStrict as M, normalizeSchemaForCCA as N, partialSuffixOverlapAny as O, normalizeSchemaForGoogle as P, sanitizeSchemaForOllama as R, kStreamingEnvelopeId as S, renderDemotedThinking as T, stringifyJson$1 as U, COMBINATOR_KEYS as V, tryParseJson as W, isDemotedThinking as _, normalizeResponsesToolCallId as a, kStreamingBlockIndex as b, resolveCacheRetention as c, sanitizeOpenAIResponsesHistoryItemsForReplay as d, stripOpenAIResponsesComputerLinkedReasoningIdsForReplay as f, clearStreamingPartialJson as g, transformMessages as h, getOpenAIResponsesHistoryPayload as i, NO_STRICT as j, flattenExclusiveRequiredRootUnion as k, sanitizeOpenAIResponsesAssistantFallbackItemsForReplay as l, redactSensitiveInObject as m, getHeaderCaseInsensitive as n, normalizeSystemPrompts as o, stripUnpairedOpenAIResponsesComputerReasoningIdsForReplay as p, getOpenAIResponsesHistoryItems as r, normalizeToolCallId as s, createOpenAIResponsesHistoryPayload as t, sanitizeOpenAIResponsesAssistantHistoryItemsForReplay as u, kCursorExecResolved as v, kStreamingPartialJson as w, kStreamingBlockKind as x, kStreamingArgumentsDone as y, sanitizeSchemaForOpenAIResponses as z };
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 };