zidane 5.14.4 → 6.0.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 (202) hide show
  1. package/dist/{acp-24uU2WDs.js → acp-Irby04Us.js} +7 -8
  2. package/dist/{acp-24uU2WDs.js.map → acp-Irby04Us.js.map} +1 -1
  3. package/dist/acp-cli.js +7 -7
  4. package/dist/acp.d.ts +2 -3
  5. package/dist/acp.d.ts.map +1 -1
  6. package/dist/acp.js +1 -1
  7. package/dist/{agent-Cch2ayTt.js → agent-DkSmGkDM.js} +10871 -5411
  8. package/dist/agent-DkSmGkDM.js.map +1 -0
  9. package/dist/agent.d.ts +1 -2
  10. package/dist/agent.js +2 -2
  11. package/dist/{anthropic-RGqsJlC8.js → anthropic-CTHsdFG9.js} +46 -6
  12. package/dist/anthropic-CTHsdFG9.js.map +1 -0
  13. package/dist/{auth-C-ms5N2x.js → auth-BDSu_0t3.js} +13 -86
  14. package/dist/auth-BDSu_0t3.js.map +1 -0
  15. package/dist/chat/pure.d.ts +4 -4
  16. package/dist/chat/pure.js +4 -3
  17. package/dist/chat.d.ts +45 -8
  18. package/dist/chat.d.ts.map +1 -1
  19. package/dist/chat.js +9 -6
  20. package/dist/chat.js.map +1 -1
  21. package/dist/completion-core-CXYSVhZo.js +147 -0
  22. package/dist/completion-core-CXYSVhZo.js.map +1 -0
  23. package/dist/{context-breakdown-kO-pDsay.js → context-breakdown-Dzo25N45.js} +2 -23
  24. package/dist/context-breakdown-Dzo25N45.js.map +1 -0
  25. package/dist/contexts/daytona.d.ts +3 -3
  26. package/dist/contexts/daytona.js +1 -1
  27. package/dist/contexts/docker.d.ts +10 -2
  28. package/dist/contexts/docker.d.ts.map +1 -1
  29. package/dist/contexts/docker.js +142 -103
  30. package/dist/contexts/docker.js.map +1 -1
  31. package/dist/contexts/e2b.d.ts +2 -2
  32. package/dist/contexts/e2b.js +1 -1
  33. package/dist/contexts/sandbox.d.ts +1 -1
  34. package/dist/contexts/sandbox.js +4 -1
  35. package/dist/contexts/sandbox.js.map +1 -1
  36. package/dist/{contexts-Lzf5huID.js → contexts-Vone3qQQ.js} +26 -37
  37. package/dist/contexts-Vone3qQQ.js.map +1 -0
  38. package/dist/contexts.d.ts +3 -3
  39. package/dist/contexts.js +1 -1
  40. package/dist/errors.d.ts +1 -2
  41. package/dist/errors.js +1 -1
  42. package/dist/eval.d.ts +1 -1
  43. package/dist/eval.js +3 -3
  44. package/dist/exec-file-size-PXkr-MGA.js +63 -0
  45. package/dist/exec-file-size-PXkr-MGA.js.map +1 -0
  46. package/dist/extensions.d.ts +2 -0
  47. package/dist/extensions.js +2 -0
  48. package/dist/generate-data-WL_yGVL6.js +324 -0
  49. package/dist/generate-data-WL_yGVL6.js.map +1 -0
  50. package/dist/headless.d.ts +1 -1
  51. package/dist/headless.js +15 -10
  52. package/dist/headless.js.map +1 -1
  53. package/dist/index-B8UtiZy7.d.ts +14967 -0
  54. package/dist/index-B8UtiZy7.d.ts.map +1 -0
  55. package/dist/{index-B3ciFUZx.d.ts → index-DsPQbyUn.d.ts} +2 -2
  56. package/dist/index-DsPQbyUn.d.ts.map +1 -0
  57. package/dist/index.d.ts +6 -12
  58. package/dist/index.js +20 -43
  59. package/dist/index.js.map +1 -1
  60. package/dist/{logger-Ktm-lj1s.js → logger-DBX9uYOw.js} +108 -5
  61. package/dist/logger-DBX9uYOw.js.map +1 -0
  62. package/dist/login-DOF8pMVM.js +539 -0
  63. package/dist/login-DOF8pMVM.js.map +1 -0
  64. package/dist/{mcp-Dn5W65Lv.js → mcp-CcvuVXB9.js} +2 -2
  65. package/dist/{mcp-Dn5W65Lv.js.map → mcp-CcvuVXB9.js.map} +1 -1
  66. package/dist/mcp.d.ts +1 -1
  67. package/dist/mcp.js +1 -1
  68. package/dist/{messages-YZQLKaz2.js → messages-CwujiS74.js} +4 -4
  69. package/dist/messages-CwujiS74.js.map +1 -0
  70. package/dist/{openai-compat-0Y7jcncn.js → openai-compat-BvgYGSR1.js} +7 -6
  71. package/dist/{openai-compat-0Y7jcncn.js.map → openai-compat-BvgYGSR1.js.map} +1 -1
  72. package/dist/output/stream-json.d.ts +1 -2
  73. package/dist/output/stream-json.d.ts.map +1 -1
  74. package/dist/output/terminal.d.ts +1 -2
  75. package/dist/output/terminal.d.ts.map +1 -1
  76. package/dist/{glob-DluQFSw1.js → output-cap-kBUHBlnq.js} +50 -2
  77. package/dist/output-cap-kBUHBlnq.js.map +1 -0
  78. package/dist/presets.d.ts +1 -2
  79. package/dist/presets.js +1 -1
  80. package/dist/providers/anthropic.d.ts +2 -2
  81. package/dist/providers/anthropic.js +2 -2
  82. package/dist/providers/arcee.d.ts +1 -1
  83. package/dist/providers/arcee.js +1 -1
  84. package/dist/providers/baseten.d.ts +1 -1
  85. package/dist/providers/baseten.js +1 -1
  86. package/dist/providers/cerebras.d.ts +1 -1
  87. package/dist/providers/cerebras.js +1 -1
  88. package/dist/providers/local.d.ts +1 -1
  89. package/dist/providers/local.js +1 -1
  90. package/dist/providers/openai-compat.d.ts +1 -1
  91. package/dist/providers/openai-compat.js +1 -1
  92. package/dist/providers/openai.d.ts +1 -1
  93. package/dist/providers/openai.js +4 -4
  94. package/dist/providers/openai.js.map +1 -1
  95. package/dist/providers/openrouter.d.ts +1 -1
  96. package/dist/providers/openrouter.js +1 -1
  97. package/dist/providers/xai.d.ts +1 -1
  98. package/dist/providers/xai.js +1 -1
  99. package/dist/{providers-DgmdYGKm.js → providers-z6LDMAr3.js} +3 -3
  100. package/dist/{providers-DgmdYGKm.js.map → providers-z6LDMAr3.js.map} +1 -1
  101. package/dist/providers.d.ts +1 -1
  102. package/dist/providers.js +4 -4
  103. package/dist/{read-state-BymF41Jb.js → read-state-Dq_TXUX1.js} +2 -2
  104. package/dist/{read-state-BymF41Jb.js.map → read-state-Dq_TXUX1.js.map} +1 -1
  105. package/dist/{interpolate-BtIgcCuz.js → resolve-Cr8JSL_O.js} +562 -136
  106. package/dist/resolve-Cr8JSL_O.js.map +1 -0
  107. package/dist/restate.d.ts +2 -2
  108. package/dist/restate.js +2 -2
  109. package/dist/{sandbox-Dgy-m6UF.d.ts → sandbox-CgjG2VvQ.d.ts} +2 -2
  110. package/dist/{sandbox-Dgy-m6UF.d.ts.map → sandbox-CgjG2VvQ.d.ts.map} +1 -1
  111. package/dist/session/sqlite.d.ts +1 -1
  112. package/dist/{session-CqrAFAKJ.js → session-CsdDIPY8.js} +108 -3
  113. package/dist/session-CsdDIPY8.js.map +1 -0
  114. package/dist/session.d.ts +2 -2
  115. package/dist/session.js +3 -3
  116. package/dist/skills-Bsb0rvWI.js +295 -0
  117. package/dist/skills-Bsb0rvWI.js.map +1 -0
  118. package/dist/skills.d.ts +2 -3
  119. package/dist/skills.js +3 -24
  120. package/dist/{errors-CkTvg97v.d.ts → timeout-8vSIRjzl.d.ts} +10 -2
  121. package/dist/timeout-8vSIRjzl.d.ts.map +1 -0
  122. package/dist/{timeout-kGGSXagK.js → timeout-BDetbuN6.js} +59 -2
  123. package/dist/timeout-BDetbuN6.js.map +1 -0
  124. package/dist/tool-formatters-DY0TDb1r.d.ts +378 -0
  125. package/dist/tool-formatters-DY0TDb1r.d.ts.map +1 -0
  126. package/dist/tools/fetch-url.d.ts +1 -1
  127. package/dist/tools/web-search.d.ts +1 -1
  128. package/dist/tools.d.ts +2 -3
  129. package/dist/tools.js +3 -4
  130. package/dist/{transcript-anchors-BHIgMlPq.d.ts → transcript-anchors-Cb-bDbNH.d.ts} +233 -640
  131. package/dist/transcript-anchors-Cb-bDbNH.d.ts.map +1 -0
  132. package/dist/{transcript-anchors-DsoBHg43.js → transcript-anchors-DSRPWjiH.js} +391 -961
  133. package/dist/transcript-anchors-DSRPWjiH.js.map +1 -0
  134. package/dist/tui.d.ts +335 -11
  135. package/dist/tui.d.ts.map +1 -1
  136. package/dist/tui.js +6375 -1892
  137. package/dist/tui.js.map +1 -1
  138. package/dist/{turn-operations-Dw02ZoSQ.d.ts → turn-operations-CgMROLsr.d.ts} +29 -4
  139. package/dist/turn-operations-CgMROLsr.d.ts.map +1 -0
  140. package/dist/{turn-operations-tG0vuBNc.js → turn-operations-Dq9Kx7m2.js} +321 -81
  141. package/dist/turn-operations-Dq9Kx7m2.js.map +1 -0
  142. package/dist/{types-BqdTeBaC.d.ts → types-BDccavwj.d.ts} +42 -1
  143. package/dist/types-BDccavwj.d.ts.map +1 -0
  144. package/dist/{types-CyVGdbia.js → types-BIarq1qE.js} +90 -2
  145. package/dist/types-BIarq1qE.js.map +1 -0
  146. package/dist/types.d.ts +5 -6
  147. package/dist/types.js +1 -1
  148. package/dist/{xai-tPdbAGkq.js → xai-B_e6TOA8.js} +2 -2
  149. package/dist/{xai-tPdbAGkq.js.map → xai-B_e6TOA8.js.map} +1 -1
  150. package/docs/ARCHITECTURE.md +1 -1
  151. package/docs/CHAT.md +7 -6
  152. package/docs/EXECUTION_CONTEXT.md +16 -0
  153. package/docs/EXTENSIONS.md +1063 -0
  154. package/docs/SKILL.md +16 -0
  155. package/docs/TUI.md +10 -3
  156. package/package.json +12 -3
  157. package/dist/agent-Cch2ayTt.js.map +0 -1
  158. package/dist/agent-EFWt6uQ_.d.ts +0 -6914
  159. package/dist/agent-EFWt6uQ_.d.ts.map +0 -1
  160. package/dist/anthropic-RGqsJlC8.js.map +0 -1
  161. package/dist/auth-C-ms5N2x.js.map +0 -1
  162. package/dist/context-breakdown-kO-pDsay.js.map +0 -1
  163. package/dist/contexts-Lzf5huID.js.map +0 -1
  164. package/dist/errors-CkTvg97v.d.ts.map +0 -1
  165. package/dist/glob-DluQFSw1.js.map +0 -1
  166. package/dist/glob-shell-rJMoCIGb.js +0 -21
  167. package/dist/glob-shell-rJMoCIGb.js.map +0 -1
  168. package/dist/index-B3ciFUZx.d.ts.map +0 -1
  169. package/dist/index-BtzE3Uaq.d.ts +0 -2738
  170. package/dist/index-BtzE3Uaq.d.ts.map +0 -1
  171. package/dist/index-tSzOaWNt.d.ts +0 -316
  172. package/dist/index-tSzOaWNt.d.ts.map +0 -1
  173. package/dist/interpolate-BtIgcCuz.js.map +0 -1
  174. package/dist/logger-DGiGf7DW.d.ts +0 -102
  175. package/dist/logger-DGiGf7DW.d.ts.map +0 -1
  176. package/dist/logger-Ktm-lj1s.js.map +0 -1
  177. package/dist/login-CCA-1lgK.js +0 -267
  178. package/dist/login-CCA-1lgK.js.map +0 -1
  179. package/dist/messages-YZQLKaz2.js.map +0 -1
  180. package/dist/policy-DcGlpaNs.d.ts +0 -129
  181. package/dist/policy-DcGlpaNs.d.ts.map +0 -1
  182. package/dist/presets-BQWYMHdd.js +0 -114
  183. package/dist/presets-BQWYMHdd.js.map +0 -1
  184. package/dist/run-summary-DkN8KsHM.d.ts +0 -249
  185. package/dist/run-summary-DkN8KsHM.d.ts.map +0 -1
  186. package/dist/session-CqrAFAKJ.js.map +0 -1
  187. package/dist/shell-quote-BmnhZmdM.js +0 -33
  188. package/dist/shell-quote-BmnhZmdM.js.map +0 -1
  189. package/dist/skills.js.map +0 -1
  190. package/dist/timeout-CpFm0jJ6.d.ts +0 -10
  191. package/dist/timeout-CpFm0jJ6.d.ts.map +0 -1
  192. package/dist/timeout-kGGSXagK.js.map +0 -1
  193. package/dist/tool-formatters-C6iLgc9f.d.ts +0 -1454
  194. package/dist/tool-formatters-C6iLgc9f.d.ts.map +0 -1
  195. package/dist/tools-CCd8e-HT.js +0 -1739
  196. package/dist/tools-CCd8e-HT.js.map +0 -1
  197. package/dist/transcript-anchors-BHIgMlPq.d.ts.map +0 -1
  198. package/dist/transcript-anchors-DsoBHg43.js.map +0 -1
  199. package/dist/turn-operations-Dw02ZoSQ.d.ts.map +0 -1
  200. package/dist/turn-operations-tG0vuBNc.js.map +0 -1
  201. package/dist/types-BqdTeBaC.d.ts.map +0 -1
  202. package/dist/types-CyVGdbia.js.map +0 -1
@@ -1,5 +1,4 @@
1
- import { t as Agent } from "../agent-EFWt6uQ_.js";
2
- import { Sn as HeadlessEvent, Tn as HeadlessResult, bn as FormattedHeadlessTurnEvent, wn as HeadlessOutputFormat, yn as FormattedHeadlessResult } from "../index-BtzE3Uaq.js";
1
+ import { An as HeadlessEvent, Dn as FormattedHeadlessResult, Mi as Agent, Mn as HeadlessOutputFormat, Nn as HeadlessResult, On as FormattedHeadlessTurnEvent } from "../index-B8UtiZy7.js";
3
2
 
4
3
  //#region src/output/stream-json.d.ts
5
4
  type StreamJsonOutputFormat = HeadlessOutputFormat;
@@ -1 +1 @@
1
- {"version":3,"file":"stream-json.d.ts","names":[],"sources":["../../src/output/stream-json.ts"],"mappings":";;;;KA2BY,sBAAA,GAAyB,oBAAoB;AAAA,KAC7C,mBAAA,GAAsB,OAAO,CAAC,aAAA;EAAiB,IAAA;AAAA;AAAA,UAE1C,uBAAA;EACf,MAAA,GAAS,sBAAsB;EAC/B,YAAA;AAAA;AAAA,UAGe,uBAAA,SAAgC,uBAAuB;EACtE,KAAA,IAAS,IAAA;AAAA;AAAA,iBAiBK,yBAAA,CACd,KAAA,EAAO,mBAAA,EACP,OAAA,GAAS,uBAAA,GACR,0BAAA;AAAA,iBAIa,0BAAA,CACd,KAAA,EAAO,mBAAA,EACP,OAAA,GAAS,uBAA4B;AAAA,iBAKvB,sBAAA,CACd,MAAA,EAAQ,cAAA,EACR,OAAA,GAAS,uBAAA,GACR,uBAAA;AAAA,iBAIa,uBAAA,CACd,MAAA,EAAQ,cAAA,EACR,OAAA,GAAS,uBAA4B;AAAA,iBAKvB,6BAAA,CACd,OAAA,GAAS,uBAAA,IACP,KAAA,EAAO,aAAa;AAAA,iBASR,qBAAA,CACd,KAAA,EAAO,KAAA,EACP,OAAA,GAAS,uBAA4B"}
1
+ {"version":3,"file":"stream-json.d.ts","names":[],"sources":["../../src/output/stream-json.ts"],"mappings":";;;KA2BY,sBAAA,GAAyB,oBAAoB;AAAA,KAC7C,mBAAA,GAAsB,OAAO,CAAC,aAAA;EAAiB,IAAA;AAAA;AAAA,UAE1C,uBAAA;EACf,MAAA,GAAS,sBAAsB;EAC/B,YAAA;AAAA;AAAA,UAGe,uBAAA,SAAgC,uBAAuB;EACtE,KAAA,IAAS,IAAA;AAAA;AAAA,iBAiBK,yBAAA,CACd,KAAA,EAAO,mBAAA,EACP,OAAA,GAAS,uBAAA,GACR,0BAAA;AAAA,iBAIa,0BAAA,CACd,KAAA,EAAO,mBAAA,EACP,OAAA,GAAS,uBAA4B;AAAA,iBAKvB,sBAAA,CACd,MAAA,EAAQ,cAAA,EACR,OAAA,GAAS,uBAAA,GACR,uBAAA;AAAA,iBAIa,uBAAA,CACd,MAAA,EAAQ,cAAA,EACR,OAAA,GAAS,uBAA4B;AAAA,iBAKvB,6BAAA,CACd,OAAA,GAAS,uBAAA,IACP,KAAA,EAAO,aAAa;AAAA,iBASR,qBAAA,CACd,KAAA,EAAO,KAAA,EACP,OAAA,GAAS,uBAA4B"}
@@ -1,5 +1,4 @@
1
- import { r as AgentHooks, t as Agent } from "../agent-EFWt6uQ_.js";
2
- import { t as Preset } from "../index-BtzE3Uaq.js";
1
+ import { Mi as Agent, Pi as AgentHooks, t as Preset } from "../index-B8UtiZy7.js";
3
2
 
4
3
  //#region src/output/terminal.d.ts
5
4
  interface TerminalOutputOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"terminal.d.ts","names":[],"sources":["../../src/output/terminal.ts"],"mappings":";;;;UA+CiB,qBAAA;EACf,WAAA;EACA,KAAA;EACA,WAAA;EACA,mBAAA,IAAuB,GAAA,EAAK,UAAA,CAAW,UAAA;EACvC,kBAAA,IAAsB,KAAA,EAAO,UAAA,CAAW,UAAA;AAAA;AAAA,iBAG1B,mBAAA,CAAoB,KAAA,EAAO,KAAA,EAAO,KAAA,UAAe,MAAA,UAAgB,MAAA,EAAQ,MAAM,EAAE,KAAA;;;;;;;;;iBAsB3E,mBAAA,CAAoB,KAAA,EAAO,KAAA,EAAO,KAAA,UAAe,MAAA,UAAgB,MAAA,EAAQ,MAAA,EAAQ,OAAA,GAAS,qBAAA,GAA6B,OAAA"}
