@cursor/july 0.1.96 → 0.1.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/bin/agent-serve.js +14 -3
- package/dist/channels/origin/api.d.ts +15 -4
- package/dist/channels/origin/api.d.ts.map +1 -1
- package/dist/channels/origin/api.js +19 -3
- package/dist/channels/origin/binding.d.ts +11 -0
- package/dist/channels/origin/binding.d.ts.map +1 -1
- package/dist/channels/origin/binding.js +41 -25
- package/dist/channels/origin/index.d.ts +1 -0
- package/dist/channels/origin/index.d.ts.map +1 -1
- package/dist/channels/origin/index.js +1 -0
- package/dist/channels/origin/origin-channel.d.ts.map +1 -1
- package/dist/channels/origin/origin-channel.js +3 -0
- package/dist/channels/origin/reactions.d.ts +56 -0
- package/dist/channels/origin/reactions.d.ts.map +1 -0
- package/dist/channels/origin/reactions.js +67 -0
- package/dist/channels/origin/types.d.ts +11 -0
- package/dist/channels/origin/types.d.ts.map +1 -1
- package/dist/channels/slack/approvals.d.ts +16 -0
- package/dist/channels/slack/approvals.d.ts.map +1 -1
- package/dist/channels/slack/approvals.js +86 -0
- package/dist/channels/slack/cli-project.d.ts +19 -0
- package/dist/channels/slack/cli-project.d.ts.map +1 -0
- package/dist/channels/slack/cli-project.js +234 -0
- package/dist/channels/slack/defaults.d.ts.map +1 -1
- package/dist/channels/slack/defaults.js +97 -39
- package/dist/channels/slack/init.d.ts +3 -2
- package/dist/channels/slack/init.d.ts.map +1 -1
- package/dist/channels/slack/init.js +5 -5
- package/dist/channels/slack/interactive.d.ts +2 -1
- package/dist/channels/slack/interactive.d.ts.map +1 -1
- package/dist/channels/slack/interactive.js +15 -4
- package/dist/channels/slack/manifest.d.ts +1 -1
- package/dist/channels/slack/manifest.js +1 -1
- package/dist/channels/slack/setup.d.ts +1 -1
- package/dist/channels/slack/setup.d.ts.map +1 -1
- package/dist/channels/slack/setup.js +10 -6
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +1 -0
- package/dist/channels/slack/tool-approval-events.d.ts.map +1 -1
- package/dist/channels/slack/tool-approval-events.js +91 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +4 -4
- package/dist/docs/assets/{app.jXleCmOc.js → app.B3rWNYE1.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.BU9nHdnQ.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.8LhyglIT.js → VPLocalSearchBox.C1lhqJJR.js} +1 -1
- package/dist/docs/assets/chunks/{theme.9ged-pr2.js → theme.B40_SXuv.js} +2 -2
- package/dist/docs/assets/{deployment.md.D9msOFOW.js → deployment.md.MFPKqsqI.js} +2 -2
- package/dist/docs/assets/{guides_mcp-oauth.md.DPYmBCbV.js → guides_mcp-oauth.md.CN-6YmTJ.js} +4 -4
- package/dist/docs/assets/{guides_mcp-oauth.md.DPYmBCbV.lean.js → guides_mcp-oauth.md.CN-6YmTJ.lean.js} +1 -1
- package/dist/docs/assets/guides_slack.md.VDXQV3ja.js +22 -0
- package/dist/docs/assets/guides_slack.md.VDXQV3ja.lean.js +1 -0
- package/dist/docs/assets/index.md.CVeRUOeZ.js +5 -0
- package/dist/docs/assets/{reference_agent-config.md.Cp_x38Nl.js → reference_agent-config.md.BHeYMgme.js} +1 -1
- package/dist/docs/assets/{reference_cli.md.CCnG-nJx.js → reference_cli.md.RyZf5OTE.js} +9 -6
- package/dist/docs/assets/{reference_cli.md.CCnG-nJx.lean.js → reference_cli.md.RyZf5OTE.lean.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.BH8Oc0D0.js → reference_connections.md.DxldvyIB.js} +4 -3
- package/dist/docs/assets/{reference_http-api.md.D89k1mdm.js → reference_http-api.md.5zOAbV86.js} +1 -1
- package/dist/docs/assets/reference_sessions.md.NxFP_CAC.js +1 -0
- package/dist/docs/assets/{reference_tools.md.BHeXn2id.js → reference_tools.md.B84gw9Ii.js} +1 -1
- package/dist/docs/assets/templates_agents-md.md.CXSMZljE.js +2 -0
- package/dist/docs/assets/templates_agents-md.md.CXSMZljE.lean.js +1 -0
- package/dist/docs/assets/troubleshooting.md.DCiPBhYs.js +1 -0
- package/dist/docs/building-with-agents.html +4 -4
- package/dist/docs/concepts.html +4 -4
- package/dist/docs/deployment.html +7 -7
- package/dist/docs/deployment.md +5 -4
- package/dist/docs/evals.html +4 -4
- package/dist/docs/guides/agent-to-agent.html +4 -4
- package/dist/docs/guides/cloud-runtime.html +4 -4
- package/dist/docs/guides/convert-automation.html +4 -4
- package/dist/docs/guides/github.html +4 -4
- package/dist/docs/guides/human-in-the-loop.html +4 -4
- package/dist/docs/guides/mcp-oauth.html +8 -8
- package/dist/docs/guides/mcp-oauth.md +26 -8
- package/dist/docs/guides/opentelemetry.html +4 -4
- package/dist/docs/guides/slack.html +17 -33
- package/dist/docs/guides/slack.md +92 -201
- 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 +5 -3
- package/dist/docs/llms-full.txt +299 -653
- package/dist/docs/llms.txt +2 -2
- package/dist/docs/quickstart.html +4 -4
- package/dist/docs/reference/agent-config.html +6 -6
- package/dist/docs/reference/agent-config.md +2 -2
- package/dist/docs/reference/artifacts.html +4 -4
- package/dist/docs/reference/channels.html +4 -4
- package/dist/docs/reference/cli.html +13 -10
- package/dist/docs/reference/cli.md +38 -16
- package/dist/docs/reference/connections.html +9 -8
- package/dist/docs/reference/connections.md +6 -3
- package/dist/docs/reference/hooks.html +4 -4
- package/dist/docs/reference/http-api.html +6 -6
- package/dist/docs/reference/http-api.md +2 -1
- package/dist/docs/reference/instructions.html +4 -4
- package/dist/docs/reference/playground.html +4 -4
- package/dist/docs/reference/project-layout.html +4 -4
- package/dist/docs/reference/prompt.html +4 -4
- package/dist/docs/reference/schedules.html +4 -4
- package/dist/docs/reference/sessions.html +5 -5
- package/dist/docs/reference/sessions.md +4 -2
- package/dist/docs/reference/skills.html +4 -4
- package/dist/docs/reference/subagents.html +4 -4
- package/dist/docs/reference/tools.html +6 -6
- package/dist/docs/reference/tools.md +9 -2
- 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/agents-md.html +28 -0
- package/dist/docs/templates/agents-md.md +105 -0
- package/dist/docs/templates/code-wiki.html +5 -5
- package/dist/docs/templates/demo.html +4 -4
- package/dist/docs/templates/pr-autofixer.html +4 -4
- package/dist/docs/templates/security-help.html +4 -4
- package/dist/docs/templates/security-reviewer.html +5 -5
- package/dist/docs/templates/triage.html +4 -4
- package/dist/docs/troubleshooting.html +5 -5
- package/dist/docs/troubleshooting.md +2 -2
- package/dist/evals/run-facts.d.ts.map +1 -1
- package/dist/evals/run-facts.js +27 -0
- package/dist/internal/advertise-tools.d.ts.map +1 -1
- package/dist/internal/advertise-tools.js +15 -9
- package/dist/internal/approval-gate.d.ts +12 -13
- package/dist/internal/approval-gate.d.ts.map +1 -1
- package/dist/internal/approval-gate.js +16 -21
- package/dist/internal/chat-client.js +10 -0
- package/dist/internal/cli-deploy.d.ts +5 -0
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +50 -17
- package/dist/internal/cli-mcp-oauth.js +8 -18
- package/dist/internal/cli-slack-manual.d.ts +24 -2
- package/dist/internal/cli-slack-manual.d.ts.map +1 -1
- package/dist/internal/cli-slack-manual.js +251 -20
- package/dist/internal/cli-slack.d.ts +9 -2
- package/dist/internal/cli-slack.d.ts.map +1 -1
- package/dist/internal/cli-slack.js +29 -82
- package/dist/internal/cursor/account-mcp.d.ts +1 -0
- package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
- package/dist/internal/cursor/account-mcp.js +17 -0
- package/dist/internal/cursor-agent-template.d.ts +1 -1
- package/dist/internal/cursor-agent-template.d.ts.map +1 -1
- package/dist/internal/cursor-agent-template.js +1 -0
- package/dist/internal/deploy-client.d.ts +17 -0
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +31 -10
- package/dist/internal/env-file.d.ts +19 -0
- package/dist/internal/env-file.d.ts.map +1 -0
- package/dist/internal/env-file.js +90 -0
- package/dist/internal/framework-file-storage.d.ts +1 -1
- package/dist/internal/framework-file-storage.d.ts.map +1 -1
- package/dist/internal/framework-file-storage.js +6 -0
- package/dist/internal/hosted-delivery-protocol.d.ts +7 -0
- package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
- package/dist/internal/hosted-delivery-protocol.js +7 -0
- package/dist/internal/hosted-delivery.d.ts +6 -0
- package/dist/internal/hosted-delivery.d.ts.map +1 -1
- package/dist/internal/hosted-delivery.js +63 -22
- package/dist/internal/hosted-execution-diag.d.ts +48 -0
- package/dist/internal/hosted-execution-diag.d.ts.map +1 -0
- package/dist/internal/hosted-execution-diag.js +150 -0
- package/dist/internal/http-channel.d.ts.map +1 -1
- package/dist/internal/http-channel.js +81 -1
- package/dist/internal/init-project.d.ts.map +1 -1
- package/dist/internal/init-project.js +2 -0
- package/dist/internal/logs-client.d.ts +5 -0
- package/dist/internal/logs-client.d.ts.map +1 -1
- package/dist/internal/logs-client.js +5 -0
- package/dist/internal/mcp-endpoint.js +2 -3
- package/dist/internal/mcp-host.d.ts +10 -0
- package/dist/internal/mcp-host.d.ts.map +1 -1
- package/dist/internal/mcp-host.js +57 -8
- package/dist/internal/mcp-oauth-on-demand.d.ts +68 -0
- package/dist/internal/mcp-oauth-on-demand.d.ts.map +1 -0
- package/dist/internal/mcp-oauth-on-demand.js +287 -0
- package/dist/internal/mcp-oauth-persist.d.ts +42 -0
- package/dist/internal/mcp-oauth-persist.d.ts.map +1 -0
- package/dist/internal/mcp-oauth-persist.js +92 -0
- package/dist/internal/mcp-oauth.d.ts +1 -0
- package/dist/internal/mcp-oauth.d.ts.map +1 -1
- package/dist/internal/mcp-oauth.js +10 -2
- package/dist/internal/otel/collector.d.ts.map +1 -1
- package/dist/internal/otel/collector.js +22 -9
- package/dist/internal/server.d.ts +3 -0
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +49 -22
- package/dist/internal/session-engine.d.ts +88 -3
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +515 -43
- package/dist/internal/sessions-client.d.ts +9 -7
- package/dist/internal/sessions-client.d.ts.map +1 -1
- package/dist/internal/sessions-client.js +3 -1
- package/dist/internal/storage-coordinator.d.ts +7 -0
- package/dist/internal/storage-coordinator.d.ts.map +1 -1
- package/dist/internal/storage-coordinator.js +28 -5
- package/dist/internal/storage-roles.d.ts +5 -0
- package/dist/internal/storage-roles.d.ts.map +1 -1
- package/dist/internal/stream-progress.d.ts.map +1 -1
- package/dist/internal/stream-progress.js +10 -0
- package/dist/internal/tool-policy.d.ts +9 -1
- package/dist/internal/tool-policy.d.ts.map +1 -1
- package/dist/internal/tool-policy.js +13 -0
- package/dist/internal/trajectory.d.ts.map +1 -1
- package/dist/internal/trajectory.js +10 -0
- package/dist/internal/turn-outbox.d.ts +24 -0
- package/dist/internal/turn-outbox.d.ts.map +1 -0
- package/dist/internal/turn-outbox.js +80 -0
- package/dist/playground/assets/{index-Cx9CclK_.js → index-DrkI6y5O.js} +45 -45
- package/dist/playground/assets/index-DzNGwm7q.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage-backends/cursor-hosted.d.ts +1 -1
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/storage-backends/cursor-hosted.js +12 -0
- package/dist/storage.d.ts +8 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/types.d.ts +63 -7
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +5 -3
- package/docs/deployment.md +5 -4
- package/docs/guides/mcp-oauth.md +26 -8
- package/docs/guides/slack.md +93 -202
- package/docs/reference/agent-config.md +2 -2
- package/docs/reference/cli.md +38 -16
- package/docs/reference/connections.md +6 -3
- package/docs/reference/http-api.md +2 -1
- package/docs/reference/sessions.md +4 -2
- package/docs/reference/tools.md +9 -2
- package/docs/templates/agents-md.md +110 -0
- package/docs/troubleshooting.md +2 -2
- package/package.json +1 -1
- package/skills/create-agent/SKILL.md +2 -1
- package/skills/mcp-auth/SKILL.md +6 -3
- package/skills/setup-slack/SKILL.md +23 -13
- package/src/bin/agent-serve.ts +13 -1
- package/src/channels/origin/api.ts +24 -5
- package/src/channels/origin/binding.ts +55 -26
- package/src/channels/origin/index.ts +1 -0
- package/src/channels/origin/origin-channel.ts +4 -0
- package/src/channels/origin/reactions.ts +82 -0
- package/src/channels/origin/types.ts +11 -0
- package/src/channels/slack/approvals.ts +105 -0
- package/src/channels/slack/cli-project.ts +267 -0
- package/src/channels/slack/defaults.ts +109 -46
- package/src/channels/slack/init.ts +10 -5
- package/src/channels/slack/interactive.ts +35 -9
- package/src/channels/slack/manifest.ts +1 -1
- package/src/channels/slack/setup.ts +10 -6
- package/src/channels/slack/slack-channel.ts +1 -0
- package/src/channels/slack/tool-approval-events.ts +93 -0
- package/src/evals/run-facts.ts +32 -0
- package/src/internal/advertise-tools.ts +31 -10
- package/src/internal/approval-gate.ts +20 -29
- package/src/internal/chat-client.ts +19 -0
- package/src/internal/cli-deploy.ts +79 -9
- package/src/internal/cli-mcp-oauth.ts +7 -21
- package/src/internal/cli-slack-manual.ts +350 -18
- package/src/internal/cli-slack.ts +40 -84
- package/src/internal/cursor/account-mcp.ts +21 -0
- package/src/internal/cursor-agent-template.ts +1 -0
- package/src/internal/deploy-client.ts +43 -0
- package/src/internal/env-file.ts +84 -0
- package/src/internal/framework-file-storage.ts +7 -1
- package/src/internal/hosted-delivery-protocol.ts +7 -0
- package/src/internal/hosted-delivery.ts +100 -27
- package/src/internal/hosted-execution-diag.ts +207 -0
- package/src/internal/http-channel.ts +99 -0
- package/src/internal/init-project.ts +2 -0
- package/src/internal/logs-client.ts +5 -0
- package/src/internal/mcp-endpoint.ts +13 -4
- package/src/internal/mcp-host.ts +77 -11
- package/src/internal/mcp-oauth-on-demand.ts +352 -0
- package/src/internal/mcp-oauth-persist.ts +127 -0
- package/src/internal/mcp-oauth.ts +17 -1
- package/src/internal/otel/collector.ts +30 -0
- package/src/internal/server.ts +59 -9
- package/src/internal/session-engine.ts +659 -56
- package/src/internal/sessions-client.ts +17 -8
- package/src/internal/storage-coordinator.ts +38 -8
- package/src/internal/storage-roles.ts +7 -0
- package/src/internal/stream-progress.ts +19 -0
- package/src/internal/tool-policy.ts +18 -0
- package/src/internal/trajectory.ts +10 -0
- package/src/internal/turn-outbox.ts +85 -0
- package/src/storage-backends/cursor-hosted.ts +13 -1
- package/src/storage.ts +12 -0
- package/src/types.ts +68 -8
- package/templates/agents-md/README.md +39 -0
- package/templates/agents-md/agent/agent.ts +8 -0
- package/templates/agents-md/agent/channels/github.ts +10 -0
- package/templates/agents-md/agent/channels/queue.ts +28 -0
- package/templates/agents-md/agent/channels/slack.ts +9 -0
- package/templates/agents-md/agent/instructions.md +39 -0
- package/templates/agents-md/agent/lib/collect.ts +439 -0
- package/templates/agents-md/agent/lib/config.ts +8 -0
- package/templates/agents-md/agent/lib/paths.ts +51 -0
- package/templates/agents-md/agent/schedules/weekly.ts +17 -0
- package/templates/agents-md/agent/tools/apply_agents.ts +226 -0
- package/templates/agents-md/evals/agents.eval.ts +135 -0
- package/templates/agents-md/evals/evals.config.ts +5 -0
- package/templates/agents-md/init.json +38 -0
- package/templates/agents-md/package.json +18 -0
- package/templates/agents-md/tsconfig.json +12 -0
- package/dist/docs/assets/chunks/@localSearchIndexroot.DFoGuETX.js +0 -1
- package/dist/docs/assets/guides_slack.md.C32HsdKk.js +0 -38
- package/dist/docs/assets/guides_slack.md.C32HsdKk.lean.js +0 -1
- package/dist/docs/assets/index.md.CI93Ltlb.js +0 -5
- package/dist/docs/assets/reference_sessions.md.D0mIh4KK.js +0 -1
- package/dist/docs/assets/troubleshooting.md.Ctv3T8C2.js +0 -1
- package/dist/docs/design/agsh.md +0 -406
- package/dist/playground/assets/index-B1DDvBeC.css +0 -1
- package/docs/design/agsh.md +0 -406
- /package/dist/docs/assets/{deployment.md.D9msOFOW.lean.js → deployment.md.MFPKqsqI.lean.js} +0 -0
- /package/dist/docs/assets/{index.md.CI93Ltlb.lean.js → index.md.CVeRUOeZ.lean.js} +0 -0
- /package/dist/docs/assets/{reference_agent-config.md.Cp_x38Nl.lean.js → reference_agent-config.md.BHeYMgme.lean.js} +0 -0
- /package/dist/docs/assets/{reference_connections.md.BH8Oc0D0.lean.js → reference_connections.md.DxldvyIB.lean.js} +0 -0
- /package/dist/docs/assets/{reference_http-api.md.D89k1mdm.lean.js → reference_http-api.md.5zOAbV86.lean.js} +0 -0
- /package/dist/docs/assets/{reference_sessions.md.D0mIh4KK.lean.js → reference_sessions.md.NxFP_CAC.lean.js} +0 -0
- /package/dist/docs/assets/{reference_tools.md.BHeXn2id.lean.js → reference_tools.md.B84gw9Ii.lean.js} +0 -0
- /package/dist/docs/assets/{troubleshooting.md.Ctv3T8C2.lean.js → troubleshooting.md.DCiPBhYs.lean.js} +0 -0
|
@@ -15,6 +15,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
15
15
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
16
16
|
});
|
|
17
17
|
};
|
|
18
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
18
19
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
19
20
|
import { dirname, join } from "node:path";
|
|
20
21
|
import { mergeABInstructions, resolveABMaxPlaygroundSessions, resolveABSplit, } from "../ab.js";
|
|
@@ -24,11 +25,11 @@ import { SlackAskDedupeStore, SlackNudgeStore, } from "../channels/slack/nudge-s
|
|
|
24
25
|
import { resolveDedicatedSlackHostBinding } from "../channels/slack/slack-channel.js";
|
|
25
26
|
import { AGENT_SERVE_USER_STORE_FILES_SOURCE_ID, agentStoreKeys, } from "../files.js";
|
|
26
27
|
import { cursorHostedFiles, isCursorHostedFilesAvailable, isCursorUserStoreFilesAvailable, } from "../files-backends/cursor-hosted.js";
|
|
27
|
-
import { DEFAULT_MODEL, DIRECT_TOOL_CALL_CHANNEL_ID, isHostOauthConnectionTransport, isSymbolicConnectionTransport, } from "../types.js";
|
|
28
|
+
import { DEFAULT_MODEL, DIRECT_TOOL_CALL_CHANNEL_ID, isCursorAccountTransport, isHostOauthConnectionTransport, isSymbolicConnectionTransport, } from "../types.js";
|
|
28
29
|
import { ABCollector } from "./ab-collector.js";
|
|
29
30
|
import { foldABStream } from "./ab-fold.js";
|
|
30
31
|
import { buildABSnapshot } from "./ab-snapshot.js";
|
|
31
|
-
import { resolveAdvertisedTools } from "./advertise-tools.js";
|
|
32
|
+
import { resolveAdvertisedTools, } from "./advertise-tools.js";
|
|
32
33
|
import { ApprovalGate } from "./approval-gate.js";
|
|
33
34
|
import { ArtifactsStore } from "./artifacts-store.js";
|
|
34
35
|
import { SessionAuthError, samePrincipal } from "./auth.js";
|
|
@@ -47,7 +48,8 @@ import { createHostPlatforms, createHostSlackClient, } from "./host-platforms.js
|
|
|
47
48
|
import { HostedAdmissionLocalSendError, isDuringHostedAdmission, } from "./hosted-admission-context.js";
|
|
48
49
|
import { formatContinuationToken, newContinuationKey, newSessionId, newToolCallId, parseContinuationToken, } from "./ids.js";
|
|
49
50
|
import { validateToolInput } from "./json-schema.js";
|
|
50
|
-
import { McpHost } from "./mcp-host.js";
|
|
51
|
+
import { isMcpNeedsAuthError, McpHost } from "./mcp-host.js";
|
|
52
|
+
import { McpOauthOnDemandHub } from "./mcp-oauth-on-demand.js";
|
|
51
53
|
import { shouldStartProcessMemoryTelemetry, startProcessMemoryTelemetry, } from "./process-memory-telemetry.js";
|
|
52
54
|
import { buildSessionContextBlock, SCHEDULE_CHANNEL_PREFIX, } from "./prompt-context.js";
|
|
53
55
|
import { assertCloudCanHonorAccountServersFilters } from "./resolved-connections.js";
|
|
@@ -56,11 +58,12 @@ import { SessionStore } from "./session-store.js";
|
|
|
56
58
|
import { syncSkillsToStore } from "./skills-sync.js";
|
|
57
59
|
import { steeringEnabled } from "./steering.js";
|
|
58
60
|
import { StorageCoordinator } from "./storage-coordinator.js";
|
|
59
|
-
import { decideToolCall,
|
|
61
|
+
import { decideToolCall, directCallEffect } from "./tool-policy.js";
|
|
60
62
|
import { normalizeToolResult, toolCallErrorMessage } from "./tool-result.js";
|
|
61
63
|
import { estimateTurnCostFromApi, roundCostUsd, } from "./turn-cost.js";
|
|
62
64
|
import { TurnGovernor } from "./turn-governor.js";
|
|
63
65
|
import { TurnLeaseStore } from "./turn-lease-store.js";
|
|
66
|
+
import { TurnOutbox } from "./turn-outbox.js";
|
|
64
67
|
import { buildAgentsMdContent, buildCloudMemorySection, ensureOwnGitRoot, isNestedInGitRepo, materializeWorkspace, SERVER_TOOLS_MCP_SERVER_NAME, writeWorkspaceFiles, } from "./workspace.js";
|
|
65
68
|
export const HTTP_CHANNEL_ID = "http";
|
|
66
69
|
export { SCHEDULE_CHANNEL_PREFIX } from "./prompt-context.js";
|
|
@@ -134,6 +137,19 @@ export class ApprovalInterruptedError extends Error {
|
|
|
134
137
|
this.name = "ApprovalInterruptedError";
|
|
135
138
|
}
|
|
136
139
|
}
|
|
140
|
+
export class AuthNotFoundError extends Error {
|
|
141
|
+
constructor(sessionId, callId) {
|
|
142
|
+
super(`No pending MCP auth for session ${sessionId} call ${callId}`);
|
|
143
|
+
this.name = "AuthNotFoundError";
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
export class AuthInterruptedError extends Error {
|
|
147
|
+
constructor(sessionId, callId) {
|
|
148
|
+
super(`MCP auth for session ${sessionId} call ${callId} is no longer live (host may have restarted while the tool was parked)`);
|
|
149
|
+
this.name = "AuthInterruptedError";
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const mcpAuthAls = new AsyncLocalStorage();
|
|
137
153
|
export class SessionEngine {
|
|
138
154
|
constructor(options) {
|
|
139
155
|
var _a, _b, _c, _d, _e;
|
|
@@ -143,6 +159,13 @@ export class SessionEngine {
|
|
|
143
159
|
/** Sessions with a turn being admitted (before the run promise exists). */
|
|
144
160
|
this.pendingTurns = new Set();
|
|
145
161
|
this.activeTurns = new Map();
|
|
162
|
+
/**
|
|
163
|
+
* Sessions whose workspace a turn in this process has materialized. A
|
|
164
|
+
* session is busy from admit — before the governor slot and the turn's
|
|
165
|
+
* own materialize — so a read running alongside a turn consults this,
|
|
166
|
+
* not busy, to know whether the workspace is ready to be left alone.
|
|
167
|
+
*/
|
|
168
|
+
this.materializedWorkspaces = new Set();
|
|
146
169
|
/** Context used by the cloud turn's HTTP MCP callbacks. */
|
|
147
170
|
this.activeToolContexts = new Map();
|
|
148
171
|
/**
|
|
@@ -179,6 +202,8 @@ export class SessionEngine {
|
|
|
179
202
|
this.dispatchChains = new Map();
|
|
180
203
|
this.backgroundWork = new Set();
|
|
181
204
|
this.approvals = new ApprovalGate();
|
|
205
|
+
this.auths = new ApprovalGate();
|
|
206
|
+
this.oauthHub = new McpOauthOnDemandHub();
|
|
182
207
|
/** Serve-time resolved connections (see {@link setResolvedConnections}). */
|
|
183
208
|
this.resolvedConnections = [];
|
|
184
209
|
/** Sessions whose completed turns are fully priced (no further backfill). */
|
|
@@ -203,6 +228,7 @@ export class SessionEngine {
|
|
|
203
228
|
this.nudgeStore = new SlackNudgeStore(join(options.stateRoot, "slack-nudges"));
|
|
204
229
|
this.askDedupe = new SlackAskDedupeStore(join(options.stateRoot, "slack-asks"));
|
|
205
230
|
this.turnLeases = new TurnLeaseStore(join(options.stateRoot, "turn-leases"));
|
|
231
|
+
this.outbox = new TurnOutbox(join(options.stateRoot, "outbox"));
|
|
206
232
|
this.logs = new EventLogStore((sessionId) => this.sessions.eventFilePath(sessionId), (sessionId, error) => this.logger(`[agent-sdk] failed to persist events for ${sessionId}: ${describeError(error)}`));
|
|
207
233
|
// Framework session state (records, event chunks, continuations) is
|
|
208
234
|
// mirrored to whatever this selects; see framework-storage-selection.ts
|
|
@@ -284,10 +310,20 @@ export class SessionEngine {
|
|
|
284
310
|
setCloudServerToolsConnection(connection) {
|
|
285
311
|
this.cloudServerToolsConnection = connection;
|
|
286
312
|
}
|
|
313
|
+
setMcpOauthCallbackUrl(url) {
|
|
314
|
+
this.oauthHub.callbackUrl = url;
|
|
315
|
+
this.mcpHost.setOAuthRedirectUrl(url);
|
|
316
|
+
}
|
|
317
|
+
setCursorAccountAuthProbe(probe) {
|
|
318
|
+
this.probeCursorAccount = probe;
|
|
319
|
+
}
|
|
320
|
+
get oauthCallbackHub() {
|
|
321
|
+
return this.oauthHub;
|
|
322
|
+
}
|
|
287
323
|
/** Shared host services (MCP / GitHub / Slack / reminders / evals / kv / files / otel / Slack nudges). */
|
|
288
324
|
get host() {
|
|
289
325
|
return {
|
|
290
|
-
mcp: this.mcpHost,
|
|
326
|
+
mcp: this.wrapMcp(this.mcpHost),
|
|
291
327
|
github: this.platforms.github,
|
|
292
328
|
slack: this.platforms.slack,
|
|
293
329
|
reminders: this.reminderApi,
|
|
@@ -584,12 +620,33 @@ export class SessionEngine {
|
|
|
584
620
|
const now = new Date().toISOString();
|
|
585
621
|
const channelState = this.initialChannelState(channelId, sendOptions.state);
|
|
586
622
|
const purpose = sendOptions.purpose === "eval" ? "eval" : "live";
|
|
587
|
-
let record =
|
|
623
|
+
let record = {
|
|
624
|
+
sessionId: (_d = sendOptions.hostedSessionId) !== null && _d !== void 0 ? _d : newSessionId(),
|
|
625
|
+
channelId,
|
|
626
|
+
mode: (_e = sendOptions.mode) !== null && _e !== void 0 ? _e : "chat",
|
|
627
|
+
purpose,
|
|
628
|
+
dryRun: sendOptions.dryRun === true ? true : undefined,
|
|
629
|
+
continuationKey: (_f = sendOptions.continuationToken) !== null && _f !== void 0 ? _f : newContinuationKey(),
|
|
630
|
+
auth,
|
|
631
|
+
title: sendOptions.title,
|
|
632
|
+
channelState,
|
|
633
|
+
workspaceOverride: sendOptions.workspaceDir,
|
|
634
|
+
pendingWorkspaceFiles: sendOptions.workspaceFiles,
|
|
635
|
+
pendingImages: sendOptions.images,
|
|
636
|
+
cloudOverride: sendOptions.cloud,
|
|
637
|
+
sdkAgentId: sendOptions.sdkAgentId,
|
|
638
|
+
turnCount: 0,
|
|
639
|
+
createdAt: now,
|
|
640
|
+
updatedAt: now,
|
|
641
|
+
};
|
|
588
642
|
yield this.sessions.save(record);
|
|
589
643
|
(_a = this.storage) === null || _a === void 0 ? void 0 : _a.sessionRecord(record);
|
|
590
644
|
yield this.appendEvent(record.sessionId, {
|
|
591
645
|
type: "session.started",
|
|
592
|
-
data: {
|
|
646
|
+
data: {
|
|
647
|
+
channelId,
|
|
648
|
+
dryRun: record.dryRun === true ? true : undefined,
|
|
649
|
+
},
|
|
593
650
|
});
|
|
594
651
|
record = yield this.enrollABs(record);
|
|
595
652
|
const since = (yield this.logs.get(record.sessionId)).count;
|
|
@@ -791,10 +848,28 @@ export class SessionEngine {
|
|
|
791
848
|
const prior = (_a = this.admissionChains.get(sessionId)) !== null && _a !== void 0 ? _a : Promise.resolve();
|
|
792
849
|
const admitted = prior
|
|
793
850
|
.catch(() => { })
|
|
794
|
-
.then(() => this
|
|
851
|
+
.then(() => __awaiter(this, void 0, void 0, function* () {
|
|
852
|
+
// Another server holds the turn: hand the message to it and coalesce.
|
|
853
|
+
if (yield this.turnLeases.runningElsewhere(sessionId)) {
|
|
854
|
+
yield this.outbox.post(sessionId, { message, options });
|
|
855
|
+
return true;
|
|
856
|
+
}
|
|
857
|
+
return this.admitTurn(sessionId, message, options);
|
|
858
|
+
}));
|
|
795
859
|
this.admissionChains.set(sessionId, admitted.catch(() => { }));
|
|
796
860
|
return admitted;
|
|
797
861
|
}
|
|
862
|
+
/** Admit what other servers handed to this turn's holder. Never awaited by the lifecycle. */
|
|
863
|
+
drainOutbox(sessionId) {
|
|
864
|
+
void this.outbox
|
|
865
|
+
.takeAll(sessionId)
|
|
866
|
+
.then((items) => {
|
|
867
|
+
for (const item of items) {
|
|
868
|
+
void this.startTurn(sessionId, item.message, item.options).catch(() => { });
|
|
869
|
+
}
|
|
870
|
+
})
|
|
871
|
+
.catch(() => { });
|
|
872
|
+
}
|
|
798
873
|
enqueueCoalesced(sessionId, item) {
|
|
799
874
|
var _a;
|
|
800
875
|
const queue = (_a = this.coalesceQueues.get(sessionId)) !== null && _a !== void 0 ? _a : [];
|
|
@@ -1004,6 +1079,8 @@ export class SessionEngine {
|
|
|
1004
1079
|
let lifecycle;
|
|
1005
1080
|
lifecycle = (() => __awaiter(this, void 0, void 0, function* () {
|
|
1006
1081
|
let outcome;
|
|
1082
|
+
const poll = setInterval(() => this.drainOutbox(sessionId), 1000);
|
|
1083
|
+
poll.unref();
|
|
1007
1084
|
try {
|
|
1008
1085
|
outcome = yield this.executeTurn(record, turnId, message, isFirstTurn, abort.signal);
|
|
1009
1086
|
}
|
|
@@ -1013,6 +1090,9 @@ export class SessionEngine {
|
|
|
1013
1090
|
errorMessage: describeError(error),
|
|
1014
1091
|
};
|
|
1015
1092
|
}
|
|
1093
|
+
finally {
|
|
1094
|
+
clearInterval(poll);
|
|
1095
|
+
}
|
|
1016
1096
|
this.lastOutcomes.set(sessionId, outcome);
|
|
1017
1097
|
const wasCurrent = this.activeTurns.get(sessionId) === lifecycle;
|
|
1018
1098
|
if (wasCurrent) {
|
|
@@ -1038,6 +1118,10 @@ export class SessionEngine {
|
|
|
1038
1118
|
// The drain may have nested a successor turn, which took its own
|
|
1039
1119
|
// reference; the lease outlives this release until that one ends too.
|
|
1040
1120
|
yield lease.release();
|
|
1121
|
+
// Handed off between the last poll and the release: nobody else will.
|
|
1122
|
+
if (!abort.signal.aborted) {
|
|
1123
|
+
this.drainOutbox(sessionId);
|
|
1124
|
+
}
|
|
1041
1125
|
return outcome;
|
|
1042
1126
|
}))();
|
|
1043
1127
|
this.activeTurns.set(sessionId, lifecycle);
|
|
@@ -1087,6 +1171,7 @@ export class SessionEngine {
|
|
|
1087
1171
|
this.coalesceDrains.has(sessionId) ||
|
|
1088
1172
|
((_b = (_a = this.coalesceQueues.get(sessionId)) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0;
|
|
1089
1173
|
this.clearCoalesced(sessionId);
|
|
1174
|
+
yield this.outbox.clear(sessionId);
|
|
1090
1175
|
const record = yield this.sessions.get(sessionId);
|
|
1091
1176
|
const continuationKey = record === null || record === void 0 ? void 0 : record.continuationKey;
|
|
1092
1177
|
if (continuationKey !== undefined && continuationKey !== null) {
|
|
@@ -1275,6 +1360,7 @@ export class SessionEngine {
|
|
|
1275
1360
|
seed: isFirstTurn,
|
|
1276
1361
|
stateRoot: this.stateRoot,
|
|
1277
1362
|
});
|
|
1363
|
+
this.materializedWorkspaces.add(sessionId);
|
|
1278
1364
|
// Must precede the carrier: the harness resolves rules, skills,
|
|
1279
1365
|
// `mcp.json` and hooks from its git root, so a workspace nested in an
|
|
1280
1366
|
// outer repo would load that repo's hooks instead of the ones written
|
|
@@ -1337,12 +1423,15 @@ export class SessionEngine {
|
|
|
1337
1423
|
}
|
|
1338
1424
|
catch (error) {
|
|
1339
1425
|
this.approvals.cancelSession(sessionId, "deny");
|
|
1426
|
+
this.auths.cancelSession(sessionId, "deny");
|
|
1340
1427
|
outcome = { status: "error", errorMessage: describeError(error) };
|
|
1341
1428
|
}
|
|
1342
1429
|
finally {
|
|
1343
1430
|
permit.release();
|
|
1344
1431
|
this.approvals.cancelSession(sessionId, "deny");
|
|
1432
|
+
this.auths.cancelSession(sessionId, "deny");
|
|
1345
1433
|
yield this.clearPendingApprovals(sessionId);
|
|
1434
|
+
yield this.clearPendingAuths(sessionId);
|
|
1346
1435
|
// Anything still queued belongs to the next turn's boundary drain, not
|
|
1347
1436
|
// to this turn's edge detection.
|
|
1348
1437
|
this.deliveredNudges.delete(sessionId);
|
|
@@ -1833,11 +1922,17 @@ export class SessionEngine {
|
|
|
1833
1922
|
// named passthroughs resolved fresh on every turn — reminder fires and
|
|
1834
1923
|
// post-restart follow-ups included — and a listing failure throws,
|
|
1835
1924
|
// failing the turn closed.
|
|
1836
|
-
for (const tool of yield
|
|
1925
|
+
for (const tool of yield mcpAuthAls.run({
|
|
1926
|
+
sessionId: record.sessionId,
|
|
1927
|
+
turnId,
|
|
1928
|
+
callId: newToolCallId("mcp"),
|
|
1929
|
+
toolName: "mcp",
|
|
1930
|
+
emit,
|
|
1931
|
+
}, () => resolveAdvertisedTools({
|
|
1837
1932
|
agent,
|
|
1838
1933
|
session: this.sessionInfo(record),
|
|
1839
|
-
hostMcp: this.
|
|
1840
|
-
})) {
|
|
1934
|
+
hostMcp: this.advertiseMcp(),
|
|
1935
|
+
}))) {
|
|
1841
1936
|
register(tool);
|
|
1842
1937
|
}
|
|
1843
1938
|
return tools;
|
|
@@ -1945,7 +2040,13 @@ export class SessionEngine {
|
|
|
1945
2040
|
}
|
|
1946
2041
|
const started = Date.now();
|
|
1947
2042
|
this.logger(`[session] tool ${args.tool.name} start`);
|
|
1948
|
-
const result = yield
|
|
2043
|
+
const result = yield mcpAuthAls.run({
|
|
2044
|
+
sessionId: args.record.sessionId,
|
|
2045
|
+
turnId: args.turnId,
|
|
2046
|
+
callId: toolCallId,
|
|
2047
|
+
toolName: args.tool.name,
|
|
2048
|
+
emit: args.emit,
|
|
2049
|
+
}, () => execute(validation.value, toolCtx));
|
|
1949
2050
|
this.logger(`[session] tool ${args.tool.name} done (${Date.now() - started}ms)`);
|
|
1950
2051
|
return normalizeToolResult(result);
|
|
1951
2052
|
}
|
|
@@ -1970,7 +2071,7 @@ export class SessionEngine {
|
|
|
1970
2071
|
args: args.args,
|
|
1971
2072
|
requestedAt,
|
|
1972
2073
|
};
|
|
1973
|
-
const resolutionPromise = this.approvals.wait(
|
|
2074
|
+
const resolutionPromise = this.approvals.wait(args.sessionId, pendingRecord);
|
|
1974
2075
|
yield this.updateRecord(args.sessionId, (current) => { var _a; return (Object.assign(Object.assign({}, current), { pendingApprovals: [
|
|
1975
2076
|
...((_a = current.pendingApprovals) !== null && _a !== void 0 ? _a : []).filter((item) => item.callId !== args.callId),
|
|
1976
2077
|
pendingRecord,
|
|
@@ -2056,6 +2157,245 @@ export class SessionEngine {
|
|
|
2056
2157
|
yield this.updateRecord(sessionId, (current) => { var _a; return (Object.assign(Object.assign({}, current), { pendingApprovals: ((_a = current.pendingApprovals) !== null && _a !== void 0 ? _a : []).filter((item) => item.callId !== callId) })); });
|
|
2057
2158
|
});
|
|
2058
2159
|
}
|
|
2160
|
+
wrapMcp(inner) {
|
|
2161
|
+
return {
|
|
2162
|
+
names: () => inner.names(),
|
|
2163
|
+
listTools: (name) => this.withMcpAuth(name, () => inner.listTools(name)),
|
|
2164
|
+
callTool: (name, tool, args) => this.withMcpAuth(name, () => inner.callTool(name, tool, args)),
|
|
2165
|
+
};
|
|
2166
|
+
}
|
|
2167
|
+
advertiseMcp() {
|
|
2168
|
+
return {
|
|
2169
|
+
listTools: (name) => this.withMcpListAuth(name, () => this.mcpHost.listTools(name)),
|
|
2170
|
+
callTool: (name, tool, args) => this.withMcpAuth(name, () => this.mcpHost.callTool(name, tool, args)),
|
|
2171
|
+
oneOff: (connection) => {
|
|
2172
|
+
const inner = this.mcpHost.oneOff(connection);
|
|
2173
|
+
return {
|
|
2174
|
+
listTools: () => this.withMcpListAuth(connection.name, () => inner.listTools()),
|
|
2175
|
+
callTool: (tool, args) => this.withMcpAuth(connection.name, () => inner.callTool(tool, args)),
|
|
2176
|
+
};
|
|
2177
|
+
},
|
|
2178
|
+
};
|
|
2179
|
+
}
|
|
2180
|
+
withMcpListAuth(connection, run) {
|
|
2181
|
+
const ctx = mcpAuthAls.getStore();
|
|
2182
|
+
if (ctx === undefined) {
|
|
2183
|
+
return this.withMcpAuth(connection, run);
|
|
2184
|
+
}
|
|
2185
|
+
const toolName = `mcp:${connection}`;
|
|
2186
|
+
return mcpAuthAls.run(Object.assign(Object.assign({}, ctx), { callId: newToolCallId(toolName), toolName }), () => this.withMcpAuth(connection, run));
|
|
2187
|
+
}
|
|
2188
|
+
withMcpAuth(connection, run) {
|
|
2189
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2190
|
+
try {
|
|
2191
|
+
return yield run();
|
|
2192
|
+
}
|
|
2193
|
+
catch (error) {
|
|
2194
|
+
if (!isMcpNeedsAuthError(error)) {
|
|
2195
|
+
throw error;
|
|
2196
|
+
}
|
|
2197
|
+
return yield this.parkAndRetryMcp(connection, run, error);
|
|
2198
|
+
}
|
|
2199
|
+
});
|
|
2200
|
+
}
|
|
2201
|
+
parkAndRetryMcp(connection, run, error) {
|
|
2202
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2203
|
+
const ctx = mcpAuthAls.getStore();
|
|
2204
|
+
if (ctx === undefined) {
|
|
2205
|
+
throw error;
|
|
2206
|
+
}
|
|
2207
|
+
const minted = yield this.mintAuthUrl(connection, ctx.sessionId);
|
|
2208
|
+
if (minted === undefined) {
|
|
2209
|
+
throw error;
|
|
2210
|
+
}
|
|
2211
|
+
if ("authorized" in minted) {
|
|
2212
|
+
yield this.persistHostedMcpOauth(connection);
|
|
2213
|
+
yield this.mcpHost.dropClient(connection);
|
|
2214
|
+
return yield this.withMcpAuth(connection, run);
|
|
2215
|
+
}
|
|
2216
|
+
if (minted.state !== "") {
|
|
2217
|
+
const bind = this.oauthHub.bind(minted.state, ctx.sessionId, ctx.callId);
|
|
2218
|
+
if (bind === "already_done") {
|
|
2219
|
+
yield this.persistHostedMcpOauth(connection);
|
|
2220
|
+
yield this.mcpHost.dropClient(connection);
|
|
2221
|
+
return yield this.withMcpAuth(connection, run);
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
const decision = yield this.parkForAuth({
|
|
2225
|
+
sessionId: ctx.sessionId,
|
|
2226
|
+
turnId: ctx.turnId,
|
|
2227
|
+
callId: ctx.callId,
|
|
2228
|
+
toolName: ctx.toolName,
|
|
2229
|
+
connection,
|
|
2230
|
+
authUrl: minted.authUrl,
|
|
2231
|
+
emit: ctx.emit,
|
|
2232
|
+
});
|
|
2233
|
+
if (decision === "deny") {
|
|
2234
|
+
throw new Error(`MCP connection "${connection}" authorization was denied.`);
|
|
2235
|
+
}
|
|
2236
|
+
yield this.persistHostedMcpOauth(connection);
|
|
2237
|
+
yield this.mcpHost.dropClient(connection);
|
|
2238
|
+
return yield this.withMcpAuth(connection, run);
|
|
2239
|
+
});
|
|
2240
|
+
}
|
|
2241
|
+
persistHostedMcpOauth(connection) {
|
|
2242
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2243
|
+
const authored = this.authoredConnection(connection);
|
|
2244
|
+
if (authored === undefined ||
|
|
2245
|
+
!isHostOauthConnectionTransport(authored.transport)) {
|
|
2246
|
+
return;
|
|
2247
|
+
}
|
|
2248
|
+
yield this.oauthHub.persistFor(connection, authored.transport.url);
|
|
2249
|
+
});
|
|
2250
|
+
}
|
|
2251
|
+
authoredConnection(name) {
|
|
2252
|
+
var _a;
|
|
2253
|
+
var _b;
|
|
2254
|
+
return ((_b = this.project.agent.connections.find((entry) => entry.name === name)) !== null && _b !== void 0 ? _b : (_a = this.project.agent.hostConnections) === null || _a === void 0 ? void 0 : _a.find((entry) => entry.name === name));
|
|
2255
|
+
}
|
|
2256
|
+
mintAuthUrl(connection, sessionId) {
|
|
2257
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2258
|
+
const authored = this.authoredConnection(connection);
|
|
2259
|
+
if (authored === undefined) {
|
|
2260
|
+
return undefined;
|
|
2261
|
+
}
|
|
2262
|
+
if (isCursorAccountTransport(authored.transport)) {
|
|
2263
|
+
const probe = this.probeCursorAccount;
|
|
2264
|
+
if (probe === undefined) {
|
|
2265
|
+
return undefined;
|
|
2266
|
+
}
|
|
2267
|
+
const authUrl = yield probe(connection);
|
|
2268
|
+
if (authUrl === undefined || authUrl === "") {
|
|
2269
|
+
return undefined;
|
|
2270
|
+
}
|
|
2271
|
+
return { authUrl, state: "" };
|
|
2272
|
+
}
|
|
2273
|
+
if (!isHostOauthConnectionTransport(authored.transport)) {
|
|
2274
|
+
return undefined;
|
|
2275
|
+
}
|
|
2276
|
+
return yield this.oauthHub.mint({
|
|
2277
|
+
connection,
|
|
2278
|
+
url: authored.transport.url,
|
|
2279
|
+
type: authored.transport.type === "sse" ? "sse" : "http",
|
|
2280
|
+
headers: authored.transport.headers,
|
|
2281
|
+
sessionId,
|
|
2282
|
+
});
|
|
2283
|
+
});
|
|
2284
|
+
}
|
|
2285
|
+
parkForAuth(args) {
|
|
2286
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2287
|
+
const requestedAt = new Date().toISOString();
|
|
2288
|
+
const pendingRecord = {
|
|
2289
|
+
callId: args.callId,
|
|
2290
|
+
turnId: args.turnId,
|
|
2291
|
+
toolName: args.toolName,
|
|
2292
|
+
connection: args.connection,
|
|
2293
|
+
authUrl: args.authUrl,
|
|
2294
|
+
requestedAt,
|
|
2295
|
+
};
|
|
2296
|
+
const resolutionPromise = this.auths.wait(args.sessionId, pendingRecord);
|
|
2297
|
+
yield this.updateRecord(args.sessionId, (current) => { var _a; return (Object.assign(Object.assign({}, current), { pendingAuths: [
|
|
2298
|
+
...((_a = current.pendingAuths) !== null && _a !== void 0 ? _a : []).filter((item) => item.callId !== args.callId),
|
|
2299
|
+
pendingRecord,
|
|
2300
|
+
] })); });
|
|
2301
|
+
args.emit({
|
|
2302
|
+
type: "action.auth_requested",
|
|
2303
|
+
data: {
|
|
2304
|
+
callId: args.callId,
|
|
2305
|
+
toolName: args.toolName,
|
|
2306
|
+
connection: args.connection,
|
|
2307
|
+
authUrl: args.authUrl,
|
|
2308
|
+
},
|
|
2309
|
+
});
|
|
2310
|
+
this.logger(`[session] tool ${args.toolName} awaiting MCP auth ${args.connection} (${args.callId})`);
|
|
2311
|
+
const { decision, by } = yield resolutionPromise;
|
|
2312
|
+
yield this.updateRecord(args.sessionId, (current) => { var _a; return (Object.assign(Object.assign({}, current), { pendingAuths: ((_a = current.pendingAuths) !== null && _a !== void 0 ? _a : []).filter((item) => item.callId !== args.callId) })); });
|
|
2313
|
+
args.emit({
|
|
2314
|
+
type: "action.auth_resolved",
|
|
2315
|
+
data: {
|
|
2316
|
+
callId: args.callId,
|
|
2317
|
+
toolName: args.toolName,
|
|
2318
|
+
connection: args.connection,
|
|
2319
|
+
decision,
|
|
2320
|
+
by,
|
|
2321
|
+
},
|
|
2322
|
+
});
|
|
2323
|
+
this.logger(`[session] tool ${args.toolName} MCP auth ${decision} (${args.callId})`);
|
|
2324
|
+
return decision;
|
|
2325
|
+
});
|
|
2326
|
+
}
|
|
2327
|
+
clearPendingAuths(sessionId) {
|
|
2328
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2329
|
+
yield this.oauthHub.abortSession(sessionId);
|
|
2330
|
+
const current = yield this.sessions.get(sessionId);
|
|
2331
|
+
if (current === undefined ||
|
|
2332
|
+
current.pendingAuths === undefined ||
|
|
2333
|
+
current.pendingAuths.length === 0) {
|
|
2334
|
+
return;
|
|
2335
|
+
}
|
|
2336
|
+
yield this.updateRecord(sessionId, (record) => (Object.assign(Object.assign({}, record), { pendingAuths: [] })));
|
|
2337
|
+
});
|
|
2338
|
+
}
|
|
2339
|
+
listPendingAuths(sessionId) {
|
|
2340
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2341
|
+
var _a;
|
|
2342
|
+
const record = yield this.sessions.get(sessionId);
|
|
2343
|
+
if (record === undefined) {
|
|
2344
|
+
return [];
|
|
2345
|
+
}
|
|
2346
|
+
const live = this.auths.list(sessionId);
|
|
2347
|
+
if (live.length > 0) {
|
|
2348
|
+
return live;
|
|
2349
|
+
}
|
|
2350
|
+
return (_a = record.pendingAuths) !== null && _a !== void 0 ? _a : [];
|
|
2351
|
+
});
|
|
2352
|
+
}
|
|
2353
|
+
resolveAuth(sessionId, callId, decision, auth, options) {
|
|
2354
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2355
|
+
var _a, _b;
|
|
2356
|
+
const record = yield this.sessions.get(sessionId);
|
|
2357
|
+
if (record === undefined) {
|
|
2358
|
+
throw new AuthNotFoundError(sessionId, callId);
|
|
2359
|
+
}
|
|
2360
|
+
const ownershipAuth = (options === null || options === void 0 ? void 0 : options.asSessionOwner) === true ? record.auth : auth;
|
|
2361
|
+
if (!samePrincipal(record.auth, ownershipAuth)) {
|
|
2362
|
+
throw new SessionAuthError(sessionId);
|
|
2363
|
+
}
|
|
2364
|
+
const pending = (_b = ((_a = record.pendingAuths) !== null && _a !== void 0 ? _a : []).find((item) => item.callId === callId)) !== null && _b !== void 0 ? _b : this.auths.list(sessionId).find((item) => item.callId === callId);
|
|
2365
|
+
if (pending === undefined) {
|
|
2366
|
+
throw new AuthNotFoundError(sessionId, callId);
|
|
2367
|
+
}
|
|
2368
|
+
const resolvedBy = approvalResolverLabel(auth);
|
|
2369
|
+
if (decision === "deny") {
|
|
2370
|
+
yield this.oauthHub.abortCall(sessionId, callId);
|
|
2371
|
+
}
|
|
2372
|
+
if (!this.auths.resolve(sessionId, callId, decision, resolvedBy)) {
|
|
2373
|
+
yield this.removePendingAuth(sessionId, callId);
|
|
2374
|
+
throw new AuthInterruptedError(sessionId, callId);
|
|
2375
|
+
}
|
|
2376
|
+
return pending;
|
|
2377
|
+
});
|
|
2378
|
+
}
|
|
2379
|
+
removePendingAuth(sessionId, callId) {
|
|
2380
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2381
|
+
yield this.updateRecord(sessionId, (current) => { var _a; return (Object.assign(Object.assign({}, current), { pendingAuths: ((_a = current.pendingAuths) !== null && _a !== void 0 ? _a : []).filter((item) => item.callId !== callId) })); });
|
|
2382
|
+
});
|
|
2383
|
+
}
|
|
2384
|
+
runWithMcpPark(sessionId, toolName, fn) {
|
|
2385
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2386
|
+
const active = this.activeToolContexts.get(sessionId);
|
|
2387
|
+
if (active === undefined) {
|
|
2388
|
+
return fn();
|
|
2389
|
+
}
|
|
2390
|
+
return mcpAuthAls.run({
|
|
2391
|
+
sessionId,
|
|
2392
|
+
turnId: active.turnId,
|
|
2393
|
+
callId: newToolCallId(toolName),
|
|
2394
|
+
toolName,
|
|
2395
|
+
emit: active.emit,
|
|
2396
|
+
}, fn);
|
|
2397
|
+
});
|
|
2398
|
+
}
|
|
2059
2399
|
// ==========================================================================
|
|
2060
2400
|
// Direct tool calls (deterministic invocation, no model turn)
|
|
2061
2401
|
// ==========================================================================
|
|
@@ -2070,8 +2410,10 @@ export class SessionEngine {
|
|
|
2070
2410
|
* and materialized workspace) and the call is recorded on the session's
|
|
2071
2411
|
* event stream as `actions.requested` / `action.result` under a
|
|
2072
2412
|
* per-call `turnId` (the call id), so it shows up in trajectories.
|
|
2073
|
-
*
|
|
2074
|
-
*
|
|
2413
|
+
* While a model turn is running, a read-effect call runs alongside it
|
|
2414
|
+
* (the turn's workspace is read as-is) and a write-effect call is
|
|
2415
|
+
* rejected with {@link SessionBusyError}. Without a session, the tool
|
|
2416
|
+
* runs against an **ephemeral** scratch
|
|
2075
2417
|
* workspace under `<stateRoot>/tool-calls/<callId>` (materialized with
|
|
2076
2418
|
* seed files, removed after the call returns).
|
|
2077
2419
|
*
|
|
@@ -2111,26 +2453,22 @@ export class SessionEngine {
|
|
|
2111
2453
|
throw new InvalidContinuationTokenError(`expected "<channelId>:<key>" (as /v1/sessions lists it), got "${options.continuationToken}"`);
|
|
2112
2454
|
}
|
|
2113
2455
|
// A token that maps to a live (or restorable) session takes the
|
|
2114
|
-
// session path: same owner check, same
|
|
2115
|
-
//
|
|
2116
|
-
//
|
|
2456
|
+
// session path: same owner check, same busy semantics, same event
|
|
2457
|
+
// recording as an explicit sessionId. Skipping those just because
|
|
2458
|
+
// the caller addressed the session by token would fail open.
|
|
2117
2459
|
record = (_b = (yield this.sessions.findByContinuation(continuation.channelId, continuation.key))) !== null && _b !== void 0 ? _b : (yield this.restoreSessionByContinuation(continuation.channelId, continuation.key));
|
|
2118
2460
|
if (record !== undefined && !samePrincipal(record.auth, auth)) {
|
|
2119
2461
|
throw new SessionAuthError(record.sessionId);
|
|
2120
2462
|
}
|
|
2121
2463
|
}
|
|
2122
2464
|
if (record !== undefined) {
|
|
2123
|
-
// Direct calls respect the same serialization as follow-up sends: a
|
|
2124
|
-
// running model turn owns the session workspace and event stream.
|
|
2125
|
-
if (this.activeTurns.has(record.sessionId) ||
|
|
2126
|
-
this.pendingTurns.has(record.sessionId)) {
|
|
2127
|
-
throw new SessionBusyError(record.sessionId);
|
|
2128
|
-
}
|
|
2129
2465
|
return {
|
|
2130
2466
|
record,
|
|
2131
2467
|
session: this.sessionInfo(record),
|
|
2132
2468
|
workspaceDir: this.harnessCwd(record),
|
|
2133
2469
|
scratchDir: undefined,
|
|
2470
|
+
busy: this.activeTurns.has(record.sessionId) ||
|
|
2471
|
+
this.pendingTurns.has(record.sessionId),
|
|
2134
2472
|
};
|
|
2135
2473
|
}
|
|
2136
2474
|
// No session behind the token (or no token at all): a synthetic
|
|
@@ -2150,6 +2488,7 @@ export class SessionEngine {
|
|
|
2150
2488
|
},
|
|
2151
2489
|
workspaceDir: scratchDir,
|
|
2152
2490
|
scratchDir,
|
|
2491
|
+
busy: false,
|
|
2153
2492
|
};
|
|
2154
2493
|
});
|
|
2155
2494
|
}
|
|
@@ -2182,8 +2521,32 @@ export class SessionEngine {
|
|
|
2182
2521
|
};
|
|
2183
2522
|
});
|
|
2184
2523
|
}
|
|
2524
|
+
/**
|
|
2525
|
+
* One catalog tool by name. Authored tools are local — their schema does
|
|
2526
|
+
* not depend on session identity or connection listings — so a detail
|
|
2527
|
+
* fetch for `ls` must not wait on every advertised MCP server.
|
|
2528
|
+
*/
|
|
2529
|
+
describeCatalogTool(toolName_1) {
|
|
2530
|
+
return __awaiter(this, arguments, void 0, function* (toolName, options = {}) {
|
|
2531
|
+
const authored = this.project.agent.tools.find((tool) => tool.name === toolName);
|
|
2532
|
+
if (authored !== undefined) {
|
|
2533
|
+
return { tool: authored };
|
|
2534
|
+
}
|
|
2535
|
+
const catalog = yield this.listCatalogTools(options);
|
|
2536
|
+
const tool = catalog.tools.find((entry) => entry.name === toolName);
|
|
2537
|
+
if (tool === undefined) {
|
|
2538
|
+
return {
|
|
2539
|
+
tool: undefined,
|
|
2540
|
+
availableTools: catalog.tools.map((entry) => entry.name),
|
|
2541
|
+
connectionErrors: catalog.connectionErrors,
|
|
2542
|
+
};
|
|
2543
|
+
}
|
|
2544
|
+
return { tool };
|
|
2545
|
+
});
|
|
2546
|
+
}
|
|
2185
2547
|
callTool(toolName_1) {
|
|
2186
2548
|
return __awaiter(this, arguments, void 0, function* (toolName, input = {}, options = {}) {
|
|
2549
|
+
var _a;
|
|
2187
2550
|
const callId = newToolCallId(toolName);
|
|
2188
2551
|
// Identity resolves before the tool lookup: advertised connection tools
|
|
2189
2552
|
// only exist relative to a session (per-session auth), so finding them
|
|
@@ -2203,7 +2566,7 @@ export class SessionEngine {
|
|
|
2203
2566
|
const advertised = yield resolveAdvertisedTools({
|
|
2204
2567
|
agent: this.project.agent,
|
|
2205
2568
|
session,
|
|
2206
|
-
hostMcp: this.
|
|
2569
|
+
hostMcp: this.advertiseMcp(),
|
|
2207
2570
|
});
|
|
2208
2571
|
tool = advertised.find((t) => t.name === toolName);
|
|
2209
2572
|
}
|
|
@@ -2220,6 +2583,17 @@ export class SessionEngine {
|
|
|
2220
2583
|
if (!validation.ok) {
|
|
2221
2584
|
throw new ToolInputError({ toolName, detail: validation.message });
|
|
2222
2585
|
}
|
|
2586
|
+
// A running model turn owns the session workspace: a direct write would
|
|
2587
|
+
// race the harness's own edits, so it waits (409). A read runs alongside
|
|
2588
|
+
// the turn — the operator inspecting a live session is the point — and
|
|
2589
|
+
// its events stay separable by their per-call turnId. The effect can
|
|
2590
|
+
// depend on the input, hence deciding after validation; an MCP tool
|
|
2591
|
+
// nothing classifies is a write here, fail-closed.
|
|
2592
|
+
if (identity.busy &&
|
|
2593
|
+
record !== undefined &&
|
|
2594
|
+
directCallEffect(tool, validation.value) !== "read") {
|
|
2595
|
+
throw new SessionBusyError(record.sessionId);
|
|
2596
|
+
}
|
|
2223
2597
|
let workspaceUnavailable = false;
|
|
2224
2598
|
try {
|
|
2225
2599
|
yield mkdir(workspaceDir, { recursive: true });
|
|
@@ -2239,28 +2613,50 @@ export class SessionEngine {
|
|
|
2239
2613
|
// to write) authored tool may rely on ctx.workspaceDir being the
|
|
2240
2614
|
// real session workspace, so silently relocating it is not safe —
|
|
2241
2615
|
// fail typed instead.
|
|
2616
|
+
//
|
|
2617
|
+
// A shared `local.workspaceDir` (change-monitor's phantom /repo) is
|
|
2618
|
+
// that path by design. Relocating it to scratch would flag a false
|
|
2619
|
+
// session-state warning; keep the borrowed cwd and skip the flag.
|
|
2242
2620
|
const relocatable = tool.advertised === true ||
|
|
2243
|
-
|
|
2621
|
+
directCallEffect(tool, validation.value) === "read";
|
|
2244
2622
|
if (!relocatable) {
|
|
2245
2623
|
throw new WorkspaceUnavailableError(toolName, error);
|
|
2246
2624
|
}
|
|
2247
|
-
this.
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2625
|
+
if (((_a = this.project.agent.local) === null || _a === void 0 ? void 0 : _a.workspaceDir) !== undefined) {
|
|
2626
|
+
this.logger(`[session] tool ${toolName} harness cwd unavailable (direct ${callId}); keeping borrowed workspace`);
|
|
2627
|
+
}
|
|
2628
|
+
else {
|
|
2629
|
+
this.logger(`[session] tool ${toolName} workspace unavailable (direct ${callId}); using scratch: ${error instanceof Error ? error.message : String(error)}`);
|
|
2630
|
+
scratchDir = join(this.stateRoot, "tool-calls", callId);
|
|
2631
|
+
workspaceDir = scratchDir;
|
|
2632
|
+
workspaceUnavailable = true;
|
|
2633
|
+
yield mkdir(workspaceDir, { recursive: true });
|
|
2634
|
+
}
|
|
2252
2635
|
}
|
|
2253
2636
|
// Match what a model turn would see: session workspaces get the same
|
|
2254
2637
|
// scaffold as executeTurn (seeds only before the first turn); scratch
|
|
2255
|
-
// workspaces are materialized fresh.
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2638
|
+
// workspaces are materialized fresh. A read running alongside a turn
|
|
2639
|
+
// that has materialized its workspace leaves it alone — re-seeding
|
|
2640
|
+
// would restore files the agent deleted mid-turn. A session is busy
|
|
2641
|
+
// from admit, though, so a read that lands while the first turn is
|
|
2642
|
+
// still queued or scaffolding materializes the workspace itself, seeds
|
|
2643
|
+
// included (turnCount is already 1 for that pending first turn).
|
|
2644
|
+
const turnMaterialized = record !== undefined &&
|
|
2645
|
+
identity.busy &&
|
|
2646
|
+
this.materializedWorkspaces.has(record.sessionId);
|
|
2647
|
+
if (record === undefined || workspaceUnavailable || !turnMaterialized) {
|
|
2648
|
+
yield materializeWorkspace({
|
|
2649
|
+
agent: this.project.agent,
|
|
2650
|
+
workspaceDir: record === undefined || workspaceUnavailable
|
|
2651
|
+
? workspaceDir
|
|
2652
|
+
: this.scaffoldDir(record),
|
|
2653
|
+
seed: record === undefined ||
|
|
2654
|
+
workspaceUnavailable ||
|
|
2655
|
+
record.turnCount === 0 ||
|
|
2656
|
+
(identity.busy && record.turnCount === 1),
|
|
2657
|
+
stateRoot: this.stateRoot,
|
|
2658
|
+
});
|
|
2659
|
+
}
|
|
2264
2660
|
// A per-call turnId keeps these events visible in trajectories (which
|
|
2265
2661
|
// drop turn-less action events) without attributing them to a model turn.
|
|
2266
2662
|
if (record !== undefined) {
|
|
@@ -2303,7 +2699,7 @@ export class SessionEngine {
|
|
|
2303
2699
|
isError = false;
|
|
2304
2700
|
}
|
|
2305
2701
|
else {
|
|
2306
|
-
|
|
2702
|
+
const run = () => execute(validation.value, {
|
|
2307
2703
|
toolCallId: callId,
|
|
2308
2704
|
session,
|
|
2309
2705
|
workspaceDir,
|
|
@@ -2321,7 +2717,16 @@ export class SessionEngine {
|
|
|
2321
2717
|
: session.auth })),
|
|
2322
2718
|
getSession: (channelId, sessionId) => this.getChannelSession(channelId, sessionId),
|
|
2323
2719
|
emit,
|
|
2324
|
-
})
|
|
2720
|
+
});
|
|
2721
|
+
result = normalizeToolResult(record !== undefined && emit !== undefined
|
|
2722
|
+
? yield mcpAuthAls.run({
|
|
2723
|
+
sessionId: record.sessionId,
|
|
2724
|
+
turnId: callId,
|
|
2725
|
+
callId,
|
|
2726
|
+
toolName,
|
|
2727
|
+
emit,
|
|
2728
|
+
}, run)
|
|
2729
|
+
: yield run());
|
|
2325
2730
|
isError = isErrorEnvelope(result);
|
|
2326
2731
|
}
|
|
2327
2732
|
}
|
|
@@ -2688,6 +3093,64 @@ export class SessionEngine {
|
|
|
2688
3093
|
};
|
|
2689
3094
|
});
|
|
2690
3095
|
}
|
|
3096
|
+
/**
|
|
3097
|
+
* The single newest session visible to `caller` (`GET /v1/sessions?latest=1`).
|
|
3098
|
+
*
|
|
3099
|
+
* Short-circuits the full listing: the local store already holds every
|
|
3100
|
+
* session this host created plus the startup bulk restore, so the common
|
|
3101
|
+
* case answers from memory without a sink round trip. Only when the local
|
|
3102
|
+
* store has nothing for the caller (fresh host, `restore: "off"`) does it
|
|
3103
|
+
* ask the sink — for a bounded newest-written window when the backend
|
|
3104
|
+
* can order by write time, else the full list. A session written by
|
|
3105
|
+
* another replica moments ago can lose to a local one; callers that need
|
|
3106
|
+
* the exact newest row should use the full listing.
|
|
3107
|
+
*/
|
|
3108
|
+
latestSessionWithSource(caller, options) {
|
|
3109
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3110
|
+
var _a;
|
|
3111
|
+
var _b;
|
|
3112
|
+
const includeAll = (_b = options === null || options === void 0 ? void 0 : options.includeAll) !== null && _b !== void 0 ? _b : false;
|
|
3113
|
+
const newestVisible = (records) => {
|
|
3114
|
+
let newest;
|
|
3115
|
+
for (const record of records) {
|
|
3116
|
+
if (!(includeAll || samePrincipal(record.auth, caller))) {
|
|
3117
|
+
continue;
|
|
3118
|
+
}
|
|
3119
|
+
if (newest === undefined ||
|
|
3120
|
+
record.updatedAt.localeCompare(newest.updatedAt) > 0) {
|
|
3121
|
+
newest = record;
|
|
3122
|
+
}
|
|
3123
|
+
}
|
|
3124
|
+
return newest;
|
|
3125
|
+
};
|
|
3126
|
+
const local = newestVisible(yield this.sessions.list());
|
|
3127
|
+
if (local !== undefined) {
|
|
3128
|
+
return {
|
|
3129
|
+
sessions: this.summarizeSessionRecords([local], caller, includeAll),
|
|
3130
|
+
source: "local",
|
|
3131
|
+
};
|
|
3132
|
+
}
|
|
3133
|
+
if (((_a = this.storage) === null || _a === void 0 ? void 0 : _a.isCursorHosted) === true) {
|
|
3134
|
+
try {
|
|
3135
|
+
const window = yield this.storage.listNewestSessionsFromSink(LATEST_SESSION_SINK_WINDOW);
|
|
3136
|
+
if (window !== undefined) {
|
|
3137
|
+
const stored = newestVisible(window);
|
|
3138
|
+
if (stored !== undefined) {
|
|
3139
|
+
return {
|
|
3140
|
+
sessions: this.summarizeSessionRecords([stored], caller, includeAll),
|
|
3141
|
+
source: "cursor-hosted",
|
|
3142
|
+
};
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
catch (error) {
|
|
3147
|
+
this.logger(`[agent-sdk] cursor-hosted newest-session lookup failed; falling back to the full list: ${describeError(error)}`);
|
|
3148
|
+
}
|
|
3149
|
+
}
|
|
3150
|
+
const listed = yield this.listSessionsWithSource(caller, options);
|
|
3151
|
+
return { sessions: listed.sessions.slice(0, 1), source: listed.source };
|
|
3152
|
+
});
|
|
3153
|
+
}
|
|
2691
3154
|
/**
|
|
2692
3155
|
* Durable sink rows plus local records (local wins on the same id when
|
|
2693
3156
|
* newer — covers debounce windows that have not flushed yet). Newest
|
|
@@ -2734,6 +3197,7 @@ export class SessionEngine {
|
|
|
2734
3197
|
: undefined,
|
|
2735
3198
|
createdAt: record.createdAt,
|
|
2736
3199
|
updatedAt: record.updatedAt,
|
|
3200
|
+
dryRun: record.dryRun === true ? true : undefined,
|
|
2737
3201
|
continuationToken: record.httpContinuationKey !== undefined
|
|
2738
3202
|
? formatContinuationToken(HTTP_CHANNEL_ID, record.httpContinuationKey)
|
|
2739
3203
|
: record.continuationKey === null
|
|
@@ -3006,7 +3470,7 @@ export class SessionEngine {
|
|
|
3006
3470
|
this.coalesceDrains.has(sessionId));
|
|
3007
3471
|
}
|
|
3008
3472
|
sessionInfo(record) {
|
|
3009
|
-
return Object.assign(Object.assign(Object.assign(
|
|
3473
|
+
return Object.assign(Object.assign(Object.assign({ id: record.sessionId, channelId: record.channelId, mode: record.mode, purpose: record.purpose === "eval" ? "eval" : "live", dryRun: record.dryRun === true ? true : undefined, auth: record.auth, continuationKey: record.continuationKey }, (record.abs === undefined ? {} : { abs: record.abs })), (record.title === undefined ? {} : { title: record.title })), (record.sdkAgentId === undefined
|
|
3010
3474
|
? {}
|
|
3011
3475
|
: { sdkAgentId: record.sdkAgentId }));
|
|
3012
3476
|
}
|
|
@@ -3291,6 +3755,8 @@ export class SessionEngine {
|
|
|
3291
3755
|
var _a, _b, _c, _d, _e;
|
|
3292
3756
|
(_a = this.stopMemoryTelemetry) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
3293
3757
|
this.approvals.cancelAll("deny");
|
|
3758
|
+
this.auths.cancelAll("deny");
|
|
3759
|
+
yield this.oauthHub.close();
|
|
3294
3760
|
yield Promise.allSettled([...this.activeTurns.values()]);
|
|
3295
3761
|
yield Promise.allSettled([...this.backgroundWork]);
|
|
3296
3762
|
yield Promise.allSettled([...this.dispatchChains.values()]);
|
|
@@ -3307,6 +3773,12 @@ export class SessionEngine {
|
|
|
3307
3773
|
}
|
|
3308
3774
|
/** Parallel event-stream loads during the startup bulk restore. */
|
|
3309
3775
|
const RESTORE_FETCH_CONCURRENCY = 8;
|
|
3776
|
+
/**
|
|
3777
|
+
* Newest-written sink rows fetched for `GET /v1/sessions?latest=1` when the
|
|
3778
|
+
* local store has nothing for the caller. Wide enough that the caller's own
|
|
3779
|
+
* session is normally inside it even when other principals are busier.
|
|
3780
|
+
*/
|
|
3781
|
+
const LATEST_SESSION_SINK_WINDOW = 50;
|
|
3310
3782
|
/** NDJSON payload for a restored event stream; undefined when empty. */
|
|
3311
3783
|
function mergePendingImages(current, incoming) {
|
|
3312
3784
|
if (incoming === undefined) {
|