Skip to content

fix(coding-agent): persist kernel stderr to disk and bound the in-memory tail - #1947

Open
snimu wants to merge 2 commits into
mainfrom
fix/kernel-stderr-log
Open

fix(coding-agent): persist kernel stderr to disk and bound the in-memory tail#1947
snimu wants to merge 2 commits into
mainfrom
fix/kernel-stderr-log

Conversation

@snimu

@snimu snimu commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

When a Python kernel failed to start, the failure was often undiagnosable: its stderr lived only in an in-memory string that died with the process, and the startup error showed just the last kilobyte of it. Nothing stayed on disk to inspect after the fact — and on the other end, a long-lived chatty kernel grew that same string without bound for its whole lifetime, even though every reader only ever showed the tail.

The fix is spawn-shaped because the kernel's stderr is startup-shaped: the runtime dup2's fd 2 into its protocol pipe before it reports ready (repl.py _setup_fds), so the process-level stderr only ever carries pre-ready bytes — interpreter, venv, and import failures; everything after ready already flows through the protocol into the bounded per-execution stderr. So at spawn the manager now opens kernel-stderr.log in the session's artifact directory, rotates it to .old when it exceeds 5 MiB (once per spawn — pre-ready output is startup-bounded), and hands the fd straight to the child as its stderr slot. The OS writes the bytes: no host-side relay, decoding, buffering, or flush to get wrong, and the file is complete the moment the process exits.

Startup failure messages read their 1 KiB tail from that file, plus any host-side [kernel] diagnostics from the in-memory string, now bounded to an 8 KiB tail. Sessions without an artifact directory (or whose log open fails) fall back to the previous pipe-plus-memory-tail behavior. The log persists across kernel restarts within the rotation cap.

Validation: two pins — a kernel that writes CR progress output and a split multi-byte character with no trailing newline before dying produces a log byte-identical to what it wrote, with that tail in the startup error; and a log pre-filled past 5 MiB rotates to .old at the next spawn, with the new incarnation's stderr starting a fresh file. repl-kernel test suites and root npm run check green.

Linear: RES-1246 https://linear.app/primeintellect/issue/RES-1246/persist-python-kernel-stderr-to-disk-and-bound-the-in-memory-buffer

Comment thread packages/coding-agent/src/core/kernel/repl-manager.ts Outdated
Comment thread packages/coding-agent/src/core/tools/ipython.ts
Comment thread packages/coding-agent/src/core/kernel/repl-manager.ts Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 3f8023f. Configure here.

Comment thread packages/coding-agent/src/core/kernel/repl-manager.ts
@snimu
snimu requested a review from xeophon September 1, 2026 13:14
xeophon
xeophon previously approved these changes Sep 1, 2026
Comment thread packages/coding-agent/src/core/kernel/repl-manager.ts
Comment thread packages/coding-agent/src/core/kernel/repl-manager.ts Outdated
Comment thread packages/coding-agent/src/core/kernel/repl-manager.ts Outdated
kernelStderr accumulated the kernel's stderr in memory for its lifetime
while every reader shows at most the last 1 KiB. Hand the spawned kernel
an fd onto kernel-stderr.log in the session artifact directory (rotated
once per spawn) so the full pre-ready stderr stays inspectable, read
failure tails from that file, and bound the in-memory diagnostics tail
to 8 KiB (ENG-5832).
@snimu
snimu force-pushed the fix/kernel-stderr-log branch from 2b0f40f to b951f55 Compare September 1, 2026 13:58
Comment thread packages/coding-agent/src/core/kernel/repl-manager.ts
…up failures

stderrTail() loaded the whole log to slice 1KB off the end; a kernel that
spews to stderr until the 30s ready timeout can leave a log far too large
to buffer in the host, so the failure report now does a positional read
of the last 1KB only.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants