import { VoiceSessionSnapshot } from '../voice/voiceSession'; /** * A problem worth TELLING the user about that does not warrant killing the * session. * * These exist because the previous behaviour was the failure mode this whole * feature keeps hitting: the overlay said "Listening…" while the recogniser was * dead, and nothing anywhere said otherwise. `useVoiceInput` reports `network` * and `unknown` and the session ignored both. */ export type VoiceSessionNotice = "network" | "not-capturing" | "nothing-heard" | "recognition-failed"; interface Options { /** Send a turn. The reply is observed via `latestReply`, not returned here. */ /** * Send a turn. * * ★ The session id is handed over HERE rather than exposed for the parent to * read, so the value that stamps the turn is the one live at the instant it * was spoken. A parent reading an exposed id would sample it a render later, * which is a race the very first turn of a session is most likely to lose. */ onSubmit: (text: string, voiceSessionId: string) => void; /** * Id + text of the newest assistant reply. A CHANGE of id is what advances * the session out of `thinking` — the text alone is not enough, because two * consecutive replies can be identical. */ latestReply: { id: string; text: string; } | null; /** Language the user is speaking, so the recogniser is pointed correctly. */ language: string; } /** * Drives a live voice conversation (BOFF-7120). * * Deliberately thin: the loop itself is `voiceSessionReducer`, which is pure and * tested, and playback is the assistant's EXISTING auto-speak path rather than a * second speaking mechanism. Reusing auto-speak is what keeps the "never speak a * reply in a language this device has no voice for" guarantee from BOFF-7106/7107 * true inside the session too — a bespoke playback path here would have quietly * bypassed all of it. * * What this hook owns is only the parts a reducer cannot: the silence timer, the * microphone's lifetime, and turning "auto-speak is currently on" back off again * when the session ends. */ export declare function useVoiceSession({ onSubmit, latestReply, language }: Options): { session: Readonly; /** A recoverable problem worth showing, or null when all is well. */ notice: VoiceSessionNotice | null; /** * The reply as it is being spoken, chunk by chunk — for the live caption. * * Relayed from the speech provider rather than read there directly by the * UI, because the voice session is already this hook's contract with the * component and a second speech consumer would be a second way for the two * to disagree about what is playing. */ spokenChunks: { chunks: string[]; index: number; } | null; /** Whether the microphone is genuinely capturing right now. */ capturing: boolean; /** * True once started and not yet ended — what decides whether to render. * * ★ A failure keeps it true. `fail` sets phase `ended`, so this used to go * false the instant the microphone was refused and the panel vanished * without ever saying why. `end` clears the error, which is how the user * dismisses it. */ active: boolean; /** The user has cut the assistant off and capture has not resumed yet. */ interrupting: boolean; /** Quiet has fallen and the correction window is running. */ awaitingEndpoint: boolean; /** Can a session be offered at all on this device? */ available: boolean; start: () => void; end: () => void; toggleMute: () => void; interrupt: () => void; }; export {}; //# sourceMappingURL=useVoiceSession.d.ts.map