/** * voice-setup.ts, the daemon's managed local-voice setup service, composed * once per runtime (extracted from runtime/services.ts). * * `install()` is SINGLE-FLIGHT: concurrent installs are never meaningful, a * second (and every further) concurrent caller joins the in-progress install's * promise instead of starting parallel multi-hundred-MB downloads. * * `status()` carries LIVE INSTALL PROGRESS: the install verb is plain * request/response, so during a ~209MB provision a surface would otherwise only * render busy→receipt. While an install runs, the provisioner's onProgress * stream is folded into a poll-able snapshot and status() returns it as * `installInProgress` (absent otherwise), surfaces poll status during install; * no streaming infrastructure involved. */ import { type VoiceComponentOutcome, type VoiceKeySupersede, type VoiceProvisionOptions, type VoiceProvisionResult, type VoiceRoundTripProof, type VoiceRuntimeStatus } from '../voice/provisioning/index.js'; import { type WakeModelChunkRequest, type WakeModelChunkResult, type WakeSetupService } from './wake-setup.js'; import type { WakeInstallProvisionOutcome } from '../voice/wake/install-provision.js'; /** What voice.local.install resolves with (the wire receipt). */ export interface VoiceInstallReceipt { /** * True only when the runtime was installed AND proved working by a live * round trip. Bytes on disk are not the claim anyone cares about, see * voice/provisioning/round-trip-proof.ts. */ readonly provisioned: boolean; readonly platform: VoiceProvisionResult['platform']; readonly tts: VoiceProvisionResult['tts']; readonly stt: VoiceProvisionResult['stt']; readonly components: readonly VoiceComponentOutcome[]; readonly configured: { readonly set: readonly { key: string; value: string; }[]; readonly skipped: readonly { key: string; reason: string; }[]; /** Keys taken over from an install this managed runtime replaces. */ readonly superseded: readonly VoiceKeySupersede[]; }; /** * The live proof: a phrase spoken by the managed TTS and read back by the * managed STT. Absent only when STT was not provisioned at all, in which case * there is nothing to prove a round trip with. */ readonly proof?: VoiceRoundTripProof | undefined; /** Plain-language lines a surface prints as-is: what was replaced, what was proven. */ readonly notes: readonly string[]; } export interface VoiceSetupServiceDeps { readonly managedVoiceRoot: string; readonly getConfig: (key: string) => string; readonly setConfig: (key: string, value: string) => void; /** Clear the local engine's tripped circuit breaker after a successful (re-)install. */ readonly resetLocalEngineFailureState: () => void; /** Critical-tier admission gate (MemoryGovernor). */ readonly admitExpensiveWork: (label: string) => { allowed: boolean; reason?: string | undefined; }; /** Provisioner seam (tests inject fetch/extractor via a wrapper). */ readonly provision?: ((options: VoiceProvisionOptions) => Promise) | undefined; /** * The live round-trip proof seam. Injected by tests so no real engine has to * run; defaults to actually speaking a phrase and transcribing it back. */ readonly prove?: ((options: { readonly ttsEngine: string; readonly ttsBinary: string; readonly ttsModelPath: string; readonly sttEngine: string; readonly sttBinary: string; readonly sttModelPath: string; }) => Promise) | undefined; /** Status-read seam (tests). */ readonly readStatus?: ((options: { managedRoot: string; }) => VoiceRuntimeStatus) | undefined; } export interface VoiceSetupService { status(): VoiceRuntimeStatus; install(): Promise; /** Wake-word artifact state, verified by content. See runtime/wake-setup.ts. */ wakeStatus(): ReturnType; wakeProvision(): ReturnType; /** * Install/boot provisioning: fetch whatever is missing, never throw, report one * line. Not admission-gated, unlike {@link wakeProvision}, a host that refused * this under memory pressure would ship an install with no model and no retry * until someone noticed, and the 6 MB it buffers is not what puts a daemon under * pressure. It joins the same single flight, so it cannot double the work either. */ wakeEnsureProvisioned(options?: { readonly recoveryHint?: string | undefined; }): Promise; wakeModelChunk(request: WakeModelChunkRequest): WakeModelChunkResult; } export declare function createVoiceSetupService(deps: VoiceSetupServiceDeps): VoiceSetupService; //# sourceMappingURL=voice-setup.d.ts.map