@recombine-ai/bosun 0.10.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/README.md +12 -0
- package/bin/bosun.js +3 -44
- 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/{Dp760K13.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/BoPSJr4b.js +1 -0
- 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/{CNLU4B3p.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/CVlsAO8k.js +11 -0
- 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/{DTXUDKH5.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/DXUXXCDA.js +1 -0
- 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/{CF66fWJN.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.BCmKHiYo.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.BdQ4KFOK.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.DWNYX1kH.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-C1mGPV-S.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-DblV-OAd.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/{Button-Dsy3QY7B.js → Button-BLigKkGG.js} +2 -2
- package/build/server/chunks/Button-BLigKkGG.js.map +1 -0
- package/build/server/chunks/{ChatStepTrace-1q74tVYO.js → ChatStepTrace-CqqIjRLU.js} +47 -11
- package/build/server/chunks/ChatStepTrace-CqqIjRLU.js.map +1 -0
- package/build/server/chunks/{Input-CHFlfduw.js → Input-OdQKNdS6.js} +1 -2
- package/build/server/chunks/Input-OdQKNdS6.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/Modal-DtVsRmmO.js.map +1 -1
- package/build/server/chunks/{_layout.svelte-DJ4kDgDL.js → _layout.svelte-B-CkD4a0.js} +14 -8
- package/build/server/chunks/_layout.svelte-B-CkD4a0.js.map +1 -0
- package/build/server/chunks/{_layout.svelte-B2lwUacy.js → _layout.svelte-BBFCF-xw.js} +8 -4
- 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-FufhMKh4.js → _page.svelte-0J2xaeyC.js} +71 -16
- 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-GaxktsuT.js → _page.svelte-C_S_qUgZ.js} +480 -72
- 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-CA3-vgl2.js → _page.svelte-Cxh9_vUl.js} +151 -100
- package/build/server/chunks/_page.svelte-Cxh9_vUl.js.map +1 -0
- package/build/server/chunks/_page.svelte-zOI_s_3J.js +2151 -0
- package/build/server/chunks/_page.svelte-zOI_s_3J.js.map +1 -0
- package/build/server/chunks/agents-context-rV2narXG.js.map +1 -1
- 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/edit-workspace-context-B1nYQ5hD.js.map +1 -1
- package/build/server/chunks/index-CSpGrMM2.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 +4 -4
- 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 +31 -0
- package/src/backend/lib/voice-agent-lifecycle.ts +16 -0
- package/src/backend/roleplay/agents.ts +189 -69
- package/src/backend/roleplay/message-dispatcher.ts +0 -7
- package/src/backend/roleplay/router.ts +14 -17
- package/src/backend/roleplay/trace-serialization.spec.ts +35 -0
- package/src/backend/roleplay/trace-serialization.ts +57 -0
- package/src/backend/roleplay/variants.ts +33 -49
- package/src/backend/tests/academy.ts +202 -100
- package/src/backend/tests/analyze.ts +0 -3
- package/src/backend/tests/data.spec.ts +139 -0
- package/src/backend/tests/data.ts +452 -68
- package/src/backend/tests/emulate-agents.ts +60 -44
- 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 +28 -2
- package/src/backend/tests/suite.ts +13 -4
- package/build/client/_app/immutable/assets/0.B4t3dozz.css +0 -1
- package/build/client/_app/immutable/assets/0.B4t3dozz.css.br +0 -0
- package/build/client/_app/immutable/assets/0.B4t3dozz.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/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/Ajb1KYIn.js +0 -1
- package/build/client/_app/immutable/chunks/Ajb1KYIn.js.br +0 -0
- package/build/client/_app/immutable/chunks/Ajb1KYIn.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/BM0jKynj.js.br +0 -0
- package/build/client/_app/immutable/chunks/BM0jKynj.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/BwtfALfL.js +0 -11
- package/build/client/_app/immutable/chunks/BwtfALfL.js.br +0 -0
- package/build/client/_app/immutable/chunks/BwtfALfL.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BxsDwlgp.js +0 -4
- package/build/client/_app/immutable/chunks/BxsDwlgp.js.br +0 -0
- package/build/client/_app/immutable/chunks/BxsDwlgp.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/C4D-JXnS.js +0 -1
- package/build/client/_app/immutable/chunks/C4D-JXnS.js.br +0 -0
- package/build/client/_app/immutable/chunks/C4D-JXnS.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/CF66fWJN.js.br +0 -0
- package/build/client/_app/immutable/chunks/CF66fWJN.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CNLU4B3p.js.br +0 -0
- package/build/client/_app/immutable/chunks/CNLU4B3p.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/CqO5tR2_.js +0 -1
- package/build/client/_app/immutable/chunks/CqO5tR2_.js.br +0 -0
- package/build/client/_app/immutable/chunks/CqO5tR2_.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/D-wf2QNc.js +0 -1
- package/build/client/_app/immutable/chunks/D-wf2QNc.js.br +0 -0
- package/build/client/_app/immutable/chunks/D-wf2QNc.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/DTXUDKH5.js.br +0 -0
- package/build/client/_app/immutable/chunks/DTXUDKH5.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/DhBm2Vx9.js +0 -1
- package/build/client/_app/immutable/chunks/DhBm2Vx9.js.br +0 -0
- package/build/client/_app/immutable/chunks/DhBm2Vx9.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Dp760K13.js.br +0 -0
- package/build/client/_app/immutable/chunks/Dp760K13.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/_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/xebNt8-Z.js +0 -1
- package/build/client/_app/immutable/chunks/xebNt8-Z.js.br +0 -0
- package/build/client/_app/immutable/chunks/xebNt8-Z.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.C4wJtvtH.js +0 -2
- package/build/client/_app/immutable/entry/app.C4wJtvtH.js.br +0 -0
- package/build/client/_app/immutable/entry/app.C4wJtvtH.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.BId2vqhS.js +0 -1
- package/build/client/_app/immutable/entry/start.BId2vqhS.js.br +0 -2
- package/build/client/_app/immutable/entry/start.BId2vqhS.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.BCmKHiYo.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.BCmKHiYo.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.8skEZBEw.js +0 -1
- package/build/client/_app/immutable/nodes/1.8skEZBEw.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.8skEZBEw.js.gz +0 -0
- package/build/client/_app/immutable/nodes/10.YgmBfSWN.js +0 -5
- package/build/client/_app/immutable/nodes/10.YgmBfSWN.js.br +0 -0
- package/build/client/_app/immutable/nodes/10.YgmBfSWN.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.D8ydco6g.js +0 -3
- package/build/client/_app/immutable/nodes/17.D8ydco6g.js.br +0 -0
- package/build/client/_app/immutable/nodes/17.D8ydco6g.js.gz +0 -0
- package/build/client/_app/immutable/nodes/18.C67CqGm5.js +0 -11
- package/build/client/_app/immutable/nodes/18.C67CqGm5.js.br +0 -0
- package/build/client/_app/immutable/nodes/18.C67CqGm5.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.BdQ4KFOK.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.BdQ4KFOK.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.nCmkz6kS.js +0 -1
- package/build/client/_app/immutable/nodes/3.nCmkz6kS.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.nCmkz6kS.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.DAwO0_Am.js +0 -1
- package/build/client/_app/immutable/nodes/4.DAwO0_Am.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.DAwO0_Am.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.C_SvvZjG.js +0 -1
- package/build/client/_app/immutable/nodes/5.C_SvvZjG.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.C_SvvZjG.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.DfOe9lph.js +0 -1
- package/build/client/_app/immutable/nodes/6.DfOe9lph.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.DfOe9lph.js.gz +0 -0
- package/build/client/_app/immutable/nodes/8.DWNYX1kH.js.br +0 -0
- package/build/client/_app/immutable/nodes/8.DWNYX1kH.js.gz +0 -0
- package/build/client/_app/immutable/nodes/9.D7SG4T7Z.js +0 -2
- package/build/client/_app/immutable/nodes/9.D7SG4T7Z.js.br +0 -0
- package/build/client/_app/immutable/nodes/9.D7SG4T7Z.js.gz +0 -0
- package/build/server/chunks/0-D5BNSI7t.js +0 -9
- package/build/server/chunks/0-D5BNSI7t.js.map +0 -1
- package/build/server/chunks/1-C1mGPV-S.js +0 -9
- package/build/server/chunks/10-BUo1e_HG.js +0 -9
- package/build/server/chunks/10-BUo1e_HG.js.map +0 -1
- package/build/server/chunks/17-iNFqG1My.js +0 -9
- package/build/server/chunks/17-iNFqG1My.js.map +0 -1
- package/build/server/chunks/18-u8T5X6fM.js +0 -9
- package/build/server/chunks/18-u8T5X6fM.js.map +0 -1
- package/build/server/chunks/2-tLlSByHA.js +0 -9
- package/build/server/chunks/2-tLlSByHA.js.map +0 -1
- package/build/server/chunks/3-D1KY9yVZ.js +0 -9
- package/build/server/chunks/3-D1KY9yVZ.js.map +0 -1
- package/build/server/chunks/4-7zu0cJha.js +0 -9
- package/build/server/chunks/4-7zu0cJha.js.map +0 -1
- package/build/server/chunks/5-DblV-OAd.js +0 -9
- package/build/server/chunks/6-BDC5budM.js +0 -9
- package/build/server/chunks/6-BDC5budM.js.map +0 -1
- package/build/server/chunks/8-DhmD-opq.js +0 -9
- package/build/server/chunks/8-DhmD-opq.js.map +0 -1
- package/build/server/chunks/9-BGj28GI6.js +0 -9
- package/build/server/chunks/9-BGj28GI6.js.map +0 -1
- package/build/server/chunks/AgentSidebar-XdGj1sqT.js.map +0 -1
- package/build/server/chunks/Button-Dsy3QY7B.js.map +0 -1
- package/build/server/chunks/ChatStepTrace-1q74tVYO.js.map +0 -1
- package/build/server/chunks/Input-CHFlfduw.js.map +0 -1
- package/build/server/chunks/_layout.svelte-B2lwUacy.js.map +0 -1
- package/build/server/chunks/_layout.svelte-C7JgNCIu.js.map +0 -1
- package/build/server/chunks/_layout.svelte-DJ4kDgDL.js.map +0 -1
- package/build/server/chunks/_page.svelte-Bl1WcAXy.js +0 -671
- package/build/server/chunks/_page.svelte-Bl1WcAXy.js.map +0 -1
- package/build/server/chunks/_page.svelte-CA3-vgl2.js.map +0 -1
- package/build/server/chunks/_page.svelte-DDpBtd3X.js.map +0 -1
- package/build/server/chunks/_page.svelte-FufhMKh4.js.map +0 -1
- package/build/server/chunks/_page.svelte-GaxktsuT.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
|
@@ -28,28 +28,30 @@ export async function generateReplyVariants(props: {
|
|
|
28
28
|
agentId: string
|
|
29
29
|
region?: string | null
|
|
30
30
|
states: AgentState[]
|
|
31
|
-
prevStateId: string | null
|
|
32
|
-
rawUserMessage: string
|
|
33
31
|
count: number
|
|
34
32
|
context: Record<string, any>
|
|
35
33
|
}): Promise<GeneratedVariant[]> {
|
|
36
|
-
const { agentId, region, states,
|
|
34
|
+
const { agentId, region, states, count, context } = props
|
|
37
35
|
if (!Number.isFinite(count) || count <= 0) return []
|
|
36
|
+
const targetState = states.at(-1)
|
|
37
|
+
if (!targetState) throw new Error('No saved roleplay state found for variants')
|
|
38
38
|
|
|
39
39
|
const rootPath = await getRootPath()
|
|
40
40
|
const { factories } = await getAgentFactories(rootPath, getImportNonce())
|
|
41
41
|
const factory = factories[agentId]
|
|
42
42
|
if (!factory) throw new Error(`Cannot find agent ${agentId}`)
|
|
43
43
|
|
|
44
|
-
const statesById = new Map
|
|
45
|
-
for (const state of states) statesById.set(state.id, clone(state))
|
|
44
|
+
const statesById = new Map(states.map((state) => [state.id, clone(state)]))
|
|
46
45
|
|
|
46
|
+
const prevStateId = targetState.prev
|
|
47
47
|
const prevState = prevStateId ? (statesById.get(prevStateId) ?? null) : null
|
|
48
48
|
if (prevStateId && !prevState) {
|
|
49
49
|
throw new Error('Could not find the previous roleplay state for this reply')
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
const message =
|
|
52
|
+
const message = latestInputMessage(targetState)
|
|
53
|
+
if (!message) throw new Error('Could not reconstruct the input message for variants')
|
|
54
|
+
|
|
53
55
|
return Promise.all(
|
|
54
56
|
Array.from({ length: count }, (_, index) =>
|
|
55
57
|
generateSingleReplyVariant({
|
|
@@ -59,7 +61,6 @@ export async function generateReplyVariants(props: {
|
|
|
59
61
|
context,
|
|
60
62
|
prevState,
|
|
61
63
|
statesById,
|
|
62
|
-
rawUserMessage,
|
|
63
64
|
message
|
|
64
65
|
})
|
|
65
66
|
)
|
|
@@ -84,20 +85,6 @@ export function replaceSavedState(
|
|
|
84
85
|
return next
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
function parseRawUserMessage(raw: string): Message {
|
|
88
|
-
const trimmed = String(raw ?? '').trim()
|
|
89
|
-
if (!trimmed) throw new Error('Could not reconstruct the user message for variants')
|
|
90
|
-
|
|
91
|
-
const imageMatch = /^\[image\]\s+(.+)$/u.exec(trimmed)
|
|
92
|
-
if (imageMatch) {
|
|
93
|
-
const imageUrl = (imageMatch[1] ?? '').trim()
|
|
94
|
-
if (!imageUrl) throw new Error('Image variant message is missing its URL')
|
|
95
|
-
return { sender: 'user', text: '', imageUrl }
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return { sender: 'user', text: trimmed }
|
|
99
|
-
}
|
|
100
|
-
|
|
101
88
|
function collectMessagesUpToState(
|
|
102
89
|
statesById: Map<string, AgentState>,
|
|
103
90
|
stateId: string | null
|
|
@@ -124,30 +111,32 @@ function collectMessagesUpToState(
|
|
|
124
111
|
}
|
|
125
112
|
|
|
126
113
|
function collectMessagesFromHistory(history: AgentState['history']): Message[] {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
114
|
+
return history.filter((entry) => entry.type === 'message').map((entry) => entry.payload)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function latestInputMessage(state: AgentState): Message | null {
|
|
118
|
+
const entry = [...state.history]
|
|
119
|
+
.reverse()
|
|
120
|
+
.find(
|
|
121
|
+
(entry) =>
|
|
122
|
+
entry.type === 'message' &&
|
|
123
|
+
(entry.payload.sender === 'user' || entry.payload.sender === 'system')
|
|
124
|
+
)
|
|
125
|
+
return entry ? clone(entry.payload as Message) : null
|
|
133
126
|
}
|
|
134
127
|
|
|
135
128
|
function extractVariantText(state: AgentState): string {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
}
|
|
129
|
+
const traceEntry = [...state.history].reverse().find((entry) => {
|
|
130
|
+
if (entry.type !== 'conversational-trace') return false
|
|
131
|
+
const trace = entry.payload
|
|
132
|
+
return trace.eventName === 'finished-main-streaming-step' || trace.eventName === 'sent-message'
|
|
133
|
+
})
|
|
134
|
+
if (traceEntry) return String((traceEntry.payload as ConversationalTrace).content ?? '')
|
|
144
135
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (payload.sender === 'agent') return String(payload.text ?? '')
|
|
150
|
-
}
|
|
136
|
+
const messageEntry = [...state.history]
|
|
137
|
+
.reverse()
|
|
138
|
+
.find((entry) => entry.type === 'message' && entry.payload.sender === 'agent')
|
|
139
|
+
if (messageEntry) return String((messageEntry.payload as Message).text ?? '')
|
|
151
140
|
|
|
152
141
|
return ''
|
|
153
142
|
}
|
|
@@ -171,10 +160,9 @@ async function generateSingleReplyVariant(props: {
|
|
|
171
160
|
context: Record<string, any>
|
|
172
161
|
prevState: AgentState | null
|
|
173
162
|
statesById: Map<string, AgentState>
|
|
174
|
-
rawUserMessage: string
|
|
175
163
|
message: Message
|
|
176
164
|
}): Promise<GeneratedVariant> {
|
|
177
|
-
const { index, factory, region, context, prevState, statesById,
|
|
165
|
+
const { index, factory, region, context, prevState, statesById, message } = props
|
|
178
166
|
|
|
179
167
|
const state = createVariantState(prevState?.id ?? null, index)
|
|
180
168
|
const scheduleSeed = clone(prevState?.schedule ?? {})
|
|
@@ -212,9 +200,6 @@ async function generateSingleReplyVariant(props: {
|
|
|
212
200
|
}
|
|
213
201
|
const conversationalTracer: ConversationalTracer = {
|
|
214
202
|
addConversationalTrace: (trace: ConversationalTrace) => {
|
|
215
|
-
;(trace as any).bosunStateId = state.id
|
|
216
|
-
;(trace as any).bosunPrevStateId = state.prev
|
|
217
|
-
;(trace as any).bosunUserMessage = rawUserMessage
|
|
218
203
|
state.history.push({
|
|
219
204
|
type: 'conversational-trace',
|
|
220
205
|
payload: trace
|
|
@@ -228,9 +213,6 @@ async function generateSingleReplyVariant(props: {
|
|
|
228
213
|
const current = (ctx.get() as Record<string, unknown> | null | undefined) || {}
|
|
229
214
|
ctx.set({ ...current, recombineRegion: region })
|
|
230
215
|
}
|
|
231
|
-
if (context && typeof context === 'object') {
|
|
232
|
-
ctx.swap(region ? { ...context, recombineRegion: region } : context)
|
|
233
|
-
}
|
|
234
216
|
|
|
235
217
|
const getMessages = () => [
|
|
236
218
|
...collectMessagesUpToState(statesById, state.prev),
|
|
@@ -263,6 +245,8 @@ async function generateSingleReplyVariant(props: {
|
|
|
263
245
|
}
|
|
264
246
|
})
|
|
265
247
|
|
|
248
|
+
ctx.swap(region ? { ...context, recombineRegion: region } : context)
|
|
249
|
+
|
|
266
250
|
scheduler.setState(scheduleSeed)
|
|
267
251
|
|
|
268
252
|
if (!state.prev && hasStart(agent)) {
|
|
@@ -1,21 +1,27 @@
|
|
|
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'
|
|
10
9
|
import path from 'node:path'
|
|
11
|
-
import { readSuite } from './suite'
|
|
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>
|
|
@@ -30,9 +36,13 @@ interface CsvRow {
|
|
|
30
36
|
expected_output: string
|
|
31
37
|
similarity_threshold: number | string
|
|
32
38
|
pinned: 'TRUE' | 'FALSE'
|
|
33
|
-
context: string
|
|
39
|
+
context: string | Record<string, unknown>
|
|
40
|
+
mocks?: string | Record<string, unknown>
|
|
34
41
|
timeout: string
|
|
42
|
+
capture_mode?: string
|
|
35
43
|
scenario?: string
|
|
44
|
+
step?: string
|
|
45
|
+
author?: string
|
|
36
46
|
}
|
|
37
47
|
|
|
38
48
|
export interface ResultEntry {
|
|
@@ -65,6 +75,7 @@ export interface WrittenRunReportConfig {
|
|
|
65
75
|
}
|
|
66
76
|
|
|
67
77
|
export interface WrittenRunReportRow extends TableRow {
|
|
78
|
+
test: SuiteTestRow
|
|
68
79
|
agent: string
|
|
69
80
|
test_id: string
|
|
70
81
|
run_timestamp: string
|
|
@@ -84,9 +95,34 @@ export interface WrittenRunReport {
|
|
|
84
95
|
type PromptTestsScope = 'all' | 'pinned'
|
|
85
96
|
|
|
86
97
|
type PromptTestsSelection = { scope: PromptTestsScope } | { testId: string }
|
|
98
|
+
type CaptureMode = 'immediate' | 'final'
|
|
87
99
|
|
|
88
100
|
const activeRunsBySuiteKey = new Map<string, AbortController>()
|
|
89
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
|
+
|
|
90
126
|
export type SuiteSelection = {
|
|
91
127
|
// `suiteKey` is the filesystem/report key (e.g. `voiceSupport.en-gb`).
|
|
92
128
|
// `agentId` is the canonical factory key (workflow export key, e.g. `voiceSupport`).
|
|
@@ -116,6 +152,7 @@ export async function runPromptTestsManaged(
|
|
|
116
152
|
return await runPromptTests(suite, selection, { signal: controller.signal })
|
|
117
153
|
} finally {
|
|
118
154
|
activeRunsBySuiteKey.delete(suite.suiteKey)
|
|
155
|
+
activeProgressBySuiteKey.delete(suite.suiteKey)
|
|
119
156
|
}
|
|
120
157
|
}
|
|
121
158
|
|
|
@@ -209,7 +246,7 @@ function toTestInputs(
|
|
|
209
246
|
value: row.assertion_value
|
|
210
247
|
},
|
|
211
248
|
{
|
|
212
|
-
type: 'similar' as
|
|
249
|
+
type: 'similar' as const,
|
|
213
250
|
value: String(row.expected_output),
|
|
214
251
|
threshold: Number(row.similarity_threshold) / 100
|
|
215
252
|
}
|
|
@@ -217,7 +254,9 @@ function toTestInputs(
|
|
|
217
254
|
context: (() => {
|
|
218
255
|
const testCtx = makeContext(row.context)
|
|
219
256
|
return defaultContext ? mergeContexts(defaultContext, testCtx) : testCtx
|
|
220
|
-
})()
|
|
257
|
+
})(),
|
|
258
|
+
captureMode: row.capture_mode === 'final' ? 'final' : 'immediate',
|
|
259
|
+
mocks: typeof row.mocks === 'undefined' ? undefined : makeContext(row.mocks)
|
|
221
260
|
}
|
|
222
261
|
})
|
|
223
262
|
}
|
|
@@ -226,6 +265,7 @@ export class RecombineAgentProvider implements ApiProvider {
|
|
|
226
265
|
protected providerId: string
|
|
227
266
|
public config: Record<string, unknown>
|
|
228
267
|
private abortSignal?: AbortSignal
|
|
268
|
+
private onTestStarted?: (testId: string) => void
|
|
229
269
|
|
|
230
270
|
constructor(options: ProviderOptions) {
|
|
231
271
|
this.providerId = options.id || 'recombine-agent'
|
|
@@ -236,6 +276,10 @@ export class RecombineAgentProvider implements ApiProvider {
|
|
|
236
276
|
this.abortSignal = signal
|
|
237
277
|
}
|
|
238
278
|
|
|
279
|
+
setOnTestStarted(callback: (testId: string) => void) {
|
|
280
|
+
this.onTestStarted = callback
|
|
281
|
+
}
|
|
282
|
+
|
|
239
283
|
id() {
|
|
240
284
|
return this.providerId
|
|
241
285
|
}
|
|
@@ -244,17 +288,25 @@ export class RecombineAgentProvider implements ApiProvider {
|
|
|
244
288
|
const projectRoot = path.dirname(await getRootPath())
|
|
245
289
|
const vars = (context?.vars || {}) as unknown as {
|
|
246
290
|
agentId: string
|
|
291
|
+
testId: string
|
|
247
292
|
region?: string
|
|
248
293
|
conversation: Conversation
|
|
249
294
|
conversationParseError?: string
|
|
250
295
|
context: Context
|
|
296
|
+
mocks?: Context
|
|
297
|
+
captureMode?: CaptureMode | string
|
|
251
298
|
}
|
|
299
|
+
const testId = String(vars.testId ?? '')
|
|
300
|
+
if (testId) this.onTestStarted?.(testId)
|
|
252
301
|
|
|
253
302
|
if (typeof vars.conversationParseError === 'string' && vars.conversationParseError.trim()) {
|
|
254
303
|
return { output: '', error: vars.conversationParseError }
|
|
255
304
|
}
|
|
256
305
|
|
|
306
|
+
const captureMode: CaptureMode = vars.captureMode === 'final' ? 'final' : 'immediate'
|
|
257
307
|
let captured: string = ''
|
|
308
|
+
let captureEnabled = false
|
|
309
|
+
const finalCaptureErrors: string[] = []
|
|
258
310
|
const capturedLogs: string[] = []
|
|
259
311
|
const capturedStepTraces: StepTrace[] = []
|
|
260
312
|
|
|
@@ -265,7 +317,7 @@ export class RecombineAgentProvider implements ApiProvider {
|
|
|
265
317
|
// Clone the conversation so parallel runs don't share the same array reference.
|
|
266
318
|
// Shallow-clone each message; messages are simple { sender, text } objects in this flow.
|
|
267
319
|
const conv: Conversation = Array.isArray(vars.conversation)
|
|
268
|
-
?
|
|
320
|
+
? vars.conversation.map((m) => ({ ...m }))
|
|
269
321
|
: []
|
|
270
322
|
|
|
271
323
|
// Prepare a streaming log writer so logs are written as they occur
|
|
@@ -280,7 +332,6 @@ export class RecombineAgentProvider implements ApiProvider {
|
|
|
280
332
|
const stepTracer: StepTracer = {
|
|
281
333
|
addStepTrace: (stepTrace: StepTrace) => {
|
|
282
334
|
try {
|
|
283
|
-
console.log(`trace: ${stepTrace.name}`)
|
|
284
335
|
capturedStepTraces.push(stepTrace)
|
|
285
336
|
} catch {
|
|
286
337
|
// best-effort capture; ignore serialization issues
|
|
@@ -307,6 +358,9 @@ export class RecombineAgentProvider implements ApiProvider {
|
|
|
307
358
|
line = line.slice(0, 5000) + '... [TRUNCATED]'
|
|
308
359
|
}
|
|
309
360
|
capturedLogs.push(line)
|
|
361
|
+
if (captureMode === 'final' && captureEnabled && level === 'error') {
|
|
362
|
+
finalCaptureErrors.push(line)
|
|
363
|
+
}
|
|
310
364
|
try {
|
|
311
365
|
logStream.write(line + '\n')
|
|
312
366
|
} catch {
|
|
@@ -331,14 +385,24 @@ export class RecombineAgentProvider implements ApiProvider {
|
|
|
331
385
|
getMessages: () => conv,
|
|
332
386
|
sendMessage: async (message: Message | string) => {
|
|
333
387
|
const m = typeof message === 'string' ? { sender: 'agent', text: message } : message
|
|
334
|
-
if (m.sender === 'agent') {
|
|
335
|
-
|
|
336
|
-
|
|
388
|
+
if (captureEnabled && m.sender === 'agent') {
|
|
389
|
+
const text = typeof m.text === 'string' ? m.text : JSON.stringify(m)
|
|
390
|
+
if (captureMode === 'final' || !captured) {
|
|
391
|
+
captured = text
|
|
392
|
+
logger.log('Agent message captured:', captured)
|
|
393
|
+
} else {
|
|
394
|
+
logger.log('Agent message ignored after immediate capture:', text)
|
|
395
|
+
}
|
|
337
396
|
}
|
|
338
397
|
},
|
|
398
|
+
onBeforeTestResponse: () => {
|
|
399
|
+
captured = ''
|
|
400
|
+
captureEnabled = true
|
|
401
|
+
},
|
|
339
402
|
stepTracer,
|
|
340
403
|
logger,
|
|
341
404
|
context: vars.context || {},
|
|
405
|
+
mocks: vars.mocks,
|
|
342
406
|
abortSignal: this.abortSignal
|
|
343
407
|
})
|
|
344
408
|
|
|
@@ -378,6 +442,19 @@ export class RecombineAgentProvider implements ApiProvider {
|
|
|
378
442
|
? capturedStepTraces.map(sanitizeTrace)
|
|
379
443
|
: []
|
|
380
444
|
|
|
445
|
+
if (captureMode === 'final' && finalCaptureErrors.length > 0) {
|
|
446
|
+
const detail = finalCaptureErrors.at(-1) ?? 'Unknown final capture error'
|
|
447
|
+
return {
|
|
448
|
+
output: captured,
|
|
449
|
+
error: `Final capture failed because a subsequent step emitted an error: ${detail}`,
|
|
450
|
+
metadata: {
|
|
451
|
+
logs: capturedLogs,
|
|
452
|
+
stepTraces: sanitizedStepTraces,
|
|
453
|
+
rawStepTraces: capturedStepTraces
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
381
458
|
if (captured && captured.trim()) {
|
|
382
459
|
return {
|
|
383
460
|
output: captured,
|
|
@@ -399,6 +476,7 @@ export class RecombineAgentProvider implements ApiProvider {
|
|
|
399
476
|
}
|
|
400
477
|
}
|
|
401
478
|
} catch (err) {
|
|
479
|
+
if (this.abortSignal?.aborted) throw err
|
|
402
480
|
const msg = err instanceof Error ? `${err.name}: ${err.message}` : String(err)
|
|
403
481
|
capturedLogs.push(`[ERROR] ${msg}`)
|
|
404
482
|
try {
|
|
@@ -531,15 +609,15 @@ export async function runPromptTests(
|
|
|
531
609
|
const onlyTestId = 'testId' in selection ? selection.testId : undefined
|
|
532
610
|
const suiteKey = suite.suiteKey
|
|
533
611
|
const loadedSuite = await readSuite(suiteKey)
|
|
534
|
-
const rows = loadedSuite.tests
|
|
612
|
+
const rows = loadedSuite.tests
|
|
535
613
|
const cfg = (await tryReadConfig(suiteKey)) || {}
|
|
536
614
|
|
|
537
615
|
const repeats = Number(cfg?.repeats ?? 1)
|
|
538
|
-
const concurrency = Number(cfg?.concurrency ??
|
|
616
|
+
const concurrency = Math.min(75, Math.max(1, Math.floor(Number(cfg?.concurrency ?? 75))))
|
|
539
617
|
const baseContext = loadedSuite?.meta?.defaultContext || {}
|
|
540
618
|
|
|
541
619
|
// Add an index field to each row for mapping
|
|
542
|
-
const typedRows = rows
|
|
620
|
+
const typedRows = rows
|
|
543
621
|
const indexedRows = typedRows.map((row, index) => ({ ...row, index }))
|
|
544
622
|
|
|
545
623
|
if (onlyTestId && !indexedRows.some((row) => String(row.id ?? '') === String(onlyTestId))) {
|
|
@@ -547,12 +625,27 @@ export async function runPromptTests(
|
|
|
547
625
|
}
|
|
548
626
|
|
|
549
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)
|
|
550
638
|
|
|
551
639
|
// Provider function with stable label
|
|
552
640
|
const providerInstance = new RecombineAgentProvider({
|
|
553
641
|
id: 'recombine-agent'
|
|
554
642
|
})
|
|
555
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
|
+
})
|
|
556
649
|
const providerFn = Object.assign(
|
|
557
650
|
(_promptStr: string, ctx?: CallApiContextParams) => {
|
|
558
651
|
if (signal?.aborted) {
|
|
@@ -566,37 +659,40 @@ export async function runPromptTests(
|
|
|
566
659
|
const hookKey = `__bosun_promptfoo_hook_${process.pid}_${Date.now()}_${Math.random().toString(16).slice(2)}`
|
|
567
660
|
const extensionCode = `globalThis[${JSON.stringify(hookKey)}]?.(output, context)`
|
|
568
661
|
|
|
569
|
-
const
|
|
662
|
+
const testSuite = {
|
|
570
663
|
prompts: ['agent-run'], // placeholder; provider ignores
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
{
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
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
|
+
: {})
|
|
586
680
|
}
|
|
587
|
-
|
|
681
|
+
})),
|
|
588
682
|
providers: [providerFn],
|
|
589
683
|
extensions: [extensionCode]
|
|
590
|
-
}
|
|
684
|
+
}
|
|
591
685
|
|
|
592
|
-
const
|
|
686
|
+
const rootPath = await getRootPath()
|
|
687
|
+
installTestPromptCacheBust(rootPath)
|
|
688
|
+
const projectRoot = path.dirname(rootPath)
|
|
593
689
|
const outDir = path.join(projectRoot, 'data', 'test_runs')
|
|
594
690
|
await mkdir(outDir, { recursive: true })
|
|
595
691
|
|
|
596
692
|
// Use full ISO timestamp and sanitize ':' for filesystem safety
|
|
597
693
|
const iso = new Date().toISOString()
|
|
598
694
|
const isoFile = iso.replace(/:/g, '-')
|
|
599
|
-
const outPath = path.join(outDir, `${suiteKey}.${isoFile}
|
|
695
|
+
const outPath = path.join(outDir, `${suiteKey}.${isoFile}${REPORT_JSON_SUFFIX}`)
|
|
600
696
|
|
|
601
697
|
async function writeReport(report: WrittenRunReport) {
|
|
602
698
|
const dir = path.dirname(outPath)
|
|
@@ -639,7 +735,7 @@ export async function runPromptTests(
|
|
|
639
735
|
|
|
640
736
|
const byTestId = new Map<string, WrittenRunReportRow>()
|
|
641
737
|
|
|
642
|
-
const originalRowById = new Map<string,
|
|
738
|
+
const originalRowById = new Map<string, SuiteTestRow>()
|
|
643
739
|
for (const r of typedRows) {
|
|
644
740
|
const id = String((r as any)?.id ?? '').trim()
|
|
645
741
|
if (id) originalRowById.set(id, r)
|
|
@@ -685,6 +781,7 @@ export async function runPromptTests(
|
|
|
685
781
|
String((originalRow as any).pinned || '').toUpperCase() === 'TRUE' ? 'TRUE' : 'FALSE'
|
|
686
782
|
const nextRow: WrittenRunReportRow = {
|
|
687
783
|
...(originalRow as any),
|
|
784
|
+
test: originalRow,
|
|
688
785
|
prompts: `suite://${suiteKey}?testId=${testId}`,
|
|
689
786
|
success_rate_percent: 0,
|
|
690
787
|
success_rate: '0/0',
|
|
@@ -704,6 +801,15 @@ export async function runPromptTests(
|
|
|
704
801
|
|
|
705
802
|
const entry = toResultEntry(r)
|
|
706
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
|
+
}
|
|
707
813
|
|
|
708
814
|
const counts = countsByTestId.get(testId) ?? { pass: 0, total: 0 }
|
|
709
815
|
counts.total += 1
|
|
@@ -722,75 +828,68 @@ export async function runPromptTests(
|
|
|
722
828
|
}
|
|
723
829
|
}
|
|
724
830
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
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
|
+
}
|
|
738
854
|
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
results: [
|
|
765
|
-
{
|
|
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
|
+
({
|
|
766
880
|
success: false,
|
|
767
881
|
response: { output: '' },
|
|
768
882
|
error: msg,
|
|
769
|
-
metadata: { testId
|
|
770
|
-
} as any
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
if (originalRow && testId) {
|
|
776
|
-
const rowToWrite = buildTableRows([ev], [originalRow], suiteKey)[0]
|
|
777
|
-
const pinned: 'TRUE' | 'FALSE' =
|
|
778
|
-
(rowToWrite.pinned || '').toUpperCase() === 'TRUE' ? 'TRUE' : 'FALSE'
|
|
779
|
-
byTestId.set(testId, {
|
|
780
|
-
...rowToWrite,
|
|
781
|
-
agent: suiteKey,
|
|
782
|
-
test_id: testId,
|
|
783
|
-
run_timestamp: iso,
|
|
784
|
-
run_config: JSON.stringify(runConfig),
|
|
785
|
-
pinned_at_run: scope === 'all' || !!onlyTestId ? 'TRUE' : pinned,
|
|
786
|
-
run_scope: scope
|
|
787
|
-
})
|
|
788
|
-
body.rows = Array.from(byTestId.values())
|
|
789
|
-
await enqueueWrite()
|
|
790
|
-
}
|
|
791
|
-
}
|
|
883
|
+
metadata: { testId }
|
|
884
|
+
}) as any
|
|
885
|
+
)
|
|
886
|
+
} as PFEval
|
|
887
|
+
persistEvaluation(evaluation)
|
|
888
|
+
await enqueueWrite()
|
|
792
889
|
}
|
|
793
890
|
} finally {
|
|
891
|
+
if (previousIsTest == null) delete process.env.IS_TEST
|
|
892
|
+
else process.env.IS_TEST = previousIsTest
|
|
794
893
|
if (writeTimer) clearTimeout(writeTimer)
|
|
795
894
|
writeTimer = null
|
|
796
895
|
delete (globalThis as any)[hookKey]
|
|
@@ -800,6 +899,9 @@ export async function runPromptTests(
|
|
|
800
899
|
// Ensure the final report is written even if no tests ran (or an update was skipped).
|
|
801
900
|
body.rows = Array.from(byTestId.values())
|
|
802
901
|
await enqueueWrite()
|
|
902
|
+
void queueReportCompression(outPath).catch((error) => {
|
|
903
|
+
console.error(`Failed to compress completed test report ${path.basename(outPath)}`, error)
|
|
904
|
+
})
|
|
803
905
|
|
|
804
906
|
return body
|
|
805
907
|
}
|