Files
OpenResearch/ui
Daniel Kim 5228228b2d Auto-generate and animate chat session titles (v0.1.84) (#135)
* Auto-generate chat session titles from the first message

Chat sessions were titled with a 64-char truncation of the first user
message. Now the first message also kicks off a short-lived headless
harness child that names the session, in parallel with the turn.

- store: new chat_sessions.title_source column ('fallback' / 'generated'
  / 'user'; NULL on legacy rows) via the best-effort ALTER pattern.
  set_chat_session_title takes a source; set_chat_session_title_if_empty
  becomes set_chat_session_title_if_placeholder — one conditional UPDATE
  that lets a generated title replace the placeholder while a user
  Rename, a legacy title, and an already-generated title all stand.
- harness: defaulted Harness::generate_title, implemented for Claude
  (claude -p --model haiku --max-turns 1) and Codex (codex exec --json
  at low reasoning effort). Both children run tool-less and MCP-less,
  hermetically in a temp cwd, under a shared TITLE_TIMEOUT. Prompt and
  output sanitizer live in the new harness/title.rs so both halves are
  unit-testable; opencode and cursor keep the default.
- opencode fix: TurnCtx::set_title's if-empty check could never fire —
  the placeholder write always beat it — so native opencode titles were
  silently dropped. The provenance check revives them, and the seed
  title opencode stamps on every new session ("New session - <ts>") is
  now skipped so it can't latch and block the real one.
- chat: one emit_session helper for the re-read/resolve-busy/broadcast
  sequence shared by set_archived, set_title and auto-titling; the
  placeholder now takes the first non-empty line.

No UI changes: the existing chat.session SSE upsert re-renders Recents.

* Animate the reveal of auto-generated session titles

An auto-title used to pop into the sidebar with no acknowledgement that
anything happened. Now it materializes character by character.

- session_json gains "titleSource" so the UI can tell a harness-generated
  title from a placeholder or a user rename.
- New TitleReveal component, used by both the Recents row and the chat
  header so the effect is identical in each. Characters are aria-hidden
  behind an aria-label — a screen reader hears one title, not forty
  single-letter spans — and render as a plain string when not animating.
- The reveal plays only on a live chat.session event that changes a title
  we already had on screen, and only for titleSource "generated": renames
  and page loads swap silently. A per-session nonce remounts the spans so
  a second retitle replays rather than sitting on a finished animation.
- CSS: 240ms per character, 14ms stagger capped at 500ms, fading in from
  blurred and slightly below. No color, no scale, no layout shift, and
  @media (prefers-reduced-motion: reduce) turns it off entirely.

* Trim the skills catalog from codex title requests

The plugin/skills catalog injected ~6k prompt tokens (24.3k -> 18k input
measured) into a one-line title request that ignores it.

* Strip the agent system prompt from claude title requests

--system-prompt replaces the ~8.5k-token Claude Code scaffolding with one
sentence (measured 8.5k -> 1.9k input tokens; wall time unchanged at ~3s,
which is node boot + one API round trip).
2026-07-27 18:22:18 -07:00
..
2026-07-06 20:05:41 -07:00
2026-07-06 20:05:41 -07:00
2026-07-06 20:05:41 -07:00