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
@@ -1,697 +1,829 @@
1
- const require_logger = require("./logger-COuQb2xB.cjs");
2
- const require_invariant = require("./invariant-kfQ8Bu82.cjs");
3
- const require_esm = require("./esm-CtEPLdAj.cjs");
4
- const require_pythonUtils = require("./pythonUtils-tAJvvpS-.cjs");
5
- const require_fileExtensions = require("./fileExtensions-bYh77CN8.cjs");
6
- const require_types = require("./types-CeaeaZdP.cjs");
7
- const require_render = require("./render-DfQSFxGE.cjs");
8
- const require_fetch = require("./fetch-CJU5ELPa.cjs");
1
+ const require_rolldown_runtime = require("./rolldown-runtime-D_mwlA32.cjs");
2
+ const require_logger = require("./logger-cfNpzI4o.cjs");
3
+ const require_invariant = require("./invariant-QtnLD03y.cjs");
4
+ const require_types = require("./types-CxJvaY2S.cjs");
5
+ const require_fetch = require("./fetch-Dw4XZHjj.cjs");
6
+ const require_version = require("./version-BWCSaByA.cjs");
7
+ const require_fileExtensions = require("./fileExtensions-BhdwzYaD.cjs");
8
+ const require_esm = require("./esm-BIKakvNa.cjs");
9
+ const require_render = require("./render-BNTrbmBw.cjs");
10
+ const require_pythonUtils = require("./pythonUtils-Cokhluq3.cjs");
9
11
  let fs = require("fs");
10
- fs = require_logger.__toESM(fs);
12
+ fs = require_rolldown_runtime.__toESM(fs, 1);
11
13
  let path = require("path");
12
- path = require_logger.__toESM(path);
14
+ path = require_rolldown_runtime.__toESM(path, 1);
13
15
  let js_yaml = require("js-yaml");
14
- js_yaml = require_logger.__toESM(js_yaml);
16
+ js_yaml = require_rolldown_runtime.__toESM(js_yaml, 1);
15
17
  let dotenv = require("dotenv");
16
- dotenv = require_logger.__toESM(dotenv);
18
+ dotenv = require_rolldown_runtime.__toESM(dotenv, 1);
17
19
  let os = require("os");
18
- os = require_logger.__toESM(os);
20
+ os = require_rolldown_runtime.__toESM(os, 1);
19
21
  let dedent = require("dedent");
20
- dedent = require_logger.__toESM(dedent);
22
+ dedent = require_rolldown_runtime.__toESM(dedent, 1);
21
23
  let fs_promises = require("fs/promises");
22
- fs_promises = require_logger.__toESM(fs_promises);
24
+ fs_promises = require_rolldown_runtime.__toESM(fs_promises, 1);
25
+ let nunjucks = require("nunjucks");
26
+ nunjucks = require_rolldown_runtime.__toESM(nunjucks, 1);
27
+ let csv_parse_sync = require("csv-parse/sync");
23
28
  let glob = require("glob");
24
29
  let fast_deep_equal = require("fast-deep-equal");
25
- fast_deep_equal = require_logger.__toESM(fast_deep_equal);
26
- let csv_parse_sync = require("csv-parse/sync");
27
- let nunjucks = require("nunjucks");
28
- nunjucks = require_logger.__toESM(nunjucks);
30
+ fast_deep_equal = require_rolldown_runtime.__toESM(fast_deep_equal, 1);
29
31
  let fast_xml_parser = require("fast-xml-parser");
30
32
  let csv_stringify_sync = require("csv-stringify/sync");
