fix(tui): render instruction updates as compact notices - #41900
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Instruction-update notices in the TUI now always render as a compact one-liner (
◈ Instructions updated: core/codemode) instead of sometimes dumping the entire model-facing update text — up to a full multi-hundred-line Code Mode catalog — into the transcript.Before / After
Before: the TUI had two divergent paths for
session.instructions.updated, and which one you saw depended on how the message reached you:Instructions updated: <source keys>. This is the small notice users are used to.SessionNoticeMessageV2renderedmessage.textverbatim. A restart-triggered Code Mode catalog update therefore appeared as a wall of text.The verbatim render regressed in #36254 (July 10), which replaced the previous hardcoded
"Instructions updated"label withprops.message.text. The two paths also disagreed on whether to show a message: the projector skips text-less deltas (initial baseline, empty renders), but the live fold only skipped the initial baseline — so a live-shown notice could silently vanish on reload.After: both paths produce the same message shape and the renderer never shows the full text:
Systemmessage gains an optionaldescription—Instructions updated: <delta keys>— built by the projector from the durable event's delta.text, compactdescription) and now skips text-less deltas exactly like the projector.SessionNoticeMessageV2rendersdescription ?? "Instructions updated"for system messages. The plain-label fallback covers messages projected before this change.The model-facing contract is untouched:
message.textstill carries the full frozen update, whichto-llm-message.tssends as the system message on every request rebuild and compaction summarizes. Only human display changes.How
packages/schema/src/session-message.ts—Session.Message.Systemgains optionaldescription, mirroringSynthetic.packages/core/src/session/message-updater.ts— projector populatesdescriptionfromevent.data.deltakeys.packages/tui/src/context/data.tsx— live event fold mirrors the projector: skipstext: undefinedevents, stores fulltextplus compactdescription.packages/tui/src/routes/session/index.tsx—SessionNoticeMessageV2showsdescription ?? "Instructions updated", nevertext.packages/client/src/promise/generated/types.ts— regenerated (bun run generatefrompackages/client).sequenceDiagram participant Core as Projector (core) participant TUI as TUI event fold participant View as SessionNoticeMessageV2 Note over Core,TUI: session.instructions.updated { delta, text? } Core->>Core: skip if text undefined Core->>View: System { text, description: "Instructions updated: keys" } TUI->>TUI: skip if text undefined (now matching) TUI->>View: same shape, synthesized live View->>View: render description ?? "Instructions updated"Scope
descriptiononto previously projected messages; they fall back to the plain"Instructions updated"label. Projections are rebuildable if exact parity is ever wanted.Testing
From package directories:
packages/schema,packages/core,packages/tui,packages/client:bun typecheck— clean.packages/core:bun test test/instruction-state.test.ts test/session-runner.test.ts test/bus.test.ts— 204 pass.packages/tui:bun test test/cli/tui/data.test.tsx test/cli/tui/inline-tool-wrap-snapshot.test.tsx— 52 pass. The data test previously asserted the divergent live behavior (message for a text-less delta, compact string stored intext); it now asserts the unified shape and the text-less skip.