Skip to content

fix(daemon): present a captured engine's stdout as a pseudo-terminal - #245

Merged
outofcoffee merged 5 commits into
mainfrom
fix-serve-load-log
Sep 25, 2026
Merged

outofcoffee merged 5 commits into
mainfrom
fix-serve-load-log

Conversation

@outofcoffee

@outofcoffee outofcoffee commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

A model download is silent in the engine log, because the engine only draws its progress to a terminal.

Summary

  • The daemon (and with it the serve view) now presents a captured engine's stdout as a pseudo-terminal, so terminal-only output — a model download's progress among it — is produced while supervised and lands in the engine log
  • A normaliser turns the terminal stream into the log's clean lines: no escape sequences reach the file, and a line the engine redraws in place (a progress bar) is recorded as its state — first and final always, any further distinct state at most once per 2 s — so a long download leaves a legible progression rather than a wall of overwrites
  • The engine's stderr keeps going to the log file directly, and the capture tells the engine NO_COLOR=1 so its log lines do not reach the file coloured through the stderr path
  • Where a pseudo-terminal cannot be opened (Windows, a restricted environment) the capture falls back to writing stdout to the log file directly — no worse than before
  • Off-terminal serve and serve --api forward the engine's output byte-for-byte as before: no pseudo-terminal, no normaliser, no NO_COLOR

Implementation details

The normaliser (internal/daemon/ptylog.go) keeps the terminal's lines as a column and records the states of the ones the engine redraws, rather than emulating a screen. The engine's up-down cursor dance is part of each redraw, so a cursor move moves the drawing between the column's lines and never ends one; a state's replacement is deferred to the next text byte; and a half-rate tick records a pending state on every line, because a bar's last state outlives the engine's move off its line. The pump always drains the master so the engine can never wedge on a full terminal, and the log file closes only after the pump's final record.

The change is specified in openspec/changes/engine-pty-log-capture/ and its rationale in docs/maintainer/internals.md.

Fixes #226

Pete Cornish added 4 commits September 25, 2026 04:36
…minal

The serve view and the daemon capture the engine's output to a log file,
so an engine that gates terminal-only output on stdout being a terminal
llama.cpp's model download progress among them produces none of it.
The proposal presents the captured engine's stdout as a pseudo-terminal
and records redrawing lines as their state.
llama.cpp prints a download's progress only when stdout is a terminal, so under the capture — stdout pointed at the log file — a model download is silent. The pseudo-terminal makes the engine produce the output, and a pump normalises the terminal stream into the log's lines: a redrawing line recorded as its state, first and final always and a further distinct state at most once per two seconds, no escape sequences reaching the log.
An engine that moves onto a line it has already written and writes
there without a carriage return rewrites the line the way the
terminal shows it; the normaliser was extending the content the line
held. The move now settles the state the line draws, and the next
write starts a new state of the line.

The change also closes the package's remaining coverage gaps: the
escape sequences the engines may send, the no-pseudo-terminal
fallback, the pump's end-of-stream drain, and the supervisor's
refused starts.
The maintainer internals gains the capture's rationale: the
normaliser's line model and the rules a 'simplification' would
break, the NO_COLOR rule, and the fallback the tests keep alive.
@outofcoffee outofcoffee added bug Something isn't working go Pull requests that update go code labels Sep 25, 2026
@outofcoffee
outofcoffee marked this pull request as ready for review September 25, 2026 11:33
@outofcoffee
outofcoffee merged commit 60d8ffb into main Sep 25, 2026
5 checks passed
@outofcoffee
outofcoffee deleted the fix-serve-load-log branch September 25, 2026 11:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working go Pull requests that update go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: serve log doesn't show model pull progress from engine

1 participant