pi-cursor-sdk 0.2.0 → 0.3.7
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 +73 -0
- package/README.md +55 -51
- package/dist/bundled-context-windows.js +39 -0
- package/dist/context-window-cache.js +92 -0
- package/dist/context.js +353 -0
- package/dist/cursor-active-tools.js +3 -0
- package/dist/cursor-agent-message-web-tools.js +165 -0
- package/dist/cursor-agents-context-registration.js +17 -0
- package/dist/cursor-agents-context.js +127 -0
- package/dist/cursor-api-key.js +34 -0
- package/dist/cursor-bridge-contract.js +27 -0
- package/dist/cursor-cloud-lifecycle.js +650 -0
- package/dist/cursor-cloud-local-state.js +460 -0
- package/dist/cursor-cloud-options.js +145 -0
- package/dist/cursor-cloud-reporting.js +222 -0
- package/dist/cursor-compact-tool-summary.js +75 -0
- package/dist/cursor-config.js +613 -0
- package/dist/cursor-context-tools.js +6 -0
- package/dist/cursor-display-only-trace.js +11 -0
- package/dist/cursor-display-text.js +18 -0
- package/dist/cursor-durable-fs.js +53 -0
- package/dist/cursor-edit-diff.js +13 -0
- package/dist/cursor-env-boolean.js +19 -0
- package/dist/cursor-fallback-models.generated.js +7760 -0
- package/dist/cursor-fallback-warning.js +15 -0
- package/dist/cursor-http1.js +45 -0
- package/dist/cursor-incomplete-tool-visibility.js +83 -0
- package/dist/cursor-live-run-accounting.js +55 -0
- package/dist/cursor-live-run-coordinator.js +409 -0
- package/dist/cursor-mcp-timeout-override.js +116 -0
- package/dist/cursor-model-lifecycle.js +32 -0
- package/dist/cursor-model.js +5 -0
- package/dist/cursor-native-replay-routing.js +35 -0
- package/dist/cursor-native-replay-trace.js +28 -0
- package/dist/cursor-native-tool-display-registration.js +102 -0
- package/dist/cursor-native-tool-display-replay.js +428 -0
- package/dist/cursor-native-tool-display-state.js +70 -0
- package/dist/cursor-native-tool-display-tools.js +123 -0
- package/dist/cursor-native-tool-names.js +11 -0
- package/dist/cursor-partial-content-emitter.js +130 -0
- package/dist/cursor-pi-context.js +30 -0
- package/dist/cursor-pi-tool-bridge-abort.js +114 -0
- package/dist/cursor-pi-tool-bridge-constants.js +6 -0
- package/dist/cursor-pi-tool-bridge-diagnostics.js +125 -0
- package/dist/cursor-pi-tool-bridge-env.js +18 -0
- package/dist/cursor-pi-tool-bridge-mcp.js +100 -0
- package/dist/cursor-pi-tool-bridge-run.js +355 -0
- package/dist/cursor-pi-tool-bridge-server.js +163 -0
- package/dist/cursor-pi-tool-bridge-snapshot.js +63 -0
- package/dist/cursor-pi-tool-bridge-types.js +1 -0
- package/dist/cursor-pi-tool-bridge.js +123 -0
- package/dist/cursor-provider-errors.js +311 -0
- package/dist/cursor-provider-lazy.js +39 -0
- package/dist/cursor-provider-live-run-drain.js +420 -0
- package/dist/cursor-provider-overflow.js +90 -0
- package/dist/cursor-provider-run-finalizer.js +176 -0
- package/dist/cursor-provider-run-outcome.js +76 -0
- package/dist/cursor-provider-turn-coordinator.js +293 -0
- package/dist/cursor-provider-turn-display-router.js +158 -0
- package/dist/cursor-provider-turn-emit.js +41 -0
- package/dist/cursor-provider-turn-finalize.js +154 -0
- package/dist/cursor-provider-turn-lifecycle-emitter.js +126 -0
- package/dist/cursor-provider-turn-prepare.js +379 -0
- package/dist/cursor-provider-turn-runner.js +146 -0
- package/dist/cursor-provider-turn-sdk-normalizer.js +74 -0
- package/dist/cursor-provider-turn-send.js +138 -0
- package/dist/cursor-provider-turn-shell-output.js +117 -0
- package/dist/cursor-provider-turn-tool-ledger.js +99 -0
- package/dist/cursor-provider-turn-types.js +1 -0
- package/dist/cursor-provider.js +72 -0
- package/dist/cursor-question-tool.js +194 -0
- package/dist/cursor-record-utils.js +61 -0
- package/dist/cursor-replay-activity-builders.js +114 -0
- package/dist/cursor-replay-source-names.js +27 -0
- package/dist/cursor-replay-summary-args.js +105 -0
- package/dist/cursor-replay-tool-details.js +167 -0
- package/dist/cursor-ripgrep-path.js +27 -0
- package/dist/cursor-run-final-text.js +63 -0
- package/dist/cursor-runtime-state.js +380 -0
- package/dist/cursor-sdk-billed-usage.js +86 -0
- package/dist/cursor-sdk-event-debug-constants.js +33 -0
- package/dist/cursor-sdk-event-debug-session.js +107 -0
- package/dist/cursor-sdk-event-debug.js +461 -0
- package/dist/cursor-sdk-output-filter.js +1 -0
- package/dist/cursor-sdk-process-error-guard.js +221 -0
- package/dist/cursor-sdk-runtime.js +3 -0
- package/dist/cursor-sensitive-text.js +23 -0
- package/dist/cursor-session-agent-cleanup.js +311 -0
- package/dist/cursor-session-agent-lifecycle.js +32 -0
- package/dist/cursor-session-agent-lineage.js +103 -0
- package/dist/cursor-session-agent-resume.js +417 -0
- package/dist/cursor-session-agent.js +507 -0
- package/dist/cursor-session-compaction-prep.js +21 -0
- package/dist/cursor-session-scope.js +113 -0
- package/dist/cursor-session-send-policy.js +18 -0
- package/dist/cursor-session-store.js +105 -0
- package/dist/cursor-session-turn-queue.js +50 -0
- package/dist/cursor-setting-sources.js +15 -0
- package/dist/cursor-skill-tool.js +230 -0
- package/dist/cursor-state.js +519 -0
- package/dist/cursor-task-presentation.js +59 -0
- package/dist/cursor-tool-lifecycle.js +94 -0
- package/dist/cursor-tool-manifest.js +34 -0
- package/dist/cursor-tool-presentation-registry.js +305 -0
- package/dist/cursor-tool-result-display-readers.js +158 -0
- package/dist/cursor-tool-transcript.js +32 -0
- package/dist/cursor-tool-visibility.js +28 -0
- package/dist/cursor-transcript-tool-formatters.js +618 -0
- package/dist/cursor-transcript-tool-specs.js +284 -0
- package/dist/cursor-transcript-utils.js +170 -0
- package/dist/cursor-usage-accounting.js +166 -0
- package/dist/cursor-web-tool-activity.js +23 -0
- package/dist/cursor-web-tool-args.js +12 -0
- package/dist/index.js +82 -0
- package/dist/model-discovery.js +305 -0
- package/dist/model-list-cache.js +156 -0
- package/docs/cursor-dogfood-checklist.md +2 -1
- package/docs/cursor-live-smoke-checklist.md +13 -12
- package/docs/cursor-model-ux-spec.md +27 -6
- package/docs/cursor-native-tool-replay.md +13 -13
- package/docs/cursor-native-tool-visual-audit.md +6 -3
- package/docs/cursor-testing-lessons.md +14 -8
- package/docs/cursor-tool-surfaces.md +5 -5
- package/docs/platform-smoke.md +3 -3
- package/package.json +19 -7
- package/platform-smoke.config.mjs +1 -1
- package/scripts/build.mjs +126 -0
- package/scripts/cloud-runtime-smoke.mjs +3 -1
- package/scripts/debug-provider-events.mjs +3 -1
- package/scripts/debug-sdk-events.mjs +1 -1
- package/scripts/isolated-cursor-smoke.sh +5 -4
- package/scripts/lib/cloud-smoke-cleanup-evidence.mjs +1 -1
- package/scripts/lib/cursor-visual-render.mjs +1 -1
- package/scripts/lib/ensure-built.mjs +16 -0
- package/scripts/lib/local-resume-smoke-harness.mjs +1 -1
- package/scripts/local-resume-smoke.mjs +3 -1
- package/scripts/platform-smoke/card-detect.mjs +1 -1
- package/scripts/platform-smoke/live-suite-runner.mjs +1 -1
- package/scripts/platform-smoke/render-ansi.mjs +1 -1
- package/scripts/platform-smoke/targets.mjs +2 -2
- package/scripts/prepare.mjs +102 -0
- package/scripts/steering-rpc-smoke.mjs +4 -2
- package/scripts/tmux-live-smoke.sh +11 -11
- package/scripts/visual-tui-smoke-self-test.mjs +4 -1
- package/scripts/visual-tui-smoke.mjs +51 -7
- package/src/bundled-context-windows.ts +4 -1
- package/src/context.ts +27 -4
- package/src/cursor-agents-context-registration.ts +2 -2
- package/src/cursor-agents-context.ts +24 -10
- package/src/cursor-api-key.ts +5 -4
- package/src/cursor-cloud-reporting.ts +23 -2
- package/src/cursor-context-tools.ts +3 -1
- package/src/cursor-fallback-models.generated.ts +592 -204
- package/src/cursor-live-run-coordinator.ts +11 -6
- package/src/cursor-native-tool-display-registration.ts +10 -11
- package/src/cursor-partial-content-emitter.ts +13 -0
- package/src/cursor-pi-context.ts +44 -0
- package/src/cursor-provider-errors.ts +1 -1
- package/src/cursor-provider-lazy.ts +5 -4
- package/src/cursor-provider-live-run-drain.ts +14 -9
- package/src/cursor-provider-run-finalizer.ts +1 -0
- package/src/cursor-provider-turn-coordinator.ts +15 -0
- package/src/cursor-provider-turn-emit.ts +6 -0
- package/src/cursor-provider-turn-finalize.ts +12 -0
- package/src/cursor-provider-turn-prepare.ts +10 -5
- package/src/cursor-provider-turn-types.ts +2 -0
- package/src/cursor-sdk-billed-usage.ts +107 -0
- package/src/cursor-sdk-process-error-guard.ts +6 -4
- package/src/cursor-session-agent-lifecycle.ts +8 -9
- package/src/cursor-session-agent-resume.ts +23 -0
- package/src/cursor-session-compaction-prep.ts +4 -0
- package/src/cursor-skill-tool.ts +1 -1
- package/src/cursor-tool-manifest.ts +1 -1
- package/src/cursor-usage-accounting.ts +70 -9
- package/src/index.ts +1 -1
- package/tsconfig.build.json +8 -0
- package/tsconfig.json +16 -0
|
@@ -7,6 +7,11 @@ import type {
|
|
|
7
7
|
} from "@earendil-works/pi-coding-agent";
|
|
8
8
|
import { clearCursorSdkHttp1 } from "./cursor-http1.js";
|
|
9
9
|
import { onCursorSessionScopeKeyChange } from "./cursor-session-scope.js";
|
|
10
|
+
import {
|
|
11
|
+
disposeSessionCursorAgent,
|
|
12
|
+
invalidateSessionAgent,
|
|
13
|
+
resetSessionCursorAgent,
|
|
14
|
+
} from "./cursor-session-agent.js";
|
|
10
15
|
|
|
11
16
|
export interface CursorSessionAgentLifecycleExtensionApi {
|
|
12
17
|
on(event: "session_shutdown", handler: ExtensionHandler<SessionShutdownEvent>): void;
|
|
@@ -18,11 +23,9 @@ export interface CursorSessionAgentLifecycleExtensionApi {
|
|
|
18
23
|
|
|
19
24
|
export function registerCursorSessionAgentLifecycle(pi: CursorSessionAgentLifecycleExtensionApi): void {
|
|
20
25
|
onCursorSessionScopeKeyChange(async (previousScopeKey) => {
|
|
21
|
-
const { disposeSessionCursorAgent } = await import("./cursor-session-agent.js");
|
|
22
26
|
await disposeSessionCursorAgent(previousScopeKey);
|
|
23
27
|
});
|
|
24
28
|
pi.on("session_shutdown", async (event) => {
|
|
25
|
-
const { disposeSessionCursorAgent, resetSessionCursorAgent } = await import("./cursor-session-agent.js");
|
|
26
29
|
try {
|
|
27
30
|
if (event.reason === "reload") {
|
|
28
31
|
await resetSessionCursorAgent();
|
|
@@ -33,20 +36,16 @@ export function registerCursorSessionAgentLifecycle(pi: CursorSessionAgentLifecy
|
|
|
33
36
|
clearCursorSdkHttp1();
|
|
34
37
|
}
|
|
35
38
|
});
|
|
36
|
-
pi.on("session_compact",
|
|
37
|
-
const { invalidateSessionAgent } = await import("./cursor-session-agent.js");
|
|
39
|
+
pi.on("session_compact", () => {
|
|
38
40
|
invalidateSessionAgent();
|
|
39
41
|
});
|
|
40
|
-
pi.on("session_before_tree",
|
|
41
|
-
const { invalidateSessionAgent } = await import("./cursor-session-agent.js");
|
|
42
|
+
pi.on("session_before_tree", () => {
|
|
42
43
|
invalidateSessionAgent();
|
|
43
44
|
});
|
|
44
45
|
pi.on("session_tree", async () => {
|
|
45
|
-
const { resetSessionCursorAgent } = await import("./cursor-session-agent.js");
|
|
46
46
|
await resetSessionCursorAgent();
|
|
47
47
|
});
|
|
48
|
-
pi.on("model_select",
|
|
49
|
-
const { invalidateSessionAgent } = await import("./cursor-session-agent.js");
|
|
48
|
+
pi.on("model_select", () => {
|
|
50
49
|
invalidateSessionAgent();
|
|
51
50
|
});
|
|
52
51
|
}
|
|
@@ -81,6 +81,19 @@ const state: CursorSessionResumeState = {
|
|
|
81
81
|
unownedUserEntryIds: new Set(),
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
+
// Compaction summarizer sends commit a one-message resume handle. Drop it so the
|
|
85
|
+
// next normal turn_end cannot persist that lineage (#223).
|
|
86
|
+
let resumeHandlePersistSuppressed = false;
|
|
87
|
+
|
|
88
|
+
export function suppressCursorSessionAgentResumeHandlePersist(): void {
|
|
89
|
+
resumeHandlePersistSuppressed = true;
|
|
90
|
+
state.pendingHandle = undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function allowCursorSessionAgentResumeHandlePersist(): void {
|
|
94
|
+
resumeHandlePersistSuppressed = false;
|
|
95
|
+
}
|
|
96
|
+
|
|
84
97
|
function hashParts(parts: readonly string[]): string {
|
|
85
98
|
const hash = createHash("sha256");
|
|
86
99
|
for (const part of parts) {
|
|
@@ -360,6 +373,7 @@ export function getMatchingCursorSessionAgentResumeHandle(poolKey: string): Curs
|
|
|
360
373
|
}
|
|
361
374
|
|
|
362
375
|
export function persistCursorSessionAgentResumeHandle(input: PendingCursorSessionAgentResumeHandle): void {
|
|
376
|
+
if (resumeHandlePersistSuppressed) return;
|
|
363
377
|
if (!isCursorLocalAgentId(input.agentId)) return;
|
|
364
378
|
state.pendingHandle = {
|
|
365
379
|
runtime: input.runtime,
|
|
@@ -371,6 +385,11 @@ export function persistCursorSessionAgentResumeHandle(input: PendingCursorSessio
|
|
|
371
385
|
}
|
|
372
386
|
|
|
373
387
|
function flushPendingCursorSessionAgentResumeHandle(branch: readonly SessionEntry[]): void {
|
|
388
|
+
if (resumeHandlePersistSuppressed) {
|
|
389
|
+
state.pendingHandle = undefined;
|
|
390
|
+
restoreFromBranch(branch);
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
374
393
|
restoreFromBranch(branch);
|
|
375
394
|
const pending = state.pendingHandle;
|
|
376
395
|
state.pendingHandle = undefined;
|
|
@@ -442,6 +461,8 @@ export function registerCursorSessionAgentResume(pi: CursorSessionAgentResumeExt
|
|
|
442
461
|
restoreFromSessionManager(ctx.sessionManager);
|
|
443
462
|
});
|
|
444
463
|
pi.on("session_compact", (event, ctx) => {
|
|
464
|
+
state.pendingHandle = undefined;
|
|
465
|
+
resumeHandlePersistSuppressed = false;
|
|
445
466
|
const branch = ctx.sessionManager.getBranch();
|
|
446
467
|
if (branch.length > 0) {
|
|
447
468
|
restoreFromSessionManager(ctx.sessionManager);
|
|
@@ -471,6 +492,7 @@ function resetStateForTests(): void {
|
|
|
471
492
|
state.lastBranchHandle = undefined;
|
|
472
493
|
state.pendingHandle = undefined;
|
|
473
494
|
state.unownedUserEntryIds = new Set();
|
|
495
|
+
resumeHandlePersistSuppressed = false;
|
|
474
496
|
}
|
|
475
497
|
|
|
476
498
|
export const __testUtils = {
|
|
@@ -479,4 +501,5 @@ export const __testUtils = {
|
|
|
479
501
|
reset: resetStateForTests,
|
|
480
502
|
set: setStateForTests,
|
|
481
503
|
state,
|
|
504
|
+
isResumeHandlePersistSuppressed: () => resumeHandlePersistSuppressed,
|
|
482
505
|
};
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { cursorLiveRuns } from "./cursor-provider-live-run-drain.js";
|
|
2
2
|
import { resetSessionCursorAgent } from "./cursor-session-agent.js";
|
|
3
|
+
import { suppressCursorSessionAgentResumeHandlePersist } from "./cursor-session-agent-resume.js";
|
|
3
4
|
import { getCursorSessionScopeKey } from "./cursor-session-scope.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Prepare the pooled Cursor session agent for pi compaction summarization.
|
|
7
8
|
* Releases any scoped live-run drain state still tied to the pooled agent, then
|
|
8
9
|
* disposes the pool entry so summarization acquires a clean SDK agent.
|
|
10
|
+
* Suppresses local-resume handle persist so the summarizer send cannot leak
|
|
11
|
+
* a one-message handle into the next normal turn (#223).
|
|
9
12
|
*/
|
|
10
13
|
export async function prepareCursorSessionForCompaction(
|
|
11
14
|
scopeKey: string = getCursorSessionScopeKey(),
|
|
12
15
|
): Promise<void> {
|
|
16
|
+
suppressCursorSessionAgentResumeHandlePersist();
|
|
13
17
|
while (true) {
|
|
14
18
|
const run = cursorLiveRuns.getActiveForScope(scopeKey);
|
|
15
19
|
if (!run || run.disposed) break;
|
package/src/cursor-skill-tool.ts
CHANGED
|
@@ -18,7 +18,7 @@ import { resolveEffectiveCursorConfigForContext } from "./cursor-runtime-state.j
|
|
|
18
18
|
export const CURSOR_ACTIVATE_SKILL_TOOL_NAME = "cursor_activate_skill";
|
|
19
19
|
export const CURSOR_ACTIVATE_SKILL_MCP_NAME = "pi__cursor_activate_skill";
|
|
20
20
|
|
|
21
|
-
const AVAILABLE_SKILLS_SECTION_PATTERN =
|
|
21
|
+
const AVAILABLE_SKILLS_SECTION_PATTERN = /<skills>\nThe following skills provide specialized instructions for specific tasks\.[\s\S]*?<\/available_skills>\n<\/skills>|\n\nThe following skills provide specialized instructions for specific tasks\.[\s\S]*?<\/available_skills>/;
|
|
22
22
|
const MAX_SKILL_RESOURCES = 80;
|
|
23
23
|
const RESOURCE_DIR_NAMES = ["scripts", "references", "assets"] as const;
|
|
24
24
|
|
|
@@ -4,7 +4,7 @@ import type { CursorPiToolBridgeSnapshot } from "./cursor-pi-tool-bridge-types.j
|
|
|
4
4
|
export const CURSOR_TOOL_MANIFEST_ENV = "PI_CURSOR_TOOL_MANIFEST";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Representative @cursor/sdk@1.0.
|
|
7
|
+
* Representative @cursor/sdk@1.0.27 local-agent ToolType values; actual exposure can vary by run.
|
|
8
8
|
* See docs/cursor-native-tool-replay.md#sdk-tooltype-replay-matrix.
|
|
9
9
|
*/
|
|
10
10
|
export const CURSOR_HOST_TOOL_MANIFEST_SUMMARY =
|
|
@@ -91,18 +91,30 @@ function getCursorSdkUncachedInputTokens(turnUsage: CursorSdkTurnUsage): number
|
|
|
91
91
|
return turnUsage.inputTokens - turnUsage.cacheReadTokens - turnUsage.cacheWriteTokens;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
export function
|
|
94
|
+
export function isCursorSdkUsagePartitionSafe(turnUsage: CursorSdkTurnUsage, model: Model<Api>): boolean {
|
|
95
95
|
const counts = [turnUsage.inputTokens, turnUsage.outputTokens, turnUsage.cacheReadTokens, turnUsage.cacheWriteTokens];
|
|
96
96
|
const uncachedInput = getCursorSdkUncachedInputTokens(turnUsage);
|
|
97
97
|
return (
|
|
98
98
|
counts.every((count) => Number.isFinite(count) && count >= 0) &&
|
|
99
99
|
Number.isFinite(uncachedInput) &&
|
|
100
100
|
uncachedInput >= 0 &&
|
|
101
|
-
turnUsage.outputTokens <= model.maxTokens
|
|
101
|
+
turnUsage.outputTokens <= model.maxTokens
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function isCursorSdkUsageSafeForPiMessage(turnUsage: CursorSdkTurnUsage, model: Model<Api>): boolean {
|
|
106
|
+
return (
|
|
107
|
+
isCursorSdkUsagePartitionSafe(turnUsage, model) &&
|
|
102
108
|
turnUsage.inputTokens + turnUsage.outputTokens <= model.contextWindow
|
|
103
109
|
);
|
|
104
110
|
}
|
|
105
111
|
|
|
112
|
+
export interface CursorSdkUsageApplyOptions {
|
|
113
|
+
runtime: CursorRuntime;
|
|
114
|
+
turn?: CursorSdkTurnUsage;
|
|
115
|
+
billed?: CursorSdkTurnUsage;
|
|
116
|
+
}
|
|
117
|
+
|
|
106
118
|
export function applyCursorSdkUsage(partial: AssistantMessage, turnUsage: CursorSdkTurnUsage): void {
|
|
107
119
|
// Pi treats input/cacheRead/cacheWrite as disjoint additive prompt components.
|
|
108
120
|
partial.usage.input = getCursorSdkUncachedInputTokens(turnUsage);
|
|
@@ -117,8 +129,23 @@ function isCompatibleCursorAssistantMeasurement(assistant: AssistantMessage, mod
|
|
|
117
129
|
return assistant.api === model.api && assistant.provider === model.provider && assistant.model === model.id;
|
|
118
130
|
}
|
|
119
131
|
|
|
132
|
+
function getLatestCompactionBoundary(context: Context): { index: number; tokensBefore?: number } | undefined {
|
|
133
|
+
for (let index = context.messages.length - 1; index >= 0; index -= 1) {
|
|
134
|
+
const message = context.messages[index] as { role?: string; tokensBefore?: number };
|
|
135
|
+
if (message.role !== "compactionSummary") continue;
|
|
136
|
+
const tokensBefore = message.tokensBefore;
|
|
137
|
+
return {
|
|
138
|
+
index,
|
|
139
|
+
tokensBefore: Number.isFinite(tokensBefore) && tokensBefore !== undefined && tokensBefore > 0 ? Math.floor(tokensBefore) : undefined,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
|
|
120
145
|
function getLastAcceptedContextOccupancy(context: Context, model: Model<Api>): number {
|
|
146
|
+
const boundary = getLatestCompactionBoundary(context);
|
|
121
147
|
for (let index = context.messages.length - 1; index >= 0; index -= 1) {
|
|
148
|
+
if (boundary && index < boundary.index) break;
|
|
122
149
|
const message = context.messages[index];
|
|
123
150
|
if (message.role !== "assistant" || !("usage" in message)) continue;
|
|
124
151
|
const assistant = message as AssistantMessage;
|
|
@@ -127,7 +154,9 @@ function getLastAcceptedContextOccupancy(context: Context, model: Model<Api>): n
|
|
|
127
154
|
const { usage } = assistant;
|
|
128
155
|
const total =
|
|
129
156
|
usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
|
|
130
|
-
if (Number.isFinite(total)
|
|
157
|
+
if (!Number.isFinite(total) || total <= 0 || total > model.contextWindow) continue;
|
|
158
|
+
if (boundary?.tokensBefore !== undefined && total >= boundary.tokensBefore) continue;
|
|
159
|
+
return total;
|
|
131
160
|
}
|
|
132
161
|
return 0;
|
|
133
162
|
}
|
|
@@ -146,18 +175,50 @@ export function applyCursorApproximateUsage(partial: AssistantMessage, model: Mo
|
|
|
146
175
|
);
|
|
147
176
|
}
|
|
148
177
|
|
|
178
|
+
function applyCursorOccupancyEstimate(partial: AssistantMessage, model: Model<Api>, context: Context): void {
|
|
179
|
+
partial.usage.totalTokens = Math.max(
|
|
180
|
+
estimateCursorContextTotalTokens(partial, model, context),
|
|
181
|
+
getLastAcceptedContextOccupancy(context, model),
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function isCurrentLocalOccupancy(turn: CursorSdkTurnUsage, model: Model<Api>, context: Context): boolean {
|
|
186
|
+
if (!isCursorSdkUsageSafeForPiMessage(turn, model)) return false;
|
|
187
|
+
const tokensBefore = getLatestCompactionBoundary(context)?.tokensBefore;
|
|
188
|
+
return tokensBefore === undefined || turn.inputTokens + turn.outputTokens < tokensBefore;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function applyResolvedCursorOccupancy(
|
|
192
|
+
partial: AssistantMessage,
|
|
193
|
+
model: Model<Api>,
|
|
194
|
+
context: Context,
|
|
195
|
+
localTurn: CursorSdkTurnUsage | undefined,
|
|
196
|
+
): void {
|
|
197
|
+
if (localTurn && isCurrentLocalOccupancy(localTurn, model, context)) {
|
|
198
|
+
partial.usage.totalTokens = localTurn.inputTokens + localTurn.outputTokens;
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
applyCursorOccupancyEstimate(partial, model, context);
|
|
202
|
+
}
|
|
203
|
+
|
|
149
204
|
export function applyCursorUsage(
|
|
150
205
|
partial: AssistantMessage,
|
|
151
206
|
model: Model<Api>,
|
|
152
207
|
context: Context,
|
|
153
208
|
sessionInputTokens: number,
|
|
154
|
-
sdkUsage?:
|
|
209
|
+
sdkUsage?: CursorSdkUsageApplyOptions,
|
|
155
210
|
): void {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
211
|
+
const billed = sdkUsage?.billed;
|
|
212
|
+
const localTurn = sdkUsage?.runtime === "local" ? sdkUsage.turn : undefined;
|
|
213
|
+
if (billed && isCursorSdkUsagePartitionSafe(billed, model)) {
|
|
214
|
+
applyCursorSdkUsage(partial, billed);
|
|
215
|
+
applyResolvedCursorOccupancy(partial, model, context, localTurn);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
// Only local raw turn-ended usage has a captured full-prompt/cache-partition occupancy contract.
|
|
219
|
+
if (localTurn && isCursorSdkUsageSafeForPiMessage(localTurn, model)) {
|
|
220
|
+
applyCursorSdkUsage(partial, localTurn);
|
|
221
|
+
applyResolvedCursorOccupancy(partial, model, context, localTurn);
|
|
161
222
|
return;
|
|
162
223
|
}
|
|
163
224
|
applyCursorApproximateUsage(partial, model, context, sessionInputTokens);
|
package/src/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { registerCursorFallbackIssueWarning } from "./cursor-fallback-warning.js
|
|
|
15
15
|
import { registerCursorAgentsContextDedup } from "./cursor-agents-context-registration.js";
|
|
16
16
|
import { registerCursorOverflowNormalization } from "./cursor-provider-overflow.js";
|
|
17
17
|
import { registerCursorSdkSessionProcessErrorGuard } from "./cursor-sdk-process-error-guard.js";
|
|
18
|
+
import { prepareCursorSessionForCompaction } from "./cursor-session-compaction-prep.js";
|
|
18
19
|
|
|
19
20
|
type CursorExtensionApi =
|
|
20
21
|
& Pick<ExtensionAPI, "registerProvider" | "registerCommand" | "on">
|
|
@@ -54,7 +55,6 @@ export default async function (pi: CursorExtensionApi) {
|
|
|
54
55
|
registerCursorSessionAgentLifecycle(pi);
|
|
55
56
|
registerCursorSessionAgentResume(pi);
|
|
56
57
|
pi.on("session_before_compact", async () => {
|
|
57
|
-
const { prepareCursorSessionForCompaction } = await import("./cursor-session-compaction-prep.js");
|
|
58
58
|
await prepareCursorSessionForCompaction();
|
|
59
59
|
});
|
|
60
60
|
registerCursorRuntimeControls(pi);
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"outDir": "dist",
|
|
10
|
+
"rootDir": "src",
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"noEmit": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["src"],
|
|
15
|
+
"exclude": ["node_modules", "dist"]
|
|
16
|
+
}
|