Skip to content

simulate: tool output behind t, and stop reprints duplicating the job view - #931

Open
u9g wants to merge 9 commits into
mainfrom
feat/simulate-full-tool-detail
Open

simulate: tool output behind t, and stop reprints duplicating the job view#931
u9g wants to merge 9 commits into
mainfrom
feat/simulate-full-tool-detail

Conversation

@u9g

@u9g u9g commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Two changes to the job detail view, together because the second is unusable without the first, plus a small --project fix that rode along.

Tool output moves behind t

Tool outputs are payloads written for the model, not for a reader — a policy blob or a lookup table's worth of JSON sitting between two spoken turns buries the conversation the job is about. They were previously always shown, clipped to 80 characters, which is the worst of both: still noisy, and too short to answer what a tool actually returned when a job failed on a tool call.

They are now off the transcript by default and shown whole on t. The hint reads t show tool output / t hide tool output, and is omitted when the open job has no tool output to show.

The tool call itself stays on the transcript either way — which tool ran, with a preview of its arguments, is part of reading what the agent did. Argument previews now clip on a rune boundary; args[:80] is a byte slice and these payloads carry guest names and quoted speech, so a rune landing on the boundary was emitted halved.

A reprint erases the copy it replaces

Toggling anything that rewrites the middle of the job body — which is what tool output does — used to leave a duplicate copy of the whole job in the scrollback, one per keypress. ctrl+L already had this: pressing it a few times stacked copies.

Since #928 the detail view is printed into the terminal rather than windowed in the alt screen. flushDetail diffs each render against detailPrinted and prints only the growth, so the common case (a log line arriving, the transcript landing with the summary) costs one appended tail. A render that is not an append can't be patched in place — scrollback is immutable — so detailTail falls back to returning the whole body. But clearScrollback was only prepended when detailPrinted == "", i.e. on the first print of a job, so every later whole-body reprint landed below the copy it was meant to replace.

The first condition widens to any reprint — nothing printed yet, or a render that isn't an append — and clearScrollback is prepended in both cases.

For ctrl+L the asymmetry is why it looked erratic: the Logs: block is the tail of renderDetail, so turning logs on was a pure append and behaved, while turning them off shortened the render and reprinted everything.

Notes

  • clearScrollback is ESC[3J, so it takes the pre-TUI shell scrollback with it. That was already true of every job you opened (see the comment on the const); it is now also true per toggle. Reaching rows that have scrolled off isn't possible any other way.
  • No tests. The reprint behavior is an ANSI prefix on a tea.Println, not something a detailTail unit test can observe, and asserting on rendered TUI output is what we avoid in this file. The transcript and hint logic were checked with throwaway tests — default hides output, t shows it whole, hint absent when there is nothing to show, rune-boundary clip — none of them committed.

Verification

go build ./..., go vet ./cmd/lk, gofmt, and the existing ./cmd/lk suite pass. The rendering and hint logic were exercised directly against a fixture shaped like a real emergency-dispatch job. The interactive path — actually pressing t and ctrl+L in a live TUI — has been spot-checked against a --view run but is worth a second pair of eyes.

u9g added 5 commits August 3, 2026 19:58
The detail view is printed into the scrollback incrementally: flushDetail
diffs the render against what it already printed and prints only the
growth. A render that is not an append of the previous one cannot be
patched in place, so it is reprinted whole — but clearScrollback was only
prepended on the first print of a job, leaving the superseded copy above
it.

Toggling logs with ctrl+L off is exactly that case (the Logs block is the
tail of renderDetail, so turning it on appends but turning it off
shortens), so every toggle stacked another copy of the job.
The transcript clips tool arguments and outputs to 80 characters, which
is right for reading the conversation but hides exactly what a tool was
asked for and what came back — the part you want when a job failed on a
tool call.

t, in the job detail view, toggles the clip off: arguments and outputs
render whole, wrapped to the transcript measure with continuations
indented under the marker. The hint offers the key only when the open
job has something clipped to reveal.

Clipping now cuts on a rune boundary; tool payloads carry guest names and
quoted speech, and a byte slice could halve a rune.
Tool outputs are payloads written for the model, not for a reader: a
policy blob or a lookup table's worth of JSON between two spoken turns
buries the conversation the job is about. Keep them off the transcript
and put them behind t, whole rather than clipped, since a clipped payload
answers nothing about why a job failed on a tool call.

The tool call itself stays on the transcript either way — which tool ran,
with a preview of its arguments, is part of reading what the agent did.
The verb was implicit on the way in and explicit on the way out.
@u9g u9g changed the title simulate: full tool detail on t, and stop reprints duplicating the job view simulate: tool output behind t, and stop reprints duplicating the job view Aug 4, 2026
GetSimulationRun accepts an API key or a session token, and the session
path rejects the request when project_id is absent. Every caller already
has the resolved project, so pass it through.
Comment thread cmd/lk/simulate.go Outdated
Comment thread cmd/lk/simulate.go Outdated
Comment thread cmd/lk/simulate.go Outdated
u9g added 3 commits August 5, 2026 13:27
The re-open hint read --project off the command, so it only reproduced
an explicitly passed project. The resolved config already carries the
name for every configured-project path, and pinning it means the hint
targets the same project even if the default changes.
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