@code-yeongyu/senpi 2026.8.22 → 2026.8.23
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 +35 -0
- package/dist/bun-runtime.d.ts +58 -0
- package/dist/bun-runtime.d.ts.map +1 -0
- package/dist/bun-runtime.js +163 -0
- package/dist/bun-runtime.js.map +1 -0
- package/dist/cli.js +45 -2
- package/dist/cli.js.map +1 -1
- package/dist/core/agent-session.d.ts +7 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +81 -26
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/agent-settled-delivery.d.ts +13 -1
- package/dist/core/agent-settled-delivery.d.ts.map +1 -1
- package/dist/core/agent-settled-delivery.js +33 -2
- package/dist/core/agent-settled-delivery.js.map +1 -1
- package/dist/core/extensions/builtin/goal/cache-warm-renderer.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/cache-warm-renderer.js +2 -3
- package/dist/core/extensions/builtin/goal/cache-warm-renderer.js.map +1 -1
- package/dist/core/extensions/builtin/goal/cache-warm.d.ts +6 -0
- package/dist/core/extensions/builtin/goal/cache-warm.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/cache-warm.js +43 -0
- package/dist/core/extensions/builtin/goal/cache-warm.js.map +1 -1
- package/dist/core/model-config-schema.d.ts +12 -12
- package/dist/core/model-config-schema.js +2 -2
- package/dist/core/model-config-schema.js.map +1 -1
- package/dist/core/model-resolver.js +2 -2
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/session-work-barrier.d.ts.map +1 -1
- package/dist/core/session-work-barrier.js +38 -1
- package/dist/core/session-work-barrier.js.map +1 -1
- package/dist/modes/interactive/components/status-indicator.d.ts +3 -0
- package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-indicator.js +7 -1
- package/dist/modes/interactive/components/status-indicator.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +2 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +39 -7
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/senpi +45 -2
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +32 -0
- package/node_modules/@code-yeongyu/senpi-codemode/README.md +5 -0
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/extension/eval-notifier.ts +16 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/extension/runtime-factory.ts +4 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/extension/runtime-info.ts +41 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +9 -3
- package/node_modules/@code-yeongyu/senpi-codemode/src/interpreters/detect.ts +17 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/interpreters/resolve-command.ts +68 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/timeouts/idle-timeout.ts +33 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-runtime.ts +5 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool-options.ts +3 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool.ts +2 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +60 -3
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/runtime-label.ts +49 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/types.ts +13 -0
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts +5 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js +13 -5
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/cursor/composer-prompt.d.ts +27 -0
- package/node_modules/@earendil-works/pi-ai/dist/cursor/composer-prompt.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/cursor/composer-prompt.js +54 -0
- package/node_modules/@earendil-works/pi-ai/dist/cursor/composer-prompt.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/nvidia.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/kimi-xtml/markers.d.ts +4 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/kimi-xtml/markers.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/kimi-xtml/markers.js +14 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/kimi-xtml/markers.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/kimi-xtml/recovery-stream.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/kimi-xtml/recovery-stream.js +65 -35
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/kimi-xtml/recovery-stream.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/kimi-xtml/thinking-recovery.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/kimi-xtml/thinking-recovery.js +40 -12
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/kimi-xtml/thinking-recovery.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
JSON_TREE_SCALAR_LEN_EXPANDED,
|
|
20
20
|
renderJsonTreeLines,
|
|
21
21
|
} from "./json-tree.ts";
|
|
22
|
+
import { formatRuntimeBadge } from "./runtime-label.ts";
|
|
22
23
|
import { codePointPrefix, formatDuration, renderToolCallWidget } from "./tool-widgets.ts";
|
|
23
24
|
import type {
|
|
24
25
|
EvalCellResult,
|
|
@@ -69,14 +70,38 @@ const TOOL_CALL_PREVIEW_COUNT = 5;
|
|
|
69
70
|
const TOOL_CALL_COLLAPSED_VISUAL_LINES = 4;
|
|
70
71
|
const TOOL_CALL_COLLAPSED_ERROR_CODE_POINTS = 512;
|
|
71
72
|
const TOOL_ERROR_OMISSION_MARKER = "[tool error omitted]";
|
|
73
|
+
const LIVE_ELAPSED_TICK_MS = 1_000;
|
|
72
74
|
|
|
73
75
|
class PlainTextComponent implements EvalRenderComponent {
|
|
74
76
|
#blocks: readonly RenderBlock[] = [];
|
|
77
|
+
#ticker: ReturnType<typeof setInterval> | undefined;
|
|
75
78
|
|
|
76
79
|
setBlocks(blocks: readonly RenderBlock[]): void {
|
|
77
80
|
this.#blocks = blocks;
|
|
78
81
|
}
|
|
79
82
|
|
|
83
|
+
/**
|
|
84
|
+
* The host only animates tool rows for streaming args, `task`, and results carrying
|
|
85
|
+
* `details.progress`; an eval row matches none of them, so nothing repaints it between
|
|
86
|
+
* update events. While a cell is non-terminal this drives the repaint itself so the
|
|
87
|
+
* header's elapsed time advances, and it emits no tool updates or RPC traffic.
|
|
88
|
+
*/
|
|
89
|
+
syncLiveTicker(isLive: boolean, invalidate: () => void): void {
|
|
90
|
+
if (!isLive) {
|
|
91
|
+
this.stopLiveTicker();
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (this.#ticker !== undefined) return;
|
|
95
|
+
this.#ticker = setInterval(invalidate, LIVE_ELAPSED_TICK_MS);
|
|
96
|
+
this.#ticker.unref?.();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
stopLiveTicker(): void {
|
|
100
|
+
if (this.#ticker === undefined) return;
|
|
101
|
+
clearInterval(this.#ticker);
|
|
102
|
+
this.#ticker = undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
80
105
|
render(width: number): string[] {
|
|
81
106
|
const lines: string[] = [];
|
|
82
107
|
for (const block of this.#blocks) {
|
|
@@ -109,6 +134,16 @@ function componentFor(context: RenderContext | ResultRenderContext): PlainTextCo
|
|
|
109
134
|
return new PlainTextComponent();
|
|
110
135
|
}
|
|
111
136
|
|
|
137
|
+
/** Render-time clock; tests inject a fixed value so elapsed output never depends on wall time. */
|
|
138
|
+
function renderNow(context: RenderContext | ResultRenderContext): number {
|
|
139
|
+
const injected: unknown = Reflect.get(context, "now");
|
|
140
|
+
return typeof injected === "number" && Number.isFinite(injected) ? injected : Date.now();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function hasLiveCell(details: EvalToolDetails | undefined): boolean {
|
|
144
|
+
return (details?.cells ?? []).some((cell) => isLiveCellStatus(cell.status) && cell.startedAt !== undefined);
|
|
145
|
+
}
|
|
146
|
+
|
|
112
147
|
function style(theme: Theme | undefined, color: ThemeColor, text: string): string {
|
|
113
148
|
return theme ? theme.fg(color, text) : text;
|
|
114
149
|
}
|
|
@@ -187,6 +222,8 @@ type RenderEnvironment = {
|
|
|
187
222
|
readonly spinnerFrame: number | undefined;
|
|
188
223
|
readonly width: number;
|
|
189
224
|
readonly meta: TruncationMeta | undefined;
|
|
225
|
+
/** Render-time clock, injected so elapsed time is deterministic under test. */
|
|
226
|
+
readonly now: number;
|
|
190
227
|
};
|
|
191
228
|
type CellBadges = {
|
|
192
229
|
readonly reset: boolean;
|
|
@@ -231,6 +268,10 @@ function spinner(frame: number | undefined): string {
|
|
|
231
268
|
return SPINNER_FRAMES.at((frame ?? 0) % SPINNER_FRAMES.length) ?? SPINNER_FRAMES[0];
|
|
232
269
|
}
|
|
233
270
|
|
|
271
|
+
function isLiveCellStatus(status: CellStatus): boolean {
|
|
272
|
+
return status === "pending" || status === "running" || status === "detached";
|
|
273
|
+
}
|
|
274
|
+
|
|
234
275
|
function cellPresentation(status: CellStatus, spinnerFrame: number | undefined): StatusPresentation {
|
|
235
276
|
switch (status) {
|
|
236
277
|
case "pending":
|
|
@@ -259,12 +300,21 @@ function renderPrefixed(text: string, environment: RenderEnvironment, prefixStyl
|
|
|
259
300
|
);
|
|
260
301
|
}
|
|
261
302
|
|
|
303
|
+
// A running cell only receives updates on output/status events, so a stored duration
|
|
304
|
+
// freezes between them. Non-terminal cells therefore derive elapsed time from the
|
|
305
|
+
// render-time clock; terminal cells keep their settled duration verbatim.
|
|
306
|
+
function cellElapsedMs(cell: EvalCellResult, environment: RenderEnvironment): number | undefined {
|
|
307
|
+
if (!isLiveCellStatus(cell.status) || cell.startedAt === undefined) return cell.durationMs;
|
|
308
|
+
return Math.max(0, environment.now - cell.startedAt);
|
|
309
|
+
}
|
|
310
|
+
|
|
262
311
|
function cellHeader(cell: EvalCellResult, environment: RenderEnvironment, badges: CellBadges): string {
|
|
263
312
|
const presentation = cellPresentation(cell.status, environment.spinnerFrame);
|
|
264
|
-
|
|
313
|
+
const runtimeBadge = cell.runtime === undefined ? "" : ` (${formatRuntimeBadge(cell.language, cell.runtime)})`;
|
|
314
|
+
let header = `eval ${cell.language}${runtimeBadge} ${presentation.label} ${presentation.icon}`;
|
|
265
315
|
const throughputBadge = badges.throughput === undefined ? undefined : formatThroughputBadge(badges.throughput);
|
|
266
316
|
if (throughputBadge !== undefined) header += ` · ${throughputBadge}`;
|
|
267
|
-
const elapsedMs = badges.throughput?.wallDurationMs ?? cell
|
|
317
|
+
const elapsedMs = badges.throughput?.wallDurationMs ?? cellElapsedMs(cell, environment);
|
|
268
318
|
if (elapsedMs !== undefined) header += ` · ${formatDuration(elapsedMs)}`;
|
|
269
319
|
if (badges.reset) header += " · reset";
|
|
270
320
|
if (badges.timeout !== undefined) header += ` · timeout ${badges.timeout}s`;
|
|
@@ -780,7 +830,9 @@ function resultHeader(
|
|
|
780
830
|
color = "error";
|
|
781
831
|
break;
|
|
782
832
|
}
|
|
783
|
-
|
|
833
|
+
const runtimeBadge =
|
|
834
|
+
details?.runtime === undefined ? "" : ` (${formatRuntimeBadge(details.language, details.runtime)})`;
|
|
835
|
+
return style(theme, color, `eval ${details?.language ?? "?"}${runtimeBadge} ${status}`);
|
|
784
836
|
}
|
|
785
837
|
|
|
786
838
|
function resultMetadata(
|
|
@@ -843,6 +895,7 @@ export function renderEvalCall(
|
|
|
843
895
|
spinnerFrame: context.spinnerFrame,
|
|
844
896
|
width,
|
|
845
897
|
meta: undefined,
|
|
898
|
+
now: renderNow(context),
|
|
846
899
|
};
|
|
847
900
|
const cell: EvalCellResult = {
|
|
848
901
|
index: 0,
|
|
@@ -873,6 +926,7 @@ export function renderEvalResult(
|
|
|
873
926
|
const details = result.details;
|
|
874
927
|
const expanded = options.expanded || context.expanded;
|
|
875
928
|
const imageProtocol = context.imageProtocol ?? null;
|
|
929
|
+
component.syncLiveTicker(hasLiveCell(details), context.invalidate);
|
|
876
930
|
if (details?.cells !== undefined && details.cells.length > 0) {
|
|
877
931
|
const blocks: RenderBlock[] = [
|
|
878
932
|
{
|
|
@@ -885,6 +939,7 @@ export function renderEvalResult(
|
|
|
885
939
|
spinnerFrame: context.spinnerFrame,
|
|
886
940
|
width,
|
|
887
941
|
meta: details.meta,
|
|
942
|
+
now: renderNow(context),
|
|
888
943
|
},
|
|
889
944
|
args: context.args,
|
|
890
945
|
showImageFallback: context.showImages && imageProtocol === null,
|
|
@@ -936,6 +991,7 @@ export function renderEvalResult(
|
|
|
936
991
|
spinnerFrame: context.spinnerFrame,
|
|
937
992
|
width,
|
|
938
993
|
meta: details?.meta,
|
|
994
|
+
now: renderNow(context),
|
|
939
995
|
};
|
|
940
996
|
return [
|
|
941
997
|
...renderStatusEvents(nonAgentEvents, environment),
|
|
@@ -957,6 +1013,7 @@ export function renderEvalResult(
|
|
|
957
1013
|
spinnerFrame: context.spinnerFrame,
|
|
958
1014
|
width,
|
|
959
1015
|
meta: details?.meta,
|
|
1016
|
+
now: renderNow(context),
|
|
960
1017
|
}),
|
|
961
1018
|
},
|
|
962
1019
|
);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import type { EvalLanguage, EvalRuntimeInfo } from "./types.ts";
|
|
3
|
+
|
|
4
|
+
const MAX_BADGE_PATH_CODE_POINTS = 40;
|
|
5
|
+
const ELLIPSIS = "\u2026";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* One-line runtime badge for eval headers, e.g. "3.14.7, ~/.venv/bin/python3"
|
|
9
|
+
* or "node 26.7.0, /opt/…/bin/node". The js language always carries the
|
|
10
|
+
* runtime name because node and bun are otherwise indistinguishable.
|
|
11
|
+
*/
|
|
12
|
+
export function formatRuntimeBadge(language: EvalLanguage, runtime: EvalRuntimeInfo, home: string = homedir()): string {
|
|
13
|
+
const label = language === "js" ? `${runtime.name} ${runtime.version}` : runtime.version;
|
|
14
|
+
if (runtime.path === undefined || runtime.path.length === 0) return label;
|
|
15
|
+
return `${label}, ${minifyPath(runtime.path, home)}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Home-contracts and middle-truncates a path so header badges stay short. */
|
|
19
|
+
export function minifyPath(path: string, home: string = homedir()): string {
|
|
20
|
+
const contracted = contractHome(path, home);
|
|
21
|
+
if (codePointLength(contracted) <= MAX_BADGE_PATH_CODE_POINTS) return contracted;
|
|
22
|
+
const separator = contracted.includes("/") ? "/" : "\\";
|
|
23
|
+
const segments = contracted.split(separator).filter((segment) => segment.length > 0);
|
|
24
|
+
const head = contracted.startsWith(separator) ? `${separator}${segments[0] ?? ""}` : (segments[0] ?? "");
|
|
25
|
+
const tail: string[] = [];
|
|
26
|
+
for (let index = segments.length - 1; index >= 1; index -= 1) {
|
|
27
|
+
const attempt = joinTruncated(head, [segments[index] ?? "", ...tail], separator);
|
|
28
|
+
if (codePointLength(attempt) > MAX_BADGE_PATH_CODE_POINTS) break;
|
|
29
|
+
tail.unshift(segments[index] ?? "");
|
|
30
|
+
}
|
|
31
|
+
if (tail.length > 0) return joinTruncated(head, tail, separator);
|
|
32
|
+
const suffix = [...contracted].slice(-(MAX_BADGE_PATH_CODE_POINTS - 1)).join("");
|
|
33
|
+
return `${ELLIPSIS}${suffix}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function joinTruncated(head: string, tail: readonly string[], separator: string): string {
|
|
37
|
+
return `${head}${separator}${ELLIPSIS}${separator}${tail.join(separator)}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function contractHome(path: string, home: string): string {
|
|
41
|
+
if (home.length === 0) return path;
|
|
42
|
+
if (path === home) return "~";
|
|
43
|
+
if (path.startsWith(`${home}/`) || path.startsWith(`${home}\\`)) return `~${path.slice(home.length)}`;
|
|
44
|
+
return path;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function codePointLength(text: string): number {
|
|
48
|
+
return [...text].length;
|
|
49
|
+
}
|
|
@@ -140,6 +140,15 @@ export interface EvalToolCallSummary {
|
|
|
140
140
|
|
|
141
141
|
export type EvalStatusEvent = { readonly op: string } & Readonly<Record<string, unknown>>;
|
|
142
142
|
|
|
143
|
+
/** Identity of the runtime executing a kernel: interpreter or JS host. */
|
|
144
|
+
export interface EvalRuntimeInfo {
|
|
145
|
+
readonly name: string;
|
|
146
|
+
readonly version: string;
|
|
147
|
+
readonly path?: string;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export type EvalRuntimes = Readonly<Partial<Record<EvalLanguage, EvalRuntimeInfo>>>;
|
|
151
|
+
|
|
143
152
|
export type EvalDisplayOutput =
|
|
144
153
|
| { readonly type: "json"; readonly data: unknown }
|
|
145
154
|
| { readonly type: "image"; readonly data: string; readonly mimeType: string }
|
|
@@ -152,9 +161,12 @@ export type EvalCellResult = {
|
|
|
152
161
|
readonly code: string;
|
|
153
162
|
readonly language: EvalLanguage;
|
|
154
163
|
readonly output: string;
|
|
164
|
+
readonly runtime?: EvalRuntimeInfo;
|
|
155
165
|
readonly status: "pending" | "running" | "detached" | "complete" | "error" | "cancelled";
|
|
156
166
|
readonly exitCode?: number;
|
|
157
167
|
readonly durationMs?: number;
|
|
168
|
+
/** Epoch ms when the cell started; lets renderers tick elapsed time between update events. */
|
|
169
|
+
readonly startedAt?: number;
|
|
158
170
|
readonly statusEvents?: readonly EvalStatusEvent[];
|
|
159
171
|
readonly hasMarkdown?: boolean;
|
|
160
172
|
};
|
|
@@ -162,6 +174,7 @@ export type EvalCellResult = {
|
|
|
162
174
|
export interface EvalToolDetails {
|
|
163
175
|
readonly language: EvalLanguage;
|
|
164
176
|
readonly languages?: readonly EvalLanguage[];
|
|
177
|
+
readonly runtime?: EvalRuntimeInfo;
|
|
165
178
|
readonly summary?: string;
|
|
166
179
|
readonly durationMs: number;
|
|
167
180
|
/** True wall-clock elapsed time since the cell started; `durationMs` stays kernel-reported. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@earendil-works/pi-agent-core",
|
|
3
3
|
"private": true,
|
|
4
|
-
"version": "2026.8.
|
|
4
|
+
"version": "2026.8.23",
|
|
5
5
|
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"prepublishOnly": "npm run build"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.8.
|
|
40
|
-
"@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.8.
|
|
39
|
+
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.8.23",
|
|
40
|
+
"@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.8.23",
|
|
41
41
|
"diff": "9.0.0",
|
|
42
42
|
"ignore": "7.0.6",
|
|
43
43
|
"typebox": "1.3.16",
|
|
@@ -168,8 +168,12 @@ export declare function buildMcpToolDefinitions(tools: Tool[] | undefined): McpT
|
|
|
168
168
|
* Build one Cursor system-message JSON blob per system prompt. When no system
|
|
169
169
|
* prompt is provided, returns a single default greeting so we never emit an
|
|
170
170
|
* empty `rootPromptMessagesJson` head.
|
|
171
|
+
*
|
|
172
|
+
* Composer models get their operating prefix as its own leading blob rather
|
|
173
|
+
* than concatenated into the host prompt, so Cursor's per-blob prompt cache
|
|
174
|
+
* keeps the prefix stable while the host prompt changes underneath it.
|
|
171
175
|
*/
|
|
172
|
-
export declare function buildCursorSystemPromptJsons(systemPrompt: string | undefined): string[];
|
|
176
|
+
export declare function buildCursorSystemPromptJsons(systemPrompt: string | undefined, modelId?: string): string[];
|
|
173
177
|
/** Exported for tests: decodes Cursor history blobs built from conversation messages. */
|
|
174
178
|
export declare function buildCursorHistoryForTest(messages: Message[], activeUserMessageIndex?: number): {
|
|
175
179
|
rootPromptMessagesJson: unknown[];
|
|
@@ -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;
|
|
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;AAKpC,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,EAsDtB,MAAM,gCAAgC,CAAC;AAgBxC,OAAO,KAAK,EACX,kBAAkB,EAClB,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,EAGjB,uBAAuB,EACvB,MAAM,yBAAyB,CAAC;AASjC,YAAY,EACX,kBAAkB,EAClB,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,0BAA0B,EAC1B,uBAAuB,GACvB,MAAM,yBAAyB,CAAC;AAEjC,eAAO,MAAM,cAAc,2BAA2B,CAAC;AACvD,eAAO,MAAM,qBAAqB,2BAA2B,CAAC;AAE9D,gFAAgF;AAChF,eAAO,MAAM,sCAAsC,QAAS,CAAC;AAC7D,oGAAoG;AACpG,eAAO,MAAM,gDAAgD,QAA6C,CAAC;AAC3G,mEAAmE;AACnE,eAAO,MAAM,gCAAgC,OAAO,CAAC;AAsCrD,oFAAoF;AACpF,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAU/G;AAoDD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,SAAI,GAAG,MAAM,CAMvE;AAiBD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAY5E;AAED,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,cAAc,EAAE,kBAAkB,CAghBrE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,cAAc,EAAE,mBAAmB,CAM5E,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG;IACtC,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC/B,CAAC,qBAAqB,CAAC,CAAC,EAAE,MAAM,CAAC;IACjC,CAAC,sBAAsB,CAAC,CAAC,EAAE,MAAM,CAAC;IAClC,CAAC,mBAAmB,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,aAAa,GAAG,aAAa,CAAC;IACtE,CAAC,oBAAoB,CAAC,CAAC,EAAE,MAAM,CAAC;IAChC,CAAC,mBAAmB,CAAC,CAAC,EAAE,IAAI,CAAC;CAC7B,CAAC;AAEF,MAAM,WAAW,UAAU;IAC1B,gBAAgB,EAAE,CAAC,WAAW,GAAG;QAAE,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;IAC5E,oBAAoB,EAAE,CAAC,eAAe,GAAG;QAAE,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;IACpF,eAAe,EAAE,aAAa,GAAG,IAAI,CAAC;IACtC;;;;OAIG;IACH,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC1C,+FAA+F;IAC/F,sBAAsB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACpC,YAAY,EAAE,CAAC,CAAC,EAAE,CAAC,WAAW,GAAG;QAAE,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;IACrF,gBAAgB,EAAE,CAAC,CAAC,EAAE,CAAC,eAAe,GAAG;QAAE,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7F,WAAW,EAAE,CAAC,CAAC,EAAE,aAAa,GAAG,IAAI,KAAK,IAAI,CAAC;IAC/C;;;;OAIG;IACH,YAAY,CAAC,EAAE,uBAAuB,CAAC;CACvC;AAMD,MAAM,WAAW,UAAU;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,2EAA2E;IAC3E,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,iHAAiH;AACjH,wBAAsB,mBAAmB,CACxC,GAAG,EAAE,kBAAkB,EACvB,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,2BAA2B,EACnC,KAAK,EAAE,UAAU,EACjB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EAClC,SAAS,EAAE,KAAK,CAAC,iBAAiB,EAClC,YAAY,EAAE,kBAAkB,GAAG,SAAS,EAC5C,YAAY,EAAE,uBAAuB,GAAG,SAAS,EACjD,UAAU,EAAE,UAAU,EACtB,mBAAmB,EAAE,iBAAiB,EAAE,EACxC,wBAAwB,CAAC,EAAE,CAAC,UAAU,EAAE,0BAA0B,KAAK,IAAI,GACzE,OAAO,CAAC,IAAI,CAAC,CA8Bf;AAwoCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EACtD,IAAI,EAAE,KAAK,EACX,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,SAAS,EACjF,YAAY,EAAE,uBAAuB,GAAG,SAAS,EACjD,mBAAmB,EAAE,CAAC,UAAU,EAAE,iBAAiB,KAAK,OAAO,EAC/D,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,EAC1C,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,EACtC,OAAO,EAAE,iBAAiB,GAAG,IAAI,GAC/B,OAAO,CAAC;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,iBAAiB,CAAA;CAAE,CAAC,CA0ClE;AAsfD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAS9G;AAuND;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CACjC,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,2BAA2B,EACnC,KAAK,EAAE,UAAU,GACf,IAAI,CAyBN;AAuND;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CACzC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC7C,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC7C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWzB;AAgCD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,4BAA4B,CAC3C,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,2BAA2B,EACnC,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,IAAI,CAgBN;AAqCD,oGAAoG;AACpG,wBAAgB,wBAAwB,CACvC,MAAM,EAAE,GAAG,EACX,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,2BAA2B,EACnC,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,UAAU,GACpB,IAAI,CAsNN;AAoHD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CASjE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,SAAS,GAAG,iBAAiB,EAAE,CAyBtF;AA6FD;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CASzG;AAwPD,yFAAyF;AACzF,wBAAgB,yBAAyB,CACxC,QAAQ,EAAE,OAAO,EAAE,EACnB,sBAAsB,SAAqC,GACzD;IACF,sBAAsB,EAAE,OAAO,EAAE,CAAC;IAClC,oBAAoB,EAAE,OAAO,EAAE,CAAC;IAChC,oBAAoB,EAAE,OAAO,EAAE,EAAE,CAAC;CAClC,CAsBA;AAoND,MAAM,WAAW,qBAAqB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB,GAAG,OAAO,CAAC,qBAAqB,EAAE,GAAG,IAAI,CAAC,CAqG1C"}
|
|
@@ -19,6 +19,7 @@ import { createHash, randomUUID } from "node:crypto";
|
|
|
19
19
|
import * as http2 from "node:http2";
|
|
20
20
|
import { create, fromBinary, fromJson, toBinary, toJson } from "@bufbuild/protobuf";
|
|
21
21
|
import { ValueSchema } from "@bufbuild/protobuf/wkt";
|
|
22
|
+
import { CURSOR_COMPOSER_PROMPT, isCursorComposerModel } from "../cursor/composer-prompt.js";
|
|
22
23
|
import { calculateCost } from "../models.js";
|
|
23
24
|
import { clearStreamingPartialJson, kCursorExecResolved, kStreamingBlockIndex, kStreamingBlockKind, kStreamingEnvelopeId, kStreamingLastParseLen, kStreamingPartialJson, } from "../utils/block-symbols.js";
|
|
24
25
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
@@ -3024,13 +3025,20 @@ function findLastUserMessageIndex(messages) {
|
|
|
3024
3025
|
* Build one Cursor system-message JSON blob per system prompt. When no system
|
|
3025
3026
|
* prompt is provided, returns a single default greeting so we never emit an
|
|
3026
3027
|
* empty `rootPromptMessagesJson` head.
|
|
3028
|
+
*
|
|
3029
|
+
* Composer models get their operating prefix as its own leading blob rather
|
|
3030
|
+
* than concatenated into the host prompt, so Cursor's per-blob prompt cache
|
|
3031
|
+
* keeps the prefix stable while the host prompt changes underneath it.
|
|
3027
3032
|
*/
|
|
3028
|
-
export function buildCursorSystemPromptJsons(systemPrompt) {
|
|
3033
|
+
export function buildCursorSystemPromptJsons(systemPrompt, modelId) {
|
|
3029
3034
|
const trimmed = systemPrompt?.trim();
|
|
3030
|
-
|
|
3031
|
-
|
|
3035
|
+
const host = trimmed
|
|
3036
|
+
? [JSON.stringify({ role: "system", content: trimmed })]
|
|
3037
|
+
: [JSON.stringify({ role: "system", content: "You are a helpful assistant." })];
|
|
3038
|
+
if (modelId !== undefined && isCursorComposerModel(modelId)) {
|
|
3039
|
+
return [JSON.stringify({ role: "system", content: CURSOR_COMPOSER_PROMPT }), ...host];
|
|
3032
3040
|
}
|
|
3033
|
-
return
|
|
3041
|
+
return host;
|
|
3034
3042
|
}
|
|
3035
3043
|
/**
|
|
3036
3044
|
* Build `ConversationStateStructure.rootPromptMessagesJson` blob IDs for the
|
|
@@ -3316,7 +3324,7 @@ function extractImages(content) {
|
|
|
3316
3324
|
}
|
|
3317
3325
|
async function buildGrpcRequest(model, context, options, state) {
|
|
3318
3326
|
const blobStore = state.blobStore;
|
|
3319
|
-
const systemPromptIds = buildCursorSystemPromptJsons(context.systemPrompt).map((json) => storeCursorBlob(blobStore, new TextEncoder().encode(json)));
|
|
3327
|
+
const systemPromptIds = buildCursorSystemPromptJsons(context.systemPrompt, model.id).map((json) => storeCursorBlob(blobStore, new TextEncoder().encode(json)));
|
|
3320
3328
|
const activeUserMessageIndex = context.messages.length - 1;
|
|
3321
3329
|
const activeMessage = context.messages[activeUserMessageIndex];
|
|
3322
3330
|
const activeUserMessage = activeMessage?.role === "user" ? activeMessage : undefined;
|