@cursor/bdk 0.2.9 → 0.2.11
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/artifacts.js +3 -5
- package/dist/bin/agent-serve.js +803 -812
- package/dist/channels/bitbucket/api.js +305 -321
- package/dist/channels/bitbucket/binding.js +97 -61
- package/dist/channels/bitbucket/bitbucket-channel.d.ts +15 -1
- package/dist/channels/bitbucket/bitbucket-channel.d.ts.map +1 -1
- package/dist/channels/bitbucket/bitbucket-channel.js +95 -42
- package/dist/channels/bitbucket/bitbucket-webhook.d.ts +11 -0
- package/dist/channels/bitbucket/bitbucket-webhook.d.ts.map +1 -1
- package/dist/channels/bitbucket/bitbucket-webhook.js +214 -204
- package/dist/channels/bitbucket/checks.js +9 -21
- package/dist/channels/bitbucket/cursor-account.js +1 -1
- package/dist/channels/bitbucket/defaults.js +14 -4
- package/dist/channels/bitbucket/events.js +1 -2
- package/dist/channels/bitbucket/index.d.ts +6 -2
- package/dist/channels/bitbucket/index.d.ts.map +1 -1
- package/dist/channels/bitbucket/index.js +6 -2
- package/dist/channels/bitbucket/replay.js +80 -56
- package/dist/channels/bitbucket/state.js +16 -7
- package/dist/channels/bitbucket/types.d.ts +11 -2
- package/dist/channels/bitbucket/types.d.ts.map +1 -1
- package/dist/channels/checks.js +18 -28
- package/dist/channels/deployments/deployments-channel.js +26 -34
- package/dist/channels/github/api.js +216 -210
- package/dist/channels/github/auth.d.ts +5 -1
- package/dist/channels/github/auth.d.ts.map +1 -1
- package/dist/channels/github/auth.js +157 -174
- package/dist/channels/github/binding.js +48 -39
- package/dist/channels/github/checks.js +9 -14
- package/dist/channels/github/cursor-account.js +6 -11
- package/dist/channels/github/defaults.js +105 -130
- package/dist/channels/github/forward.js +13 -17
- package/dist/channels/github/github-channel.d.ts +43 -2
- package/dist/channels/github/github-channel.d.ts.map +1 -1
- package/dist/channels/github/github-channel.js +1228 -958
- package/dist/channels/github/progress.js +145 -146
- package/dist/channels/github/replay.js +30 -39
- package/dist/channels/github/state.js +40 -16
- package/dist/channels/github/types.d.ts +30 -6
- package/dist/channels/github/types.d.ts.map +1 -1
- package/dist/channels/gitlab/api.js +100 -114
- package/dist/channels/gitlab/binding.js +52 -33
- package/dist/channels/gitlab/checks.js +28 -29
- package/dist/channels/gitlab/cursor-account.js +1 -1
- package/dist/channels/gitlab/defaults.js +9 -3
- package/dist/channels/gitlab/gitlab-channel.d.ts +16 -1
- package/dist/channels/gitlab/gitlab-channel.d.ts.map +1 -1
- package/dist/channels/gitlab/gitlab-channel.js +95 -42
- package/dist/channels/gitlab/gitlab-webhook.d.ts +10 -1
- package/dist/channels/gitlab/gitlab-webhook.d.ts.map +1 -1
- package/dist/channels/gitlab/gitlab-webhook.js +282 -249
- package/dist/channels/gitlab/index.d.ts +6 -2
- package/dist/channels/gitlab/index.d.ts.map +1 -1
- package/dist/channels/gitlab/index.js +6 -2
- package/dist/channels/gitlab/replay.js +50 -27
- package/dist/channels/gitlab/state.js +14 -6
- package/dist/channels/gitlab/types.d.ts +13 -2
- package/dist/channels/gitlab/types.d.ts.map +1 -1
- package/dist/channels/origin/api.js +100 -116
- package/dist/channels/origin/binding.js +15 -16
- package/dist/channels/origin/checks.js +30 -28
- package/dist/channels/origin/defaults.js +50 -65
- package/dist/channels/origin/origin-channel.js +266 -272
- package/dist/channels/origin/origin-webhook.js +70 -88
- package/dist/channels/origin/reactions.js +9 -21
- package/dist/channels/origin/state.js +13 -5
- package/dist/channels/slack/agentic-delivery.js +426 -478
- package/dist/channels/slack/agentic-posted.js +9 -10
- package/dist/channels/slack/agentic-signals.js +2 -3
- package/dist/channels/slack/api.js +417 -427
- package/dist/channels/slack/approvals.js +1 -1
- package/dist/channels/slack/assistant.js +37 -47
- package/dist/channels/slack/attachments.js +188 -206
- package/dist/channels/slack/auth.js +8 -6
- package/dist/channels/slack/bot-mentions.js +31 -45
- package/dist/channels/slack/channel-watch.js +42 -48
- package/dist/channels/slack/cli-project.js +112 -137
- package/dist/channels/slack/code-fences.js +3 -5
- package/dist/channels/slack/constants.js +2 -2
- package/dist/channels/slack/credentials.js +23 -38
- package/dist/channels/slack/defaults.js +292 -331
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +533 -460
- package/dist/channels/slack/doctor.js +200 -214
- package/dist/channels/slack/eval-directive.js +79 -96
- package/dist/channels/slack/event-id-dedupe.js +1 -1
- package/dist/channels/slack/external-policy.js +26 -39
- package/dist/channels/slack/footer.js +28 -41
- package/dist/channels/slack/inbound.d.ts +1 -0
- package/dist/channels/slack/inbound.d.ts.map +1 -1
- package/dist/channels/slack/inbound.js +50 -31
- package/dist/channels/slack/init.d.ts +1 -5
- package/dist/channels/slack/init.d.ts.map +1 -1
- package/dist/channels/slack/init.js +42 -59
- package/dist/channels/slack/interactive.d.ts +9 -3
- package/dist/channels/slack/interactive.d.ts.map +1 -1
- package/dist/channels/slack/interactive.js +160 -162
- package/dist/channels/slack/links.js +1 -2
- package/dist/channels/slack/live-delivery.js +172 -190
- package/dist/channels/slack/manifest.d.ts.map +1 -1
- package/dist/channels/slack/manifest.js +44 -23
- package/dist/channels/slack/message-body.js +2 -2
- package/dist/channels/slack/nudge-carrier.js +30 -42
- package/dist/channels/slack/nudge-store.js +164 -191
- package/dist/channels/slack/paint-start.js +66 -81
- package/dist/channels/slack/placeholder.js +123 -152
- package/dist/channels/slack/pr-ref.js +1 -1
- package/dist/channels/slack/progress-delivery.js +65 -78
- package/dist/channels/slack/reasoning-card.js +36 -49
- package/dist/channels/slack/recording-sink.js +12 -24
- package/dist/channels/slack/reply-options.js +7 -12
- package/dist/channels/slack/self-identity.js +27 -35
- package/dist/channels/slack/sender-name.d.ts +12 -3
- package/dist/channels/slack/sender-name.d.ts.map +1 -1
- package/dist/channels/slack/sender-name.js +57 -61
- package/dist/channels/slack/setup.js +2 -4
- package/dist/channels/slack/slack-channel.d.ts +6 -4
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +441 -308
- package/dist/channels/slack/socket-mode.js +38 -52
- package/dist/channels/slack/thread-context.js +143 -160
- package/dist/channels/slack/tool-approval-events.js +149 -166
- package/dist/channels/slack/tool-cards.js +6 -11
- package/dist/channels/slack/tool-chip.js +1 -2
- package/dist/channels/slack/types.d.ts +15 -17
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/channels/slack/upload.js +84 -97
- package/dist/channels/slack/user-info.js +27 -41
- package/dist/channels.js +9 -20
- package/dist/dashboard-session-url.js +3 -4
- package/dist/docs/404.html +2 -2
- package/dist/docs/assets/{app.BNhEdGa8.js → app.DXI7bwox.js} +4 -4
- package/dist/docs/assets/{building-with-agents.md.BPjPFxFg.js → building-with-agents.md.Df87rAe1.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.CtLtpWcx.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.DIdUV1Ph.js → VPLocalSearchBox.BrbO5mEe.js} +1 -1
- package/dist/docs/assets/chunks/{arc.lELI4_SR.js → arc.BOG1yms8.js} +1 -1
- package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.iCMdvuoM.js → architectureDiagram-Q4EWVU46.C0hsMZnZ.js} +1 -1
- package/dist/docs/assets/chunks/{baseUniq.C1-nDJBf.js → baseUniq.H044KjKs.js} +1 -1
- package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.ClemzBox.js → blockDiagram-DXYQGD6D.BsRW6GoB.js} +1 -1
- package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.BqTak6cR.js → c4Diagram-AHTNJAMY.B9HV5PFR.js} +1 -1
- package/dist/docs/assets/chunks/channel.CBwrU9rP.js +1 -0
- package/dist/docs/assets/chunks/{chunk-4BX2VUAB.CUS3qs_R.js → chunk-4BX2VUAB.CPoT_ajl.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-4TB4RGXK.dz5fdHcl.js → chunk-4TB4RGXK.DZBwWuCL.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-55IACEB6.D6BEBmve.js → chunk-55IACEB6.CZ3yTiyq.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-EDXVE4YY.B5uK4ID9.js → chunk-EDXVE4YY.6DfvHSd8.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-FMBD7UC4.PgOJgNQs.js → chunk-FMBD7UC4.CpBj8HfK.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-OYMX7WX6.CvkTrCii.js → chunk-OYMX7WX6.BdKo8YqS.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-QZHKN3VN.BnSfKYsB.js → chunk-QZHKN3VN.BnXNyxJx.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-YZCP3GAM.MZH6v5UC.js → chunk-YZCP3GAM.Cg1OcF8G.js} +1 -1
- package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.CbC_mrvB.js +1 -0
- package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.CbC_mrvB.js +1 -0
- package/dist/docs/assets/chunks/clone.BTvFyY1a.js +1 -0
- package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.BBbw_YZi.js → cose-bilkent-S5V4N54A.1SP8al9c.js} +1 -1
- package/dist/docs/assets/chunks/{dagre-KV5264BT.CNJB2l7E.js → dagre-KV5264BT.DS1L6hJt.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-5BDNPKRD.BQzlnFfq.js → diagram-5BDNPKRD.ChsausbG.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.DkgqqZMz.js → diagram-G4DWMVQ6.3XsptNWj.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-MMDJMWI5.DIT8L7H_.js → diagram-MMDJMWI5.DPA9Dk_P.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-TYMM5635.3xLPZWGJ.js → diagram-TYMM5635.BVswXWrB.js} +1 -1
- package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.5_IHz8jF.js → erDiagram-SMLLAGMA.BSak5OSP.js} +1 -1
- package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.BGUCXz8A.js → flowDiagram-DWJPFMVM.CQgN4TTz.js} +1 -1
- package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.DbfFavS1.js → ganttDiagram-T4ZO3ILL.GrT0kA4a.js} +1 -1
- package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.D2yKdeNW.js → gitGraphDiagram-UUTBAWPF.CdS7Ucll.js} +1 -1
- package/dist/docs/assets/chunks/{graph.CSCxwHba.js → graph.BVqKRmRo.js} +1 -1
- package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.FDeb6xHY.js → infoDiagram-42DDH7IO.C3C9FRto.js} +1 -1
- package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.DbeYs9VL.js → ishikawaDiagram-UXIWVN3A.2FuAh_Zj.js} +1 -1
- package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.CWjKINpx.js → journeyDiagram-VCZTEJTY.CaHMfK4b.js} +1 -1
- package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.B4FrAlwz.js → kanban-definition-6JOO6SKY.CjhIUwcA.js} +1 -1
- package/dist/docs/assets/chunks/{layout.DFGxQ9ab.js → layout.CGU3gfSf.js} +1 -1
- package/dist/docs/assets/chunks/{linear.BmjZ-G59.js → linear.DaihpW_n.js} +1 -1
- package/dist/docs/assets/chunks/{min.DZSxulMW.js → min.BS-j8kHQ.js} +1 -1
- package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.CHLi3-aN.js → mindmap-definition-QFDTVHPH.BVJ1Bbnk.js} +1 -1
- package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.DteG-CkU.js → pieDiagram-DEJITSTG.Cz1WIv9r.js} +1 -1
- package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.D458ipN3.js → quadrantDiagram-34T5L4WZ.DKLFxcjy.js} +1 -1
- package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.DcFgUxst.js → requirementDiagram-MS252O5E.BHegiK7x.js} +1 -1
- package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.BwQAMmSA.js → sankeyDiagram-XADWPNL6.DYkY6yPc.js} +1 -1
- package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.B_Xdsrh9.js → sequenceDiagram-FGHM5R23.DYQ1QUrI.js} +1 -1
- package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.CdfDW6-C.js → stateDiagram-FHFEXIEX.Iru8BsFo.js} +1 -1
- package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.BYXl4LW6.js +1 -0
- package/dist/docs/assets/chunks/{theme.sfdL3srp.js → theme.DaplWQhQ.js} +2 -2
- package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.56-4hXaC.js → timeline-definition-GMOUNBTQ.BwFA8hiX.js} +1 -1
- package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.CvZSQBO7.js → vennDiagram-DHZGUBPP.CZ60W1C_.js} +1 -1
- package/dist/docs/assets/chunks/{wardley-RL74JXVD.C9qc8k39.js → wardley-RL74JXVD.iXazD3Z7.js} +1 -1
- package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.D9s0nihi.js → wardleyDiagram-NUSXRM2D.B69D2r8-.js} +1 -1
- package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.BVJSpYrC.js → xychartDiagram-5P7HB3ND.CLPZEIU9.js} +1 -1
- package/dist/docs/assets/{deployment.md.BdqTiGdc.js → deployment.md.BYuEcDBv.js} +2 -2
- package/dist/docs/assets/{guides_bitbucket.md.BB6fqD-M.js → guides_bitbucket.md.CKUayYtD.js} +3 -3
- package/dist/docs/assets/{guides_bitbucket.md.BB6fqD-M.lean.js → guides_bitbucket.md.CKUayYtD.lean.js} +1 -1
- package/dist/docs/assets/{guides_github.md.Cr1Xlf-m.js → guides_github.md.TuNiZAOQ.js} +4 -4
- package/dist/docs/assets/{guides_github.md.Cr1Xlf-m.lean.js → guides_github.md.TuNiZAOQ.lean.js} +1 -1
- package/dist/docs/assets/{guides_gitlab.md.CMpmFi4M.js → guides_gitlab.md.CtNI4fSH.js} +4 -4
- package/dist/docs/assets/{guides_gitlab.md.CMpmFi4M.lean.js → guides_gitlab.md.CtNI4fSH.lean.js} +1 -1
- package/dist/docs/assets/guides_migrate.md.sCAvvlC6.js +7 -0
- package/dist/docs/assets/guides_migrate.md.sCAvvlC6.lean.js +1 -0
- package/dist/docs/assets/{reference_cli.md.GwugN3n-.js → reference_cli.md.dYCAL2lB.js} +4 -3
- package/dist/docs/assets/reference_cli.md.dYCAL2lB.lean.js +1 -0
- package/dist/docs/assets/troubleshooting.md.x-GBa7wN.js +1 -0
- package/dist/docs/assets/{troubleshooting.md.Bscj6ODe.lean.js → troubleshooting.md.x-GBa7wN.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +37 -37
- package/dist/docs/building-with-agents.md +2 -0
- package/dist/docs/deployment.html +38 -38
- package/dist/docs/deployment.md +7 -0
- package/dist/docs/evals.html +36 -36
- package/dist/docs/guides/agent-to-agent.html +35 -35
- package/dist/docs/guides/bitbucket.html +38 -38
- package/dist/docs/guides/bitbucket.md +9 -1
- package/dist/docs/guides/cloud-agents.html +35 -35
- package/dist/docs/guides/convert-automation.html +35 -35
- package/dist/docs/guides/github.html +39 -39
- package/dist/docs/guides/github.md +20 -4
- package/dist/docs/guides/gitlab.html +38 -38
- package/dist/docs/guides/gitlab.md +9 -1
- 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 +35 -35
- package/dist/docs/guides/mcp-oauth.html +35 -35
- package/dist/docs/guides/migrate.html +66 -0
- package/dist/docs/guides/migrate.md +122 -0
- 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 +214 -6
- package/dist/docs/llms.txt +1 -0
- package/dist/docs/quickstart.html +35 -35
- package/dist/docs/reference/agent-config.html +35 -35
- package/dist/docs/reference/artifacts.html +35 -35
- package/dist/docs/reference/channels.html +35 -35
- package/dist/docs/reference/cli.html +39 -38
- package/dist/docs/reference/cli.md +39 -0
- package/dist/docs/reference/connections.html +35 -35
- package/dist/docs/reference/evals.html +35 -35
- package/dist/docs/reference/extensions.html +35 -35
- 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/grokbot-agents.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 +36 -36
- package/dist/docs/troubleshooting.md +1 -0
- package/dist/evals/assertions.js +20 -34
- package/dist/evals/expect.js +3 -6
- package/dist/evals/judge.js +5 -8
- package/dist/evals/loaders.js +45 -62
- package/dist/evals/matchers.js +2 -3
- package/dist/evals/reporters.js +43 -67
- package/dist/evals/results.js +1 -1
- package/dist/evals/run-facts.js +5 -6
- package/dist/evals.js +27 -15
- package/dist/extensions/cursor-cloud-agents/extension.js +4 -1
- package/dist/extensions/cursor-cloud-agents/lib/backend.js +100 -126
- package/dist/extensions/cursor-cloud-agents/lib/fleet.js +22 -38
- package/dist/extensions/cursor-cloud-agents/lib/repos.js +8 -10
- package/dist/extensions/cursor-cloud-agents/lib/transcript.js +2 -3
- package/dist/extensions/cursor-cloud-agents/lib/watch.js +52 -66
- package/dist/extensions/cursor-cloud-agents/reminders/cloud-agent-stop-watch.js +29 -40
- package/dist/extensions/cursor-cloud-agents/tools/cancel.js +6 -17
- package/dist/extensions/cursor-cloud-agents/tools/dump.js +25 -36
- package/dist/extensions/cursor-cloud-agents/tools/get.js +3 -14
- package/dist/extensions/cursor-cloud-agents/tools/launch.js +13 -21
- package/dist/extensions/cursor-cloud-agents/tools/list.js +8 -19
- package/dist/extensions/cursor-cloud-agents/tools/reply.js +5 -16
- package/dist/extensions/cursor-grokbot-agents/extension.js +4 -1
- package/dist/extensions/cursor-grokbot-agents/lib/agents.js +3 -3
- package/dist/extensions/cursor-grokbot-agents/lib/backend.js +53 -73
- package/dist/extensions/cursor-grokbot-agents/lib/contacts.js +10 -23
- package/dist/extensions/cursor-grokbot-agents/lib/conversation.js +112 -132
- package/dist/extensions/cursor-grokbot-agents/lib/lock.js +1 -2
- package/dist/extensions/cursor-grokbot-agents/tools/ask.js +5 -16
- package/dist/extensions/cursor-grokbot-agents/tools/check.js +4 -15
- package/dist/extensions/cursor-grokbot-agents/tools/interrupt.js +2 -13
- package/dist/extensions/cursor-grokbot-agents/tools/list.js +11 -23
- package/dist/extensions/jev/extension.js +3 -3
- package/dist/extensions/jev/lib/evaluate.js +43 -60
- package/dist/extensions/jev/tools/evaluate.js +6 -17
- package/dist/extensions/slack-communication/tools/post-file.js +1 -1
- package/dist/extensions.js +3 -5
- package/dist/files-backends/cursor-hosted.js +504 -523
- package/dist/files-backends/local-fs.js +72 -134
- package/dist/files.js +3 -3
- package/dist/filesystem.js +562 -861
- package/dist/index.js +16 -35
- package/dist/internal/advertise-tools.js +74 -86
- package/dist/internal/artifacts-store.js +298 -361
- package/dist/internal/as-of.js +2 -4
- package/dist/internal/authored-alias-hooks.js +6 -4
- package/dist/internal/authored-loaders.js +37 -52
- package/dist/internal/bounded-int.js +1 -2
- package/dist/internal/bounded.js +13 -24
- package/dist/internal/brand.js +1 -1
- package/dist/internal/browser-origin-guard.js +4 -4
- package/dist/internal/builtin-tools/artifacts.js +15 -27
- package/dist/internal/builtin-tools/index.js +2 -3
- package/dist/internal/builtin-tools/reminders.js +33 -52
- package/dist/internal/channel-architecture.d.ts +21 -0
- package/dist/internal/channel-architecture.d.ts.map +1 -0
- package/dist/internal/channel-architecture.js +41 -0
- package/dist/internal/channel-dispatch.js +3 -4
- package/dist/internal/channel-route-dispatch.js +40 -51
- package/dist/internal/channel-state.js +1 -1
- package/dist/internal/chat-client.js +319 -340
- package/dist/internal/cli-ax.js +1262 -1294
- package/dist/internal/cli-bitbucket.js +244 -272
- package/dist/internal/cli-convert-automation.js +137 -151
- package/dist/internal/cli-cursor.js +126 -147
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +1457 -1507
- package/dist/internal/cli-docs.js +130 -147
- package/dist/internal/cli-github.js +437 -476
- package/dist/internal/cli-gitlab.js +259 -288
- package/dist/internal/cli-images.js +266 -334
- package/dist/internal/cli-manifest.js +25 -37
- package/dist/internal/cli-mcp-oauth.js +228 -247
- package/dist/internal/cli-mcp.js +358 -383
- package/dist/internal/cli-migrate.js +73 -90
- package/dist/internal/cli-skills.js +35 -47
- package/dist/internal/cli-slack-manual.d.ts +0 -1
- package/dist/internal/cli-slack-manual.d.ts.map +1 -1
- package/dist/internal/cli-slack-manual.js +175 -204
- package/dist/internal/cli-slack.d.ts +1 -1
- package/dist/internal/cli-slack.d.ts.map +1 -1
- package/dist/internal/cli-slack.js +416 -456
- package/dist/internal/cloud-merge.js +7 -3
- package/dist/internal/cloud-turn-cost.js +8 -1
- package/dist/internal/connection-env.js +5 -6
- package/dist/internal/continuation-channel.js +10 -7
- package/dist/internal/continuation-identity.js +85 -67
- package/dist/internal/conversation-mirror.js +112 -131
- package/dist/internal/convert-automation/convert-workflow.js +21 -31
- package/dist/internal/cron.js +3 -3
- package/dist/internal/cursor/account-mcp.js +147 -146
- package/dist/internal/cursor/backend-client.js +290 -320
- package/dist/internal/cursor/bound-secret-file.js +3 -3
- package/dist/internal/cursor/credentials.js +127 -142
- package/dist/internal/cursor/cursor-api-transport.js +4 -8
- package/dist/internal/cursor/github-credentials.js +91 -108
- package/dist/internal/cursor/hosted-bound-secrets.js +3 -4
- package/dist/internal/cursor/hosted-deployment-secrets.js +1 -1
- package/dist/internal/cursor/hosted-store-secrets.js +5 -9
- package/dist/internal/cursor/session-token.js +36 -48
- package/dist/internal/cursor/store-api-client.js +77 -92
- package/dist/internal/cursor-account-mcp-auth.js +132 -149
- package/dist/internal/cursor-agent-template.js +1 -1
- package/dist/internal/cursor-deployment-relay.js +33 -54
- package/dist/internal/cursor-event-relay.js +65 -59
- package/dist/internal/cursor-relay-core.js +258 -286
- package/dist/internal/deferred-channel-session.js +3 -12
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +413 -475
- package/dist/internal/deploy-manifest.d.ts +17 -0
- package/dist/internal/deploy-manifest.d.ts.map +1 -1
- package/dist/internal/deploy-manifest.js +71 -21
- package/dist/internal/deploy-source.js +31 -43
- package/dist/internal/discovery/agent-config.js +45 -59
- package/dist/internal/discovery/agent.js +276 -280
- package/dist/internal/discovery/channels.js +67 -80
- package/dist/internal/discovery/connections.js +286 -296
- package/dist/internal/discovery/context.js +2 -13
- package/dist/internal/discovery/cursor-plugin.js +223 -259
- package/dist/internal/discovery/extension-overlay.js +104 -131
- package/dist/internal/discovery/extensions.js +276 -281
- package/dist/internal/discovery/fs.js +56 -79
- package/dist/internal/discovery/hooks.js +39 -50
- package/dist/internal/discovery/info.js +17 -19
- package/dist/internal/discovery/instructions.js +58 -71
- package/dist/internal/discovery/modules.js +45 -58
- package/dist/internal/discovery/project.d.ts.map +1 -1
- package/dist/internal/discovery/project.js +192 -215
- package/dist/internal/discovery/reminders.js +41 -52
- package/dist/internal/discovery/runtime.js +1 -1
- package/dist/internal/discovery/schedules.js +71 -82
- package/dist/internal/discovery/seed-files.js +21 -32
- package/dist/internal/discovery/services.js +74 -96
- package/dist/internal/discovery/skills.js +77 -94
- package/dist/internal/discovery/subagent.js +79 -95
- package/dist/internal/discovery/tools.js +12 -23
- package/dist/internal/distribution.js +2 -2
- package/dist/internal/docs-site.js +30 -45
- package/dist/internal/duration.js +1 -1
- package/dist/internal/env-file.js +48 -64
- package/dist/internal/eval-judge-model.js +17 -28
- package/dist/internal/eval-run-store.js +265 -254
- package/dist/internal/eval-runner.d.ts +8 -0
- package/dist/internal/eval-runner.d.ts.map +1 -1
- package/dist/internal/eval-runner.js +406 -408
- package/dist/internal/eval-transport.d.ts +24 -0
- package/dist/internal/eval-transport.d.ts.map +1 -0
- package/dist/internal/eval-transport.js +22 -0
- package/dist/internal/evals-client.js +242 -246
- package/dist/internal/event-log.js +72 -120
- package/dist/internal/event-mapper.js +30 -31
- package/dist/internal/factory-resource-channel.js +16 -30
- package/dist/internal/filesystem/errors.js +6 -6
- package/dist/internal/filesystem/format.js +10 -13
- package/dist/internal/filesystem/merge.js +52 -94
- package/dist/internal/filesystem/nearest.js +15 -27
- package/dist/internal/filesystem/scratch.js +65 -85
- package/dist/internal/filesystem/tools.js +221 -241
- package/dist/internal/filesystem/walk.js +76 -143
- package/dist/internal/framework-file-storage.js +118 -139
- package/dist/internal/framework-storage-selection.js +21 -13
- package/dist/internal/frontmatter.js +4 -6
- package/dist/internal/github-fanout.js +50 -64
- package/dist/internal/guest-network.js +96 -109
- package/dist/internal/handleAgentServeTrigger.js +121 -126
- package/dist/internal/host-files.js +73 -88
- package/dist/internal/host-kv.js +21 -36
- package/dist/internal/host-otel.js +22 -19
- package/dist/internal/host-platforms.js +49 -63
- package/dist/internal/hosted-catch-protocol.d.ts +1 -0
- package/dist/internal/hosted-catch-protocol.d.ts.map +1 -1
- package/dist/internal/hosted-catch-protocol.js +1 -0
- package/dist/internal/hosted-catch.d.ts +5 -3
- package/dist/internal/hosted-catch.d.ts.map +1 -1
- package/dist/internal/hosted-catch.js +84 -93
- package/dist/internal/hosted-delivery-protocol.js +32 -8
- package/dist/internal/hosted-delivery.d.ts +13 -1
- package/dist/internal/hosted-delivery.d.ts.map +1 -1
- package/dist/internal/hosted-delivery.js +614 -584
- package/dist/internal/hosted-eval-cases.d.ts +21 -0
- package/dist/internal/hosted-eval-cases.d.ts.map +1 -0
- package/dist/internal/hosted-eval-cases.js +162 -0
- package/dist/internal/hosted-execution-diag.js +38 -30
- package/dist/internal/hosted-execution-flush.js +75 -66
- package/dist/internal/hosted-execution-latency.js +16 -8
- package/dist/internal/hosted-managed-automation.js +2 -2
- package/dist/internal/hosting.js +2 -3
- package/dist/internal/http-channel-define.js +4 -1
- package/dist/internal/http-channel.js +101 -112
- package/dist/internal/http-control-plane-session.d.ts +18 -1
- package/dist/internal/http-control-plane-session.d.ts.map +1 -1
- package/dist/internal/http-control-plane-session.js +66 -32
- package/dist/internal/incoming-headers-to-fetch.js +1 -2
- package/dist/internal/init-interview.js +73 -93
- package/dist/internal/init-project.js +182 -214
- package/dist/internal/init-scaffold.js +10 -21
- package/dist/internal/inline-stdio-mcp.js +80 -86
- package/dist/internal/install-cursor-skills.js +231 -273
- package/dist/internal/legacy-command-guard.js +18 -31
- package/dist/internal/listen-port.js +34 -45
- package/dist/internal/local-control-plane.js +293 -307
- package/dist/internal/local-env.js +1 -1
- package/dist/internal/local-ingress.js +15 -9
- package/dist/internal/log-ring.js +1 -2
- package/dist/internal/logs-client.js +207 -227
- package/dist/internal/map-pool.js +24 -38
- package/dist/internal/mcp-endpoint.js +204 -180
- package/dist/internal/mcp-host.js +165 -168
- package/dist/internal/mcp-oauth-on-demand.js +170 -207
- package/dist/internal/mcp-oauth-persist.js +15 -29
- package/dist/internal/mcp-oauth.js +209 -266
- package/dist/internal/named-webhook-secret.d.ts +39 -0
- package/dist/internal/named-webhook-secret.d.ts.map +1 -0
- package/dist/internal/named-webhook-secret.js +47 -0
- package/dist/internal/open-browser.js +2 -3
- package/dist/internal/otel/collector.js +104 -68
- package/dist/internal/otel/config.js +24 -37
- package/dist/internal/otel/http.js +5 -7
- package/dist/internal/otel/mcp.js +3 -12
- package/dist/internal/otel/runtime.js +69 -83
- package/dist/internal/package-inline-stdio.js +57 -65
- package/dist/internal/peer-connections.js +9 -5
- package/dist/internal/platform-schedule-sync.js +39 -54
- package/dist/internal/platform-timers.js +176 -210
- package/dist/internal/playground/static.js +1 -2
- package/dist/internal/playground/toolchain.js +37 -53
- package/dist/internal/playground-proxy.js +230 -270
- package/dist/internal/process-memory-telemetry.js +33 -51
- package/dist/internal/prompt-context.js +3 -6
- package/dist/internal/reminder-control-plane-protocol.js +46 -13
- package/dist/internal/reminder-runner.js +770 -785
- package/dist/internal/reminder-schedule.js +1 -1
- package/dist/internal/reminder-store.js +57 -78
- package/dist/internal/request-error-status.js +1 -3
- package/dist/internal/request-headers.js +2 -2
- package/dist/internal/resolve-prod-target.js +119 -135
- package/dist/internal/resolved-connections.js +16 -6
- package/dist/internal/run-client.js +221 -229
- package/dist/internal/runtime-dispatch-runner.js +18 -43
- package/dist/internal/schedule-runner.js +49 -58
- package/dist/internal/scm/pr-url.js +7 -6
- package/dist/internal/sdk-runner.js +388 -363
- package/dist/internal/serve-restart.js +26 -39
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +1283 -1244
- package/dist/internal/session-cost.js +7 -9
- package/dist/internal/session-engine.d.ts +3 -1
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +2801 -2777
- package/dist/internal/session-links.js +12 -16
- package/dist/internal/session-run-log.js +134 -82
- package/dist/internal/session-store.js +133 -164
- package/dist/internal/sessions-client.js +97 -118
- package/dist/internal/skill-catalog.js +18 -23
- package/dist/internal/skills-sync.js +16 -30
- package/dist/internal/slack-provision-client.js +90 -116
- package/dist/internal/start-log-store.js +48 -67
- package/dist/internal/steering.js +1 -2
- package/dist/internal/storage-coordinator.js +160 -196
- package/dist/internal/store-mirror.js +16 -30
- package/dist/internal/stream-progress.js +6 -8
- package/dist/internal/terminal-style.js +3 -4
- package/dist/internal/testing/scm-continuation-fixtures.js +6 -2
- package/dist/internal/testing/slack-continuation-fixtures.d.ts +26 -0
- package/dist/internal/testing/slack-continuation-fixtures.d.ts.map +1 -0
- package/dist/internal/testing/slack-continuation-fixtures.js +136 -0
- package/dist/internal/tool-catalog.js +11 -5
- package/dist/internal/tool-result.js +1 -1
- package/dist/internal/trajectory.js +19 -22
- package/dist/internal/turn-cost.js +52 -62
- package/dist/internal/turn-governor.js +5 -8
- package/dist/internal/turn-lease-store.js +85 -105
- package/dist/internal/turn-outbox.js +28 -43
- package/dist/internal/update-check.js +231 -259
- package/dist/internal/v2-hosting.js +1 -2
- package/dist/internal/workspace-sync.js +25 -41
- package/dist/internal/workspace.js +111 -139
- package/dist/kv/memory-kv.js +27 -51
- package/dist/memory.js +106 -148
- package/dist/otel.js +5 -8
- package/dist/playground/assets/{index-Co4CUVTQ.js → index-Be0-1hw2.js} +45 -45
- package/dist/playground/assets/index-Clz6uHj9.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/prompt.js +2 -4
- package/dist/storage-backends/cursor-hosted-v2.js +53 -83
- package/dist/storage-backends/cursor-hosted.js +105 -145
- package/dist/storage-backends/file-kv.js +100 -128
- package/dist/storage-protocol.js +3 -5
- package/dist/storage.js +17 -26
- package/dist/types.d.ts +68 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +20 -18
- package/docs/building-with-agents.md +2 -0
- package/docs/deployment.md +7 -0
- package/docs/guides/bitbucket.md +9 -1
- package/docs/guides/github.md +20 -4
- package/docs/guides/gitlab.md +9 -1
- package/docs/guides/migrate.md +127 -0
- package/docs/reference/cli.md +39 -0
- package/docs/troubleshooting.md +1 -0
- package/package.json +1 -1
- package/skills/debug/SKILL.md +1 -0
- package/skills/github/SKILL.md +23 -0
- package/skills/migrate-v2/SKILL.md +51 -10
- package/dist/docs/assets/chunks/@localSearchIndexroot.BJ8UZggu.js +0 -1
- package/dist/docs/assets/chunks/channel.BTJ5J9FI.js +0 -1
- package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.D4BZ3cVV.js +0 -1
- package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.D4BZ3cVV.js +0 -1
- package/dist/docs/assets/chunks/clone.62tX-O-1.js +0 -1
- package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.DkTs1aEU.js +0 -1
- package/dist/docs/assets/reference_cli.md.GwugN3n-.lean.js +0 -1
- package/dist/docs/assets/troubleshooting.md.Bscj6ODe.js +0 -1
- package/dist/playground/assets/index-C1g_PTTZ.css +0 -1
- /package/dist/docs/assets/{building-with-agents.md.BPjPFxFg.lean.js → building-with-agents.md.Df87rAe1.lean.js} +0 -0
- /package/dist/docs/assets/{deployment.md.BdqTiGdc.lean.js → deployment.md.BYuEcDBv.lean.js} +0 -0
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { randomBytes } from "node:crypto";
|
|
11
2
|
import { packageVersion } from "./distribution.js";
|
|
12
3
|
import { dispatchOutcome } from "./channel-dispatch.js";
|
|
@@ -27,19 +18,16 @@ import { endActiveHttpSpan } from "./otel/http.js";
|
|
|
27
18
|
import { ReminderValidationError, UnknownReminderError } from "./reminder-runner.js";
|
|
28
19
|
import { mapThrownRequestError, statusForThrownRequestError } from "./request-error-status.js";
|
|
29
20
|
import { HostedEnqueueNotActiveError } from "./session-engine.js";
|
|
30
|
-
function responseToReply(response) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
serverTiming: (_a = response.headers.get("server-timing")) !== null && _a !== void 0 ? _a : undefined,
|
|
41
|
-
};
|
|
42
|
-
});
|
|
21
|
+
async function responseToReply(response) {
|
|
22
|
+
const value = (await response.json());
|
|
23
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
24
|
+
throw new Error("Hosted delivery produced a non-object JSON response.");
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
status: response.status,
|
|
28
|
+
body: value,
|
|
29
|
+
serverTiming: response.headers.get("server-timing") ?? undefined,
|
|
30
|
+
};
|
|
43
31
|
}
|
|
44
32
|
function responseFromReply(reply) {
|
|
45
33
|
return Response.json(reply.body, {
|
|
@@ -79,16 +67,14 @@ function boundedMessage(text) {
|
|
|
79
67
|
* Carry it, bounded, into the terminal channel_dispatch_failed so the
|
|
80
68
|
* control plane's failure log is diagnosable.
|
|
81
69
|
*/
|
|
82
|
-
function channelDispatchDetail(response) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
});
|
|
70
|
+
async function channelDispatchDetail(response) {
|
|
71
|
+
try {
|
|
72
|
+
const text = (await response.text()).trim();
|
|
73
|
+
return text === "" ? undefined : boundedMessage(text);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
92
78
|
}
|
|
93
79
|
function terminalHostedError(status, error, message) {
|
|
94
80
|
return hostedGuestErrorResponse({
|
|
@@ -160,18 +146,16 @@ function mappedAdmissionFailure(error) {
|
|
|
160
146
|
* Dispatch is the adapter the mounted channel attached. Hosted delivery
|
|
161
147
|
* does not switch on `channelKind`.
|
|
162
148
|
*/
|
|
163
|
-
export function dispatchHostedAdmission(input) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return runDuringHostedAdmission(() => runAdmission(input, adapter));
|
|
174
|
-
});
|
|
149
|
+
export async function dispatchHostedAdmission(input) {
|
|
150
|
+
const adapter = getHostedAdmissionAdapter(input.definition);
|
|
151
|
+
if (adapter === undefined || adapter.kind !== input.delivery.channelKind) {
|
|
152
|
+
return {
|
|
153
|
+
response: terminalHostedError(422, "channel_kind_mismatch"),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
// The admission window marker follows the async graph into task bodies so
|
|
157
|
+
// the engine can refuse local sends that would bypass the capture stub.
|
|
158
|
+
return runDuringHostedAdmission(() => runAdmission(input, adapter));
|
|
175
159
|
}
|
|
176
160
|
/**
|
|
177
161
|
* Reserved reminder admission: parse the compact payload and invoke
|
|
@@ -179,42 +163,14 @@ export function dispatchHostedAdmission(input) {
|
|
|
179
163
|
* `skip`) and never opens the send-capture / model-session path here —
|
|
180
164
|
* prompt-form fires still follow up inside the runner.
|
|
181
165
|
*/
|
|
182
|
-
function dispatchHostedReminderAdmission(input, delivery) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
if (
|
|
186
|
-
|
|
187
|
-
return transientHostedError(503, "reminder_dispatch_unavailable", "This guest has no reminder CP executor wired for hosted admission.");
|
|
188
|
-
}
|
|
189
|
-
try {
|
|
190
|
-
const result = yield input.executeReminderDescriptor(descriptor);
|
|
191
|
-
const outcome = result.outcome === "noop" ? "skip" : "task";
|
|
192
|
-
return Response.json({
|
|
193
|
-
ok: true,
|
|
194
|
-
v: HOSTED_DELIVERY_PROTOCOL_VERSION,
|
|
195
|
-
outcome,
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
catch (error) {
|
|
199
|
-
if (error instanceof UnknownReminderError) {
|
|
200
|
-
return terminalHostedError(404, "unknown_reminder", boundedMessage(error.message));
|
|
201
|
-
}
|
|
202
|
-
if (error instanceof ReminderValidationError) {
|
|
203
|
-
return terminalHostedError(400, "invalid_reminder", boundedMessage(error.message));
|
|
204
|
-
}
|
|
205
|
-
// Transient CP apply/fetch failures must remain retryable.
|
|
206
|
-
throw error;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
if (input.fireReminder === undefined) {
|
|
210
|
-
return transientHostedError(503, "reminder_dispatch_unavailable", "This guest has no reminder runner wired for hosted admission.");
|
|
211
|
-
}
|
|
212
|
-
const payload = parseHostedReminderFirePayload(delivery.payload);
|
|
213
|
-
if (payload === undefined) {
|
|
214
|
-
return terminalHostedError(400, "invalid_reminder_payload", "Expected reminder descriptor or legacy payload { reminderId, fireCount }.");
|
|
166
|
+
async function dispatchHostedReminderAdmission(input, delivery) {
|
|
167
|
+
const descriptor = parseHostedReminderFireDescriptorPayload(delivery.payload);
|
|
168
|
+
if (descriptor !== undefined) {
|
|
169
|
+
if (input.executeReminderDescriptor === undefined) {
|
|
170
|
+
return transientHostedError(503, "reminder_dispatch_unavailable", "This guest has no reminder CP executor wired for hosted admission.");
|
|
215
171
|
}
|
|
216
172
|
try {
|
|
217
|
-
const result =
|
|
173
|
+
const result = await input.executeReminderDescriptor(descriptor);
|
|
218
174
|
const outcome = result.outcome === "noop" ? "skip" : "task";
|
|
219
175
|
return Response.json({
|
|
220
176
|
ok: true,
|
|
@@ -229,114 +185,143 @@ function dispatchHostedReminderAdmission(input, delivery) {
|
|
|
229
185
|
if (error instanceof ReminderValidationError) {
|
|
230
186
|
return terminalHostedError(400, "invalid_reminder", boundedMessage(error.message));
|
|
231
187
|
}
|
|
188
|
+
// Transient CP apply/fetch failures must remain retryable.
|
|
232
189
|
throw error;
|
|
233
190
|
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
dispatched = yield adapter.dispatch({
|
|
255
|
-
channelId: input.delivery.channelId,
|
|
256
|
-
eventType: input.delivery.eventType,
|
|
257
|
-
payload: input.delivery.payload,
|
|
258
|
-
deliveryId: input.delivery.deliveryId,
|
|
259
|
-
args,
|
|
260
|
-
mailboxContinuationKey: input.delivery.mailboxContinuationKey,
|
|
261
|
-
platformHandoff: input.delivery.platformHandoff,
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
catch (error) {
|
|
265
|
-
const mapped = mappedAdmissionFailure(error);
|
|
266
|
-
if (mapped !== undefined) {
|
|
267
|
-
return mapped;
|
|
268
|
-
}
|
|
269
|
-
return {
|
|
270
|
-
response: terminalHostedError(500, "agent_admission_threw", boundedMessage(error instanceof Error ? error.message : String(error))),
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
if (!dispatched.ok) {
|
|
274
|
-
return {
|
|
275
|
-
response: terminalHostedError(dispatched.status >= 400 ? dispatched.status : 502, "channel_dispatch_failed", yield channelDispatchDetail(dispatched)),
|
|
276
|
-
};
|
|
191
|
+
}
|
|
192
|
+
if (input.fireReminder === undefined) {
|
|
193
|
+
return transientHostedError(503, "reminder_dispatch_unavailable", "This guest has no reminder runner wired for hosted admission.");
|
|
194
|
+
}
|
|
195
|
+
const payload = parseHostedReminderFirePayload(delivery.payload);
|
|
196
|
+
if (payload === undefined) {
|
|
197
|
+
return terminalHostedError(400, "invalid_reminder_payload", "Expected reminder descriptor or legacy payload { reminderId, fireCount }.");
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
const result = await input.fireReminder(payload.reminderId, payload.fireCount);
|
|
201
|
+
const outcome = result.outcome === "noop" ? "skip" : "task";
|
|
202
|
+
return Response.json({
|
|
203
|
+
ok: true,
|
|
204
|
+
v: HOSTED_DELIVERY_PROTOCOL_VERSION,
|
|
205
|
+
outcome,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
if (error instanceof UnknownReminderError) {
|
|
210
|
+
return terminalHostedError(404, "unknown_reminder", boundedMessage(error.message));
|
|
277
211
|
}
|
|
278
|
-
|
|
279
|
-
|
|
212
|
+
if (error instanceof ReminderValidationError) {
|
|
213
|
+
return terminalHostedError(400, "invalid_reminder", boundedMessage(error.message));
|
|
280
214
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
215
|
+
throw error;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
async function runAdmission(input, adapter) {
|
|
219
|
+
const background = [];
|
|
220
|
+
let captured;
|
|
221
|
+
const capturingArgs = {
|
|
222
|
+
...input.args,
|
|
223
|
+
send: async (message, options = {}) => {
|
|
224
|
+
if (captured !== undefined) {
|
|
225
|
+
throw new HostedSendLimitExceeded();
|
|
285
226
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
227
|
+
captured = { message, options };
|
|
228
|
+
return createDeferredChannelSession();
|
|
229
|
+
},
|
|
230
|
+
waitUntil: promise => {
|
|
231
|
+
background.push(promise);
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
const args = adapter.prepareArgs?.(capturingArgs) ?? capturingArgs;
|
|
235
|
+
let dispatched;
|
|
236
|
+
try {
|
|
237
|
+
dispatched = await adapter.dispatch({
|
|
238
|
+
channelId: input.delivery.channelId,
|
|
239
|
+
eventType: input.delivery.eventType,
|
|
240
|
+
payload: input.delivery.payload,
|
|
241
|
+
deliveryId: input.delivery.deliveryId,
|
|
242
|
+
args,
|
|
243
|
+
mailboxContinuationKey: input.delivery.mailboxContinuationKey,
|
|
244
|
+
platformHandoff: input.delivery.platformHandoff,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
const mapped = mappedAdmissionFailure(error);
|
|
249
|
+
if (mapped !== undefined) {
|
|
250
|
+
return mapped;
|
|
304
251
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
252
|
+
return {
|
|
253
|
+
response: terminalHostedError(500, "agent_admission_threw", boundedMessage(error instanceof Error ? error.message : String(error))),
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
if (!dispatched.ok) {
|
|
257
|
+
return {
|
|
258
|
+
response: terminalHostedError(dispatched.status >= 400 ? dispatched.status : 502, "channel_dispatch_failed", await channelDispatchDetail(dispatched)),
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
try {
|
|
262
|
+
await Promise.all(background);
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
const mapped = mappedAdmissionFailure(error);
|
|
266
|
+
if (mapped !== undefined) {
|
|
267
|
+
return mapped;
|
|
312
268
|
}
|
|
313
|
-
const rejection = outcome === "skip" ? yield handlerRejection(dispatched) : undefined;
|
|
314
269
|
return {
|
|
315
|
-
response:
|
|
270
|
+
response: terminalHostedError(503, "background_dispatch_failed", boundedMessage(error instanceof Error ? error.message : String(error))),
|
|
316
271
|
};
|
|
317
|
-
}
|
|
272
|
+
}
|
|
273
|
+
if (captured !== undefined) {
|
|
274
|
+
return {
|
|
275
|
+
response: Response.json({
|
|
276
|
+
ok: true,
|
|
277
|
+
v: HOSTED_DELIVERY_PROTOCOL_VERSION,
|
|
278
|
+
outcome: "send",
|
|
279
|
+
}),
|
|
280
|
+
pendingSend: {
|
|
281
|
+
channelId: input.delivery.channelId,
|
|
282
|
+
message: captured.message,
|
|
283
|
+
options: captured.options,
|
|
284
|
+
mailboxContinuationKey: input.delivery.mailboxContinuationKey,
|
|
285
|
+
},
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
// A "send" tag with nothing captured means the channel's send bypassed the
|
|
289
|
+
// capture stub, so there is nothing for the control plane to execute.
|
|
290
|
+
const outcome = dispatchOutcome(dispatched);
|
|
291
|
+
if (outcome === undefined || outcome === "send") {
|
|
292
|
+
return {
|
|
293
|
+
response: terminalHostedError(502, "channel_outcome_missing"),
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
const rejection = outcome === "skip" ? await handlerRejection(dispatched) : undefined;
|
|
297
|
+
return {
|
|
298
|
+
response: Response.json({
|
|
299
|
+
ok: true,
|
|
300
|
+
v: HOSTED_DELIVERY_PROTOCOL_VERSION,
|
|
301
|
+
outcome,
|
|
302
|
+
...(rejection === undefined ? {} : { rejection, engineVersion: packageVersion() }),
|
|
303
|
+
}),
|
|
304
|
+
};
|
|
318
305
|
}
|
|
319
306
|
/** Handler 4xx on a skip. Benign skips (nothing to do) have no status. */
|
|
320
|
-
function handlerRejection(response) {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
return undefined;
|
|
326
|
-
}
|
|
327
|
-
const record = body;
|
|
328
|
-
if (record.skipped !== true) {
|
|
329
|
-
return undefined;
|
|
330
|
-
}
|
|
331
|
-
return parseHostedAdmissionHandlerRejection({
|
|
332
|
-
reason: record.reason,
|
|
333
|
-
status: record.status,
|
|
334
|
-
});
|
|
307
|
+
async function handlerRejection(response) {
|
|
308
|
+
try {
|
|
309
|
+
const body = (await response.clone().json());
|
|
310
|
+
if (typeof body !== "object" || body === null || Array.isArray(body)) {
|
|
311
|
+
return undefined;
|
|
335
312
|
}
|
|
336
|
-
|
|
313
|
+
const record = body;
|
|
314
|
+
if (record.skipped !== true) {
|
|
337
315
|
return undefined;
|
|
338
316
|
}
|
|
339
|
-
|
|
317
|
+
return parseHostedAdmissionHandlerRejection({
|
|
318
|
+
reason: record.reason,
|
|
319
|
+
status: record.status,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
catch {
|
|
323
|
+
return undefined;
|
|
324
|
+
}
|
|
340
325
|
}
|
|
341
326
|
function withServerTiming(response, durationMs, guestNetwork, latency) {
|
|
342
327
|
const parts = [`agent_sdk;desc="hosted";dur=${Math.max(0, durationMs).toFixed(1)}`];
|
|
@@ -391,15 +376,14 @@ function logGuestNetworkWait(phase, stats) {
|
|
|
391
376
|
console.info(`[bdk] guest network ${stats.outcome} phase=${phase} waitMs=${String(stats.waitMs)} probes=${String(stats.probeAttempts)}`);
|
|
392
377
|
}
|
|
393
378
|
export function registerHostedDeliveryRoute(input) {
|
|
394
|
-
var _a, _b;
|
|
395
379
|
const pending = new Map();
|
|
396
380
|
const admissions = new Map();
|
|
397
381
|
const activeOwners = new Map();
|
|
398
|
-
const pendingTtlMs = 10 *
|
|
382
|
+
const pendingTtlMs = 10 * 60_000;
|
|
399
383
|
/** Keep an in-flight owner turn addressable for status polls. */
|
|
400
|
-
const ownerTurnPendingTtlMs = 12 * 60 *
|
|
401
|
-
const waitForNetwork =
|
|
402
|
-
const consumeBoundSecrets =
|
|
384
|
+
const ownerTurnPendingTtlMs = 12 * 60 * 60_000;
|
|
385
|
+
const waitForNetwork = input.waitForGuestNetwork ?? (() => waitForGuestNetworkReady());
|
|
386
|
+
const consumeBoundSecrets = input.consumeBoundSecrets ?? (() => consumeHostedBoundSecrets());
|
|
403
387
|
/**
|
|
404
388
|
* Close the bind-file handoff before anything else touches the request.
|
|
405
389
|
* A surviving secret is retryable: the control plane re-binds and the next
|
|
@@ -411,9 +395,9 @@ export function registerHostedDeliveryRoute(input) {
|
|
|
411
395
|
? undefined
|
|
412
396
|
: transientHostedError(503, consumed.code, boundedMessage(consumed.message));
|
|
413
397
|
};
|
|
414
|
-
const finishNetworkWait = (phase) =>
|
|
398
|
+
const finishNetworkWait = async (phase) => {
|
|
415
399
|
try {
|
|
416
|
-
const timing = guestNetworkStatsFromWait(
|
|
400
|
+
const timing = guestNetworkStatsFromWait(await waitForNetwork());
|
|
417
401
|
logGuestNetworkWait(phase, timing);
|
|
418
402
|
return { timing };
|
|
419
403
|
}
|
|
@@ -430,7 +414,7 @@ export function registerHostedDeliveryRoute(input) {
|
|
|
430
414
|
response: transientHostedError(503, GUEST_NETWORK_UNAVAILABLE, boundedMessage(message)),
|
|
431
415
|
};
|
|
432
416
|
}
|
|
433
|
-
}
|
|
417
|
+
};
|
|
434
418
|
const pruneExpired = () => {
|
|
435
419
|
const now = Date.now();
|
|
436
420
|
for (const [token, item] of pending) {
|
|
@@ -444,50 +428,48 @@ export function registerHostedDeliveryRoute(input) {
|
|
|
444
428
|
}
|
|
445
429
|
}
|
|
446
430
|
};
|
|
447
|
-
const runAdmissionOperation = (delivery, definition) =>
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
return yield responseToReply(finish(terminalHostedError(404, "channel_not_found", `No channel named "${delivery.channelId}" is mounted.`)));
|
|
463
|
-
}
|
|
464
|
-
const admitted = yield dispatchHostedAdmission({
|
|
465
|
-
delivery,
|
|
466
|
-
definition,
|
|
467
|
-
args: input.buildHandlerArgs(delivery.channelId),
|
|
468
|
-
});
|
|
469
|
-
if (admitted.pendingSend === undefined) {
|
|
470
|
-
return yield responseToReply(finish(admitted.response));
|
|
471
|
-
}
|
|
472
|
-
pruneExpired();
|
|
473
|
-
const admissionToken = randomBytes(24).toString("hex");
|
|
474
|
-
pending.set(admissionToken, {
|
|
475
|
-
send: admitted.pendingSend,
|
|
476
|
-
channelKind: delivery.channelKind,
|
|
477
|
-
expiresAt: Date.now() + pendingTtlMs,
|
|
478
|
-
deliveryId: delivery.deliveryId,
|
|
479
|
-
});
|
|
480
|
-
return yield responseToReply(finish(Response.json({
|
|
481
|
-
ok: true,
|
|
482
|
-
v: HOSTED_DELIVERY_PROTOCOL_VERSION,
|
|
483
|
-
outcome: "send",
|
|
484
|
-
admissionToken,
|
|
485
|
-
})));
|
|
431
|
+
const runAdmissionOperation = async (delivery, definition) => afterHostedWork(input.flushOtel, async () => {
|
|
432
|
+
const startedAt = performance.now();
|
|
433
|
+
let guestNetwork;
|
|
434
|
+
const finish = (response) => withServerTiming(response, performance.now() - startedAt, guestNetwork);
|
|
435
|
+
try {
|
|
436
|
+
const network = await finishNetworkWait("admission");
|
|
437
|
+
guestNetwork = network.timing;
|
|
438
|
+
if (network.response !== undefined) {
|
|
439
|
+
return await responseToReply(finish(network.response));
|
|
440
|
+
}
|
|
441
|
+
if (isHostedReminderAdmission(delivery)) {
|
|
442
|
+
return await responseToReply(finish(await dispatchHostedReminderAdmission(input, delivery)));
|
|
443
|
+
}
|
|
444
|
+
if (definition === undefined) {
|
|
445
|
+
return await responseToReply(finish(terminalHostedError(404, "channel_not_found", `No channel named "${delivery.channelId}" is mounted.`)));
|
|
486
446
|
}
|
|
487
|
-
|
|
488
|
-
|
|
447
|
+
const admitted = await dispatchHostedAdmission({
|
|
448
|
+
delivery,
|
|
449
|
+
definition,
|
|
450
|
+
args: input.buildHandlerArgs(delivery.channelId),
|
|
451
|
+
});
|
|
452
|
+
if (admitted.pendingSend === undefined) {
|
|
453
|
+
return await responseToReply(finish(admitted.response));
|
|
489
454
|
}
|
|
490
|
-
|
|
455
|
+
pruneExpired();
|
|
456
|
+
const admissionToken = randomBytes(24).toString("hex");
|
|
457
|
+
pending.set(admissionToken, {
|
|
458
|
+
send: admitted.pendingSend,
|
|
459
|
+
channelKind: delivery.channelKind,
|
|
460
|
+
expiresAt: Date.now() + pendingTtlMs,
|
|
461
|
+
deliveryId: delivery.deliveryId,
|
|
462
|
+
});
|
|
463
|
+
return await responseToReply(finish(Response.json({
|
|
464
|
+
ok: true,
|
|
465
|
+
v: HOSTED_DELIVERY_PROTOCOL_VERSION,
|
|
466
|
+
outcome: "send",
|
|
467
|
+
admissionToken,
|
|
468
|
+
})));
|
|
469
|
+
}
|
|
470
|
+
catch (error) {
|
|
471
|
+
return await responseToReply(finish(terminalHostedError(503, "internal_error", boundedMessage(error instanceof Error ? error.message : String(error)))));
|
|
472
|
+
}
|
|
491
473
|
});
|
|
492
474
|
// Hosted callers reach this only through Anyrun's signed pod-port URL.
|
|
493
475
|
// The marker is a second, route-specific fence distinct from channel auth.
|
|
@@ -505,86 +487,83 @@ export function registerHostedDeliveryRoute(input) {
|
|
|
505
487
|
method: "POST",
|
|
506
488
|
pattern: `${input.base}${HOSTED_ADMISSION_PATH}`,
|
|
507
489
|
auth: [auth],
|
|
508
|
-
handler: (request) =>
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
490
|
+
handler: async (request) => afterHostedWork(input.flushOtel, async () => {
|
|
491
|
+
const startedAt = performance.now();
|
|
492
|
+
const finish = (response) => withServerTiming(response, performance.now() - startedAt);
|
|
493
|
+
const unconsumed = finishBoundSecrets();
|
|
494
|
+
if (unconsumed !== undefined) {
|
|
495
|
+
return finish(unconsumed);
|
|
496
|
+
}
|
|
497
|
+
const rawAdmission = await readJsonObject(request);
|
|
498
|
+
const delivery = parseHostedAdmission(rawAdmission);
|
|
499
|
+
if (delivery === undefined) {
|
|
500
|
+
const rawKeys = typeof rawAdmission === "object" &&
|
|
501
|
+
rawAdmission !== null &&
|
|
502
|
+
!Array.isArray(rawAdmission)
|
|
503
|
+
? Object.keys(rawAdmission)
|
|
504
|
+
: [];
|
|
505
|
+
console.info(`[bdk] hosted admission rejected: envelope failed to parse keys=${JSON.stringify(rawKeys)} hasManagedAutomation=${String(rawKeys.includes("managedAutomation"))}`);
|
|
506
|
+
return finish(terminalHostedError(400, "invalid_hosted_admission", "Expected a supported Agent SDK hosted-admission envelope."));
|
|
507
|
+
}
|
|
508
|
+
pruneExpired();
|
|
509
|
+
const existing = admissions.get(delivery.deliveryId);
|
|
510
|
+
if (delivery.mode === "status") {
|
|
511
|
+
if (existing === undefined) {
|
|
512
|
+
return finish(transientHostedError(409, "hosted_admission_unavailable", "No hosted admission is in flight for this delivery."));
|
|
516
513
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
514
|
+
return existing.settledReply === undefined
|
|
515
|
+
? finish(Response.json({
|
|
516
|
+
ok: true,
|
|
517
|
+
v: HOSTED_DELIVERY_PROTOCOL_VERSION,
|
|
518
|
+
outcome: "running",
|
|
519
|
+
}))
|
|
520
|
+
: responseFromReply(existing.settledReply);
|
|
521
|
+
}
|
|
522
|
+
if (existing !== undefined) {
|
|
523
|
+
if (existing.settledReply !== undefined && isTransientRetryReply(existing.settledReply)) {
|
|
524
|
+
admissions.delete(delivery.deliveryId);
|
|
527
525
|
}
|
|
528
|
-
|
|
529
|
-
const existing = admissions.get(delivery.deliveryId);
|
|
530
|
-
if (delivery.mode === "status") {
|
|
531
|
-
if (existing === undefined) {
|
|
532
|
-
return finish(transientHostedError(409, "hosted_admission_unavailable", "No hosted admission is in flight for this delivery."));
|
|
533
|
-
}
|
|
526
|
+
else {
|
|
534
527
|
return existing.settledReply === undefined
|
|
535
528
|
? finish(Response.json({
|
|
536
529
|
ok: true,
|
|
537
530
|
v: HOSTED_DELIVERY_PROTOCOL_VERSION,
|
|
538
|
-
outcome: "
|
|
531
|
+
outcome: "started",
|
|
539
532
|
}))
|
|
540
533
|
: responseFromReply(existing.settledReply);
|
|
541
534
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
};
|
|
575
|
-
admissions.set(delivery.deliveryId, operation);
|
|
576
|
-
const quickReply = yield Promise.race([
|
|
577
|
-
execution,
|
|
578
|
-
new Promise(resolve => setImmediate(() => resolve(undefined))),
|
|
579
|
-
]);
|
|
580
|
-
if (quickReply !== undefined) {
|
|
581
|
-
return responseFromReply(quickReply);
|
|
582
|
-
}
|
|
583
|
-
return finish(Response.json({
|
|
584
|
-
ok: true,
|
|
585
|
-
v: HOSTED_DELIVERY_PROTOCOL_VERSION,
|
|
586
|
-
outcome: "started",
|
|
587
|
-
}));
|
|
535
|
+
}
|
|
536
|
+
console.info(`[bdk] hosted admission received deliveryId=${delivery.deliveryId} channelId=${delivery.channelId} channelKind=${delivery.channelKind} eventType=${delivery.eventType} sessionMode=${delivery.sessionMode} managedAutomation=${delivery.managedAutomation === undefined ? "<absent>" : `automationUuid=${delivery.managedAutomation.automationUuid} mcpServerNames=${String(delivery.managedAutomation.mcpServerNames.length)} slackChannels=${delivery.managedAutomation.slackChannels === undefined ? "<absent>" : JSON.stringify(delivery.managedAutomation.slackChannels)}`}`);
|
|
537
|
+
recordHostedManagedAutomation(delivery);
|
|
538
|
+
const reminder = isHostedReminderAdmission(delivery);
|
|
539
|
+
const definition = reminder
|
|
540
|
+
? undefined
|
|
541
|
+
: input.channels.find(candidate => candidate.id === delivery.channelId)?.definition;
|
|
542
|
+
if (!reminder && definition === undefined) {
|
|
543
|
+
return finish(terminalHostedError(404, "channel_not_found", `No channel named "${delivery.channelId}" is mounted.`));
|
|
544
|
+
}
|
|
545
|
+
let operation;
|
|
546
|
+
const execution = runAdmissionOperation(delivery, definition).then(reply => {
|
|
547
|
+
operation.settledReply = reply;
|
|
548
|
+
operation.expiresAt = Date.now() + pendingTtlMs;
|
|
549
|
+
return reply;
|
|
550
|
+
});
|
|
551
|
+
operation = {
|
|
552
|
+
execution,
|
|
553
|
+
expiresAt: Date.now() + ownerTurnPendingTtlMs,
|
|
554
|
+
};
|
|
555
|
+
admissions.set(delivery.deliveryId, operation);
|
|
556
|
+
const quickReply = await Promise.race([
|
|
557
|
+
execution,
|
|
558
|
+
new Promise(resolve => setImmediate(() => resolve(undefined))),
|
|
559
|
+
]);
|
|
560
|
+
if (quickReply !== undefined) {
|
|
561
|
+
return responseFromReply(quickReply);
|
|
562
|
+
}
|
|
563
|
+
return finish(Response.json({
|
|
564
|
+
ok: true,
|
|
565
|
+
v: HOSTED_DELIVERY_PROTOCOL_VERSION,
|
|
566
|
+
outcome: "started",
|
|
588
567
|
}));
|
|
589
568
|
}),
|
|
590
569
|
});
|
|
@@ -592,303 +571,356 @@ export function registerHostedDeliveryRoute(input) {
|
|
|
592
571
|
method: "POST",
|
|
593
572
|
pattern: `${input.base}${HOSTED_EXECUTION_PATH}`,
|
|
594
573
|
auth: [auth],
|
|
595
|
-
handler: (request) =>
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
574
|
+
handler: async (request) => afterHostedWork(input.flushOtel, async () => {
|
|
575
|
+
const startedAt = performance.now();
|
|
576
|
+
let guestNetwork;
|
|
577
|
+
let latencySnapshot;
|
|
578
|
+
const finish = (response) => withServerTiming(response, performance.now() - startedAt, guestNetwork, latencySnapshot);
|
|
579
|
+
const unconsumed = finishBoundSecrets();
|
|
580
|
+
if (unconsumed !== undefined) {
|
|
581
|
+
return finish(unconsumed);
|
|
582
|
+
}
|
|
583
|
+
const execution = parseHostedExecution(await readJsonObject(request));
|
|
584
|
+
if (execution === undefined) {
|
|
585
|
+
return finish(terminalHostedError(400, "invalid_hosted_execution", "Expected a supported Agent SDK hosted-execution envelope."));
|
|
586
|
+
}
|
|
587
|
+
pruneExpired();
|
|
588
|
+
const admitted = pending.get(execution.admissionToken);
|
|
589
|
+
if (admitted === undefined) {
|
|
590
|
+
return finish(transientHostedError(409, "hosted_admission_unavailable", "The hosted admission token is missing or expired."));
|
|
591
|
+
}
|
|
592
|
+
if (admitted.sessionPublicId !== undefined &&
|
|
593
|
+
admitted.sessionPublicId !== execution.sessionPublicId) {
|
|
594
|
+
return finish(transientHostedError(409, "hosted_admission_session_mismatch", "The hosted admission token is already bound to another session."));
|
|
595
|
+
}
|
|
596
|
+
if (execution.mode === "start" &&
|
|
597
|
+
admitted.settledReply !== undefined &&
|
|
598
|
+
isTransientRetryReply(admitted.settledReply)) {
|
|
599
|
+
delete admitted.settledReply;
|
|
600
|
+
delete admitted.execution;
|
|
601
|
+
}
|
|
602
|
+
if (execution.mode === "status" ||
|
|
603
|
+
(execution.mode === "start" && admitted.execution !== undefined)) {
|
|
604
|
+
if (admitted.settledReply !== undefined) {
|
|
605
|
+
return responseFromReply(admitted.settledReply);
|
|
618
606
|
}
|
|
619
|
-
if (execution
|
|
620
|
-
|
|
621
|
-
isTransientRetryReply(admitted.settledReply)) {
|
|
622
|
-
delete admitted.settledReply;
|
|
623
|
-
delete admitted.execution;
|
|
607
|
+
if (admitted.execution === undefined) {
|
|
608
|
+
return finish(transientHostedError(409, "hosted_admission_unavailable", "The hosted admission token has no owner turn in flight."));
|
|
624
609
|
}
|
|
625
|
-
if (execution.mode === "
|
|
626
|
-
(execution.mode === "start" && admitted.execution !== undefined)) {
|
|
627
|
-
if (admitted.settledReply !== undefined) {
|
|
628
|
-
return responseFromReply(admitted.settledReply);
|
|
629
|
-
}
|
|
630
|
-
if (admitted.execution === undefined) {
|
|
631
|
-
return finish(transientHostedError(409, "hosted_admission_unavailable", "The hosted admission token has no owner turn in flight."));
|
|
632
|
-
}
|
|
633
|
-
if (execution.mode === "start") {
|
|
634
|
-
return finish(Response.json({
|
|
635
|
-
ok: true,
|
|
636
|
-
v: HOSTED_DELIVERY_PROTOCOL_VERSION,
|
|
637
|
-
outcome: "started",
|
|
638
|
-
}));
|
|
639
|
-
}
|
|
610
|
+
if (execution.mode === "start") {
|
|
640
611
|
return finish(Response.json({
|
|
641
612
|
ok: true,
|
|
642
613
|
v: HOSTED_DELIVERY_PROTOCOL_VERSION,
|
|
643
|
-
outcome: "
|
|
614
|
+
outcome: "started",
|
|
644
615
|
}));
|
|
645
616
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
buildHandlerArgs: input.buildHandlerArgs,
|
|
659
|
-
});
|
|
660
|
-
return finish(Response.json(Object.assign({ ok: true, v: HOSTED_DELIVERY_PROTOCOL_VERSION }, enqueueOutcome)));
|
|
617
|
+
return finish(Response.json({
|
|
618
|
+
ok: true,
|
|
619
|
+
v: HOSTED_DELIVERY_PROTOCOL_VERSION,
|
|
620
|
+
outcome: "running",
|
|
621
|
+
}));
|
|
622
|
+
}
|
|
623
|
+
admitted.sessionPublicId = execution.sessionPublicId;
|
|
624
|
+
if (execution.mode === "enqueue") {
|
|
625
|
+
const network = await finishNetworkWait("execution");
|
|
626
|
+
guestNetwork = network.timing;
|
|
627
|
+
if (network.response !== undefined) {
|
|
628
|
+
return finish(network.response);
|
|
661
629
|
}
|
|
662
|
-
|
|
663
|
-
|
|
630
|
+
const enqueueOutcome = await enqueueIntoActiveOwner({
|
|
631
|
+
activeOwners,
|
|
632
|
+
sessionPublicId: execution.sessionPublicId,
|
|
633
|
+
deliveryId: admitted.deliveryId,
|
|
634
|
+
send: admitted.send,
|
|
635
|
+
buildHandlerArgs: input.buildHandlerArgs,
|
|
636
|
+
});
|
|
637
|
+
return finish(Response.json({
|
|
638
|
+
ok: true,
|
|
639
|
+
v: HOSTED_DELIVERY_PROTOCOL_VERSION,
|
|
640
|
+
...enqueueOutcome,
|
|
641
|
+
}));
|
|
642
|
+
}
|
|
643
|
+
if (admitted.execution === undefined) {
|
|
644
|
+
admitted.expiresAt = Date.now() + ownerTurnPendingTtlMs;
|
|
645
|
+
}
|
|
646
|
+
admitted.execution ??= afterHostedWork(input.flushOtel, async () => {
|
|
647
|
+
const network = await finishNetworkWait("execution");
|
|
648
|
+
guestNetwork = network.timing;
|
|
649
|
+
if (network.response !== undefined) {
|
|
650
|
+
return await responseToReply(finish(network.response));
|
|
664
651
|
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
}
|
|
671
|
-
const startedAt = performance.now();
|
|
672
|
-
const executionId = hostedExecutionDiagId(execution.admissionToken);
|
|
673
|
-
const sinks = Object.assign(Object.assign(Object.assign(Object.assign({}, (input.stateRoot === undefined ? {} : { stateRoot: input.stateRoot })), (input.persistSessionRun === undefined
|
|
652
|
+
const startedAt = performance.now();
|
|
653
|
+
const executionId = hostedExecutionDiagId(execution.admissionToken);
|
|
654
|
+
const sinks = {
|
|
655
|
+
...(input.stateRoot === undefined ? {} : { stateRoot: input.stateRoot }),
|
|
656
|
+
...(input.persistSessionRun === undefined
|
|
674
657
|
? {}
|
|
675
|
-
: { persistSessionRun: input.persistSessionRun })
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
658
|
+
: { persistSessionRun: input.persistSessionRun }),
|
|
659
|
+
...(input.flushStartLog === undefined ? {} : { flushStartLog: input.flushStartLog }),
|
|
660
|
+
...(input.snapshotLogs === undefined ? {} : { snapshotLogs: input.snapshotLogs }),
|
|
661
|
+
};
|
|
662
|
+
const writeDiag = async (fields) => {
|
|
663
|
+
const classification = fields.failureCode === undefined
|
|
664
|
+
? undefined
|
|
665
|
+
: hostedFailureClassification(fields.failureCode);
|
|
666
|
+
await flushHostedExecutionRecord(sinks, {
|
|
667
|
+
executionId,
|
|
668
|
+
sessionPublicId: execution.sessionPublicId,
|
|
669
|
+
sessionId: fields.sessionId,
|
|
670
|
+
turnStatus: fields.turnStatus,
|
|
671
|
+
durationMs: Math.max(0, Math.round(performance.now() - startedAt)),
|
|
672
|
+
...(fields.message === undefined ? {} : { message: fields.message }),
|
|
673
|
+
...(fields.abortReason === undefined ? {} : { abortReason: fields.abortReason }),
|
|
674
|
+
failureCode: fields.failureCode,
|
|
675
|
+
...(fields.errorCode === undefined ? {} : { errorCode: fields.errorCode }),
|
|
676
|
+
classification,
|
|
677
|
+
...(fields.error === undefined ? {} : { error: fields.error }),
|
|
689
678
|
});
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
yield Promise.allSettled([...owner.inflightInjects]);
|
|
727
|
-
}
|
|
728
|
-
// Failed turns drain too: their record/continuation updates must
|
|
729
|
-
// survive the park just like a finished turn's.
|
|
730
|
-
yield (_a = input.drainSessionDurability) === null || _a === void 0 ? void 0 : _a.call(input, session.id);
|
|
731
|
-
drainAt = hostedExecutionNow();
|
|
732
|
-
const consumedDeliveryIds = [
|
|
733
|
-
owner.primaryDeliveryId,
|
|
734
|
-
...owner.acceptedDeliveryIds,
|
|
735
|
-
];
|
|
736
|
-
if (consumedDeliveryIds.length > HOSTED_MAX_CONSUMED_DELIVERY_IDS) {
|
|
737
|
-
throw new Error(`hosted execute consumedDeliveryIds length ${String(consumedDeliveryIds.length)} exceeds cap ${String(HOSTED_MAX_CONSUMED_DELIVERY_IDS)}`);
|
|
738
|
-
}
|
|
739
|
-
// Evict before the reply: TAS parks and hibernates this process
|
|
740
|
-
// as soon as the POST returns. A leftover SDK handle freezes a
|
|
741
|
-
// dead Connect/HTTP2 session that the next wake then reuses.
|
|
742
|
-
evictHostedSdkSessions(input.evictSdkSession, session.id, execution.sessionPublicId);
|
|
743
|
-
const hostedFailure = outcome.status === "finished"
|
|
744
|
-
? undefined
|
|
745
|
-
: hostedFailureForUnfinishedTurn(outcome);
|
|
746
|
-
yield writeDiag(Object.assign({ sessionId: session.id, turnStatus: outcome.status, message: outcome.errorMessage, abortReason: abortReasonFromTurnStatus(outcome.status, outcome.cancellationReason), failureCode: hostedFailure === null || hostedFailure === void 0 ? void 0 : hostedFailure.error }, (outcome.errorCode === undefined ? {} : { errorCode: outcome.errorCode })));
|
|
747
|
-
const reply = hostedFailure !== undefined
|
|
748
|
-
? {
|
|
749
|
-
status: 503,
|
|
750
|
-
body: Object.assign({ ok: false, error: hostedFailure.error, retry: hostedFailure.retry, classification: hostedFailureClassification(hostedFailure.error), turnStatus: outcome.status, message: outcome.errorMessage }, (outcome.errorCode === undefined
|
|
751
|
-
? {}
|
|
752
|
-
: { errorCode: outcome.errorCode })),
|
|
753
|
-
}
|
|
754
|
-
: {
|
|
755
|
-
status: 200,
|
|
756
|
-
body: {
|
|
757
|
-
ok: true,
|
|
758
|
-
v: HOSTED_DELIVERY_PROTOCOL_VERSION,
|
|
759
|
-
outcome: "send",
|
|
760
|
-
consumedDeliveryIds,
|
|
761
|
-
},
|
|
762
|
-
};
|
|
763
|
-
// Finalize as late as possible so `post_drain` and `total`
|
|
764
|
-
// include eviction + diag write after durability drain.
|
|
765
|
-
latencySnapshot = finalizeHostedExecutionLatency({
|
|
766
|
-
completionAt,
|
|
767
|
-
drainAt,
|
|
768
|
-
endedAt: hostedExecutionNow(),
|
|
679
|
+
};
|
|
680
|
+
// Claim the file before the turn runs. If a later status request
|
|
681
|
+
// fails, the host reads this record while the turn may still be
|
|
682
|
+
// running; the marker prevents it from surfacing the previous
|
|
683
|
+
// delivery's terminal record.
|
|
684
|
+
await writeDiag({
|
|
685
|
+
sessionId: "",
|
|
686
|
+
turnStatus: HOSTED_EXECUTION_DIAG_RUNNING_STATUS,
|
|
687
|
+
});
|
|
688
|
+
let sessionId = "";
|
|
689
|
+
const owner = {
|
|
690
|
+
primaryDeliveryId: admitted.deliveryId,
|
|
691
|
+
acceptedDeliveryIds: [],
|
|
692
|
+
accepting: true,
|
|
693
|
+
inflightInjects: new Set(),
|
|
694
|
+
enqueueResults: new Map(),
|
|
695
|
+
};
|
|
696
|
+
activeOwners.set(execution.sessionPublicId, owner);
|
|
697
|
+
return await runWithHostedExecutionLatency({ channelKind: admitted.channelKind }, async () => {
|
|
698
|
+
let completionAt;
|
|
699
|
+
let drainAt;
|
|
700
|
+
try {
|
|
701
|
+
const args = input.buildHandlerArgs(admitted.send.channelId, execution.sessionPublicId);
|
|
702
|
+
const options = {
|
|
703
|
+
...admitted.send.options,
|
|
704
|
+
mailboxContinuation: {
|
|
705
|
+
key: admitted.send.mailboxContinuationKey,
|
|
706
|
+
},
|
|
707
|
+
};
|
|
708
|
+
const session = input.startSend === undefined
|
|
709
|
+
? await args.send(admitted.send.message, options)
|
|
710
|
+
: await input.startSend({
|
|
711
|
+
args,
|
|
712
|
+
message: admitted.send.message,
|
|
713
|
+
options,
|
|
714
|
+
sessionPublicId: execution.sessionPublicId,
|
|
769
715
|
});
|
|
770
|
-
|
|
716
|
+
sessionId = session.id;
|
|
717
|
+
// The pre-turn claim used an empty sessionId. Stamp the
|
|
718
|
+
// engine id now so a dashboard / session-view poll that
|
|
719
|
+
// only has the factory `ses_…` can follow `session-events/`.
|
|
720
|
+
await writeDiag({
|
|
721
|
+
sessionId,
|
|
722
|
+
turnStatus: HOSTED_EXECUTION_DIAG_RUNNING_STATUS,
|
|
723
|
+
});
|
|
724
|
+
const outcome = await refreshStartLogWhile(sinks, execution.sessionPublicId, () => session.waitForCompletion());
|
|
725
|
+
completionAt = hostedExecutionNow();
|
|
726
|
+
// Status is the owner turn. waitForCompletion still waited
|
|
727
|
+
// for any drained successor so this process is not parked
|
|
728
|
+
// mid-follow-up; a successor failure must not 503-retry the
|
|
729
|
+
// owner after satellites already ran.
|
|
730
|
+
// Close acceptance at the turn boundary, before durability
|
|
731
|
+
// work creates an idle-but-still-addressable window.
|
|
732
|
+
owner.accepting = false;
|
|
733
|
+
if (owner.inflightInjects.size > 0) {
|
|
734
|
+
await Promise.allSettled([...owner.inflightInjects]);
|
|
771
735
|
}
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
// during post-drain work; otherwise collapse to endedAt.
|
|
783
|
-
latencySnapshot = finalizeHostedExecutionLatency({
|
|
784
|
-
completionAt: completionAt !== null && completionAt !== void 0 ? completionAt : endedAt,
|
|
785
|
-
drainAt: drainAt !== null && drainAt !== void 0 ? drainAt : endedAt,
|
|
786
|
-
endedAt,
|
|
787
|
-
});
|
|
788
|
-
throw error;
|
|
736
|
+
// Failed turns drain too: their record/continuation updates must
|
|
737
|
+
// survive the park just like a finished turn's.
|
|
738
|
+
await input.drainSessionDurability?.(session.id);
|
|
739
|
+
drainAt = hostedExecutionNow();
|
|
740
|
+
const consumedDeliveryIds = [
|
|
741
|
+
owner.primaryDeliveryId,
|
|
742
|
+
...owner.acceptedDeliveryIds,
|
|
743
|
+
];
|
|
744
|
+
if (consumedDeliveryIds.length > HOSTED_MAX_CONSUMED_DELIVERY_IDS) {
|
|
745
|
+
throw new Error(`hosted execute consumedDeliveryIds length ${String(consumedDeliveryIds.length)} exceeds cap ${String(HOSTED_MAX_CONSUMED_DELIVERY_IDS)}`);
|
|
789
746
|
}
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
747
|
+
// Evict before the reply: TAS parks and hibernates this process
|
|
748
|
+
// as soon as the POST returns. A leftover SDK handle freezes a
|
|
749
|
+
// dead Connect/HTTP2 session that the next wake then reuses.
|
|
750
|
+
evictHostedSdkSessions(input.evictSdkSession, session.id, execution.sessionPublicId);
|
|
751
|
+
const hostedFailure = outcome.status === "finished"
|
|
752
|
+
? undefined
|
|
753
|
+
: hostedFailureForUnfinishedTurn(outcome);
|
|
754
|
+
await writeDiag({
|
|
755
|
+
sessionId: session.id,
|
|
756
|
+
turnStatus: outcome.status,
|
|
757
|
+
message: outcome.errorMessage,
|
|
758
|
+
abortReason: abortReasonFromTurnStatus(outcome.status, outcome.cancellationReason),
|
|
759
|
+
failureCode: hostedFailure?.error,
|
|
760
|
+
...(outcome.errorCode === undefined ? {} : { errorCode: outcome.errorCode }),
|
|
761
|
+
});
|
|
762
|
+
const reply = hostedFailure !== undefined
|
|
763
|
+
? {
|
|
764
|
+
status: 503,
|
|
765
|
+
body: {
|
|
766
|
+
ok: false,
|
|
767
|
+
error: hostedFailure.error,
|
|
768
|
+
retry: hostedFailure.retry,
|
|
769
|
+
classification: hostedFailureClassification(hostedFailure.error),
|
|
770
|
+
turnStatus: outcome.status,
|
|
771
|
+
message: outcome.errorMessage,
|
|
772
|
+
...(outcome.errorCode === undefined
|
|
773
|
+
? {}
|
|
774
|
+
: { errorCode: outcome.errorCode }),
|
|
775
|
+
},
|
|
793
776
|
}
|
|
777
|
+
: {
|
|
778
|
+
status: 200,
|
|
779
|
+
body: {
|
|
780
|
+
ok: true,
|
|
781
|
+
v: HOSTED_DELIVERY_PROTOCOL_VERSION,
|
|
782
|
+
outcome: "send",
|
|
783
|
+
consumedDeliveryIds,
|
|
784
|
+
},
|
|
785
|
+
};
|
|
786
|
+
// Finalize as late as possible so `post_drain` and `total`
|
|
787
|
+
// include eviction + diag write after durability drain.
|
|
788
|
+
latencySnapshot = finalizeHostedExecutionLatency({
|
|
789
|
+
completionAt,
|
|
790
|
+
drainAt,
|
|
791
|
+
endedAt: hostedExecutionNow(),
|
|
792
|
+
});
|
|
793
|
+
return await responseToReply(finish(Response.json(reply.body, { status: reply.status })));
|
|
794
|
+
}
|
|
795
|
+
catch (error) {
|
|
796
|
+
owner.accepting = false;
|
|
797
|
+
if (owner.inflightInjects.size > 0) {
|
|
798
|
+
await Promise.allSettled([...owner.inflightInjects]);
|
|
794
799
|
}
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
}, error => {
|
|
801
|
-
admitted.settledReply = {
|
|
802
|
-
status: 503,
|
|
803
|
-
body: {
|
|
804
|
-
ok: false,
|
|
805
|
-
error: "internal_error",
|
|
806
|
-
retry: HOSTED_GUEST_RETRY_TERMINAL,
|
|
807
|
-
classification: hostedFailureClassification("internal_error"),
|
|
800
|
+
evictHostedSdkSessions(input.evictSdkSession, sessionId, execution.sessionPublicId);
|
|
801
|
+
const thrownErrorCode = describeErrorCode(error);
|
|
802
|
+
await writeDiag({
|
|
803
|
+
sessionId: "",
|
|
804
|
+
turnStatus: "error",
|
|
808
805
|
message: error instanceof Error ? error.message : String(error),
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
806
|
+
abortReason: "execute_throw",
|
|
807
|
+
failureCode: "internal_error",
|
|
808
|
+
error,
|
|
809
|
+
...(thrownErrorCode === undefined ? {} : { errorCode: thrownErrorCode }),
|
|
810
|
+
});
|
|
811
|
+
const endedAt = hostedExecutionNow();
|
|
812
|
+
// Preserve completion/drain marks when the failure happened
|
|
813
|
+
// during post-drain work; otherwise collapse to endedAt.
|
|
814
|
+
latencySnapshot = finalizeHostedExecutionLatency({
|
|
815
|
+
completionAt: completionAt ?? endedAt,
|
|
816
|
+
drainAt: drainAt ?? endedAt,
|
|
817
|
+
endedAt,
|
|
818
|
+
});
|
|
819
|
+
throw error;
|
|
821
820
|
}
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
}
|
|
821
|
+
finally {
|
|
822
|
+
if (activeOwners.get(execution.sessionPublicId) === owner) {
|
|
823
|
+
activeOwners.delete(execution.sessionPublicId);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
});
|
|
827
|
+
}).then(reply => {
|
|
828
|
+
admitted.settledReply = reply;
|
|
829
|
+
admitted.expiresAt = Date.now() + pendingTtlMs;
|
|
830
|
+
return reply;
|
|
831
|
+
}, error => {
|
|
832
|
+
admitted.settledReply = {
|
|
833
|
+
status: 503,
|
|
834
|
+
body: {
|
|
835
|
+
ok: false,
|
|
836
|
+
error: "internal_error",
|
|
837
|
+
retry: HOSTED_GUEST_RETRY_TERMINAL,
|
|
838
|
+
classification: hostedFailureClassification("internal_error"),
|
|
839
|
+
message: error instanceof Error ? error.message : String(error),
|
|
840
|
+
},
|
|
841
|
+
};
|
|
842
|
+
admitted.expiresAt = Date.now() + pendingTtlMs;
|
|
843
|
+
return admitted.settledReply;
|
|
844
|
+
});
|
|
845
|
+
if (execution.mode === "start") {
|
|
846
|
+
const quickReply = await Promise.race([
|
|
847
|
+
admitted.execution,
|
|
848
|
+
new Promise(resolve => setImmediate(() => resolve(undefined))),
|
|
849
|
+
]);
|
|
850
|
+
if (quickReply !== undefined) {
|
|
851
|
+
return responseFromReply(quickReply);
|
|
827
852
|
}
|
|
828
|
-
return finish(
|
|
829
|
-
|
|
853
|
+
return finish(Response.json({
|
|
854
|
+
ok: true,
|
|
855
|
+
v: HOSTED_DELIVERY_PROTOCOL_VERSION,
|
|
856
|
+
outcome: "started",
|
|
857
|
+
}));
|
|
858
|
+
}
|
|
859
|
+
return finish(terminalHostedError(400, "invalid_hosted_execution", "Owner execution requires start or status mode."));
|
|
830
860
|
}),
|
|
831
861
|
});
|
|
832
862
|
}
|
|
833
|
-
function enqueueIntoActiveOwner(input) {
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
863
|
+
async function enqueueIntoActiveOwner(input) {
|
|
864
|
+
const owner = input.activeOwners.get(input.sessionPublicId);
|
|
865
|
+
if (owner === undefined || !owner.accepting) {
|
|
866
|
+
return { outcome: "not_active" };
|
|
867
|
+
}
|
|
868
|
+
const existing = owner.enqueueResults.get(input.deliveryId);
|
|
869
|
+
if (existing !== undefined) {
|
|
870
|
+
const shared = await existing;
|
|
871
|
+
if (shared.outcome === "enqueued" || shared.outcome === "not_active") {
|
|
872
|
+
return { outcome: shared.outcome };
|
|
838
873
|
}
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
874
|
+
return { outcome: "not_active" };
|
|
875
|
+
}
|
|
876
|
+
let resolveResult;
|
|
877
|
+
const resultPromise = new Promise(resolve => {
|
|
878
|
+
resolveResult = resolve;
|
|
879
|
+
});
|
|
880
|
+
owner.enqueueResults.set(input.deliveryId, resultPromise);
|
|
881
|
+
// Capacity includes the primary delivery id.
|
|
882
|
+
if (1 + owner.acceptedDeliveryIds.length >= HOSTED_MAX_CONSUMED_DELIVERY_IDS) {
|
|
883
|
+
const outcome = { outcome: "not_active" };
|
|
884
|
+
resolveResult(outcome);
|
|
885
|
+
return outcome;
|
|
886
|
+
}
|
|
887
|
+
// Reserve before send so concurrent enqueues cannot oversubscribe.
|
|
888
|
+
owner.acceptedDeliveryIds.push(input.deliveryId);
|
|
889
|
+
const inject = (async () => {
|
|
890
|
+
try {
|
|
891
|
+
const args = input.buildHandlerArgs(input.send.channelId, input.sessionPublicId);
|
|
892
|
+
const enqueueOptions = {
|
|
893
|
+
...input.send.options,
|
|
894
|
+
mailboxContinuation: {
|
|
895
|
+
key: input.send.mailboxContinuationKey,
|
|
896
|
+
},
|
|
897
|
+
hostedEnqueueOnly: true,
|
|
898
|
+
};
|
|
899
|
+
const session = await args.send(input.send.message, enqueueOptions);
|
|
900
|
+
if (session.coalesced !== true) {
|
|
901
|
+
throw new HostedEnqueueNotActiveError(input.sessionPublicId);
|
|
844
902
|
}
|
|
845
|
-
|
|
903
|
+
resolveResult({ outcome: "enqueued" });
|
|
846
904
|
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
owner.enqueueResults.set(input.deliveryId, resultPromise);
|
|
852
|
-
// Capacity includes the primary delivery id.
|
|
853
|
-
if (1 + owner.acceptedDeliveryIds.length >= HOSTED_MAX_CONSUMED_DELIVERY_IDS) {
|
|
854
|
-
const outcome = { outcome: "not_active" };
|
|
855
|
-
resolveResult(outcome);
|
|
856
|
-
return outcome;
|
|
857
|
-
}
|
|
858
|
-
// Reserve before send so concurrent enqueues cannot oversubscribe.
|
|
859
|
-
owner.acceptedDeliveryIds.push(input.deliveryId);
|
|
860
|
-
const inject = (() => __awaiter(this, void 0, void 0, function* () {
|
|
861
|
-
try {
|
|
862
|
-
const args = input.buildHandlerArgs(input.send.channelId, input.sessionPublicId);
|
|
863
|
-
const enqueueOptions = Object.assign(Object.assign({}, input.send.options), { mailboxContinuation: {
|
|
864
|
-
key: input.send.mailboxContinuationKey,
|
|
865
|
-
}, hostedEnqueueOnly: true });
|
|
866
|
-
const session = yield args.send(input.send.message, enqueueOptions);
|
|
867
|
-
if (session.coalesced !== true) {
|
|
868
|
-
throw new HostedEnqueueNotActiveError(input.sessionPublicId);
|
|
869
|
-
}
|
|
870
|
-
resolveResult({ outcome: "enqueued" });
|
|
905
|
+
catch (error) {
|
|
906
|
+
const idx = owner.acceptedDeliveryIds.lastIndexOf(input.deliveryId);
|
|
907
|
+
if (idx >= 0) {
|
|
908
|
+
owner.acceptedDeliveryIds.splice(idx, 1);
|
|
871
909
|
}
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
owner.acceptedDeliveryIds.splice(idx, 1);
|
|
876
|
-
}
|
|
877
|
-
resolveResult({ outcome: "not_active" });
|
|
878
|
-
if (!(error instanceof HostedEnqueueNotActiveError)) {
|
|
879
|
-
console.warn(`[bdk] hosted enqueue inject failed deliveryId=${input.deliveryId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
880
|
-
}
|
|
910
|
+
resolveResult({ outcome: "not_active" });
|
|
911
|
+
if (!(error instanceof HostedEnqueueNotActiveError)) {
|
|
912
|
+
console.warn(`[bdk] hosted enqueue inject failed deliveryId=${input.deliveryId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
881
913
|
}
|
|
882
|
-
}))();
|
|
883
|
-
owner.inflightInjects.add(inject);
|
|
884
|
-
try {
|
|
885
|
-
yield inject;
|
|
886
914
|
}
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
}
|
|
915
|
+
})();
|
|
916
|
+
owner.inflightInjects.add(inject);
|
|
917
|
+
try {
|
|
918
|
+
await inject;
|
|
919
|
+
}
|
|
920
|
+
finally {
|
|
921
|
+
owner.inflightInjects.delete(inject);
|
|
922
|
+
}
|
|
923
|
+
return await resultPromise;
|
|
892
924
|
}
|
|
893
925
|
function evictHostedSdkSessions(evict, ...ids) {
|
|
894
926
|
if (evict === undefined) {
|
|
@@ -940,29 +972,27 @@ function hostedFailureForUnfinishedTurn(outcome) {
|
|
|
940
972
|
}
|
|
941
973
|
return { error: "turn_failed", retry: HOSTED_GUEST_RETRY_TERMINAL };
|
|
942
974
|
}
|
|
943
|
-
function afterHostedWork(flushOtel, work) {
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
endActiveHttpSpan(result.status);
|
|
949
|
-
}
|
|
950
|
-
return result;
|
|
951
|
-
}
|
|
952
|
-
catch (error) {
|
|
953
|
-
const status = statusForThrownRequestError(error);
|
|
954
|
-
endActiveHttpSpan(status, status >= 500 ? error : undefined);
|
|
955
|
-
throw error;
|
|
975
|
+
async function afterHostedWork(flushOtel, work) {
|
|
976
|
+
try {
|
|
977
|
+
const result = await work();
|
|
978
|
+
if (result instanceof Response) {
|
|
979
|
+
endActiveHttpSpan(result.status);
|
|
956
980
|
}
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
981
|
+
return result;
|
|
982
|
+
}
|
|
983
|
+
catch (error) {
|
|
984
|
+
const status = statusForThrownRequestError(error);
|
|
985
|
+
endActiveHttpSpan(status, status >= 500 ? error : undefined);
|
|
986
|
+
throw error;
|
|
987
|
+
}
|
|
988
|
+
finally {
|
|
989
|
+
if (flushOtel !== undefined) {
|
|
990
|
+
try {
|
|
991
|
+
await flushOtel();
|
|
992
|
+
}
|
|
993
|
+
catch {
|
|
994
|
+
// Soft-fail: exporter failure must not change hosted HTTP.
|
|
965
995
|
}
|
|
966
996
|
}
|
|
967
|
-
}
|
|
997
|
+
}
|
|
968
998
|
}
|