@code-yeongyu/senpi-codemode 2026.8.12-4 → 2026.8.13
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 +14 -0
- package/package.json +4 -4
- package/src/config/settings.ts +23 -0
- package/src/index.ts +3 -1
- package/src/prompt/eval-prompt.ts +1 -0
- package/src/tool/detached-cell-manager.ts +63 -1
- package/src/tool/detached-cell-notification.ts +1 -0
- package/src/tool/detached-cell-snapshot.ts +5 -0
- package/src/tool/eval-tool-options.ts +2 -0
- package/src/tool/eval-tool.ts +12 -2
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,20 @@
|
|
|
12
12
|
|
|
13
13
|
### Removed
|
|
14
14
|
|
|
15
|
+
## [2026.8.13] - 2026-08-13
|
|
16
|
+
|
|
17
|
+
### Breaking Changes
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Gave every eval cell a wall-clock hard limit (`hardLimitSeconds`, default 1800s, overridable with `SENPI_CODEMODE_HARD_LIMIT_SECONDS`) so a detached or tool-call-heavy cell can no longer run unbounded: the deadline survives `detach()` and is never paused by bridge tool calls, and a cell it kills reports itself to the agent as killed at the hard limit ([#857](https://github.com/code-yeongyu/senpi/pull/857)).
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
### Removed
|
|
28
|
+
|
|
15
29
|
## [2026.8.12-4] - 2026-08-12
|
|
16
30
|
|
|
17
31
|
### Breaking Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/senpi-codemode",
|
|
3
|
-
"version": "2026.8.
|
|
3
|
+
"version": "2026.8.13",
|
|
4
4
|
"description": "Source-only senpi extension package for codemode evaluation tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -30,14 +30,14 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@babel/parser": "8.0.4",
|
|
33
|
-
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.8.
|
|
33
|
+
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.8.13",
|
|
34
34
|
"typebox": "1.3.8"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@code-yeongyu/senpi": "2026.8.
|
|
37
|
+
"@code-yeongyu/senpi": "2026.8.13"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@code-yeongyu/senpi": "2026.8.
|
|
40
|
+
"@code-yeongyu/senpi": "2026.8.13"
|
|
41
41
|
},
|
|
42
42
|
"keywords": [
|
|
43
43
|
"senpi",
|
package/src/config/settings.ts
CHANGED
|
@@ -19,6 +19,7 @@ export const codemodeSettingsSchema = Type.Object(
|
|
|
19
19
|
),
|
|
20
20
|
),
|
|
21
21
|
cellTimeoutSeconds: Type.Optional(Type.Number({ minimum: 1 })),
|
|
22
|
+
hardLimitSeconds: Type.Optional(Type.Number({ minimum: 1 })),
|
|
22
23
|
parallelPoolWidth: Type.Optional(Type.Number({ minimum: 1 })),
|
|
23
24
|
taskTools: Type.Optional(
|
|
24
25
|
Type.Object(
|
|
@@ -63,6 +64,8 @@ export interface CodemodeSettings {
|
|
|
63
64
|
readonly jl: boolean;
|
|
64
65
|
};
|
|
65
66
|
readonly cellTimeoutSeconds: number;
|
|
67
|
+
/** Wall-clock kill deadline for a single cell; bounds detached cells too. */
|
|
68
|
+
readonly hardLimitSeconds: number;
|
|
66
69
|
readonly parallelPoolWidth: number;
|
|
67
70
|
readonly taskTools?: CodemodeTaskTools;
|
|
68
71
|
readonly outputSink?: CodemodeOutputSink;
|
|
@@ -86,6 +89,15 @@ export interface LoadedCodemodeSettings {
|
|
|
86
89
|
readonly warnings: readonly string[];
|
|
87
90
|
}
|
|
88
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Bash parity: `bash-timeout/timeout.ts` kills a command at 1800s. An eval cell gets the same
|
|
94
|
+
* unconditional wall-clock kill deadline, which — unlike `cellTimeoutSeconds` — is neither paused by
|
|
95
|
+
* host tool calls nor discarded when the cell detaches.
|
|
96
|
+
*/
|
|
97
|
+
export const DEFAULT_HARD_LIMIT_SECONDS = 1800;
|
|
98
|
+
|
|
99
|
+
export const HARD_LIMIT_ENVIRONMENT_FLAG = "SENPI_CODEMODE_HARD_LIMIT_SECONDS";
|
|
100
|
+
|
|
89
101
|
// OMP settings-schema.ts:3211-3299 has language/path settings only; eval.ts:427
|
|
90
102
|
// defaults timeout to 30s, and codemode pins concurrency-bridge.ts:30 width to 4.
|
|
91
103
|
export const defaultCodemodeSettings: ResolvedCodemodeSettings = {
|
|
@@ -96,6 +108,7 @@ export const defaultCodemodeSettings: ResolvedCodemodeSettings = {
|
|
|
96
108
|
jl: false,
|
|
97
109
|
},
|
|
98
110
|
cellTimeoutSeconds: 30,
|
|
111
|
+
hardLimitSeconds: DEFAULT_HARD_LIMIT_SECONDS,
|
|
99
112
|
parallelPoolWidth: 4,
|
|
100
113
|
taskTools: {
|
|
101
114
|
task: "task",
|
|
@@ -144,6 +157,15 @@ export function resolveEnabledLanguages(
|
|
|
144
157
|
};
|
|
145
158
|
}
|
|
146
159
|
|
|
160
|
+
/** Environment override wins over the settings file; a non-positive or malformed value is ignored. */
|
|
161
|
+
export function resolveHardLimitSeconds(settings: CodemodeSettings, env: Environment = process.env): number {
|
|
162
|
+
const override = env[HARD_LIMIT_ENVIRONMENT_FLAG];
|
|
163
|
+
if (override === undefined) return settings.hardLimitSeconds;
|
|
164
|
+
const parsed = Number.parseInt(override, 10);
|
|
165
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return settings.hardLimitSeconds;
|
|
166
|
+
return parsed;
|
|
167
|
+
}
|
|
168
|
+
|
|
147
169
|
async function loadSettingsFile(path: string): Promise<LoadedCodemodeSettings> {
|
|
148
170
|
const raw = await readFile(path, "utf8");
|
|
149
171
|
let parsed: unknown;
|
|
@@ -178,6 +200,7 @@ function mergeSettings(input: CodemodeSettingsInput): ResolvedCodemodeSettings {
|
|
|
178
200
|
jl: input.languages?.jl ?? defaultCodemodeSettings.languages.jl,
|
|
179
201
|
},
|
|
180
202
|
cellTimeoutSeconds: input.cellTimeoutSeconds ?? defaultCodemodeSettings.cellTimeoutSeconds,
|
|
203
|
+
hardLimitSeconds: input.hardLimitSeconds ?? defaultCodemodeSettings.hardLimitSeconds,
|
|
181
204
|
parallelPoolWidth: input.parallelPoolWidth ?? defaultCodemodeSettings.parallelPoolWidth,
|
|
182
205
|
taskTools: {
|
|
183
206
|
task: input.taskTools?.task ?? defaultCodemodeSettings.taskTools.task,
|
package/src/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { ExtensionContext } from "@code-yeongyu/senpi";
|
|
|
3
3
|
import type { AgentExecuteTool } from "./bridges/agent-bridge.ts";
|
|
4
4
|
import type { EvalSchemaToolInfo } from "./bridges/schema-bridge.ts";
|
|
5
5
|
import { type CompletionRequest, type CompletionResult, createCompletionHandler } from "./completion/handler.ts";
|
|
6
|
-
import { defaultCodemodeSettings } from "./config/settings.ts";
|
|
6
|
+
import { defaultCodemodeSettings, resolveHardLimitSeconds } from "./config/settings.ts";
|
|
7
7
|
import { EvalNotifier } from "./extension/eval-notifier.ts";
|
|
8
8
|
import { EVAL_CELLS_STATUS_KEY } from "./extension/eval-status.ts";
|
|
9
9
|
import { EvalStatusTicker } from "./extension/eval-status-ticker.ts";
|
|
@@ -131,6 +131,7 @@ export default function senpiCodemode(pi: CodemodeExtensionAPI, options: SenpiCo
|
|
|
131
131
|
settings: defaultCodemodeSettings,
|
|
132
132
|
cellManager: new EvalDetachedCellManager({
|
|
133
133
|
notifier,
|
|
134
|
+
hardLimitSeconds: resolveHardLimitSeconds(defaultCodemodeSettings),
|
|
134
135
|
onStatusChange: showDetachedCells,
|
|
135
136
|
onWakeSourceState: emitWakeSourceState,
|
|
136
137
|
...(options.now === undefined ? {} : { now: options.now }),
|
|
@@ -162,6 +163,7 @@ export default function senpiCodemode(pi: CodemodeExtensionAPI, options: SenpiCo
|
|
|
162
163
|
const cellManager = new EvalDetachedCellManager({
|
|
163
164
|
artifactsDir: runtime.artifactsDir,
|
|
164
165
|
notifier,
|
|
166
|
+
hardLimitSeconds: resolveHardLimitSeconds(runtime.settings),
|
|
165
167
|
onStatusChange: showDetachedCells,
|
|
166
168
|
onWakeSourceState: emitWakeSourceState,
|
|
167
169
|
...(options.now === undefined ? {} : { now: options.now }),
|
|
@@ -125,6 +125,7 @@ Fields:
|
|
|
125
125
|
- \`summary\` (REQUIRED for run) — ONE line in the USER'S conversational language stating WHAT this cell does and FOR WHAT PURPOSE (e.g. Korean conversation -> "src 전체에서 legacyClient 사용처 집계"); shown in the TUI while the cell runs; >80 chars is force-truncated.
|
|
126
126
|
- \`timeout\` (optional) — seconds. Raise only for heavy compute or long{{#if spawns}} non-agent{{/if}} tool calls.
|
|
127
127
|
- \`on_timeout\` (optional) — \`"detach"\` keeps pure computation running in interactive sessions (the default); \`"error"\` interrupts for deadline-sensitive work and is the print/json default.
|
|
128
|
+
- Every cell is killed at a wall-clock hard limit (default 1800s) that survives detach and is never paused by tool calls; a larger explicit \`timeout\` raises it, and a killed cell notifies you that it hit the limit.
|
|
128
129
|
- \`reset\` (optional) — wipe this language's kernel first.{{#ifAll py js}} Per-language: a \`py\` reset never touches the JS VM.{{/ifAll}}
|
|
129
130
|
- \`action\` (optional) — defaults to \`"run"\`. A detached cell returns its id: use \`eval({ action: "peek", cell_id })\` for buffered output/state or \`eval({ action: "stop", cell_id })\` to cancel it.
|
|
130
131
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AgentToolResult } from "@code-yeongyu/senpi";
|
|
2
|
+
import { DEFAULT_HARD_LIMIT_SECONDS } from "../config/settings.ts";
|
|
2
3
|
import { SENPI_CODEMODE_WAKE_SOURCE, type WakeSourceState } from "../extension/wake-source-state.ts";
|
|
3
4
|
import { detachedNotificationSpillPath } from "./detached-cell-notification.ts";
|
|
4
5
|
import { currentDetachedResult, detachedErrorResult, snapshotDetachedCell } from "./detached-cell-snapshot.ts";
|
|
@@ -28,6 +29,10 @@ type ManagedCell = {
|
|
|
28
29
|
liveResult: LiveResultProvider | undefined;
|
|
29
30
|
terminalResult: AgentToolResult<EvalToolDetails> | undefined;
|
|
30
31
|
notificationQueued: boolean;
|
|
32
|
+
hardLimitSeconds: number;
|
|
33
|
+
hardLimitTimer: ReturnType<typeof setTimeout> | undefined;
|
|
34
|
+
hardLimited: boolean;
|
|
35
|
+
onHardLimit: ((error: Error) => void) | undefined;
|
|
31
36
|
};
|
|
32
37
|
|
|
33
38
|
export interface EvalDetachedCellSnapshot {
|
|
@@ -37,6 +42,8 @@ export interface EvalDetachedCellSnapshot {
|
|
|
37
42
|
readonly outputTail: string;
|
|
38
43
|
readonly result: AgentToolResult<EvalToolDetails>;
|
|
39
44
|
readonly stateRetained: boolean | undefined;
|
|
45
|
+
/** Set only when the wall-clock kill deadline ended this cell. */
|
|
46
|
+
readonly hardLimitSeconds?: number;
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
export interface EvalDetachedCellNotification {
|
|
@@ -58,12 +65,20 @@ export interface EvalDetachedCellStatusEntry {
|
|
|
58
65
|
export interface EvalDetachedCellManagerOptions {
|
|
59
66
|
readonly artifactsDir?: string;
|
|
60
67
|
readonly notifier?: EvalDetachedCellNotifier;
|
|
68
|
+
/** Wall-clock kill deadline in seconds; defaults to the bash-parity 1800s. */
|
|
69
|
+
readonly hardLimitSeconds?: number;
|
|
61
70
|
readonly onStatusChange?: (entries: readonly EvalDetachedCellStatusEntry[]) => void;
|
|
62
71
|
/** Receives a full per-source liveness snapshot on every detached-cell transition; used by the goal builtin. */
|
|
63
72
|
readonly onWakeSourceState?: (state: WakeSourceState) => void;
|
|
64
73
|
readonly now?: () => number;
|
|
65
74
|
}
|
|
66
75
|
|
|
76
|
+
export function hardLimitError(cellId: string, hardLimitSeconds: number): Error {
|
|
77
|
+
const error = new Error(`Eval cell ${cellId} was killed at the ${hardLimitSeconds}s hard limit.`);
|
|
78
|
+
error.name = "TimeoutError";
|
|
79
|
+
return error;
|
|
80
|
+
}
|
|
81
|
+
|
|
67
82
|
export class EvalDetachedCellManager {
|
|
68
83
|
readonly #artifactsDir: string | undefined;
|
|
69
84
|
readonly #onStatusChange: ((entries: readonly EvalDetachedCellStatusEntry[]) => void) | undefined;
|
|
@@ -72,6 +87,7 @@ export class EvalDetachedCellManager {
|
|
|
72
87
|
readonly #detachedByLanguage = new Map<EvalLanguage, ManagedCell>();
|
|
73
88
|
readonly #notificationQueue: DetachedNotificationQueue;
|
|
74
89
|
readonly #now: () => number;
|
|
90
|
+
readonly #hardLimitSeconds: number;
|
|
75
91
|
|
|
76
92
|
constructor(options: EvalDetachedCellManagerOptions = {}) {
|
|
77
93
|
this.#artifactsDir = options.artifactsDir;
|
|
@@ -79,6 +95,7 @@ export class EvalDetachedCellManager {
|
|
|
79
95
|
this.#onWakeSourceState = options.onWakeSourceState;
|
|
80
96
|
this.#notificationQueue = new DetachedNotificationQueue(options.notifier, options.artifactsDir);
|
|
81
97
|
this.#now = options.now ?? Date.now;
|
|
98
|
+
this.#hardLimitSeconds = options.hardLimitSeconds ?? DEFAULT_HARD_LIMIT_SECONDS;
|
|
82
99
|
}
|
|
83
100
|
|
|
84
101
|
create(cellId: string, input: EvalToolInput): ManagedCell {
|
|
@@ -100,14 +117,27 @@ export class EvalDetachedCellManager {
|
|
|
100
117
|
liveResult: undefined,
|
|
101
118
|
terminalResult: undefined,
|
|
102
119
|
notificationQueued: false,
|
|
120
|
+
// An explicit longer per-call timeout raises the deadline, mirroring bash keeping explicit timeouts.
|
|
121
|
+
hardLimitSeconds: Math.max(this.#hardLimitSeconds, input.timeout ?? 0),
|
|
122
|
+
hardLimitTimer: undefined,
|
|
123
|
+
hardLimited: false,
|
|
124
|
+
onHardLimit: undefined,
|
|
103
125
|
terminal: Promise.withResolvers<EvalDetachedCellSnapshot>(),
|
|
104
126
|
};
|
|
105
127
|
this.#cells.set(cellId, cell);
|
|
128
|
+
this.#armHardLimit(cell);
|
|
106
129
|
return cell;
|
|
107
130
|
}
|
|
108
131
|
|
|
109
|
-
markRunning(
|
|
132
|
+
markRunning(
|
|
133
|
+
cell: ManagedCell,
|
|
134
|
+
kernel: EvalKernel,
|
|
135
|
+
liveResult: LiveResultProvider,
|
|
136
|
+
/** Foreground killer: the still-awaited CellExecution owns interrupting and rejecting its own call. */
|
|
137
|
+
onHardLimit?: (error: Error) => void,
|
|
138
|
+
): void {
|
|
110
139
|
if (cell.state !== "running") return;
|
|
140
|
+
cell.onHardLimit = onHardLimit;
|
|
111
141
|
cell.kernel = kernel;
|
|
112
142
|
cell.liveResult = liveResult;
|
|
113
143
|
cell.canDetach = true;
|
|
@@ -179,6 +209,7 @@ export class EvalDetachedCellManager {
|
|
|
179
209
|
result: AgentToolResult<EvalToolDetails>,
|
|
180
210
|
): boolean {
|
|
181
211
|
if (!allowsDetachedCellTransition(cell.state, state)) return false;
|
|
212
|
+
this.#clearHardLimit(cell);
|
|
182
213
|
cell.state = state;
|
|
183
214
|
cell.terminalResult = result;
|
|
184
215
|
cell.liveResult = undefined;
|
|
@@ -198,6 +229,37 @@ export class EvalDetachedCellManager {
|
|
|
198
229
|
return true;
|
|
199
230
|
}
|
|
200
231
|
|
|
232
|
+
#armHardLimit(cell: ManagedCell): void {
|
|
233
|
+
const timer = setTimeout(() => void this.#expireHardLimit(cell), cell.hardLimitSeconds * 1_000);
|
|
234
|
+
timer.unref?.();
|
|
235
|
+
cell.hardLimitTimer = timer;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
#clearHardLimit(cell: ManagedCell): void {
|
|
239
|
+
if (cell.hardLimitTimer === undefined) return;
|
|
240
|
+
clearTimeout(cell.hardLimitTimer);
|
|
241
|
+
cell.hardLimitTimer = undefined;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* The wall-clock kill deadline. Unlike the idle watchdog it is never paused by a bridge tool call and
|
|
246
|
+
* survives detach, so it is the only bound a detached cell has.
|
|
247
|
+
*/
|
|
248
|
+
async #expireHardLimit(cell: ManagedCell): Promise<void> {
|
|
249
|
+
if (!detachedCellIsActive(cell.state)) return;
|
|
250
|
+
const foreground = cell.state === "running" && cell.onHardLimit !== undefined;
|
|
251
|
+
cell.hardLimited = true;
|
|
252
|
+
const error = hardLimitError(cell.cellId, cell.hardLimitSeconds);
|
|
253
|
+
if (!this.#settle(cell, "cancelled", currentDetachedResult(cell))) return;
|
|
254
|
+
if (foreground) {
|
|
255
|
+
cell.onHardLimit?.(error);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if (cell.kernel === undefined) return;
|
|
259
|
+
const handle = await cell.kernel.interrupt(error.message);
|
|
260
|
+
cell.stateRetained = await handle.stateRetained;
|
|
261
|
+
}
|
|
262
|
+
|
|
201
263
|
#emitStatus(): void {
|
|
202
264
|
const liveCells = [...this.#detachedByLanguage.values()];
|
|
203
265
|
this.#onStatusChange?.(
|
|
@@ -66,6 +66,7 @@ function textContent(cell: EvalDetachedCellSnapshot): string {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
function outcomeOf(cell: EvalDetachedCellSnapshot): string {
|
|
69
|
+
if (cell.hardLimitSeconds !== undefined) return `was killed at the ${cell.hardLimitSeconds}s hard limit`;
|
|
69
70
|
if (cell.state === "completed") return "completed";
|
|
70
71
|
if (cell.state === "cancelled") return "cancelled";
|
|
71
72
|
return "failed";
|
|
@@ -12,6 +12,8 @@ export interface DetachedCellResultSource {
|
|
|
12
12
|
stateRetained: boolean | undefined;
|
|
13
13
|
liveResult: (() => AgentToolResult<EvalToolDetails>) | undefined;
|
|
14
14
|
terminalResult: AgentToolResult<EvalToolDetails> | undefined;
|
|
15
|
+
hardLimited?: boolean;
|
|
16
|
+
hardLimitSeconds?: number;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
export function snapshotDetachedCell(cell: DetachedCellResultSource, nowMs: number): EvalDetachedCellSnapshot {
|
|
@@ -24,6 +26,9 @@ export function snapshotDetachedCell(cell: DetachedCellResultSource, nowMs: numb
|
|
|
24
26
|
outputTail: detachedOutputTail(result),
|
|
25
27
|
result,
|
|
26
28
|
stateRetained: cell.stateRetained,
|
|
29
|
+
...(cell.hardLimited === true && cell.hardLimitSeconds !== undefined
|
|
30
|
+
? { hardLimitSeconds: cell.hardLimitSeconds }
|
|
31
|
+
: {}),
|
|
27
32
|
};
|
|
28
33
|
}
|
|
29
34
|
|
|
@@ -19,6 +19,8 @@ export interface CreateEvalToolOptions {
|
|
|
19
19
|
readonly enabledLanguages: EnabledEvalLanguages;
|
|
20
20
|
readonly kernelManager: EvalKernelManager;
|
|
21
21
|
readonly cellTimeoutSeconds: number;
|
|
22
|
+
/** Wall-clock kill deadline applied to every cell; only used when this factory creates its own manager. */
|
|
23
|
+
readonly hardLimitSeconds?: number;
|
|
22
24
|
readonly executeTool: ExecuteTool;
|
|
23
25
|
readonly listTools?: () => readonly EvalSchemaToolInfo[];
|
|
24
26
|
readonly complete?: (request: CompletionRequest, ctx: ExtensionContext) => Promise<CompletionResult>;
|
package/src/tool/eval-tool.ts
CHANGED
|
@@ -32,7 +32,12 @@ export function createEvalTool(options: CreateEvalToolOptions): ToolDefinition<E
|
|
|
32
32
|
...(options.hostLine === undefined ? {} : { hostLine: options.hostLine }),
|
|
33
33
|
});
|
|
34
34
|
const languages = enabledLanguageList(options.enabledLanguages);
|
|
35
|
-
const cellManager =
|
|
35
|
+
const cellManager =
|
|
36
|
+
options.cellManager ??
|
|
37
|
+
new EvalDetachedCellManager({
|
|
38
|
+
...(options.artifactsDir === undefined ? {} : { artifactsDir: options.artifactsDir }),
|
|
39
|
+
...(options.hardLimitSeconds === undefined ? {} : { hardLimitSeconds: options.hardLimitSeconds }),
|
|
40
|
+
});
|
|
36
41
|
return {
|
|
37
42
|
name: "eval",
|
|
38
43
|
label: "Eval",
|
|
@@ -194,7 +199,12 @@ async function executeCell(
|
|
|
194
199
|
...(options.imageResizer === undefined ? {} : { imageResizer: options.imageResizer }),
|
|
195
200
|
});
|
|
196
201
|
handler = activeHandler;
|
|
197
|
-
cellManager.markRunning(
|
|
202
|
+
cellManager.markRunning(
|
|
203
|
+
cell,
|
|
204
|
+
kernel,
|
|
205
|
+
() => activeHandler.liveResult(),
|
|
206
|
+
(error) => execution.cancel(error),
|
|
207
|
+
);
|
|
198
208
|
if ("setContext" in options.kernelManager && typeof options.kernelManager.setContext === "function") {
|
|
199
209
|
options.kernelManager.setContext(bridgeContext);
|
|
200
210
|
}
|