promptfoo 0.121.4 → 0.121.7

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 (497) hide show
  1. package/dist/src/{ListApp-DQkFNqE9.js → ListApp-DLmM02JS.js} +1 -1
  2. package/dist/src/{accounts-DhMYUUbu.js → accounts-Ca7WIoPY.js} +12 -7
  3. package/dist/src/{accounts-F9d_5sMC.js → accounts-CjFnOPmb.js} +14 -9
  4. package/dist/src/{accounts-Dy17bs4D.cjs → accounts-CmWzeD2d.cjs} +16 -10
  5. package/dist/src/{accounts-DdJ2pHMI.js → accounts-DanM1wq_.js} +13 -8
  6. package/dist/src/{agentic-utils-qFlm6zes.js → agentic-utils-CJ0j3fBi.js} +3 -3
  7. package/dist/src/{agentic-utils-w68v6_Dz.js → agentic-utils-DDEGRV9v.js} +3 -3
  8. package/dist/src/{agentic-utils-BpX5b23w.cjs → agentic-utils-DvPWSUpb.cjs} +8 -7
  9. package/dist/src/{agentic-utils-P172hM8B.js → agentic-utils-TxUEMPYS.js} +2 -2
  10. package/dist/src/{agents-BahDpe5G.cjs → agents-B4sRuXg3.cjs} +7 -6
  11. package/dist/src/{agents-pQeBEXMm.js → agents-B8q7h_ek.js} +5 -5
  12. package/dist/src/{agents-CgaMXvLM.js → agents-CBgJvRkB.js} +21 -10
  13. package/dist/src/{agents-C-R_jfzI.js → agents-CYn2n3QP.js} +4 -4
  14. package/dist/src/{agents-8FDnTriG.js → agents-D-vDNFx4.js} +21 -10
  15. package/dist/src/{agents-aYPQLf8W.js → agents-LrHuQqr1.js} +20 -9
  16. package/dist/src/{agents-DJ35I3Nt.js → agents-QGg76OF-.js} +5 -5
  17. package/dist/src/{agents-D7-HGxUj.cjs → agents-eHZ9nlgA.cjs} +21 -10
  18. package/dist/src/{aimlapi-sgYnkE54.js → aimlapi-CJEbQ0o6.js} +7 -7
  19. package/dist/src/{aimlapi-BD6J9oKt.js → aimlapi-D5HXzZ0s.js} +6 -6
  20. package/dist/src/{aimlapi-qcK4OT55.cjs → aimlapi-T6HGNxNe.cjs} +7 -7
  21. package/dist/src/{aimlapi-BCq3MHeL.js → aimlapi-eYv3a_DK.js} +7 -7
  22. package/dist/src/app/app/tsconfig.app.tsbuildinfo +1 -1
  23. package/dist/src/app/assets/Report-BNHJKN35.js +1 -0
  24. package/dist/src/app/assets/index-BnT6P6sF.js +388 -0
  25. package/dist/src/app/assets/index-yhM8y1PP.css +1 -0
  26. package/dist/src/app/assets/{scroll-timeline-D9IT_e8Z.js → scroll-timeline-RpeTwOvs.js} +1 -1
  27. package/dist/src/app/assets/sync-5gq6fmG4.js +4 -0
  28. package/dist/src/app/assets/vendor-charts-BL9OMNU7.js +36 -0
  29. package/dist/src/app/assets/{vendor-markdown-Ch00wnNI.js → vendor-markdown-BYsQqn7Z.js} +10 -10
  30. package/dist/src/app/assets/{vendor-react-CVvmk1UB.js → vendor-react-CqWgVW6T.js} +2 -2
  31. package/dist/src/app/assets/{vendor-utils-BnEYbx2Q.js → vendor-utils-BHPO71pu.js} +1 -1
  32. package/dist/src/app/index.html +31 -6
  33. package/dist/src/{audio-COrn8rM6.js → audio-BqnRvcWG.js} +3 -3
  34. package/dist/src/{audio-DcVKoInv.js → audio-CPMtV1yR.js} +4 -4
  35. package/dist/src/{audio-B7izf48x.js → audio-DyiebVB3.js} +4 -4
  36. package/dist/src/{audio-BQtNuYBj.cjs → audio-FnxbEnSE.cjs} +4 -4
  37. package/dist/src/authoritativeMarkupInjection-BZIywVjG.js +74 -0
  38. package/dist/src/authoritativeMarkupInjection-DyAXAsSr.js +75 -0
  39. package/dist/src/authoritativeMarkupInjection-F2gBw0lN.cjs +74 -0
  40. package/dist/src/authoritativeMarkupInjection-QEQmFS83.js +74 -0
  41. package/dist/src/{base-PYJvBE1i.js → base-CKLo890h.js} +4 -3
  42. package/dist/src/{base-fZ9wgg50.js → base-Co80MMCi.js} +5 -4
  43. package/dist/src/{base-D-670DX8.cjs → base-DGJW48uz.cjs} +5 -4
  44. package/dist/src/{base-yrI1Yal4.js → base-E9I8zXjz.js} +5 -4
  45. package/dist/src/bestOfN-B3wNzjSB.js +137 -0
  46. package/dist/src/bestOfN-BBsO41z4.js +136 -0
  47. package/dist/src/bestOfN-CAwmg5UL.cjs +140 -0
  48. package/dist/src/bestOfN-_kTi8Bxe.js +136 -0
  49. package/dist/src/{blobs-D2FAd1Q5.cjs → blobs-B0977K1O.cjs} +7 -6
  50. package/dist/src/{blobs-BCZavS8s.js → blobs-CeFdPn_T.js} +3 -3
  51. package/dist/src/{blobs-BQWqnnvL.js → blobs-DODuTK-a.js} +3 -3
  52. package/dist/src/{blobs-C-F78Kfn.js → blobs-Dwef1Ao1.js} +2 -2
  53. package/dist/src/{cache-BIyPcp5v.cjs → cache-CPGUA4Yl.cjs} +135 -25
  54. package/dist/src/cache-Cf7b4pWE.js +3 -0
  55. package/dist/src/{cache-D5NZmMiT.js → cache-DIXbtkNO.js} +125 -10
  56. package/dist/src/{cache-mb7c8hbp.js → cache-DpPWrkTE.js} +128 -12
  57. package/dist/src/{cache-C4Xb-hNb.js → cache-roFAE0cI.js} +126 -11
  58. package/dist/src/{chat-I9izLm49.js → chat-CUCorGiL.js} +12 -12
  59. package/dist/src/{chat-BPXSW8Bv.cjs → chat-DG1wG4w0.cjs} +6 -6
  60. package/dist/src/{chat-BfPaS15_.js → chat-Dabu84Br.js} +12 -12
  61. package/dist/src/{chat-Dr3DUQ0D.js → chat-DqUFcWI0.js} +12 -12
  62. package/dist/src/{chat-CclRbxGf.cjs → chat-DxTDQ83C.cjs} +14 -13
  63. package/dist/src/{chat-MKxMnZJZ.js → chat-GmlolEwo.js} +4 -4
  64. package/dist/src/{chat-0bwXjVP0.js → chat-TP8Qifkh.js} +6 -6
  65. package/dist/src/{chat-mW0ORo8G.js → chat-iwaM5UTQ.js} +6 -6
  66. package/dist/src/{chatkit-zUIVoDos.js → chatkit-B6DWi70Q.js} +4 -4
  67. package/dist/src/{chatkit-BoWoSgXl.cjs → chatkit-BYveR48_.cjs} +6 -5
  68. package/dist/src/{chatkit-Cv6AhukM.js → chatkit-fARZwEfV.js} +3 -3
  69. package/dist/src/{chatkit-CJnHRRMM.js → chatkit-lb6FK02w.js} +4 -4
  70. package/dist/src/{claude-agent-sdk-Dtq_L-Sc.js → claude-agent-sdk-BQNp_y-F.js} +212 -67
  71. package/dist/src/{claude-agent-sdk-BQNuLaAK.js → claude-agent-sdk-D5Jl0SDh.js} +212 -67
  72. package/dist/src/{claude-agent-sdk-CPJo3dBQ.cjs → claude-agent-sdk-DH416NBD.cjs} +218 -72
  73. package/dist/src/{claude-agent-sdk-nfAIcxNf.js → claude-agent-sdk-x1XJ1-pU.js} +212 -67
  74. package/dist/src/{cloud-DQZ5sVjW.js → cloud-D3DiFqH6.js} +3 -3
  75. package/dist/src/cloud-p96PA4MH.js +3 -0
  76. package/dist/src/{cloudflare-ai-BIB567w6.js → cloudflare-ai-B6NVI3ax.js} +4 -4
  77. package/dist/src/{cloudflare-ai-Dl3N9OVD.cjs → cloudflare-ai-CEAW-xQa.cjs} +6 -6
  78. package/dist/src/{cloudflare-ai-DlKr0rY7.js → cloudflare-ai-RFSojyXG.js} +6 -6
  79. package/dist/src/{cloudflare-ai-DGLte7Py.js → cloudflare-ai-r4tbYmWU.js} +6 -6
  80. package/dist/src/{cloudflare-gateway-CiIZHU0Q.js → cloudflare-gateway-BCkLouto.js} +5 -5
  81. package/dist/src/{cloudflare-gateway-DI1HNP5F.js → cloudflare-gateway-BaZ4insB.js} +3 -3
  82. package/dist/src/{cloudflare-gateway-BDZrYydE.js → cloudflare-gateway-CF-Vb-2Z.js} +5 -5
  83. package/dist/src/{cloudflare-gateway-BYDp495F.cjs → cloudflare-gateway-TJMLBj6I.cjs} +5 -5
  84. package/dist/src/codex-app-server-B8KHEiF4.js +1915 -0
  85. package/dist/src/codex-app-server-CnrLBCeA.cjs +1921 -0
  86. package/dist/src/codex-app-server-DIXZ230V.js +1915 -0
  87. package/dist/src/codex-app-server-Dd22dC_N.js +1916 -0
  88. package/dist/src/{codex-sdk-CpqiOqDO.js → codex-sdk-B6Wah8Pa.js} +6 -6
  89. package/dist/src/codex-sdk-BGjVAk23.js +3 -0
  90. package/dist/src/{codex-sdk-C2_M2pl_.cjs → codex-sdk-CFF6gUyi.cjs} +18 -10
  91. package/dist/src/{codex-sdk-Rtky3M4I.js → codex-sdk-CmQABzV3.js} +6 -6
  92. package/dist/src/{codex-sdk-CErXn7qh.js → codex-sdk-D2d54RL8.js} +5 -5
  93. package/dist/src/{cometapi-CtJ-mS8R.js → cometapi-Bu9B8NUY.js} +8 -8
  94. package/dist/src/{cometapi-DT-jlVCB.js → cometapi-CtzNCHKu.js} +7 -7
  95. package/dist/src/{cometapi-UVOryo4W.cjs → cometapi-DHCDlQUI.cjs} +8 -8
  96. package/dist/src/{cometapi-BUlt_ELa.js → cometapi-OBILPLlu.js} +8 -8
  97. package/dist/src/{completion-HUe8wDhZ.js → completion-CO2e1_62.js} +6 -6
  98. package/dist/src/{completion-BozdoXba.cjs → completion-CSYfl2cd.cjs} +6 -6
  99. package/dist/src/{completion-x0a_c2y1.js → completion-DZNxcyfG.js} +6 -6
  100. package/dist/src/{completion-Dnxn7E-j.js → completion-sNvCLTAP.js} +5 -5
  101. package/dist/src/constants-BjJV0cRr.js +6 -0
  102. package/dist/src/constants-DH5XYLKZ.js +7 -0
  103. package/dist/src/constants-DZGEFLsu.js +6 -0
  104. package/dist/src/constants-a2kYssQk.cjs +11 -0
  105. package/dist/src/{createHash-4gFQpDDv.js → createHash-BtbSX3mj.js} +1 -1
  106. package/dist/src/{createHash-CwDVU5xr.js → createHash-CGVzWdjj.js} +1 -1
  107. package/dist/src/{createHash-B7KvgoOD.cjs → createHash-CSiqnK5P.cjs} +2 -2
  108. package/dist/src/{createHash-ChI45QR1.js → createHash-CgRvs4Fn.js} +1 -1
  109. package/dist/src/crescendo-BXEJK_bi.cjs +704 -0
  110. package/dist/src/crescendo-CU_Y2i-m.js +702 -0
  111. package/dist/src/crescendo-J1Xx4_zb.js +703 -0
  112. package/dist/src/crescendo-QiaSLW0d.js +701 -0
  113. package/dist/src/custom-BJfP00Bh.js +619 -0
  114. package/dist/src/custom-CZVn-1-r.js +620 -0
  115. package/dist/src/custom-Cqia7M0D.cjs +621 -0
  116. package/dist/src/custom-notggYVl.js +618 -0
  117. package/dist/src/{docker-DCgsveLD.js → docker-4D1eL6Gq.js} +6 -6
  118. package/dist/src/{docker-ClnmCf1Z.js → docker-BBv1WUDu.js} +5 -5
  119. package/dist/src/{docker-DS4_Osau.cjs → docker-D06JUoe2.cjs} +6 -6
  120. package/dist/src/{docker-CQmlA2NU.js → docker-DdJQBxK9.js} +6 -6
  121. package/dist/src/{embedding-D3xTseo7.js → embedding--UZVe4_7.js} +6 -6
  122. package/dist/src/{embedding-I45KG3o7.cjs → embedding-BbrwopfX.cjs} +6 -6
  123. package/dist/src/{embedding-nFbumxcv.js → embedding-Bi3rxrZF.js} +5 -5
  124. package/dist/src/{embedding-DD9wa3ae.js → embedding-C251p1-8.js} +6 -6
  125. package/dist/src/{errors-Cw810C93.js → errors-9PcUL8BC.js} +1 -1
  126. package/dist/src/{esm-Dh4dOLlt.js → esm-B6whoAcf.js} +2 -2
  127. package/dist/src/{esm-CtEPLdAj.cjs → esm-BIKakvNa.cjs} +8 -7
  128. package/dist/src/{esm-C7PnfdF8.js → esm-BTK1W7lG.js} +1 -1
  129. package/dist/src/{esm-tVgYPY-f.js → esm-Bexx2PFc.js} +2 -2
  130. package/dist/src/{eval-u4UVafl6.js → eval-0VRANImH.js} +21 -21
  131. package/dist/src/{eval-CzJFfFO9.js → eval-DscR5iOM.js} +1 -1
  132. package/dist/src/{evalResult-Bgm9ZH31.js → evalResult-2RRJvFyB.js} +41 -16
  133. package/dist/src/{evalResult-KZqXl4XP.cjs → evalResult-CvtS8h8u.cjs} +51 -15
  134. package/dist/src/evalResult-DqzsS6_W.js +3 -0
  135. package/dist/src/{evalResult-D3hVYFis.js → evalResult-eUkJv9Ko.js} +40 -15
  136. package/dist/src/evaluator-DNdJF1Gv.js +3 -0
  137. package/dist/src/{evaluator-IvuDYSvQ.js → evaluator-DRoiYB2q.js} +1060 -187
  138. package/dist/src/evaluatorHelpers-BsYP_muT.js +511 -0
  139. package/dist/src/evaluatorHelpers-CRqTvSux.cjs +537 -0
  140. package/dist/src/evaluatorHelpers-DuqFFfq7.js +510 -0
  141. package/dist/src/{extractor-CAfTSraf.js → extractor-BR7XAzAL.js} +6 -6
  142. package/dist/src/{extractor-WVPOrH43.cjs → extractor-BdxEtt3J.cjs} +6 -6
  143. package/dist/src/{extractor-DNSeBVOJ.js → extractor-CIW3iN-b.js} +6 -6
  144. package/dist/src/{extractor-Dk6bRWkv.js → extractor-CxRtnaHl.js} +5 -5
  145. package/dist/src/{fetch-B0Z3Oe4k.js → fetch-BufrQtvR.js} +93 -40
  146. package/dist/src/{fetch-BEWnXrrG.js → fetch-DXUnXkVU.js} +89 -40
  147. package/dist/src/{fetch-CJU5ELPa.cjs → fetch-Dw4XZHjj.cjs} +330 -270
  148. package/dist/src/{fetch-Di00EQrc.js → fetch-It34O8Ur.js} +305 -252
  149. package/dist/src/fetch-_YgGd2qv.js +3 -0
  150. package/dist/src/{fileExtensions-bYh77CN8.cjs → fileExtensions-BhdwzYaD.cjs} +24 -1
  151. package/dist/src/{fileExtensions-DnqA1y9x.js → fileExtensions-CXRfY3Ss.js} +12 -2
  152. package/dist/src/{fileExtensions-AWa2ZML4.js → fileExtensions-D4GCJ67J.js} +12 -2
  153. package/dist/src/{formatDuration-DZzPsexs.js → formatDuration-CMVNrYvE.js} +1 -1
  154. package/dist/src/{genaiTracer-yRuxj9-L.cjs → genaiTracer-14nugQQx.cjs} +14 -2
  155. package/dist/src/{genaiTracer-DWdZ28hY.js → genaiTracer-BPVvltoW.js} +2 -2
  156. package/dist/src/{genaiTracer-XnrcgDCe.js → genaiTracer-D18lYzhB.js} +2 -2
  157. package/dist/src/{genaiTracer-COYDi-tC.js → genaiTracer-jJKYsnjc.js} +2 -2
  158. package/dist/src/goat-Ckd3q3AY.js +467 -0
  159. package/dist/src/goat-Qgurm-NP.js +466 -0
  160. package/dist/src/goat-ghadEDdy.js +465 -0
  161. package/dist/src/goat-una6pZGP.cjs +469 -0
  162. package/dist/src/graders-BDT7dif6.js +3 -0
  163. package/dist/src/{graders-eIHhRqoC.js → graders-BGP99PdK.js} +2416 -2224
  164. package/dist/src/{graders-Zy3x0zqX.js → graders-BX0f2tvS.js} +2423 -2226
  165. package/dist/src/{graders-pvbReLLn.js → graders-C0nXU_ZP.js} +1806 -1609
  166. package/dist/src/{graders--zknU_uk.cjs → graders-ClrU2fnd.cjs} +2219 -1949
  167. package/dist/src/hydra-BSNZZm2M.js +543 -0
  168. package/dist/src/hydra-BxdG4nkg.js +541 -0
  169. package/dist/src/hydra-DE4xWwyc.js +542 -0
  170. package/dist/src/hydra-DrJttnvw.cjs +542 -0
  171. package/dist/src/image-B4oBtu6J.js +443 -0
  172. package/dist/src/{image-dnoUgPrC.js → image-BN-hjLL9.js} +4 -4
  173. package/dist/src/{image-9302QVqR.js → image-B_fPIwdg.js} +3 -3
  174. package/dist/src/image-BvUAW344.js +442 -0
  175. package/dist/src/image-Cvjwx1uY.js +442 -0
  176. package/dist/src/{image-De2FBmYV.cjs → image-DfVCGPbI.cjs} +4 -4
  177. package/dist/src/{image-u7-rKnYU.js → image-QzmydkiG.js} +4 -4
  178. package/dist/src/image-X0oY4350.cjs +465 -0
  179. package/dist/src/index.cjs +1689 -558
  180. package/dist/src/index.d.cts +3270 -1624
  181. package/dist/src/index.d.ts +3270 -1624
  182. package/dist/src/index.js +1553 -438
  183. package/dist/src/indirectWebPwn-02ZIghCS.js +259 -0
  184. package/dist/src/indirectWebPwn-BJ22AbQa.cjs +397 -0
  185. package/dist/src/indirectWebPwn-CbjUG0rh.js +385 -0
  186. package/dist/src/indirectWebPwn-CfQJt3gk.cjs +260 -0
  187. package/dist/src/indirectWebPwn-DBQhOjoD.js +260 -0
  188. package/dist/src/indirectWebPwn-OsXnKejv.js +259 -0
  189. package/dist/src/indirectWebPwn-tNx9OZ35.js +385 -0
  190. package/dist/src/indirectWebPwn-uyWdHx04.js +386 -0
  191. package/dist/src/inputVariables-B0qUChbV.js +467 -0
  192. package/dist/src/inputVariables-DUGMb9Ka.js +464 -0
  193. package/dist/src/inputVariables-DXFdi7AI.js +468 -0
  194. package/dist/src/inputVariables-Dq9W-Z3a.cjs +475 -0
  195. package/dist/src/{interactiveCheck-CLERUB0c.js → interactiveCheck-C4QlIuoR.js} +2 -2
  196. package/dist/src/{invariant-BtWWVVhl.js → invariant-B2Rf6avk.js} +1 -1
  197. package/dist/src/{invariant-vgHWClmd.js → invariant-DIYf9sP1.js} +1 -1
  198. package/dist/src/{invariant-kfQ8Bu82.cjs → invariant-QtnLD03y.cjs} +1 -1
  199. package/dist/src/iterative-CpU6i2As.js +490 -0
  200. package/dist/src/iterative-DJQEQpG3.js +491 -0
  201. package/dist/src/iterative-DQBuWM-j.cjs +493 -0
  202. package/dist/src/iterative-FTS4Bz67.js +492 -0
  203. package/dist/src/iterativeImage-BUABMVOA.js +413 -0
  204. package/dist/src/iterativeImage-ByFWkxax.cjs +415 -0
  205. package/dist/src/iterativeImage-BzUapOUi.js +414 -0
  206. package/dist/src/iterativeImage-Doz8mgxF.js +413 -0
  207. package/dist/src/iterativeMeta-B3YiAOc8.js +386 -0
  208. package/dist/src/iterativeMeta-C7APE_P1.js +385 -0
  209. package/dist/src/iterativeMeta-CSS8M6Ds.cjs +385 -0
  210. package/dist/src/iterativeMeta-DgoQ7bLh.js +384 -0
  211. package/dist/src/iterativeTree-B5zxBBSW.js +769 -0
  212. package/dist/src/iterativeTree-CNyIk0Yn.js +768 -0
  213. package/dist/src/iterativeTree-CPMF10ve.cjs +771 -0
  214. package/dist/src/iterativeTree-DvZ7GBwt.js +770 -0
  215. package/dist/src/{knowledgeBase-Dgc7CBWF.js → knowledgeBase-BadkINlJ.js} +24 -10
  216. package/dist/src/{knowledgeBase-RhFPGWDc.js → knowledgeBase-Bi_8sV-H.js} +25 -11
  217. package/dist/src/{knowledgeBase-lm9RXSAm.js → knowledgeBase-CkMljjdg.js} +25 -11
  218. package/dist/src/{knowledgeBase-Bpoe_nLu.cjs → knowledgeBase-DUh34xba.cjs} +25 -11
  219. package/dist/src/{litellm-DRjpcSa7.js → litellm-BKBo0jpC.js} +5 -5
  220. package/dist/src/{litellm-C2kqjxqp.js → litellm-BXyn5kZK.js} +5 -5
  221. package/dist/src/{litellm-p37R1dzQ.js → litellm-CNcfbCfa.js} +4 -4
  222. package/dist/src/{litellm-CoyI4IAl.cjs → litellm-CtAr7bKG.cjs} +5 -5
  223. package/dist/src/{logger-DksKw1Qc.js → logger-BbY6ypFL.js} +2 -2
  224. package/dist/src/{logger-B88EkIn6.js → logger-KD8JjCRJ.js} +2 -2
  225. package/dist/src/{logger-COuQb2xB.cjs → logger-cfNpzI4o.cjs} +13 -55
  226. package/dist/src/{luma-ray-KgTCXrZC.js → luma-ray-BMX1iEB6.js} +5 -5
  227. package/dist/src/{luma-ray-B863CmuZ.js → luma-ray-CR5TSpp4.js} +5 -5
  228. package/dist/src/{luma-ray-BxVKaW2a.cjs → luma-ray-D3FUc2K3.cjs} +9 -8
  229. package/dist/src/{luma-ray-BTTLtqQ8.js → luma-ray-OEMmS1RB.js} +6 -6
  230. package/dist/src/main.js +909 -369
  231. package/dist/src/memoryPoisoning-CM83NWYl.js +107 -0
  232. package/dist/src/memoryPoisoning-D8h9gXJF.js +106 -0
  233. package/dist/src/memoryPoisoning-Dp-btinn.cjs +106 -0
  234. package/dist/src/memoryPoisoning-cLuCoTuJ.js +106 -0
  235. package/dist/src/{messages-BTQz42fn.js → messages-BabO-cX8.js} +273 -17
  236. package/dist/src/{messages-811uVVW5.cjs → messages-DBPir0TQ.cjs} +278 -18
  237. package/dist/src/{messages-zWbkLLHz.js → messages-DGUlSNU7.js} +273 -17
  238. package/dist/src/{messages-MYTQ2TWp.js → messages-vsE_-Lv0.js} +273 -17
  239. package/dist/src/{meteor-DHdzY1Ss.js → meteor--TZYICTI.js} +2 -2
  240. package/dist/src/{meteor-Co1VQ1u5.cjs → meteor-CR226f7Z.cjs} +2 -2
  241. package/dist/src/{meteor-CU5UAE-H.js → meteor-Cl_yd7rJ.js} +2 -2
  242. package/dist/src/{meteor-DuAFv6gF.js → meteor-Dce-_zGQ.js} +1 -1
  243. package/dist/src/mischievousUser-0l8GD7Dp.js +46 -0
  244. package/dist/src/mischievousUser-BUOP9W5r.js +46 -0
  245. package/dist/src/mischievousUser-frFYKxu6.js +47 -0
  246. package/dist/src/mischievousUser-olGgHIVR.cjs +46 -0
  247. package/dist/src/{modelslab-Dk1JAtVo.cjs → modelslab-CNV5bMSk.cjs} +7 -7
  248. package/dist/src/{modelslab-D0erNWKe.js → modelslab-Cogmu4mG.js} +6 -6
  249. package/dist/src/{modelslab-DIq-6y7x.js → modelslab-Dzst7VTU.js} +6 -6
  250. package/dist/src/{modelslab-wu9yi5GE.js → modelslab-EyDczZ5A.js} +7 -7
  251. package/dist/src/{nova-reel-CCFRfeRb.js → nova-reel-BGPNBOMS.js} +6 -6
  252. package/dist/src/{nova-reel-DQrm74ng.js → nova-reel-B_5NKFu1.js} +5 -5
  253. package/dist/src/{nova-reel-gr11WG7f.js → nova-reel-C4eUJGse.js} +5 -5
  254. package/dist/src/{nova-reel-CrLXVKQf.cjs → nova-reel-CjJRxI1X.cjs} +9 -8
  255. package/dist/src/{nova-sonic-BYdp-QLs.js → nova-sonic-BNGmgfFz.js} +4 -4
  256. package/dist/src/{nova-sonic-TDgrlTk7.js → nova-sonic-ChPlh5na.js} +4 -4
  257. package/dist/src/{nova-sonic-B_ZXcUJB.js → nova-sonic-CrV0iaY_.js} +3 -3
  258. package/dist/src/{nova-sonic-i5tUvXKn.cjs → nova-sonic-DuOG9Aun.cjs} +5 -4
  259. package/dist/src/{openai-DhVEmgeZ.js → openai-BMHD2Huo.js} +2 -2
  260. package/dist/src/{openai-URNyItar.cjs → openai-C3uXv8wS.cjs} +2 -2
  261. package/dist/src/{openai-Qsvz25mV.js → openai-CJrsh9n4.js} +2 -2
  262. package/dist/src/{openai-iYtrXzOX.js → openai-zgwBb4Ff.js} +1 -1
  263. package/dist/src/{openclaw-CnQ363Wi.js → openclaw-BIHlu_36.js} +10 -8
  264. package/dist/src/{openclaw-CwzlQSQX.js → openclaw-CF7fMido.js} +9 -7
  265. package/dist/src/{openclaw-wX9rtfke.cjs → openclaw-Dphc01BY.cjs} +18 -15
  266. package/dist/src/{openclaw-CLWrW03k.js → openclaw-zIJAsz3P.js} +10 -8
  267. package/dist/src/{opencode-sdk-BUu5Nevv.js → opencode-sdk-B3vlPLsp.js} +40 -5
  268. package/dist/src/{opencode-sdk-BxD8vXp_.js → opencode-sdk-D05JSgMQ.js} +40 -5
  269. package/dist/src/{opencode-sdk-BZ2idgYA.cjs → opencode-sdk-DoY6GbWw.cjs} +46 -10
  270. package/dist/src/{opencode-sdk-GI2KaAXq.js → opencode-sdk-sRKYHGoI.js} +39 -4
  271. package/dist/src/{otlpReceiver-BntK801g.js → otlpReceiver--gTpSagc.js} +120 -4
  272. package/dist/src/{otlpReceiver-DmVulbhC.js → otlpReceiver-B2eaKC8C.js} +120 -4
  273. package/dist/src/{otlpReceiver-B2z58l4e.js → otlpReceiver-BXjcRqAM.js} +119 -3
  274. package/dist/src/{otlpReceiver-BfcVq2Nq.cjs → otlpReceiver-CvJdBGSc.cjs} +125 -7
  275. package/dist/src/packageParser--MWTSrPW.js +36 -0
  276. package/dist/src/packageParser-CgE-ziRo.js +35 -0
  277. package/dist/src/packageParser-QoCS1FMl.cjs +54 -0
  278. package/dist/src/packageParser-hwwSGnAZ.js +35 -0
  279. package/dist/src/processShim-BBxt7LKO.js +95 -0
  280. package/dist/src/processShim-BcGzU8fY.js +94 -0
  281. package/dist/src/processShim-C_z3aRvF.js +94 -0
  282. package/dist/src/processShim-DSY9BV2T.cjs +98 -0
  283. package/dist/src/promptLength-0qIHyhA5.js +71 -0
  284. package/dist/src/promptLength-4X-Wd8PG.js +72 -0
  285. package/dist/src/promptLength-B9nZEfO6.js +71 -0
  286. package/dist/src/promptLength-BbBbDHNj.cjs +94 -0
  287. package/dist/src/promptfoo-BDrfT30-.js +180 -0
  288. package/dist/src/promptfoo-Cm4hiy1Y.js +180 -0
  289. package/dist/src/promptfoo-Rjp-MeBb.js +181 -0
  290. package/dist/src/promptfoo-b-baRMj-.cjs +205 -0
  291. package/dist/src/prompts-BYMtqPCw.js +259 -0
  292. package/dist/src/prompts-C-bqE1Yp.js +260 -0
  293. package/dist/src/prompts-Cp_Qx5Ml.js +270 -0
  294. package/dist/src/prompts-DHhQsANy.js +259 -0
  295. package/dist/src/prompts-D_QpZ2Dm.js +271 -0
  296. package/dist/src/prompts-hNvWBD3z.cjs +284 -0
  297. package/dist/src/prompts-huDVH2CI.js +270 -0
  298. package/dist/src/prompts-p78Hul5i.cjs +289 -0
  299. package/dist/src/{providerRegistry-CPQ_CmVO.js → providerRegistry-1gB5vtzQ.js} +2 -2
  300. package/dist/src/{providerRegistry-CQMdTmHP.cjs → providerRegistry-CZO_w7ue.cjs} +2 -2
  301. package/dist/src/{providerRegistry-Bvh8mv85.js → providerRegistry-DHcFiVWX.js} +1 -1
  302. package/dist/src/{providerRegistry-CWoPjKFZ.js → providerRegistry-ReCd0sFa.js} +2 -2
  303. package/dist/src/{providers-BV_KMZje.js → providers-B9KzWxAX.js} +10558 -21587
  304. package/dist/src/{providers-DruaQfwu.js → providers-BCCz6_IX.js} +1228 -12196
  305. package/dist/src/{providers-1eKkXBKp.cjs → providers-BDVVIQM6.cjs} +10649 -21843
  306. package/dist/src/{providers-iUt5fbAN.js → providers-BYAn82cf.js} +1 -1
  307. package/dist/src/{providers-Domz_llv.js → providers-DVYRZP4E.js} +10589 -21570
  308. package/dist/src/{pythonUtils-Cldx7huE.js → pythonUtils-CLCgQ9tt.js} +3 -3
  309. package/dist/src/{pythonUtils-CnndUbW-.js → pythonUtils-CgYxeSmO.js} +3 -3
  310. package/dist/src/{pythonUtils-tAJvvpS-.cjs → pythonUtils-Cokhluq3.cjs} +8 -7
  311. package/dist/src/{pythonUtils-C2UQ30Rz.js → pythonUtils-D0BYebvX.js} +3 -3
  312. package/dist/src/{quiverai-DFotyafY.cjs → quiverai-BAp6iTZD.cjs} +4 -4
  313. package/dist/src/{quiverai-aPPvXOgn.js → quiverai-BvIhI_0l.js} +4 -4
  314. package/dist/src/{quiverai-DR0SnIQV.js → quiverai-CdTWPe-A.js} +3 -3
  315. package/dist/src/{quiverai-CtWi6x_g.js → quiverai-Cv7rJKDz.js} +4 -4
  316. package/dist/src/registry-BUJrgjwv.js +124 -0
  317. package/dist/src/registry-DXm1t_x0.js +125 -0
  318. package/dist/src/registry-Dp5EqoXc.js +124 -0
  319. package/dist/src/registry-KCVF1CFC.cjs +124 -0
  320. package/dist/src/{server-D6Il2Sob.js → remoteGeneration-B1_XsKXU.js} +16 -108
  321. package/dist/src/{server-BSB45Nt9.js → remoteGeneration-COpWcmWd.js} +15 -146
  322. package/dist/src/{server-Dx2TyCH2.cjs → remoteGeneration-DS9N3pgB.cjs} +30 -119
  323. package/dist/src/remoteGeneration-DsaSwmG2.js +217 -0
  324. package/dist/src/render-BNTrbmBw.cjs +384 -0
  325. package/dist/src/render-CSP99NLm.js +348 -0
  326. package/dist/src/render-DFfDeYUK.js +347 -0
  327. package/dist/src/{render-CgVDrJmM.js → render-DznWrxGO.js} +2 -2
  328. package/dist/src/render-_6ur1fhE.js +347 -0
  329. package/dist/src/resourceAttributes-D1jP3kL5.js +17 -0
  330. package/dist/src/resourceAttributes-DQbBB--2.js +16 -0
  331. package/dist/src/resourceAttributes-ephgOvdR.cjs +27 -0
  332. package/dist/src/resourceAttributes-v6-I67fn.js +16 -0
  333. package/dist/src/{responses-Bi9vBuW_.cjs → responses-1UFFF9N_.cjs} +51 -16
  334. package/dist/src/{responses-DL9m8CyY.js → responses-B3W2JvOQ.js} +49 -15
  335. package/dist/src/{responses--OsX2aYW.js → responses-B6ktc3Ra.js} +49 -15
  336. package/dist/src/{responses-C-flexAY.js → responses-URRzV8qE.js} +49 -15
  337. package/dist/src/rolldown-runtime-D_mwlA32.cjs +43 -0
  338. package/dist/src/rubyUtils-BYVlQ94c.js +3 -0
  339. package/dist/src/{rubyUtils-DsGrTx8R.js → rubyUtils-CXlFM2rR.js} +3 -3
  340. package/dist/src/{rubyUtils-DVLeA2jg.js → rubyUtils-CnlW8AYb.js} +3 -3
  341. package/dist/src/{rubyUtils-B6eljPuh.cjs → rubyUtils-CqUWBZAt.cjs} +18 -27
  342. package/dist/src/{rubyUtils-CYSQEG4a.js → rubyUtils-DdGojpfv.js} +3 -3
  343. package/dist/src/runtimeTransform-BJOpL9Yc.js +142 -0
  344. package/dist/src/runtimeTransform-Dgh_D7DU.js +143 -0
  345. package/dist/src/runtimeTransform-DigbjU1r.js +142 -0
  346. package/dist/src/runtimeTransform-ON3YYILw.cjs +147 -0
  347. package/dist/src/{sagemaker-BVkaG2-l.js → sagemaker-CujrzP1a.js} +62 -51
  348. package/dist/src/{sagemaker-XnfhheQv.cjs → sagemaker-DzffAqo_.cjs} +65 -53
  349. package/dist/src/{sagemaker-D67yzMzs.js → sagemaker-vhtSV7JI.js} +62 -51
  350. package/dist/src/{sagemaker-BveBvuxm.js → sagemaker-yr1QKeBs.js} +61 -50
  351. package/dist/src/{scanner-1DqWi1Ej.js → scanner-DS0109SS.js} +7 -7
  352. package/dist/src/server/index.js +5105 -605
  353. package/dist/src/server-B8rqV126.cjs +126 -0
  354. package/dist/src/server-BaLytskk.js +3 -0
  355. package/dist/src/server-CMJD10J4.js +107 -0
  356. package/dist/src/server-Ddp8GNMp.js +146 -0
  357. package/dist/src/server-DhMHosWj.js +182 -0
  358. package/dist/src/shared-7pmVZLNO.js +1334 -0
  359. package/dist/src/shared-9WHQ1oNE.js +1335 -0
  360. package/dist/src/{fileExtensions-BArZuxsI.js → shared-BoG7qLMv.js} +12 -2
  361. package/dist/src/shared-D6IjElRI.js +1334 -0
  362. package/dist/src/shared-WkgnDkcg.cjs +1436 -0
  363. package/dist/src/{signal-CE5G3a7x.js → signal-CSurUUyV.js} +3 -3
  364. package/dist/src/simulatedUser-C9aQObBI.js +222 -0
  365. package/dist/src/simulatedUser-Cu601Dd4.cjs +227 -0
  366. package/dist/src/simulatedUser-U_qAHnuB.js +222 -0
  367. package/dist/src/simulatedUser-p3tACcmw.js +223 -0
  368. package/dist/src/{slack-DDUe-5MC.js → slack-Bapo-7_8.js} +2 -2
  369. package/dist/src/{slack-1Rhq0EoV.cjs → slack-DMC1QVEg.cjs} +3 -2
  370. package/dist/src/{slack-D5Wpy8LM.js → slack-DTEFhrMn.js} +2 -2
  371. package/dist/src/{slack-acRb0IqQ.js → slack-k-_CP84Q.js} +1 -1
  372. package/dist/src/storage-BU4qcnOb.js +875 -0
  373. package/dist/src/storage-CA-v9V2v.cjs +911 -0
  374. package/dist/src/storage-CD-GWAdx.js +822 -0
  375. package/dist/src/storage-QdU-SmvD.js +834 -0
  376. package/dist/src/{store-DAAyxcy6.cjs → store-B2NDDooM.cjs} +60 -24
  377. package/dist/src/{store-CYEy5J2D.js → store-DKd5592Q.js} +51 -20
  378. package/dist/src/{store-M0b1WfYb.js → store-HpopRVzl.js} +50 -19
  379. package/dist/src/store-IbiRIF3k.js +3 -0
  380. package/dist/src/strategies-7CS3Alao.cjs +2360 -0
  381. package/dist/src/strategies-CiSeroPH.js +2331 -0
  382. package/dist/src/strategies-DRJjGTIY.js +2333 -0
  383. package/dist/src/{tables-DQ4WU5tX.js → tables-CRSXQ2Ke.js} +2 -2
  384. package/dist/src/{tables-CsWou1Bx.js → tables-CxjU7bBd.js} +3 -3
  385. package/dist/src/{tables-DUfh1F7Z.cjs → tables-DBIJU0WE.cjs} +6 -5
  386. package/dist/src/{tables-C4CH3zRr.js → tables-DafUHOeh.js} +3 -3
  387. package/dist/src/{telemetry-CQPez_Jp.js → telemetry-00ezXr_t.js} +5 -4
  388. package/dist/src/telemetry-ByPqDcKC.js +3 -0
  389. package/dist/src/{telemetry-Dsw_faFj.cjs → telemetry-CJ7FnCsc.cjs} +18 -11
  390. package/dist/src/{telemetry-dbaJ0E98.js → telemetry-DmXYcJNV.js} +5 -4
  391. package/dist/src/{telemetry-Dvqxv3YC.js → telemetry-DwX9XUN5.js} +4 -3
  392. package/dist/src/{text-KvuD2Iko.js → text-Db-Wt2u2.js} +1 -1
  393. package/dist/src/{text-DHxdyQqT.js → text-DwYK5EBn.js} +1 -1
  394. package/dist/src/{text-BVi-cLPJ.cjs → text-nywWsRBM.cjs} +1 -1
  395. package/dist/src/{tokenUsageUtils-C-bmyHoE.js → tokenUsageUtils-BjVkdk18.js} +1 -1
  396. package/dist/src/{tokenUsageUtils-CXrvO-wA.js → tokenUsageUtils-CDet74yk.js} +1 -1
  397. package/dist/src/tokenUsageUtils-CmnQ0G2m.js +142 -0
  398. package/dist/src/{tokenUsageUtils-Bb7DkZPz.cjs → tokenUsageUtils-_B-P8IAi.cjs} +1 -1
  399. package/dist/src/toolAttributes-BAjwcBf0.cjs +103 -0
  400. package/dist/src/toolAttributes-COVgDrBG.js +87 -0
  401. package/dist/src/toolAttributes-DJ9ZEKXD.js +86 -0
  402. package/dist/src/tracingOptions-BnwKCkSB.js +221 -0
  403. package/dist/src/tracingOptions-Chi74lOD.js +219 -0
  404. package/dist/src/tracingOptions-DrbSFaKy.cjs +249 -0
  405. package/dist/src/tracingOptions-ji2OuXbT.js +220 -0
  406. package/dist/src/{transcription-DuWDupG7.js → transcription-B8uIgCYX.js} +5 -5
  407. package/dist/src/{transcription-CJspiD2c.js → transcription-CfU5loSq.js} +6 -6
  408. package/dist/src/{transcription-V2HaAmy2.js → transcription-Dkd22_4K.js} +6 -6
  409. package/dist/src/{transcription-BvjmiYB1.cjs → transcription-mzuf18Mq.cjs} +9 -8
  410. package/dist/src/{transform-lQrDE1BQ.js → transform-BIMynQsA.js} +9 -9
  411. package/dist/src/transform-BnSTnFlp.js +187 -0
  412. package/dist/src/transform-BnSXWmU_2.cjs +221 -0
  413. package/dist/src/transform-CGt7Kt3y2.js +186 -0
  414. package/dist/src/transform-CrPGTsij.js +186 -0
  415. package/dist/src/{transform-CTeuTR3S.cjs → transform-DhNkAUs8.cjs} +13 -12
  416. package/dist/src/{transform-CG0ehZNG.js → transform-DmvYBRll.js} +9 -9
  417. package/dist/src/{transform-zDhMmzwX.js → transform-EtD4jAWi.js} +9 -9
  418. package/dist/src/{transformersAvailability-CcHusyhw.js → transformersAvailability-0ThtPved.js} +1 -1
  419. package/dist/src/transformersAvailability-BYydDE5U.js +35 -0
  420. package/dist/src/{transformersAvailability-DLlROWhg.js → transformersAvailability-BvyU9vDD.js} +1 -1
  421. package/dist/src/{transformersAvailability-Cju9mHgR.cjs → transformersAvailability-BytPvKUW.cjs} +1 -1
  422. package/dist/src/{types-Dm9JM6Vb.js → types-BFevViUY.js} +115 -19
  423. package/dist/src/{types-Bgh5SOn6.js → types-BJQBBPTP.js} +115 -19
  424. package/dist/src/{types-CeaeaZdP.cjs → types-CxJvaY2S.cjs} +357 -172
  425. package/dist/src/{types-BGQDAP8i.js → types-D6glLbdF.js} +271 -170
  426. package/dist/src/{util-BYvQUPp7.js → util--WMgw7wM.js} +28 -8
  427. package/dist/src/{util-C9J8ahRn.js → util-5WnCSb0h.js} +72 -48
  428. package/dist/src/{util-CN3SrLT4.cjs → util-BSIuSLVK.cjs} +74 -49
  429. package/dist/src/{util-C8e5uydV.js → util-Bx677_k2.js} +154 -147
  430. package/dist/src/util-CN8om2rz.cjs +386 -0
  431. package/dist/src/{util-DDs-7g6-.js → util-CoQWM76y.js} +28 -8
  432. package/dist/src/util-DNl96nNs.js +327 -0
  433. package/dist/src/{util-DxWpWjhc.js → util-DURocbYR.js} +667 -507
  434. package/dist/src/util-Df8YMvS1.js +327 -0
  435. package/dist/src/{util-DvU2Pw8c.js → util-DiQ3QvBB.js} +28 -8
  436. package/dist/src/{util-oGMLA7vc.js → util-I-Rf-KaD.js} +862 -577
  437. package/dist/src/{util-olYL5C6N.cjs → util-IYzs5Y04.cjs} +33 -7
  438. package/dist/src/{util-D9TisOyk.js → util-LKTmNsMQ.js} +71 -47
  439. package/dist/src/{util-Bxn8emtE.cjs → util-SPsvFONY.cjs} +738 -582
  440. package/dist/src/{util-D3q0WQ-0.js → util-efByNxcr.js} +72 -48
  441. package/dist/src/util-kDURhgJW.js +328 -0
  442. package/dist/src/{utils-DJfvjyMj.js → utils-B0lzitHZ.js} +3 -3
  443. package/dist/src/{utils-BLJKfv0y.js → utils-BFOh20Gb.js} +3 -3
  444. package/dist/src/{utils-hXtCYanr.js → utils-BGY69tk_.js} +2 -2
  445. package/dist/src/{utils-B05gLxER.cjs → utils-Ve6kuJsa.cjs} +3 -3
  446. package/dist/src/version-BK20a4sw.js +16 -0
  447. package/dist/src/version-BWCSaByA.cjs +27 -0
  448. package/dist/src/version-eRkNuGv8.js +17 -0
  449. package/dist/src/version-lpHV_53E.js +16 -0
  450. package/dist/tsconfig.tsbuildinfo +1 -1
  451. package/package.json +56 -28
  452. package/dist/src/app/assets/Report-CQYFezYu.js +0 -1
  453. package/dist/src/app/assets/index-BXGkeMwh.css +0 -1
  454. package/dist/src/app/assets/index-BzJt18Jz.js +0 -385
  455. package/dist/src/app/assets/sync-IjzpWrOE.js +0 -4
  456. package/dist/src/app/assets/vendor-charts-BNdH8TCw.js +0 -36
  457. package/dist/src/cache-Cr9oLMUa.js +0 -3
  458. package/dist/src/cache-DbLsVWB2.cjs +0 -3
  459. package/dist/src/cloud-Hphvo8kr.js +0 -3
  460. package/dist/src/codex-sdk-BAmYE7qy.js +0 -3
  461. package/dist/src/codex-sdk-CWEnH70W.cjs +0 -2
  462. package/dist/src/evalResult-D8MT9p0s.js +0 -3
  463. package/dist/src/evalResult-DElBuddX.js +0 -2
  464. package/dist/src/evalResult-Dvc-iucu.cjs +0 -2
  465. package/dist/src/evaluator-CVessDWe.js +0 -3
  466. package/dist/src/fetch-C7bGKDlQ.js +0 -3
  467. package/dist/src/graders-BOAzQEUe.cjs +0 -2
  468. package/dist/src/graders-D4BTsZdG2.js +0 -3
  469. package/dist/src/graders-DOJK1XpV.js +0 -2
  470. package/dist/src/graders-NAv9LcBn.js +0 -2
  471. package/dist/src/image-B5Mv-Z3h.js +0 -257
  472. package/dist/src/image-DVz2RiMF.js +0 -258
  473. package/dist/src/image-qUpPvmNZ.js +0 -257
  474. package/dist/src/image-x6KqLQl4.cjs +0 -280
  475. package/dist/src/providers-Bp4S-FvO.js +0 -2
  476. package/dist/src/providers-DV3ax9e_.cjs +0 -3
  477. package/dist/src/providers-u9Enmfok.js +0 -2
  478. package/dist/src/render-CH-62LbA.js +0 -135
  479. package/dist/src/render-CMEpfLaO.js +0 -136
  480. package/dist/src/render-DHIZ6_k8.js +0 -135
  481. package/dist/src/render-DfQSFxGE.cjs +0 -165
  482. package/dist/src/rubyUtils-D1L2d3jb.js +0 -3
  483. package/dist/src/rubyUtils-DUbq4tff.cjs +0 -2
  484. package/dist/src/server-BNYztJkh.js +0 -385
  485. package/dist/src/server-DCtHUqlp.js +0 -3
  486. package/dist/src/server-DaA2eR26.cjs +0 -2
  487. package/dist/src/store-CWOSz6D_.cjs +0 -2
  488. package/dist/src/store-DCDBhv7B.js +0 -3
  489. package/dist/src/store-Dn9HUkdW.js +0 -240
  490. package/dist/src/telemetry-C1IqxcdW.js +0 -3
  491. package/dist/src/telemetry-C4ZEa_es.cjs +0 -2
  492. package/dist/src/transform-Bbg6A8Jk.js +0 -216
  493. package/dist/src/transform-CUnzlsbn.cjs +0 -228
  494. package/dist/src/transform-DYX1_Xnh.js +0 -216
  495. package/dist/src/transform-DgKlRr73.cjs +0 -2
  496. package/dist/src/transform-M6ITAESf.js +0 -3
  497. package/dist/src/transform-UN5UGu8U.js +0 -213
