feat(chat): model chip in chat header + mobile menu info row; remove "New conversation" and "Show thinking" #68

Closed
opened 2026-07-09 13:10:27 +02:00 by dominik.polakovics · 1 comment

Design was grilled and resolved interactively on 2026-07-09. All decisions below are final; implement as specified.

What

  1. Show the run's model in the chat UI:
    • Desktop (≥640px): a small read-only chip in the chat header, next to the existing state chip (left group, after the title): [←] Title (working) (Sonnet 5 · high) …… [actions].
    • Mobile (<640px): a non-interactive info row pinned at the top of the ••• menu panel — muted styling, no hover state, NOT a role="menuitem" (excluded from keyboard menu navigation), separated from the action items below.
  2. Remove the "New conversation" button and the "Show thinking" toggle from both surfaces (desktop header + mobile ••• menu).

Resolved decisions

  • Truth source: spawn-time model from the run row (runs.model / run().model, already loaded in RunChat via getRun). A mid-session /model switch is knowingly NOT reflected — no backend work.
  • Content: model · effort (mirrors History.tsx:128). Use pretty labels from the provider catalog (GET /providersmodels/efforts option labels, same as the NewRun composer chips), falling back to the raw id when the catalog has no match. Hide the chip/row entirely if run().model is empty (legacy rows).
  • Interactivity: read-only, both surfaces. No model switching.
  • "New conversation" removal depth: remove both UI surfaces AND the now-dead frontend plumbing — clearConfirming state, the two-step confirm UI, and the canClear/onClear prop wiring in RunChat.tsx. Do not touch the backend clear endpoint / provider clear capability.
  • "Show thinking" removal depth: remove both toggles, delete the showThinking signal and props, and make the paint-time filter unconditionally drop thinking blocks (thinking is permanently hidden in the web chat; transcripts on disk keep everything).

Code map (verified 2026-07-09, branch main)

  • web/src/routes/RunChat.tsx — everything chat:
    • ChatHeader component at :779; desktop actions cluster with "New conversation" :912-934 (incl. confirm) and "Show thinking" :937-945.
    • ChatMenu (mobile ••• panel) at :1026; menu items Show/Hide thinking :1077-1088, New conversation… + confirm :1103-1137.
    • showThinking signal at :126; thinking filtered at paint via hiddenThinking :622-623, applied :690.
    • run().model / run().provider / run().effort in scope (resource at :89-92); providers list loaded at :95; runProvider() at :491-497.
  • web/src/base.css.chip base class :723; mobile-first hiding of .chat-desktop-actions/.chat-state-chip :2562-2568; chat-menu panel styles :2570-2593; desktop @media (min-width: 640px) flip :2882-2904. The new desktop chip should hide <640px the same way .chat-state-chip does.
  • web/src/api.tsRun.provider/model/effort :421-439; Provider/listProviders :356-370.
  • Format precedent: web/src/routes/History.tsx:128 ({model} · {effort}).

Acceptance

  • Desktop chat header shows a muted read-only model · effort chip beside the state chip; nothing shown when model is empty.
  • Mobile ••• menu opens with the info row at top; row is skipped by arrow-key navigation and has no hover/active affordance.
  • "New conversation" and "Show thinking" appear nowhere in the chat UI; rg -n "showThinking|clearConfirming|canClear|onToggleThinking" web/src returns nothing.
  • Thinking blocks never render in the chat transcript.
  • Backend clear path untouched (web diff only).
