pi-cursor-sdk 0.1.56 → 0.1.57
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 +45 -1
- package/README.md +100 -28
- package/docs/cursor-live-smoke-checklist.md +7 -7
- package/docs/cursor-model-ux-spec.md +45 -38
- package/docs/cursor-native-tool-replay.md +2 -2
- package/docs/cursor-native-tool-visual-audit.md +1 -1
- package/docs/cursor-testing-lessons.md +20 -7
- package/docs/cursor-tool-surfaces.md +13 -2
- package/docs/platform-smoke-implementation.md +220 -0
- package/docs/platform-smoke.md +183 -247
- package/package.json +38 -6
- package/platform-smoke.config.mjs +5 -1
- package/scripts/cloud-runtime-smoke.d.mts +3 -0
- package/scripts/cloud-runtime-smoke.mjs +502 -0
- package/scripts/debug-provider-events.mjs +7 -2
- package/scripts/isolated-cursor-smoke.sh +4 -6
- package/scripts/lib/cursor-child-process.d.mts +1 -0
- package/scripts/lib/cursor-child-process.mjs +137 -7
- package/scripts/lib/local-resume-smoke-harness.mjs +543 -0
- package/scripts/local-resume-cleanup-smoke.mjs +108 -0
- package/scripts/local-resume-smoke.d.mts +1 -0
- package/scripts/local-resume-smoke.mjs +642 -0
- package/scripts/platform-smoke/artifact-anchored-extract.d.mts +10 -0
- package/scripts/platform-smoke/artifact-anchored-extract.mjs +111 -0
- package/scripts/platform-smoke/artifact-bundle-chunk.mjs +57 -0
- package/scripts/platform-smoke/artifact-bundle-contract.mjs +34 -0
- package/scripts/platform-smoke/artifact-fs-safety.mjs +311 -0
- package/scripts/platform-smoke/artifact-openat-extract.c +335 -0
- package/scripts/platform-smoke/artifact-secrets.mjs +155 -0
- package/scripts/platform-smoke/artifacts.mjs +293 -65
- package/scripts/platform-smoke/card-detect.mjs +16 -4
- package/scripts/platform-smoke/crabbox-runner.mjs +45 -3
- package/scripts/platform-smoke/doctor.mjs +20 -10
- package/scripts/platform-smoke/live-suite-runner.mjs +18 -57
- package/scripts/platform-smoke/local-resume-runner.mjs +252 -0
- package/scripts/platform-smoke/local-resume-suites.d.mts +15 -0
- package/scripts/platform-smoke/local-resume-suites.mjs +104 -0
- package/scripts/platform-smoke/scenarios.mjs +16 -2
- package/scripts/platform-smoke/target-runtime.mjs +206 -0
- package/scripts/platform-smoke/targets.mjs +33 -141
- package/scripts/platform-smoke/visual-evidence.mjs +6 -7
- package/scripts/platform-smoke/wrapped-line-match.mjs +9 -0
- package/scripts/platform-smoke.mjs +40 -27
- package/scripts/refresh-cursor-model-snapshots.mjs +18 -6
- package/scripts/steering-rpc-smoke.mjs +12 -2
- package/scripts/tmux-live-smoke.sh +3 -5
- package/shared/cursor-cloud-lifecycle-constants.d.mts +3 -0
- package/shared/cursor-cloud-lifecycle-constants.mjs +7 -0
- package/shared/cursor-sensitive-text.mjs +7 -1
- package/src/context.ts +5 -2
- package/src/cursor-agents-context-registration.ts +7 -0
- package/src/cursor-agents-context.ts +3 -1
- package/src/cursor-api-key.ts +15 -1
- package/src/cursor-bridge-contract.ts +3 -0
- package/src/cursor-cloud-lifecycle.ts +733 -0
- package/src/cursor-cloud-options.ts +206 -0
- package/src/cursor-cloud-reporting.ts +246 -0
- package/src/cursor-config.ts +659 -0
- package/src/cursor-display-only-trace.ts +14 -0
- package/src/cursor-display-text.ts +8 -2
- package/src/cursor-durable-fs.ts +49 -0
- package/src/cursor-fallback-models.generated.ts +2045 -485
- package/src/cursor-live-run-accounting.ts +7 -1
- package/src/cursor-live-run-coordinator.ts +1 -0
- package/src/cursor-pi-tool-bridge-run.ts +14 -4
- package/src/cursor-provider-live-run-drain.ts +5 -0
- package/src/cursor-provider-run-finalizer.ts +36 -28
- package/src/cursor-provider-turn-finalize.ts +72 -6
- package/src/cursor-provider-turn-prepare.ts +228 -12
- package/src/cursor-provider-turn-runner.ts +41 -13
- package/src/cursor-provider-turn-send.ts +59 -16
- package/src/cursor-provider-turn-types.ts +44 -10
- package/src/cursor-runtime-state.ts +478 -0
- package/src/cursor-sdk-event-debug.ts +46 -6
- package/src/cursor-sdk-process-error-guard.ts +101 -30
- package/src/cursor-session-agent-cleanup.ts +328 -0
- package/src/cursor-session-agent-resume.ts +439 -0
- package/src/cursor-session-agent.ts +109 -13
- package/src/cursor-session-scope.ts +35 -2
- package/src/cursor-session-send-policy.ts +1 -1
- package/src/cursor-skill-tool.ts +30 -11
- package/src/cursor-state.ts +112 -69
- package/src/cursor-usage-accounting.ts +14 -4
- package/src/index.ts +11 -2
- package/src/model-discovery.ts +10 -56
|
@@ -38,7 +38,13 @@ export function takeCursorLiveSdkTurnUsage(state: CursorLiveRunAccountingState):
|
|
|
38
38
|
sdkTurnUsage?: CursorSdkTurnUsage;
|
|
39
39
|
} {
|
|
40
40
|
const { sdkTurnUsage, ...nextState } = state;
|
|
41
|
-
return {
|
|
41
|
+
return {
|
|
42
|
+
state: {
|
|
43
|
+
...nextState,
|
|
44
|
+
sdkTurnEnded: false,
|
|
45
|
+
},
|
|
46
|
+
sdkTurnUsage,
|
|
47
|
+
};
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
function asToolResultMessage(message: Message): ToolResultMessage | undefined {
|
|
@@ -150,6 +150,16 @@ export class CursorPiToolBridgeRunImpl implements CursorPiToolBridgeRun {
|
|
|
150
150
|
this.debugRecorder = recorder;
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
private recordBridgeRaw(
|
|
154
|
+
payload: Parameters<NonNullable<CursorPiToolBridgeRunOptions["debugRecorder"]>["recordBridgeRaw"]>[0],
|
|
155
|
+
): void {
|
|
156
|
+
try {
|
|
157
|
+
this.debugRecorder?.recordBridgeRaw(payload);
|
|
158
|
+
} catch {
|
|
159
|
+
// Debug capture must never block or strand a bridge call.
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
153
163
|
async resolveToolResults(toolResults: readonly ToolResultMessage[]): Promise<void> {
|
|
154
164
|
let resolvedCount = 0;
|
|
155
165
|
for (const toolResult of toolResults) {
|
|
@@ -298,11 +308,11 @@ export class CursorPiToolBridgeRunImpl implements CursorPiToolBridgeRun {
|
|
|
298
308
|
}
|
|
299
309
|
this.queuedRequests.push(request);
|
|
300
310
|
this.emitRequestQueuedDiagnostic(request);
|
|
301
|
-
this.
|
|
311
|
+
this.recordBridgeRaw({ kind: "queued", request });
|
|
302
312
|
return;
|
|
303
313
|
}
|
|
304
314
|
this.emitRequestQueuedDiagnostic(request);
|
|
305
|
-
this.
|
|
315
|
+
this.recordBridgeRaw({ kind: "queued", request });
|
|
306
316
|
this.dispatchPendingToolRequest(pending, this.onToolRequest);
|
|
307
317
|
});
|
|
308
318
|
}
|
|
@@ -331,7 +341,7 @@ export class CursorPiToolBridgeRunImpl implements CursorPiToolBridgeRun {
|
|
|
331
341
|
pending.settled = true;
|
|
332
342
|
this.removePending(pending);
|
|
333
343
|
this.emitRequestResolvedDiagnostic(pending.request, result.isError === true);
|
|
334
|
-
this.
|
|
344
|
+
this.recordBridgeRaw({ kind: "resolved", request: pending.request, result });
|
|
335
345
|
pending.resolve(result);
|
|
336
346
|
}
|
|
337
347
|
|
|
@@ -340,7 +350,7 @@ export class CursorPiToolBridgeRunImpl implements CursorPiToolBridgeRun {
|
|
|
340
350
|
pending.settled = true;
|
|
341
351
|
this.removePending(pending);
|
|
342
352
|
this.emitRequestRejectedDiagnostic(pending.request, kind);
|
|
343
|
-
this.
|
|
353
|
+
this.recordBridgeRaw({
|
|
344
354
|
kind: "rejected",
|
|
345
355
|
request: pending.request,
|
|
346
356
|
error: error.message,
|
|
@@ -22,6 +22,7 @@ import { type CursorPiBridgeToolRequest } from "./cursor-pi-tool-bridge.js";
|
|
|
22
22
|
import { resetSessionCursorAgent } from "./cursor-session-agent.js";
|
|
23
23
|
import { applyCursorUsage } from "./cursor-usage-accounting.js";
|
|
24
24
|
import { CursorPartialContentEmitter } from "./cursor-partial-content-emitter.js";
|
|
25
|
+
import { emitDisplayOnlyTraceBlock } from "./cursor-display-only-trace.js";
|
|
25
26
|
import { trimCurrentTurnAlreadyEmittedCursorText } from "./cursor-run-final-text.js";
|
|
26
27
|
import { formatCursorSdkAbortMessage, resolveCursorSdkAbortCause } from "./cursor-provider-errors.js";
|
|
27
28
|
import { formatInactiveCursorReplayTrace } from "./cursor-native-replay-trace.js";
|
|
@@ -379,6 +380,10 @@ export async function drainCursorLiveRunTurn(
|
|
|
379
380
|
applyCursorUsage(partial, model, context, cursorLiveRuns.takeTurnInputTokens(run, toolResultInputTokens), {
|
|
380
381
|
turn: cursorLiveRuns.takeSdkTurnUsage(run),
|
|
381
382
|
});
|
|
383
|
+
if (run.resumeNotice) {
|
|
384
|
+
emitDisplayOnlyTraceBlock(stream, partial, run.resumeNotice);
|
|
385
|
+
run.resumeNotice = undefined;
|
|
386
|
+
}
|
|
382
387
|
partial.stopReason = "stop";
|
|
383
388
|
stream.push({ type: "done", reason: "stop", message: partial });
|
|
384
389
|
await cursorLiveRuns.release(run);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AssistantMessage } from "@earendil-works/pi-ai/compat";
|
|
2
|
-
import {
|
|
2
|
+
import { cursorLiveRuns } from "./cursor-provider-live-run-drain.js";
|
|
3
3
|
import {
|
|
4
4
|
classifyCursorRunEmission,
|
|
5
5
|
getCursorRunAbortMessage,
|
|
@@ -23,27 +23,32 @@ import type {
|
|
|
23
23
|
CursorProviderTurnRunnerParams,
|
|
24
24
|
CursorProviderTurnSend,
|
|
25
25
|
CursorProviderTurnSendResult,
|
|
26
|
+
LiveCursorProviderTurnRuntime,
|
|
27
|
+
LocalCursorProviderTurnPrepareResult,
|
|
26
28
|
} from "./cursor-provider-turn-types.js";
|
|
27
29
|
import { applyCursorUsage } from "./cursor-usage-accounting.js";
|
|
28
30
|
import { hasUsableText } from "./cursor-record-utils.js";
|
|
31
|
+
import { emitDisplayOnlyTraceBlock } from "./cursor-display-only-trace.js";
|
|
29
32
|
export type CursorTurnTerminalEvent =
|
|
30
33
|
| {
|
|
31
34
|
kind: "direct";
|
|
32
35
|
prepared: CursorProviderTurnPrepareResult;
|
|
33
36
|
outcome: CursorRunOutcome;
|
|
37
|
+
displayOnlyTraceBlock?: string;
|
|
34
38
|
}
|
|
35
39
|
| { kind: "error"; prepared: CursorProviderTurnPrepareResult | undefined; error: unknown };
|
|
36
40
|
|
|
37
41
|
function applyLiveRunOutcome(
|
|
38
42
|
outcome: CursorRunOutcome,
|
|
39
|
-
prepared:
|
|
43
|
+
prepared: LocalCursorProviderTurnPrepareResult & { runtime: LiveCursorProviderTurnRuntime },
|
|
40
44
|
context: CursorProviderTurnRunnerParams["context"],
|
|
41
45
|
): void {
|
|
42
|
-
if (prepared.runtime.
|
|
46
|
+
if (prepared.runtime.liveRun.disposed) return;
|
|
43
47
|
const { liveRun } = prepared.runtime;
|
|
44
48
|
switch (classifyCursorRunEmission(outcome)) {
|
|
45
49
|
case "finished":
|
|
46
|
-
prepared.
|
|
50
|
+
prepared.lifecycle.commitSend(context, prepared.meta.bootstrap);
|
|
51
|
+
if (prepared.meta.resumeNotice) liveRun.resumeNotice = prepared.meta.resumeNotice;
|
|
47
52
|
cursorLiveRuns.markFinished(liveRun, outcome.kind === "finished" ? outcome.finalText : "");
|
|
48
53
|
break;
|
|
49
54
|
case "cancelled":
|
|
@@ -69,7 +74,7 @@ export interface CursorRunFinalizerParams {
|
|
|
69
74
|
|
|
70
75
|
export interface StartCursorLiveRunCompletionParams {
|
|
71
76
|
send: CursorProviderTurnSend;
|
|
72
|
-
prepared:
|
|
77
|
+
prepared: LocalCursorProviderTurnPrepareResult & { runtime: LiveCursorProviderTurnRuntime };
|
|
73
78
|
modelId: string;
|
|
74
79
|
discardIncompleteTools: (outcome: IncompleteCursorToolRunOutcomeInput) => void;
|
|
75
80
|
}
|
|
@@ -84,7 +89,6 @@ export class CursorRunFinalizer {
|
|
|
84
89
|
const sdkEventDebug = this.params.sdkEventDebug();
|
|
85
90
|
const { send, prepared, modelId, discardIncompleteTools } = startParams;
|
|
86
91
|
const { run, cursorAgentMessageOffset } = send;
|
|
87
|
-
if (prepared.runtime.kind !== "live") throw new Error("startLiveRunCompletion requires a live run");
|
|
88
92
|
const { liveRun } = prepared.runtime;
|
|
89
93
|
const waitCompletion = awaitFinalizeCursorRunOutcome({
|
|
90
94
|
run,
|
|
@@ -100,30 +104,30 @@ export class CursorRunFinalizer {
|
|
|
100
104
|
cacheContextWindow: true,
|
|
101
105
|
contextWindowAgentId: liveRun.agent.agentId,
|
|
102
106
|
})
|
|
103
|
-
.then(async (
|
|
104
|
-
applyLiveRunOutcome(outcome, prepared, runnerParams.context);
|
|
107
|
+
.then(async (finalized) => {
|
|
108
|
+
applyLiveRunOutcome(finalized.outcome, prepared, runnerParams.context);
|
|
105
109
|
})
|
|
106
|
-
.catch(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
);
|
|
110
|
+
.catch((error: unknown) => {
|
|
111
|
+
this.safeCleanup(() => discardIncompleteTools({ status: "error" }));
|
|
112
|
+
if (!liveRun.disposed) {
|
|
113
|
+
cursorLiveRuns.markError(
|
|
114
|
+
liveRun,
|
|
115
|
+
sanitizeCursorProviderError(error, this.params.resolvedApiKey() ?? runnerParams.options?.apiKey),
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
this.safeCleanup(() => sdkEventDebug?.recordWaitResult({ status: "error", error: String(error) }));
|
|
119
|
+
this.safeCleanup(() => sdkEventDebug?.recordError("run_wait", error));
|
|
116
120
|
});
|
|
117
|
-
// Mark the pooled agent busy as soon as the SDK run exists so auto-compaction summarization
|
|
121
|
+
// Mark the pooled local agent busy as soon as the SDK run exists so auto-compaction summarization
|
|
118
122
|
// (and other concurrent acquires) wait for run.wait() instead of hitting AgentBusyError.
|
|
119
|
-
prepared.
|
|
123
|
+
prepared.lifecycle.trackRunCompletion(waitCompletion);
|
|
120
124
|
return { waitCompletion, prepared };
|
|
121
125
|
}
|
|
122
126
|
|
|
123
127
|
async applyTerminalEvent(event: CursorTurnTerminalEvent): Promise<void> {
|
|
124
128
|
if (this.terminalApplied) return;
|
|
125
129
|
if (event.kind === "direct") {
|
|
126
|
-
await this.applyDirectOutcome(event.prepared, event.outcome);
|
|
130
|
+
await this.applyDirectOutcome(event.prepared, event.outcome, event.displayOnlyTraceBlock);
|
|
127
131
|
this.terminalApplied = true;
|
|
128
132
|
return;
|
|
129
133
|
}
|
|
@@ -151,6 +155,7 @@ export class CursorRunFinalizer {
|
|
|
151
155
|
.catch(() => {});
|
|
152
156
|
return;
|
|
153
157
|
}
|
|
158
|
+
await prepared?.lifecycle.dispose().catch(() => {});
|
|
154
159
|
await this.finalizeSdkEventDebugBestEffort();
|
|
155
160
|
this.safeCleanup(() => this.params.sdkProcessErrorGuard.dispose());
|
|
156
161
|
}
|
|
@@ -158,45 +163,48 @@ export class CursorRunFinalizer {
|
|
|
158
163
|
private async applyDirectOutcome(
|
|
159
164
|
prepared: CursorProviderTurnPrepareResult,
|
|
160
165
|
outcome: CursorRunOutcome,
|
|
166
|
+
displayOnlyTraceBlock: string | undefined,
|
|
161
167
|
): Promise<void> {
|
|
162
168
|
const { stream, partial, model, context } = this.params.runnerParams;
|
|
163
169
|
prepared.runtime.turnCoordinator.closeTraceBlock();
|
|
164
170
|
switch (classifyCursorRunEmission(outcome)) {
|
|
165
171
|
case "cancelled":
|
|
166
|
-
await
|
|
172
|
+
await prepared.lifecycle.abandon();
|
|
167
173
|
this.pushTerminalError(partial, "aborted", getCursorRunAbortMessage(outcome));
|
|
168
174
|
break;
|
|
169
175
|
case "failed":
|
|
170
|
-
await
|
|
176
|
+
await prepared.lifecycle.abandon();
|
|
171
177
|
this.pushTerminalError(partial, "error", outcome.kind === "error" ? outcome.errorMessage : "Cursor SDK run failed.");
|
|
172
178
|
break;
|
|
173
179
|
case "finished":
|
|
174
|
-
prepared.
|
|
180
|
+
prepared.lifecycle.commitSend(context, prepared.meta.bootstrap);
|
|
175
181
|
prepared.runtime.turnCoordinator.flushText(
|
|
176
182
|
outcome.kind === "finished" && hasUsableText(outcome.finalText) ? [outcome.finalText] : [],
|
|
177
183
|
);
|
|
178
184
|
applyCursorUsage(partial, model, context, prepared.meta.promptInputTokens, {
|
|
179
185
|
turn: prepared.runtime.turnCoordinator.lastSdkTurnUsage,
|
|
180
186
|
});
|
|
187
|
+
if (prepared.meta.resumeNotice) emitDisplayOnlyTraceBlock(stream, partial, prepared.meta.resumeNotice);
|
|
188
|
+
if (displayOnlyTraceBlock) emitDisplayOnlyTraceBlock(stream, partial, displayOnlyTraceBlock);
|
|
181
189
|
stream.push({ type: "done", reason: "stop", message: partial });
|
|
182
190
|
break;
|
|
183
191
|
}
|
|
184
192
|
}
|
|
185
193
|
|
|
186
194
|
private async applyErrorOutcome(prepared: CursorProviderTurnPrepareResult | undefined, error: unknown): Promise<void> {
|
|
187
|
-
this.
|
|
188
|
-
prepared?.runtime.turnCoordinator.discardIncompleteStartedToolCalls(
|
|
195
|
+
this.safeCleanup(() => prepared?.runtime.turnCoordinator.discardIncompleteStartedToolCalls(
|
|
189
196
|
buildIncompleteCursorToolRunOutcome({
|
|
190
197
|
status: error instanceof CursorLiveRunAbortError ? "cancelled" : "error",
|
|
191
198
|
signalAborted: error instanceof CursorLiveRunAbortError,
|
|
192
199
|
}),
|
|
193
|
-
);
|
|
200
|
+
));
|
|
194
201
|
const activeLiveRun = prepared?.runtime.liveRun;
|
|
195
202
|
if (activeLiveRun && !activeLiveRun.disposed) {
|
|
196
203
|
await cursorLiveRuns.release(activeLiveRun);
|
|
197
204
|
} else {
|
|
198
|
-
await
|
|
205
|
+
await prepared?.lifecycle.abandon();
|
|
199
206
|
}
|
|
207
|
+
this.safeCleanup(() => this.params.sdkEventDebug()?.recordError("provider_stream", error));
|
|
200
208
|
if (error instanceof CursorLiveRunAbortError) {
|
|
201
209
|
this.params.sdkProcessErrorGuard.suppressAbortErrors();
|
|
202
210
|
this.pushTerminalError(this.params.runnerParams.partial, "aborted", this.abortMessage());
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import type { RunError, SDKAgent } from "@cursor/sdk";
|
|
2
2
|
import { loadCursorTranscriptWebToolCallsAfterOffset } from "./cursor-agent-message-web-tools.js";
|
|
3
|
+
import {
|
|
4
|
+
collectCursorCloudRunReport,
|
|
5
|
+
formatCursorCloudRunReport,
|
|
6
|
+
type CursorCloudRunReport,
|
|
7
|
+
} from "./cursor-cloud-reporting.js";
|
|
8
|
+
import { recordCursorCloudLifecycleRun } from "./cursor-cloud-lifecycle.js";
|
|
3
9
|
import { getCheckpointContextWindow, saveCachedContextWindow } from "./context-window-cache.js";
|
|
10
|
+
import { scrubSensitiveText } from "./cursor-sensitive-text.js";
|
|
4
11
|
import type { CursorSdkEventDebugSink } from "./cursor-sdk-event-debug.js";
|
|
5
12
|
import type { CursorSdkTurnCoordinator } from "./cursor-provider-turn-coordinator.js";
|
|
6
13
|
import {
|
|
@@ -78,6 +85,22 @@ async function replayCursorTranscriptWebToolCalls(
|
|
|
78
85
|
}
|
|
79
86
|
}
|
|
80
87
|
|
|
88
|
+
function scrubCursorCloudReportingError(error: unknown, apiKey: string | undefined): Error {
|
|
89
|
+
return new Error(scrubSensitiveText(error instanceof Error ? error.message : String(error), apiKey));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function recordCursorCloudReportingError(
|
|
93
|
+
sdkEventDebug: CursorSdkEventDebugSink | undefined,
|
|
94
|
+
error: unknown,
|
|
95
|
+
apiKey: string | undefined,
|
|
96
|
+
): void {
|
|
97
|
+
try {
|
|
98
|
+
sdkEventDebug?.recordError("cloud_run_report", scrubCursorCloudReportingError(error, apiKey));
|
|
99
|
+
} catch {
|
|
100
|
+
// Debug reporting must never affect provider execution.
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
81
104
|
export interface AwaitFinalizeCursorRunOutcomeParams {
|
|
82
105
|
run: Awaited<ReturnType<SDKAgent["send"]>>;
|
|
83
106
|
prepared: CursorProviderTurnPrepareResult;
|
|
@@ -95,10 +118,15 @@ export interface AwaitFinalizeCursorRunOutcomeParams {
|
|
|
95
118
|
contextWindowAgentId?: string;
|
|
96
119
|
}
|
|
97
120
|
|
|
121
|
+
export interface FinalizedCursorRunOutcome {
|
|
122
|
+
outcome: CursorRunOutcome;
|
|
123
|
+
displayOnlyTraceBlock?: string;
|
|
124
|
+
}
|
|
125
|
+
|
|
98
126
|
/** Single wait/finalize path for SDK runs: wait, debug capture, transcript replay, incomplete tools, artifacts, context cache. */
|
|
99
|
-
export async function awaitFinalizeCursorRunOutcome(params: AwaitFinalizeCursorRunOutcomeParams): Promise<
|
|
127
|
+
export async function awaitFinalizeCursorRunOutcome(params: AwaitFinalizeCursorRunOutcomeParams): Promise<FinalizedCursorRunOutcome> {
|
|
128
|
+
const apiKey = params.resolvedApiKey ?? params.optionsApiKey;
|
|
100
129
|
const waitResult = params.waitResult ?? (await params.run.wait());
|
|
101
|
-
params.sdkEventDebug?.recordWaitResult(waitResult);
|
|
102
130
|
const outcome = buildCursorRunOutcomeFromWait({
|
|
103
131
|
waitResult,
|
|
104
132
|
prepared: params.prepared,
|
|
@@ -108,7 +136,41 @@ export async function awaitFinalizeCursorRunOutcome(params: AwaitFinalizeCursorR
|
|
|
108
136
|
resolvedApiKey: params.resolvedApiKey,
|
|
109
137
|
optionsApiKey: params.optionsApiKey,
|
|
110
138
|
});
|
|
111
|
-
|
|
139
|
+
let displayOnlyTraceBlock: string | undefined;
|
|
140
|
+
if (params.prepared.runtimeTarget === "cloud" && isCursorRunFinishedSuccessfully(outcome)) {
|
|
141
|
+
let report: CursorCloudRunReport = { agentId: params.run.agentId, runId: params.run.id, branches: [] };
|
|
142
|
+
try {
|
|
143
|
+
report = await collectCursorCloudRunReport({
|
|
144
|
+
agent: params.prepared.agent,
|
|
145
|
+
run: params.run,
|
|
146
|
+
waitResult,
|
|
147
|
+
apiKey,
|
|
148
|
+
});
|
|
149
|
+
} catch (error) {
|
|
150
|
+
recordCursorCloudReportingError(params.sdkEventDebug, error, apiKey);
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
recordCursorCloudLifecycleRun(report, { apiKey });
|
|
154
|
+
} catch (error) {
|
|
155
|
+
recordCursorCloudReportingError(params.sdkEventDebug, error, apiKey);
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
params.sdkEventDebug?.recordProviderEvent("cloud_run_report", report);
|
|
159
|
+
} catch (error) {
|
|
160
|
+
recordCursorCloudReportingError(params.sdkEventDebug, error, apiKey);
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
displayOnlyTraceBlock = formatCursorCloudRunReport(report, { apiKey });
|
|
164
|
+
} catch (error) {
|
|
165
|
+
recordCursorCloudReportingError(params.sdkEventDebug, error, apiKey);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
params.sdkEventDebug?.recordWaitResult(waitResult);
|
|
170
|
+
} catch {
|
|
171
|
+
// Debug reporting must never affect provider execution.
|
|
172
|
+
}
|
|
173
|
+
if (params.prepared.runtimeTarget === "local" && isCursorRunFinishedSuccessfully(outcome)) {
|
|
112
174
|
await replayCursorTranscriptWebToolCalls(
|
|
113
175
|
params.run.agentId,
|
|
114
176
|
params.prepared.cwd,
|
|
@@ -118,9 +180,13 @@ export async function awaitFinalizeCursorRunOutcome(params: AwaitFinalizeCursorR
|
|
|
118
180
|
);
|
|
119
181
|
}
|
|
120
182
|
params.prepared.runtime.turnCoordinator.discardIncompleteStartedToolCalls(outcome.incompleteTools);
|
|
121
|
-
|
|
122
|
-
|
|
183
|
+
try {
|
|
184
|
+
await params.sdkEventDebug?.captureRunArtifacts(params.run);
|
|
185
|
+
} catch {
|
|
186
|
+
// Debug artifact failures must never affect provider execution.
|
|
187
|
+
}
|
|
188
|
+
if (params.prepared.runtimeTarget === "local" && params.cacheContextWindow !== false) {
|
|
123
189
|
await cacheSdkContextWindow(params.contextWindowAgentId ?? params.run.agentId, params.modelId, params.prepared.cwd);
|
|
124
190
|
}
|
|
125
|
-
return outcome;
|
|
191
|
+
return { outcome, displayOnlyTraceBlock };
|
|
126
192
|
}
|