promptfoo 0.121.3 → 0.121.5

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 (394) hide show
  1. package/README.md +1 -1
  2. package/dist/src/{ListApp-Du7YVwj5.js → ListApp-BRUsT43Y.js} +1 -1
  3. package/dist/src/{accounts-BPyfpSeU.cjs → accounts-BIFntVWB.cjs} +5 -5
  4. package/dist/src/{accounts-CFLK3mnD.js → accounts-CLJHCDDb.js} +6 -6
  5. package/dist/src/{accounts-B2XmGjty.js → accounts-CaLNYnf7.js} +5 -5
  6. package/dist/src/{accounts-Xatc0RYb.js → accounts-bnyHT7Ju.js} +5 -5
  7. package/dist/src/{agentic-utils-36epdqwB.js → agentic-utils-B5krlibj.js} +3 -3
  8. package/dist/src/{agentic-utils-DIYAAYE7.js → agentic-utils-Ba67xmgs.js} +3 -3
  9. package/dist/src/{agentic-utils-D8yXo5Lm.js → agentic-utils-BclbiXiq.js} +4 -4
  10. package/dist/src/{agentic-utils-DAVsChuB.cjs → agentic-utils-D2x0wGhB.cjs} +3 -3
  11. package/dist/src/{agents-CLQ-P15P.js → agents-BGqaTDnr.js} +5 -7
  12. package/dist/src/{agents-wg3ohknq.js → agents-BV9yFpXX.js} +6 -7
  13. package/dist/src/{agents-CgBniSlI.js → agents-BYdMl1UE.js} +5 -9
  14. package/dist/src/{agents-Bqgfdokm.js → agents-DhxWMCtH.js} +35 -14
  15. package/dist/src/{agents-BBWxKSM0.cjs → agents-DiWmQYH9.cjs} +5 -7
  16. package/dist/src/{agents-CAYbM7qD.cjs → agents-WULPVjbH.cjs} +34 -12
  17. package/dist/src/{agents-DSSTV4bv.js → agents-emVcx3yh.js} +35 -13
  18. package/dist/src/{agents-BBVJCIYr.js → agents-n6vPqV3i.js} +35 -13
  19. package/dist/src/{aimlapi-BwGC1TtS.js → aimlapi-BxqK9HF_.js} +8 -14
  20. package/dist/src/{aimlapi-Bv8Fmc-b.cjs → aimlapi-BzLjZI_m.cjs} +8 -15
  21. package/dist/src/{aimlapi-MgSLdvy7.js → aimlapi-DR4pgeiC.js} +7 -14
  22. package/dist/src/{aimlapi-DaC3qZ-o.js → aimlapi-uPGp0Zdo.js} +7 -16
  23. package/dist/src/app/app/tsconfig.app.tsbuildinfo +1 -0
  24. package/dist/src/app/assets/Report-vjzrbgce.js +1 -0
  25. package/dist/src/app/assets/index-B3NQ8HTd.js +385 -0
  26. package/dist/src/app/assets/index-Cli2yAXv.css +1 -0
  27. package/dist/src/app/assets/rolldown-runtime-COnpUsM8.js +1 -0
  28. package/dist/src/app/assets/scroll-timeline-D9IT_e8Z.js +1 -0
  29. package/dist/src/app/assets/sync-IjzpWrOE.js +4 -0
  30. package/dist/src/app/assets/vendor-charts-BNdH8TCw.js +36 -0
  31. package/dist/src/app/assets/vendor-markdown-Ch00wnNI.js +29 -0
  32. package/dist/src/app/assets/vendor-react-CVvmk1UB.js +9 -0
  33. package/dist/src/app/assets/vendor-utils-BnEYbx2Q.js +37 -0
  34. package/dist/src/app/index.html +32 -7
  35. package/dist/src/{audio-Bn44pQxv.js → audio-BvpTOArF.js} +4 -4
  36. package/dist/src/{audio-DVFjQ67_.cjs → audio-C0vDeS0j.cjs} +4 -4
  37. package/dist/src/{audio-DjU9GswO.js → audio-CScmnmEB.js} +4 -5
  38. package/dist/src/{audio-DDA5WHdx.js → audio-Da8U9IS5.js} +4 -4
  39. package/dist/src/{base-CKjwebIH.js → base-BOMaNEes.js} +3 -3
  40. package/dist/src/{base-CqzQ4K8j.js → base-BTux96b1.js} +3 -3
  41. package/dist/src/{base-BboXIF_0.cjs → base-Tw6uhH8K.cjs} +3 -3
  42. package/dist/src/{base-Cz2ZC_iA.js → base-dYsl2hmL.js} +3 -3
  43. package/dist/src/{blobs-C6j0bvFz.cjs → blobs-B95F_7vE.cjs} +3 -3
  44. package/dist/src/{blobs-DXTl6J3H.js → blobs-BW4U31ue.js} +3 -3
  45. package/dist/src/{blobs-BUWmKWzo.js → blobs-D_gg8nbm.js} +4 -4
  46. package/dist/src/{blobs-B1JriOyi.js → blobs-DjLby-uP.js} +4 -4
  47. package/dist/src/cache-BI5BY7ey.js +280 -0
  48. package/dist/src/cache-BRkhlH3k.cjs +3 -0
  49. package/dist/src/cache-BlC6aeJ0.js +3 -0
  50. package/dist/src/cache-Bzttsk0X.js +310 -0
  51. package/dist/src/cache-Cr-qWIbP.js +310 -0
  52. package/dist/src/cache-DGg-yTZG.cjs +376 -0
  53. package/dist/src/{chat-BEwdgGEg.js → chat-BLOdH60v.js} +63 -37
  54. package/dist/src/{chat-B0iaWhoh.js → chat-Cx_LkwvZ.js} +63 -37
  55. package/dist/src/{chat-DK1U-eZ-.js → chat-D9nudO9b.js} +5 -14
  56. package/dist/src/{chat-pxmiVpWe.js → chat-DChSH_Es.js} +63 -37
  57. package/dist/src/{chat-B-52XYI1.js → chat-DG2LkwLq.js} +3 -13
  58. package/dist/src/{chat-BtIKkLKx.cjs → chat-DH97tVV9.cjs} +3 -13
  59. package/dist/src/{chat-BE0qTA8e.js → chat-aMQZw6R7.js} +4 -16
  60. package/dist/src/{chat-CM8qWR3_.cjs → chat-vYqqv1gP.cjs} +64 -38
  61. package/dist/src/{chatkit-_8eJqKcD.js → chatkit-B8X34dQc.js} +4 -4
  62. package/dist/src/{chatkit-BYGQlHlV.js → chatkit-BXu42Qwt.js} +4 -4
  63. package/dist/src/{chatkit-a2D6mY6s.js → chatkit-CbMRoeYw.js} +4 -4
  64. package/dist/src/{chatkit-Cx174XI3.cjs → chatkit-D44VyUyB.cjs} +4 -4
  65. package/dist/src/{claude-agent-sdk-8ddRp1L2.cjs → claude-agent-sdk-BRq0bbIK.cjs} +23 -18
  66. package/dist/src/{claude-agent-sdk-CMjh4LFH.js → claude-agent-sdk-BjriSVRZ.js} +20 -15
  67. package/dist/src/{claude-agent-sdk-HgbFioFw.js → claude-agent-sdk-BzNZeZ0N.js} +20 -15
  68. package/dist/src/{claude-agent-sdk-Bq5EArsX.js → claude-agent-sdk-DYv_AJ8u.js} +21 -17
  69. package/dist/src/cloud-CoD5OacT.js +3 -0
  70. package/dist/src/{cloud-z8KZpUoa.js → cloud-Da0bofJd.js} +25 -13
  71. package/dist/src/{cloudflare-ai-Bbp26N0L.js → cloudflare-ai-CXC4b1EU.js} +5 -14
  72. package/dist/src/{cloudflare-ai-BGyXlpXJ.js → cloudflare-ai-CyBoIs1Q.js} +7 -15
  73. package/dist/src/{cloudflare-ai-DdKP9TKT.js → cloudflare-ai-DGOwgexC.js} +6 -17
  74. package/dist/src/{cloudflare-ai-C62x6MQG.cjs → cloudflare-ai-DJv5qnyb.cjs} +6 -15
  75. package/dist/src/{cloudflare-gateway-DXhtXDRb.js → cloudflare-gateway-1sAoOyft.js} +6 -16
  76. package/dist/src/{cloudflare-gateway-D-e9i1Sn.js → cloudflare-gateway-D-dnkzCF.js} +5 -18
  77. package/dist/src/{cloudflare-gateway-Dx36ftqF.cjs → cloudflare-gateway-DKVjkDav.cjs} +4 -15
  78. package/dist/src/{cloudflare-gateway-BwAaUgeW.js → cloudflare-gateway-TJkVrZlB.js} +4 -15
  79. package/dist/src/codex-app-server-CCLjqCh9.js +1915 -0
  80. package/dist/src/codex-app-server-CCe0TiDc.js +1915 -0
  81. package/dist/src/codex-app-server-CPW1LFwh.js +1916 -0
  82. package/dist/src/codex-app-server-VMRnjZ68.cjs +1920 -0
  83. package/dist/src/codex-sdk-1jm_qPHf.js +3 -0
  84. package/dist/src/codex-sdk-Bd8UbO9q.cjs +1172 -0
  85. package/dist/src/codex-sdk-BgEFQ70r.js +1164 -0
  86. package/dist/src/codex-sdk-Bzb_TqX9.js +1165 -0
  87. package/dist/src/codex-sdk-Danroptg.cjs +2 -0
  88. package/dist/src/codex-sdk-DfvDTN33.js +1165 -0
  89. package/dist/src/{cometapi-BDyV-NNm.js → cometapi-B5ImDlSm.js} +9 -15
  90. package/dist/src/{cometapi-C3hOlM7-.cjs → cometapi-BgAkuYCw.cjs} +9 -16
  91. package/dist/src/{cometapi-hhL4TAh3.js → cometapi-CC7hWxmX.js} +8 -15
  92. package/dist/src/{cometapi-sp7sJpBD.js → cometapi-CCbpHkuF.js} +8 -17
  93. package/dist/src/{completion-DoYy49ti.js → completion-2iuYVxwi.js} +8 -57
  94. package/dist/src/{completion-BCimtq-h.js → completion-CrD6MQ93.js} +8 -57
  95. package/dist/src/{completion-DlXUhj5c.cjs → completion-DtQ72Bm3.cjs} +7 -62
  96. package/dist/src/{completion-DCjv7RZ3.js → completion-Vq_ad618.js} +8 -57
  97. package/dist/src/{createHash-CTQmL3G2.js → createHash-4gFQpDDv.js} +3 -3
  98. package/dist/src/{createHash-Da8fMwqB.js → createHash-DPpsZgFF.js} +3 -3
  99. package/dist/src/{createHash-DmPQkvBh.js → createHash-Un4Q_huE.js} +3 -3
  100. package/dist/src/{createHash-BYwImsYv.cjs → createHash-VvBIc-AW.cjs} +4 -4
  101. package/dist/src/{docker-CxCkwMzc.js → docker--3qzPa-6.js} +6 -14
  102. package/dist/src/{docker-Cqj2-QVi.cjs → docker-D3AY-5F5.cjs} +7 -15
  103. package/dist/src/{docker-FeBni2dw.js → docker-DCsCDvwM.js} +7 -14
  104. package/dist/src/{docker-DpguQj-w.js → docker-Dorv4_Dg.js} +6 -16
  105. package/dist/src/embedding-BXhN5lCH.cjs +63 -0
  106. package/dist/src/embedding-ChS1ivFS.js +58 -0
  107. package/dist/src/embedding-DNRvZwRN.js +59 -0
  108. package/dist/src/embedding-D_bI4NDq.js +58 -0
  109. package/dist/src/entrypoint.js +69 -6
  110. package/dist/src/{errors-P6ll7XSJ.js → errors-DFHe4L-n.js} +1 -1
  111. package/dist/src/{esm-SUNIX1x3.js → esm-B6whoAcf.js} +15 -6
  112. package/dist/src/{esm-CKWP3u_P.js → esm-BRkfNsYs.js} +16 -7
  113. package/dist/src/{esm-7UIl0pPM.js → esm-BX8fwlAO.js} +27 -18
  114. package/dist/src/{esm-CipptfDu.cjs → esm-B_rGuPTo.cjs} +15 -6
  115. package/dist/src/eval-BQPLBJbw.js +3 -0
  116. package/dist/src/{eval-BTqTn7lb.js → eval-DJ_4A-tr.js} +50 -21
  117. package/dist/src/evalResult-BBJAHAtw.cjs +2 -0
  118. package/dist/src/evalResult-BBK58h2B.js +3 -0
  119. package/dist/src/{evalResult-DpARzUCb.cjs → evalResult-Cx-8OWkb.cjs} +29 -11
  120. package/dist/src/{evalResult-DUDShQrm.js → evalResult-D6P5I5il.js} +29 -11
  121. package/dist/src/{evalResult-BkIhRdTe.js → evalResult-pSvGWFMo.js} +29 -11
  122. package/dist/src/evalResult-spPqh1G_.js +2 -0
  123. package/dist/src/{evaluator-BcvOGaam.js → evaluator-D-UIbbYq.js} +3975 -2152
  124. package/dist/src/evaluator-DgLKaZk8.js +3 -0
  125. package/dist/src/{extractor-D_wd8jxt.js → extractor-BM3jRERL.js} +6 -6
  126. package/dist/src/{extractor-DG3sSfXE.cjs → extractor-Dxr2J_wK.cjs} +6 -6
  127. package/dist/src/{extractor-CAZ2G3Kh.js → extractor-DxyiFhPk.js} +6 -6
  128. package/dist/src/{extractor-C8XwivI9.js → extractor-YlZbUMsL.js} +6 -6
  129. package/dist/src/fetch-8viavNv8.js +3 -0
  130. package/dist/src/{fetch-DoVRJZhJ.js → fetch-B6ch2nU2.js} +199 -60
  131. package/dist/src/{fetch-CVAtKnI3.js → fetch-D9xxyC1p.js} +404 -252
  132. package/dist/src/{fetch-BnR9wSnm.cjs → fetch-NuqXW1Xb.cjs} +415 -263
  133. package/dist/src/{fetch-BiYv2BZc.js → fetch-Y5qX_kST.js} +222 -70
  134. package/dist/src/{fileExtensions-LcDYkU4v.js → fileExtensions-8CjoL7vB.js} +1 -1
  135. package/dist/src/{fileExtensions-DnqA1y9x.js → fileExtensions-BGh-W-HT.js} +1 -1
  136. package/dist/src/{fileExtensions-bYh77CN8.cjs → fileExtensions-D9h-8Wxg.cjs} +1 -1
  137. package/dist/src/{fileExtensions-Ds-foDzt.js → fileExtensions-DysCsxNG.js} +1 -1
  138. package/dist/src/{formatDuration-DgBVMN65.js → formatDuration-Ch4A7G3o.js} +1 -1
  139. package/dist/src/{genaiTracer-BfxrvSUb.cjs → genaiTracer-BokHC-MW.cjs} +7 -3
  140. package/dist/src/{genaiTracer-C1rxGO8Q.js → genaiTracer-C3ZPQU60.js} +6 -2
  141. package/dist/src/{genaiTracer-70Z8BIuV.js → genaiTracer-CFny3gOy.js} +6 -2
  142. package/dist/src/{genaiTracer-D3fD9dNV.js → genaiTracer-DxODqT9e.js} +6 -2
  143. package/dist/src/golang/wrapper.go +1 -1
  144. package/dist/src/{graders-DG7mhg-b.js → graders-BoUqsCEm.js} +7402 -5699
  145. package/dist/src/{graders-BElhu9ZY.cjs → graders-Bw1wk_21.cjs} +5220 -3437
  146. package/dist/src/graders-C84JI-m5.js +2 -0
  147. package/dist/src/graders-CBbd0K0Q.cjs +2 -0
  148. package/dist/src/graders-CbQqpHSN.js +3 -0
  149. package/dist/src/{graders-RjHF8VfG.js → graders-CgPn32yp.js} +7400 -5697
  150. package/dist/src/{graders-BXAJ0sbS.js → graders-CwrbifOo.js} +6136 -4433
  151. package/dist/src/graders-DS42d3ZG.js +2 -0
  152. package/dist/src/{image-6WQXK8m8.js → image-BeWaInPF.js} +4 -4
  153. package/dist/src/{image-PoF6DN3x.js → image-BmilRNqO.js} +8 -8
  154. package/dist/src/{image--F58eEIn.cjs → image-CxJoa3aW.cjs} +8 -8
  155. package/dist/src/{image-fza3zuKs.cjs → image-D10dNAav.cjs} +4 -4
  156. package/dist/src/{image-DO0RYnjH.js → image-Dr_3I3nK.js} +4 -5
  157. package/dist/src/{image-B8b6f36E.js → image-DsGRlkh7.js} +8 -8
  158. package/dist/src/{image-CoxZp9PZ.js → image-a_SGUobh.js} +8 -8
  159. package/dist/src/{image-xNbw5ph2.js → image-qjO6FWPs.js} +4 -4
  160. package/dist/src/index.cjs +4835 -2582
  161. package/dist/src/index.d.cts +2782 -31
  162. package/dist/src/index.d.ts +2783 -32
  163. package/dist/src/index.js +4817 -2564
  164. package/dist/src/{interactiveCheck-BnMYOjMu.js → interactiveCheck-CCICw2cy.js} +2 -2
  165. package/dist/src/{invariant-BtWWVVhl.js → invariant-B2Rf6avk.js} +1 -1
  166. package/dist/src/{invariant-vgHWClmd.js → invariant-DIYf9sP1.js} +1 -1
  167. package/dist/src/{knowledgeBase-Bi7CmDbx.js → knowledgeBase-BBETc5-S.js} +6 -8
  168. package/dist/src/{knowledgeBase-DqrLX8fy.cjs → knowledgeBase-C8qOo26M.cjs} +6 -8
  169. package/dist/src/{knowledgeBase-DFRXPZl_.js → knowledgeBase-CzAi2rUI.js} +7 -8
  170. package/dist/src/{knowledgeBase-Ce3ofVan.js → knowledgeBase-Dr3Kib7F.js} +6 -10
  171. package/dist/src/{litellm-CKiAxnoM.js → litellm-BLSiANhk.js} +6 -14
  172. package/dist/src/{litellm-CnHI69aj.cjs → litellm-CaUmV7Mk.cjs} +6 -15
  173. package/dist/src/{litellm-Tc294Jhj.js → litellm-DQGo_juI.js} +5 -14
  174. package/dist/src/{litellm-Bo2gQXpo.js → litellm-DRc4qWfc.js} +5 -16
  175. package/dist/src/{logger-BcJBzSSA.js → logger-BbY6ypFL.js} +41 -12
  176. package/dist/src/{logger-D5iKBpu_.cjs → logger-COuQb2xB.cjs} +51 -10
  177. package/dist/src/{logger-DO8_zM18.js → logger-Ct2S6Yx-.js} +40 -11
  178. package/dist/src/{logger-BnkjG2jt.js → logger-KD8JjCRJ.js} +41 -12
  179. package/dist/src/{luma-ray-C9q8rdQe.js → luma-ray-B-tNZzqW.js} +6 -10
  180. package/dist/src/{luma-ray-DP0QA9qn.js → luma-ray-CtS3OlGq.js} +6 -10
  181. package/dist/src/{luma-ray-0ehMPt5N.js → luma-ray-PJJgUjOc.js} +6 -11
  182. package/dist/src/{luma-ray-m9Ku2meV.cjs → luma-ray-if-Ml4R9.cjs} +6 -10
  183. package/dist/src/main.d.ts +1 -26
  184. package/dist/src/main.js +1188 -679
  185. package/dist/src/messages-B9dSjrNf.js +544 -0
  186. package/dist/src/messages-BnsVHUnm.cjs +558 -0
  187. package/dist/src/messages-CI69Lasb.js +543 -0
  188. package/dist/src/messages-CewuNcNS.js +543 -0
  189. package/dist/src/{meteor-DLZZ3osF.cjs → meteor-BBGcGeCa.cjs} +1 -1
  190. package/dist/src/{meteor-DUiCJRC-.js → meteor-BKTM-7KS.js} +1 -1
  191. package/dist/src/{meteor-44VjEACX.js → meteor-CeGo0Lu2.js} +2 -2
  192. package/dist/src/{meteor-D-SotUw9.js → meteor-Wc_aUVvu.js} +2 -2
  193. package/dist/src/{modelslab-B5J-ZM5c.js → modelslab-BCLOtfek.js} +8 -10
  194. package/dist/src/{modelslab-IQbNg-r7.cjs → modelslab-BkapYJhh.cjs} +7 -10
  195. package/dist/src/{modelslab-BTOT8FUO.js → modelslab-D73OnKSx.js} +7 -10
  196. package/dist/src/{modelslab-BI458moT.js → modelslab-zpz9JcK0.js} +7 -12
  197. package/dist/src/{nova-reel-BZ9y-Y5s.js → nova-reel-B8F_TK5w.js} +7 -10
  198. package/dist/src/{nova-reel-Xw1SXLpg.js → nova-reel-Bx0NFV2f.js} +6 -10
  199. package/dist/src/{nova-reel-DEeQlnOJ.js → nova-reel-CNGJTLtG.js} +6 -12
  200. package/dist/src/{nova-reel-CE5etkv9.cjs → nova-reel-DkT7tnoB.cjs} +6 -10
  201. package/dist/src/{nova-sonic-Ogqf-csn.js → nova-sonic-BaXRN1cr.js} +5 -7
  202. package/dist/src/{nova-sonic-DXTLpi-r.js → nova-sonic-BeTRaFOh.js} +4 -7
  203. package/dist/src/{nova-sonic-DWswpN1E.js → nova-sonic-CL7Zqv0G.js} +4 -9
  204. package/dist/src/{nova-sonic-N0yCm0vb.cjs → nova-sonic-YT426juD.cjs} +4 -7
  205. package/dist/src/{openai-BcB5KlTk.js → openai-BMHD2Huo.js} +6 -3
  206. package/dist/src/{openai-BMcwgD5C.js → openai-BT-JvDse.js} +6 -3
  207. package/dist/src/{openai-CoxGAQwn.cjs → openai-Cy1XLs0c.cjs} +6 -3
  208. package/dist/src/{openai-D6wITiVn.js → openai-D4fxGvRx.js} +6 -3
  209. package/dist/src/openclaw-Bq7RVR3k.js +1200 -0
  210. package/dist/src/openclaw-DA8U4DsD.js +1201 -0
  211. package/dist/src/openclaw-DObVgpjC.js +1200 -0
  212. package/dist/src/openclaw-DUBZP3GL.cjs +1206 -0
  213. package/dist/src/{opencode-sdk-CHCs7dEb.js → opencode-sdk-BB40Wir1.js} +6 -8
  214. package/dist/src/{opencode-sdk-DDxj4QqH.js → opencode-sdk-BM1UAIv1.js} +6 -8
  215. package/dist/src/{opencode-sdk-WWJhnbKr.cjs → opencode-sdk-CeqiOcOU.cjs} +7 -9
  216. package/dist/src/{opencode-sdk-C71Z0ehR.js → opencode-sdk-ChdK7F7z.js} +6 -9
  217. package/dist/src/{otlpReceiver-CZL48YfC.js → otlpReceiver-C6thJRXi.js} +154 -98
  218. package/dist/src/{otlpReceiver-C9KlUtxh.js → otlpReceiver-CcdIikOu.js} +154 -98
  219. package/dist/src/{otlpReceiver-DHKqJlsz.cjs → otlpReceiver-DNSQj6bf.cjs} +154 -98
  220. package/dist/src/{otlpReceiver-CavGAA6k.js → otlpReceiver-UYMQx3sy.js} +154 -98
  221. package/dist/src/{providerRegistry-BkzVH5Ba.js → providerRegistry-1gB5vtzQ.js} +2 -2
  222. package/dist/src/{providerRegistry-BTDgfV5h.cjs → providerRegistry-BESeALrr.cjs} +2 -2
  223. package/dist/src/{providerRegistry-CUWki5mQ.js → providerRegistry-DoACwqhD.js} +2 -2
  224. package/dist/src/{providerRegistry-B9lh-_tx.js → providerRegistry-PMsleEzs.js} +2 -2
  225. package/dist/src/providers-BuyzKt7C.js +2 -0
  226. package/dist/src/providers-C7lNVBjX.cjs +3 -0
  227. package/dist/src/providers-CCE2COJi2.js +2 -0
  228. package/dist/src/{providers-Cn73d5sr.js → providers-CJh7iriU.js} +17180 -16823
  229. package/dist/src/providers-Ctcc592x.js +3 -0
  230. package/dist/src/{providers-DvddrgxL.js → providers-DRrerKra.js} +1052 -695
  231. package/dist/src/{providers-Ch6Mr0gn.js → providers-DT-GtF2t.js} +16716 -16359
  232. package/dist/src/{providers-CScd1wN6.cjs → providers-eDShy16E.cjs} +19893 -19506
  233. package/dist/src/python/persistent_wrapper.py +0 -5
  234. package/dist/src/{pythonUtils-Cpo0Ez1p.js → pythonUtils-C4tltmIn.js} +4 -4
  235. package/dist/src/{pythonUtils-dAVigVK-.cjs → pythonUtils-CoLaCwNY.cjs} +4 -4
  236. package/dist/src/{pythonUtils-Bzwbgpbg.js → pythonUtils-DMO68Jg7.js} +3 -3
  237. package/dist/src/{pythonUtils-wIqk7zAf.js → pythonUtils-DNqbnRdx.js} +3 -3
  238. package/dist/src/{quiverai-BeofbLVc.js → quiverai-BSS9a7wV.js} +4 -4
  239. package/dist/src/{quiverai-DVSEqJiq.js → quiverai-Bk1KrvL6.js} +4 -4
  240. package/dist/src/{quiverai-CcUhPIBg.cjs → quiverai-Bpx6MZ7T.cjs} +4 -4
  241. package/dist/src/{quiverai-CCQn73lq.js → quiverai-CPKhWgaT.js} +4 -5
  242. package/dist/src/render-7uNJ2V14.js +135 -0
  243. package/dist/src/render-DlscvAUJ.js +135 -0
  244. package/dist/src/render-eui5p5mL.js +136 -0
  245. package/dist/src/{render-BHl6QVq9.js → render-nj-UaPdn.js} +2 -3
  246. package/dist/src/render-tG6ir9_g.cjs +165 -0
  247. package/dist/src/{responses-CgNyTPsY.js → responses-1ztiVYsx.js} +56 -17
  248. package/dist/src/{responses-BKP_WYis.js → responses-B8haB-mD.js} +56 -17
  249. package/dist/src/{responses-CQb1Tj69.js → responses-BiaBguAu.js} +56 -17
  250. package/dist/src/{responses-mo0KQDbu.cjs → responses-CF-ayauu.cjs} +56 -17
  251. package/dist/src/rubyUtils-4hjGxvju.js +3 -0
  252. package/dist/src/{rubyUtils-DECSbsfY.js → rubyUtils-BI0p46eZ.js} +3 -3
  253. package/dist/src/{rubyUtils-CiVfln3g.js → rubyUtils-CIQFnVz4.js} +3 -3
  254. package/dist/src/rubyUtils-CO-tuszQ.cjs +2 -0
  255. package/dist/src/{rubyUtils-PgU-gHmx.js → rubyUtils-DGnoCYL2.js} +4 -4
  256. package/dist/src/{rubyUtils-CGeUtCfW.cjs → rubyUtils-DoifqkiA.cjs} +5 -4
  257. package/dist/src/{sagemaker-CqeASYE5.js → sagemaker-BDLeW29y.js} +14 -18
  258. package/dist/src/{sagemaker-MUbD5V3v.js → sagemaker-C5T60MKf.js} +14 -19
  259. package/dist/src/{sagemaker-CVv8W7so.js → sagemaker-ClS_NB07.js} +14 -18
  260. package/dist/src/{sagemaker-jiw1wQa-.cjs → sagemaker-ljtY12VM.cjs} +14 -18
  261. package/dist/src/{scanner-DVDeUz1r.js → scanner-nOCWNIXa.js} +130 -35
  262. package/dist/src/server/golang/wrapper.go +1 -1
  263. package/dist/src/server/index.js +4829 -2529
  264. package/dist/src/server/python/persistent_wrapper.py +0 -5
  265. package/dist/src/{server-BtoCXeXI.cjs → server-BEECpeGG.cjs} +140 -6
  266. package/dist/src/{server-DZ9MtCn0.js → server-ByiF3qlg.js} +129 -9
  267. package/dist/src/{server-Cns05F1j.js → server-ByxbqAcQ.js} +128 -8
  268. package/dist/src/server-C0XKRNB_.cjs +2 -0
  269. package/dist/src/server-C_15p79-.js +3 -0
  270. package/dist/src/{server-CP9qKM40.js → server-gyd6d4Hc.js} +126 -7
  271. package/dist/src/{signal-C3ZTsUgi.js → signal-DTtUuU3l.js} +3 -3
  272. package/dist/src/{slack-DCEV-vWP.js → slack-4zZX1OKP.js} +2 -2
  273. package/dist/src/{slack-94iG3T0s.cjs → slack-BLlsDpfG.cjs} +2 -2
  274. package/dist/src/{slack-BR0HtO3K.js → slack-BPYLQLgb.js} +2 -2
  275. package/dist/src/{slack-2sdpGzbt.js → slack-Bamy_7te.js} +2 -2
  276. package/dist/src/{store-CLyU7AtI.cjs → store-2K0kDi80.cjs} +3 -3
  277. package/dist/src/{store-VB0GP46K.js → store-2OXm_eBY.js} +3 -3
  278. package/dist/src/store-BELqNwvz.js +3 -0
  279. package/dist/src/{store-Cj258DgL.js → store-BPkzEyFM.js} +3 -3
  280. package/dist/src/{store-P8OKm19S.js → store-CPh25336.js} +3 -3
  281. package/dist/src/store-uQZ4AjPe.cjs +2 -0
  282. package/dist/src/{tables-BEIFz2tM.js → tables-BMSOS2Gg.js} +3 -3
  283. package/dist/src/{tables-BdZQEpRz.cjs → tables-CXbaZ9y1.cjs} +3 -3
  284. package/dist/src/{tables-DmzvLbeZ.js → tables-NlvH23ky.js} +3 -3
  285. package/dist/src/{tables-kC7R5kiK.js → tables-WgdUZ8Ck.js} +3 -3
  286. package/dist/src/{telemetry-DPXLd7UE.js → telemetry--iqaGyaS.js} +5 -4
  287. package/dist/src/{telemetry-re627Lre.cjs → telemetry-CEQxGnMZ.cjs} +8 -7
  288. package/dist/src/{telemetry-BugWqKiu.js → telemetry-CgdVGV8N.js} +5 -4
  289. package/dist/src/{telemetry-BnH5VJAU.js → telemetry-DWdGHvEf.js} +5 -4
  290. package/dist/src/telemetry-DjNoC_n3.cjs +2 -0
  291. package/dist/src/telemetry-ZdPZc0fm.js +3 -0
  292. package/dist/src/{text-CW1cyrwj.cjs → text-BiNME7QG.cjs} +1 -1
  293. package/dist/src/{text-Db-Wt2u2.js → text-D4lz-Jg_.js} +1 -1
  294. package/dist/src/{text-TIv0QYnd.js → text-DDQP0tuQ.js} +1 -1
  295. package/dist/src/{text-B_UCRPp2.js → text-NWvfMfkF.js} +1 -1
  296. package/dist/src/{tokenUsageUtils-DflFMjS0.js → tokenUsageUtils-2wIvAhB3.js} +7 -3
  297. package/dist/src/{tokenUsageUtils-BDGe-iyI.js → tokenUsageUtils-4c780gFd.js} +7 -3
  298. package/dist/src/{tokenUsageUtils-NYT-WKS6.js → tokenUsageUtils-BjVkdk18.js} +7 -3
  299. package/dist/src/{tokenUsageUtils-bVa1ga6f.cjs → tokenUsageUtils-C9odhsbW.cjs} +7 -3
  300. package/dist/src/{transcription-CaMivnjG.js → transcription-84t4ALo2.js} +7 -11
  301. package/dist/src/{transcription-Hb3VnC4M.js → transcription-Bm2emLmJ.js} +8 -11
  302. package/dist/src/{transcription-BvtsrzRG.cjs → transcription-CZ4LG5hQ.cjs} +9 -13
  303. package/dist/src/{transcription-DOMMTu01.js → transcription-D7Q0vJsh.js} +7 -13
  304. package/dist/src/{transform-DrleutM3.js → transform-B-b6Cq-q.js} +8 -6
  305. package/dist/src/transform-BQt0BeAW.js +3 -0
  306. package/dist/src/transform-Bq5oqC0s.cjs +2 -0
  307. package/dist/src/{transform-ZrG2dvlo.cjs → transform-C9izGX54.cjs} +5 -5
  308. package/dist/src/{transform-BzK09Q_9.js → transform-CwbAZ84V.js} +5 -5
  309. package/dist/src/{transform-0BwoBsvO.cjs → transform-Dg4LcO1Y.cjs} +18 -10
  310. package/dist/src/{transform-B2-jIv68.js → transform-DtooZqYY.js} +8 -6
  311. package/dist/src/{transform-ljLYHEPh.js → transform-DzCF-wqV.js} +5 -5
  312. package/dist/src/{transform-DyDAwEpE.js → transform-_DpNB4qp.js} +9 -7
  313. package/dist/src/{transform-BqPkNPYm.js → transform-eGiUAv86.js} +5 -5
  314. package/dist/src/{transformersAvailability-DKoRtQLy.cjs → transformersAvailability-B22swDxr.cjs} +1 -1
  315. package/dist/src/{transformersAvailability-BGkzavwb.js → transformersAvailability-lvCCvuPT.js} +1 -1
  316. package/dist/src/{transformersAvailability-D6c6ROpT.js → transformersAvailability-rJGPccjr.js} +1 -1
  317. package/dist/src/{types-Cd3ygw8W.js → types-BDjGOq4E.js} +354 -24
  318. package/dist/src/{types-CIhFeUC4.js → types-BVH9hjgW.js} +364 -23
  319. package/dist/src/{types-D8cGDZbL.cjs → types-CgG2rKiW.cjs} +534 -167
  320. package/dist/src/{types-q8GXGF65.js → types-DNRZVOue.js} +498 -167
  321. package/dist/src/{util-BLvy9qfE.js → util-3pBZZb_H.js} +151 -149
  322. package/dist/src/{util-CFj4YKIn.cjs → util-A5_ZsQUn.cjs} +66 -44
  323. package/dist/src/{util-BtoGs5Cb.js → util-B9CNhyac.js} +66 -44
  324. package/dist/src/{util-Bm3E9jpK.js → util-BQOCAHQC.js} +692 -690
  325. package/dist/src/{util-vNmDL5DT.js → util-BVXcTwXu.js} +138 -36
  326. package/dist/src/{util-CgDCK4KI.js → util-BlFVL0UF.js} +66 -44
  327. package/dist/src/{util-DM2rTn_6.js → util-C-kmRosx.js} +66 -44
  328. package/dist/src/{util-DbVG-yZU.js → util-DFPeFkiV.js} +138 -36
  329. package/dist/src/{util-DMFeUvLz.js → util-DN0-b81k.js} +138 -36
  330. package/dist/src/{util--9u9UVCt.cjs → util-Dpmm_dAI.cjs} +143 -35
  331. package/dist/src/{util-CMMkIxfU.js → util-Dub0f_ej.js} +693 -691
  332. package/dist/src/{util-CuLo2pMR.cjs → util-DvpHnLt0.cjs} +714 -719
  333. package/dist/src/{utils-DOjD4dTC.js → utils-BUMN8orw.js} +6 -4
  334. package/dist/src/{utils-DKw8mrgr.cjs → utils-DkVeShIB.cjs} +6 -4
  335. package/dist/src/{utils-DEuL4VNB.js → utils-kt7lv30R.js} +6 -4
  336. package/dist/src/{utils-CFxO9KGo.js → utils-o8S5huU2.js} +6 -4
  337. package/dist/src/version-0frU0UTr.js +16 -0
  338. package/dist/src/version-CbpiUINz.js +17 -0
  339. package/dist/src/version-CbuBKu2U.js +16 -0
  340. package/dist/src/version-D9zu9FWB.cjs +27 -0
  341. package/dist/tsconfig.tsbuildinfo +1 -1
  342. package/package.json +57 -46
  343. package/dist/src/app/assets/index-B6l9CVVb.js +0 -439
  344. package/dist/src/app/assets/index-DyZ0Ep37.css +0 -1
  345. package/dist/src/app/assets/scroll-timeline-BdJZVXlz.js +0 -1
  346. package/dist/src/app/assets/sync-CStkzc6u.js +0 -4
  347. package/dist/src/app/assets/vendor-charts-BnDWwBlI.js +0 -36
  348. package/dist/src/app/assets/vendor-markdown-Bz7N-ca6.js +0 -29
  349. package/dist/src/app/assets/vendor-react-AtKqiNEf.js +0 -4
  350. package/dist/src/app/assets/vendor-syntax-D06x6TQF.js +0 -2
  351. package/dist/src/app/assets/vendor-utils-BvMHZmO7.js +0 -37
  352. package/dist/src/cache-C5yFZ4gC.cjs +0 -816
  353. package/dist/src/cache-CaT5tPgo.js +0 -756
  354. package/dist/src/cache-CyCanoMu.js +0 -6
  355. package/dist/src/cache-DSqR6ezl.js +0 -726
  356. package/dist/src/cache-Df_QFDNu.cjs +0 -5
  357. package/dist/src/cache-HP0NP4k3.js +0 -756
  358. package/dist/src/cloud-DE3t1-ZI.js +0 -4
  359. package/dist/src/codex-sdk-BQEw16R_.js +0 -834
  360. package/dist/src/codex-sdk-C_07GuVS.js +0 -834
  361. package/dist/src/codex-sdk-DE5G18dx.js +0 -835
  362. package/dist/src/codex-sdk-ZLKfDjqP.cjs +0 -838
  363. package/dist/src/eval-7aEqoMs3.js +0 -15
  364. package/dist/src/evalResult-CYNHkk5A.js +0 -12
  365. package/dist/src/evalResult-CuvJeNiM.js +0 -10
  366. package/dist/src/evalResult-tGdilrWt.cjs +0 -10
  367. package/dist/src/evaluator-BBUqRhz1.js +0 -36
  368. package/dist/src/fetch-UWU706qb.js +0 -5
  369. package/dist/src/graders-BxfEguVY.js +0 -32
  370. package/dist/src/graders-CzVMbEnv.js +0 -34
  371. package/dist/src/graders-DjCXfj0l.cjs +0 -32
  372. package/dist/src/graders-kHzIWOKu.js +0 -32
  373. package/dist/src/messages-DJNo37Ko.js +0 -246
  374. package/dist/src/messages-Dy9QecMs.js +0 -245
  375. package/dist/src/messages-HJsyEh4o.cjs +0 -257
  376. package/dist/src/messages-biC_ex-p.js +0 -245
  377. package/dist/src/openclaw-0Sv7AK3O.js +0 -580
  378. package/dist/src/openclaw-CXxbKgDH.cjs +0 -586
  379. package/dist/src/openclaw-D1FSCps-.js +0 -580
  380. package/dist/src/openclaw-D2ENvu7a.js +0 -582
  381. package/dist/src/providers-BSLEaIQG.js +0 -32
  382. package/dist/src/providers-D-FnDg8k.cjs +0 -31
  383. package/dist/src/providers-DEYiFVAo.js +0 -30
  384. package/dist/src/providers-sS2WI8YD.js +0 -30
  385. package/dist/src/rubyUtils-B1HXG4ej.cjs +0 -4
  386. package/dist/src/rubyUtils-Rt6pKA96.js +0 -5
  387. package/dist/src/server-B0Xh1Gx-.js +0 -7
  388. package/dist/src/server-DJTKu9IR.cjs +0 -5
  389. package/dist/src/store-C5u6MgC8.js +0 -6
  390. package/dist/src/store-CNHk-De4.cjs +0 -5
  391. package/dist/src/telemetry-Yig0Tino.js +0 -7
  392. package/dist/src/telemetry-p8Pwqm1i.cjs +0 -5
  393. package/dist/src/transform-ChNIpHz7.js +0 -6
  394. package/dist/src/transform-PtQ6rAE3.cjs +0 -5
