@cursor/july 0.1.111 → 0.1.112
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/dist/bin/agent-serve.js +18 -1
- package/dist/channels/github/github-channel.d.ts +29 -19
- package/dist/channels/github/github-channel.d.ts.map +1 -1
- package/dist/channels/github/github-channel.js +29 -19
- package/dist/channels/slack/agentic-delivery.d.ts.map +1 -1
- package/dist/channels/slack/agentic-delivery.js +2 -0
- package/dist/channels/slack/dispatch.d.ts +11 -1
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +142 -39
- package/dist/channels/slack/placeholder.d.ts +26 -0
- package/dist/channels/slack/placeholder.d.ts.map +1 -1
- package/dist/channels/slack/placeholder.js +28 -0
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +9 -16
- package/dist/docs/404.html +2 -2
- package/dist/docs/assets/{app.Drol6mi6.js → app.DxTdhphC.js} +4 -4
- package/dist/docs/assets/building-with-agents.md.BBCx0AUo.js +9 -0
- package/dist/docs/assets/building-with-agents.md.BBCx0AUo.lean.js +1 -0
- package/dist/docs/assets/chunks/@localSearchIndexroot.QmjDU6Jh.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.CdqoBZJX.js → VPLocalSearchBox.CR3KTF0X.js} +1 -1
- package/dist/docs/assets/chunks/{arc.BVX3ycTn.js → arc.CVVqBOdS.js} +1 -1
- package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.CcChnMxX.js → architectureDiagram-Q4EWVU46.CJHGP4ki.js} +1 -1
- package/dist/docs/assets/chunks/{baseUniq.xwtXO-yt.js → baseUniq.r7UVVRBP.js} +1 -1
- package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.CijZ_taK.js → blockDiagram-DXYQGD6D.DKmMaTre.js} +1 -1
- package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.0FBvwBvK.js → c4Diagram-AHTNJAMY.DDJsntUO.js} +1 -1
- package/dist/docs/assets/chunks/channel.BjpoSbz_.js +1 -0
- package/dist/docs/assets/chunks/{chunk-4BX2VUAB.CELMmMDA.js → chunk-4BX2VUAB.BK2rKt6W.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-4TB4RGXK.C4bhFtSm.js → chunk-4TB4RGXK.DRLV8RnF.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-55IACEB6.ZnQ9gRRQ.js → chunk-55IACEB6.DaKjxtb7.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-EDXVE4YY.DPlmglG-.js → chunk-EDXVE4YY.C5sPCIT1.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-FMBD7UC4.BrUk8pff.js → chunk-FMBD7UC4.CSGWyNTB.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-OYMX7WX6.CcmWIncu.js → chunk-OYMX7WX6.D5tK9XEr.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-QZHKN3VN.D65-cs8I.js → chunk-QZHKN3VN.BeZGd1UZ.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-YZCP3GAM.qoXZpG9F.js → chunk-YZCP3GAM.U_tfWwQR.js} +1 -1
- package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.BgxOlMHw.js +1 -0
- package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.BgxOlMHw.js +1 -0
- package/dist/docs/assets/chunks/clone.DRuGBKZC.js +1 -0
- package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.8rYtqudO.js → cose-bilkent-S5V4N54A.DVeRXIb6.js} +1 -1
- package/dist/docs/assets/chunks/{dagre-KV5264BT.DrRP1fOh.js → dagre-KV5264BT.BpKJAeRZ.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-5BDNPKRD.DHj_xA2_.js → diagram-5BDNPKRD.BQOtrd1Z.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.Bz_6nAKj.js → diagram-G4DWMVQ6.CSDAhjPI.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-MMDJMWI5.BWA0xSW9.js → diagram-MMDJMWI5.Dpztst2S.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-TYMM5635.CpTJLNJI.js → diagram-TYMM5635.qJHRizHR.js} +1 -1
- package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.-7AWWSrP.js → erDiagram-SMLLAGMA.vbDotH3l.js} +1 -1
- package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.BTnQ742_.js → flowDiagram-DWJPFMVM.CqS_ZQr4.js} +1 -1
- package/dist/docs/assets/chunks/framework.BNw1pucY.js +19 -0
- package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.B5_HiiQ5.js → ganttDiagram-T4ZO3ILL.DTLdR4pN.js} +1 -1
- package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.CZcNTFZd.js → gitGraphDiagram-UUTBAWPF.D04lnbnr.js} +1 -1
- package/dist/docs/assets/chunks/{graph.V2GLaab4.js → graph.BlfqLJsM.js} +1 -1
- package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.7pZOkCCU.js → infoDiagram-42DDH7IO.tAooImWA.js} +1 -1
- package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.DSMo3Qa3.js → ishikawaDiagram-UXIWVN3A.ClUsVqnJ.js} +1 -1
- package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.BNEgWN1S.js → journeyDiagram-VCZTEJTY.C3tUgyCg.js} +1 -1
- package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.B-4d4tC7.js → kanban-definition-6JOO6SKY.CtD9-QCe.js} +1 -1
- package/dist/docs/assets/chunks/{layout.Dvbn9nSb.js → layout.D38U-LnT.js} +1 -1
- package/dist/docs/assets/chunks/{linear.D2GM4p4b.js → linear.BJmssyhN.js} +1 -1
- package/dist/docs/assets/chunks/{min.DVBtLK-B.js → min.DNgXoouU.js} +1 -1
- package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.CnJRI55x.js → mindmap-definition-QFDTVHPH.Dcp6cxeu.js} +1 -1
- package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.CtoaTFlA.js → pieDiagram-DEJITSTG.CLDw6zIs.js} +1 -1
- package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.DtT24_vN.js → quadrantDiagram-34T5L4WZ.CYaeeY4c.js} +1 -1
- package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.CjSO4o8f.js → requirementDiagram-MS252O5E.gMYuRpq2.js} +1 -1
- package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.-wWiIVWa.js → sankeyDiagram-XADWPNL6.CZqyHFbc.js} +1 -1
- package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.DSk8s4gX.js → sequenceDiagram-FGHM5R23.BTsCjUDN.js} +1 -1
- package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.BFKAsdkN.js → stateDiagram-FHFEXIEX.CftT9mLJ.js} +1 -1
- package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.-43J68xB.js +1 -0
- package/dist/docs/assets/chunks/{theme.C0MctGaz.js → theme.B_7J9ZsV.js} +2 -2
- package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.TUNJbAFe.js → timeline-definition-GMOUNBTQ.DbU3WUNw.js} +1 -1
- package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.C-RGNnk4.js → vennDiagram-DHZGUBPP.ixsq-q2u.js} +1 -1
- package/dist/docs/assets/chunks/wardley-RL74JXVD.WRXz-Dux.js +162 -0
- package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.DH4zt73Y.js → wardleyDiagram-NUSXRM2D.C0ewvgbp.js} +1 -1
- package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.B-3k6bF6.js → xychartDiagram-5P7HB3ND.nAEhF4bO.js} +1 -1
- package/dist/docs/assets/deployment.md.D2jQZuFx.js +32 -0
- package/dist/docs/assets/deployment.md.D2jQZuFx.lean.js +1 -0
- package/dist/docs/assets/evals.md.BYvfZ-PO.js +72 -0
- package/dist/docs/assets/evals.md.BYvfZ-PO.lean.js +1 -0
- package/dist/docs/assets/guides_agent-to-agent.md.8oDTfu-E.js +30 -0
- package/dist/docs/assets/guides_agent-to-agent.md.8oDTfu-E.lean.js +1 -0
- package/dist/docs/assets/guides_bitbucket.md.mpevW-VP.js +145 -0
- package/dist/docs/assets/guides_bitbucket.md.mpevW-VP.lean.js +1 -0
- package/dist/docs/assets/guides_cloud-agents.md.Cp1O3u-X.js +15 -0
- package/dist/docs/assets/guides_cloud-agents.md.Cp1O3u-X.lean.js +1 -0
- package/dist/docs/assets/guides_convert-automation.md.CqEyfP6Y.js +43 -0
- package/dist/docs/assets/guides_convert-automation.md.CqEyfP6Y.lean.js +1 -0
- package/dist/docs/assets/guides_github.md.BwpBp3ed.js +156 -0
- package/dist/docs/assets/guides_github.md.BwpBp3ed.lean.js +1 -0
- package/dist/docs/assets/guides_gitlab.md.DaEC3nMk.js +153 -0
- package/dist/docs/assets/guides_gitlab.md.DaEC3nMk.lean.js +1 -0
- package/dist/docs/assets/guides_grokbot-agents.md.CMhZNdEU.js +16 -0
- package/dist/docs/assets/guides_grokbot-agents.md.CMhZNdEU.lean.js +1 -0
- package/dist/docs/assets/guides_improve.md.Bnp4F99w.js +22 -0
- package/dist/docs/assets/guides_improve.md.Bnp4F99w.lean.js +1 -0
- package/dist/docs/assets/guides_mcp-oauth.md.bSFakfCY.js +50 -0
- package/dist/docs/assets/guides_mcp-oauth.md.bSFakfCY.lean.js +1 -0
- package/dist/docs/assets/guides_opentelemetry.md.BKDxQmmd.js +35 -0
- package/dist/docs/assets/guides_opentelemetry.md.BKDxQmmd.lean.js +1 -0
- package/dist/docs/assets/guides_slack.md.Bo96y42E.js +70 -0
- package/dist/docs/assets/guides_slack.md.Bo96y42E.lean.js +1 -0
- package/dist/docs/assets/guides_webhooks.md.1A72_VEE.js +92 -0
- package/dist/docs/assets/guides_webhooks.md.1A72_VEE.lean.js +1 -0
- package/dist/docs/assets/hillclimbing.md.D4E1o5Sa.js +7 -0
- package/dist/docs/assets/hillclimbing.md.D4E1o5Sa.lean.js +1 -0
- package/dist/docs/assets/{index.md.BFVyY2KT.js → index.md.C-t81M5J.js} +2 -2
- package/dist/docs/assets/{index.md.BFVyY2KT.lean.js → index.md.C-t81M5J.lean.js} +1 -1
- package/dist/docs/assets/{quickstart.md.D3MjSZN-.js → quickstart.md.DAvVhuuU.js} +1 -1
- package/dist/docs/assets/{quickstart.md.D3MjSZN-.lean.js → quickstart.md.DAvVhuuU.lean.js} +1 -1
- package/dist/docs/assets/{reference_agent-config.md.CfVA-LZJ.js → reference_agent-config.md.DGPyw7ms.js} +1 -1
- package/dist/docs/assets/{reference_agent-config.md.CfVA-LZJ.lean.js → reference_agent-config.md.DGPyw7ms.lean.js} +1 -1
- package/dist/docs/assets/{reference_artifacts.md.Vf7qyIZ-.js → reference_artifacts.md.Bu_4HmsD.js} +1 -1
- package/dist/docs/assets/{reference_artifacts.md.Vf7qyIZ-.lean.js → reference_artifacts.md.Bu_4HmsD.lean.js} +1 -1
- package/dist/docs/assets/{reference_channels.md.icqLKcTc.js → reference_channels.md.nFWbzAic.js} +1 -1
- package/dist/docs/assets/{reference_channels.md.icqLKcTc.lean.js → reference_channels.md.nFWbzAic.lean.js} +1 -1
- package/dist/docs/assets/{reference_cli.md.B2dBL6L8.js → reference_cli.md.DLWDz9ij.js} +3 -1
- package/dist/docs/assets/{reference_cli.md.B2dBL6L8.lean.js → reference_cli.md.DLWDz9ij.lean.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.Cb3U_c8n.js → reference_connections.md.CmyrlXfY.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.Cb3U_c8n.lean.js → reference_connections.md.CmyrlXfY.lean.js} +1 -1
- package/dist/docs/assets/reference_evals.md.DNJzM_yf.js +57 -0
- package/dist/docs/assets/reference_evals.md.DNJzM_yf.lean.js +1 -0
- package/dist/docs/assets/reference_extensions.md.Ceq-qT8d.js +58 -0
- package/dist/docs/assets/reference_extensions.md.Ceq-qT8d.lean.js +1 -0
- package/dist/docs/assets/{reference_hooks.md.CZuynAxj.js → reference_hooks.md.B7uzNENk.js} +2 -2
- package/dist/docs/assets/{reference_hooks.md.CZuynAxj.lean.js → reference_hooks.md.B7uzNENk.lean.js} +1 -1
- package/dist/docs/assets/{reference_http-api.md.DTKcYE6L.js → reference_http-api.md.CduHavZ2.js} +1 -1
- package/dist/docs/assets/{reference_http-api.md.DTKcYE6L.lean.js → reference_http-api.md.CduHavZ2.lean.js} +1 -1
- package/dist/docs/assets/{reference_instructions.md.D7gkckK-.js → reference_instructions.md.CU1My5My.js} +1 -1
- package/dist/docs/assets/{reference_instructions.md.D7gkckK-.lean.js → reference_instructions.md.CU1My5My.lean.js} +1 -1
- package/dist/docs/assets/{reference_playground.md.D2YExv5K.js → reference_playground.md.Ch2d0Iqi.js} +1 -1
- package/dist/docs/assets/{reference_playground.md.D2YExv5K.lean.js → reference_playground.md.Ch2d0Iqi.lean.js} +1 -1
- package/dist/docs/assets/{reference_project-layout.md.DPxbUJyt.js → reference_project-layout.md.BGhgpy9V.js} +1 -1
- package/dist/docs/assets/{reference_project-layout.md.DPxbUJyt.lean.js → reference_project-layout.md.BGhgpy9V.lean.js} +1 -1
- package/dist/docs/assets/{reference_prompt.md.BQ5uAv1F.js → reference_prompt.md.Ccp0R53H.js} +1 -1
- package/dist/docs/assets/{reference_prompt.md.BQ5uAv1F.lean.js → reference_prompt.md.Ccp0R53H.lean.js} +1 -1
- package/dist/docs/assets/{reference_schedules.md.BasfZWO-.js → reference_schedules.md.B2Nm6FaD.js} +1 -1
- package/dist/docs/assets/{reference_schedules.md.BasfZWO-.lean.js → reference_schedules.md.B2Nm6FaD.lean.js} +1 -1
- package/dist/docs/assets/{reference_sessions.md.YKvIsWAx.js → reference_sessions.md.1_6Vyv7x.js} +1 -1
- package/dist/docs/assets/{reference_sessions.md.YKvIsWAx.lean.js → reference_sessions.md.1_6Vyv7x.lean.js} +1 -1
- package/dist/docs/assets/{reference_skills.md.rNgpsGd0.js → reference_skills.md.DjQkRefx.js} +1 -1
- package/dist/docs/assets/{reference_skills.md.rNgpsGd0.lean.js → reference_skills.md.DjQkRefx.lean.js} +1 -1
- package/dist/docs/assets/{reference_subagents.md.e5qitjJt.js → reference_subagents.md.BHsSMMyO.js} +1 -1
- package/dist/docs/assets/{reference_subagents.md.e5qitjJt.lean.js → reference_subagents.md.BHsSMMyO.lean.js} +1 -1
- package/dist/docs/assets/{reference_tools.md.BdCO2aHZ.js → reference_tools.md.BYzUTeVA.js} +1 -1
- package/dist/docs/assets/{reference_tools.md.BdCO2aHZ.lean.js → reference_tools.md.BYzUTeVA.lean.js} +1 -1
- package/dist/docs/assets/{templates_agentic-owners.md.Da_AGDlH.js → templates_agentic-owners.md.9M575F5C.js} +1 -1
- package/dist/docs/assets/{templates_agentic-owners.md.Da_AGDlH.lean.js → templates_agentic-owners.md.9M575F5C.lean.js} +1 -1
- package/dist/docs/assets/{templates_pr-autofixer.md.DqxocIGh.js → templates_pr-autofixer.md.ws0DDXDy.js} +1 -1
- package/dist/docs/assets/{templates_pr-autofixer.md.DqxocIGh.lean.js → templates_pr-autofixer.md.ws0DDXDy.lean.js} +1 -1
- package/dist/docs/assets/{templates_security-reviewer.md.Bhnvd8VE.js → templates_security-reviewer.md.KEFYXzfK.js} +1 -1
- package/dist/docs/assets/{templates_security-reviewer.md.Bhnvd8VE.lean.js → templates_security-reviewer.md.KEFYXzfK.lean.js} +1 -1
- package/dist/docs/assets/templates_thermo-quality-review.md.VNJ_mohX.js +3 -0
- package/dist/docs/assets/templates_thermo-quality-review.md.VNJ_mohX.lean.js +1 -0
- package/dist/docs/assets/templates_thermo-review.md.Hi3zWOkP.js +3 -0
- package/dist/docs/assets/templates_thermo-review.md.Hi3zWOkP.lean.js +1 -0
- package/dist/docs/assets/{templates_triage.md.BdBWO9Ic.js → templates_triage.md.CVGe_FG6.js} +1 -1
- package/dist/docs/assets/{templates_triage.md.BdBWO9Ic.lean.js → templates_triage.md.CVGe_FG6.lean.js} +1 -1
- package/dist/docs/assets/troubleshooting.md.mnfFG2Em.js +1 -0
- package/dist/docs/assets/troubleshooting.md.mnfFG2Em.lean.js +1 -0
- package/dist/docs/building-with-agents.html +44 -48
- package/dist/docs/building-with-agents.md +94 -82
- package/dist/docs/deployment.html +59 -78
- package/dist/docs/deployment.md +117 -363
- package/dist/docs/evals.html +85 -224
- package/dist/docs/evals.md +146 -673
- package/dist/docs/guides/agent-to-agent.html +58 -42
- package/dist/docs/guides/agent-to-agent.md +112 -35
- package/dist/docs/guides/bitbucket.html +179 -44
- package/dist/docs/guides/bitbucket.md +249 -48
- package/dist/docs/guides/cloud-agents.html +46 -40
- package/dist/docs/guides/cloud-agents.md +119 -66
- package/dist/docs/guides/convert-automation.html +80 -49
- package/dist/docs/guides/convert-automation.md +156 -147
- package/dist/docs/guides/github.html +184 -92
- package/dist/docs/guides/github.md +260 -245
- package/dist/docs/guides/gitlab.html +184 -45
- package/dist/docs/guides/gitlab.md +249 -50
- package/dist/docs/guides/grokbot-agents.html +48 -41
- package/dist/docs/guides/grokbot-agents.md +99 -53
- package/dist/docs/guides/improve.html +48 -40
- package/dist/docs/guides/improve.md +111 -58
- package/dist/docs/guides/mcp-oauth.html +74 -52
- package/dist/docs/guides/mcp-oauth.md +111 -121
- package/dist/docs/guides/opentelemetry.html +63 -54
- package/dist/docs/guides/opentelemetry.md +96 -165
- package/dist/docs/guides/slack.html +83 -59
- package/dist/docs/guides/slack.md +157 -227
- package/dist/docs/guides/webhooks.html +97 -230
- package/dist/docs/guides/webhooks.md +154 -385
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +44 -38
- package/dist/docs/hillclimbing.md +101 -55
- package/dist/docs/index.html +38 -38
- package/dist/docs/index.md +2 -0
- package/dist/docs/llms-full.txt +3082 -3104
- package/dist/docs/llms.txt +21 -18
- package/dist/docs/quickstart.html +37 -37
- package/dist/docs/reference/agent-config.html +37 -37
- package/dist/docs/reference/artifacts.html +38 -38
- package/dist/docs/reference/channels.html +37 -37
- package/dist/docs/reference/cli.html +39 -37
- package/dist/docs/reference/cli.md +2 -0
- package/dist/docs/reference/connections.html +37 -37
- package/dist/docs/reference/evals.html +116 -0
- package/dist/docs/reference/evals.md +293 -0
- package/dist/docs/reference/extensions.html +80 -84
- package/dist/docs/reference/extensions.md +127 -199
- package/dist/docs/reference/hooks.html +39 -39
- package/dist/docs/reference/hooks.md +34 -34
- package/dist/docs/reference/http-api.html +37 -37
- package/dist/docs/reference/instructions.html +37 -37
- package/dist/docs/reference/playground.html +37 -37
- package/dist/docs/reference/project-layout.html +37 -37
- package/dist/docs/reference/prompt.html +37 -37
- package/dist/docs/reference/schedules.html +37 -37
- package/dist/docs/reference/sessions.html +37 -37
- package/dist/docs/reference/skills.html +37 -37
- package/dist/docs/reference/subagents.html +37 -37
- package/dist/docs/reference/tools.html +37 -37
- package/dist/docs/templates/agentic-owners.html +38 -38
- package/dist/docs/templates/pr-autofixer.html +37 -37
- package/dist/docs/templates/security-reviewer.html +38 -38
- package/dist/docs/templates/thermo-quality-review.html +62 -0
- package/dist/docs/templates/thermo-quality-review.md +75 -0
- package/dist/docs/templates/thermo-review.html +62 -0
- package/dist/docs/templates/thermo-review.md +74 -0
- package/dist/docs/templates/triage.html +37 -37
- package/dist/docs/troubleshooting.html +38 -38
- package/dist/docs/troubleshooting.md +97 -66
- package/dist/extensions/cursor-cloud-agents/skills/handoff.md +3 -7
- package/dist/extensions/improve/extension.d.ts +3 -1
- package/dist/extensions/improve/extension.d.ts.map +1 -1
- package/dist/extensions/improve/extension.js +4 -2
- package/dist/extensions/improve/skills/yourself.js +1 -1
- package/dist/filesystem.d.ts +46 -2
- package/dist/filesystem.d.ts.map +1 -1
- package/dist/filesystem.js +149 -102
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/cli-ax.d.ts +6 -0
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +72 -14
- package/dist/internal/continuation-identity.d.ts.map +1 -1
- package/dist/internal/continuation-identity.js +1 -0
- package/dist/internal/cursor-agent-template.d.ts +1 -1
- package/dist/internal/cursor-agent-template.d.ts.map +1 -1
- package/dist/internal/cursor-agent-template.js +2 -0
- package/dist/internal/filesystem/tools.d.ts.map +1 -1
- package/dist/internal/filesystem/tools.js +2 -2
- package/dist/internal/filesystem/walk.d.ts +7 -4
- package/dist/internal/filesystem/walk.d.ts.map +1 -1
- package/dist/internal/filesystem/walk.js +34 -11
- package/dist/internal/hosted-admission-adapter.d.ts +3 -0
- package/dist/internal/hosted-admission-adapter.d.ts.map +1 -1
- package/dist/internal/hosted-delivery-protocol.d.ts +17 -0
- package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
- package/dist/internal/hosted-delivery-protocol.js +50 -1
- package/dist/internal/hosted-delivery.d.ts.map +1 -1
- package/dist/internal/hosted-delivery.js +8 -0
- package/dist/internal/init-project.d.ts.map +1 -1
- package/dist/internal/init-project.js +4 -0
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +94 -39
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +11 -5
- package/dist/internal/skill-catalog.d.ts +28 -0
- package/dist/internal/skill-catalog.d.ts.map +1 -0
- package/dist/internal/skill-catalog.js +44 -0
- package/dist/playground/assets/index-B1c1LeIf.js +67 -0
- package/dist/playground/assets/index-CK2LX3iD.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +2 -0
- package/docs/building-with-agents.md +96 -84
- package/docs/deployment.md +118 -364
- package/docs/evals.md +147 -674
- package/docs/guides/agent-to-agent.md +113 -36
- package/docs/guides/bitbucket.md +250 -49
- package/docs/guides/cloud-agents.md +119 -67
- package/docs/guides/convert-automation.md +157 -148
- package/docs/guides/github.md +261 -246
- package/docs/guides/gitlab.md +250 -51
- package/docs/guides/grokbot-agents.md +100 -55
- package/docs/guides/improve.md +112 -59
- package/docs/guides/mcp-oauth.md +112 -122
- package/docs/guides/opentelemetry.md +97 -166
- package/docs/guides/slack.md +158 -228
- package/docs/guides/webhooks.md +155 -386
- package/docs/hillclimbing.md +102 -56
- package/docs/reference/cli.md +2 -0
- package/docs/reference/evals.md +298 -0
- package/docs/reference/extensions.md +128 -200
- package/docs/reference/hooks.md +34 -34
- package/docs/templates/thermo-quality-review.md +80 -0
- package/docs/templates/thermo-review.md +79 -0
- package/docs/troubleshooting.md +98 -67
- package/package.json +1 -1
- package/skills/github/SKILL.md +21 -13
- package/src/bin/agent-serve.ts +22 -0
- package/src/channels/github/github-channel.ts +29 -19
- package/src/channels/slack/agentic-delivery.ts +2 -0
- package/src/channels/slack/dispatch.ts +126 -4
- package/src/channels/slack/placeholder.ts +51 -0
- package/src/channels/slack/slack-channel.ts +9 -2
- package/src/extensions/cursor-cloud-agents/skills/handoff.md +3 -7
- package/src/extensions/improve/extension.ts +4 -2
- package/src/extensions/improve/skills/yourself.ts +1 -1
- package/src/filesystem.ts +168 -65
- package/src/index.ts +3 -0
- package/src/internal/cli-ax.ts +88 -15
- package/src/internal/continuation-identity.ts +1 -0
- package/src/internal/cursor-agent-template.ts +2 -0
- package/src/internal/filesystem/tools.ts +2 -0
- package/src/internal/filesystem/walk.ts +60 -15
- package/src/internal/hosted-admission-adapter.ts +3 -0
- package/src/internal/hosted-delivery-protocol.ts +78 -1
- package/src/internal/hosted-delivery.ts +8 -0
- package/src/internal/init-project.ts +4 -0
- package/src/internal/server.ts +104 -41
- package/src/internal/session-engine.ts +16 -4
- package/src/internal/skill-catalog.ts +69 -0
- package/src/types.ts +9 -0
- package/templates/thermo-quality-review/README.md +35 -0
- package/templates/thermo-quality-review/agent/agent.ts +8 -0
- package/templates/thermo-quality-review/agent/channels/github.ts +42 -0
- package/templates/thermo-quality-review/agent/instructions.md +43 -0
- package/templates/thermo-quality-review/agent/tools/post_findings.ts +70 -0
- package/templates/thermo-quality-review/evals/evals.config.ts +5 -0
- package/templates/thermo-quality-review/evals/review.eval.ts +62 -0
- package/templates/thermo-quality-review/package.json +18 -0
- package/templates/thermo-quality-review/tsconfig.json +12 -0
- package/templates/thermo-review/README.md +35 -0
- package/templates/thermo-review/agent/agent.ts +8 -0
- package/templates/thermo-review/agent/channels/github.ts +42 -0
- package/templates/thermo-review/agent/instructions.md +40 -0
- package/templates/thermo-review/agent/tools/post_findings.ts +70 -0
- package/templates/thermo-review/evals/evals.config.ts +5 -0
- package/templates/thermo-review/evals/review.eval.ts +53 -0
- package/templates/thermo-review/package.json +18 -0
- package/templates/thermo-review/tsconfig.json +12 -0
- package/dist/docs/assets/building-with-agents.md.CEGVXkmO.js +0 -13
- package/dist/docs/assets/building-with-agents.md.CEGVXkmO.lean.js +0 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.DtXk1hy-.js +0 -1
- package/dist/docs/assets/chunks/channel.Bkv1N-gK.js +0 -1
- package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.CZDco1o8.js +0 -1
- package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.CZDco1o8.js +0 -1
- package/dist/docs/assets/chunks/clone.YSt_40_s.js +0 -1
- package/dist/docs/assets/chunks/framework.dypDpWZ3.js +0 -19
- package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.C4CLm481.js +0 -1
- package/dist/docs/assets/chunks/wardley-RL74JXVD.g5efOWmT.js +0 -162
- package/dist/docs/assets/deployment.md.Dm4Qo3hp.js +0 -51
- package/dist/docs/assets/deployment.md.Dm4Qo3hp.lean.js +0 -1
- package/dist/docs/assets/evals.md.BLDRt5LH.js +0 -211
- package/dist/docs/assets/evals.md.BLDRt5LH.lean.js +0 -1
- package/dist/docs/assets/guides_agent-to-agent.md.BI0xclmy.js +0 -14
- package/dist/docs/assets/guides_agent-to-agent.md.BI0xclmy.lean.js +0 -1
- package/dist/docs/assets/guides_bitbucket.md.CTpCl__f.js +0 -10
- package/dist/docs/assets/guides_bitbucket.md.CTpCl__f.lean.js +0 -1
- package/dist/docs/assets/guides_cloud-agents.md.lSE_l7lH.js +0 -9
- package/dist/docs/assets/guides_cloud-agents.md.lSE_l7lH.lean.js +0 -1
- package/dist/docs/assets/guides_convert-automation.md.Ck6Cr68A.js +0 -12
- package/dist/docs/assets/guides_convert-automation.md.Ck6Cr68A.lean.js +0 -1
- package/dist/docs/assets/guides_github.md.D6ER29dG.js +0 -64
- package/dist/docs/assets/guides_github.md.D6ER29dG.lean.js +0 -1
- package/dist/docs/assets/guides_gitlab.md.P-TjBnS5.js +0 -14
- package/dist/docs/assets/guides_gitlab.md.P-TjBnS5.lean.js +0 -1
- package/dist/docs/assets/guides_grokbot-agents.md.WBZIOvkz.js +0 -9
- package/dist/docs/assets/guides_grokbot-agents.md.WBZIOvkz.lean.js +0 -1
- package/dist/docs/assets/guides_improve.md.BKaDuKKK.js +0 -14
- package/dist/docs/assets/guides_improve.md.BKaDuKKK.lean.js +0 -1
- package/dist/docs/assets/guides_mcp-oauth.md.DMNMpXtO.js +0 -28
- package/dist/docs/assets/guides_mcp-oauth.md.DMNMpXtO.lean.js +0 -1
- package/dist/docs/assets/guides_opentelemetry.md._CRfDyzH.js +0 -26
- package/dist/docs/assets/guides_opentelemetry.md._CRfDyzH.lean.js +0 -1
- package/dist/docs/assets/guides_slack.md.DdT8rmsj.js +0 -46
- package/dist/docs/assets/guides_slack.md.DdT8rmsj.lean.js +0 -1
- package/dist/docs/assets/guides_webhooks.md.aQW10HRe.js +0 -225
- package/dist/docs/assets/guides_webhooks.md.aQW10HRe.lean.js +0 -1
- package/dist/docs/assets/hillclimbing.md.Dq4kkVIL.js +0 -1
- package/dist/docs/assets/hillclimbing.md.Dq4kkVIL.lean.js +0 -1
- package/dist/docs/assets/reference_extensions.md.wlFD3cUR.js +0 -62
- package/dist/docs/assets/reference_extensions.md.wlFD3cUR.lean.js +0 -1
- package/dist/docs/assets/troubleshooting.md.BcgNoYtJ.js +0 -1
- package/dist/docs/assets/troubleshooting.md.BcgNoYtJ.lean.js +0 -1
- package/dist/playground/assets/index-BLlKgZtI.css +0 -1
- package/dist/playground/assets/index-CDS5p9sR.js +0 -67
package/dist/docs/evals.md
CHANGED
|
@@ -1,778 +1,251 @@
|
|
|
1
1
|
# Evals
|
|
2
2
|
|
|
3
|
-
An eval sends a fixed
|
|
4
|
-
trajectory
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
month's fix still holds.
|
|
8
|
-
|
|
9
|
-
Nothing is mocked. The runner starts (or targets) a real agent server,
|
|
10
|
-
drives sessions over the public API, and grades the events it gets
|
|
11
|
-
back. The model runs and server tools execute, so
|
|
12
|
-
[keep side effects out of eval sessions](#keep-side-effects-out-of-eval-sessions)
|
|
13
|
-
before you point an eval at an agent that posts anywhere.
|
|
3
|
+
An eval sends a fixed input to the real agent and checks the resulting
|
|
4
|
+
trajectory: whether the turn succeeded, which tools ran, and what shape
|
|
5
|
+
the answer took. Use evals to protect behavior you already understand,
|
|
6
|
+
not to discover what the prompt should do.
|
|
14
7
|
|
|
15
|
-
|
|
8
|
+
Evals run real model turns and real tools. Guard external writes before
|
|
9
|
+
running a suite against an agent that can post, merge, or deploy.
|
|
16
10
|
|
|
17
|
-
|
|
18
|
-
are asking.
|
|
19
|
-
|
|
20
|
-
| You want to | Use |
|
|
21
|
-
| --- | --- |
|
|
22
|
-
| Gate one fixed input's behavior, locally and in CI | Evals (this page) |
|
|
23
|
-
| Observe every live session: metrics, audit, alerts | [Hooks](/docs/reference/hooks.md) |
|
|
24
|
-
| Improve an agent one measured round at a time | [Hillclimbing](/docs/hillclimbing.md); each kept win lands an eval |
|
|
25
|
-
|
|
26
|
-
[Hooks, channel events, or evals?](/docs/reference/hooks.md#hooks-channel-events-or-evals)
|
|
27
|
-
has the side-by-side table.
|
|
28
|
-
|
|
29
|
-
### When not to write an eval
|
|
30
|
-
|
|
31
|
-
- Test a server tool's own logic with
|
|
32
|
-
`agent-sdk call <tool> --dir . --input '{...}'` or a unit test. No
|
|
33
|
-
model turn, no credential.
|
|
34
|
-
- Explore a prompt with `agent-sdk run --dir . --message "..."` and
|
|
35
|
-
read the trajectory. Write the eval once you know which decision to
|
|
36
|
-
gate.
|
|
37
|
-
- Stop a bad turn while it runs with
|
|
38
|
-
[`needsApproval`](/docs/reference/tools.md#gate-a-tool-on-human-approval)
|
|
39
|
-
on the tool or `defineResult`. Evals grade
|
|
40
|
-
after the fact.
|
|
41
|
-
|
|
42
|
-
## Write your first eval
|
|
43
|
-
|
|
44
|
-
Evals live under the project-root `evals/` directory, a sibling of
|
|
45
|
-
`agent/`. `agent/evals/` is silently ignored. Discovery loads every
|
|
46
|
-
`.eval.ts` (or `.eval.js`) file under `evals/`, plus one config file.
|
|
47
|
-
|
|
48
|
-
```text
|
|
49
|
-
my-agent/
|
|
50
|
-
agent/
|
|
51
|
-
agent.ts
|
|
52
|
-
tools/inspect_pr.ts
|
|
53
|
-
evals/
|
|
54
|
-
evals.config.ts # required to run: maxConcurrency
|
|
55
|
-
readiness.eval.ts # id: readiness
|
|
56
|
-
prs.eval.ts # cases: prs/checkout, prs/search
|
|
57
|
-
```
|
|
11
|
+
## Protect a tool decision
|
|
58
12
|
|
|
59
|
-
|
|
60
|
-
and
|
|
13
|
+
This smoke case asks for a PR verdict, requires the read-only inspection
|
|
14
|
+
tool, and fails if the agent tries to approve. The CLI reports all three
|
|
15
|
+
decisions together instead of stopping at the first miss.
|
|
61
16
|
|
|
62
17
|
```ts
|
|
63
18
|
// evals/readiness.eval.ts
|
|
64
19
|
import { defineEval, includes } from "@cursor/july/evals";
|
|
65
20
|
|
|
66
21
|
export default defineEval({
|
|
67
|
-
description: "Inspects a PR without approving it.",
|
|
68
22
|
tags: ["smoke"],
|
|
69
|
-
timeoutMs: 120_000,
|
|
70
23
|
async test(t) {
|
|
71
24
|
await t.send(
|
|
72
25
|
"Is https://github.com/acme/checkout/pull/42 ready to approve?"
|
|
73
26
|
);
|
|
27
|
+
|
|
74
28
|
t.succeeded();
|
|
75
29
|
t.calledTool("inspect_pr");
|
|
76
30
|
t.notCalledTool("approve_pr");
|
|
77
|
-
t.check(t.reply, includes(/ready|approve/i));
|
|
31
|
+
t.check(t.reply, includes(/ready|blocked|approve/i));
|
|
78
32
|
},
|
|
79
33
|
});
|
|
80
34
|
```
|
|
81
35
|
|
|
36
|
+
Evals live in the project-root `evals/` directory, beside `agent/`.
|
|
37
|
+
Add the required concurrency config once:
|
|
38
|
+
|
|
82
39
|
```ts
|
|
83
40
|
// evals/evals.config.ts
|
|
84
41
|
import { defineEvalConfig } from "@cursor/july/evals";
|
|
85
42
|
|
|
86
|
-
export default defineEvalConfig({
|
|
43
|
+
export default defineEvalConfig({
|
|
44
|
+
maxConcurrency: 20,
|
|
45
|
+
});
|
|
87
46
|
```
|
|
88
47
|
|
|
89
|
-
Run it under Node 22.13 or newer (never Bun) with a Cursor credential
|
|
90
|
-
in place; see [Credentials](#credentials):
|
|
91
|
-
|
|
92
48
|
```bash
|
|
93
49
|
agent-sdk eval --dir . --list
|
|
94
|
-
agent-sdk eval --dir .
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
```text
|
|
98
|
-
PASS readiness (14.2s) — Inspects a PR without approving it.
|
|
99
|
-
✓ succeeded
|
|
100
|
-
✓ calledTool(inspect_pr)
|
|
101
|
-
✓ notCalledTool(approve_pr)
|
|
102
|
-
✓ check(includes)
|
|
103
|
-
|
|
104
|
-
1 passed, 0 failed, 1 total
|
|
105
|
-
artifacts: <project state directory>/evals/2026-09-11T15-02-11-402Z
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
Every local run writes each case's assertions, inputs, tool calls, and
|
|
109
|
-
`t.log` lines under that artifacts directory. Open
|
|
110
|
-
`evals/<case-id>.json` there when a case fails; see
|
|
111
|
-
[Where results land](#where-results-land).
|
|
112
|
-
|
|
113
|
-
## Name cases by path
|
|
114
|
-
|
|
115
|
-
The file path is the eval's identity, so you don't author an id.
|
|
116
|
-
`evals/builds/api.eval.ts` becomes `builds/api`. An `index` filename
|
|
117
|
-
collapses to its directory: `evals/builds/index.eval.ts` becomes
|
|
118
|
-
`builds`.
|
|
119
|
-
|
|
120
|
-
One file can hold several datapoints through `cases`. Provide either
|
|
121
|
-
`test` or `cases`, not both. Each case id becomes `<fileId>/<case.id>`:
|
|
122
|
-
|
|
123
|
-
```ts
|
|
124
|
-
// evals/prs.eval.ts: prs/checkout, prs/search
|
|
125
|
-
export default defineEval({
|
|
126
|
-
tags: ["smoke", "prs"],
|
|
127
|
-
cases: [
|
|
128
|
-
{
|
|
129
|
-
id: "checkout",
|
|
130
|
-
description: "Checkout PR readiness.",
|
|
131
|
-
async test(t) {
|
|
132
|
-
await t.send(
|
|
133
|
-
"Is https://github.com/acme/checkout/pull/42 ready to approve?"
|
|
134
|
-
);
|
|
135
|
-
t.succeeded();
|
|
136
|
-
t.calledTool("inspect_pr");
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
id: "search",
|
|
141
|
-
async test(t) {
|
|
142
|
-
await t.send(
|
|
143
|
-
"Check https://github.com/acme/search/pull/7 before approval."
|
|
144
|
-
);
|
|
145
|
-
t.succeeded();
|
|
146
|
-
t.calledTool("inspect_pr");
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
|
-
],
|
|
150
|
-
});
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
Case ids are single path segments, unique within the file. A case can
|
|
154
|
-
set its own `description`, `tags`, `timeoutMs`, `iterations`, `judge`,
|
|
155
|
-
`reporters`, and `metadata`. A case-level value replaces the file-level
|
|
156
|
-
one for that datapoint, except `metadata`, which merges with case keys
|
|
157
|
-
winning, and `reporters`, which adds to the file's list. `metadata` is
|
|
158
|
-
free-form data carried onto the result and every reporter.
|
|
159
|
-
|
|
160
|
-
A file may instead export an array of `defineEval` calls to fan out
|
|
161
|
-
over a dataset. Ids are then the file id plus a zero-padded index
|
|
162
|
-
(`sql/0000`, `sql/0001`, ...); see [Load a dataset](#load-a-dataset).
|
|
163
|
-
Prefer `cases` when datapoints are hand-written and deserve stable
|
|
164
|
-
names.
|
|
165
|
-
|
|
166
|
-
### Iterations
|
|
167
|
-
|
|
168
|
-
`iterations` (file or case, default `1`, cap `100`) runs a datapoint
|
|
169
|
-
repeatedly. Discovery expands `iterations: 3` on case `nyc` to runnable
|
|
170
|
-
ids `weather/nyc/1`, `weather/nyc/2`, and `weather/nyc/3`. The filter
|
|
171
|
-
`weather/nyc` still selects all three. Each expanded case exposes
|
|
172
|
-
`t.iteration` and `t.iterations`.
|
|
173
|
-
|
|
174
|
-
`maxConcurrency` counts authored datapoints, not expanded iterations.
|
|
175
|
-
Iterations of one datapoint share a concurrency slot and run in
|
|
176
|
-
sequence, so a suite of 11 cases with 3 iterations each and
|
|
177
|
-
`maxConcurrency: 20` has at most 11 cases in flight.
|
|
178
|
-
|
|
179
|
-
## Drive the agent with `t.send`
|
|
180
|
-
|
|
181
|
-
`t.send(message, options?)` runs one turn and waits for it to settle:
|
|
182
|
-
complete, park on an approval request, or fail. Several sends in one
|
|
183
|
-
case share the session, which is how you write multi-turn evals.
|
|
184
|
-
|
|
185
|
-
Each send resolves to a turn result: `message` (the assistant text),
|
|
186
|
-
`sessionId`, `events`, `toolCalls` (tool names in order), `ok`, and
|
|
187
|
-
`index`. The turn carries the same assertion vocabulary as `t`, scoped
|
|
188
|
-
to that turn, so you can grade an intermediate turn before the next
|
|
189
|
-
send overwrites `t.reply`. `turn.expectOk()` throws when the turn
|
|
190
|
-
failed, for later steps that depend on it.
|
|
191
|
-
|
|
192
|
-
Read the whole case with `t.reply` (last assistant text), `t.events`
|
|
193
|
-
(every event so far), `t.turns` (settled turns, oldest first), and
|
|
194
|
-
`t.sessionId`. `t.signal` aborts when the case hits its timeout; pass
|
|
195
|
-
it to your own async work.
|
|
196
|
-
|
|
197
|
-
Three options apply on the first send only, because they shape session
|
|
198
|
-
creation:
|
|
199
|
-
|
|
200
|
-
| Option | Effect |
|
|
201
|
-
| --- | --- |
|
|
202
|
-
| `workspaceFiles` | `{ path: contents }` seeded into the local session workspace. Prefer this over machine-local paths |
|
|
203
|
-
| `workspaceDir` | Absolute harness cwd for the local runtime |
|
|
204
|
-
| `cloud` | Per-session cloud options merged over the agent's static `cloud` config. Pin a fixture repo here for cloud evals instead of on the agent's default `cloud.repos`. On the cloud runtime, seeded files reach the agent as described under [Choose a runtime](/docs/reference/agent-config.md#choose-a-runtime) |
|
|
205
|
-
|
|
206
|
-
```ts
|
|
207
|
-
await t.send("Review pr/diff.patch and post findings.", {
|
|
208
|
-
workspaceFiles: {
|
|
209
|
-
"pr/diff.patch": [
|
|
210
|
-
"diff --git a/app/routes/search.ts b/app/routes/search.ts",
|
|
211
|
-
"+res.send(`<h1>Results for ${req.query.q}</h1>`);",
|
|
212
|
-
].join("\n"),
|
|
213
|
-
},
|
|
214
|
-
});
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
## Assert over the trajectory
|
|
218
|
-
|
|
219
|
-
Assertions record; they never throw. One run reports every failure
|
|
220
|
-
instead of dying on the first. Assertions on `t` read the whole run.
|
|
221
|
-
Assertions on a turn read only that turn.
|
|
222
|
-
|
|
223
|
-
| Gate | Checks |
|
|
224
|
-
| --- | --- |
|
|
225
|
-
| `t.succeeded()` | the run did not fail and is not parked on an unanswered approval |
|
|
226
|
-
| `t.parked()` | the run cleanly parked on an unanswered approval request |
|
|
227
|
-
| `t.messageIncludes(token)` | the joined assistant text matches a string or `RegExp` |
|
|
228
|
-
| `t.calledTool(name, matcher?)` | a matching call to `name` happened |
|
|
229
|
-
| `t.notCalledTool(name)` | no request for `name`, in any lifecycle state |
|
|
230
|
-
| `t.loadedSkill(name)` | the agent opened `skills/<name>/SKILL.md` (read, grep, or shell `cat`) |
|
|
231
|
-
| `t.toolOrder(names)` | tool requests appear in this relative order; extra calls allowed |
|
|
232
|
-
| `t.usedNoTools()` | no tool calls at all |
|
|
233
|
-
| `t.maxToolCalls(max)` | at most `max` tool calls |
|
|
234
|
-
| `t.noFailedActions()` | no tool call reported an error |
|
|
235
|
-
| `t.calledSubagent(name, matcher?)` | a matching subagent delegation happened |
|
|
236
|
-
| `t.taggedArtifact(kind?, predicate?)` | at least one [artifact](/docs/reference/artifacts.md) was tagged |
|
|
237
|
-
| `t.event(type, matcher?)` | at least one matching [event](/docs/reference/sessions.md#which-events-can-i-stream) of `type` |
|
|
238
|
-
| `t.notEvent(type, matcher?)` | no matching event of `type` |
|
|
239
|
-
| `t.eventOrder(matchers)` | matching event groups occur in this relative order |
|
|
240
|
-
| `t.eventsSatisfy(label, predicate)` | your predicate over the typed event stream |
|
|
241
|
-
| `t.check(value, expectation)` | any value, against a [builder](#grade-values-with-expectation-builders) |
|
|
242
|
-
| `t.score(name, value)` | a 0-1 score you computed; soft until you add a bar |
|
|
243
|
-
|
|
244
|
-
Three more assertions gate and return the matched fact. They stop the
|
|
245
|
-
test body when nothing matches, without a duplicate execution error.
|
|
246
|
-
`t.requireToolCall(name, matcher?)` returns the call so later code can
|
|
247
|
-
read its `input` and `output`. `t.requireInputRequest(filter?)` returns
|
|
248
|
-
the single pending approval request. `await t.require(value, expectation)`
|
|
249
|
-
does the same for a value check.
|
|
250
|
-
|
|
251
|
-
A case with no assertions passes when at least one turn completed. Add
|
|
252
|
-
`t.succeeded()` and behavior gates anyway. They make the contract
|
|
253
|
-
visible in review.
|
|
254
|
-
|
|
255
|
-
### What good cases assert
|
|
256
|
-
|
|
257
|
-
Gate decisions and shape, not prose. Model wording varies run to run.
|
|
258
|
-
Tool choice, tool avoidance, and output structure are the stable
|
|
259
|
-
contract.
|
|
260
|
-
|
|
261
|
-
1. `t.succeeded()`: always, first.
|
|
262
|
-
2. The tool decision: `calledTool` for the intended path,
|
|
263
|
-
`notCalledTool` for the likely wrong alternative. The pair is
|
|
264
|
-
stronger than either alone.
|
|
265
|
-
3. Output shape: a regex for the contract (`/ready|blocked/i`, a JSON
|
|
266
|
-
marker, a findings-block fence), never exact sentences.
|
|
267
|
-
4. For structured output, parse `t.reply` and check fields with
|
|
268
|
-
`matches` or `satisfies` instead of substring-matching JSON.
|
|
269
|
-
|
|
270
|
-
The common failure modes: asserting exact phrasing, packing more than
|
|
271
|
-
about five gates into one case (split it), and cases that depend on
|
|
272
|
-
live external state that drifts (pin the input).
|
|
273
|
-
|
|
274
|
-
### Narrow tool assertions with matchers
|
|
275
|
-
|
|
276
|
-
With no matcher, `calledTool` is request-based: a requested call counts
|
|
277
|
-
even before its result arrives. A matcher narrows it:
|
|
278
|
-
|
|
279
|
-
```ts
|
|
280
|
-
t.calledTool("inspect_pr", { status: "completed" });
|
|
281
|
-
t.calledTool("apply_agents", { input: { verdict: "update" } });
|
|
282
|
-
t.calledTool("bash", { input: { command: /^gh pr view/ }, count: 1 });
|
|
283
|
-
t.calledTool("read_file", {
|
|
284
|
-
output: (value) => String(value).includes("TODO"),
|
|
285
|
-
});
|
|
50
|
+
agent-sdk eval --dir . --tag smoke
|
|
286
51
|
```
|
|
287
52
|
|
|
288
|
-
|
|
289
|
-
predicate. Object literals partial-deep-match, so `{ verdict: "update" }`
|
|
290
|
-
matches arguments that also carry other keys. `status` is one of
|
|
291
|
-
`completed`, `failed`, `pending`, or `rejected` (a human denied the
|
|
292
|
-
approval). `calledSubagent` takes `{ output, status, count, callId }`.
|
|
293
|
-
`event`, `notEvent`, and `eventOrder` take `{ data, count }`.
|
|
294
|
-
|
|
295
|
-
### Grade values with expectation builders
|
|
53
|
+
## Check answer shape or quality
|
|
296
54
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
| Builder | Checks | Severity |
|
|
301
|
-
| --- | --- | --- |
|
|
302
|
-
| `includes(string \| RegExp)` | substring or match; structured values are stringified first | gate |
|
|
303
|
-
| `equals(value)` | deep equality | gate |
|
|
304
|
-
| `matches(schema)` | a Standard Schema (Zod, Valibot, ...) or anything with `safeParse` | gate |
|
|
305
|
-
| `similarity(expected)` | normalized text similarity, 0-1 | soft |
|
|
306
|
-
| `satisfies(predicate, label)` | your predicate; `label` is the failure detail | gate |
|
|
55
|
+
Prefer a deterministic shape check when the output has a contract. The
|
|
56
|
+
failure tells you which field was wrong, and the case remains stable
|
|
57
|
+
when the model changes its wording.
|
|
307
58
|
|
|
308
59
|
```ts
|
|
309
|
-
import { matches
|
|
60
|
+
import { matches } from "@cursor/july/evals";
|
|
310
61
|
import { z } from "zod";
|
|
311
62
|
|
|
312
63
|
const verdict = JSON.parse(t.reply ?? "{}");
|
|
313
64
|
t.check(
|
|
314
65
|
verdict,
|
|
315
|
-
matches(
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
66
|
+
matches(
|
|
67
|
+
z.object({
|
|
68
|
+
ready: z.boolean(),
|
|
69
|
+
blockers: z.array(z.string()),
|
|
70
|
+
})
|
|
71
|
+
)
|
|
320
72
|
);
|
|
321
73
|
```
|
|
322
74
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
### Record without gating
|
|
327
|
-
|
|
328
|
-
- `t.metric(name, value)` records a structured score or label. It shows
|
|
329
|
-
on the CLI result, the playground case card, JUnit output, and
|
|
330
|
-
artifacts.
|
|
331
|
-
- `t.log(message)` records a debug line, streamed under `--verbose`.
|
|
332
|
-
- `t.skip(reason)` ends the case as skipped. Skipped cases report
|
|
333
|
-
separately and never change the exit code. Call it before sending
|
|
334
|
-
messages.
|
|
335
|
-
|
|
336
|
-
## Gates, soft scores, and verdicts
|
|
337
|
-
|
|
338
|
-
Every assertion returns a handle, so severity rides on the assertion
|
|
339
|
-
instead of a separate thresholds map:
|
|
75
|
+
Use a judge when correctness depends on meaning that a schema, regex, or
|
|
76
|
+
known value cannot capture:
|
|
340
77
|
|
|
341
78
|
```ts
|
|
342
|
-
t.
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
t.judge.closedQA("cites a source").gate(0.8); // promoted to a gate
|
|
79
|
+
t.judge
|
|
80
|
+
.factuality("The lint step failed on src/sidebar.ts.")
|
|
81
|
+
.atLeast(0.8);
|
|
346
82
|
```
|
|
347
83
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
Each case ends with one verdict:
|
|
84
|
+
Judge checks are tracked scores until you give them a hard gate.
|
|
85
|
+
Configure the judge model in `evals.config.ts`. The
|
|
86
|
+
[Evals reference](/docs/reference/evals.md#judges) owns grader options and
|
|
87
|
+
severity rules.
|
|
354
88
|
|
|
355
|
-
|
|
356
|
-
| --- | --- | --- |
|
|
357
|
-
| `passed` | every gate passed and no soft bar was missed | 0 |
|
|
358
|
-
| `failed` | a gate failed, or the test body threw | 1 |
|
|
359
|
-
| `scored` | only soft bars were missed | 0, or 1 under `--strict` |
|
|
360
|
-
| `skipped` | `t.skip(reason)`, or a judge with no credentials | 0 |
|
|
89
|
+
## Test a conversation or approval
|
|
361
90
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
once the bars are trustworthy.
|
|
366
|
-
|
|
367
|
-
## Judge free-form output
|
|
368
|
-
|
|
369
|
-
When wording matters and no regex captures it, `t.judge` grades with an
|
|
370
|
-
LLM. The graders are `factuality(expected)`, `summarizes(expected)`,
|
|
371
|
-
`closedQA(criteria)`, and `sql(expected)`. Each scores `t.reply` by
|
|
372
|
-
default; pass `{ on }` to grade another value.
|
|
91
|
+
Several `t.send` calls in one case share a session. Assertions on a
|
|
92
|
+
returned turn inspect only that turn, while assertions on `t` inspect
|
|
93
|
+
the whole conversation.
|
|
373
94
|
|
|
374
95
|
```ts
|
|
375
|
-
const
|
|
376
|
-
|
|
377
|
-
t.judge.closedQA("names the failing step", { on: summary.message }).gate(1);
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
Judge assertions are soft by default, so a judge never fails a build
|
|
381
|
-
until you give it a bar with `.atLeast()` or promote it with `.gate()`.
|
|
382
|
-
The recorded detail names the choice the judge made and its rationale.
|
|
383
|
-
|
|
384
|
-
The judge model comes from `defineEvalConfig({ judge })`,
|
|
385
|
-
`defineEval({ judge })`, a case-level `judge`, or a per-call
|
|
386
|
-
`{ model }`. The nearest one wins. A judge call with no model
|
|
387
|
-
configured fails the case. A judge that cannot reach a model (no
|
|
388
|
-
credential) ends the case as `skipped`, unless a deterministic gate
|
|
389
|
-
already failed.
|
|
96
|
+
const first = await t.send("Inspect PR 42.");
|
|
97
|
+
first.calledTool("inspect_pr");
|
|
390
98
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
input to your prompt: wrap it with `fenceUntrusted` and include
|
|
396
|
-
`EVAL_JUDGE_INJECTION_GUARD`, as the built-in graders do.
|
|
397
|
-
|
|
398
|
-
```ts
|
|
399
|
-
import {
|
|
400
|
-
EVAL_JUDGE_INJECTION_GUARD,
|
|
401
|
-
fenceUntrusted,
|
|
402
|
-
} from "@cursor/july/evals";
|
|
403
|
-
|
|
404
|
-
const gold = ["XSS in search.ts", "open redirect in login.ts"];
|
|
405
|
-
const reply = await t.judge.model(
|
|
406
|
-
[
|
|
407
|
-
"For each GOLD finding, answer whether SUBMISSION reports it.",
|
|
408
|
-
"Reply with one line per finding: <index> YES|NO.",
|
|
409
|
-
EVAL_JUDGE_INJECTION_GUARD,
|
|
410
|
-
fenceUntrusted("GOLD", gold.map((g, i) => `${i + 1}. ${g}`).join("\n")),
|
|
411
|
-
fenceUntrusted("SUBMISSION", t.reply ?? ""),
|
|
412
|
-
].join("\n\n")
|
|
413
|
-
);
|
|
414
|
-
const hits = reply.match(/\bYES\b/g)?.length ?? 0;
|
|
415
|
-
t.score("recall", hits / gold.length).atLeast(0.5);
|
|
99
|
+
const followUp = await t.send("Now summarize only the blockers.");
|
|
100
|
+
followUp.usedNoTools();
|
|
101
|
+
t.check(followUp.message, includes(/blocker/i));
|
|
102
|
+
t.succeeded();
|
|
416
103
|
```
|
|
417
104
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
Eval sessions run the real agent, tools included. A reviewer that
|
|
421
|
-
comments on GitHub or posts to Slack will do so from an eval unless
|
|
422
|
-
the tool checks the session's purpose. Eval sessions carry
|
|
423
|
-
`purpose: "eval"`; live traffic carries `"live"`. Branch on it in the
|
|
424
|
-
tool, hook, or result handler that actuates:
|
|
105
|
+
For a tool that requires approval, the expected result is a parked turn
|
|
106
|
+
instead of a completed one:
|
|
425
107
|
|
|
426
108
|
```ts
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}
|
|
432
|
-
// post the review
|
|
433
|
-
}
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
Return a shaped result instead of throwing, so the eval can still
|
|
437
|
-
assert `t.calledTool("post_findings", { input: ... })` on the decision.
|
|
438
|
-
The same check belongs in [hooks](/docs/reference/hooks.md) that meter or
|
|
439
|
-
page and in `defineResult` commits.
|
|
440
|
-
|
|
441
|
-
## Worked examples
|
|
442
|
-
|
|
443
|
-
### Multi-turn: grade each turn
|
|
444
|
-
|
|
445
|
-
```ts
|
|
446
|
-
// evals/intro.eval.ts
|
|
447
|
-
import { defineEval, includes, satisfies } from "@cursor/july/evals";
|
|
448
|
-
|
|
449
|
-
export default defineEval({
|
|
450
|
-
description: "Introduces itself once; a repeat mention gets a short ack.",
|
|
451
|
-
async test(t) {
|
|
452
|
-
const intro = await t.send("Meet Jenny! @Jenny introduce yourself.");
|
|
453
|
-
intro.expectOk();
|
|
454
|
-
t.check(intro.message, includes(/jenny/i));
|
|
455
|
-
|
|
456
|
-
const repeat = await t.send("Meet, @Jenny!");
|
|
457
|
-
t.succeeded();
|
|
458
|
-
repeat.usedNoTools();
|
|
459
|
-
t.check(
|
|
460
|
-
repeat.message,
|
|
461
|
-
satisfies((r) => (r as string).trim().length <= 280, "short ack")
|
|
462
|
-
);
|
|
463
|
-
t.check(
|
|
464
|
-
repeat.message,
|
|
465
|
-
satisfies((r) => !/what i can do/i.test(r as string), "no second intro")
|
|
466
|
-
);
|
|
467
|
-
},
|
|
109
|
+
await t.send("Apply the approved policy update.");
|
|
110
|
+
t.parked();
|
|
111
|
+
t.calledTool("apply_policy", {
|
|
112
|
+
input: { verdict: "update" },
|
|
468
113
|
});
|
|
469
114
|
```
|
|
470
115
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
116
|
+
Pair an approval case with a safe branch that calls
|
|
117
|
+
`t.notCalledTool("apply_policy")`, so both sides of the decision stay
|
|
118
|
+
protected.
|
|
474
119
|
|
|
475
|
-
|
|
120
|
+
## Pin realistic inputs
|
|
476
121
|
|
|
477
|
-
|
|
478
|
-
|
|
122
|
+
A useful eval changes only when the agent changes. Freeze canonical chat
|
|
123
|
+
prompts, seed workspace evidence directly, and save webhook payloads
|
|
124
|
+
instead of depending on a developer's checkout or live external state.
|
|
479
125
|
|
|
480
126
|
```ts
|
|
481
|
-
|
|
482
|
-
{
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
workspaceFiles: {
|
|
488
|
-
"week/prs.md": RULE,
|
|
489
|
-
"week/slack.md": SLACK,
|
|
490
|
-
"week/tree/AGENTS.md.txt": "# API\n\nKeep handlers thin.\n",
|
|
491
|
-
},
|
|
492
|
-
});
|
|
493
|
-
t.parked();
|
|
494
|
-
t.calledTool("apply_agents", { input: { verdict: "update" } });
|
|
127
|
+
await t.send("Review pr/diff.patch and report blockers.", {
|
|
128
|
+
workspaceFiles: {
|
|
129
|
+
"pr/diff.patch": [
|
|
130
|
+
"diff --git a/app/routes/search.ts b/app/routes/search.ts",
|
|
131
|
+
"+res.send(`<h1>Results for ${req.query.q}</h1>`);",
|
|
132
|
+
].join("\n"),
|
|
495
133
|
},
|
|
496
|
-
},
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
`t.parked()` and `t.succeeded()` are exclusive: a parked run is a clean
|
|
500
|
-
stop on an unanswered approval, not a completed one. Pair the parked
|
|
501
|
-
case with a sibling that expects `verdict: "skip"` and `t.succeeded()`,
|
|
502
|
-
so both branches stay pinned.
|
|
503
|
-
|
|
504
|
-
## Pin fixtures
|
|
505
|
-
|
|
506
|
-
A fixed input is what makes an eval repeatable. Pick the fixture by the
|
|
507
|
-
surface under test.
|
|
508
|
-
|
|
509
|
-
| Agent surface | Fixture |
|
|
510
|
-
| --- | --- |
|
|
511
|
-
| Chat or domain assistant | One canonical prompt string, chosen once and frozen |
|
|
512
|
-
| Tool-heavy | Run `agent-sdk call <tool>` first to pin what the tool returns, then freeze the prompt that triggers it |
|
|
513
|
-
| GitHub webhook | `agent-sdk github replay <pr> --events '*' --dry-run --out fixtures/github` snapshots real payloads for offline replay ([GitHub guide](/docs/guides/github.md#test-with-github-replay)) |
|
|
514
|
-
| PR reviewer with host preparation | Diff, metadata, and gold labels pinned to commit SHAs; keep any live PR matrix small |
|
|
515
|
-
| Workspace-dependent | `workspaceFiles` on the first `t.send`, never developer-machine paths |
|
|
516
|
-
|
|
517
|
-
Tag the fast, reliably passing core `smoke` and run `--tag smoke` in
|
|
518
|
-
the inner loop. Leave slow or drift-prone cases untagged for explicit
|
|
519
|
-
runs.
|
|
520
|
-
|
|
521
|
-
### Materialize API-backed fixtures
|
|
522
|
-
|
|
523
|
-
An input that only points at external data (a pull request URL, a
|
|
524
|
-
snapshot id, a pair of commit SHAs) is not self-contained. Fetch it once
|
|
525
|
-
and commit the rendered fixture before you expand the suite:
|
|
526
|
-
|
|
527
|
-
1. Save the diff, metadata, and labels under `fixtures/` at pinned
|
|
528
|
-
revisions.
|
|
529
|
-
2. Seed those files with `workspaceFiles`, or read them from the
|
|
530
|
-
fixture directory.
|
|
531
|
-
3. Assert decisions and output shape against the saved evidence.
|
|
532
|
-
4. Keep a small `smoke` subset for any remaining live checks.
|
|
533
|
-
|
|
534
|
-
`maxConcurrency` limits parallel datapoints, not the model or API
|
|
535
|
-
fan-out inside one datapoint. Materialized fixtures keep a large suite
|
|
536
|
-
from exhausting provider and GitHub rate limits.
|
|
537
|
-
|
|
538
|
-
### Load a dataset
|
|
539
|
-
|
|
540
|
-
Read committed fixtures with `loadJson`, `loadJsonl`, and `loadYaml`
|
|
541
|
-
from `@cursor/july/evals/loaders`. Relative paths resolve against the
|
|
542
|
-
project root the runner discovered, not the cwd the CLI ran from. Eval
|
|
543
|
-
files are ES modules, so top-level `await` can load a dataset and fan
|
|
544
|
-
one file out over it:
|
|
545
|
-
|
|
546
|
-
```ts
|
|
547
|
-
// evals/sql.eval.ts: sql/0000, sql/0001, ...
|
|
548
|
-
import { defineEval, equals } from "@cursor/july/evals";
|
|
549
|
-
import { loadYaml } from "@cursor/july/evals/loaders";
|
|
550
|
-
|
|
551
|
-
const rows = await loadYaml<{ task: string; prompt: string; sql: string }[]>(
|
|
552
|
-
"evals/data/cases.yaml"
|
|
553
|
-
);
|
|
554
|
-
|
|
555
|
-
export default rows.map((row) =>
|
|
556
|
-
defineEval({
|
|
557
|
-
description: row.task,
|
|
558
|
-
async test(t) {
|
|
559
|
-
await t.send(row.prompt);
|
|
560
|
-
t.succeeded();
|
|
561
|
-
t.check(t.reply, equals(row.sql));
|
|
562
|
-
},
|
|
563
|
-
})
|
|
564
|
-
);
|
|
565
|
-
```
|
|
566
|
-
|
|
567
|
-
## Configure eval runs
|
|
568
|
-
|
|
569
|
-
`evals/evals.config.ts` (or `.js`) holds project-wide defaults. It must
|
|
570
|
-
set `maxConcurrency`. Each case issues real model requests, so
|
|
571
|
-
concurrency is hard-capped at 200; the templates use 10.
|
|
572
|
-
`eval --list` works without the file. Running a case does not.
|
|
573
|
-
|
|
574
|
-
```ts
|
|
575
|
-
import { defineEvalConfig } from "@cursor/july/evals";
|
|
576
|
-
|
|
577
|
-
export default defineEvalConfig({
|
|
578
|
-
maxConcurrency: 20,
|
|
579
|
-
timeoutMs: 180_000,
|
|
580
|
-
judge: { model: "gpt-5.4-mini" },
|
|
581
134
|
});
|
|
582
135
|
```
|
|
583
136
|
|
|
584
|
-
|
|
585
|
-
| --- | --- | --- |
|
|
586
|
-
| `maxConcurrency` | required | Datapoints in flight at once, 1-200 |
|
|
587
|
-
| `timeoutMs` | `180_000` | Per-case timeout. Precedence: case or file `timeoutMs`, then `--timeout-ms`, then this value |
|
|
588
|
-
| `judge` | unset | Default judge model for `t.judge.*` |
|
|
589
|
-
| `reporters` | unset | Destinations that observe every case; `--skip-report` suppresses them |
|
|
590
|
-
| `maxPlaygroundRuns` | `20` | Batches kept in playground history (cap 500). Counts `--prod` and `--url` batches, not the default local run |
|
|
591
|
-
|
|
592
|
-
Reporters ship results somewhere; the runner still does the grading.
|
|
593
|
-
`JUnit({ filePath, suiteName? })` writes JUnit XML and
|
|
594
|
-
`Artifacts({ dir })` writes per-case files, both from
|
|
595
|
-
`@cursor/july/evals/reporters`. A custom reporter is an object with any
|
|
596
|
-
of `onRunStart`, `onEvalComplete`, and `onRunComplete`. A reporter that
|
|
597
|
-
throws is logged and never fails the run. CI usually attaches the
|
|
598
|
-
built-in two with `--junit` and `--artifacts` instead of `reporters`,
|
|
599
|
-
so output paths stay with the pipeline, not the eval author.
|
|
600
|
-
|
|
601
|
-
Playground batches survive restarts when the project configures
|
|
602
|
-
durable storage. Otherwise they live in process
|
|
603
|
-
memory until `serve` exits.
|
|
604
|
-
|
|
605
|
-
## Run evals from the CLI
|
|
137
|
+
For GitHub agents, snapshot a PR into committed fixtures:
|
|
606
138
|
|
|
607
139
|
```bash
|
|
608
|
-
agent-sdk
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
agent-sdk eval --dir . --tag smoke --tag pull-request # any matching tag
|
|
613
|
-
agent-sdk eval --dir . --verbose # t.log lines + reply snippets
|
|
614
|
-
agent-sdk eval --dir . --timeout-ms 300000 # override the per-case timeout
|
|
140
|
+
agent-sdk github replay acme/checkout#42 \
|
|
141
|
+
--events '*' \
|
|
142
|
+
--dry-run \
|
|
143
|
+
--out fixtures/github
|
|
615
144
|
```
|
|
616
145
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
and
|
|
146
|
+
Keep a small, fast `smoke` set for every change. Put larger datasets and
|
|
147
|
+
drift-prone live cases behind an explicit selection. See
|
|
148
|
+
[Datasets and fixtures](/docs/reference/evals.md#datasets-and-fixtures) for
|
|
149
|
+
loaders and case expansion.
|
|
621
150
|
|
|
622
|
-
|
|
623
|
-
cases don't inherit your checkout's `AGENTS.md` and session state stays
|
|
624
|
-
out of the project. Artifacts still land in the project state
|
|
625
|
-
directory; see [Where results land](#where-results-land). `--slug`
|
|
626
|
-
picks the target in a multi-agent directory.
|
|
151
|
+
## Run and debug a regression suite
|
|
627
152
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
`--artifacts`, `--max-concurrency`, `--skip-report`) do not apply. See
|
|
632
|
-
[Run evals in the playground or on a deployment](#run-evals-in-the-playground-or-on-a-deployment).
|
|
153
|
+
Run one case while iterating, then the smoke suite before review. A
|
|
154
|
+
failure artifact records the input, assertions, tool calls, and final
|
|
155
|
+
text, making it the first place to look before changing the prompt.
|
|
633
156
|
|
|
634
157
|
```bash
|
|
635
|
-
agent-sdk eval --
|
|
636
|
-
|
|
158
|
+
agent-sdk eval --dir . readiness
|
|
159
|
+
agent-sdk eval --dir . --tag smoke
|
|
160
|
+
agent-sdk eval --dir . --json
|
|
637
161
|
```
|
|
638
162
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
Model turns need a
|
|
644
|
-
[Cursor credential](/docs/reference/cli.md#environment-variables):
|
|
645
|
-
`CURSOR_API_KEY`, `CURSOR_SERVICE_ACCOUNT_KEY`, or a saved
|
|
646
|
-
`agent-sdk login`. The judge uses the same one. `eval --list` needs
|
|
647
|
-
none.
|
|
163
|
+
By default, results land under `evals/<stamp>/` in the project state
|
|
164
|
+
directory. Open `evals/<case-id>.json` inside that run directory for the
|
|
165
|
+
failed case. This artifact location is independent of `--state-root`;
|
|
166
|
+
pass `--artifacts <dir>` to choose another destination.
|
|
648
167
|
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
`evals/` in the project state directory, whatever `--state-root` says.
|
|
653
|
-
`--artifacts <dir>` chooses the path and `--no-artifacts` skips them.
|
|
654
|
-
The directory holds `summary.json`,
|
|
655
|
-
`results.jsonl`, and `evals/<case-id>.json` with every assertion, the
|
|
656
|
-
inputs, tool calls with arguments and output, the final text, and
|
|
657
|
-
`t.log` lines. Start there when a case fails. `--out <file>` also
|
|
658
|
-
writes the full results JSON to a path of your choice.
|
|
659
|
-
|
|
660
|
-
The artifact does not include the session's event stream. Pass
|
|
661
|
-
`--state-root <path>` to keep the ephemeral server's
|
|
662
|
-
[session data](/docs/reference/sessions.md#where-does-the-agent-sdk-store-session-data)
|
|
663
|
-
on disk when you need the raw events.
|
|
168
|
+
Model turns need a credential. Resolution checks `CURSOR_API_KEY`,
|
|
169
|
+
`CURSOR_API_KEY_FILE`, `CURSOR_SERVICE_ACCOUNT_KEY`, then a saved
|
|
170
|
+
`agent-sdk login`. `eval --list` only discovers cases and needs none.
|
|
664
171
|
|
|
665
172
|
## Run evals in CI
|
|
666
173
|
|
|
667
|
-
|
|
668
|
-
|
|
174
|
+
Write machine-readable output and JUnit annotations, then let a failed
|
|
175
|
+
gate fail the job:
|
|
669
176
|
|
|
670
177
|
```bash
|
|
671
|
-
# CURSOR_API_KEY comes from the CI secret store
|
|
178
|
+
# CURSOR_API_KEY comes from the CI secret store.
|
|
672
179
|
agent-sdk eval --dir . --json --no-stream \
|
|
673
180
|
--junit reports/evals.xml \
|
|
674
181
|
--artifacts reports/evals \
|
|
675
182
|
> reports/evals.json
|
|
676
183
|
```
|
|
677
184
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
setting, for example to run lower on a shared runner.
|
|
682
|
-
|
|
683
|
-
The JSON on stdout carries the totals and one result per case:
|
|
684
|
-
|
|
685
|
-
```json
|
|
686
|
-
{
|
|
687
|
-
"ok": true,
|
|
688
|
-
"passed": 1,
|
|
689
|
-
"failed": 0,
|
|
690
|
-
"scored": 0,
|
|
691
|
-
"skipped": 0,
|
|
692
|
-
"strict": false,
|
|
693
|
-
"artifactsDir": "/work/my-agent/reports/evals",
|
|
694
|
-
"results": [
|
|
695
|
-
{
|
|
696
|
-
"id": "readiness",
|
|
697
|
-
"verdict": "passed",
|
|
698
|
-
"ok": true,
|
|
699
|
-
"assertions": [
|
|
700
|
-
{ "name": "succeeded", "passed": true },
|
|
701
|
-
{ "name": "calledTool(inspect_pr)", "passed": true }
|
|
702
|
-
],
|
|
703
|
-
"sessionId": "ses_123",
|
|
704
|
-
"inputs": ["Is https://github.com/acme/checkout/pull/42 ready to approve?"],
|
|
705
|
-
"toolCalls": [{ "toolName": "inspect_pr", "isError": false }],
|
|
706
|
-
"metrics": {},
|
|
707
|
-
"logs": [],
|
|
708
|
-
"durationMs": 12340
|
|
709
|
-
}
|
|
710
|
-
]
|
|
711
|
-
}
|
|
712
|
-
```
|
|
185
|
+
Run `--tag smoke` on pull requests and the full suite on a schedule when
|
|
186
|
+
cost or latency makes every-push coverage impractical. Use soft scores
|
|
187
|
+
for a new probabilistic benchmark until its threshold is trustworthy.
|
|
713
188
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
A soft miss shows as `"severity": "soft"` with `score` and `threshold`
|
|
717
|
-
on the assertion. This shape lets CI report the failed assertion
|
|
718
|
-
without parsing terminal text.
|
|
189
|
+
The [CLI reference](/docs/reference/cli.md#eval) covers selectors, hosted
|
|
190
|
+
runs, exit codes, and JSON output.
|
|
719
191
|
|
|
720
|
-
Keep
|
|
721
|
-
|
|
722
|
-
- Run `--tag smoke` on every push and the full suite on a schedule.
|
|
723
|
-
- For probabilistic behavior, use `iterations` and a soft bar instead
|
|
724
|
-
of one hard gate.
|
|
192
|
+
## Keep side effects out of eval sessions
|
|
725
193
|
|
|
726
|
-
|
|
194
|
+
Eval sessions carry `purpose: "eval"`. Check it at the deterministic
|
|
195
|
+
write boundary and return the decision without performing the external
|
|
196
|
+
action:
|
|
727
197
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
198
|
+
```ts
|
|
199
|
+
async execute({ findings }, ctx) {
|
|
200
|
+
if (ctx.session.purpose === "eval") {
|
|
201
|
+
return {
|
|
202
|
+
posted: false,
|
|
203
|
+
reason: "eval",
|
|
204
|
+
count: findings.length,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
732
207
|
|
|
733
|
-
|
|
734
|
-
|
|
208
|
+
return await postFindings(findings);
|
|
209
|
+
}
|
|
735
210
|
```
|
|
736
211
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
server's playground history:
|
|
212
|
+
This preserves the tool call in the trajectory, so the eval can still
|
|
213
|
+
assert that the agent chose to post.
|
|
740
214
|
|
|
741
|
-
|
|
742
|
-
agent-sdk eval --prod --slug vulnerability-scanner --tag deepsec
|
|
743
|
-
# Eval ID: <evalId>
|
|
744
|
-
# Playground: <deployment>/playground?view=evals&evalRunId=<evalId>
|
|
745
|
-
agent-sdk eval status <evalId> --prod --slug vulnerability-scanner
|
|
746
|
-
agent-sdk eval cancel <evalId> --prod --slug vulnerability-scanner
|
|
747
|
-
```
|
|
215
|
+
## Evals, hooks, or hillclimbing?
|
|
748
216
|
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
[Playground eval routes](/docs/reference/http-api.md#playground-eval-routes).
|
|
217
|
+
Use an eval to gate one fixed input. Use a
|
|
218
|
+
[hook](/docs/reference/hooks.md) to observe every live session for metrics,
|
|
219
|
+
auditing, or alerts. Use [hillclimbing](/docs/hillclimbing.md) to decide
|
|
220
|
+
which source change improves a fixed set of inputs; every kept
|
|
221
|
+
hillclimb change should add an eval.
|
|
755
222
|
|
|
756
|
-
##
|
|
223
|
+
## Gates and scores
|
|
757
224
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
225
|
+
`t.succeeded()`, tool assertions, and deterministic checks are hard
|
|
226
|
+
gates by default. A failed gate fails the case. `.soft()` records a
|
|
227
|
+
measurement without blocking, while `.atLeast(threshold)` records a
|
|
228
|
+
score and marks a miss as `scored`.
|
|
229
|
+
|
|
230
|
+
Start with decisions and output shape: the intended tool, the tempting
|
|
231
|
+
wrong tool, and one structural check. Exact prose is rarely a stable
|
|
232
|
+
contract.
|
|
233
|
+
|
|
234
|
+
## Keep improvements with regression evals
|
|
763
235
|
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
236
|
+
Every kept improvement needs an eval that would have failed before the
|
|
237
|
+
change. A tool-choice gate, bounded `maxToolCalls`, or output-shape check
|
|
238
|
+
turns the improvement into a durable contract.
|
|
767
239
|
|
|
768
|
-
|
|
240
|
+
Never weaken an existing gate to make a new implementation pass. That
|
|
241
|
+
moves the freeze line instead of proving the change.
|
|
769
242
|
|
|
770
|
-
|
|
243
|
+
## Related
|
|
771
244
|
|
|
772
|
-
- [
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
- [Sessions
|
|
778
|
-
|
|
245
|
+
- [Evals reference](/docs/reference/evals.md): complete authoring and runner
|
|
246
|
+
contracts
|
|
247
|
+
- [`skills/evals/SKILL.md`](https://github.com/cursor/cursor/blob/main/packages/agent-serve/skills/evals/SKILL.md): author and seed
|
|
248
|
+
cases with a coding agent
|
|
249
|
+
- [Hillclimbing](/docs/hillclimbing.md): measure a change and lock the win
|
|
250
|
+
- [Sessions](/docs/reference/sessions.md): events available to trajectory
|
|
251
|
+
assertions
|