Skip to content

fix(tui): render committed run_code rows through the shared Code Mode rules - #4

Merged
Quorafind merged 5 commits into
mainfrom
release/v1.5.4
Sep 22, 2026
Merged

Quorafind merged 5 commits into
mainfrom
release/v1.5.4

Conversation

@Quorafind

Copy link
Copy Markdown
Collaborator

What

run_code (Code Mode) rows that carry prose next to the tool call never reach the
streaming card: their body comes from collect_tool_block_body_lines_with_width,
which knew nothing about Code Mode. Every accumulated code_mode/dispatch progress
event was therefore drawn as body text, so reopening a session replayed the whole
dispatch stream and the completion summary the streaming card shows was missing.

run_code now goes through the same rules that card uses, reusing the shared
rebon_render helpers instead of reimplementing them: the summary from
completed_summary, the final output with progress events filtered out by
tool_progress_metadata, a single reason line for a failed call (raw_output["error"],
else the last content block), and the program under a JavaScript: label in Verbose
only, since a committed row has no Ctrl+O expansion to hide it behind. A completed call
with no output says No final output received, matching the streaming card. The
existing preview budget still bounds the body.

README

The four demo recordings were 1018x694 and 1.0 MB together. They are re-encoded to
780x532, with each dropped frame's duration summed into the frame that replaces it, so
every clip keeps its exact running time (39980/51280/47660/30960 ms before and after,
verified by parsing the ANMF duration headers). The total is now 471 KB. Both READMEs
lay the demos out as a table with the description on the left and the recording on the
right.

Known trade-off: the frame count is halved, so playback drops from about 5.3 fps to
2.6 fps. The timeline is unchanged, but motion is choppier.

Verification

  • cargo test -p rebon-tui --lib — 1243 passed, 0 failed
  • cargo test -p rebon-render — 671 passed, 0 failed
  • cargo test -p rebon-cli — 1980 + 1 + 23 passed, 0 failed
  • rustfmt --edition 2021 --check clean on the changed files
  • Each webp decodes fully, and a rendered frame was inspected for legibility at 780px

… rules

A committed assistant row that carries prose alongside its tool call never
reaches the streaming card: its body lines come from
collect_tool_block_body_lines_with_width, which knew nothing about Code
Mode. Every code_mode/dispatch progress event the row had accumulated was
drawn as body text, so reopening a session replayed the whole dispatch
stream, and the completion summary the streaming card shows was missing.

Route `run_code` through the same rules that card uses, reusing the shared
rebon_render helpers instead of reimplementing them: the summary from
completed_summary, the final output with progress events filtered out by
tool_progress_metadata, a single reason line for a failed call
(raw_output["error"], else the last content block), and the program under
a JavaScript: label in Verbose only, since a committed row has no Ctrl+O
expansion to hide it behind. The existing preview budget still bounds
non-Verbose bodies, and every other tool's body is unchanged.
The four demo recordings were 1018x694 and 1.0 MB together, which pushed
the rest of the Demo section out of sight. Re-encode them to 780x532 and
drop every other frame while summing the dropped frame's duration into the
one that replaces it, so each clip keeps its exact running time (verified
by parsing the ANMF duration headers: 39980/51280/47660/30960 ms before
and after). The total falls to 470 KB and the text stays legible at the
width GitHub renders.

Lay the demos out as a table with the description on the left and the
recording on the right, in both READMEs. The Chinese one references the
assets one level up from docs/.
First-prompt routing could only pick a model inside the provider in
force: the decision had no provider field, and both the main-session and
the worker path pinned the resolve to the current provider and asserted
it stayed there.

ModelRoutingDecision now carries a provider, and routed_target() reads it
in one place for both callers. A provider switch has to name a model with
it, because a model id belongs to the provider that serves it — the
router never asks one provider for another's model. The classifier is
offered every usable provider's models, grouped by provider, and the
decision is checked against the provider it names: the model has to
belong to it, and the reasoning effort has to be one that model supports.
routerModel itself still has to belong to the provider in force, since
the classification request runs there.

A declared provider now suppresses automatic routing the way a declared
model already did: a route that can move the worker must not overrule a
provider the dispatch named.

The routing notice names the provider it switched to, so a session that
changes legs says so.
The classifier's system prompt was fixed, and biased toward the cheapest
suitable candidate, so routing could never be told that hard work deserves
a frontier model. A user could name the classifying model and nothing else.

The plugin now takes a `policy` setting: free text, appended to the
classifier's prompt and marked as outranking the cost preference, with a
text row in the settings panel beside the model row. The row stores the
user's words as written; empty removes the key, so "no policy" is one state
in the file rather than two that differ by whitespace.

The effort check asked the model table whether the target model supports
the effort, and refused when the table carried no row for it. Every custom
provider's own model id is such a model, so a decision naming an effort on
the provider's default model was rejected and the turn ran unrouted. The
table speaks only for the models it lists; where it has no row, the
provider's own declaration governs.
@Quorafind
Quorafind merged commit d294399 into main Sep 22, 2026
16 of 18 checks passed
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.

1 participant