@@ -1,10 +1,12 @@
1
- const require_logger = require("./logger-D5iKBpu_.cjs");
1
+ const require_logger = require("./logger-COuQb2xB.cjs");
2
2
  const require_invariant = require("./invariant-kfQ8Bu82.cjs");
3
- const require_esm = require("./esm-CipptfDu.cjs");
4
- const require_pythonUtils = require("./pythonUtils-dAVigVK-.cjs");
5
- const require_fileExtensions = require("./fileExtensions-bYh77CN8.cjs");
6
- const require_types = require("./types-D8cGDZbL.cjs");
7
- const require_fetch = require("./fetch-BnR9wSnm.cjs");
3
+ const require_fetch = require("./fetch-NuqXW1Xb.cjs");
4
+ const require_version = require("./version-D9zu9FWB.cjs");
5
+ const require_types = require("./types-CgG2rKiW.cjs");
6
+ const require_esm = require("./esm-B_rGuPTo.cjs");
7
+ const require_render = require("./render-tG6ir9_g.cjs");
8
+ const require_pythonUtils = require("./pythonUtils-CoLaCwNY.cjs");
9
+ const require_fileExtensions = require("./fileExtensions-D9h-8Wxg.cjs");
8
10
  let fs = require("fs");
9
11
  fs = require_logger.__toESM(fs);
