@code-yeongyu/senpi-ai 2026.8.21 → 2026.8.22-2
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/dist/api/cursor-agent/stream-retry.d.ts +21 -0
- package/dist/api/cursor-agent/stream-retry.d.ts.map +1 -0
- package/dist/api/cursor-agent/stream-retry.js +36 -0
- package/dist/api/cursor-agent/stream-retry.js.map +1 -0
- package/dist/api/cursor-agent/types.d.ts +10 -0
- package/dist/api/cursor-agent/types.d.ts.map +1 -1
- package/dist/api/cursor-agent/types.js.map +1 -1
- package/dist/api/cursor-agent.d.ts +6 -0
- package/dist/api/cursor-agent.d.ts.map +1 -1
- package/dist/api/cursor-agent.js +166 -26
- package/dist/api/cursor-agent.js.map +1 -1
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/github-copilot.json +1 -1
- package/dist/providers/data/google.json +1 -1
- package/dist/providers/data/nvidia.json +1 -1
- package/dist/providers/data/opencode-go.json +1 -1
- package/dist/providers/data/opencode.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type CursorStreamRetryCause = "stall" | "transport" | "clean-end";
|
|
2
|
+
export declare class CursorRetryableStreamError extends Error {
|
|
3
|
+
readonly retryCause: CursorStreamRetryCause;
|
|
4
|
+
constructor(message: string, retryCause: CursorStreamRetryCause, options?: ErrorOptions);
|
|
5
|
+
}
|
|
6
|
+
export declare function isCursorRetryableStreamError(error: unknown): error is CursorRetryableStreamError;
|
|
7
|
+
export declare function cursorStreamRetryDelayMs(options: {
|
|
8
|
+
attempt: number;
|
|
9
|
+
baseDelayMs?: number;
|
|
10
|
+
fixedDelayMs?: number;
|
|
11
|
+
random?: () => number;
|
|
12
|
+
}): number;
|
|
13
|
+
export declare function shouldRetryCursorStream(options: {
|
|
14
|
+
error: unknown;
|
|
15
|
+
retries: number;
|
|
16
|
+
maxRetries: number;
|
|
17
|
+
sawTurnEnded: boolean;
|
|
18
|
+
aborted: boolean;
|
|
19
|
+
}): boolean;
|
|
20
|
+
export declare function waitForCursorStreamRetry(delayMs: number, signal?: AbortSignal): Promise<void>;
|
|
21
|
+
//# sourceMappingURL=stream-retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-retry.d.ts","sourceRoot":"","sources":["../../../src/api/cursor-agent/stream-retry.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,WAAW,GAAG,WAAW,CAAC;AAEzE,qBAAa,0BAA2B,SAAQ,KAAK;IACpD,QAAQ,CAAC,UAAU,EAAE,sBAAsB,CAAC;gBAEhC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,sBAAsB,EAAE,OAAO,CAAC,EAAE,YAAY;CAKvF;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,0BAA0B,CAEhG;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;CACtB,GAAG,MAAM,CAMT;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAChD,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CAOV;AAED,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAanG"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export class CursorRetryableStreamError extends Error {
|
|
2
|
+
constructor(message, retryCause, options) {
|
|
3
|
+
super(message, options);
|
|
4
|
+
this.name = "CursorRetryableStreamError";
|
|
5
|
+
this.retryCause = retryCause;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export function isCursorRetryableStreamError(error) {
|
|
9
|
+
return error instanceof CursorRetryableStreamError;
|
|
10
|
+
}
|
|
11
|
+
export function cursorStreamRetryDelayMs(options) {
|
|
12
|
+
if (options.fixedDelayMs !== undefined)
|
|
13
|
+
return Math.max(0, options.fixedDelayMs);
|
|
14
|
+
const baseDelayMs = options.baseDelayMs ?? 1000;
|
|
15
|
+
const backoffMs = Math.min(baseDelayMs * 2 ** options.attempt, 60_000);
|
|
16
|
+
const jitter = Math.floor(backoffMs * 0.2 * (options.random ?? Math.random)());
|
|
17
|
+
return backoffMs + jitter;
|
|
18
|
+
}
|
|
19
|
+
export function shouldRetryCursorStream(options) {
|
|
20
|
+
return (!options.sawTurnEnded &&
|
|
21
|
+
!options.aborted &&
|
|
22
|
+
options.retries < options.maxRetries &&
|
|
23
|
+
isCursorRetryableStreamError(options.error));
|
|
24
|
+
}
|
|
25
|
+
export async function waitForCursorStreamRetry(delayMs, signal) {
|
|
26
|
+
if (delayMs <= 0 || signal?.aborted)
|
|
27
|
+
return;
|
|
28
|
+
await new Promise((resolve) => {
|
|
29
|
+
const timer = setTimeout(resolve, delayMs);
|
|
30
|
+
signal?.addEventListener("abort", () => {
|
|
31
|
+
clearTimeout(timer);
|
|
32
|
+
resolve();
|
|
33
|
+
}, { once: true });
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=stream-retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-retry.js","sourceRoot":"","sources":["../../../src/api/cursor-agent/stream-retry.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IAGpD,YAAY,OAAe,EAAE,UAAkC,EAAE,OAAsB;QACtF,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;QACzC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC9B,CAAC;CACD;AAED,MAAM,UAAU,4BAA4B,CAAC,KAAc;IAC1D,OAAO,KAAK,YAAY,0BAA0B,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,OAKxC;IACA,IAAI,OAAO,CAAC,YAAY,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACjF,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,IAAI,CAAC;IAChD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC/E,OAAO,SAAS,GAAG,MAAM,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,OAMvC;IACA,OAAO,CACN,CAAC,OAAO,CAAC,YAAY;QACrB,CAAC,OAAO,CAAC,OAAO;QAChB,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,UAAU;QACpC,4BAA4B,CAAC,OAAO,CAAC,KAAK,CAAC,CAC3C,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,OAAe,EAAE,MAAoB;IACnF,IAAI,OAAO,IAAI,CAAC,IAAI,MAAM,EAAE,OAAO;QAAE,OAAO;IAC5C,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QACnC,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC3C,MAAM,EAAE,gBAAgB,CACvB,OAAO,EACP,GAAG,EAAE;YACJ,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,EAAE,CAAC;QACX,CAAC,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CACd,CAAC;IACH,CAAC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["export type CursorStreamRetryCause = \"stall\" | \"transport\" | \"clean-end\";\n\nexport class CursorRetryableStreamError extends Error {\n\treadonly retryCause: CursorStreamRetryCause;\n\n\tconstructor(message: string, retryCause: CursorStreamRetryCause, options?: ErrorOptions) {\n\t\tsuper(message, options);\n\t\tthis.name = \"CursorRetryableStreamError\";\n\t\tthis.retryCause = retryCause;\n\t}\n}\n\nexport function isCursorRetryableStreamError(error: unknown): error is CursorRetryableStreamError {\n\treturn error instanceof CursorRetryableStreamError;\n}\n\nexport function cursorStreamRetryDelayMs(options: {\n\tattempt: number;\n\tbaseDelayMs?: number;\n\tfixedDelayMs?: number;\n\trandom?: () => number;\n}): number {\n\tif (options.fixedDelayMs !== undefined) return Math.max(0, options.fixedDelayMs);\n\tconst baseDelayMs = options.baseDelayMs ?? 1000;\n\tconst backoffMs = Math.min(baseDelayMs * 2 ** options.attempt, 60_000);\n\tconst jitter = Math.floor(backoffMs * 0.2 * (options.random ?? Math.random)());\n\treturn backoffMs + jitter;\n}\n\nexport function shouldRetryCursorStream(options: {\n\terror: unknown;\n\tretries: number;\n\tmaxRetries: number;\n\tsawTurnEnded: boolean;\n\taborted: boolean;\n}): boolean {\n\treturn (\n\t\t!options.sawTurnEnded &&\n\t\t!options.aborted &&\n\t\toptions.retries < options.maxRetries &&\n\t\tisCursorRetryableStreamError(options.error)\n\t);\n}\n\nexport async function waitForCursorStreamRetry(delayMs: number, signal?: AbortSignal): Promise<void> {\n\tif (delayMs <= 0 || signal?.aborted) return;\n\tawait new Promise<void>((resolve) => {\n\t\tconst timer = setTimeout(resolve, delayMs);\n\t\tsignal?.addEventListener(\n\t\t\t\"abort\",\n\t\t\t() => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tresolve();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t});\n}\n"]}
|
|
@@ -118,5 +118,15 @@ export interface CursorAgentOptions extends StreamOptions {
|
|
|
118
118
|
* variant request shape.
|
|
119
119
|
*/
|
|
120
120
|
thinkingSelection?: ThinkingSelection;
|
|
121
|
+
/** Override stream health bounds for deterministic provider integration tests. */
|
|
122
|
+
streamHealthFailThresholdMs?: number;
|
|
123
|
+
/** @deprecated Accepted for compatibility; heartbeat/checkpoint frames are always liveness. */
|
|
124
|
+
streamHealthHeartbeatOnlyThresholdMs?: number;
|
|
125
|
+
/** Maximum pre-completion stall/transport retries (default 10). */
|
|
126
|
+
streamStallMaxRetries?: number;
|
|
127
|
+
/** Fixed retry delay for tests; production uses exponential backoff plus jitter. */
|
|
128
|
+
streamStallRetryDelayMs?: number;
|
|
129
|
+
/** Override the post-turn exec drain bound for deterministic tests. */
|
|
130
|
+
turnEndDrainTimeoutMs?: number;
|
|
121
131
|
}
|
|
122
132
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/api/cursor-agent/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/api/cursor-agent/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/api/cursor-agent/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG","sourcesContent":["/**\n * Cursor exec-channel handler contracts.\n *\n * The Cursor agent protocol is server-driven: mid-turn, the server sends\n * `ExecServerMessage` frames asking the CLIENT to run a tool and blocks until\n * the reply arrives on the same stream. The host (coding-agent) supplies\n * these handlers; the `cursor-agent` API dispatches frames onto them, sends\n * their protobuf answers back on the wire, synthesizes already-resolved\n * `toolCall` blocks into the assistant message, and pairs each with a\n * `ToolResultMessage` delivered through {@link CursorToolResultHandler}.\n *\n * Everything here is type-only over the generated protobuf shapes, so it is\n * safe to import from browser-reachable modules.\n */\n\nimport type { StreamOptions, ThinkingSelection, ToolResultMessage } from \"../../types.ts\";\nimport type {\n\tDeleteArgs,\n\tDeleteResult,\n\tDiagnosticsArgs,\n\tDiagnosticsResult,\n\tGrepArgs,\n\tGrepResult,\n\tLsArgs,\n\tLsResult,\n\tMcpResult,\n\tPiBashExecArgs,\n\tPiBashExecResult,\n\tPiEditExecArgs,\n\tPiEditExecResult,\n\tPiFindExecArgs,\n\tPiFindExecResult,\n\tPiGrepExecArgs,\n\tPiGrepExecResult,\n\tPiLsExecArgs,\n\tPiLsExecResult,\n\tPiReadExecArgs,\n\tPiReadExecResult,\n\tPiWriteExecArgs,\n\tPiWriteExecResult,\n\tReadArgs,\n\tReadResult,\n\tShellArgs,\n\tShellResult,\n\tWriteArgs,\n\tWriteResult,\n} from \"./gen/agent_pb.ts\";\n\n/**\n * The three return forms an exec handler may use: a wire result with an\n * optional transcript pairing, a bare wire result, or a bare\n * `ToolResultMessage` from which the wire result is derived.\n */\nexport type CursorExecHandlerResult<T> = { result: T; toolResult?: ToolResultMessage } | T | ToolResultMessage;\n\n/**\n * Optional rewrite of a Cursor exec-channel tool result.\n * May return a Promise. Returning `undefined` keeps the original result.\n */\nexport type CursorToolResultHandler = (\n\tresult: ToolResultMessage,\n) => ToolResultMessage | undefined | Promise<ToolResultMessage | undefined>;\n\n/**\n * Identifies the synthesized assistant block a Cursor exec call was filed\n * under, so paths that produce no handler `toolResult` can still pair one.\n */\nexport interface CursorExecPairing {\n\ttoolCallId: string;\n\ttoolName: string;\n}\n\nexport interface CursorMcpCall {\n\tname: string;\n\tproviderIdentifier: string;\n\ttoolName: string;\n\ttoolCallId: string;\n\targs: Record<string, unknown>;\n\trawArgs: Record<string, Uint8Array>;\n\t/**\n\t * The frame asks only whether this call would be permitted — it must not\n\t * run. The server sends it to resolve a smart-mode approval decision ahead\n\t * of the real invocation; executing here would fire a side-effecting tool\n\t * the user has not yet been asked about (and fire it twice once the real\n\t * call arrives).\n\t */\n\tapprovalOnly?: boolean;\n}\n\nexport interface CursorShellStreamCallbacks {\n\tonStdout(data: string): void;\n\tonStderr(data: string): void;\n}\n\n/**\n * A modern Pi exec frame plus the call id the dispatcher minted for it.\n *\n * Unlike the legacy exec args (`ReadArgs`, `ShellArgs`, ...), the Pi frames\n * carry no `tool_call_id` field: the id rides the streamed `ToolCall`\n * envelope instead. The exec channel has no access to that envelope, so the\n * dispatcher mints an id and hands it to the handler, keeping the synthesized\n * transcript block and its paired `toolResult` on the same key.\n */\nexport interface CursorPiCall<TArgs> {\n\targs: TArgs;\n\ttoolCallId: string;\n}\n\nexport interface CursorExecHandlers {\n\tread?: (args: ReadArgs) => Promise<CursorExecHandlerResult<ReadResult>>;\n\tls?: (args: LsArgs) => Promise<CursorExecHandlerResult<LsResult>>;\n\tgrep?: (args: GrepArgs) => Promise<CursorExecHandlerResult<GrepResult>>;\n\twrite?: (args: WriteArgs) => Promise<CursorExecHandlerResult<WriteResult>>;\n\tdelete?: (args: DeleteArgs) => Promise<CursorExecHandlerResult<DeleteResult>>;\n\tshell?: (args: ShellArgs) => Promise<CursorExecHandlerResult<ShellResult>>;\n\tshellStream?: (\n\t\targs: ShellArgs,\n\t\tcallbacks: CursorShellStreamCallbacks,\n\t) => Promise<CursorExecHandlerResult<ShellResult>>;\n\tdiagnostics?: (args: DiagnosticsArgs) => Promise<CursorExecHandlerResult<DiagnosticsResult>>;\n\tmcp?: (call: CursorMcpCall) => Promise<CursorExecHandlerResult<McpResult>>;\n\t/**\n\t * Answers \"would this MCP call be permitted\", without running it.\n\t *\n\t * `true` only when the host's policy resolves to a definite allow. A\n\t * pending prompt is `false`: it can only be answered interactively at\n\t * execution time. When no handler is registered the provider refuses,\n\t * since it cannot decide.\n\t */\n\tmcpApprovalPreflight?: (call: CursorMcpCall) => Promise<boolean>;\n\t/**\n\t * Modern Cursor CLI Pi tool frames (`ExecServerMessage` 45-51). They are a\n\t * distinct frame family from the legacy `readArgs`/`shellArgs`/... set:\n\t * different args, different result oneofs, and no `tool_call_id`.\n\t */\n\tpiRead?: (call: CursorPiCall<PiReadExecArgs>) => Promise<CursorExecHandlerResult<PiReadExecResult>>;\n\tpiBash?: (call: CursorPiCall<PiBashExecArgs>) => Promise<CursorExecHandlerResult<PiBashExecResult>>;\n\tpiEdit?: (call: CursorPiCall<PiEditExecArgs>) => Promise<CursorExecHandlerResult<PiEditExecResult>>;\n\tpiWrite?: (call: CursorPiCall<PiWriteExecArgs>) => Promise<CursorExecHandlerResult<PiWriteExecResult>>;\n\tpiGrep?: (call: CursorPiCall<PiGrepExecArgs>) => Promise<CursorExecHandlerResult<PiGrepExecResult>>;\n\tpiFind?: (call: CursorPiCall<PiFindExecArgs>) => Promise<CursorExecHandlerResult<PiFindExecResult>>;\n\tpiLs?: (call: CursorPiCall<PiLsExecArgs>) => Promise<CursorExecHandlerResult<PiLsExecResult>>;\n\tonToolResult?: CursorToolResultHandler;\n}\n\n/** Stream options accepted by the `cursor-agent` API. */\nexport interface CursorAgentOptions extends StreamOptions {\n\t/** Optional server-side system prompt override (RunRequest.customSystemPrompt). */\n\tcustomSystemPrompt?: string;\n\t/** Conversation id override; defaults to `sessionId`, else a random UUID per stream. */\n\tconversationId?: string;\n\t/** Cursor exec/MCP tool handlers supplied by the host. */\n\texecHandlers?: CursorExecHandlers;\n\t/** Receives every exec-channel tool result for transcript pairing. */\n\tonToolResult?: CursorToolResultHandler;\n\t/**\n\t * Provenance-bearing thinking selection rendered into\n\t * `RequestedModel.parameters`; absent selections keep the representative\n\t * variant request shape.\n\t */\n\tthinkingSelection?: ThinkingSelection;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/api/cursor-agent/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG","sourcesContent":["/**\n * Cursor exec-channel handler contracts.\n *\n * The Cursor agent protocol is server-driven: mid-turn, the server sends\n * `ExecServerMessage` frames asking the CLIENT to run a tool and blocks until\n * the reply arrives on the same stream. The host (coding-agent) supplies\n * these handlers; the `cursor-agent` API dispatches frames onto them, sends\n * their protobuf answers back on the wire, synthesizes already-resolved\n * `toolCall` blocks into the assistant message, and pairs each with a\n * `ToolResultMessage` delivered through {@link CursorToolResultHandler}.\n *\n * Everything here is type-only over the generated protobuf shapes, so it is\n * safe to import from browser-reachable modules.\n */\n\nimport type { StreamOptions, ThinkingSelection, ToolResultMessage } from \"../../types.ts\";\nimport type {\n\tDeleteArgs,\n\tDeleteResult,\n\tDiagnosticsArgs,\n\tDiagnosticsResult,\n\tGrepArgs,\n\tGrepResult,\n\tLsArgs,\n\tLsResult,\n\tMcpResult,\n\tPiBashExecArgs,\n\tPiBashExecResult,\n\tPiEditExecArgs,\n\tPiEditExecResult,\n\tPiFindExecArgs,\n\tPiFindExecResult,\n\tPiGrepExecArgs,\n\tPiGrepExecResult,\n\tPiLsExecArgs,\n\tPiLsExecResult,\n\tPiReadExecArgs,\n\tPiReadExecResult,\n\tPiWriteExecArgs,\n\tPiWriteExecResult,\n\tReadArgs,\n\tReadResult,\n\tShellArgs,\n\tShellResult,\n\tWriteArgs,\n\tWriteResult,\n} from \"./gen/agent_pb.ts\";\n\n/**\n * The three return forms an exec handler may use: a wire result with an\n * optional transcript pairing, a bare wire result, or a bare\n * `ToolResultMessage` from which the wire result is derived.\n */\nexport type CursorExecHandlerResult<T> = { result: T; toolResult?: ToolResultMessage } | T | ToolResultMessage;\n\n/**\n * Optional rewrite of a Cursor exec-channel tool result.\n * May return a Promise. Returning `undefined` keeps the original result.\n */\nexport type CursorToolResultHandler = (\n\tresult: ToolResultMessage,\n) => ToolResultMessage | undefined | Promise<ToolResultMessage | undefined>;\n\n/**\n * Identifies the synthesized assistant block a Cursor exec call was filed\n * under, so paths that produce no handler `toolResult` can still pair one.\n */\nexport interface CursorExecPairing {\n\ttoolCallId: string;\n\ttoolName: string;\n}\n\nexport interface CursorMcpCall {\n\tname: string;\n\tproviderIdentifier: string;\n\ttoolName: string;\n\ttoolCallId: string;\n\targs: Record<string, unknown>;\n\trawArgs: Record<string, Uint8Array>;\n\t/**\n\t * The frame asks only whether this call would be permitted — it must not\n\t * run. The server sends it to resolve a smart-mode approval decision ahead\n\t * of the real invocation; executing here would fire a side-effecting tool\n\t * the user has not yet been asked about (and fire it twice once the real\n\t * call arrives).\n\t */\n\tapprovalOnly?: boolean;\n}\n\nexport interface CursorShellStreamCallbacks {\n\tonStdout(data: string): void;\n\tonStderr(data: string): void;\n}\n\n/**\n * A modern Pi exec frame plus the call id the dispatcher minted for it.\n *\n * Unlike the legacy exec args (`ReadArgs`, `ShellArgs`, ...), the Pi frames\n * carry no `tool_call_id` field: the id rides the streamed `ToolCall`\n * envelope instead. The exec channel has no access to that envelope, so the\n * dispatcher mints an id and hands it to the handler, keeping the synthesized\n * transcript block and its paired `toolResult` on the same key.\n */\nexport interface CursorPiCall<TArgs> {\n\targs: TArgs;\n\ttoolCallId: string;\n}\n\nexport interface CursorExecHandlers {\n\tread?: (args: ReadArgs) => Promise<CursorExecHandlerResult<ReadResult>>;\n\tls?: (args: LsArgs) => Promise<CursorExecHandlerResult<LsResult>>;\n\tgrep?: (args: GrepArgs) => Promise<CursorExecHandlerResult<GrepResult>>;\n\twrite?: (args: WriteArgs) => Promise<CursorExecHandlerResult<WriteResult>>;\n\tdelete?: (args: DeleteArgs) => Promise<CursorExecHandlerResult<DeleteResult>>;\n\tshell?: (args: ShellArgs) => Promise<CursorExecHandlerResult<ShellResult>>;\n\tshellStream?: (\n\t\targs: ShellArgs,\n\t\tcallbacks: CursorShellStreamCallbacks,\n\t) => Promise<CursorExecHandlerResult<ShellResult>>;\n\tdiagnostics?: (args: DiagnosticsArgs) => Promise<CursorExecHandlerResult<DiagnosticsResult>>;\n\tmcp?: (call: CursorMcpCall) => Promise<CursorExecHandlerResult<McpResult>>;\n\t/**\n\t * Answers \"would this MCP call be permitted\", without running it.\n\t *\n\t * `true` only when the host's policy resolves to a definite allow. A\n\t * pending prompt is `false`: it can only be answered interactively at\n\t * execution time. When no handler is registered the provider refuses,\n\t * since it cannot decide.\n\t */\n\tmcpApprovalPreflight?: (call: CursorMcpCall) => Promise<boolean>;\n\t/**\n\t * Modern Cursor CLI Pi tool frames (`ExecServerMessage` 45-51). They are a\n\t * distinct frame family from the legacy `readArgs`/`shellArgs`/... set:\n\t * different args, different result oneofs, and no `tool_call_id`.\n\t */\n\tpiRead?: (call: CursorPiCall<PiReadExecArgs>) => Promise<CursorExecHandlerResult<PiReadExecResult>>;\n\tpiBash?: (call: CursorPiCall<PiBashExecArgs>) => Promise<CursorExecHandlerResult<PiBashExecResult>>;\n\tpiEdit?: (call: CursorPiCall<PiEditExecArgs>) => Promise<CursorExecHandlerResult<PiEditExecResult>>;\n\tpiWrite?: (call: CursorPiCall<PiWriteExecArgs>) => Promise<CursorExecHandlerResult<PiWriteExecResult>>;\n\tpiGrep?: (call: CursorPiCall<PiGrepExecArgs>) => Promise<CursorExecHandlerResult<PiGrepExecResult>>;\n\tpiFind?: (call: CursorPiCall<PiFindExecArgs>) => Promise<CursorExecHandlerResult<PiFindExecResult>>;\n\tpiLs?: (call: CursorPiCall<PiLsExecArgs>) => Promise<CursorExecHandlerResult<PiLsExecResult>>;\n\tonToolResult?: CursorToolResultHandler;\n}\n\n/** Stream options accepted by the `cursor-agent` API. */\nexport interface CursorAgentOptions extends StreamOptions {\n\t/** Optional server-side system prompt override (RunRequest.customSystemPrompt). */\n\tcustomSystemPrompt?: string;\n\t/** Conversation id override; defaults to `sessionId`, else a random UUID per stream. */\n\tconversationId?: string;\n\t/** Cursor exec/MCP tool handlers supplied by the host. */\n\texecHandlers?: CursorExecHandlers;\n\t/** Receives every exec-channel tool result for transcript pairing. */\n\tonToolResult?: CursorToolResultHandler;\n\t/**\n\t * Provenance-bearing thinking selection rendered into\n\t * `RequestedModel.parameters`; absent selections keep the representative\n\t * variant request shape.\n\t */\n\tthinkingSelection?: ThinkingSelection;\n\t/** Override stream health bounds for deterministic provider integration tests. */\n\tstreamHealthFailThresholdMs?: number;\n\t/** @deprecated Accepted for compatibility; heartbeat/checkpoint frames are always liveness. */\n\tstreamHealthHeartbeatOnlyThresholdMs?: number;\n\t/** Maximum pre-completion stall/transport retries (default 10). */\n\tstreamStallMaxRetries?: number;\n\t/** Fixed retry delay for tests; production uses exponential backoff plus jitter. */\n\tstreamStallRetryDelayMs?: number;\n\t/** Override the post-turn exec drain bound for deterministic tests. */\n\tturnEndDrainTimeoutMs?: number;\n}\n"]}
|
|
@@ -24,6 +24,12 @@ import type { CursorAgentOptions, CursorExecHandlerResult, CursorExecHandlers, C
|
|
|
24
24
|
export type { CursorAgentOptions, CursorExecHandlerResult, CursorExecHandlers, CursorExecPairing, CursorMcpCall, CursorPiCall, CursorShellStreamCallbacks, CursorToolResultHandler, } from "./cursor-agent/types.ts";
|
|
25
25
|
export declare const CURSOR_API_URL = "https://api2.cursor.sh";
|
|
26
26
|
export declare const CURSOR_CLIENT_VERSION = "cli-2026.07.23-e383d2b";
|
|
27
|
+
/** Maximum inbound silence before a Cursor turn without turnEnded is failed. */
|
|
28
|
+
export declare const CURSOR_STREAM_HEALTH_FAIL_THRESHOLD_MS = 30000;
|
|
29
|
+
/** @deprecated Heartbeats and checkpoints count as inbound liveness without a separate deadline. */
|
|
30
|
+
export declare const CURSOR_STREAM_HEALTH_HEARTBEAT_ONLY_THRESHOLD_MS: number;
|
|
31
|
+
/** Maximum time allowed to drain exec handlers after turnEnded. */
|
|
32
|
+
export declare const CURSOR_TURN_END_DRAIN_TIMEOUT_MS = 5000;
|
|
27
33
|
/** Reduce caller-supplied headers to what this HTTP/2 request can legally carry. */
|
|
28
34
|
export declare function sanitizeCursorCallerHeaders(headers: Record<string, string> | undefined): Record<string, string>;
|
|
29
35
|
export declare function frameConnectMessage(data: Uint8Array, flags?: number): Buffer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor-agent.d.ts","sourceRoot":"","sources":["../../src/api/cursor-agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAIpC,OAAO,KAAK,EAEX,gBAAgB,EAGhB,OAAO,EAEP,mBAAmB,EACnB,cAAc,EACd,WAAW,EACX,eAAe,EACf,IAAI,EACJ,QAAQ,EACR,iBAAiB,EACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAGN,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AA0BvE,OAAO,EAIN,KAAK,kBAAkB,EAcvB,KAAK,0BAA0B,EA+D/B,KAAK,iBAAiB,
|
|
1
|
+
{"version":3,"file":"cursor-agent.d.ts","sourceRoot":"","sources":["../../src/api/cursor-agent.ts"],"names":[],"mappings":"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"}
|
package/dist/api/cursor-agent.js
CHANGED
|
@@ -31,11 +31,18 @@ import { buildMcpStateResult, buildNeutralHookResult, buildPiBashError, buildPiB
|
|
|
31
31
|
import { AgentClientMessageSchema, AgentConversationTurnStructureSchema, AgentRunRequestSchema, AgentServerMessageSchema, AgentStoreConflictErrorSchema, AgentStoreConflictResultSchema, AssistantMessageSchema, BackgroundShellSpawnResultSchema, CanvasDiagnosticsErrorSchema, CanvasDiagnosticsResultSchema, ClientHeartbeatSchema, ComputerUseErrorSchema, ComputerUseResultSchema, ConversationActionSchema, ConversationSearchErrorSchema, ConversationSearchResultSchema, ConversationStateStructureSchema, ConversationStepSchema, ConversationTurnStructureSchema, DeleteErrorSchema, DeleteRejectedSchema, DeleteResultSchema, DeleteSuccessSchema, DiagnosticsErrorSchema, DiagnosticsRejectedSchema, DiagnosticsResultSchema, DiagnosticsSuccessSchema, ExecClientControlMessageSchema, ExecClientHeartbeatSchema, ExecClientMessageSchema, ExecClientStreamCloseSchema, ExecClientThrowSchema, FetchErrorSchema, FetchResultSchema, ForceBackgroundShellResultSchema, ForceBackgroundShellStatus, ForceBackgroundSubagentResultSchema, ForceBackgroundSubagentStatus, GetBlobResultSchema, GetUsableModelsRequestSchema, GetUsableModelsResponseSchema, GrepContentMatchSchema, GrepContentResultSchema, GrepCountResultSchema, GrepErrorSchema, GrepFileCountSchema, GrepFileMatchSchema, GrepFilesResultSchema, GrepResultSchema, GrepSuccessSchema, GrepUnionResultSchema, KvClientMessageSchema, ListMcpResourcesExecResultSchema, ListMcpResourcesSuccessSchema, LsDirectoryTreeNode_FileSchema, LsDirectoryTreeNodeSchema, LsErrorSchema, LsRejectedSchema, LsResultSchema, LsSuccessSchema, McpAllowlistPrecheckResultSchema, McpApprovedSchema, McpArgsSchema, McpErrorSchema, McpImageContentSchema, McpRejectedSchema, McpResultSchema, McpSuccessSchema, McpTextContentSchema, McpToolCallSchema, McpToolDefinitionSchema, McpToolErrorSchema, McpToolNotFoundSchema, McpToolResultContentItemSchema, McpToolResultSchema, ModelDetailsSchema, ReadErrorSchema, ReadMcpResourceExecResultSchema, ReadMcpResourceNotFoundSchema, ReadRejectedSchema, ReadResultSchema, ReadSuccessSchema, RecordScreenFailureSchema, RecordScreenResultSchema, RequestContextResultSchema, RequestContextSchema, RequestContextSuccessSchema, ResumeActionSchema, SelectedContextSchema, SelectedImageSchema, SetBlobResultSchema, ShellAllowlistPrecheckResultSchema, ShellFailureSchema, ShellRejectedSchema, ShellResultSchema, ShellStreamExitSchema, ShellStreamSchema, ShellStreamStartSchema, ShellStreamStderrSchema, ShellStreamStdoutSchema, ShellSuccessSchema, SmartModeClassifierErrorSchema, SmartModeClassifierResultSchema, SubagentAwaitNotFoundSchema, SubagentAwaitResultSchema, SubagentErrorSchema, SubagentResultSchema, ToolCallSchema, UserMessageActionSchema, UserMessageSchema, WebFetchAllowlistPrecheckResultSchema, WriteErrorSchema, WriteRejectedSchema, WriteResultSchema, WriteShellStdinErrorSchema, WriteShellStdinResultSchema, WriteSuccessSchema, } from "./cursor-agent/gen/agent_pb.js";
|
|
32
32
|
import { composeShellCommand, omitUndefinedArgs, piLimit, piLsPath, piReadArgs, piTimeout, } from "./cursor-agent/pi-args.js";
|
|
33
33
|
import { buildRequestedModel } from "./cursor-agent/reasoning-params.js";
|
|
34
|
+
import { CursorRetryableStreamError, cursorStreamRetryDelayMs, shouldRetryCursorStream, waitForCursorStreamRetry, } from "./cursor-agent/stream-retry.js";
|
|
34
35
|
import { CURSOR_CONVERSATION_POISONED_MESSAGE, createConversationRotationStore, isZeroTokenResourceExhausted, resolveConversationRotationPersistPath, } from "./cursor-conversation-rotation.js";
|
|
35
36
|
import { keepUsableCursorTaskArgs } from "./cursor-task-args.js";
|
|
36
37
|
export const CURSOR_API_URL = "https://api2.cursor.sh";
|
|
37
38
|
export const CURSOR_CLIENT_VERSION = "cli-2026.07.23-e383d2b";
|
|
38
39
|
const EXEC_HEARTBEAT_INTERVAL_MS = 3000;
|
|
40
|
+
/** Maximum inbound silence before a Cursor turn without turnEnded is failed. */
|
|
41
|
+
export const CURSOR_STREAM_HEALTH_FAIL_THRESHOLD_MS = 30_000;
|
|
42
|
+
/** @deprecated Heartbeats and checkpoints count as inbound liveness without a separate deadline. */
|
|
43
|
+
export const CURSOR_STREAM_HEALTH_HEARTBEAT_ONLY_THRESHOLD_MS = CURSOR_STREAM_HEALTH_FAIL_THRESHOLD_MS * 3;
|
|
44
|
+
/** Maximum time allowed to drain exec handlers after turnEnded. */
|
|
45
|
+
export const CURSOR_TURN_END_DRAIN_TIMEOUT_MS = 5000;
|
|
39
46
|
/**
|
|
40
47
|
* HTTP/1 connection-specific headers that HTTP/2 forbids. Node's
|
|
41
48
|
* `http2.request()` throws on these rather than dropping them.
|
|
@@ -221,8 +228,10 @@ export const stream = (model, context, options) => {
|
|
|
221
228
|
let h2Client = null;
|
|
222
229
|
let h2Request = null;
|
|
223
230
|
let heartbeatTimer = null;
|
|
231
|
+
let streamHealthTimer = null;
|
|
224
232
|
let h2Settled = false;
|
|
225
233
|
let sawTurnEnded = false;
|
|
234
|
+
let turnEndDrainTimedOut = false;
|
|
226
235
|
let endStreamError = null;
|
|
227
236
|
// Reachable from the catch: a stream that dies mid-turn must still close
|
|
228
237
|
// and pair the blocks it left open.
|
|
@@ -233,6 +242,10 @@ export const stream = (model, context, options) => {
|
|
|
233
242
|
if (h2Settled)
|
|
234
243
|
return;
|
|
235
244
|
h2Settled = true;
|
|
245
|
+
if (streamHealthTimer) {
|
|
246
|
+
clearTimeout(streamHealthTimer);
|
|
247
|
+
streamHealthTimer = null;
|
|
248
|
+
}
|
|
236
249
|
if (error !== undefined) {
|
|
237
250
|
rejectH2(error);
|
|
238
251
|
return;
|
|
@@ -252,19 +265,25 @@ export const stream = (model, context, options) => {
|
|
|
252
265
|
let baseConversationId;
|
|
253
266
|
let conversationId;
|
|
254
267
|
let usageState;
|
|
255
|
-
let
|
|
268
|
+
let retryAttempt = false;
|
|
256
269
|
let attempt = 0;
|
|
270
|
+
let streamRetries = 0;
|
|
271
|
+
let forceResumeAction = false;
|
|
272
|
+
let pinnedRequestedModel;
|
|
273
|
+
let pinnedModelDetails;
|
|
257
274
|
do {
|
|
258
|
-
|
|
275
|
+
retryAttempt = false;
|
|
259
276
|
attempt += 1;
|
|
260
277
|
h2Settled = false;
|
|
261
278
|
sawTurnEnded = false;
|
|
279
|
+
turnEndDrainTimedOut = false;
|
|
262
280
|
endStreamError = null;
|
|
263
281
|
openBlockState = undefined;
|
|
264
282
|
const h2Completion = new Promise((resolve, reject) => {
|
|
265
283
|
resolveH2 = resolve;
|
|
266
284
|
rejectH2 = reject;
|
|
267
285
|
});
|
|
286
|
+
let attemptSawCheckpoint = false;
|
|
268
287
|
try {
|
|
269
288
|
const apiKey = options?.apiKey;
|
|
270
289
|
if (!apiKey) {
|
|
@@ -275,11 +294,16 @@ export const stream = (model, context, options) => {
|
|
|
275
294
|
const blobStore = conversationBlobStores.get(conversationId) ?? new Map();
|
|
276
295
|
conversationBlobStores.set(conversationId, blobStore);
|
|
277
296
|
const cachedState = conversationStateCache.get(conversationId);
|
|
278
|
-
const { requestBytes, conversationState } = await buildGrpcRequest(model, context, options, {
|
|
297
|
+
const { requestBytes, conversationState, requestedModel, modelDetails } = await buildGrpcRequest(model, context, options, {
|
|
279
298
|
conversationId,
|
|
280
299
|
blobStore,
|
|
281
300
|
conversationState: cachedState,
|
|
301
|
+
forceResumeAction,
|
|
302
|
+
pinnedRequestedModel,
|
|
303
|
+
pinnedModelDetails,
|
|
282
304
|
});
|
|
305
|
+
pinnedRequestedModel ??= requestedModel;
|
|
306
|
+
pinnedModelDetails ??= modelDetails;
|
|
283
307
|
conversationStateCache.set(conversationId, conversationState);
|
|
284
308
|
const requestContextTools = buildMcpToolDefinitions(context.tools);
|
|
285
309
|
const baseUrl = model.baseUrl || CURSOR_API_URL;
|
|
@@ -300,9 +324,28 @@ export const stream = (model, context, options) => {
|
|
|
300
324
|
"x-cursor-client-type": "cli",
|
|
301
325
|
"x-request-id": randomUUID(),
|
|
302
326
|
};
|
|
303
|
-
|
|
304
|
-
h2Client
|
|
305
|
-
|
|
327
|
+
const attemptH2Client = http2.connect(baseUrl);
|
|
328
|
+
h2Client = attemptH2Client;
|
|
329
|
+
attemptH2Client.on("error", (error) => {
|
|
330
|
+
if (h2Client !== attemptH2Client)
|
|
331
|
+
return;
|
|
332
|
+
const mapped = mapH2TransportError(error, baseUrl);
|
|
333
|
+
settleH2(sawTurnEnded
|
|
334
|
+
? mapped
|
|
335
|
+
: new CursorRetryableStreamError(mapped instanceof Error ? mapped.message : String(mapped), "transport", { cause: mapped }));
|
|
336
|
+
});
|
|
337
|
+
attemptH2Client.on("goaway", () => {
|
|
338
|
+
if (h2Client === attemptH2Client && !h2Settled && !sawTurnEnded) {
|
|
339
|
+
settleH2(new CursorRetryableStreamError("Cursor HTTP/2 session received GOAWAY", "transport"));
|
|
340
|
+
h2Request?.close();
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
attemptH2Client.on("close", () => {
|
|
344
|
+
if (h2Client === attemptH2Client && !h2Settled && !sawTurnEnded && !endStreamError) {
|
|
345
|
+
settleH2(new CursorRetryableStreamError("Cursor HTTP/2 session closed", "transport"));
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
h2Request = attemptH2Client.request(requestHeaders);
|
|
306
349
|
if (attempt === 1) {
|
|
307
350
|
stream.push({ type: "start", partial: output });
|
|
308
351
|
}
|
|
@@ -337,8 +380,55 @@ export const stream = (model, context, options) => {
|
|
|
337
380
|
};
|
|
338
381
|
openBlockState = state;
|
|
339
382
|
const onConversationCheckpoint = (checkpoint) => {
|
|
383
|
+
attemptSawCheckpoint = true;
|
|
340
384
|
conversationStateCache.set(conversationId, checkpoint);
|
|
341
385
|
};
|
|
386
|
+
const healthFailThresholdMs = options?.streamHealthFailThresholdMs ?? CURSOR_STREAM_HEALTH_FAIL_THRESHOLD_MS;
|
|
387
|
+
let lastInboundFrameAt = Date.now();
|
|
388
|
+
let turnEndCompletionStarted = false;
|
|
389
|
+
const armStreamHealthTimer = () => {
|
|
390
|
+
if (streamHealthTimer)
|
|
391
|
+
clearTimeout(streamHealthTimer);
|
|
392
|
+
if (sawTurnEnded || h2Settled)
|
|
393
|
+
return;
|
|
394
|
+
const now = Date.now();
|
|
395
|
+
const deadline = lastInboundFrameAt + healthFailThresholdMs;
|
|
396
|
+
streamHealthTimer = setTimeout(() => {
|
|
397
|
+
streamHealthTimer = null;
|
|
398
|
+
if (sawTurnEnded || h2Settled)
|
|
399
|
+
return;
|
|
400
|
+
const stalledFor = Date.now() - lastInboundFrameAt;
|
|
401
|
+
if (stalledFor < healthFailThresholdMs) {
|
|
402
|
+
armStreamHealthTimer();
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
settleH2(new CursorRetryableStreamError("Cursor stream ended before turnEnded: inbound stream stalled", "stall"));
|
|
406
|
+
h2Request?.close();
|
|
407
|
+
}, Math.max(0, deadline - now));
|
|
408
|
+
};
|
|
409
|
+
const completeAfterTurnEnded = async () => {
|
|
410
|
+
const drainTimeoutMs = options?.turnEndDrainTimeoutMs ?? CURSOR_TURN_END_DRAIN_TIMEOUT_MS;
|
|
411
|
+
let timeout;
|
|
412
|
+
const drained = await Promise.race([
|
|
413
|
+
drainInFlightDispatches().then(() => true),
|
|
414
|
+
new Promise((resolve) => {
|
|
415
|
+
timeout = setTimeout(() => resolve(false), drainTimeoutMs);
|
|
416
|
+
}),
|
|
417
|
+
]);
|
|
418
|
+
if (timeout)
|
|
419
|
+
clearTimeout(timeout);
|
|
420
|
+
if (h2Settled)
|
|
421
|
+
return;
|
|
422
|
+
if (!drained) {
|
|
423
|
+
turnEndDrainTimedOut = true;
|
|
424
|
+
settleH2(new Error(`Cursor exec dispatches did not settle within ${drainTimeoutMs}ms after turnEnded`));
|
|
425
|
+
h2Request?.close();
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
h2Request?.close();
|
|
429
|
+
settleH2();
|
|
430
|
+
};
|
|
431
|
+
armStreamHealthTimer();
|
|
342
432
|
h2Request.on("data", (chunk) => {
|
|
343
433
|
// Steady state drains fully per chunk; alias the fresh h2 chunk
|
|
344
434
|
// instead of copying it through Buffer.concat.
|
|
@@ -360,8 +450,12 @@ export const stream = (model, context, options) => {
|
|
|
360
450
|
}
|
|
361
451
|
try {
|
|
362
452
|
const serverMessage = fromBinary(AgentServerMessageSchema, messageBytes);
|
|
363
|
-
const
|
|
364
|
-
serverMessage.message.value.message?.case
|
|
453
|
+
const interactionUpdateCase = serverMessage.message.case === "interactionUpdate"
|
|
454
|
+
? serverMessage.message.value.message?.case
|
|
455
|
+
: undefined;
|
|
456
|
+
const isTurnEnded = interactionUpdateCase === "turnEnded";
|
|
457
|
+
lastInboundFrameAt = Date.now();
|
|
458
|
+
armStreamHealthTimer();
|
|
365
459
|
// Dispatch is fire-and-forget so the socket keeps draining
|
|
366
460
|
// while a handler runs, but the promise is tracked: `done`
|
|
367
461
|
// must not be pushed while an exec handler is still resolving,
|
|
@@ -372,10 +466,13 @@ export const stream = (model, context, options) => {
|
|
|
372
466
|
});
|
|
373
467
|
inFlightDispatches.add(dispatch);
|
|
374
468
|
void dispatch.finally(() => inFlightDispatches.delete(dispatch));
|
|
375
|
-
//
|
|
376
|
-
//
|
|
377
|
-
|
|
469
|
+
// turnEnded is the definitive application completion signal. Drain
|
|
470
|
+
// every dispatch it follows, then close our side of the stream so a
|
|
471
|
+
// server that keeps HTTP/2 open cannot hold the turn hostage.
|
|
472
|
+
if (isTurnEnded && !turnEndCompletionStarted) {
|
|
378
473
|
sawTurnEnded = true;
|
|
474
|
+
turnEndCompletionStarted = true;
|
|
475
|
+
void completeAfterTurnEnded().catch((error) => settleH2(error));
|
|
379
476
|
}
|
|
380
477
|
}
|
|
381
478
|
catch (e) {
|
|
@@ -401,10 +498,17 @@ export const stream = (model, context, options) => {
|
|
|
401
498
|
}
|
|
402
499
|
});
|
|
403
500
|
h2Request.on("end", () => {
|
|
501
|
+
if (!sawTurnEnded && !endStreamError) {
|
|
502
|
+
settleH2(new CursorRetryableStreamError("Cursor stream ended before turnEnded", "clean-end"));
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
404
505
|
settleH2();
|
|
405
506
|
});
|
|
406
507
|
h2Request.on("error", (error) => {
|
|
407
|
-
|
|
508
|
+
const mapped = mapH2TransportError(error, baseUrl);
|
|
509
|
+
settleH2(sawTurnEnded
|
|
510
|
+
? mapped
|
|
511
|
+
: new CursorRetryableStreamError(mapped instanceof Error ? mapped.message : String(mapped), "transport", { cause: mapped }));
|
|
408
512
|
});
|
|
409
513
|
if (options?.signal) {
|
|
410
514
|
options.signal.addEventListener("abort", () => {
|
|
@@ -435,8 +539,43 @@ export const stream = (model, context, options) => {
|
|
|
435
539
|
// Same reason as the success path: a handler still running would land
|
|
436
540
|
// its real result after the turn finalized and be discarded — even
|
|
437
541
|
// though the tool may already have run side effects. On abort the
|
|
438
|
-
// drain returns immediately.
|
|
439
|
-
|
|
542
|
+
// drain returns immediately. A post-turn drain timeout is already the
|
|
543
|
+
// bound: do not wait forever a second time in the error path.
|
|
544
|
+
if (!turnEndDrainTimedOut)
|
|
545
|
+
await drainInFlightDispatches();
|
|
546
|
+
const shouldRetryStream = shouldRetryCursorStream({
|
|
547
|
+
error,
|
|
548
|
+
retries: streamRetries,
|
|
549
|
+
maxRetries: options?.streamStallMaxRetries ?? 10,
|
|
550
|
+
sawTurnEnded,
|
|
551
|
+
aborted: options?.signal?.aborted === true,
|
|
552
|
+
});
|
|
553
|
+
if (shouldRetryStream) {
|
|
554
|
+
if (openBlockState) {
|
|
555
|
+
// Resume responses continue from the server checkpoint. Close any
|
|
556
|
+
// locally open cards before resetting per-attempt bookkeeping; no
|
|
557
|
+
// speculative replay deduplication is attempted.
|
|
558
|
+
endCurrentTextBlock(output, stream, openBlockState);
|
|
559
|
+
endCurrentThinkingBlock(output, stream, openBlockState);
|
|
560
|
+
flushOpenToolCalls(output, stream, openBlockState);
|
|
561
|
+
}
|
|
562
|
+
forceResumeAction ||= attemptSawCheckpoint;
|
|
563
|
+
const retryDelayMs = cursorStreamRetryDelayMs({
|
|
564
|
+
attempt: streamRetries,
|
|
565
|
+
fixedDelayMs: options?.streamStallRetryDelayMs,
|
|
566
|
+
});
|
|
567
|
+
streamRetries += 1;
|
|
568
|
+
retryAttempt = true;
|
|
569
|
+
await waitForCursorStreamRetry(retryDelayMs, options?.signal);
|
|
570
|
+
if (options?.signal?.aborted) {
|
|
571
|
+
retryAttempt = false;
|
|
572
|
+
output.stopReason = "aborted";
|
|
573
|
+
output.errorMessage = "Request was aborted";
|
|
574
|
+
stream.push({ type: "error", reason: output.stopReason, error: output });
|
|
575
|
+
stream.end();
|
|
576
|
+
}
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
440
579
|
// A stream that dies mid-turn leaves blocks open. Closing them here
|
|
441
580
|
// settles their live cards and pairs the server-owned calls that
|
|
442
581
|
// nothing else answers — an unpaired call is stripped from every
|
|
@@ -485,14 +624,14 @@ export const stream = (model, context, options) => {
|
|
|
485
624
|
const blobs = conversationBlobStores.get(conversationId);
|
|
486
625
|
if (blobs)
|
|
487
626
|
conversationBlobStores.set(decision.wireId, blobs);
|
|
488
|
-
|
|
627
|
+
retryAttempt = true;
|
|
489
628
|
}
|
|
490
629
|
else {
|
|
491
630
|
message = CURSOR_CONVERSATION_POISONED_MESSAGE;
|
|
492
631
|
}
|
|
493
632
|
}
|
|
494
633
|
}
|
|
495
|
-
if (!
|
|
634
|
+
if (!retryAttempt) {
|
|
496
635
|
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
|
497
636
|
output.errorMessage = message;
|
|
498
637
|
stream.push({ type: "error", reason: output.stopReason, error: output });
|
|
@@ -509,7 +648,7 @@ export const stream = (model, context, options) => {
|
|
|
509
648
|
h2Request = null;
|
|
510
649
|
h2Client = null;
|
|
511
650
|
}
|
|
512
|
-
} while (
|
|
651
|
+
} while (retryAttempt);
|
|
513
652
|
})();
|
|
514
653
|
return stream;
|
|
515
654
|
};
|
|
@@ -3195,7 +3334,7 @@ async function buildGrpcRequest(model, context, options, state) {
|
|
|
3195
3334
|
}
|
|
3196
3335
|
}
|
|
3197
3336
|
const action = create(ConversationActionSchema, {
|
|
3198
|
-
action: userContent && (userText.trim().length > 0 || hasUserImages)
|
|
3337
|
+
action: !state.forceResumeAction && userContent && (userText.trim().length > 0 || hasUserImages)
|
|
3199
3338
|
? {
|
|
3200
3339
|
case: "userMessageAction",
|
|
3201
3340
|
value: create(UserMessageActionSchema, {
|
|
@@ -3244,15 +3383,16 @@ async function buildGrpcRequest(model, context, options, state) {
|
|
|
3244
3383
|
rootPromptMessagesJson,
|
|
3245
3384
|
turns,
|
|
3246
3385
|
});
|
|
3247
|
-
const requestedModel = buildRequestedModel(model, options?.thinkingSelection);
|
|
3386
|
+
const requestedModel = state.pinnedRequestedModel ?? buildRequestedModel(model, options?.thinkingSelection);
|
|
3248
3387
|
const wireModelId = requestedModel.modelId;
|
|
3249
3388
|
const cursorMaxMode = model.compat?.cursorMaxMode === true;
|
|
3250
|
-
const modelDetails =
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3389
|
+
const modelDetails = state.pinnedModelDetails ??
|
|
3390
|
+
create(ModelDetailsSchema, {
|
|
3391
|
+
modelId: wireModelId,
|
|
3392
|
+
displayModelId: model.id,
|
|
3393
|
+
displayName: model.name,
|
|
3394
|
+
...(cursorMaxMode ? { maxMode: true } : undefined),
|
|
3395
|
+
});
|
|
3256
3396
|
const runRequest = create(AgentRunRequestSchema, {
|
|
3257
3397
|
conversationState,
|
|
3258
3398
|
action,
|
|
@@ -3272,7 +3412,7 @@ async function buildGrpcRequest(model, context, options, state) {
|
|
|
3272
3412
|
bytes: requestBytes.length,
|
|
3273
3413
|
tools: context.tools?.length ?? 0,
|
|
3274
3414
|
});
|
|
3275
|
-
return { requestBytes, blobStore, conversationState };
|
|
3415
|
+
return { requestBytes, blobStore, conversationState, requestedModel, modelDetails };
|
|
3276
3416
|
}
|
|
3277
3417
|
function hasImages(content) {
|
|
3278
3418
|
return content.some((item) => item.type === "image");
|