Summary
The eval tool admits at most ONE detached cell per language. A second cell for a busy language is rejected with detachedKernelBusyError ("The js eval kernel is busy running detached cell ..."), so the model has to wait or switch languages. oh-my-pi runs eval cells as jobs (default cap 15) and lets cells for one language queue on that language's kernel.
Expected (ideal state)
- A cell submitted while its language kernel is busy is ADMITTED as
queued on that kernel's existing run queue and runs after the active cell; state is still shared per language and execution inside a kernel stays serial.
- Background capacity is a single session-wide setting
maxDetachedCells (default 15). At the cap a cell keeps running in the foreground until its foreground window elapses and is then cancelled with a typed eval_background_capacity_reached error naming the live cells; a short cell is never rejected.
stop on a queued cell dequeues it without interrupting the kernel; interrupt is cell-targeted so cancelling one cell never stops another cell's run; kernel messages (text/display/tool-call/pause) are routed to the cell that produced them.
reset: true while the language has other live cells is refused with eval_kernel_busy_reset_refused listing them.
- New
eval({ action: "list" }) reports live and recently settled cells (id, language, state, elapsed, queued-behind).
- Queued cells do not consume their run budget while waiting.
Actual
packages/senpi-codemode/src/tool/detached-cell-manager.ts:36 keeps #detachedByLanguage: Map<EvalLanguage, ManagedCell>; detach() (L99-108) refuses when the language slot is taken; eval-tool.ts:76-82 throws the busy error before running.
kernels/js/context-manager.ts:94-107: interrupt(reason) acts on the active run; with no active run it takes the first QUEUED run and restarts the worker.
kernels/py/kernel.ts:59-63: interrupt settles EVERY queued run. rb/jl (kernels/shared/subprocess-kernel.ts:52-71) retire the interpreter.
- One
onMessage per language is rebound on each getKernel call, so a second cell's callback would receive the first cell's output.
(line numbers at main cd317ee647)
Scope / acceptance
- Cell-targeted queue control on every kernel (
cancelQueued, interrupt(reason, cellId), per-run onStarted/onMessage, queueSnapshot).
- Capped detached set +
queued state in the cell manager; tool-boundary admission; list action; reset refusal; maxDetachedCells setting + env override; prompt/footer/docs text updated; existing cap tests rewritten to the new contract (none deleted).
- Deterministic real-kernel QA script proving queued admission, list, stop, reset refusal and exactly-once notifications.
Related
Summary
The
evaltool admits at most ONE detached cell per language. A second cell for a busy language is rejected withdetachedKernelBusyError("The js eval kernel is busy running detached cell ..."), so the model has to wait or switch languages. oh-my-pi runs eval cells as jobs (default cap 15) and lets cells for one language queue on that language's kernel.Expected (ideal state)
queuedon that kernel's existing run queue and runs after the active cell; state is still shared per language and execution inside a kernel stays serial.maxDetachedCells(default 15). At the cap a cell keeps running in the foreground until its foreground window elapses and is then cancelled with a typedeval_background_capacity_reachederror naming the live cells; a short cell is never rejected.stopon a queued cell dequeues it without interrupting the kernel;interruptis cell-targeted so cancelling one cell never stops another cell's run; kernel messages (text/display/tool-call/pause) are routed to the cell that produced them.reset: truewhile the language has other live cells is refused witheval_kernel_busy_reset_refusedlisting them.eval({ action: "list" })reports live and recently settled cells (id, language, state, elapsed, queued-behind).Actual
packages/senpi-codemode/src/tool/detached-cell-manager.ts:36keeps#detachedByLanguage: Map<EvalLanguage, ManagedCell>;detach()(L99-108) refuses when the language slot is taken;eval-tool.ts:76-82throws the busy error before running.kernels/js/context-manager.ts:94-107:interrupt(reason)acts on the active run; with no active run it takes the first QUEUED run and restarts the worker.kernels/py/kernel.ts:59-63: interrupt settles EVERY queued run. rb/jl (kernels/shared/subprocess-kernel.ts:52-71) retire the interpreter.onMessageper language is rebound on eachgetKernelcall, so a second cell's callback would receive the first cell's output.(line numbers at main
cd317ee647)Scope / acceptance
cancelQueued,interrupt(reason, cellId), per-runonStarted/onMessage,queueSnapshot).queuedstate in the cell manager; tool-boundary admission;listaction; reset refusal;maxDetachedCellssetting + env override; prompt/footer/docs text updated; existing cap tests rewritten to the new contract (none deleted).Related