Skip to content

Follow T3's server config live in the TUI - #22

Merged
krishhgg merged 6 commits into
masterfrom
t3term/nightly-live-provider-config
Oct 10, 2026
Merged

krishhgg merged 6 commits into
masterfrom
t3term/nightly-live-provider-config

Conversation

@krishhgg

@krishhgg krishhgg commented Oct 9, 2026 •

Copy link
Copy Markdown
Owner

The TUI now follows T3's server configuration live, so provider and model changes reach its chips and open menus. Reconnects keep the last configuration until a fresh snapshot arrives. Servers that refuse the subscription retain the existing menu-time reads.

Parent PR #21 has merged. This PR targets master. It also removes the walkthrough requirement at the user's request.

Verification

Sol reviewed and ran these at 15af96bfbdacfccb57e21e7021f4e75ba5f70e1f:

  • git diff --check e15c522..15af96b: passed.

  • cargo fmt --all -- --check: passed.

  • cargo clippy --locked --all-targets -- -D warnings: passed.

  • cargo test --locked: all 293 passed, comprising 274 library, 2 main, 9 CLI and 8 fake-server tests.

  • macOS: SUCCESS

  • Linux build (unsupported): SUCCESS

The new tests exercise the actual RPC client against fake WebSockets and the full App against an offline client. They cover exact empty subscription payloads, cursor-free fresh snapshots, backoff reset, cancellation during connect/retry/stream, request-scoped legacy refusals, preservation of the shared shell watch, live menu/chip changes, selection identity, draft preservation, late unary results and fallback reads. No real T3 server, Keychain or user settings were used. Greptile reviewed the same commit, gave it 5/5 and found no actionable issues.

Decision log

What I noticed

The TUI refreshed provider data at startup and when a menu opened. Provider notices need live configuration even with no menu open.

How I confirmed it

The pinned nightly f570bd21663f56ce94c41829d3b7d72886e25a34 defines subscribeServerConfig with an empty payload, version-1 snapshots and field replacement events. Its client reducer keeps unrelated fields when a delta arrives. The new fake-server and App tests confirm the corresponding Rust behavior.

Options

Use the shared RPC connection with a snapshot-based config watcher. Keep shell and thread subscriptions sequence-based. Preserve unary server.getConfig reads for servers that refuse the config subscription. Polling and a new connection for config were unnecessary.

What review changed

Sol found a formatter difference and requested WebSocket and App coverage. Claude fixed formatting and wrote six WebSocket tests and seven App tests, in addition to the three reducer tests. The compatibility question was checked against T3's request-scoped unknown-method test and refusal frames. Those refusals stop only the config watch and trigger unary fallback. Formatting, Clippy and all tests now pass. Greptile's final review found no actionable issues.

Known limits

This adds no provider banner, setup action, theme subscription or usage-limit action. Configuration survives transient reconnects until a new snapshot. A connection-wide protocol defect still retries as other watchers do; it is not treated as an unknown-method refusal. Compatibility testing uses fake frames and the pinned T3 contract, not a live legacy server. This PR changes no TUI layout and has no new visual captures. The first-ten audit's CI, Greptile context and unrelated CLI output gaps are separate maintenance work.

RetriggerConfidence Score: 5/5

The PR appears safe to merge; no actionable issues were found.

Summary

The TUI follows T3’s server config over the existing shared WebSocket.

  • The TUI follows T3’s provider and model changes while it stays open.
  • Pull requests now use a short description and a five-part decision log.

No actionable issues were found. The diff’s whitespace check passed; this review did not run the test suite.

krishhgg explicitly leaves provider banners, setup actions, theme changes and usage-limit actions out of scope. Connection-wide defects still retry. Live legacy-server testing, new visual captures and unrelated maintenance work are also documented limits.

krishhgg explicitly documents preserving the draft when its provider disappears while its chip shows the thread’s model. krishhgg also explicitly requested removing the walkthrough requirement.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Shared RPC connection] --> B[Config subscription]
  B --> C[Snapshot or field change]
  C --> D[Update held config and revision]
  D --> E[Refresh chips and open menus]
  B --> F[Connection drops]
  F --> G[Keep config and retry]
  G --> B
  B --> H[Request refused]
  H --> I[Read config when menus open]
  J[Unary config answer] --> K{Revision still matches?}
  K -->|Yes| D
  K -->|No| L[Ignore old answer]
