import { type VerifiedDownloadSpec } from '../provisioning/download-verified.js'; import { type WakeWordModelManifest } from '../provisioning/wake-word-manifest.js'; import type { WakeArtifactStatus, WakeUnavailableReason } from './types.js'; /** Directory layout of the managed wake-word tree. */ export interface ManagedWakePaths { /** `/wake`. */ readonly wakeRoot: string; /** Pinned classifiers, one file per model version. */ readonly modelsDir: string; /** The shared speech-embedding backbone. */ readonly frontEndDir: string; /** User-supplied models, never checksum-pinned. */ readonly customDir: string; /** Session-scoped retained audio, only used when retainAudio is session-temp. */ readonly retainedDir: string; /** The pinned classifier for the resolved version, in onnx form. */ readonly classifierPath: string; /** * The same pinned classifier in TensorFlow Lite form, for a runtime that * cannot load onnx. Provisioned beside the onnx build so the daemon can serve * either form; not required for the detector this SDK runs. */ readonly mobileClassifierPath: string; /** The attribution NOTICE that must travel with the classifier. */ readonly noticePath: string; /** The speech-embedding backbone. */ readonly embeddingPath: string; /** * The attribution NOTICE that must travel with the speech-embedding backbone, * on exactly the terms the classifier's does. * * Three artifacts are redistributed by this tree, the classifier, Google's * Apache-2.0 `speech_embedding` build, and the speech gate, and each carries * an attribution file that a deployment redistributing it must carry with it. * The daemon serves the embedding's bytes over the same chunk path it serves * the classifier's, so fetching one NOTICE and not the others would leave part * of the attribution set on the server it was published from. */ readonly embeddingNoticePath: string; /** * The speech gate `voice.wake.vadThreshold` runs. It lives beside the embedding * rather than with the classifiers because it is front-end infrastructure: one * head shared by every wake model, over the embedding they all consume. */ readonly vadPath: string; /** The speech gate's attribution NOTICE, on the same terms as the other two. */ readonly vadNoticePath: string; } /** Resolve the managed wake-word paths for a model version. */ export declare function resolveManagedWakePaths(managedRoot: string, version?: string): ManagedWakePaths; /** * Content-verified status of one artifact. `verified` means the bytes on disk * hash to the pin, never that the path exists. */ export declare function wakeArtifactStatus(path: string, spec: VerifiedDownloadSpec): WakeArtifactStatus; /** One model the engine should load, resolved to a file. */ export interface ResolvedWakeModelFile { readonly id: string; readonly path: string; /** * True for the managed, checksum-pinned artifact. False for a file loaded from * a custom directory as-is, which `voice.wake.customModelDir`'s description * promises explicitly, because it is the difference between a model whose * bytes were verified and one that was not. */ readonly pinned: boolean; } /** * Turn `voice.wake.models` into files to load. * * The pinned default id resolves inside the managed tree. Any other id resolves * against `voice.wake.customModelDir`, and when that row is EMPTY it falls back * to the managed `custom` directory, the fallback the row's description * promises, implemented here rather than left for each host to re-derive, since * a host that skipped it would look for custom models in the process's working * directory. */ export declare function resolveWakeModelFiles(modelIds: readonly string[], options: { readonly managedRoot: string; readonly customModelDir?: string | undefined; readonly version?: string | undefined; }): readonly ResolvedWakeModelFile[]; /** Whether the wake-word runtime can start, and if not, honestly why. */ export interface WakeProvisionStatus { readonly ready: boolean; readonly reason: WakeUnavailableReason | null; readonly classifier: WakeArtifactStatus; /** * The tflite twin of the classifier. Reported so a surface can say whether the * daemon can serve that form, and deliberately NOT part of {@link ready}: the * detector this SDK runs loads the onnx build, so a host missing only the * tflite is a host that detects. */ readonly mobileClassifier: WakeArtifactStatus; readonly notice: WakeArtifactStatus; readonly embedding: WakeArtifactStatus; /** * The front end's attribution NOTICE. Part of {@link ready} for the same reason * the classifier's `notice` is: an artifact whose attribution is not on disk is * not an artifact this tree may hand to anything, and the daemon hands the * embedding's bytes to browsers. */ readonly embeddingNotice: WakeArtifactStatus; /** The speech gate's head and its NOTICE. */ readonly vad: WakeArtifactStatus; readonly vadNotice: WakeArtifactStatus; /** * The speech gate is on disk and content-verified. Reported SEPARATELY from * {@link ready}: `voice.wake.vadThreshold` defaults to 0, so a detector with no * gate on disk is fully operational, and folding the gate into `ready` would * make every existing installation look broken until it re-provisioned. */ readonly vadReady: boolean; /** Total bytes a fresh provision would download. */ readonly downloadBytes: number; /** The model version these paths resolve to, or null when unpinned. */ readonly modelVersion: string | null; /** * Always true today and surfaced wherever the model is described: the recall * figures behind this model are measured on synthesised speech only. No human * has recorded the wake phrase. */ readonly recallIsSyntheticOnly: boolean; } /** Report what is on disk, verifying by content. Never downloads. */ export declare function wakeProvisionStatus(options: { readonly managedRoot: string; readonly version?: string | undefined; }): WakeProvisionStatus; /** * Which artifact a progress event or outcome is about. * * `mobile-classifier` is the tflite form of the same classifier, a separate * component rather than a detail of `classifier`, so a receipt can report one * landing and the other not. `embedding-notice` and `vad-notice` are the front * end's and the speech gate's attribution files, listed on the same terms as the * classifier's `notice`: three artifacts are redistributed from this tree and * each has its own NOTICE to travel with. */ export type WakeProvisionComponent = 'classifier' | 'mobile-classifier' | 'notice' | 'embedding' | 'embedding-notice' | 'vad' | 'vad-notice'; /** Progress for one artifact during provisioning. */ export interface WakeProvisionProgress { readonly component: WakeProvisionComponent; readonly phase: 'skip' | 'download' | 'verify' | 'done' | 'error'; readonly message?: string | undefined; readonly bytesTotal?: number | undefined; } /** One artifact's outcome. */ export interface WakeComponentOutcome { readonly component: WakeProvisionComponent; readonly state: 'installed' | 'skipped' | 'failed'; readonly path: string; readonly bytes?: number | undefined; /** Honest "got X, want Y" on a checksum failure. */ readonly error?: string | undefined; } export interface WakeProvisionResult { /** * The DETECTOR can run: the onnx classifier, its NOTICE and the embedding all * landed. Deliberately not "every artifact landed", see * {@link mobileFormatReady}, because this is the field a surface renders as * "wake works", and the tflite twin is not something the detector loads. */ readonly ready: boolean; /** The tflite form landed too, so the daemon can serve it. */ readonly mobileFormatReady: boolean; /** * The speech gate landed too. Separate from {@link ready} for the same reason * {@link WakeProvisionStatus.vadReady} is: the detector runs without the gate, * because `voice.wake.vadThreshold` is 0 unless someone turns it on. */ readonly vadReady: boolean; readonly modelVersion: string | null; readonly outcomes: readonly WakeComponentOutcome[]; /** The classifier's attribution NOTICE, which must travel with it wherever it goes. */ readonly noticePath: string | null; /** The front end's attribution NOTICE, on exactly the same terms. */ readonly embeddingNoticePath: string | null; /** Restated at every provisioning boundary, not only in docs. */ readonly recallIsSyntheticOnly: boolean; } export interface WakeProvisionOptions { readonly managedRoot: string; readonly version?: string | undefined; readonly fetchImpl?: typeof fetch | undefined; readonly timeoutMs?: number | undefined; readonly onProgress?: ((progress: WakeProvisionProgress) => void) | undefined; } /** * Download and verify every wake-word artifact. * * Resumable: re-running after a partial or interrupted provision re-checks each * artifact by content and fetches only what does not already match. An artifact * present but failing its checksum is REPLACED, never used, a truncated or * mismatched download is a re-fetch, and if the re-fetch also fails the result * says so rather than reporting success over a bad file. */ export declare function provisionWakeWordModels(options: WakeProvisionOptions): Promise; /** * The wake-phrase model's user-facing description, including the qualification * that must accompany every surfacing of it. * * Wherever a surface names the model, it names this too. The recall figures are * measured entirely on text-to-speech output, no human has recorded the phrase * "hey goodvibes", so quoting a recall number without this sentence would * present a synthetic result as a real one. */ export declare function describeWakeModel(model: WakeWordModelManifest): string; //# sourceMappingURL=provisioning.d.ts.map