import { ReactNode } from 'react'; import { Color } from 'three'; import { SDKRouterClient, ChatMessage } from '@sdkrouter/client'; type LiquidOrbMode = 'idle' | 'listening' | 'thinking' | 'speaking'; type PulseType = 'success' | 'error' | 'info'; interface AudioFrame { low: number; mid: number; high: number; volume: number; } type QualityTier = 'high' | 'medium' | 'low'; interface OrbParams { noiseFrequency: number; noiseAmplitude: number; noiseSpeed: number; breathSpeed: number; breathAmplitude: number; distortion: number; color1: string; color2: string; /** Pre-parsed Color objects — written by useOrbController, read by useOrbUniforms (avoids hex parse per frame) */ _color1?: Color; _color2?: Color; emissiveIntensity: number; glowOpacity: number; glowScale: number; iridescence: number; } interface AudioReactivityConfig { lowGain: number; midGain: number; highGain: number; volumeGain: number; smoothAttack: number; smoothRelease: number; emissiveGain: number; } declare const DEFAULT_AUDIO_REACTIVITY: AudioReactivityConfig; interface LiquidOrbConfig { presets?: Partial>>; audioReactivity?: Partial; lerpSpeed?: number; } interface LiquidOrbProps { mode?: LiquidOrbMode; audioSource?: HTMLAudioElement | null; size?: number; config?: LiquidOrbConfig; className?: string; children?: ReactNode; } interface LiquidOrbContextValue { mode: LiquidOrbMode; setMode: (mode: LiquidOrbMode) => void; triggerPulse: (type: PulseType) => void; /** Write mic audio frame data directly into the orb's audio pipeline */ writeAudioFrame: (frame: AudioFrame) => void; } /** * useVAD — Professional Voice Activity Detection hook * * Features: * - Adaptive noise floor detection (auto-calibrates to background noise) * - Speech onset detection with debounce (doesn't trigger on transient sounds) * - Speech end detection with grace period (allows pauses between words) * - Minimum speech duration (ignores very short sounds) * - Energy smoothing (rolling average to avoid jitter) * - Configurable thresholds and timings */ interface VADConfig { /** Silence duration (ms) before triggering speech end. Default 1500 */ silenceTimeout: number; /** Grace period (ms) — if speech resumes within this time, continue. Default 300 */ gracePeriod: number; /** Minimum speech duration (ms) before allowing end detection. Default 500 */ minSpeechDuration: number; /** Maximum recording duration (ms). 0 = unlimited. Default 30000 */ maxDuration: number; /** Base RMS threshold for silence detection. Default 0.015 */ silenceThreshold: number; /** Multiplier above noise floor to detect speech. Default 2.5 */ speechThresholdMultiplier: number; /** Noise floor calibration duration (ms). Default 500 */ calibrationDuration: number; /** Energy smoothing factor (0-1). Higher = more smoothing. Default 0.3 */ smoothingFactor: number; } type ConversationPhase = 'idle' | 'listening' | 'thinking' | 'speaking'; interface UseConversationOptions { /** SDKRouterClient instance with audioUrl + llmUrl configured */ client: SDKRouterClient; /** TTS voice, default 'nova' */ voice?: string; /** LLM model or alias, default '@standard'. E.g. Model.smart() */ llmModel?: string; /** TTS model or alias, default '@cheap'. E.g. AudioModel.quality() */ ttsModel?: string; /** STT model or alias, default '@cheap'. E.g. AudioModel.cheap() */ sttModel?: string; /** System prompt prepended to conversation */ systemPrompt?: string; /** STT language hint (ISO 639-1) */ language?: string; /** Silence duration (ms) before auto-stop recording. Default 600ms for conversation. */ silenceTimeout?: number; /** Advanced VAD config for fine-tuning speech detection */ vadConfig?: Partial; /** TTS mode: 'buffered' (default), 'realtime' (SSE buffered), or 'streaming' (MediaSource real-time playback) */ ttsMode?: 'buffered' | 'realtime' | 'streaming'; /** Called whenever the conversation phase changes */ onPhaseChange?: (phase: ConversationPhase) => void; /** Called when user transcript is ready */ onTranscript?: (text: string) => void; /** Called when assistant response is ready */ onResponse?: (text: string) => void; /** Called on any error */ onError?: (error: Error) => void; /** Called every animation frame with mic FFT data during recording */ onAudioFrame?: (frame: { low: number; mid: number; high: number; volume: number; }) => void; /** Called on each SSE chunk with server-side audio analysis during TTS streaming */ onTTSAudioFrame?: (frame: { low: number; mid: number; high: number; volume: number; }) => void; /** Instructions for gpt-4o-mini-tts to control tone, pacing, and style across chunks */ ttsInstructions?: string; /** Speed of generated audio (0.25 to 4.0, default 1.0) */ ttsSpeed?: number; } interface UseConversationReturn { /** Current conversation phase */ phase: ConversationPhase; /** Main toggle: idle→listen, listening→stop+process, speaking→interrupt */ toggle: () => void; /** Force back to idle */ stop: () => void; /** Full conversation history */ messages: ChatMessage[]; /** Last user transcript */ transcript: string; /** Last assistant response */ response: string; /** Last error message */ error: string | null; /** Current TTS audio element (null when not speaking) */ ttsAudioEl: HTMLAudioElement | null; } declare function useConversation(options: UseConversationOptions): UseConversationReturn; export { type AudioFrame as A, type ConversationPhase as C, DEFAULT_AUDIO_REACTIVITY as D, type LiquidOrbProps as L, type OrbParams as O, type PulseType as P, type QualityTier as Q, type UseConversationOptions as U, type VADConfig as V, type LiquidOrbMode as a, type LiquidOrbConfig as b, type LiquidOrbContextValue as c, type AudioReactivityConfig as d, type UseConversationReturn as e, useConversation as u };