feat(desktop): agent composer cleanup: a quiet model button, names without "Claude", harness marks

Merged
DA
8d ago
+347-244

Dean asked for a cleanup of the agent tab composer. This PR does five things:

  • the model picker loses its border, resting fill, and icon
  • the picker gets a trailing chevron
  • the dot between model and effort goes
  • model names drop the leading "Claude"
  • the menus show the Claude Code and Codex marks in place of the Anthropic and OpenAI logos

He later added that every model-and-effort pair uses one shared ModelLabel.

What changes

Model picker button (agent-model-chip.tsx; the "New agent" draft tab uses the same composer)

  • It is a .toolbar-button now. There is no border and no resting background. The fill shows on hover, on press, and while the menu is open.
  • It has no leading provider icon. It reads "Opus 5.5 High": the name in the body colour, then the effort dimmed in --text-secondary, with no "·". If the fast version is on, "Fast" follows the effort ("Opus 5.5 High Fast").
  • A small muted chevron-down sits at the end. The words truncate before the chevron when the foot is narrow.
  • The button stays a single child of .agent-model-chip inside PromptInputTools, so the context-usage ring PR can add a sibling next to it without touching it.

One ModelLabel (planning/model-label.tsx)

  • It draws every model-and-effort pair the same way: the composer button and a subagent's row, both in an agent tab and in its worker's tab. The row loses the provider logo and the dot.
  • choiceWords, choiceDetail, and choiceLabel in coding-agent-model.ts produce the words. choiceLabel is the plain string used for the Start button's hover hint ("Opus 5.5 High").
  • The model menu's checked row says "High Fast" with no dot.

No "Claude" in model names

  • modelLabel (#shared/model-label.ts) is the one display-name function. It strips a leading "Claude " from both the catalog's name and the readable fallback built from the id.
  • It covers tab names, tooltips, menu rows, Settings ▸ Coding agents, copied-transcript headings, and the main process's notifications.
  • Model ids are untouched, both stored and on the wire. OpenAI names stay whole ("GPT-5.6 Terra").
  • The menus still find a model by its catalog name, so typing "claude" lists the Claude models.

Harness marks (provider-marks.tsx, HarnessMark)

  • Claude Code: Clawd in #D97757, taken verbatim from resources/clawd.svg in Anthropic's own Claude Code VS Code extension (publisher Anthropic, v2.1.296). Anthropic's press kit has only the Claude Code wordmark, which uses the spark. The mark is inline SVG.
  • Codex: OpenAI publishes no vector of the cloud logo. Its official art is webview/assets/codex-app-ga-logo-3e5209898ca3.png (104×104) in OpenAI's own Codex VS Code extension (publisher openai, v26.51007.21434). I scaled it whole to 16, 32, and 48 px (srcSet 1x/2x/3x) and recompressed it losslessly to 724 B, 2.0 KB, and 3.4 KB.
  • The Codex PNGs are separate files in src/renderer/marks/. scripts/build.mjs copies them to dist/renderer/marks/, the way it already copies the Excalidraw fonts. They are not base64 in renderer.js, and CSP img-src 'self' already covers them. The renderer bundle is about 180 B smaller gzipped (677,205 → 677,025; budget 698,487).
  • The orchestrator approved both sources.
  • The composer button and subagent rows show no mark. The model menus and Settings show a mark per model.

Tests

  • Composer: the button has no .provider-mark. Its words come first, the chevron is last and is its only glyph, and it reads "Opus 5.5 High" with "High" in .model-label-detail. The chip reads "Opus 5.5 Low Fast" and "GPT-6.1 Sol Low" across picks.
  • Subagent row: it reads "Sonnet 5.5 Medium", with the effort dimmed and no mark.
  • modelLabel: it drops "Claude " from the catalog name and from the id fallback, and leaves "GPT-5.6 Terra" whole.
  • Settings menu: each row's mark is the harness's own: an svg for Anthropic models and marks/codex-16.png for OpenAI. Searching "claude" finds the Claude models by catalog name.
  • Updated expectations: notifications, tab names, and Start's hint follow the new names.

Frames (headless Chrome: the real AgentComposer, ModelMenu, and TranscriptSubagent over the built styles.css)

Two subagent rows, two composers at rest, and one with its menu open, which shows the open fill and both marks.

DarkLight
darklight

Mac verification

CI could not verify the Mac UI, because a PR builds nothing for the Mac. ./scripts/verify.sh was not run: this was built on a Linux cloud VM. LUKE-159 is the manual Mac pass. ./scripts/check.sh exits 0.

🤖 Generated with Claude Code