import type { MusicProvider } from "./types.js";
/**
 * Lyria 3 Pro music/BGM provider via OpenRouter.
 *
 * Ports the (deleted) music_generate.py logic to TS. Unlike Seedance's async
 * videos job, Lyria streams synchronously over the OpenAI-compatible
 * chat/completions endpoint:
 *
 *   POST https://openrouter.ai/api/v1/chat/completions
 *   body { model: "google/lyria-3-pro-preview", modalities: ["text","audio"],
 *          messages: [{ role: "user", content: [...refImages, {type:"text",text}] }],
 *          stream: true, ...(seed) ...(temperature) }
 *
 * The SSE response is line-framed: `data: {json}` chunks terminated by
 * `data: [DONE]`, interspersed with `: OPENROUTER PROCESSING` heartbeat lines
 * (which do NOT start with "data: " and are skipped). Audio arrives base64-
 * encoded in `delta.audio.data` (primary, verified live 2026-06-10 — a single
 * ~1.8 MB ID3/MP3 chunk for a ~74s clip); a `delta.images[].image_url.url`
 * `data:audio/...;base64,...` fallback covers other audio models. Chunks are
 * b64-decoded and joined into the final mp3 bytes.
 *
 * There is NO duration parameter — Lyria emits a full ~1–2 minute track at a
 * flat ~$0.08/track. The server endpoint optionally truncates with ffmpeg.
 *
 * Defenses (mirror gemini-tts.ts): a non-OK status throws; a 200 whose
 * content-type is text/JSON is an error envelope (no audio) and throws; an
 * in-stream `error` chunk throws; zero collected audio bytes throws rather than
 * writing a silent 0-byte file.
 *
 * Falls back to a stub (no network) when no apiKey is provided, so a keyless
 * install never crashes — mirrors createSeedanceProvider.
 */
export declare const LYRIA_URL = "https://openrouter.ai/api/v1/chat/completions";
export declare const LYRIA_MODEL = "google/lyria-3-pro-preview";
/**
 * Discriminable error for the "200 SSE but 0 audio bytes" failure (D2,
 * PRD-0009). Lyria intermittently streams a clean 200 whose chunks carry no
 * audio bytes; the provider throws rather than writing a silent 0-byte file
 * (correct — never persist a broken asset). The BGM route catches THIS specific
 * type to do a single automatic retry + emit a UPSTREAM_EMPTY_AUDIO 502 with an
 * actionable message. A `.code` tag means the route never has to string-match a
 * human message (which would silently break if the wording changed).
 */
export declare class EmptyAudioError extends Error {
    name: string;
    readonly code: "EMPTY_AUDIO";
    constructor(message?: string);
}
/** Type-guard the route uses to decide whether to retry (avoids instanceof
 *  pitfalls across module/realm boundaries — the `.code` tag is canonical). */
export declare function isEmptyAudioError(err: unknown): err is EmptyAudioError;
export interface LyriaProviderDeps {
    /** Injectable fetch so tests never hit the network. */
    fetch?: typeof globalThis.fetch;
    /** Override OpenRouter URL (for testing). */
    baseUrl?: string;
}
export declare function createLyriaProvider(constructorKey: string, deps?: LyriaProviderDeps): MusicProvider;
export declare const lyriaProvider: MusicProvider;
//# sourceMappingURL=lyria.d.ts.map