@code-yeongyu/senpi-ai 2026.8.21-3 → 2026.8.22
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 +5 -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 +1 -1
- package/dist/api/cursor-agent.d.ts.map +1 -1
- package/dist/api/cursor-agent.js +95 -30
- 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/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"]}
|
|
@@ -120,7 +120,12 @@ export interface CursorAgentOptions extends StreamOptions {
|
|
|
120
120
|
thinkingSelection?: ThinkingSelection;
|
|
121
121
|
/** Override stream health bounds for deterministic provider integration tests. */
|
|
122
122
|
streamHealthFailThresholdMs?: number;
|
|
123
|
+
/** @deprecated Accepted for compatibility; heartbeat/checkpoint frames are always liveness. */
|
|
123
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;
|
|
124
129
|
/** Override the post-turn exec drain bound for deterministic tests. */
|
|
125
130
|
turnEndDrainTimeoutMs?: number;
|
|
126
131
|
}
|
|
@@ -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\t/** Override stream health bounds for deterministic provider integration tests. */\n\tstreamHealthFailThresholdMs?: number;\n\tstreamHealthHeartbeatOnlyThresholdMs?: number;\n\t/** Override the post-turn exec drain bound for deterministic tests. */\n\tturnEndDrainTimeoutMs?: number;\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"]}
|
|
@@ -26,7 +26,7 @@ export declare const CURSOR_API_URL = "https://api2.cursor.sh";
|
|
|
26
26
|
export declare const CURSOR_CLIENT_VERSION = "cli-2026.07.23-e383d2b";
|
|
27
27
|
/** Maximum inbound silence before a Cursor turn without turnEnded is failed. */
|
|
28
28
|
export declare const CURSOR_STREAM_HEALTH_FAIL_THRESHOLD_MS = 30000;
|
|
29
|
-
/**
|
|
29
|
+
/** @deprecated Heartbeats and checkpoints count as inbound liveness without a separate deadline. */
|
|
30
30
|
export declare const CURSOR_STREAM_HEALTH_HEARTBEAT_ONLY_THRESHOLD_MS: number;
|
|
31
31
|
/** Maximum time allowed to drain exec handlers after turnEnded. */
|
|
32
32
|
export declare const CURSOR_TURN_END_DRAIN_TIMEOUT_MS = 5000;
|
|
@@ -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,6 +31,7 @@ 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";
|
|
@@ -38,7 +39,7 @@ export const CURSOR_CLIENT_VERSION = "cli-2026.07.23-e383d2b";
|
|
|
38
39
|
const EXEC_HEARTBEAT_INTERVAL_MS = 3000;
|
|
39
40
|
/** Maximum inbound silence before a Cursor turn without turnEnded is failed. */
|
|
40
41
|
export const CURSOR_STREAM_HEALTH_FAIL_THRESHOLD_MS = 30_000;
|
|
41
|
-
/**
|
|
42
|
+
/** @deprecated Heartbeats and checkpoints count as inbound liveness without a separate deadline. */
|
|
42
43
|
export const CURSOR_STREAM_HEALTH_HEARTBEAT_ONLY_THRESHOLD_MS = CURSOR_STREAM_HEALTH_FAIL_THRESHOLD_MS * 3;
|
|
43
44
|
/** Maximum time allowed to drain exec handlers after turnEnded. */
|
|
44
45
|
export const CURSOR_TURN_END_DRAIN_TIMEOUT_MS = 5000;
|
|
@@ -264,10 +265,14 @@ export const stream = (model, context, options) => {
|
|
|
264
265
|
let baseConversationId;
|
|
265
266
|
let conversationId;
|
|
266
267
|
let usageState;
|
|
267
|
-
let
|
|
268
|
+
let retryAttempt = false;
|
|
268
269
|
let attempt = 0;
|
|
270
|
+
let streamRetries = 0;
|
|
271
|
+
let forceResumeAction = false;
|
|
272
|
+
let pinnedRequestedModel;
|
|
273
|
+
let pinnedModelDetails;
|
|
269
274
|
do {
|
|
270
|
-
|
|
275
|
+
retryAttempt = false;
|
|
271
276
|
attempt += 1;
|
|
272
277
|
h2Settled = false;
|
|
273
278
|
sawTurnEnded = false;
|
|
@@ -278,6 +283,7 @@ export const stream = (model, context, options) => {
|
|
|
278
283
|
resolveH2 = resolve;
|
|
279
284
|
rejectH2 = reject;
|
|
280
285
|
});
|
|
286
|
+
let attemptSawCheckpoint = false;
|
|
281
287
|
try {
|
|
282
288
|
const apiKey = options?.apiKey;
|
|
283
289
|
if (!apiKey) {
|
|
@@ -288,11 +294,16 @@ export const stream = (model, context, options) => {
|
|
|
288
294
|
const blobStore = conversationBlobStores.get(conversationId) ?? new Map();
|
|
289
295
|
conversationBlobStores.set(conversationId, blobStore);
|
|
290
296
|
const cachedState = conversationStateCache.get(conversationId);
|
|
291
|
-
const { requestBytes, conversationState } = await buildGrpcRequest(model, context, options, {
|
|
297
|
+
const { requestBytes, conversationState, requestedModel, modelDetails } = await buildGrpcRequest(model, context, options, {
|
|
292
298
|
conversationId,
|
|
293
299
|
blobStore,
|
|
294
300
|
conversationState: cachedState,
|
|
301
|
+
forceResumeAction,
|
|
302
|
+
pinnedRequestedModel,
|
|
303
|
+
pinnedModelDetails,
|
|
295
304
|
});
|
|
305
|
+
pinnedRequestedModel ??= requestedModel;
|
|
306
|
+
pinnedModelDetails ??= modelDetails;
|
|
296
307
|
conversationStateCache.set(conversationId, conversationState);
|
|
297
308
|
const requestContextTools = buildMcpToolDefinitions(context.tools);
|
|
298
309
|
const baseUrl = model.baseUrl || CURSOR_API_URL;
|
|
@@ -313,9 +324,28 @@ export const stream = (model, context, options) => {
|
|
|
313
324
|
"x-cursor-client-type": "cli",
|
|
314
325
|
"x-request-id": randomUUID(),
|
|
315
326
|
};
|
|
316
|
-
|
|
317
|
-
h2Client
|
|
318
|
-
|
|
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);
|
|
319
349
|
if (attempt === 1) {
|
|
320
350
|
stream.push({ type: "start", partial: output });
|
|
321
351
|
}
|
|
@@ -350,12 +380,11 @@ export const stream = (model, context, options) => {
|
|
|
350
380
|
};
|
|
351
381
|
openBlockState = state;
|
|
352
382
|
const onConversationCheckpoint = (checkpoint) => {
|
|
383
|
+
attemptSawCheckpoint = true;
|
|
353
384
|
conversationStateCache.set(conversationId, checkpoint);
|
|
354
385
|
};
|
|
355
386
|
const healthFailThresholdMs = options?.streamHealthFailThresholdMs ?? CURSOR_STREAM_HEALTH_FAIL_THRESHOLD_MS;
|
|
356
|
-
const heartbeatOnlyThresholdMs = options?.streamHealthHeartbeatOnlyThresholdMs ?? CURSOR_STREAM_HEALTH_HEARTBEAT_ONLY_THRESHOLD_MS;
|
|
357
387
|
let lastInboundFrameAt = Date.now();
|
|
358
|
-
let lastMeaningfulFrameAt = lastInboundFrameAt;
|
|
359
388
|
let turnEndCompletionStarted = false;
|
|
360
389
|
const armStreamHealthTimer = () => {
|
|
361
390
|
if (streamHealthTimer)
|
|
@@ -363,18 +392,17 @@ export const stream = (model, context, options) => {
|
|
|
363
392
|
if (sawTurnEnded || h2Settled)
|
|
364
393
|
return;
|
|
365
394
|
const now = Date.now();
|
|
366
|
-
const deadline =
|
|
395
|
+
const deadline = lastInboundFrameAt + healthFailThresholdMs;
|
|
367
396
|
streamHealthTimer = setTimeout(() => {
|
|
368
397
|
streamHealthTimer = null;
|
|
369
398
|
if (sawTurnEnded || h2Settled)
|
|
370
399
|
return;
|
|
371
400
|
const stalledFor = Date.now() - lastInboundFrameAt;
|
|
372
|
-
|
|
373
|
-
if (stalledFor < healthFailThresholdMs && meaningfulStalledFor < heartbeatOnlyThresholdMs) {
|
|
401
|
+
if (stalledFor < healthFailThresholdMs) {
|
|
374
402
|
armStreamHealthTimer();
|
|
375
403
|
return;
|
|
376
404
|
}
|
|
377
|
-
settleH2(new
|
|
405
|
+
settleH2(new CursorRetryableStreamError("Cursor stream ended before turnEnded: inbound stream stalled", "stall"));
|
|
378
406
|
h2Request?.close();
|
|
379
407
|
}, Math.max(0, deadline - now));
|
|
380
408
|
};
|
|
@@ -426,11 +454,7 @@ export const stream = (model, context, options) => {
|
|
|
426
454
|
? serverMessage.message.value.message?.case
|
|
427
455
|
: undefined;
|
|
428
456
|
const isTurnEnded = interactionUpdateCase === "turnEnded";
|
|
429
|
-
const isLivenessOnly = interactionUpdateCase === "heartbeat" ||
|
|
430
|
-
serverMessage.message.case === "conversationCheckpointUpdate";
|
|
431
457
|
lastInboundFrameAt = Date.now();
|
|
432
|
-
if (!isLivenessOnly)
|
|
433
|
-
lastMeaningfulFrameAt = lastInboundFrameAt;
|
|
434
458
|
armStreamHealthTimer();
|
|
435
459
|
// Dispatch is fire-and-forget so the socket keeps draining
|
|
436
460
|
// while a handler runs, but the promise is tracked: `done`
|
|
@@ -474,10 +498,17 @@ export const stream = (model, context, options) => {
|
|
|
474
498
|
}
|
|
475
499
|
});
|
|
476
500
|
h2Request.on("end", () => {
|
|
501
|
+
if (!sawTurnEnded && !endStreamError) {
|
|
502
|
+
settleH2(new CursorRetryableStreamError("Cursor stream ended before turnEnded", "clean-end"));
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
477
505
|
settleH2();
|
|
478
506
|
});
|
|
479
507
|
h2Request.on("error", (error) => {
|
|
480
|
-
|
|
508
|
+
const mapped = mapH2TransportError(error, baseUrl);
|
|
509
|
+
settleH2(sawTurnEnded
|
|
510
|
+
? mapped
|
|
511
|
+
: new CursorRetryableStreamError(mapped instanceof Error ? mapped.message : String(mapped), "transport", { cause: mapped }));
|
|
481
512
|
});
|
|
482
513
|
if (options?.signal) {
|
|
483
514
|
options.signal.addEventListener("abort", () => {
|
|
@@ -512,6 +543,39 @@ export const stream = (model, context, options) => {
|
|
|
512
543
|
// bound: do not wait forever a second time in the error path.
|
|
513
544
|
if (!turnEndDrainTimedOut)
|
|
514
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
|
+
}
|
|
515
579
|
// A stream that dies mid-turn leaves blocks open. Closing them here
|
|
516
580
|
// settles their live cards and pairs the server-owned calls that
|
|
517
581
|
// nothing else answers — an unpaired call is stripped from every
|
|
@@ -560,14 +624,14 @@ export const stream = (model, context, options) => {
|
|
|
560
624
|
const blobs = conversationBlobStores.get(conversationId);
|
|
561
625
|
if (blobs)
|
|
562
626
|
conversationBlobStores.set(decision.wireId, blobs);
|
|
563
|
-
|
|
627
|
+
retryAttempt = true;
|
|
564
628
|
}
|
|
565
629
|
else {
|
|
566
630
|
message = CURSOR_CONVERSATION_POISONED_MESSAGE;
|
|
567
631
|
}
|
|
568
632
|
}
|
|
569
633
|
}
|
|
570
|
-
if (!
|
|
634
|
+
if (!retryAttempt) {
|
|
571
635
|
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
|
572
636
|
output.errorMessage = message;
|
|
573
637
|
stream.push({ type: "error", reason: output.stopReason, error: output });
|
|
@@ -584,7 +648,7 @@ export const stream = (model, context, options) => {
|
|
|
584
648
|
h2Request = null;
|
|
585
649
|
h2Client = null;
|
|
586
650
|
}
|
|
587
|
-
} while (
|
|
651
|
+
} while (retryAttempt);
|
|
588
652
|
})();
|
|
589
653
|
return stream;
|
|
590
654
|
};
|
|
@@ -3270,7 +3334,7 @@ async function buildGrpcRequest(model, context, options, state) {
|
|
|
3270
3334
|
}
|
|
3271
3335
|
}
|
|
3272
3336
|
const action = create(ConversationActionSchema, {
|
|
3273
|
-
action: userContent && (userText.trim().length > 0 || hasUserImages)
|
|
3337
|
+
action: !state.forceResumeAction && userContent && (userText.trim().length > 0 || hasUserImages)
|
|
3274
3338
|
? {
|
|
3275
3339
|
case: "userMessageAction",
|
|
3276
3340
|
value: create(UserMessageActionSchema, {
|
|
@@ -3319,15 +3383,16 @@ async function buildGrpcRequest(model, context, options, state) {
|
|
|
3319
3383
|
rootPromptMessagesJson,
|
|
3320
3384
|
turns,
|
|
3321
3385
|
});
|
|
3322
|
-
const requestedModel = buildRequestedModel(model, options?.thinkingSelection);
|
|
3386
|
+
const requestedModel = state.pinnedRequestedModel ?? buildRequestedModel(model, options?.thinkingSelection);
|
|
3323
3387
|
const wireModelId = requestedModel.modelId;
|
|
3324
3388
|
const cursorMaxMode = model.compat?.cursorMaxMode === true;
|
|
3325
|
-
const modelDetails =
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
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
|
+
});
|
|
3331
3396
|
const runRequest = create(AgentRunRequestSchema, {
|
|
3332
3397
|
conversationState,
|
|
3333
3398
|
action,
|
|
@@ -3347,7 +3412,7 @@ async function buildGrpcRequest(model, context, options, state) {
|
|
|
3347
3412
|
bytes: requestBytes.length,
|
|
3348
3413
|
tools: context.tools?.length ?? 0,
|
|
3349
3414
|
});
|
|
3350
|
-
return { requestBytes, blobStore, conversationState };
|
|
3415
|
+
return { requestBytes, blobStore, conversationState, requestedModel, modelDetails };
|
|
3351
3416
|
}
|
|
3352
3417
|
function hasImages(content) {
|
|
3353
3418
|
return content.some((item) => item.type === "image");
|