@code-yeongyu/senpi-ai 2026.8.19 → 2026.8.20

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.
Files changed (31) hide show
  1. package/dist/api/cursor-agent.d.ts +2 -0
  2. package/dist/api/cursor-agent.d.ts.map +1 -1
  3. package/dist/api/cursor-agent.js +284 -209
  4. package/dist/api/cursor-agent.js.map +1 -1
  5. package/dist/api/cursor-conversation-rotation.d.ts +37 -0
  6. package/dist/api/cursor-conversation-rotation.d.ts.map +1 -0
  7. package/dist/api/cursor-conversation-rotation.js +110 -0
  8. package/dist/api/cursor-conversation-rotation.js.map +1 -0
  9. package/dist/api/cursor-task-args.d.ts +3 -0
  10. package/dist/api/cursor-task-args.d.ts.map +1 -0
  11. package/dist/api/cursor-task-args.js +17 -0
  12. package/dist/api/cursor-task-args.js.map +1 -0
  13. package/dist/cursor/selection-descriptor.d.ts.map +1 -1
  14. package/dist/cursor/selection-descriptor.js +27 -11
  15. package/dist/cursor/selection-descriptor.js.map +1 -1
  16. package/dist/providers/data/.manifest.json +1 -1
  17. package/dist/providers/data/amazon-bedrock.json +1 -1
  18. package/dist/providers/data/baseten.json +1 -1
  19. package/dist/providers/data/huggingface.json +1 -1
  20. package/dist/providers/data/opencode-go.json +1 -1
  21. package/dist/providers/data/opencode.json +1 -1
  22. package/dist/providers/data/openrouter.json +1 -1
  23. package/dist/providers/data/vercel-ai-gateway.json +1 -1
  24. package/dist/tool-call-middleware/index.d.ts.map +1 -1
  25. package/dist/tool-call-middleware/index.js +2 -0
  26. package/dist/tool-call-middleware/index.js.map +1 -1
  27. package/dist/utils/overflow.d.ts +30 -0
  28. package/dist/utils/overflow.d.ts.map +1 -1
  29. package/dist/utils/overflow.js +33 -0
  30. package/dist/utils/overflow.js.map +1 -1
  31. package/package.json +2 -2
