← All posts

v0.3.7 — Pluggable Speech Providers, Usage Charts, and Model-Generated Session Titles

Speech is now a provider abstraction with Gemini Live, OpenAI TTS, OpenAI Realtime (preview), local Supertonic-3 (experimental), and a user-defined custom-TTS form. The Usage page gained five charts, the chat header now lets the model rename the current session, and the responsive layout finally keeps every setting reachable from sm to lg.

0.3.7 is a layout-and-voice release. The chat header keeps every action visible across sm, md, and lg, the Settings dialog gets a wider sidebar and in-tab sub-navigation, speech grows from a single Gemini Live path into a pluggable provider system, and the Usage page learns to draw charts.

Model-Generated Session Titles

A new Sparkles button in the chat header (and a matching mobile-menu entry) asks the active model to rename the current session based on its content. The handler snapshots the live messages, feeds a preview to the model with a minimal-reasoning configuration, and writes the cleaned title back via sessions.updateTitle. Tooltip feedback reports "Generating title…", "Renamed to …", or the error message.

Speech & Voice — New Tab, New Providers

Speech is now its own Settings tab, and src/keating/speech.ts exposes a SpeechProvider interface backed by a lazy registry. Built-in providers:

  • Gemini Live — existing audio-out path, refactored behind the interface. Stable.
  • OpenAI TTSgpt-4o-mini-tts, tts-1, and tts-1-hd via /v1/audio/speech, with steerable affect/pace on the mini model. Stable.
  • OpenAI Realtime — full WebRTC duplex: mints an ephemeral session, exchanges SDP, attaches the mic when enabled, and plays the remote audio track. Flagged preview (per-utterance session, untested against your account).
  • Supertonic-3 (local) — wires onnxruntime-web and downloads the 4 ONNX files plus tts.json and unicode_indexer.json from the Hugging Face repo. Flagged experimental: sessions load and warm up, but the text→tokens→duration→vectors→vocoder synthesis pipeline still needs to be ported from the Python supertonic package.
  • Custom TTS — paste any OpenAI-compatible /v1/audio/speech endpoint: label, base URL, model id, voice, provider-key name, and optional API path.

A microphone toggle in the same tab is honored by duplex providers like OpenAI Realtime. The voice tool the agent calls (keating_voice) dispatches to the active provider through the registry instead of hard-coding Gemini.

Usage Charts

The Usage page now includes five panels powered by src/components/UsageCharts.tsx:

  • Topic mix donut — artifacts grouped by topic, recharts PieChart with a shared palette.
  • Feedback signal donut — confident / off-track / confused from learnerState.feedbackHistory.
  • Curriculum timeline — a hand-rolled SVG Gantt across learnerState.sessions (start/end + topics covered), color-matched to the donut.
  • Daily activity heatmap — 12 weeks of sessions/day, GitHub-style grid (also hand-rolled SVG).
  • Coming up — open Verification checklists plus learnerState.weaknesses[] / strengths[]. Honest stand-in for "due" work since storage has no SRS field yet.

Responsive Layout & Settings Navigation

At the md breakpoint the chat header was silently dropping Settings, New Session, History, Speech, and Artifacts: the hamburger was hidden (md:hidden) before the inline icons started showing. All seven action icons now render together from sm upward and the hamburger collapses to xs only; the mobile dropdown gained the missing New Session / Session history entries.

The Settings dialog widened to max-w-5xl with a wider sidebar on md/lg, and the heavy Providers & Models tab gained a sticky chip-style sub-section navigator (Cloud / Visibility / My Models / Custom Providers) with scrollIntoView jumps and per-section scroll-mt-20. The Speech & Voice tab uses the same pattern.

Suggested-Prompts Auto-Load-More

The suggested-prompts strip used to randomize three items and only let the "More" pill swap them out. Pressing the right-arrow at the end of the list now appends fresh suggestions filtered against what's already been shown, growing the strip until the underlying pool is exhausted. The "More" pill follows the same semantics and hides once nothing new is left.

Honest Status: Preview vs. Experimental

The Speech tab uses badge color to tell you exactly where each provider stands. Stable providers ship no badge. Preview means the integration is wired end-to-end but hasn't been validated against a live account in this release — OpenAI Realtime falls here because the per-utterance session pattern needs to mature into a persistent duplex channel. Experimental means the wiring deliberately stops short of a working call — Supertonic-3 falls here because the four ONNX models load fine in browser, but reproducing the Python supertonic package's tokenization, duration alignment, voice-style conditioning, and vocoder windowing in JS is its own follow-up. Picking either provider surfaces a clear error rather than a silent failure.