1
+ {"version":3,"file":"terminal.d.ts","names":[],"sources":["../../src/output/terminal.ts"],"mappings":";;;UA+CiB,qBAAA;EACf,WAAA;EACA,KAAA;EACA,WAAA;EACA,mBAAA,IAAuB,GAAA,EAAK,UAAA,CAAW,UAAA;EACvC,kBAAA,IAAsB,KAAA,EAAO,UAAA,CAAW,UAAA;AAAA;AAAA,iBAG1B,mBAAA,CAAoB,KAAA,EAAO,KAAA,EAAO,KAAA,UAAe,MAAA,UAAgB,MAAA,EAAQ,MAAM,EAAE,KAAA;;;;;;;;;iBAsB3E,mBAAA,CAAoB,KAAA,EAAO,KAAA,EAAO,KAAA,UAAe,MAAA,UAAgB,MAAA,EAAQ,MAAA,EAAQ,OAAA,GAAS,qBAAA,GAA6B,OAAA"}
@@ -265,6 +265,54 @@ async function globFilesLocal(pattern, cwd, options) {
265
265
  return globPortable(pattern, cwd, limit, includeMetadata, signal);
266
266
  }
267
267
  //#endregion
268
- export { parseGitLsFiles as i, globLiteralPrefix as n, GIT_LS_FILES_COMMAND as r, globFilesLocal as t };
268
+ //#region src/contexts/output-cap.ts
269
+ /** Default per-stream cap shared by exec transports. */
270
+ const DEFAULT_MAX_OUTPUT_BUFFER = 10 * 1024 * 1024;
271
+ /**
272
+ * Append `chunk` to `slot` under `maxBytes`. Returns:
273
+ *
274
+ * - `'ok'` — appended in full
275
+ * - `'overflow'` — partially appended up to the cap (cut on a UTF-8
276
+ * codepoint boundary); the caller should stop the
277
+ * producer and mark the result truncated
278
+ * - `'dropped'` — slot already full, nothing appended (still
279
+ * truncation: this chunk's data is lost)
280
+ */
281
+ function appendCapped(slot, chunk, maxBytes) {
282
+ if (slot.bytes >= maxBytes) return "dropped";
283
+ const room = maxBytes - slot.bytes;
284
+ if (chunk.length <= room) {
285
+ slot.text += chunk.toString("utf8");
286
+ slot.bytes += chunk.length;
287
+ return "ok";
288
+ }
289
+ let end = room;
290
+ while (end > 0 && (chunk[end] & 192) === 128) end--;
291
+ const piece = chunk.subarray(0, end);
292
+ slot.text += piece.toString("utf8");
293
+ slot.bytes += piece.length;
294
+ return "overflow";
295
+ }
296
+ /**
297
+ * The overflow message contract shared by every capped exec transport
298
+ * and by the tool-side consumers that must recognize it (`read_file` /
299
+ * `edit` surface transport overflows honestly instead of "File not
300
+ * found"). Producers MUST build the message through
301
+ * {@link outputExceededMessage} and consumers MUST detect it through
302
+ * {@link isOutputExceededMessage} — a reworded literal on either side
303
+ * would silently break the recognition and regress the misleading
304
+ * errors this contract exists to prevent.
305
+ */
306
+ const OUTPUT_EXCEEDED_MARKER = "output exceeded";
307
+ /** Build a transport overflow message. `detail` describes the transport's reaction. */
308
+ function outputExceededMessage(maxBytes, detail) {
309
+ return `${OUTPUT_EXCEEDED_MARKER} ${maxBytes}-byte buffer; ${detail}`;
310
+ }
311
+ /** Recognize a transport overflow in an error/stderr string. */
312
+ function isOutputExceededMessage(message) {
313
+ return message.includes(OUTPUT_EXCEEDED_MARKER);
314
+ }
315
+ //#endregion
316
+ export { globFilesLocal as a, parseGitLsFiles as c, outputExceededMessage as i, appendCapped as n, globLiteralPrefix as o, isOutputExceededMessage as r, GIT_LS_FILES_COMMAND as s, DEFAULT_MAX_OUTPUT_BUFFER as t };
269
317
 
270
- //# sourceMappingURL=glob-DluQFSw1.js.map
318
+ //# sourceMappingURL=output-cap-kBUHBlnq.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output-cap-kBUHBlnq.js","names":[],"sources":["../src/contexts/git-ls-files.ts","../src/contexts/git-ls-files-local.ts","../src/contexts/glob.ts","../src/contexts/output-cap.ts"],"sourcesContent":["/**\n * Pure (node-free) `git ls-files` helpers shared by the gitignore-aware paths\n * of the `glob` and `grep` tools.\n *\n * `git ls-files --cached --others --exclude-standard` lists tracked files plus\n * untracked-but-not-ignored files, applying `.gitignore`, `.git/info/exclude`,\n * and the user's global excludes. Git never descends ignored directories\n * (`node_modules`, build output, …), so this is both correct and sub-second on\n * large repos — unlike a raw filesystem walk.\n *\n * This module has ZERO node imports so it can be pulled into edge/workerd\n * bundles (e.g. via the `grep` tool, which drives git through the execution\n * context's `exec` seam). The node-spawn variant lives in\n * `./git-ls-files-local`.\n */\n\n/** Argv for `git ls-files`, NUL-delimited so paths with newlines stay intact. */\nexport const GIT_LS_FILES_ARGS = ['ls-files', '--cached', '--others', '--exclude-standard', '-z'] as const\n\n/** The same invocation as a shell command string for the `exec` seam. */\nexport const GIT_LS_FILES_COMMAND = `git ${GIT_LS_FILES_ARGS.join(' ')}`\n\n/** Split NUL-delimited `git ls-files -z` output into paths. */\nexport function parseGitLsFiles(stdout: string): string[] {\n return stdout.split('\\0').filter(p => p.length > 0)\n}\n","/**\n * Node-spawn `git ls-files` runner used by the local process context's glob.\n *\n * Kept separate from `./git-ls-files` (which stays node-free for edge bundles)\n * because this leg imports `node:child_process`.\n */\n\nimport { spawn } from 'node:child_process'\nimport { GIT_LS_FILES_ARGS, parseGitLsFiles } from './git-ls-files'\n\n/**\n * Run `git ls-files` in `cwd` and return its non-ignored paths (relative to\n * `cwd`). Returns `null` when the directory is not a git repo, git is missing,\n * or the call aborts — callers treat `null` as \"fall back to a filesystem\n * walk\". Never throws.\n */\nexport async function gitListFilesLocal(cwd: string, signal?: AbortSignal): Promise<string[] | null> {\n return new Promise<string[] | null>((resolveP) => {\n let child: ReturnType<typeof spawn>\n try {\n child = spawn('git', [...GIT_LS_FILES_ARGS], { cwd, stdio: ['ignore', 'pipe', 'pipe'] })\n }\n catch {\n resolveP(null)\n return\n }\n if (signal?.aborted) {\n child.kill('SIGTERM')\n resolveP(null)\n return\n }\n const stdoutChunks: string[] = []\n const onAbort = () => child.kill('SIGTERM')\n signal?.addEventListener('abort', onAbort, { once: true })\n child.stdout?.setEncoding('utf8')\n child.stdout?.on('data', chunk => stdoutChunks.push(chunk as string))\n child.on('error', () => {\n signal?.removeEventListener('abort', onAbort)\n resolveP(null)\n })\n child.on('close', (code) => {\n signal?.removeEventListener('abort', onAbort)\n if (code !== 0 || signal?.aborted) {\n resolveP(null)\n return\n }\n resolveP(parseGitLsFiles(stdoutChunks.join('')))\n })\n })\n}\n","import type { ListFileMetadata } from './types'\nimport { readdir, stat } from 'node:fs/promises'\nimport { dirname, resolve, sep } from 'node:path'\nimport { lazyAsync } from '../lazy'\nimport { gitListFilesLocal } from './git-ls-files-local'\n\ntype NodeGlob = (pattern: string, options: { cwd: string }) => AsyncIterable<string>\n\ninterface BunGlobInstance { scan: (options: { cwd: string, onlyFiles?: boolean, dot?: boolean }) => AsyncIterable<string> }\ntype BunGlobCtor = new (pattern: string) => BunGlobInstance\n\nconst loadNativeNodeGlob = lazyAsync(async (): Promise<NodeGlob | undefined> => {\n const candidate = (await import('node:fs/promises') as { glob?: unknown }).glob\n return typeof candidate === 'function' ? candidate as NodeGlob : undefined\n})\n\nfunction forcePortable(): boolean {\n return (globalThis as { __zidaneForcePortableGlobForTests?: boolean }).__zidaneForcePortableGlobForTests === true\n}\n\nasync function loadNodeGlob(): Promise<NodeGlob | undefined> {\n if (forcePortable())\n return undefined\n return loadNativeNodeGlob()\n}\n\n/**\n * Bun's `node:fs/promises.glob` buffers the entire directory walk before\n * yielding (so an early `limit` break never fires — a broad `**` pattern over\n * a large `node_modules` hangs). `Bun.Glob().scan()` streams incrementally and\n * is the fast path under Bun. Returns undefined off Bun or when tests force the\n * portable walker.\n */\nfunction loadBunGlob(): BunGlobCtor | undefined {\n if (forcePortable())\n return undefined\n const bun = (globalThis as { Bun?: { Glob?: unknown } }).Bun\n return bun && typeof bun.Glob === 'function' ? bun.Glob as BunGlobCtor : undefined\n}\n\nfunction escapeRegexChar(char: string): string {\n return /[\\\\^$.*+?()[\\]{}|]/.test(char) ? `\\\\${char}` : char\n}\n\nexport function expandBraces(pattern: string): string[] {\n const start = pattern.indexOf('{')\n if (start === -1)\n return [pattern]\n const end = pattern.indexOf('}', start + 1)\n if (end === -1)\n return [pattern]\n const body = pattern.slice(start + 1, end)\n if (!body || !body.includes(','))\n return [pattern]\n return body\n .split(',')\n .flatMap(part => expandBraces(`${pattern.slice(0, start)}${part}${pattern.slice(end + 1)}`))\n}\n\nexport function globPatternToRegex(pattern: string): RegExp {\n let out = '^'\n for (let i = 0; i < pattern.length; i++) {\n const char = pattern[i]\n const next = pattern[i + 1]\n if (char === '*') {\n if (next === '*') {\n const after = pattern[i + 2]\n if (after === '/') {\n out += '(?:[^/]+/)*'\n i += 2\n }\n else {\n out += '.*'\n i += 1\n }\n }\n else {\n out += '[^/]*'\n }\n }\n else if (char === '?') {\n out += '[^/]'\n }\n else if (char === '[') {\n const end = pattern.indexOf(']', i + 1)\n if (end === -1) {\n out += '\\\\['\n }\n else {\n let cls = pattern.slice(i + 1, end)\n if (cls.startsWith('!'))\n cls = `^${cls.slice(1)}`\n out += `[${cls}]`\n i = end\n }\n }\n else {\n out += escapeRegexChar(char)\n }\n }\n return new RegExp(`${out}$`)\n}\n\nexport function globLiteralPrefix(pattern: string): string {\n const firstMeta = pattern.search(/[*?[\\]{}]/)\n const prefix = firstMeta === -1 ? dirname(pattern) : pattern.slice(0, firstMeta)\n const slash = prefix.lastIndexOf('/')\n if (slash === -1)\n return ''\n return prefix.slice(0, slash)\n}\n\nexport function hasGlobPattern(path: string): boolean {\n return /[*?[\\]{}]/.test(path)\n}\n\n/**\n * True when a pattern can match files outside `cwd` — an absolute path, a\n * Windows drive, or any `..` segment. Such patterns can't use the `git\n * ls-files` path (git only knows files under the repo) and fall back to the\n * filesystem walk.\n */\nfunction patternEscapesCwd(pattern: string): boolean {\n const norm = pattern.split(sep).join('/')\n if (norm.startsWith('/') || /^[a-z]:/i.test(norm))\n return true\n return norm.split('/').includes('..')\n}\n\nasync function addMetadata(cwd: string, rel: string, includeMetadata: boolean): Promise<ListFileMetadata | null> {\n try {\n const s = await stat(resolve(cwd, rel))\n if (!s.isFile())\n return null\n return includeMetadata ? { path: rel, size: s.size, mtimeMs: s.mtimeMs } : { path: rel }\n }\n catch {\n return null\n }\n}\n\nfunction compilePattern(pattern: string): RegExp[] {\n return expandBraces(pattern.split(sep).join('/')).map(globPatternToRegex)\n}\n\n/** Match the (already non-ignored) `git ls-files` set against the glob pattern. */\nasync function matchGitFiles(\n gitFiles: readonly string[],\n pattern: string,\n cwd: string,\n limit: number,\n includeMetadata: boolean,\n signal: AbortSignal | undefined,\n): Promise<ListFileMetadata[]> {\n const regexes = compilePattern(pattern)\n const out: ListFileMetadata[] = []\n for (const rel of gitFiles) {\n if (signal?.aborted || out.length >= limit)\n break\n if (!regexes.some(regex => regex.test(rel)))\n continue\n out.push(includeMetadata ? await addMetadata(cwd, rel, true) ?? { path: rel } : { path: rel })\n }\n return out.sort((a, b) => a.path.localeCompare(b.path))\n}\n\n/** Depth-first walk that matches against `regexes` and stops at `limit`. */\nasync function walkMatch(\n root: string,\n prefix: string,\n regexes: RegExp[],\n cwd: string,\n limit: number,\n includeMetadata: boolean,\n signal: AbortSignal | undefined,\n out: ListFileMetadata[],\n): Promise<void> {\n if (out.length >= limit || signal?.aborted)\n return\n let entries: Array<{ name: string, isDirectory: () => boolean, isFile: () => boolean }>\n try {\n entries = await readdir(resolve(root, prefix), { encoding: 'utf8', withFileTypes: true })\n }\n catch {\n return\n }\n for (const entry of entries) {\n if (out.length >= limit || signal?.aborted)\n return\n const rel = prefix ? `${prefix}/${entry.name}` : entry.name\n if (entry.isDirectory()) {\n await walkMatch(root, rel, regexes, cwd, limit, includeMetadata, signal, out)\n }\n else if (entry.isFile() && regexes.some(regex => regex.test(rel))) {\n out.push(includeMetadata ? await addMetadata(cwd, rel, true) ?? { path: rel } : { path: rel })\n }\n }\n}\n\nasync function globPortable(\n pattern: string,\n cwd: string,\n limit: number,\n includeMetadata: boolean,\n signal: AbortSignal | undefined,\n): Promise<ListFileMetadata[]> {\n const normalized = pattern.split(sep).join('/')\n const startPrefix = globLiteralPrefix(normalized)\n const regexes = expandBraces(normalized).map(globPatternToRegex)\n const out: ListFileMetadata[] = []\n await walkMatch(cwd, startPrefix, regexes, cwd, limit, includeMetadata, signal, out)\n return out.sort((a, b) => a.path.localeCompare(b.path))\n}\n\nasync function collectFromIterable(\n iter: AsyncIterable<string>,\n cwd: string,\n limit: number,\n includeMetadata: boolean,\n signal: AbortSignal | undefined,\n): Promise<ListFileMetadata[] | null> {\n const results: ListFileMetadata[] = []\n // A native scan can throw mid-iteration on a pathological tree (e.g. a\n // recursive symlink cycle → ENAMETOOLONG) and there's no way to resume it.\n // Signal the caller (null) to recover via the portable walk, which recurses\n // only into real directories and isolates per-directory errors.\n try {\n for await (const rel of iter) {\n if (signal?.aborted)\n break\n const entry = await addMetadata(cwd, rel, includeMetadata)\n if (!entry)\n continue\n results.push(entry)\n if (results.length >= limit)\n break\n }\n }\n catch {\n return null\n }\n return results.sort((a, b) => a.path.localeCompare(b.path))\n}\n\nfunction globViaBun(\n BunGlob: BunGlobCtor,\n pattern: string,\n cwd: string,\n limit: number,\n includeMetadata: boolean,\n signal: AbortSignal | undefined,\n): Promise<ListFileMetadata[] | null> {\n // `dot: true` keeps dotfile matching consistent with the Node + portable\n // paths; `onlyFiles: true` mirrors their file-only results.\n const scan = new BunGlob(pattern).scan({ cwd, onlyFiles: true, dot: true })\n return collectFromIterable(scan, cwd, limit, includeMetadata, signal)\n}\n\nexport async function globFilesLocal(\n pattern: string,\n cwd: string,\n options: { limit: number, metadata?: boolean, gitignore?: boolean, signal?: AbortSignal },\n): Promise<ListFileMetadata[]> {\n const includeMetadata = options.metadata === true\n const { limit, signal } = options\n\n // Default path: intersect the pattern with git's non-ignored file set. Git\n // skips `.gitignore`d trees (`node_modules`, build dirs) entirely, so this is\n // both correct and fast — and never triggers the Bun `fs.glob` hang. The\n // test-only force-portable flag also bypasses it so the filesystem walker\n // stays directly exercisable.\n if (options.gitignore !== false && !forcePortable() && !patternEscapesCwd(pattern)) {\n const gitFiles = await gitListFilesLocal(cwd, signal)\n if (gitFiles)\n return matchGitFiles(gitFiles, pattern, cwd, limit, includeMetadata, signal)\n }\n\n // Fallback path: filesystem glob (gitignore disabled, not a git repo, or the\n // pattern escapes cwd). Prefer a fast native scanner; if it throws on a\n // pathological tree (null), recover via the portable walk.\n const bunGlob = loadBunGlob()\n if (bunGlob) {\n const viaBun = await globViaBun(bunGlob, pattern, cwd, limit, includeMetadata, signal)\n if (viaBun)\n return viaBun\n }\n else {\n const nodeGlob = await loadNodeGlob()\n if (nodeGlob) {\n const viaNode = await collectFromIterable(nodeGlob(pattern, { cwd }), cwd, limit, includeMetadata, signal)\n if (viaNode)\n return viaNode\n }\n }\n\n return globPortable(pattern, cwd, limit, includeMetadata, signal)\n}\n\n// `globFilesViaShell` moved to `./glob-shell` (node-free) so remote-only\n// contexts can import it without pulling this module's `node:fs` imports.\n// Re-exported here for back-compat.\nexport { globFilesViaShell } from './glob-shell'\n","/**\n * Byte-capped output accumulation — the shared primitive behind every\n * exec transport's stdout/stderr buffering. A context that buffers\n * command output in host memory MUST bound it: an uncapped `cat` of a\n * multi-GB file (directly, or via a `readFile`-through-exec\n * implementation like docker's) OOMs the HOST process regardless of any\n * limits inside the container/sandbox.\n *\n * The math lives here so process + docker (and future transports) share\n * one definition of \"capped\": byte accounting (not UTF-16 `.length`,\n * which undercounts multi-byte UTF-8) and codepoint-boundary cuts (a\n * blind byte slice can split a UTF-8 sequence and corrupt the tail).\n * Overflow ORCHESTRATION stays with each transport — process kills the\n * child's process group, docker destroys the stream and lets the\n * server-side `timeout` wrapper reap the command.\n */\n\nimport type { Buffer } from 'node:buffer'\n\n/** Default per-stream cap shared by exec transports. */\nexport const DEFAULT_MAX_OUTPUT_BUFFER = 10 * 1024 * 1024\n\nexport interface CappedSlot {\n text: string\n bytes: number\n}\n\n/**\n * Append `chunk` to `slot` under `maxBytes`. Returns:\n *\n * - `'ok'` — appended in full\n * - `'overflow'` — partially appended up to the cap (cut on a UTF-8\n * codepoint boundary); the caller should stop the\n * producer and mark the result truncated\n * - `'dropped'` — slot already full, nothing appended (still\n * truncation: this chunk's data is lost)\n */\nexport function appendCapped(slot: CappedSlot, chunk: Buffer, maxBytes: number): 'ok' | 'overflow' | 'dropped' {\n if (slot.bytes >= maxBytes)\n return 'dropped'\n const room = maxBytes - slot.bytes\n if (chunk.length <= room) {\n slot.text += chunk.toString('utf8')\n slot.bytes += chunk.length\n return 'ok'\n }\n // Cut on a UTF-8 codepoint boundary: if the byte right after the cut is\n // a continuation byte (0b10xxxxxx), back off until it isn't.\n let end = room\n while (end > 0 && ((chunk[end] as number) & 0xC0) === 0x80)\n end--\n const piece = chunk.subarray(0, end)\n slot.text += piece.toString('utf8')\n slot.bytes += piece.length\n return 'overflow'\n}\n\n/**\n * The overflow message contract shared by every capped exec transport\n * and by the tool-side consumers that must recognize it (`read_file` /\n * `edit` surface transport overflows honestly instead of \"File not\n * found\"). Producers MUST build the message through\n * {@link outputExceededMessage} and consumers MUST detect it through\n * {@link isOutputExceededMessage} — a reworded literal on either side\n * would silently break the recognition and regress the misleading\n * errors this contract exists to prevent.\n */\nconst OUTPUT_EXCEEDED_MARKER = 'output exceeded'\n\n/** Build a transport overflow message. `detail` describes the transport's reaction. */\nexport function outputExceededMessage(maxBytes: number, detail: string): string {\n return `${OUTPUT_EXCEEDED_MARKER} ${maxBytes}-byte buffer; ${detail}`\n}\n\n/** Recognize a transport overflow in an error/stderr string. */\nexport function isOutputExceededMessage(message: string): boolean {\n return message.includes(OUTPUT_EXCEEDED_MARKER)\n}\n"],"mappings":"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"}
package/dist/presets.d.ts CHANGED
@@ -1,3 +1,2 @@
1
- import { n as AgentHookMap } from "./agent-EFWt6uQ_.js";
2
- import { a as basicTools, i as _default, n as composePresets, r as definePreset, t as Preset } from "./index-BtzE3Uaq.js";
1
+ import { Ni as AgentHookMap, a as basicTools, i as _default, n as composePresets, r as definePreset, t as Preset } from "./index-B8UtiZy7.js";
3
2
  export { type AgentHookMap, Preset, _default as basic, basicTools, composePresets, definePreset };