Loading

Reviews (1) · Last reviewed commit: "docs: record the live server config in t..." · Reviewed by Greptile

krishhgg and others added 6 commits October 9, 2026 16:11
The user no longer wants a walkthrough for each pull request. Sol's
role loses it, and the pull request rules drop the walkthrough line.
The decision log keeps its five parts, now named in AGENTS.md as
headings instead of pointing at the pr-walkthrough repository.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The TUI read server.getConfig at start and each time a menu opened, so
a provider's status or models changed only when someone opened a menu.
It now subscribes to subscribeServerConfig, with an empty payload so T3
sends none of the theme or usage-limit events t3term doesn't read.

projection::apply_config applies the stream as T3's own client does: a
snapshot replaces the whole configuration, providerStatuses replaces
the whole provider list, and settingsUpdated and keybindingsUpdated
replace their own fields. Changes before any configuration, other
versions and types, and items missing what they change are ignored.

The watcher behind watch_shell and watch_thread now takes a Resume. The
orchestration streams resume after their last sequence as before. The
config stream has no cursor, so it resubscribes with the same empty
payload and gets a fresh snapshot, which also resets the backoff. Every
watcher now stops as soon as its receiver is dropped, including while
it connects or waits to retry.

Menus read server.getConfig only while the TUI has no configuration or
after T3 refused the subscription. Each read carries the count of
changes the subscription had made, and an answer that comes after a
newer change is dropped. A change keeps an open menu's highlight on its
entry and lays the sidebar out again only when its capabilities change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The config subscription now has fake WebSocket tests for its exact
request frame, a fresh snapshot after each drop with no cursor, backoff
that resets on a snapshot, stopping when the receiver goes while it
connects or waits, and both ways T3 refuses it. The unknown-method test
shares one connection with a shell watch, which keeps its items and
never reconnects.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Seven App tests drive the config subscription through the real event
handlers and draw frames on a TestBackend. A runtime that never runs
counts each model-list read the TUI starts, so the tests show which
paths read and which use the copy the TUI holds:

- provider changes reach the chip and the next menu with no read
- an open menu keeps its highlight on the same model as rows move,
  and falls back to the thread's model when that provider goes
- drafts and the composer survive a provider leaving and coming back
- a read that answers after live config is discarded
- a read fills the menu until the first snapshot replaces it
- a reconnect keeps the config, snooze shelf included, until a fresh
  snapshot
- after a refusal, each menu reads once and switching menus reads
  nothing

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The README's model section says the chips and menus follow T3's
provider list, and what happens to a draft whose provider goes. How it
works gains a server config entry: the empty subscription payload, a
fresh snapshot after each drop, the backoff and the getConfig fallback
when T3 refuses. The tests paragraph names the new fake server and TUI
config tests. Sprint row 15 is this pull request, #22.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@krishhgg
krishhgg changed the base branch from t3term/nightly-thread-error-banner to master October 10, 2026 05:09
@krishhgg
krishhgg marked this pull request as ready for review October 10, 2026 05:09
@krishhgg
krishhgg merged commit cb51f8c into master Oct 10, 2026
3 checks passed
krishhgg added a commit that referenced this pull request Oct 10, 2026
#22 merged at cb51f8c while this branch was open, and both added to the
README's tests paragraph and the sprint table. The merge keeps #22's text
and row, adds this branch's sentences after it and fills in row 15's merge
commit, so the record counts 15 merged sprint PRs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
krishhgg added a commit that referenced this pull request Oct 10, 2026
protocol-fidelity now includes src/models.rs, which reads the providers,
models and option descriptors in the server config. The rule and the
instructions no longer say every stream resumes with afterSequence. The
shell and thread subscriptions do, and subscribeServerConfig resubscribes
with an empty payload and starts from a fresh snapshot, as client.rs does
since #22. The audit table in docs/sprint.md records both changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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