{"version":3,"file":"index.cjs","names":["generateRunId","generateRunId","AIError","ProviderError","REPORT_SCHEMA_VERSION","resolveObservers","computeCost"],"sources":["../../../../../../../packages/ai-live/src/realtime/realtime.ts","../../../../../../../packages/ai-live/src/video/video.ts","../../../../../../../packages/ai-live/src/mock/index.ts","../../../../../../../packages/ai-live/src/index.ts"],"sourcesContent":["import { generateRunId } from \"@warlock.js/ai\";\nimport type {\n  RealtimeOptions,\n  RealtimeReport,\n  RealtimeSession,\n} from \"../contracts/realtime.contract\";\n\n/**\n * Open a live duplex voice session — the stateful primitive of\n * `@warlock.js/ai-live`. Connects through the provided\n * {@link RealtimeOptions.transport} (an OpenAI Realtime WebSocket\n * adapter, a mock in tests), then hands back a {@link RealtimeSession}\n * you drive: push audio/text in, consume the event stream out, and\n * `close()` to end it and receive a `type: \"realtime\"` report for the\n * cost/observability surfaces.\n *\n * Unlike the one-shot `ai.*` verbs, this returns a long-lived session —\n * its closest sibling is `ai.orchestrator`. Keeping the transport\n * pluggable is what lets the session surface ship without hard-wiring a\n * WebSocket dependency.\n *\n * @example\n * const session = await ai.realtime({ transport, model: \"gpt-realtime\", voice: \"alloy\" });\n * session.sendAudio(micChunk, \"audio/pcm\");\n * for await (const event of session.events()) {\n *   if (event.type === \"audio\") speaker.write(event.base64);\n * }\n * const report = await session.close();\n */\nexport async function realtime(options: RealtimeOptions): Promise<RealtimeSession> {\n  const runId = generateRunId(\"realtime\");\n  const startedAt = new Date().toISOString();\n  const startPerf = performance.now();\n\n  const connection = await options.transport.connect({\n    model: options.model,\n    voice: options.voice,\n    instructions: options.instructions,\n  });\n\n  let report: RealtimeReport | undefined;\n\n  return {\n    sendAudio: (base64, mediaType) => connection.sendAudio(base64, mediaType),\n    sendText: (text) => connection.sendText(text),\n    events: () => connection.events(),\n    async close(): Promise<RealtimeReport> {\n      // Idempotent — closing twice returns the first report, never\n      // re-tears-down the connection.\n      if (report) {\n        return report;\n      }\n\n      await connection.close();\n\n      report = {\n        runId,\n        rootRunId: runId,\n        type: \"realtime\",\n        name: options.name ?? \"realtime\",\n        status: \"completed\",\n        startedAt,\n        endedAt: new Date().toISOString(),\n        duration: performance.now() - startPerf,\n        ...(options.sessionId ? { sessionId: options.sessionId } : {}),\n      };\n\n      return report;\n    },\n  };\n}\n","import {\n  AIError,\n  computeCost,\n  generateRunId,\n  ProviderError,\n  REPORT_SCHEMA_VERSION,\n  resolveObservers,\n  stampReportLineage,\n  type BaseReport,\n  type ExecuteResult,\n  type FlowObserveOption,\n  type ModelPricing,\n  type Usage,\n} from \"@warlock.js/ai\";\nimport type {\n  GeneratedVideo,\n  VideoModelContract,\n  VideoModelPricing,\n} from \"../contracts/video.contract\";\n\n/** Parameters for {@link video}. `model` comes from an adapter's `video({ name })`. */\nexport type VideoParams = {\n  model: VideoModelContract;\n  prompt: string;\n  durationSeconds?: number;\n  aspectRatio?: string;\n  resolution?: string;\n  negativePrompt?: string;\n  signal?: AbortSignal;\n  observe?: FlowObserveOption;\n  sessionId?: string;\n  name?: string;\n  options?: Record<string, unknown>;\n};\n\n/** Success payload of a {@link video} run. */\nexport type VideoData = { video: GeneratedVideo };\n\n/** The report node a {@link video} run produces (`type: \"video\"`). */\nexport type VideoReport = BaseReport & {\n  type: \"video\";\n  model: { name: string; provider: string };\n  /** Final clip duration in seconds, when reported. */\n  durationSeconds?: number;\n};\n\n/** Result envelope of {@link video} — the uniform `{ data, error, usage, report }`. */\nexport type VideoResult = ExecuteResult<VideoData> & { type: \"video\"; report: VideoReport };\n\n/**\n * Generate a video from a text prompt — the moving-image verb of the\n * output-modality track. The adapter hides the provider's submit→poll\n * job, so this returns the framework's uniform never-throws envelope:\n *\n * - **Never throws.** Provider failures surface as a typed `AIError`.\n * - **Cost-truth.** `usage.cost` is filled per-second (Sora / Veo) or\n *   per-token, folding into the same `Usage.cost` rollup as everything else.\n * - **Observable.** The completed {@link VideoReport} routes to any\n *   registered `Observer` via the shared `observe` seam.\n *\n * @example\n * const { data, error } = await ai.video({\n *   model: sora.video({ name: \"sora-2\", pricing: { perSecond: 0.1 } }),\n *   prompt: \"a timelapse of a city skyline at dusk, cinematic\",\n *   durationSeconds: 8,\n * });\n * if (!error) download(data.video);\n */\nexport async function video(params: VideoParams): Promise<VideoResult> {\n  const { model, prompt } = params;\n\n  const runId = generateRunId(\"video\");\n  const startedAt = new Date().toISOString();\n  const startPerf = performance.now();\n\n  const usage: Usage = { input: 0, output: 0, total: 0 };\n  let data: VideoData | undefined;\n  let error: AIError | undefined;\n  let status: VideoReport[\"status\"] = \"completed\";\n  let durationSeconds: number | undefined;\n\n  try {\n    const response = await model.generate(prompt, {\n      durationSeconds: params.durationSeconds,\n      aspectRatio: params.aspectRatio,\n      resolution: params.resolution,\n      negativePrompt: params.negativePrompt,\n      signal: params.signal,\n      ...params.options,\n    });\n\n    Object.assign(usage, response.usage);\n    durationSeconds = response.durationSeconds;\n\n    if (usage.cost === undefined) {\n      const cost = computeVideoCost(usage, durationSeconds, model.pricing);\n      if (cost !== undefined) {\n        usage.cost = cost;\n      }\n    }\n\n    data = { video: response.video };\n  } catch (thrown) {\n    error =\n      thrown instanceof AIError ? thrown : new ProviderError(toMessage(thrown), { cause: thrown });\n    status = params.signal?.aborted ? \"cancelled\" : \"failed\";\n  }\n\n  const report: VideoReport = {\n    runId,\n    rootRunId: runId,\n    name: params.name ?? \"video\",\n    type: \"video\",\n    status,\n    error,\n    startedAt,\n    endedAt: new Date().toISOString(),\n    duration: performance.now() - startPerf,\n    usage,\n    children: [],\n    model: { name: model.name, provider: model.provider },\n    ...(durationSeconds !== undefined ? { durationSeconds } : {}),\n    reportSchemaVersion: REPORT_SCHEMA_VERSION,\n  };\n\n  stampReportLineage(report, { rootRunId: runId, sessionId: params.sessionId });\n\n  for (const observer of resolveObservers(params.observe)) {\n    try {\n      await observer.collect(report);\n    } catch {\n      // Isolate observer failures — never break the run.\n    }\n  }\n\n  return { type: \"video\", data, error, usage, report };\n}\n\n/**\n * Price a video run: `perSecond × durationSeconds` (per-second metering,\n * attributed to `cost.output`) wins when configured, otherwise the\n * standard token math. Returns `undefined` when no usable pricing is\n * present.\n */\nfunction computeVideoCost(\n  usage: Usage,\n  durationSeconds: number | undefined,\n  pricing: VideoModelPricing | undefined,\n): ModelPricing | undefined {\n  if (!pricing) {\n    return undefined;\n  }\n\n  if (pricing.perSecond !== undefined) {\n    if (durationSeconds === undefined) {\n      return undefined;\n    }\n    return { input: 0, output: durationSeconds * pricing.perSecond };\n  }\n\n  if (pricing.input !== undefined && pricing.output !== undefined) {\n    return computeCost(usage, { input: pricing.input, output: pricing.output });\n  }\n\n  return undefined;\n}\n\n/** Best-effort message for a non-`AIError` thrown value. */\nfunction toMessage(thrown: unknown): string {\n  return thrown instanceof Error ? thrown.message : String(thrown);\n}\n","import type { Usage } from \"@warlock.js/ai\";\nimport type {\n  RealtimeConnectConfig,\n  RealtimeConnection,\n  RealtimeEvent,\n  RealtimeTransport,\n} from \"../contracts/realtime.contract\";\nimport type {\n  GeneratedVideo,\n  VideoGenerationResponse,\n  VideoModelContract,\n  VideoModelPricing,\n  VideoOptions,\n} from \"../contracts/video.contract\";\n\n/** One scripted response for a {@link MockVideoModel}. */\nexport type MockVideoResponse = {\n  video?: GeneratedVideo;\n  usage?: Usage;\n  durationSeconds?: number;\n  error?: Error;\n};\n\n/** Deterministic {@link VideoModelContract} double for tests — no HTTP, no polling. */\nexport class MockVideoModel implements VideoModelContract {\n  public readonly provider = \"mock\";\n  public readonly calls: { prompt: string; options: VideoOptions | undefined }[] = [];\n\n  private callIndex = 0;\n\n  public constructor(\n    public readonly name: string,\n    private readonly responses: MockVideoResponse[],\n    public readonly pricing?: VideoModelPricing,\n  ) {}\n\n  public async generate(prompt: string, options?: VideoOptions): Promise<VideoGenerationResponse> {\n    this.calls.push({ prompt, options });\n\n    const response = this.responses[Math.min(this.callIndex, this.responses.length - 1)] ?? {};\n    this.callIndex += 1;\n\n    if (response.error) {\n      throw response.error;\n    }\n\n    return {\n      video: response.video ?? {\n        type: \"url\",\n        url: \"https://mock/video.mp4\",\n        mediaType: \"video/mp4\",\n      },\n      usage: response.usage ?? { input: 0, output: 0, total: 0 },\n      durationSeconds: response.durationSeconds ?? options?.durationSeconds ?? 5,\n    };\n  }\n}\n\n/** A recording {@link RealtimeConnection} the mock transport hands back. */\nexport class MockRealtimeConnection implements RealtimeConnection {\n  public readonly sentAudio: { base64: string; mediaType: string }[] = [];\n  public readonly sentText: string[] = [];\n  public closed = false;\n\n  public constructor(private readonly scripted: RealtimeEvent[]) {}\n\n  public sendAudio(base64: string, mediaType: string): void {\n    this.sentAudio.push({ base64, mediaType });\n  }\n\n  public sendText(text: string): void {\n    this.sentText.push(text);\n  }\n\n  public async *events(): AsyncIterable<RealtimeEvent> {\n    for (const event of this.scripted) {\n      yield event;\n    }\n  }\n\n  public async close(): Promise<void> {\n    this.closed = true;\n  }\n}\n\n/** Deterministic {@link RealtimeTransport} double — scripts the event stream, records sends. */\nexport class MockRealtimeTransport implements RealtimeTransport {\n  public readonly connectConfigs: RealtimeConnectConfig[] = [];\n  public lastConnection?: MockRealtimeConnection;\n\n  public constructor(private readonly scriptedEvents: RealtimeEvent[] = []) {}\n\n  public async connect(config: RealtimeConnectConfig): Promise<RealtimeConnection> {\n    this.connectConfigs.push(config);\n    this.lastConnection = new MockRealtimeConnection(this.scriptedEvents);\n    return this.lastConnection;\n  }\n}\n","import { ai } from \"@warlock.js/ai\";\nimport { realtime } from \"./realtime/realtime\";\nimport { video } from \"./video/video\";\n\n/**\n * Augment the shared `Ai` facade with this package's two heavy\n * modalities. Importing `@warlock.js/ai-live` mounts `ai.video` +\n * `ai.realtime` as a side effect, mirroring how `@warlock.js/ai-tools`\n * mounts `ai.mcp` / `ai.tools` and `@warlock.js/ai-workspace` mounts\n * `ai.workspace`.\n */\ndeclare module \"@warlock.js/ai\" {\n  interface Ai {\n    /**\n     * Text-to-video generation (Sora / Veo / Kling-class). Async under\n     * the hood (submit→poll), surfaced as the uniform never-throws\n     * `{ data, error, usage, report }` envelope. Ships in `@warlock.js/ai-live`.\n     */\n    video: typeof video;\n    /**\n     * Live duplex voice sessions (OpenAI Realtime-class). A stateful\n     * session over a pluggable transport — push audio/text in, consume\n     * events out, `close()` for a report. Ships in `@warlock.js/ai-live`.\n     */\n    realtime: typeof realtime;\n  }\n}\n\nai.video = video;\nai.realtime = realtime;\n\nexport { realtime, video };\nexport type { VideoData, VideoParams, VideoReport, VideoResult } from \"./video/video\";\nexport * from \"./contracts/video.contract\";\nexport * from \"./contracts/realtime.contract\";\nexport * from \"./mock\";\n"],"mappings":"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"}