Add Brave browser detection to pwaUtils.ts since Brave exposes the
SpeechRecognition API but silently blocks it from returning results,
causing false positive feature detection.
- Add `Is.Browser.Brave` detection via `navigator.brave` property
- Update `browserSpeechRecognitionCapability()` to mark Brave as
unsupported with a clear warning message
- Gate Call button (both mobile and desktop) on speech recognition
capability since Call fundamentally requires voice input
- CallWizard already displays capability warnings, so Brave users
navigating directly to /call will see a clear explanation
Closes#1061
Co-authored-by: Enrico Ros <enricoros@users.noreply.github.com>
Refactor the AIX client streaming pipeline for Zustand-style immutability
and clean outcome classification, preparing for the agentic execution layer.
ContentReassembler:
- All fragment mutations go through _pushFragment/_replaceFragmentAt/_spliceFragment
(new array refs per update, no in-place mutation)
- Generator fields (genModelName, genProviderInfraLabel, genUpstreamHandle,
legacyGenTokenStopReason) consolidated into a single `generator` object,
replaced immutably when particles arrive
- _classifyTermination() replaces _deriveTokenStopReasonOrAppendError() -
pure function returning { outcome, tsr, errorMessage }
- finalizeReassembly() returns AixChatGenerateContent_LL_Result (extends
streaming type with outcome + cgMetricsLg) instead of void
- Initial state snapshot for full reset (replaces initialGenerator field)
Type system:
- AixChatGenerateContent_LL: streaming-only (fragments + generator)
- AixChatGenerateContent_LL_Result: extends LL with outcome + cgMetricsLg
- AixChatGenerateTerminal_LL: 'completed' | 'failed' | 'aborted'
- Outcome flows LL -> L2 -> L3 without leaking into DMessage/stores
- Unified vocabulary throughout (no more success/errored mapping)
LL streaming loop:
- Restructured with break/continue for guaranteed finalizeReassembly()
- Drain in-flight processing before retry/terminal decisions
- Abort-during-retry-backoff surfaces original error (not 'aborted')
- Retryable path first, terminal fallthrough
Callers:
- Remove structuredClone() calls (structural sharing makes them unnecessary)
- Spread fragments/generator directly into stores
Also includes:
- move Accumulator inside the Reassembler
- drain in-flight before client-retry
- improved continue/retry visualizations
- retrier has less status inside (removed resume handle, now external)
Fixes#1055