pi-cursor-sdk 0.1.21 → 0.1.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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.1.22 - 2026-05-28
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Fix pi auto-compaction `AgentBusyError` (`already has active run`) by marking pooled session agents busy as soon as a Cursor SDK `run.wait()` starts (live and direct turns), releasing scoped live-run drain state, and resetting the pooled agent on `session_before_compact` before summarization streams (`prepareCursorSessionForCompaction` in `src/cursor-session-compaction-prep.ts`).
|
|
10
|
+
|
|
5
11
|
## 0.1.21 - 2026-05-28
|
|
6
12
|
|
|
7
13
|
**Upgrade:** Requires **pi 0.76.0+** and installs exact **`@cursor/sdk@1.0.14`**. Older pi or Cursor SDK combinations are not supported on this release line.
|
|
@@ -39,7 +39,7 @@ Current implementation notes:
|
|
|
39
39
|
- Max Mode context windows are distinct from default/non-Max context windows. `@cursor/sdk` 1.0.14 documentation says the SDK may enable Max Mode automatically when a selected model requires it, but the public local-agent `ModelSelection` path still does not expose a manual Max Mode selector. Do not advertise Max Mode context windows unless the SDK catalog exposes an exact parameter/variant or the SDK public API adds a Max Mode selector that the extension actually sends.
|
|
40
40
|
- `@cursor/sdk` 1.0.14 adds latest-style `ModelListItem.aliases`. The extension registers only unambiguous aliases as pi model IDs (with the same context suffixes when applicable) and sends the alias back in `ModelSelection.id`, while sharing Cursor-only state such as fast defaults with the underlying catalog `id`. Aliases shared by multiple base models, such as generic family aliases, are skipped because the pi row metadata would otherwise imply one base model while Cursor may resolve the alias to another.
|
|
41
41
|
- Session-scoped Cursor SDK agent pooling reuses one live `@cursor/sdk` agent across compatible follow-up turns within the same pi session scope. `planCursorSessionSend()` in `src/cursor-session-send-policy.ts` decides whether the next turn sends a full bootstrap prompt or an incremental follow-up, whether the SDK agent must be recreated, and why. `computeCursorContextFingerprint()` and `shouldBootstrapCursorContext()` remain the context-only bootstrap signal. The pool recreates the agent when context diverges, when branch or compaction summaries appear after `/tree` navigation or compaction, after 20 completed incremental sends, when the API key identity changes, after send errors, on `session_shutdown`, and when `session_before_tree` / `session_tree` invalidate the active branch. Incremental sends omit the full Cursor SDK tool boundary block because the session agent retains prior bootstrap context, but every send ends with a short tool tail guard placed after the latest user request (including an explicit shell `cd` hint).
|
|
42
|
-
- Pi steering/follow-up delivery can arrive while a split live Cursor SDK run is still active. The provider resolves pending live runs by scanning trailing `toolResult` messages while skipping trailing `user` messages, tracks the active live run per session scope, and resumes the in-flight run instead of calling `Agent.send()` again. When the context ends with steering user text after tool results, the provider releases the prior live run and chains an incremental `Agent.send()` for the latest user message in the same provider turn; if the prior run emits more text or tool requests after steering arrives, that stale activity is cancelled instead of surfacing another old-run tool turn and losing the new user input. A pre-send guard waits for or resumes any still-active scoped live run before starting a fresh send so `@cursor/sdk` `AgentBusyError` (`already has active run`) does not surface to pi users.
|
|
42
|
+
- Pi steering/follow-up delivery can arrive while a split live Cursor SDK run is still active. The provider resolves pending live runs by scanning trailing `toolResult` messages while skipping trailing `user` messages, tracks the active live run per session scope, and resumes the in-flight run instead of calling `Agent.send()` again. When the context ends with steering user text after tool results, the provider releases the prior live run and chains an incremental `Agent.send()` for the latest user message in the same provider turn; if the prior run emits more text or tool requests after steering arrives, that stale activity is cancelled instead of surfacing another old-run tool turn and losing the new user input. A pre-send guard waits for or resumes any still-active scoped live run before starting a fresh send so `@cursor/sdk` `AgentBusyError` (`already has active run`) does not surface to pi users. Pooled session agents mark busy as soon as live/direct `run.wait()` tracking starts (`trackRunCompletion` on the session lease), and `acquireSessionCursorAgent()` awaits that busy state before returning a lease so send planning, transcript offsets, and later `Agent.send()` do not race the prior turn's SDK run completion (for example pi auto-compaction summarization). `session_before_compact` calls `prepareCursorSessionForCompaction()` to release scoped live-run drain state and reset the pooled agent before summarization streams. Tracked completions and send commits are scoped to the pooled agent `instanceId` so disposal/replacement drops stale tracking and ignores late commits from disposed agents.
|
|
43
43
|
|
|
44
44
|
## Goal
|
|
45
45
|
|
package/package.json
CHANGED
|
@@ -113,6 +113,9 @@ export class CursorRunFinalizer {
|
|
|
113
113
|
sanitizeCursorProviderError(error, this.params.resolvedApiKey() ?? runnerParams.options?.apiKey),
|
|
114
114
|
);
|
|
115
115
|
});
|
|
116
|
+
// Mark the pooled agent busy as soon as the SDK run exists so auto-compaction summarization
|
|
117
|
+
// (and other concurrent acquires) wait for run.wait() instead of hitting AgentBusyError.
|
|
118
|
+
prepared.sessionAgentLease.trackRunCompletion(waitCompletion);
|
|
116
119
|
return { waitCompletion, prepared };
|
|
117
120
|
}
|
|
118
121
|
|
|
@@ -139,7 +142,6 @@ export class CursorRunFinalizer {
|
|
|
139
142
|
}
|
|
140
143
|
this.params.runnerParams.sdkEventDebugRef.current = undefined;
|
|
141
144
|
if (liveCompletion) {
|
|
142
|
-
this.safeCleanup(() => liveCompletion.prepared.sessionAgentLease.trackRunCompletion(liveCompletion.waitCompletion));
|
|
143
145
|
void liveCompletion.waitCompletion
|
|
144
146
|
.finally(async () => {
|
|
145
147
|
await this.finalizeSdkEventDebugBestEffort();
|
|
@@ -105,7 +105,7 @@ export class CursorProviderTurnRunner {
|
|
|
105
105
|
return;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
const
|
|
108
|
+
const outcomePromise = awaitFinalizeCursorRunOutcome({
|
|
109
109
|
run: send.run,
|
|
110
110
|
prepared,
|
|
111
111
|
cursorAgentMessageOffset: send.cursorAgentMessageOffset,
|
|
@@ -117,6 +117,8 @@ export class CursorProviderTurnRunner {
|
|
|
117
117
|
sdkEventDebug: this.sdkEventDebug,
|
|
118
118
|
contextWindowAgentId: prepared.contextWindowAgentId,
|
|
119
119
|
});
|
|
120
|
+
prepared.sessionAgentLease.trackRunCompletion(outcomePromise);
|
|
121
|
+
const outcome = await outcomePromise;
|
|
120
122
|
await runFinalizer.applyTerminalEvent({ kind: "direct", prepared, outcome });
|
|
121
123
|
} catch (error) {
|
|
122
124
|
await runFinalizer.applyTerminalEvent({ kind: "error", prepared, error });
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { cursorLiveRuns } from "./cursor-provider-live-run-drain.js";
|
|
2
|
+
import { resetSessionCursorAgent } from "./cursor-session-agent.js";
|
|
3
|
+
import { getCursorSessionScopeKey } from "./cursor-session-scope.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Prepare the pooled Cursor session agent for pi compaction summarization.
|
|
7
|
+
* Releases any scoped live-run drain state still tied to the pooled agent, then
|
|
8
|
+
* disposes the pool entry so summarization acquires a clean SDK agent.
|
|
9
|
+
*/
|
|
10
|
+
export async function prepareCursorSessionForCompaction(
|
|
11
|
+
scopeKey: string = getCursorSessionScopeKey(),
|
|
12
|
+
): Promise<void> {
|
|
13
|
+
while (true) {
|
|
14
|
+
const run = cursorLiveRuns.getActiveForScope(scopeKey);
|
|
15
|
+
if (!run || run.disposed) break;
|
|
16
|
+
await cursorLiveRuns.release(run);
|
|
17
|
+
}
|
|
18
|
+
await resetSessionCursorAgent(scopeKey);
|
|
19
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -7,10 +7,11 @@ import { registerCursorQuestionTool } from "./cursor-question-tool.js";
|
|
|
7
7
|
import { registerCursorSessionCwd } from "./cursor-session-cwd.js";
|
|
8
8
|
import { registerCursorAgentsContextDedup } from "./cursor-agents-context.js";
|
|
9
9
|
import { registerCursorSessionAgent } from "./cursor-session-agent.js";
|
|
10
|
+
import { prepareCursorSessionForCompaction } from "./cursor-session-compaction-prep.js";
|
|
10
11
|
import { streamCursor } from "./cursor-provider.js";
|
|
11
12
|
|
|
12
13
|
type CursorExtensionApi =
|
|
13
|
-
& Pick<ExtensionAPI, "registerProvider" | "registerCommand">
|
|
14
|
+
& Pick<ExtensionAPI, "registerProvider" | "registerCommand" | "on">
|
|
14
15
|
& Parameters<typeof registerCursorSessionCwd>[0]
|
|
15
16
|
& Parameters<typeof registerCursorSessionAgent>[0]
|
|
16
17
|
& Parameters<typeof registerCursorRuntimeControls>[0]
|
|
@@ -38,6 +39,9 @@ export default async function (pi: CursorExtensionApi) {
|
|
|
38
39
|
// Session cwd must register before other session_start listeners that depend on it.
|
|
39
40
|
registerCursorSessionCwd(pi);
|
|
40
41
|
registerCursorSessionAgent(pi);
|
|
42
|
+
pi.on("session_before_compact", async () => {
|
|
43
|
+
await prepareCursorSessionForCompaction();
|
|
44
|
+
});
|
|
41
45
|
registerCursorRuntimeControls(pi);
|
|
42
46
|
registerCursorNativeToolDisplay(pi);
|
|
43
47
|
registerCursorQuestionTool(pi);
|