import type { LocalAgentStore, RunError, SDKAgent } from "@cursor/sdk"; import { loadCursorTranscriptWebToolCallsAfterOffset } from "./agent-message-web-tools.js"; import { getCheckpointContextWindow, saveCachedContextWindow } from "./context-window-cache.js"; import type { CursorSdkEventDebugSink } from "./sdk-event-debug.js"; import type { CursorSdkTurnCoordinator } from "./provider-turn-coordinator.js"; import { resolveCursorRunOutcome, type CursorRunOutcome, } from "./provider-run-outcome.js"; import type { CursorProviderTurnPrepareResult } from "./provider-turn-types.js"; import { loadCursorSdk } from "./sdk-runtime.js"; import { attachCursorSdkBilledTurnUsage } from "./sdk-billed-usage.js"; export async function cacheSdkContextWindow( agentId: string, modelId: string, cwd?: string, store?: LocalAgentStore, ): Promise { try { const { createAgentPlatform } = await loadCursorSdk(); const platform = await createAgentPlatform( cwd || store ? { ...(cwd ? { workspaceRef: cwd, scopedWorkspaceRef: cwd } : {}), ...(store ? { localStore: store } : {}), } : undefined, ); const checkpoint = await platform.checkpointStore.loadLatest(agentId); const contextWindow = getCheckpointContextWindow(checkpoint); if (contextWindow) saveCachedContextWindow(modelId, contextWindow); } catch { // Context-window cache failures must not affect response streaming. } } export interface BuildCursorRunOutcomeParams { waitResult: Awaited>["wait"]>>; prepared: CursorProviderTurnPrepareResult; signal?: AbortSignal; runResultFallback?: string; runErrorFallback?: RunError; resolvedApiKey?: string; optionsApiKey?: string; } export function buildCursorRunOutcomeFromWait(params: BuildCursorRunOutcomeParams): CursorRunOutcome { const { waitResult, prepared } = params; const { turnCoordinator, liveRun } = prepared.runtime; const { textDeltas } = turnCoordinator; return resolveCursorRunOutcome({ waitResult, signalAborted: params.signal?.aborted, textDeltas, emittedText: liveRun?.emittedText ?? textDeltas.join(""), planTextCandidate: turnCoordinator.planTextCandidate, selectFinalTextOptions: liveRun ? undefined : { allowPartialPrefix: true }, runResultFallback: params.runResultFallback, runErrorFallback: params.runErrorFallback, resolvedApiKey: params.resolvedApiKey, optionsApiKey: params.optionsApiKey, }); } async function replayCursorTranscriptWebToolCalls( agentId: string, cwd: string, messageOffset: number | undefined, turnStore: LocalAgentStore, turnCoordinator: CursorSdkTurnCoordinator, sdkEventDebug: CursorSdkEventDebugSink | undefined, ): Promise { try { const transcriptToolCalls = await loadCursorTranscriptWebToolCallsAfterOffset({ agentId, cwd, offset: messageOffset, store: turnStore, }); if (transcriptToolCalls.length === 0) return; sdkEventDebug?.recordCoordinatorEvent("cursor-transcript-web-tools", { agentId, messageOffset, count: transcriptToolCalls.length, }); turnCoordinator.handleTranscriptCompletedToolCalls(transcriptToolCalls); } catch (error) { sdkEventDebug?.recordError("cursor_transcript_web_tools", error); } } export interface AwaitFinalizeCursorRunOutcomeParams { run: Awaited>; prepared: CursorProviderTurnPrepareResult; cursorAgentMessageOffset: number | undefined; modelId: string; signal?: AbortSignal; runResultFallback?: string; runErrorFallback?: RunError; resolvedApiKey?: string; optionsApiKey?: string; sdkEventDebug?: CursorSdkEventDebugSink; waitResult?: Awaited>["wait"]>>; cacheContextWindow?: boolean; } export interface FinalizedCursorRunOutcome { outcome: CursorRunOutcome; } /** Single wait/finalize path for SDK runs: wait, debug capture, transcript replay, incomplete tools, artifacts, context cache. */ export async function awaitFinalizeCursorRunOutcome(params: AwaitFinalizeCursorRunOutcomeParams): Promise { const waitResult = params.waitResult ?? (await params.run.wait()); const outcome = buildCursorRunOutcomeFromWait({ waitResult, prepared: params.prepared, signal: params.signal, runResultFallback: params.runResultFallback, runErrorFallback: params.runErrorFallback, resolvedApiKey: params.resolvedApiKey, optionsApiKey: params.optionsApiKey, }); const billed = await attachCursorSdkBilledTurnUsage({ agent: params.prepared.sessionAgentLease.agent, agentId: params.run.agentId, }); params.prepared.runtime.billedTurnUsage = billed.turn; if (params.prepared.runtime.liveRun) { params.prepared.runtime.liveRun.billedTurnUsage = billed.turn; } try { params.sdkEventDebug?.recordWaitResult(waitResult); } catch { // Debug reporting must never affect provider execution. } if (outcome.kind === "finished") { await replayCursorTranscriptWebToolCalls( params.run.agentId, params.prepared.cwd, params.cursorAgentMessageOffset, params.prepared.sessionAgentLease.store, params.prepared.runtime.turnCoordinator, params.sdkEventDebug, ); } params.prepared.runtime.turnCoordinator.discardIncompleteStartedToolCalls(outcome.incompleteTools); try { await params.sdkEventDebug?.captureRunArtifacts(params.run); } catch { // Debug artifact failures must never affect provider execution. } if (params.cacheContextWindow !== false) { await cacheSdkContextWindow( params.prepared.sessionAgentLease.agent.agentId, params.modelId, params.prepared.cwd, params.prepared.sessionAgentLease.store, ); } return { outcome }; }