@cursor/july 0.1.93 → 0.1.94
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/AGENTS.md +8 -20
- package/README.md +4 -26
- package/dist/channels/slack/attachments.js +2 -2
- package/dist/channels/slack/dispatch.d.ts +0 -7
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +4 -7
- package/dist/channels/slack/eval-directive.d.ts +5 -12
- package/dist/channels/slack/eval-directive.d.ts.map +1 -1
- package/dist/channels/slack/eval-directive.js +8 -19
- package/dist/channels/slack/index.d.ts +0 -6
- package/dist/channels/slack/index.d.ts.map +1 -1
- package/dist/channels/slack/index.js +0 -6
- package/dist/channels/slack/setup.d.ts +4 -4
- package/dist/channels/slack/setup.d.ts.map +1 -1
- package/dist/channels/slack/setup.js +8 -15
- package/dist/channels/slack/slack-channel.d.ts +6 -13
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +15 -101
- package/dist/channels/slack/types.d.ts +12 -79
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/channels/slack/types.js +1 -15
- package/dist/client.d.ts +14 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +12 -0
- package/dist/connections.d.ts +18 -9
- package/dist/connections.d.ts.map +1 -1
- package/dist/connections.js +17 -8
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +4 -4
- package/dist/docs/assets/{app.CjWU-x0z.js → app.CFDEas4I.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.DU3U2Ij2.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.Cxy8ySFQ.js → VPLocalSearchBox.B1IIYpYS.js} +1 -1
- package/dist/docs/assets/chunks/{theme.Dvq1Bktu.js → theme.Ct4NSiLm.js} +2 -2
- package/dist/docs/assets/concepts.md.lwAgBIMI.js +1 -0
- package/dist/docs/assets/{deployment.md.DoLFAzfm.js → deployment.md.D9msOFOW.js} +3 -8
- package/dist/docs/assets/{deployment.md.DoLFAzfm.lean.js → deployment.md.D9msOFOW.lean.js} +1 -1
- package/dist/docs/assets/{guides_agent-to-agent.md.B3JIaAqz.js → guides_agent-to-agent.md.BDb0t1QV.js} +1 -1
- package/dist/docs/assets/guides_cloud-runtime.md.CkYbjnAX.js +9 -0
- package/dist/docs/assets/guides_cloud-runtime.md.CkYbjnAX.lean.js +1 -0
- package/dist/docs/assets/{guides_convert-automation.md.Bboisykk.js → guides_convert-automation.md.B4sjlodG.js} +1 -1
- package/dist/docs/assets/{guides_github.md.DqJhuaN1.js → guides_github.md.Cnh2mL4a.js} +1 -1
- package/dist/docs/assets/{guides_mcp-oauth.md.CJvrXtkN.js → guides_mcp-oauth.md.DPYmBCbV.js} +7 -9
- package/dist/docs/assets/{guides_mcp-oauth.md.CJvrXtkN.lean.js → guides_mcp-oauth.md.DPYmBCbV.lean.js} +1 -1
- package/dist/docs/assets/{guides_slack.md.mqeNKs84.js → guides_slack.md.C32HsdKk.js} +5 -11
- package/dist/docs/assets/guides_slack.md.C32HsdKk.lean.js +1 -0
- package/dist/docs/assets/index.md.DRakGHFe.js +5 -0
- package/dist/docs/assets/{index.md.B-lVR4wT.lean.js → index.md.DRakGHFe.lean.js} +1 -1
- package/dist/docs/assets/{quickstart.md.BrmfrrIr.js → quickstart.md.Nj_LjW_a.js} +1 -1
- package/dist/docs/assets/{reference_cli.md.D9KESDsD.js → reference_cli.md.Cw6_ICYG.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.DB6SsN6U.js → reference_connections.md.BH8Oc0D0.js} +5 -5
- package/dist/docs/assets/{reference_connections.md.DB6SsN6U.lean.js → reference_connections.md.BH8Oc0D0.lean.js} +1 -1
- package/dist/docs/assets/{reference_hooks.md.BxN87gCw.js → reference_hooks.md.a8BJxMR5.js} +1 -1
- package/dist/docs/assets/reference_http-api.md.D89k1mdm.js +11 -0
- package/dist/docs/assets/reference_http-api.md.D89k1mdm.lean.js +1 -0
- package/dist/docs/assets/reference_project-layout.md.Bv4KOtlB.js +19 -0
- package/dist/docs/assets/{reference_skills.md.BFW9retM.js → reference_skills.md.8son6Hjm.js} +3 -3
- package/dist/docs/assets/{reference_subagents.md.Xoav0AII.js → reference_subagents.md.CfsIloPm.js} +1 -1
- package/dist/docs/assets/{reference_tools.md.DuKvkYWG.js → reference_tools.md.BHeXn2id.js} +3 -3
- package/dist/docs/assets/{reference_tools.md.DuKvkYWG.lean.js → reference_tools.md.BHeXn2id.lean.js} +1 -1
- package/dist/docs/assets/{templates_pr-autofixer.md.R4K_qytS.js → templates_pr-autofixer.md.DU7dQpor.js} +2 -2
- package/dist/docs/assets/{templates_pr-autofixer.md.R4K_qytS.lean.js → templates_pr-autofixer.md.DU7dQpor.lean.js} +1 -1
- package/dist/docs/assets/{templates_security-reviewer.md.ByFyRta2.js → templates_security-reviewer.md.CTa7u_l1.js} +2 -2
- package/dist/docs/assets/{templates_security-reviewer.md.ByFyRta2.lean.js → templates_security-reviewer.md.CTa7u_l1.lean.js} +1 -1
- package/dist/docs/assets/troubleshooting.md.Ctv3T8C2.js +1 -0
- package/dist/docs/building-with-agents.html +4 -4
- package/dist/docs/concepts.html +5 -5
- package/dist/docs/concepts.md +1 -0
- package/dist/docs/deployment.html +7 -12
- package/dist/docs/deployment.md +1 -20
- package/dist/docs/design/agsh.md +406 -0
- package/dist/docs/evals.html +4 -4
- package/dist/docs/guides/agent-to-agent.html +6 -6
- package/dist/docs/guides/agent-to-agent.md +2 -2
- package/dist/docs/guides/cloud-runtime.html +6 -6
- package/dist/docs/guides/cloud-runtime.md +1 -0
- package/dist/docs/guides/convert-automation.html +6 -6
- package/dist/docs/guides/convert-automation.md +1 -1
- package/dist/docs/guides/github.html +6 -6
- package/dist/docs/guides/github.md +4 -4
- package/dist/docs/guides/human-in-the-loop.html +4 -4
- package/dist/docs/guides/mcp-oauth.html +11 -13
- package/dist/docs/guides/mcp-oauth.md +10 -18
- package/dist/docs/guides/opentelemetry.html +5 -5
- package/dist/docs/guides/slack.html +9 -15
- package/dist/docs/guides/slack.md +9 -46
- package/dist/docs/guides/webhooks.html +4 -4
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +4 -4
- package/dist/docs/index.html +6 -6
- package/dist/docs/index.md +0 -28
- package/dist/docs/llms-full.txt +712 -2830
- package/dist/docs/llms.txt +2 -16
- package/dist/docs/quickstart.html +6 -6
- package/dist/docs/quickstart.md +2 -3
- package/dist/docs/reference/agent-config.html +4 -4
- package/dist/docs/reference/artifacts.html +4 -4
- package/dist/docs/reference/channels.html +4 -4
- package/dist/docs/reference/cli.html +6 -6
- package/dist/docs/reference/cli.md +2 -1
- package/dist/docs/reference/connections.html +9 -9
- package/dist/docs/reference/connections.md +15 -11
- package/dist/docs/reference/hooks.html +6 -6
- package/dist/docs/reference/hooks.md +2 -3
- package/dist/docs/reference/http-api.html +6 -6
- package/dist/docs/reference/http-api.md +8 -0
- package/dist/docs/reference/instructions.html +4 -4
- package/dist/docs/reference/playground.html +4 -4
- package/dist/docs/reference/project-layout.html +8 -6
- package/dist/docs/reference/project-layout.md +5 -1
- package/dist/docs/reference/prompt.html +4 -4
- package/dist/docs/reference/schedules.html +4 -4
- package/dist/docs/reference/sessions.html +4 -4
- package/dist/docs/reference/skills.html +7 -7
- package/dist/docs/reference/subagents.html +6 -6
- package/dist/docs/reference/subagents.md +2 -2
- package/dist/docs/reference/tools.html +7 -7
- package/dist/docs/reference/tools.md +19 -3
- package/dist/docs/scaffolding-agents.html +4 -4
- package/dist/docs/storage.html +4 -4
- package/dist/docs/templates/agentic-owners.html +4 -4
- package/dist/docs/templates/demo.html +4 -4
- package/dist/docs/templates/pr-autofixer.html +6 -6
- package/dist/docs/templates/pr-autofixer.md +4 -3
- package/dist/docs/templates/security-reviewer.html +5 -5
- package/dist/docs/templates/security-reviewer.md +2 -3
- package/dist/docs/templates/triage.html +4 -4
- package/dist/docs/troubleshooting.html +5 -5
- package/dist/docs/troubleshooting.md +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/advertise-tools.d.ts +11 -0
- package/dist/internal/advertise-tools.d.ts.map +1 -1
- package/dist/internal/advertise-tools.js +47 -9
- package/dist/internal/cli-mcp-oauth.d.ts.map +1 -1
- package/dist/internal/cli-mcp-oauth.js +7 -4
- package/dist/internal/convert-automation/convert-workflow.d.ts.map +1 -1
- package/dist/internal/convert-automation/convert-workflow.js +26 -15
- package/dist/internal/convert-automation/slug.d.ts +0 -2
- package/dist/internal/convert-automation/slug.d.ts.map +1 -1
- package/dist/internal/convert-automation/slug.js +0 -8
- package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
- package/dist/internal/cursor/account-mcp.js +5 -1
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +88 -13
- package/dist/internal/hosted-delivery.d.ts.map +1 -1
- package/dist/internal/hosted-delivery.js +22 -9
- package/dist/internal/mcp-endpoint.js +3 -3
- package/dist/internal/mcp-host.d.ts +8 -7
- package/dist/internal/mcp-host.d.ts.map +1 -1
- package/dist/internal/mcp-host.js +8 -7
- package/dist/internal/peer-connections.d.ts.map +1 -1
- package/dist/internal/peer-connections.js +5 -1
- package/dist/internal/playground/static.d.ts +0 -3
- package/dist/internal/playground/static.d.ts.map +1 -1
- package/dist/internal/resolved-connections.d.ts.map +1 -1
- package/dist/internal/resolved-connections.js +5 -7
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +113 -172
- package/dist/internal/session-engine.d.ts +45 -10
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +208 -65
- package/dist/internal/tool-catalog.d.ts +31 -0
- package/dist/internal/tool-catalog.d.ts.map +1 -0
- package/dist/internal/tool-catalog.js +67 -0
- package/dist/playground/assets/{index-D9MFzhNE.js → index-B3JCyigB.js} +1 -1
- package/dist/playground/index.html +1 -1
- package/dist/types.d.ts +72 -23
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +19 -0
- package/docs/README.md +0 -28
- package/docs/concepts.md +1 -0
- package/docs/deployment.md +1 -20
- package/docs/design/agsh.md +406 -0
- package/docs/guides/agent-to-agent.md +2 -2
- package/docs/guides/cloud-runtime.md +1 -0
- package/docs/guides/convert-automation.md +1 -1
- package/docs/guides/github.md +4 -4
- package/docs/guides/mcp-oauth.md +10 -18
- package/docs/guides/slack.md +10 -47
- package/docs/quickstart.md +2 -3
- package/docs/reference/cli.md +2 -1
- package/docs/reference/connections.md +15 -11
- package/docs/reference/hooks.md +2 -3
- package/docs/reference/http-api.md +8 -0
- package/docs/reference/project-layout.md +5 -1
- package/docs/reference/subagents.md +2 -2
- package/docs/reference/tools.md +19 -3
- package/docs/templates/pr-autofixer.md +4 -3
- package/docs/templates/security-reviewer.md +2 -3
- package/docs/troubleshooting.md +2 -2
- package/package.json +9 -2
- package/skills/create-agent/SKILL.md +6 -13
- package/skills/debug/SKILL.md +2 -4
- package/skills/evals/SKILL.md +1 -1
- package/skills/framework-map/SKILL.md +3 -2
- package/skills/mcp-auth/SKILL.md +10 -13
- package/skills/setup-slack/SKILL.md +21 -137
- package/src/channels/slack/attachments.ts +2 -2
- package/src/channels/slack/dispatch.ts +2 -16
- package/src/channels/slack/eval-directive.ts +8 -27
- package/src/channels/slack/index.ts +0 -6
- package/src/channels/slack/setup.ts +8 -15
- package/src/channels/slack/slack-channel.ts +14 -125
- package/src/channels/slack/types.ts +12 -96
- package/src/client.ts +23 -0
- package/src/connections.ts +20 -7
- package/src/index.ts +2 -0
- package/src/internal/advertise-tools.ts +45 -7
- package/src/internal/cli-mcp-oauth.ts +6 -4
- package/src/internal/convert-automation/convert-workflow.ts +29 -17
- package/src/internal/convert-automation/slug.ts +0 -9
- package/src/internal/cursor/account-mcp.ts +4 -1
- package/src/internal/discovery.ts +104 -13
- package/src/internal/fixtures/units-server.ts +52 -0
- package/src/internal/hosted-delivery.ts +60 -28
- package/src/internal/mcp-endpoint.ts +3 -3
- package/src/internal/mcp-host.ts +8 -7
- package/src/internal/peer-connections.ts +4 -1
- package/src/internal/playground/static.ts +1 -3
- package/src/internal/resolved-connections.ts +8 -10
- package/src/internal/server.ts +151 -251
- package/src/internal/session-engine.ts +254 -69
- package/src/internal/tool-catalog.ts +106 -0
- package/src/types.ts +90 -23
- package/templates/pr-autofixer/agent/channels/slack.ts +8 -2
- package/templates/triage/README.md +2 -1
- package/templates/triage/overlays/jira/agent/mcp-connections/tracker.ts +0 -1
- package/templates/triage/overlays/linear/agent/mcp-connections/tracker.ts +0 -1
- package/dist/channels/slack/cursor-account.d.ts +0 -87
- package/dist/channels/slack/cursor-account.d.ts.map +0 -1
- package/dist/channels/slack/cursor-account.js +0 -100
- package/dist/docs/assets/chunks/@localSearchIndexroot.ChpIC3Zy.js +0 -1
- package/dist/docs/assets/concepts.md.F6AiPorA.js +0 -1
- package/dist/docs/assets/example-agents_approval-buddy.md.DmezILPg.js +0 -10
- package/dist/docs/assets/example-agents_approval-buddy.md.DmezILPg.lean.js +0 -1
- package/dist/docs/assets/example-agents_benny.md.B0kwY7D_.js +0 -5
- package/dist/docs/assets/example-agents_benny.md.B0kwY7D_.lean.js +0 -1
- package/dist/docs/assets/example-agents_bugbot.md.BRGMi9O2.js +0 -11
- package/dist/docs/assets/example-agents_bugbot.md.BRGMi9O2.lean.js +0 -1
- package/dist/docs/assets/example-agents_codebase-wiki.md.BBNw9Ekr.js +0 -8
- package/dist/docs/assets/example-agents_codebase-wiki.md.BBNw9Ekr.lean.js +0 -1
- package/dist/docs/assets/example-agents_codeowners-review.md.Bfta-lBU.js +0 -8
- package/dist/docs/assets/example-agents_codeowners-review.md.Bfta-lBU.lean.js +0 -1
- package/dist/docs/assets/example-agents_concierge.md.BzB2b20R.js +0 -22
- package/dist/docs/assets/example-agents_concierge.md.BzB2b20R.lean.js +0 -1
- package/dist/docs/assets/example-agents_index.md.ChBp0AX6.js +0 -2
- package/dist/docs/assets/example-agents_index.md.ChBp0AX6.lean.js +0 -1
- package/dist/docs/assets/example-agents_knowledge-base.md.CrA85ig-.js +0 -11
- package/dist/docs/assets/example-agents_knowledge-base.md.CrA85ig-.lean.js +0 -1
- package/dist/docs/assets/example-agents_oncall.md.DK4XkYTd.js +0 -10
- package/dist/docs/assets/example-agents_oncall.md.DK4XkYTd.lean.js +0 -1
- package/dist/docs/assets/example-agents_security-reviewer.md.74pPpWYj.js +0 -19
- package/dist/docs/assets/example-agents_security-reviewer.md.74pPpWYj.lean.js +0 -1
- package/dist/docs/assets/example-agents_slack-agent.md.D7Kdj5BV.js +0 -5
- package/dist/docs/assets/example-agents_slack-agent.md.D7Kdj5BV.lean.js +0 -1
- package/dist/docs/assets/example-agents_weather-agent.md.CaGpmw3Y.js +0 -25
- package/dist/docs/assets/example-agents_weather-agent.md.CaGpmw3Y.lean.js +0 -1
- package/dist/docs/assets/guides_cloud-runtime.md.BnvjPiia.js +0 -9
- package/dist/docs/assets/guides_cloud-runtime.md.BnvjPiia.lean.js +0 -1
- package/dist/docs/assets/guides_slack.md.mqeNKs84.lean.js +0 -1
- package/dist/docs/assets/index.md.B-lVR4wT.js +0 -5
- package/dist/docs/assets/reference_http-api.md.C68BERYr.js +0 -11
- package/dist/docs/assets/reference_http-api.md.C68BERYr.lean.js +0 -1
- package/dist/docs/assets/reference_project-layout.md.WN9nwJht.js +0 -17
- package/dist/docs/assets/troubleshooting.md.vCWwvqcJ.js +0 -1
- package/dist/docs/example-agents/approval-buddy.html +0 -36
- package/dist/docs/example-agents/approval-buddy.md +0 -266
- package/dist/docs/example-agents/benny.html +0 -31
- package/dist/docs/example-agents/benny.md +0 -173
- package/dist/docs/example-agents/bugbot.html +0 -37
- package/dist/docs/example-agents/bugbot.md +0 -229
- package/dist/docs/example-agents/codebase-wiki.html +0 -34
- package/dist/docs/example-agents/codebase-wiki.md +0 -167
- package/dist/docs/example-agents/codeowners-review.html +0 -34
- package/dist/docs/example-agents/codeowners-review.md +0 -192
- package/dist/docs/example-agents/concierge.html +0 -48
- package/dist/docs/example-agents/concierge.md +0 -200
- package/dist/docs/example-agents/index.html +0 -28
- package/dist/docs/example-agents/index.md +0 -99
- package/dist/docs/example-agents/knowledge-base.html +0 -37
- package/dist/docs/example-agents/knowledge-base.md +0 -168
- package/dist/docs/example-agents/oncall.html +0 -36
- package/dist/docs/example-agents/oncall.md +0 -212
- package/dist/docs/example-agents/security-reviewer.html +0 -45
- package/dist/docs/example-agents/security-reviewer.md +0 -265
- package/dist/docs/example-agents/slack-agent.html +0 -31
- package/dist/docs/example-agents/slack-agent.md +0 -142
- package/dist/docs/example-agents/weather-agent.html +0 -51
- package/dist/docs/example-agents/weather-agent.md +0 -297
- package/dist/internal/cursor-slack-relay.d.ts +0 -96
- package/dist/internal/cursor-slack-relay.d.ts.map +0 -1
- package/dist/internal/cursor-slack-relay.js +0 -176
- package/docs/example-agents/approval-buddy.md +0 -271
- package/docs/example-agents/benny.md +0 -178
- package/docs/example-agents/bugbot.md +0 -234
- package/docs/example-agents/codebase-wiki.md +0 -172
- package/docs/example-agents/codeowners-review.md +0 -197
- package/docs/example-agents/concierge.md +0 -205
- package/docs/example-agents/index.md +0 -104
- package/docs/example-agents/knowledge-base.md +0 -173
- package/docs/example-agents/oncall.md +0 -217
- package/docs/example-agents/security-reviewer.md +0 -270
- package/docs/example-agents/slack-agent.md +0 -147
- package/docs/example-agents/weather-agent.md +0 -302
- package/src/channels/slack/cursor-account.ts +0 -202
- package/src/internal/cursor-slack-relay.ts +0 -249
- /package/dist/docs/assets/{concepts.md.F6AiPorA.lean.js → concepts.md.lwAgBIMI.lean.js} +0 -0
- /package/dist/docs/assets/{guides_agent-to-agent.md.B3JIaAqz.lean.js → guides_agent-to-agent.md.BDb0t1QV.lean.js} +0 -0
- /package/dist/docs/assets/{guides_convert-automation.md.Bboisykk.lean.js → guides_convert-automation.md.B4sjlodG.lean.js} +0 -0
- /package/dist/docs/assets/{guides_github.md.DqJhuaN1.lean.js → guides_github.md.Cnh2mL4a.lean.js} +0 -0
- /package/dist/docs/assets/{quickstart.md.BrmfrrIr.lean.js → quickstart.md.Nj_LjW_a.lean.js} +0 -0
- /package/dist/docs/assets/{reference_cli.md.D9KESDsD.lean.js → reference_cli.md.Cw6_ICYG.lean.js} +0 -0
- /package/dist/docs/assets/{reference_hooks.md.BxN87gCw.lean.js → reference_hooks.md.a8BJxMR5.lean.js} +0 -0
- /package/dist/docs/assets/{reference_project-layout.md.WN9nwJht.lean.js → reference_project-layout.md.Bv4KOtlB.lean.js} +0 -0
- /package/dist/docs/assets/{reference_skills.md.BFW9retM.lean.js → reference_skills.md.8son6Hjm.lean.js} +0 -0
- /package/dist/docs/assets/{reference_subagents.md.Xoav0AII.lean.js → reference_subagents.md.CfsIloPm.lean.js} +0 -0
- /package/dist/docs/assets/{troubleshooting.md.vCWwvqcJ.lean.js → troubleshooting.md.Ctv3T8C2.lean.js} +0 -0
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
type ConnectionTransport,
|
|
50
50
|
DEFAULT_MODEL,
|
|
51
51
|
DIRECT_TOOL_CALL_CHANNEL_ID,
|
|
52
|
+
type DiscoveredTool,
|
|
52
53
|
type HookHandler,
|
|
53
54
|
type HostContext,
|
|
54
55
|
type HttpChannelDefinition,
|
|
@@ -117,6 +118,7 @@ import {
|
|
|
117
118
|
newContinuationKey,
|
|
118
119
|
newSessionId,
|
|
119
120
|
newToolCallId,
|
|
121
|
+
parseContinuationToken,
|
|
120
122
|
} from "./ids.js";
|
|
121
123
|
import { validateToolInput } from "./json-schema.js";
|
|
122
124
|
import { McpHost } from "./mcp-host.js";
|
|
@@ -136,7 +138,7 @@ import { SessionStore } from "./session-store.js";
|
|
|
136
138
|
import { syncSkillsToStore } from "./skills-sync.js";
|
|
137
139
|
import { StorageCoordinator } from "./storage-coordinator.js";
|
|
138
140
|
import type { FrameworkSessionStore } from "./storage-roles.js";
|
|
139
|
-
import { decideToolCall } from "./tool-policy.js";
|
|
141
|
+
import { decideToolCall, resolveEffect } from "./tool-policy.js";
|
|
140
142
|
import { normalizeToolResult, toolCallErrorMessage } from "./tool-result.js";
|
|
141
143
|
import {
|
|
142
144
|
type EstimateTurnCostFn,
|
|
@@ -197,6 +199,30 @@ export class ToolNotDirectlyCallableError extends Error {
|
|
|
197
199
|
}
|
|
198
200
|
}
|
|
199
201
|
|
|
202
|
+
export class InvalidContinuationTokenError extends Error {
|
|
203
|
+
constructor(detail: string) {
|
|
204
|
+
super(`Invalid continuation token: ${detail}`);
|
|
205
|
+
this.name = "InvalidContinuationTokenError";
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* A session-bound direct call whose harness cwd cannot be materialized and
|
|
211
|
+
* whose effect is not read: a write tool may rely on ctx.workspaceDir being
|
|
212
|
+
* the real session workspace, so it fails typed instead of silently running
|
|
213
|
+
* in a scratch directory.
|
|
214
|
+
*/
|
|
215
|
+
export class WorkspaceUnavailableError extends Error {
|
|
216
|
+
constructor(toolName: string, cause: unknown) {
|
|
217
|
+
super(
|
|
218
|
+
`Session workspace unavailable for tool "${toolName}": ${
|
|
219
|
+
cause instanceof Error ? cause.message : String(cause)
|
|
220
|
+
}`
|
|
221
|
+
);
|
|
222
|
+
this.name = "WorkspaceUnavailableError";
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
200
226
|
export class ToolInputError extends Error {
|
|
201
227
|
constructor(args: { toolName: string; detail: string }) {
|
|
202
228
|
super(`Invalid input for tool "${args.toolName}": ${args.detail}`);
|
|
@@ -474,7 +500,10 @@ export class SessionEngine {
|
|
|
474
500
|
// resolves them; the host-side MCP registry starts with the concrete
|
|
475
501
|
// connections and gains the rest via setResolvedConnections.
|
|
476
502
|
this.mcpHost = new McpHost(
|
|
477
|
-
|
|
503
|
+
[
|
|
504
|
+
...options.project.agent.connections,
|
|
505
|
+
...(options.project.agent.hostConnections ?? []),
|
|
506
|
+
].filter(
|
|
478
507
|
(connection) => !isSymbolicConnectionTransport(connection.transport)
|
|
479
508
|
)
|
|
480
509
|
);
|
|
@@ -2148,27 +2177,17 @@ export class SessionEngine {
|
|
|
2148
2177
|
* Connection names a cloud turn can only reach through the host connection
|
|
2149
2178
|
* bridge on the tool MCP endpoint: filtered account connections without a
|
|
2150
2179
|
* public bridge URL, and host-OAuth connections whose tokens live on this
|
|
2151
|
-
* host.
|
|
2152
|
-
* must not see the connection at all, on any runtime.
|
|
2180
|
+
* host.
|
|
2153
2181
|
*/
|
|
2154
2182
|
cloudBridgeableConnectionNames(): string[] {
|
|
2155
|
-
const hostOnlyNames = new Set(
|
|
2156
|
-
this.project.agent.connections
|
|
2157
|
-
.filter((connection) => connection.hostOnly === true)
|
|
2158
|
-
.map((connection) => connection.name)
|
|
2159
|
-
);
|
|
2160
2183
|
const names: string[] = [];
|
|
2161
2184
|
for (const connection of this.project.agent.connections) {
|
|
2162
|
-
if (
|
|
2163
|
-
!hostOnlyNames.has(connection.name) &&
|
|
2164
|
-
isHostOauthConnectionTransport(connection.transport)
|
|
2165
|
-
) {
|
|
2185
|
+
if (isHostOauthConnectionTransport(connection.transport)) {
|
|
2166
2186
|
names.push(connection.name);
|
|
2167
2187
|
}
|
|
2168
2188
|
}
|
|
2169
2189
|
for (const resolved of this.resolvedConnections) {
|
|
2170
2190
|
if (
|
|
2171
|
-
!hostOnlyNames.has(resolved.name) &&
|
|
2172
2191
|
resolved.accountServersFilter !== undefined &&
|
|
2173
2192
|
resolved.cloudUrl === undefined
|
|
2174
2193
|
) {
|
|
@@ -2181,8 +2200,7 @@ export class SessionEngine {
|
|
|
2181
2200
|
/**
|
|
2182
2201
|
* True when cloud turns reach `name` through the host connection bridge —
|
|
2183
2202
|
* the gate the tool MCP endpoint applies before forwarding a bridge
|
|
2184
|
-
* request to `host.mcp`, so
|
|
2185
|
-
* stay unreachable from a VM.
|
|
2203
|
+
* request to `host.mcp`, so arbitrary names stay unreachable from a VM.
|
|
2186
2204
|
*/
|
|
2187
2205
|
isCloudBridgedConnection(name: string): boolean {
|
|
2188
2206
|
if (this.cloudServerToolsConnection === undefined) {
|
|
@@ -2212,10 +2230,11 @@ export class SessionEngine {
|
|
|
2212
2230
|
}
|
|
2213
2231
|
|
|
2214
2232
|
/**
|
|
2215
|
-
* Authored + resolved MCP servers for a turn. Skips
|
|
2216
|
-
*
|
|
2217
|
-
*
|
|
2218
|
-
*
|
|
2233
|
+
* Authored + resolved MCP servers for a turn. Skips advertised
|
|
2234
|
+
* connections (those surface as named server tools). On cloud turns,
|
|
2235
|
+
* connections whose credential lives on this host — filtered account
|
|
2236
|
+
* connections without a public bridge URL, host-OAuth servers — mount
|
|
2237
|
+
* as host connection bridges over the tool MCP endpoint instead of
|
|
2219
2238
|
* being omitted or failing the turn closed.
|
|
2220
2239
|
*/
|
|
2221
2240
|
private buildMcpServers(
|
|
@@ -2229,16 +2248,17 @@ export class SessionEngine {
|
|
|
2229
2248
|
return {};
|
|
2230
2249
|
}
|
|
2231
2250
|
// Advertised connections surface as named server tools instead of an
|
|
2232
|
-
// attached MCP server (each tool appears exactly once)
|
|
2233
|
-
|
|
2234
|
-
const hostOnlyNames = new Set(
|
|
2251
|
+
// attached MCP server (each tool appears exactly once).
|
|
2252
|
+
const advertisedNames = new Set(
|
|
2235
2253
|
this.project.agent.connections
|
|
2236
|
-
.filter(
|
|
2237
|
-
(connection) =>
|
|
2238
|
-
connection.hostOnly === true || connection.advertiseTools === true
|
|
2239
|
-
)
|
|
2254
|
+
.filter((connection) => connection.advertiseTools === true)
|
|
2240
2255
|
.map((connection) => connection.name)
|
|
2241
2256
|
);
|
|
2257
|
+
const hostConnectionNames = new Set(
|
|
2258
|
+
(this.project.agent.hostConnections ?? []).map(
|
|
2259
|
+
(connection) => connection.name
|
|
2260
|
+
)
|
|
2261
|
+
);
|
|
2242
2262
|
const bridgedNames = new Set(
|
|
2243
2263
|
runtime === "cloud" &&
|
|
2244
2264
|
sessionId !== undefined &&
|
|
@@ -2250,7 +2270,9 @@ export class SessionEngine {
|
|
|
2250
2270
|
assertCloudCanHonorAccountServersFilters({
|
|
2251
2271
|
runtime,
|
|
2252
2272
|
resolvedConnections: this.resolvedConnections.filter(
|
|
2253
|
-
(resolved) =>
|
|
2273
|
+
(resolved) =>
|
|
2274
|
+
!advertisedNames.has(resolved.name) &&
|
|
2275
|
+
!hostConnectionNames.has(resolved.name)
|
|
2254
2276
|
),
|
|
2255
2277
|
bridgedNames,
|
|
2256
2278
|
});
|
|
@@ -2260,7 +2282,10 @@ export class SessionEngine {
|
|
|
2260
2282
|
: this.cloudBridgeTransport(sessionId, name);
|
|
2261
2283
|
const servers: Record<string, ConnectionTransport> = {};
|
|
2262
2284
|
for (const connection of this.project.agent.connections) {
|
|
2263
|
-
if (
|
|
2285
|
+
if (
|
|
2286
|
+
advertisedNames.has(connection.name) ||
|
|
2287
|
+
hostConnectionNames.has(connection.name)
|
|
2288
|
+
) {
|
|
2264
2289
|
continue;
|
|
2265
2290
|
}
|
|
2266
2291
|
if (isSymbolicConnectionTransport(connection.transport)) {
|
|
@@ -2301,7 +2326,10 @@ export class SessionEngine {
|
|
|
2301
2326
|
servers[connection.name] = connection.transport;
|
|
2302
2327
|
}
|
|
2303
2328
|
for (const resolved of this.resolvedConnections) {
|
|
2304
|
-
if (
|
|
2329
|
+
if (
|
|
2330
|
+
advertisedNames.has(resolved.name) ||
|
|
2331
|
+
hostConnectionNames.has(resolved.name)
|
|
2332
|
+
) {
|
|
2305
2333
|
continue;
|
|
2306
2334
|
}
|
|
2307
2335
|
const url = runtime === "cloud" ? resolved.cloudUrl : resolved.localUrl;
|
|
@@ -2346,16 +2374,14 @@ export class SessionEngine {
|
|
|
2346
2374
|
|
|
2347
2375
|
/**
|
|
2348
2376
|
* True when a connection with per-session `auth` attaches to the model
|
|
2349
|
-
* (not
|
|
2377
|
+
* (not advertised). These turns set
|
|
2350
2378
|
* {@link RunnerTurnRequest.perSendMcpServers} so the evaluated headers
|
|
2351
2379
|
* ride every send instead of being pinned on the cached agent handle.
|
|
2352
2380
|
*/
|
|
2353
2381
|
private hasAttachedAuthedConnections(): boolean {
|
|
2354
2382
|
return this.project.agent.connections.some(
|
|
2355
2383
|
(connection) =>
|
|
2356
|
-
connection.auth !== undefined &&
|
|
2357
|
-
connection.hostOnly !== true &&
|
|
2358
|
-
connection.advertiseTools !== true
|
|
2384
|
+
connection.auth !== undefined && connection.advertiseTools !== true
|
|
2359
2385
|
);
|
|
2360
2386
|
}
|
|
2361
2387
|
|
|
@@ -2371,9 +2397,7 @@ export class SessionEngine {
|
|
|
2371
2397
|
): Promise<ReadonlyMap<string, Record<string, string>> | undefined> {
|
|
2372
2398
|
const authed = this.project.agent.connections.filter(
|
|
2373
2399
|
(connection) =>
|
|
2374
|
-
connection.auth !== undefined &&
|
|
2375
|
-
connection.hostOnly !== true &&
|
|
2376
|
-
connection.advertiseTools !== true
|
|
2400
|
+
connection.auth !== undefined && connection.advertiseTools !== true
|
|
2377
2401
|
);
|
|
2378
2402
|
if (authed.length === 0) {
|
|
2379
2403
|
return undefined;
|
|
@@ -2783,12 +2807,168 @@ export class SessionEngine {
|
|
|
2783
2807
|
* with the same `{ content, isError }` envelope the model would see, not
|
|
2784
2808
|
* an exception.
|
|
2785
2809
|
*/
|
|
2810
|
+
/**
|
|
2811
|
+
* The session identity a direct call (or catalog listing) runs under:
|
|
2812
|
+
* an explicit sessionId, a continuation token resolved to a live (or
|
|
2813
|
+
* restorable) session with the same owner/busy checks a sessionId call
|
|
2814
|
+
* gets, or — when neither maps to a session — a synthetic identity
|
|
2815
|
+
* carrying the token's channel id and continuation key so binding
|
|
2816
|
+
* resolvers (e.g. VFS mounts) can still serve the call.
|
|
2817
|
+
*/
|
|
2818
|
+
private async resolveDirectCallIdentity(
|
|
2819
|
+
callId: string,
|
|
2820
|
+
options: Pick<CallToolOptions, "auth" | "sessionId" | "continuationToken">
|
|
2821
|
+
): Promise<{
|
|
2822
|
+
record: SessionRecord | undefined;
|
|
2823
|
+
session: SessionInfo;
|
|
2824
|
+
workspaceDir: string;
|
|
2825
|
+
scratchDir: string | undefined;
|
|
2826
|
+
}> {
|
|
2827
|
+
if (
|
|
2828
|
+
options.sessionId !== undefined &&
|
|
2829
|
+
options.continuationToken !== undefined
|
|
2830
|
+
) {
|
|
2831
|
+
throw new InvalidContinuationTokenError(
|
|
2832
|
+
"mutually exclusive with sessionId — a real session already carries its own continuation key"
|
|
2833
|
+
);
|
|
2834
|
+
}
|
|
2835
|
+
const auth = options.auth ?? null;
|
|
2836
|
+
let record: SessionRecord | undefined;
|
|
2837
|
+
let continuation: { channelId: string; key: string } | null = null;
|
|
2838
|
+
if (options.sessionId !== undefined) {
|
|
2839
|
+
record = await this.sessions.get(options.sessionId);
|
|
2840
|
+
if (record === undefined) {
|
|
2841
|
+
throw new UnknownSessionError(options.sessionId);
|
|
2842
|
+
}
|
|
2843
|
+
} else if (options.continuationToken !== undefined) {
|
|
2844
|
+
continuation = parseContinuationToken(options.continuationToken);
|
|
2845
|
+
if (continuation === null) {
|
|
2846
|
+
throw new InvalidContinuationTokenError(
|
|
2847
|
+
`expected "<channelId>:<key>" (as /v1/sessions lists it), got "${options.continuationToken}"`
|
|
2848
|
+
);
|
|
2849
|
+
}
|
|
2850
|
+
// A token that maps to a live (or restorable) session takes the
|
|
2851
|
+
// session path: same owner check, same turn serialization, same
|
|
2852
|
+
// event recording as an explicit sessionId. Skipping those just
|
|
2853
|
+
// because the caller addressed the session by token would fail open.
|
|
2854
|
+
record =
|
|
2855
|
+
(await this.sessions.findByContinuation(
|
|
2856
|
+
continuation.channelId,
|
|
2857
|
+
continuation.key
|
|
2858
|
+
)) ??
|
|
2859
|
+
(await this.restoreSessionByContinuation(
|
|
2860
|
+
continuation.channelId,
|
|
2861
|
+
continuation.key
|
|
2862
|
+
));
|
|
2863
|
+
if (record !== undefined && !samePrincipal(record.auth, auth)) {
|
|
2864
|
+
throw new SessionAuthError(record.sessionId);
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
if (record !== undefined) {
|
|
2868
|
+
// Direct calls respect the same serialization as follow-up sends: a
|
|
2869
|
+
// running model turn owns the session workspace and event stream.
|
|
2870
|
+
if (
|
|
2871
|
+
this.activeTurns.has(record.sessionId) ||
|
|
2872
|
+
this.pendingTurns.has(record.sessionId)
|
|
2873
|
+
) {
|
|
2874
|
+
throw new SessionBusyError(record.sessionId);
|
|
2875
|
+
}
|
|
2876
|
+
return {
|
|
2877
|
+
record,
|
|
2878
|
+
session: this.sessionInfo(record),
|
|
2879
|
+
workspaceDir: this.harnessCwd(record),
|
|
2880
|
+
scratchDir: undefined,
|
|
2881
|
+
};
|
|
2882
|
+
}
|
|
2883
|
+
// No session behind the token (or no token at all): a synthetic
|
|
2884
|
+
// session carries the token's channel id and key, so binding resolvers
|
|
2885
|
+
// keyed on the continuation key (e.g. VFS mounts) can serve the call
|
|
2886
|
+
// with no live session. The workspace stays scratch and nothing is
|
|
2887
|
+
// recorded on a session event stream.
|
|
2888
|
+
const scratchDir = join(this.stateRoot, "tool-calls", callId);
|
|
2889
|
+
return {
|
|
2890
|
+
record: undefined,
|
|
2891
|
+
session: {
|
|
2892
|
+
id: callId,
|
|
2893
|
+
channelId: continuation?.channelId ?? DIRECT_TOOL_CALL_CHANNEL_ID,
|
|
2894
|
+
mode: "task",
|
|
2895
|
+
continuationKey: continuation?.key,
|
|
2896
|
+
auth,
|
|
2897
|
+
},
|
|
2898
|
+
workspaceDir: scratchDir,
|
|
2899
|
+
scratchDir,
|
|
2900
|
+
};
|
|
2901
|
+
}
|
|
2902
|
+
|
|
2903
|
+
/**
|
|
2904
|
+
* The live tool catalog for one session identity: authored server tools
|
|
2905
|
+
* plus the advertised passthroughs a turn under the same identity would
|
|
2906
|
+
* see, under their model-facing names. A connection whose listing fails
|
|
2907
|
+
* is skipped and reported in `connectionErrors` — the inspection surface
|
|
2908
|
+
* degrades legibly instead of hiding every other tool behind one broken
|
|
2909
|
+
* connector.
|
|
2910
|
+
*/
|
|
2911
|
+
async listCatalogTools(
|
|
2912
|
+
options: Pick<
|
|
2913
|
+
CallToolOptions,
|
|
2914
|
+
"auth" | "sessionId" | "continuationToken"
|
|
2915
|
+
> = {}
|
|
2916
|
+
): Promise<{
|
|
2917
|
+
tools: DiscoveredTool[];
|
|
2918
|
+
connectionErrors: Array<{ connection: string; message: string }>;
|
|
2919
|
+
}> {
|
|
2920
|
+
const { session } = await this.resolveDirectCallIdentity(
|
|
2921
|
+
newToolCallId("catalog"),
|
|
2922
|
+
options
|
|
2923
|
+
);
|
|
2924
|
+
const connectionErrors: Array<{ connection: string; message: string }> = [];
|
|
2925
|
+
const advertised = await resolveAdvertisedTools({
|
|
2926
|
+
agent: this.project.agent,
|
|
2927
|
+
session,
|
|
2928
|
+
hostMcp: this.mcpHost,
|
|
2929
|
+
onConnectionError: (connection, error) => {
|
|
2930
|
+
connectionErrors.push({
|
|
2931
|
+
connection,
|
|
2932
|
+
message: error instanceof Error ? error.message : String(error),
|
|
2933
|
+
});
|
|
2934
|
+
},
|
|
2935
|
+
});
|
|
2936
|
+
return {
|
|
2937
|
+
tools: [...this.project.agent.tools, ...advertised],
|
|
2938
|
+
connectionErrors,
|
|
2939
|
+
};
|
|
2940
|
+
}
|
|
2941
|
+
|
|
2786
2942
|
async callTool(
|
|
2787
2943
|
toolName: string,
|
|
2788
2944
|
input: unknown = {},
|
|
2789
2945
|
options: CallToolOptions = {}
|
|
2790
2946
|
): Promise<ToolCallOutcome> {
|
|
2791
|
-
const
|
|
2947
|
+
const callId = newToolCallId(toolName);
|
|
2948
|
+
// Identity resolves before the tool lookup: advertised connection tools
|
|
2949
|
+
// only exist relative to a session (per-session auth), so finding them
|
|
2950
|
+
// needs the same identity the call runs under.
|
|
2951
|
+
const identity = await this.resolveDirectCallIdentity(callId, options);
|
|
2952
|
+
const record = identity.record;
|
|
2953
|
+
const session = identity.session;
|
|
2954
|
+
let workspaceDir = identity.workspaceDir;
|
|
2955
|
+
let scratchDir = identity.scratchDir;
|
|
2956
|
+
let tool = this.project.agent.tools.find((t) => t.name === toolName);
|
|
2957
|
+
if (
|
|
2958
|
+
tool === undefined &&
|
|
2959
|
+
this.project.agent.connections.some((c) => c.advertiseTools === true)
|
|
2960
|
+
) {
|
|
2961
|
+
// Advertised passthroughs are ordinary server tools in the session's
|
|
2962
|
+
// namespace; resolve the live listing so direct calls address them by
|
|
2963
|
+
// the same model-facing name a turn would. A listing failure fails
|
|
2964
|
+
// the call closed, like it fails a turn.
|
|
2965
|
+
const advertised = await resolveAdvertisedTools({
|
|
2966
|
+
agent: this.project.agent,
|
|
2967
|
+
session,
|
|
2968
|
+
hostMcp: this.mcpHost,
|
|
2969
|
+
});
|
|
2970
|
+
tool = advertised.find((t) => t.name === toolName);
|
|
2971
|
+
}
|
|
2792
2972
|
if (tool === undefined) {
|
|
2793
2973
|
throw new UnknownToolError(
|
|
2794
2974
|
toolName,
|
|
@@ -2805,47 +2985,51 @@ export class SessionEngine {
|
|
|
2805
2985
|
if (!validation.ok) {
|
|
2806
2986
|
throw new ToolInputError({ toolName, detail: validation.message });
|
|
2807
2987
|
}
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
let session: SessionInfo;
|
|
2813
|
-
let workspaceDir: string;
|
|
2814
|
-
let scratchDir: string | undefined;
|
|
2815
|
-
if (options.sessionId !== undefined) {
|
|
2816
|
-
record = await this.sessions.get(options.sessionId);
|
|
2988
|
+
let workspaceUnavailable = false;
|
|
2989
|
+
try {
|
|
2990
|
+
await mkdir(workspaceDir, { recursive: true });
|
|
2991
|
+
} catch (error) {
|
|
2817
2992
|
if (record === undefined) {
|
|
2818
|
-
throw
|
|
2993
|
+
throw error;
|
|
2819
2994
|
}
|
|
2820
|
-
//
|
|
2821
|
-
//
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2995
|
+
// A session's harness cwd can be a path the serving process cannot
|
|
2996
|
+
// create (e.g. an absolute `local.cwd` like /repo on a hosted pod
|
|
2997
|
+
// where the sandboxed harness would have made it). Read-effect calls
|
|
2998
|
+
// fall back to a scratch workspace instead of failing: tools that
|
|
2999
|
+
// resolve their state from the session identity (VFS mounts) never
|
|
3000
|
+
// touch ctx.workspaceDir. Advertised passthroughs are relocatable by
|
|
3001
|
+
// construction: their execute body forwards to the connection and
|
|
3002
|
+
// never reads the workspace. A write (or undeclared, which resolves
|
|
3003
|
+
// to write) authored tool may rely on ctx.workspaceDir being the
|
|
3004
|
+
// real session workspace, so silently relocating it is not safe —
|
|
3005
|
+
// fail typed instead.
|
|
3006
|
+
const relocatable =
|
|
3007
|
+
tool.advertised === true ||
|
|
3008
|
+
resolveEffect(tool.definition.effect, validation.value) === "read";
|
|
3009
|
+
if (!relocatable) {
|
|
3010
|
+
throw new WorkspaceUnavailableError(toolName, error);
|
|
2827
3011
|
}
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
channelId: DIRECT_TOOL_CALL_CHANNEL_ID,
|
|
2834
|
-
mode: "task",
|
|
2835
|
-
auth,
|
|
2836
|
-
};
|
|
3012
|
+
this.logger(
|
|
3013
|
+
`[session] tool ${toolName} workspace unavailable (direct ${callId}); using scratch: ${
|
|
3014
|
+
error instanceof Error ? error.message : String(error)
|
|
3015
|
+
}`
|
|
3016
|
+
);
|
|
2837
3017
|
scratchDir = join(this.stateRoot, "tool-calls", callId);
|
|
2838
3018
|
workspaceDir = scratchDir;
|
|
3019
|
+
workspaceUnavailable = true;
|
|
3020
|
+
await mkdir(workspaceDir, { recursive: true });
|
|
2839
3021
|
}
|
|
2840
|
-
await mkdir(workspaceDir, { recursive: true });
|
|
2841
3022
|
// Match what a model turn would see: session workspaces get the same
|
|
2842
3023
|
// scaffold as executeTurn (seeds only before the first turn); scratch
|
|
2843
3024
|
// workspaces are materialized fresh.
|
|
2844
3025
|
await materializeWorkspace({
|
|
2845
3026
|
agent: this.project.agent,
|
|
2846
3027
|
workspaceDir:
|
|
2847
|
-
record === undefined
|
|
2848
|
-
|
|
3028
|
+
record === undefined || workspaceUnavailable
|
|
3029
|
+
? workspaceDir
|
|
3030
|
+
: this.scaffoldDir(record),
|
|
3031
|
+
seed:
|
|
3032
|
+
record === undefined || workspaceUnavailable || record.turnCount === 0,
|
|
2849
3033
|
stateRoot: this.stateRoot,
|
|
2850
3034
|
});
|
|
2851
3035
|
|
|
@@ -2981,8 +3165,9 @@ export class SessionEngine {
|
|
|
2981
3165
|
isError,
|
|
2982
3166
|
result,
|
|
2983
3167
|
durationMs,
|
|
2984
|
-
|
|
2985
|
-
|
|
3168
|
+
errorMessage,
|
|
3169
|
+
sessionId: record?.sessionId,
|
|
3170
|
+
scratchWorkspace: workspaceUnavailable ? true : undefined,
|
|
2986
3171
|
};
|
|
2987
3172
|
}
|
|
2988
3173
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Projections for the live tool catalog (`GET /v1/tools` and
|
|
3
|
+
* `GET /v1/tools/:name`): the session's tool namespace exactly as a turn
|
|
4
|
+
* would assemble it — authored server tools plus advertised MCP
|
|
5
|
+
* passthroughs — under model-facing names.
|
|
6
|
+
*
|
|
7
|
+
* Titles are curated data, never derived from descriptions: advertised
|
|
8
|
+
* tools inherit the upstream server's MCP `annotations.title` (bounded at
|
|
9
|
+
* listing time), and the well-known non-MCP tool names carry a hardcoded
|
|
10
|
+
* title here so every deployment shows the same display names.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type {
|
|
14
|
+
DiscoveredTool,
|
|
15
|
+
JsonSchemaObject,
|
|
16
|
+
ToolEffect,
|
|
17
|
+
ToolExecution,
|
|
18
|
+
} from "../types.js";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Display names for the well-known tool names that do not come from MCP
|
|
22
|
+
* (authored tools have no title field; adding one to `defineTool` for a
|
|
23
|
+
* presentation concern is not worth the authoring surface).
|
|
24
|
+
*/
|
|
25
|
+
const WELL_KNOWN_TOOL_TITLES: Readonly<Record<string, string>> = {
|
|
26
|
+
diff: "Show change diffs",
|
|
27
|
+
glob: "Find files by pattern",
|
|
28
|
+
grep: "Search file contents",
|
|
29
|
+
ls: "List a directory",
|
|
30
|
+
read: "Read a file",
|
|
31
|
+
search: "Search with a typed query",
|
|
32
|
+
write: "Write a file",
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function catalogTitle(tool: DiscoveredTool): string | undefined {
|
|
36
|
+
if (tool.advertised === true) {
|
|
37
|
+
return tool.annotations?.title;
|
|
38
|
+
}
|
|
39
|
+
return WELL_KNOWN_TOOL_TITLES[tool.name];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Sand connector identifiers scope the connector name by owner
|
|
44
|
+
* (`dashboard-team-<id>-Buildkite`, `dashboard-<Name>`, `user-<Name>`);
|
|
45
|
+
* the suffix is the human-meaningful name.
|
|
46
|
+
*/
|
|
47
|
+
const CONNECTOR_SCOPE_PREFIX = /^(?:dashboard-team-\d+-|dashboard-|user-)/;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Where a tool comes from, for humans: the upstream connector/plugin name
|
|
51
|
+
* when the tool declares one (the reserved `__conn__` selector's values
|
|
52
|
+
* name it), the connection name otherwise. One aggregating connection
|
|
53
|
+
* (e.g. a tenant `plugins` endpoint) hosts tools from several connectors,
|
|
54
|
+
* and "plugins" tells an operator nothing — "Buildkite" does.
|
|
55
|
+
*/
|
|
56
|
+
function catalogSource(tool: DiscoveredTool): string | undefined {
|
|
57
|
+
if (tool.advertised !== true) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
const properties = tool.inputSchema.properties as
|
|
61
|
+
| Record<string, { enum?: unknown[] } | undefined>
|
|
62
|
+
| undefined;
|
|
63
|
+
const first = properties?.__conn__?.enum?.[0];
|
|
64
|
+
if (typeof first === "string" && first !== "") {
|
|
65
|
+
return first.replace(CONNECTOR_SCOPE_PREFIX, "");
|
|
66
|
+
}
|
|
67
|
+
return tool.connection;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Light listing entry: identifiers and curated display data only. */
|
|
71
|
+
export interface CatalogListEntry {
|
|
72
|
+
name: string;
|
|
73
|
+
title?: string;
|
|
74
|
+
/** Connection name for advertised MCP tools; absent for authored tools. */
|
|
75
|
+
source?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Full description behind `GET /v1/tools/:name`. */
|
|
79
|
+
export interface CatalogDetailEntry extends CatalogListEntry {
|
|
80
|
+
description: string;
|
|
81
|
+
execution: ToolExecution;
|
|
82
|
+
needsApproval: boolean;
|
|
83
|
+
effect?: ToolEffect | "dynamic";
|
|
84
|
+
inputSchema: JsonSchemaObject;
|
|
85
|
+
outputSchema?: JsonSchemaObject;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function catalogListEntry(tool: DiscoveredTool): CatalogListEntry {
|
|
89
|
+
return {
|
|
90
|
+
name: tool.name,
|
|
91
|
+
title: catalogTitle(tool),
|
|
92
|
+
source: catalogSource(tool),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function catalogDetailEntry(tool: DiscoveredTool): CatalogDetailEntry {
|
|
97
|
+
return {
|
|
98
|
+
...catalogListEntry(tool),
|
|
99
|
+
description: tool.description,
|
|
100
|
+
execution: tool.execution,
|
|
101
|
+
needsApproval: tool.needsApproval,
|
|
102
|
+
effect: tool.effect,
|
|
103
|
+
inputSchema: tool.inputSchema,
|
|
104
|
+
outputSchema: tool.outputSchema,
|
|
105
|
+
};
|
|
106
|
+
}
|