@code-yeongyu/senpi-codemode 2026.10.3 → 2026.10.5
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 +32 -0
- package/README.md +17 -0
- package/package.json +5 -4
- package/src/bridge/memory-protocol.ts +14 -0
- package/src/bridge/protocol.ts +19 -1
- package/src/extension/kernel-registration.ts +96 -0
- package/src/extension/kernel-registry.ts +105 -0
- package/src/extension/kernel-replacement.ts +230 -0
- package/src/extension/runtime-factory.ts +1 -0
- package/src/extension/session-manager-contract.ts +42 -0
- package/src/extension/session-manager.ts +63 -52
- package/src/kernels/jl/kernel.ts +3 -1
- package/src/kernels/js/active-cell-control.ts +73 -0
- package/src/kernels/js/context-manager.ts +69 -188
- package/src/kernels/js/kernel-memory-bridge.ts +110 -0
- package/src/kernels/js/tool-call-queue.ts +32 -0
- package/src/kernels/js/worker-children.ts +35 -0
- package/src/kernels/js/worker-core.js +8 -0
- package/src/kernels/js/worker-host.ts +9 -0
- package/src/kernels/js/worker-recovery.ts +60 -0
- package/src/kernels/py/kernel-contract.ts +2 -1
- package/src/kernels/py/kernel.ts +48 -8
- package/src/kernels/py/transport.ts +25 -4
- package/src/kernels/rb/kernel.ts +3 -1
- package/src/kernels/session-env.ts +3 -0
- package/src/kernels/shared/kernel-death.ts +39 -0
- package/src/kernels/shared/subprocess-contract.ts +2 -1
- package/src/kernels/shared/subprocess-kernel.ts +33 -2
- package/src/kernels/shared/subprocess-queue.ts +6 -0
- package/src/tool/cell-runtime.ts +17 -4
- package/src/tool/detached-cell-notification.ts +13 -2
- package/src/tool/types.ts +14 -0
|
@@ -44,6 +44,11 @@ export class SubprocessRunQueue {
|
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/** Removes every queued run that has not started, oldest first. */
|
|
48
|
+
drain(): PendingRun[] {
|
|
49
|
+
return this.#queue.splice(0);
|
|
50
|
+
}
|
|
51
|
+
|
|
47
52
|
releaseActive(run: PendingRun): boolean {
|
|
48
53
|
if (this.#active !== run) return false;
|
|
49
54
|
this.#active = null;
|
|
@@ -114,6 +119,7 @@ export class SubprocessRunQueue {
|
|
|
114
119
|
onMessage?.(message);
|
|
115
120
|
return false;
|
|
116
121
|
case "webview-connect":
|
|
122
|
+
case "memory-query-result":
|
|
117
123
|
return false;
|
|
118
124
|
default: {
|
|
119
125
|
const exhaustive: never = message;
|
package/src/tool/cell-runtime.ts
CHANGED
|
@@ -5,7 +5,14 @@ import { formatModelTruncationNotice } from "../output/output-meta.ts";
|
|
|
5
5
|
import { DEFAULT_MAX_BYTES, TailLineRing } from "../output/streaming-output.ts";
|
|
6
6
|
import type { EvalToolCallMetric } from "./call-capture.ts";
|
|
7
7
|
import { type EvalImageResizer, EvalOutputCollector, type EvalOutputResult } from "./image.ts";
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
EvalKernelState,
|
|
10
|
+
EvalMemoryDetails,
|
|
11
|
+
EvalRuntimeInfo,
|
|
12
|
+
EvalStatusEvent,
|
|
13
|
+
EvalToolDetails,
|
|
14
|
+
EvalToolInput,
|
|
15
|
+
} from "./types.ts";
|
|
9
16
|
|
|
10
17
|
const LIVE_UPDATE_LINES = 8;
|
|
11
18
|
/** Same cadence as the core bash tool's streaming updates (BASH_UPDATE_THROTTLE_MS). */
|
|
@@ -48,6 +55,8 @@ export class CellResultBuilder {
|
|
|
48
55
|
readonly #output: EvalOutputCollector;
|
|
49
56
|
readonly #state: CellState;
|
|
50
57
|
#memory: KernelMemoryReport | undefined;
|
|
58
|
+
#restartNotice: string | undefined;
|
|
59
|
+
#kernelState: EvalKernelState | undefined;
|
|
51
60
|
readonly #liveLines = new TailLineRing({ maxBytes: DEFAULT_MAX_BYTES * 2, maxLines: LIVE_UPDATE_LINES });
|
|
52
61
|
#lastOutputUpdateAt = 0;
|
|
53
62
|
#outputUpdateTimer: ReturnType<typeof setTimeout> | undefined;
|
|
@@ -85,6 +94,8 @@ export class CellResultBuilder {
|
|
|
85
94
|
async finalize(result: KernelResult): Promise<AgentToolResult<EvalToolDetails>> {
|
|
86
95
|
this.#state.durationMs = result.durationMs;
|
|
87
96
|
this.#memory = result.memory;
|
|
97
|
+
this.#restartNotice = result.notice;
|
|
98
|
+
this.#kernelState = result.kernelState;
|
|
88
99
|
if (result.ok) {
|
|
89
100
|
if (result.valueRepr) this.#output.pushValue(`${result.valueRepr}\n`);
|
|
90
101
|
this.#state.status = "complete";
|
|
@@ -160,9 +171,10 @@ export class CellResultBuilder {
|
|
|
160
171
|
? `(displayed ${output.images.length} image${output.images.length === 1 ? "" : "s"}; no text output)`
|
|
161
172
|
: "(no output)");
|
|
162
173
|
const text = output.meta === undefined ? shown : `${shown}\n${formatModelTruncationNotice(output.meta)}`;
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
174
|
+
const noticeParts = [this.#restartNotice, this.#memory?.notice].flatMap((notice) =>
|
|
175
|
+
notice === undefined ? [] : [{ type: "text" as const, text: notice }],
|
|
176
|
+
);
|
|
177
|
+
return { content: [{ type: "text", text }, ...noticeParts, ...output.images], details };
|
|
166
178
|
}
|
|
167
179
|
|
|
168
180
|
#details(output: EvalOutputResult | undefined, isError: boolean): EvalToolDetails {
|
|
@@ -202,6 +214,7 @@ export class CellResultBuilder {
|
|
|
202
214
|
...(output?.notice === undefined ? {} : { notice: output.notice }),
|
|
203
215
|
...(output?.meta === undefined ? {} : { meta: output.meta }),
|
|
204
216
|
...(output === undefined || this.#memory === undefined ? {} : { memory: memoryDetails(this.#memory) }),
|
|
217
|
+
...(this.#kernelState === undefined ? {} : { kernelState: this.#kernelState }),
|
|
205
218
|
};
|
|
206
219
|
}
|
|
207
220
|
|
|
@@ -2,7 +2,7 @@ import { mkdir, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import type { EvalDetachedCellNotification, EvalDetachedCellSnapshot } from "./detached-cell-manager.ts";
|
|
4
4
|
import { interruptionStateNote, unknownInterruptionStateNote } from "./interrupt-note.ts";
|
|
5
|
-
import type { EvalMemoryDetails } from "./types.ts";
|
|
5
|
+
import type { EvalKernelState, EvalMemoryDetails } from "./types.ts";
|
|
6
6
|
|
|
7
7
|
const NOTIFICATION_TAIL_BYTES = 512;
|
|
8
8
|
|
|
@@ -78,11 +78,22 @@ function outcomeOf(cell: EvalDetachedCellSnapshot): string {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
function stateNoteOf(cell: EvalDetachedCellSnapshot): string {
|
|
81
|
-
if (cell.state !== "cancelled")
|
|
81
|
+
if (cell.state !== "cancelled") {
|
|
82
|
+
const kernelState = cell.result.details?.kernelState;
|
|
83
|
+
return kernelState === undefined ? memoryStateNote(cell.result.details?.memory) : KERNEL_STATE_NOTES[kernelState];
|
|
84
|
+
}
|
|
82
85
|
const note = interruptionStateNote(cell.language, cell.stateRetained) ?? unknownInterruptionStateNote(cell.language);
|
|
83
86
|
return cell.interruptNote === undefined ? note : `${note} ${cell.interruptNote.trim()}`;
|
|
84
87
|
}
|
|
85
88
|
|
|
89
|
+
/** A kernel death decides what survived, whatever the memory report says. */
|
|
90
|
+
const KERNEL_STATE_NOTES: Readonly<Record<EvalKernelState, string>> = {
|
|
91
|
+
lost: "The kernel died while this cell ran - every global is lost; the next eval cell runs on a fresh kernel.",
|
|
92
|
+
restarted:
|
|
93
|
+
"The kernel was restarted before this cell ran - globals from earlier cells are gone; this cell's variables are available to the next eval cell.",
|
|
94
|
+
"not-run": "This cell never ran and changed no kernel state.",
|
|
95
|
+
};
|
|
96
|
+
|
|
86
97
|
export function memoryStateNote(memory: EvalMemoryDetails | undefined): string {
|
|
87
98
|
if (memory?.overCeiling === true)
|
|
88
99
|
return "Kernel memory is over its ceiling - the kernel restarts before the next eval cell and every global is lost.";
|
package/src/tool/types.ts
CHANGED
|
@@ -161,6 +161,12 @@ export interface KernelInterruptHandle {
|
|
|
161
161
|
readonly note?: string;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
/** An unstarted cell a dead kernel hands back, so its replacement runs it with the same input and callbacks. */
|
|
165
|
+
export interface PendingCell {
|
|
166
|
+
readonly input: EvalKernelRunInput;
|
|
167
|
+
readonly settle: (result: EvalKernelResult) => void;
|
|
168
|
+
}
|
|
169
|
+
|
|
164
170
|
export interface EvalKernel {
|
|
165
171
|
run(input: EvalKernelRunInput): Promise<EvalKernelResult>;
|
|
166
172
|
cancelQueued(cellId: string, reason: string): boolean;
|
|
@@ -171,6 +177,10 @@ export interface EvalKernel {
|
|
|
171
177
|
close(): Promise<void>;
|
|
172
178
|
/** Names this kernel has registered; JS collides with other languages in the same session. */
|
|
173
179
|
listKernelToolNames?(): readonly string[];
|
|
180
|
+
/** False once the interpreter died on its own; the session manager then replaces the instance. */
|
|
181
|
+
isAlive?(): boolean;
|
|
182
|
+
/** Hands over, and forgets, every queued cell of a dead kernel that never started. */
|
|
183
|
+
drainPending?(): readonly PendingCell[];
|
|
174
184
|
}
|
|
175
185
|
|
|
176
186
|
export interface EvalKernelManager {
|
|
@@ -273,6 +283,10 @@ export interface EvalToolDetails {
|
|
|
273
283
|
readonly meta?: TruncationMeta;
|
|
274
284
|
/** Kernel memory after the cell; its notice text is delivered as its own content part. */
|
|
275
285
|
readonly memory?: EvalMemoryDetails;
|
|
286
|
+
/** What a kernel death did to this cell's state, when one did. */
|
|
287
|
+
readonly kernelState?: EvalKernelState;
|
|
276
288
|
}
|
|
277
289
|
|
|
290
|
+
export type EvalKernelState = NonNullable<EvalKernelResult["kernelState"]>;
|
|
291
|
+
|
|
278
292
|
export type EvalMemoryDetails = Omit<KernelMemoryReport, "notice">;
|