pi-cursor-sdk 0.1.62 → 0.3.6
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/CHANGELOG.md +85 -0
- package/README.md +57 -53
- package/dist/bundled-context-windows.js +39 -0
- package/dist/context-window-cache.js +92 -0
- package/dist/context.js +338 -0
- package/dist/cursor-active-tools.js +3 -0
- package/dist/cursor-agent-message-web-tools.js +165 -0
- package/dist/cursor-agents-context-registration.js +17 -0
- package/dist/cursor-agents-context.js +113 -0
- package/dist/cursor-api-key.js +34 -0
- package/dist/cursor-bridge-contract.js +27 -0
- package/dist/cursor-cloud-lifecycle.js +650 -0
- package/dist/cursor-cloud-local-state.js +460 -0
- package/dist/cursor-cloud-options.js +145 -0
- package/dist/cursor-cloud-reporting.js +222 -0
- package/dist/cursor-compact-tool-summary.js +75 -0
- package/dist/cursor-config.js +613 -0
- package/dist/cursor-context-tools.js +4 -0
- package/dist/cursor-display-only-trace.js +11 -0
- package/dist/cursor-display-text.js +18 -0
- package/dist/cursor-durable-fs.js +53 -0
- package/dist/cursor-edit-diff.js +13 -0
- package/dist/cursor-env-boolean.js +19 -0
- package/dist/cursor-fallback-models.generated.js +7760 -0
- package/dist/cursor-fallback-warning.js +15 -0
- package/dist/cursor-http1.js +45 -0
- package/dist/cursor-incomplete-tool-visibility.js +83 -0
- package/dist/cursor-live-run-accounting.js +55 -0
- package/dist/cursor-live-run-coordinator.js +406 -0
- package/dist/cursor-mcp-timeout-override.js +116 -0
- package/dist/cursor-model-lifecycle.js +32 -0
- package/dist/cursor-model.js +5 -0
- package/dist/cursor-native-replay-routing.js +35 -0
- package/dist/cursor-native-replay-trace.js +28 -0
- package/dist/cursor-native-tool-display-registration.js +102 -0
- package/dist/cursor-native-tool-display-replay.js +428 -0
- package/dist/cursor-native-tool-display-state.js +70 -0
- package/dist/cursor-native-tool-display-tools.js +123 -0
- package/dist/cursor-native-tool-names.js +11 -0
- package/dist/cursor-partial-content-emitter.js +118 -0
- package/dist/cursor-pi-tool-bridge-abort.js +114 -0
- package/dist/cursor-pi-tool-bridge-constants.js +6 -0
- package/dist/cursor-pi-tool-bridge-diagnostics.js +125 -0
- package/dist/cursor-pi-tool-bridge-env.js +18 -0
- package/dist/cursor-pi-tool-bridge-mcp.js +100 -0
- package/dist/cursor-pi-tool-bridge-run.js +355 -0
- package/dist/cursor-pi-tool-bridge-server.js +163 -0
- package/dist/cursor-pi-tool-bridge-snapshot.js +63 -0
- package/dist/cursor-pi-tool-bridge-types.js +1 -0
- package/dist/cursor-pi-tool-bridge.js +123 -0
- package/dist/cursor-provider-errors.js +311 -0
- package/dist/cursor-provider-lazy.js +39 -0
- package/dist/cursor-provider-live-run-drain.js +412 -0
- package/dist/cursor-provider-overflow.js +90 -0
- package/dist/cursor-provider-run-finalizer.js +176 -0
- package/dist/cursor-provider-run-outcome.js +76 -0
- package/dist/cursor-provider-turn-coordinator.js +275 -0
- package/dist/cursor-provider-turn-display-router.js +158 -0
- package/dist/cursor-provider-turn-emit.js +35 -0
- package/dist/cursor-provider-turn-finalize.js +154 -0
- package/dist/cursor-provider-turn-lifecycle-emitter.js +126 -0
- package/dist/cursor-provider-turn-prepare.js +374 -0
- package/dist/cursor-provider-turn-runner.js +146 -0
- package/dist/cursor-provider-turn-sdk-normalizer.js +74 -0
- package/dist/cursor-provider-turn-send.js +138 -0
- package/dist/cursor-provider-turn-shell-output.js +117 -0
- package/dist/cursor-provider-turn-tool-ledger.js +99 -0
- package/dist/cursor-provider-turn-types.js +1 -0
- package/dist/cursor-provider.js +72 -0
- package/dist/cursor-question-tool.js +194 -0
- package/dist/cursor-record-utils.js +61 -0
- package/dist/cursor-replay-activity-builders.js +114 -0
- package/dist/cursor-replay-source-names.js +27 -0
- package/dist/cursor-replay-summary-args.js +105 -0
- package/dist/cursor-replay-tool-details.js +167 -0
- package/dist/cursor-ripgrep-path.js +27 -0
- package/dist/cursor-run-final-text.js +63 -0
- package/dist/cursor-runtime-state.js +380 -0
- package/dist/cursor-sdk-billed-usage.js +86 -0
- package/dist/cursor-sdk-event-debug-constants.js +33 -0
- package/dist/cursor-sdk-event-debug-session.js +107 -0
- package/dist/cursor-sdk-event-debug.js +461 -0
- package/dist/cursor-sdk-output-filter.js +1 -0
- package/dist/cursor-sdk-process-error-guard.js +221 -0
- package/dist/cursor-sdk-runtime.js +3 -0
- package/dist/cursor-sensitive-text.js +23 -0
- package/dist/cursor-session-agent-cleanup.js +311 -0
- package/dist/cursor-session-agent-lifecycle.js +32 -0
- package/dist/cursor-session-agent-lineage.js +103 -0
- package/dist/cursor-session-agent-resume.js +417 -0
- package/dist/cursor-session-agent.js +507 -0
- package/dist/cursor-session-compaction-prep.js +21 -0
- package/dist/cursor-session-scope.js +113 -0
- package/dist/cursor-session-send-policy.js +18 -0
- package/dist/cursor-session-store.js +105 -0
- package/dist/cursor-session-turn-queue.js +50 -0
- package/dist/cursor-setting-sources.js +15 -0
- package/dist/cursor-skill-tool.js +230 -0
- package/dist/cursor-state.js +519 -0
- package/dist/cursor-task-presentation.js +59 -0
- package/dist/cursor-tool-lifecycle.js +94 -0
- package/dist/cursor-tool-manifest.js +34 -0
- package/dist/cursor-tool-presentation-registry.js +305 -0
- package/dist/cursor-tool-result-display-readers.js +158 -0
- package/dist/cursor-tool-transcript.js +32 -0
- package/dist/cursor-tool-visibility.js +28 -0
- package/dist/cursor-transcript-tool-formatters.js +618 -0
- package/dist/cursor-transcript-tool-specs.js +284 -0
- package/dist/cursor-transcript-utils.js +170 -0
- package/dist/cursor-usage-accounting.js +166 -0
- package/dist/cursor-web-tool-activity.js +23 -0
- package/dist/cursor-web-tool-args.js +12 -0
- package/dist/index.js +82 -0
- package/dist/model-discovery.js +305 -0
- package/dist/model-list-cache.js +156 -0
- package/docs/cursor-dogfood-checklist.md +2 -1
- package/docs/cursor-live-smoke-checklist.md +15 -14
- package/docs/cursor-model-ux-spec.md +29 -8
- package/docs/cursor-native-tool-replay.md +13 -13
- package/docs/cursor-native-tool-visual-audit.md +6 -3
- package/docs/cursor-testing-lessons.md +7 -7
- package/docs/cursor-tool-surfaces.md +5 -5
- package/docs/platform-smoke.md +6 -6
- package/node_modules/fast-uri/index.js +37 -1
- package/node_modules/fast-uri/package.json +1 -1
- package/node_modules/fast-uri/test/security.test.js +136 -0
- package/node_modules/hono/dist/cjs/context.js +28 -13
- package/node_modules/hono/dist/cjs/helper/proxy/index.js +4 -0
- package/node_modules/hono/dist/cjs/helper/streaming/sse.js +1 -1
- package/node_modules/hono/dist/cjs/hono-base.js +3 -2
- package/node_modules/hono/dist/cjs/jsx/base.js +27 -23
- package/node_modules/hono/dist/cjs/jsx/hooks/index.js +16 -13
- package/node_modules/hono/dist/cjs/middleware/cache/index.js +103 -8
- package/node_modules/hono/dist/cjs/middleware/compress/index.js +5 -0
- package/node_modules/hono/dist/cjs/middleware/cors/index.js +2 -2
- package/node_modules/hono/dist/cjs/middleware/etag/index.js +1 -1
- package/node_modules/hono/dist/cjs/middleware/jwk/jwk.js +9 -4
- package/node_modules/hono/dist/cjs/middleware/jwt/jwt.js +9 -4
- package/node_modules/hono/dist/cjs/middleware/language/language.js +10 -6
- package/node_modules/hono/dist/cjs/middleware/method-not-allowed/index.js +90 -0
- package/node_modules/hono/dist/cjs/middleware/secure-headers/secure-headers.js +10 -4
- package/node_modules/hono/dist/cjs/request.js +7 -9
- package/node_modules/hono/dist/cjs/router/reg-exp-router/node.js +55 -56
- package/node_modules/hono/dist/cjs/router/reg-exp-router/router.js +64 -85
- package/node_modules/hono/dist/cjs/router/reg-exp-router/trie.js +13 -5
- package/node_modules/hono/dist/cjs/router.js +1 -1
- package/node_modules/hono/dist/cjs/utils/accept.js +1 -1
- package/node_modules/hono/dist/cjs/utils/cookie.js +3 -2
- package/node_modules/hono/dist/cjs/utils/url.js +8 -8
- package/node_modules/hono/dist/context.js +28 -13
- package/node_modules/hono/dist/helper/proxy/index.js +4 -0
- package/node_modules/hono/dist/helper/streaming/sse.js +1 -1
- package/node_modules/hono/dist/hono-base.js +3 -2
- package/node_modules/hono/dist/jsx/base.js +27 -23
- package/node_modules/hono/dist/jsx/hooks/index.js +16 -13
- package/node_modules/hono/dist/middleware/cache/index.js +103 -8
- package/node_modules/hono/dist/middleware/compress/index.js +5 -0
- package/node_modules/hono/dist/middleware/cors/index.js +2 -2
- package/node_modules/hono/dist/middleware/etag/index.js +1 -1
- package/node_modules/hono/dist/middleware/jwk/jwk.js +9 -4
- package/node_modules/hono/dist/middleware/jwt/jwt.js +9 -4
- package/node_modules/hono/dist/middleware/language/language.js +10 -6
- package/node_modules/hono/dist/middleware/method-not-allowed/index.js +68 -0
- package/node_modules/hono/dist/middleware/secure-headers/secure-headers.js +10 -4
- package/node_modules/hono/dist/request.js +8 -10
- package/node_modules/hono/dist/router/reg-exp-router/node.js +55 -56
- package/node_modules/hono/dist/router/reg-exp-router/router.js +64 -85
- package/node_modules/hono/dist/router/reg-exp-router/trie.js +13 -5
- package/node_modules/hono/dist/router.js +1 -1
- package/node_modules/hono/dist/types/adapter/aws-lambda/types.d.ts +9 -0
- package/node_modules/hono/dist/types/client/types.d.ts +1 -1
- package/node_modules/hono/dist/types/hono-base.d.ts +4 -3
- package/node_modules/hono/dist/types/jsx/base.d.ts +4 -2
- package/node_modules/hono/dist/types/jsx/dom/index.d.ts +5 -5
- package/node_modules/hono/dist/types/jsx/dom/intrinsic-element/components.d.ts +2 -2
- package/node_modules/hono/dist/types/jsx/dom/server.d.ts +5 -5
- package/node_modules/hono/dist/types/jsx/hooks/index.d.ts +8 -6
- package/node_modules/hono/dist/types/jsx/index.d.ts +5 -5
- package/node_modules/hono/dist/types/middleware/cache/index.d.ts +6 -4
- package/node_modules/hono/dist/types/middleware/cors/index.d.ts +1 -1
- package/node_modules/hono/dist/types/middleware/jsx-renderer/index.d.ts +2 -2
- package/node_modules/hono/dist/types/middleware/jwk/jwk.d.ts +2 -0
- package/node_modules/hono/dist/types/middleware/jwt/jwt.d.ts +2 -0
- package/node_modules/hono/dist/types/middleware/method-not-allowed/index.d.ts +49 -0
- package/node_modules/hono/dist/types/router/reg-exp-router/node.d.ts +1 -1
- package/node_modules/hono/dist/types/router/reg-exp-router/trie.d.ts +2 -1
- package/node_modules/hono/dist/types/router.d.ts +1 -1
- package/node_modules/hono/dist/types/utils/headers.d.ts +2 -2
- package/node_modules/hono/dist/types/utils/url.d.ts +1 -0
- package/node_modules/hono/dist/utils/accept.js +1 -1
- package/node_modules/hono/dist/utils/cookie.js +4 -3
- package/node_modules/hono/dist/utils/url.js +6 -7
- package/node_modules/hono/package.json +10 -3
- package/node_modules/ip-address/README.md +146 -126
- package/node_modules/ip-address/dist/common.d.ts +29 -0
- package/node_modules/ip-address/dist/common.js +44 -5
- package/node_modules/ip-address/dist/common.js.map +1 -1
- package/node_modules/ip-address/dist/ipv4.d.ts +8 -1
- package/node_modules/ip-address/dist/ipv4.js +24 -20
- package/node_modules/ip-address/dist/ipv4.js.map +1 -1
- package/node_modules/ip-address/dist/ipv6.d.ts +68 -3
- package/node_modules/ip-address/dist/ipv6.js +180 -53
- package/node_modules/ip-address/dist/ipv6.js.map +1 -1
- package/node_modules/ip-address/dist/v4/constants.js +5 -1
- package/node_modules/ip-address/dist/v4/constants.js.map +1 -1
- package/node_modules/ip-address/dist/v6/constants.js +3 -2
- package/node_modules/ip-address/dist/v6/constants.js.map +1 -1
- package/node_modules/ip-address/package.json +6 -4
- package/package.json +23 -11
- package/platform-smoke.config.mjs +1 -1
- package/scripts/build.mjs +126 -0
- package/scripts/cloud-runtime-smoke.mjs +3 -1
- package/scripts/debug-provider-events.mjs +3 -1
- package/scripts/debug-sdk-events.mjs +1 -1
- package/scripts/isolated-cursor-smoke.sh +5 -4
- package/scripts/lib/cloud-smoke-cleanup-evidence.mjs +1 -1
- package/scripts/lib/cursor-visual-render.mjs +1 -1
- package/scripts/lib/ensure-built.mjs +16 -0
- package/scripts/lib/local-resume-smoke-harness.mjs +1 -1
- package/scripts/local-resume-smoke.mjs +3 -1
- package/scripts/platform-smoke/card-detect.mjs +1 -1
- package/scripts/platform-smoke/live-suite-runner.mjs +16 -40
- package/scripts/platform-smoke/platform-build-windows.ps1 +1 -1
- package/scripts/platform-smoke/render-ansi.mjs +1 -1
- package/scripts/platform-smoke/scenarios.mjs +1 -1
- package/scripts/platform-smoke/targets.mjs +2 -2
- package/scripts/platform-smoke.mjs +5 -5
- package/scripts/prepare.mjs +102 -0
- package/scripts/refresh-cursor-model-snapshots.mjs +16 -7
- package/scripts/steering-rpc-smoke.mjs +4 -2
- package/scripts/tmux-live-smoke.sh +11 -11
- package/scripts/visual-tui-smoke-self-test.mjs +4 -1
- package/scripts/visual-tui-smoke.mjs +51 -7
- package/shared/cursor-model-selection-identities.d.mts +21 -0
- package/shared/cursor-model-selection-identities.mjs +95 -0
- package/src/bundled-context-windows.ts +21 -12
- package/src/context.ts +1 -1
- package/src/cursor-agents-context-registration.ts +2 -2
- package/src/cursor-agents-context.ts +0 -2
- package/src/cursor-api-key.ts +5 -4
- package/src/cursor-cloud-reporting.ts +23 -2
- package/src/cursor-context-tools.ts +1 -1
- package/src/cursor-display-only-trace.ts +1 -1
- package/src/cursor-fallback-models.generated.ts +1726 -824
- package/src/cursor-live-run-accounting.ts +1 -1
- package/src/cursor-live-run-coordinator.ts +2 -1
- package/src/cursor-native-replay-routing.ts +1 -1
- package/src/cursor-native-tool-display-registration.ts +10 -11
- package/src/cursor-partial-content-emitter.ts +1 -1
- package/src/cursor-pi-tool-bridge-mcp.ts +1 -1
- package/src/cursor-pi-tool-bridge-run.ts +1 -1
- package/src/cursor-pi-tool-bridge-types.ts +1 -1
- package/src/cursor-provider-errors.ts +1 -1
- package/src/cursor-provider-lazy.ts +6 -5
- package/src/cursor-provider-live-run-drain.ts +2 -1
- package/src/cursor-provider-overflow.ts +1 -1
- package/src/cursor-provider-run-finalizer.ts +2 -1
- package/src/cursor-provider-turn-coordinator.ts +1 -1
- package/src/cursor-provider-turn-finalize.ts +12 -0
- package/src/cursor-provider-turn-lifecycle-emitter.ts +1 -1
- package/src/cursor-provider-turn-prepare.ts +1 -1
- package/src/cursor-provider-turn-types.ts +3 -1
- package/src/cursor-provider.ts +1 -1
- package/src/cursor-run-final-text.ts +1 -1
- package/src/cursor-sdk-billed-usage.ts +107 -0
- package/src/cursor-sdk-event-debug.ts +1 -1
- package/src/cursor-sdk-process-error-guard.ts +6 -4
- package/src/cursor-session-agent-lifecycle.ts +8 -9
- package/src/cursor-session-agent-resume.ts +23 -0
- package/src/cursor-session-agent.ts +1 -1
- package/src/cursor-session-compaction-prep.ts +4 -0
- package/src/cursor-session-send-policy.ts +1 -1
- package/src/cursor-tool-manifest.ts +1 -1
- package/src/cursor-usage-accounting.ts +71 -10
- package/src/index.ts +1 -1
- package/src/model-discovery.ts +32 -89
- package/tsconfig.build.json +8 -0
- package/tsconfig.json +16 -0
- package/node_modules/cross-spawn/node_modules/which/CHANGELOG.md +0 -166
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { CursorLiveRunAbortError } from "./cursor-live-run-coordinator.js";
|
|
2
|
+
import { drainExistingCursorLiveRunBeforeSend } from "./cursor-provider-live-run-drain.js";
|
|
3
|
+
import { invalidateSessionAgent } from "./cursor-session-agent.js";
|
|
4
|
+
import { getCursorSessionCwd, getCursorSessionScopeKey } from "./cursor-session-scope.js";
|
|
5
|
+
import { installCursorSdkProcessErrorGuard } from "./cursor-sdk-process-error-guard.js";
|
|
6
|
+
import { CursorSdkEventDebugSink } from "./cursor-sdk-event-debug.js";
|
|
7
|
+
import { awaitFinalizeCursorRunOutcome } from "./cursor-provider-turn-finalize.js";
|
|
8
|
+
import { discardIncompleteToolsFromPrepared, emitCursorLiveTurn, } from "./cursor-provider-turn-emit.js";
|
|
9
|
+
import { CursorRunFinalizer } from "./cursor-provider-run-finalizer.js";
|
|
10
|
+
import { prepareCursorProviderTurn, requireCursorApiKey, resolveCursorProviderTurnConfig, } from "./cursor-provider-turn-prepare.js";
|
|
11
|
+
import { sendCursorProviderTurn } from "./cursor-provider-turn-send.js";
|
|
12
|
+
function requireLocalLivePreparedTurn(prepared) {
|
|
13
|
+
if (prepared.runtimeTarget !== "local" || prepared.runtime.kind !== "live") {
|
|
14
|
+
throw new Error("Cursor live run requires a local live prepared turn");
|
|
15
|
+
}
|
|
16
|
+
return prepared;
|
|
17
|
+
}
|
|
18
|
+
export class CursorProviderTurnRunner {
|
|
19
|
+
params;
|
|
20
|
+
sdkEventDebug;
|
|
21
|
+
resolvedApiKey;
|
|
22
|
+
runtimeTarget;
|
|
23
|
+
constructor(params) {
|
|
24
|
+
this.params = params;
|
|
25
|
+
}
|
|
26
|
+
get options() {
|
|
27
|
+
return this.params.options;
|
|
28
|
+
}
|
|
29
|
+
throwIfAborted() {
|
|
30
|
+
if (this.options?.signal?.aborted)
|
|
31
|
+
throw new CursorLiveRunAbortError();
|
|
32
|
+
}
|
|
33
|
+
async run(sdkProcessErrorGuard) {
|
|
34
|
+
const { stream, partial, model, context, options, sdkEventDebugRef } = this.params;
|
|
35
|
+
let prepared;
|
|
36
|
+
let sendResult;
|
|
37
|
+
let liveCompletion;
|
|
38
|
+
const runFinalizer = new CursorRunFinalizer({
|
|
39
|
+
runnerParams: this.params,
|
|
40
|
+
sdkEventDebug: () => this.sdkEventDebug,
|
|
41
|
+
sdkProcessErrorGuard,
|
|
42
|
+
resolvedApiKey: () => this.resolvedApiKey,
|
|
43
|
+
runtimeTarget: () => this.runtimeTarget,
|
|
44
|
+
});
|
|
45
|
+
try {
|
|
46
|
+
this.throwIfAborted();
|
|
47
|
+
const cwd = getCursorSessionCwd();
|
|
48
|
+
this.sdkEventDebug = CursorSdkEventDebugSink.maybeCreate({
|
|
49
|
+
cwd,
|
|
50
|
+
modelId: model.id,
|
|
51
|
+
provider: model.provider,
|
|
52
|
+
});
|
|
53
|
+
sdkEventDebugRef.current = this.sdkEventDebug;
|
|
54
|
+
this.sdkEventDebug?.recordContextSnapshot(context);
|
|
55
|
+
// Resolved once here, before any drain await, so the drain decision and the
|
|
56
|
+
// prepare dispatch below always act on the same config snapshot.
|
|
57
|
+
const resolvedConfig = resolveCursorProviderTurnConfig(cwd);
|
|
58
|
+
this.runtimeTarget = resolvedConfig.runtime.value;
|
|
59
|
+
if (resolvedConfig.runtime.value === "local") {
|
|
60
|
+
// The observed local-executor closed-pipe EPIPE is contained only from this
|
|
61
|
+
// turn's pre-send live-run drain through run completion; for live runs the
|
|
62
|
+
// finalizer holds the guard until run.wait() settles. A hit marks
|
|
63
|
+
// this scope's pooled agent transport dead so the next acquire recreates it.
|
|
64
|
+
const localScopeKey = getCursorSessionScopeKey();
|
|
65
|
+
sdkProcessErrorGuard.containLocalTransportClosedPipe(() => invalidateSessionAgent(localScopeKey, { deadTransport: true }));
|
|
66
|
+
if ((await drainExistingCursorLiveRunBeforeSend(stream, partial, model, context, options?.signal, this.sdkEventDebug)) ===
|
|
67
|
+
"stream_ended") {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
this.throwIfAborted();
|
|
72
|
+
this.resolvedApiKey = requireCursorApiKey(options);
|
|
73
|
+
prepared = await prepareCursorProviderTurn({
|
|
74
|
+
params: this.params,
|
|
75
|
+
cwd,
|
|
76
|
+
resolvedApiKey: this.resolvedApiKey,
|
|
77
|
+
sdkEventDebug: this.sdkEventDebug,
|
|
78
|
+
throwIfAborted: () => this.throwIfAborted(),
|
|
79
|
+
resolvedConfig,
|
|
80
|
+
});
|
|
81
|
+
sendResult = await sendCursorProviderTurn({
|
|
82
|
+
params: this.params,
|
|
83
|
+
prepared,
|
|
84
|
+
sdkEventDebug: this.sdkEventDebug,
|
|
85
|
+
sdkProcessErrorGuard,
|
|
86
|
+
throwIfAborted: () => this.throwIfAborted(),
|
|
87
|
+
resolvedApiKey: this.resolvedApiKey,
|
|
88
|
+
});
|
|
89
|
+
const { send } = sendResult;
|
|
90
|
+
if (prepared.runtime.kind === "live") {
|
|
91
|
+
const livePrepared = requireLocalLivePreparedTurn(prepared);
|
|
92
|
+
liveCompletion = runFinalizer.startLiveRunCompletion({
|
|
93
|
+
send,
|
|
94
|
+
prepared: livePrepared,
|
|
95
|
+
modelId: model.id,
|
|
96
|
+
discardIncompleteTools: (outcome) => discardIncompleteToolsFromPrepared(livePrepared, outcome),
|
|
97
|
+
});
|
|
98
|
+
await emitCursorLiveTurn({
|
|
99
|
+
params: this.params,
|
|
100
|
+
prepared: livePrepared,
|
|
101
|
+
sdkEventDebug: this.sdkEventDebug,
|
|
102
|
+
discardIncompleteTools: (outcome) => discardIncompleteToolsFromPrepared(livePrepared, outcome),
|
|
103
|
+
});
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const outcomePromise = awaitFinalizeCursorRunOutcome({
|
|
107
|
+
run: send.run,
|
|
108
|
+
prepared,
|
|
109
|
+
cursorAgentMessageOffset: send.cursorAgentMessageOffset,
|
|
110
|
+
modelId: model.id,
|
|
111
|
+
signal: options?.signal,
|
|
112
|
+
runResultFallback: send.run.result,
|
|
113
|
+
runErrorFallback: send.run.error,
|
|
114
|
+
resolvedApiKey: this.resolvedApiKey,
|
|
115
|
+
optionsApiKey: options?.apiKey,
|
|
116
|
+
sdkEventDebug: this.sdkEventDebug,
|
|
117
|
+
contextWindowAgentId: prepared.contextWindowAgentId,
|
|
118
|
+
});
|
|
119
|
+
prepared.lifecycle.trackRunCompletion(outcomePromise);
|
|
120
|
+
const finalized = await outcomePromise;
|
|
121
|
+
await runFinalizer.applyTerminalEvent({
|
|
122
|
+
kind: "direct",
|
|
123
|
+
prepared,
|
|
124
|
+
outcome: finalized.outcome,
|
|
125
|
+
displayOnlyTraceBlock: finalized.displayOnlyTraceBlock,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
await runFinalizer.applyTerminalEvent({ kind: "error", prepared, error });
|
|
130
|
+
}
|
|
131
|
+
finally {
|
|
132
|
+
await runFinalizer.cleanup(prepared, sendResult, liveCompletion);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async handleOuterCatch(error) {
|
|
136
|
+
const runFinalizer = new CursorRunFinalizer({
|
|
137
|
+
runnerParams: this.params,
|
|
138
|
+
sdkEventDebug: () => this.sdkEventDebug,
|
|
139
|
+
sdkProcessErrorGuard: installCursorSdkProcessErrorGuard(),
|
|
140
|
+
resolvedApiKey: () => this.resolvedApiKey,
|
|
141
|
+
runtimeTarget: () => this.runtimeTarget,
|
|
142
|
+
});
|
|
143
|
+
await runFinalizer.applyTerminalEvent({ kind: "error", prepared: undefined, error });
|
|
144
|
+
await runFinalizer.cleanup(undefined, undefined, undefined);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { asRecord } from "./cursor-record-utils.js";
|
|
2
|
+
import { mergeShellOutputDeltasIntoCursorToolCall, } from "./cursor-provider-turn-shell-output.js";
|
|
3
|
+
function mergeCursorToolCalls(startedToolCall, completedToolCall) {
|
|
4
|
+
const started = asRecord(startedToolCall);
|
|
5
|
+
const completed = asRecord(completedToolCall);
|
|
6
|
+
if (!started)
|
|
7
|
+
return completedToolCall;
|
|
8
|
+
if (!completed)
|
|
9
|
+
return startedToolCall;
|
|
10
|
+
return {
|
|
11
|
+
...started,
|
|
12
|
+
...completed,
|
|
13
|
+
name: completed.name ?? started.name,
|
|
14
|
+
type: completed.type ?? started.type,
|
|
15
|
+
args: completed.args ?? started.args,
|
|
16
|
+
input: completed.input ?? started.input,
|
|
17
|
+
result: completed.result ?? started.result,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function resolveCursorToolCompletion(options) {
|
|
21
|
+
const bridgeStartedCallId = options.ledger.takeBridgeStartedCallId(typeof options.callId === "string" ? options.callId : "");
|
|
22
|
+
if (bridgeStartedCallId) {
|
|
23
|
+
options.ledger.recordCompletedIdentity(`cursor-tool:${bridgeStartedCallId}`);
|
|
24
|
+
return { action: "ignore-bridge", identity: `cursor-tool:${bridgeStartedCallId}` };
|
|
25
|
+
}
|
|
26
|
+
let matchedStartedCallId;
|
|
27
|
+
let resolvedToolCall;
|
|
28
|
+
let identity;
|
|
29
|
+
let source;
|
|
30
|
+
if (options.source === "delta") {
|
|
31
|
+
const callId = options.callId;
|
|
32
|
+
identity = typeof callId === "string" ? `cursor-tool:${callId}` : undefined;
|
|
33
|
+
resolvedToolCall = mergeCursorToolCalls(options.startedToolCall, options.toolCall);
|
|
34
|
+
if (typeof callId === "string" && options.ledger.hasStartedToolCall(callId)) {
|
|
35
|
+
options.onClearStartedCallId?.(callId);
|
|
36
|
+
options.ledger.clearStartedToolCall(callId);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
matchedStartedCallId = options.ledger.removeStartedToolCallForStep(options.toolCall, callId);
|
|
40
|
+
if (matchedStartedCallId)
|
|
41
|
+
options.onClearStartedCallId?.(matchedStartedCallId);
|
|
42
|
+
}
|
|
43
|
+
resolvedToolCall = mergeShellOutputDeltasIntoCursorToolCall(resolvedToolCall, matchedStartedCallId
|
|
44
|
+
? options.shellOutput.takeDeltasForCall(matchedStartedCallId)
|
|
45
|
+
: typeof callId === "string"
|
|
46
|
+
? options.shellOutput.takeDeltasForCall(callId)
|
|
47
|
+
: undefined);
|
|
48
|
+
source = identity || matchedStartedCallId ? "started" : "fallback";
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
matchedStartedCallId = options.ledger.removeStartedToolCallForStep(options.toolCall, options.callId);
|
|
52
|
+
if (matchedStartedCallId) {
|
|
53
|
+
options.onClearStartedCallId?.(matchedStartedCallId);
|
|
54
|
+
}
|
|
55
|
+
resolvedToolCall = mergeShellOutputDeltasIntoCursorToolCall(options.toolCall, matchedStartedCallId ? options.shellOutput.takeDeltasForCall(matchedStartedCallId) : undefined);
|
|
56
|
+
const identityId = typeof options.callId === "string" ? options.callId : matchedStartedCallId;
|
|
57
|
+
identity = identityId ? `cursor-tool:${identityId}` : undefined;
|
|
58
|
+
}
|
|
59
|
+
if (options.liveRun?.bridgeRun?.isBridgeMcpToolCall(resolvedToolCall)) {
|
|
60
|
+
const bridgeIdentity = options.source === "step" && matchedStartedCallId ? `cursor-tool:${matchedStartedCallId}` : identity;
|
|
61
|
+
if (bridgeIdentity)
|
|
62
|
+
options.ledger.recordCompletedIdentity(bridgeIdentity);
|
|
63
|
+
return { action: "ignore-bridge", identity: bridgeIdentity };
|
|
64
|
+
}
|
|
65
|
+
if (options.source === "delta") {
|
|
66
|
+
return { action: "handle", toolCall: resolvedToolCall, identity, source, matchedStartedCallId };
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
action: "handle",
|
|
70
|
+
toolCall: resolvedToolCall,
|
|
71
|
+
identity,
|
|
72
|
+
matchedStartedCallId,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { countCursorAgentMessages } from "./cursor-agent-message-web-tools.js";
|
|
2
|
+
import { createCursorCloudLifecyclePersistenceError, recordCursorCloudLifecycleSafely, } from "./cursor-cloud-lifecycle.js";
|
|
3
|
+
import { CursorLiveRunAbortError } from "./cursor-live-run-coordinator.js";
|
|
4
|
+
import { cursorLiveRuns } from "./cursor-provider-live-run-drain.js";
|
|
5
|
+
import { consumeCursorLocalForceOverride } from "./cursor-runtime-state.js";
|
|
6
|
+
import { recordCursorSessionAgentLineage } from "./cursor-session-agent-lineage.js";
|
|
7
|
+
const CLOUD_LEDGER_CANCEL_TIMEOUT_MS = 5000;
|
|
8
|
+
async function requestBoundedCloudRunCancellation(run) {
|
|
9
|
+
let timer;
|
|
10
|
+
const timeout = new Promise((resolve) => {
|
|
11
|
+
timer = setTimeout(() => resolve(false), CLOUD_LEDGER_CANCEL_TIMEOUT_MS);
|
|
12
|
+
timer.unref?.();
|
|
13
|
+
});
|
|
14
|
+
try {
|
|
15
|
+
return await Promise.race([
|
|
16
|
+
Promise.resolve().then(() => run.cancel()).then(() => true, () => false),
|
|
17
|
+
timeout,
|
|
18
|
+
]);
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
if (timer)
|
|
22
|
+
clearTimeout(timer);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function recordDebug(action) {
|
|
26
|
+
try {
|
|
27
|
+
action();
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Debug capture is optional and must never change provider execution.
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export async function sendCursorProviderTurn(sendParams) {
|
|
34
|
+
const { params, prepared, sdkEventDebug, sdkProcessErrorGuard, throwIfAborted, resolvedApiKey } = sendParams;
|
|
35
|
+
const { options } = params;
|
|
36
|
+
const { agent, cwd, payload, meta, runtime } = prepared;
|
|
37
|
+
const { turnCoordinator, liveRun } = runtime;
|
|
38
|
+
let completed = false;
|
|
39
|
+
let sdkRun = null;
|
|
40
|
+
const abortListener = () => {
|
|
41
|
+
sdkProcessErrorGuard.suppressAbortErrors();
|
|
42
|
+
liveRun?.bridgeRun?.cancel("Cursor SDK run aborted");
|
|
43
|
+
if (sdkRun) {
|
|
44
|
+
sdkRun.cancel().catch(() => { });
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const abortSignal = options?.signal;
|
|
48
|
+
const abortRegistration = abortSignal
|
|
49
|
+
? { signal: abortSignal, listener: abortListener }
|
|
50
|
+
: undefined;
|
|
51
|
+
try {
|
|
52
|
+
abortRegistration?.signal.addEventListener("abort", abortListener, { once: true });
|
|
53
|
+
throwIfAborted();
|
|
54
|
+
let cursorAgentMessageOffset;
|
|
55
|
+
if (prepared.runtimeTarget === "local") {
|
|
56
|
+
try {
|
|
57
|
+
cursorAgentMessageOffset = await countCursorAgentMessages(agent.agentId, cwd, prepared.sessionAgentLease.store);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
recordDebug(() => sdkEventDebug?.recordError("cursor_agent_message_count", error));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
throwIfAborted();
|
|
64
|
+
recordDebug(() => sdkEventDebug?.recordSendMeta({
|
|
65
|
+
mode: meta.sendPlan.mode,
|
|
66
|
+
reason: meta.sendPlan.reason,
|
|
67
|
+
resetAgent: meta.sendPlan.resetAgent,
|
|
68
|
+
bootstrap: meta.bootstrap,
|
|
69
|
+
promptText: meta.prompt.text,
|
|
70
|
+
imageCount: meta.prompt.images.length,
|
|
71
|
+
useNativeToolReplay: meta.useNativeToolReplay,
|
|
72
|
+
bridgeEnabled: meta.bridgeEnabled,
|
|
73
|
+
nativeReplayId: meta.nativeReplayId,
|
|
74
|
+
promptInputTokens: meta.promptInputTokens,
|
|
75
|
+
agentMode: meta.agentMode,
|
|
76
|
+
}));
|
|
77
|
+
recordDebug(() => sdkEventDebug?.recordSendPayload(payload));
|
|
78
|
+
recordDebug(() => sdkEventDebug?.recordProviderEvent("agent_send_start", payload));
|
|
79
|
+
const sendOptions = {
|
|
80
|
+
mode: meta.agentMode,
|
|
81
|
+
model: meta.modelSelection,
|
|
82
|
+
onDelta: (args) => {
|
|
83
|
+
recordDebug(() => sdkEventDebug?.recordOnDelta(args.update));
|
|
84
|
+
turnCoordinator.handleDelta(args.update);
|
|
85
|
+
},
|
|
86
|
+
onStep: (args) => {
|
|
87
|
+
recordDebug(() => sdkEventDebug?.recordOnStep(args.step));
|
|
88
|
+
turnCoordinator.handleStep(args.step);
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
throwIfAborted();
|
|
92
|
+
if (prepared.runtimeTarget === "local" && consumeCursorLocalForceOverride(prepared.localForce)) {
|
|
93
|
+
sendOptions.local = { force: true };
|
|
94
|
+
}
|
|
95
|
+
const runPromise = agent.send(payload, sendOptions);
|
|
96
|
+
// Record at send initiation (promise created), including later reject/cancel paths.
|
|
97
|
+
if (prepared.runtimeTarget === "local") {
|
|
98
|
+
recordCursorSessionAgentLineage(agent.agentId);
|
|
99
|
+
}
|
|
100
|
+
const run = await runPromise;
|
|
101
|
+
sdkRun = run;
|
|
102
|
+
if (prepared.runtimeTarget === "cloud" && !recordCursorCloudLifecycleSafely({ agentId: run.agentId, runId: run.id }, resolvedApiKey)) {
|
|
103
|
+
const cancellationConfirmed = await requestBoundedCloudRunCancellation(run);
|
|
104
|
+
throw createCursorCloudLifecyclePersistenceError(run.agentId, "run", cancellationConfirmed, resolvedApiKey);
|
|
105
|
+
}
|
|
106
|
+
recordDebug(() => sdkEventDebug?.recordRunMeta({
|
|
107
|
+
runId: run.id,
|
|
108
|
+
requestId: run.requestId,
|
|
109
|
+
agentId: run.agentId,
|
|
110
|
+
status: run.status,
|
|
111
|
+
}));
|
|
112
|
+
recordDebug(() => sdkEventDebug?.attachRunStream(run));
|
|
113
|
+
recordDebug(() => sdkEventDebug?.recordProviderEvent("agent_send_returned", {
|
|
114
|
+
runId: run.id,
|
|
115
|
+
requestId: run.requestId,
|
|
116
|
+
agentId: run.agentId,
|
|
117
|
+
status: run.status,
|
|
118
|
+
}));
|
|
119
|
+
if (liveRun)
|
|
120
|
+
cursorLiveRuns.attachSdkRun(liveRun, run);
|
|
121
|
+
if (options?.signal?.aborted) {
|
|
122
|
+
sdkProcessErrorGuard.suppressAbortErrors();
|
|
123
|
+
liveRun?.bridgeRun?.cancel("Cursor SDK run aborted");
|
|
124
|
+
await run.cancel().catch(() => { });
|
|
125
|
+
throw new CursorLiveRunAbortError();
|
|
126
|
+
}
|
|
127
|
+
completed = true;
|
|
128
|
+
return {
|
|
129
|
+
send: { run, cursorAgentMessageOffset },
|
|
130
|
+
abortRegistration,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
if (!completed && abortRegistration) {
|
|
135
|
+
abortRegistration.signal.removeEventListener("abort", abortRegistration.listener);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { asRecord, getField, hasUsableText } from "./cursor-record-utils.js";
|
|
2
|
+
import { scrubSensitiveText } from "./cursor-sensitive-text.js";
|
|
3
|
+
import { truncateCursorDisplayLine } from "./cursor-display-text.js";
|
|
4
|
+
import { classifyCursorToolVisibility } from "./cursor-tool-visibility.js";
|
|
5
|
+
const SHELL_OUTPUT_PROGRESS_MAX_DELTAS_PER_CALL = 3;
|
|
6
|
+
export function isCursorShellToolCall(toolCall) {
|
|
7
|
+
return classifyCursorToolVisibility(toolCall).normalizedKey === "shell";
|
|
8
|
+
}
|
|
9
|
+
export function getCursorShellOutputDelta(update) {
|
|
10
|
+
if (update.type !== "shell-output-delta")
|
|
11
|
+
return undefined;
|
|
12
|
+
const event = getField(update, "event");
|
|
13
|
+
const eventCase = getField(event, "case");
|
|
14
|
+
if (eventCase !== "stdout" && eventCase !== "stderr")
|
|
15
|
+
return undefined;
|
|
16
|
+
const value = getField(event, "value");
|
|
17
|
+
const data = getField(value, "data");
|
|
18
|
+
if (typeof data !== "string" || data.length === 0)
|
|
19
|
+
return undefined;
|
|
20
|
+
return { stream: eventCase, data };
|
|
21
|
+
}
|
|
22
|
+
function getCursorShellOutputProgressPreview(data) {
|
|
23
|
+
return data
|
|
24
|
+
.split(/\r?\n/)
|
|
25
|
+
.map((line) => line.trim())
|
|
26
|
+
.find((line) => line.length > 0);
|
|
27
|
+
}
|
|
28
|
+
export function formatCursorShellOutputProgressText(progress, apiKey) {
|
|
29
|
+
const preview = getCursorShellOutputProgressPreview(progress.data);
|
|
30
|
+
if (!preview)
|
|
31
|
+
return undefined;
|
|
32
|
+
return `Cursor shell ${progress.stream}: ${truncateCursorDisplayLine(scrubSensitiveText(preview, apiKey), 160)}\n`;
|
|
33
|
+
}
|
|
34
|
+
export function mergeShellOutputDeltasIntoCursorToolCall(toolCall, deltas) {
|
|
35
|
+
if (!deltas)
|
|
36
|
+
return toolCall;
|
|
37
|
+
const stdout = deltas.stdout.join("");
|
|
38
|
+
const stderr = deltas.stderr.join("");
|
|
39
|
+
if (!hasUsableText(stdout) && !hasUsableText(stderr))
|
|
40
|
+
return toolCall;
|
|
41
|
+
const toolRecord = asRecord(toolCall);
|
|
42
|
+
const result = getField(toolRecord, "result");
|
|
43
|
+
const resultRecord = asRecord(result);
|
|
44
|
+
if (!toolRecord || !resultRecord || resultRecord.status !== "success")
|
|
45
|
+
return toolCall;
|
|
46
|
+
const value = getField(resultRecord, "value");
|
|
47
|
+
const valueRecord = asRecord(value);
|
|
48
|
+
const completedStdout = getField(valueRecord, "stdout");
|
|
49
|
+
const completedStderr = getField(valueRecord, "stderr");
|
|
50
|
+
if (hasUsableText(typeof completedStdout === "string" ? completedStdout : undefined))
|
|
51
|
+
return toolCall;
|
|
52
|
+
if (hasUsableText(typeof completedStderr === "string" ? completedStderr : undefined))
|
|
53
|
+
return toolCall;
|
|
54
|
+
return {
|
|
55
|
+
...toolRecord,
|
|
56
|
+
result: {
|
|
57
|
+
...resultRecord,
|
|
58
|
+
value: {
|
|
59
|
+
...(valueRecord ?? {}),
|
|
60
|
+
stdout,
|
|
61
|
+
stderr,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export class CursorShellOutputTracker {
|
|
67
|
+
activeShellCallIds = new Set();
|
|
68
|
+
ambiguousShellOutputCallIds = new Set();
|
|
69
|
+
shellOutputDeltasByCallId = new Map();
|
|
70
|
+
shellOutputProgressCountsByCallId = new Map();
|
|
71
|
+
onShellToolStarted(callId) {
|
|
72
|
+
this.activeShellCallIds.add(callId);
|
|
73
|
+
}
|
|
74
|
+
onShellToolCleared(callId) {
|
|
75
|
+
this.activeShellCallIds.delete(callId);
|
|
76
|
+
this.ambiguousShellOutputCallIds.delete(callId);
|
|
77
|
+
this.shellOutputProgressCountsByCallId.delete(callId);
|
|
78
|
+
}
|
|
79
|
+
appendShellOutputDelta(delta) {
|
|
80
|
+
if (this.activeShellCallIds.size !== 1) {
|
|
81
|
+
for (const activeCallId of this.activeShellCallIds) {
|
|
82
|
+
this.ambiguousShellOutputCallIds.add(activeCallId);
|
|
83
|
+
this.shellOutputDeltasByCallId.delete(activeCallId);
|
|
84
|
+
this.shellOutputProgressCountsByCallId.delete(activeCallId);
|
|
85
|
+
}
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
const [callId] = this.activeShellCallIds;
|
|
89
|
+
if (!callId || this.ambiguousShellOutputCallIds.has(callId))
|
|
90
|
+
return undefined;
|
|
91
|
+
let deltas = this.shellOutputDeltasByCallId.get(callId);
|
|
92
|
+
if (!deltas) {
|
|
93
|
+
deltas = { stdout: [], stderr: [] };
|
|
94
|
+
this.shellOutputDeltasByCallId.set(callId, deltas);
|
|
95
|
+
}
|
|
96
|
+
deltas[delta.stream].push(delta.data);
|
|
97
|
+
if (!getCursorShellOutputProgressPreview(delta.data))
|
|
98
|
+
return undefined;
|
|
99
|
+
const progressCount = this.shellOutputProgressCountsByCallId.get(callId) ?? 0;
|
|
100
|
+
if (progressCount >= SHELL_OUTPUT_PROGRESS_MAX_DELTAS_PER_CALL)
|
|
101
|
+
return undefined;
|
|
102
|
+
this.shellOutputProgressCountsByCallId.set(callId, progressCount + 1);
|
|
103
|
+
return { ...delta, callId };
|
|
104
|
+
}
|
|
105
|
+
takeDeltasForCall(callId) {
|
|
106
|
+
const deltas = this.shellOutputDeltasByCallId.get(callId);
|
|
107
|
+
this.shellOutputDeltasByCallId.delete(callId);
|
|
108
|
+
this.shellOutputProgressCountsByCallId.delete(callId);
|
|
109
|
+
return deltas;
|
|
110
|
+
}
|
|
111
|
+
clear() {
|
|
112
|
+
this.activeShellCallIds.clear();
|
|
113
|
+
this.ambiguousShellOutputCallIds.clear();
|
|
114
|
+
this.shellOutputDeltasByCallId.clear();
|
|
115
|
+
this.shellOutputProgressCountsByCallId.clear();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { getToolArgs, getToolName } from "./cursor-transcript-utils.js";
|
|
2
|
+
export class CursorToolCompletionLedger {
|
|
3
|
+
startedToolCalls = new Map();
|
|
4
|
+
bridgeStartedToolCallIds = new Set();
|
|
5
|
+
completedToolIdentities = new Set();
|
|
6
|
+
completedStartedToolFingerprints = new Set();
|
|
7
|
+
completedFallbackToolFingerprints = new Set();
|
|
8
|
+
getStartedToolCall(callId) {
|
|
9
|
+
return this.startedToolCalls.get(callId);
|
|
10
|
+
}
|
|
11
|
+
hasStartedToolCall(callId) {
|
|
12
|
+
return this.startedToolCalls.has(callId);
|
|
13
|
+
}
|
|
14
|
+
registerStartedToolCall(callId, toolCall) {
|
|
15
|
+
this.startedToolCalls.set(callId, toolCall);
|
|
16
|
+
}
|
|
17
|
+
markBridgeStarted(callId) {
|
|
18
|
+
this.bridgeStartedToolCallIds.add(callId);
|
|
19
|
+
}
|
|
20
|
+
takeBridgeStartedCallId(callId) {
|
|
21
|
+
if (!this.bridgeStartedToolCallIds.has(callId))
|
|
22
|
+
return undefined;
|
|
23
|
+
this.bridgeStartedToolCallIds.delete(callId);
|
|
24
|
+
return callId;
|
|
25
|
+
}
|
|
26
|
+
clearStartedToolCall(callId) {
|
|
27
|
+
this.startedToolCalls.delete(callId);
|
|
28
|
+
this.bridgeStartedToolCallIds.delete(callId);
|
|
29
|
+
}
|
|
30
|
+
removeStartedToolCallForStep(toolCall, stepId) {
|
|
31
|
+
if (typeof stepId === "string" && this.startedToolCalls.has(stepId)) {
|
|
32
|
+
this.clearStartedToolCall(stepId);
|
|
33
|
+
return stepId;
|
|
34
|
+
}
|
|
35
|
+
const fingerprint = getStartedToolCallFingerprint(toolCall);
|
|
36
|
+
for (const [callId, startedToolCall] of this.startedToolCalls) {
|
|
37
|
+
if (getStartedToolCallFingerprint(startedToolCall) !== fingerprint)
|
|
38
|
+
continue;
|
|
39
|
+
this.clearStartedToolCall(callId);
|
|
40
|
+
return callId;
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
recordCompletedIdentity(identity) {
|
|
45
|
+
this.completedToolIdentities.add(identity);
|
|
46
|
+
}
|
|
47
|
+
shouldSkipDuplicateCompletion(input) {
|
|
48
|
+
if (input.identity && this.completedToolIdentities.has(input.identity)) {
|
|
49
|
+
return "identity-already-completed";
|
|
50
|
+
}
|
|
51
|
+
if (input.source === "started") {
|
|
52
|
+
if (this.completedFallbackToolFingerprints.has(input.fingerprint)) {
|
|
53
|
+
return "fallback-fingerprint-already-completed";
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
if (this.completedStartedToolFingerprints.has(input.fingerprint) ||
|
|
58
|
+
this.completedFallbackToolFingerprints.has(input.fingerprint)) {
|
|
59
|
+
return "fingerprint-already-completed";
|
|
60
|
+
}
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
recordCompletedTool(input) {
|
|
64
|
+
if (input.identity)
|
|
65
|
+
this.completedToolIdentities.add(input.identity);
|
|
66
|
+
if (input.source === "started") {
|
|
67
|
+
this.completedStartedToolFingerprints.add(input.fingerprint);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
this.completedFallbackToolFingerprints.add(input.fingerprint);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
clear() {
|
|
74
|
+
this.startedToolCalls.clear();
|
|
75
|
+
this.bridgeStartedToolCallIds.clear();
|
|
76
|
+
this.completedToolIdentities.clear();
|
|
77
|
+
this.completedStartedToolFingerprints.clear();
|
|
78
|
+
this.completedFallbackToolFingerprints.clear();
|
|
79
|
+
}
|
|
80
|
+
/** Exposed for incomplete-tool discard iteration. */
|
|
81
|
+
startedToolCallEntries() {
|
|
82
|
+
return this.startedToolCalls.entries();
|
|
83
|
+
}
|
|
84
|
+
clearStartedToolCalls() {
|
|
85
|
+
this.startedToolCalls.clear();
|
|
86
|
+
this.bridgeStartedToolCallIds.clear();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export function getToolFingerprint(value) {
|
|
90
|
+
try {
|
|
91
|
+
return JSON.stringify(value);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return String(value);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export function getStartedToolCallFingerprint(toolCall) {
|
|
98
|
+
return getToolFingerprint({ toolName: getToolName(toolCall), args: getToolArgs(toolCall) });
|
|
99
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { createAssistantMessageEventStream, } from "@earendil-works/pi-ai";
|
|
2
|
+
import { cursorLiveRuns, DEFAULT_CURSOR_NATIVE_REPLAY_IDLE_DISPOSE_MS, getPendingCursorLiveRun, hasTrailingUserMessagesAfterToolResults, releaseAllPendingCursorLiveRunsForTests, resetCursorNativeReplayIdleDisposeMs, setCursorNativeReplayIdleDisposeMs, } from "./cursor-provider-live-run-drain.js";
|
|
3
|
+
import { disposeAllSessionCursorAgents } from "./cursor-session-agent.js";
|
|
4
|
+
import { attachCursorSdkEventDebugPiStreamTap } from "./cursor-sdk-event-debug.js";
|
|
5
|
+
import { installCursorSdkProcessErrorGuard } from "./cursor-sdk-process-error-guard.js";
|
|
6
|
+
import { sanitizeCursorProviderError } from "./cursor-provider-errors.js";
|
|
7
|
+
import { resolveCursorApiKey } from "./cursor-api-key.js";
|
|
8
|
+
import { CursorProviderTurnRunner } from "./cursor-provider-turn-runner.js";
|
|
9
|
+
import { getCursorSessionScopeKey } from "./cursor-session-scope.js";
|
|
10
|
+
import { runExclusiveCursorSessionTurn, __testUtils as cursorSessionTurnQueueTestUtils } from "./cursor-session-turn-queue.js";
|
|
11
|
+
function makeInitialMessage(model) {
|
|
12
|
+
return {
|
|
13
|
+
role: "assistant",
|
|
14
|
+
content: [],
|
|
15
|
+
api: model.api,
|
|
16
|
+
provider: model.provider,
|
|
17
|
+
model: model.id,
|
|
18
|
+
usage: {
|
|
19
|
+
input: 0,
|
|
20
|
+
output: 0,
|
|
21
|
+
cacheRead: 0,
|
|
22
|
+
cacheWrite: 0,
|
|
23
|
+
totalTokens: 0,
|
|
24
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
25
|
+
},
|
|
26
|
+
stopReason: "stop",
|
|
27
|
+
timestamp: Date.now(),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export function streamCursor(model, context, options) {
|
|
31
|
+
const stream = createAssistantMessageEventStream();
|
|
32
|
+
const sdkEventDebugRef = {};
|
|
33
|
+
attachCursorSdkEventDebugPiStreamTap(stream, sdkEventDebugRef);
|
|
34
|
+
(async () => {
|
|
35
|
+
const partial = makeInitialMessage(model);
|
|
36
|
+
const runner = new CursorProviderTurnRunner({
|
|
37
|
+
model,
|
|
38
|
+
context,
|
|
39
|
+
stream,
|
|
40
|
+
partial,
|
|
41
|
+
options,
|
|
42
|
+
sdkEventDebugRef,
|
|
43
|
+
});
|
|
44
|
+
try {
|
|
45
|
+
stream.push({ type: "start", partial });
|
|
46
|
+
await runExclusiveCursorSessionTurn(getCursorSessionScopeKey(), () => runner.run(installCursorSdkProcessErrorGuard()), options?.signal);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
await runner.handleOuterCatch(error);
|
|
50
|
+
}
|
|
51
|
+
stream.end();
|
|
52
|
+
})().catch((error) => {
|
|
53
|
+
const partial = makeInitialMessage(model);
|
|
54
|
+
partial.stopReason = "error";
|
|
55
|
+
partial.errorMessage = sanitizeCursorProviderError(error, resolveCursorApiKey(options?.apiKey));
|
|
56
|
+
stream.push({ type: "error", reason: "error", error: partial });
|
|
57
|
+
stream.end();
|
|
58
|
+
});
|
|
59
|
+
return stream;
|
|
60
|
+
}
|
|
61
|
+
export const __testUtils = {
|
|
62
|
+
DEFAULT_CURSOR_NATIVE_REPLAY_IDLE_DISPOSE_MS,
|
|
63
|
+
pendingCursorNativeRunCount: cursorLiveRuns.count,
|
|
64
|
+
getPendingCursorLiveRun,
|
|
65
|
+
getActiveCursorLiveRunForScope: cursorLiveRuns.getActiveForScope,
|
|
66
|
+
hasTrailingUserMessagesAfterToolResults,
|
|
67
|
+
setCursorNativeReplayIdleDisposeMs,
|
|
68
|
+
resetCursorNativeReplayIdleDisposeMs,
|
|
69
|
+
releaseAllPendingCursorLiveRunsForTests,
|
|
70
|
+
resetSessionCursorAgents: () => disposeAllSessionCursorAgents(),
|
|
71
|
+
resetSessionTurnQueue: cursorSessionTurnQueueTestUtils.reset,
|
|
72
|
+
};
|