10
12
  let path = require("path");
@@ -19,802 +21,801 @@ let dedent = require("dedent");
19
21
  dedent = require_logger.__toESM(dedent);
20
22
  let fs_promises = require("fs/promises");
21
23
  fs_promises = require_logger.__toESM(fs_promises);
24
+ let nunjucks = require("nunjucks");
25
+ nunjucks = require_logger.__toESM(nunjucks);
26
+ let csv_parse_sync = require("csv-parse/sync");
22
27
  let glob = require("glob");
23
28
  let fast_deep_equal = require("fast-deep-equal");
24
29
  fast_deep_equal = require_logger.__toESM(fast_deep_equal);
25
- let csv_parse_sync = require("csv-parse/sync");
26
- let nunjucks = require("nunjucks");
27
- nunjucks = require_logger.__toESM(nunjucks);
28
30
  let fast_xml_parser = require("fast-xml-parser");
29
31
  let csv_stringify_sync = require("csv-stringify/sync");
30
- //#region src/util/provider.ts
31
- function canonicalizeProviderId(id) {
32
- if (id.startsWith("file://")) {
33
- const filePath = id.slice(7);
34
- return path.isAbsolute(filePath) ? id : `file://${path.resolve(filePath)}`;
35
- }
36
- for (const prefix of [
37
- "exec:",
38
- "python:",
39
- "golang:"
40
- ]) if (id.startsWith(prefix)) {
41
- const filePath = id.slice(prefix.length);
42
- if (filePath.includes("/") || filePath.includes("\\")) return `${prefix}${path.resolve(filePath)}`;
43
- return id;
32
+ //#region src/util/functions/loadFunction.ts
33
+ const functionCache = {};
34
+ /**
35
+ * Loads a function from a JavaScript or Python file
36
+ * @param options Options for loading the function
37
+ * @returns The loaded function
38
+ */
39
+ async function loadFunction({ filePath, functionName, defaultFunctionName = "func", basePath = require_logger.state.basePath, useCache = true }) {
40
+ const cacheKey = `${filePath}${functionName ? `:${functionName}` : ""}`;
41
+ if (useCache && functionCache[cacheKey]) return functionCache[cacheKey];
42
+ const resolvedPath = basePath ? path.default.resolve(basePath, filePath) : filePath;
43
+ 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`);
44
+ try {
45
+ let func;
46
+ if (require_fileExtensions.isJavascriptFile(resolvedPath)) {
47
+ const module = await require_esm.importModule(resolvedPath, functionName);
48
+ let moduleFunc;
49
+ if (functionName) moduleFunc = module;
50
+ else moduleFunc = typeof module === "function" ? module : module?.default?.default || module?.default || module?.[defaultFunctionName] || module;
51
+ 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}")`);
52
+ func = moduleFunc;
53
+ } else {
54
+ const result = (...args) => require_pythonUtils.runPython(resolvedPath, functionName || defaultFunctionName, args);
55
+ func = result;
56
+ }
57
+ if (useCache) functionCache[cacheKey] = func;
58
+ return func;
59
+ } catch (err) {
60
+ require_logger.logger.error(`Failed to load function: ${err.message}`);
61
+ throw err;
44
62
  }
45
- if ((id.endsWith(".js") || id.endsWith(".ts") || id.endsWith(".mjs")) && (id.includes("/") || id.includes("\\"))) return `file://${path.resolve(id)}`;
46
- return id;
47
- }
48
- function getProviderLabel(provider) {
49
- return provider?.label && typeof provider.label === "string" ? provider.label : void 0;
50
63
  }