Design was grilled and resolved interactively on 2026-07-09. All decisions below are final; implement as specified. ## What 1. Show the run's model in the chat UI: - **Desktop (≥640px):** a small read-only chip in the chat header, next to the existing state chip (left group, after the title): `[←] Title (working) (Sonnet 5 · high) …… [actions]`. - **Mobile (<640px):** a **non-interactive info row pinned at the top of the ••• menu panel** — muted styling, no hover state, NOT a `role="menuitem"` (excluded from keyboard menu navigation), separated from the action items below. 2. Remove the **"New conversation"** button and the **"Show thinking"** toggle from both surfaces (desktop header + mobile ••• menu). ## Resolved decisions - **Truth source:** spawn-time model from the run row (`runs.model` / `run().model`, already loaded in RunChat via `getRun`). A mid-session `/model` switch is knowingly NOT reflected — no backend work. - **Content:** `model · effort` (mirrors History.tsx:128). Use pretty labels from the provider catalog (`GET /providers` → `models`/`efforts` option labels, same as the NewRun composer chips), falling back to the raw id when the catalog has no match. Hide the chip/row entirely if `run().model` is empty (legacy rows). - **Interactivity:** read-only, both surfaces. No model switching. - **"New conversation" removal depth:** remove both UI surfaces AND the now-dead frontend plumbing — `clearConfirming` state, the two-step confirm UI, and the `canClear`/`onClear` prop wiring in RunChat.tsx. **Do not touch** the backend clear endpoint / provider clear capability. - **"Show thinking" removal depth:** remove both toggles, delete the `showThinking` signal and props, and make the paint-time filter unconditionally drop thinking blocks (thinking is permanently hidden in the web chat; transcripts on disk keep everything). ## Code map (verified 2026-07-09, branch main) - `web/src/routes/RunChat.tsx` — everything chat: - `ChatHeader` component at `:779`; desktop actions cluster with "New conversation" `:912-934` (incl. confirm) and "Show thinking" `:937-945`. - `ChatMenu` (mobile ••• panel) at `:1026`; menu items Show/Hide thinking `:1077-1088`, New conversation… + confirm `:1103-1137`. - `showThinking` signal at `:126`; thinking filtered at paint via `hiddenThinking` `:622-623`, applied `:690`. - `run().model` / `run().provider` / `run().effort` in scope (resource at `:89-92`); providers list loaded at `:95`; `runProvider()` at `:491-497`. - `web/src/base.css` — `.chip` base class `:723`; mobile-first hiding of `.chat-desktop-actions`/`.chat-state-chip` `:2562-2568`; chat-menu panel styles `:2570-2593`; desktop `@media (min-width: 640px)` flip `:2882-2904`. The new desktop chip should hide <640px the same way `.chat-state-chip` does. - `web/src/api.ts` — `Run.provider/model/effort` `:421-439`; `Provider`/`listProviders` `:356-370`. - Format precedent: `web/src/routes/History.tsx:128` (`{model} · {effort}`). ## Acceptance - Desktop chat header shows a muted read-only `model · effort` chip beside the state chip; nothing shown when model is empty. - Mobile ••• menu opens with the info row at top; row is skipped by arrow-key navigation and has no hover/active affordance. - "New conversation" and "Show thinking" appear nowhere in the chat UI; `rg -n "showThinking|clearConfirming|canClear|onToggleThinking" web/src` returns nothing. - Thinking blocks never render in the chat transcript. - Backend clear path untouched (`web` diff only).
Author
Owner

This was generated by AI while landing a PR.

Landing audit — PR #69 (afk/68) → VERDICT: PASS

Verification signal: No readable CI/forge token in this session, so nothing pre-vouched — ran the project's own checks on the PR head (dc66f7e):

  • npm run test546/546 across 37 files (incl. the 5 new model-chip tests)
  • npm run lint → clean
  • npm run build (tsc --noEmit + vite) → clean

Mergeability: origin/main is an ancestor of afk/68 — merges cleanly, no conflict.

Convention & AFK contract: Title is Conventional Commits (feat(chat): …); body carries a working Closes #68.

Diff review (web-only: RunChat.tsx, RunChat.test.tsx, base.css): Matches every resolved decision on this issue —

  • Desktop .chat-model-chip: muted, display:none <640px and inline-block ≥640px (same gate as the state chip); catalog pretty label with raw-id fallback; hidden on empty model; no dangling separator on empty effort.
  • Mobile .chat-menu-info: non-interactive role="none" div pinned atop the ••• panel, set off by a bottom border; excluded from [role=menuitem] navigation.
  • Removals: showThinking, clearConfirming/clearing, canClear/clearCommand/sendClear, composerLocked, and all prop wiring gone; thinking dropped unconditionally at paint (stream + expanded tool groups) while grouping still runs over the full list.
  • Acceptance grep rg -n "showThinking|clearConfirming|canClear|onToggleThinking" web/src → no matches; no dangling refs to any other removed symbol.

No blockers. Awaiting explicit free-text merge go-ahead.

> *This was generated by AI while landing a PR.* **Landing audit — PR #69 (`afk/68`) → VERDICT: PASS** **Verification signal:** No readable CI/forge token in this session, so nothing pre-vouched — ran the project's own checks on the PR head (`dc66f7e`): - `npm run test` → **546/546** across 37 files (incl. the 5 new model-chip tests) - `npm run lint` → clean - `npm run build` (`tsc --noEmit` + vite) → clean **Mergeability:** `origin/main` is an ancestor of `afk/68` — merges cleanly, no conflict. **Convention & AFK contract:** Title is Conventional Commits (`feat(chat): …`); body carries a working `Closes #68`. **Diff review (web-only: `RunChat.tsx`, `RunChat.test.tsx`, `base.css`):** Matches every resolved decision on this issue — - Desktop `.chat-model-chip`: muted, `display:none` <640px and `inline-block` ≥640px (same gate as the state chip); catalog pretty label with raw-id fallback; hidden on empty model; no dangling separator on empty effort. - Mobile `.chat-menu-info`: non-interactive `role="none"` div pinned atop the ••• panel, set off by a bottom border; excluded from `[role=menuitem]` navigation. - Removals: `showThinking`, `clearConfirming`/`clearing`, `canClear`/`clearCommand`/`sendClear`, `composerLocked`, and all prop wiring gone; thinking dropped unconditionally at paint (stream + expanded tool groups) while grouping still runs over the full list. - Acceptance grep `rg -n "showThinking|clearConfirming|canClear|onToggleThinking" web/src` → no matches; no dangling refs to any other removed symbol. No blockers. Awaiting explicit free-text merge go-ahead.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Cloonar/coding-lab#68
No description provided.