ensureRunnerScript() memoized the staged runner path in a module-level
RUNNER_SCRIPT_PATH and returned it on the warm path with no existence
check, defeating the cold path's own self-heal. If the tmpdir cache
(os.tmpdir()/omp-<lang>-runner) was cleared mid-session (e.g. a macOS
periodic clean_tmps sweep), the process kept handing out a path to a
deleted file and every later Python/Julia/Ruby kernel start failed to
spawn until restart.
Extract the three copy-pasted ensureRunnerScript implementations into a
single stageRunnerScript helper that re-checks fs.existsSync before
reusing the memoized path, so a swept runner is re-staged on the next
call. Route the Python, Julia, and Ruby kernels through it.
Fixes#8140
- Python, Ruby and Julia each carried their own copy of the same session
maps, acquire/reset/replace/dispose lifecycle and executeOnSession; one
generic registry now owns it, parameterized by a per-language descriptor.
- Julia additionally re-implemented seven executor-base helpers locally; those
copies are gone and executor-base gained sparse managed-env and timeout
resolver hooks so Julia's differing behavior survives unchanged.
- All twelve exported entry points keep their names and signatures.
Python/Ruby raise on the removed keyword via their keyword-only
signatures; the Julia helper's kwargs... catch-all silently swallowed
agent("..."; model="default") and forwarded it to the bridge, where
the "+": "delete" strip discarded it. A caller could keep thinking a
model override was honored. Reject model loudly, matching the strict
removal decision on #7621.
Completes the maintainer's removal of per-call model selection from
subagent spawns (9f8aa87dbf removed it from the task tool and the
model-facing agent() docs/prompt, but the eval agent() runtime and all
four preludes still accepted and forwarded a per-call model).
Subagents now always resolve through the selected agent's frontmatter
model and settings, so an explicit model: "default" can no longer
silently route children onto the parent session model.
- agent-bridge: drops "model?" from agentArgsSchema and the request
forward; adds "+": "delete" so a legacy model argument is stripped
(same contract as the task wire schemas).
- JS/Python/Ruby/Julia preludes: remove the model parameter from
agent(); completion()'s tier selector is unchanged.
- docs (tools/eval.md, python-repl.md) updated to the removed surface.
Refs #6438
- Introduce `@oh-my-pi/omptype` as a new ArkType-compatible schema validation package featuring a lazy JIT runtime, JSON Schema emission, and compatibility adapters.
- Replace `arktype` across workspace packages and test utilities with `@oh-my-pi/omptype`.
- Add benchmark suites, tests, and documentation for the new validation engine and adapters.
- Update workspace build, test runner, and release configurations to include the new package.
- Split the Python bridge signal: the raw abort reaches tools (so
subagents die with the turn) while a shielded signal governs how long
the host waits, so a cancel can no longer settle a cell on top of a
still-running isolation merge.
- Mirrored the contract in the JS runtime: abort in-flight tool calls
immediately, then drain any deferExternalAbort phase before killing
the worker, and refuse new bridge calls once cancelled.
- Held a finished worker result until the run's tool calls drain. A
floated agent() previously settled the cell at once, dropping the
run's abort listener and leaving the subagent running with nothing
able to cancel it.
- Added regression coverage for all three, each verified to fail
without its fix.
Combined native HWND and stdio TTY evidence so compiled Windows Terminal launches no longer set CREATE_NO_WINDOW for the Python eval kernel.
Fixes#7343
- resolveOwnerScopedSessionKey's getOwners in the Python and JS executors
only read live sessions, so a subagent reset issued while the shared
kernel was still starting resolved to the base key, awaited the
parent's startup, and shut its brand-new kernel down.
- Python and JS starting sessions are now owner-bearing records like
Ruby/Julia's: owners attach synchronously before startup resolves,
getOwners and per-owner disposal consult them, and the final
sessions.set is identity-guarded so a disposed starting record cannot
resurrect its kernel.
- Regression: deferred PythonKernel.start proves a concurrent subagent
reset forks immediately and never reaps the parent's starting kernel
(fails with the previous getOwners).
- Subagents inherit the parent's eval session id, so a child's
reset: true destroyed the co-owned kernel and every sibling's
interpreter state mid-session.
- resolveOwnerScopedSessionKey now routes a reset from a non-exclusive
owner onto a deterministic per-owner fork key: the requester gets a
fresh private kernel, co-owners keep the shared one, and the fork
stays sticky for that owner until its teardown reaps it.
- Applied across Python, JavaScript, Ruby, and Julia executors; JS
contexts gained an owner registry plus disposeVmContextsByOwner,
wired into EvalRunner.disposeKernels and SDK session teardown.
- Covered by pure key-resolution contracts and an end-to-end JS test:
co-owner reset forks, shared state survives, fork is sticky, and
per-owner dispose reaps only the fork.
- Configure the python eval prelude to use a custom urllib opener that ignores environment proxies.
- Add test coverage verifying parallel tool bridge calls succeed when proxy variables are set.
- Filter out runner-internal frames from runtime exception tracebacks to start at user code.
- Omit full tracebacks for cell syntax errors to render only the caret display with `<cell>` filename.
OutputSink.dump() was the only path that closed the spill Bun.FileSink.
The bash and Python executors re-throw on failure and their finally
blocks never closed the sink, so any large-output command that errored
leaked the artifact descriptor until an unrelated read (e.g. a SKILL.md
load) hit EMFILE.
Added an idempotent OutputSink.dispose() that closes the sink exactly
once (awaiting any in-flight sink creation, guarding post-finalize
resurrection) and wired it into every executor's finally block.
Fixes#6463
Tracked retained Python kernel generations and shared one replacement promise per dead generation. Reset and disposal now invalidate and drain replacement work before allowing a new session to take ownership.
Added deterministic fake-kernel coverage for concurrent callers, cancellation, reset, owner/global disposal, and independent cwd keys.
Fixes#6367
Add an optional `apply` parameter to the `task` tool so
`isolated: true, apply: false` captures patch/branch artifacts without
applying changes to the parent checkout. Available as a flat top-level
control and per `tasks[]` item. Shares the task/eval isolation-to-executor
translation via a single `toStructuredSubagentIsolationControls` adapter.
- Preserved goal-mode tool injection for ordinary explicit tool lists.
- Kept plan-mode LSP and IRC unavailable under the host capability clamp.
- Added regressions for both capability boundaries.
- Added per-invocation task schemas with strict and permissive validation.
- Shared task and eval agent policy, artifacts, isolation, and lifecycle handling.
- Enabled host-restricted plan-mode eval agents and persisted their capability clamp.
Fixes#5279
- Removed `selector`/`sel` arguments from read and grep tool schemas and related execution arg handling.
- Reworked read and grep path processing to parse line selectors from `path` suffixes instead of separate fields, including inline range propagation.
- Updated delegation and execution call paths (including JS/Python preludes and executor tests) to pass selectors embedded in `path`.
- Updated read/grep prompt docs and changelog for the breaking inline-selector API, and removed obsolete selector-specific tests and expectations.
- Kept opaque MCP resource paths unchanged during JS pagination.
- Sent JS line ranges through the read tool selector field.
- Covered the shipped JS prelude and updated the changelog.
Fixes#5353
- Kept opaque MCP resource paths unchanged during pagination.
- Sent line ranges through the read tool selector field.
- Covered paged artifact and MCP reads in the Python prelude test.
Fixes#5353
- Routed non-local URI reads through the session read tool.
- Preserved offset and limit as host line selectors.
- Covered artifact delegation with the shipped Python prelude.
Fixes#5353
- Disabled the eval watchdog when timeout is explicitly zero.
- Classified session deadline aborts as TimeoutError while preserving their message.
- Documented and tested both timeout contracts.
Fixes#5250
- Replaced legacy `pi/` role alias prefix with canonical `@` syntax across model resolution, documentation, and tests.
- Added support for bare `*` default alias and multiple alias prefix detection with custom role resolution in `resolveConfiguredRolePattern()`.
- Enhanced thinking suffix parsing to accept unambiguous abbreviations (minimum 2 characters) for effort and level selectors.
- Extended `resolveCliModel()` and `filterAvailableModelsByEnabledPatterns()` to accept settings parameter for role alias resolution from `--model` flag.