## Why
The sidebar chooser used hard-coded keys and hints instead of configured list bindings, limiting navigation and making custom shortcuts inconsistent.
## What changed
- Use configured list actions for chooser navigation, acceptance, and cancellation, including key chords, page movement, and jumps to the first or last choice. Show the configured shortcuts in footer and retry hints.
- Place “New side chat” first and group existing chats into compact rows with a count and optional thread colors. Keep the selected chat visible in short panes.
- Highlight inactive side-chat tabs on hover while preserving the selected tab's styling. Redraw when the hovered tab changes and suppress hover highlighting during pane resizing.
## Testing
Extend interaction tests and snapshots to cover custom acceptance chords, `j`/`k` navigation, paging, and tab hover styles and redraws with either pane focused, including the fallback when terminal colors are unavailable.
GitOrigin-RevId: bad992b3786215dcb5569acfc72af8841fad949d
## What changed
Read `final_answer_moderation` metadata and attach `moderation: { moderated: boolean }` to the completed final-answer message only when its item ID matches. Apply this in both normal and plan modes, and reset the pending decision when a new response starts.
Preserve the answer's native item ID and moderation flag through legacy events and history reconstruction. Combine text parts into one legacy event when a moderation decision is present.
Expose nullable moderation data on app-server agent messages and update the JSON schemas, TypeScript types, and Python models.
## Testing
Add an integration test for moderation on completed answers and their legacy events. Extend protocol conversion tests to cover populated moderation data and serialization as `null` when absent.
GitOrigin-RevId: f286b67731a84b3daf5d10b7644f2e31b62f0e53
## Why
Sidebar resizing previously required an open side chat, leaving the chooser without the same width controls.
## What changed
- Support keyboard resizing, width presets, and divider dragging for the sidebar chooser, with resize hints that fit narrow sidebars.
- Keep keyboard resize mode active across startup thread assignment and replacement of the chooser by a new side chat, so `Enter` finishes resizing without submitting the parent draft.
- Activate resize bindings only when a split is available, and prevent divider drags from starting while the split is animating.
## Testing
Add regression coverage for chooser resizing, width preservation when switching between the chooser and a chat, startup and side-chat creation transitions, draft preservation, and unavailable resize bindings in narrow terminals.
GitOrigin-RevId: 511cd4bb5894e6f33f0cf5d7472bb3013361ffe0
## Why
The TUI's cached active turn can be stale when a cloud message is submitted. A lost reply also leaves delivery uncertain, so automatically resending the draft risks submitting it twice.
## What changed
- Let the cloud server choose whether an Enter submission starts or steers a turn, and apply its receipt to the matching client message ID.
- Keep Tab-queued input waiting until the admitted turn finishes, including before its start notification arrives.
- Restore rejected submissions to the composer. Hold duplicate or unconfirmed submissions out of automatic delivery until history confirms them.
- Reconcile saved drafts and pending steers by client message ID when resuming sessions, and preserve submissions belonging to other turns during interruption recovery.
- Classify cloud preflight failures as invalid parameters so rejected queued input can be restored safely.
## Testing
Add regression coverage for cloud receipt outcomes, queued-input ordering, rejected drafts, lost replies, interruption recovery, and session resume with identical message text but distinct client IDs.
GitOrigin-RevId: ec4eb581e450488434bc4614ec59273d73ffd0a1
## What changed
- When side retention is enabled, let the sidebar chooser create additional side chats from the main chat or reopen existing ones.
- Add numbered, clickable tabs and keyboard navigation in the chooser. Keep the selected tab visible when space is limited.
- Preserve drafts, transcript history, and the sidebar layout when switching between sibling side chats.
- Make `/side` with a prompt request a new side chat, while `/side` without arguments reopens the selected side chat. Preserve existing reuse behavior when side retention is disabled.
## Testing
Extend TUI tests and snapshots to cover creating sibling side chats, switching through the chooser and tabs, retaining drafts and history, and restoring image attachments after failed creation.
GitOrigin-RevId: 4166010c253c40a409390f7020b69478c04cf98c
## Why
Starting a side chat waits for fork and setup requests. Keep the workspace responsive during those requests and let users return to an existing side chat through the sidebar chooser.
## What changed
- Add a clickable `Side chat` tab and `+` chooser, plus the configurable `focus_sidebar_tabs` action bound to `leader t` by default.
- Create workspace side chats in the background, showing loading and failure states with `Enter` to retry and `Esc` to go back. Preserve opening prompts and avoid taking focus when the user has moved away.
- Retain inherited permission profiles and defer startup notifications until the side chat is registered on its owning backend.
- Quiet the parent composer while the chooser has focus and prevent completion popups or repeated activation keys from consuming chooser input.
## Testing
Extend tests and snapshots for loading and failure states, returning to an existing chat, draft preservation, inherited permissions, focus transitions, and deferred MCP startup notifications.
GitOrigin-RevId: 244bcd3f170819e2260f21dc1041cf8899fe048c
## What changed
- Open a sidebar chooser when no side chat exists, with keyboard and mouse controls to start a new side chat while preserving the parent draft.
- Animate sidebar opening and closing, including reversing an unfinished transition, when animations are enabled.
- Show context-aware workspace shortcuts in a floating panel after a short delay, and render presets in the same overlay without moving the composer.
- Prevent chooser input from accepting an approval dialog before it has been painted.
## Testing
Add coverage for chooser activation and draft preservation, sidebar animation reversal, shortcut and preset snapshots, and approval input handling.
GitOrigin-RevId: 014112622a94798f4e611756c55112dfd8016051
## What changed
- Add Space to set the default provider from Model providers settings, persisting `model_provider` on the connected server. Keep provider details available and disable selection when server configuration or client launch settings fix the provider.
- Apply the choice to `/new` while preserving the current chat. Refresh account details for new chats and reject account data that does not match the started provider.
- Block stale `/model` choices during saves and after confirmed or uncertain provider changes, including across reconnects. Tell users to restart the app server and TUI to refresh the model list, and discard queued picker actions from another backend or chat.
## Testing
Add coverage for provider saves, retry after disconnection, concurrent-save prevention, stale model choices, and account/provider matching, with updated provider-picker snapshots.
GitOrigin-RevId: af6d149f7de7a2eaa09a31935f7088faa64d6a59
## What changed
Add configurable pane actions with default leader shortcuts:
- `leader z` zooms or restores the focused conversation pane.
- `leader ,`, `leader .`, and `leader =` minimize, maximize, or equalize pane widths within layout limits.
- `leader shift-h` and `leader shift-l` move the divider while the side pane has focus.
- `leader r` enters resize mode, highlighting the divider and showing keyboard hints. Arrow keys or `h`/`l` move it one column; Shift+Left/Right move it ten columns. Enter or Esc saves the width to `tui.sidebar_width_percent`.
Discard resize previews when terminal focus is lost or the split layout becomes unavailable. Preserve exact column widths at the current terminal size for presets and completed keyboard resizing, avoiding percentage-rounding drift.
## Testing
Extend TUI tests and snapshots to cover zoom and restore, width presets, divider movement, resize previews and persistence, and interrupted resizing. Extend keymap tests to cover zoom binding conflicts and custom chords.
GitOrigin-RevId: 7dd823fd8c2a0c90368c66f254c4fdd7c863c8a8
## What changed
- Allow dragging the pane divider and save the preferred width in `tui.sidebar_width_percent`, defaulting to one third of the terminal. Defer reflow until release when retained images are present.
- Support scrolling and loading older history in the unfocused pane, opening links, copying selections, and clicking its composer to switch focus while preserving the clicked text position.
- Keep assistant replies, running command completion, and turn status current in the unfocused pane without duplicating answers or completion metadata when focus returns.
## Testing
Add regression coverage for divider previews and saved widths, image-aware resizing, composer clicks, unfocused history pagination and copying, and streaming replies and command completion across focus changes.
GitOrigin-RevId: a26accc0f8df3c17f53bc915db29a11c8de3c480
## Why
Directional pane switching cleared the parent conversation's transcript selection or Find state, so returning to it interrupted the interaction.
## What changed
Route left/right pane switches through the existing conversation toggle to park and restore each pane's transcript interaction. Explicitly focusing the main composer still clears transcript interaction.
## Testing
Extend the side-conversation test to cover restoring selections, Find text and caret position, and composer input after scrolling. Add a snapshot verifying that Find remains editable after switching away and back.
GitOrigin-RevId: 172f9be0df15517fbfe7f3773b63cbd1cef1cc77
## Why
Pressing `Ctrl-/` immediately after `/btw` must not switch focus before the queued side-conversation prompt is dispatched.
## What changed
Wait for queued app events to drain before reading terminal input when the displayed thread belongs to a parent/side conversation pair, even when side retention is disabled. This keeps queued prompts and transcript updates ahead of focus changes.
## Testing
Extend the side-conversation startup test to toggle focus at the earliest allowed opportunity and verify that the turn starts on the side thread. Also check that a queued request to reopen the side conversation blocks terminal input until handled.
GitOrigin-RevId: cb46636d35de97b02994ed68a32eb971cd7bf6db
## What changed
- Add configurable `focus_pane_left` and `focus_pane_right` actions, defaulting to `leader left` / `leader h` and `leader right` / `leader l`.
- Move focus to the parent or open side conversation without reopening a hidden pane. Preserve the current interaction when no neighbor is available, and accept fresh typing after a no-op shortcut while suppressing reported key repeats.
- Expose the actions in the keymap picker and configuration schema, and prevent workspace-only pane bindings from claiming keys in classic mode.
## Testing
Add regression coverage for pane navigation, preserved transcript selection and search, fresh typing after a no-op, key capture, and binding conflicts and limits.
GitOrigin-RevId: 7f7629d15cffcd35d1353b36c5c9208dbb1034e8
## What changed
- Add configurable `focus_main_composer` and `focus_sidebar_content` actions, with default `leader c` and `leader s` bindings in workspace mode.
- Let users return to the main composer while keeping the side pane open, or focus the side conversation and hide it when already focused.
- Clear transcript search, selection, and activity focus when returning to the main composer, including when hiding the side pane.
## Testing
Extend tests for focus switching, blocked thread switches, offline composer focus, key capture, and binding conflicts.
GitOrigin-RevId: da624ce7e00a63c4f13870e55c4bc95f09b32cc4
## What changed
Add `tui.keymap.global.hide_pane`, defaulting to `leader -` in workspace mode. Hiding a focused side conversation returns to its parent while retaining the conversation, drafts, and view state for reopening.
Expose the action in the workspace keymap picker, validate binding conflicts, and suppress held shortcut keys after switching focus.
## Testing
Add coverage for hiding and reopening at split-pane and narrow widths, preserving conversation state, shortcut availability, key capture, and repeat/release handling.
GitOrigin-RevId: 6897c34b208041e6f90ae0e18c781eebd62566bd
## What changed
Add optional `contentTokenCount` metadata to `item/completed` notifications, carrying the producer-supplied token count for each completed assistant message in default and plan modes. Counts include any sampled footer and are `null` when unavailable.
Keep this telemetry separate from stored thread items and omit it from subsequent model requests. Update the protocol schemas and generated TypeScript and Python types.
## Testing
Add coverage for per-message counts, including zero, in default and plan modes; missing and malformed metadata; backward-compatible notification decoding; and exclusion from subsequent model requests.
GitOrigin-RevId: 35973037a42650fa2d7569da8e88cb81215cf971
## What changed
- With multi-backend support enabled, show the current host before the first submission and use `leader b` to cycle through available connections. Expose the shortcut as `tui.keymap.global.change_host`.
- Preserve the conversation name and composer draft, including cursor position, attachments, pending pastes, and literal versus shell-command interpretation of `!`.
- Save explicit host choices in user-only `tui.default_hosts`, scoped to the local project and user identity. Use the saved host for new conversations, falling back to the first available connection when it is unavailable.
- Prepare the destination and check directory trust before replacing the current conversation. Block switching during voice calls and active turns, and remove replaced blank conversations from the session overview.
## Testing
Add coverage for shortcut visibility and remapping, draft and name preservation, project/user preference isolation, unavailable-host fallback, destination trust and startup failures, and voice-call guards.
GitOrigin-RevId: def7b088951336bec8fe3962954fba9b861f91c6
## What changed
- Add the disabled-by-default `tui_workspace` feature for the owned transcript view. At terminal widths of at least 100 columns, show the parent conversation beside its side conversation, with only the focused composer accepting input.
- Retain the inactive conversation's transcript, draft, and status, and restore reading and search state when switching focus.
- Keep drawing and input paused until history replay completes, while refreshing skills in the background.
## Testing
Add snapshots and regression tests for pane resizing and composer styling, retained streaming output, history search after replay, pending skills refreshes, and modal input protection.
GitOrigin-RevId: 68938f263353b0cd3a9e9562e06293bfc8251cc6
## Why
Streaming answers and plans need to wrap to the conversation's allocated width, which can differ from the terminal width. Resizing while reading earlier output should not report new activity unless new output has arrived.
## What changed
Reflow live streams when preparing the owned conversation layout, using its allocated width. Update the observed live revision after presentation-only reflow so it does not trigger `New activity`, while preserving notifications for unseen output.
## Testing
Add regression coverage for streaming answer and plan tables across width changes, including a narrow-layout snapshot, preservation of the reading position, and activity notifications when new output arrives before a resize.
GitOrigin-RevId: a9831c5a1a5ffb7477e7868d4ecca430d6ee50f3
## What changed
- Group threads needing approval first in `/subagents`, mark them with `(needs approval)`, and initially select the first waiting thread.
- Refresh the open picker and approval notice as requests and agent metadata change, preserving the selected thread when rows move.
- Use consistent agent labels across the picker and approval notice, preferring agent paths and using UUID suffixes to distinguish unnamed agents.
- Track approval requests that arrive before thread metadata and refresh pending approvals after reconnecting.
## Testing
Extend the picker test and snapshots to cover approvals arriving while the picker is open, agent paths arriving later, and selection staying on the same thread after reordering.
GitOrigin-RevId: b7dd943d151ce98d1978f7c6b9f5e16903b9075b
## What changed
Split conversation rendering into preparation, painting, and post-draw steps. Use the supplied conversation bounds for transcript wrapping, composer layout, suggestion overlays, cursor placement, and the empty-state animation.
Preserve surrounding text and image placements during input-triggered redraws. Keep centered dialogs relative to the full viewport and restore neighboring content when they close.
## Testing
Extend regression tests and add a snapshot for conversations rendered at an offset, covering selection, link hit testing, cursor placement, scroll preservation, neighboring images, and dialog dismissal.
GitOrigin-RevId: 0dbca3f8d1064f2d58856c3bc77a4dab1c099cdd
## Why
`Ctrl+L` discarded the retained transcript along with the terminal display, making earlier exchanges unavailable in the detailed transcript.
## What changed
Keep earlier exchanges accessible through `Ctrl+T` while starting a fresh terminal display with a new header. Treat that header as the boundary for compact scrolling, pinned prompts, and resize replay so cleared content stays hidden in the normal view. Allow the detailed transcript to load older history after clearing.
## Testing
Extend the `Ctrl+L` regression test and add a detailed-transcript snapshot covering retained exchanges, draft preservation, older-history loading, and cleared-content visibility after resizing and replay.
GitOrigin-RevId: f1eb73e903a7957cedafb52678c607858fb2d77f
## What changed
- Add the disabled-by-default `tui_extensions_statusline` feature to render configured status items and their picker preview through a shared UI tree renderer.
- Support text, HTTP(S) links, rows, spacers, dividers, and gaps with rendering budgets, text sanitization, and width-aware truncation that keeps the ellipsis outside hyperlinks.
- Use plain text for the extension status line and hide the picker's theme color toggle while preserving the saved color preference.
## Testing
Add coverage for tree serialization and URL validation, Unicode widths, hyperlink clipping, picker previews, color preference preservation, and token usage updates across renderer switches.
GitOrigin-RevId: a6b87c2b1096765d61296d73e142834fcd53ceee
## Why
Existing chats retain their provider configuration when the selected provider changes. Reject resume and input until the configured provider matches the chat, while keeping history readable and allowing recovery after configuration is restored.
## What changed
- Validate saved providers before applying resume overrides, preserving the provider when only model or reasoning settings change.
- Check the current provider selection, including profiles and launch overrides, before accepting input. Reject input when configuration cannot be loaded.
- Return structured `ModelProviderError` data for provider mismatches, missing definitions, and policy conflicts, with generated JSON Schema, TypeScript, and Python types.
## Testing
Add coverage for override bypass prevention, provider restoration, readable history after rejection, and blocked requests sending no inference traffic. Verify schema fields and Python round trips match the error wire format.
GitOrigin-RevId: 051f97c3815c547d8411c71b770df30eae969f68
## What changed
Split saved-thread resume into preparation and activation. Preparation resolves configuration and attaches to the destination thread before activation replaces the displayed conversation.
Keep stored-backend configuration and local settings separate from active settings during preparation, while retaining the existing eager settings refresh for active-backend resumes. Use the destination backend for working-directory, permission, and directory-trust checks.
Carry the backend identity in the prepared result and reject activation through a different backend before changing the active conversation or composer.
## Testing
Extend coverage for preserving active settings and composer drafts during preparation, rejecting activation through another backend, applying destination remote-permission checks, and retaining active-backend settings refresh behavior.
GitOrigin-RevId: 7171f1abcf4bdd62793c21232a8b895bb809cf70
## What changed
Replace `UserHistoryCell`'s `spoken` boolean with `UserMessagePresentation`, defaulting to `Plain` and using `Spoken` for speech transcripts. Route rendering checks through `is_spoken()`, preserving the existing prompt styling and whitespace handling.
GitOrigin-RevId: d0683a2b536a7d71f68fd9a089e6839d0ab0cc65
## What changed
- Add nullable `startedAtMs` and `completedAtMs` fields to `ThreadItem` in live notifications and turn history. Values are Unix milliseconds when recorded.
- Preserve recorded item times through history reconstruction, pagination, and resume, including command start times recorded during approval.
- Separate the Rust item payload into `ThreadItemPayload` while keeping the JSON payload flat, and update consumers, schemas, and generated TypeScript and Python types.
## Testing
Extend coverage for timestamp serialization, history reconstruction, paginated reads and resume, and persisted Python SDK items.
GitOrigin-RevId: ecbcee95af52db7c807b46a6e9deb30e5fba1f80
## Why
Automatic marketplace update failures were only logged, leaving users without a visible startup warning.
## What changed
Send marketplace update errors and task startup failures through app-server warning notifications. Queue background warnings until a client initializes in both standalone and in-process servers, and centralize startup configuration warning delivery.
## Testing
Add a TUI integration test and snapshot covering two marketplace name mismatch failures, the warning count, and navigation between their details with `F2` and the arrow keys.
GitOrigin-RevId: af55a5555affd9d89ac15a546163daeaafd3b3e8
## Why
Resuming a thread can replace saved model settings with global defaults. A selected service tier can also be lost when the current model does not support it.
## What changed
- Restore saved service tier, reasoning summary, and personality on resume unless the caller explicitly overrides them, respecting thread ownership of settings snapshots.
- Retain the selected service tier for persistence, settings notifications, and resume comparisons while filtering the effective tier against the current model's capabilities.
- Carry the runtime model, service tier, and personality into thread revert reconstruction.
- Persist initial thread settings before user input during MCP startup so an interrupted first turn retains its settings checkpoint.
## Testing
Extend regression coverage for cold resume and explicit overrides, unsupported service tiers, settings preservation during revert, and settings checkpoints before user input when MCP startup is interrupted.
GitOrigin-RevId: e5ec012a5678048c5eedd443e524f38c142bf9fd
## Why
Queued prompts can resume before a pending permissions menu opens, and local
`/permissions` commands can bypass guards for outstanding permission changes.
Attaching to a different project can also retain model access information from
the launch directory.
## What changed
- Route `/permissions` through app permission guards and hold queued prompts
while the menu is pending. Settle the hold when opening is rejected, discovery
is invalidated, or a covering request is resolved.
- Apply the custom permission profile selection check beyond embedded servers.
- Refresh API-key model access when the first attached session changes the
working directory, including with an embedded server. Propagate the widget's
model catalog to the app and server even when the model response matches the
widget's already-updated catalog.
- Skip sessions reported as `thread not loaded` during name lookup for all
server types instead of falling back to unverified list metadata.
## Testing
Add regression coverage for permission guards, queued prompts across successive
permission menus, invalidated and covered menus, model catalog propagation,
project changes on initial attachment, and name lookup across server pages with
unreadable entries.
GitOrigin-RevId: eb49cb5268ce0ce1e40009b73a0180f23e61ed72
## What changed
Add a `BackendSessions` collection to own app-server sessions and poll their events fairly with cancellation-safe receives. Track listening state per backend so pausing or closing one stream leaves the others available, and resume polling after reconnect. Shut down all registered sessions on exit.
Ignore background backend disconnect, lag, account, and rate-limit events that would otherwise update the displayed conversation's UI.
## Testing
Add coverage for polling three sessions, paused and closed stream isolation, cancellation, and session replacement after reconnect. Extend event ownership coverage to verify that background lifecycle and account events leave the displayed connection and rate-limit state untouched.
GitOrigin-RevId: 9ed82abc77aaf4bfeb86eb72161ad90fe20177ad
## Why
Command-line initial prompts bypass the composer and were missing from local recall history, so pressing Up could skip them and retrieve cross-session history instead.
## What changed
Record accepted initial prompts in local recall history with their draft metadata. Add image placeholders where needed so recalled local attachments survive resubmission. Leave synchronously rejected prompts out of recall history.
## Testing
Add regression tests for recall order before cross-session history, ordering after transcript replay, queued prompts appearing once, rejected submissions, and image attachment recall and resubmission. Add a snapshot of the recalled initial prompt.
GitOrigin-RevId: 0a12221ae285f01bff4b5860e546c8f7ee3c71e3
## Why
Events from another backend must not mutate the current backend's thread or connection state, even when native thread IDs collide.
## What changed
Attach the session's `BackendId` to incoming app-server events and check it before dispatching to thread caches or UI handlers. Apply the same check when waiting for a thread revert notification.
## Testing
Add regression tests covering ignored foreign notifications, approval requests, lag and disconnect events, accepted events from the current backend, and preservation of backend identity on transport events.
GitOrigin-RevId: 2577ab78e0592726f5f05e3426772899e6cb7c7e
## Why
Thread unload timing used the server-wide delay, ignoring per-thread configuration overrides. Clients need to control how long individual idle, unsubscribed threads remain loaded.
## What changed
- Resolve unload timing from each loaded thread's `thread_unload_delay_secs` configuration. Setting it to `0` allows immediate unloading once the thread has no subscribers or activity.
- Allow this runtime retention override in `experimentalPredictionMode` forks while continuing to reject other configuration overrides. Reject negative values and delays too large to schedule.
- Replace the source-specific immediate-unload behavior with explicit configuration.
## Testing
Extend integration coverage for per-thread delays, unloading after active turns finish, fork overrides, and invalid prediction-fork delays. Verify that immediate unloading preserves persistent history and that cold resumes and ordinary nested forks use their default delay instead of retaining the previous runtime's override.
GitOrigin-RevId: fcb82bd73a101260c51e2a8476f94320c23ac929
## Why
MCP tool discovery discarded response-level `_meta`, leaving server-status clients unable to inspect metadata associated with the tool catalog.
## What changed
- Preserve opaque `_meta` from the first `tools/list` page through catalog refreshes and caches.
- Expose it as `toolListMeta` in `McpServerStatus`, with `null` when unavailable, and update generated schemas and bindings.
- Scope cached Apps catalog metadata to discovery settings, including client capabilities and extensions, while retaining tools from older caches without metadata.
- Restrict server capabilities in status snapshots to the selected servers.
## Testing
Add regression coverage for listing legacy cached Apps tools during failed startup, and update protocol serialization expectations for nullable `toolListMeta`.
GitOrigin-RevId: 62335e2fd8c482067a7a78a7612b58c3eaa9fb55
## Why
A thread ID alone does not identify the backend that owns a session. Resume and fork selections must retain that ownership across connection replacement so they cannot operate on another backend, even when thread IDs match.
## What changed
- Add a process-local `BackendId` to app-server sessions and session targets, preserving it across reconnects and auxiliary picker connections.
- Reject selections from a different backend before changing session state or sending resume, fork, or unarchive requests.
- Disable local-daemon fallback to an embedded server for auxiliary pickers and after selecting a session, while retaining fallback for fresh startup.
## Testing
Add regression coverage for foreign selections with matching thread IDs, startup resume and fork rejection before requests, shared ownership across picker connections, and fallback eligibility.
GitOrigin-RevId: 05a3ca0a901a8dc24337d130548aa2c048b4d586
## What changed
- Add a TUI picker with ten numbered preset slots, an editor, and confirmation before replacement or deletion.
- Create presets from composer text or current model, reasoning effort, and speed settings. Run saved inputs through the normal queued submission path while preserving the composer draft.
- Persist presets under `tui.presets` in the active user configuration, respecting configuration layer ownership and leaving in-memory settings unchanged when writes fail.
- Preserve permissions when changing effort or speed for the effective model, keep default collaboration settings intact in Plan mode, and allow standard-speed selection with older app servers.
## Testing
Add persistence tests for save, replace, delete, configuration ownership, and write failures; picker and confirmation snapshots; and regression coverage for model permissions and standard-speed fallback.
GitOrigin-RevId: 5f11699112cd404cc8e954872d53495c6edd0c0a
## What changed
Allow `/model [model] --reasoning <level> --speed <tier>` to update the current session without changing saved defaults. Both space-separated and `=` flag values are supported; omitting the model applies settings to the current model. Bare `/model` still opens the picker.
Validate model availability, supported reasoning levels, and speed tiers before applying changes. Reject unknown flags, duplicate settings, and missing values. Apply model, reasoning, and speed together after server acceptance.
Restore each thread's speed when switching threads, and use destination configuration defaults for new sessions instead of carrying over the active session's speed.
## Testing
Extend regression coverage for inline commands, invalid arguments, unchanged saved defaults, settings-only updates to hidden current models, destination speed defaults, and speed restoration on the next turn after switching threads.
GitOrigin-RevId: ad9cecbdb3554e34a6518367364978a37fb68439
## Why
When a command starts before an assistant message completes, the TUI can flush the streamed text and then render it again when the completion arrives. This duplicates the preamble in both live output and replay.
## What changed
Track the turn ID, item ID, and source text of the flushed message. Skip rendering its completion again when the identity and text match, allowing for the trailing newline added during stream finalization. Continue rendering completions whose identity or text differs.
## Testing
Add an end-to-end test that delays message completion until a command starts and checks that live and replayed transcripts contain the preamble once. Add regression coverage for completions with different text or item IDs.
GitOrigin-RevId: 59af0198a99f26ba8ba2a47644ba662301c30011
## Why
Terminal status previously collapsed completed and failed turns into `idle` and reported blocking prompts without a reason. Blocking detection also depended on terminal title settings.
## What changed
- Emit `done` and `error` through OSC 7501 for live turn results, retaining them until deliberate keyboard, paste, or mouse input acknowledges them. Mouse movement does not acknowledge results.
- Classify blocking requests with `kind=permission`, `kind=question`, or `kind=auth`, including requests hidden behind another view or delayed while typing, independently of terminal title settings.
- Keep pending follow-up work and active goals `working`. Treat interrupted turns and replayed results as `idle` rather than new results.
- Preserve the existing iTerm2 OSC 21337 labels and indicators, mapping `done` and `error` to `Idle`.
## Testing
Add lifecycle and input-acknowledgment tests covering approvals, completion, failure, interruption, replay, pending follow-ups, and active goals. Extend blocking-request assertions and terminal protocol snapshots for the new states and reasons.
GitOrigin-RevId: 90bad1d54d8b3b9e3cec66fbd3bf3df0c42b995b
## Why
Persisted subagent threads could be reported as unavailable when selected after unloading, even though their saved history could be restored.
## What changed
Attempt to resume selected threads marked closed, including those with a cached live channel, and restore their transcript through the existing attachment flow.
## Testing
Extend coverage for V1 and V2 subagents to verify saved transcript restoration, the appropriate direct-input behavior, and reattachment when a close notification from the previous runtime is still queued.
GitOrigin-RevId: f45d16b954ce5f9f30ca4c6c6f640937390dd78d
## What changed
- Add `terminal_columns` and `terminal_rows` buckets to `codex.tui.start`.
- Record `codex.tui.terminal_size` for new turns in the active thread and for resize bucket changes after the terminal size settles for 15 seconds. Reuse launch context and suppress duplicate turn notifications.
- Respect analytics consent for the built-in metrics exporter while allowing explicitly configured OTLP collectors. Apply consent checks to the active exporter across provider replacements.
## Testing
Add coverage for exporter replacement and consent after config reloads. Extend the PTY integration test to verify startup size buckets, turn-start observations, and delayed resize observations with analytics disabled and an explicit OTLP collector.
GitOrigin-RevId: e01a900cd3f04a36731078f725c75374596cb01b
## Why
Pending requests can outlive a session switch, and different threads or connections can reuse request IDs. Replies and resolution notifications must stay associated with the request that prompted them.
## What changed
- Retain the original app-server reply handle for pending and buffered requests, including requests replayed after thread attachment or session reset.
- Scope user input, MCP elicitation, and user verification bookkeeping by thread, and send user input answers to the requesting thread.
- Keep background resolution notifications from dismissing foreground prompts.
- Consume failed replies to closed connections and clear pending replay state without falling through to another request route.
## Testing
Add WebSocket regression tests for direct and buffered approvals with colliding request IDs and replies to closed connections. Extend coverage for foreground prompt preservation and thread-scoped user verification cancellation.
GitOrigin-RevId: 541acb9910e92f6f2e83c27d2a2384185d4f8fec
## Why
Startup configuration warnings can reflect settings from when the background server started, even after those settings have been fixed. A restart lets users refresh the server without leaving the TUI.
## What changed
- Add a confirmed restart action to `/daemon`, warning that active or queued work in other chats may be interrupted. Reconnect automatically and let an in-progress restart finish if the TUI exits.
- Verify that Codex manages a local server before enabling restart, including servers discovered with auto-start disabled and those started by `codex agents`.
- Show a restart hint on the first startup configuration warning for managed servers, preserving the original diagnostic for copying and dismissal.
- Repaint the full surface of centered dialogs to restore background colors over cached blank cells.
## Testing
Add CLI integration coverage for agents startup and restarting a discovered daemon with auto-start disabled. Extend TUI tests for confirmation, cancellation, unmanaged servers, warning hints and dismissal, and dialog background rendering.
GitOrigin-RevId: 8e4319fab84f13bf6e7335deb93364fccaff14a7
## What changed
- Group preferences into Appearance, Notifications, Input, Sessions, and Text selection tabs, with search and links to existing theme, status line, terminal title, and keyboard editors.
- Persist preference changes to the selected local configuration file, apply supported changes immediately, and show save errors, configuration overrides, and restart requirements in the panel.
- Add a delayed notification test and controls for notification timing while preserving custom event filters.
- Add `tui.copy_on_select_clear_selection`, disabled by default, to clear transcript selection highlights only after confirmed automatic clipboard delivery.
- Keep local configuration editors usable while disconnected and prevent held activation keys or buffered input from triggering actions across editor and reconnect transitions.
## Testing
Add regression tests and rendering snapshots for panel navigation, search, dependency states, editor handoffs, offline persistence, notification timers, custom filter preservation, and confirmed-copy deselection.
GitOrigin-RevId: a16d218046060fcb6e61705a803fcd9297266e6e
## Why
Large test futures can occupy their caller's stack frame even when passed directly to `Box::pin`.
## What changed
- Add a non-inlined `box_future` helper and `boxed_future!` macro to construct and box futures outside the caller's poll frame. Use them for heavyweight TUI fixtures and test scenarios.
- Return the shared `App` fixture as `Box<App>` to keep it on the heap.
- Treat `ConnectionAborted` as a closed connection in the realtime speech test server, alongside `BrokenPipe` and `ConnectionReset`.
GitOrigin-RevId: 7bbf2020a5ec12bae8e0365ddf5641deef93b544
## Why
Navigating to another thread discarded side conversations, preventing users from returning to them later.
## What changed
- Keep side conversations and their event listeners, channels, and pending requests across thread switches and session resets.
- Reopen a parent's existing side conversation with `/side` and submit any supplied question there. Resolve side toggles by the current thread's parent relationship.
- Limit explicit return-and-discard behavior to the active side conversation, and shut down retained side conversations when exiting.
## Testing
Extend regression tests to cover reopening a side conversation after navigating away, preserving its listener and pending approval during a reset, and restricting discard selection to the active side.
GitOrigin-RevId: ff80566970414ba190ff650d5e413ef63dc65449
## Why
Clients starting delegated work need to attribute descendant turns to the original turn and retain that attribution through completion and history reads.
## What changed
- Accept optional `parentTurnId` and `rootTurnId` in `turn/start`, and expose `rootTurnId` on returned turns and lifecycle notifications.
- Default new turns to their own root when none is supplied. Preserve the active turn's root when steering, ignoring incoming lineage fields.
- Carry root IDs through completion, interruption, recovery, and fork boundaries, and persist them for paginated history reads. Leave unknown roots null in older history.
- Update protocol schemas and generated TypeScript and Python bindings.
## Testing
Extend coverage for default and explicit roots, steering without changing lineage, interrupted and recovered turns, history reads after restart in both history modes, nested fork pagination, and compatibility with older database writers.
GitOrigin-RevId: f1a570a12bd11742929fd2e8b017e5d35aa07dcb
## Why
Recovering an interrupted turn replaced its original trigger with `retry` and restored only its root lineage from model context. Turns suspended before that context was written could lose their attribution entirely.
## What changed
- Persist regular-turn attribution in `TurnStartedEvent` and compaction resume metadata, including the trigger, parent and root turn IDs, and initiating agent path.
- Restore matching attribution during recovery, keep unknown triggers absent, and retain the model-context root fallback for older records.
- Reconstruct attribution from surviving turns across rollback and late completion or abort events, and clear inherited attribution when spawning a forked agent.
## Testing
Add coverage for repeated cold recovery, suspension before context persistence, legacy rollouts, fresh attribution on subsequent turns, compaction checkpoints, rollback, and late terminal events.
GitOrigin-RevId: 85b5763e8fbd48a1ea2c07cfda8196e63c2cd33a
## What changed
- Remove redundant snapshot fixtures and selected rendering test cases across the TUI.
- Replace several full-output snapshots with direct assertions on messages, popup state, status indicators, and rendered content.
- Consolidate slash-command aliases, command-prefix selection, category titles, and hook events into shared test loops.
- Use shared snapshots for the setup import prompt and paginated transcript overlay across platforms.
GitOrigin-RevId: 461e30ebaf70ba930d91a135d2fc598ee4f04f27