@@ -0,0 +1,1916 @@
1
+ #!/usr/bin/env node
2
+ import { N as state, O as getEnvString, m as sanitizeObject, p as normalizeFieldName, s as logger, u as REDACTED } from "./logger-BbY6ypFL.js";
3
+ import { n as VERSION } from "./version-eRkNuGv8.js";
4
+ import { i as withGenAISpan, n as getTraceparent } from "./genaiTracer-BPVvltoW.js";
5
+ import { n as renderVarsInObject } from "./render-CSP99NLm.js";
6
+ import { t as providerRegistry } from "./providerRegistry-ReCd0sFa.js";
7
+ import { z } from "zod";
8
+ import fs from "fs";
9
+ import path from "path";
10
+ import dedent from "dedent";
11
+ import crypto from "crypto";
12
+ import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
13
+ import readline from "readline";
14
+ import { spawn } from "child_process";
15
+ //#region src/providers/openai/codex-app-server.ts
16
+ const MAX_BUFFERED_JSON_RPC_CHARS = 5e6;
17
+ const DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
18
+ const DEFAULT_STARTUP_TIMEOUT_MS = 3e4;
19
+ const MINIMAL_CLI_ENV_KEYS = [
20
+ "PATH",
21
+ "Path",
22
+ "HOME",
23
+ "USER",
24
+ "USERNAME",
25
+ "USERPROFILE",
26
+ "TMPDIR",
27
+ "TMP",
28
+ "TEMP",
29
+ "SHELL",
30
+ "COMSPEC",
31
+ "SystemRoot",
32
+ "PATHEXT",
33
+ "LANG",
34
+ "LC_ALL",
35
+ "TERM"
36
+ ];
37
+ const COMMON_OPTIONAL_PROCESS_ENV_KEYS = [
38
+ "CODEX_HOME",
39
+ "HTTP_PROXY",
40
+ "HTTPS_PROXY",
41
+ "ALL_PROXY",
42
+ "NO_PROXY",
43
+ "SSL_CERT_FILE",
44
+ "SSL_CERT_DIR",
45
+ "REQUESTS_CA_BUNDLE",
46
+ "NODE_EXTRA_CA_CERTS",
47
+ "SSH_AUTH_SOCK",
48
+ "GIT_SSH_COMMAND"
49
+ ];
50
+ const CODEX_MODEL_PRICING = {
51
+ "gpt-5.4": {
52
+ input: 2.5,
53
+ output: 15,
54
+ cache_read: .25
55
+ },
56
+ "gpt-5.4-pro": {
57
+ input: 30,
58
+ output: 180,
59
+ cache_read: 30
60
+ },
61
+ "gpt-5.3-codex": {
62
+ input: 1.75,
63
+ output: 14,
64
+ cache_read: .175
65
+ },
66
+ "gpt-5.3-codex-spark": {
67
+ input: .5,
68
+ output: 4,
69
+ cache_read: .05
70
+ },
71
+ "gpt-5.2": {
72
+ input: 1.75,
73
+ output: 14,
74
+ cache_read: .175
75
+ },
76
+ "gpt-5.2-codex": {
77
+ input: 1.75,
78
+ output: 14,
79
+ cache_read: .175
80
+ },
81
+ "gpt-5.1-codex": {
82
+ input: 2,
83
+ output: 8,
84
+ cache_read: .2
85
+ },
86
+ "gpt-5.1-codex-max": {
87
+ input: 3,
88
+ output: 12,
89
+ cache_read: .3
90
+ },
91
+ "gpt-5.1-codex-mini": {
92
+ input: .5,
93
+ output: 2,
94
+ cache_read: .05
95
+ },
96
+ "gpt-5-codex": {
97
+ input: 2,
98
+ output: 8,
99
+ cache_read: .2
100
+ },
101
+ "gpt-5-codex-mini": {
102
+ input: .5,
103
+ output: 2,
104
+ cache_read: .05
105
+ },
106
+ "gpt-5": {
107
+ input: 2,
108
+ output: 8,
109
+ cache_read: .2
110
+ }
111
+ };
112
+ const CodexCliEnvValueSchema = z.union([
113
+ z.string(),
114
+ z.number(),
115
+ z.boolean()
116
+ ]).transform(String);
117
+ const CodexAppServerReasoningEffortSchema = z.enum([
118
+ "none",
119
+ "minimal",
120
+ "low",
121
+ "medium",
122
+ "high",
123
+ "xhigh"
124
+ ]);
125
+ const CodexAppServerGranularApprovalPolicySchema = z.object({ granular: z.object({
126
+ sandbox_approval: z.boolean(),
127
+ rules: z.boolean(),
128
+ skill_approval: z.boolean(),
129
+ request_permissions: z.boolean(),
130
+ mcp_elicitations: z.boolean()
131
+ }).strict() }).strict();
132
+ const CodexAppServerApprovalPolicySchema = z.union([z.enum([
133
+ "never",
134
+ "on-request",
135
+ "on-failure",
136
+ "untrusted"
137
+ ]), CodexAppServerGranularApprovalPolicySchema]);
138
+ const CommandExecutionApprovalDecisionSchema = z.union([
139
+ z.enum([
140
+ "accept",
141
+ "acceptForSession",
142
+ "decline",
143
+ "cancel"
144
+ ]),
145
+ z.object({ acceptWithExecpolicyAmendment: z.object({ execpolicy_amendment: z.array(z.string()) }).strict() }).strict(),
146
+ z.object({ applyNetworkPolicyAmendment: z.object({ network_policy_amendment: z.object({
147
+ host: z.string().min(1),
148
+ action: z.enum(["allow", "deny"])
149
+ }).strict() }).strict() }).strict()
150
+ ]);
151
+ const McpElicitationPolicySchema = z.union([z.enum([
152
+ "accept",
153
+ "decline",
154
+ "cancel"
155
+ ]), z.object({
156
+ action: z.enum([
157
+ "accept",
158
+ "decline",
159
+ "cancel"
160
+ ]),
161
+ content: z.unknown().optional(),
162
+ _meta: z.unknown().optional()
163
+ }).strict()]);
164
+ const CollaborationModeSchema = z.object({
165
+ mode: z.enum(["plan", "default"]),
166
+ settings: z.object({
167
+ model: z.string().min(1),
168
+ reasoning_effort: CodexAppServerReasoningEffortSchema.nullable(),
169
+ developer_instructions: z.string().nullable()
170
+ }).strict()
171
+ }).strict();
172
+ const ServerRequestPolicySchema = z.object({
173
+ command_execution: CommandExecutionApprovalDecisionSchema.optional(),
174
+ file_change: z.enum([
175
+ "accept",
176
+ "acceptForSession",
177
+ "decline",
178
+ "cancel"
179
+ ]).optional(),
180
+ permissions: z.object({
181
+ permissions: z.record(z.string(), z.unknown()).optional(),
182
+ scope: z.enum(["turn", "session"]).optional()
183
+ }).optional(),
184
+ user_input: z.union([z.enum(["empty", "first-option"]), z.record(z.string(), z.union([z.string(), z.array(z.string())]))]).optional(),
185
+ mcp_elicitation: McpElicitationPolicySchema.optional(),
186
+ dynamic_tools: z.record(z.string(), z.object({
187
+ success: z.boolean().optional(),
188
+ text: z.string().optional(),
189
+ contentItems: z.array(z.union([z.object({
190
+ type: z.literal("inputText"),
191
+ text: z.string()
192
+ }), z.object({
193
+ type: z.literal("inputImage"),
194
+ imageUrl: z.string()
195
+ })])).optional()
196
+ })).optional()
197
+ }).strict();
198
+ const CodexAppServerConfigShape = {
199
+ basePath: z.string().optional(),
200
+ prefix: z.string().optional(),
201
+ suffix: z.string().optional(),
202
+ provider: z.unknown().optional(),
203
+ linkedTargetId: z.string().optional(),
204
+ apiKey: z.string().min(1).optional(),
205
+ base_url: z.string().min(1).optional(),
206
+ working_dir: z.string().min(1).optional(),
207
+ additional_directories: z.array(z.string().min(1)).optional(),
208
+ skip_git_repo_check: z.boolean().optional(),
209
+ codex_path_override: z.string().min(1).optional(),
210
+ model: z.string().min(1).optional(),
211
+ model_provider: z.string().min(1).optional(),
212
+ service_tier: z.enum(["fast", "flex"]).optional(),
213
+ sandbox_mode: z.enum([
214
+ "read-only",
215
+ "workspace-write",
216
+ "danger-full-access"
217
+ ]).optional(),
218
+ sandbox_policy: z.record(z.string(), z.unknown()).optional(),
219
+ network_access_enabled: z.boolean().optional(),
220
+ approval_policy: CodexAppServerApprovalPolicySchema.optional(),
221
+ approvals_reviewer: z.enum(["user", "guardian_subagent"]).optional(),
222
+ model_reasoning_effort: CodexAppServerReasoningEffortSchema.optional(),
223
+ reasoning_summary: z.enum([
224
+ "auto",
225
+ "concise",
226
+ "detailed",
227
+ "none"
228
+ ]).optional(),
229
+ personality: z.enum([
230
+ "none",
231
+ "friendly",
232
+ "pragmatic"
233
+ ]).optional(),
234
+ base_instructions: z.string().min(1).optional(),
235
+ developer_instructions: z.string().min(1).optional(),
236
+ collaboration_mode: CollaborationModeSchema.optional(),
237
+ output_schema: z.record(z.string(), z.unknown()).optional(),
238
+ thread_id: z.string().min(1).optional(),
239
+ persist_threads: z.boolean().optional(),
240
+ thread_pool_size: z.number().int().positive().optional(),
241
+ thread_cleanup: z.enum([
242
+ "unsubscribe",
243
+ "archive",
244
+ "none"
245
+ ]).optional(),
246
+ ephemeral: z.boolean().optional(),
247
+ persist_extended_history: z.boolean().optional(),
248
+ experimental_raw_events: z.boolean().optional(),
249
+ experimental_api: z.boolean().optional(),
250
+ include_raw_events: z.boolean().optional(),
251
+ cli_config: z.record(z.string(), z.unknown()).optional(),
252
+ cli_env: z.record(z.string(), CodexCliEnvValueSchema).optional(),
253
+ inherit_process_env: z.boolean().optional(),
254
+ reuse_server: z.boolean().optional(),
255
+ deep_tracing: z.boolean().optional(),
256
+ request_timeout_ms: z.number().int().positive().optional(),
257
+ startup_timeout_ms: z.number().int().positive().optional(),
258
+ turn_timeout_ms: z.number().int().positive().optional(),
259
+ server_request_policy: ServerRequestPolicySchema.optional()
260
+ };
261
+ const CodexAppServerConfigSchema = z.object(CodexAppServerConfigShape).strict();
262
+ const CodexAppServerMergedPromptConfigSchema = z.object(CodexAppServerConfigShape).strip();
263
+ function createDeferred() {
264
+ let resolve;
265
+ let reject;
266
+ return {
267
+ promise: new Promise((promiseResolve, promiseReject) => {
268
+ resolve = promiseResolve;
269
+ reject = promiseReject;
270
+ }),
271
+ resolve,
272
+ reject
273
+ };
274
+ }
275
+ function parseCodexAppServerConfig(config, options = {}) {
276
+ const schema = options.stripUnknownKeys ? CodexAppServerMergedPromptConfigSchema : CodexAppServerConfigSchema;
277
+ try {
278
+ return schema.parse(config ?? {});
279
+ } catch (error) {
280
+ if (error instanceof z.ZodError) {
281
+ const issues = error.issues.map((issue) => {
282
+ return `${issue.path.length > 0 ? issue.path.join(".") : "(root)"}: ${issue.message}`;
283
+ }).join("; ");
284
+ throw new Error(`Invalid OpenAI Codex app-server config: ${issues}`);
285
+ }
286
+ throw error;
287
+ }
288
+ }
289
+ function mergeOptionalRecord(base, override) {
290
+ if (!base && !override) return;
291
+ return {
292
+ ...base ?? {},
293
+ ...override ?? {}
294
+ };
295
+ }
296
+ function mergeServerRequestPolicy(base, override) {
297
+ if (!base && !override) return;
298
+ const merged = {
299
+ ...base ?? {},
300
+ ...override ?? {}
301
+ };
302
+ const permissions = mergeOptionalRecord(base?.permissions, override?.permissions);
303
+ const dynamicTools = mergeOptionalRecord(base?.dynamic_tools, override?.dynamic_tools);
304
+ if (permissions) merged.permissions = permissions;
305
+ else delete merged.permissions;
306
+ if (dynamicTools) merged.dynamic_tools = dynamicTools;
307
+ else delete merged.dynamic_tools;
308
+ return merged;
309
+ }
310
+ function mergeCodexAppServerConfig(base, override) {
311
+ if (!override) return { ...base };
312
+ return {
313
+ ...base,
314
+ ...override,
315
+ cli_config: mergeOptionalRecord(base.cli_config, override.cli_config),
316
+ cli_env: mergeOptionalRecord(base.cli_env, override.cli_env),
317
+ server_request_policy: mergeServerRequestPolicy(base.server_request_policy, override.server_request_policy)
318
+ };
319
+ }
320
+ function getMinimalProcessEnv() {
321
+ const env = {};
322
+ for (const key of MINIMAL_CLI_ENV_KEYS) {
323
+ const value = process.env[key];
324
+ if (typeof value === "string" && value.length > 0) env[key] = value;
325
+ }
326
+ return env;
327
+ }
328
+ function isPlainObject(value) {
329
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
330
+ }
331
+ function flattenConfig(value, prefix = "") {
332
+ const entries = [];
333
+ for (const [key, entryValue] of Object.entries(value)) {
334
+ const nextKey = prefix ? `${prefix}.${key}` : key;
335
+ if (isPlainObject(entryValue)) entries.push(...flattenConfig(entryValue, nextKey));
336
+ else if (entryValue !== void 0) entries.push({
337
+ key: nextKey,
338
+ value: entryValue
339
+ });
340
+ }
341
+ return entries;
342
+ }
343
+ function toTomlLiteral(value) {
344
+ if (typeof value === "string") return JSON.stringify(value);
345
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
346
+ if (Array.isArray(value)) return `[${value.map((item) => toTomlLiteral(item)).join(", ")}]`;
347
+ if (value === null) return "\"\"";
348
+ return JSON.stringify(value);
349
+ }
350
+ function getJsonRpcErrorMessage(message) {
351
+ if (typeof message.error?.message === "string" && message.error.message) return message.error.message;
352
+ return "Unknown app-server error";
353
+ }
354
+ function createAbortError(message) {
355
+ const error = new Error(message);
356
+ error.name = "AbortError";
357
+ return error;
358
+ }
359
+ var CodexAppServerConnection = class {
360
+ instanceId;
361
+ process;
362
+ lineInterface;
363
+ nextRequestId = 1;
364
+ pending = /* @__PURE__ */ new Map();
365
+ closed = false;
366
+ stderrChunks = [];
367
+ stderrTotalLength = 0;
368
+ bufferedJsonRpcLines = [];
369
+ closePromise = null;
370
+ constructor(options) {
371
+ this.options = options;
372
+ this.instanceId = options.connectionInstanceId;
373
+ this.process = spawn(options.command, options.args, {
374
+ env: options.env,
375
+ stdio: [
376
+ "pipe",
377
+ "pipe",
378
+ "pipe"
379
+ ]
380
+ });
381
+ this.lineInterface = readline.createInterface({ input: this.process.stdout });
382
+ this.lineInterface.on("line", (line) => this.handleLine(line));
383
+ this.process.stderr.on("data", (chunk) => this.recordStderr(chunk));
384
+ this.process.stdin.on("error", (error) => {
385
+ logger.debug("[CodexAppServer] stdin error", { error: error.message });
386
+ });
387
+ this.process.on("error", (error) => this.handleProcessFailure(error));
388
+ this.process.on("exit", (code, signal) => {
389
+ if (this.closed) this.rejectPending(/* @__PURE__ */ new Error("codex app-server process closed"));
390
+ else this.handleProcessFailure(/* @__PURE__ */ new Error(`codex app-server exited with code ${code ?? "null"} signal ${signal ?? "null"}`));
391
+ });
392
+ }
393
+ async initialize(config) {
394
+ await this.request("initialize", {
395
+ clientInfo: {
396
+ name: "promptfoo_codex_app_server",
397
+ title: "Promptfoo Codex App Server Provider",
398
+ version: VERSION
399
+ },
400
+ capabilities: { experimentalApi: config.experimental_api ?? true }
401
+ }, { timeoutMs: this.options.startupTimeoutMs });
402
+ this.notify("initialized", {});
403
+ }
404
+ request(method, params, options = {}) {
405
+ if (this.closed) return Promise.reject(/* @__PURE__ */ new Error("codex app-server connection is closed"));
406
+ if (options.abortSignal?.aborted) return Promise.reject(createAbortError(`codex app-server request aborted: ${method}`));
407
+ const id = this.nextRequestId++;
408
+ const message = {
409
+ method,
410
+ id
411
+ };
412
+ if (params !== void 0) message.params = params;
413
+ const timeoutMs = options.timeoutMs ?? this.options.requestTimeoutMs;
414
+ return new Promise((resolve, reject) => {
415
+ const pendingRequest = {
416
+ method,
417
+ resolve,
418
+ reject,
419
+ abortSignal: options.abortSignal,
420
+ onResponse: options.onResponse
421
+ };
422
+ pendingRequest.timeout = setTimeout(() => {
423
+ const error = /* @__PURE__ */ new Error(`codex app-server request timed out: ${method}`);
424
+ this.pending.delete(id);
425
+ if (options.abortSignal && pendingRequest.abortListener) options.abortSignal.removeEventListener("abort", pendingRequest.abortListener);
426
+ reject(error);
427
+ this.closeAfterRequestTimeout(method, error);
428
+ }, timeoutMs);
429
+ if (options.abortSignal) {
430
+ pendingRequest.abortListener = () => {
431
+ const error = createAbortError(`codex app-server request aborted: ${method}`);
432
+ this.pending.delete(id);
433
+ if (pendingRequest.timeout) clearTimeout(pendingRequest.timeout);
434
+ reject(error);
435
+ logger.debug("[CodexAppServer] JSON-RPC request aborted", {
436
+ error: error.message,
437
+ method
438
+ });
439
+ };
440
+ options.abortSignal.addEventListener("abort", pendingRequest.abortListener, { once: true });
441
+ }
442
+ this.pending.set(id, pendingRequest);
443
+ this.send(message);
444
+ });
445
+ }
446
+ notify(method, params) {
447
+ const message = { method };
448
+ if (params !== void 0) message.params = params;
449
+ this.send(message);
450
+ }
451
+ getStderr() {
452
+ return this.stderrChunks.join("").slice(-1e4);
453
+ }
454
+ async close() {
455
+ if (this.closePromise !== null) return this.closePromise;
456
+ this.closePromise = new Promise((resolve) => {
457
+ this.closed = true;
458
+ this.rejectPending(/* @__PURE__ */ new Error("codex app-server connection closed"));
459
+ this.lineInterface.close();
460
+ const finish = () => resolve();
461
+ const killTimer = setTimeout(() => {
462
+ try {
463
+ if (!this.process.killed) this.process.kill("SIGKILL");
464
+ } catch {}
465
+ finish();
466
+ }, 1e3);
467
+ this.process.once("exit", () => {
468
+ clearTimeout(killTimer);
469
+ finish();
470
+ });
471
+ if (this.process.killed || this.process.exitCode !== null) {
472
+ clearTimeout(killTimer);
473
+ finish();
474
+ return;
475
+ }
476
+ try {
477
+ this.process.stdin.end();
478
+ this.process.kill("SIGTERM");
479
+ } catch {
480
+ clearTimeout(killTimer);
481
+ finish();
482
+ }
483
+ });
484
+ return this.closePromise;
485
+ }
486
+ handleLine(line) {
487
+ const trimmed = line.trim();
488
+ if (!trimmed && this.bufferedJsonRpcLines.length === 0) return;
489
+ const candidateLines = this.bufferedJsonRpcLines.length > 0 ? [...this.bufferedJsonRpcLines, line] : [trimmed];
490
+ const candidate = candidateLines.join("\\n");
491
+ let message;
492
+ try {
493
+ message = JSON.parse(candidate);
494
+ } catch (error) {
495
+ if (this.shouldBufferJsonRpcLine(error, trimmed)) {
496
+ this.bufferedJsonRpcLines = candidateLines;
497
+ if (candidate.length > MAX_BUFFERED_JSON_RPC_CHARS) {
498
+ logger.warn("[CodexAppServer] Dropping oversized partial JSON-RPC message", {
499
+ error,
500
+ bufferedChars: candidate.length
501
+ });
502
+ this.bufferedJsonRpcLines = [];
503
+ }
504
+ return;
505
+ }
506
+ logger.warn("[CodexAppServer] Failed to parse JSON-RPC line", {
507
+ error,
508
+ line: candidate
509
+ });
510
+ this.bufferedJsonRpcLines = [];
511
+ return;
512
+ }
513
+ this.bufferedJsonRpcLines = [];
514
+ this.handleMessage(message);
515
+ }
516
+ shouldBufferJsonRpcLine(error, trimmedLine) {
517
+ if (this.bufferedJsonRpcLines.length > 0) return true;
518
+ if (!trimmedLine.startsWith("{")) return false;
519
+ const message = error instanceof Error ? error.message : String(error);
520
+ return /Unterminated string|Unexpected end of JSON input|Bad control character/i.test(message);
521
+ }
522
+ handleMessage(message) {
523
+ if (message.id !== void 0 && (message.result !== void 0 || message.error !== void 0)) {
524
+ this.handleResponse(message);
525
+ return;
526
+ }
527
+ if (message.id !== void 0 && message.method) {
528
+ this.handleServerRequest(message);
529
+ return;
530
+ }
531
+ if (message.method) {
532
+ this.options.onNotification(message);
533
+ return;
534
+ }
535
+ logger.debug("[CodexAppServer] Ignoring unknown JSON-RPC message shape", { message });
536
+ }
537
+ handleResponse(message) {
538
+ const pendingRequest = this.pending.get(message.id);
539
+ if (!pendingRequest) {
540
+ logger.debug("[CodexAppServer] Received response for unknown request", { id: message.id });
541
+ return;
542
+ }
543
+ this.pending.delete(message.id);
544
+ if (pendingRequest.timeout) clearTimeout(pendingRequest.timeout);
545
+ if (pendingRequest.abortSignal && pendingRequest.abortListener) pendingRequest.abortSignal.removeEventListener("abort", pendingRequest.abortListener);
546
+ if (message.error) {
547
+ pendingRequest.reject(new Error(getJsonRpcErrorMessage(message)));
548
+ return;
549
+ }
550
+ try {
551
+ pendingRequest.onResponse?.(message.result);
552
+ } catch (error) {
553
+ pendingRequest.reject(error instanceof Error ? error : new Error(String(error)));
554
+ return;
555
+ }
556
+ pendingRequest.resolve(message.result);
557
+ }
558
+ async handleServerRequest(message) {
559
+ try {
560
+ const result = await this.options.onServerRequest(message);
561
+ this.send({
562
+ id: message.id,
563
+ result
564
+ });
565
+ } catch (error) {
566
+ const errorMessage = error instanceof Error ? error.message : String(error);
567
+ try {
568
+ this.send({
569
+ id: message.id,
570
+ error: {
571
+ code: -32e3,
572
+ message: errorMessage
573
+ }
574
+ });
575
+ } catch (sendError) {
576
+ logger.debug("[CodexAppServer] Failed to send error response for server request", {
577
+ error: sendError,
578
+ originalError: errorMessage,
579
+ method: message.method
580
+ });
581
+ }
582
+ }
583
+ }
584
+ recordStderr(chunk) {
585
+ const text = chunk.toString("utf8");
586
+ this.stderrChunks.push(text);
587
+ this.stderrTotalLength += text.length;
588
+ if (this.stderrTotalLength > 2e4) {
589
+ const truncated = this.getStderr();
590
+ this.stderrChunks = [truncated];
591
+ this.stderrTotalLength = truncated.length;
592
+ }
593
+ logger.debug("[CodexAppServer] stderr", { text });
594
+ }
595
+ handleProcessFailure(error) {
596
+ if (this.closed) return;
597
+ this.closed = true;
598
+ this.rejectPending(error);
599
+ logger.error("[CodexAppServer] Process failure", {
600
+ error: error.message,
601
+ stderr: this.getStderr()
602
+ });
603
+ this.options.onClose(error);
604
+ }
605
+ closeAfterRequestTimeout(method, error) {
606
+ if (this.closed) return;
607
+ logger.warn("[CodexAppServer] Closing app-server after JSON-RPC request timeout", {
608
+ error: error.message,
609
+ method
610
+ });
611
+ this.options.onClose(error);
612
+ this.close().catch((closeError) => {
613
+ logger.debug("[CodexAppServer] Error closing app-server after request timeout", { error: closeError });
614
+ });
615
+ }
616
+ rejectPending(error) {
617
+ for (const [id, pendingRequest] of this.pending) {
618
+ if (pendingRequest.timeout) clearTimeout(pendingRequest.timeout);
619
+ if (pendingRequest.abortSignal && pendingRequest.abortListener) pendingRequest.abortSignal.removeEventListener("abort", pendingRequest.abortListener);
620
+ pendingRequest.reject(error);
621
+ this.pending.delete(id);
622
+ }
623
+ }
624
+ send(message) {
625
+ if (this.closed) throw new Error("codex app-server connection is closed");
626
+ this.process.stdin.write(`${JSON.stringify(message)}\n`);
627
+ }
628
+ };
629
+ var OpenAICodexAppServerProvider = class {
630
+ config;
631
+ env;
632
+ apiKey;
633
+ providerId = "openai:codex-app-server";
634
+ connections = /* @__PURE__ */ new Map();
635
+ connectionPromises = /* @__PURE__ */ new Map();
636
+ initializingConnections = /* @__PURE__ */ new Set();
637
+ threads = /* @__PURE__ */ new Map();
638
+ threadPromises = /* @__PURE__ */ new Map();
639
+ threadPromiseConnectionInstances = /* @__PURE__ */ new Map();
640
+ protectedThreadCounts = /* @__PURE__ */ new Map();
641
+ threadRunQueues = /* @__PURE__ */ new Map();
642
+ activeTurnsByThread = /* @__PURE__ */ new Map();
643
+ activeTurnsByTurn = /* @__PURE__ */ new Map();
644
+ validatedWorkingDirs = /* @__PURE__ */ new Set();
645
+ ignoredProviderEnvWarningShown = false;
646
+ omittedProcessEnvWarningShown = false;
647
+ deepTracingWarningShown = false;
648
+ constructor(options = {}) {
649
+ this.config = parseCodexAppServerConfig(options.config);
650
+ this.env = options.env;
651
+ this.apiKey = this.getApiKey();
652
+ this.providerId = options.id ?? this.providerId;
653
+ providerRegistry.register(this);
654
+ }
655
+ id() {
656
+ return this.providerId;
657
+ }
658
+ getApiKey(config = this.config) {
659
+ return config.apiKey || this.env?.OPENAI_API_KEY || this.env?.CODEX_API_KEY || getEnvString("OPENAI_API_KEY") || getEnvString("CODEX_API_KEY");
660
+ }
661
+ requiresApiKey() {
662
+ return false;
663
+ }
664
+ toString() {
665
+ return "[OpenAI Codex App Server Provider]";
666
+ }
667
+ async cleanup() {
668
+ this.resolveActiveTurns(/* @__PURE__ */ new Error("codex app-server provider cleanup interrupted active turn"));
669
+ this.threads.clear();
670
+ this.threadPromises.clear();
671
+ this.threadPromiseConnectionInstances.clear();
672
+ this.threadRunQueues.clear();
673
+ this.activeTurnsByThread.clear();
674
+ this.activeTurnsByTurn.clear();
675
+ this.protectedThreadCounts.clear();
676
+ this.validatedWorkingDirs.clear();
677
+ const connections = Array.from(new Set([...this.connections.values(), ...this.initializingConnections]));
678
+ this.connections.clear();
679
+ this.connectionPromises.clear();
680
+ this.initializingConnections.clear();
681
+ await Promise.all(connections.map((connection) => connection.close().catch((error) => {
682
+ logger.warn("[CodexAppServer] Error during cleanup", { error });
683
+ })));
684
+ }
685
+ async shutdown() {
686
+ try {
687
+ await this.cleanup();
688
+ } finally {
689
+ providerRegistry.unregister(this);
690
+ }
691
+ }
692
+ async callApi(prompt, context, callOptions) {
693
+ const config = renderVarsInObject(mergeCodexAppServerConfig(this.config, context?.prompt?.config), context?.vars);
694
+ const requestedModel = typeof config.model === "string" && config.model ? config.model : void 0;
695
+ return withGenAISpan(this.buildSpanContext(prompt, context, requestedModel), () => this.callApiInternal(prompt, context, callOptions, config), (response) => this.extractSpanResult(response, requestedModel));
696
+ }
697
+ buildSpanContext(prompt, context, requestedModel) {
698
+ return {
699
+ system: "openai",
700
+ operationName: "chat",
701
+ model: requestedModel ?? "codex-app-server",
702
+ providerId: this.id(),
703
+ evalId: context?.evaluationId || context?.test?.metadata?.evaluationId,
704
+ testIndex: typeof context?.test?.vars?.__testIdx === "number" ? context.test.vars.__testIdx : void 0,
705
+ promptLabel: context?.prompt?.label,
706
+ traceparent: context?.traceparent,
707
+ requestBody: prompt
708
+ };
709
+ }
710
+ extractSpanResult(response, requestedModel) {
711
+ const result = {};
712
+ if (response.tokenUsage) result.tokenUsage = response.tokenUsage;
713
+ if (response.sessionId) result.responseId = response.sessionId;
714
+ if (requestedModel) result.responseModel = requestedModel;
715
+ if (response.cached !== void 0) result.cacheHit = response.cached;
716
+ if (response.output !== void 0) result.responseBody = typeof response.output === "string" ? response.output : JSON.stringify(response.output);
717
+ if (response.metadata?.codexAppServer?.itemCounts) result.additionalAttributes = {
718
+ ...result.additionalAttributes,
719
+ "codex.app_server.items.breakdown": JSON.stringify(response.metadata.codexAppServer.itemCounts)
720
+ };
721
+ return result;
722
+ }
723
+ async callApiInternal(prompt, context, callOptions, rawConfig) {
724
+ let config;
725
+ try {
726
+ config = parseCodexAppServerConfig(rawConfig, { stripUnknownKeys: true });
727
+ } catch (error) {
728
+ const errorMessage = error instanceof Error ? error.message : String(error);
729
+ logger.error("Error calling OpenAI Codex app-server", { error: errorMessage });
730
+ return { error: `Error calling OpenAI Codex app-server: ${errorMessage}` };
731
+ }
732
+ if (callOptions?.abortSignal?.aborted) return { error: "OpenAI Codex app-server call aborted before it started" };
733
+ const workingDirectory = this.resolveWorkingDirectory(config);
734
+ const resolvedConfig = {
735
+ approval_policy: "never",
736
+ sandbox_mode: "read-only",
737
+ network_access_enabled: false,
738
+ ephemeral: true,
739
+ thread_cleanup: "unsubscribe",
740
+ reuse_server: true,
741
+ ...config,
742
+ working_dir: workingDirectory,
743
+ additional_directories: this.resolveAdditionalDirectories(config)
744
+ };
745
+ const currentTraceparent = getTraceparent();
746
+ const apiKey = this.getApiKey(resolvedConfig);
747
+ const env = this.prepareEnvironment(resolvedConfig, currentTraceparent, apiKey);
748
+ const promptInput = this.parsePromptInput(prompt);
749
+ const connectionKey = this.generateConnectionKey(env, resolvedConfig);
750
+ const useReusableConnection = resolvedConfig.reuse_server !== false && !resolvedConfig.deep_tracing;
751
+ let localConnection;
752
+ try {
753
+ this.validateWorkingDirectory(resolvedConfig.working_dir, resolvedConfig.skip_git_repo_check);
754
+ this.warnOnceForDeepTracingThreadOptions(resolvedConfig);
755
+ const connection = useReusableConnection ? await this.getOrCreateConnection(connectionKey, env, resolvedConfig) : await this.createConnection(connectionKey, env, resolvedConfig);
756
+ if (!useReusableConnection) localConnection = connection;
757
+ const promptCacheBasis = context?.prompt?.raw ?? prompt;
758
+ const threadHandle = await this.getOrCreateThread(connection, connectionKey, promptCacheBasis, resolvedConfig, useReusableConnection, callOptions);
759
+ this.protectThread(threadHandle.threadId);
760
+ let turnStarted = false;
761
+ try {
762
+ const queueKey = this.getThreadRunQueueKey(resolvedConfig, threadHandle);
763
+ return await this.runSerializedThreadTurn(queueKey, callOptions?.abortSignal, async () => {
764
+ turnStarted = true;
765
+ const state = this.createTurnState(connectionKey, connection.instanceId, threadHandle.threadId, promptInput, resolvedConfig, env);
766
+ this.registerTurnState(state);
767
+ try {
768
+ const turnResponse = await connection.request("turn/start", this.buildTurnStartParams(threadHandle.threadId, promptInput, resolvedConfig), {
769
+ abortSignal: callOptions?.abortSignal,
770
+ timeoutMs: this.getRequestTimeoutMs(resolvedConfig),
771
+ onResponse: (response) => {
772
+ const turnId = response?.turn?.id;
773
+ if (typeof turnId === "string") this.updateTurnStateId(state, turnId);
774
+ }
775
+ });
776
+ if (typeof turnResponse?.turn?.id === "string") this.updateTurnStateId(state, turnResponse.turn.id);
777
+ await this.waitForTurnCompletion(connection, state, resolvedConfig, callOptions);
778
+ return this.buildProviderResponse(state, threadHandle, resolvedConfig);
779
+ } finally {
780
+ this.unregisterTurnState(state);
781
+ await this.cleanupThreadAfterTurn(connection, threadHandle, resolvedConfig);
782
+ }
783
+ });
784
+ } finally {
785
+ this.unprotectThread(threadHandle.threadId);
786
+ if (!turnStarted) await this.cleanupThreadAfterTurn(connection, threadHandle, resolvedConfig, { skipIfActiveTurn: true });
787
+ this.scheduleThreadPoolEnforcement(connection, connectionKey, resolvedConfig);
788
+ }
789
+ } catch (error) {
790
+ if (error instanceof Error && error.name === "AbortError" || callOptions?.abortSignal?.aborted) {
791
+ logger.warn("OpenAI Codex app-server call aborted");
792
+ return { error: "OpenAI Codex app-server call aborted" };
793
+ }
794
+ const errorMessage = error instanceof Error ? error.message : String(error);
795
+ logger.error("Error calling OpenAI Codex app-server", { error: errorMessage });
796
+ return { error: `Error calling OpenAI Codex app-server: ${errorMessage}` };
797
+ } finally {
798
+ if (localConnection) await localConnection.close().catch((error) => {
799
+ logger.debug("[CodexAppServer] Error closing local connection", { error });
800
+ });
801
+ }
802
+ }
803
+ resolveWorkingDirectory(config) {
804
+ const basePath = config.basePath || state.basePath || process.cwd();
805
+ if (!config.working_dir) return process.cwd();
806
+ return path.resolve(basePath, config.working_dir);
807
+ }
808
+ resolveAdditionalDirectories(config) {
809
+ if (!config.additional_directories?.length) return;
810
+ const basePath = config.basePath || state.basePath || process.cwd();
811
+ return config.additional_directories.map((directory) => path.resolve(basePath, directory));
812
+ }
813
+ prepareEnvironment(config, traceparent, apiKey = this.getApiKey(config)) {
814
+ const inheritProcessEnv = config.inherit_process_env === true;
815
+ const cliEnv = Object.fromEntries(Object.entries(config.cli_env ?? {}).map(([key, value]) => [key, String(value)]));
816
+ const env = {
817
+ ...inheritProcessEnv ? process.env : getMinimalProcessEnv(),
818
+ ...cliEnv
819
+ };
820
+ const ignoredProviderEnvKeys = Object.keys(this.env ?? {}).filter((key) => key !== "OPENAI_API_KEY" && key !== "CODEX_API_KEY" && !(key in (config.cli_env ?? {}))).sort();
821
+ if (ignoredProviderEnvKeys.length > 0 && !this.ignoredProviderEnvWarningShown) {
822
+ logger.warn("[CodexAppServer] Ignoring promptfoo-level env overrides for the Codex app-server process. Move these keys into config.cli_env if Codex shell commands need them.", { envKeys: ignoredProviderEnvKeys });
823
+ this.ignoredProviderEnvWarningShown = true;
824
+ }
825
+ if (!inheritProcessEnv && !this.omittedProcessEnvWarningShown) {
826
+ const omittedProcessEnvKeys = this.getOmittedOptionalProcessEnvKeys(config, env);
827
+ if (omittedProcessEnvKeys.length > 0) {
828
+ logger.warn("[CodexAppServer] Optional Codex app-server process env vars are not inherited by default. Move these keys into config.cli_env or set inherit_process_env: true if Codex commands need them.", { envKeys: omittedProcessEnvKeys });
829
+ this.omittedProcessEnvWarningShown = true;
830
+ }
831
+ }
832
+ const sortedEnv = {};
833
+ for (const key of Object.keys(env).sort()) if (env[key] !== void 0) sortedEnv[key] = env[key];
834
+ if (apiKey) {
835
+ sortedEnv.OPENAI_API_KEY = apiKey;
836
+ sortedEnv.CODEX_API_KEY = apiKey;
837
+ }
838
+ if (config.base_url) {
839
+ sortedEnv.OPENAI_BASE_URL = config.base_url;
840
+ sortedEnv.OPENAI_API_BASE_URL = config.base_url;
841
+ }
842
+ if (config.deep_tracing) {
843
+ if (!sortedEnv.OTEL_EXPORTER_OTLP_ENDPOINT) sortedEnv.OTEL_EXPORTER_OTLP_ENDPOINT = "http://127.0.0.1:4318";
844
+ if (!sortedEnv.OTEL_EXPORTER_OTLP_PROTOCOL) sortedEnv.OTEL_EXPORTER_OTLP_PROTOCOL = "http/json";
845
+ if (!sortedEnv.OTEL_SERVICE_NAME) sortedEnv.OTEL_SERVICE_NAME = "codex-app-server";
846
+ if (!sortedEnv.OTEL_TRACES_EXPORTER) sortedEnv.OTEL_TRACES_EXPORTER = "otlp";
847
+ if (traceparent) sortedEnv.TRACEPARENT = traceparent;
848
+ } else delete sortedEnv.TRACEPARENT;
849
+ return sortedEnv;
850
+ }
851
+ getOmittedOptionalProcessEnvKeys(config, env) {
852
+ const shouldWarnForSshEnv = config.network_access_enabled === true;
853
+ return COMMON_OPTIONAL_PROCESS_ENV_KEYS.filter((key) => typeof process.env[key] === "string" && !(key in env) && (shouldWarnForSshEnv || key !== "SSH_AUTH_SOCK" && key !== "GIT_SSH_COMMAND"));
854
+ }
855
+ buildAppServerArgs(config) {
856
+ const args = [
857
+ "app-server",
858
+ "--listen",
859
+ "stdio://"
860
+ ];
861
+ const cliConfig = this.getResolvedCliConfig(config);
862
+ for (const { key, value } of flattenConfig(cliConfig)) args.push("-c", `${key}=${toTomlLiteral(value)}`);
863
+ return args;
864
+ }
865
+ getResolvedCliConfig(config) {
866
+ return { ...config.cli_config ?? {} };
867
+ }
868
+ getRequestTimeoutMs(config) {
869
+ return config.request_timeout_ms ?? DEFAULT_REQUEST_TIMEOUT_MS;
870
+ }
871
+ async getOrCreateConnection(connectionKey, env, config) {
872
+ const existing = this.connections.get(connectionKey);
873
+ if (existing) return existing;
874
+ const pending = this.connectionPromises.get(connectionKey);
875
+ if (pending) return pending;
876
+ let connectionPromise;
877
+ connectionPromise = this.createConnection(connectionKey, env, config).then((connection) => {
878
+ if (this.connectionPromises.get(connectionKey) !== connectionPromise) {
879
+ connection.close().catch((error) => {
880
+ logger.debug("[CodexAppServer] Error closing stale initialized connection", { error });
881
+ });
882
+ throw new Error("codex app-server connection was closed during cleanup");
883
+ }
884
+ this.connections.set(connectionKey, connection);
885
+ return connection;
886
+ }).finally(() => {
887
+ this.connectionPromises.delete(connectionKey);
888
+ });
889
+ this.connectionPromises.set(connectionKey, connectionPromise);
890
+ return connectionPromise;
891
+ }
892
+ async createConnection(connectionKey, env, config) {
893
+ const connectionInstanceId = `${connectionKey}:${crypto.randomUUID()}`;
894
+ const connection = new CodexAppServerConnection({
895
+ connectionInstanceId,
896
+ command: config.codex_path_override ?? "codex",
897
+ args: this.buildAppServerArgs(config),
898
+ env,
899
+ requestTimeoutMs: this.getRequestTimeoutMs(config),
900
+ startupTimeoutMs: config.startup_timeout_ms ?? DEFAULT_STARTUP_TIMEOUT_MS,
901
+ onNotification: (message) => this.handleNotification(message),
902
+ onServerRequest: (message) => this.handleServerRequest(message, config),
903
+ onClose: (error) => this.handleConnectionClose(connectionKey, connectionInstanceId, error)
904
+ });
905
+ this.initializingConnections.add(connection);
906
+ try {
907
+ await connection.initialize(config);
908
+ return connection;
909
+ } catch (error) {
910
+ await connection.close().catch((closeError) => {
911
+ logger.debug("[CodexAppServer] Error closing app-server after failed initialization", { error: closeError });
912
+ });
913
+ throw error;
914
+ } finally {
915
+ this.initializingConnections.delete(connection);
916
+ }
917
+ }
918
+ handleConnectionClose(connectionKey, connectionInstanceId, error) {
919
+ logger.warn("[CodexAppServer] Connection closed", {
920
+ connectionKey,
921
+ error: error.message
922
+ });
923
+ if (this.connections.get(connectionKey)?.instanceId === connectionInstanceId) {
924
+ this.connections.delete(connectionKey);
925
+ this.connectionPromises.delete(connectionKey);
926
+ for (const [threadCacheKey, handle] of this.threads) if (handle.connectionKey === connectionKey) this.threads.delete(threadCacheKey);
927
+ for (const [threadCacheKey] of this.threadPromises) if (this.threadPromiseConnectionInstances.get(threadCacheKey) === connectionInstanceId) {
928
+ this.threadPromises.delete(threadCacheKey);
929
+ this.threadPromiseConnectionInstances.delete(threadCacheKey);
930
+ }
931
+ }
932
+ this.resolveActiveTurns(error, (state) => state.connectionInstanceId === connectionInstanceId);
933
+ }
934
+ resolveActiveTurns(error, predicate = () => true) {
935
+ for (const state of new Set(this.activeTurnsByThread.values())) {
936
+ if (!predicate(state)) continue;
937
+ state.error = error.message;
938
+ state.completed.resolve();
939
+ }
940
+ }
941
+ generateConnectionKey(env, config) {
942
+ const stableEnv = { ...env };
943
+ delete stableEnv.TRACEPARENT;
944
+ const keyData = {
945
+ env: stableEnv,
946
+ codex_path_override: config.codex_path_override,
947
+ cli_config: this.getResolvedCliConfig(config),
948
+ experimental_api: config.experimental_api
949
+ };
950
+ return `openai:codex-app-server:connection:${crypto.createHash("sha256").update(JSON.stringify(keyData)).digest("hex")}`;
951
+ }
952
+ generateThreadCacheKey(connectionKey, promptCacheBasis, config) {
953
+ const keyData = {
954
+ connectionKey,
955
+ prompt: promptCacheBasis,
956
+ working_dir: config.working_dir,
957
+ additional_directories: config.additional_directories,
958
+ model: config.model,
959
+ model_provider: config.model_provider,
960
+ service_tier: config.service_tier,
961
+ sandbox_mode: config.sandbox_mode,
962
+ sandbox_policy: config.sandbox_policy,
963
+ network_access_enabled: config.network_access_enabled,
964
+ approval_policy: config.approval_policy,
965
+ approvals_reviewer: config.approvals_reviewer,
966
+ model_reasoning_effort: config.model_reasoning_effort,
967
+ reasoning_summary: config.reasoning_summary,
968
+ personality: config.personality,
969
+ base_instructions: config.base_instructions,
970
+ developer_instructions: config.developer_instructions,
971
+ collaboration_mode: config.collaboration_mode,
972
+ output_schema: config.output_schema,
973
+ base_url: config.base_url,
974
+ ephemeral: config.ephemeral,
975
+ experimental_raw_events: config.experimental_raw_events,
976
+ persist_extended_history: config.persist_extended_history
977
+ };
978
+ return `openai:codex-app-server:thread:${crypto.createHash("sha256").update(JSON.stringify(keyData)).digest("hex")}`;
979
+ }
980
+ async getOrCreateThread(connection, connectionKey, promptCacheBasis, config, allowThreadPersistence, callOptions) {
981
+ const canPersistThread = allowThreadPersistence && config.persist_threads === true;
982
+ if (config.thread_id) {
983
+ const cacheKey = canPersistThread ? `${connectionKey}:thread_id:${config.thread_id}` : void 0;
984
+ const cachedOrPending = this.getCachedOrPendingThread(cacheKey);
985
+ if (cachedOrPending !== void 0) return this.waitForThreadHandle(cachedOrPending, callOptions?.abortSignal);
986
+ this.throwIfThreadWaitAborted(callOptions?.abortSignal);
987
+ const threadPromise = this.cacheThreadPromise(cacheKey, connection.instanceId, async () => {
988
+ const response = await connection.request("thread/resume", this.buildThreadResumeParams(config.thread_id, config), { timeoutMs: this.getRequestTimeoutMs(config) });
989
+ const handle = {
990
+ connectionKey,
991
+ threadId: response?.thread?.id ?? config.thread_id,
992
+ response,
993
+ cacheKey,
994
+ persistent: canPersistThread
995
+ };
996
+ if (cacheKey) this.threads.set(cacheKey, handle);
997
+ return handle;
998
+ });
999
+ return cacheKey ? this.waitForThreadHandle(threadPromise, callOptions?.abortSignal) : this.waitForThreadHandle(threadPromise, callOptions?.abortSignal, { onAbortResolvedThread: (threadHandle) => this.cleanupThreadAfterTurn(connection, threadHandle, config, { skipIfProtected: true }) });
1000
+ }
1001
+ const cacheKey = canPersistThread ? this.generateThreadCacheKey(connectionKey, promptCacheBasis, config) : void 0;
1002
+ const cachedOrPending = this.getCachedOrPendingThread(cacheKey);
1003
+ if (cachedOrPending !== void 0) return this.waitForThreadHandle(cachedOrPending, callOptions?.abortSignal);
1004
+ this.throwIfThreadWaitAborted(callOptions?.abortSignal);
1005
+ const threadPromise = this.cacheThreadPromise(cacheKey, connection.instanceId, async () => {
1006
+ const poolSize = config.thread_pool_size ?? 1;
1007
+ if (cacheKey && this.threads.size >= poolSize) await this.evictOldestInactiveCachedThread(connection, connectionKey, this.getRequestTimeoutMs(config));
1008
+ const response = await connection.request("thread/start", this.buildThreadStartParams(config), { timeoutMs: this.getRequestTimeoutMs(config) });
1009
+ const threadId = response?.thread?.id;
1010
+ if (typeof threadId !== "string" || !threadId) throw new Error("codex app-server did not return a thread id");
1011
+ const handle = {
1012
+ connectionKey,
1013
+ threadId,
1014
+ response,
1015
+ cacheKey,
1016
+ persistent: canPersistThread
1017
+ };
1018
+ if (cacheKey) this.threads.set(cacheKey, handle);
1019
+ return handle;
1020
+ });
1021
+ return cacheKey ? this.waitForThreadHandle(threadPromise, callOptions?.abortSignal) : this.waitForThreadHandle(threadPromise, callOptions?.abortSignal, { onAbortResolvedThread: (threadHandle) => this.cleanupThreadAfterTurn(connection, threadHandle, config, { skipIfProtected: true }) });
1022
+ }
1023
+ getCachedOrPendingThread(cacheKey) {
1024
+ if (!cacheKey) return;
1025
+ return this.threads.get(cacheKey) ?? this.threadPromises.get(cacheKey);
1026
+ }
1027
+ cacheThreadPromise(cacheKey, connectionInstanceId, createThread) {
1028
+ if (!cacheKey) return createThread();
1029
+ let threadPromise;
1030
+ threadPromise = createThread().finally(() => {
1031
+ if (this.threadPromises.get(cacheKey) === threadPromise) {
1032
+ this.threadPromises.delete(cacheKey);
1033
+ this.threadPromiseConnectionInstances.delete(cacheKey);
1034
+ }
1035
+ });
1036
+ this.threadPromises.set(cacheKey, threadPromise);
1037
+ this.threadPromiseConnectionInstances.set(cacheKey, connectionInstanceId);
1038
+ return threadPromise;
1039
+ }
1040
+ throwIfThreadWaitAborted(abortSignal) {
1041
+ if (abortSignal?.aborted) throw createAbortError("Codex app-server thread wait aborted");
1042
+ }
1043
+ async waitForThreadHandle(thread, abortSignal, options = {}) {
1044
+ const threadPromise = Promise.resolve(thread);
1045
+ if (!abortSignal) return threadPromise;
1046
+ let abortCleanupScheduled = false;
1047
+ const scheduleAbortCleanup = () => {
1048
+ if (abortCleanupScheduled) return;
1049
+ abortCleanupScheduled = true;
1050
+ threadPromise.then(async (threadHandle) => {
1051
+ if (options.onAbortResolvedThread) await options.onAbortResolvedThread(threadHandle);
1052
+ }).catch((error) => {
1053
+ logger.debug("[CodexAppServer] Thread request finished with error after abort", { error });
1054
+ });
1055
+ };
1056
+ const createThreadAbortError = () => createAbortError(options.abortMessage ?? "Codex app-server thread wait aborted");
1057
+ if (abortSignal.aborted) {
1058
+ scheduleAbortCleanup();
1059
+ throw createThreadAbortError();
1060
+ }
1061
+ let abortListener;
1062
+ const abortPromise = new Promise((_, reject) => {
1063
+ abortListener = () => {
1064
+ scheduleAbortCleanup();
1065
+ reject(createThreadAbortError());
1066
+ };
1067
+ abortSignal.addEventListener("abort", abortListener, { once: true });
1068
+ });
1069
+ try {
1070
+ return await Promise.race([threadPromise, abortPromise]);
1071
+ } finally {
1072
+ if (abortListener) abortSignal.removeEventListener("abort", abortListener);
1073
+ }
1074
+ }
1075
+ scheduleThreadPoolEnforcement(fallbackConnection, fallbackConnectionKey, config) {
1076
+ if (!config.persist_threads || config.thread_id) return;
1077
+ this.enforceThreadPoolLimit(fallbackConnection, fallbackConnectionKey, config).catch((error) => {
1078
+ logger.debug("[CodexAppServer] Error enforcing thread pool limit", { error });
1079
+ });
1080
+ }
1081
+ async enforceThreadPoolLimit(fallbackConnection, fallbackConnectionKey, config) {
1082
+ const poolSize = config.thread_pool_size ?? 1;
1083
+ while (this.threads.size > poolSize) if (!await this.evictOldestInactiveCachedThread(fallbackConnection, fallbackConnectionKey, this.getRequestTimeoutMs(config))) return;
1084
+ }
1085
+ async evictOldestInactiveCachedThread(fallbackConnection, fallbackConnectionKey, timeoutMs) {
1086
+ for (const [cacheKey, handle] of this.threads) {
1087
+ if (this.isThreadProtected(handle.threadId)) continue;
1088
+ await this.evictCachedThread(fallbackConnection, fallbackConnectionKey, cacheKey, timeoutMs);
1089
+ return true;
1090
+ }
1091
+ logger.debug("[CodexAppServer] Thread pool is full, but all cached threads are active");
1092
+ return false;
1093
+ }
1094
+ async evictCachedThread(fallbackConnection, fallbackConnectionKey, cacheKey, timeoutMs) {
1095
+ const evicted = this.threads.get(cacheKey);
1096
+ this.threads.delete(cacheKey);
1097
+ if (!evicted) return;
1098
+ const connection = this.connections.get(evicted.connectionKey) ?? (evicted.connectionKey === fallbackConnectionKey ? fallbackConnection : void 0);
1099
+ if (!connection) {
1100
+ logger.debug("[CodexAppServer] Evicted cached thread without an active connection", { threadId: evicted.threadId });
1101
+ return;
1102
+ }
1103
+ try {
1104
+ await connection.request("thread/unsubscribe", { threadId: evicted.threadId }, { timeoutMs });
1105
+ } catch (error) {
1106
+ logger.warn("[CodexAppServer] Failed to unsubscribe evicted cached thread", {
1107
+ error,
1108
+ threadId: evicted.threadId
1109
+ });
1110
+ }
1111
+ }
1112
+ buildThreadStartParams(config) {
1113
+ return {
1114
+ ...config.model ? { model: config.model } : {},
1115
+ ...config.model_provider ? { modelProvider: config.model_provider } : {},
1116
+ ...config.service_tier ? { serviceTier: config.service_tier } : {},
1117
+ ...config.working_dir ? { cwd: config.working_dir } : {},
1118
+ approvalPolicy: config.approval_policy ?? "never",
1119
+ ...config.approvals_reviewer ? { approvalsReviewer: config.approvals_reviewer } : {},
1120
+ sandbox: config.sandbox_mode ?? "read-only",
1121
+ ...Object.keys(config.cli_config ?? {}).length > 0 ? { config: config.cli_config } : {},
1122
+ serviceName: "promptfoo",
1123
+ ...config.base_instructions ? { baseInstructions: config.base_instructions } : {},
1124
+ ...config.developer_instructions ? { developerInstructions: config.developer_instructions } : {},
1125
+ ...config.personality ? { personality: config.personality } : {},
1126
+ ...config.base_url ? { config: {
1127
+ ...config.cli_config ?? {},
1128
+ base_url: config.base_url
1129
+ } } : {},
1130
+ ephemeral: config.ephemeral ?? true,
1131
+ experimentalRawEvents: config.experimental_raw_events ?? false,
1132
+ persistExtendedHistory: config.persist_extended_history ?? false
1133
+ };
1134
+ }
1135
+ buildThreadResumeParams(threadId, config) {
1136
+ return {
1137
+ threadId,
1138
+ ...config.model ? { model: config.model } : {},
1139
+ ...config.model_provider ? { modelProvider: config.model_provider } : {},
1140
+ ...config.service_tier ? { serviceTier: config.service_tier } : {},
1141
+ ...config.working_dir ? { cwd: config.working_dir } : {},
1142
+ approvalPolicy: config.approval_policy ?? "never",
1143
+ ...config.approvals_reviewer ? { approvalsReviewer: config.approvals_reviewer } : {},
1144
+ sandbox: config.sandbox_mode ?? "read-only",
1145
+ ...Object.keys(config.cli_config ?? {}).length > 0 ? { config: config.cli_config } : {},
1146
+ ...config.base_instructions ? { baseInstructions: config.base_instructions } : {},
1147
+ ...config.developer_instructions ? { developerInstructions: config.developer_instructions } : {},
1148
+ ...config.personality ? { personality: config.personality } : {},
1149
+ persistExtendedHistory: config.persist_extended_history ?? false
1150
+ };
1151
+ }
1152
+ buildTurnStartParams(threadId, input, config) {
1153
+ return {
1154
+ threadId,
1155
+ input,
1156
+ ...config.working_dir ? { cwd: config.working_dir } : {},
1157
+ approvalPolicy: config.approval_policy ?? "never",
1158
+ ...config.approvals_reviewer ? { approvalsReviewer: config.approvals_reviewer } : {},
1159
+ ...config.sandbox_policy || config.network_access_enabled !== void 0 ? { sandboxPolicy: this.buildSandboxPolicy(config) } : {},
1160
+ ...config.model ? { model: config.model } : {},
1161
+ ...config.service_tier ? { serviceTier: config.service_tier } : {},
1162
+ ...config.model_reasoning_effort ? { effort: config.model_reasoning_effort } : {},
1163
+ ...config.reasoning_summary ? { summary: config.reasoning_summary } : {},
1164
+ ...config.personality ? { personality: config.personality } : {},
1165
+ ...config.collaboration_mode ? { collaborationMode: config.collaboration_mode } : {},
1166
+ ...config.output_schema ? { outputSchema: config.output_schema } : {}
1167
+ };
1168
+ }
1169
+ buildSandboxPolicy(config) {
1170
+ if (config.sandbox_policy) return config.sandbox_policy;
1171
+ const networkAccess = config.network_access_enabled === true;
1172
+ switch (config.sandbox_mode ?? "read-only") {
1173
+ case "danger-full-access": return { type: "dangerFullAccess" };
1174
+ case "workspace-write": return {
1175
+ type: "workspaceWrite",
1176
+ writableRoots: [config.working_dir, ...config.additional_directories ?? []].filter(Boolean),
1177
+ readOnlyAccess: { type: "fullAccess" },
1178
+ networkAccess,
1179
+ excludeTmpdirEnvVar: false,
1180
+ excludeSlashTmp: false
1181
+ };
1182
+ default: return {
1183
+ type: "readOnly",
1184
+ access: { type: "fullAccess" },
1185
+ networkAccess
1186
+ };
1187
+ }
1188
+ }
1189
+ parsePromptInput(prompt) {
1190
+ let parsedPrompt;
1191
+ try {
1192
+ parsedPrompt = JSON.parse(prompt);
1193
+ } catch {
1194
+ return [{
1195
+ type: "text",
1196
+ text: prompt,
1197
+ text_elements: []
1198
+ }];
1199
+ }
1200
+ if (!Array.isArray(parsedPrompt) || parsedPrompt.length === 0) return [{
1201
+ type: "text",
1202
+ text: prompt,
1203
+ text_elements: []
1204
+ }];
1205
+ const input = [];
1206
+ for (const item of parsedPrompt) {
1207
+ if (!this.isPromptInputItem(item)) return [{
1208
+ type: "text",
1209
+ text: prompt,
1210
+ text_elements: []
1211
+ }];
1212
+ input.push(this.normalizePromptInputItem(item));
1213
+ }
1214
+ return input;
1215
+ }
1216
+ isPromptInputItem(item) {
1217
+ if (!item || typeof item !== "object" || Array.isArray(item)) return false;
1218
+ if ("type" in item && item.type === "text") return "text" in item && typeof item.text === "string";
1219
+ if ("type" in item && item.type === "image") return "url" in item && typeof item.url === "string";
1220
+ if ("type" in item && (item.type === "local_image" || item.type === "localImage")) return "path" in item && typeof item.path === "string";
1221
+ if ("type" in item && (item.type === "skill" || item.type === "mention")) return "name" in item && typeof item.name === "string" && "path" in item && typeof item.path === "string";
1222
+ return false;
1223
+ }
1224
+ normalizePromptInputItem(item) {
1225
+ switch (item.type) {
1226
+ case "text": return {
1227
+ type: "text",
1228
+ text: item.text,
1229
+ text_elements: []
1230
+ };
1231
+ case "image": return {
1232
+ type: "image",
1233
+ url: item.url
1234
+ };
1235
+ case "local_image":
1236
+ case "localImage": return {
1237
+ type: "localImage",
1238
+ path: item.path
1239
+ };
1240
+ case "skill": return {
1241
+ type: "skill",
1242
+ name: item.name,
1243
+ path: item.path
1244
+ };
1245
+ case "mention": return {
1246
+ type: "mention",
1247
+ name: item.name,
1248
+ path: item.path
1249
+ };
1250
+ }
1251
+ }
1252
+ formatPromptInputForTrace(input) {
1253
+ return input.map((item) => {
1254
+ switch (item.type) {
1255
+ case "text": return item.text;
1256
+ case "image": return `[image: ${item.url}]`;
1257
+ case "localImage": return `[local_image: ${item.path}]`;
1258
+ case "skill": return `[skill: ${item.name} ${item.path}]`;
1259
+ case "mention": return `[mention: ${item.name} ${item.path}]`;
1260
+ }
1261
+ }).join("\n");
1262
+ }
1263
+ createTurnState(connectionKey, connectionInstanceId, threadId, promptInput, config, appServerEnv) {
1264
+ return {
1265
+ connectionKey,
1266
+ connectionInstanceId,
1267
+ threadId,
1268
+ config,
1269
+ appServerEnv,
1270
+ promptInput,
1271
+ items: [],
1272
+ itemStarts: [],
1273
+ notifications: [],
1274
+ notificationCount: 0,
1275
+ serverRequests: [],
1276
+ agentMessageDeltas: [],
1277
+ agentMessageDeltasByItemId: /* @__PURE__ */ new Map(),
1278
+ completed: createDeferred(),
1279
+ activeSpans: /* @__PURE__ */ new Map(),
1280
+ itemStartTimes: /* @__PURE__ */ new Map(),
1281
+ lastEventTime: Date.now()
1282
+ };
1283
+ }
1284
+ registerTurnState(state) {
1285
+ this.activeTurnsByThread.set(state.threadId, state);
1286
+ if (state.turnId) this.activeTurnsByTurn.set(state.turnId, state);
1287
+ }
1288
+ updateTurnStateId(state, turnId) {
1289
+ if (state.turnId && state.turnId !== turnId) this.activeTurnsByTurn.delete(state.turnId);
1290
+ state.turnId = turnId;
1291
+ this.activeTurnsByTurn.set(turnId, state);
1292
+ }
1293
+ unregisterTurnState(state) {
1294
+ this.activeTurnsByThread.delete(state.threadId);
1295
+ if (state.turnId) this.activeTurnsByTurn.delete(state.turnId);
1296
+ this.endUnclosedItemSpans(state);
1297
+ }
1298
+ protectThread(threadId) {
1299
+ this.protectedThreadCounts.set(threadId, (this.protectedThreadCounts.get(threadId) ?? 0) + 1);
1300
+ }
1301
+ unprotectThread(threadId) {
1302
+ const count = this.protectedThreadCounts.get(threadId);
1303
+ if (!count || count <= 1) {
1304
+ this.protectedThreadCounts.delete(threadId);
1305
+ return;
1306
+ }
1307
+ this.protectedThreadCounts.set(threadId, count - 1);
1308
+ }
1309
+ isThreadProtected(threadId) {
1310
+ return this.activeTurnsByThread.has(threadId) || (this.protectedThreadCounts.get(threadId) ?? 0) > 0;
1311
+ }
1312
+ getTurnState(threadId, turnId) {
1313
+ if (turnId) return this.activeTurnsByTurn.get(turnId);
1314
+ if (threadId) return this.activeTurnsByThread.get(threadId);
1315
+ }
1316
+ handleNotification(message) {
1317
+ const params = message.params ?? {};
1318
+ const state = this.getTurnState(params.threadId, params.turnId);
1319
+ if (!state) {
1320
+ logger.debug("[CodexAppServer] Notification without active turn", { method: message.method });
1321
+ return;
1322
+ }
1323
+ state.notificationCount += 1;
1324
+ if (state.config.include_raw_events) state.notifications.push(message);
1325
+ const eventTime = Date.now();
1326
+ switch (message.method) {
1327
+ case "turn/started":
1328
+ if (typeof params.turn?.id === "string") this.updateTurnStateId(state, params.turn.id);
1329
+ break;
1330
+ case "item/started":
1331
+ this.handleItemStarted(state, params.item, eventTime);
1332
+ break;
1333
+ case "item/completed":
1334
+ this.handleItemCompleted(state, params.item, eventTime);
1335
+ break;
1336
+ case "item/agentMessage/delta":
1337
+ this.handleAgentMessageDelta(state, params);
1338
+ break;
1339
+ case "thread/tokenUsage/updated":
1340
+ state.rawTokenUsage = params.tokenUsage;
1341
+ state.tokenUsage = this.buildTokenUsage(params.tokenUsage);
1342
+ break;
1343
+ case "turn/completed":
1344
+ state.turn = params.turn;
1345
+ if (params.turn?.status === "failed") state.error = params.turn?.error?.message ?? "Codex app-server turn failed";
1346
+ state.completed.resolve();
1347
+ break;
1348
+ case "error":
1349
+ if (params.willRetry === true) {
1350
+ logger.debug("[CodexAppServer] Retryable error received", {
1351
+ error: params.error?.message,
1352
+ threadId: params.threadId,
1353
+ turnId: params.turnId
1354
+ });
1355
+ break;
1356
+ }
1357
+ state.error = params.error?.message ?? "Codex app-server error";
1358
+ state.completed.resolve();
1359
+ break;
1360
+ }
1361
+ state.lastEventTime = eventTime;
1362
+ }
1363
+ handleItemStarted(state, item, eventTime) {
1364
+ if (!item) return;
1365
+ state.itemStarts.push(item);
1366
+ if (!item.id) return;
1367
+ const itemId = String(item.id);
1368
+ const span = this.startItemSpan(item, itemId);
1369
+ state.activeSpans.set(itemId, span);
1370
+ state.itemStartTimes.set(itemId, eventTime);
1371
+ }
1372
+ handleItemCompleted(state, item, eventTime) {
1373
+ if (!item) return;
1374
+ state.items.push(item);
1375
+ const itemId = item.id ? String(item.id) : crypto.randomUUID();
1376
+ const span = state.activeSpans.get(itemId) ?? this.startItemSpan(item, itemId, state.lastEventTime);
1377
+ const startTime = state.itemStartTimes.get(itemId) ?? state.lastEventTime;
1378
+ this.applyItemCompletionAttributes(span, item, eventTime, startTime);
1379
+ span.end();
1380
+ state.activeSpans.delete(itemId);
1381
+ state.itemStartTimes.delete(itemId);
1382
+ }
1383
+ handleAgentMessageDelta(state, params) {
1384
+ if (typeof params.delta !== "string") return;
1385
+ state.agentMessageDeltas.push(params.delta);
1386
+ if (typeof params.itemId === "string") {
1387
+ const existing = state.agentMessageDeltasByItemId.get(params.itemId) ?? "";
1388
+ state.agentMessageDeltasByItemId.set(params.itemId, existing + params.delta);
1389
+ }
1390
+ }
1391
+ async handleServerRequest(message, config) {
1392
+ const params = message.params ?? {};
1393
+ const state = this.getTurnState(params.threadId ?? params.conversationId, params.turnId);
1394
+ const record = {
1395
+ id: message.id,
1396
+ method: message.method ?? "unknown",
1397
+ params: this.sanitizeForMetadata(params)
1398
+ };
1399
+ try {
1400
+ const response = this.buildServerRequestResponse(message, state?.config ?? config);
1401
+ record.response = this.sanitizeForMetadata(response);
1402
+ state?.serverRequests.push(record);
1403
+ return response;
1404
+ } catch (error) {
1405
+ record.error = error instanceof Error ? error.message : String(error);
1406
+ state?.serverRequests.push(record);
1407
+ throw error;
1408
+ }
1409
+ }
1410
+ buildServerRequestResponse(message, config) {
1411
+ const policy = config.server_request_policy ?? {};
1412
+ switch (message.method) {
1413
+ case "item/commandExecution/requestApproval": return { decision: policy.command_execution ?? "decline" };
1414
+ case "execCommandApproval": return this.buildLegacyApprovalResponse(policy.command_execution);
1415
+ case "item/fileChange/requestApproval": return { decision: policy.file_change ?? "decline" };
1416
+ case "applyPatchApproval": return this.buildLegacyApprovalResponse(policy.file_change);
1417
+ case "item/permissions/requestApproval": return {
1418
+ permissions: policy.permissions?.permissions ?? {},
1419
+ scope: policy.permissions?.scope ?? "turn"
1420
+ };
1421
+ case "item/tool/requestUserInput": return this.buildUserInputResponse(message.params, policy.user_input ?? "empty");
1422
+ case "mcpServer/elicitation/request": return this.buildMcpElicitationResponse(policy.mcp_elicitation);
1423
+ case "item/tool/call": return this.buildDynamicToolResponse(message.params, policy.dynamic_tools);
1424
+ case "account/chatgptAuthTokens/refresh": throw new Error("ChatGPT auth token refresh requests are not supported by promptfoo");
1425
+ default: throw new Error(`Unsupported codex app-server request: ${message.method ?? "unknown"}`);
1426
+ }
1427
+ }
1428
+ buildLegacyApprovalResponse(decision = "decline") {
1429
+ if (typeof decision !== "string") return { decision: "denied" };
1430
+ switch (decision) {
1431
+ case "accept": return { decision: "approved" };
1432
+ case "acceptForSession": return { decision: "approved_for_session" };
1433
+ case "cancel": return { decision: "abort" };
1434
+ case "decline": return { decision: "denied" };
1435
+ }
1436
+ }
1437
+ buildMcpElicitationResponse(policy = "decline") {
1438
+ if (typeof policy === "string") return {
1439
+ action: policy,
1440
+ content: null,
1441
+ _meta: null
1442
+ };
1443
+ return {
1444
+ action: policy.action,
1445
+ content: policy.content ?? null,
1446
+ _meta: policy._meta ?? null
1447
+ };
1448
+ }
1449
+ buildUserInputResponse(params, policy) {
1450
+ const answers = {};
1451
+ const questions = Array.isArray(params?.questions) ? params.questions : [];
1452
+ for (const question of questions) {
1453
+ if (!question?.id || typeof question.id !== "string") continue;
1454
+ if (policy === "empty") {
1455
+ answers[question.id] = { answers: [] };
1456
+ continue;
1457
+ }
1458
+ if (policy === "first-option") {
1459
+ const firstLabel = Array.isArray(question.options) && typeof question.options[0]?.label === "string" ? question.options[0].label : "";
1460
+ answers[question.id] = { answers: firstLabel ? [firstLabel] : [] };
1461
+ continue;
1462
+ }
1463
+ const configuredAnswer = policy[question.id];
1464
+ answers[question.id] = { answers: Array.isArray(configuredAnswer) ? configuredAnswer : configuredAnswer ? [configuredAnswer] : [] };
1465
+ }
1466
+ return { answers };
1467
+ }
1468
+ buildDynamicToolResponse(params, tools) {
1469
+ const configured = typeof params?.tool === "string" ? tools?.[params.tool] : void 0;
1470
+ if (!configured) return {
1471
+ contentItems: [{
1472
+ type: "inputText",
1473
+ text: "No dynamic tool response configured."
1474
+ }],
1475
+ success: false
1476
+ };
1477
+ return {
1478
+ contentItems: configured.contentItems ?? [{
1479
+ type: "inputText",
1480
+ text: configured.text ?? ""
1481
+ }],
1482
+ success: configured.success ?? true
1483
+ };
1484
+ }
1485
+ async waitForTurnCompletion(connection, state, config, callOptions) {
1486
+ const interruptTurn = () => {
1487
+ if (!state.turnId) return;
1488
+ connection.request("turn/interrupt", {
1489
+ threadId: state.threadId,
1490
+ turnId: state.turnId
1491
+ }, { timeoutMs: 5e3 }).catch((error) => {
1492
+ logger.debug("[CodexAppServer] Error interrupting turn", { error });
1493
+ });
1494
+ };
1495
+ let timeout;
1496
+ let abortListener;
1497
+ const timeoutPromise = config.turn_timeout_ms ? new Promise((_, reject) => {
1498
+ timeout = setTimeout(() => {
1499
+ interruptTurn();
1500
+ reject(/* @__PURE__ */ new Error(`codex app-server turn timed out after ${config.turn_timeout_ms}ms`));
1501
+ }, config.turn_timeout_ms);
1502
+ }) : void 0;
1503
+ const abortPromise = callOptions?.abortSignal ? new Promise((_, reject) => {
1504
+ abortListener = () => {
1505
+ interruptTurn();
1506
+ reject(createAbortError("OpenAI Codex app-server call aborted"));
1507
+ };
1508
+ callOptions.abortSignal?.addEventListener("abort", abortListener, { once: true });
1509
+ }) : void 0;
1510
+ try {
1511
+ await Promise.race([
1512
+ state.completed.promise,
1513
+ timeoutPromise,
1514
+ abortPromise
1515
+ ].filter((promise) => Boolean(promise)));
1516
+ } finally {
1517
+ if (timeout) clearTimeout(timeout);
1518
+ if (abortListener && callOptions?.abortSignal) callOptions.abortSignal.removeEventListener("abort", abortListener);
1519
+ }
1520
+ if (state.error) throw new Error(state.error);
1521
+ }
1522
+ async cleanupThreadAfterTurn(connection, threadHandle, config, options = {}) {
1523
+ if (threadHandle.persistent || config.thread_cleanup === "none") return;
1524
+ if (options.skipIfProtected && this.isThreadProtected(threadHandle.threadId)) return;
1525
+ if (options.skipIfActiveTurn && this.activeTurnsByThread.has(threadHandle.threadId)) return;
1526
+ if (config.thread_id && (this.protectedThreadCounts.get(threadHandle.threadId) ?? 0) > 1) return;
1527
+ if (config.thread_id && config.thread_cleanup === "archive") return;
1528
+ try {
1529
+ if (config.thread_cleanup === "archive") await connection.request("thread/archive", { threadId: threadHandle.threadId }, { timeoutMs: this.getRequestTimeoutMs(config) });
1530
+ else await connection.request("thread/unsubscribe", { threadId: threadHandle.threadId }, { timeoutMs: this.getRequestTimeoutMs(config) });
1531
+ } catch (error) {
1532
+ logger.warn("[CodexAppServer] Error cleaning up thread after turn", {
1533
+ threadId: threadHandle.threadId,
1534
+ error
1535
+ });
1536
+ }
1537
+ }
1538
+ getThreadRunQueueKey(config, threadHandle) {
1539
+ if (config.thread_id) return `thread_id:${threadHandle.threadId}`;
1540
+ if (config.deep_tracing) return;
1541
+ if (threadHandle.persistent && threadHandle.cacheKey) return threadHandle.cacheKey;
1542
+ }
1543
+ async runSerializedThreadTurn(queueKey, abortSignal, executeTurn) {
1544
+ if (!queueKey) return executeTurn();
1545
+ const previousRun = this.threadRunQueues.get(queueKey) ?? Promise.resolve();
1546
+ let releaseCurrentRun = () => {};
1547
+ const currentRun = new Promise((resolve) => {
1548
+ releaseCurrentRun = resolve;
1549
+ });
1550
+ const queuedRun = previousRun.catch(() => void 0).then(() => currentRun);
1551
+ this.threadRunQueues.set(queueKey, queuedRun);
1552
+ queuedRun.finally(() => {
1553
+ if (this.threadRunQueues.get(queueKey) === queuedRun) this.threadRunQueues.delete(queueKey);
1554
+ });
1555
+ try {
1556
+ await this.waitForPreviousThreadRun(previousRun, abortSignal);
1557
+ return await executeTurn();
1558
+ } finally {
1559
+ releaseCurrentRun();
1560
+ }
1561
+ }
1562
+ async waitForPreviousThreadRun(previousRun, abortSignal) {
1563
+ const previousRunDone = previousRun.catch(() => void 0);
1564
+ if (!abortSignal) {
1565
+ await previousRunDone;
1566
+ return;
1567
+ }
1568
+ if (abortSignal.aborted) throw createAbortError("Codex app-server thread turn wait aborted");
1569
+ let onAbort;
1570
+ const abortPromise = new Promise((_, reject) => {
1571
+ onAbort = () => reject(createAbortError("Codex app-server thread turn wait aborted"));
1572
+ abortSignal.addEventListener("abort", onAbort, { once: true });
1573
+ });
1574
+ try {
1575
+ await Promise.race([previousRunDone, abortPromise]);
1576
+ } finally {
1577
+ if (onAbort) abortSignal.removeEventListener("abort", onAbort);
1578
+ }
1579
+ }
1580
+ buildProviderResponse(state, threadHandle, config) {
1581
+ const output = this.getFinalOutput(state);
1582
+ const normalizedItems = state.items.map((item) => this.normalizeItemForMetadata(item));
1583
+ const raw = {
1584
+ output,
1585
+ thread: this.sanitizeForMetadata(threadHandle.response?.thread),
1586
+ turn: this.sanitizeForMetadata(state.turn),
1587
+ items: normalizedItems,
1588
+ tokenUsage: this.sanitizeForMetadata(state.rawTokenUsage),
1589
+ serverRequests: state.serverRequests,
1590
+ ...config.include_raw_events ? { notifications: this.sanitizeForMetadata(state.notifications) } : {}
1591
+ };
1592
+ const metadata = this.buildResponseMetadata(state, threadHandle, config, normalizedItems);
1593
+ return {
1594
+ output,
1595
+ tokenUsage: state.tokenUsage,
1596
+ cost: this.calculateResponseCost(state.tokenUsage, config.model),
1597
+ metadata,
1598
+ raw: JSON.stringify(raw),
1599
+ sessionId: threadHandle.threadId
1600
+ };
1601
+ }
1602
+ getFinalOutput(state) {
1603
+ const completedAgentMessages = state.items.filter((item) => item?.type === "agentMessage" && typeof item.text === "string").map((item) => item.text);
1604
+ if (completedAgentMessages.length > 0) return completedAgentMessages[completedAgentMessages.length - 1];
1605
+ const deltaMessages = Array.from(state.agentMessageDeltasByItemId.values()).filter(Boolean);
1606
+ if (deltaMessages.length > 0) return deltaMessages[deltaMessages.length - 1];
1607
+ return state.agentMessageDeltas.join("");
1608
+ }
1609
+ buildResponseMetadata(state, threadHandle, config, normalizedItems) {
1610
+ const skillMetadata = this.buildSkillMetadata(state.items, this.getSkillRootPrefixes(config, state.appServerEnv));
1611
+ return {
1612
+ codexAppServer: {
1613
+ threadId: threadHandle.threadId,
1614
+ turnId: state.turnId,
1615
+ model: config.model,
1616
+ modelProvider: config.model_provider,
1617
+ cwd: config.working_dir,
1618
+ sandboxMode: config.sandbox_mode ?? "read-only",
1619
+ approvalPolicy: config.approval_policy ?? "never",
1620
+ itemCounts: this.getItemCounts(state.items),
1621
+ items: normalizedItems,
1622
+ serverRequests: state.serverRequests,
1623
+ notificationCount: state.notificationCount
1624
+ },
1625
+ ...skillMetadata?.skillCalls.length ? { skillCalls: skillMetadata.skillCalls } : {},
1626
+ ...skillMetadata && skillMetadata.attemptedSkillCalls.length > skillMetadata.skillCalls.length ? { attemptedSkillCalls: skillMetadata.attemptedSkillCalls } : {}
1627
+ };
1628
+ }
1629
+ normalizeItemForMetadata(item) {
1630
+ const base = {
1631
+ id: item?.id,
1632
+ type: item?.type,
1633
+ status: item?.status
1634
+ };
1635
+ switch (item?.type) {
1636
+ case "commandExecution": return this.sanitizeForMetadata({
1637
+ ...base,
1638
+ command: item.command,
1639
+ cwd: item.cwd,
1640
+ exitCode: item.exitCode,
1641
+ durationMs: item.durationMs,
1642
+ aggregatedOutput: item.aggregatedOutput
1643
+ });
1644
+ case "fileChange": return this.sanitizeForMetadata({
1645
+ ...base,
1646
+ changes: item.changes
1647
+ });
1648
+ case "mcpToolCall": return this.sanitizeForMetadata({
1649
+ ...base,
1650
+ server: item.server,
1651
+ tool: item.tool,
1652
+ arguments: item.arguments,
1653
+ result: item.result,
1654
+ error: item.error,
1655
+ durationMs: item.durationMs
1656
+ });
1657
+ case "dynamicToolCall": return this.sanitizeForMetadata({
1658
+ ...base,
1659
+ tool: item.tool,
1660
+ arguments: item.arguments,
1661
+ success: item.success,
1662
+ contentItems: item.contentItems,
1663
+ durationMs: item.durationMs
1664
+ });
1665
+ case "webSearch": return this.sanitizeForMetadata({
1666
+ ...base,
1667
+ query: item.query,
1668
+ action: item.action
1669
+ });
1670
+ case "agentMessage": return this.sanitizeForMetadata({
1671
+ ...base,
1672
+ text: item.text
1673
+ });
1674
+ case "reasoning": return this.sanitizeForMetadata({
1675
+ ...base,
1676
+ summary: item.summary,
1677
+ content: item.content
1678
+ });
1679
+ default: return this.sanitizeForMetadata(base);
1680
+ }
1681
+ }
1682
+ buildTokenUsage(rawTokenUsage) {
1683
+ const usage = rawTokenUsage?.last ?? rawTokenUsage?.total ?? rawTokenUsage;
1684
+ if (!usage) return;
1685
+ const prompt = usage.inputTokens ?? usage.input_tokens;
1686
+ const completion = usage.outputTokens ?? usage.output_tokens;
1687
+ const cached = usage.cachedInputTokens ?? usage.cached_input_tokens ?? 0;
1688
+ if (typeof prompt !== "number" || typeof completion !== "number") return;
1689
+ return {
1690
+ prompt,
1691
+ completion,
1692
+ total: prompt + completion,
1693
+ cached
1694
+ };
1695
+ }
1696
+ calculateResponseCost(tokenUsage, model) {
1697
+ if (!tokenUsage || !model) return 0;
1698
+ const pricing = CODEX_MODEL_PRICING[model];
1699
+ if (!pricing) return 0;
1700
+ const cachedTokens = tokenUsage.cached || 0;
1701
+ return ((tokenUsage.prompt || 0) - cachedTokens) * (pricing.input / 1e6) + cachedTokens * (pricing.cache_read / 1e6) + (tokenUsage.completion || 0) * (pricing.output / 1e6);
1702
+ }
1703
+ getItemCounts(items) {
1704
+ const counts = {};
1705
+ for (const item of items) {
1706
+ const type = typeof item?.type === "string" ? item.type : "unknown";
1707
+ counts[type] = (counts[type] ?? 0) + 1;
1708
+ }
1709
+ return counts;
1710
+ }
1711
+ validateWorkingDirectory(workingDir, skipGitCheck = false) {
1712
+ const cacheKey = `${workingDir}:${skipGitCheck}`;
1713
+ if (this.validatedWorkingDirs.has(cacheKey)) return;
1714
+ let stats;
1715
+ try {
1716
+ stats = fs.statSync(workingDir);
1717
+ } catch (err) {
1718
+ throw new Error(`Working directory ${workingDir} does not exist or isn't accessible: ${err.message}`);
1719
+ }
1720
+ if (!stats.isDirectory()) throw new Error(`Working directory ${workingDir} is not a directory`);
1721
+ if (!skipGitCheck && !this.isInsideGitRepository(workingDir)) throw new Error(dedent`Working directory ${workingDir} is not inside a Git repository.
1722
+
1723
+ Codex app-server requires a Git repository by default to prevent unrecoverable errors.
1724
+
1725
+ To bypass this check, set skip_git_repo_check: true in your provider config.`);
1726
+ this.validatedWorkingDirs.add(cacheKey);
1727
+ }
1728
+ isInsideGitRepository(workingDir) {
1729
+ return this.findGitRepositoryRoot(workingDir) !== void 0;
1730
+ }
1731
+ findGitRepositoryRoot(workingDir) {
1732
+ let currentDir = path.resolve(workingDir);
1733
+ while (true) {
1734
+ if (fs.existsSync(path.join(currentDir, ".git"))) return currentDir;
1735
+ const parentDir = path.dirname(currentDir);
1736
+ if (parentDir === currentDir) return;
1737
+ currentDir = parentDir;
1738
+ }
1739
+ }
1740
+ warnOnceForDeepTracingThreadOptions(config) {
1741
+ if (!config.deep_tracing || this.deepTracingWarningShown || !config.persist_threads && (config.thread_pool_size ?? 0) <= 1) return;
1742
+ logger.warn("[CodexAppServer] deep_tracing requires a fresh app-server process per call. Persistent thread pooling options (persist_threads, thread_pool_size) are ignored when deep_tracing is enabled. Explicit thread_id values are still resumed and serialized.");
1743
+ this.deepTracingWarningShown = true;
1744
+ }
1745
+ startItemSpan(item, itemId, startTime) {
1746
+ return trace.getTracer("promptfoo.codex-app-server").startSpan(this.getSpanNameForItem(item), {
1747
+ kind: SpanKind.INTERNAL,
1748
+ ...startTime === void 0 ? {} : { startTime },
1749
+ attributes: {
1750
+ "codex.app_server.item.id": itemId,
1751
+ "codex.app_server.item.type": item?.type ?? "unknown",
1752
+ ...this.getAttributesForItem(item)
1753
+ }
1754
+ });
1755
+ }
1756
+ applyItemCompletionAttributes(span, item, eventTime, startTime) {
1757
+ for (const [key, value] of Object.entries(this.getCompletionAttributesForItem(item))) span.setAttribute(key, value);
1758
+ span.setAttribute("codex.app_server.duration_ms", eventTime - startTime);
1759
+ if (this.isItemError(item)) span.setStatus({
1760
+ code: SpanStatusCode.ERROR,
1761
+ message: this.getItemErrorMessage(item)
1762
+ });
1763
+ else span.setStatus({ code: SpanStatusCode.OK });
1764
+ }
1765
+ endUnclosedItemSpans(state) {
1766
+ for (const [itemId, span] of state.activeSpans) {
1767
+ logger.warn("[CodexAppServer] Item span not properly closed", { itemId });
1768
+ span.setStatus({
1769
+ code: SpanStatusCode.ERROR,
1770
+ message: "Span not properly closed"
1771
+ });
1772
+ span.end();
1773
+ }
1774
+ state.activeSpans.clear();
1775
+ state.itemStartTimes.clear();
1776
+ }
1777
+ getSpanNameForItem(item) {
1778
+ switch (item?.type) {
1779
+ case "commandExecution": return `exec ${typeof item.command === "string" ? item.command.split(" ")[0] || "command" : "command"}`;
1780
+ case "fileChange": return "file change";
1781
+ case "mcpToolCall": return `mcp ${item.server ?? "unknown"}/${item.tool ?? "unknown"}`;
1782
+ case "dynamicToolCall": return `tool ${item.tool ?? "unknown"}`;
1783
+ case "agentMessage": return "agent response";
1784
+ case "reasoning": return "reasoning";
1785
+ case "webSearch": return "web search";
1786
+ default: return `codex.app_server.${item?.type ?? "unknown"}`;
1787
+ }
1788
+ }
1789
+ getAttributesForItem(item) {
1790
+ const attrs = {};
1791
+ if (item?.type === "commandExecution" && typeof item.command === "string") attrs["codex.command"] = this.sanitizeTraceText(item.command, "Codex app-server command trace attribute") ?? "";
1792
+ if (item?.type === "mcpToolCall") {
1793
+ if (typeof item.server === "string") attrs["codex.mcp.server"] = item.server;
1794
+ if (typeof item.tool === "string") attrs["codex.mcp.tool"] = item.tool;
1795
+ }
1796
+ if (item?.type === "dynamicToolCall" && typeof item.tool === "string") attrs["codex.tool.name"] = item.tool;
1797
+ if (item?.type === "webSearch" && typeof item.query === "string") attrs["codex.search.query"] = this.sanitizeTraceText(item.query, "Codex app-server web search trace attribute") ?? "";
1798
+ return attrs;
1799
+ }
1800
+ getCompletionAttributesForItem(item) {
1801
+ const attrs = {};
1802
+ if (typeof item?.status === "string") attrs["codex.status"] = item.status;
1803
+ if (item?.type === "commandExecution") {
1804
+ if (typeof item.exitCode === "number") attrs["codex.exit_code"] = item.exitCode;
1805
+ if (typeof item.aggregatedOutput === "string") attrs["codex.output"] = this.sanitizeTraceText(item.aggregatedOutput, "Codex app-server command output trace attribute") ?? "";
1806
+ }
1807
+ if (item?.type === "agentMessage" && typeof item.text === "string") attrs["codex.message"] = this.sanitizeTraceText(item.text, "Codex app-server message trace attribute") ?? "";
1808
+ return attrs;
1809
+ }
1810
+ isItemError(item) {
1811
+ return item?.status === "failed" || item?.status === "declined" || item?.error !== void 0 || item?.type === "commandExecution" && typeof item.exitCode === "number" && item.exitCode !== 0;
1812
+ }
1813
+ getItemErrorMessage(item) {
1814
+ return (typeof item?.error?.message === "string" ? item.error.message : null) || (item?.type === "commandExecution" && item.exitCode !== 0 ? `Command exited with code ${item.exitCode}` : null) || "Item failed";
1815
+ }
1816
+ getSkillRootPrefixes(config, appServerEnv) {
1817
+ const prefixes = /* @__PURE__ */ new Set();
1818
+ const addPrefix = (candidate) => {
1819
+ if (!candidate) return;
1820
+ const normalized = candidate.replace(/\\/g, "/").replace(/\/+$/g, "");
1821
+ if (normalized) prefixes.add(normalized);
1822
+ };
1823
+ addPrefix(appServerEnv.CODEX_HOME);
1824
+ addPrefix("/etc/codex");
1825
+ if (config.working_dir) {
1826
+ const resolvedWorkingDir = path.resolve(config.working_dir).replace(/\\/g, "/");
1827
+ addPrefix(path.posix.join(resolvedWorkingDir, ".agents"));
1828
+ const gitRoot = this.findGitRepositoryRoot(resolvedWorkingDir);
1829
+ if (gitRoot) addPrefix(path.posix.join(gitRoot.replace(/\\/g, "/"), ".agents"));
1830
+ }
1831
+ const homeDir = appServerEnv.HOME || appServerEnv.USERPROFILE;
1832
+ if (homeDir) addPrefix(path.posix.join(homeDir.replace(/\\/g, "/"), ".codex"));
1833
+ return Array.from(prefixes);
1834
+ }
1835
+ buildSkillMetadata(items, skillRootPrefixes) {
1836
+ if (!Array.isArray(items) || items.length === 0) return;
1837
+ const attemptedSkillCalls = this.extractSkillCallsFromItems(items, skillRootPrefixes);
1838
+ const skillCalls = this.extractSkillCallsFromItems(items, skillRootPrefixes, { requireSuccessfulCommand: true });
1839
+ if (skillCalls.length === 0 && attemptedSkillCalls.length <= skillCalls.length) return;
1840
+ return {
1841
+ attemptedSkillCalls,
1842
+ skillCalls
1843
+ };
1844
+ }
1845
+ extractSkillCallsFromItems(items, skillRootPrefixes, options = {}) {
1846
+ const skillCalls = /* @__PURE__ */ new Map();
1847
+ for (const item of items) {
1848
+ if (item?.type !== "commandExecution") continue;
1849
+ if (options.requireSuccessfulCommand && !this.isSuccessfulCommandExecution(item)) continue;
1850
+ if (typeof item.command !== "string" || !item.command.trim()) continue;
1851
+ for (const skillPath of this.extractSkillPathCandidates(item.command, skillRootPrefixes)) skillCalls.set(skillPath.path, skillPath);
1852
+ }
1853
+ return Array.from(skillCalls.values()).map((skillCall) => ({
1854
+ name: skillCall.name,
1855
+ path: skillCall.path,
1856
+ source: "heuristic"
1857
+ }));
1858
+ }
1859
+ isSuccessfulCommandExecution(item) {
1860
+ if (item?.type !== "commandExecution") return false;
1861
+ if (typeof item.status === "string" && item.status !== "completed") return false;
1862
+ if (typeof item.exitCode === "number" && item.exitCode !== 0) return false;
1863
+ return true;
1864
+ }
1865
+ extractSkillPathCandidates(text, skillRootPrefixes = []) {
1866
+ const matches = /* @__PURE__ */ new Map();
1867
+ for (const rawToken of text.split(/\s+/)) {
1868
+ const token = rawToken.replace(/^[`"'([{<]+|[`"',;:)\]}>]+$/g, "").trim();
1869
+ if (!token) continue;
1870
+ const normalizedPath = token.replace(/\\/g, "/");
1871
+ const repoMatch = normalizedPath.match(/^\.agents\/skills\/([^/\s]+)\/SKILL\.md$/);
1872
+ if (repoMatch && this.isValidSkillName(repoMatch[1])) {
1873
+ matches.set(normalizedPath, {
1874
+ name: repoMatch[1],
1875
+ path: normalizedPath
1876
+ });
1877
+ continue;
1878
+ }
1879
+ const matchingRoot = skillRootPrefixes.find((prefix) => normalizedPath.startsWith(`${prefix}/skills/`));
1880
+ if (!matchingRoot) continue;
1881
+ const customRootMatch = normalizedPath.slice(matchingRoot.length + 1).match(/^skills\/([^/\s]+)\/SKILL\.md$/);
1882
+ if (customRootMatch && this.isValidSkillName(customRootMatch[1])) matches.set(normalizedPath, {
1883
+ name: customRootMatch[1],
1884
+ path: normalizedPath
1885
+ });
1886
+ }
1887
+ return Array.from(matches.values());
1888
+ }
1889
+ isValidSkillName(name) {
1890
+ return /^[A-Za-z0-9._:-]+$/.test(name);
1891
+ }
1892
+ sanitizeTraceText(value, context) {
1893
+ const sanitized = this.redactTracePii(sanitizeObject(value, { context }));
1894
+ if (typeof sanitized === "string") return sanitized;
1895
+ if (sanitized === void 0 || sanitized === null) return;
1896
+ try {
1897
+ return JSON.stringify(sanitized);
1898
+ } catch (error) {
1899
+ logger.debug("[CodexAppServer] Failed to stringify sanitized trace text", { error });
1900
+ return;
1901
+ }
1902
+ }
1903
+ sanitizeForMetadata(value) {
1904
+ return this.redactTracePii(sanitizeObject(value, { context: "Codex app-server metadata" }));
1905
+ }
1906
+ redactTracePii(value) {
1907
+ if (typeof value === "string") return value.replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, REDACTED).replace(/\b(?:sk-(?:proj-)?[A-Za-z0-9_-]{20,}|sk-ant-[A-Za-z0-9_-]{20,}|AKIA[A-Z0-9]{16}|AIza[A-Za-z0-9_-]{35}|Bearer\s+[A-Za-z0-9._~+/-]{20,}|Basic\s+[A-Za-z0-9+/=]{20,})\b/g, REDACTED).replace(/\b(api[_-]?key|token|password|secret|authorization|auth)\s*([=:])(\s*)(["']?)[^\s"'`]+(\4)/gi, (_match, key, separator, spacing, quote) => `${key}${separator}${spacing}${quote}${REDACTED}${quote}`);
1908
+ if (Array.isArray(value)) return value.map((item) => this.redactTracePii(item));
1909
+ if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => [key, normalizeFieldName(key).includes("email") ? REDACTED : this.redactTracePii(entryValue)]));
1910
+ return value;
1911
+ }
1912
+ };
1913
+ //#endregion
1914
+ export { OpenAICodexAppServerProvider };
1915
+
1916
+ //# sourceMappingURL=codex-app-server-Dd22dC_N.js.map