31
- //#region src/util/provider.ts
32
- function canonicalizeProviderId(id) {
33
- if (id.startsWith("file://")) {
34
- const filePath = id.slice(7);
35
- return path.isAbsolute(filePath) ? id : `file://${path.resolve(filePath)}`;
36
- }
37
- for (const prefix of [
38
- "exec:",
39
- "python:",
40
- "golang:"
41
- ]) if (id.startsWith(prefix)) {
42
- const filePath = id.slice(prefix.length);
43
- if (filePath.includes("/") || filePath.includes("\\")) return `${prefix}${path.resolve(filePath)}`;
44
- return id;
33
+ //#region src/util/functions/loadFunction.ts
34
+ const functionCache = {};
35
+ /**
36
+ * Loads a function from a JavaScript or Python file
37
+ * @param options Options for loading the function
38
+ * @returns The loaded function
39
+ */
40
+ async function loadFunction({ filePath, functionName, defaultFunctionName = "func", basePath = require_logger.state.basePath, useCache = true }) {
41
+ const cacheKey = `${filePath}${functionName ? `:${functionName}` : ""}`;
42
+ if (useCache && functionCache[cacheKey]) return functionCache[cacheKey];
43
+ const resolvedPath = basePath ? path.default.resolve(basePath, filePath) : filePath;
44
+ if (!require_fileExtensions.isJavascriptFile(resolvedPath) && !resolvedPath.endsWith(".py")) throw new Error(`File must be a JavaScript (${require_fileExtensions.JAVASCRIPT_EXTENSIONS.join(", ")}) or Python (.py) file`);
45
+ try {
46
+ let func;
47
+ if (require_fileExtensions.isJavascriptFile(resolvedPath)) {
48
+ const module = await require_esm.importModule(resolvedPath, functionName);
49
+ let moduleFunc;
50
+ if (functionName) moduleFunc = module;
51
+ else moduleFunc = typeof module === "function" ? module : module?.default?.default || module?.default || module?.[defaultFunctionName] || module;
52
+ if (typeof moduleFunc !== "function") throw new Error(functionName ? `JavaScript file must export a "${functionName}" function` : `JavaScript file must export a function (as default export or named export "${defaultFunctionName}")`);
53
+ func = moduleFunc;
54
+ } else {
55
+ const result = (...args) => require_pythonUtils.runPython(resolvedPath, functionName || defaultFunctionName, args);
56
+ func = result;
57
+ }
58
+ if (useCache) functionCache[cacheKey] = func;
59
+ return func;
60
+ } catch (err) {
61
+ require_logger.logger.error(`Failed to load function: ${err.message}`);
62
+ throw err;
45
63
  }
46
- if ((id.endsWith(".js") || id.endsWith(".ts") || id.endsWith(".mjs")) && (id.includes("/") || id.includes("\\"))) return `file://${path.resolve(id)}`;
47
- return id;
48
- }
49
- function getProviderLabel(provider) {
50
- return provider?.label && typeof provider.label === "string" ? provider.label : void 0;
51
64
  }
52
- function providerToIdentifier(provider) {
53
- if (!provider) return;
54
- if (typeof provider === "string") return canonicalizeProviderId(provider);
55
- const label = getProviderLabel(provider);
56
- if (label) return label;
57
- if (require_types.isApiProvider(provider)) return canonicalizeProviderId(provider.id());
58
- if (require_types.isProviderOptions(provider)) {
59
- if (provider.id) return canonicalizeProviderId(provider.id);
60
- return;
61
- }
62
- if (typeof provider === "object" && "id" in provider && typeof provider.id === "string") return canonicalizeProviderId(provider.id);
65
+ /**
66
+ * Extracts the file path and function name from a file:// URL
67
+ * @param fileUrl The file:// URL (e.g., "file://path/to/file.js:functionName")
68
+ * @returns The file path and optional function name
69
+ */
70
+ function parseFileUrl(fileUrl) {
71
+ if (!fileUrl.startsWith("file://")) throw new Error("URL must start with file://");
72
+ const urlWithoutProtocol = fileUrl.slice(7);
73
+ const lastColonIndex = urlWithoutProtocol.lastIndexOf(":");
74
+ if (lastColonIndex > 1) return {
75
+ filePath: urlWithoutProtocol.slice(0, lastColonIndex),
76
+ functionName: urlWithoutProtocol.slice(lastColonIndex + 1)
77
+ };
78
+ return { filePath: urlWithoutProtocol };
63
79
  }
80
+ //#endregion
81
+ //#region src/util/file.ts
64
82
  /**
65
- * Gets a descriptive identifier string for a provider, showing both label and ID when both exist.
66
- * Useful for error messages to help users debug provider reference issues.
83
+ * Simple Nunjucks engine specifically for file paths
84
+ * This function is separate from the main getNunjucksEngine to avoid circular dependencies
67
85
  */
68
- function getProviderDescription(provider) {
69
- const label = provider.label;
70
- const id = provider.id();
71
- if (label && label !== id) return `${label} (${id})`;
72
- return id;
86
+ function getNunjucksEngineForFilePath() {
87
+ const env = nunjucks.default.configure({ autoescape: false });
88
+ env.addGlobal("env", {
89
+ ...process.env,
90
+ ...require_logger.state.config?.env
91
+ });
92
+ return env;
73
93
  }
74
94
  /**
75
- * Checks if a provider reference matches a given provider.
76
- * Supports exact matching and wildcard patterns.
95
+ * Loads content from an external file if the input is a file path, otherwise
96
+ * returns the input as-is. Supports Nunjucks templating for file paths.
97
+ *
98
+ * @param filePath - The input to process. Can be a file path string starting with "file://",
99
+ * an array of file paths, or any other type of data.
100
+ * @param context - Optional context to control file loading behavior. 'assertion' context
101
+ * preserves Python/JS file references instead of loading their content.
102
+ * @returns The loaded content if the input was a file path, otherwise the original input.
103
+ * For JSON and YAML files, the content is parsed into an object.
104
+ * For other file types, the raw file content is returned as a string.
105
+ *
106
+ * @throws {Error} If the specified file does not exist.
77
107
  */
78
- function doesProviderRefMatch(ref, provider) {
79
- const label = provider.label;
80
- const id = provider.id();
81
- const canonicalRef = canonicalizeProviderId(ref);
82
- const canonicalId = canonicalizeProviderId(id);
83
- if (label && label === ref) return true;
84
- if (id === ref || canonicalId === canonicalRef) return true;
85
- if (ref.endsWith("*")) {
86
- const prefix = ref.slice(0, -1);
87
- if (label?.startsWith(prefix) || id.startsWith(prefix) || canonicalId.startsWith(prefix)) return true;
108
+ function maybeLoadFromExternalFile(filePath, context) {
109
+ if (Array.isArray(filePath)) return filePath.map((path$3) => {
110
+ return maybeLoadFromExternalFile(path$3, context);
111
+ });
112
+ if (typeof filePath !== "string") return filePath;
113
+ if (!filePath.startsWith("file://")) return filePath;
114
+ const renderedFilePath = getNunjucksEngineForFilePath().renderString(filePath, {});
115
+ const { filePath: cleanPath, functionName } = parseFileUrl(renderedFilePath);
116
+ if (context === "assertion" && (cleanPath.endsWith(".py") || require_fileExtensions.isJavascriptFile(cleanPath))) {
117
+ require_logger.logger.debug(`Preserving Python/JS file reference in assertion context: ${renderedFilePath}`);
118
+ return renderedFilePath;
88
119
  }
89
- if (label?.startsWith(`${ref}:`) || id.startsWith(`${ref}:`) || canonicalId.startsWith(`${ref}:`)) return true;
90
- return false;
120
+ if (context === "vars") {
121
+ require_logger.logger.debug(`Preserving file reference in vars context: ${renderedFilePath}`);
122
+ return renderedFilePath;
123
+ }
124
+ if (functionName && (cleanPath.endsWith(".py") || require_fileExtensions.isJavascriptFile(cleanPath))) return renderedFilePath;
125
+ const pathToUse = functionName && !(cleanPath.endsWith(".py") || require_fileExtensions.isJavascriptFile(cleanPath)) ? renderedFilePath.slice(7) : cleanPath;
126
+ const resolvedPath = path.resolve(require_logger.state.basePath || "", pathToUse);
127
+ if ((0, glob.hasMagic)(pathToUse)) {
128
+ const matchedFiles = (0, glob.globSync)(resolvedPath, { windowsPathsNoEscape: true });
129
+ if (matchedFiles.length === 0) throw new Error(`No files found matching pattern: ${resolvedPath}`);
130
+ const allContents = [];
131
+ for (const matchedFile of matchedFiles) {
132
+ let contents;
133
+ try {
134
+ contents = fs.readFileSync(matchedFile, "utf8");
135
+ } catch (error) {
136
+ if (error.code === "ENOENT") {
137
+ require_logger.logger.debug(`File disappeared during glob expansion: ${matchedFile}`);
138
+ continue;
139
+ }
140
+ throw error;
141
+ }
142
+ if (matchedFile.endsWith(".json")) {
143
+ const parsed = JSON.parse(contents);
144
+ if (Array.isArray(parsed)) allContents.push(...parsed);
145
+ else allContents.push(parsed);
146
+ } else if (matchedFile.endsWith(".yaml") || matchedFile.endsWith(".yml")) {
147
+ const parsed = js_yaml.default.load(contents);
148
+ if (parsed === null || parsed === void 0) continue;
149
+ if (Array.isArray(parsed)) allContents.push(...parsed);
150
+ else allContents.push(parsed);
151
+ } else if (matchedFile.endsWith(".csv")) {
152
+ const records = (0, csv_parse_sync.parse)(contents, { columns: true });
153
+ if (records.length > 0 && Object.keys(records[0]).length === 1) allContents.push(...records.map((record) => Object.values(record)[0]));
154
+ else allContents.push(...records);
155
+ } else allContents.push(contents);
156
+ }
157
+ return allContents;
158
+ }
159
+ const finalPath = resolvedPath;
160
+ let contents;
161
+ try {
162
+ contents = fs.readFileSync(finalPath, "utf8");
163
+ } catch (error) {
164
+ if (error.code === "ENOENT") throw new Error(`File does not exist: ${finalPath}`);
165
+ throw new Error(`Failed to read file ${finalPath}: ${error}`);
166
+ }
167
+ if (finalPath.endsWith(".json")) try {
168
+ return JSON.parse(contents);
169
+ } catch (error) {
170
+ throw new Error(`Failed to parse JSON file ${finalPath}: ${error}`);
171
+ }
172
+ if (finalPath.endsWith(".yaml") || finalPath.endsWith(".yml")) try {
173
+ return js_yaml.default.load(contents);
174
+ } catch (error) {
175
+ throw new Error(`Failed to parse YAML file ${finalPath}: ${error}`);
176
+ }
177
+ if (finalPath.endsWith(".csv")) {
178
+ const records = (0, csv_parse_sync.parse)(contents, { columns: true });
179
+ if (records.length > 0 && Object.keys(records[0]).length === 1) return records.map((record) => Object.values(record)[0]);
180
+ return records;
181
+ }
182
+ return contents;
91
183
  }
92
184
  /**
93
- * Checks if a provider is allowed based on a list of allowed references.
185
+ * Resolves a relative file path with respect to a base path, handling cloud configuration appropriately.
186
+ * When using a cloud configuration, the current working directory is always used instead of the context's base path.
187
+ *
188
+ * @param filePath - The relative or absolute file path to resolve.
189
+ * @param isCloudConfig - Whether this is a cloud configuration.
190
+ * @returns The resolved absolute file path.
94
191
  */
95
- function isProviderAllowed(provider, allowedProviders) {
96
- if (!Array.isArray(allowedProviders)) return true;
97
- if (allowedProviders.length === 0) return false;
98
- return allowedProviders.some((ref) => doesProviderRefMatch(ref, provider));
192
+ function getResolvedRelativePath(filePath, isCloudConfig) {
193
+ if (path.isAbsolute(filePath) || !isCloudConfig) return filePath;
194
+ return path.join(process.cwd(), filePath);
99
195
  }
100
196
  /**
101
- * Detects if a provider uses OpenAI models.
102
- * This includes direct OpenAI providers and Azure OpenAI.
197
+ * Recursively loads external file references from a configuration object.
198
+ *
199
+ * @param config - The configuration object to process
200
+ * @param context - Optional context to control file loading behavior
201
+ * @returns The configuration with external file references resolved
103
202
  */
104
- function isOpenAiProvider(providerId) {
105
- const lowerProviderId = providerId.toLowerCase();
106
- if (lowerProviderId.startsWith("openai:")) return true;
107
- if (lowerProviderId.startsWith("azureopenai:")) return true;
108
- if (lowerProviderId.startsWith("azure:")) {
109
- if ([
110
- "gpt",
111
- "openai",
112
- "davinci",
113
- "curie",
114
- "babbage",
115
- "ada",
116
- "text-embedding",
117
- "whisper",
118
- "dall-e",
119
- "tts"
120
- ].some((indicator) => lowerProviderId.includes(indicator))) return true;
203
+ function maybeLoadConfigFromExternalFile(config, context) {
204
+ if (Array.isArray(config)) return config.map((item) => maybeLoadConfigFromExternalFile(item, context));
205
+ if (typeof config === "object" && config !== null) {
206
+ const result = {};
207
+ for (const key of Object.keys(config)) {
208
+ const childContext = key === "value" && "type" in config && typeof config.type === "string" && (config.type === "python" || config.type === "javascript") ? "assertion" : key === "vars" ? "vars" : context;
209
+ const value = maybeLoadConfigFromExternalFile(config[key], childContext);
210
+ if (key === "__proto__") Object.defineProperty(result, key, {
211
+ value,
212
+ enumerable: true,
213
+ configurable: true,
214
+ writable: true
215
+ });
216
+ else result[key] = value;
217
+ }
218
+ return result;
121
219
  }
122
- return false;
220
+ return maybeLoadFromExternalFile(config, context);
123
221
  }
124
222
  /**
125
- * Detects if a provider uses Anthropic/Claude models.
126
- * This includes direct Anthropic providers, Bedrock with Claude, and Vertex with Claude.
223
+ * Parses a file path or glob pattern to extract function names and file extensions.
224
+ * Function names can be specified in the filename like this:
225
+ * prompt.py:myFunction or prompts.js:myFunction.
226
+ * @param basePath - The base path for file resolution.
227
+ * @param promptPath - The path or glob pattern.
228
+ * @returns Parsed details including function name, file extension, and directory status.
127
229
  */
128
- function isAnthropicProvider(providerId) {
129
- const lowerProviderId = providerId.toLowerCase();
130
- if (lowerProviderId.startsWith("anthropic:")) return true;
131
- if (lowerProviderId.startsWith("bedrock:")) {
132
- if (lowerProviderId.includes("claude") || lowerProviderId.includes("anthropic")) return true;
133
- }
134
- if (lowerProviderId.startsWith("vertex:")) {
135
- if (lowerProviderId.includes("claude")) return true;
136
- }
137
- return false;
138
- }
139
- const KNOWN_ENV_VARS = {
140
- openai: "OPENAI_API_KEY",
141
- anthropic: "ANTHROPIC_API_KEY",
142
- google: "GOOGLE_API_KEY",
143
- mistral: "MISTRAL_API_KEY",
144
- cohere: "COHERE_API_KEY",
145
- replicate: "REPLICATE_API_TOKEN",
146
- voyage: "VOYAGE_API_KEY",
147
- ai21: "AI21_API_KEY",
148
- xai: "XAI_API_KEY",
149
- groq: "GROQ_API_KEY",
150
- deepseek: "DEEPSEEK_API_KEY",
151
- perplexity: "PERPLEXITY_API_KEY",
152
- hyperbolic: "HYPERBOLIC_API_KEY",
153
- cerebras: "CEREBRAS_API_KEY",
154
- togetherai: "TOGETHER_API_KEY",
155
- fal: "FAL_KEY",
156
- huggingface: "HF_TOKEN",
157
- "cloudflare-ai": "CLOUDFLARE_API_KEY"
158
- };
159
- function getDefaultEnvVar(providerId) {
160
- const prefix = providerId.split(":")[0];
161
- return KNOWN_ENV_VARS[prefix] || `${prefix.toUpperCase()}_API_KEY`;
162
- }
163
- /**
164
- * Pre-checks providers for missing API keys before evaluation starts.
165
- * Assumes getApiKey() is side-effect free (no network calls or token refresh).
166
- */
167
- function checkProviderApiKeys(providers) {
168
- const missingApiKeys = /* @__PURE__ */ new Map();
169
- for (const provider of providers) {
170
- const p = provider;
171
- if (typeof p.getApiKey !== "function") continue;
172
- if (provider.id().startsWith("azure:")) continue;
173
- const requiresKey = typeof p.requiresApiKey === "function" ? p.requiresApiKey() : p.config?.apiKeyRequired !== false;
174
- let apiKey;
175
- try {
176
- apiKey = p.getApiKey();
177
- } catch {
178
- apiKey = void 0;
179
- }
180
- if (requiresKey && !apiKey) {
181
- const envVar = p.config?.apiKeyEnvar || getDefaultEnvVar(provider.id());
182
- if (!missingApiKeys.has(envVar)) missingApiKeys.set(envVar, []);
183
- missingApiKeys.get(envVar).push(provider.id());
230
+ function parsePathOrGlob(basePath, promptPath) {
231
+ if (promptPath.startsWith("file://")) promptPath = promptPath.slice(7);
232
+ const filePath = path.resolve(basePath, promptPath);
233
+ let filename = path.relative(basePath, filePath);
234
+ let functionName;
235
+ if (filename.includes(":")) {
236
+ const lastColonIndex = filename.lastIndexOf(":");
237
+ if (lastColonIndex > 1) {
238
+ const pathWithoutFunction = filename.slice(0, lastColonIndex);
239
+ if (require_fileExtensions.isJavascriptFile(pathWithoutFunction) || pathWithoutFunction.endsWith(".py") || pathWithoutFunction.endsWith(".go") || pathWithoutFunction.endsWith(".rb")) {
240
+ functionName = filename.slice(lastColonIndex + 1);
241
+ filename = pathWithoutFunction;
242
+ }
184
243
  }
185
244
  }
186
- return missingApiKeys;
245
+ let stats;
246
+ try {
247
+ stats = fs.statSync(path.join(basePath, filename));
248
+ } catch (err) {
249
+ if (require_logger.getEnvBool("PROMPTFOO_STRICT_FILES")) throw err;
250
+ }
251
+ const normalizedFilePath = filePath.replace(/\\/g, "/");
252
+ const isPathPattern = stats?.isDirectory() || (0, glob.hasMagic)(promptPath) || (0, glob.hasMagic)(normalizedFilePath);
253
+ const safeFilename = path.relative(basePath, require_esm.safeResolve(basePath, filename));
254
+ return {
255
+ extension: isPathPattern ? void 0 : path.parse(safeFilename).ext,
256
+ filePath: path.join(basePath, safeFilename),
257
+ functionName,
258
+ isPathPattern
259
+ };
260
+ }
261
+ function readOutput(outputPath) {
262
+ const ext = path.parse(outputPath).ext.slice(1);
263
+ switch (ext) {
264
+ case "json": return JSON.parse(fs.readFileSync(outputPath, "utf-8"));
265
+ default: throw new Error(`Unsupported output file format: ${ext} currently only supports json`);
266
+ }
187
267
  }
188
268
  /**
189
- * Detects if a provider uses Google models.
190
- * This includes direct Google/Vertex providers with Gemini and other Google models.
191
- * Note: Vertex with Claude models is NOT counted as Google (it's Anthropic).
269
+ * Load custom Nunjucks filters from external files.
270
+ * Note: If a glob pattern matches multiple files, only the last file's export is used.
271
+ * Each filter name should typically resolve to a single file.
192
272
  */
193
- function isGoogleProvider(providerId) {
194
- const lowerProviderId = providerId.toLowerCase();
195
- if (lowerProviderId.startsWith("google:")) return true;
196
- if (lowerProviderId.startsWith("vertex:")) {
197
- if (!lowerProviderId.includes("claude")) return true;
273
+ async function readFilters(filters, basePath = "") {
274
+ const ret = {};
275
+ for (const [name, filterPath] of Object.entries(filters)) {
276
+ const filePaths = (0, glob.globSync)(path.join(basePath, filterPath), { windowsPathsNoEscape: true });
277
+ for (const filePath of filePaths) ret[name] = await require_esm.importModule(path.resolve(filePath));
198
278
  }
199
- return false;
279
+ return ret;
200
280
  }
201
- //#endregion
202
- //#region src/util/comparison.ts
203
281
  /**
204
- * Explicit runtime variable names that don't follow the underscore convention.
205
- * These are added during evaluation but aren't part of the original test definition.
282
+ * Loads configuration from an external file with variable rendering.
283
+ * This is a convenience wrapper that combines renderVarsInObject and maybeLoadFromExternalFile.
206
284
  *
207
- * - sessionId: Added by multi-turn strategy providers (GOAT, Crescendo)
285
+ * Use this for simple config fields that:
286
+ * - Need variable rendering ({{ vars.x }}, {{ env.X }})
287
+ * - May reference external files (file://path.json)
288
+ * - Don't have nested file references that need loading
208
289
  *
209
- * Note: Variables starting with underscore (e.g., _conversation) are automatically
210
- * treated as runtime variables and filtered out.
211
- */
212
- const EXPLICIT_RUNTIME_VAR_KEYS = ["sessionId"];
213
- /**
214
- * Checks if a variable key is a runtime-only variable that should be filtered
215
- * when comparing test cases.
290
+ * For fields with nested file references (like response_format.schema),
291
+ * use maybeLoadResponseFormatFromExternalFile instead.
216
292
  *
217
- * Runtime variables are identified by:
218
- * 1. Starting with underscore (_) - convention for internal/runtime vars
219
- * 2. Being in the explicit runtime var list (for legacy vars like sessionId)
293
+ * @param config - The configuration to process
294
+ * @param vars - Variables for template rendering
295
+ * @returns The processed configuration with variables rendered and files loaded
220
296
  */
221
- function isRuntimeVar(key) {
222
- return key.startsWith("_") || EXPLICIT_RUNTIME_VAR_KEYS.includes(key);
297
+ function maybeLoadFromExternalFileWithVars(config, vars) {
298
+ return maybeLoadFromExternalFile(require_render.renderVarsInObject(config, vars));
223
299
  }
224
300
  /**
225
- * Filters out runtime-only variables that are added during evaluation
226
- * but aren't part of the original test definition.
301
+ * Loads response_format configuration from an external file with variable rendering.
227
302
  *
228
- * This is used when comparing test cases to determine if a result
229
- * corresponds to a particular test, regardless of runtime state.
303
+ * This function handles the special case where response_format may contain:
304
+ * 1. A top-level file reference (file://format.json)
305
+ * 2. A nested schema reference for json_schema type (schema: file://schema.json)
230
306
  *
231
- * Runtime variables are identified by:
232
- * - Starting with underscore (e.g., _conversation, _metadata)
233
- * - Being in the explicit list (e.g., sessionId for backward compatibility)
307
+ * Both levels need variable rendering and file loading.
308
+ *
309
+ * @param responseFormat - The response_format configuration
310
+ * @param vars - Variables for template rendering
311
+ * @returns The processed response_format with all files loaded
234
312
  */
235
- function filterRuntimeVars(vars) {
236
- if (!vars || typeof vars !== "object" || Array.isArray(vars)) return vars;
237
- const filtered = {};
238
- for (const [key, value] of Object.entries(vars)) if (!isRuntimeVar(key)) filtered[key] = value;
239
- return filtered;
313
+ function maybeLoadResponseFormatFromExternalFile(responseFormat, vars) {
314
+ if (responseFormat === void 0 || responseFormat === null) return responseFormat;
315
+ const loaded = maybeLoadFromExternalFile(require_render.renderVarsInObject(responseFormat, vars));
316
+ if (!loaded || typeof loaded !== "object") return loaded;
317
+ if (loaded.type === "json_schema") {
318
+ const nestedSchema = loaded.schema || loaded.json_schema?.schema;
319
+ if (nestedSchema) {
320
+ const loadedSchema = maybeLoadFromExternalFile(require_render.renderVarsInObject(nestedSchema, vars));
321
+ if (loaded.schema !== void 0) return {
322
+ ...loaded,
323
+ schema: loadedSchema
324
+ };
325
+ else if (loaded.json_schema?.schema !== void 0) return {
326
+ ...loaded,
327
+ json_schema: {
328
+ ...loaded.json_schema,
329
+ schema: loadedSchema
330
+ }
331
+ };
332
+ }
333
+ }
334
+ return loaded;
240
335
  }
241
336
  /**
242
- * Extracts only runtime variables from a vars object.
243
- * This is the inverse of filterRuntimeVars.
337
+ * Renders variables in a tools object and loads from external file if applicable.
338
+ * This function combines renderVarsInObject and maybeLoadFromExternalFile into a single step
339
+ * specifically for handling tools configurations.
244
340
  *
245
- * Used to restore runtime state when re-running filtered tests.
341
+ * Supports loading from JSON, YAML, Python, and JavaScript files.
342
+ *
343
+ * @param tools - The tools configuration object or array to process.
344
+ * @param vars - Variables to use for rendering.
345
+ * @returns The processed tools configuration with variables rendered and content loaded from files if needed.
346
+ * @throws {Error} If the loaded tools are in an invalid format
246
347
  */
247
- function extractRuntimeVars(vars) {
248
- if (!vars || typeof vars !== "object" || Array.isArray(vars)) return;
249
- const extracted = {};
250
- for (const [key, value] of Object.entries(vars)) if (isRuntimeVar(key)) extracted[key] = value;
251
- return Object.keys(extracted).length > 0 ? extracted : void 0;
348
+ async function maybeLoadToolsFromExternalFile(tools, vars) {
349
+ const rendered = require_render.renderVarsInObject(tools, vars);
350
+ if (typeof rendered === "string" && rendered.startsWith("file://")) {
351
+ const { filePath, functionName } = parseFileUrl(rendered);
352
+ if (functionName && (filePath.endsWith(".py") || require_fileExtensions.isJavascriptFile(filePath))) {
353
+ const fileType = filePath.endsWith(".py") ? "Python" : "JavaScript";
354
+ require_logger.logger.debug(`[maybeLoadToolsFromExternalFile] Loading tools from ${fileType} file: ${filePath}:${functionName}`);
355
+ try {
356
+ let toolDefinitions;
357
+ if (filePath.endsWith(".py")) {
358
+ const absPath = require_esm.safeResolve(require_logger.state.basePath || process.cwd(), filePath);
359
+ require_logger.logger.debug(`[maybeLoadToolsFromExternalFile] Resolved Python path: ${absPath}`);
360
+ toolDefinitions = await require_pythonUtils.runPython(absPath, functionName, []);
361
+ } else {
362
+ const absPath = require_esm.safeResolve(require_logger.state.basePath || process.cwd(), filePath);
363
+ require_logger.logger.debug(`[maybeLoadToolsFromExternalFile] Resolved JavaScript path: ${absPath}`);
364
+ const module = await require_esm.importModule(absPath);
365
+ const fn = module[functionName] || module.default?.[functionName];
366
+ if (typeof fn !== "function") {
367
+ const availableExports = Object.keys(module).filter((k) => k !== "default");
368
+ const basePath = require_logger.state.basePath || process.cwd();
369
+ throw new Error(`Function "${functionName}" not found in ${filePath}. Available exports: ${availableExports.length > 0 ? availableExports.join(", ") : "(none)"}\nResolved from: ${basePath}`);
370
+ }
371
+ toolDefinitions = await Promise.resolve(fn());
372
+ }
373
+ if (!toolDefinitions || typeof toolDefinitions === "string" || typeof toolDefinitions === "number" || typeof toolDefinitions === "boolean") throw new Error(`Function "${functionName}" must return an array or object of tool definitions, but returned: ${toolDefinitions === null ? "null" : typeof toolDefinitions}`);
374
+ require_logger.logger.debug(`[maybeLoadToolsFromExternalFile] Successfully loaded ${Array.isArray(toolDefinitions) ? toolDefinitions.length : "object"} tools`);
375
+ return toolDefinitions;
376
+ } catch (err) {
377
+ const errorMessage = err instanceof Error ? err.message : String(err);
378
+ const basePath = require_logger.state.basePath || process.cwd();
379
+ throw new Error(`Failed to load tools from ${rendered}:\n${errorMessage}\n\nMake sure the function "${functionName}" exists and returns a valid tool definition array.\nResolved from: ${basePath}`);
380
+ }
381
+ }
382
+ if (filePath.endsWith(".py") || require_fileExtensions.isJavascriptFile(filePath)) {
383
+ const ext = filePath.endsWith(".py") ? "Python" : "JavaScript";
384
+ const basePath = require_logger.state.basePath || process.cwd();
385
+ throw new Error(`Cannot load tools from ${rendered}\n${ext} files require a function name. Use this format:\n tools: file://${filePath}:get_tools\n\nYour ${ext} file should export a function that returns tool definitions:\n` + (filePath.endsWith(".py") ? ` def get_tools():\n return [{"type": "function", "function": {...}}]` : ` module.exports.get_tools = () => [{ type: "function", function: {...} }];`) + `\n\nResolved from: ${basePath}`);
386
+ }
387
+ }
388
+ if (Array.isArray(rendered)) {
389
+ const results = await Promise.all(rendered.map((item) => maybeLoadToolsFromExternalFile(item, vars)));
390
+ if (results.every((r) => Array.isArray(r))) return results.flat();
391
+ return results;
392
+ }
393
+ if (typeof rendered !== "string") return rendered;
394
+ const loaded = maybeLoadFromExternalFile(rendered);
395
+ if (loaded !== void 0 && loaded !== null && typeof loaded === "string") {
396
+ if (loaded.startsWith("file://")) throw new Error(`Failed to load tools from ${loaded}\nEnsure the file exists and contains valid JSON or YAML tool definitions.`);
397
+ if (loaded.includes("def ") || loaded.includes("import ")) throw new Error("Invalid tools configuration: file appears to contain Python code.\nPython files require a function name. Use this format:\n tools: file://tools.py:get_tools");
398
+ throw new Error("Invalid tools configuration: expected an array or object, but got a string.\nIf using file://, ensure the file contains valid JSON or YAML tool definitions.");
399
+ }
400
+ return loaded;
252
401
  }
253
- function varsMatch(vars1, vars2) {
254
- return (0, fast_deep_equal.default)(vars1, vars2);
402
+ //#endregion
403
+ //#region src/util/providerRef.ts
404
+ const PROVIDER_OPTION_KEYS = new Set([
405
+ "id",
406
+ "label",
407
+ "config",
408
+ "prompts",
409
+ "transform",
410
+ "delay",
411
+ "env",
412
+ "inputs"
413
+ ]);
414
+ /** Returns true if the value is a non-empty string suitable as a provider identifier. */
415
+ function isValidProviderId(id) {
416
+ return typeof id === "string" && id !== "";
417
+ }
418
+ function getProviderLabel(provider) {
419
+ if ((typeof provider === "object" || typeof provider === "function") && provider !== null && "label" in provider && typeof provider.label === "string") return provider.label;
255
420
  }
256
421
  /**
257
- * Generate a unique key for a test case for deduplication purposes.
258
- * Excludes runtime variables and includes strategyId to distinguish tests
259
- * with the same prompt but different strategies.
260
- *
261
- * @param testCase - The test case to generate a key for
262
- * @returns A JSON string that uniquely identifies the test case
422
+ * Resolves relative file paths in provider IDs to absolute paths for consistent matching.
423
+ * Handles file://, exec:, python:, golang: prefixes and bare .js/.ts/.mjs paths.
263
424
  */
264
- function getTestCaseDeduplicationKey(testCase) {
265
- const filteredVars = filterRuntimeVars(testCase.vars);
266
- const strategyId = testCase.metadata?.strategyId || "none";
267
- return JSON.stringify({
268
- vars: filteredVars,
269
- strategyId
270
- });
271
- }
272
- /**
273
- * Deduplicates an array of test cases based on their vars and strategyId.
274
- * Tests with the same vars but different strategies are considered different.
275
- * Runtime variables (like _conversation, sessionId) are filtered out before comparison.
276
- *
277
- * @param tests - Array of test cases to deduplicate
278
- * @returns Deduplicated array of test cases
279
- */
280
- function deduplicateTestCases(tests) {
281
- const seen = /* @__PURE__ */ new Set();
282
- return tests.filter((test) => {
283
- const key = getTestCaseDeduplicationKey(test);
284
- if (seen.has(key)) return false;
285
- seen.add(key);
286
- return true;
287
- });
288
- }
289
- function resultIsForTestCase(result, testCase) {
290
- const testProviderId = testCase.provider ? providerToIdentifier(testCase.provider) : void 0;
291
- const resultProviderId = providerToIdentifier(result.provider);
292
- const providersMatch = !testProviderId || !resultProviderId || testProviderId === resultProviderId;
293
- const resultVars = filterRuntimeVars(result.vars);
294
- const testVars = filterRuntimeVars(testCase.vars);
295
- const doVarsMatch = varsMatch(testVars, resultVars);
296
- const isMatch = doVarsMatch && providersMatch;
297
- if (!isMatch) {
298
- const varKeys = testVars ? Object.keys(testVars).join(", ") : "none";
299
- require_logger.logger.debug(`[resultIsForTestCase] No match: vars=${doVarsMatch}, providers=${providersMatch}`, {
300
- testProvider: testProviderId || "none",
301
- resultProvider: resultProviderId || "none",
302
- testVarKeys: varKeys
303
- });
425
+ function canonicalizeProviderId(id) {
426
+ if (id.startsWith("file://")) {
427
+ const filePath = id.slice(7);
428
+ return path.default.isAbsolute(filePath) ? id : `file://${path.default.resolve(filePath)}`;
304
429
  }
305
- return isMatch;
430
+ for (const prefix of [
431
+ "exec:",
432
+ "python:",
433
+ "golang:"
434
+ ]) if (id.startsWith(prefix)) {
435
+ const filePath = id.slice(prefix.length);
436
+ if (filePath.includes("/") || filePath.includes("\\")) return `${prefix}${path.default.resolve(filePath)}`;
437
+ return id;
438
+ }
439
+ if ((id.endsWith(".js") || id.endsWith(".ts") || id.endsWith(".mjs")) && (id.includes("/") || id.includes("\\"))) return `file://${path.default.resolve(id)}`;
440
+ return id;
306
441
  }
307
- //#endregion
308
- //#region src/util/env.ts
309
442
  /**
310
- * Load environment variables from .env file(s).
311
- * @param envPath - Single path, array of paths, or undefined for default .env loading.
312
- * When paths are explicitly specified, all files must exist or an error is thrown.
313
- * When multiple files are provided, later files override values from earlier files.
443
+ * Returns true for provider refs that should be expanded from YAML/JSON config files.
314
444
  */
315
- function setupEnv(envPath) {
316
- if (envPath) {
317
- const paths = (Array.isArray(envPath) ? envPath : [envPath]).flatMap((p) => p.includes(",") ? p.split(",").map((s) => s.trim()) : p.trim()).filter((p) => p.length > 0);
318
- if (paths.length === 0) {
319
- dotenv.default.config({ quiet: true });
320
- return;
321
- }
322
- for (const p of paths) if (!fs.existsSync(p)) throw new Error(`Environment file not found: ${p}`);
323
- if (paths.length === 1) require_logger.logger.info(`Loading environment variables from ${paths[0]}`);
324
- else require_logger.logger.info(`Loading environment variables from: ${paths.join(", ")}`);
325
- const pathArg = paths.length === 1 ? paths[0] : paths;
326
- dotenv.default.config({
327
- path: pathArg,
328
- override: true,
329
- quiet: true
330
- });
331
- } else dotenv.default.config({ quiet: true });
445
+ function isProviderConfigFileReference(providerPath) {
446
+ return providerPath.startsWith("file://") && (providerPath.endsWith(".yaml") || providerPath.endsWith(".yml") || providerPath.endsWith(".json"));
332
447
  }
333
- //#endregion
334
- //#region src/util/functions/loadFunction.ts
335
- const functionCache = {};
336
448
  /**
337
- * Loads a function from a JavaScript or Python file
338
- * @param options Options for loading the function
339
- * @returns The loaded function
449
+ * Reads a provider config file and normalizes single-provider and multi-provider files.
450
+ * Returns a `wasArray` flag so callers can detect multi-provider files that require
451
+ * `loadApiProviders` instead of `loadApiProvider`.
340
452
  */
341
- async function loadFunction({ filePath, functionName, defaultFunctionName = "func", basePath = require_logger.state.basePath, useCache = true }) {
342
- const cacheKey = `${filePath}${functionName ? `:${functionName}` : ""}`;
343
- if (useCache && functionCache[cacheKey]) return functionCache[cacheKey];
344
- const resolvedPath = basePath ? path.default.resolve(basePath, filePath) : filePath;
345
- if (!require_fileExtensions.isJavascriptFile(resolvedPath) && !resolvedPath.endsWith(".py")) throw new Error(`File must be a JavaScript (${require_fileExtensions.JAVASCRIPT_EXTENSIONS.join(", ")}) or Python (.py) file`);
453
+ function readProviderConfigFile(providerPath, basePath) {
454
+ const relativePath = providerPath.slice(7);
455
+ const resolvedPath = path.default.isAbsolute(relativePath) ? relativePath : path.default.join(basePath || process.cwd(), relativePath);
456
+ let rawContent;
346
457
  try {
347
- let func;
348
- if (require_fileExtensions.isJavascriptFile(resolvedPath)) {
349
- const module = await require_esm.importModule(resolvedPath, functionName);
350
- let moduleFunc;
351
- if (functionName) moduleFunc = module;
352
- else moduleFunc = typeof module === "function" ? module : module?.default?.default || module?.default || module?.[defaultFunctionName] || module;
353
- if (typeof moduleFunc !== "function") throw new Error(functionName ? `JavaScript file must export a "${functionName}" function` : `JavaScript file must export a function (as default export or named export "${defaultFunctionName}")`);
354
- func = moduleFunc;
355
- } else {
356
- const result = (...args) => require_pythonUtils.runPython(resolvedPath, functionName || defaultFunctionName, args);
357
- func = result;
358
- }
359
- if (useCache) functionCache[cacheKey] = func;
360
- return func;
458
+ rawContent = js_yaml.default.load(fs.default.readFileSync(resolvedPath, "utf8"));
361
459
  } catch (err) {
362
- require_logger.logger.error(`Failed to load function: ${err.message}`);
363
- throw err;
460
+ throw new Error(`Failed to load provider config ${relativePath}: ${err instanceof Error ? err.message : err}`);
364
461
  }
365
- }
366
- /**
367
- * Extracts the file path and function name from a file:// URL
368
- * @param fileUrl The file:// URL (e.g., "file://path/to/file.js:functionName")
369
- * @returns The file path and optional function name
370
- */
371
- function parseFileUrl(fileUrl) {
372
- if (!fileUrl.startsWith("file://")) throw new Error("URL must start with file://");
373
- const urlWithoutProtocol = fileUrl.slice(7);
374
- const lastColonIndex = urlWithoutProtocol.lastIndexOf(":");
375
- if (lastColonIndex > 1) return {
376
- filePath: urlWithoutProtocol.slice(0, lastColonIndex),
377
- functionName: urlWithoutProtocol.slice(lastColonIndex + 1)
462
+ const fileContent = maybeLoadConfigFromExternalFile(rawContent);
463
+ require_invariant.invariant(fileContent, `Provider config ${relativePath} is undefined`);
464
+ return {
465
+ configs: [fileContent].flat(),
466
+ relativePath,
467
+ wasArray: Array.isArray(fileContent)
378
468
  };
379
- return { filePath: urlWithoutProtocol };
380
469
  }
381
- //#endregion
382
- //#region src/util/file.ts
383
470
  /**
384
- * Simple Nunjucks engine specifically for file paths
385
- * This function is separate from the main getNunjucksEngine to avoid circular dependencies
471
+ * Loads provider config objects from a file-backed provider reference.
386
472
  */
387
- function getNunjucksEngineForFilePath() {
388
- const env = nunjucks.default.configure({ autoescape: false });
389
- env.addGlobal("env", {
390
- ...process.env,
391
- ...require_logger.state.config?.env
392
- });
393
- return env;
473
+ function loadProviderConfigsFromFile(providerPath, basePath) {
474
+ return readProviderConfigFile(providerPath, basePath).configs;
394
475
  }
395
476
  /**
396
- * Loads content from an external file if the input is a file path, otherwise
397
- * returns the input as-is. Supports Nunjucks templating for file paths.
398
- *
399
- * @param filePath - The input to process. Can be a file path string starting with "file://",
400
- * an array of file paths, or any other type of data.
401
- * @param context - Optional context to control file loading behavior. 'assertion' context
402
- * preserves Python/JS file references instead of loading their content.
403
- * @returns The loaded content if the input was a file path, otherwise the original input.
404
- * For JSON and YAML files, the content is parsed into an object.
405
- * For other file types, the raw file content is returned as a string.
406
- *
407
- * @throws {Error} If the specified file does not exist.
477
+ * Pure, synchronous classifier that converts every supported provider reference shape
478
+ * into a discriminated descriptor. Does not read files or instantiate providers.
408
479
  */
409
- function maybeLoadFromExternalFile(filePath, context) {
410
- if (Array.isArray(filePath)) return filePath.map((path$2) => {
411
- return maybeLoadFromExternalFile(path$2, context);
412
- });
413
- if (typeof filePath !== "string") return filePath;
414
- if (!filePath.startsWith("file://")) return filePath;
415
- const renderedFilePath = getNunjucksEngineForFilePath().renderString(filePath, {});
416
- const { filePath: cleanPath, functionName } = parseFileUrl(renderedFilePath);
417
- if (context === "assertion" && (cleanPath.endsWith(".py") || require_fileExtensions.isJavascriptFile(cleanPath))) {
418
- require_logger.logger.debug(`Preserving Python/JS file reference in assertion context: ${renderedFilePath}`);
419
- return renderedFilePath;
480
+ function normalizeProviderRef(provider, options = {}) {
481
+ const { index } = options;
482
+ if (typeof provider === "string") {
483
+ if (!isValidProviderId(provider)) return {
484
+ kind: "unknown",
485
+ id: index === void 0 ? "unknown" : `unknown-${index}`
486
+ };
487
+ if (isProviderConfigFileReference(provider)) return {
488
+ kind: "file",
489
+ id: provider,
490
+ loadProviderPath: provider
491
+ };
492
+ return {
493
+ kind: "named",
494
+ id: provider,
495
+ loadProviderPath: provider
496
+ };
420
497
  }
421
- if (context === "vars") {
422
- require_logger.logger.debug(`Preserving file reference in vars context: ${renderedFilePath}`);
423
- return renderedFilePath;
498
+ if (typeof provider === "function") {
499
+ const label = getProviderLabel(provider);
500
+ return {
501
+ kind: "function",
502
+ id: label ?? (index === void 0 ? "custom-function" : `custom-function-${index}`),
503
+ label
504
+ };
424
505
  }
425
- if (functionName && (cleanPath.endsWith(".py") || require_fileExtensions.isJavascriptFile(cleanPath))) return renderedFilePath;
426
- const pathToUse = functionName && !(cleanPath.endsWith(".py") || require_fileExtensions.isJavascriptFile(cleanPath)) ? renderedFilePath.slice(7) : cleanPath;
427
- const resolvedPath = path.resolve(require_logger.state.basePath || "", pathToUse);
428
- if ((0, glob.hasMagic)(pathToUse)) {
429
- const matchedFiles = (0, glob.globSync)(resolvedPath, { windowsPathsNoEscape: true });
430
- if (matchedFiles.length === 0) throw new Error(`No files found matching pattern: ${resolvedPath}`);
431
- const allContents = [];
432
- for (const matchedFile of matchedFiles) {
433
- let contents;
434
- try {
435
- contents = fs.readFileSync(matchedFile, "utf8");
436
- } catch (error) {
437
- if (error.code === "ENOENT") {
438
- require_logger.logger.debug(`File disappeared during glob expansion: ${matchedFile}`);
439
- continue;
440
- }
441
- throw error;
506
+ if (typeof provider === "object" && provider !== null && !Array.isArray(provider)) {
507
+ const providerId = provider.id;
508
+ const label = getProviderLabel(provider);
509
+ if (isValidProviderId(providerId)) return {
510
+ kind: "options",
511
+ id: providerId,
512
+ label,
513
+ loadOptions: provider,
514
+ loadProviderPath: providerId
515
+ };
516
+ const keys = Object.keys(provider);
517
+ if (keys.length === 1 && !PROVIDER_OPTION_KEYS.has(keys[0])) {
518
+ const originalId = keys[0];
519
+ const providerObject = provider[originalId];
520
+ if (typeof providerObject === "object" && providerObject !== null && !Array.isArray(providerObject) && isValidProviderId(originalId)) {
521
+ const id = isValidProviderId(providerObject.id) ? providerObject.id : originalId;
522
+ return {
523
+ kind: "map",
524
+ id,
525
+ label: getProviderLabel(providerObject),
526
+ loadOptions: {
527
+ ...providerObject,
528
+ id
529
+ },
530
+ loadProviderPath: originalId
531
+ };
442
532
  }
443
- if (matchedFile.endsWith(".json")) {
444
- const parsed = JSON.parse(contents);
445
- if (Array.isArray(parsed)) allContents.push(...parsed);
446
- else allContents.push(parsed);
447
- } else if (matchedFile.endsWith(".yaml") || matchedFile.endsWith(".yml")) {
448
- const parsed = js_yaml.default.load(contents);
449
- if (parsed === null || parsed === void 0) continue;
450
- if (Array.isArray(parsed)) allContents.push(...parsed);
451
- else allContents.push(parsed);
452
- } else if (matchedFile.endsWith(".csv")) {
453
- const records = (0, csv_parse_sync.parse)(contents, { columns: true });
454
- if (records.length > 0 && Object.keys(records[0]).length === 1) allContents.push(...records.map((record) => Object.values(record)[0]));
455
- else allContents.push(...records);
456
- } else allContents.push(contents);
457
533
  }
458
- return allContents;
459
- }
460
- const finalPath = resolvedPath;
461
- let contents;
462
- try {
463
- contents = fs.readFileSync(finalPath, "utf8");
464
- } catch (error) {
465
- if (error.code === "ENOENT") throw new Error(`File does not exist: ${finalPath}`);
466
- throw new Error(`Failed to read file ${finalPath}: ${error}`);
467
- }
468
- if (finalPath.endsWith(".json")) try {
469
- return JSON.parse(contents);
470
- } catch (error) {
471
- throw new Error(`Failed to parse JSON file ${finalPath}: ${error}`);
534
+ if (isValidProviderId(label)) return {
535
+ kind: "unknown",
536
+ id: label,
537
+ label
538
+ };
472
539
  }
473
- if (finalPath.endsWith(".yaml") || finalPath.endsWith(".yml")) try {
474
- return js_yaml.default.load(contents);
475
- } catch (error) {
476
- throw new Error(`Failed to parse YAML file ${finalPath}: ${error}`);
540
+ return {
541
+ kind: "unknown",
542
+ id: index === void 0 ? "unknown" : `unknown-${index}`
543
+ };
544
+ }
545
+ //#endregion
546
+ //#region src/util/provider.ts
547
+ function providerToIdentifier(provider) {
548
+ if (!provider) return;
549
+ if (typeof provider === "string") return canonicalizeProviderId(provider);
550
+ const { label } = normalizeProviderRef(provider);
551
+ if (label) return label;
552
+ if (require_types.isApiProvider(provider)) return canonicalizeProviderId(provider.id());
553
+ if (require_types.isProviderOptions(provider)) {
554
+ if (provider.id) return canonicalizeProviderId(provider.id);
555
+ return;
477
556
  }
478
- if (finalPath.endsWith(".csv")) {
479
- const records = (0, csv_parse_sync.parse)(contents, { columns: true });
480
- if (records.length > 0 && Object.keys(records[0]).length === 1) return records.map((record) => Object.values(record)[0]);
481
- return records;
557
+ if (typeof provider === "object" && "id" in provider && typeof provider.id === "string") return canonicalizeProviderId(provider.id);
558
+ }
559
+ /**
560
+ * Gets a descriptive identifier string for a provider, showing both label and ID when both exist.
561
+ * Useful for error messages to help users debug provider reference issues.
562
+ */
563
+ function getProviderDescription(provider) {
564
+ const label = provider.label;
565
+ const id = provider.id();
566
+ if (label && label !== id) return `${label} (${id})`;
567
+ return id;
568
+ }
569
+ /**
570
+ * Checks if a provider reference matches a given provider.
571
+ * Supports exact matching and wildcard patterns.
572
+ */
573
+ function doesProviderRefMatch(ref, provider) {
574
+ const label = provider.label;
575
+ const id = provider.id();
576
+ const canonicalRef = canonicalizeProviderId(ref);
577
+ const canonicalId = canonicalizeProviderId(id);
578
+ if (label && label === ref) return true;
579
+ if (id === ref || canonicalId === canonicalRef) return true;
580
+ if (ref.endsWith("*")) {
581
+ const prefix = ref.slice(0, -1);
582
+ if (label?.startsWith(prefix) || id.startsWith(prefix) || canonicalId.startsWith(prefix)) return true;
482
583
  }
483
- return contents;
584
+ if (label?.startsWith(`${ref}:`) || id.startsWith(`${ref}:`) || canonicalId.startsWith(`${ref}:`)) return true;
585
+ return false;
484
586
  }
485
587
  /**
486
- * Resolves a relative file path with respect to a base path, handling cloud configuration appropriately.
487
- * When using a cloud configuration, the current working directory is always used instead of the context's base path.
488
- *
489
- * @param filePath - The relative or absolute file path to resolve.
490
- * @param isCloudConfig - Whether this is a cloud configuration.
491
- * @returns The resolved absolute file path.
588
+ * Checks if a provider is allowed based on a list of allowed references.
492
589
  */
493
- function getResolvedRelativePath(filePath, isCloudConfig) {
494
- if (path.isAbsolute(filePath) || !isCloudConfig) return filePath;
495
- return path.join(process.cwd(), filePath);
590
+ function isProviderAllowed(provider, allowedProviders) {
591
+ if (!Array.isArray(allowedProviders)) return true;
592
+ if (allowedProviders.length === 0) return false;
593
+ return allowedProviders.some((ref) => doesProviderRefMatch(ref, provider));
496
594
  }
497
595
  /**
498
- * Recursively loads external file references from a configuration object.
499
- *
500
- * @param config - The configuration object to process
501
- * @param context - Optional context to control file loading behavior
502
- * @returns The configuration with external file references resolved
596
+ * Detects if a provider uses OpenAI models.
597
+ * This includes direct OpenAI providers and Azure OpenAI.
503
598
  */
504
- function maybeLoadConfigFromExternalFile(config, context) {
505
- if (Array.isArray(config)) return config.map((item) => maybeLoadConfigFromExternalFile(item, context));
506
- if (typeof config === "object" && config !== null) {
507
- const result = {};
508
- for (const key of Object.keys(config)) {
509
- const childContext = key === "value" && "type" in config && typeof config.type === "string" && (config.type === "python" || config.type === "javascript") ? "assertion" : key === "vars" ? "vars" : context;
510
- result[key] = maybeLoadConfigFromExternalFile(config[key], childContext);
511
- }
512
- return result;
599
+ function isOpenAiProvider(providerId) {
600
+ const lowerProviderId = providerId.toLowerCase();
601
+ if (lowerProviderId.startsWith("openai:")) return true;
602
+ if (lowerProviderId.startsWith("azureopenai:")) return true;
603
+ if (lowerProviderId.startsWith("azure:")) {
604
+ if ([
605
+ "gpt",
606
+ "openai",
607
+ "davinci",
608
+ "curie",
609
+ "babbage",
610
+ "ada",
611
+ "text-embedding",
612
+ "whisper",
613
+ "dall-e",
614
+ "tts"
615
+ ].some((indicator) => lowerProviderId.includes(indicator))) return true;
513
616
  }
514
- return maybeLoadFromExternalFile(config, context);
617
+ return false;
515
618
  }
516
619
  /**
517
- * Parses a file path or glob pattern to extract function names and file extensions.
518
- * Function names can be specified in the filename like this:
519
- * prompt.py:myFunction or prompts.js:myFunction.
520
- * @param basePath - The base path for file resolution.
521
- * @param promptPath - The path or glob pattern.
522
- * @returns Parsed details including function name, file extension, and directory status.
620
+ * Detects if a provider uses Anthropic/Claude models.
621
+ * This includes direct Anthropic providers, Bedrock with Claude, and Vertex with Claude.
523
622
  */
524
- function parsePathOrGlob(basePath, promptPath) {
525
- if (promptPath.startsWith("file://")) promptPath = promptPath.slice(7);
526
- const filePath = path.resolve(basePath, promptPath);
527
- let filename = path.relative(basePath, filePath);
528
- let functionName;
529
- if (filename.includes(":")) {
530
- const lastColonIndex = filename.lastIndexOf(":");
531
- if (lastColonIndex > 1) {
532
- const pathWithoutFunction = filename.slice(0, lastColonIndex);
533
- if (require_fileExtensions.isJavascriptFile(pathWithoutFunction) || pathWithoutFunction.endsWith(".py") || pathWithoutFunction.endsWith(".go") || pathWithoutFunction.endsWith(".rb")) {
534
- functionName = filename.slice(lastColonIndex + 1);
535
- filename = pathWithoutFunction;
536
- }
537
- }
623
+ function isAnthropicProvider(providerId) {
624
+ const lowerProviderId = providerId.toLowerCase();
625
+ if (lowerProviderId.startsWith("anthropic:")) return true;
626
+ if (lowerProviderId.startsWith("bedrock:")) {
627
+ if (lowerProviderId.includes("claude") || lowerProviderId.includes("anthropic")) return true;
538
628
  }
539
- let stats;
540
- try {
541
- stats = fs.statSync(path.join(basePath, filename));
542
- } catch (err) {
543
- if (require_logger.getEnvBool("PROMPTFOO_STRICT_FILES")) throw err;
629
+ if (lowerProviderId.startsWith("vertex:")) {
630
+ if (lowerProviderId.includes("claude")) return true;
544
631
  }
545
- const normalizedFilePath = filePath.replace(/\\/g, "/");
546
- const isPathPattern = stats?.isDirectory() || (0, glob.hasMagic)(promptPath) || (0, glob.hasMagic)(normalizedFilePath);
547
- const safeFilename = path.relative(basePath, require_esm.safeResolve(basePath, filename));
548
- return {
549
- extension: isPathPattern ? void 0 : path.parse(safeFilename).ext,
550
- filePath: path.join(basePath, safeFilename),
551
- functionName,
552
- isPathPattern
553
- };
632
+ return false;
554
633
  }
555
- function readOutput(outputPath) {
556
- const ext = path.parse(outputPath).ext.slice(1);
557
- switch (ext) {
558
- case "json": return JSON.parse(fs.readFileSync(outputPath, "utf-8"));
559
- default: throw new Error(`Unsupported output file format: ${ext} currently only supports json`);
634
+ const KNOWN_ENV_VARS = {
635
+ openai: "OPENAI_API_KEY",
636
+ anthropic: "ANTHROPIC_API_KEY",
637
+ google: "GOOGLE_API_KEY",
638
+ mistral: "MISTRAL_API_KEY",
639
+ cohere: "COHERE_API_KEY",
640
+ replicate: "REPLICATE_API_TOKEN",
641
+ voyage: "VOYAGE_API_KEY",
642
+ ai21: "AI21_API_KEY",
643
+ xai: "XAI_API_KEY",
644
+ groq: "GROQ_API_KEY",
645
+ deepseek: "DEEPSEEK_API_KEY",
646
+ perplexity: "PERPLEXITY_API_KEY",
647
+ hyperbolic: "HYPERBOLIC_API_KEY",
648
+ cerebras: "CEREBRAS_API_KEY",
649
+ togetherai: "TOGETHER_API_KEY",
650
+ fal: "FAL_KEY",
651
+ huggingface: "HF_TOKEN",
652
+ "cloudflare-ai": "CLOUDFLARE_API_KEY"
653
+ };
654
+ function getDefaultEnvVar(providerId) {
655
+ const prefix = providerId.split(":")[0];
656
+ return KNOWN_ENV_VARS[prefix] || `${prefix.toUpperCase()}_API_KEY`;
657
+ }
658
+ /**
659
+ * Pre-checks providers for missing API keys before evaluation starts.
660
+ * Assumes getApiKey() is side-effect free (no network calls or token refresh).
661
+ */
662
+ function checkProviderApiKeys(providers) {
663
+ const missingApiKeys = /* @__PURE__ */ new Map();
664
+ for (const provider of providers) {
665
+ const p = provider;
666
+ if (typeof p.getApiKey !== "function") continue;
667
+ if (provider.id().startsWith("azure:")) continue;
668
+ const requiresKey = typeof p.requiresApiKey === "function" ? p.requiresApiKey() : p.config?.apiKeyRequired !== false;
669
+ let apiKey;
670
+ try {
671
+ apiKey = p.getApiKey();
672
+ } catch {
673
+ apiKey = void 0;
674
+ }
675
+ if (requiresKey && !apiKey) {
676
+ const envVar = p.config?.apiKeyEnvar || getDefaultEnvVar(provider.id());
677
+ if (!missingApiKeys.has(envVar)) missingApiKeys.set(envVar, []);
678
+ missingApiKeys.get(envVar).push(provider.id());
679
+ }
560
680
  }
681
+ return missingApiKeys;
561
682
  }
562
683
  /**
563
- * Load custom Nunjucks filters from external files.
564
- * Note: If a glob pattern matches multiple files, only the last file's export is used.
565
- * Each filter name should typically resolve to a single file.
684
+ * Detects if a provider uses Google models.
685
+ * This includes direct Google/Vertex providers with Gemini and other Google models.
686
+ * Note: Vertex with Claude models is NOT counted as Google (it's Anthropic).
566
687
  */
567
- async function readFilters(filters, basePath = "") {
568
- const ret = {};
569
- for (const [name, filterPath] of Object.entries(filters)) {
570
- const filePaths = (0, glob.globSync)(path.join(basePath, filterPath), { windowsPathsNoEscape: true });
571
- for (const filePath of filePaths) ret[name] = await require_esm.importModule(path.resolve(filePath));
688
+ function isGoogleProvider(providerId) {
689
+ const lowerProviderId = providerId.toLowerCase();
690
+ if (lowerProviderId.startsWith("google:")) return true;
691
+ if (lowerProviderId.startsWith("vertex:")) {
692
+ if (!lowerProviderId.includes("claude")) return true;
572
693
  }
573
- return ret;
694
+ return false;
574
695
  }
696
+ //#endregion
697
+ //#region src/util/comparison.ts
575
698
  /**
576
- * Loads configuration from an external file with variable rendering.
577
- * This is a convenience wrapper that combines renderVarsInObject and maybeLoadFromExternalFile.
699
+ * Explicit runtime variable names that don't follow the underscore convention.
700
+ * These are added during evaluation but aren't part of the original test definition.
578
701
  *
579
- * Use this for simple config fields that:
580
- * - Need variable rendering ({{ vars.x }}, {{ env.X }})
581
- * - May reference external files (file://path.json)
582
- * - Don't have nested file references that need loading
702
+ * - sessionId: Added by multi-turn strategy providers (GOAT, Crescendo)
583
703
  *
584
- * For fields with nested file references (like response_format.schema),
585
- * use maybeLoadResponseFormatFromExternalFile instead.
704
+ * Note: Variables starting with underscore (e.g., _conversation) are automatically
705
+ * treated as runtime variables and filtered out.
706
+ */
707
+ const EXPLICIT_RUNTIME_VAR_KEYS = ["sessionId"];
708
+ /**
709
+ * Checks if a variable key is a runtime-only variable that should be filtered
710
+ * when comparing test cases.
586
711
  *
587
- * @param config - The configuration to process
588
- * @param vars - Variables for template rendering
589
- * @returns The processed configuration with variables rendered and files loaded
712
+ * Runtime variables are identified by:
713
+ * 1. Starting with underscore (_) - convention for internal/runtime vars
714
+ * 2. Being in the explicit runtime var list (for legacy vars like sessionId)
590
715
  */
591
- function maybeLoadFromExternalFileWithVars(config, vars) {
592
- return maybeLoadFromExternalFile(require_render.renderVarsInObject(config, vars));
716
+ function isRuntimeVar(key) {
717
+ return key.startsWith("_") || EXPLICIT_RUNTIME_VAR_KEYS.includes(key);
593
718
  }
594
719
  /**
595
- * Loads response_format configuration from an external file with variable rendering.
720
+ * Filters out runtime-only variables that are added during evaluation
721
+ * but aren't part of the original test definition.
596
722
  *
597
- * This function handles the special case where response_format may contain:
598
- * 1. A top-level file reference (file://format.json)
599
- * 2. A nested schema reference for json_schema type (schema: file://schema.json)
723
+ * This is used when comparing test cases to determine if a result
724
+ * corresponds to a particular test, regardless of runtime state.
600
725
  *
601
- * Both levels need variable rendering and file loading.
726
+ * Runtime variables are identified by:
727
+ * - Starting with underscore (e.g., _conversation, _metadata)
728
+ * - Being in the explicit list (e.g., sessionId for backward compatibility)
729
+ */
730
+ function filterRuntimeVars(vars) {
731
+ if (!vars || typeof vars !== "object" || Array.isArray(vars)) return vars;
732
+ const filtered = {};
733
+ for (const [key, value] of Object.entries(vars)) if (!isRuntimeVar(key)) filtered[key] = value;
734
+ return filtered;
735
+ }
736
+ /**
737
+ * Extracts only runtime variables from a vars object.
738
+ * This is the inverse of filterRuntimeVars.
602
739
  *
603
- * @param responseFormat - The response_format configuration
604
- * @param vars - Variables for template rendering
605
- * @returns The processed response_format with all files loaded
740
+ * Used to restore runtime state when re-running filtered tests.
606
741
  */
607
- function maybeLoadResponseFormatFromExternalFile(responseFormat, vars) {
608
- if (responseFormat === void 0 || responseFormat === null) return responseFormat;
609
- const loaded = maybeLoadFromExternalFile(require_render.renderVarsInObject(responseFormat, vars));
610
- if (!loaded || typeof loaded !== "object") return loaded;
611
- if (loaded.type === "json_schema") {
612
- const nestedSchema = loaded.schema || loaded.json_schema?.schema;
613
- if (nestedSchema) {
614
- const loadedSchema = maybeLoadFromExternalFile(require_render.renderVarsInObject(nestedSchema, vars));
615
- if (loaded.schema !== void 0) return {
616
- ...loaded,
617
- schema: loadedSchema
618
- };
619
- else if (loaded.json_schema?.schema !== void 0) return {
620
- ...loaded,
621
- json_schema: {
622
- ...loaded.json_schema,
623
- schema: loadedSchema
624
- }
625
- };
626
- }
627
- }
628
- return loaded;
742
+ function extractRuntimeVars(vars) {
743
+ if (!vars || typeof vars !== "object" || Array.isArray(vars)) return;
744
+ const extracted = {};
745
+ for (const [key, value] of Object.entries(vars)) if (isRuntimeVar(key)) extracted[key] = value;
746
+ return Object.keys(extracted).length > 0 ? extracted : void 0;
747
+ }
748
+ function varsMatch(vars1, vars2) {
749
+ return (0, fast_deep_equal.default)(vars1, vars2);
629
750
  }
630
751
  /**
631
- * Renders variables in a tools object and loads from external file if applicable.
632
- * This function combines renderVarsInObject and maybeLoadFromExternalFile into a single step
633
- * specifically for handling tools configurations.
752
+ * Generate a unique key for a test case for deduplication purposes.
753
+ * Excludes runtime variables and includes strategyId to distinguish tests
754
+ * with the same prompt but different strategies.
634
755
  *
635
- * Supports loading from JSON, YAML, Python, and JavaScript files.
756
+ * @param testCase - The test case to generate a key for
757
+ * @returns A JSON string that uniquely identifies the test case
758
+ */
759
+ function getTestCaseDeduplicationKey(testCase) {
760
+ const filteredVars = filterRuntimeVars(testCase.vars);
761
+ const strategyId = testCase.metadata?.strategyId || "none";
762
+ return JSON.stringify({
763
+ vars: filteredVars,
764
+ strategyId
765
+ });
766
+ }
767
+ /**
768
+ * Deduplicates an array of test cases based on their vars and strategyId.
769
+ * Tests with the same vars but different strategies are considered different.
770
+ * Runtime variables (like _conversation, sessionId) are filtered out before comparison.
636
771
  *
637
- * @param tools - The tools configuration object or array to process.
638
- * @param vars - Variables to use for rendering.
639
- * @returns The processed tools configuration with variables rendered and content loaded from files if needed.
640
- * @throws {Error} If the loaded tools are in an invalid format
772
+ * @param tests - Array of test cases to deduplicate
773
+ * @returns Deduplicated array of test cases
641
774
  */
642
- async function maybeLoadToolsFromExternalFile(tools, vars) {
643
- const rendered = require_render.renderVarsInObject(tools, vars);
644
- if (typeof rendered === "string" && rendered.startsWith("file://")) {
645
- const { filePath, functionName } = parseFileUrl(rendered);
646
- if (functionName && (filePath.endsWith(".py") || require_fileExtensions.isJavascriptFile(filePath))) {
647
- const fileType = filePath.endsWith(".py") ? "Python" : "JavaScript";
648
- require_logger.logger.debug(`[maybeLoadToolsFromExternalFile] Loading tools from ${fileType} file: ${filePath}:${functionName}`);
649
- try {
650
- let toolDefinitions;
651
- if (filePath.endsWith(".py")) {
652
- const absPath = require_esm.safeResolve(require_logger.state.basePath || process.cwd(), filePath);
653
- require_logger.logger.debug(`[maybeLoadToolsFromExternalFile] Resolved Python path: ${absPath}`);
654
- toolDefinitions = await require_pythonUtils.runPython(absPath, functionName, []);
655
- } else {
656
- const absPath = require_esm.safeResolve(require_logger.state.basePath || process.cwd(), filePath);
657
- require_logger.logger.debug(`[maybeLoadToolsFromExternalFile] Resolved JavaScript path: ${absPath}`);
658
- const module = await require_esm.importModule(absPath);
659
- const fn = module[functionName] || module.default?.[functionName];
660
- if (typeof fn !== "function") {
661
- const availableExports = Object.keys(module).filter((k) => k !== "default");
662
- const basePath = require_logger.state.basePath || process.cwd();
663
- throw new Error(`Function "${functionName}" not found in ${filePath}. Available exports: ${availableExports.length > 0 ? availableExports.join(", ") : "(none)"}\nResolved from: ${basePath}`);
664
- }
665
- toolDefinitions = await Promise.resolve(fn());
666
- }
667
- if (!toolDefinitions || typeof toolDefinitions === "string" || typeof toolDefinitions === "number" || typeof toolDefinitions === "boolean") throw new Error(`Function "${functionName}" must return an array or object of tool definitions, but returned: ${toolDefinitions === null ? "null" : typeof toolDefinitions}`);
668
- require_logger.logger.debug(`[maybeLoadToolsFromExternalFile] Successfully loaded ${Array.isArray(toolDefinitions) ? toolDefinitions.length : "object"} tools`);
669
- return toolDefinitions;
670
- } catch (err) {
671
- const errorMessage = err instanceof Error ? err.message : String(err);
672
- const basePath = require_logger.state.basePath || process.cwd();
673
- throw new Error(`Failed to load tools from ${rendered}:\n${errorMessage}\n\nMake sure the function "${functionName}" exists and returns a valid tool definition array.\nResolved from: ${basePath}`);
674
- }
675
- }
676
- if (filePath.endsWith(".py") || require_fileExtensions.isJavascriptFile(filePath)) {
677
- const ext = filePath.endsWith(".py") ? "Python" : "JavaScript";
678
- const basePath = require_logger.state.basePath || process.cwd();
679
- throw new Error(`Cannot load tools from ${rendered}\n${ext} files require a function name. Use this format:\n tools: file://${filePath}:get_tools\n\nYour ${ext} file should export a function that returns tool definitions:\n` + (filePath.endsWith(".py") ? ` def get_tools():\n return [{"type": "function", "function": {...}}]` : ` module.exports.get_tools = () => [{ type: "function", function: {...} }];`) + `\n\nResolved from: ${basePath}`);
680
- }
681
- }
682
- if (Array.isArray(rendered)) {
683
- const results = await Promise.all(rendered.map((item) => maybeLoadToolsFromExternalFile(item, vars)));
684
- if (results.every((r) => Array.isArray(r))) return results.flat();
685
- return results;
686
- }
687
- if (typeof rendered !== "string") return rendered;
688
- const loaded = maybeLoadFromExternalFile(rendered);
689
- if (loaded !== void 0 && loaded !== null && typeof loaded === "string") {
690
- if (loaded.startsWith("file://")) throw new Error(`Failed to load tools from ${loaded}\nEnsure the file exists and contains valid JSON or YAML tool definitions.`);
691
- if (loaded.includes("def ") || loaded.includes("import ")) throw new Error("Invalid tools configuration: file appears to contain Python code.\nPython files require a function name. Use this format:\n tools: file://tools.py:get_tools");
692
- throw new Error("Invalid tools configuration: expected an array or object, but got a string.\nIf using file://, ensure the file contains valid JSON or YAML tool definitions.");
775
+ function deduplicateTestCases(tests) {
776
+ const seen = /* @__PURE__ */ new Set();
777
+ return tests.filter((test) => {
778
+ const key = getTestCaseDeduplicationKey(test);
779
+ if (seen.has(key)) return false;
780
+ seen.add(key);
781
+ return true;
782
+ });
783
+ }
784
+ function resultIsForTestCase(result, testCase) {
785
+ const testProviderId = testCase.provider ? providerToIdentifier(testCase.provider) : void 0;
786
+ const resultProviderId = providerToIdentifier(result.provider);
787
+ const providersMatch = !testProviderId || !resultProviderId || testProviderId === resultProviderId;
788
+ const resultVars = filterRuntimeVars(result.vars);
789
+ const testVars = filterRuntimeVars(testCase.vars);
790
+ const doVarsMatch = varsMatch(testVars, resultVars);
791
+ const isMatch = doVarsMatch && providersMatch;
792
+ if (!isMatch) {
793
+ const varKeys = testVars ? Object.keys(testVars).join(", ") : "none";
794
+ require_logger.logger.debug(`[resultIsForTestCase] No match: vars=${doVarsMatch}, providers=${providersMatch}`, {
795
+ testProvider: testProviderId || "none",
796
+ resultProvider: resultProviderId || "none",
797
+ testVarKeys: varKeys
798
+ });
693
799
  }
694
- return loaded;
800
+ return isMatch;
801
+ }
802
+ //#endregion
803
+ //#region src/util/env.ts
804
+ /**
805
+ * Load environment variables from .env file(s).
806
+ * @param envPath - Single path, array of paths, or undefined for default .env loading.
807
+ * When paths are explicitly specified, all files must exist or an error is thrown.
808
+ * When multiple files are provided, later files override values from earlier files.
809
+ */
810
+ function setupEnv(envPath) {
811
+ if (envPath) {
812
+ const paths = (Array.isArray(envPath) ? envPath : [envPath]).flatMap((p) => p.includes(",") ? p.split(",").map((s) => s.trim()) : p.trim()).filter((p) => p.length > 0);
813
+ if (paths.length === 0) {
814
+ dotenv.default.config({ quiet: true });
815
+ return;
816
+ }
817
+ for (const p of paths) if (!fs.existsSync(p)) throw new Error(`Environment file not found: ${p}`);
818
+ if (paths.length === 1) require_logger.logger.info(`Loading environment variables from ${paths[0]}`);
819
+ else require_logger.logger.info(`Loading environment variables from: ${paths.join(", ")}`);
820
+ const pathArg = paths.length === 1 ? paths[0] : paths;
821
+ dotenv.default.config({
822
+ path: pathArg,
823
+ override: true,
824
+ quiet: true
825
+ });
826
+ } else dotenv.default.config({ quiet: true });
695
827
  }
696
828
  //#endregion
697
829
  //#region src/googleSheets.ts
@@ -1040,13 +1172,13 @@ function createOutputMetadata(evalRecord) {
1040
1172
  evaluationCreatedAt = void 0;
1041
1173
  }
1042
1174
  return {
1043
- promptfooVersion: require_fetch.VERSION,
1175
+ promptfooVersion: require_version.VERSION,
1044
1176
  nodeVersion: process.version,
1045
1177
  platform: os.platform(),
1046
1178
  arch: os.arch(),
1047
1179
  exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
1048
1180
  evaluationCreatedAt,
1049
- author: evalRecord.author
1181
+ author: evalRecord.author ?? void 0
1050
1182
  };
1051
1183
  }
1052
1184
  /**
@@ -1265,12 +1397,24 @@ Object.defineProperty(exports, "isProviderAllowed", {
1265
1397
  return isProviderAllowed;
1266
1398
  }
1267
1399
  });
1400
+ Object.defineProperty(exports, "isProviderConfigFileReference", {
1401
+ enumerable: true,
1402
+ get: function() {
1403
+ return isProviderConfigFileReference;
1404
+ }
1405
+ });
1268
1406
  Object.defineProperty(exports, "loadFunction", {
1269
1407
  enumerable: true,
1270
1408
  get: function() {
1271
1409
  return loadFunction;
1272
1410
  }
1273
1411
  });
1412
+ Object.defineProperty(exports, "loadProviderConfigsFromFile", {
1413
+ enumerable: true,
1414
+ get: function() {
1415
+ return loadProviderConfigsFromFile;
1416
+ }
1417
+ });
1274
1418
  Object.defineProperty(exports, "maybeLoadConfigFromExternalFile", {
1275
1419
  enumerable: true,
1276
1420
  get: function() {
@@ -1301,6 +1445,12 @@ Object.defineProperty(exports, "maybeLoadToolsFromExternalFile", {
1301
1445
  return maybeLoadToolsFromExternalFile;
1302
1446
  }
1303
1447
  });
1448
+ Object.defineProperty(exports, "normalizeProviderRef", {
1449
+ enumerable: true,
1450
+ get: function() {
1451
+ return normalizeProviderRef;
1452
+ }
1453
+ });
1304
1454
  Object.defineProperty(exports, "parseFileUrl", {
1305
1455
  enumerable: true,
1306
1456
  get: function() {
@@ -1331,6 +1481,12 @@ Object.defineProperty(exports, "readOutput", {
1331
1481
  return readOutput;
1332
1482
  }
1333
1483
  });
1484
+ Object.defineProperty(exports, "readProviderConfigFile", {
1485
+ enumerable: true,
1486
+ get: function() {
1487
+ return readProviderConfigFile;
1488
+ }
1489
+ });
1334
1490
  Object.defineProperty(exports, "resultIsForTestCase", {
1335
1491
  enumerable: true,
1336
1492
  get: function() {
@@ -1356,4 +1512,4 @@ Object.defineProperty(exports, "writeOutput", {
1356
1512
  }
1357
1513
  });
1358
1514
 
1359
- //# sourceMappingURL=util-Bxn8emtE.cjs.map
1515
+ //# sourceMappingURL=util-SPsvFONY.cjs.map