export type SonioxConfig = { apiKey: string; model: string; terms: string[]; /** BCP-47 language hints sent to Soniox. Without them the model * auto-detects PER UTTERANCE and can drift — observed 2026-07-18: "Koi, * when was the last time Miguel logged in" transcribed as "各位,我们 was * the last time…" (Mandarin), so the wake word never matched and every * request was blocked as unaddressed. */ languageHints: string[]; }; /** Parse KEY=VALUE lines (the ~/.skykoi/.env format the mac daemon reads). */ export declare function parseDotenv(raw: string): Record; export declare function resolveSonioxConfig(env?: NodeJS.ProcessEnv, dotenvText?: string): SonioxConfig | null; /** Same transcript hygiene as the daemon: drop STT static and filler. */ export declare function isBlankAudio(text: string): boolean; /** * Parse `ffmpeg -list_devices true -f dshow -i dummy` stderr into audio * device names, in listing order (first = the default-ish pick). */ export declare function parseDshowAudioDevices(stderr: string): string[]; type FlushedSegment = { text: string; speaker: string | null; early?: boolean; }; /** * Accumulates Soniox final tokens into utterance segments, flushing on the * ""/"" endpoint markers — a straight port of the daemon's * handle()/flushSegment() pair, factored pure for tests. * * EARLY EMIT: the endpoint marker only arrives after ~0.5-1s of trailing * silence — dead time for spoken control words. When `earlyMatch` is given * and the ACCUMULATING text already matches (e.g. "koi, pause the video"), * the segment is emitted immediately (marked `early`), once per segment. * The normal endpoint flush still emits the full utterance afterwards; * downstream dedup makes the double emission a no-op. */ export declare class SegmentAssembler { private readonly earlyMatch?; private text; private counts; private earlyEmitted; constructor(earlyMatch?: ((text: string) => boolean) | undefined); /** Feed one Soniox message's tokens; returns any segments it completed. */ push(tokens: Array>): FlushedSegment[]; /** Text committed so far in the CURRENT (unflushed) segment. */ currentText(): string; private flush; } /** * Start the always-on listener. Missing prerequisites never give up: they are * announced ONCE (JSONL error line + log) and re-checked every minute, so a * key that arrives later — org provisioning landing, or the person pasting * one into ~/.skykoi/.env — brings the ears up without a restart. */ export declare function startWindowsAudioCapture(): { stop: () => void; }; export {};