@recombine-ai/bosun 0.11.1 → 0.11.2
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.
- package/build/client/_app/immutable/assets/0.CH-WU4JN.css +1 -0
- package/build/client/_app/immutable/assets/0.CH-WU4JN.css.br +0 -0
- package/build/client/_app/immutable/assets/0.CH-WU4JN.css.gz +0 -0
- package/build/client/_app/immutable/assets/{10.BX46PfEJ.css → 10.DIVePEYf.css} +1 -1
- package/build/client/_app/immutable/assets/10.DIVePEYf.css.br +0 -0
- package/build/client/_app/immutable/assets/10.DIVePEYf.css.gz +0 -0
- package/build/client/_app/immutable/chunks/{AocOovHL.js → 07xNIa59.js} +2 -2
- package/build/client/_app/immutable/chunks/07xNIa59.js.br +0 -0
- package/build/client/_app/immutable/chunks/07xNIa59.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BDl2QuyN.js +1 -0
- package/build/client/_app/immutable/chunks/BDl2QuyN.js.br +0 -0
- package/build/client/_app/immutable/chunks/BDl2QuyN.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{CqxCTxvJ.js → BI42X8h_.js} +1 -1
- package/build/client/_app/immutable/chunks/BI42X8h_.js.br +0 -0
- package/build/client/_app/immutable/chunks/BI42X8h_.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BJTwdUYr.js +1 -0
- package/build/client/_app/immutable/chunks/BJTwdUYr.js.br +0 -0
- package/build/client/_app/immutable/chunks/BJTwdUYr.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BLu86SbA.js +1 -0
- package/build/client/_app/immutable/chunks/BLu86SbA.js.br +0 -0
- package/build/client/_app/immutable/chunks/BLu86SbA.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BNifnXkO.js +1 -0
- package/build/client/_app/immutable/chunks/BNifnXkO.js.br +2 -0
- package/build/client/_app/immutable/chunks/BNifnXkO.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{BM0jKynj.js → BPNEONy5.js} +1 -1
- package/build/client/_app/immutable/chunks/BPNEONy5.js.br +0 -0
- package/build/client/_app/immutable/chunks/BPNEONy5.js.gz +0 -0
- package/build/client/_app/immutable/chunks/B_K7D6rX.js +2 -0
- package/build/client/_app/immutable/chunks/B_K7D6rX.js.br +0 -0
- package/build/client/_app/immutable/chunks/B_K7D6rX.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Bj8jfBTi.js +1 -0
- package/build/client/_app/immutable/chunks/Bj8jfBTi.js.br +0 -0
- package/build/client/_app/immutable/chunks/Bj8jfBTi.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{BR5f5i_E.js → BoPSJr4b.js} +1 -1
- package/build/client/_app/immutable/chunks/BoPSJr4b.js.br +0 -0
- package/build/client/_app/immutable/chunks/BoPSJr4b.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BsDZe4N6.js +1 -0
- package/build/client/_app/immutable/chunks/BsDZe4N6.js.br +0 -0
- package/build/client/_app/immutable/chunks/BsDZe4N6.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{CXo2BVs0.js → Buo-57fF.js} +1 -1
- package/build/client/_app/immutable/chunks/Buo-57fF.js.br +0 -0
- package/build/client/_app/immutable/chunks/Buo-57fF.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{C-whEtKd.js → C39ai1md.js} +1 -1
- package/build/client/_app/immutable/chunks/C39ai1md.js.br +0 -0
- package/build/client/_app/immutable/chunks/C39ai1md.js.gz +0 -0
- package/build/client/_app/immutable/chunks/C7he4XPB.js +1 -0
- package/build/client/_app/immutable/chunks/C7he4XPB.js.br +0 -0
- package/build/client/_app/immutable/chunks/C7he4XPB.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{DYhTBLDc.js → CAjPRvNs.js} +2 -2
- package/build/client/_app/immutable/chunks/CAjPRvNs.js.br +0 -0
- package/build/client/_app/immutable/chunks/CAjPRvNs.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CJYOmGlC.js +1 -0
- package/build/client/_app/immutable/chunks/CJYOmGlC.js.br +0 -0
- package/build/client/_app/immutable/chunks/CJYOmGlC.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{UiXQyKcj.js → CMQRtcOV.js} +1 -1
- package/build/client/_app/immutable/chunks/CMQRtcOV.js.br +0 -0
- package/build/client/_app/immutable/chunks/CMQRtcOV.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{HJHYLHDn.js → CPXdAKdv.js} +1 -1
- package/build/client/_app/immutable/chunks/CPXdAKdv.js.br +0 -0
- package/build/client/_app/immutable/chunks/CPXdAKdv.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{DTlGvFHe.js → CVlsAO8k.js} +1 -1
- package/build/client/_app/immutable/chunks/CVlsAO8k.js.br +0 -0
- package/build/client/_app/immutable/chunks/CVlsAO8k.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{DNLcpWO_.js → CX0Ekq8t.js} +1 -1
- package/build/client/_app/immutable/chunks/CX0Ekq8t.js.br +0 -0
- package/build/client/_app/immutable/chunks/CX0Ekq8t.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Ca197UDq.js +1 -0
- package/build/client/_app/immutable/chunks/Ca197UDq.js.br +0 -0
- package/build/client/_app/immutable/chunks/Ca197UDq.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CaHl3dME.js +1 -0
- package/build/client/_app/immutable/chunks/CaHl3dME.js.br +0 -0
- package/build/client/_app/immutable/chunks/CaHl3dME.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Cql_e8Of.js +1 -0
- package/build/client/_app/immutable/chunks/Cql_e8Of.js.br +2 -0
- package/build/client/_app/immutable/chunks/Cql_e8Of.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{Dv8m1cTI.js → CxLomzuE.js} +1 -1
- package/build/client/_app/immutable/chunks/CxLomzuE.js.br +0 -0
- package/build/client/_app/immutable/chunks/{Dv8m1cTI.js.gz → CxLomzuE.js.gz} +0 -0
- package/build/client/_app/immutable/chunks/Cyai3SOj.js +1 -0
- package/build/client/_app/immutable/chunks/Cyai3SOj.js.br +0 -0
- package/build/client/_app/immutable/chunks/Cyai3SOj.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{-g1l5aoS.js → CyvQWZoe.js} +4 -4
- package/build/client/_app/immutable/chunks/CyvQWZoe.js.br +0 -0
- package/build/client/_app/immutable/chunks/CyvQWZoe.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CzXNWL4m.js +1 -0
- package/build/client/_app/immutable/chunks/CzXNWL4m.js.br +1 -0
- package/build/client/_app/immutable/chunks/CzXNWL4m.js.gz +0 -0
- package/build/client/_app/immutable/chunks/D-B5X35l.js +1 -0
- package/build/client/_app/immutable/chunks/D-B5X35l.js.br +0 -0
- package/build/client/_app/immutable/chunks/D-B5X35l.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DJriQKD9.js +2 -0
- package/build/client/_app/immutable/chunks/DJriQKD9.js.br +0 -0
- package/build/client/_app/immutable/chunks/DJriQKD9.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{BL8rPcmP.js → DXUXXCDA.js} +1 -1
- package/build/client/_app/immutable/chunks/DXUXXCDA.js.br +0 -0
- package/build/client/_app/immutable/chunks/DXUXXCDA.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{CZLNSMhF.js → Dslf9OwW.js} +10 -10
- package/build/client/_app/immutable/chunks/Dslf9OwW.js.br +0 -0
- package/build/client/_app/immutable/chunks/Dslf9OwW.js.gz +0 -0
- package/build/client/_app/immutable/chunks/QpaC6J6s.js +1 -0
- package/build/client/_app/immutable/chunks/QpaC6J6s.js.br +0 -0
- package/build/client/_app/immutable/chunks/QpaC6J6s.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{HXxIsSOO.js → iAhzu4tv.js} +1 -1
- package/build/client/_app/immutable/chunks/iAhzu4tv.js.br +0 -0
- package/build/client/_app/immutable/chunks/iAhzu4tv.js.gz +0 -0
- package/build/client/_app/immutable/chunks/i_5fJYKS.js +3 -0
- package/build/client/_app/immutable/chunks/i_5fJYKS.js.br +0 -0
- package/build/client/_app/immutable/chunks/i_5fJYKS.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{Cosugfe8.js → nYD9wsyN.js} +1 -1
- package/build/client/_app/immutable/chunks/nYD9wsyN.js.br +0 -0
- package/build/client/_app/immutable/chunks/nYD9wsyN.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{BIpSIzUr.js → uLGP0py1.js} +1 -1
- package/build/client/_app/immutable/chunks/uLGP0py1.js.br +0 -0
- package/build/client/_app/immutable/chunks/uLGP0py1.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.Cr7CMG-3.js +2 -0
- package/build/client/_app/immutable/entry/app.Cr7CMG-3.js.br +0 -0
- package/build/client/_app/immutable/entry/app.Cr7CMG-3.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.CDNd0Bml.js +1 -0
- package/build/client/_app/immutable/entry/start.CDNd0Bml.js.br +2 -0
- package/build/client/_app/immutable/entry/start.CDNd0Bml.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{0.BiYgQci8.js → 0.AyqKXI2h.js} +2 -2
- package/build/client/_app/immutable/nodes/0.AyqKXI2h.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.AyqKXI2h.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.BRmfm-nN.js +1 -0
- package/build/client/_app/immutable/nodes/1.BRmfm-nN.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.BRmfm-nN.js.gz +0 -0
- package/build/client/_app/immutable/nodes/10.D03jjkr4.js +7 -0
- package/build/client/_app/immutable/nodes/10.D03jjkr4.js.br +0 -0
- package/build/client/_app/immutable/nodes/10.D03jjkr4.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{15.Wmhj7gOy.js → 15.BFy4oAT6.js} +1 -1
- package/build/client/_app/immutable/nodes/15.BFy4oAT6.js.br +0 -0
- package/build/client/_app/immutable/nodes/15.BFy4oAT6.js.gz +0 -0
- package/build/client/_app/immutable/nodes/17.BOYU_WTT.js +3 -0
- package/build/client/_app/immutable/nodes/17.BOYU_WTT.js.br +0 -0
- package/build/client/_app/immutable/nodes/17.BOYU_WTT.js.gz +0 -0
- package/build/client/_app/immutable/nodes/18.Ddx80a4f.js +11 -0
- package/build/client/_app/immutable/nodes/18.Ddx80a4f.js.br +0 -0
- package/build/client/_app/immutable/nodes/18.Ddx80a4f.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{2.DniQTiGZ.js → 2.CZEboQjo.js} +20 -20
- package/build/client/_app/immutable/nodes/2.CZEboQjo.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.CZEboQjo.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.dAV7FviN.js +1 -0
- package/build/client/_app/immutable/nodes/3.dAV7FviN.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.dAV7FviN.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.Cm_vMAEA.js +1 -0
- package/build/client/_app/immutable/nodes/4.Cm_vMAEA.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.Cm_vMAEA.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.DPWuTlaI.js +1 -0
- package/build/client/_app/immutable/nodes/5.DPWuTlaI.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.DPWuTlaI.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.DY-NLaRW.js +1 -0
- package/build/client/_app/immutable/nodes/6.DY-NLaRW.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.DY-NLaRW.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{8.2oZsfzo8.js → 8.Chuqhf8W.js} +1 -1
- package/build/client/_app/immutable/nodes/8.Chuqhf8W.js.br +0 -0
- package/build/client/_app/immutable/nodes/8.Chuqhf8W.js.gz +0 -0
- package/build/client/_app/immutable/nodes/9.BOEM8f6B.js +2 -0
- package/build/client/_app/immutable/nodes/9.BOEM8f6B.js.br +0 -0
- package/build/client/_app/immutable/nodes/9.BOEM8f6B.js.gz +0 -0
- package/build/client/_app/version.json +1 -1
- package/build/client/_app/version.json.br +0 -0
- package/build/client/_app/version.json.gz +0 -0
- package/build/server/chunks/0-TQkJBtAu.js +9 -0
- package/build/server/chunks/0-TQkJBtAu.js.map +1 -0
- package/build/server/chunks/1-CKxKlw1l.js +9 -0
- package/build/server/chunks/{1-BQkMpHdq.js.map → 1-CKxKlw1l.js.map} +1 -1
- package/build/server/chunks/10-Bly5Nk7M.js +9 -0
- package/build/server/chunks/10-Bly5Nk7M.js.map +1 -0
- package/build/server/chunks/{15-CZBxPMAc.js → 15-BMEAVslz.js} +2 -2
- package/build/server/chunks/{15-CZBxPMAc.js.map → 15-BMEAVslz.js.map} +1 -1
- package/build/server/chunks/17-C8CYQOYP.js +9 -0
- package/build/server/chunks/17-C8CYQOYP.js.map +1 -0
- package/build/server/chunks/18-CtXVGBbS.js +9 -0
- package/build/server/chunks/18-CtXVGBbS.js.map +1 -0
- package/build/server/chunks/2-DvD0dAh0.js +9 -0
- package/build/server/chunks/2-DvD0dAh0.js.map +1 -0
- package/build/server/chunks/3-DBzpRDK8.js +9 -0
- package/build/server/chunks/3-DBzpRDK8.js.map +1 -0
- package/build/server/chunks/4-BUNytyC2.js +9 -0
- package/build/server/chunks/4-BUNytyC2.js.map +1 -0
- package/build/server/chunks/5-DNo8_tFS.js +9 -0
- package/build/server/chunks/{5-C7KuaSU9.js.map → 5-DNo8_tFS.js.map} +1 -1
- package/build/server/chunks/6-DUMdIfbf.js +9 -0
- package/build/server/chunks/6-DUMdIfbf.js.map +1 -0
- package/build/server/chunks/8-DxTJ555u.js +9 -0
- package/build/server/chunks/8-DxTJ555u.js.map +1 -0
- package/build/server/chunks/9-B4-5k50d.js +9 -0
- package/build/server/chunks/9-B4-5k50d.js.map +1 -0
- package/build/server/chunks/{AgentSidebar-XdGj1sqT.js → AgentSidebar-DvIlda-E.js} +5 -6
- package/build/server/chunks/AgentSidebar-DvIlda-E.js.map +1 -0
- package/build/server/chunks/{ChatStepTrace-DnvGtFpb.js → ChatStepTrace-CqqIjRLU.js} +41 -7
- package/build/server/chunks/ChatStepTrace-CqqIjRLU.js.map +1 -0
- package/build/server/chunks/MockGenerator-GEpXTgX0.js +117 -0
- package/build/server/chunks/MockGenerator-GEpXTgX0.js.map +1 -0
- package/build/server/chunks/{_layout.svelte-C5Y9nSXi.js → _layout.svelte-B-CkD4a0.js} +12 -6
- package/build/server/chunks/_layout.svelte-B-CkD4a0.js.map +1 -0
- package/build/server/chunks/{_layout.svelte-_oqm8kmr.js → _layout.svelte-BBFCF-xw.js} +7 -3
- package/build/server/chunks/_layout.svelte-BBFCF-xw.js.map +1 -0
- package/build/server/chunks/{_layout.svelte-C7JgNCIu.js → _layout.svelte-cPhmW5bZ.js} +3 -1
- package/build/server/chunks/_layout.svelte-cPhmW5bZ.js.map +1 -0
- package/build/server/chunks/{_page.svelte-QlYvVgTj.js → _page.svelte-0J2xaeyC.js} +70 -15
- package/build/server/chunks/_page.svelte-0J2xaeyC.js.map +1 -0
- package/build/server/chunks/{_page.svelte-BpRksNEG.js → _page.svelte-BgoX8Y6N.js} +2 -2
- package/build/server/chunks/{_page.svelte-BpRksNEG.js.map → _page.svelte-BgoX8Y6N.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-bkzbqII3.js → _page.svelte-C_S_qUgZ.js} +479 -71
- package/build/server/chunks/_page.svelte-C_S_qUgZ.js.map +1 -0
- package/build/server/chunks/{_page.svelte-DDpBtd3X.js → _page.svelte-CqGOvPRO.js} +3 -4
- package/build/server/chunks/_page.svelte-CqGOvPRO.js.map +1 -0
- package/build/server/chunks/{_page.svelte-DOhPbizt.js → _page.svelte-Cxh9_vUl.js} +34 -22
- package/build/server/chunks/_page.svelte-Cxh9_vUl.js.map +1 -0
- package/build/server/chunks/{_page.svelte-CEhhEdMi.js → _page.svelte-zOI_s_3J.js} +122 -71
- package/build/server/chunks/_page.svelte-zOI_s_3J.js.map +1 -0
- package/build/server/chunks/conversation-view-memory-BZguFlTt.js +20 -0
- package/build/server/chunks/conversation-view-memory-BZguFlTt.js.map +1 -0
- package/build/server/chunks/log-content.svelte-CfQzj-v_.js.map +1 -1
- package/build/server/chunks/{client-DzvEkq51.js → source-selection-CcN1cgXc.js} +122 -117
- package/build/server/chunks/source-selection-CcN1cgXc.js.map +1 -0
- package/build/server/index.js +1 -1
- package/build/server/index.js.map +1 -1
- package/build/server/manifest.js +14 -14
- package/build/server/manifest.js.map +1 -1
- package/package.json +3 -3
- package/src/backend/lib/get-agent-factories.spec.ts +59 -0
- package/src/backend/lib/get-agent-factories.ts +31 -1
- package/src/backend/lib/voice-agent-lifecycle.test.ts +12 -8
- package/src/backend/lib/voice-agent-lifecycle.ts +2 -1
- package/src/backend/roleplay/agents.ts +18 -0
- package/src/backend/roleplay/router.ts +8 -3
- package/src/backend/tests/academy.ts +151 -93
- package/src/backend/tests/analyze.ts +0 -3
- package/src/backend/tests/data.spec.ts +139 -0
- package/src/backend/tests/data.ts +296 -65
- package/src/backend/tests/emulate-agents.ts +45 -45
- package/src/backend/tests/openai-prompt-cache.ts +68 -0
- package/src/backend/tests/promptfoo-runtime.spec.ts +41 -0
- package/src/backend/tests/promptfoo-runtime.ts +27 -0
- package/src/backend/tests/report-files.spec.ts +42 -0
- package/src/backend/tests/report-files.ts +101 -0
- package/src/backend/tests/router.ts +7 -1
- package/build/client/_app/immutable/assets/0.Dz9hcoGY.css +0 -1
- package/build/client/_app/immutable/assets/0.Dz9hcoGY.css.br +0 -0
- package/build/client/_app/immutable/assets/0.Dz9hcoGY.css.gz +0 -0
- package/build/client/_app/immutable/assets/10.BX46PfEJ.css.br +0 -0
- package/build/client/_app/immutable/assets/10.BX46PfEJ.css.gz +0 -0
- package/build/client/_app/immutable/chunks/-g1l5aoS.js.br +0 -0
- package/build/client/_app/immutable/chunks/-g1l5aoS.js.gz +0 -0
- package/build/client/_app/immutable/chunks/7E8m6dwk.js +0 -1
- package/build/client/_app/immutable/chunks/7E8m6dwk.js.br +0 -0
- package/build/client/_app/immutable/chunks/7E8m6dwk.js.gz +0 -0
- package/build/client/_app/immutable/chunks/7qRqthsa.js +0 -1
- package/build/client/_app/immutable/chunks/7qRqthsa.js.br +0 -2
- package/build/client/_app/immutable/chunks/7qRqthsa.js.gz +0 -0
- package/build/client/_app/immutable/chunks/AocOovHL.js.br +0 -0
- package/build/client/_app/immutable/chunks/AocOovHL.js.gz +0 -0
- package/build/client/_app/immutable/chunks/B0iEglSe.js +0 -1
- package/build/client/_app/immutable/chunks/B0iEglSe.js.br +0 -0
- package/build/client/_app/immutable/chunks/B0iEglSe.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BIpSIzUr.js.br +0 -0
- package/build/client/_app/immutable/chunks/BIpSIzUr.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BL8rPcmP.js.br +0 -0
- package/build/client/_app/immutable/chunks/BL8rPcmP.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BM0jKynj.js.br +0 -0
- package/build/client/_app/immutable/chunks/BM0jKynj.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BR5f5i_E.js.br +0 -0
- package/build/client/_app/immutable/chunks/BR5f5i_E.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BTvePR6r.js +0 -1
- package/build/client/_app/immutable/chunks/BTvePR6r.js.br +0 -2
- package/build/client/_app/immutable/chunks/BTvePR6r.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Bcu62lFq.js +0 -1
- package/build/client/_app/immutable/chunks/Bcu62lFq.js.br +0 -0
- package/build/client/_app/immutable/chunks/Bcu62lFq.js.gz +0 -0
- package/build/client/_app/immutable/chunks/C-whEtKd.js.br +0 -2
- package/build/client/_app/immutable/chunks/C-whEtKd.js.gz +0 -0
- package/build/client/_app/immutable/chunks/C1WqE8CP.js +0 -1
- package/build/client/_app/immutable/chunks/C1WqE8CP.js.br +0 -2
- package/build/client/_app/immutable/chunks/C1WqE8CP.js.gz +0 -0
- package/build/client/_app/immutable/chunks/C4SnSfql.js +0 -1
- package/build/client/_app/immutable/chunks/C4SnSfql.js.br +0 -0
- package/build/client/_app/immutable/chunks/C4SnSfql.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CSv1VDXg.js +0 -1
- package/build/client/_app/immutable/chunks/CSv1VDXg.js.br +0 -0
- package/build/client/_app/immutable/chunks/CSv1VDXg.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CXo2BVs0.js.br +0 -0
- package/build/client/_app/immutable/chunks/CXo2BVs0.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CZLNSMhF.js.br +0 -0
- package/build/client/_app/immutable/chunks/CZLNSMhF.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Cosugfe8.js.br +0 -0
- package/build/client/_app/immutable/chunks/Cosugfe8.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CqxCTxvJ.js.br +0 -0
- package/build/client/_app/immutable/chunks/CqxCTxvJ.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CxLG58rb.js +0 -1
- package/build/client/_app/immutable/chunks/CxLG58rb.js.br +0 -0
- package/build/client/_app/immutable/chunks/CxLG58rb.js.gz +0 -0
- package/build/client/_app/immutable/chunks/D-puyTnN.js +0 -1
- package/build/client/_app/immutable/chunks/D-puyTnN.js.br +0 -0
- package/build/client/_app/immutable/chunks/D-puyTnN.js.gz +0 -0
- package/build/client/_app/immutable/chunks/D4obUD_s.js +0 -1
- package/build/client/_app/immutable/chunks/D4obUD_s.js.br +0 -0
- package/build/client/_app/immutable/chunks/D4obUD_s.js.gz +0 -0
- package/build/client/_app/immutable/chunks/D8e7SQh9.js +0 -1
- package/build/client/_app/immutable/chunks/D8e7SQh9.js.br +0 -0
- package/build/client/_app/immutable/chunks/D8e7SQh9.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DNLcpWO_.js.br +0 -0
- package/build/client/_app/immutable/chunks/DNLcpWO_.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DTlGvFHe.js.br +0 -0
- package/build/client/_app/immutable/chunks/DTlGvFHe.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DYhTBLDc.js.br +0 -0
- package/build/client/_app/immutable/chunks/DYhTBLDc.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DlZKMmqG.js +0 -4
- package/build/client/_app/immutable/chunks/DlZKMmqG.js.br +0 -0
- package/build/client/_app/immutable/chunks/DlZKMmqG.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Dv0gjm25.js +0 -1
- package/build/client/_app/immutable/chunks/Dv0gjm25.js.br +0 -0
- package/build/client/_app/immutable/chunks/Dv0gjm25.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Dv8m1cTI.js.br +0 -0
- package/build/client/_app/immutable/chunks/HJHYLHDn.js.br +0 -0
- package/build/client/_app/immutable/chunks/HJHYLHDn.js.gz +0 -0
- package/build/client/_app/immutable/chunks/HXxIsSOO.js.br +0 -0
- package/build/client/_app/immutable/chunks/HXxIsSOO.js.gz +0 -0
- package/build/client/_app/immutable/chunks/UiXQyKcj.js.br +0 -0
- package/build/client/_app/immutable/chunks/UiXQyKcj.js.gz +0 -0
- package/build/client/_app/immutable/chunks/_yZg6Sf-.js +0 -2
- package/build/client/_app/immutable/chunks/_yZg6Sf-.js.br +0 -0
- package/build/client/_app/immutable/chunks/_yZg6Sf-.js.gz +0 -0
- package/build/client/_app/immutable/chunks/ks45gSgq.js +0 -1
- package/build/client/_app/immutable/chunks/ks45gSgq.js.br +0 -0
- package/build/client/_app/immutable/chunks/ks45gSgq.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.qxHHRD2v.js +0 -2
- package/build/client/_app/immutable/entry/app.qxHHRD2v.js.br +0 -0
- package/build/client/_app/immutable/entry/app.qxHHRD2v.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.CSxD7zE8.js +0 -1
- package/build/client/_app/immutable/entry/start.CSxD7zE8.js.br +0 -2
- package/build/client/_app/immutable/entry/start.CSxD7zE8.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.BiYgQci8.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.BiYgQci8.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.CShtqUFK.js +0 -1
- package/build/client/_app/immutable/nodes/1.CShtqUFK.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.CShtqUFK.js.gz +0 -0
- package/build/client/_app/immutable/nodes/10.dE-XOJgk.js +0 -7
- package/build/client/_app/immutable/nodes/10.dE-XOJgk.js.br +0 -0
- package/build/client/_app/immutable/nodes/10.dE-XOJgk.js.gz +0 -0
- package/build/client/_app/immutable/nodes/15.Wmhj7gOy.js.br +0 -0
- package/build/client/_app/immutable/nodes/15.Wmhj7gOy.js.gz +0 -0
- package/build/client/_app/immutable/nodes/17.BwzZwCD0.js +0 -3
- package/build/client/_app/immutable/nodes/17.BwzZwCD0.js.br +0 -0
- package/build/client/_app/immutable/nodes/17.BwzZwCD0.js.gz +0 -0
- package/build/client/_app/immutable/nodes/18.BUMDuaQF.js +0 -11
- package/build/client/_app/immutable/nodes/18.BUMDuaQF.js.br +0 -0
- package/build/client/_app/immutable/nodes/18.BUMDuaQF.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.DniQTiGZ.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.DniQTiGZ.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.BIO1e-qq.js +0 -1
- package/build/client/_app/immutable/nodes/3.BIO1e-qq.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.BIO1e-qq.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.BwfVTawo.js +0 -1
- package/build/client/_app/immutable/nodes/4.BwfVTawo.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.BwfVTawo.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.DdodCQcX.js +0 -1
- package/build/client/_app/immutable/nodes/5.DdodCQcX.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.DdodCQcX.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.EIjYVI_W.js +0 -1
- package/build/client/_app/immutable/nodes/6.EIjYVI_W.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.EIjYVI_W.js.gz +0 -0
- package/build/client/_app/immutable/nodes/8.2oZsfzo8.js.br +0 -0
- package/build/client/_app/immutable/nodes/8.2oZsfzo8.js.gz +0 -0
- package/build/client/_app/immutable/nodes/9.CjWG6Ha9.js +0 -2
- package/build/client/_app/immutable/nodes/9.CjWG6Ha9.js.br +0 -0
- package/build/client/_app/immutable/nodes/9.CjWG6Ha9.js.gz +0 -0
- package/build/server/chunks/0-S8VzkGgQ.js +0 -9
- package/build/server/chunks/0-S8VzkGgQ.js.map +0 -1
- package/build/server/chunks/1-BQkMpHdq.js +0 -9
- package/build/server/chunks/10-D1k3_nkw.js +0 -9
- package/build/server/chunks/10-D1k3_nkw.js.map +0 -1
- package/build/server/chunks/17-B72NO3Iu.js +0 -9
- package/build/server/chunks/17-B72NO3Iu.js.map +0 -1
- package/build/server/chunks/18-4kgQqgz-.js +0 -9
- package/build/server/chunks/18-4kgQqgz-.js.map +0 -1
- package/build/server/chunks/2-DO8jW3Pl.js +0 -9
- package/build/server/chunks/2-DO8jW3Pl.js.map +0 -1
- package/build/server/chunks/3-0_f3eZZi.js +0 -9
- package/build/server/chunks/3-0_f3eZZi.js.map +0 -1
- package/build/server/chunks/4-UxjRsyDW.js +0 -9
- package/build/server/chunks/4-UxjRsyDW.js.map +0 -1
- package/build/server/chunks/5-C7KuaSU9.js +0 -9
- package/build/server/chunks/6-C6EG0SXo.js +0 -9
- package/build/server/chunks/6-C6EG0SXo.js.map +0 -1
- package/build/server/chunks/8-BTSvDZhI.js +0 -9
- package/build/server/chunks/8-BTSvDZhI.js.map +0 -1
- package/build/server/chunks/9-CepnUatA.js +0 -9
- package/build/server/chunks/9-CepnUatA.js.map +0 -1
- package/build/server/chunks/AgentSidebar-XdGj1sqT.js.map +0 -1
- package/build/server/chunks/ChatStepTrace-DnvGtFpb.js.map +0 -1
- package/build/server/chunks/_layout.svelte-C5Y9nSXi.js.map +0 -1
- package/build/server/chunks/_layout.svelte-C7JgNCIu.js.map +0 -1
- package/build/server/chunks/_layout.svelte-_oqm8kmr.js.map +0 -1
- package/build/server/chunks/_page.svelte-CEhhEdMi.js.map +0 -1
- package/build/server/chunks/_page.svelte-DDpBtd3X.js.map +0 -1
- package/build/server/chunks/_page.svelte-DOhPbizt.js.map +0 -1
- package/build/server/chunks/_page.svelte-QlYvVgTj.js.map +0 -1
- package/build/server/chunks/_page.svelte-bkzbqII3.js.map +0 -1
- package/build/server/chunks/client-DzvEkq51.js.map +0 -1
- package/build/server/chunks/source-selection-eA--VEKo.js +0 -124
- package/build/server/chunks/source-selection-eA--VEKo.js.map +0 -1
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
// cspell:words conv
|
|
2
|
-
import { type ProviderOptions } from 'promptfoo'
|
|
3
|
-
import * as promptfoo from 'promptfoo'
|
|
4
2
|
import { type Message, type StepTrace, type StepTracer } from '@recombine-ai/engine'
|
|
5
3
|
import { loadAgents } from './emulate-agents'
|
|
6
|
-
import {
|
|
4
|
+
import { installTestPromptCacheBust } from './openai-prompt-cache'
|
|
5
|
+
import { promptfoo } from './promptfoo-runtime'
|
|
7
6
|
// Backend: per-project JSON test suites (no CSV)
|
|
8
7
|
import { tryReadConfig } from './config'
|
|
9
8
|
import { mkdir, rename, unlink, writeFile } from 'node:fs/promises'
|
|
@@ -11,11 +10,18 @@ import path from 'node:path'
|
|
|
11
10
|
import { readSuite, type TestRow as SuiteTestRow } from './suite'
|
|
12
11
|
// Use types derived from promptfoo exports instead of incorrect default type imports
|
|
13
12
|
|
|
14
|
-
import type {
|
|
13
|
+
import type {
|
|
14
|
+
ApiProvider,
|
|
15
|
+
Assertion as PFAssertion,
|
|
16
|
+
CallApiContextParams,
|
|
17
|
+
ProviderOptions,
|
|
18
|
+
ProviderResponse
|
|
19
|
+
} from 'promptfoo'
|
|
15
20
|
import deepmerge from 'deepmerge'
|
|
16
21
|
import fs from 'node:fs'
|
|
17
22
|
import { getRootPath } from '../lib/get-root-path'
|
|
18
23
|
import { makeContext } from './context-utils'
|
|
24
|
+
import { queueReportCompression, REPORT_JSON_SUFFIX } from './report-files'
|
|
19
25
|
|
|
20
26
|
// ----------------- Type aliases & helpers -----------------
|
|
21
27
|
type Context = Record<string, unknown>
|
|
@@ -93,6 +99,30 @@ type CaptureMode = 'immediate' | 'final'
|
|
|
93
99
|
|
|
94
100
|
const activeRunsBySuiteKey = new Map<string, AbortController>()
|
|
95
101
|
|
|
102
|
+
export interface PromptTestsProgress {
|
|
103
|
+
plannedTestIds: string[]
|
|
104
|
+
runningTestIds: string[]
|
|
105
|
+
completedTestIds: string[]
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
type MutablePromptTestsProgress = PromptTestsProgress & {
|
|
109
|
+
expectedRuns: number
|
|
110
|
+
startedTestIds: Set<string>
|
|
111
|
+
completedRunsByTestId: Map<string, number>
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const activeProgressBySuiteKey = new Map<string, MutablePromptTestsProgress>()
|
|
115
|
+
|
|
116
|
+
export function getPromptTestsProgress(suiteKey: string): PromptTestsProgress | null {
|
|
117
|
+
const progress = activeProgressBySuiteKey.get(suiteKey)
|
|
118
|
+
if (!progress) return null
|
|
119
|
+
return {
|
|
120
|
+
plannedTestIds: [...progress.plannedTestIds],
|
|
121
|
+
runningTestIds: [...progress.runningTestIds],
|
|
122
|
+
completedTestIds: [...progress.completedTestIds]
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
96
126
|
export type SuiteSelection = {
|
|
97
127
|
// `suiteKey` is the filesystem/report key (e.g. `voiceSupport.en-gb`).
|
|
98
128
|
// `agentId` is the canonical factory key (workflow export key, e.g. `voiceSupport`).
|
|
@@ -122,6 +152,7 @@ export async function runPromptTestsManaged(
|
|
|
122
152
|
return await runPromptTests(suite, selection, { signal: controller.signal })
|
|
123
153
|
} finally {
|
|
124
154
|
activeRunsBySuiteKey.delete(suite.suiteKey)
|
|
155
|
+
activeProgressBySuiteKey.delete(suite.suiteKey)
|
|
125
156
|
}
|
|
126
157
|
}
|
|
127
158
|
|
|
@@ -234,6 +265,7 @@ export class RecombineAgentProvider implements ApiProvider {
|
|
|
234
265
|
protected providerId: string
|
|
235
266
|
public config: Record<string, unknown>
|
|
236
267
|
private abortSignal?: AbortSignal
|
|
268
|
+
private onTestStarted?: (testId: string) => void
|
|
237
269
|
|
|
238
270
|
constructor(options: ProviderOptions) {
|
|
239
271
|
this.providerId = options.id || 'recombine-agent'
|
|
@@ -244,6 +276,10 @@ export class RecombineAgentProvider implements ApiProvider {
|
|
|
244
276
|
this.abortSignal = signal
|
|
245
277
|
}
|
|
246
278
|
|
|
279
|
+
setOnTestStarted(callback: (testId: string) => void) {
|
|
280
|
+
this.onTestStarted = callback
|
|
281
|
+
}
|
|
282
|
+
|
|
247
283
|
id() {
|
|
248
284
|
return this.providerId
|
|
249
285
|
}
|
|
@@ -252,6 +288,7 @@ export class RecombineAgentProvider implements ApiProvider {
|
|
|
252
288
|
const projectRoot = path.dirname(await getRootPath())
|
|
253
289
|
const vars = (context?.vars || {}) as unknown as {
|
|
254
290
|
agentId: string
|
|
291
|
+
testId: string
|
|
255
292
|
region?: string
|
|
256
293
|
conversation: Conversation
|
|
257
294
|
conversationParseError?: string
|
|
@@ -259,6 +296,8 @@ export class RecombineAgentProvider implements ApiProvider {
|
|
|
259
296
|
mocks?: Context
|
|
260
297
|
captureMode?: CaptureMode | string
|
|
261
298
|
}
|
|
299
|
+
const testId = String(vars.testId ?? '')
|
|
300
|
+
if (testId) this.onTestStarted?.(testId)
|
|
262
301
|
|
|
263
302
|
if (typeof vars.conversationParseError === 'string' && vars.conversationParseError.trim()) {
|
|
264
303
|
return { output: '', error: vars.conversationParseError }
|
|
@@ -293,7 +332,6 @@ export class RecombineAgentProvider implements ApiProvider {
|
|
|
293
332
|
const stepTracer: StepTracer = {
|
|
294
333
|
addStepTrace: (stepTrace: StepTrace) => {
|
|
295
334
|
try {
|
|
296
|
-
console.log(`trace: ${stepTrace.name}`)
|
|
297
335
|
capturedStepTraces.push(stepTrace)
|
|
298
336
|
} catch {
|
|
299
337
|
// best-effort capture; ignore serialization issues
|
|
@@ -438,6 +476,7 @@ export class RecombineAgentProvider implements ApiProvider {
|
|
|
438
476
|
}
|
|
439
477
|
}
|
|
440
478
|
} catch (err) {
|
|
479
|
+
if (this.abortSignal?.aborted) throw err
|
|
441
480
|
const msg = err instanceof Error ? `${err.name}: ${err.message}` : String(err)
|
|
442
481
|
capturedLogs.push(`[ERROR] ${msg}`)
|
|
443
482
|
try {
|
|
@@ -574,7 +613,7 @@ export async function runPromptTests(
|
|
|
574
613
|
const cfg = (await tryReadConfig(suiteKey)) || {}
|
|
575
614
|
|
|
576
615
|
const repeats = Number(cfg?.repeats ?? 1)
|
|
577
|
-
const concurrency = Number(cfg?.concurrency ??
|
|
616
|
+
const concurrency = Math.min(75, Math.max(1, Math.floor(Number(cfg?.concurrency ?? 75))))
|
|
578
617
|
const baseContext = loadedSuite?.meta?.defaultContext || {}
|
|
579
618
|
|
|
580
619
|
// Add an index field to each row for mapping
|
|
@@ -586,12 +625,27 @@ export async function runPromptTests(
|
|
|
586
625
|
}
|
|
587
626
|
|
|
588
627
|
const tests = toTestInputs(indexedRows, baseContext, selection)
|
|
628
|
+
const plannedTestIds = tests.map((test) => String(test.id ?? '')).filter(Boolean)
|
|
629
|
+
const progress: MutablePromptTestsProgress = {
|
|
630
|
+
plannedTestIds,
|
|
631
|
+
runningTestIds: [],
|
|
632
|
+
completedTestIds: [],
|
|
633
|
+
expectedRuns: repeats,
|
|
634
|
+
startedTestIds: new Set(),
|
|
635
|
+
completedRunsByTestId: new Map()
|
|
636
|
+
}
|
|
637
|
+
activeProgressBySuiteKey.set(suiteKey, progress)
|
|
589
638
|
|
|
590
639
|
// Provider function with stable label
|
|
591
640
|
const providerInstance = new RecombineAgentProvider({
|
|
592
641
|
id: 'recombine-agent'
|
|
593
642
|
})
|
|
594
643
|
providerInstance.setAbortSignal(signal)
|
|
644
|
+
providerInstance.setOnTestStarted((testId) => {
|
|
645
|
+
if (progress.completedTestIds.includes(testId)) return
|
|
646
|
+
progress.startedTestIds.add(testId)
|
|
647
|
+
progress.runningTestIds = [...progress.startedTestIds]
|
|
648
|
+
})
|
|
595
649
|
const providerFn = Object.assign(
|
|
596
650
|
(_promptStr: string, ctx?: CallApiContextParams) => {
|
|
597
651
|
if (signal?.aborted) {
|
|
@@ -605,39 +659,40 @@ export async function runPromptTests(
|
|
|
605
659
|
const hookKey = `__bosun_promptfoo_hook_${process.pid}_${Date.now()}_${Math.random().toString(16).slice(2)}`
|
|
606
660
|
const extensionCode = `globalThis[${JSON.stringify(hookKey)}]?.(output, context)`
|
|
607
661
|
|
|
608
|
-
const
|
|
662
|
+
const testSuite = {
|
|
609
663
|
prompts: ['agent-run'], // placeholder; provider ignores
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
{
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
}
|
|
664
|
+
tests: tests.map((test) => ({
|
|
665
|
+
description: test.scenario,
|
|
666
|
+
metadata: { testId: test.id },
|
|
667
|
+
assert: test.assertions,
|
|
668
|
+
model: 'not used!',
|
|
669
|
+
vars: {
|
|
670
|
+
agentId: suite.agentId,
|
|
671
|
+
testId: String(test.id ?? ''),
|
|
672
|
+
...(suite.region ? { region: suite.region } : {}),
|
|
673
|
+
context: test.context,
|
|
674
|
+
...(typeof test.mocks !== 'undefined' ? { mocks: test.mocks } : {}),
|
|
675
|
+
captureMode: test.captureMode,
|
|
676
|
+
conversation: test.conversation,
|
|
677
|
+
...(test.conversationParseError
|
|
678
|
+
? { conversationParseError: test.conversationParseError }
|
|
679
|
+
: {})
|
|
627
680
|
}
|
|
628
|
-
|
|
681
|
+
})),
|
|
629
682
|
providers: [providerFn],
|
|
630
683
|
extensions: [extensionCode]
|
|
631
|
-
}
|
|
684
|
+
}
|
|
632
685
|
|
|
633
|
-
const
|
|
686
|
+
const rootPath = await getRootPath()
|
|
687
|
+
installTestPromptCacheBust(rootPath)
|
|
688
|
+
const projectRoot = path.dirname(rootPath)
|
|
634
689
|
const outDir = path.join(projectRoot, 'data', 'test_runs')
|
|
635
690
|
await mkdir(outDir, { recursive: true })
|
|
636
691
|
|
|
637
692
|
// Use full ISO timestamp and sanitize ':' for filesystem safety
|
|
638
693
|
const iso = new Date().toISOString()
|
|
639
694
|
const isoFile = iso.replace(/:/g, '-')
|
|
640
|
-
const outPath = path.join(outDir, `${suiteKey}.${isoFile}
|
|
695
|
+
const outPath = path.join(outDir, `${suiteKey}.${isoFile}${REPORT_JSON_SUFFIX}`)
|
|
641
696
|
|
|
642
697
|
async function writeReport(report: WrittenRunReport) {
|
|
643
698
|
const dir = path.dirname(outPath)
|
|
@@ -746,6 +801,15 @@ export async function runPromptTests(
|
|
|
746
801
|
|
|
747
802
|
const entry = toResultEntry(r)
|
|
748
803
|
reportRow.results.push(entry)
|
|
804
|
+
const completedRuns = (progress.completedRunsByTestId.get(testId) ?? 0) + 1
|
|
805
|
+
progress.completedRunsByTestId.set(testId, completedRuns)
|
|
806
|
+
if (completedRuns >= progress.expectedRuns) {
|
|
807
|
+
progress.startedTestIds.delete(testId)
|
|
808
|
+
progress.runningTestIds = [...progress.startedTestIds]
|
|
809
|
+
if (!progress.completedTestIds.includes(testId)) {
|
|
810
|
+
progress.completedTestIds = [...progress.completedTestIds, testId]
|
|
811
|
+
}
|
|
812
|
+
}
|
|
749
813
|
|
|
750
814
|
const counts = countsByTestId.get(testId) ?? { pass: 0, total: 0 }
|
|
751
815
|
counts.total += 1
|
|
@@ -764,77 +828,68 @@ export async function runPromptTests(
|
|
|
764
828
|
}
|
|
765
829
|
}
|
|
766
830
|
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
831
|
+
const selectedOriginalRows = plannedTestIds
|
|
832
|
+
.map((testId) => originalRowById.get(testId))
|
|
833
|
+
.filter((row): row is SuiteTestRow => !!row)
|
|
834
|
+
const persistEvaluation = (evaluation: PFEval) => {
|
|
835
|
+
for (const rowToWrite of buildTableRows([evaluation], selectedOriginalRows, suiteKey)) {
|
|
836
|
+
const testId = String(rowToWrite.id ?? '')
|
|
837
|
+
const originalRow = originalRowById.get(testId)
|
|
838
|
+
if (!testId || !originalRow) continue
|
|
839
|
+
const pinned: 'TRUE' | 'FALSE' =
|
|
840
|
+
(rowToWrite.pinned || '').toUpperCase() === 'TRUE' ? 'TRUE' : 'FALSE'
|
|
841
|
+
byTestId.set(testId, {
|
|
842
|
+
...rowToWrite,
|
|
843
|
+
test: originalRow,
|
|
844
|
+
agent: suiteKey,
|
|
845
|
+
test_id: testId,
|
|
846
|
+
run_timestamp: iso,
|
|
847
|
+
run_config: JSON.stringify(runConfig),
|
|
848
|
+
pinned_at_run: scope === 'all' || !!onlyTestId ? 'TRUE' : pinned,
|
|
849
|
+
run_scope: scope
|
|
850
|
+
})
|
|
851
|
+
}
|
|
852
|
+
body.rows = Array.from(byTestId.values())
|
|
853
|
+
}
|
|
780
854
|
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
const ev = {
|
|
807
|
-
results: [
|
|
808
|
-
{
|
|
855
|
+
const previousIsTest = process.env.IS_TEST
|
|
856
|
+
process.env.IS_TEST = 'true'
|
|
857
|
+
try {
|
|
858
|
+
if (tests.length > 0 && !signal?.aborted) {
|
|
859
|
+
const evaluation = await promptfoo.evaluate(testSuite, {
|
|
860
|
+
repeat: repeats,
|
|
861
|
+
cache: false,
|
|
862
|
+
maxConcurrency: concurrency,
|
|
863
|
+
// Bosun reports run progress in the tests UI. Promptfoo's terminal progress bars
|
|
864
|
+
// continuously rewrite stdout (up to 20 bars at higher concurrency).
|
|
865
|
+
showProgressBar: false,
|
|
866
|
+
abortSignal: signal
|
|
867
|
+
})
|
|
868
|
+
persistEvaluation(evaluation)
|
|
869
|
+
await enqueueWrite()
|
|
870
|
+
}
|
|
871
|
+
} catch (err) {
|
|
872
|
+
const cancelled =
|
|
873
|
+
!!signal?.aborted || (err instanceof Error && /operation cancelled/i.test(err.message || ''))
|
|
874
|
+
if (!cancelled) {
|
|
875
|
+
const msg = err instanceof Error ? `${err.name}: ${err.message}` : String(err)
|
|
876
|
+
const evaluation = {
|
|
877
|
+
results: plannedTestIds.map(
|
|
878
|
+
(testId) =>
|
|
879
|
+
({
|
|
809
880
|
success: false,
|
|
810
881
|
response: { output: '' },
|
|
811
882
|
error: msg,
|
|
812
|
-
metadata: { testId
|
|
813
|
-
} as any
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
if (originalRow && testId) {
|
|
819
|
-
const rowToWrite = buildTableRows([ev], [originalRow], suiteKey)[0]
|
|
820
|
-
const pinned: 'TRUE' | 'FALSE' =
|
|
821
|
-
(rowToWrite.pinned || '').toUpperCase() === 'TRUE' ? 'TRUE' : 'FALSE'
|
|
822
|
-
byTestId.set(testId, {
|
|
823
|
-
...rowToWrite,
|
|
824
|
-
test: originalRow,
|
|
825
|
-
agent: suiteKey,
|
|
826
|
-
test_id: testId,
|
|
827
|
-
run_timestamp: iso,
|
|
828
|
-
run_config: JSON.stringify(runConfig),
|
|
829
|
-
pinned_at_run: scope === 'all' || !!onlyTestId ? 'TRUE' : pinned,
|
|
830
|
-
run_scope: scope
|
|
831
|
-
})
|
|
832
|
-
body.rows = Array.from(byTestId.values())
|
|
833
|
-
await enqueueWrite()
|
|
834
|
-
}
|
|
835
|
-
}
|
|
883
|
+
metadata: { testId }
|
|
884
|
+
}) as any
|
|
885
|
+
)
|
|
886
|
+
} as PFEval
|
|
887
|
+
persistEvaluation(evaluation)
|
|
888
|
+
await enqueueWrite()
|
|
836
889
|
}
|
|
837
890
|
} finally {
|
|
891
|
+
if (previousIsTest == null) delete process.env.IS_TEST
|
|
892
|
+
else process.env.IS_TEST = previousIsTest
|
|
838
893
|
if (writeTimer) clearTimeout(writeTimer)
|
|
839
894
|
writeTimer = null
|
|
840
895
|
delete (globalThis as any)[hookKey]
|
|
@@ -844,6 +899,9 @@ export async function runPromptTests(
|
|
|
844
899
|
// Ensure the final report is written even if no tests ran (or an update was skipped).
|
|
845
900
|
body.rows = Array.from(byTestId.values())
|
|
846
901
|
await enqueueWrite()
|
|
902
|
+
void queueReportCompression(outPath).catch((error) => {
|
|
903
|
+
console.error(`Failed to compress completed test report ${path.basename(outPath)}`, error)
|
|
904
|
+
})
|
|
847
905
|
|
|
848
906
|
return body
|
|
849
907
|
}
|
|
@@ -107,9 +107,6 @@ export async function analyzeTraceQuotes(input: {
|
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
const conversation = decodeHtmlEntities(String(input.stringifiedConversation ?? ''))
|
|
110
|
-
if (!conversation) {
|
|
111
|
-
throw new Error('Missing conversation')
|
|
112
|
-
}
|
|
113
110
|
|
|
114
111
|
const resolvedModel = resolveModel(input.model)
|
|
115
112
|
if (!resolvedModel) {
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { mkdtemp, mkdir, readdir, readFile, rm, stat, utimes, writeFile } from 'node:fs/promises'
|
|
2
|
+
import os from 'node:os'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
5
|
+
|
|
6
|
+
const root = vi.hoisted(() => ({ path: '' }))
|
|
7
|
+
|
|
8
|
+
vi.mock('../lib/get-root-path', () => ({
|
|
9
|
+
getRootPath: async () => root.path
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
import { getRunResultEntry, loadLatestResultsByTest } from './data'
|
|
13
|
+
import { compressReportFile } from './report-files'
|
|
14
|
+
|
|
15
|
+
const temporaryDirectories: string[] = []
|
|
16
|
+
|
|
17
|
+
afterEach(async () => {
|
|
18
|
+
await Promise.all(temporaryDirectories.splice(0).map((dir) => rm(dir, { recursive: true })))
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
function testRow(id: string) {
|
|
22
|
+
return {
|
|
23
|
+
id,
|
|
24
|
+
pinned: 'TRUE',
|
|
25
|
+
scenario: id,
|
|
26
|
+
assertion_type: 'equals',
|
|
27
|
+
assertion_value: '',
|
|
28
|
+
conversation: 'user: hello',
|
|
29
|
+
expected_output: 'hello',
|
|
30
|
+
timeout: '0',
|
|
31
|
+
similarity_threshold: '50',
|
|
32
|
+
context: {}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function reportRow(testId: string, success: boolean) {
|
|
37
|
+
return {
|
|
38
|
+
test_id: testId,
|
|
39
|
+
pinned_at_run: 'TRUE',
|
|
40
|
+
success_rate_percent: success ? 100 : 0,
|
|
41
|
+
success_rate: success ? '1/1' : '0/1',
|
|
42
|
+
results: [
|
|
43
|
+
{
|
|
44
|
+
success,
|
|
45
|
+
result: `${testId}-${success ? 'pass' : 'fail'}`,
|
|
46
|
+
evaluation: '',
|
|
47
|
+
errors: ''
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function writeReport(dir: string, agent: string, timestamp: string, rows: unknown[]) {
|
|
54
|
+
const file = path.join(dir, `${agent}.${timestamp}.report.json`)
|
|
55
|
+
await writeFile(file, JSON.stringify({ rows }), 'utf8')
|
|
56
|
+
return file
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
describe('loadLatestResultsByTest', () => {
|
|
60
|
+
it('persists summaries and incrementally reads appended reports', async () => {
|
|
61
|
+
const projectDir = await mkdtemp(path.join(os.tmpdir(), 'bosun-latest-results-'))
|
|
62
|
+
temporaryDirectories.push(projectDir)
|
|
63
|
+
const bosunDir = path.join(projectDir, 'src', 'lib', 'bosun')
|
|
64
|
+
const reportDir = path.join(bosunDir, 'data', 'test_runs')
|
|
65
|
+
await mkdir(reportDir, { recursive: true })
|
|
66
|
+
root.path = path.join(bosunDir, 'index.ts')
|
|
67
|
+
|
|
68
|
+
const agent = `agent-${Date.now()}-${Math.random().toString(16).slice(2)}`
|
|
69
|
+
await writeFile(
|
|
70
|
+
path.join(bosunDir, `${agent}.tests.jsonl`),
|
|
71
|
+
[
|
|
72
|
+
JSON.stringify({ version: 1, meta: {} }),
|
|
73
|
+
JSON.stringify(testRow('a')),
|
|
74
|
+
JSON.stringify(testRow('b'))
|
|
75
|
+
].join('\n') + '\n',
|
|
76
|
+
'utf8'
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
const firstReport = await writeReport(reportDir, agent, '2026-07-16T10-00-00.000Z', [
|
|
80
|
+
reportRow('a', false),
|
|
81
|
+
reportRow('b', false)
|
|
82
|
+
])
|
|
83
|
+
await utimes(firstReport, 1_700_000_000, 1_700_000_000)
|
|
84
|
+
await writeReport(reportDir, agent, '2026-07-16T11-00-00.000Z', [reportRow('a', true)])
|
|
85
|
+
|
|
86
|
+
const initial = await loadLatestResultsByTest(agent)
|
|
87
|
+
expect(initial.a.results[0].success).toBe(true)
|
|
88
|
+
expect(initial.a.previous).toMatchObject({ success_count: 0, total_runs: 1 })
|
|
89
|
+
expect(initial.b.is_old).toBe(true)
|
|
90
|
+
|
|
91
|
+
expect((await readdir(reportDir)).some((name) => name.includes('latest-results'))).toBe(true)
|
|
92
|
+
|
|
93
|
+
// Keep the cached file signature but make the old report unreadable as JSON. An incremental
|
|
94
|
+
// update must only read the newly appended report and therefore still succeed.
|
|
95
|
+
const firstState = await stat(firstReport)
|
|
96
|
+
const original = await readFile(firstReport)
|
|
97
|
+
await writeFile(firstReport, Buffer.alloc(original.length, 0x20))
|
|
98
|
+
await utimes(firstReport, firstState.atimeMs / 1000, firstState.mtimeMs / 1000)
|
|
99
|
+
expect((await stat(firstReport)).mtimeMs).toBe(firstState.mtimeMs)
|
|
100
|
+
await writeReport(reportDir, agent, '2026-07-16T12-00-00.000Z', [reportRow('b', true)])
|
|
101
|
+
|
|
102
|
+
const updated = await loadLatestResultsByTest(agent)
|
|
103
|
+
expect(updated.a.is_old).toBe(true)
|
|
104
|
+
expect(updated.b.results[0]).toMatchObject({ success: true, result: 'b-pass' })
|
|
105
|
+
expect(updated.b.previous).toMatchObject({ success_count: 0, total_runs: 1 })
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('loads compressed reports and keeps the cache valid when the latest report is compressed', async () => {
|
|
109
|
+
const projectDir = await mkdtemp(path.join(os.tmpdir(), 'bosun-gzip-results-'))
|
|
110
|
+
temporaryDirectories.push(projectDir)
|
|
111
|
+
const bosunDir = path.join(projectDir, 'src', 'lib', 'bosun')
|
|
112
|
+
const reportDir = path.join(bosunDir, 'data', 'test_runs')
|
|
113
|
+
await mkdir(reportDir, { recursive: true })
|
|
114
|
+
root.path = path.join(bosunDir, 'index.ts')
|
|
115
|
+
|
|
116
|
+
const agent = `agent-${Date.now()}-${Math.random().toString(16).slice(2)}`
|
|
117
|
+
await writeFile(
|
|
118
|
+
path.join(bosunDir, `${agent}.tests.jsonl`),
|
|
119
|
+
[JSON.stringify({ version: 1, meta: {} }), JSON.stringify(testRow('a'))].join('\n') + '\n',
|
|
120
|
+
'utf8'
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
await compressReportFile(
|
|
124
|
+
await writeReport(reportDir, agent, '2026-07-16T10-00-00.000Z', [reportRow('a', false)])
|
|
125
|
+
)
|
|
126
|
+
const latestReport = await writeReport(reportDir, agent, '2026-07-16T11-00-00.000Z', [
|
|
127
|
+
reportRow('a', true)
|
|
128
|
+
])
|
|
129
|
+
|
|
130
|
+
const initial = await loadLatestResultsByTest(agent)
|
|
131
|
+
expect(initial.a.results[0].success).toBe(true)
|
|
132
|
+
expect(initial.a.previous).toMatchObject({ success_count: 0, total_runs: 1 })
|
|
133
|
+
|
|
134
|
+
await compressReportFile(latestReport)
|
|
135
|
+
const compressed = await loadLatestResultsByTest(agent)
|
|
136
|
+
expect(compressed.a.results[0]).toMatchObject({ success: true, result: 'a-pass' })
|
|
137
|
+
expect((await getRunResultEntry(agent, 'a')).success).toBe(true)
|
|
138
|
+
})
|
|
139
|
+
})
|