51
- function providerToIdentifier(provider) {
52
- if (!provider) return;
53
- if (typeof provider === "string") return canonicalizeProviderId(provider);
54
- const label = getProviderLabel(provider);
55
- if (label) return label;
56
- if (require_types.isApiProvider(provider)) return canonicalizeProviderId(provider.id());
57
- if (require_types.isProviderOptions(provider)) {
58
- if (provider.id) return canonicalizeProviderId(provider.id);
59
- return;
60
- }
61
- if (typeof provider === "object" && "id" in provider && typeof provider.id === "string") return canonicalizeProviderId(provider.id);
64
+ /**
65
+ * Extracts the file path and function name from a file:// URL
66
+ * @param fileUrl The file:// URL (e.g., "file://path/to/file.js:functionName")
67
+ * @returns The file path and optional function name
68
+ */
69
+ function parseFileUrl(fileUrl) {
70
+ if (!fileUrl.startsWith("file://")) throw new Error("URL must start with file://");
71
+ const urlWithoutProtocol = fileUrl.slice(7);
72
+ const lastColonIndex = urlWithoutProtocol.lastIndexOf(":");
73
+ if (lastColonIndex > 1) return {
74
+ filePath: urlWithoutProtocol.slice(0, lastColonIndex),
75
+ functionName: urlWithoutProtocol.slice(lastColonIndex + 1)
76
+ };
77
+ return { filePath: urlWithoutProtocol };
62
78
  }
79
+ //#endregion
80
+ //#region src/util/file.ts
63
81
  /**
64
- * Gets a descriptive identifier string for a provider, showing both label and ID when both exist.
65
- * Useful for error messages to help users debug provider reference issues.
82
+ * Simple Nunjucks engine specifically for file paths
83
+ * This function is separate from the main getNunjucksEngine to avoid circular dependencies
66
84
  */
67
- function getProviderDescription(provider) {
68
- const label = provider.label;
69
- const id = provider.id();
70
- if (label && label !== id) return `${label} (${id})`;
71
- return id;
85
+ function getNunjucksEngineForFilePath() {
86
+ const env = nunjucks.default.configure({ autoescape: false });
87
+ env.addGlobal("env", {
88
+ ...process.env,
89
+ ...require_logger.state.config?.env
90
+ });
91
+ return env;
72
92
  }
73
93
  /**
74
- * Checks if a provider reference matches a given provider.
75
- * Supports exact matching and wildcard patterns.
94
+ * Loads content from an external file if the input is a file path, otherwise
95
+ * returns the input as-is. Supports Nunjucks templating for file paths.
96
+ *
97
+ * @param filePath - The input to process. Can be a file path string starting with "file://",
98
+ * an array of file paths, or any other type of data.
99
+ * @param context - Optional context to control file loading behavior. 'assertion' context
100
+ * preserves Python/JS file references instead of loading their content.
101
+ * @returns The loaded content if the input was a file path, otherwise the original input.
102
+ * For JSON and YAML files, the content is parsed into an object.
103
+ * For other file types, the raw file content is returned as a string.
104
+ *
105
+ * @throws {Error} If the specified file does not exist.
76
106
  */
77
- function doesProviderRefMatch(ref, provider) {
78
- const label = provider.label;
79
- const id = provider.id();
80
- const canonicalRef = canonicalizeProviderId(ref);
81
- const canonicalId = canonicalizeProviderId(id);
82
- if (label && label === ref) return true;
83
- if (id === ref || canonicalId === canonicalRef) return true;
84
- if (ref.endsWith("*")) {
85
- const prefix = ref.slice(0, -1);
86
- if (label?.startsWith(prefix) || id.startsWith(prefix) || canonicalId.startsWith(prefix)) return true;
107
+ function maybeLoadFromExternalFile(filePath, context) {
108
+ if (Array.isArray(filePath)) return filePath.map((path$3) => {
109
+ return maybeLoadFromExternalFile(path$3, context);
110
+ });
111
+ if (typeof filePath !== "string") return filePath;
112
+ if (!filePath.startsWith("file://")) return filePath;
113
+ const renderedFilePath = getNunjucksEngineForFilePath().renderString(filePath, {});
114
+ const { filePath: cleanPath, functionName } = parseFileUrl(renderedFilePath);
115
+ if (context === "assertion" && (cleanPath.endsWith(".py") || require_fileExtensions.isJavascriptFile(cleanPath))) {
116
+ require_logger.logger.debug(`Preserving Python/JS file reference in assertion context: ${renderedFilePath}`);
117
+ return renderedFilePath;
87
118
  }
88
- if (label?.startsWith(`${ref}:`) || id.startsWith(`${ref}:`) || canonicalId.startsWith(`${ref}:`)) return true;
89
- return false;
119
+ if (context === "vars") {
120
+ require_logger.logger.debug(`Preserving file reference in vars context: ${renderedFilePath}`);
121
+ return renderedFilePath;
122
+ }
123
+ if (functionName && (cleanPath.endsWith(".py") || require_fileExtensions.isJavascriptFile(cleanPath))) return renderedFilePath;
124
+ const pathToUse = functionName && !(cleanPath.endsWith(".py") || require_fileExtensions.isJavascriptFile(cleanPath)) ? renderedFilePath.slice(7) : cleanPath;
125
+ const resolvedPath = path.resolve(require_logger.state.basePath || "", pathToUse);
126
+ if ((0, glob.hasMagic)(pathToUse)) {
127
+ const matchedFiles = (0, glob.globSync)(resolvedPath, { windowsPathsNoEscape: true });
128
+ if (matchedFiles.length === 0) throw new Error(`No files found matching pattern: ${resolvedPath}`);
129
+ const allContents = [];
130
+ for (const matchedFile of matchedFiles) {
131
+ let contents;
132
+ try {
133
+ contents = fs.readFileSync(matchedFile, "utf8");
134
+ } catch (error) {
135
+ if (error.code === "ENOENT") {
136
+ require_logger.logger.debug(`File disappeared during glob expansion: ${matchedFile}`);
137
+ continue;
138
+ }
139
+ throw error;
140
+ }
141
+ if (matchedFile.endsWith(".json")) {
142
+ const parsed = JSON.parse(contents);
143
+ if (Array.isArray(parsed)) allContents.push(...parsed);
144
+ else allContents.push(parsed);
145
+ } else if (matchedFile.endsWith(".yaml") || matchedFile.endsWith(".yml")) {
146
+ const parsed = js_yaml.default.load(contents);
147
+ if (parsed === null || parsed === void 0) continue;
148
+ if (Array.isArray(parsed)) allContents.push(...parsed);
149
+ else allContents.push(parsed);
150
+ } else if (matchedFile.endsWith(".csv")) {
151
+ const records = (0, csv_parse_sync.parse)(contents, { columns: true });
152
+ if (records.length > 0 && Object.keys(records[0]).length === 1) allContents.push(...records.map((record) => Object.values(record)[0]));
153
+ else allContents.push(...records);
154
+ } else allContents.push(contents);
155
+ }
156
+ return allContents;
157
+ }
158
+ const finalPath = resolvedPath;
159
+ let contents;
160
+ try {
161
+ contents = fs.readFileSync(finalPath, "utf8");
162
+ } catch (error) {
163
+ if (error.code === "ENOENT") throw new Error(`File does not exist: ${finalPath}`);
164
+ throw new Error(`Failed to read file ${finalPath}: ${error}`);
165
+ }
166
+ if (finalPath.endsWith(".json")) try {
167
+ return JSON.parse(contents);
168
+ } catch (error) {
169
+ throw new Error(`Failed to parse JSON file ${finalPath}: ${error}`);
170
+ }
171
+ if (finalPath.endsWith(".yaml") || finalPath.endsWith(".yml")) try {
172
+ return js_yaml.default.load(contents);
173
+ } catch (error) {
174
+ throw new Error(`Failed to parse YAML file ${finalPath}: ${error}`);
175
+ }
176
+ if (finalPath.endsWith(".csv")) {
177
+ const records = (0, csv_parse_sync.parse)(contents, { columns: true });
178
+ if (records.length > 0 && Object.keys(records[0]).length === 1) return records.map((record) => Object.values(record)[0]);
179
+ return records;
180
+ }
181
+ return contents;
90
182
  }
91
183
  /**
92
- * Checks if a provider is allowed based on a list of allowed references.
184
+ * Resolves a relative file path with respect to a base path, handling cloud configuration appropriately.
185
+ * When using a cloud configuration, the current working directory is always used instead of the context's base path.
186
+ *
187
+ * @param filePath - The relative or absolute file path to resolve.
188
+ * @param isCloudConfig - Whether this is a cloud configuration.
189
+ * @returns The resolved absolute file path.
93
190
  */
94
- function isProviderAllowed(provider, allowedProviders) {
95
- if (!Array.isArray(allowedProviders)) return true;
96
- if (allowedProviders.length === 0) return false;
97
- return allowedProviders.some((ref) => doesProviderRefMatch(ref, provider));
191
+ function getResolvedRelativePath(filePath, isCloudConfig) {
192
+ if (path.isAbsolute(filePath) || !isCloudConfig) return filePath;
193
+ return path.join(process.cwd(), filePath);
98
194
  }
99
195
  /**
100
- * Detects if a provider uses OpenAI models.
101
- * This includes direct OpenAI providers and Azure OpenAI.
196
+ * Recursively loads external file references from a configuration object.
197
+ *
198
+ * @param config - The configuration object to process
199
+ * @param context - Optional context to control file loading behavior
200
+ * @returns The configuration with external file references resolved
102
201
  */
103
- function isOpenAiProvider(providerId) {
104
- const lowerProviderId = providerId.toLowerCase();
105
- if (lowerProviderId.startsWith("openai:")) return true;
106
- if (lowerProviderId.startsWith("azureopenai:")) return true;
107
- if (lowerProviderId.startsWith("azure:")) {
108
- if ([
109
- "gpt",
110
- "openai",
111
- "davinci",
112
- "curie",
113
- "babbage",
114
- "ada",
115
- "text-embedding",
116
- "whisper",
117
- "dall-e",
118
- "tts"
119
- ].some((indicator) => lowerProviderId.includes(indicator))) return true;
202
+ function maybeLoadConfigFromExternalFile(config, context) {
203
+ if (Array.isArray(config)) return config.map((item) => maybeLoadConfigFromExternalFile(item, context));
204
+ if (typeof config === "object" && config !== null) {
205
+ const result = {};
206
+ for (const key of Object.keys(config)) {
207
+ const childContext = key === "value" && "type" in config && typeof config.type === "string" && (config.type === "python" || config.type === "javascript") ? "assertion" : key === "vars" ? "vars" : context;
208
+ result[key] = maybeLoadConfigFromExternalFile(config[key], childContext);
209
+ }
210
+ return result;
120
211
  }
121
- return false;
212
+ return maybeLoadFromExternalFile(config, context);
122
213
  }
123
214
  /**
124
- * Detects if a provider uses Anthropic/Claude models.
125
- * This includes direct Anthropic providers, Bedrock with Claude, and Vertex with Claude.
215
+ * Parses a file path or glob pattern to extract function names and file extensions.
216
+ * Function names can be specified in the filename like this:
217
+ * prompt.py:myFunction or prompts.js:myFunction.
218
+ * @param basePath - The base path for file resolution.
219
+ * @param promptPath - The path or glob pattern.
220
+ * @returns Parsed details including function name, file extension, and directory status.
126
221
  */
127
- function isAnthropicProvider(providerId) {
128
- const lowerProviderId = providerId.toLowerCase();
129
- if (lowerProviderId.startsWith("anthropic:")) return true;
130
- if (lowerProviderId.startsWith("bedrock:")) {
131
- if (lowerProviderId.includes("claude") || lowerProviderId.includes("anthropic")) return true;
132
- }
133
- if (lowerProviderId.startsWith("vertex:")) {
134
- if (lowerProviderId.includes("claude")) return true;
135
- }
136
- return false;
137
- }
138
- const KNOWN_ENV_VARS = {
139
- openai: "OPENAI_API_KEY",
140
- anthropic: "ANTHROPIC_API_KEY",
141
- google: "GOOGLE_API_KEY",
142
- mistral: "MISTRAL_API_KEY",
143
- cohere: "COHERE_API_KEY",
144
- replicate: "REPLICATE_API_TOKEN",
145
- voyage: "VOYAGE_API_KEY",
146
- ai21: "AI21_API_KEY",
147
- xai: "XAI_API_KEY",
148
- groq: "GROQ_API_KEY",
149
- deepseek: "DEEPSEEK_API_KEY",
150
- perplexity: "PERPLEXITY_API_KEY",
151
- hyperbolic: "HYPERBOLIC_API_KEY",
152
- cerebras: "CEREBRAS_API_KEY",
153
- togetherai: "TOGETHER_API_KEY",
154
- fal: "FAL_KEY",
155
- huggingface: "HF_TOKEN",
156
- "cloudflare-ai": "CLOUDFLARE_API_KEY"
157
- };
158
- function getDefaultEnvVar(providerId) {
159
- const prefix = providerId.split(":")[0];
160
- return KNOWN_ENV_VARS[prefix] || `${prefix.toUpperCase()}_API_KEY`;
161
- }
162
- /**
163
- * Pre-checks providers for missing API keys before evaluation starts.
164
- * Assumes getApiKey() is side-effect free (no network calls or token refresh).
165
- */
166
- function checkProviderApiKeys(providers) {
167
- const missingApiKeys = /* @__PURE__ */ new Map();
168
- for (const provider of providers) {
169
- const p = provider;
170
- if (typeof p.getApiKey !== "function") continue;
171
- if (provider.id().startsWith("azure:")) continue;
172
- const requiresKey = typeof p.requiresApiKey === "function" ? p.requiresApiKey() : p.config?.apiKeyRequired !== false;
173
- let apiKey;
174
- try {
175
- apiKey = p.getApiKey();
176
- } catch {
177
- apiKey = void 0;
178
- }
179
- if (requiresKey && !apiKey) {
180
- const envVar = p.config?.apiKeyEnvar || getDefaultEnvVar(provider.id());
181
- if (!missingApiKeys.has(envVar)) missingApiKeys.set(envVar, []);
182
- missingApiKeys.get(envVar).push(provider.id());
222
+ function parsePathOrGlob(basePath, promptPath) {
223
+ if (promptPath.startsWith("file://")) promptPath = promptPath.slice(7);
224
+ const filePath = path.resolve(basePath, promptPath);
225
+ let filename = path.relative(basePath, filePath);
226
+ let functionName;
227
+ if (filename.includes(":")) {
228
+ const lastColonIndex = filename.lastIndexOf(":");
229
+ if (lastColonIndex > 1) {
230
+ const pathWithoutFunction = filename.slice(0, lastColonIndex);
231
+ if (require_fileExtensions.isJavascriptFile(pathWithoutFunction) || pathWithoutFunction.endsWith(".py") || pathWithoutFunction.endsWith(".go") || pathWithoutFunction.endsWith(".rb")) {
232
+ functionName = filename.slice(lastColonIndex + 1);
233
+ filename = pathWithoutFunction;
234
+ }
183
235
  }
184
236
  }
185
- return missingApiKeys;
237
+ let stats;
238
+ try {
239
+ stats = fs.statSync(path.join(basePath, filename));
240
+ } catch (err) {
241
+ if (require_logger.getEnvBool("PROMPTFOO_STRICT_FILES")) throw err;
242
+ }
243
+ const normalizedFilePath = filePath.replace(/\\/g, "/");
244
+ const isPathPattern = stats?.isDirectory() || (0, glob.hasMagic)(promptPath) || (0, glob.hasMagic)(normalizedFilePath);
245
+ const safeFilename = path.relative(basePath, require_esm.safeResolve(basePath, filename));
246
+ return {
247
+ extension: isPathPattern ? void 0 : path.parse(safeFilename).ext,
248
+ filePath: path.join(basePath, safeFilename),
249
+ functionName,
250
+ isPathPattern
251
+ };
252
+ }
253
+ function readOutput(outputPath) {
254
+ const ext = path.parse(outputPath).ext.slice(1);
255
+ switch (ext) {
256
+ case "json": return JSON.parse(fs.readFileSync(outputPath, "utf-8"));
257
+ default: throw new Error(`Unsupported output file format: ${ext} currently only supports json`);
258
+ }
186
259
  }
187
260
  /**
188
- * Detects if a provider uses Google models.
189
- * This includes direct Google/Vertex providers with Gemini and other Google models.
190
- * Note: Vertex with Claude models is NOT counted as Google (it's Anthropic).
261
+ * Load custom Nunjucks filters from external files.
262
+ * Note: If a glob pattern matches multiple files, only the last file's export is used.
263
+ * Each filter name should typically resolve to a single file.
191
264
  */
192
- function isGoogleProvider(providerId) {
193
- const lowerProviderId = providerId.toLowerCase();
194
- if (lowerProviderId.startsWith("google:")) return true;
195
- if (lowerProviderId.startsWith("vertex:")) {
196
- if (!lowerProviderId.includes("claude")) return true;
265
+ async function readFilters(filters, basePath = "") {
266
+ const ret = {};
267
+ for (const [name, filterPath] of Object.entries(filters)) {
268
+ const filePaths = (0, glob.globSync)(path.join(basePath, filterPath), { windowsPathsNoEscape: true });
269
+ for (const filePath of filePaths) ret[name] = await require_esm.importModule(path.resolve(filePath));
197
270
  }
198
- return false;
271
+ return ret;
199
272
  }
200
- //#endregion
201
- //#region src/util/comparison.ts
202
273
  /**
203
- * Explicit runtime variable names that don't follow the underscore convention.
204
- * These are added during evaluation but aren't part of the original test definition.
274
+ * Loads configuration from an external file with variable rendering.
275
+ * This is a convenience wrapper that combines renderVarsInObject and maybeLoadFromExternalFile.
205
276
  *
206
- * - sessionId: Added by multi-turn strategy providers (GOAT, Crescendo)
277
+ * Use this for simple config fields that:
278
+ * - Need variable rendering ({{ vars.x }}, {{ env.X }})
279
+ * - May reference external files (file://path.json)
280
+ * - Don't have nested file references that need loading
207
281
  *
208
- * Note: Variables starting with underscore (e.g., _conversation) are automatically
209
- * treated as runtime variables and filtered out.
210
- */
211
- const EXPLICIT_RUNTIME_VAR_KEYS = ["sessionId"];
212
- /**
213
- * Checks if a variable key is a runtime-only variable that should be filtered
214
- * when comparing test cases.
282
+ * For fields with nested file references (like response_format.schema),
283
+ * use maybeLoadResponseFormatFromExternalFile instead.
215
284
  *
216
- * Runtime variables are identified by:
217
- * 1. Starting with underscore (_) - convention for internal/runtime vars
218
- * 2. Being in the explicit runtime var list (for legacy vars like sessionId)
285
+ * @param config - The configuration to process
286
+ * @param vars - Variables for template rendering
287
+ * @returns The processed configuration with variables rendered and files loaded
219
288
  */
220
- function isRuntimeVar(key) {
221
- return key.startsWith("_") || EXPLICIT_RUNTIME_VAR_KEYS.includes(key);
289
+ function maybeLoadFromExternalFileWithVars(config, vars) {
290
+ return maybeLoadFromExternalFile(require_render.renderVarsInObject(config, vars));
222
291
  }
223
292
  /**
224
- * Filters out runtime-only variables that are added during evaluation
225
- * but aren't part of the original test definition.
293
+ * Loads response_format configuration from an external file with variable rendering.
226
294
  *
227
- * This is used when comparing test cases to determine if a result
228
- * corresponds to a particular test, regardless of runtime state.
295
+ * This function handles the special case where response_format may contain:
296
+ * 1. A top-level file reference (file://format.json)
297
+ * 2. A nested schema reference for json_schema type (schema: file://schema.json)
229
298
  *
230
- * Runtime variables are identified by:
231
- * - Starting with underscore (e.g., _conversation, _metadata)
232
- * - Being in the explicit list (e.g., sessionId for backward compatibility)
299
+ * Both levels need variable rendering and file loading.
300
+ *
301
+ * @param responseFormat - The response_format configuration
302
+ * @param vars - Variables for template rendering
303
+ * @returns The processed response_format with all files loaded
233
304
  */
234
- function filterRuntimeVars(vars) {
235
- if (!vars || typeof vars !== "object" || Array.isArray(vars)) return vars;
236
- const filtered = {};
237
- for (const [key, value] of Object.entries(vars)) if (!isRuntimeVar(key)) filtered[key] = value;
238
- return filtered;
305
+ function maybeLoadResponseFormatFromExternalFile(responseFormat, vars) {
306
+ if (responseFormat === void 0 || responseFormat === null) return responseFormat;
307
+ const loaded = maybeLoadFromExternalFile(require_render.renderVarsInObject(responseFormat, vars));
308
+ if (!loaded || typeof loaded !== "object") return loaded;
309
+ if (loaded.type === "json_schema") {
310
+ const nestedSchema = loaded.schema || loaded.json_schema?.schema;
311
+ if (nestedSchema) {
312
+ const loadedSchema = maybeLoadFromExternalFile(require_render.renderVarsInObject(nestedSchema, vars));
313
+ if (loaded.schema !== void 0) return {
314
+ ...loaded,
315
+ schema: loadedSchema
316
+ };
317
+ else if (loaded.json_schema?.schema !== void 0) return {
318
+ ...loaded,
319
+ json_schema: {
320
+ ...loaded.json_schema,
321
+ schema: loadedSchema
322
+ }
323
+ };
324
+ }
325
+ }
326
+ return loaded;
239
327
  }
240
328
  /**
241
- * Extracts only runtime variables from a vars object.
242
- * This is the inverse of filterRuntimeVars.
329
+ * Renders variables in a tools object and loads from external file if applicable.
330
+ * This function combines renderVarsInObject and maybeLoadFromExternalFile into a single step
331
+ * specifically for handling tools configurations.
243
332
  *
244
- * Used to restore runtime state when re-running filtered tests.
333
+ * Supports loading from JSON, YAML, Python, and JavaScript files.
334
+ *
335
+ * @param tools - The tools configuration object or array to process.
336
+ * @param vars - Variables to use for rendering.
337
+ * @returns The processed tools configuration with variables rendered and content loaded from files if needed.
338
+ * @throws {Error} If the loaded tools are in an invalid format
245
339
  */
246
- function extractRuntimeVars(vars) {
247
- if (!vars || typeof vars !== "object" || Array.isArray(vars)) return;
248
- const extracted = {};
249
- for (const [key, value] of Object.entries(vars)) if (isRuntimeVar(key)) extracted[key] = value;
250
- return Object.keys(extracted).length > 0 ? extracted : void 0;
340
+ async function maybeLoadToolsFromExternalFile(tools, vars) {
341
+ const rendered = require_render.renderVarsInObject(tools, vars);
342
+ if (typeof rendered === "string" && rendered.startsWith("file://")) {
343
+ const { filePath, functionName } = parseFileUrl(rendered);
344
+ if (functionName && (filePath.endsWith(".py") || require_fileExtensions.isJavascriptFile(filePath))) {
345
+ const fileType = filePath.endsWith(".py") ? "Python" : "JavaScript";
346
+ require_logger.logger.debug(`[maybeLoadToolsFromExternalFile] Loading tools from ${fileType} file: ${filePath}:${functionName}`);
347
+ try {
348
+ let toolDefinitions;
349
+ if (filePath.endsWith(".py")) {
350
+ const absPath = require_esm.safeResolve(require_logger.state.basePath || process.cwd(), filePath);
351
+ require_logger.logger.debug(`[maybeLoadToolsFromExternalFile] Resolved Python path: ${absPath}`);
352
+ toolDefinitions = await require_pythonUtils.runPython(absPath, functionName, []);
353
+ } else {
354
+ const absPath = require_esm.safeResolve(require_logger.state.basePath || process.cwd(), filePath);
355
+ require_logger.logger.debug(`[maybeLoadToolsFromExternalFile] Resolved JavaScript path: ${absPath}`);
356
+ const module = await require_esm.importModule(absPath);
357
+ const fn = module[functionName] || module.default?.[functionName];
358
+ if (typeof fn !== "function") {
359
+ const availableExports = Object.keys(module).filter((k) => k !== "default");
360
+ const basePath = require_logger.state.basePath || process.cwd();
361
+ throw new Error(`Function "${functionName}" not found in ${filePath}. Available exports: ${availableExports.length > 0 ? availableExports.join(", ") : "(none)"}\nResolved from: ${basePath}`);
362
+ }
363
+ toolDefinitions = await Promise.resolve(fn());
364
+ }
365
+ 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}`);
366
+ require_logger.logger.debug(`[maybeLoadToolsFromExternalFile] Successfully loaded ${Array.isArray(toolDefinitions) ? toolDefinitions.length : "object"} tools`);
367
+ return toolDefinitions;
368
+ } catch (err) {
369
+ const errorMessage = err instanceof Error ? err.message : String(err);
370
+ const basePath = require_logger.state.basePath || process.cwd();
371
+ 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}`);
372
+ }
373
+ }
374
+ if (filePath.endsWith(".py") || require_fileExtensions.isJavascriptFile(filePath)) {
375
+ const ext = filePath.endsWith(".py") ? "Python" : "JavaScript";
376
+ const basePath = require_logger.state.basePath || process.cwd();
377
+ 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}`);
378
+ }
379
+ }
380
+ if (Array.isArray(rendered)) {
381
+ const results = await Promise.all(rendered.map((item) => maybeLoadToolsFromExternalFile(item, vars)));
382
+ if (results.every((r) => Array.isArray(r))) return results.flat();
383
+ return results;
384
+ }
385
+ if (typeof rendered !== "string") return rendered;
386
+ const loaded = maybeLoadFromExternalFile(rendered);
387
+ if (loaded !== void 0 && loaded !== null && typeof loaded === "string") {
388
+ 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.`);
389
+ 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");
390
+ 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.");
391
+ }
392
+ return loaded;
251
393
  }
252
- function varsMatch(vars1, vars2) {
253
- return (0, fast_deep_equal.default)(vars1, vars2);
394
+ //#endregion
395
+ //#region src/util/providerRef.ts
396
+ const PROVIDER_OPTION_KEYS = new Set([
397
+ "id",
398
+ "label",
399
+ "config",
400
+ "prompts",
401
+ "transform",
402
+ "delay",
403
+ "env",
404
+ "inputs"
405
+ ]);
406
+ /** Returns true if the value is a non-empty string suitable as a provider identifier. */
407
+ function isValidProviderId(id) {
408
+ return typeof id === "string" && id !== "";
409
+ }
410
+ function getProviderLabel(provider) {
411
+ if ((typeof provider === "object" || typeof provider === "function") && provider !== null && "label" in provider && typeof provider.label === "string") return provider.label;
254
412
  }
255
413
  /**
256
- * Generate a unique key for a test case for deduplication purposes.
257
- * Excludes runtime variables and includes strategyId to distinguish tests
258
- * with the same prompt but different strategies.
259
- *
260
- * @param testCase - The test case to generate a key for
261
- * @returns A JSON string that uniquely identifies the test case
414
+ * Resolves relative file paths in provider IDs to absolute paths for consistent matching.
415
+ * Handles file://, exec:, python:, golang: prefixes and bare .js/.ts/.mjs paths.
262
416
  */
263
- function getTestCaseDeduplicationKey(testCase) {
264
- const filteredVars = filterRuntimeVars(testCase.vars);
265
- const strategyId = testCase.metadata?.strategyId || "none";
266
- return JSON.stringify({
267
- vars: filteredVars,
268
- strategyId
269
- });
270
- }
271
- /**
272
- * Deduplicates an array of test cases based on their vars and strategyId.
273
- * Tests with the same vars but different strategies are considered different.
274
- * Runtime variables (like _conversation, sessionId) are filtered out before comparison.
275
- *
276
- * @param tests - Array of test cases to deduplicate
277
- * @returns Deduplicated array of test cases
278
- */
279
- function deduplicateTestCases(tests) {
280
- const seen = /* @__PURE__ */ new Set();
281
- return tests.filter((test) => {
282
- const key = getTestCaseDeduplicationKey(test);
283
- if (seen.has(key)) return false;
284
- seen.add(key);
285
- return true;
286
- });
287
- }
288
- function resultIsForTestCase(result, testCase) {
289
- const testProviderId = testCase.provider ? providerToIdentifier(testCase.provider) : void 0;
290
- const resultProviderId = providerToIdentifier(result.provider);
291
- const providersMatch = !testProviderId || !resultProviderId || testProviderId === resultProviderId;
292
- const resultVars = filterRuntimeVars(result.vars);
293
- const testVars = filterRuntimeVars(testCase.vars);
294
- const doVarsMatch = varsMatch(testVars, resultVars);
295
- const isMatch = doVarsMatch && providersMatch;
296
- if (!isMatch) {
297
- const varKeys = testVars ? Object.keys(testVars).join(", ") : "none";
298
- require_logger.logger.debug(`[resultIsForTestCase] No match: vars=${doVarsMatch}, providers=${providersMatch}`, {
299
- testProvider: testProviderId || "none",
300
- resultProvider: resultProviderId || "none",
301
- testVarKeys: varKeys
302
- });
417
+ function canonicalizeProviderId(id) {
418
+ if (id.startsWith("file://")) {
419
+ const filePath = id.slice(7);
420
+ return path.default.isAbsolute(filePath) ? id : `file://${path.default.resolve(filePath)}`;
303
421
  }
304
- return isMatch;
422
+ for (const prefix of [
423
+ "exec:",
424
+ "python:",
425
+ "golang:"
426
+ ]) if (id.startsWith(prefix)) {
427
+ const filePath = id.slice(prefix.length);
428
+ if (filePath.includes("/") || filePath.includes("\\")) return `${prefix}${path.default.resolve(filePath)}`;
429
+ return id;
430
+ }
431
+ if ((id.endsWith(".js") || id.endsWith(".ts") || id.endsWith(".mjs")) && (id.includes("/") || id.includes("\\"))) return `file://${path.default.resolve(id)}`;
432
+ return id;
305
433
  }
306
- //#endregion
307
- //#region src/util/env.ts
308
434
  /**
309
- * Load environment variables from .env file(s).
310
- * @param envPath - Single path, array of paths, or undefined for default .env loading.
311
- * When paths are explicitly specified, all files must exist or an error is thrown.
312
- * When multiple files are provided, later files override values from earlier files.
435
+ * Returns true for provider refs that should be expanded from YAML/JSON config files.
313
436
  */
314
- function setupEnv(envPath) {
315
- if (envPath) {
316
- const paths = (Array.isArray(envPath) ? envPath : [envPath]).flatMap((p) => p.includes(",") ? p.split(",").map((s) => s.trim()) : p.trim()).filter((p) => p.length > 0);
317
- if (paths.length === 0) {
318
- dotenv.default.config({ quiet: true });
319
- return;
320
- }
321
- for (const p of paths) if (!fs.existsSync(p)) throw new Error(`Environment file not found: ${p}`);
322
- if (paths.length === 1) require_logger.logger.info(`Loading environment variables from ${paths[0]}`);
323
- else require_logger.logger.info(`Loading environment variables from: ${paths.join(", ")}`);
324
- const pathArg = paths.length === 1 ? paths[0] : paths;
325
- dotenv.default.config({
326
- path: pathArg,
327
- override: true,
328
- quiet: true
329
- });
330
- } else dotenv.default.config({ quiet: true });
437
+ function isProviderConfigFileReference(providerPath) {
438
+ return providerPath.startsWith("file://") && (providerPath.endsWith(".yaml") || providerPath.endsWith(".yml") || providerPath.endsWith(".json"));
331
439
  }
332
- //#endregion
333
- //#region src/util/functions/loadFunction.ts
334
- const functionCache = {};
335
440
  /**
336
- * Loads a function from a JavaScript or Python file
337
- * @param options Options for loading the function
338
- * @returns The loaded function
441
+ * Reads a provider config file and normalizes single-provider and multi-provider files.
442
+ * Returns a `wasArray` flag so callers can detect multi-provider files that require
443
+ * `loadApiProviders` instead of `loadApiProvider`.
339
444
  */
340
- async function loadFunction({ filePath, functionName, defaultFunctionName = "func", basePath = require_logger.state.basePath, useCache = true }) {
341
- const cacheKey = `${filePath}${functionName ? `:${functionName}` : ""}`;
342
- if (useCache && functionCache[cacheKey]) return functionCache[cacheKey];
343
- const resolvedPath = basePath ? path.default.resolve(basePath, filePath) : filePath;
344
- 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`);
445
+ function readProviderConfigFile(providerPath, basePath) {
446
+ const relativePath = providerPath.slice(7);
447
+ const resolvedPath = path.default.isAbsolute(relativePath) ? relativePath : path.default.join(basePath || process.cwd(), relativePath);
448
+ let rawContent;
345
449
  try {
346
- let func;
347
- if (require_fileExtensions.isJavascriptFile(resolvedPath)) {
348
- const module = await require_esm.importModule(resolvedPath, functionName);
349
- let moduleFunc;
350
- if (functionName) moduleFunc = module;
351
- else moduleFunc = typeof module === "function" ? module : module?.default?.default || module?.default || module?.[defaultFunctionName] || module;
352
- 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}")`);
353
- func = moduleFunc;
354
- } else {
355
- const result = (...args) => require_pythonUtils.runPython(resolvedPath, functionName || defaultFunctionName, args);
356
- func = result;
357
- }
358
- if (useCache) functionCache[cacheKey] = func;
359
- return func;
450
+ rawContent = js_yaml.default.load(fs.default.readFileSync(resolvedPath, "utf8"));
360
451
  } catch (err) {
361
- require_logger.logger.error(`Failed to load function: ${err.message}`);
362
- throw err;
452
+ throw new Error(`Failed to load provider config ${relativePath}: ${err instanceof Error ? err.message : err}`);
363
453
  }
364
- }
365
- /**
366
- * Extracts the file path and function name from a file:// URL
367
- * @param fileUrl The file:// URL (e.g., "file://path/to/file.js:functionName")
368
- * @returns The file path and optional function name
369
- */
370
- function parseFileUrl(fileUrl) {
371
- if (!fileUrl.startsWith("file://")) throw new Error("URL must start with file://");
372
- const urlWithoutProtocol = fileUrl.slice(7);
373
- const lastColonIndex = urlWithoutProtocol.lastIndexOf(":");
374
- if (lastColonIndex > 1) return {
375
- filePath: urlWithoutProtocol.slice(0, lastColonIndex),
376
- functionName: urlWithoutProtocol.slice(lastColonIndex + 1)
454
+ const fileContent = maybeLoadConfigFromExternalFile(rawContent);
455
+ require_invariant.invariant(fileContent, `Provider config ${relativePath} is undefined`);
456
+ return {
457
+ configs: [fileContent].flat(),
458
+ relativePath,
459
+ wasArray: Array.isArray(fileContent)
377
460
  };
378
- return { filePath: urlWithoutProtocol };
379
461
  }
380
- //#endregion
381
- //#region src/util/templates.ts
382
462
  /**
383
- * Get a Nunjucks engine instance with optional filters and configuration.
384
- * @param filters - Optional map of custom Nunjucks filters.
385
- * @param throwOnUndefined - Whether to throw an error on undefined variables.
386
- * @param isGrader - Whether this engine is being used in a grader context.
387
- * Nunjucks is always enabled in grader mode.
388
- * @returns A configured Nunjucks environment.
463
+ * Loads provider config objects from a file-backed provider reference.
389
464
  */
390
- function getNunjucksEngine(filters, throwOnUndefined = false, isGrader = false) {
391
- if (!isGrader && require_logger.getEnvBool("PROMPTFOO_DISABLE_TEMPLATING")) return { renderString: (template) => template };
392
- const env = nunjucks.default.configure({
393
- autoescape: false,
394
- throwOnUndefined
395
- });
396
- const envGlobals = {
397
- ...require_logger.getEnvBool("PROMPTFOO_DISABLE_TEMPLATE_ENV_VARS", require_logger.getEnvBool("PROMPTFOO_SELF_HOSTED", false)) ? {} : process.env,
398
- ...require_logger.state.config?.env
399
- };
400
- env.addGlobal("env", envGlobals);
401
- env.addFilter("load", function(str) {
402
- return JSON.parse(str);
403
- });
404
- if (filters) for (const [name, filter] of Object.entries(filters)) env.addFilter(name, filter);
405
- return env;
465
+ function loadProviderConfigsFromFile(providerPath, basePath) {
466
+ return readProviderConfigFile(providerPath, basePath).configs;
406
467
  }
407
468
  /**
408
- * Parse Nunjucks template to extract variables.
409
- * @param template - The Nunjucks template string.
410
- * @returns An array of variables used in the template.
469
+ * Pure, synchronous classifier that converts every supported provider reference shape
470
+ * into a discriminated descriptor. Does not read files or instantiate providers.
411
471
  */
412
- function extractVariablesFromTemplate(template) {
413
- const variableSet = /* @__PURE__ */ new Set();
414
- const regex = /\{\{[\s]*([^{}\s|]+)[\s]*(?:\|[^}]+)?\}\}|\{%[\s]*(?:if|for)[\s]+([^{}\s]+)[\s]*.*?%\}/g;
415
- template = template.replace(/\{#[\s\S]*?#\}/g, "");
416
- let match;
417
- while ((match = regex.exec(template)) !== null) {
418
- const variable = match[1] || match[2];
419
- if (variable) variableSet.add(variable);
420
- }
421
- const forLoopRegex = /\{%[\s]*for[\s]+(\w+)[\s]+in[\s]+(\w+)[\s]*%\}/g;
422
- while ((match = forLoopRegex.exec(template)) !== null) {
423
- variableSet.delete(match[1]);
424
- variableSet.add(match[2]);
425
- }
426
- return Array.from(variableSet);
427
- }
428
- /**
429
- * Extract variables from multiple Nunjucks templates.
430
- * @param templates - An array of Nunjucks template strings.
431
- * @returns An array of variables used in the templates.
432
- */
433
- function extractVariablesFromTemplates(templates) {
434
- const variableSet = /* @__PURE__ */ new Set();
435
- for (const template of templates) extractVariablesFromTemplate(template).forEach((variable) => variableSet.add(variable));
436
- return Array.from(variableSet);
437
- }
438
- //#endregion
439
- //#region src/util/render.ts
440
- /**
441
- * Renders ONLY environment variable templates in an object, leaving all other templates untouched.
442
- * This allows env vars to be resolved at provider load time while preserving runtime var templates.
443
- *
444
- * Supports full Nunjucks syntax for env vars including filters and expressions:
445
- * - {{ env.VAR_NAME }}
446
- * - {{ env['VAR-NAME'] }}
447
- * - {{ env["VAR-NAME"] }}
448
- * - {{ env.VAR | default('fallback') }}
449
- * - {{ env.VAR | upper }}
450
- *
451
- * Preserves non-env templates for runtime rendering:
452
- * - {{ vars.x }} - preserved as literal
453
- * - {{ prompt }} - preserved as literal
454
- *
455
- * Implementation: Uses regex to find env templates, delegates to Nunjucks for rendering.
456
- * This ensures full Nunjucks feature support while preserving non-env templates.
457
- *
458
- * @param obj - The object to process
459
- * @param envOverrides - Optional env vars to merge with (or replace) the base env
460
- * @param replaceBase - If true, envOverrides replaces the base env entirely instead of merging
461
- * @returns The object with only env templates rendered
462
- */
463
- function renderEnvOnlyInObject(obj, envOverrides, replaceBase) {
464
- if (require_logger.getEnvBool("PROMPTFOO_DISABLE_TEMPLATING")) return obj;
465
- if (typeof obj === "string") {
466
- const nunjucks = getNunjucksEngine();
467
- const baseEnvGlobals = nunjucks.getGlobal("env");
468
- const envGlobals = replaceBase ? envOverrides ?? {} : envOverrides ? {
469
- ...baseEnvGlobals,
470
- ...envOverrides
471
- } : baseEnvGlobals;
472
- return obj.replace(/\{\{(?:[^}]|\}(?!\}))*\}\}/g, (match) => {
473
- if (!match.match(/\benv\.|env\[/)) return match;
474
- const varMatch = match.match(/env\.(\w+)|env\[['"]([^'"]+)['"]\]/);
475
- const varName = varMatch?.[1] || varMatch?.[2];
476
- if (match.includes("|") || varName && varName in envGlobals && envGlobals[varName] !== void 0) try {
477
- return nunjucks.renderString(match, { env: envGlobals });
478
- } catch (error) {
479
- require_logger.logger.debug(`Failed to render env template "${match}": ${error instanceof Error ? error.message : String(error)}`);
480
- return match;
481
- }
482
- return match;
483
- });
472
+ function normalizeProviderRef(provider, options = {}) {
473
+ const { index } = options;
474
+ if (typeof provider === "string") {
475
+ if (!isValidProviderId(provider)) return {
476
+ kind: "unknown",
477
+ id: index === void 0 ? "unknown" : `unknown-${index}`
478
+ };
479
+ if (isProviderConfigFileReference(provider)) return {
480
+ kind: "file",
481
+ id: provider,
482
+ loadProviderPath: provider
483
+ };
484
+ return {
485
+ kind: "named",
486
+ id: provider,
487
+ loadProviderPath: provider
488
+ };
484
489
  }
485
- if (Array.isArray(obj)) return obj.map((item) => renderEnvOnlyInObject(item, envOverrides, replaceBase));
486
- if (typeof obj === "object" && obj !== null) {
487
- const result = {};
488
- for (const key in obj) result[key] = renderEnvOnlyInObject(obj[key], envOverrides, replaceBase);
489
- return result;
490
+ if (typeof provider === "function") {
491
+ const label = getProviderLabel(provider);
492
+ return {
493
+ kind: "function",
494
+ id: label ?? (index === void 0 ? "custom-function" : `custom-function-${index}`),
495
+ label
496
+ };
490
497
  }
491
- return obj;
492
- }
493
- function renderVarsInObject(obj, vars) {
494
- if (!vars || require_logger.getEnvBool("PROMPTFOO_DISABLE_TEMPLATING")) return obj;
495
- if (typeof obj === "string") return getNunjucksEngine().renderString(obj, vars);
496
- if (Array.isArray(obj)) return obj.map((item) => renderVarsInObject(item, vars));
497
- if (typeof obj === "object" && obj !== null) {
498
- const result = {};
499
- for (const key in obj) result[key] = renderVarsInObject(obj[key], vars);
500
- return result;
501
- } else if (typeof obj === "function") return renderVarsInObject(obj({ vars }));
502
- return obj;
498
+ if (typeof provider === "object" && provider !== null && !Array.isArray(provider)) {
499
+ const providerId = provider.id;
500
+ const label = getProviderLabel(provider);
501
+ if (isValidProviderId(providerId)) return {
502
+ kind: "options",
503
+ id: providerId,
504
+ label,
505
+ loadOptions: provider,
506
+ loadProviderPath: providerId
507
+ };
508
+ const keys = Object.keys(provider);
509
+ if (keys.length === 1 && !PROVIDER_OPTION_KEYS.has(keys[0])) {
510
+ const originalId = keys[0];
511
+ const providerObject = provider[originalId];
512
+ if (typeof providerObject === "object" && providerObject !== null && !Array.isArray(providerObject) && isValidProviderId(originalId)) {
513
+ const id = isValidProviderId(providerObject.id) ? providerObject.id : originalId;
514
+ return {
515
+ kind: "map",
516
+ id,
517
+ label: getProviderLabel(providerObject),
518
+ loadOptions: {
519
+ ...providerObject,
520
+ id
521
+ },
522
+ loadProviderPath: originalId
523
+ };
524
+ }
525
+ }
526
+ if (isValidProviderId(label)) return {
527
+ kind: "unknown",
528
+ id: label,
529
+ label
530
+ };
531
+ }
532
+ return {
533
+ kind: "unknown",
534
+ id: index === void 0 ? "unknown" : `unknown-${index}`
535
+ };
503
536
  }
504
537
  //#endregion
505
- //#region src/util/file.ts
538
+ //#region src/util/provider.ts
539
+ function providerToIdentifier(provider) {
540
+ if (!provider) return;
541
+ if (typeof provider === "string") return canonicalizeProviderId(provider);
542
+ const { label } = normalizeProviderRef(provider);
543
+ if (label) return label;
544
+ if (require_types.isApiProvider(provider)) return canonicalizeProviderId(provider.id());
545
+ if (require_types.isProviderOptions(provider)) {
546
+ if (provider.id) return canonicalizeProviderId(provider.id);
547
+ return;
548
+ }
549
+ if (typeof provider === "object" && "id" in provider && typeof provider.id === "string") return canonicalizeProviderId(provider.id);
550
+ }
506
551
  /**
507
- * Simple Nunjucks engine specifically for file paths
508
- * This function is separate from the main getNunjucksEngine to avoid circular dependencies
552
+ * Gets a descriptive identifier string for a provider, showing both label and ID when both exist.
553
+ * Useful for error messages to help users debug provider reference issues.
509
554
  */
510
- function getNunjucksEngineForFilePath() {
511
- const env = nunjucks.default.configure({ autoescape: false });
512
- env.addGlobal("env", {
513
- ...process.env,
514
- ...require_logger.state.config?.env
515
- });
516
- return env;
555
+ function getProviderDescription(provider) {
556
+ const label = provider.label;
557
+ const id = provider.id();
558
+ if (label && label !== id) return `${label} (${id})`;
559
+ return id;
517
560
  }
518
561
  /**
519
- * Loads content from an external file if the input is a file path, otherwise
520
- * returns the input as-is. Supports Nunjucks templating for file paths.
521
- *
522
- * @param filePath - The input to process. Can be a file path string starting with "file://",
523
- * an array of file paths, or any other type of data.
524
- * @param context - Optional context to control file loading behavior. 'assertion' context
525
- * preserves Python/JS file references instead of loading their content.
526
- * @returns The loaded content if the input was a file path, otherwise the original input.
527
- * For JSON and YAML files, the content is parsed into an object.
528
- * For other file types, the raw file content is returned as a string.
529
- *
530
- * @throws {Error} If the specified file does not exist.
562
+ * Checks if a provider reference matches a given provider.
563
+ * Supports exact matching and wildcard patterns.
531
564
  */
532
- function maybeLoadFromExternalFile(filePath, context) {
533
- if (Array.isArray(filePath)) return filePath.map((path$2) => {
534
- return maybeLoadFromExternalFile(path$2, context);
535
- });
536
- if (typeof filePath !== "string") return filePath;
537
- if (!filePath.startsWith("file://")) return filePath;
538
- const renderedFilePath = getNunjucksEngineForFilePath().renderString(filePath, {});
539
- const { filePath: cleanPath, functionName } = parseFileUrl(renderedFilePath);
540
- if (context === "assertion" && (cleanPath.endsWith(".py") || require_fileExtensions.isJavascriptFile(cleanPath))) {
541
- require_logger.logger.debug(`Preserving Python/JS file reference in assertion context: ${renderedFilePath}`);
542
- return renderedFilePath;
543
- }
544
- if (context === "vars") {
545
- require_logger.logger.debug(`Preserving file reference in vars context: ${renderedFilePath}`);
546
- return renderedFilePath;
547
- }
548
- if (functionName && (cleanPath.endsWith(".py") || require_fileExtensions.isJavascriptFile(cleanPath))) return renderedFilePath;
549
- const pathToUse = functionName && !(cleanPath.endsWith(".py") || require_fileExtensions.isJavascriptFile(cleanPath)) ? renderedFilePath.slice(7) : cleanPath;
550
- const resolvedPath = path.resolve(require_logger.state.basePath || "", pathToUse);
551
- if ((0, glob.hasMagic)(pathToUse)) {
552
- const matchedFiles = (0, glob.globSync)(resolvedPath, { windowsPathsNoEscape: true });
553
- if (matchedFiles.length === 0) throw new Error(`No files found matching pattern: ${resolvedPath}`);
554
- const allContents = [];
555
- for (const matchedFile of matchedFiles) {
556
- let contents;
557
- try {
558
- contents = fs.readFileSync(matchedFile, "utf8");
559
- } catch (error) {
560
- if (error.code === "ENOENT") {
561
- require_logger.logger.debug(`File disappeared during glob expansion: ${matchedFile}`);
562
- continue;
563
- }
564
- throw error;
565
- }
566
- if (matchedFile.endsWith(".json")) {
567
- const parsed = JSON.parse(contents);
568
- if (Array.isArray(parsed)) allContents.push(...parsed);
569
- else allContents.push(parsed);
570
- } else if (matchedFile.endsWith(".yaml") || matchedFile.endsWith(".yml")) {
571
- const parsed = js_yaml.default.load(contents);
572
- if (parsed === null || parsed === void 0) continue;
573
- if (Array.isArray(parsed)) allContents.push(...parsed);
574
- else allContents.push(parsed);
575
- } else if (matchedFile.endsWith(".csv")) {
576
- const records = (0, csv_parse_sync.parse)(contents, { columns: true });
577
- if (records.length > 0 && Object.keys(records[0]).length === 1) allContents.push(...records.map((record) => Object.values(record)[0]));
578
- else allContents.push(...records);
579
- } else allContents.push(contents);
580
- }
581
- return allContents;
582
- }
583
- const finalPath = resolvedPath;
584
- let contents;
585
- try {
586
- contents = fs.readFileSync(finalPath, "utf8");
587
- } catch (error) {
588
- if (error.code === "ENOENT") throw new Error(`File does not exist: ${finalPath}`);
589
- throw new Error(`Failed to read file ${finalPath}: ${error}`);
590
- }
591
- if (finalPath.endsWith(".json")) try {
592
- return JSON.parse(contents);
593
- } catch (error) {
594
- throw new Error(`Failed to parse JSON file ${finalPath}: ${error}`);
595
- }
596
- if (finalPath.endsWith(".yaml") || finalPath.endsWith(".yml")) try {
597
- return js_yaml.default.load(contents);
598
- } catch (error) {
599
- throw new Error(`Failed to parse YAML file ${finalPath}: ${error}`);
600
- }
601
- if (finalPath.endsWith(".csv")) {
602
- const records = (0, csv_parse_sync.parse)(contents, { columns: true });
603
- if (records.length > 0 && Object.keys(records[0]).length === 1) return records.map((record) => Object.values(record)[0]);
604
- return records;
565
+ function doesProviderRefMatch(ref, provider) {
566
+ const label = provider.label;
567
+ const id = provider.id();
568
+ const canonicalRef = canonicalizeProviderId(ref);
569
+ const canonicalId = canonicalizeProviderId(id);
570
+ if (label && label === ref) return true;
571
+ if (id === ref || canonicalId === canonicalRef) return true;
572
+ if (ref.endsWith("*")) {
573
+ const prefix = ref.slice(0, -1);
574
+ if (label?.startsWith(prefix) || id.startsWith(prefix) || canonicalId.startsWith(prefix)) return true;
605
575
  }
606
- return contents;
576
+ if (label?.startsWith(`${ref}:`) || id.startsWith(`${ref}:`) || canonicalId.startsWith(`${ref}:`)) return true;
577
+ return false;
607
578
  }
608
579
  /**
609
- * Resolves a relative file path with respect to a base path, handling cloud configuration appropriately.
610
- * When using a cloud configuration, the current working directory is always used instead of the context's base path.
611
- *
612
- * @param filePath - The relative or absolute file path to resolve.
613
- * @param isCloudConfig - Whether this is a cloud configuration.
614
- * @returns The resolved absolute file path.
580
+ * Checks if a provider is allowed based on a list of allowed references.
615
581
  */
616
- function getResolvedRelativePath(filePath, isCloudConfig) {
617
- if (path.isAbsolute(filePath) || !isCloudConfig) return filePath;
618
- return path.join(process.cwd(), filePath);
582
+ function isProviderAllowed(provider, allowedProviders) {
583
+ if (!Array.isArray(allowedProviders)) return true;
584
+ if (allowedProviders.length === 0) return false;
585
+ return allowedProviders.some((ref) => doesProviderRefMatch(ref, provider));
619
586
  }
620
587
  /**
621
- * Recursively loads external file references from a configuration object.
622
- *
623
- * @param config - The configuration object to process
624
- * @param context - Optional context to control file loading behavior
625
- * @returns The configuration with external file references resolved
588
+ * Detects if a provider uses OpenAI models.
589
+ * This includes direct OpenAI providers and Azure OpenAI.
626
590
  */
627
- function maybeLoadConfigFromExternalFile(config, context) {
628
- if (Array.isArray(config)) return config.map((item) => maybeLoadConfigFromExternalFile(item, context));
629
- if (config && typeof config === "object" && config !== null) {
630
- const result = {};
631
- for (const key of Object.keys(config)) {
632
- const childContext = key === "value" && typeof config === "object" && config && "type" in config && typeof config.type === "string" && (config.type === "python" || config.type === "javascript") ? "assertion" : key === "vars" ? "vars" : context;
633
- result[key] = maybeLoadConfigFromExternalFile(config[key], childContext);
634
- }
635
- return result;
591
+ function isOpenAiProvider(providerId) {
592
+ const lowerProviderId = providerId.toLowerCase();
593
+ if (lowerProviderId.startsWith("openai:")) return true;
594
+ if (lowerProviderId.startsWith("azureopenai:")) return true;
595
+ if (lowerProviderId.startsWith("azure:")) {
596
+ if ([
597
+ "gpt",
598
+ "openai",
599
+ "davinci",
600
+ "curie",
601
+ "babbage",
602
+ "ada",
603
+ "text-embedding",
604
+ "whisper",
605
+ "dall-e",
606
+ "tts"
607
+ ].some((indicator) => lowerProviderId.includes(indicator))) return true;
636
608
  }
637
- return maybeLoadFromExternalFile(config, context);
609
+ return false;
638
610
  }
639
611
  /**
640
- * Parses a file path or glob pattern to extract function names and file extensions.
641
- * Function names can be specified in the filename like this:
642
- * prompt.py:myFunction or prompts.js:myFunction.
643
- * @param basePath - The base path for file resolution.
644
- * @param promptPath - The path or glob pattern.
645
- * @returns Parsed details including function name, file extension, and directory status.
612
+ * Detects if a provider uses Anthropic/Claude models.
613
+ * This includes direct Anthropic providers, Bedrock with Claude, and Vertex with Claude.
646
614
  */
647
- function parsePathOrGlob(basePath, promptPath) {
648
- if (promptPath.startsWith("file://")) promptPath = promptPath.slice(7);
649
- const filePath = path.resolve(basePath, promptPath);
650
- let filename = path.relative(basePath, filePath);
651
- let functionName;
652
- if (filename.includes(":")) {
653
- const lastColonIndex = filename.lastIndexOf(":");
654
- if (lastColonIndex > 1) {
655
- const pathWithoutFunction = filename.slice(0, lastColonIndex);
656
- if (require_fileExtensions.isJavascriptFile(pathWithoutFunction) || pathWithoutFunction.endsWith(".py") || pathWithoutFunction.endsWith(".go") || pathWithoutFunction.endsWith(".rb")) {
657
- functionName = filename.slice(lastColonIndex + 1);
658
- filename = pathWithoutFunction;
659
- }
660
- }
615
+ function isAnthropicProvider(providerId) {
616
+ const lowerProviderId = providerId.toLowerCase();
617
+ if (lowerProviderId.startsWith("anthropic:")) return true;
618
+ if (lowerProviderId.startsWith("bedrock:")) {
619
+ if (lowerProviderId.includes("claude") || lowerProviderId.includes("anthropic")) return true;
661
620
  }
662
- let stats;
663
- try {
664
- stats = fs.statSync(path.join(basePath, filename));
665
- } catch (err) {
666
- if (require_logger.getEnvBool("PROMPTFOO_STRICT_FILES")) throw err;
621
+ if (lowerProviderId.startsWith("vertex:")) {
622
+ if (lowerProviderId.includes("claude")) return true;
667
623
  }
668
- const normalizedFilePath = filePath.replace(/\\/g, "/");
669
- const isPathPattern = stats?.isDirectory() || (0, glob.hasMagic)(promptPath) || (0, glob.hasMagic)(normalizedFilePath);
670
- const safeFilename = path.relative(basePath, require_esm.safeResolve(basePath, filename));
671
- return {
672
- extension: isPathPattern ? void 0 : path.parse(safeFilename).ext,
673
- filePath: path.join(basePath, safeFilename),
674
- functionName,
675
- isPathPattern
676
- };
624
+ return false;
677
625
  }
678
- function readOutput(outputPath) {
679
- const ext = path.parse(outputPath).ext.slice(1);
680
- switch (ext) {
681
- case "json": return JSON.parse(fs.readFileSync(outputPath, "utf-8"));
682
- default: throw new Error(`Unsupported output file format: ${ext} currently only supports json`);
626
+ const KNOWN_ENV_VARS = {
627
+ openai: "OPENAI_API_KEY",
628
+ anthropic: "ANTHROPIC_API_KEY",
629
+ google: "GOOGLE_API_KEY",
630
+ mistral: "MISTRAL_API_KEY",
631
+ cohere: "COHERE_API_KEY",
632
+ replicate: "REPLICATE_API_TOKEN",
633
+ voyage: "VOYAGE_API_KEY",
634
+ ai21: "AI21_API_KEY",
635
+ xai: "XAI_API_KEY",
636
+ groq: "GROQ_API_KEY",
637
+ deepseek: "DEEPSEEK_API_KEY",
638
+ perplexity: "PERPLEXITY_API_KEY",
639
+ hyperbolic: "HYPERBOLIC_API_KEY",
640
+ cerebras: "CEREBRAS_API_KEY",
641
+ togetherai: "TOGETHER_API_KEY",
642
+ fal: "FAL_KEY",
643
+ huggingface: "HF_TOKEN",
644
+ "cloudflare-ai": "CLOUDFLARE_API_KEY"
645
+ };
646
+ function getDefaultEnvVar(providerId) {
647
+ const prefix = providerId.split(":")[0];
648
+ return KNOWN_ENV_VARS[prefix] || `${prefix.toUpperCase()}_API_KEY`;
649
+ }
650
+ /**
651
+ * Pre-checks providers for missing API keys before evaluation starts.
652
+ * Assumes getApiKey() is side-effect free (no network calls or token refresh).
653
+ */
654
+ function checkProviderApiKeys(providers) {
655
+ const missingApiKeys = /* @__PURE__ */ new Map();
656
+ for (const provider of providers) {
657
+ const p = provider;
658
+ if (typeof p.getApiKey !== "function") continue;
659
+ if (provider.id().startsWith("azure:")) continue;
660
+ const requiresKey = typeof p.requiresApiKey === "function" ? p.requiresApiKey() : p.config?.apiKeyRequired !== false;
661
+ let apiKey;
662
+ try {
663
+ apiKey = p.getApiKey();
664
+ } catch {
665
+ apiKey = void 0;
666
+ }
667
+ if (requiresKey && !apiKey) {
668
+ const envVar = p.config?.apiKeyEnvar || getDefaultEnvVar(provider.id());
669
+ if (!missingApiKeys.has(envVar)) missingApiKeys.set(envVar, []);
670
+ missingApiKeys.get(envVar).push(provider.id());
671
+ }
683
672
  }
673
+ return missingApiKeys;
684
674
  }
685
675
  /**
686
- * Load custom Nunjucks filters from external files.
687
- * Note: If a glob pattern matches multiple files, only the last file's export is used.
688
- * Each filter name should typically resolve to a single file.
676
+ * Detects if a provider uses Google models.
677
+ * This includes direct Google/Vertex providers with Gemini and other Google models.
678
+ * Note: Vertex with Claude models is NOT counted as Google (it's Anthropic).
689
679
  */
690
- async function readFilters(filters, basePath = "") {
691
- const ret = {};
692
- for (const [name, filterPath] of Object.entries(filters)) {
693
- const filePaths = (0, glob.globSync)(path.join(basePath, filterPath), { windowsPathsNoEscape: true });
694
- for (const filePath of filePaths) ret[name] = await require_esm.importModule(path.resolve(filePath));
680
+ function isGoogleProvider(providerId) {
681
+ const lowerProviderId = providerId.toLowerCase();
682
+ if (lowerProviderId.startsWith("google:")) return true;
683
+ if (lowerProviderId.startsWith("vertex:")) {
684
+ if (!lowerProviderId.includes("claude")) return true;
695
685
  }
696
- return ret;
686
+ return false;
697
687
  }
688
+ //#endregion
689
+ //#region src/util/comparison.ts
698
690
  /**
699
- * Loads configuration from an external file with variable rendering.
700
- * This is a convenience wrapper that combines renderVarsInObject and maybeLoadFromExternalFile.
691
+ * Explicit runtime variable names that don't follow the underscore convention.
692
+ * These are added during evaluation but aren't part of the original test definition.
701
693
  *
702
- * Use this for simple config fields that:
703
- * - Need variable rendering ({{ vars.x }}, {{ env.X }})
704
- * - May reference external files (file://path.json)
705
- * - Don't have nested file references that need loading
694
+ * - sessionId: Added by multi-turn strategy providers (GOAT, Crescendo)
706
695
  *
707
- * For fields with nested file references (like response_format.schema),
708
- * use maybeLoadResponseFormatFromExternalFile instead.
696
+ * Note: Variables starting with underscore (e.g., _conversation) are automatically
697
+ * treated as runtime variables and filtered out.
698
+ */
699
+ const EXPLICIT_RUNTIME_VAR_KEYS = ["sessionId"];
700
+ /**
701
+ * Checks if a variable key is a runtime-only variable that should be filtered
702
+ * when comparing test cases.
709
703
  *
710
- * @param config - The configuration to process
711
- * @param vars - Variables for template rendering
712
- * @returns The processed configuration with variables rendered and files loaded
704
+ * Runtime variables are identified by:
705
+ * 1. Starting with underscore (_) - convention for internal/runtime vars
706
+ * 2. Being in the explicit runtime var list (for legacy vars like sessionId)
713
707
  */
714
- function maybeLoadFromExternalFileWithVars(config, vars) {
715
- return maybeLoadFromExternalFile(renderVarsInObject(config, vars));
708
+ function isRuntimeVar(key) {
709
+ return key.startsWith("_") || EXPLICIT_RUNTIME_VAR_KEYS.includes(key);
716
710
  }
717
711
  /**
718
- * Loads response_format configuration from an external file with variable rendering.
712
+ * Filters out runtime-only variables that are added during evaluation
713
+ * but aren't part of the original test definition.
719
714
  *
720
- * This function handles the special case where response_format may contain:
721
- * 1. A top-level file reference (file://format.json)
722
- * 2. A nested schema reference for json_schema type (schema: file://schema.json)
715
+ * This is used when comparing test cases to determine if a result
716
+ * corresponds to a particular test, regardless of runtime state.
723
717
  *
724
- * Both levels need variable rendering and file loading.
718
+ * Runtime variables are identified by:
719
+ * - Starting with underscore (e.g., _conversation, _metadata)
720
+ * - Being in the explicit list (e.g., sessionId for backward compatibility)
721
+ */
722
+ function filterRuntimeVars(vars) {
723
+ if (!vars || typeof vars !== "object" || Array.isArray(vars)) return vars;
724
+ const filtered = {};
725
+ for (const [key, value] of Object.entries(vars)) if (!isRuntimeVar(key)) filtered[key] = value;
726
+ return filtered;
727
+ }
728
+ /**
729
+ * Extracts only runtime variables from a vars object.
730
+ * This is the inverse of filterRuntimeVars.
725
731
  *
726
- * @param responseFormat - The response_format configuration
727
- * @param vars - Variables for template rendering
728
- * @returns The processed response_format with all files loaded
732
+ * Used to restore runtime state when re-running filtered tests.
729
733
  */
730
- function maybeLoadResponseFormatFromExternalFile(responseFormat, vars) {
731
- if (responseFormat === void 0 || responseFormat === null) return responseFormat;
732
- const loaded = maybeLoadFromExternalFile(renderVarsInObject(responseFormat, vars));
733
- if (!loaded || typeof loaded !== "object") return loaded;
734
- if (loaded.type === "json_schema") {
735
- const nestedSchema = loaded.schema || loaded.json_schema?.schema;
736
- if (nestedSchema) {
737
- const loadedSchema = maybeLoadFromExternalFile(renderVarsInObject(nestedSchema, vars));
738
- if (loaded.schema !== void 0) return {
739
- ...loaded,
740
- schema: loadedSchema
741
- };
742
- else if (loaded.json_schema?.schema !== void 0) return {
743
- ...loaded,
744
- json_schema: {
745
- ...loaded.json_schema,
746
- schema: loadedSchema
747
- }
748
- };
749
- }
750
- }
751
- return loaded;
734
+ function extractRuntimeVars(vars) {
735
+ if (!vars || typeof vars !== "object" || Array.isArray(vars)) return;
736
+ const extracted = {};
737
+ for (const [key, value] of Object.entries(vars)) if (isRuntimeVar(key)) extracted[key] = value;
738
+ return Object.keys(extracted).length > 0 ? extracted : void 0;
739
+ }
740
+ function varsMatch(vars1, vars2) {
741
+ return (0, fast_deep_equal.default)(vars1, vars2);
752
742
  }
753
743
  /**
754
- * Renders variables in a tools object and loads from external file if applicable.
755
- * This function combines renderVarsInObject and maybeLoadFromExternalFile into a single step
756
- * specifically for handling tools configurations.
744
+ * Generate a unique key for a test case for deduplication purposes.
745
+ * Excludes runtime variables and includes strategyId to distinguish tests
746
+ * with the same prompt but different strategies.
757
747
  *
758
- * Supports loading from JSON, YAML, Python, and JavaScript files.
748
+ * @param testCase - The test case to generate a key for
749
+ * @returns A JSON string that uniquely identifies the test case
750
+ */
751
+ function getTestCaseDeduplicationKey(testCase) {
752
+ const filteredVars = filterRuntimeVars(testCase.vars);
753
+ const strategyId = testCase.metadata?.strategyId || "none";
754
+ return JSON.stringify({
755
+ vars: filteredVars,
756
+ strategyId
757
+ });
758
+ }
759
+ /**
760
+ * Deduplicates an array of test cases based on their vars and strategyId.
761
+ * Tests with the same vars but different strategies are considered different.
762
+ * Runtime variables (like _conversation, sessionId) are filtered out before comparison.
759
763
  *
760
- * @param tools - The tools configuration object or array to process.
761
- * @param vars - Variables to use for rendering.
762
- * @returns The processed tools configuration with variables rendered and content loaded from files if needed.
763
- * @throws {Error} If the loaded tools are in an invalid format
764
+ * @param tests - Array of test cases to deduplicate
765
+ * @returns Deduplicated array of test cases
764
766
  */
765
- async function maybeLoadToolsFromExternalFile(tools, vars) {
766
- const rendered = renderVarsInObject(tools, vars);
767
- if (typeof rendered === "string" && rendered.startsWith("file://")) {
768
- const { filePath, functionName } = parseFileUrl(rendered);
769
- if (functionName && (filePath.endsWith(".py") || require_fileExtensions.isJavascriptFile(filePath))) {
770
- const fileType = filePath.endsWith(".py") ? "Python" : "JavaScript";
771
- require_logger.logger.debug(`[maybeLoadToolsFromExternalFile] Loading tools from ${fileType} file: ${filePath}:${functionName}`);
772
- try {
773
- let toolDefinitions;
774
- if (filePath.endsWith(".py")) {
775
- const absPath = require_esm.safeResolve(require_logger.state.basePath || process.cwd(), filePath);
776
- require_logger.logger.debug(`[maybeLoadToolsFromExternalFile] Resolved Python path: ${absPath}`);
777
- toolDefinitions = await require_pythonUtils.runPython(absPath, functionName, []);
778
- } else {
779
- const absPath = require_esm.safeResolve(require_logger.state.basePath || process.cwd(), filePath);
780
- require_logger.logger.debug(`[maybeLoadToolsFromExternalFile] Resolved JavaScript path: ${absPath}`);
781
- const module = await require_esm.importModule(absPath);
782
- const fn = module[functionName] || module.default?.[functionName];
783
- if (typeof fn !== "function") {
784
- const availableExports = Object.keys(module).filter((k) => k !== "default");
785
- const basePath = require_logger.state.basePath || process.cwd();
786
- throw new Error(`Function "${functionName}" not found in ${filePath}. Available exports: ${availableExports.length > 0 ? availableExports.join(", ") : "(none)"}\nResolved from: ${basePath}`);
787
- }
788
- toolDefinitions = await Promise.resolve(fn());
789
- }
790
- 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}`);
791
- require_logger.logger.debug(`[maybeLoadToolsFromExternalFile] Successfully loaded ${Array.isArray(toolDefinitions) ? toolDefinitions.length : "object"} tools`);
792
- return toolDefinitions;
793
- } catch (err) {
794
- const errorMessage = err instanceof Error ? err.message : String(err);
795
- const basePath = require_logger.state.basePath || process.cwd();
796
- 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}`);
797
- }
798
- }
799
- if (filePath.endsWith(".py") || require_fileExtensions.isJavascriptFile(filePath)) {
800
- const ext = filePath.endsWith(".py") ? "Python" : "JavaScript";
801
- const basePath = require_logger.state.basePath || process.cwd();
802
- 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}`);
803
- }
804
- }
805
- if (Array.isArray(rendered)) {
806
- const results = await Promise.all(rendered.map((item) => maybeLoadToolsFromExternalFile(item, vars)));
807
- if (results.every((r) => Array.isArray(r))) return results.flat();
808
- return results;
809
- }
810
- if (typeof rendered !== "string") return rendered;
811
- const loaded = maybeLoadFromExternalFile(rendered);
812
- if (loaded !== void 0 && loaded !== null && typeof loaded === "string") {
813
- 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.`);
814
- 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");
815
- 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.");
767
+ function deduplicateTestCases(tests) {
768
+ const seen = /* @__PURE__ */ new Set();
769
+ return tests.filter((test) => {
770
+ const key = getTestCaseDeduplicationKey(test);
771
+ if (seen.has(key)) return false;
772
+ seen.add(key);
773
+ return true;
774
+ });
775
+ }
776
+ function resultIsForTestCase(result, testCase) {
777
+ const testProviderId = testCase.provider ? providerToIdentifier(testCase.provider) : void 0;
778
+ const resultProviderId = providerToIdentifier(result.provider);
779
+ const providersMatch = !testProviderId || !resultProviderId || testProviderId === resultProviderId;
780
+ const resultVars = filterRuntimeVars(result.vars);
781
+ const testVars = filterRuntimeVars(testCase.vars);
782
+ const doVarsMatch = varsMatch(testVars, resultVars);
783
+ const isMatch = doVarsMatch && providersMatch;
784
+ if (!isMatch) {
785
+ const varKeys = testVars ? Object.keys(testVars).join(", ") : "none";
786
+ require_logger.logger.debug(`[resultIsForTestCase] No match: vars=${doVarsMatch}, providers=${providersMatch}`, {
787
+ testProvider: testProviderId || "none",
788
+ resultProvider: resultProviderId || "none",
789
+ testVarKeys: varKeys
790
+ });
816
791
  }
817
- return loaded;
792
+ return isMatch;
793
+ }
794
+ //#endregion
795
+ //#region src/util/env.ts
796
+ /**
797
+ * Load environment variables from .env file(s).
798
+ * @param envPath - Single path, array of paths, or undefined for default .env loading.
799
+ * When paths are explicitly specified, all files must exist or an error is thrown.
800
+ * When multiple files are provided, later files override values from earlier files.
801
+ */
802
+ function setupEnv(envPath) {
803
+ if (envPath) {
804
+ const paths = (Array.isArray(envPath) ? envPath : [envPath]).flatMap((p) => p.includes(",") ? p.split(",").map((s) => s.trim()) : p.trim()).filter((p) => p.length > 0);
805
+ if (paths.length === 0) {
806
+ dotenv.default.config({ quiet: true });
807
+ return;
808
+ }
809
+ for (const p of paths) if (!fs.existsSync(p)) throw new Error(`Environment file not found: ${p}`);
810
+ if (paths.length === 1) require_logger.logger.info(`Loading environment variables from ${paths[0]}`);
811
+ else require_logger.logger.info(`Loading environment variables from: ${paths.join(", ")}`);
812
+ const pathArg = paths.length === 1 ? paths[0] : paths;
813
+ dotenv.default.config({
814
+ path: pathArg,
815
+ override: true,
816
+ quiet: true
817
+ });
818
+ } else dotenv.default.config({ quiet: true });
818
819
  }
819
820
  //#endregion
820
821
  //#region src/googleSheets.ts
@@ -1163,7 +1164,7 @@ function createOutputMetadata(evalRecord) {
1163
1164
  evaluationCreatedAt = void 0;
1164
1165
  }
1165
1166
  return {
1166
- promptfooVersion: require_fetch.VERSION,
1167
+ promptfooVersion: require_version.VERSION,
1167
1168
  nodeVersion: process.version,
1168
1169
  platform: os.platform(),
1169
1170
  arch: os.arch(),
@@ -1254,7 +1255,7 @@ async function writeOutput(outputPath, evalRecord, shareableUrl) {
1254
1255
  const redactedConfig = sanitizeConfigForOutput(evalRecord.config);
1255
1256
  const template = await fs_promises.readFile(path.join(require_esm.getDirectory(), "tableOutput.html"), "utf-8");
1256
1257
  const htmlTable = [[...table.head.vars, ...table.head.prompts.map((prompt) => `[${prompt.provider}] ${prompt.label}`)], ...table.body.map((row) => [...row.vars, ...row.outputs.map(outputToSimpleString)])];
1257
- const htmlOutput = getNunjucksEngine().renderString(template, {
1258
+ const htmlOutput = require_render.getNunjucksEngine().renderString(template, {
1258
1259
  config: redactedConfig,
1259
1260
  table: htmlTable,
1260
1261
  results: summary
@@ -1328,18 +1329,6 @@ Object.defineProperty(exports, "extractRuntimeVars", {
1328
1329
  return extractRuntimeVars;
1329
1330
  }
1330
1331
  });
1331
- Object.defineProperty(exports, "extractVariablesFromTemplate", {
1332
- enumerable: true,
1333
- get: function() {
1334
- return extractVariablesFromTemplate;
1335
- }
1336
- });
1337
- Object.defineProperty(exports, "extractVariablesFromTemplates", {
1338
- enumerable: true,
1339
- get: function() {
1340
- return extractVariablesFromTemplates;
1341
- }
1342
- });
1343
1332
  Object.defineProperty(exports, "fetchCsvFromGoogleSheet", {
1344
1333
  enumerable: true,
1345
1334
  get: function() {
@@ -1352,12 +1341,6 @@ Object.defineProperty(exports, "filterRuntimeVars", {
1352
1341
  return filterRuntimeVars;
1353
1342
  }
1354
1343
  });
1355
- Object.defineProperty(exports, "getNunjucksEngine", {
1356
- enumerable: true,
1357
- get: function() {
1358
- return getNunjucksEngine;
1359
- }
1360
- });
1361
1344
  Object.defineProperty(exports, "getNunjucksEngineForFilePath", {
1362
1345
  enumerable: true,
1363
1346
  get: function() {
@@ -1406,12 +1389,24 @@ Object.defineProperty(exports, "isProviderAllowed", {
1406
1389
  return isProviderAllowed;
1407
1390
  }
1408
1391
  });
1392
+ Object.defineProperty(exports, "isProviderConfigFileReference", {
1393
+ enumerable: true,
1394
+ get: function() {
1395
+ return isProviderConfigFileReference;
1396
+ }
1397
+ });
1409
1398
  Object.defineProperty(exports, "loadFunction", {
1410
1399
  enumerable: true,
1411
1400
  get: function() {
1412
1401
  return loadFunction;
1413
1402
  }
1414
1403
  });
1404
+ Object.defineProperty(exports, "loadProviderConfigsFromFile", {
1405
+ enumerable: true,
1406
+ get: function() {
1407
+ return loadProviderConfigsFromFile;
1408
+ }
1409
+ });
1415
1410
  Object.defineProperty(exports, "maybeLoadConfigFromExternalFile", {
1416
1411
  enumerable: true,
1417
1412
  get: function() {
@@ -1442,6 +1437,12 @@ Object.defineProperty(exports, "maybeLoadToolsFromExternalFile", {
1442
1437
  return maybeLoadToolsFromExternalFile;
1443
1438
  }
1444
1439
  });
1440
+ Object.defineProperty(exports, "normalizeProviderRef", {
1441
+ enumerable: true,
1442
+ get: function() {
1443
+ return normalizeProviderRef;
1444
+ }
1445
+ });
1445
1446
  Object.defineProperty(exports, "parseFileUrl", {
1446
1447
  enumerable: true,
1447
1448
  get: function() {
@@ -1472,16 +1473,10 @@ Object.defineProperty(exports, "readOutput", {
1472
1473
  return readOutput;
1473
1474
  }
1474
1475
  });
1475
- Object.defineProperty(exports, "renderEnvOnlyInObject", {
1476
- enumerable: true,
1477
- get: function() {
1478
- return renderEnvOnlyInObject;
1479
- }
1480
- });
1481
- Object.defineProperty(exports, "renderVarsInObject", {
1476
+ Object.defineProperty(exports, "readProviderConfigFile", {
1482
1477
  enumerable: true,
1483
1478
  get: function() {
1484
- return renderVarsInObject;
1479
+ return readProviderConfigFile;
1485
1480
  }
1486
1481
  });
1487
1482
  Object.defineProperty(exports, "resultIsForTestCase", {
@@ -1509,4 +1504,4 @@ Object.defineProperty(exports, "writeOutput", {
1509
1504
  }
1510
1505
  });
1511
1506
 
1512
- //# sourceMappingURL=util-CuLo2pMR.cjs.map
1507
+ //# sourceMappingURL=util-DvpHnLt0.cjs.map