@cursor/bdk 0.2.3 → 0.2.4
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 +9 -1
- package/dist/channels/slack/attachments.d.ts +2 -1
- package/dist/channels/slack/attachments.d.ts.map +1 -1
- package/dist/channels/slack/attachments.js +19 -9
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +26 -24
- package/dist/channels/slack/thread-context.d.ts +21 -11
- package/dist/channels/slack/thread-context.d.ts.map +1 -1
- package/dist/channels/slack/thread-context.js +75 -27
- package/dist/docs/404.html +2 -2
- package/dist/docs/assets/{app.BOIHhrKi.js → app.4kQ8Db_q.js} +4 -4
- package/dist/docs/assets/chunks/@localSearchIndexroot.CvuAJ0My.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.D49zVZqM.js → VPLocalSearchBox.DY1RwB8Q.js} +1 -1
- package/dist/docs/assets/chunks/{arc.hmjb-sc4.js → arc.CxE_fSPK.js} +1 -1
- package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.CxEI1KqM.js → architectureDiagram-Q4EWVU46.CPX426ui.js} +1 -1
- package/dist/docs/assets/chunks/{baseUniq.DHHvBWoV.js → baseUniq.CB52JrKG.js} +1 -1
- package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.DnXW-3bu.js → blockDiagram-DXYQGD6D.J0cNaQCL.js} +1 -1
- package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.e-47O2jM.js → c4Diagram-AHTNJAMY.DJn3vEGT.js} +1 -1
- package/dist/docs/assets/chunks/channel.BoNycAoN.js +1 -0
- package/dist/docs/assets/chunks/{chunk-4BX2VUAB.3ry4pYXB.js → chunk-4BX2VUAB.Dao618F6.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-4TB4RGXK.DGIZFRx6.js → chunk-4TB4RGXK.QW8Rhjai.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-55IACEB6.DKBnqg9U.js → chunk-55IACEB6.DfRLLKF_.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-EDXVE4YY.BIU8Ue5k.js → chunk-EDXVE4YY.CIV2ApKQ.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-FMBD7UC4.DP-TFhjI.js → chunk-FMBD7UC4.BEheSuxp.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-OYMX7WX6.Ux0OYj5v.js → chunk-OYMX7WX6.CUN88ENB.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-QZHKN3VN.BzHMwYox.js → chunk-QZHKN3VN.CgqCs8b_.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-YZCP3GAM.D4OGAsSP.js → chunk-YZCP3GAM.iCH0nnTJ.js} +1 -1
- package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.C4x07Gkj.js +1 -0
- package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.C4x07Gkj.js +1 -0
- package/dist/docs/assets/chunks/clone.Db22cH_-.js +1 -0
- package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.Jq_7BUNx.js → cose-bilkent-S5V4N54A.BLcUxhWE.js} +1 -1
- package/dist/docs/assets/chunks/{dagre-KV5264BT.Di-skR2x.js → dagre-KV5264BT.Ep7LofOm.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-5BDNPKRD.DeREHIdH.js → diagram-5BDNPKRD.Bzf4GSQ4.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.C7Kcqxro.js → diagram-G4DWMVQ6.DD6Jh-eM.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-MMDJMWI5.BK3eohyo.js → diagram-MMDJMWI5.oOIl8bWd.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-TYMM5635.C6TyymXT.js → diagram-TYMM5635.DHs85Ade.js} +1 -1
- package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.DYGG-gGx.js → erDiagram-SMLLAGMA.BIb5ghCk.js} +1 -1
- package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.C9nBcSV4.js → flowDiagram-DWJPFMVM.DV4paY9k.js} +1 -1
- package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.wAg_ymsp.js → ganttDiagram-T4ZO3ILL.AyEKA6_v.js} +1 -1
- package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.B87j9Oeg.js → gitGraphDiagram-UUTBAWPF.BltiCDFo.js} +1 -1
- package/dist/docs/assets/chunks/{graph.CuFMj31w.js → graph.DzuEYGdC.js} +1 -1
- package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.P_mLGumP.js → infoDiagram-42DDH7IO.BV2l981J.js} +1 -1
- package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.DyuL_MsT.js → ishikawaDiagram-UXIWVN3A.BA4Izf-m.js} +1 -1
- package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.CtP09IoJ.js → journeyDiagram-VCZTEJTY.DjaFbFS3.js} +1 -1
- package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.BoeSYPZo.js → kanban-definition-6JOO6SKY.CfTFieDs.js} +1 -1
- package/dist/docs/assets/chunks/{layout.B0lMMtNo.js → layout.DzfWqTBV.js} +1 -1
- package/dist/docs/assets/chunks/{linear.HxRBiAFX.js → linear.BO6mpulV.js} +1 -1
- package/dist/docs/assets/chunks/{min.BGlFFHwS.js → min.BGgTadgT.js} +1 -1
- package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.JyLBD9M8.js → mindmap-definition-QFDTVHPH.DPuIXVWY.js} +1 -1
- package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.DnSmNZF8.js → pieDiagram-DEJITSTG.BOnl3bBg.js} +1 -1
- package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.CUCnbfCa.js → quadrantDiagram-34T5L4WZ.DNB6Ckdc.js} +1 -1
- package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.py0IVUn5.js → requirementDiagram-MS252O5E.D5-Qo7vb.js} +1 -1
- package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.Bkc-HWYp.js → sankeyDiagram-XADWPNL6.8t65cesf.js} +1 -1
- package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.Dqn8Mlv2.js → sequenceDiagram-FGHM5R23.CaG07BdS.js} +1 -1
- package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.JikkoQUU.js → stateDiagram-FHFEXIEX.TKOweTB6.js} +1 -1
- package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.CuqmyQc4.js +1 -0
- package/dist/docs/assets/chunks/{theme.b6HQ6zG_.js → theme.Dx-JhpTB.js} +2 -2
- package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.BvpSXiBj.js → timeline-definition-GMOUNBTQ.fE53zQ2s.js} +1 -1
- package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.CU7MVnZx.js → vennDiagram-DHZGUBPP.DJsZZaJg.js} +1 -1
- package/dist/docs/assets/chunks/{wardley-RL74JXVD.BKwC4ctG.js → wardley-RL74JXVD.844kyrjl.js} +1 -1
- package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.BfaF6Uhe.js → wardleyDiagram-NUSXRM2D.CMZ-Ru_t.js} +1 -1
- package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.Bg5dcpj4.js → xychartDiagram-5P7HB3ND.XXrhBc7a.js} +1 -1
- package/dist/docs/assets/{deployment.md.BJ8i7Q6p.js → deployment.md.UhnJIMr-.js} +2 -2
- package/dist/docs/assets/{deployment.md.BJ8i7Q6p.lean.js → deployment.md.UhnJIMr-.lean.js} +1 -1
- package/dist/docs/assets/{guides_jev.md.BNDm14Gy.js → guides_jev.md.CRcgmjDb.js} +2 -2
- package/dist/docs/assets/{guides_jev.md.BNDm14Gy.lean.js → guides_jev.md.CRcgmjDb.lean.js} +1 -1
- package/dist/docs/assets/{reference_agent-config.md.DzGI777n.js → reference_agent-config.md.Cj5uBKp4.js} +1 -1
- package/dist/docs/assets/{reference_extensions.md.CPPrkWlJ.js → reference_extensions.md.pa2tN-e4.js} +4 -3
- package/dist/docs/assets/{reference_extensions.md.CPPrkWlJ.lean.js → reference_extensions.md.pa2tN-e4.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +35 -35
- package/dist/docs/deployment.html +37 -37
- package/dist/docs/deployment.md +4 -1
- package/dist/docs/evals.html +35 -35
- package/dist/docs/guides/agent-to-agent.html +35 -35
- package/dist/docs/guides/bitbucket.html +35 -35
- package/dist/docs/guides/cloud-agents.html +35 -35
- package/dist/docs/guides/convert-automation.html +35 -35
- package/dist/docs/guides/github.html +35 -35
- package/dist/docs/guides/gitlab.html +35 -35
- package/dist/docs/guides/grokbot-agents.html +35 -35
- package/dist/docs/guides/hooks.html +35 -35
- package/dist/docs/guides/improve.html +35 -35
- package/dist/docs/guides/jev.html +37 -37
- package/dist/docs/guides/jev.md +7 -0
- package/dist/docs/guides/mcp-oauth.html +35 -35
- package/dist/docs/guides/opentelemetry.html +35 -35
- package/dist/docs/guides/slack.html +35 -35
- package/dist/docs/guides/webhooks.html +35 -35
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +35 -35
- package/dist/docs/index.html +35 -35
- package/dist/docs/llms-full.txt +25 -2
- package/dist/docs/quickstart.html +35 -35
- package/dist/docs/reference/agent-config.html +37 -37
- package/dist/docs/reference/agent-config.md +1 -1
- package/dist/docs/reference/artifacts.html +35 -35
- package/dist/docs/reference/channels.html +35 -35
- package/dist/docs/reference/cli.html +35 -35
- package/dist/docs/reference/connections.html +35 -35
- package/dist/docs/reference/evals.html +35 -35
- package/dist/docs/reference/extensions.html +39 -38
- package/dist/docs/reference/extensions.md +13 -0
- package/dist/docs/reference/hooks.html +35 -35
- package/dist/docs/reference/http-api.html +35 -35
- package/dist/docs/reference/instructions.html +35 -35
- package/dist/docs/reference/playground.html +35 -35
- package/dist/docs/reference/project-layout.html +35 -35
- package/dist/docs/reference/prompt.html +35 -35
- package/dist/docs/reference/schedules.html +35 -35
- package/dist/docs/reference/sessions.html +35 -35
- package/dist/docs/reference/skills.html +35 -35
- package/dist/docs/reference/subagents.html +35 -35
- package/dist/docs/reference/tools.html +35 -35
- package/dist/docs/templates/agentic-owners.html +35 -35
- package/dist/docs/templates/security-reviewer.html +35 -35
- package/dist/docs/templates/thermo-quality-review.html +35 -35
- package/dist/docs/templates/thermo-review.html +35 -35
- package/dist/docs/templates/triage.html +35 -35
- package/dist/docs/troubleshooting.html +35 -35
- package/dist/extensions/jev/extension.d.ts +3 -0
- package/dist/extensions/jev/extension.d.ts.map +1 -1
- package/dist/extensions/jev/extension.js +10 -1
- package/dist/extensions/jev/lib/evaluate.d.ts +4 -0
- package/dist/extensions/jev/lib/evaluate.d.ts.map +1 -1
- package/dist/extensions/jev/lib/evaluate.js +6 -2
- package/dist/extensions.d.ts +4 -2
- package/dist/extensions.d.ts.map +1 -1
- package/dist/extensions.js +5 -2
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +19 -5
- package/dist/internal/discovery/agent-config.d.ts +6 -5
- package/dist/internal/discovery/agent-config.d.ts.map +1 -1
- package/dist/internal/discovery/agent-config.js +29 -28
- package/dist/internal/discovery/agent.js +1 -1
- package/dist/internal/discovery/extensions.d.ts.map +1 -1
- package/dist/internal/discovery/extensions.js +12 -0
- package/dist/internal/hosting.d.ts +8 -0
- package/dist/internal/hosting.d.ts.map +1 -1
- package/dist/internal/hosting.js +24 -0
- package/dist/types.d.ts +18 -2
- package/dist/types.d.ts.map +1 -1
- package/docs/deployment.md +4 -1
- package/docs/guides/jev.md +7 -0
- package/docs/reference/agent-config.md +1 -1
- package/docs/reference/extensions.md +13 -0
- package/package.json +1 -9
- package/dist/docs/assets/chunks/@localSearchIndexroot.D5L-b34G.js +0 -1
- package/dist/docs/assets/chunks/channel.BbOGaJQP.js +0 -1
- package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.Db58HCb1.js +0 -1
- package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.Db58HCb1.js +0 -1
- package/dist/docs/assets/chunks/clone.Co4MBflG.js +0 -1
- package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.CMsKhrW0.js +0 -1
- package/src/artifacts.ts +0 -68
- package/src/bin/agent-serve.ts +0 -1854
- package/src/channels/bitbucket/api.ts +0 -891
- package/src/channels/bitbucket/binding.ts +0 -417
- package/src/channels/bitbucket/bitbucket-channel.ts +0 -162
- package/src/channels/bitbucket/bitbucket-webhook.ts +0 -519
- package/src/channels/bitbucket/checks.ts +0 -146
- package/src/channels/bitbucket/cursor-account.ts +0 -106
- package/src/channels/bitbucket/defaults.ts +0 -100
- package/src/channels/bitbucket/events.ts +0 -74
- package/src/channels/bitbucket/index.ts +0 -51
- package/src/channels/bitbucket/replay.ts +0 -421
- package/src/channels/bitbucket/state.ts +0 -59
- package/src/channels/bitbucket/types.ts +0 -261
- package/src/channels/change-monitors/change-monitors-channel.ts +0 -63
- package/src/channels/change-monitors/index.ts +0 -8
- package/src/channels/change-monitors/types.ts +0 -42
- package/src/channels/checks.ts +0 -185
- package/src/channels/deployments/deployments-channel.ts +0 -224
- package/src/channels/deployments/index.ts +0 -25
- package/src/channels/deployments/types.ts +0 -92
- package/src/channels/github/api.ts +0 -526
- package/src/channels/github/auth.ts +0 -293
- package/src/channels/github/binding.ts +0 -233
- package/src/channels/github/checks.ts +0 -145
- package/src/channels/github/cursor-account.ts +0 -303
- package/src/channels/github/defaults.ts +0 -168
- package/src/channels/github/events.ts +0 -67
- package/src/channels/github/forward.ts +0 -359
- package/src/channels/github/github-channel.ts +0 -2334
- package/src/channels/github/index.ts +0 -54
- package/src/channels/github/progress.ts +0 -365
- package/src/channels/github/replay.ts +0 -372
- package/src/channels/github/state.ts +0 -124
- package/src/channels/github/types.ts +0 -590
- package/src/channels/gitlab/api.ts +0 -329
- package/src/channels/gitlab/binding.ts +0 -231
- package/src/channels/gitlab/checks.ts +0 -228
- package/src/channels/gitlab/cursor-account.ts +0 -105
- package/src/channels/gitlab/defaults.ts +0 -80
- package/src/channels/gitlab/events.ts +0 -37
- package/src/channels/gitlab/gitlab-channel.ts +0 -160
- package/src/channels/gitlab/gitlab-webhook.ts +0 -509
- package/src/channels/gitlab/index.ts +0 -44
- package/src/channels/gitlab/replay.ts +0 -328
- package/src/channels/gitlab/state.ts +0 -55
- package/src/channels/gitlab/types.ts +0 -247
- package/src/channels/issues/index.ts +0 -9
- package/src/channels/issues/issues-channel.ts +0 -45
- package/src/channels/issues/types.ts +0 -38
- package/src/channels/origin/api.ts +0 -507
- package/src/channels/origin/binding.ts +0 -114
- package/src/channels/origin/checks.ts +0 -250
- package/src/channels/origin/cursor-account.ts +0 -58
- package/src/channels/origin/defaults.ts +0 -140
- package/src/channels/origin/events.ts +0 -35
- package/src/channels/origin/index.ts +0 -35
- package/src/channels/origin/origin-channel.ts +0 -815
- package/src/channels/origin/origin-webhook.ts +0 -296
- package/src/channels/origin/reactions.ts +0 -72
- package/src/channels/origin/state.ts +0 -54
- package/src/channels/origin/types.ts +0 -295
- package/src/channels/slack/agentic-delivery.ts +0 -634
- package/src/channels/slack/agentic-posted.ts +0 -135
- package/src/channels/slack/agentic-signals.ts +0 -231
- package/src/channels/slack/api.ts +0 -761
- package/src/channels/slack/approvals.ts +0 -279
- package/src/channels/slack/assistant.ts +0 -76
- package/src/channels/slack/attachments.ts +0 -596
- package/src/channels/slack/auth.ts +0 -127
- package/src/channels/slack/blocks.ts +0 -131
- package/src/channels/slack/bot-mentions.ts +0 -318
- package/src/channels/slack/channel-watch.ts +0 -314
- package/src/channels/slack/cli-project.ts +0 -249
- package/src/channels/slack/code-fences.ts +0 -171
- package/src/channels/slack/constants.ts +0 -38
- package/src/channels/slack/credentials.ts +0 -88
- package/src/channels/slack/defaults.ts +0 -714
- package/src/channels/slack/dispatch.ts +0 -1060
- package/src/channels/slack/doctor.ts +0 -338
- package/src/channels/slack/eval-directive.ts +0 -306
- package/src/channels/slack/event-id-dedupe.ts +0 -30
- package/src/channels/slack/external-policy.ts +0 -75
- package/src/channels/slack/footer.ts +0 -106
- package/src/channels/slack/inbound.ts +0 -416
- package/src/channels/slack/index.ts +0 -53
- package/src/channels/slack/init.ts +0 -169
- package/src/channels/slack/interactive.ts +0 -406
- package/src/channels/slack/links.ts +0 -23
- package/src/channels/slack/live-delivery.ts +0 -489
- package/src/channels/slack/log.ts +0 -70
- package/src/channels/slack/manifest.ts +0 -240
- package/src/channels/slack/message-body.ts +0 -82
- package/src/channels/slack/nudge-carrier.ts +0 -224
- package/src/channels/slack/nudge-store.ts +0 -334
- package/src/channels/slack/paint-start.ts +0 -93
- package/src/channels/slack/placeholder.ts +0 -358
- package/src/channels/slack/pr-ref.ts +0 -74
- package/src/channels/slack/progress-delivery.ts +0 -138
- package/src/channels/slack/reasoning-card.ts +0 -125
- package/src/channels/slack/reasoning-chip.ts +0 -41
- package/src/channels/slack/recording-sink.ts +0 -167
- package/src/channels/slack/redact.ts +0 -6
- package/src/channels/slack/reply-options.ts +0 -279
- package/src/channels/slack/setup.ts +0 -125
- package/src/channels/slack/slack-channel.ts +0 -744
- package/src/channels/slack/socket-mode.ts +0 -140
- package/src/channels/slack/stop.ts +0 -25
- package/src/channels/slack/stream.ts +0 -66
- package/src/channels/slack/thread-context.ts +0 -485
- package/src/channels/slack/tool-approval-events.ts +0 -233
- package/src/channels/slack/tool-cards.ts +0 -198
- package/src/channels/slack/tool-chip.ts +0 -34
- package/src/channels/slack/types.ts +0 -787
- package/src/channels/slack/upload.ts +0 -137
- package/src/channels.ts +0 -543
- package/src/connections.ts +0 -153
- package/src/dashboard-session-url.ts +0 -30
- package/src/evals/assertions.ts +0 -688
- package/src/evals/expect.ts +0 -250
- package/src/evals/judge.ts +0 -329
- package/src/evals/loaders.ts +0 -111
- package/src/evals/matchers.ts +0 -223
- package/src/evals/reporters.ts +0 -257
- package/src/evals/results.ts +0 -130
- package/src/evals/run-facts.ts +0 -306
- package/src/evals.ts +0 -709
- package/src/extensions/cursor-cloud-agents/extension.ts +0 -131
- package/src/extensions/cursor-cloud-agents/lib/backend.ts +0 -386
- package/src/extensions/cursor-cloud-agents/lib/channels.ts +0 -11
- package/src/extensions/cursor-cloud-agents/lib/fleet.ts +0 -98
- package/src/extensions/cursor-cloud-agents/lib/inputs.ts +0 -5
- package/src/extensions/cursor-cloud-agents/lib/repos.ts +0 -80
- package/src/extensions/cursor-cloud-agents/lib/transcript.ts +0 -19
- package/src/extensions/cursor-cloud-agents/skills/handoff.md +0 -37
- package/src/extensions/cursor-cloud-agents/tools/cancel.ts +0 -21
- package/src/extensions/cursor-cloud-agents/tools/dump.ts +0 -47
- package/src/extensions/cursor-cloud-agents/tools/get.ts +0 -18
- package/src/extensions/cursor-cloud-agents/tools/launch.ts +0 -62
- package/src/extensions/cursor-cloud-agents/tools/list.ts +0 -31
- package/src/extensions/cursor-cloud-agents/tools/reply.ts +0 -36
- package/src/extensions/cursor-grokbot-agents/extension.ts +0 -132
- package/src/extensions/cursor-grokbot-agents/lib/agents.ts +0 -42
- package/src/extensions/cursor-grokbot-agents/lib/backend.ts +0 -208
- package/src/extensions/cursor-grokbot-agents/lib/contacts.ts +0 -74
- package/src/extensions/cursor-grokbot-agents/lib/conversation.ts +0 -260
- package/src/extensions/cursor-grokbot-agents/lib/inputs.ts +0 -21
- package/src/extensions/cursor-grokbot-agents/lib/lock.ts +0 -26
- package/src/extensions/cursor-grokbot-agents/skills/consult.md +0 -40
- package/src/extensions/cursor-grokbot-agents/tools/ask.ts +0 -32
- package/src/extensions/cursor-grokbot-agents/tools/check.ts +0 -25
- package/src/extensions/cursor-grokbot-agents/tools/interrupt.ts +0 -17
- package/src/extensions/cursor-grokbot-agents/tools/list.ts +0 -26
- package/src/extensions/improve/extension.ts +0 -69
- package/src/extensions/improve/skills/yourself.ts +0 -50
- package/src/extensions/jev/extension.ts +0 -95
- package/src/extensions/jev/lib/evaluate.ts +0 -266
- package/src/extensions/jev/skills/gated-write.md +0 -25
- package/src/extensions/jev/skills/questions.md +0 -33
- package/src/extensions/jev/tools/evaluate.ts +0 -82
- package/src/extensions/slack-communication/evals/harness.ts +0 -705
- package/src/extensions/slack-communication/evals/slack-communication.eval.ts +0 -830
- package/src/extensions/slack-communication/evals/slack-placeholder.eval.ts +0 -172
- package/src/extensions/slack-communication/extension.ts +0 -44
- package/src/extensions/slack-communication/skills/slack-voice.ts +0 -56
- package/src/extensions/slack-communication/tools/delete-message.ts +0 -33
- package/src/extensions/slack-communication/tools/edit-message.ts +0 -42
- package/src/extensions/slack-communication/tools/post-card.ts +0 -28
- package/src/extensions/slack-communication/tools/post-file.ts +0 -82
- package/src/extensions/slack-communication/tools/post-update.ts +0 -40
- package/src/extensions/slack-communication/tools/react.ts +0 -30
- package/src/extensions/slack-communication/tools/set-status.ts +0 -21
- package/src/extensions.ts +0 -179
- package/src/files-backends/agent-store-presigned-url.ts +0 -11
- package/src/files-backends/cursor-hosted.ts +0 -1212
- package/src/files-backends/local-fs.ts +0 -163
- package/src/files.ts +0 -293
- package/src/filesystem.ts +0 -2005
- package/src/hooks.ts +0 -30
- package/src/index.ts +0 -259
- package/src/internal/advertise-tools.ts +0 -370
- package/src/internal/approval-gate.ts +0 -103
- package/src/internal/artifacts-store.ts +0 -836
- package/src/internal/as-of.ts +0 -257
- package/src/internal/auth.ts +0 -46
- package/src/internal/authored-alias-hooks.ts +0 -138
- package/src/internal/authored-loaders.ts +0 -188
- package/src/internal/bounded-int.ts +0 -24
- package/src/internal/bounded.ts +0 -25
- package/src/internal/brand.ts +0 -28
- package/src/internal/browser-origin-guard.ts +0 -67
- package/src/internal/builtin-tools/artifacts.ts +0 -62
- package/src/internal/builtin-tools/index.ts +0 -53
- package/src/internal/builtin-tools/reminders.ts +0 -145
- package/src/internal/channel-dispatch.ts +0 -129
- package/src/internal/channel-route-dispatch.ts +0 -58
- package/src/internal/channel-state.ts +0 -83
- package/src/internal/chat-client.ts +0 -594
- package/src/internal/cli-ax.ts +0 -2318
- package/src/internal/cli-bitbucket.ts +0 -438
- package/src/internal/cli-convert-automation.ts +0 -335
- package/src/internal/cli-cursor.ts +0 -282
- package/src/internal/cli-deploy.ts +0 -2519
- package/src/internal/cli-docs.ts +0 -192
- package/src/internal/cli-github.ts +0 -806
- package/src/internal/cli-gitlab.ts +0 -452
- package/src/internal/cli-images.ts +0 -672
- package/src/internal/cli-manifest.ts +0 -56
- package/src/internal/cli-mcp-oauth.ts +0 -396
- package/src/internal/cli-mcp.ts +0 -808
- package/src/internal/cli-skills.ts +0 -98
- package/src/internal/cli-slack-manual.ts +0 -418
- package/src/internal/cli-slack.ts +0 -874
- package/src/internal/cloud-merge.ts +0 -51
- package/src/internal/cloud-turn-cost.ts +0 -159
- package/src/internal/connection-env.ts +0 -106
- package/src/internal/continuation-channel.ts +0 -233
- package/src/internal/continuation-identity.ts +0 -935
- package/src/internal/conversation-mirror.ts +0 -423
- package/src/internal/convert-automation/convert-workflow.ts +0 -1377
- package/src/internal/convert-automation/slug.ts +0 -29
- package/src/internal/convert-automation/types.ts +0 -212
- package/src/internal/cron.ts +0 -76
- package/src/internal/cursor/account-mcp.ts +0 -692
- package/src/internal/cursor/backend-client.ts +0 -984
- package/src/internal/cursor/bound-secret-file.ts +0 -101
- package/src/internal/cursor/credentials.ts +0 -560
- package/src/internal/cursor/cursor-api-transport.ts +0 -65
- package/src/internal/cursor/github-credentials.ts +0 -228
- package/src/internal/cursor/hosted-bound-secrets.ts +0 -71
- package/src/internal/cursor/hosted-deployment-secrets.ts +0 -100
- package/src/internal/cursor/hosted-store-secrets.ts +0 -152
- package/src/internal/cursor/session-token.ts +0 -111
- package/src/internal/cursor/store-api-client.ts +0 -323
- package/src/internal/cursor-account-mcp-auth.ts +0 -303
- package/src/internal/cursor-agent-template.ts +0 -50
- package/src/internal/cursor-deployment-relay.ts +0 -315
- package/src/internal/cursor-event-relay.ts +0 -675
- package/src/internal/cursor-relay-core.ts +0 -563
- package/src/internal/deferred-channel-session.ts +0 -61
- package/src/internal/deploy-client.ts +0 -1574
- package/src/internal/deploy-manifest.ts +0 -361
- package/src/internal/deploy-source.ts +0 -144
- package/src/internal/describe-error.ts +0 -32
- package/src/internal/dev-mode.ts +0 -20
- package/src/internal/discovery/agent-config.ts +0 -288
- package/src/internal/discovery/agent.ts +0 -381
- package/src/internal/discovery/channels.ts +0 -100
- package/src/internal/discovery/connections.ts +0 -516
- package/src/internal/discovery/context.ts +0 -38
- package/src/internal/discovery/cursor-plugin.ts +0 -628
- package/src/internal/discovery/extension-overlay.ts +0 -247
- package/src/internal/discovery/extensions.ts +0 -490
- package/src/internal/discovery/fs.ts +0 -103
- package/src/internal/discovery/hooks.ts +0 -63
- package/src/internal/discovery/info.ts +0 -174
- package/src/internal/discovery/instructions.ts +0 -98
- package/src/internal/discovery/modules.ts +0 -107
- package/src/internal/discovery/names.ts +0 -45
- package/src/internal/discovery/project.ts +0 -319
- package/src/internal/discovery/reminders.ts +0 -65
- package/src/internal/discovery/runtime.ts +0 -158
- package/src/internal/discovery/schedules.ts +0 -120
- package/src/internal/discovery/seed-files.ts +0 -34
- package/src/internal/discovery/services.ts +0 -151
- package/src/internal/discovery/skills.ts +0 -174
- package/src/internal/discovery/subagent.ts +0 -138
- package/src/internal/discovery/tools.ts +0 -170
- package/src/internal/discovery.ts +0 -27
- package/src/internal/distribution.ts +0 -126
- package/src/internal/docs-site.ts +0 -248
- package/src/internal/duration.ts +0 -37
- package/src/internal/env-file.ts +0 -83
- package/src/internal/eval-judge-model.ts +0 -142
- package/src/internal/eval-run-store.ts +0 -585
- package/src/internal/eval-runner.ts +0 -823
- package/src/internal/evals-client.ts +0 -475
- package/src/internal/event-log.ts +0 -342
- package/src/internal/event-mapper.ts +0 -811
- package/src/internal/expected-delivery-failure.ts +0 -34
- package/src/internal/factory-resource-channel.ts +0 -103
- package/src/internal/filesystem/errors.ts +0 -207
- package/src/internal/filesystem/format.ts +0 -253
- package/src/internal/filesystem/merge.ts +0 -192
- package/src/internal/filesystem/nearest.ts +0 -112
- package/src/internal/filesystem/scratch.ts +0 -239
- package/src/internal/filesystem/sdk-schemas.ts +0 -204
- package/src/internal/filesystem/tools.ts +0 -804
- package/src/internal/filesystem/walk.ts +0 -366
- package/src/internal/fixtures/units-server.ts +0 -52
- package/src/internal/framework-file-storage.ts +0 -357
- package/src/internal/framework-storage-selection.ts +0 -156
- package/src/internal/frontmatter.ts +0 -108
- package/src/internal/github-fanout.ts +0 -144
- package/src/internal/guest-network.ts +0 -391
- package/src/internal/handleAgentServeTrigger.ts +0 -286
- package/src/internal/host-files.ts +0 -341
- package/src/internal/host-kv.ts +0 -81
- package/src/internal/host-otel.ts +0 -231
- package/src/internal/host-platforms.ts +0 -170
- package/src/internal/hosted-admission-adapter.ts +0 -47
- package/src/internal/hosted-admission-context.ts +0 -37
- package/src/internal/hosted-catch-protocol.ts +0 -112
- package/src/internal/hosted-catch.ts +0 -179
- package/src/internal/hosted-delivery-protocol.ts +0 -824
- package/src/internal/hosted-delivery.ts +0 -1410
- package/src/internal/hosted-execution-diag.ts +0 -291
- package/src/internal/hosted-execution-flush.ts +0 -136
- package/src/internal/hosted-execution-latency.ts +0 -301
- package/src/internal/hosted-managed-automation.ts +0 -116
- package/src/internal/hosting.ts +0 -114
- package/src/internal/http-channel-define.ts +0 -25
- package/src/internal/http-channel.ts +0 -669
- package/src/internal/http-control-plane-session.ts +0 -110
- package/src/internal/ids.ts +0 -39
- package/src/internal/incoming-headers-to-fetch.ts +0 -45
- package/src/internal/init-interview.ts +0 -360
- package/src/internal/init-project.ts +0 -711
- package/src/internal/init-scaffold.ts +0 -182
- package/src/internal/inline-stdio-define-stub.ts +0 -4
- package/src/internal/inline-stdio-mcp.ts +0 -230
- package/src/internal/install-cursor-skills.ts +0 -604
- package/src/internal/is-record.ts +0 -3
- package/src/internal/json-schema.ts +0 -95
- package/src/internal/legacy-command-guard.ts +0 -66
- package/src/internal/listen-port.ts +0 -85
- package/src/internal/local-control-plane.ts +0 -442
- package/src/internal/local-env.ts +0 -59
- package/src/internal/local-ingress.ts +0 -90
- package/src/internal/log-ring.ts +0 -59
- package/src/internal/logs-client.ts +0 -477
- package/src/internal/map-pool.ts +0 -39
- package/src/internal/mcp-endpoint.ts +0 -747
- package/src/internal/mcp-host.ts +0 -509
- package/src/internal/mcp-oauth-on-demand.ts +0 -337
- package/src/internal/mcp-oauth-persist.ts +0 -118
- package/src/internal/mcp-oauth.ts +0 -549
- package/src/internal/net.ts +0 -29
- package/src/internal/open-browser.ts +0 -41
- package/src/internal/otel/attrs.ts +0 -16
- package/src/internal/otel/collector.ts +0 -937
- package/src/internal/otel/config.ts +0 -287
- package/src/internal/otel/http.ts +0 -122
- package/src/internal/otel/mcp.ts +0 -56
- package/src/internal/otel/propagation.ts +0 -17
- package/src/internal/otel/runtime.ts +0 -441
- package/src/internal/package-inline-stdio.ts +0 -114
- package/src/internal/peer-connections.ts +0 -96
- package/src/internal/platform-schedule-sync.ts +0 -75
- package/src/internal/platform-timers.ts +0 -365
- package/src/internal/playground/static.ts +0 -278
- package/src/internal/playground/toolchain.ts +0 -270
- package/src/internal/playground-proxy.ts +0 -564
- package/src/internal/process-memory-telemetry.ts +0 -334
- package/src/internal/project-layout.ts +0 -31
- package/src/internal/prompt-context.ts +0 -116
- package/src/internal/reminder-control-plane-protocol.ts +0 -482
- package/src/internal/reminder-runner.ts +0 -1559
- package/src/internal/reminder-schedule.ts +0 -104
- package/src/internal/reminder-store.ts +0 -176
- package/src/internal/request-error-status.ts +0 -95
- package/src/internal/request-headers.ts +0 -21
- package/src/internal/resolve-prod-target.ts +0 -334
- package/src/internal/resolved-connections.ts +0 -190
- package/src/internal/router.ts +0 -143
- package/src/internal/run-client.ts +0 -354
- package/src/internal/runtime-dispatch-runner.ts +0 -50
- package/src/internal/sanitize-mcp-tool-name.ts +0 -31
- package/src/internal/schedule-runner.ts +0 -154
- package/src/internal/scm/pr-url.ts +0 -245
- package/src/internal/sdk-runner.ts +0 -959
- package/src/internal/serve-restart.ts +0 -113
- package/src/internal/server.ts +0 -3147
- package/src/internal/session-cost.ts +0 -208
- package/src/internal/session-engine.ts +0 -5622
- package/src/internal/session-links.ts +0 -84
- package/src/internal/session-run-log.ts +0 -535
- package/src/internal/session-store.ts +0 -307
- package/src/internal/session-urls.ts +0 -32
- package/src/internal/sessions-client.ts +0 -239
- package/src/internal/skill-catalog.ts +0 -66
- package/src/internal/skills-sync.ts +0 -55
- package/src/internal/slack-provision-client.ts +0 -544
- package/src/internal/slack-thread-key.ts +0 -11
- package/src/internal/sleep.ts +0 -3
- package/src/internal/start-log-store.ts +0 -164
- package/src/internal/steering.ts +0 -17
- package/src/internal/storage-coordinator.ts +0 -800
- package/src/internal/storage-roles.ts +0 -86
- package/src/internal/storage.ts +0 -1
- package/src/internal/store-api-protocol.ts +0 -205
- package/src/internal/store-mirror.ts +0 -73
- package/src/internal/stream-progress.ts +0 -294
- package/src/internal/terminal-style.ts +0 -133
- package/src/internal/testing/factory-resource-fixtures.ts +0 -84
- package/src/internal/testing/scm-continuation-fixtures.ts +0 -285
- package/src/internal/tool-catalog.ts +0 -104
- package/src/internal/tool-policy.ts +0 -222
- package/src/internal/tool-result.ts +0 -50
- package/src/internal/trajectory.ts +0 -418
- package/src/internal/turn-cost.ts +0 -136
- package/src/internal/turn-governor.ts +0 -145
- package/src/internal/turn-lease-store.ts +0 -144
- package/src/internal/turn-outbox.ts +0 -77
- package/src/internal/update-check.ts +0 -517
- package/src/internal/v2-hosting.ts +0 -52
- package/src/internal/workspace-sync.ts +0 -114
- package/src/internal/workspace.ts +0 -505
- package/src/kv/memory-kv.ts +0 -94
- package/src/kv.ts +0 -18
- package/src/memory.ts +0 -487
- package/src/otel-public.ts +0 -24
- package/src/otel.ts +0 -320
- package/src/prompt.ts +0 -80
- package/src/reminders.ts +0 -65
- package/src/schedules.ts +0 -31
- package/src/skills.ts +0 -27
- package/src/storage-backends/cursor-hosted-v2.ts +0 -204
- package/src/storage-backends/cursor-hosted.ts +0 -388
- package/src/storage-backends/file-kv.ts +0 -276
- package/src/storage-protocol.ts +0 -261
- package/src/storage.ts +0 -408
- package/src/tools.ts +0 -166
- package/src/types.ts +0 -3776
- /package/dist/docs/assets/{reference_agent-config.md.DzGI777n.lean.js → reference_agent-config.md.Cj5uBKp4.lean.js} +0 -0
|
@@ -1,959 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Executes turns on the Cursor harness through `@cursor/sdk`.
|
|
3
|
-
* Each framework session maps 1:1 to an SDK agent. Local agents use the
|
|
4
|
-
* session id as the SDK agent id and materialize a workspace for project
|
|
5
|
-
* settings; cloud agents use Cursor cloud (`bc-…` ids) with optional
|
|
6
|
-
* `cloud` options from `defineAgent`.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { mkdir } from "node:fs/promises";
|
|
10
|
-
import {
|
|
11
|
-
Agent,
|
|
12
|
-
type AgentDefinition,
|
|
13
|
-
type AgentOptions,
|
|
14
|
-
type CloudAgentOptions,
|
|
15
|
-
Cursor,
|
|
16
|
-
createAgentPlatform,
|
|
17
|
-
type LocalAgentStore,
|
|
18
|
-
type ModelSelection,
|
|
19
|
-
type Run,
|
|
20
|
-
type RunResult,
|
|
21
|
-
type SDKAgent,
|
|
22
|
-
} from "@cursor/sdk";
|
|
23
|
-
import { SqliteLocalAgentStore } from "@cursor/sdk/sqlite";
|
|
24
|
-
import {
|
|
25
|
-
DEFAULT_MODEL,
|
|
26
|
-
type ModelSetting,
|
|
27
|
-
type RunnerSubagent,
|
|
28
|
-
type RunnerTurnRequest,
|
|
29
|
-
type TurnOutcome,
|
|
30
|
-
type TurnUsage,
|
|
31
|
-
} from "../types.js";
|
|
32
|
-
import { mapSdkTokenUsage, usageTokenSum } from "./cloud-turn-cost.js";
|
|
33
|
-
import type { ConversationMirror } from "./conversation-mirror.js";
|
|
34
|
-
import { resolveApiKeySync } from "./cursor/credentials.js";
|
|
35
|
-
import { describeError } from "./describe-error.js";
|
|
36
|
-
import { CLI_COMMAND_NAME as CLI } from "./distribution.js";
|
|
37
|
-
import { sleep } from "./sleep.js";
|
|
38
|
-
|
|
39
|
-
/** Mirrors @cursor/sdk's SteerAckOutcome; the published dist may predate it. */
|
|
40
|
-
export type SteerAckOutcome = "complete_delivered" | "revert_to_followup";
|
|
41
|
-
|
|
42
|
-
/** Internal seam between the session engine and the Cursor SDK harness. */
|
|
43
|
-
export interface AgentRunner {
|
|
44
|
-
runTurn(request: RunnerTurnRequest): Promise<TurnOutcome>;
|
|
45
|
-
steer?(request: { sessionId: string; text: string }): Promise<SteerAckOutcome>;
|
|
46
|
-
/**
|
|
47
|
-
* Resolve a local workspace before any session needs it, so the first turn
|
|
48
|
-
* is not the one that pays for it. Best effort, hence the reported outcome:
|
|
49
|
-
* a runner that cannot warm must say so rather than let a caller log
|
|
50
|
-
* success over a workspace that was never touched.
|
|
51
|
-
*/
|
|
52
|
-
prewarm?(request: RunnerPrewarmRequest): Promise<PrewarmOutcome>;
|
|
53
|
-
dispose?(): Promise<void>;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* The parts of a turn that decide which local executor it runs on. Must stay
|
|
58
|
-
* a subset of {@link RunnerTurnRequest} — anything that disagrees warms an
|
|
59
|
-
* executor no turn will ask for.
|
|
60
|
-
*/
|
|
61
|
-
export type RunnerPrewarmRequest = Pick<
|
|
62
|
-
RunnerTurnRequest,
|
|
63
|
-
| "workspaceDir"
|
|
64
|
-
| "runnerStateDir"
|
|
65
|
-
| "sandbox"
|
|
66
|
-
| "tools"
|
|
67
|
-
| "disallowedTools"
|
|
68
|
-
| "mcpServers"
|
|
69
|
-
| "perSendMcpServers"
|
|
70
|
-
| "subagents"
|
|
71
|
-
| "model"
|
|
72
|
-
>;
|
|
73
|
-
|
|
74
|
-
/** Whether a workspace was actually resolved, and why not when it wasn't. */
|
|
75
|
-
export type PrewarmOutcome =
|
|
76
|
-
| { readonly warmed: true }
|
|
77
|
-
| { readonly warmed: false; readonly reason: string };
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* How long a non-`--dev` serve holds workspace scans (rules, skills,
|
|
81
|
-
* `AGENTS.md`, ignore files). The SDK default is 20s for an editor whose
|
|
82
|
-
* files move under it; agent-serve checkouts only change on deploy, so a
|
|
83
|
-
* missed mid-process edit is the right trade. `CURSOR_RIPWALK_CACHE_TTL_MS`
|
|
84
|
-
* still wins when set. `--dev` leaves the 20s default so skill edits show up.
|
|
85
|
-
*/
|
|
86
|
-
export const SERVE_WORKSPACE_SCAN_CACHE_TTL_MS: number = 24 * 60 * 60 * 1000;
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Resolve the SDK workspace-scan TTL for this serve. `undefined` means "do
|
|
90
|
-
* not call `Cursor.configure`" and leave the SDK at its 20s editor default.
|
|
91
|
-
*/
|
|
92
|
-
export function resolveServeWorkspaceScanCacheTtlMs(args: {
|
|
93
|
-
dev: boolean;
|
|
94
|
-
env?: NodeJS.ProcessEnv;
|
|
95
|
-
}): number | undefined {
|
|
96
|
-
const raw = (args.env ?? process.env).CURSOR_RIPWALK_CACHE_TTL_MS?.trim();
|
|
97
|
-
if (raw !== undefined && raw !== "") {
|
|
98
|
-
const parsed = Number(raw);
|
|
99
|
-
if (Number.isFinite(parsed) && parsed > 0) {
|
|
100
|
-
return parsed;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
if (args.dev) {
|
|
104
|
-
return undefined;
|
|
105
|
-
}
|
|
106
|
-
return SERVE_WORKSPACE_SCAN_CACHE_TTL_MS;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export interface CursorSdkRunnerOptions {
|
|
110
|
-
/** Cursor API key. Defaults to the `CURSOR_API_KEY` environment variable. */
|
|
111
|
-
apiKey?: string;
|
|
112
|
-
/**
|
|
113
|
-
* Conversation store override. Defaults to a JSONL store under the
|
|
114
|
-
* engine's state root; install `sqlite3` and pass an SQLite-backed
|
|
115
|
-
* `LocalAgentStore` for heavy multi-session concurrency.
|
|
116
|
-
*/
|
|
117
|
-
store?: LocalAgentStore;
|
|
118
|
-
/**
|
|
119
|
-
* Durable mirror for local conversations (v2 hosted engines). Hydrated
|
|
120
|
-
* before `Agent.resume` so a follow-up landing on a fresh pod finds the
|
|
121
|
-
* conversation, and persisted — awaited — after each local turn settles,
|
|
122
|
-
* because a hosted pod can be parked right after the execution reply.
|
|
123
|
-
*/
|
|
124
|
-
conversationMirror?: ConversationMirror;
|
|
125
|
-
/** Diagnostics for degraded paths (resume-miss fallback). */
|
|
126
|
-
logger?: (line: string) => void;
|
|
127
|
-
/**
|
|
128
|
-
* Hold workspace scans this long (ms). Applied via `Cursor.configure` so
|
|
129
|
-
* each new local executor reuses the walk. Omit to keep the SDK 20s default.
|
|
130
|
-
*/
|
|
131
|
-
workspaceScanCacheTtlMs?: number;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* How long one SDK agent handle (and the Connect transport inside it) may be
|
|
136
|
-
* reused before the runner retires it.
|
|
137
|
-
*
|
|
138
|
-
* The transport exchanges the account API key for a short-lived access token
|
|
139
|
-
* (`SessionType.API_KEY_TOKEN`, 60 minutes) once per handle, and has no
|
|
140
|
-
* reliable refresh: an Unauthenticated rejection on the agent's streaming RPC
|
|
141
|
-
* surfaces while the stream is being read — outside the transport's
|
|
142
|
-
* request-time 401 retry — so an expired token gets replayed on every
|
|
143
|
-
* subsequent turn until the handle is rebuilt. Long-lived sessions (watch
|
|
144
|
-
* wakes, crons) hit this at the ~60 minute mark and then fail forever.
|
|
145
|
-
* Retiring the handle comfortably before the token can expire keeps them
|
|
146
|
-
* healthy: `Agent.resume` rehydrates the same conversation from the runner
|
|
147
|
-
* store on a fresh transport, so recycling costs only transport warmth.
|
|
148
|
-
*/
|
|
149
|
-
const MAX_AGENT_HANDLE_AGE_MS = 45 * 60 * 1000;
|
|
150
|
-
|
|
151
|
-
interface CachedAgentHandle {
|
|
152
|
-
agent: Promise<SDKAgent>;
|
|
153
|
-
openedAtMs: number;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* The backend's `NotLoggedIn` copy ("Authentication error" title, "try
|
|
158
|
-
* logging out and back in." detail) as it surfaces through SDK RunResults.
|
|
159
|
-
* Deliberately narrow: this gates a one-shot in-place retry, and matching
|
|
160
|
-
* broader error text would retry turns that a fresh transport cannot fix.
|
|
161
|
-
*/
|
|
162
|
-
export function isAuthErrorMessage(message: string | undefined): boolean {
|
|
163
|
-
if (message === undefined) {
|
|
164
|
-
return false;
|
|
165
|
-
}
|
|
166
|
-
return /authentication error|try logging out and back in/i.test(message);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/** Cloud `wait()` copy for `stream_expired` / a missing start-state blob. */
|
|
170
|
-
function isStreamExpiredErrorMessage(message: string | undefined): boolean {
|
|
171
|
-
if (message === undefined) {
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
return /run stream is no longer available|\[stream_expired\]/i.test(message);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function retryReason(message: string | undefined, isFirstTurn: boolean): string | undefined {
|
|
178
|
-
if (isStreamExpiredErrorMessage(message)) {
|
|
179
|
-
return "cloud run stream expired";
|
|
180
|
-
}
|
|
181
|
-
// First-turn auth is the credential; a fresh handle cannot fix it.
|
|
182
|
-
if (!isFirstTurn && isAuthErrorMessage(message)) {
|
|
183
|
-
return "authentication failure";
|
|
184
|
-
}
|
|
185
|
-
return undefined;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* The SDK rejects a selection the credential's catalog does not list with
|
|
190
|
-
* this copy, thrown from `Agent.create` / `Agent.resume` before the turn
|
|
191
|
-
* streams anything. Matched on the message because the SDK uses its generic
|
|
192
|
-
* configuration error here.
|
|
193
|
-
*/
|
|
194
|
-
export function isUnavailableModelSelectionMessage(message: string | undefined): boolean {
|
|
195
|
-
return message !== undefined && /cannot use this model/i.test(message);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export function isUnavailableModelSelectionError(error: unknown): boolean {
|
|
199
|
-
const message = error instanceof Error ? error.message : undefined;
|
|
200
|
-
return isUnavailableModelSelectionMessage(message);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Inference / provider capacity on the selected model. `wait()` stores the
|
|
205
|
-
* connect status on `error.code` and strips `[code]` from the message, so
|
|
206
|
-
* both must be checked. `[unavailable]` in text is the connect status, not
|
|
207
|
-
* a loose "temporarily unavailable" substring.
|
|
208
|
-
*/
|
|
209
|
-
export function isModelCapacityError(
|
|
210
|
-
message: string | undefined,
|
|
211
|
-
code?: string | undefined,
|
|
212
|
-
): boolean {
|
|
213
|
-
if (isGithubApiRateLimitMessage(message)) {
|
|
214
|
-
return false;
|
|
215
|
-
}
|
|
216
|
-
if (code !== undefined && /^(resource_exhausted|unavailable)$/i.test(code)) {
|
|
217
|
-
return true;
|
|
218
|
-
}
|
|
219
|
-
return message !== undefined && /resource_exhausted|\[unavailable\]/i.test(message);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/** GitHub token 429s share `resource_exhausted` with model capacity. */
|
|
223
|
-
export function isGithubApiRateLimitMessage(message: string | undefined): boolean {
|
|
224
|
-
if (message === undefined) {
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
return /github/i.test(message) && /(rate limit|\b429\b)/i.test(message);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
export function isModelCapacityErrorMessage(message: string | undefined): boolean {
|
|
231
|
-
return isModelCapacityError(message);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/** Catalog refusal or capacity: the authored fallback list can still save the turn. */
|
|
235
|
-
export function shouldFallbackToNextModel(
|
|
236
|
-
message: string | undefined,
|
|
237
|
-
code?: string | undefined,
|
|
238
|
-
): boolean {
|
|
239
|
-
return isUnavailableModelSelectionMessage(message) || isModelCapacityError(message, code);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
export function shouldFallbackToNextModelOnError(error: unknown): boolean {
|
|
243
|
-
const message = error instanceof Error ? error.message : undefined;
|
|
244
|
-
return shouldFallbackToNextModel(message, errorCodeOf(error));
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
function errorCodeOf(error: unknown): string | undefined {
|
|
248
|
-
if (typeof error !== "object" || error === null || !("code" in error)) {
|
|
249
|
-
return undefined;
|
|
250
|
-
}
|
|
251
|
-
const code = (error as { code?: unknown }).code;
|
|
252
|
-
return typeof code === "string" ? code : undefined;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
function modelSettingLabel(model: ModelSetting | undefined): string {
|
|
256
|
-
if (model === undefined) {
|
|
257
|
-
return "default";
|
|
258
|
-
}
|
|
259
|
-
return typeof model === "string" ? model : model.id;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/** Primary model, then authored fallbacks. No fallbacks keeps today's single attempt. */
|
|
263
|
-
function modelAttemptChain(request: RunnerTurnRequest): Array<ModelSetting | undefined> {
|
|
264
|
-
const fallbacks = request.modelFallbacks ?? [];
|
|
265
|
-
if (fallbacks.length === 0) {
|
|
266
|
-
return [request.model];
|
|
267
|
-
}
|
|
268
|
-
return [request.model ?? DEFAULT_MODEL, ...fallbacks];
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* A rejected create may already have stored the agent id. Later attempts
|
|
273
|
-
* resume that id so the next model does not die on "already exists". A
|
|
274
|
-
* create that threw before persisting falls through the runner's not-found
|
|
275
|
-
* path and creates again. Cloud turns that never received a server id stay
|
|
276
|
-
* on create: resuming the framework session id is not a cloud agent.
|
|
277
|
-
*/
|
|
278
|
-
function modelAttemptRequest(
|
|
279
|
-
request: RunnerTurnRequest,
|
|
280
|
-
model: ModelSetting | undefined,
|
|
281
|
-
attempt: number,
|
|
282
|
-
): RunnerTurnRequest {
|
|
283
|
-
if (attempt === 0) {
|
|
284
|
-
return model === request.model ? request : { ...request, model };
|
|
285
|
-
}
|
|
286
|
-
const persistedId = request.sdkAgentId ?? request.sessionId;
|
|
287
|
-
if (
|
|
288
|
-
request.runtime === "cloud" &&
|
|
289
|
-
request.isFirstTurn &&
|
|
290
|
-
!isServerMintedCloudAgentId(persistedId)
|
|
291
|
-
) {
|
|
292
|
-
return { ...request, model };
|
|
293
|
-
}
|
|
294
|
-
return {
|
|
295
|
-
...request,
|
|
296
|
-
model,
|
|
297
|
-
isFirstTurn: false,
|
|
298
|
-
sdkAgentId: persistedId,
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
export class CursorSdkRunner implements AgentRunner {
|
|
303
|
-
private readonly agents = new Map<string, CachedAgentHandle>();
|
|
304
|
-
private readonly activeRuns = new Map<string, Run>();
|
|
305
|
-
private readonly stores = new Map<string, Promise<LocalAgentStore>>();
|
|
306
|
-
private readonly prewarmReleases: Array<() => Promise<void>> = [];
|
|
307
|
-
|
|
308
|
-
constructor(private readonly options: CursorSdkRunnerOptions = {}) {
|
|
309
|
-
if (options.workspaceScanCacheTtlMs !== undefined) {
|
|
310
|
-
Cursor.configure({
|
|
311
|
-
local: { workspaceScanCacheTtlMs: options.workspaceScanCacheTtlMs },
|
|
312
|
-
});
|
|
313
|
-
this.log(`[agent-sdk] workspace scan cache ttl=${options.workspaceScanCacheTtlMs}ms`);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
async runTurn(request: RunnerTurnRequest): Promise<TurnOutcome> {
|
|
318
|
-
// Fail closed: this runner only knows the Cursor SDK's local and cloud
|
|
319
|
-
// harnesses. A grokbot turn reaching it means the serve wiring skipped
|
|
320
|
-
// the Grok Bot runner — running it on the local harness would silently
|
|
321
|
-
// swap the box (and the SendToUser contract) out from under the agent.
|
|
322
|
-
if (request.runtime === "grokbot") {
|
|
323
|
-
throw new Error(
|
|
324
|
-
`Session ${request.sessionId} is a grokbot turn, which the Cursor SDK runner cannot execute. Serve must route grokbot turns to the Grok Bot runner.`,
|
|
325
|
-
);
|
|
326
|
-
}
|
|
327
|
-
const models = modelAttemptChain(request);
|
|
328
|
-
let lastError: unknown;
|
|
329
|
-
for (let attempt = 0; attempt < models.length; attempt++) {
|
|
330
|
-
const model = models[attempt];
|
|
331
|
-
let streamed = false;
|
|
332
|
-
const attemptRequest = modelAttemptRequest(request, model, attempt);
|
|
333
|
-
try {
|
|
334
|
-
const outcome = await this.runTurnWithTransportRetry(attemptRequest, () => {
|
|
335
|
-
streamed = true;
|
|
336
|
-
});
|
|
337
|
-
if (
|
|
338
|
-
outcome.status !== "error" ||
|
|
339
|
-
streamed ||
|
|
340
|
-
request.signal?.aborted === true ||
|
|
341
|
-
!shouldFallbackToNextModel(outcome.errorMessage, outcome.errorCode) ||
|
|
342
|
-
attempt === models.length - 1
|
|
343
|
-
) {
|
|
344
|
-
return outcome;
|
|
345
|
-
}
|
|
346
|
-
this.logModelFallback(request.sessionId, model, models[attempt + 1], outcome.errorMessage);
|
|
347
|
-
} catch (error) {
|
|
348
|
-
lastError = error;
|
|
349
|
-
if (
|
|
350
|
-
streamed ||
|
|
351
|
-
request.signal?.aborted === true ||
|
|
352
|
-
!shouldFallbackToNextModelOnError(error) ||
|
|
353
|
-
attempt === models.length - 1
|
|
354
|
-
) {
|
|
355
|
-
throw error;
|
|
356
|
-
}
|
|
357
|
-
const message = error instanceof Error ? error.message : undefined;
|
|
358
|
-
this.logModelFallback(request.sessionId, model, models[attempt + 1], message);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
throw lastError;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* One model attempt, plus the existing in-place transport retry (expired
|
|
366
|
-
* cloud stream, or a follow-up auth failure) on that same model. Model
|
|
367
|
-
* fallback is the caller's job: this returns the error outcome when a
|
|
368
|
-
* fresh handle cannot fix it.
|
|
369
|
-
*/
|
|
370
|
-
private async runTurnWithTransportRetry(
|
|
371
|
-
request: RunnerTurnRequest,
|
|
372
|
-
onStreamed: () => void,
|
|
373
|
-
): Promise<TurnOutcome> {
|
|
374
|
-
let sawUpdate = false;
|
|
375
|
-
const tracked: RunnerTurnRequest = {
|
|
376
|
-
...request,
|
|
377
|
-
onUpdate: update => {
|
|
378
|
-
sawUpdate = true;
|
|
379
|
-
onStreamed();
|
|
380
|
-
return request.onUpdate(update);
|
|
381
|
-
},
|
|
382
|
-
};
|
|
383
|
-
const outcome = await this.runTurnAttempt(tracked);
|
|
384
|
-
if (outcome.status !== "error" || sawUpdate || request.signal?.aborted === true) {
|
|
385
|
-
return outcome;
|
|
386
|
-
}
|
|
387
|
-
const reason = retryReason(outcome.errorMessage, request.isFirstTurn);
|
|
388
|
-
if (reason === undefined) {
|
|
389
|
-
return outcome;
|
|
390
|
-
}
|
|
391
|
-
// Log the original error even when the retry succeeds so the expiry
|
|
392
|
-
// still shows up in Datadog.
|
|
393
|
-
this.log(
|
|
394
|
-
`[agent-sdk] session ${request.sessionId}: ${reason}: ${outcome.errorMessage}; retrying the turn`,
|
|
395
|
-
);
|
|
396
|
-
try {
|
|
397
|
-
return await this.runTurnAttempt(tracked);
|
|
398
|
-
} catch {
|
|
399
|
-
return outcome;
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
private logModelFallback(
|
|
404
|
-
sessionId: string,
|
|
405
|
-
from: ModelSetting | undefined,
|
|
406
|
-
to: ModelSetting | undefined,
|
|
407
|
-
message: string | undefined,
|
|
408
|
-
): void {
|
|
409
|
-
this.log(
|
|
410
|
-
`[agent-sdk] session ${sessionId}: cannot use model ${modelSettingLabel(from)}; retrying on ${modelSettingLabel(to)}: ${message ?? "model unavailable"}`,
|
|
411
|
-
);
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
private async runTurnAttempt(request: RunnerTurnRequest): Promise<TurnOutcome> {
|
|
415
|
-
const agentPromise = this.getAgent(request);
|
|
416
|
-
try {
|
|
417
|
-
const agent = await agentPromise;
|
|
418
|
-
const sendMessage =
|
|
419
|
-
request.images !== undefined && request.images.length > 0
|
|
420
|
-
? {
|
|
421
|
-
text: request.prompt,
|
|
422
|
-
images: request.images.map(image => ({
|
|
423
|
-
data: image.data,
|
|
424
|
-
mimeType: image.mimeType,
|
|
425
|
-
})),
|
|
426
|
-
}
|
|
427
|
-
: request.prompt;
|
|
428
|
-
const run = await agent.send(sendMessage, {
|
|
429
|
-
onDelta: async ({ update }) => {
|
|
430
|
-
try {
|
|
431
|
-
await request.onUpdate(update);
|
|
432
|
-
} catch {
|
|
433
|
-
// Stream mapping must never reject into the SDK transport.
|
|
434
|
-
}
|
|
435
|
-
},
|
|
436
|
-
// The SDK builds this send's MCP session from exactly this set, so
|
|
437
|
-
// a turn always runs on the headers the engine evaluated for it —
|
|
438
|
-
// never on the ones a previous turn opened the cached handle with.
|
|
439
|
-
...(request.runtime === "local" && request.perSendMcpServers === true
|
|
440
|
-
? { mcpServers: request.mcpServers as AgentOptions["mcpServers"] }
|
|
441
|
-
: {}),
|
|
442
|
-
...(request.runtime === "local"
|
|
443
|
-
? {
|
|
444
|
-
local: {
|
|
445
|
-
customTools: request.customTools,
|
|
446
|
-
// Follow-up turns expire any run still marked active on the
|
|
447
|
-
// agent (a preempted or crash-wedged run) so this send is not
|
|
448
|
-
// rejected with "already has active run".
|
|
449
|
-
...(request.forceExpireActiveRun === true ? { force: true } : {}),
|
|
450
|
-
},
|
|
451
|
-
}
|
|
452
|
-
: {}),
|
|
453
|
-
});
|
|
454
|
-
// A follow-up can preempt this turn: cancelling tears down execution and
|
|
455
|
-
// marks the SDK run terminal so the next send is admitted cleanly. The
|
|
456
|
-
// signal may already be aborted if the preempt landed while send() was
|
|
457
|
-
// still creating the run.
|
|
458
|
-
const signal = request.signal;
|
|
459
|
-
const onAbort = (): void => {
|
|
460
|
-
void run.cancel().catch(() => {});
|
|
461
|
-
};
|
|
462
|
-
if (signal !== undefined) {
|
|
463
|
-
if (signal.aborted) {
|
|
464
|
-
onAbort();
|
|
465
|
-
} else {
|
|
466
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
// Cloud + envVars: server mints the real `bc-…` id during createAgent
|
|
470
|
-
// inside the first send. Bind only after that so we never persist/print
|
|
471
|
-
// the provisional client-seeded id.
|
|
472
|
-
if (request.onSdkAgentId !== undefined) {
|
|
473
|
-
await request.onSdkAgentId(agent.agentId);
|
|
474
|
-
}
|
|
475
|
-
// Readable on the handle as soon as send resolves, long before wait().
|
|
476
|
-
if (
|
|
477
|
-
request.onRequestId !== undefined &&
|
|
478
|
-
run.requestId !== undefined &&
|
|
479
|
-
run.requestId !== ""
|
|
480
|
-
) {
|
|
481
|
-
await request.onRequestId(run.requestId);
|
|
482
|
-
}
|
|
483
|
-
this.activeRuns.set(request.sessionId, run);
|
|
484
|
-
try {
|
|
485
|
-
const result = await run.wait();
|
|
486
|
-
let outcome = toTurnOutcome(result);
|
|
487
|
-
if (outcome.status === "error") {
|
|
488
|
-
// An error result usually means the handle's transport is poisoned
|
|
489
|
-
// — most often a cached access token that aged past its 60-minute
|
|
490
|
-
// lifetime and gets replayed on every request (stream failures
|
|
491
|
-
// bypass the transport's 401 retry). Retire the handle so the next
|
|
492
|
-
// attempt resumes the conversation from the store on a fresh
|
|
493
|
-
// transport instead of failing every turn until a restart.
|
|
494
|
-
this.evictAgent(request.sessionId, agentPromise);
|
|
495
|
-
} else if (
|
|
496
|
-
request.runtime === "cloud" &&
|
|
497
|
-
outcome.status === "finished" &&
|
|
498
|
-
usageTokenSum(outcome.usage) <= 0 &&
|
|
499
|
-
result.id !== ""
|
|
500
|
-
) {
|
|
501
|
-
// Cloud `wait()` drops usage after stream reconnect / getRun replay,
|
|
502
|
-
// or returns an all-zero stub. `getUsage` still has the run's tokens
|
|
503
|
-
// (eventually); without them traces never record an estimated cost.
|
|
504
|
-
outcome = await fillMissingCloudUsage(agent, result.id, outcome);
|
|
505
|
-
}
|
|
506
|
-
return outcome;
|
|
507
|
-
} finally {
|
|
508
|
-
if (this.activeRuns.get(request.sessionId) === run) {
|
|
509
|
-
this.activeRuns.delete(request.sessionId);
|
|
510
|
-
}
|
|
511
|
-
signal?.removeEventListener("abort", onAbort);
|
|
512
|
-
// Mirror the conversation before replying: on hosted v2 the pod can
|
|
513
|
-
// be parked as soon as the execution reply lands, so a
|
|
514
|
-
// fire-and-forget write would race VM teardown. In the `finally` so
|
|
515
|
-
// a `wait()` that THROWS (transport death mid-turn, an abort with
|
|
516
|
-
// no follow-up) still persists the checkpoints the turn already
|
|
517
|
-
// wrote — the store is local SQLite, safe to read on the throw
|
|
518
|
-
// path, and persistConversation swallows its own errors. Guarded
|
|
519
|
-
// here (not just inside the helper) so unmirrored turns keep their
|
|
520
|
-
// exact post-wait sequencing.
|
|
521
|
-
if (request.runtime === "local" && this.options.conversationMirror !== undefined) {
|
|
522
|
-
await this.persistConversation(request, agent.agentId);
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
} catch (error) {
|
|
526
|
-
// Drop the cached agent so a dead Connect/HTTP2 session cannot poison
|
|
527
|
-
// the next turn (terminal/shell overflow often kills the transport).
|
|
528
|
-
this.evictAgent(request.sessionId, agentPromise);
|
|
529
|
-
throw error;
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
async steer(request: { sessionId: string; text: string }): Promise<SteerAckOutcome> {
|
|
534
|
-
const run = this.activeRuns.get(request.sessionId) as
|
|
535
|
-
| (Run & {
|
|
536
|
-
steer?: (text: string) => Promise<SteerAckOutcome>;
|
|
537
|
-
})
|
|
538
|
-
| undefined;
|
|
539
|
-
if (run?.steer === undefined) {
|
|
540
|
-
return "revert_to_followup";
|
|
541
|
-
}
|
|
542
|
-
try {
|
|
543
|
-
return await run.steer(request.text);
|
|
544
|
-
} catch (error) {
|
|
545
|
-
this.log(`[agent-sdk] session ${request.sessionId}: steer failed: ${describeError(error)}`);
|
|
546
|
-
return "revert_to_followup";
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
/**
|
|
551
|
-
* Build the local executor for a workspace before any session asks for it.
|
|
552
|
-
* The warmed executor is reference counted, so the lease is held until
|
|
553
|
-
* {@link dispose}; dropping it early would tear the workspace back down.
|
|
554
|
-
*/
|
|
555
|
-
async prewarm(request: RunnerPrewarmRequest): Promise<PrewarmOutcome> {
|
|
556
|
-
const platform = await createAgentPlatform();
|
|
557
|
-
const release = await platform.prewarmLocalWorkspace(await this.buildLocalOptions(request));
|
|
558
|
-
this.prewarmReleases.push(release);
|
|
559
|
-
return { warmed: true };
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
/**
|
|
563
|
-
* Drop the cached SDK agent for this session, if one is open.
|
|
564
|
-
*
|
|
565
|
-
* Hosted v2 parks and hibernates this process as soon as the execution
|
|
566
|
-
* reply lands on non-interactive channels. A leftover handle still holds
|
|
567
|
-
* the pre-freeze Connect/HTTP2 session; the next wake then reuses it and
|
|
568
|
-
* `AgentService/Run` never starts. Call after `waitForCompletion` so the
|
|
569
|
-
* hibernate snapshot has an empty cache. Slack's interactive hot-window
|
|
570
|
-
* still reuses handles because that path does not go through hosted
|
|
571
|
-
* delivery.
|
|
572
|
-
*/
|
|
573
|
-
evictSession(sessionId: string): void {
|
|
574
|
-
const cached = this.agents.get(sessionId);
|
|
575
|
-
if (cached === undefined) {
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
|
-
this.evictAgent(sessionId, cached.agent);
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
async dispose(): Promise<void> {
|
|
582
|
-
const releases = this.prewarmReleases.splice(0);
|
|
583
|
-
await Promise.allSettled(releases.map(release => release()));
|
|
584
|
-
const agents = await Promise.allSettled([...this.agents.values()].map(handle => handle.agent));
|
|
585
|
-
this.agents.clear();
|
|
586
|
-
for (const settled of agents) {
|
|
587
|
-
if (settled.status === "fulfilled") {
|
|
588
|
-
settled.value.close();
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
private getAgent(request: RunnerTurnRequest): Promise<SDKAgent> {
|
|
594
|
-
const cached = this.agents.get(request.sessionId);
|
|
595
|
-
if (cached !== undefined) {
|
|
596
|
-
const ageMs = Date.now() - cached.openedAtMs;
|
|
597
|
-
if (ageMs < MAX_AGENT_HANDLE_AGE_MS) {
|
|
598
|
-
return cached.agent;
|
|
599
|
-
}
|
|
600
|
-
// Past this age the handle's exchanged access token could expire
|
|
601
|
-
// mid-turn. Retire it and reopen below on a fresh transport.
|
|
602
|
-
this.log(
|
|
603
|
-
`[agent-sdk] session ${request.sessionId}: recycling the SDK agent handle after ${Math.round(ageMs / 60_000)} min so the turn runs on a fresh access token`,
|
|
604
|
-
);
|
|
605
|
-
this.evictAgent(request.sessionId, cached.agent);
|
|
606
|
-
}
|
|
607
|
-
const agentPromise = this.openAgent(request).catch(error => {
|
|
608
|
-
// Nothing opened, so there is no handle to close — just free the slot.
|
|
609
|
-
this.agents.delete(request.sessionId);
|
|
610
|
-
throw error;
|
|
611
|
-
});
|
|
612
|
-
this.agents.set(request.sessionId, {
|
|
613
|
-
agent: agentPromise,
|
|
614
|
-
openedAtMs: Date.now(),
|
|
615
|
-
});
|
|
616
|
-
return agentPromise;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
/**
|
|
620
|
-
* Drop a cached handle and close it best-effort to release its transport
|
|
621
|
-
* and executor lease. Identity-checked so a turn that lost a race with a
|
|
622
|
-
* newer open cannot evict the replacement handle.
|
|
623
|
-
*/
|
|
624
|
-
private evictAgent(sessionId: string, agent: Promise<SDKAgent>): void {
|
|
625
|
-
const cached = this.agents.get(sessionId);
|
|
626
|
-
if (cached === undefined || cached.agent !== agent) {
|
|
627
|
-
return;
|
|
628
|
-
}
|
|
629
|
-
this.agents.delete(sessionId);
|
|
630
|
-
void cached.agent.then(sdkAgent => sdkAgent.close()).catch(() => {});
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
private log(line: string): void {
|
|
634
|
-
(this.options.logger ?? (() => {}))(line);
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
/**
|
|
638
|
-
* Re-resolve on every turn. Hosted freeze snapshots listen unsigned; the
|
|
639
|
-
* binder drops `CURSOR_API_KEY` / `CURSOR_API_KEY_FILE` at task time into
|
|
640
|
-
* the already-running process, which must not have closed over `undefined`.
|
|
641
|
-
*/
|
|
642
|
-
private requireApiKey(): string {
|
|
643
|
-
const resolved = resolveApiKeySync({ apiKey: this.options.apiKey });
|
|
644
|
-
if (resolved === undefined) {
|
|
645
|
-
throw new Error(
|
|
646
|
-
`The Cursor SDK runner requires a Cursor credential: run \`${CLI} login\`, set CURSOR_API_KEY, CURSOR_SERVICE_ACCOUNT_KEY, or CURSOR_API_KEY_FILE, or pass serve({ apiKey }).`,
|
|
647
|
-
);
|
|
648
|
-
}
|
|
649
|
-
return resolved.apiKey;
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
private buildSharedOptions(
|
|
653
|
-
request: RunnerPrewarmRequest,
|
|
654
|
-
): Pick<AgentOptions, "model" | "apiKey" | "mcpServers" | "agents"> {
|
|
655
|
-
const subagents = toAgentDefinitions(request.subagents);
|
|
656
|
-
return {
|
|
657
|
-
model: toModelSelection(request.model ?? DEFAULT_MODEL),
|
|
658
|
-
apiKey: this.requireApiKey(),
|
|
659
|
-
// Per-send servers ride each agent.send instead (fresh per-session
|
|
660
|
-
// auth headers every turn). Keeping them out of the create/resume
|
|
661
|
-
// options also keeps the local executor cache key — which hashes
|
|
662
|
-
// these options — stable while credentials rotate.
|
|
663
|
-
...(Object.keys(request.mcpServers).length > 0 && request.perSendMcpServers !== true
|
|
664
|
-
? { mcpServers: request.mcpServers as AgentOptions["mcpServers"] }
|
|
665
|
-
: {}),
|
|
666
|
-
...(subagents === undefined ? {} : { agents: subagents }),
|
|
667
|
-
};
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
/**
|
|
671
|
-
* The options that decide which local executor a turn runs on. Prewarming
|
|
672
|
-
* goes through here too, so a warmed workspace is the one turns land on.
|
|
673
|
-
*/
|
|
674
|
-
private async buildLocalOptions(
|
|
675
|
-
request: RunnerPrewarmRequest & Pick<RunnerTurnRequest, "instructions">,
|
|
676
|
-
): Promise<AgentOptions> {
|
|
677
|
-
// Not resolveStore: an injected store is used synchronously (no
|
|
678
|
-
// microtask, no thenable assimilation), exactly as before the mirror
|
|
679
|
-
// existed.
|
|
680
|
-
const store = this.options.store ?? (await this.getStore(request.runnerStateDir));
|
|
681
|
-
return {
|
|
682
|
-
...this.buildSharedOptions(request),
|
|
683
|
-
// The built-in tool allowlist rides AgentOptions, not `local`, and is
|
|
684
|
-
// deliberately absent from openCloudAgent's options: the SDK rejects
|
|
685
|
-
// tool restrictions on cloud agents. Passed on create *and* resume
|
|
686
|
-
// (both flow through here) — the SDK does not persist it across runs.
|
|
687
|
-
...(request.tools === undefined ? {} : { tools: request.tools }),
|
|
688
|
-
...(request.disallowedTools === undefined
|
|
689
|
-
? {}
|
|
690
|
-
: { disallowedTools: request.disallowedTools }),
|
|
691
|
-
// Same shape: local-only (the SDK rejects it with `cloud`), not
|
|
692
|
-
// persisted, so it rides every create/resume. Replaces Cursor's
|
|
693
|
-
// built-in system prompt with the agent's composed instructions.
|
|
694
|
-
// Prewarm requests carry none, and the SDK's workspace cache key
|
|
695
|
-
// ignores it, so a warmed executor is still the one turns land on.
|
|
696
|
-
systemPrompt: request.instructions,
|
|
697
|
-
local: {
|
|
698
|
-
cwd: request.workspaceDir,
|
|
699
|
-
settingSources: ["project"],
|
|
700
|
-
store,
|
|
701
|
-
...(request.sandbox === true ? { sandboxOptions: { enabled: true } } : {}),
|
|
702
|
-
},
|
|
703
|
-
};
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
private async openAgent(request: RunnerTurnRequest): Promise<SDKAgent> {
|
|
707
|
-
if (request.runtime === "cloud") {
|
|
708
|
-
return this.openCloudAgent(request, this.buildSharedOptions(request));
|
|
709
|
-
}
|
|
710
|
-
return this.openLocalAgent(request);
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
private async openLocalAgent(request: RunnerTurnRequest): Promise<SDKAgent> {
|
|
714
|
-
const options = await this.buildLocalOptions(request);
|
|
715
|
-
|
|
716
|
-
if (request.isFirstTurn || request.sdkAgentId === undefined) {
|
|
717
|
-
return Agent.create({
|
|
718
|
-
...options,
|
|
719
|
-
agentId: request.sdkAgentId ?? request.sessionId,
|
|
720
|
-
});
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
const agentId = request.sdkAgentId ?? request.sessionId;
|
|
724
|
-
const mirror = this.options.conversationMirror;
|
|
725
|
-
if (mirror !== undefined) {
|
|
726
|
-
// Host replacement: restore the conversation from the durable mirror
|
|
727
|
-
// before resuming, so the thread continues instead of starting fresh.
|
|
728
|
-
// A sink failure propagates and fails the turn (retryable) — reading
|
|
729
|
-
// an outage as "nothing mirrored" would silently fork the thread.
|
|
730
|
-
const store = await this.resolveStore(request);
|
|
731
|
-
await mirror.hydrate(store, agentId);
|
|
732
|
-
}
|
|
733
|
-
try {
|
|
734
|
-
return await Agent.resume(agentId, options);
|
|
735
|
-
} catch (error) {
|
|
736
|
-
if (!isLocalAgentNotFoundError(error, agentId)) {
|
|
737
|
-
throw error;
|
|
738
|
-
}
|
|
739
|
-
// Host replacement: the session record survived in durable storage,
|
|
740
|
-
// but the conversation store died with the old pod. A fresh
|
|
741
|
-
// conversation under the same id beats failing this thread's turns
|
|
742
|
-
// forever ("Agent … not found" on every follow-up). The channel's
|
|
743
|
-
// warm-turn prompt context re-hydrates the thread history.
|
|
744
|
-
this.log(
|
|
745
|
-
`[agent-sdk] no stored conversation for ${agentId} on this host; starting a fresh one`,
|
|
746
|
-
);
|
|
747
|
-
return Agent.create({ ...options, agentId });
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
private async openCloudAgent(
|
|
752
|
-
request: RunnerTurnRequest,
|
|
753
|
-
shared: Pick<AgentOptions, "model" | "apiKey" | "mcpServers" | "agents">,
|
|
754
|
-
): Promise<SDKAgent> {
|
|
755
|
-
const cloud = toCloudAgentOptions(request.cloud, request.agentServeAgent);
|
|
756
|
-
const hasEnvVars = cloud.envVars !== undefined && Object.keys(cloud.envVars).length > 0;
|
|
757
|
-
const options: AgentOptions = {
|
|
758
|
-
...shared,
|
|
759
|
-
cloud,
|
|
760
|
-
};
|
|
761
|
-
|
|
762
|
-
const sdkAgentId = request.sdkAgentId?.trim();
|
|
763
|
-
if (sdkAgentId !== undefined && sdkAgentId !== "") {
|
|
764
|
-
// A server-minted `bc-…` id always resumes — including on the first
|
|
765
|
-
// framework turn of a session seeded via SendMessageOptions.sdkAgentId
|
|
766
|
-
// (PR→bcId affinity across session-store resets). Any persisted id
|
|
767
|
-
// resumes on later turns.
|
|
768
|
-
if (isServerMintedCloudAgentId(sdkAgentId) || !request.isFirstTurn) {
|
|
769
|
-
return Agent.resume(sdkAgentId, options);
|
|
770
|
-
}
|
|
771
|
-
if (!hasEnvVars) {
|
|
772
|
-
// Client-seeded (non bc-…) id on a brand new session: forward it to
|
|
773
|
-
// create so the server adopts it. With envVars the server must mint
|
|
774
|
-
// the id, so the seed cannot be honored and create() runs below.
|
|
775
|
-
return Agent.create({ ...options, agentId: sdkAgentId });
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
if (request.isFirstTurn) {
|
|
780
|
-
return Agent.create(options);
|
|
781
|
-
}
|
|
782
|
-
// A cloud session past its first turn should carry the bound agent id
|
|
783
|
-
// (the engine persists it via onSdkAgentId as soon as create() reports
|
|
784
|
-
// one). Reaching here means the binding turn failed before the server
|
|
785
|
-
// ever minted an agent — e.g. create() rejected its PR attach — so the
|
|
786
|
-
// session would otherwise fail every future turn. Mirror the local
|
|
787
|
-
// host-replacement path above: a fresh conversation beats failing this
|
|
788
|
-
// thread forever, and the new id binds to the session for later resumes.
|
|
789
|
-
this.log(
|
|
790
|
-
`[agent-sdk] cloud session ${request.sessionId} has no bound cloud agent; creating a fresh one`,
|
|
791
|
-
);
|
|
792
|
-
return Agent.create(options);
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
private resolveStore(
|
|
796
|
-
request: Pick<RunnerPrewarmRequest, "runnerStateDir">,
|
|
797
|
-
): Promise<LocalAgentStore> {
|
|
798
|
-
return this.options.store !== undefined
|
|
799
|
-
? Promise.resolve(this.options.store)
|
|
800
|
-
: this.getStore(request.runnerStateDir);
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
/**
|
|
804
|
-
* Mirror the settled turn's conversation. Persist failures are logged and
|
|
805
|
-
* dropped — a durable-mirror outage must not fail a turn that already ran.
|
|
806
|
-
*/
|
|
807
|
-
private async persistConversation(request: RunnerTurnRequest, sdkAgentId: string): Promise<void> {
|
|
808
|
-
const mirror = this.options.conversationMirror;
|
|
809
|
-
if (mirror === undefined) {
|
|
810
|
-
return;
|
|
811
|
-
}
|
|
812
|
-
try {
|
|
813
|
-
const store = await this.resolveStore(request);
|
|
814
|
-
await mirror.persist(store, sdkAgentId);
|
|
815
|
-
} catch (error) {
|
|
816
|
-
this.log(
|
|
817
|
-
`[agent-sdk] conversation mirror: persist for ${sdkAgentId} failed: ${
|
|
818
|
-
error instanceof Error ? error.message : String(error)
|
|
819
|
-
}`,
|
|
820
|
-
);
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
private getStore(stateDir: string): Promise<LocalAgentStore> {
|
|
825
|
-
let storePromise = this.stores.get(stateDir);
|
|
826
|
-
if (storePromise === undefined) {
|
|
827
|
-
storePromise = mkdir(stateDir, { recursive: true }).then(() =>
|
|
828
|
-
SqliteLocalAgentStore.open({
|
|
829
|
-
stateRoot: stateDir,
|
|
830
|
-
workspaceRef: stateDir,
|
|
831
|
-
}),
|
|
832
|
-
);
|
|
833
|
-
this.stores.set(stateDir, storePromise);
|
|
834
|
-
}
|
|
835
|
-
return storePromise;
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
/** Cloud agent ids minted by the server are `bc-…`; those always resume. */
|
|
840
|
-
export function isServerMintedCloudAgentId(id: string): boolean {
|
|
841
|
-
return id.startsWith("bc-");
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
/**
|
|
845
|
-
* `Agent.resume` on a store with no row for the agent ("Agent <id> not
|
|
846
|
-
* found", surfaced by every built-in {@link LocalAgentStore} backend).
|
|
847
|
-
* Deliberately narrow: transient store/transport failures must propagate
|
|
848
|
-
* rather than silently fork the thread onto a fresh conversation.
|
|
849
|
-
*/
|
|
850
|
-
export function isLocalAgentNotFoundError(error: unknown, agentId: string): boolean {
|
|
851
|
-
return (
|
|
852
|
-
error instanceof Error &&
|
|
853
|
-
error.message.includes(agentId) &&
|
|
854
|
-
/\bnot found\b/i.test(error.message)
|
|
855
|
-
);
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
export function toModelSelection(model: ModelSetting): ModelSelection {
|
|
859
|
-
if (typeof model === "string") {
|
|
860
|
-
return { id: model };
|
|
861
|
-
}
|
|
862
|
-
return {
|
|
863
|
-
id: model.id,
|
|
864
|
-
...(model.params === undefined ? {} : { params: model.params }),
|
|
865
|
-
};
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
function toCloudAgentOptions(
|
|
869
|
-
cloud: RunnerTurnRequest["cloud"],
|
|
870
|
-
agentServeAgent?: string,
|
|
871
|
-
): CloudAgentOptions {
|
|
872
|
-
return {
|
|
873
|
-
...(cloud?.env === undefined ? {} : { env: cloud.env }),
|
|
874
|
-
...(cloud?.repos === undefined ? {} : { repos: cloud.repos }),
|
|
875
|
-
...(cloud?.workOnCurrentBranch === undefined
|
|
876
|
-
? {}
|
|
877
|
-
: { workOnCurrentBranch: cloud.workOnCurrentBranch }),
|
|
878
|
-
...(cloud?.autoCreatePR === undefined ? {} : { autoCreatePR: cloud.autoCreatePR }),
|
|
879
|
-
...(cloud?.skipReviewerRequest === undefined
|
|
880
|
-
? {}
|
|
881
|
-
: { skipReviewerRequest: cloud.skipReviewerRequest }),
|
|
882
|
-
...(cloud?.envVars === undefined ? {} : { envVars: cloud.envVars }),
|
|
883
|
-
...(agentServeAgent === undefined ? {} : { agentServeAgent }),
|
|
884
|
-
};
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
function toAgentDefinitions(
|
|
888
|
-
subagents: RunnerSubagent[],
|
|
889
|
-
): Record<string, AgentDefinition> | undefined {
|
|
890
|
-
if (subagents.length === 0) {
|
|
891
|
-
return undefined;
|
|
892
|
-
}
|
|
893
|
-
const definitions: Record<string, AgentDefinition> = {};
|
|
894
|
-
for (const subagent of subagents) {
|
|
895
|
-
definitions[subagent.name] = {
|
|
896
|
-
description: subagent.description,
|
|
897
|
-
prompt: subagent.prompt,
|
|
898
|
-
model: subagent.model === undefined ? "inherit" : toModelSelection(subagent.model),
|
|
899
|
-
};
|
|
900
|
-
}
|
|
901
|
-
return definitions;
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
function toTurnOutcome(result: RunResult): TurnOutcome {
|
|
905
|
-
const usage: TurnUsage | undefined =
|
|
906
|
-
result.usage === undefined
|
|
907
|
-
? undefined
|
|
908
|
-
: {
|
|
909
|
-
inputTokens: result.usage.inputTokens,
|
|
910
|
-
outputTokens: result.usage.outputTokens,
|
|
911
|
-
cacheReadTokens: result.usage.cacheReadTokens,
|
|
912
|
-
cacheWriteTokens: result.usage.cacheWriteTokens,
|
|
913
|
-
...(result.usage.reasoningTokens === undefined
|
|
914
|
-
? {}
|
|
915
|
-
: { reasoningTokens: result.usage.reasoningTokens }),
|
|
916
|
-
};
|
|
917
|
-
return {
|
|
918
|
-
status: result.status,
|
|
919
|
-
...(result.result === undefined ? {} : { result: result.result }),
|
|
920
|
-
...(result.status === "error" ? { errorMessage: runErrorMessage(result) } : {}),
|
|
921
|
-
errorCode: result.status === "error" ? result.error?.code : undefined,
|
|
922
|
-
...(usage === undefined ? {} : { usage }),
|
|
923
|
-
};
|
|
924
|
-
}
|
|
925
|
-
|
|
926
|
-
/** Billing can lag briefly after `wait()`; retry before giving up on cost. */
|
|
927
|
-
const CLOUD_USAGE_RETRY_DELAYS_MS = [0, 400, 1200] as const;
|
|
928
|
-
|
|
929
|
-
/**
|
|
930
|
-
* Cloud `wait()` often omits usage after a stream drop. Pull the run's
|
|
931
|
-
* tokens from the usage API so the engine can still price the turn.
|
|
932
|
-
* Failures are ignored: a missing estimate is better than failing the turn.
|
|
933
|
-
*/
|
|
934
|
-
async function fillMissingCloudUsage(
|
|
935
|
-
agent: SDKAgent,
|
|
936
|
-
runId: string,
|
|
937
|
-
outcome: TurnOutcome,
|
|
938
|
-
): Promise<TurnOutcome> {
|
|
939
|
-
for (const delayMs of CLOUD_USAGE_RETRY_DELAYS_MS) {
|
|
940
|
-
if (delayMs > 0) {
|
|
941
|
-
await sleep(delayMs);
|
|
942
|
-
}
|
|
943
|
-
try {
|
|
944
|
-
const billed = await agent.getUsage({ runId });
|
|
945
|
-
const mapped = mapSdkTokenUsage(billed.usage);
|
|
946
|
-
if (usageTokenSum(mapped) <= 0) {
|
|
947
|
-
continue;
|
|
948
|
-
}
|
|
949
|
-
return { ...outcome, usage: mapped };
|
|
950
|
-
} catch {
|
|
951
|
-
// Transient usage-API failures should still burn the retry budget.
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
return outcome;
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
export function runErrorMessage(result: Pick<RunResult, "error">): string {
|
|
958
|
-
return result.error?.message?.trim() || "The Cursor agent run failed";
|
|
959
|
-
}
|