diff --git a/docs/client/architecture.md b/docs/client/architecture.md index a573884..e4fbe48 100644 --- a/docs/client/architecture.md +++ b/docs/client/architecture.md @@ -57,7 +57,8 @@ audio. It is not an unconditional byte-for-byte tunnel. | [client.ts](../../vocero-frontend/src/realtime/client.ts) | Realtime protocol, session lifecycle, audio and transcript events | | [components](../../vocero-frontend/src/components) | Chat, caller profile, settings and voice components | | [audio](../../vocero-frontend/src/audio) | TypeScript capture/playback worklets, PCM codec, and visualizer | -| [legacy-theme.css](../../vocero-frontend/src/styles/legacy-theme.css) | Retained themes and responsive visual styles alongside Tailwind | +| [legacy-theme.css](../../vocero-frontend/src/styles/legacy-theme.css) | Theme tokens, voice artwork and component appearance | +| [layout.css](../../vocero-frontend/src/styles/layout.css) | Shared responsive layout, transcript sizing and reduced-motion behavior | ## Server routes @@ -95,6 +96,12 @@ describe service-owned structure and retain loose upstream values. See 4. Assistant PCM16 audio at the current 16 kHz protocol rate is decoded and sent to [audio-playback.worklet.ts](../../vocero-frontend/src/audio/audio-playback.worklet.ts), which buffers, resamples and fades playback edges. Input speech can clear playback for barge-in. + The client flushes short final chunks on response completion and remains in + the speaking state until the worklet reports that playback has drained. + Sequence numbers reject drain notifications from superseded playback. + +Microphone meter subscribers are separate from application-state subscribers, +so level updates do not rerender the main React tree. Audio worklets are loaded through `AudioWorklet.addModule`; keep their processor registration structure intact when editing them. The speech backend's thread @@ -105,6 +112,8 @@ and cancellation model is documented in [realtime API](../speech/realtime-api.md The browser triggers external reasoning on completed user transcripts only in `OPENAI` mode. A non-empty answer replaces the native response through the external-answer path. These HTTP operations supplement the realtime audio path. +New user speech and session teardown cancel pending reasoning. Turn identity +checks reject stale HTTP results and speech callbacks even if cancellation is late. Read [reasoning](reasoning.md), [context injection](context-injection.md), and [tool calling](tool-calling.md) for the conditions and limitations of each path. diff --git a/docs/client/usage.md b/docs/client/usage.md index 12764ef..b7095ad 100644 --- a/docs/client/usage.md +++ b/docs/client/usage.md @@ -117,6 +117,10 @@ browsable pages. Voice, editable system instructions and connection settings are kept in browser `localStorage` under `s2s.ws.*` keys. A non-empty `S2S_PRIMARY_PROMPT` pins the instruction field. Restart applies connection/voice changes to a new session. +Settings and tool preferences use a draft: **Guardar** applies them and +**Cancelar** or dialog dismissal discards unsaved edits. Voice and instructions +update the live session on Save; connection changes apply on the next start. +Noise-gate calibration is explicitly live and saves immediately. Model voice names are runtime identifiers and stay unchanged across UI translations. @@ -135,19 +139,33 @@ enabled data sources and limits. `S2S_THEME=white` selects the light interface. `dark` or an empty value selects the dark aurora theme. Theme-specific sections remain hidden until configuration resolves, with a fallback to avoid an invisible page after config failure. +Configuration failures offer **Reintentar** and block session startup until a +retry succeeds. Reports load independently. Caller context gets an eight-second +loading window before the interface allows a generic session. `S2S_START_SESSION_MODE` controls initial microphone/session startup: | Value | Behavior | |---|---| | Empty/default | User taps to start | -| `TALK` | After a 2-second warmup, show an audio unlocker; a user gesture starts the session and greeting | -| `TALKFIRST` | After a 2-second warmup, attempt automatic start and inject the Spanish wake phrase; microphone failure falls back to the unlocker | +| `TALK` | After a 2-second warmup, show a dismissible startup dialog; a user gesture starts the session and greeting | +| `TALKFIRST` | After a 2-second warmup, attempt automatic start and inject the Spanish wake phrase; microphone failure falls back to the startup dialog | -The warmup is a timer, not proof that all upstream context requests have -finished. Browser permission and audio policies can still require a gesture. +The warmup starts after configuration and caller-context loading settle; +optional reports and tools can still be loading. Browser permission and audio +policies can still require a gesture. The greeting uses the same `hola vocero` input as wake-word handling. +On browsers with speech recognition, **Activar con «hola vocero»** opts into +wake-word listening for the current page session. The interface shows when the +microphone is listening for that phrase. It is off by default, pauses while a +dialog or voice session is active, and turns off when the conversation stops. + +The transcript keeps your reading position when new messages arrive. **Ir al +último mensaje** resumes following the conversation. Names and Santiago-local +times appear with each message; downloaded JSON and text retain raw timestamps +and message text. The interface respects the browser's reduced-motion setting. + ## Queue and session lifecycle Load-balancer mode proxies `POST /api/session`. A free compute slot returns a @@ -161,8 +179,9 @@ to a keepalive fetch. Expired tickets and missed join deadlines require a new attempt. Full queues return `503` with `state: "at_capacity"`. Once connected, session teardown closes the microphone, audio graph and -WebSocket. The 30-second inactivity timeout remains active when the assistant -is not speaking. Caller-profile lookup and upstream authorization operate +WebSocket. The 30-second inactivity timeout counts time waiting for user input; +processing, external reasoning and buffered playback do not consume it. +Caller-profile lookup and upstream authorization operate independently of allocation and use their existing configured endpoints. For external transcript processing, configure the selected diff --git a/vocero-api/CHANGELOG.md b/vocero-api/CHANGELOG.md index 6f994e3..376e5d8 100644 --- a/vocero-api/CHANGELOG.md +++ b/vocero-api/CHANGELOG.md @@ -9,6 +9,11 @@ the implementation at the recorded date; current operating instructions live in ### Fixed +- Consolidate responsive transcript layout, keep export controls visible on narrow screens, + and place feedback and version details below the conversation. Add jump-to-latest, + semantic message metadata, state-aware empty hints, shared sanitized Markdown rendering, + and reduced-motion support. Remove retired camera, account, and overlay styles. + - Use native dialogs for startup and mobile reports, restore focus on dismissal, and make duplicate transcript bubbles inert. Require explicit wake-word opt-in, show when it is listening, and turn it off when the conversation stops. diff --git a/vocero-frontend/src/App.tsx b/vocero-frontend/src/App.tsx index 4333978..4df3617 100644 --- a/vocero-frontend/src/App.tsx +++ b/vocero-frontend/src/App.tsx @@ -208,11 +208,6 @@ export default function App() { )} - {state.error && (