package/dist/presets.js CHANGED
@@ -1,2 +1,2 @@
1
- import { i as basic_default, n as definePreset, r as basicTools, t as composePresets } from "./presets-BQWYMHdd.js";
1
+ import { at as definePreset, it as composePresets, ot as basicTools, st as basic_default } from "./agent-DkSmGkDM.js";
2
2
  export { basic_default as basic, basicTools, composePresets, definePreset };
@@ -1,2 +1,2 @@
1
- import { An as planAnthropicThinking, Dn as anthropic, En as AnthropicThinkingPlan, On as applyAnthropicCacheBreakpoints, Tn as AnthropicParams, jn as resolveAnthropicBetas, kn as classifyAnthropicError, wn as AnthropicContextManagement } from "../agent-EFWt6uQ_.js";
2
- export { AnthropicContextManagement, AnthropicParams, AnthropicThinkingPlan, anthropic, applyAnthropicCacheBreakpoints, classifyAnthropicError, planAnthropicThinking, resolveAnthropicBetas };
1
+ import { Sm as resolveAnthropicMaxOutput, _m as applyAnthropicCacheBreakpoints, bm as planAnthropicThinking, gm as anthropic, hm as AnthropicThinkingPlan, mm as AnthropicParams, pm as AnthropicContextManagement, vm as classifyAnthropicError, xm as resolveAnthropicBetas, ym as defaultAnthropicMaxTokens } from "../index-B8UtiZy7.js";
2
+ export { AnthropicContextManagement, AnthropicParams, AnthropicThinkingPlan, anthropic, applyAnthropicCacheBreakpoints, classifyAnthropicError, defaultAnthropicMaxTokens, planAnthropicThinking, resolveAnthropicBetas, resolveAnthropicMaxOutput };
@@ -1,2 +1,2 @@
1
- import { a as resolveAnthropicBetas, i as planAnthropicThinking, n as applyAnthropicCacheBreakpoints, r as classifyAnthropicError, t as anthropic } from "../anthropic-RGqsJlC8.js";
2
- export { anthropic, applyAnthropicCacheBreakpoints, classifyAnthropicError, planAnthropicThinking, resolveAnthropicBetas };
1
+ import { a as planAnthropicThinking, i as defaultAnthropicMaxTokens, n as applyAnthropicCacheBreakpoints, o as resolveAnthropicBetas, r as classifyAnthropicError, s as resolveAnthropicMaxOutput, t as anthropic } from "../anthropic-CTHsdFG9.js";
2
+ export { anthropic, applyAnthropicCacheBreakpoints, classifyAnthropicError, defaultAnthropicMaxTokens, planAnthropicThinking, resolveAnthropicBetas, resolveAnthropicMaxOutput };
@@ -1,2 +1,2 @@
1
- import { Cn as arcee, Sn as ArceeParams } from "../agent-EFWt6uQ_.js";
1
+ import { dm as ArceeParams, fm as arcee } from "../index-B8UtiZy7.js";
2
2
  export { ArceeParams, arcee };
@@ -1,4 +1,4 @@
1
- import { m as openaiCompat } from "../openai-compat-0Y7jcncn.js";
1
+ import { m as openaiCompat } from "../openai-compat-BvgYGSR1.js";
2
2
  //#region src/providers/arcee.ts
3
3
  const BASE_URL = "https://api.arcee.ai/api/v1";