@@ -81,6 +81,8 @@ export interface BlockState {
81
81
  export interface UsageState {
82
82
  sawTokenDelta: boolean;
83
83
  sawTurnEndedUsage: boolean;
84
+ /** Last checkpoint `usedTokens`; conversation window, not billed cache. */
85
+ liveUsedTokens?: number;
84
86
  }
85
87
  /** Exported for tests: drives one Cursor server message through the stream (exec waits mark the stream busy). */
86
88
  export declare function handleServerMessage(msg: AgentServerMessage, output: AssistantMessage, stream: AssistantMessageEventStream, state: BlockState, blobStore: Map<string, Uint8Array>, h2Request: http2.ClientHttp2Stream, execHandlers: CursorExecHandlers | undefined, onToolResult: CursorToolResultHandler | undefined, usageState: UsageState, requestContextTools: McpToolDefinition[], onConversationCheckpoint?: (checkpoint: ConversationStateStructure) => void): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"cursor-agent.d.ts","sourceRoot":"","sources":["../../src/api/cursor-agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cursor-agent.d.ts","sourceRoot":"","sources":["../../src/api/cursor-agent.ts"],"names":[],"mappings":"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"}
@@ -31,6 +31,8 @@ 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 { CURSOR_CONVERSATION_POISONED_MESSAGE, createConversationRotationStore, isZeroTokenResourceExhausted, resolveConversationRotationPersistPath, } from "./cursor-conversation-rotation.js";
35
+ import { keepUsableCursorTaskArgs } from "./cursor-task-args.js";
34
36
  export const CURSOR_API_URL = "https://api2.cursor.sh";
35
37
  export const CURSOR_CLIENT_VERSION = "cli-2026.07.23-e383d2b";
36
38
  const EXEC_HEARTBEAT_INTERVAL_MS = 3000;
@@ -91,7 +93,6 @@ export function sanitizeCursorCallerHeaders(headers) {
91
93
  const NOT_IMPLEMENTED_SUFFIX = "not implemented by this client";
92
94
  const NOT_IMPLEMENTED = "Not implemented by this client";
93
95
  /** Bare gRPC `resource_exhausted` end-streams (also inside a Connect error message). */
94
- const RESOURCE_EXHAUSTED_PATTERN = /resource.?exhausted/i;
95
96
  const conversationStateCache = new Map();
96
97
  const conversationBlobStores = new Map();
97
98
  /**
@@ -101,7 +102,18 @@ const conversationBlobStores = new Map();
101
102
  * and the cached state migrates, so the retry loop's next attempt starts a
102
103
  * fresh conversation. Keyed by the base id so a failed rotation never repeats.
103
104
  */
104
- const rotatedConversationIds = new Map();
105
+ let conversationRotationStore = createConversationRotationStore({
106
+ persistPath: resolveConversationRotationPersistPath(),
107
+ });
108
+ let conversationRotationPersistPath = resolveConversationRotationPersistPath();
109
+ function rotationStore() {
110
+ const persistPath = resolveConversationRotationPersistPath();
111
+ if (persistPath !== conversationRotationPersistPath) {
112
+ conversationRotationPersistPath = persistPath;
113
+ conversationRotationStore = createConversationRotationStore({ persistPath });
114
+ }
115
+ return conversationRotationStore;
116
+ }
105
117
  const CONNECT_END_STREAM_FLAG = 0b00000010;
106
118
  function log(type, subtype, data) {
107
119
  if (!process.env.DEBUG_CURSOR)
@@ -217,10 +229,6 @@ export const stream = (model, context, options) => {
217
229
  let openBlockState;
218
230
  let resolveH2 = () => { };
219
231
  let rejectH2 = () => { };
220
- const h2Completion = new Promise((resolve, reject) => {
221
- resolveH2 = resolve;
222
- rejectH2 = reject;
223
- });
224
232
  const settleH2 = (error) => {
225
233
  if (h2Settled)
226
234
  return;
@@ -244,218 +252,264 @@ export const stream = (model, context, options) => {
244
252
  let baseConversationId;
245
253
  let conversationId;
246
254
  let usageState;
247
- try {
248
- const apiKey = options?.apiKey;
249
- if (!apiKey) {
250
- throw new Error("Cursor access token is required; run /login cursor");
251
- }
252
- baseConversationId = options?.conversationId ?? options?.sessionId ?? randomUUID();
253
- conversationId = rotatedConversationIds.get(baseConversationId) ?? baseConversationId;
254
- const blobStore = conversationBlobStores.get(conversationId) ?? new Map();
255
- conversationBlobStores.set(conversationId, blobStore);
256
- const cachedState = conversationStateCache.get(conversationId);
257
- const { requestBytes, conversationState } = await buildGrpcRequest(model, context, options, {
258
- conversationId,
259
- blobStore,
260
- conversationState: cachedState,
255
+ let retryPoisonedConversation = false;
256
+ let attempt = 0;
257
+ do {
258
+ retryPoisonedConversation = false;
259
+ attempt += 1;
260
+ h2Settled = false;
261
+ sawTurnEnded = false;
262
+ endStreamError = null;
263
+ openBlockState = undefined;
264
+ const h2Completion = new Promise((resolve, reject) => {
265
+ resolveH2 = resolve;
266
+ rejectH2 = reject;
261
267
  });
262
- conversationStateCache.set(conversationId, conversationState);
263
- const requestContextTools = buildMcpToolDefinitions(context.tools);
264
- const baseUrl = model.baseUrl || CURSOR_API_URL;
265
- const requestPath = "/agent.v1.AgentService/Run";
266
- // Caller headers are additive, and are spread FIRST so the protocol
267
- // framing, auth, and request id below always win.
268
- const callerHeaders = sanitizeCursorCallerHeaders(providerHeadersToRecord(options?.headers));
269
- const requestHeaders = {
270
- ...callerHeaders,
271
- ":method": "POST",
272
- ":path": requestPath,
273
- "content-type": "application/connect+proto",
274
- "connect-protocol-version": "1",
275
- te: "trailers",
276
- authorization: `Bearer ${apiKey}`,
277
- "x-ghost-mode": "true",
278
- "x-cursor-client-version": CURSOR_CLIENT_VERSION,
279
- "x-cursor-client-type": "cli",
280
- "x-request-id": randomUUID(),
281
- };
282
- h2Client = http2.connect(baseUrl);
283
- h2Client.on("error", (error) => settleH2(mapH2TransportError(error, baseUrl)));
284
- h2Request = h2Client.request(requestHeaders);
285
- stream.push({ type: "start", partial: output });
286
- let pendingBuffer = Buffer.alloc(0);
287
- let currentTextBlock = null;
288
- let currentThinkingBlock = null;
289
- let currentToolCall = null;
290
- const resolvedMcpToolCallIds = new Set();
291
- usageState = { sawTokenDelta: false, sawTurnEndedUsage: false };
292
- const state = {
293
- get currentTextBlock() {
294
- return currentTextBlock;
295
- },
296
- get currentThinkingBlock() {
297
- return currentThinkingBlock;
298
- },
299
- get currentToolCall() {
300
- return currentToolCall;
301
- },
302
- openToolCalls: new Map(),
303
- resolvedMcpToolCallIds,
304
- setTextBlock: (b) => {
305
- currentTextBlock = b;
306
- },
307
- setThinkingBlock: (b) => {
308
- currentThinkingBlock = b;
309
- },
310
- setToolCall: (t) => {
311
- currentToolCall = t;
312
- },
313
- onToolResult: options?.onToolResult ?? options?.execHandlers?.onToolResult,
314
- };
315
- openBlockState = state;
316
- const onConversationCheckpoint = (checkpoint) => {
317
- conversationStateCache.set(conversationId, checkpoint);
318
- };
319
- h2Request.on("data", (chunk) => {
320
- // Steady state drains fully per chunk; alias the fresh h2 chunk
321
- // instead of copying it through Buffer.concat.
322
- pendingBuffer = pendingBuffer.length === 0 ? chunk : Buffer.concat([pendingBuffer, chunk]);
323
- while (pendingBuffer.length >= 5) {
324
- const flags = pendingBuffer[0];
325
- const msgLen = pendingBuffer.readUInt32BE(1);
326
- if (pendingBuffer.length < 5 + msgLen)
327
- break;
328
- const messageBytes = pendingBuffer.subarray(5, 5 + msgLen);
329
- pendingBuffer = pendingBuffer.subarray(5 + msgLen);
330
- if (flags & CONNECT_END_STREAM_FLAG) {
331
- const endError = parseConnectEndStream(messageBytes);
332
- if (endError) {
333
- endStreamError = endError;
334
- h2Request?.close();
268
+ try {
269
+ const apiKey = options?.apiKey;
270
+ if (!apiKey) {
271
+ throw new Error("Cursor access token is required; run /login cursor");
272
+ }
273
+ baseConversationId = options?.conversationId ?? options?.sessionId ?? randomUUID();
274
+ conversationId = rotationStore().getWireId(baseConversationId);
275
+ const blobStore = conversationBlobStores.get(conversationId) ?? new Map();
276
+ conversationBlobStores.set(conversationId, blobStore);
277
+ const cachedState = conversationStateCache.get(conversationId);
278
+ const { requestBytes, conversationState } = await buildGrpcRequest(model, context, options, {
279
+ conversationId,
280
+ blobStore,
281
+ conversationState: cachedState,
282
+ });
283
+ conversationStateCache.set(conversationId, conversationState);
284
+ const requestContextTools = buildMcpToolDefinitions(context.tools);
285
+ const baseUrl = model.baseUrl || CURSOR_API_URL;
286
+ const requestPath = "/agent.v1.AgentService/Run";
287
+ // Caller headers are additive, and are spread FIRST so the protocol
288
+ // framing, auth, and request id below always win.
289
+ const callerHeaders = sanitizeCursorCallerHeaders(providerHeadersToRecord(options?.headers));
290
+ const requestHeaders = {
291
+ ...callerHeaders,
292
+ ":method": "POST",
293
+ ":path": requestPath,
294
+ "content-type": "application/connect+proto",
295
+ "connect-protocol-version": "1",
296
+ te: "trailers",
297
+ authorization: `Bearer ${apiKey}`,
298
+ "x-ghost-mode": "true",
299
+ "x-cursor-client-version": CURSOR_CLIENT_VERSION,
300
+ "x-cursor-client-type": "cli",
301
+ "x-request-id": randomUUID(),
302
+ };
303
+ h2Client = http2.connect(baseUrl);
304
+ h2Client.on("error", (error) => settleH2(mapH2TransportError(error, baseUrl)));
305
+ h2Request = h2Client.request(requestHeaders);
306
+ if (attempt === 1) {
307
+ stream.push({ type: "start", partial: output });
308
+ }
309
+ let pendingBuffer = Buffer.alloc(0);
310
+ let currentTextBlock = null;
311
+ let currentThinkingBlock = null;
312
+ let currentToolCall = null;
313
+ const resolvedMcpToolCallIds = new Set();
314
+ usageState = { sawTokenDelta: false, sawTurnEndedUsage: false };
315
+ const state = {
316
+ get currentTextBlock() {
317
+ return currentTextBlock;
318
+ },
319
+ get currentThinkingBlock() {
320
+ return currentThinkingBlock;
321
+ },
322
+ get currentToolCall() {
323
+ return currentToolCall;
324
+ },
325
+ openToolCalls: new Map(),
326
+ resolvedMcpToolCallIds,
327
+ setTextBlock: (b) => {
328
+ currentTextBlock = b;
329
+ },
330
+ setThinkingBlock: (b) => {
331
+ currentThinkingBlock = b;
332
+ },
333
+ setToolCall: (t) => {
334
+ currentToolCall = t;
335
+ },
336
+ onToolResult: options?.onToolResult ?? options?.execHandlers?.onToolResult,
337
+ };
338
+ openBlockState = state;
339
+ const onConversationCheckpoint = (checkpoint) => {
340
+ conversationStateCache.set(conversationId, checkpoint);
341
+ };
342
+ h2Request.on("data", (chunk) => {
343
+ // Steady state drains fully per chunk; alias the fresh h2 chunk
344
+ // instead of copying it through Buffer.concat.
345
+ pendingBuffer = pendingBuffer.length === 0 ? chunk : Buffer.concat([pendingBuffer, chunk]);
346
+ while (pendingBuffer.length >= 5) {
347
+ const flags = pendingBuffer[0];
348
+ const msgLen = pendingBuffer.readUInt32BE(1);
349
+ if (pendingBuffer.length < 5 + msgLen)
350
+ break;
351
+ const messageBytes = pendingBuffer.subarray(5, 5 + msgLen);
352
+ pendingBuffer = pendingBuffer.subarray(5 + msgLen);
353
+ if (flags & CONNECT_END_STREAM_FLAG) {
354
+ const endError = parseConnectEndStream(messageBytes);
355
+ if (endError) {
356
+ endStreamError = endError;
357
+ h2Request?.close();
358
+ }
359
+ continue;
335
360
  }
336
- continue;
337
- }
338
- try {
339
- const serverMessage = fromBinary(AgentServerMessageSchema, messageBytes);
340
- const isTurnEnded = serverMessage.message.case === "interactionUpdate" &&
341
- serverMessage.message.value.message?.case === "turnEnded";
342
- // Dispatch is fire-and-forget so the socket keeps draining
343
- // while a handler runs, but the promise is tracked: `done`
344
- // must not be pushed while an exec handler is still resolving,
345
- // or the buffered tool result is delivered after the turn
346
- // already finalized and the call is left unpaired.
347
- const dispatch = handleServerMessage(serverMessage, output, stream, state, blobStore, h2Request, options?.execHandlers, state.onToolResult, usageState, requestContextTools, onConversationCheckpoint).catch((error) => {
348
- log("error", "handleServerMessage", { error: String(error) });
349
- });
350
- inFlightDispatches.add(dispatch);
351
- void dispatch.finally(() => inFlightDispatches.delete(dispatch));
352
- // Application completion is not protocol success; wait for a
353
- // clean HTTP/2 end.
354
- if (isTurnEnded) {
355
- sawTurnEnded = true;
361
+ try {
362
+ const serverMessage = fromBinary(AgentServerMessageSchema, messageBytes);
363
+ const isTurnEnded = serverMessage.message.case === "interactionUpdate" &&
364
+ serverMessage.message.value.message?.case === "turnEnded";
365
+ // Dispatch is fire-and-forget so the socket keeps draining
366
+ // while a handler runs, but the promise is tracked: `done`
367
+ // must not be pushed while an exec handler is still resolving,
368
+ // or the buffered tool result is delivered after the turn
369
+ // already finalized and the call is left unpaired.
370
+ const dispatch = handleServerMessage(serverMessage, output, stream, state, blobStore, h2Request, options?.execHandlers, state.onToolResult, usageState, requestContextTools, onConversationCheckpoint).catch((error) => {
371
+ log("error", "handleServerMessage", { error: String(error) });
372
+ });
373
+ inFlightDispatches.add(dispatch);
374
+ void dispatch.finally(() => inFlightDispatches.delete(dispatch));
375
+ // Application completion is not protocol success; wait for a
376
+ // clean HTTP/2 end.
377
+ if (isTurnEnded) {
378
+ sawTurnEnded = true;
379
+ }
380
+ }
381
+ catch (e) {
382
+ log("error", "parseServerMessage", { error: String(e) });
356
383
  }
357
384
  }
358
- catch (e) {
359
- log("error", "parseServerMessage", { error: String(e) });
385
+ });
386
+ const sendHeartbeat = () => {
387
+ if (!h2Request || h2Request.closed) {
388
+ return;
389
+ }
390
+ const heartbeatMessage = create(AgentClientMessageSchema, {
391
+ message: { case: "clientHeartbeat", value: create(ClientHeartbeatSchema, {}) },
392
+ });
393
+ const heartbeatBytes = toBinary(AgentClientMessageSchema, heartbeatMessage);
394
+ h2Request.write(frameConnectMessage(heartbeatBytes));
395
+ };
396
+ h2Request.on("trailers", (trailers) => {
397
+ const status = trailers["grpc-status"];
398
+ const msg = trailers["grpc-message"];
399
+ if (status && status !== "0" && !endStreamError) {
400
+ endStreamError = new Error(`gRPC error ${status}: ${decodeURIComponent(String(msg || ""))}`);
360
401
  }
361
- }
362
- });
363
- const sendHeartbeat = () => {
364
- if (!h2Request || h2Request.closed) {
365
- return;
366
- }
367
- const heartbeatMessage = create(AgentClientMessageSchema, {
368
- message: { case: "clientHeartbeat", value: create(ClientHeartbeatSchema, {}) },
369
402
  });
370
- const heartbeatBytes = toBinary(AgentClientMessageSchema, heartbeatMessage);
371
- h2Request.write(frameConnectMessage(heartbeatBytes));
372
- };
373
- h2Request.on("trailers", (trailers) => {
374
- const status = trailers["grpc-status"];
375
- const msg = trailers["grpc-message"];
376
- if (status && status !== "0" && !endStreamError) {
377
- endStreamError = new Error(`gRPC error ${status}: ${decodeURIComponent(String(msg || ""))}`);
403
+ h2Request.on("end", () => {
404
+ settleH2();
405
+ });
406
+ h2Request.on("error", (error) => {
407
+ settleH2(mapH2TransportError(error, baseUrl));
408
+ });
409
+ if (options?.signal) {
410
+ options.signal.addEventListener("abort", () => {
411
+ h2Request?.close();
412
+ settleH2(new Error("Request was aborted"));
413
+ });
378
414
  }
379
- });
380
- h2Request.on("end", () => {
381
- settleH2();
382
- });
383
- h2Request.on("error", (error) => {
384
- settleH2(mapH2TransportError(error, baseUrl));
385
- });
386
- if (options?.signal) {
387
- options.signal.addEventListener("abort", () => {
388
- h2Request?.close();
389
- settleH2(new Error("Request was aborted"));
415
+ h2Request.write(frameConnectMessage(requestBytes));
416
+ heartbeatTimer = setInterval(sendHeartbeat, 5000);
417
+ await h2Completion;
418
+ // The transport is done, but a handler decoded from the last chunk
419
+ // may still be running. Pushing `done` now would let the host drain
420
+ // its buffered tool results before such a handler reserved its entry,
421
+ // leaving the call unpaired and stripped from rebuilt transcripts.
422
+ await drainInFlightDispatches();
423
+ endCurrentTextBlock(output, stream, state);
424
+ endCurrentThinkingBlock(output, stream, state);
425
+ flushOpenToolCalls(output, stream, state);
426
+ calculateCost(model, output.usage);
427
+ stream.push({
428
+ type: "done",
429
+ reason: output.stopReason,
430
+ message: output,
390
431
  });
432
+ stream.end();
391
433
  }
392
- h2Request.write(frameConnectMessage(requestBytes));
393
- heartbeatTimer = setInterval(sendHeartbeat, 5000);
394
- await h2Completion;
395
- // The transport is done, but a handler decoded from the last chunk
396
- // may still be running. Pushing `done` now would let the host drain
397
- // its buffered tool results before such a handler reserved its entry,
398
- // leaving the call unpaired and stripped from rebuilt transcripts.
399
- await drainInFlightDispatches();
400
- endCurrentTextBlock(output, stream, state);
401
- endCurrentThinkingBlock(output, stream, state);
402
- flushOpenToolCalls(output, stream, state);
403
- calculateCost(model, output.usage);
404
- stream.push({
405
- type: "done",
406
- reason: output.stopReason,
407
- message: output,
408
- });
409
- stream.end();
410
- }
411
- catch (error) {
412
- // Same reason as the success path: a handler still running would land
413
- // its real result after the turn finalized and be discarded — even
414
- // though the tool may already have run side effects. On abort the
415
- // drain returns immediately.
416
- await drainInFlightDispatches();
417
- // A stream that dies mid-turn leaves blocks open. Closing them here
418
- // settles their live cards and pairs the server-owned calls that
419
- // nothing else answers an unpaired call is stripped from every
420
- // rebuilt transcript.
421
- if (openBlockState) {
422
- endCurrentTextBlock(output, stream, openBlockState);
423
- endCurrentThinkingBlock(output, stream, openBlockState);
424
- flushOpenToolCalls(output, stream, openBlockState);
425
- }
426
- const message = error instanceof Error ? error.message : JSON.stringify(error);
427
- // A server-side per-conversation rejection surfaces as a bare
428
- // resource_exhausted with zero tokens the conversation is poisoned,
429
- // not the account. Rotate the wire id once and migrate cached state
430
- // so the caller's retry loop starts a fresh conversation.
431
- if (conversationId !== undefined &&
432
- baseConversationId !== undefined &&
433
- usageState !== undefined &&
434
- !usageState.sawTokenDelta &&
435
- RESOURCE_EXHAUSTED_PATTERN.test(message) &&
436
- !rotatedConversationIds.has(baseConversationId)) {
437
- const rotated = randomUUID();
438
- rotatedConversationIds.set(baseConversationId, rotated);
439
- const cached = conversationStateCache.get(conversationId);
440
- if (cached)
441
- conversationStateCache.set(rotated, cached);
442
- const blobs = conversationBlobStores.get(conversationId);
443
- if (blobs)
444
- conversationBlobStores.set(rotated, blobs);
434
+ catch (error) {
435
+ // Same reason as the success path: a handler still running would land
436
+ // its real result after the turn finalized and be discarded — even
437
+ // though the tool may already have run side effects. On abort the
438
+ // drain returns immediately.
439
+ await drainInFlightDispatches();
440
+ // A stream that dies mid-turn leaves blocks open. Closing them here
441
+ // settles their live cards and pairs the server-owned calls that
442
+ // nothing else answers — an unpaired call is stripped from every
443
+ // rebuilt transcript.
444
+ if (openBlockState) {
445
+ endCurrentTextBlock(output, stream, openBlockState);
446
+ endCurrentThinkingBlock(output, stream, openBlockState);
447
+ flushOpenToolCalls(output, stream, openBlockState);
448
+ }
449
+ let message = error instanceof Error ? error.message : JSON.stringify(error);
450
+ // A server-side per-conversation rejection surfaces as a bare
451
+ // resource_exhausted with zero tokens. That has two distinct causes:
452
+ // an oversized payload, and a genuinely poisoned conversationId.
453
+ // Only the second is fixed by rotating the wire id.
454
+ //
455
+ // The FIRST 0-token RE for a base conversation always surfaces without
456
+ // rotating, so the session layer gets first refusal: agent-session
457
+ // classifies a surfaced 0-token RE as overflow and compacts before
458
+ // retrying. Rotating here instead would swallow the error, make that
459
+ // compaction dead code, and burn the 3-rotation budget replaying the
460
+ // same oversized payload. Once that surface has happened (the flag is
461
+ // persisted with the wire id), compaction has had its turn and further
462
+ // 0-token REs rotate and retry in-call, up to the cap.
463
+ if (conversationId !== undefined &&
464
+ baseConversationId !== undefined &&
465
+ usageState !== undefined &&
466
+ isZeroTokenResourceExhausted(message, usageState.sawTokenDelta)) {
467
+ if (rotationStore().shouldSkip(baseConversationId)) {
468
+ // The base conversation burned its rotation cap; another wire id
469
+ // will not help, so surface the poisoned-conversation error and
470
+ // let the session move to a different provider.
471
+ message = CURSOR_CONVERSATION_POISONED_MESSAGE;
472
+ }
473
+ else if (rotationStore().shouldSurfaceBeforeRotating(baseConversationId)) {
474
+ // First 0-token RE for this conversation: surface it so the
475
+ // session layer can compact. If the payload really was oversized,
476
+ // the compacted retry succeeds and no rotation is ever spent.
477
+ rotationStore().markSurfaced(baseConversationId, conversationId);
478
+ }
479
+ else {
480
+ const decision = rotationStore().recordZeroTokenPoison(baseConversationId, conversationId);
481
+ if (decision.kind === "rotated") {
482
+ const cached = conversationStateCache.get(conversationId);
483
+ if (cached)
484
+ conversationStateCache.set(decision.wireId, cached);
485
+ const blobs = conversationBlobStores.get(conversationId);
486
+ if (blobs)
487
+ conversationBlobStores.set(decision.wireId, blobs);
488
+ retryPoisonedConversation = true;
489
+ }
490
+ else {
491
+ message = CURSOR_CONVERSATION_POISONED_MESSAGE;
492
+ }
493
+ }
494
+ }
495
+ if (!retryPoisonedConversation) {
496
+ output.stopReason = options?.signal?.aborted ? "aborted" : "error";
497
+ output.errorMessage = message;
498
+ stream.push({ type: "error", reason: output.stopReason, error: output });
499
+ stream.end();
500
+ }
445
501
  }
446
- output.stopReason = options?.signal?.aborted ? "aborted" : "error";
447
- output.errorMessage = message;
448
- stream.push({ type: "error", reason: output.stopReason, error: output });
449
- stream.end();
450
- }
451
- finally {
452
- if (heartbeatTimer) {
453
- clearInterval(heartbeatTimer);
454
- heartbeatTimer = null;
502
+ finally {
503
+ if (heartbeatTimer) {
504
+ clearInterval(heartbeatTimer);
505
+ heartbeatTimer = null;
506
+ }
507
+ h2Request?.close();
508
+ h2Client?.close();
509
+ h2Request = null;
510
+ h2Client = null;
455
511
  }
456
- h2Request?.close();
457
- h2Client?.close();
458
- }
512
+ } while (retryPoisonedConversation);
459
513
  })();
460
514
  return stream;
461
515
  };
@@ -2544,12 +2598,16 @@ export function processInteractionUpdate(update, output, stream, state, usageSta
2544
2598
  const toolCall = update.message.value.toolCall;
2545
2599
  if (settled[kStreamingBlockKind] === "mcp") {
2546
2600
  // Authoritative full parse of the accumulated argument buffer.
2601
+ const previousArgs = settled.arguments;
2547
2602
  const partial = settled[kStreamingPartialJson];
2548
2603
  if (partial !== undefined) {
2549
2604
  settled.arguments = parseStreamingJson(partial);
2550
2605
  }
2551
2606
  const decodedArgs = decodeMcpArgsMap(selectMcpCall(toolCall)?.args?.args);
2552
2607
  settled.arguments = mergeCursorMcpToolCallArgs(settled.arguments, decodedArgs);
2608
+ if (settled.name === "task") {
2609
+ settled.arguments = keepUsableCursorTaskArgs(previousArgs, settled.arguments);
2610
+ }
2553
2611
  }
2554
2612
  else if (settled[kStreamingBlockKind] === "connect-scm") {
2555
2613
  // The authoritative outcome arrives only here. Late args are merged
@@ -2622,8 +2680,24 @@ function applyBilledTurnEndedUsage(update, output, usageState) {
2622
2680
  }
2623
2681
  usageState.sawTurnEndedUsage = true;
2624
2682
  const usage = output.usage;
2625
- usage.cacheRead = Number(cacheReadTokens ?? 0n);
2626
- usage.cacheWrite = Number(cacheWriteTokens ?? 0n);
2683
+ const cacheRead = Number(cacheReadTokens ?? 0n);
2684
+ const cacheWrite = Number(cacheWriteTokens ?? 0n);
2685
+ const liveUsed = usageState.liveUsedTokens ?? 0;
2686
+ // Cursor sometimes reports dashboard-cumulative cache_read (millions) while
2687
+ // usedTokens stays at the real window (~150k). Folding that into totalTokens
2688
+ // forces a useless compact and then a 0-token resource_exhausted.
2689
+ if (liveUsed > 0 && cacheRead > liveUsed * 3) {
2690
+ if (outputTokens !== undefined) {
2691
+ usage.output = Number(outputTokens);
2692
+ }
2693
+ usage.cacheRead = 0;
2694
+ usage.cacheWrite = cacheWrite <= liveUsed ? cacheWrite : 0;
2695
+ usage.input = Math.max(0, liveUsed - usage.output - usage.cacheWrite);
2696
+ usage.totalTokens = liveUsed;
2697
+ return;
2698
+ }
2699
+ usage.cacheRead = cacheRead;
2700
+ usage.cacheWrite = cacheWrite;
2627
2701
  usage.input = Math.max(0, Number(inputTokens ?? 0n) - usage.cacheRead - usage.cacheWrite);
2628
2702
  if (outputTokens !== undefined) {
2629
2703
  usage.output = Number(outputTokens);
@@ -2641,6 +2715,7 @@ function applyCheckpointTokenDetails(checkpoint, output, usageState) {
2641
2715
  const usedTokens = checkpoint.tokenDetails?.usedTokens ?? 0;
2642
2716
  if (usedTokens <= 0)
2643
2717
  return;
2718
+ usageState.liveUsedTokens = usedTokens;
2644
2719
  const usage = output.usage;
2645
2720
  usage.input = Math.max(0, usedTokens - usage.output - usage.cacheRead - usage.cacheWrite);
2646
2721
  usage.totalTokens = usage.input + usage.output + usage.cacheRead + usage.cacheWrite;