4
4
  function getApiKey(params) {
@@ -1,2 +1,2 @@
1
- import { bn as baseten, xn as planBasetenReasoning, yn as BasetenParams } from "../agent-EFWt6uQ_.js";
1
+ import { cm as BasetenParams, lm as baseten, um as planBasetenReasoning } from "../index-B8UtiZy7.js";
2
2
  export { BasetenParams, baseten, planBasetenReasoning };
@@ -1,4 +1,4 @@
1
- import { m as openaiCompat } from "../openai-compat-0Y7jcncn.js";
1
+ import { m as openaiCompat } from "../openai-compat-BvgYGSR1.js";
2
2
  //#region src/providers/baseten.ts
3
3
  const BASE_URL = "https://inference.baseten.co/v1";
4
4
  /**
@@ -1,2 +1,2 @@
1
- import { _n as CerebrasParams, vn as cerebras } from "../agent-EFWt6uQ_.js";
1
+ import { om as CerebrasParams, sm as cerebras } from "../index-B8UtiZy7.js";
2
2
  export { CerebrasParams, cerebras };
@@ -1,4 +1,4 @@
1
- import { m as openaiCompat } from "../openai-compat-0Y7jcncn.js";
1
+ import { m as openaiCompat } from "../openai-compat-BvgYGSR1.js";
2
2
  //#region src/providers/cerebras.ts
3
3
  const BASE_URL = "https://api.cerebras.ai/v1";
4
4
  function getApiKey(params) {
@@ -1,2 +1,2 @@
1
- import { mn as local, pn as LocalParams } from "../agent-EFWt6uQ_.js";
1
+ import { nm as LocalParams, rm as local } from "../index-B8UtiZy7.js";
2
2
  export { LocalParams, local };
@@ -1,4 +1,4 @@
1
- import { m as openaiCompat } from "../openai-compat-0Y7jcncn.js";
1
+ import { m as openaiCompat } from "../openai-compat-BvgYGSR1.js";
2
2
  //#region src/providers/local.ts
3
3
  function getBaseURL(params) {
4
4
  if (typeof params?.baseURL === "string" && params.baseURL.length > 0) return params.baseURL;
@@ -1,2 +1,2 @@
1
- import { $t as classifyOpenAICompatError, Gt as OpenAICompatHttpError, Ht as OAIMessage, Jt as TOOL_RESULTS_TAG, Kt as OpenAICompatParams, Qt as buildAssistantContent, Ut as OAITool, Vt as ASSISTANT_TOOL_CALLS_TAG, Wt as OpenAICompatAuthHeader, Xt as applyOAIToolCacheBreakpoint, Yt as applyOAICacheBreakpoints, Zt as assistantMessage, an as toOAIMessages, en as consumeSSE, in as openaiCompat, nn as mapOAIFinishReason, on as toolResultsMessage, qt as OpenAICompatStreamError, rn as openAICompatPromptMessage, sn as userMessage, tn as formatTools } from "../agent-EFWt6uQ_.js";
1
+ import { Ap as ASSISTANT_TOOL_CALLS_TAG, Bp as assistantMessage, Fp as OpenAICompatParams, Gp as mapOAIFinishReason, Hp as classifyOpenAICompatError, Ip as OpenAICompatStreamError, Jp as toOAIMessages, Kp as openAICompatPromptMessage, Lp as TOOL_RESULTS_TAG, Mp as OAITool, Np as OpenAICompatAuthHeader, Pp as OpenAICompatHttpError, Rp as applyOAICacheBreakpoints, Up as consumeSSE, Vp as buildAssistantContent, Wp as formatTools, Xp as userMessage, Yp as toolResultsMessage, jp as OAIMessage, qp as openaiCompat, zp as applyOAIToolCacheBreakpoint } from "../index-B8UtiZy7.js";
2
2
  export { ASSISTANT_TOOL_CALLS_TAG, OAIMessage, OAITool, OpenAICompatAuthHeader, OpenAICompatHttpError, OpenAICompatParams, OpenAICompatStreamError, TOOL_RESULTS_TAG, applyOAICacheBreakpoints, applyOAIToolCacheBreakpoint, assistantMessage, buildAssistantContent, classifyOpenAICompatError, consumeSSE, formatTools, mapOAIFinishReason, openAICompatPromptMessage, openaiCompat, toOAIMessages, toolResultsMessage, userMessage };
@@ -1,2 +1,2 @@
1
- import { _ as userMessage, a as applyOAICacheBreakpoints, c as buildAssistantContent, d as formatTools, f as mapOAIFinishReason, g as toolResultsMessage, h as toOAIMessages, i as TOOL_RESULTS_TAG, l as classifyOpenAICompatError, m as openaiCompat, n as OpenAICompatHttpError, o as applyOAIToolCacheBreakpoint, p as openAICompatPromptMessage, r as OpenAICompatStreamError, s as assistantMessage, t as ASSISTANT_TOOL_CALLS_TAG, u as consumeSSE } from "../openai-compat-0Y7jcncn.js";
1
+ import { _ as userMessage, a as applyOAICacheBreakpoints, c as buildAssistantContent, d as formatTools, f as mapOAIFinishReason, g as toolResultsMessage, h as toOAIMessages, i as TOOL_RESULTS_TAG, l as classifyOpenAICompatError, m as openaiCompat, n as OpenAICompatHttpError, o as applyOAIToolCacheBreakpoint, p as openAICompatPromptMessage, r as OpenAICompatStreamError, s as assistantMessage, t as ASSISTANT_TOOL_CALLS_TAG, u as consumeSSE } from "../openai-compat-BvgYGSR1.js";
2
2
  export { ASSISTANT_TOOL_CALLS_TAG, OpenAICompatHttpError, OpenAICompatStreamError, TOOL_RESULTS_TAG, applyOAICacheBreakpoints, applyOAIToolCacheBreakpoint, assistantMessage, buildAssistantContent, classifyOpenAICompatError, consumeSSE, formatTools, mapOAIFinishReason, openAICompatPromptMessage, openaiCompat, toOAIMessages, toolResultsMessage, userMessage };
@@ -1,2 +1,2 @@
1
- import { cn as OpenAIParams, dn as openai, fn as toPiMessages, ln as classifyOpenAIError, un as mapCodexStopReason } from "../agent-EFWt6uQ_.js";
1
+ import { $p as mapCodexStopReason, Qp as classifyOpenAIError, Zp as OpenAIParams, em as openai, tm as toPiMessages } from "../index-B8UtiZy7.js";
2
2
  export { OpenAIParams, classifyOpenAIError, mapCodexStopReason, openai, toPiMessages };
@@ -1,8 +1,8 @@
1
- import { i as documentBlockMarker, n as assertResolvedMediaBlock } from "../types-CyVGdbia.js";
1
+ import { i as documentBlockMarker, n as assertResolvedMediaBlock } from "../types-BIarq1qE.js";
2
2
  import { c as classifyErrorPrelude, d as isRetryableHttpStatus, f as matchesContextExceeded, p as matchesToolPairingError } from "../errors-DJUxZg9b.js";
3
- import { _ as userMessage, b as fillEstimatedCost, g as toolResultsMessage, s as assistantMessage, w as unsupportedMediaError, y as sanitizeToolSpecs } from "../openai-compat-0Y7jcncn.js";
3
+ import { _ as userMessage, b as fillEstimatedCost, g as toolResultsMessage, s as assistantMessage, w as unsupportedMediaError, y as sanitizeToolSpecs } from "../openai-compat-BvgYGSR1.js";
4
4
  import { renderSystemForWire } from "../prompt.js";
5
- import { n as SYNTHETIC_TOOL_RESULT_PLACEHOLDER } from "../messages-YZQLKaz2.js";
5
+ import { n as SYNTHETIC_TOOL_RESULT_PLACEHOLDER } from "../messages-CwujiS74.js";
6
6
  import { i as resolveOAuthApiKey, t as extractRuntimeCredentials } from "../oauth-8LqbeI_Q.js";
7
7
  import { getModel } from "@earendil-works/pi-ai";
8
8
  import { streamOpenAICodexResponses } from "@earendil-works/pi-ai/openai-codex-responses";
@@ -456,7 +456,7 @@ function openai(params) {
456
456
  const reasoningLevel = options.thinking && options.thinking !== "off" && options.thinking !== "adaptive" ? options.thinking === "max" ? "xhigh" : options.thinking : void 0;
457
457
  const stream = streamOpenAICodexResponses(model, context, {
458
458
  apiKey,
459
- maxTokens: options.maxTokens,
459
+ ...options.maxTokens !== void 0 ? { maxTokens: options.maxTokens } : {},
460
460
  signal: options.signal,
461
461
  transport: params?.transport,
462
462
  reasoningEffort: reasoningLevel,
@@ -1 +1 @@
1
- {"version":3,"file":"openai.js","names":[],"sources":["../../src/providers/openai.ts"],"sourcesContent":["import type {\n AssistantMessage as PiAssistantMessage,\n Context as PiContext,\n Message as PiMessage,\n Model as PiModel,\n Tool as PiTool,\n Usage as PiUsage,\n} from '@earendil-works/pi-ai'\nimport type { Provider, StreamCallbacks, StreamOptions, ToolSpec, TurnResult } from '.'\nimport type { ClassifiedError } from '../errors'\nimport type { SessionContentBlock, SessionMessage, ToolResultDocumentContent, TurnFinishReason, TurnUsage } from '../types'\nimport type { OAuthParams } from './oauth'\nimport { getModel } from '@earendil-works/pi-ai'\nimport { streamOpenAICodexResponses } from '@earendil-works/pi-ai/openai-codex-responses'\nimport { classifyErrorPrelude, isRetryableHttpStatus, matchesContextExceeded, matchesToolPairingError } from '../errors'\nimport { unsupportedMediaError } from '../prompt'\nimport { SYNTHETIC_TOOL_RESULT_PLACEHOLDER } from '../session/messages'\nimport { renderSystemForWire } from '../system-prompt'\nimport { assertResolvedMediaBlock, documentBlockMarker } from '../types'\nimport { fillEstimatedCost } from './cost'\nimport { extractRuntimeCredentials, resolveOAuthApiKey } from './oauth'\nimport {\n assistantMessage,\n toolResultsMessage,\n userMessage,\n} from './openai-compat'\nimport { sanitizeToolSpecs } from './schema-sanitize'\n\nconst PROVIDER_ID = 'openai-codex'\nconst DEFAULT_MODEL = 'gpt-5.5'\n\ntype CodexModel = PiModel<'openai-codex-responses'>\n\nexport interface OpenAIParams extends OAuthParams {\n accountId?: string\n defaultModel?: string\n transport?: 'sse' | 'websocket' | 'auto'\n /**\n * Extra HTTP headers merged into every request (the streaming Responses call\n * and the token-count endpoint). Use for routing/attribution headers a proxy\n * in front of the OpenAI Codex endpoint consumes. Merged with provider\n * defaults; pi-ai lets these override defaults, so avoid `authorization` /\n * `content-type` unless you intend to replace them.\n */\n extraHeaders?: Record<string, string>\n}\n\n// pi-ai's `getModel` is typed for `KnownProvider` × `keyof models[P]`;\n// we look up by free-form `modelId` (the registry holds string ids at\n// runtime) and let pi-ai's miss-throw fall through via the wider lookup.\nconst lookupModel = getModel as (provider: string, modelId: string) => CodexModel | undefined\n\nfunction resolveModel(modelId: string): CodexModel {\n const model = lookupModel(PROVIDER_ID, modelId)\n if (model)\n return model\n\n const fallback = lookupModel(PROVIDER_ID, DEFAULT_MODEL)\n if (!fallback)\n throw new Error(`OpenAI Codex model registry is missing the default model: ${DEFAULT_MODEL}`)\n\n return { ...fallback, id: modelId, name: modelId }\n}\n\nfunction emptyUsage(): PiUsage {\n return {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n totalTokens: 0,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n }\n}\n\nfunction formatTools(tools: ToolSpec[]): PiTool[] {\n // Codex's Responses API runs the same schema validator as the OpenAI\n // Chat Completions endpoint — apply the same sanitisation pass so MCP\n // tools with non-standard root shapes don't 400 here either.\n const sanitized = sanitizeToolSpecs(tools, { profile: 'openai' })\n return sanitized.map(t => ({\n name: t.name,\n description: t.description,\n parameters: t.inputSchema as PiTool['parameters'],\n }))\n}\n\nfunction documentMarker(doc: ToolResultDocumentContent): string {\n return documentBlockMarker(doc, 'document omitted')\n}\n\nfunction piToolResultMessage(\n result: Extract<SessionContentBlock, { type: 'tool_result' }>,\n toolName = '',\n): PiMessage {\n // pi-ai's ToolResultMessage natively accepts (TextContent | ImageContent)[].\n // Map zidane's canonical union directly — no flattening needed.\n const content = typeof result.output === 'string'\n ? [{ type: 'text' as const, text: result.output }]\n : result.output.map((block) => {\n if (block.type === 'image') {\n assertResolvedMediaBlock(block, 'OpenAI wire messages')\n return { type: 'image' as const, data: block.data, mimeType: block.mediaType }\n }\n if (block.type === 'audio')\n throw unsupportedMediaError('audio', 'openai')\n if (block.type === 'video')\n throw unsupportedMediaError('video', 'openai')\n if (block.type === 'document') {\n assertResolvedMediaBlock(block, 'OpenAI wire messages')\n return { type: 'text' as const, text: documentMarker(block) }\n }\n return { type: 'text' as const, text: block.text }\n })\n\n return {\n role: 'toolResult',\n toolCallId: result.callId,\n toolName,\n content,\n isError: result.isError ?? false,\n timestamp: Date.now(),\n }\n}\n\nfunction piUserMessage(\n content: SessionContentBlock[],\n): PiMessage | null {\n for (const b of content) {\n if (b.type === 'audio')\n throw unsupportedMediaError('audio', 'openai')\n if (b.type === 'video')\n throw unsupportedMediaError('video', 'openai')\n }\n\n const textBlocks = content.filter(b => b.type === 'text')\n const imageBlocks = content.filter(b => b.type === 'image')\n const documentBlocks = content.filter(b => b.type === 'document')\n\n if (imageBlocks.length === 0 && textBlocks.length === 0 && documentBlocks.length === 0)\n return null\n\n if (imageBlocks.length === 0 && documentBlocks.length === 0 && textBlocks.length === 1)\n return { role: 'user', content: textBlocks[0].text, timestamp: Date.now() }\n\n return {\n role: 'user',\n content: [\n ...imageBlocks.map((img) => {\n assertResolvedMediaBlock(img, 'OpenAI wire messages')\n return { type: 'image' as const, data: img.data, mimeType: img.mediaType }\n }),\n // NOTE: OpenAI's API natively accepts PDFs (Responses `input_file` /\n // Chat Completions `file`), but pi-ai's message content union is\n // text|image only — it has no file content type — so documents degrade to\n // a marker here. To forward PDFs to OpenAI, route via:\n // openaiCompat({ name: 'openai', apiKey, baseURL: 'https://api.openai.com/v1',\n // capabilities: { documents: true } })\n // which emits the `{type:'file'}` Chat Completions part directly. (That\n // path accepts application/pdf only; spreadsheets/.docx need the\n // Responses API, which would require an input_file content type in pi-ai.)\n ...documentBlocks.map((block) => {\n assertResolvedMediaBlock(block, 'OpenAI wire messages')\n return { type: 'text' as const, text: documentMarker(block) }\n }),\n ...textBlocks.map(block => ({ type: 'text' as const, text: block.text })),\n ],\n timestamp: Date.now(),\n }\n}\n\nfunction piAssistantMessage(\n content: SessionContentBlock[],\n modelId: string,\n): PiAssistantMessage {\n const piContent: PiAssistantMessage['content'] = []\n for (const block of content) {\n if (block.type === 'text') {\n piContent.push({ type: 'text', text: block.text })\n }\n else if (block.type === 'thinking') {\n // Drop thinking blocks minted by another provider — Anthropic signatures\n // are not valid OpenAI `encrypted_content` and Responses API rejects them.\n if (block.signatureProducer === 'anthropic')\n continue\n piContent.push({ type: 'thinking', thinking: block.text, thinkingSignature: block.signature })\n }\n else if (block.type === 'tool_call') {\n piContent.push({ type: 'toolCall', id: block.id, name: block.name, arguments: block.input })\n }\n // `redacted_thinking` (Anthropic-only) and `provider_reasoning` (provider-\n // bound reasoning state) are intentionally dropped — Codex Responses\n // doesn't accept them.\n }\n\n return {\n role: 'assistant',\n content: piContent,\n api: 'openai-codex-responses',\n provider: PROVIDER_ID,\n model: modelId,\n usage: emptyUsage(),\n stopReason: 'stop',\n timestamp: Date.now(),\n }\n}\n\nexport function toPiMessages(messages: SessionMessage[], modelId: string): PiMessage[] {\n const out: PiMessage[] = []\n\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]\n const toolCalls = msg.content.filter((b): b is Extract<SessionContentBlock, { type: 'tool_call' }> => b.type === 'tool_call')\n\n if (msg.role === 'assistant' && toolCalls.length > 0) {\n const next = messages[i + 1]\n const nextToolResults = next?.role === 'user'\n ? next.content.filter((b): b is Extract<SessionContentBlock, { type: 'tool_result' }> => b.type === 'tool_result')\n : []\n const resultById = new Map(nextToolResults.map(result => [result.callId, result]))\n\n let assistantContent: SessionContentBlock[] = []\n for (const block of msg.content) {\n assistantContent.push(block)\n if (block.type !== 'tool_call')\n continue\n\n out.push(piAssistantMessage(assistantContent, modelId))\n assistantContent = []\n\n const result = resultById.get(block.id)\n if (result) {\n out.push(piToolResultMessage(result, block.name))\n }\n else {\n out.push(piToolResultMessage({\n type: 'tool_result',\n callId: block.id,\n output: SYNTHETIC_TOOL_RESULT_PLACEHOLDER,\n isError: true,\n }, block.name))\n }\n }\n if (assistantContent.length > 0)\n out.push(piAssistantMessage(assistantContent, modelId))\n\n if (next?.role === 'user') {\n const remainingUserContent = next.content.filter((block) => {\n if (block.type !== 'tool_result')\n return true\n // Orphan/duplicate tool results should already be removed by the\n // canonical repair pass. If one reaches this adapter, do not send it\n // as an unpaired provider message.\n return false\n })\n const userMessage = piUserMessage(remainingUserContent)\n if (userMessage)\n out.push(userMessage)\n i++\n }\n continue\n }\n\n const toolResults = msg.content.filter(b => b.type === 'tool_result')\n if (toolResults.length > 0) {\n const userMsg = msg.role === 'user'\n ? piUserMessage(msg.content.filter(b => b.type !== 'tool_result'))\n : null\n if (userMsg)\n out.push(userMsg)\n continue\n }\n\n if (msg.role === 'user') {\n const userMsg = piUserMessage(msg.content)\n if (userMsg)\n out.push(userMsg)\n continue\n }\n\n out.push(piAssistantMessage(msg.content, modelId))\n }\n\n return out\n}\n\n/**\n * Map pi-ai's `StopReason` to the zidane `TurnFinishReason` union — the same\n * native-stop-reason fidelity anthropic's `mapStopReason` / openai-compat's\n * `mapOAIFinishReason` provide. Notably `length` (max-token truncation) is no\n * longer misreported as a clean `stop`. `hasToolCalls` is the fallback for\n * messages whose stop reason is missing or doesn't carry the tool-call signal.\n */\nexport function mapCodexStopReason(stopReason: string | undefined, hasToolCalls: boolean): TurnFinishReason {\n switch (stopReason) {\n case 'toolUse':\n return 'tool-calls'\n case 'length':\n return 'length'\n case 'error':\n return 'error'\n case 'stop':\n return hasToolCalls ? 'tool-calls' : 'stop'\n case 'aborted':\n return 'other'\n default:\n return hasToolCalls ? 'tool-calls' : 'stop'\n }\n}\n\nfunction fromPiAssistantMessage(message: PiAssistantMessage): SessionMessage {\n const content: SessionContentBlock[] = []\n\n for (const block of message.content) {\n if (block.type === 'text') {\n content.push({ type: 'text', text: block.text })\n }\n else if (block.type === 'thinking') {\n const out: Extract<SessionContentBlock, { type: 'thinking' }> = {\n type: 'thinking',\n text: block.thinking,\n }\n if (typeof block.thinkingSignature === 'string') {\n out.signature = block.thinkingSignature\n out.signatureProducer = 'openai'\n }\n content.push(out)\n }\n else if (block.type === 'toolCall') {\n content.push({ type: 'tool_call', id: block.id, name: block.name, input: block.arguments })\n }\n }\n\n return { role: 'assistant', content }\n}\n\nfunction extractToolCalls(message: PiAssistantMessage) {\n return message.content\n .filter(block => block.type === 'toolCall')\n .map(block => ({\n id: block.id,\n name: block.name,\n input: block.arguments as Record<string, unknown>,\n }))\n}\n\nfunction extractText(message: PiAssistantMessage): string {\n return message.content\n .filter((block): block is Extract<PiAssistantMessage['content'][number], { type: 'text' }> => block.type === 'text')\n .map(block => block.text)\n .join('')\n}\n\nfunction toTurnUsage(usage: PiUsage, finishReason: TurnFinishReason | undefined, modelId: string): Promise<TurnUsage> {\n return fillEstimatedCost({\n input: usage.input,\n output: usage.output,\n cacheRead: usage.cacheRead || undefined,\n cacheCreation: usage.cacheWrite || undefined,\n cost: usage.cost.total || undefined,\n ...(finishReason ? { finishReason } : {}),\n modelId,\n }, 'openai')\n}\n\n/**\n * Transient pi-ai error patterns worth a loop-level retry. pi-ai already retries\n * 429 / 5xx pre-stream 3× internally (see `openai-codex-responses.js`); by the\n * time the error reaches us, that budget is exhausted. The loop-level retry\n * with its longer backoff is a second line of defense for capacity events\n * that persist past pi-ai's short retry window, plus mid-stream emissions\n * (pi-ai surfaces those as plain `Error`s with no status).\n *\n * Mirrors pi-ai's own `isRetryableError` regex so the two retry layers\n * recognize the same failure modes.\n */\nconst TRANSIENT_OPENAI_MESSAGE_RE = /rate.?limit|overloaded|service.?unavailable|upstream.?connect|connection.?refused|gateway.?time.?out|temporarily.?unavailable/i\n\n/** Numeric HTTP status codes pi-ai sometimes attaches when bubbling structured errors. */\nfunction isRetryableStatusCode(err: object): boolean {\n const status = (err as { status?: unknown }).status\n if (typeof status !== 'number')\n return false\n return isRetryableHttpStatus(status)\n}\n\n/**\n * Classify an OpenAI Codex error. pi-ai surfaces errors either as thrown `Error`s\n * (wrapping `event.error.errorMessage`) or via stream event types.\n *\n * Retryable hint is set when pi-ai's own retry budget is exhausted on a\n * transient failure — pattern-matched against `message` since pi-ai strips\n * structured fields on plain-Error throws. Set `behavior.retry.maxAttempts: 1`\n * to disable the loop-level retry.\n */\nexport function classifyOpenAIError(err: unknown): ClassifiedError | null {\n const prelude = classifyErrorPrelude(err)\n if (prelude === 'not-object')\n return null\n if (prelude === 'aborted')\n return { kind: 'aborted' }\n\n const anyErr = err as { name?: string, message?: string, code?: string, type?: string }\n\n const message = anyErr.message ?? ''\n const code = anyErr.code ?? anyErr.type\n\n if (code === 'context_length_exceeded' || matchesContextExceeded(message)) {\n return {\n kind: 'context_exceeded',\n providerCode: code ?? 'context_length_exceeded',\n message,\n }\n }\n\n if (matchesToolPairingError(message)) {\n return {\n kind: 'tool_pairing_corruption',\n providerCode: code ?? 'invalid_request_error',\n message,\n }\n }\n\n // pi-ai wraps API errors in generic `Error` — treat as provider_error when we have a message.\n if (message.length > 0) {\n const retryable = isRetryableStatusCode(anyErr) || TRANSIENT_OPENAI_MESSAGE_RE.test(message)\n return {\n kind: 'provider_error',\n providerCode: code,\n message,\n ...(retryable ? { retryable: true } : {}),\n }\n }\n\n return null\n}\n\n/**\n * A standard OpenAI API key usable against `api.openai.com` (for the exact\n * token-count endpoint), or `null` when only a Codex-OAuth credential is\n * available. Codex OAuth access tokens are JWTs (`eyJ…`) and are NOT valid\n * bearers for the standard API; a real key looks like `sk-…` (but not the\n * Anthropic `sk-ant-…` form). Checks `params.apiKey` then `OPENAI_API_KEY`.\n */\nfunction pickStandardOpenAIKey(params?: OpenAIParams): string | null {\n const candidates = [params?.apiKey, process.env.OPENAI_API_KEY]\n for (const key of candidates) {\n if (typeof key === 'string' && key.startsWith('sk-') && !key.startsWith('sk-ant-'))\n return key\n }\n return null\n}\n\n/**\n * Convert canonical {@link SessionMessage}s to OpenAI Responses-API `input`\n * items for the token-count endpoint. Only the text-bearing shape is needed\n * here (the count path sends a tiny dummy message); images/tool-results are\n * down-converted to text so the count never throws on an exotic block.\n */\nfunction toResponsesInput(messages: SessionMessage[]): unknown[] {\n return messages.map((msg) => {\n const text = msg.content\n .map(b => (b.type === 'text' ? b.text : ''))\n .filter(Boolean)\n .join('\\n')\n const part = msg.role === 'assistant' ? 'output_text' : 'input_text'\n return { role: msg.role === 'assistant' ? 'assistant' : 'user', content: [{ type: part, text }] }\n })\n}\n\n/** Convert pi-ai `PiTool` specs to Responses-API function tools. */\nfunction toResponsesTools(tools: unknown[]): unknown[] {\n return tools.map((t) => {\n const tool = t as { name?: string, description?: string, parameters?: unknown }\n return {\n type: 'function',\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters,\n }\n })\n}\n\nfunction applyPayloadOverrides(payload: unknown, options: StreamOptions): unknown {\n const body = payload as Record<string, unknown>\n\n if (options.toolChoice) {\n if (options.toolChoice.type === 'tool' && options.toolChoice.name)\n body.tool_choice = { type: 'function', name: options.toolChoice.name }\n else if (options.toolChoice.type === 'required')\n body.tool_choice = 'required'\n else\n body.tool_choice = 'auto'\n }\n\n return body\n}\n\nexport function openai(params?: OpenAIParams): Provider {\n const defaultModel = params?.defaultModel || DEFAULT_MODEL\n const baseCredentials = extractRuntimeCredentials(params)\n let runtimeCredentials = baseCredentials\n ? { ...baseCredentials, ...(params?.accountId ? { accountId: params.accountId } : {}) }\n : undefined\n\n return {\n name: 'openai',\n meta: {\n defaultModel,\n isOAuth: true,\n capabilities: {\n vision: true,\n imageInToolResult: true,\n // pi-ai's Codex Responses wire has no audio/video input content type.\n audio: false,\n video: false,\n },\n },\n formatTools,\n userMessage,\n assistantMessage,\n toolResultsMessage,\n classifyError: classifyOpenAIError,\n\n async countTokens(payload, signal): Promise<number | null> {\n // The exact count endpoint (`POST /v1/responses/input_tokens`) lives on\n // the standard OpenAI API and needs a standard `OPENAI_API_KEY` bearer.\n // This provider authenticates via Codex OAuth against the Codex backend,\n // whose token is NOT valid for that endpoint — so we only attempt the\n // count when a standard key is present (env or params.apiKey that isn't\n // an OAuth/JWT token). Otherwise return null → heuristic fallback.\n const standardKey = pickStandardOpenAIKey(params)\n if (!standardKey)\n return null\n try {\n const res = await fetch('https://api.openai.com/v1/responses/input_tokens', {\n method: 'POST',\n headers: {\n ...params?.extraHeaders,\n 'authorization': `Bearer ${standardKey}`,\n 'content-type': 'application/json',\n },\n // The Responses `input_tokens` endpoint takes the same shape as\n // `responses.create`: `instructions` (system), `input` (Responses\n // input items — NOT pi-ai messages), and function-shaped `tools`.\n body: JSON.stringify({\n model: payload.model || defaultModel,\n instructions: renderSystemForWire(payload.system),\n input: toResponsesInput(payload.messages),\n tools: toResponsesTools(payload.tools),\n }),\n ...(signal ? { signal } : {}),\n })\n if (!res.ok)\n return null\n const json = (await res.json()) as { input_tokens?: unknown }\n return typeof json.input_tokens === 'number' ? json.input_tokens : null\n }\n catch {\n return null\n }\n },\n\n async stream(options: StreamOptions, callbacks: StreamCallbacks): Promise<TurnResult> {\n const modelId = options.model || defaultModel\n const model = resolveModel(modelId)\n const apiKey = await resolveOAuthApiKey(\n {\n provider: 'openai',\n providerId: PROVIDER_ID,\n params: runtimeCredentials ? { ...params, ...runtimeCredentials } : params,\n envKey: 'OPENAI_CODEX_API_KEY',\n extraCredentialKeys: ['accountId'],\n missingError: 'No OpenAI Codex OAuth token found. Run `bun run auth --openai` first.',\n refreshError: reason => `OpenAI Codex OAuth token refresh failed. Run \\`bun run auth --openai\\` again. ${reason}`,\n },\n {\n ...callbacks,\n async onOAuthRefresh(ctx) {\n if (ctx.source === 'params') {\n runtimeCredentials = {\n access: ctx.credentials.access,\n refresh: ctx.credentials.refresh,\n expires: ctx.credentials.expires,\n ...(typeof ctx.credentials.accountId === 'string' ? { accountId: ctx.credentials.accountId } : {}),\n }\n }\n await callbacks.onOAuthRefresh?.(ctx)\n },\n },\n )\n // Codex's Responses API has no `cache_control` analogue, but the\n // system-prompt boundary marker is structural metadata that should\n // never reach the model. Strip it via `renderSystemForWire`; the\n // doctrine + env are collapsed into a single byte stream the model\n // sees as one logical prompt.\n const context: PiContext = {\n systemPrompt: renderSystemForWire(options.system),\n messages: toPiMessages(options.messages, modelId),\n tools: options.tools as PiTool[],\n }\n // OpenAI's `reasoning_effort` accepts minimal/low/medium/high/xhigh.\n // Clamp only Anthropic's `max` tier to `xhigh`; `'adaptive'` degrades to\n // no reasoning rather than forwarding an unknown value the API would reject.\n const reasoningLevel\n = options.thinking && options.thinking !== 'off' && options.thinking !== 'adaptive'\n ? options.thinking === 'max' ? 'xhigh' : options.thinking\n : undefined\n const stream = streamOpenAICodexResponses(model, context, {\n apiKey,\n maxTokens: options.maxTokens,\n signal: options.signal,\n transport: params?.transport,\n reasoningEffort: reasoningLevel,\n reasoningSummary: reasoningLevel ? 'auto' : undefined,\n ...(options.modelOptions?.fast ? { serviceTier: 'priority' as const } : {}),\n ...(params?.extraHeaders ? { headers: params.extraHeaders } : {}),\n onPayload: payload => applyPayloadOverrides(payload, options),\n })\n\n let finalMessage: PiAssistantMessage | undefined\n let text = ''\n let thinking = ''\n\n for await (const event of stream) {\n if (event.type === 'text_delta') {\n text += event.delta\n callbacks.onText(event.delta)\n }\n else if (event.type === 'thinking_delta') {\n thinking += event.delta\n callbacks.onThinking?.(event.delta)\n }\n else if (event.type === 'thinking_end') {\n const delta = event.content.startsWith(thinking)\n ? event.content.slice(thinking.length)\n : (thinking ? '' : event.content)\n if (delta) {\n thinking += delta\n callbacks.onThinking?.(delta)\n }\n }\n else if (event.type === 'done') {\n finalMessage = event.message\n }\n else if (event.type === 'error') {\n throw new Error(event.error.errorMessage || 'OpenAI Codex API error')\n }\n }\n\n finalMessage ??= await stream.result()\n text ||= extractText(finalMessage)\n\n const toolCalls = extractToolCalls(finalMessage)\n const assistantTurn = fromPiAssistantMessage(finalMessage)\n const finishReason = mapCodexStopReason(finalMessage.stopReason, toolCalls.length > 0)\n const usage = await toTurnUsage(finalMessage.usage, finishReason, modelId)\n\n return {\n assistantMessage: assistantTurn,\n text,\n toolCalls,\n done: toolCalls.length === 0,\n usage,\n }\n },\n }\n}\n"],"mappings":";;;;;;;;;AA4BA,MAAM,cAAc;AACpB,MAAM,gBAAgB;AAqBtB,MAAM,cAAc;AAEpB,SAAS,aAAa,SAA6B;CACjD,MAAM,QAAQ,YAAY,aAAa,OAAO;CAC9C,IAAI,OACF,OAAO;CAET,MAAM,WAAW,YAAY,aAAa,aAAa;CACvD,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,6DAA6D,eAAe;CAE9F,OAAO;EAAE,GAAG;EAAU,IAAI;EAAS,MAAM;CAAQ;AACnD;AAEA,SAAS,aAAsB;CAC7B,OAAO;EACL,OAAO;EACP,QAAQ;EACR,WAAW;EACX,YAAY;EACZ,aAAa;EACb,MAAM;GAAE,OAAO;GAAG,QAAQ;GAAG,WAAW;GAAG,YAAY;GAAG,OAAO;EAAE;CACrE;AACF;AAEA,SAAS,YAAY,OAA6B;CAKhD,OADkB,kBAAkB,OAAO,EAAE,SAAS,SAAS,CAChD,EAAE,KAAI,OAAM;EACzB,MAAM,EAAE;EACR,aAAa,EAAE;EACf,YAAY,EAAE;CAChB,EAAE;AACJ;AAEA,SAAS,eAAe,KAAwC;CAC9D,OAAO,oBAAoB,KAAK,kBAAkB;AACpD;AAEA,SAAS,oBACP,QACA,WAAW,IACA;CAGX,MAAM,UAAU,OAAO,OAAO,WAAW,WACrC,CAAC;EAAE,MAAM;EAAiB,MAAM,OAAO;CAAO,CAAC,IAC/C,OAAO,OAAO,KAAK,UAAU;EAC3B,IAAI,MAAM,SAAS,SAAS;GAC1B,yBAAyB,OAAO,sBAAsB;GACtD,OAAO;IAAE,MAAM;IAAkB,MAAM,MAAM;IAAM,UAAU,MAAM;GAAU;EAC/E;EACA,IAAI,MAAM,SAAS,SACjB,MAAM,sBAAsB,SAAS,QAAQ;EAC/C,IAAI,MAAM,SAAS,SACjB,MAAM,sBAAsB,SAAS,QAAQ;EAC/C,IAAI,MAAM,SAAS,YAAY;GAC7B,yBAAyB,OAAO,sBAAsB;GACtD,OAAO;IAAE,MAAM;IAAiB,MAAM,eAAe,KAAK;GAAE;EAC9D;EACA,OAAO;GAAE,MAAM;GAAiB,MAAM,MAAM;EAAK;CACnD,CAAC;CAEL,OAAO;EACL,MAAM;EACN,YAAY,OAAO;EACnB;EACA;EACA,SAAS,OAAO,WAAW;EAC3B,WAAW,KAAK,IAAI;CACtB;AACF;AAEA,SAAS,cACP,SACkB;CAClB,KAAK,MAAM,KAAK,SAAS;EACvB,IAAI,EAAE,SAAS,SACb,MAAM,sBAAsB,SAAS,QAAQ;EAC/C,IAAI,EAAE,SAAS,SACb,MAAM,sBAAsB,SAAS,QAAQ;CACjD;CAEA,MAAM,aAAa,QAAQ,QAAO,MAAK,EAAE,SAAS,MAAM;CACxD,MAAM,cAAc,QAAQ,QAAO,MAAK,EAAE,SAAS,OAAO;CAC1D,MAAM,iBAAiB,QAAQ,QAAO,MAAK,EAAE,SAAS,UAAU;CAEhE,IAAI,YAAY,WAAW,KAAK,WAAW,WAAW,KAAK,eAAe,WAAW,GACnF,OAAO;CAET,IAAI,YAAY,WAAW,KAAK,eAAe,WAAW,KAAK,WAAW,WAAW,GACnF,OAAO;EAAE,MAAM;EAAQ,SAAS,WAAW,GAAG;EAAM,WAAW,KAAK,IAAI;CAAE;CAE5E,OAAO;EACL,MAAM;EACN,SAAS;GACP,GAAG,YAAY,KAAK,QAAQ;IAC1B,yBAAyB,KAAK,sBAAsB;IACpD,OAAO;KAAE,MAAM;KAAkB,MAAM,IAAI;KAAM,UAAU,IAAI;IAAU;GAC3E,CAAC;GAUD,GAAG,eAAe,KAAK,UAAU;IAC/B,yBAAyB,OAAO,sBAAsB;IACtD,OAAO;KAAE,MAAM;KAAiB,MAAM,eAAe,KAAK;IAAE;GAC9D,CAAC;GACD,GAAG,WAAW,KAAI,WAAU;IAAE,MAAM;IAAiB,MAAM,MAAM;GAAK,EAAE;EAC1E;EACA,WAAW,KAAK,IAAI;CACtB;AACF;AAEA,SAAS,mBACP,SACA,SACoB;CACpB,MAAM,YAA2C,CAAC;CAClD,KAAK,MAAM,SAAS,SAClB,IAAI,MAAM,SAAS,QACjB,UAAU,KAAK;EAAE,MAAM;EAAQ,MAAM,MAAM;CAAK,CAAC;MAE9C,IAAI,MAAM,SAAS,YAAY;EAGlC,IAAI,MAAM,sBAAsB,aAC9B;EACF,UAAU,KAAK;GAAE,MAAM;GAAY,UAAU,MAAM;GAAM,mBAAmB,MAAM;EAAU,CAAC;CAC/F,OACK,IAAI,MAAM,SAAS,aACtB,UAAU,KAAK;EAAE,MAAM;EAAY,IAAI,MAAM;EAAI,MAAM,MAAM;EAAM,WAAW,MAAM;CAAM,CAAC;CAO/F,OAAO;EACL,MAAM;EACN,SAAS;EACT,KAAK;EACL,UAAU;EACV,OAAO;EACP,OAAO,WAAW;EAClB,YAAY;EACZ,WAAW,KAAK,IAAI;CACtB;AACF;AAEA,SAAgB,aAAa,UAA4B,SAA8B;CACrF,MAAM,MAAmB,CAAC;CAE1B,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;EACxC,MAAM,MAAM,SAAS;EACrB,MAAM,YAAY,IAAI,QAAQ,QAAQ,MAAgE,EAAE,SAAS,WAAW;EAE5H,IAAI,IAAI,SAAS,eAAe,UAAU,SAAS,GAAG;GACpD,MAAM,OAAO,SAAS,IAAI;GAC1B,MAAM,kBAAkB,MAAM,SAAS,SACnC,KAAK,QAAQ,QAAQ,MAAkE,EAAE,SAAS,aAAa,IAC/G,CAAC;GACL,MAAM,aAAa,IAAI,IAAI,gBAAgB,KAAI,WAAU,CAAC,OAAO,QAAQ,MAAM,CAAC,CAAC;GAEjF,IAAI,mBAA0C,CAAC;GAC/C,KAAK,MAAM,SAAS,IAAI,SAAS;IAC/B,iBAAiB,KAAK,KAAK;IAC3B,IAAI,MAAM,SAAS,aACjB;IAEF,IAAI,KAAK,mBAAmB,kBAAkB,OAAO,CAAC;IACtD,mBAAmB,CAAC;IAEpB,MAAM,SAAS,WAAW,IAAI,MAAM,EAAE;IACtC,IAAI,QACF,IAAI,KAAK,oBAAoB,QAAQ,MAAM,IAAI,CAAC;SAGhD,IAAI,KAAK,oBAAoB;KAC3B,MAAM;KACN,QAAQ,MAAM;KACd,QAAQ;KACR,SAAS;IACX,GAAG,MAAM,IAAI,CAAC;GAElB;GACA,IAAI,iBAAiB,SAAS,GAC5B,IAAI,KAAK,mBAAmB,kBAAkB,OAAO,CAAC;GAExD,IAAI,MAAM,SAAS,QAAQ;IASzB,MAAM,cAAc,cARS,KAAK,QAAQ,QAAQ,UAAU;KAC1D,IAAI,MAAM,SAAS,eACjB,OAAO;KAIT,OAAO;IACT,CACqD,CAAC;IACtD,IAAI,aACF,IAAI,KAAK,WAAW;IACtB;GACF;GACA;EACF;EAGA,IADoB,IAAI,QAAQ,QAAO,MAAK,EAAE,SAAS,aACzC,EAAE,SAAS,GAAG;GAC1B,MAAM,UAAU,IAAI,SAAS,SACzB,cAAc,IAAI,QAAQ,QAAO,MAAK,EAAE,SAAS,aAAa,CAAC,IAC/D;GACJ,IAAI,SACF,IAAI,KAAK,OAAO;GAClB;EACF;EAEA,IAAI,IAAI,SAAS,QAAQ;GACvB,MAAM,UAAU,cAAc,IAAI,OAAO;GACzC,IAAI,SACF,IAAI,KAAK,OAAO;GAClB;EACF;EAEA,IAAI,KAAK,mBAAmB,IAAI,SAAS,OAAO,CAAC;CACnD;CAEA,OAAO;AACT;;;;;;;;AASA,SAAgB,mBAAmB,YAAgC,cAAyC;CAC1G,QAAQ,YAAR;EACE,KAAK,WACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,SACH,OAAO;EACT,KAAK,QACH,OAAO,eAAe,eAAe;EACvC,KAAK,WACH,OAAO;EACT,SACE,OAAO,eAAe,eAAe;CACzC;AACF;AAEA,SAAS,uBAAuB,SAA6C;CAC3E,MAAM,UAAiC,CAAC;CAExC,KAAK,MAAM,SAAS,QAAQ,SAC1B,IAAI,MAAM,SAAS,QACjB,QAAQ,KAAK;EAAE,MAAM;EAAQ,MAAM,MAAM;CAAK,CAAC;MAE5C,IAAI,MAAM,SAAS,YAAY;EAClC,MAAM,MAA0D;GAC9D,MAAM;GACN,MAAM,MAAM;EACd;EACA,IAAI,OAAO,MAAM,sBAAsB,UAAU;GAC/C,IAAI,YAAY,MAAM;GACtB,IAAI,oBAAoB;EAC1B;EACA,QAAQ,KAAK,GAAG;CAClB,OACK,IAAI,MAAM,SAAS,YACtB,QAAQ,KAAK;EAAE,MAAM;EAAa,IAAI,MAAM;EAAI,MAAM,MAAM;EAAM,OAAO,MAAM;CAAU,CAAC;CAI9F,OAAO;EAAE,MAAM;EAAa;CAAQ;AACtC;AAEA,SAAS,iBAAiB,SAA6B;CACrD,OAAO,QAAQ,QACZ,QAAO,UAAS,MAAM,SAAS,UAAU,EACzC,KAAI,WAAU;EACb,IAAI,MAAM;EACV,MAAM,MAAM;EACZ,OAAO,MAAM;CACf,EAAE;AACN;AAEA,SAAS,YAAY,SAAqC;CACxD,OAAO,QAAQ,QACZ,QAAQ,UAAqF,MAAM,SAAS,MAAM,EAClH,KAAI,UAAS,MAAM,IAAI,EACvB,KAAK,EAAE;AACZ;AAEA,SAAS,YAAY,OAAgB,cAA4C,SAAqC;CACpH,OAAO,kBAAkB;EACvB,OAAO,MAAM;EACb,QAAQ,MAAM;EACd,WAAW,MAAM,aAAa,KAAA;EAC9B,eAAe,MAAM,cAAc,KAAA;EACnC,MAAM,MAAM,KAAK,SAAS,KAAA;EAC1B,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;EACvC;CACF,GAAG,QAAQ;AACb;;;;;;;;;;;;AAaA,MAAM,8BAA8B;;AAGpC,SAAS,sBAAsB,KAAsB;CACnD,MAAM,SAAU,IAA6B;CAC7C,IAAI,OAAO,WAAW,UACpB,OAAO;CACT,OAAO,sBAAsB,MAAM;AACrC;;;;;;;;;;AAWA,SAAgB,oBAAoB,KAAsC;CACxE,MAAM,UAAU,qBAAqB,GAAG;CACxC,IAAI,YAAY,cACd,OAAO;CACT,IAAI,YAAY,WACd,OAAO,EAAE,MAAM,UAAU;CAE3B,MAAM,SAAS;CAEf,MAAM,UAAU,OAAO,WAAW;CAClC,MAAM,OAAO,OAAO,QAAQ,OAAO;CAEnC,IAAI,SAAS,6BAA6B,uBAAuB,OAAO,GACtE,OAAO;EACL,MAAM;EACN,cAAc,QAAQ;EACtB;CACF;CAGF,IAAI,wBAAwB,OAAO,GACjC,OAAO;EACL,MAAM;EACN,cAAc,QAAQ;EACtB;CACF;CAIF,IAAI,QAAQ,SAAS,GAEnB,OAAO;EACL,MAAM;EACN,cAAc;EACd;EACA,GALgB,sBAAsB,MAAM,KAAK,4BAA4B,KAAK,OAAO,IAKzE,EAAE,WAAW,KAAK,IAAI,CAAC;CACzC;CAGF,OAAO;AACT;;;;;;;;AASA,SAAS,sBAAsB,QAAsC;CACnE,MAAM,aAAa,CAAC,QAAQ,QAAQ,QAAQ,IAAI,cAAc;CAC9D,KAAK,MAAM,OAAO,YAChB,IAAI,OAAO,QAAQ,YAAY,IAAI,WAAW,KAAK,KAAK,CAAC,IAAI,WAAW,SAAS,GAC/E,OAAO;CAEX,OAAO;AACT;;;;;;;AAQA,SAAS,iBAAiB,UAAuC;CAC/D,OAAO,SAAS,KAAK,QAAQ;EAC3B,MAAM,OAAO,IAAI,QACd,KAAI,MAAM,EAAE,SAAS,SAAS,EAAE,OAAO,EAAG,EAC1C,OAAO,OAAO,EACd,KAAK,IAAI;EACZ,MAAM,OAAO,IAAI,SAAS,cAAc,gBAAgB;EACxD,OAAO;GAAE,MAAM,IAAI,SAAS,cAAc,cAAc;GAAQ,SAAS,CAAC;IAAE,MAAM;IAAM;GAAK,CAAC;EAAE;CAClG,CAAC;AACH;;AAGA,SAAS,iBAAiB,OAA6B;CACrD,OAAO,MAAM,KAAK,MAAM;EACtB,MAAM,OAAO;EACb,OAAO;GACL,MAAM;GACN,MAAM,KAAK;GACX,aAAa,KAAK;GAClB,YAAY,KAAK;EACnB;CACF,CAAC;AACH;AAEA,SAAS,sBAAsB,SAAkB,SAAiC;CAChF,MAAM,OAAO;CAEb,IAAI,QAAQ,YACV,IAAI,QAAQ,WAAW,SAAS,UAAU,QAAQ,WAAW,MAC3D,KAAK,cAAc;EAAE,MAAM;EAAY,MAAM,QAAQ,WAAW;CAAK;MAClE,IAAI,QAAQ,WAAW,SAAS,YACnC,KAAK,cAAc;MAEnB,KAAK,cAAc;CAGvB,OAAO;AACT;AAEA,SAAgB,OAAO,QAAiC;CACtD,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,kBAAkB,0BAA0B,MAAM;CACxD,IAAI,qBAAqB,kBACrB;EAAE,GAAG;EAAiB,GAAI,QAAQ,YAAY,EAAE,WAAW,OAAO,UAAU,IAAI,CAAC;CAAG,IACpF,KAAA;CAEJ,OAAO;EACL,MAAM;EACN,MAAM;GACJ;GACA,SAAS;GACT,cAAc;IACZ,QAAQ;IACR,mBAAmB;IAEnB,OAAO;IACP,OAAO;GACT;EACF;EACA;EACA;EACA;EACA;EACA,eAAe;EAEf,MAAM,YAAY,SAAS,QAAgC;GAOzD,MAAM,cAAc,sBAAsB,MAAM;GAChD,IAAI,CAAC,aACH,OAAO;GACT,IAAI;IACF,MAAM,MAAM,MAAM,MAAM,oDAAoD;KAC1E,QAAQ;KACR,SAAS;MACP,GAAG,QAAQ;MACX,iBAAiB,UAAU;MAC3B,gBAAgB;KAClB;KAIA,MAAM,KAAK,UAAU;MACnB,OAAO,QAAQ,SAAS;MACxB,cAAc,oBAAoB,QAAQ,MAAM;MAChD,OAAO,iBAAiB,QAAQ,QAAQ;MACxC,OAAO,iBAAiB,QAAQ,KAAK;KACvC,CAAC;KACD,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;IAC7B,CAAC;IACD,IAAI,CAAC,IAAI,IACP,OAAO;IACT,MAAM,OAAQ,MAAM,IAAI,KAAK;IAC7B,OAAO,OAAO,KAAK,iBAAiB,WAAW,KAAK,eAAe;GACrE,QACM;IACJ,OAAO;GACT;EACF;EAEA,MAAM,OAAO,SAAwB,WAAiD;GACpF,MAAM,UAAU,QAAQ,SAAS;GACjC,MAAM,QAAQ,aAAa,OAAO;GAClC,MAAM,SAAS,MAAM,mBACnB;IACE,UAAU;IACV,YAAY;IACZ,QAAQ,qBAAqB;KAAE,GAAG;KAAQ,GAAG;IAAmB,IAAI;IACpE,QAAQ;IACR,qBAAqB,CAAC,WAAW;IACjC,cAAc;IACd,eAAc,WAAU,iFAAiF;GAC3G,GACA;IACE,GAAG;IACH,MAAM,eAAe,KAAK;KACxB,IAAI,IAAI,WAAW,UACjB,qBAAqB;MACnB,QAAQ,IAAI,YAAY;MACxB,SAAS,IAAI,YAAY;MACzB,SAAS,IAAI,YAAY;MACzB,GAAI,OAAO,IAAI,YAAY,cAAc,WAAW,EAAE,WAAW,IAAI,YAAY,UAAU,IAAI,CAAC;KAClG;KAEF,MAAM,UAAU,iBAAiB,GAAG;IACtC;GACF,CACF;GAMA,MAAM,UAAqB;IACzB,cAAc,oBAAoB,QAAQ,MAAM;IAChD,UAAU,aAAa,QAAQ,UAAU,OAAO;IAChD,OAAO,QAAQ;GACjB;GAIA,MAAM,iBACF,QAAQ,YAAY,QAAQ,aAAa,SAAS,QAAQ,aAAa,aACrE,QAAQ,aAAa,QAAQ,UAAU,QAAQ,WAC/C,KAAA;GACN,MAAM,SAAS,2BAA2B,OAAO,SAAS;IACxD;IACA,WAAW,QAAQ;IACnB,QAAQ,QAAQ;IAChB,WAAW,QAAQ;IACnB,iBAAiB;IACjB,kBAAkB,iBAAiB,SAAS,KAAA;IAC5C,GAAI,QAAQ,cAAc,OAAO,EAAE,aAAa,WAAoB,IAAI,CAAC;IACzE,GAAI,QAAQ,eAAe,EAAE,SAAS,OAAO,aAAa,IAAI,CAAC;IAC/D,YAAW,YAAW,sBAAsB,SAAS,OAAO;GAC9D,CAAC;GAED,IAAI;GACJ,IAAI,OAAO;GACX,IAAI,WAAW;GAEf,WAAW,MAAM,SAAS,QACxB,IAAI,MAAM,SAAS,cAAc;IAC/B,QAAQ,MAAM;IACd,UAAU,OAAO,MAAM,KAAK;GAC9B,OACK,IAAI,MAAM,SAAS,kBAAkB;IACxC,YAAY,MAAM;IAClB,UAAU,aAAa,MAAM,KAAK;GACpC,OACK,IAAI,MAAM,SAAS,gBAAgB;IACtC,MAAM,QAAQ,MAAM,QAAQ,WAAW,QAAQ,IAC3C,MAAM,QAAQ,MAAM,SAAS,MAAM,IAClC,WAAW,KAAK,MAAM;IAC3B,IAAI,OAAO;KACT,YAAY;KACZ,UAAU,aAAa,KAAK;IAC9B;GACF,OACK,IAAI,MAAM,SAAS,QACtB,eAAe,MAAM;QAElB,IAAI,MAAM,SAAS,SACtB,MAAM,IAAI,MAAM,MAAM,MAAM,gBAAgB,wBAAwB;GAIxE,iBAAiB,MAAM,OAAO,OAAO;GACrC,SAAS,YAAY,YAAY;GAEjC,MAAM,YAAY,iBAAiB,YAAY;GAC/C,MAAM,gBAAgB,uBAAuB,YAAY;GACzD,MAAM,eAAe,mBAAmB,aAAa,YAAY,UAAU,SAAS,CAAC;GACrF,MAAM,QAAQ,MAAM,YAAY,aAAa,OAAO,cAAc,OAAO;GAEzE,OAAO;IACL,kBAAkB;IAClB;IACA;IACA,MAAM,UAAU,WAAW;IAC3B;GACF;EACF;CACF;AACF"}
1
+ {"version":3,"file":"openai.js","names":[],"sources":["../../src/providers/openai.ts"],"sourcesContent":["import type {\n AssistantMessage as PiAssistantMessage,\n Context as PiContext,\n Message as PiMessage,\n Model as PiModel,\n Tool as PiTool,\n Usage as PiUsage,\n} from '@earendil-works/pi-ai'\nimport type { Provider, StreamCallbacks, StreamOptions, ToolSpec, TurnResult } from '.'\nimport type { ClassifiedError } from '../errors'\nimport type { SessionContentBlock, SessionMessage, ToolResultDocumentContent, TurnFinishReason, TurnUsage } from '../types'\nimport type { OAuthParams } from './oauth'\nimport { getModel } from '@earendil-works/pi-ai'\nimport { streamOpenAICodexResponses } from '@earendil-works/pi-ai/openai-codex-responses'\nimport { classifyErrorPrelude, isRetryableHttpStatus, matchesContextExceeded, matchesToolPairingError } from '../errors'\nimport { unsupportedMediaError } from '../prompt'\nimport { SYNTHETIC_TOOL_RESULT_PLACEHOLDER } from '../session/messages'\nimport { renderSystemForWire } from '../system-prompt'\nimport { assertResolvedMediaBlock, documentBlockMarker } from '../types'\nimport { fillEstimatedCost } from './cost'\nimport { extractRuntimeCredentials, resolveOAuthApiKey } from './oauth'\nimport {\n assistantMessage,\n toolResultsMessage,\n userMessage,\n} from './openai-compat'\nimport { sanitizeToolSpecs } from './schema-sanitize'\n\nconst PROVIDER_ID = 'openai-codex'\nconst DEFAULT_MODEL = 'gpt-5.5'\n\ntype CodexModel = PiModel<'openai-codex-responses'>\n\nexport interface OpenAIParams extends OAuthParams {\n accountId?: string\n defaultModel?: string\n transport?: 'sse' | 'websocket' | 'auto'\n /**\n * Extra HTTP headers merged into every request (the streaming Responses call\n * and the token-count endpoint). Use for routing/attribution headers a proxy\n * in front of the OpenAI Codex endpoint consumes. Merged with provider\n * defaults; pi-ai lets these override defaults, so avoid `authorization` /\n * `content-type` unless you intend to replace them.\n */\n extraHeaders?: Record<string, string>\n}\n\n// pi-ai's `getModel` is typed for `KnownProvider` × `keyof models[P]`;\n// we look up by free-form `modelId` (the registry holds string ids at\n// runtime) and let pi-ai's miss-throw fall through via the wider lookup.\nconst lookupModel = getModel as (provider: string, modelId: string) => CodexModel | undefined\n\nfunction resolveModel(modelId: string): CodexModel {\n const model = lookupModel(PROVIDER_ID, modelId)\n if (model)\n return model\n\n const fallback = lookupModel(PROVIDER_ID, DEFAULT_MODEL)\n if (!fallback)\n throw new Error(`OpenAI Codex model registry is missing the default model: ${DEFAULT_MODEL}`)\n\n return { ...fallback, id: modelId, name: modelId }\n}\n\nfunction emptyUsage(): PiUsage {\n return {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n totalTokens: 0,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n }\n}\n\nfunction formatTools(tools: ToolSpec[]): PiTool[] {\n // Codex's Responses API runs the same schema validator as the OpenAI\n // Chat Completions endpoint — apply the same sanitisation pass so MCP\n // tools with non-standard root shapes don't 400 here either.\n const sanitized = sanitizeToolSpecs(tools, { profile: 'openai' })\n return sanitized.map(t => ({\n name: t.name,\n description: t.description,\n parameters: t.inputSchema as PiTool['parameters'],\n }))\n}\n\nfunction documentMarker(doc: ToolResultDocumentContent): string {\n return documentBlockMarker(doc, 'document omitted')\n}\n\nfunction piToolResultMessage(\n result: Extract<SessionContentBlock, { type: 'tool_result' }>,\n toolName = '',\n): PiMessage {\n // pi-ai's ToolResultMessage natively accepts (TextContent | ImageContent)[].\n // Map zidane's canonical union directly — no flattening needed.\n const content = typeof result.output === 'string'\n ? [{ type: 'text' as const, text: result.output }]\n : result.output.map((block) => {\n if (block.type === 'image') {\n assertResolvedMediaBlock(block, 'OpenAI wire messages')\n return { type: 'image' as const, data: block.data, mimeType: block.mediaType }\n }\n if (block.type === 'audio')\n throw unsupportedMediaError('audio', 'openai')\n if (block.type === 'video')\n throw unsupportedMediaError('video', 'openai')\n if (block.type === 'document') {\n assertResolvedMediaBlock(block, 'OpenAI wire messages')\n return { type: 'text' as const, text: documentMarker(block) }\n }\n return { type: 'text' as const, text: block.text }\n })\n\n return {\n role: 'toolResult',\n toolCallId: result.callId,\n toolName,\n content,\n isError: result.isError ?? false,\n timestamp: Date.now(),\n }\n}\n\nfunction piUserMessage(\n content: SessionContentBlock[],\n): PiMessage | null {\n for (const b of content) {\n if (b.type === 'audio')\n throw unsupportedMediaError('audio', 'openai')\n if (b.type === 'video')\n throw unsupportedMediaError('video', 'openai')\n }\n\n const textBlocks = content.filter(b => b.type === 'text')\n const imageBlocks = content.filter(b => b.type === 'image')\n const documentBlocks = content.filter(b => b.type === 'document')\n\n if (imageBlocks.length === 0 && textBlocks.length === 0 && documentBlocks.length === 0)\n return null\n\n if (imageBlocks.length === 0 && documentBlocks.length === 0 && textBlocks.length === 1)\n return { role: 'user', content: textBlocks[0].text, timestamp: Date.now() }\n\n return {\n role: 'user',\n content: [\n ...imageBlocks.map((img) => {\n assertResolvedMediaBlock(img, 'OpenAI wire messages')\n return { type: 'image' as const, data: img.data, mimeType: img.mediaType }\n }),\n // NOTE: OpenAI's API natively accepts PDFs (Responses `input_file` /\n // Chat Completions `file`), but pi-ai's message content union is\n // text|image only — it has no file content type — so documents degrade to\n // a marker here. To forward PDFs to OpenAI, route via:\n // openaiCompat({ name: 'openai', apiKey, baseURL: 'https://api.openai.com/v1',\n // capabilities: { documents: true } })\n // which emits the `{type:'file'}` Chat Completions part directly. (That\n // path accepts application/pdf only; spreadsheets/.docx need the\n // Responses API, which would require an input_file content type in pi-ai.)\n ...documentBlocks.map((block) => {\n assertResolvedMediaBlock(block, 'OpenAI wire messages')\n return { type: 'text' as const, text: documentMarker(block) }\n }),\n ...textBlocks.map(block => ({ type: 'text' as const, text: block.text })),\n ],\n timestamp: Date.now(),\n }\n}\n\nfunction piAssistantMessage(\n content: SessionContentBlock[],\n modelId: string,\n): PiAssistantMessage {\n const piContent: PiAssistantMessage['content'] = []\n for (const block of content) {\n if (block.type === 'text') {\n piContent.push({ type: 'text', text: block.text })\n }\n else if (block.type === 'thinking') {\n // Drop thinking blocks minted by another provider — Anthropic signatures\n // are not valid OpenAI `encrypted_content` and Responses API rejects them.\n if (block.signatureProducer === 'anthropic')\n continue\n piContent.push({ type: 'thinking', thinking: block.text, thinkingSignature: block.signature })\n }\n else if (block.type === 'tool_call') {\n piContent.push({ type: 'toolCall', id: block.id, name: block.name, arguments: block.input })\n }\n // `redacted_thinking` (Anthropic-only) and `provider_reasoning` (provider-\n // bound reasoning state) are intentionally dropped — Codex Responses\n // doesn't accept them.\n }\n\n return {\n role: 'assistant',\n content: piContent,\n api: 'openai-codex-responses',\n provider: PROVIDER_ID,\n model: modelId,\n usage: emptyUsage(),\n stopReason: 'stop',\n timestamp: Date.now(),\n }\n}\n\nexport function toPiMessages(messages: SessionMessage[], modelId: string): PiMessage[] {\n const out: PiMessage[] = []\n\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]\n const toolCalls = msg.content.filter((b): b is Extract<SessionContentBlock, { type: 'tool_call' }> => b.type === 'tool_call')\n\n if (msg.role === 'assistant' && toolCalls.length > 0) {\n const next = messages[i + 1]\n const nextToolResults = next?.role === 'user'\n ? next.content.filter((b): b is Extract<SessionContentBlock, { type: 'tool_result' }> => b.type === 'tool_result')\n : []\n const resultById = new Map(nextToolResults.map(result => [result.callId, result]))\n\n let assistantContent: SessionContentBlock[] = []\n for (const block of msg.content) {\n assistantContent.push(block)\n if (block.type !== 'tool_call')\n continue\n\n out.push(piAssistantMessage(assistantContent, modelId))\n assistantContent = []\n\n const result = resultById.get(block.id)\n if (result) {\n out.push(piToolResultMessage(result, block.name))\n }\n else {\n out.push(piToolResultMessage({\n type: 'tool_result',\n callId: block.id,\n output: SYNTHETIC_TOOL_RESULT_PLACEHOLDER,\n isError: true,\n }, block.name))\n }\n }\n if (assistantContent.length > 0)\n out.push(piAssistantMessage(assistantContent, modelId))\n\n if (next?.role === 'user') {\n const remainingUserContent = next.content.filter((block) => {\n if (block.type !== 'tool_result')\n return true\n // Orphan/duplicate tool results should already be removed by the\n // canonical repair pass. If one reaches this adapter, do not send it\n // as an unpaired provider message.\n return false\n })\n const userMessage = piUserMessage(remainingUserContent)\n if (userMessage)\n out.push(userMessage)\n i++\n }\n continue\n }\n\n const toolResults = msg.content.filter(b => b.type === 'tool_result')\n if (toolResults.length > 0) {\n const userMsg = msg.role === 'user'\n ? piUserMessage(msg.content.filter(b => b.type !== 'tool_result'))\n : null\n if (userMsg)\n out.push(userMsg)\n continue\n }\n\n if (msg.role === 'user') {\n const userMsg = piUserMessage(msg.content)\n if (userMsg)\n out.push(userMsg)\n continue\n }\n\n out.push(piAssistantMessage(msg.content, modelId))\n }\n\n return out\n}\n\n/**\n * Map pi-ai's `StopReason` to the zidane `TurnFinishReason` union — the same\n * native-stop-reason fidelity anthropic's `mapStopReason` / openai-compat's\n * `mapOAIFinishReason` provide. Notably `length` (max-token truncation) is no\n * longer misreported as a clean `stop`. `hasToolCalls` is the fallback for\n * messages whose stop reason is missing or doesn't carry the tool-call signal.\n */\nexport function mapCodexStopReason(stopReason: string | undefined, hasToolCalls: boolean): TurnFinishReason {\n switch (stopReason) {\n case 'toolUse':\n return 'tool-calls'\n case 'length':\n return 'length'\n case 'error':\n return 'error'\n case 'stop':\n return hasToolCalls ? 'tool-calls' : 'stop'\n case 'aborted':\n return 'other'\n default:\n return hasToolCalls ? 'tool-calls' : 'stop'\n }\n}\n\nfunction fromPiAssistantMessage(message: PiAssistantMessage): SessionMessage {\n const content: SessionContentBlock[] = []\n\n for (const block of message.content) {\n if (block.type === 'text') {\n content.push({ type: 'text', text: block.text })\n }\n else if (block.type === 'thinking') {\n const out: Extract<SessionContentBlock, { type: 'thinking' }> = {\n type: 'thinking',\n text: block.thinking,\n }\n if (typeof block.thinkingSignature === 'string') {\n out.signature = block.thinkingSignature\n out.signatureProducer = 'openai'\n }\n content.push(out)\n }\n else if (block.type === 'toolCall') {\n content.push({ type: 'tool_call', id: block.id, name: block.name, input: block.arguments })\n }\n }\n\n return { role: 'assistant', content }\n}\n\nfunction extractToolCalls(message: PiAssistantMessage) {\n return message.content\n .filter(block => block.type === 'toolCall')\n .map(block => ({\n id: block.id,\n name: block.name,\n input: block.arguments as Record<string, unknown>,\n }))\n}\n\nfunction extractText(message: PiAssistantMessage): string {\n return message.content\n .filter((block): block is Extract<PiAssistantMessage['content'][number], { type: 'text' }> => block.type === 'text')\n .map(block => block.text)\n .join('')\n}\n\nfunction toTurnUsage(usage: PiUsage, finishReason: TurnFinishReason | undefined, modelId: string): Promise<TurnUsage> {\n return fillEstimatedCost({\n input: usage.input,\n output: usage.output,\n cacheRead: usage.cacheRead || undefined,\n cacheCreation: usage.cacheWrite || undefined,\n cost: usage.cost.total || undefined,\n ...(finishReason ? { finishReason } : {}),\n modelId,\n }, 'openai')\n}\n\n/**\n * Transient pi-ai error patterns worth a loop-level retry. pi-ai already retries\n * 429 / 5xx pre-stream 3× internally (see `openai-codex-responses.js`); by the\n * time the error reaches us, that budget is exhausted. The loop-level retry\n * with its longer backoff is a second line of defense for capacity events\n * that persist past pi-ai's short retry window, plus mid-stream emissions\n * (pi-ai surfaces those as plain `Error`s with no status).\n *\n * Mirrors pi-ai's own `isRetryableError` regex so the two retry layers\n * recognize the same failure modes.\n */\nconst TRANSIENT_OPENAI_MESSAGE_RE = /rate.?limit|overloaded|service.?unavailable|upstream.?connect|connection.?refused|gateway.?time.?out|temporarily.?unavailable/i\n\n/** Numeric HTTP status codes pi-ai sometimes attaches when bubbling structured errors. */\nfunction isRetryableStatusCode(err: object): boolean {\n const status = (err as { status?: unknown }).status\n if (typeof status !== 'number')\n return false\n return isRetryableHttpStatus(status)\n}\n\n/**\n * Classify an OpenAI Codex error. pi-ai surfaces errors either as thrown `Error`s\n * (wrapping `event.error.errorMessage`) or via stream event types.\n *\n * Retryable hint is set when pi-ai's own retry budget is exhausted on a\n * transient failure — pattern-matched against `message` since pi-ai strips\n * structured fields on plain-Error throws. Set `behavior.retry.maxAttempts: 1`\n * to disable the loop-level retry.\n */\nexport function classifyOpenAIError(err: unknown): ClassifiedError | null {\n const prelude = classifyErrorPrelude(err)\n if (prelude === 'not-object')\n return null\n if (prelude === 'aborted')\n return { kind: 'aborted' }\n\n const anyErr = err as { name?: string, message?: string, code?: string, type?: string }\n\n const message = anyErr.message ?? ''\n const code = anyErr.code ?? anyErr.type\n\n if (code === 'context_length_exceeded' || matchesContextExceeded(message)) {\n return {\n kind: 'context_exceeded',\n providerCode: code ?? 'context_length_exceeded',\n message,\n }\n }\n\n if (matchesToolPairingError(message)) {\n return {\n kind: 'tool_pairing_corruption',\n providerCode: code ?? 'invalid_request_error',\n message,\n }\n }\n\n // pi-ai wraps API errors in generic `Error` — treat as provider_error when we have a message.\n if (message.length > 0) {\n const retryable = isRetryableStatusCode(anyErr) || TRANSIENT_OPENAI_MESSAGE_RE.test(message)\n return {\n kind: 'provider_error',\n providerCode: code,\n message,\n ...(retryable ? { retryable: true } : {}),\n }\n }\n\n return null\n}\n\n/**\n * A standard OpenAI API key usable against `api.openai.com` (for the exact\n * token-count endpoint), or `null` when only a Codex-OAuth credential is\n * available. Codex OAuth access tokens are JWTs (`eyJ…`) and are NOT valid\n * bearers for the standard API; a real key looks like `sk-…` (but not the\n * Anthropic `sk-ant-…` form). Checks `params.apiKey` then `OPENAI_API_KEY`.\n */\nfunction pickStandardOpenAIKey(params?: OpenAIParams): string | null {\n const candidates = [params?.apiKey, process.env.OPENAI_API_KEY]\n for (const key of candidates) {\n if (typeof key === 'string' && key.startsWith('sk-') && !key.startsWith('sk-ant-'))\n return key\n }\n return null\n}\n\n/**\n * Convert canonical {@link SessionMessage}s to OpenAI Responses-API `input`\n * items for the token-count endpoint. Only the text-bearing shape is needed\n * here (the count path sends a tiny dummy message); images/tool-results are\n * down-converted to text so the count never throws on an exotic block.\n */\nfunction toResponsesInput(messages: SessionMessage[]): unknown[] {\n return messages.map((msg) => {\n const text = msg.content\n .map(b => (b.type === 'text' ? b.text : ''))\n .filter(Boolean)\n .join('\\n')\n const part = msg.role === 'assistant' ? 'output_text' : 'input_text'\n return { role: msg.role === 'assistant' ? 'assistant' : 'user', content: [{ type: part, text }] }\n })\n}\n\n/** Convert pi-ai `PiTool` specs to Responses-API function tools. */\nfunction toResponsesTools(tools: unknown[]): unknown[] {\n return tools.map((t) => {\n const tool = t as { name?: string, description?: string, parameters?: unknown }\n return {\n type: 'function',\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters,\n }\n })\n}\n\nfunction applyPayloadOverrides(payload: unknown, options: StreamOptions): unknown {\n const body = payload as Record<string, unknown>\n\n if (options.toolChoice) {\n if (options.toolChoice.type === 'tool' && options.toolChoice.name)\n body.tool_choice = { type: 'function', name: options.toolChoice.name }\n else if (options.toolChoice.type === 'required')\n body.tool_choice = 'required'\n else\n body.tool_choice = 'auto'\n }\n\n return body\n}\n\nexport function openai(params?: OpenAIParams): Provider {\n const defaultModel = params?.defaultModel || DEFAULT_MODEL\n const baseCredentials = extractRuntimeCredentials(params)\n let runtimeCredentials = baseCredentials\n ? { ...baseCredentials, ...(params?.accountId ? { accountId: params.accountId } : {}) }\n : undefined\n\n return {\n name: 'openai',\n meta: {\n defaultModel,\n isOAuth: true,\n capabilities: {\n vision: true,\n imageInToolResult: true,\n // pi-ai's Codex Responses wire has no audio/video input content type.\n audio: false,\n video: false,\n },\n },\n formatTools,\n userMessage,\n assistantMessage,\n toolResultsMessage,\n classifyError: classifyOpenAIError,\n\n async countTokens(payload, signal): Promise<number | null> {\n // The exact count endpoint (`POST /v1/responses/input_tokens`) lives on\n // the standard OpenAI API and needs a standard `OPENAI_API_KEY` bearer.\n // This provider authenticates via Codex OAuth against the Codex backend,\n // whose token is NOT valid for that endpoint — so we only attempt the\n // count when a standard key is present (env or params.apiKey that isn't\n // an OAuth/JWT token). Otherwise return null → heuristic fallback.\n const standardKey = pickStandardOpenAIKey(params)\n if (!standardKey)\n return null\n try {\n const res = await fetch('https://api.openai.com/v1/responses/input_tokens', {\n method: 'POST',\n headers: {\n ...params?.extraHeaders,\n 'authorization': `Bearer ${standardKey}`,\n 'content-type': 'application/json',\n },\n // The Responses `input_tokens` endpoint takes the same shape as\n // `responses.create`: `instructions` (system), `input` (Responses\n // input items — NOT pi-ai messages), and function-shaped `tools`.\n body: JSON.stringify({\n model: payload.model || defaultModel,\n instructions: renderSystemForWire(payload.system),\n input: toResponsesInput(payload.messages),\n tools: toResponsesTools(payload.tools),\n }),\n ...(signal ? { signal } : {}),\n })\n if (!res.ok)\n return null\n const json = (await res.json()) as { input_tokens?: unknown }\n return typeof json.input_tokens === 'number' ? json.input_tokens : null\n }\n catch {\n return null\n }\n },\n\n async stream(options: StreamOptions, callbacks: StreamCallbacks): Promise<TurnResult> {\n const modelId = options.model || defaultModel\n const model = resolveModel(modelId)\n const apiKey = await resolveOAuthApiKey(\n {\n provider: 'openai',\n providerId: PROVIDER_ID,\n params: runtimeCredentials ? { ...params, ...runtimeCredentials } : params,\n envKey: 'OPENAI_CODEX_API_KEY',\n extraCredentialKeys: ['accountId'],\n missingError: 'No OpenAI Codex OAuth token found. Run `bun run auth --openai` first.',\n refreshError: reason => `OpenAI Codex OAuth token refresh failed. Run \\`bun run auth --openai\\` again. ${reason}`,\n },\n {\n ...callbacks,\n async onOAuthRefresh(ctx) {\n if (ctx.source === 'params') {\n runtimeCredentials = {\n access: ctx.credentials.access,\n refresh: ctx.credentials.refresh,\n expires: ctx.credentials.expires,\n ...(typeof ctx.credentials.accountId === 'string' ? { accountId: ctx.credentials.accountId } : {}),\n }\n }\n await callbacks.onOAuthRefresh?.(ctx)\n },\n },\n )\n // Codex's Responses API has no `cache_control` analogue, but the\n // system-prompt boundary marker is structural metadata that should\n // never reach the model. Strip it via `renderSystemForWire`; the\n // doctrine + env are collapsed into a single byte stream the model\n // sees as one logical prompt.\n const context: PiContext = {\n systemPrompt: renderSystemForWire(options.system),\n messages: toPiMessages(options.messages, modelId),\n tools: options.tools as PiTool[],\n }\n // OpenAI's `reasoning_effort` accepts minimal/low/medium/high/xhigh.\n // Clamp only Anthropic's `max` tier to `xhigh`; `'adaptive'` degrades to\n // no reasoning rather than forwarding an unknown value the API would reject.\n const reasoningLevel\n = options.thinking && options.thinking !== 'off' && options.thinking !== 'adaptive'\n ? options.thinking === 'max' ? 'xhigh' : options.thinking\n : undefined\n const stream = streamOpenAICodexResponses(model, context, {\n apiKey,\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n signal: options.signal,\n transport: params?.transport,\n reasoningEffort: reasoningLevel,\n reasoningSummary: reasoningLevel ? 'auto' : undefined,\n ...(options.modelOptions?.fast ? { serviceTier: 'priority' as const } : {}),\n ...(params?.extraHeaders ? { headers: params.extraHeaders } : {}),\n onPayload: payload => applyPayloadOverrides(payload, options),\n })\n\n let finalMessage: PiAssistantMessage | undefined\n let text = ''\n let thinking = ''\n\n for await (const event of stream) {\n if (event.type === 'text_delta') {\n text += event.delta\n callbacks.onText(event.delta)\n }\n else if (event.type === 'thinking_delta') {\n thinking += event.delta\n callbacks.onThinking?.(event.delta)\n }\n else if (event.type === 'thinking_end') {\n const delta = event.content.startsWith(thinking)\n ? event.content.slice(thinking.length)\n : (thinking ? '' : event.content)\n if (delta) {\n thinking += delta\n callbacks.onThinking?.(delta)\n }\n }\n else if (event.type === 'done') {\n finalMessage = event.message\n }\n else if (event.type === 'error') {\n throw new Error(event.error.errorMessage || 'OpenAI Codex API error')\n }\n }\n\n finalMessage ??= await stream.result()\n text ||= extractText(finalMessage)\n\n const toolCalls = extractToolCalls(finalMessage)\n const assistantTurn = fromPiAssistantMessage(finalMessage)\n const finishReason = mapCodexStopReason(finalMessage.stopReason, toolCalls.length > 0)\n const usage = await toTurnUsage(finalMessage.usage, finishReason, modelId)\n\n return {\n assistantMessage: assistantTurn,\n text,\n toolCalls,\n done: toolCalls.length === 0,\n usage,\n }\n },\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { Bt as openrouter, Rt as OpenRouterParams, zt as normalizeOpenRouterModelId } from "../agent-EFWt6uQ_.js";
1
+ import { Dp as OpenRouterParams, Op as normalizeOpenRouterModelId, kp as openrouter } from "../index-B8UtiZy7.js";
2
2
  export { OpenRouterParams, normalizeOpenRouterModelId, openrouter };
@@ -1,4 +1,4 @@
1
- import { m as openaiCompat } from "../openai-compat-0Y7jcncn.js";
1
+ import { m as openaiCompat } from "../openai-compat-BvgYGSR1.js";
2
2
  //#region src/providers/openrouter.ts
3
3
  const BASE_URL = "https://openrouter.ai/api/v1";
4
4
  const DEFAULT_MODEL = "anthropic/claude-sonnet-4.6";
@@ -1,2 +1,2 @@
1
- import { Mt as xai, jt as XaiParams } from "../agent-EFWt6uQ_.js";
1
+ import { bp as XaiParams, xp as xai } from "../index-B8UtiZy7.js";
2
2
  export { XaiParams, xai };
@@ -1,2 +1,2 @@
1
- import { t as xai } from "../xai-tPdbAGkq.js";
1
+ import { t as xai } from "../xai-B_e6TOA8.js";
2
2
  export { xai };
@@ -1,6 +1,6 @@
1
- import { m as openaiCompat } from "./openai-compat-0Y7jcncn.js";
1
+ import { m as openaiCompat } from "./openai-compat-BvgYGSR1.js";
2
2
  import { i as resolveOAuthApiKey } from "./oauth-8LqbeI_Q.js";
3
- import { r as generatePkce } from "./xai-tPdbAGkq.js";
3
+ import { r as generatePkce } from "./xai-B_e6TOA8.js";
4
4
  //#region src/chat/oauth-page/cursor.ts
5
5
  /** pi-ai / zidane OAuth provider id. Also the credentials-file key. */
6
6
  const CURSOR_OAUTH_PROVIDER_ID = "cursor";
@@ -165,4 +165,4 @@ function cursor(params) {
165
165
  //#endregion
166
166
  export { createCursorOAuthProvider as n, cursor as t };
167
167
 
168
- //# sourceMappingURL=providers-DgmdYGKm.js.map
168
+ //# sourceMappingURL=providers-z6LDMAr3.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"providers-DgmdYGKm.js","names":[],"sources":["../src/chat/oauth-page/cursor.ts","../src/providers/cursor.ts"],"sourcesContent":["/**\n * Cursor OAuth flow.\n *\n * Unlike Anthropic / OpenAI Codex (loopback-redirect PKCE), Cursor uses a\n * **poll-based** PKCE flow with no local callback server:\n *\n * 1. Generate a PKCE verifier + challenge and a random UUID.\n * 2. Open the browser to `cursor.com/loginDeepControl?challenge&uuid&mode&redirectTarget`.\n * 3. Poll `api2.cursor.sh/auth/poll?uuid&verifier` until tokens come back\n * (HTTP 404 = \"not ready yet\", keep polling with backoff).\n * 4. Refresh via `POST api2.cursor.sh/auth/exchange_user_api_key` with\n * `Authorization: Bearer <refresh>`.\n *\n * Token expiry is derived from the access token's JWT `exp` claim (minus a\n * 5-minute safety margin), falling back to +1h when the claim is missing.\n *\n * Flow adapted from https://github.com/ndraiman/pi-cursor-provider, itself\n * derived from https://github.com/ephraimduncan/opencode-cursor.\n *\n * Cursor's auth + inference protocol is unofficial and undocumented — re-verify\n * the endpoints/params below if login starts failing.\n */\n\nimport type {\n OAuthCredentials,\n OAuthLoginCallbacks,\n OAuthProviderInterface,\n} from '@earendil-works/pi-ai/oauth'\nimport { generatePkce } from './pkce'\n\n/** pi-ai / zidane OAuth provider id. Also the credentials-file key. */\nexport const CURSOR_OAUTH_PROVIDER_ID = 'cursor'\n\nconst CURSOR_LOGIN_URL = 'https://cursor.com/loginDeepControl'\nconst CURSOR_POLL_URL = 'https://api2.cursor.sh/auth/poll'\nconst CURSOR_REFRESH_URL = 'https://api2.cursor.sh/auth/exchange_user_api_key'\n\nconst POLL_MAX_ATTEMPTS = 150\nconst POLL_BASE_DELAY_MS = 1000\nconst POLL_MAX_DELAY_MS = 10_000\nconst POLL_BACKOFF_MULTIPLIER = 1.2\nconst POLL_MAX_CONSECUTIVE_ERRORS = 3\n\n/** Fallback lifetime when the JWT carries no `exp`. */\nconst DEFAULT_TOKEN_TTL_MS = 3600 * 1000\n/** Refresh slightly early so requests don't race expiry. */\nconst TOKEN_EXPIRY_SKEW_MS = 5 * 60 * 1000\n\ninterface CursorTokenResponse {\n accessToken: string\n refreshToken: string\n}\n\n/**\n * Derive expiry (epoch ms) from a JWT's `exp` claim, minus a safety skew.\n * Returns `now + 1h` for malformed tokens so a missing claim never wedges\n * refresh into an immediate-expire loop.\n */\nexport function cursorTokenExpiry(token: string): number {\n try {\n const parts = token.split('.')\n const payload = parts[1]\n if (parts.length !== 3 || !payload)\n return Date.now() + DEFAULT_TOKEN_TTL_MS\n\n const json = JSON.parse(atob(payload.replace(/-/g, '+').replace(/_/g, '/'))) as { exp?: unknown }\n if (typeof json.exp === 'number')\n return json.exp * 1000 - TOKEN_EXPIRY_SKEW_MS\n }\n catch {\n // fall through to default\n }\n return Date.now() + DEFAULT_TOKEN_TTL_MS\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise(r => setTimeout(r, ms))\n}\n\n/**\n * Poll Cursor's auth endpoint until login completes. `404` means the user\n * hasn't finished the browser flow yet; anything else non-2xx is a hard error.\n */\nasync function pollForTokens(\n uuid: string,\n verifier: string,\n callbacks: OAuthLoginCallbacks,\n): Promise<CursorTokenResponse> {\n let wait = POLL_BASE_DELAY_MS\n let consecutiveErrors = 0\n\n for (let attempt = 0; attempt < POLL_MAX_ATTEMPTS; attempt++) {\n if (callbacks.signal?.aborted)\n throw new Error('Cursor login aborted')\n\n await delay(wait)\n\n try {\n const url = `${CURSOR_POLL_URL}?uuid=${encodeURIComponent(uuid)}&verifier=${encodeURIComponent(verifier)}`\n const response = await fetch(url, { signal: callbacks.signal })\n\n if (response.status === 404) {\n consecutiveErrors = 0\n wait = Math.min(wait * POLL_BACKOFF_MULTIPLIER, POLL_MAX_DELAY_MS)\n continue\n }\n\n if (response.ok) {\n const data = await response.json() as Partial<CursorTokenResponse>\n if (!data.accessToken || !data.refreshToken)\n throw new Error(`Cursor poll response missing tokens: ${JSON.stringify(data)}`)\n return { accessToken: data.accessToken, refreshToken: data.refreshToken }\n }\n\n throw new Error(`Cursor poll failed (${response.status})`)\n }\n catch (err) {\n if (callbacks.signal?.aborted)\n throw new Error('Cursor login aborted')\n consecutiveErrors++\n if (consecutiveErrors >= POLL_MAX_CONSECUTIVE_ERRORS)\n throw err instanceof Error ? err : new Error(String(err))\n callbacks.onProgress?.('Waiting for Cursor login to complete…')\n }\n }\n\n throw new Error('Cursor authentication timed out')\n}\n\nexport async function loginCursor(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n const { verifier, challenge } = await generatePkce()\n const uuid = crypto.randomUUID()\n\n const authUrl = new URL(CURSOR_LOGIN_URL)\n authUrl.searchParams.set('challenge', challenge)\n authUrl.searchParams.set('uuid', uuid)\n authUrl.searchParams.set('mode', 'login')\n authUrl.searchParams.set('redirectTarget', 'cli')\n\n callbacks.onAuth({\n url: authUrl.toString(),\n instructions: 'A browser window should open. Complete login in Cursor to finish.',\n })\n\n const tokens = await pollForTokens(uuid, verifier, callbacks)\n\n return {\n access: tokens.accessToken,\n refresh: tokens.refreshToken,\n expires: cursorTokenExpiry(tokens.accessToken),\n }\n}\n\nexport async function refreshCursorToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n const response = await fetch(CURSOR_REFRESH_URL, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${credentials.refresh}`,\n 'Content-Type': 'application/json',\n },\n body: '{}',\n })\n\n if (!response.ok) {\n const text = await response.text().catch(() => '')\n throw new Error(`Cursor token refresh failed (${response.status}): ${text || response.statusText}`)\n }\n\n const data = await response.json() as Partial<CursorTokenResponse>\n if (!data.accessToken)\n throw new Error(`Cursor token refresh response missing access token: ${JSON.stringify(data)}`)\n\n return {\n access: data.accessToken,\n // Cursor may omit a rotated refresh token — keep the existing one.\n refresh: data.refreshToken || credentials.refresh,\n expires: cursorTokenExpiry(data.accessToken),\n }\n}\n\n/**\n * Build a Cursor `OAuthProviderInterface`. Shape matches Anthropic / Codex so\n * it drops into `BUILTIN_PROVIDERS` and `src/auth.ts` unchanged.\n *\n * No `renderPage` parameter: Cursor's poll flow has no local callback server,\n * so there is no post-redirect page to theme.\n */\nexport function createCursorOAuthProvider(): OAuthProviderInterface {\n return {\n id: CURSOR_OAUTH_PROVIDER_ID,\n name: 'Cursor',\n usesCallbackServer: false,\n login: loginCursor,\n refreshToken: refreshCursorToken,\n getApiKey: credentials => credentials.access,\n }\n}\n","import type { Provider, StreamCallbacks } from '.'\nimport { CURSOR_OAUTH_PROVIDER_ID } from '../chat/oauth-page/cursor'\nimport { resolveOAuthApiKey } from './oauth'\nimport { openaiCompat } from './openai-compat'\n\n/**\n * Cursor provider (OAuth).\n *\n * Auth is fully wired: `bun run auth --cursor` (or the TUI wizard) logs in via\n * Cursor's poll-based PKCE flow and persists credentials; this provider resolves\n * + refreshes the OAuth token on every turn via {@link resolveOAuthApiKey}.\n *\n * Inference is **not** wired yet. Cursor does not expose an OpenAI-compatible\n * HTTP endpoint — it speaks a protobuf/Connect agent protocol over HTTP/2 to\n * `api2.cursor.sh`. Implementing `stream()` requires porting that transport\n * (generated protobuf schemas + an HTTP/2 streaming client) in-process, which\n * is intentionally left as a follow-up. Until then `stream()` resolves the\n * token (proving auth works) and then throws a clear, actionable error.\n *\n * The `openaiCompat` base supplies the message-format helpers (`formatTools`,\n * `userMessage`, `toolResultsMessage`, …) so the provider satisfies the full\n * `Provider` contract and slots into the registry; only `stream` is overridden.\n */\nexport interface CursorParams {\n /** Bypass OAuth resolution with an explicit token (mainly for tests). */\n apiKey?: string\n defaultModel?: string\n /**\n * Extra HTTP headers for the eventual Cursor transport. Accepted for API\n * parity with the other providers and forwarded to the openai-compat base,\n * but inert until Cursor inference is implemented (the `stream` override\n * currently throws before any request is made).\n */\n extraHeaders?: Record<string, string>\n}\n\nconst DEFAULT_MODEL = 'claude-4.6-sonnet'\n\nconst NOT_IMPLEMENTED_MESSAGE\n = 'Cursor OAuth login works, but inference over Cursor is not implemented yet. '\n + 'Cursor uses a protobuf/HTTP-2 agent protocol (not an OpenAI-compatible API), '\n + 'so the streaming transport still needs to be ported. Use another provider for now.'\n\nexport function cursor(params?: CursorParams): Provider {\n const defaultModel = params?.defaultModel || DEFAULT_MODEL\n\n // Base only provides the format/serialization methods; `baseURL` is never\n // hit because we override `stream` below.\n const base = openaiCompat({\n name: 'cursor',\n apiKey: params?.apiKey ?? 'oauth',\n baseURL: 'https://api2.cursor.sh',\n defaultModel,\n capabilities: { vision: true, imageInToolResult: false },\n extraHeaders: params?.extraHeaders,\n })\n\n return {\n ...base,\n meta: { ...base.meta, defaultModel },\n async stream(options, callbacks: StreamCallbacks) {\n // Resolve (and lazily refresh) the OAuth token so auth failures surface\n // here with the right remediation, distinct from the not-implemented path.\n await resolveOAuthApiKey(\n {\n provider: 'cursor',\n providerId: CURSOR_OAUTH_PROVIDER_ID,\n params,\n missingError: 'No Cursor credentials found. Run `bun run auth --cursor` first.',\n refreshError: reason => `Cursor OAuth token refresh failed. Run \\`bun run auth --cursor\\` again. ${reason}`,\n },\n callbacks,\n )\n void options\n throw new Error(NOT_IMPLEMENTED_MESSAGE)\n },\n }\n}\n"],"mappings":";;;;;AA+BA,MAAa,2BAA2B;AAExC,MAAM,mBAAmB;AACzB,MAAM,kBAAkB;AACxB,MAAM,qBAAqB;AAE3B,MAAM,oBAAoB;AAC1B,MAAM,qBAAqB;AAC3B,MAAM,oBAAoB;AAC1B,MAAM,0BAA0B;AAChC,MAAM,8BAA8B;;AAGpC,MAAM,uBAAuB,OAAO;;AAEpC,MAAM,uBAAuB,MAAS;;;;;;AAYtC,SAAgB,kBAAkB,OAAuB;CACvD,IAAI;EACF,MAAM,QAAQ,MAAM,MAAM,GAAG;EAC7B,MAAM,UAAU,MAAM;EACtB,IAAI,MAAM,WAAW,KAAK,CAAC,SACzB,OAAO,KAAK,IAAI,IAAI;EAEtB,MAAM,OAAO,KAAK,MAAM,KAAK,QAAQ,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG,CAAC,CAAC;EAC3E,IAAI,OAAO,KAAK,QAAQ,UACtB,OAAO,KAAK,MAAM,MAAO;CAC7B,QACM,CAEN;CACA,OAAO,KAAK,IAAI,IAAI;AACtB;AAEA,SAAS,MAAM,IAA2B;CACxC,OAAO,IAAI,SAAQ,MAAK,WAAW,GAAG,EAAE,CAAC;AAC3C;;;;;AAMA,eAAe,cACb,MACA,UACA,WAC8B;CAC9B,IAAI,OAAO;CACX,IAAI,oBAAoB;CAExB,KAAK,IAAI,UAAU,GAAG,UAAU,mBAAmB,WAAW;EAC5D,IAAI,UAAU,QAAQ,SACpB,MAAM,IAAI,MAAM,sBAAsB;EAExC,MAAM,MAAM,IAAI;EAEhB,IAAI;GACF,MAAM,MAAM,GAAG,gBAAgB,QAAQ,mBAAmB,IAAI,EAAE,YAAY,mBAAmB,QAAQ;GACvG,MAAM,WAAW,MAAM,MAAM,KAAK,EAAE,QAAQ,UAAU,OAAO,CAAC;GAE9D,IAAI,SAAS,WAAW,KAAK;IAC3B,oBAAoB;IACpB,OAAO,KAAK,IAAI,OAAO,yBAAyB,iBAAiB;IACjE;GACF;GAEA,IAAI,SAAS,IAAI;IACf,MAAM,OAAO,MAAM,SAAS,KAAK;IACjC,IAAI,CAAC,KAAK,eAAe,CAAC,KAAK,cAC7B,MAAM,IAAI,MAAM,wCAAwC,KAAK,UAAU,IAAI,GAAG;IAChF,OAAO;KAAE,aAAa,KAAK;KAAa,cAAc,KAAK;IAAa;GAC1E;GAEA,MAAM,IAAI,MAAM,uBAAuB,SAAS,OAAO,EAAE;EAC3D,SACO,KAAK;GACV,IAAI,UAAU,QAAQ,SACpB,MAAM,IAAI,MAAM,sBAAsB;GACxC;GACA,IAAI,qBAAqB,6BACvB,MAAM,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;GAC1D,UAAU,aAAa,uCAAuC;EAChE;CACF;CAEA,MAAM,IAAI,MAAM,iCAAiC;AACnD;AAEA,eAAsB,YAAY,WAA2D;CAC3F,MAAM,EAAE,UAAU,cAAc,MAAM,aAAa;CACnD,MAAM,OAAO,OAAO,WAAW;CAE/B,MAAM,UAAU,IAAI,IAAI,gBAAgB;CACxC,QAAQ,aAAa,IAAI,aAAa,SAAS;CAC/C,QAAQ,aAAa,IAAI,QAAQ,IAAI;CACrC,QAAQ,aAAa,IAAI,QAAQ,OAAO;CACxC,QAAQ,aAAa,IAAI,kBAAkB,KAAK;CAEhD,UAAU,OAAO;EACf,KAAK,QAAQ,SAAS;EACtB,cAAc;CAChB,CAAC;CAED,MAAM,SAAS,MAAM,cAAc,MAAM,UAAU,SAAS;CAE5D,OAAO;EACL,QAAQ,OAAO;EACf,SAAS,OAAO;EAChB,SAAS,kBAAkB,OAAO,WAAW;CAC/C;AACF;AAEA,eAAsB,mBAAmB,aAA0D;CACjG,MAAM,WAAW,MAAM,MAAM,oBAAoB;EAC/C,QAAQ;EACR,SAAS;GACP,iBAAiB,UAAU,YAAY;GACvC,gBAAgB;EAClB;EACA,MAAM;CACR,CAAC;CAED,IAAI,CAAC,SAAS,IAAI;EAChB,MAAM,OAAO,MAAM,SAAS,KAAK,EAAE,YAAY,EAAE;EACjD,MAAM,IAAI,MAAM,gCAAgC,SAAS,OAAO,KAAK,QAAQ,SAAS,YAAY;CACpG;CAEA,MAAM,OAAO,MAAM,SAAS,KAAK;CACjC,IAAI,CAAC,KAAK,aACR,MAAM,IAAI,MAAM,uDAAuD,KAAK,UAAU,IAAI,GAAG;CAE/F,OAAO;EACL,QAAQ,KAAK;EAEb,SAAS,KAAK,gBAAgB,YAAY;EAC1C,SAAS,kBAAkB,KAAK,WAAW;CAC7C;AACF;;;;;;;;AASA,SAAgB,4BAAoD;CAClE,OAAO;EACL,IAAI;EACJ,MAAM;EACN,oBAAoB;EACpB,OAAO;EACP,cAAc;EACd,YAAW,gBAAe,YAAY;CACxC;AACF;;;AChKA,MAAM,gBAAgB;AAEtB,MAAM,0BACF;AAIJ,SAAgB,OAAO,QAAiC;CACtD,MAAM,eAAe,QAAQ,gBAAgB;CAI7C,MAAM,OAAO,aAAa;EACxB,MAAM;EACN,QAAQ,QAAQ,UAAU;EAC1B,SAAS;EACT;EACA,cAAc;GAAE,QAAQ;GAAM,mBAAmB;EAAM;EACvD,cAAc,QAAQ;CACxB,CAAC;CAED,OAAO;EACL,GAAG;EACH,MAAM;GAAE,GAAG,KAAK;GAAM;EAAa;EACnC,MAAM,OAAO,SAAS,WAA4B;GAGhD,MAAM,mBACJ;IACE,UAAU;IACV,YAAY;IACZ;IACA,cAAc;IACd,eAAc,WAAU,2EAA2E;GACrG,GACA,SACF;GAEA,MAAM,IAAI,MAAM,uBAAuB;EACzC;CACF;AACF"}
1
+ {"version":3,"file":"providers-z6LDMAr3.js","names":[],"sources":["../src/chat/oauth-page/cursor.ts","../src/providers/cursor.ts"],"sourcesContent":["/**\n * Cursor OAuth flow.\n *\n * Unlike Anthropic / OpenAI Codex (loopback-redirect PKCE), Cursor uses a\n * **poll-based** PKCE flow with no local callback server:\n *\n * 1. Generate a PKCE verifier + challenge and a random UUID.\n * 2. Open the browser to `cursor.com/loginDeepControl?challenge&uuid&mode&redirectTarget`.\n * 3. Poll `api2.cursor.sh/auth/poll?uuid&verifier` until tokens come back\n * (HTTP 404 = \"not ready yet\", keep polling with backoff).\n * 4. Refresh via `POST api2.cursor.sh/auth/exchange_user_api_key` with\n * `Authorization: Bearer <refresh>`.\n *\n * Token expiry is derived from the access token's JWT `exp` claim (minus a\n * 5-minute safety margin), falling back to +1h when the claim is missing.\n *\n * Flow adapted from https://github.com/ndraiman/pi-cursor-provider, itself\n * derived from https://github.com/ephraimduncan/opencode-cursor.\n *\n * Cursor's auth + inference protocol is unofficial and undocumented — re-verify\n * the endpoints/params below if login starts failing.\n */\n\nimport type {\n OAuthCredentials,\n OAuthLoginCallbacks,\n OAuthProviderInterface,\n} from '@earendil-works/pi-ai/oauth'\nimport { generatePkce } from './pkce'\n\n/** pi-ai / zidane OAuth provider id. Also the credentials-file key. */\nexport const CURSOR_OAUTH_PROVIDER_ID = 'cursor'\n\nconst CURSOR_LOGIN_URL = 'https://cursor.com/loginDeepControl'\nconst CURSOR_POLL_URL = 'https://api2.cursor.sh/auth/poll'\nconst CURSOR_REFRESH_URL = 'https://api2.cursor.sh/auth/exchange_user_api_key'\n\nconst POLL_MAX_ATTEMPTS = 150\nconst POLL_BASE_DELAY_MS = 1000\nconst POLL_MAX_DELAY_MS = 10_000\nconst POLL_BACKOFF_MULTIPLIER = 1.2\nconst POLL_MAX_CONSECUTIVE_ERRORS = 3\n\n/** Fallback lifetime when the JWT carries no `exp`. */\nconst DEFAULT_TOKEN_TTL_MS = 3600 * 1000\n/** Refresh slightly early so requests don't race expiry. */\nconst TOKEN_EXPIRY_SKEW_MS = 5 * 60 * 1000\n\ninterface CursorTokenResponse {\n accessToken: string\n refreshToken: string\n}\n\n/**\n * Derive expiry (epoch ms) from a JWT's `exp` claim, minus a safety skew.\n * Returns `now + 1h` for malformed tokens so a missing claim never wedges\n * refresh into an immediate-expire loop.\n */\nexport function cursorTokenExpiry(token: string): number {\n try {\n const parts = token.split('.')\n const payload = parts[1]\n if (parts.length !== 3 || !payload)\n return Date.now() + DEFAULT_TOKEN_TTL_MS\n\n const json = JSON.parse(atob(payload.replace(/-/g, '+').replace(/_/g, '/'))) as { exp?: unknown }\n if (typeof json.exp === 'number')\n return json.exp * 1000 - TOKEN_EXPIRY_SKEW_MS\n }\n catch {\n // fall through to default\n }\n return Date.now() + DEFAULT_TOKEN_TTL_MS\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise(r => setTimeout(r, ms))\n}\n\n/**\n * Poll Cursor's auth endpoint until login completes. `404` means the user\n * hasn't finished the browser flow yet; anything else non-2xx is a hard error.\n */\nasync function pollForTokens(\n uuid: string,\n verifier: string,\n callbacks: OAuthLoginCallbacks,\n): Promise<CursorTokenResponse> {\n let wait = POLL_BASE_DELAY_MS\n let consecutiveErrors = 0\n\n for (let attempt = 0; attempt < POLL_MAX_ATTEMPTS; attempt++) {\n if (callbacks.signal?.aborted)\n throw new Error('Cursor login aborted')\n\n await delay(wait)\n\n try {\n const url = `${CURSOR_POLL_URL}?uuid=${encodeURIComponent(uuid)}&verifier=${encodeURIComponent(verifier)}`\n const response = await fetch(url, { signal: callbacks.signal })\n\n if (response.status === 404) {\n consecutiveErrors = 0\n wait = Math.min(wait * POLL_BACKOFF_MULTIPLIER, POLL_MAX_DELAY_MS)\n continue\n }\n\n if (response.ok) {\n const data = await response.json() as Partial<CursorTokenResponse>\n if (!data.accessToken || !data.refreshToken)\n throw new Error(`Cursor poll response missing tokens: ${JSON.stringify(data)}`)\n return { accessToken: data.accessToken, refreshToken: data.refreshToken }\n }\n\n throw new Error(`Cursor poll failed (${response.status})`)\n }\n catch (err) {\n if (callbacks.signal?.aborted)\n throw new Error('Cursor login aborted')\n consecutiveErrors++\n if (consecutiveErrors >= POLL_MAX_CONSECUTIVE_ERRORS)\n throw err instanceof Error ? err : new Error(String(err))\n callbacks.onProgress?.('Waiting for Cursor login to complete…')\n }\n }\n\n throw new Error('Cursor authentication timed out')\n}\n\nexport async function loginCursor(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n const { verifier, challenge } = await generatePkce()\n const uuid = crypto.randomUUID()\n\n const authUrl = new URL(CURSOR_LOGIN_URL)\n authUrl.searchParams.set('challenge', challenge)\n authUrl.searchParams.set('uuid', uuid)\n authUrl.searchParams.set('mode', 'login')\n authUrl.searchParams.set('redirectTarget', 'cli')\n\n callbacks.onAuth({\n url: authUrl.toString(),\n instructions: 'A browser window should open. Complete login in Cursor to finish.',\n })\n\n const tokens = await pollForTokens(uuid, verifier, callbacks)\n\n return {\n access: tokens.accessToken,\n refresh: tokens.refreshToken,\n expires: cursorTokenExpiry(tokens.accessToken),\n }\n}\n\nexport async function refreshCursorToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n const response = await fetch(CURSOR_REFRESH_URL, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${credentials.refresh}`,\n 'Content-Type': 'application/json',\n },\n body: '{}',\n })\n\n if (!response.ok) {\n const text = await response.text().catch(() => '')\n throw new Error(`Cursor token refresh failed (${response.status}): ${text || response.statusText}`)\n }\n\n const data = await response.json() as Partial<CursorTokenResponse>\n if (!data.accessToken)\n throw new Error(`Cursor token refresh response missing access token: ${JSON.stringify(data)}`)\n\n return {\n access: data.accessToken,\n // Cursor may omit a rotated refresh token — keep the existing one.\n refresh: data.refreshToken || credentials.refresh,\n expires: cursorTokenExpiry(data.accessToken),\n }\n}\n\n/**\n * Build a Cursor `OAuthProviderInterface`. Shape matches Anthropic / Codex so\n * it drops into `BUILTIN_PROVIDERS` and `src/auth.ts` unchanged.\n *\n * No `renderPage` parameter: Cursor's poll flow has no local callback server,\n * so there is no post-redirect page to theme.\n */\nexport function createCursorOAuthProvider(): OAuthProviderInterface {\n return {\n id: CURSOR_OAUTH_PROVIDER_ID,\n name: 'Cursor',\n usesCallbackServer: false,\n login: loginCursor,\n refreshToken: refreshCursorToken,\n getApiKey: credentials => credentials.access,\n }\n}\n","import type { Provider, StreamCallbacks } from '.'\nimport { CURSOR_OAUTH_PROVIDER_ID } from '../chat/oauth-page/cursor'\nimport { resolveOAuthApiKey } from './oauth'\nimport { openaiCompat } from './openai-compat'\n\n/**\n * Cursor provider (OAuth).\n *\n * Auth is fully wired: `bun run auth --cursor` (or the TUI wizard) logs in via\n * Cursor's poll-based PKCE flow and persists credentials; this provider resolves\n * + refreshes the OAuth token on every turn via {@link resolveOAuthApiKey}.\n *\n * Inference is **not** wired yet. Cursor does not expose an OpenAI-compatible\n * HTTP endpoint — it speaks a protobuf/Connect agent protocol over HTTP/2 to\n * `api2.cursor.sh`. Implementing `stream()` requires porting that transport\n * (generated protobuf schemas + an HTTP/2 streaming client) in-process, which\n * is intentionally left as a follow-up. Until then `stream()` resolves the\n * token (proving auth works) and then throws a clear, actionable error.\n *\n * The `openaiCompat` base supplies the message-format helpers (`formatTools`,\n * `userMessage`, `toolResultsMessage`, …) so the provider satisfies the full\n * `Provider` contract and slots into the registry; only `stream` is overridden.\n */\nexport interface CursorParams {\n /** Bypass OAuth resolution with an explicit token (mainly for tests). */\n apiKey?: string\n defaultModel?: string\n /**\n * Extra HTTP headers for the eventual Cursor transport. Accepted for API\n * parity with the other providers and forwarded to the openai-compat base,\n * but inert until Cursor inference is implemented (the `stream` override\n * currently throws before any request is made).\n */\n extraHeaders?: Record<string, string>\n}\n\nconst DEFAULT_MODEL = 'claude-4.6-sonnet'\n\nconst NOT_IMPLEMENTED_MESSAGE\n = 'Cursor OAuth login works, but inference over Cursor is not implemented yet. '\n + 'Cursor uses a protobuf/HTTP-2 agent protocol (not an OpenAI-compatible API), '\n + 'so the streaming transport still needs to be ported. Use another provider for now.'\n\nexport function cursor(params?: CursorParams): Provider {\n const defaultModel = params?.defaultModel || DEFAULT_MODEL\n\n // Base only provides the format/serialization methods; `baseURL` is never\n // hit because we override `stream` below.\n const base = openaiCompat({\n name: 'cursor',\n apiKey: params?.apiKey ?? 'oauth',\n baseURL: 'https://api2.cursor.sh',\n defaultModel,\n capabilities: { vision: true, imageInToolResult: false },\n extraHeaders: params?.extraHeaders,\n })\n\n return {\n ...base,\n meta: { ...base.meta, defaultModel },\n async stream(options, callbacks: StreamCallbacks) {\n // Resolve (and lazily refresh) the OAuth token so auth failures surface\n // here with the right remediation, distinct from the not-implemented path.\n await resolveOAuthApiKey(\n {\n provider: 'cursor',\n providerId: CURSOR_OAUTH_PROVIDER_ID,\n params,\n missingError: 'No Cursor credentials found. Run `bun run auth --cursor` first.',\n refreshError: reason => `Cursor OAuth token refresh failed. Run \\`bun run auth --cursor\\` again. ${reason}`,\n },\n callbacks,\n )\n void options\n throw new Error(NOT_IMPLEMENTED_MESSAGE)\n },\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { $t as classifyOpenAICompatError, At as TurnResult, Bt as openrouter, Cn as arcee, Ct as ProviderCapabilities, Dn as anthropic, Dt as ToolCall, Et as TokenCountPayload, Ft as SchemaSanitizeResult, Gt as OpenAICompatHttpError, It as sanitizeToolSchema, Kt as OpenAICompatParams, Lt as sanitizeToolSpecs, Mt as xai, Nt as SchemaSanitizeOptions, On as applyAnthropicCacheBreakpoints, Ot as ToolResult, Pt as SchemaSanitizeProfile, Rt as OpenRouterParams, Sn as ArceeParams, St as Provider, Tn as AnthropicParams, Tt as StreamOptions, Wt as OpenAICompatAuthHeader, _n as CerebrasParams, bn as baseten, cn as OpenAIParams, dn as openai, gn as cursor, hn as CursorParams, in as openaiCompat, jt as XaiParams, kt as ToolSpec, mn as local, nn as mapOAIFinishReason, pn as LocalParams, vn as cerebras, wt as StreamCallbacks, xn as planBasetenReasoning, yn as BasetenParams } from "./agent-EFWt6uQ_.js";
1
+ import { Cp as SchemaSanitizeProfile, Dp as OpenRouterParams, Ep as sanitizeToolSpecs, Fp as OpenAICompatParams, Gp as mapOAIFinishReason, Hp as classifyOpenAICompatError, Np as OpenAICompatAuthHeader, Pp as OpenAICompatHttpError, Sp as SchemaSanitizeOptions, Tp as sanitizeToolSchema, Zp as OpenAIParams, _m as applyAnthropicCacheBreakpoints, _p as ToolResult, am as cursor, bp as XaiParams, cm as BasetenParams, dm as ArceeParams, dp as Provider, em as openai, fm as arcee, fp as ProviderCapabilities, gm as anthropic, gp as ToolCall, hp as TokenCountPayload, im as CursorParams, kp as openrouter, lm as baseten, mm as AnthropicParams, mp as StreamOptions, nm as LocalParams, om as CerebrasParams, pp as StreamCallbacks, qp as openaiCompat, rm as local, sm as cerebras, um as planBasetenReasoning, vp as ToolSpec, wp as SchemaSanitizeResult, xp as xai, yp as TurnResult } from "./index-B8UtiZy7.js";
2
2
  export { type AnthropicParams, type ArceeParams, type BasetenParams, type CerebrasParams, type CursorParams, type LocalParams, type OpenAICompatAuthHeader, OpenAICompatHttpError, type OpenAICompatParams, type OpenAIParams, type OpenRouterParams, Provider, ProviderCapabilities, type SchemaSanitizeOptions, type SchemaSanitizeProfile, type SchemaSanitizeResult, StreamCallbacks, StreamOptions, TokenCountPayload, ToolCall, ToolResult, ToolSpec, TurnResult, type XaiParams, anthropic, applyAnthropicCacheBreakpoints, arcee, baseten, cerebras, classifyOpenAICompatError, cursor, local, mapOAIFinishReason, openai, openaiCompat, openrouter, planBasetenReasoning, sanitizeToolSchema, sanitizeToolSpecs, xai };
package/dist/providers.js CHANGED
@@ -1,10 +1,10 @@
1
- import { f as mapOAIFinishReason, l as classifyOpenAICompatError, m as openaiCompat, n as OpenAICompatHttpError, v as sanitizeToolSchema, y as sanitizeToolSpecs } from "./openai-compat-0Y7jcncn.js";
2
- import { n as applyAnthropicCacheBreakpoints, t as anthropic } from "./anthropic-RGqsJlC8.js";
1
+ import { f as mapOAIFinishReason, l as classifyOpenAICompatError, m as openaiCompat, n as OpenAICompatHttpError, v as sanitizeToolSchema, y as sanitizeToolSpecs } from "./openai-compat-BvgYGSR1.js";
2
+ import { n as applyAnthropicCacheBreakpoints, t as anthropic } from "./anthropic-CTHsdFG9.js";
3
3
  import { arcee } from "./providers/arcee.js";
4
4
  import { baseten, planBasetenReasoning } from "./providers/baseten.js";
5
5
  import { cerebras } from "./providers/cerebras.js";
6
- import { t as xai } from "./xai-tPdbAGkq.js";
7
- import { t as cursor } from "./providers-DgmdYGKm.js";
6
+ import { t as xai } from "./xai-B_e6TOA8.js";
7
+ import { t as cursor } from "./providers-z6LDMAr3.js";
8
8
  import { local } from "./providers/local.js";
9
9
  import { openai } from "./providers/openai.js";
10
10
  import { openrouter } from "./providers/openrouter.js";