@broberg/ai-sdk 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -13,7 +13,7 @@ interface TierSpec {
13
13
  transport: Transport;
14
14
  }
15
15
  /** High-level capability a call exercises. Mirrors the capability layer (F5). */
16
- type Capability = "chat" | "vision" | "video" | "translate" | "image" | "embedding" | "transcribe" | "ocr" | "moderation" | "mockup" | "design" | "extract" | "classify" | "rerank";
16
+ type Capability = "chat" | "vision" | "video" | "translate" | "image" | "embedding" | "transcribe" | "ocr" | "moderation" | "podcast" | "tts" | "mockup" | "design" | "extract" | "classify" | "rerank";
17
17
  type Role = "system" | "user" | "assistant" | "tool";
18
18
  /** A piece of message content. Text everywhere; image parts feed vision. */
19
19
  type ContentPart = {
@@ -208,6 +208,27 @@ interface ModerationResult {
208
208
  results: ModerationItem[];
209
209
  usage: Usage;
210
210
  }
211
+ interface DialogueTurn {
212
+ text: string;
213
+ voiceId: string;
214
+ }
215
+ interface DialogueRequest {
216
+ inputs: DialogueTurn[];
217
+ /** Output container, e.g. "mp3" (default). */
218
+ format?: string;
219
+ spec: TierSpec;
220
+ }
221
+ interface PodcastResult {
222
+ /** Episode audio bytes. */
223
+ audio: Uint8Array;
224
+ mimeType: string;
225
+ usage: Usage;
226
+ }
227
+ interface TtsRequest {
228
+ text: string;
229
+ voiceId: string;
230
+ spec: TierSpec;
231
+ }
211
232
  /** The thin contract every provider implements (F4). A provider need only
212
233
  * support the capabilities it offers — `chat` is the baseline; vision/image/
213
234
  * embedding are optional and absence is a typed capability gap. */
@@ -226,6 +247,10 @@ interface ProviderAdapter {
226
247
  transcribe?(req: TranscribeRequest): Promise<TranscribeResult>;
227
248
  ocr?(req: OcrRequest): Promise<OcrResult>;
228
249
  moderate?(req: ModerationRequest): Promise<ModerationResult>;
250
+ /** Multi-voice dialogue → one audio episode (F020). ElevenLabs. */
251
+ dialogue?(req: DialogueRequest): Promise<PodcastResult>;
252
+ /** Single-voice TTS (F020.4) → audio. ElevenLabs. */
253
+ tts?(req: TtsRequest): Promise<PodcastResult>;
229
254
  }
230
255
  interface TranslateResult {
231
256
  text: string;
@@ -1130,6 +1155,154 @@ declare const moderationInputSchema: z.ZodObject<{
1130
1155
  purpose?: string | undefined;
1131
1156
  labels?: Record<string, string> | undefined;
1132
1157
  }>;
1158
+ declare const podcastInputSchema: z.ZodObject<{
1159
+ tier: z.ZodOptional<z.ZodEnum<["fast", "smart", "powerful", "cheap", "vision", "video", "embedding"]>>;
1160
+ override: z.ZodOptional<z.ZodObject<{
1161
+ provider: z.ZodOptional<z.ZodString>;
1162
+ model: z.ZodOptional<z.ZodString>;
1163
+ transport: z.ZodOptional<z.ZodEnum<["http", "subprocess"]>>;
1164
+ }, "strip", z.ZodTypeAny, {
1165
+ provider?: string | undefined;
1166
+ model?: string | undefined;
1167
+ transport?: "http" | "subprocess" | undefined;
1168
+ }, {
1169
+ provider?: string | undefined;
1170
+ model?: string | undefined;
1171
+ transport?: "http" | "subprocess" | undefined;
1172
+ }>>;
1173
+ fallback: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodEnum<["fast", "smart", "powerful", "cheap", "vision", "video", "embedding"]>, z.ZodObject<{
1174
+ provider: z.ZodString;
1175
+ model: z.ZodString;
1176
+ transport: z.ZodEnum<["http", "subprocess"]>;
1177
+ }, "strip", z.ZodTypeAny, {
1178
+ provider: string;
1179
+ model: string;
1180
+ transport: "http" | "subprocess";
1181
+ }, {
1182
+ provider: string;
1183
+ model: string;
1184
+ transport: "http" | "subprocess";
1185
+ }>]>, "many">>;
1186
+ purpose: z.ZodOptional<z.ZodString>;
1187
+ labels: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
1188
+ script: z.ZodArray<z.ZodObject<{
1189
+ speaker: z.ZodString;
1190
+ text: z.ZodString;
1191
+ }, "strip", z.ZodTypeAny, {
1192
+ text: string;
1193
+ speaker: string;
1194
+ }, {
1195
+ text: string;
1196
+ speaker: string;
1197
+ }>, "many">;
1198
+ voices: z.ZodRecord<z.ZodString, z.ZodString>;
1199
+ format: z.ZodOptional<z.ZodString>;
1200
+ }, "strip", z.ZodTypeAny, {
1201
+ script: {
1202
+ text: string;
1203
+ speaker: string;
1204
+ }[];
1205
+ voices: Record<string, string>;
1206
+ tier?: "fast" | "smart" | "powerful" | "cheap" | "vision" | "video" | "embedding" | undefined;
1207
+ override?: {
1208
+ provider?: string | undefined;
1209
+ model?: string | undefined;
1210
+ transport?: "http" | "subprocess" | undefined;
1211
+ } | undefined;
1212
+ fallback?: ("fast" | "smart" | "powerful" | "cheap" | "vision" | "video" | "embedding" | {
1213
+ provider: string;
1214
+ model: string;
1215
+ transport: "http" | "subprocess";
1216
+ })[] | undefined;
1217
+ purpose?: string | undefined;
1218
+ labels?: Record<string, string> | undefined;
1219
+ format?: string | undefined;
1220
+ }, {
1221
+ script: {
1222
+ text: string;
1223
+ speaker: string;
1224
+ }[];
1225
+ voices: Record<string, string>;
1226
+ tier?: "fast" | "smart" | "powerful" | "cheap" | "vision" | "video" | "embedding" | undefined;
1227
+ override?: {
1228
+ provider?: string | undefined;
1229
+ model?: string | undefined;
1230
+ transport?: "http" | "subprocess" | undefined;
1231
+ } | undefined;
1232
+ fallback?: ("fast" | "smart" | "powerful" | "cheap" | "vision" | "video" | "embedding" | {
1233
+ provider: string;
1234
+ model: string;
1235
+ transport: "http" | "subprocess";
1236
+ })[] | undefined;
1237
+ purpose?: string | undefined;
1238
+ labels?: Record<string, string> | undefined;
1239
+ format?: string | undefined;
1240
+ }>;
1241
+ declare const ttsInputSchema: z.ZodObject<{
1242
+ tier: z.ZodOptional<z.ZodEnum<["fast", "smart", "powerful", "cheap", "vision", "video", "embedding"]>>;
1243
+ override: z.ZodOptional<z.ZodObject<{
1244
+ provider: z.ZodOptional<z.ZodString>;
1245
+ model: z.ZodOptional<z.ZodString>;
1246
+ transport: z.ZodOptional<z.ZodEnum<["http", "subprocess"]>>;
1247
+ }, "strip", z.ZodTypeAny, {
1248
+ provider?: string | undefined;
1249
+ model?: string | undefined;
1250
+ transport?: "http" | "subprocess" | undefined;
1251
+ }, {
1252
+ provider?: string | undefined;
1253
+ model?: string | undefined;
1254
+ transport?: "http" | "subprocess" | undefined;
1255
+ }>>;
1256
+ fallback: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodEnum<["fast", "smart", "powerful", "cheap", "vision", "video", "embedding"]>, z.ZodObject<{
1257
+ provider: z.ZodString;
1258
+ model: z.ZodString;
1259
+ transport: z.ZodEnum<["http", "subprocess"]>;
1260
+ }, "strip", z.ZodTypeAny, {
1261
+ provider: string;
1262
+ model: string;
1263
+ transport: "http" | "subprocess";
1264
+ }, {
1265
+ provider: string;
1266
+ model: string;
1267
+ transport: "http" | "subprocess";
1268
+ }>]>, "many">>;
1269
+ purpose: z.ZodOptional<z.ZodString>;
1270
+ labels: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
1271
+ text: z.ZodString;
1272
+ voice: z.ZodString;
1273
+ }, "strip", z.ZodTypeAny, {
1274
+ text: string;
1275
+ voice: string;
1276
+ tier?: "fast" | "smart" | "powerful" | "cheap" | "vision" | "video" | "embedding" | undefined;
1277
+ override?: {
1278
+ provider?: string | undefined;
1279
+ model?: string | undefined;
1280
+ transport?: "http" | "subprocess" | undefined;
1281
+ } | undefined;
1282
+ fallback?: ("fast" | "smart" | "powerful" | "cheap" | "vision" | "video" | "embedding" | {
1283
+ provider: string;
1284
+ model: string;
1285
+ transport: "http" | "subprocess";
1286
+ })[] | undefined;
1287
+ purpose?: string | undefined;
1288
+ labels?: Record<string, string> | undefined;
1289
+ }, {
1290
+ text: string;
1291
+ voice: string;
1292
+ tier?: "fast" | "smart" | "powerful" | "cheap" | "vision" | "video" | "embedding" | undefined;
1293
+ override?: {
1294
+ provider?: string | undefined;
1295
+ model?: string | undefined;
1296
+ transport?: "http" | "subprocess" | undefined;
1297
+ } | undefined;
1298
+ fallback?: ("fast" | "smart" | "powerful" | "cheap" | "vision" | "video" | "embedding" | {
1299
+ provider: string;
1300
+ model: string;
1301
+ transport: "http" | "subprocess";
1302
+ })[] | undefined;
1303
+ purpose?: string | undefined;
1304
+ labels?: Record<string, string> | undefined;
1305
+ }>;
1133
1306
  declare const aiConfigSchema: z.ZodObject<{
1134
1307
  defaults: z.ZodOptional<z.ZodRecord<z.ZodEnum<["fast", "smart", "powerful", "cheap", "vision", "video", "embedding"]>, z.ZodObject<{
1135
1308
  provider: z.ZodString;
@@ -1190,6 +1363,8 @@ type EmbeddingInput = z.infer<typeof embeddingInputSchema>;
1190
1363
  type TranscribeInput = z.infer<typeof transcribeInputSchema>;
1191
1364
  type OcrInput = z.infer<typeof ocrInputSchema>;
1192
1365
  type ModerationInput = z.infer<typeof moderationInputSchema>;
1366
+ type PodcastInput = z.infer<typeof podcastInputSchema>;
1367
+ type TtsInput = z.infer<typeof ttsInputSchema>;
1193
1368
  type AiConfig = z.infer<typeof aiConfigSchema>;
1194
1369
  /** The public facade. Defined here because it depends on the derived inputs. */
1195
1370
  interface AiClient {
@@ -1208,6 +1383,10 @@ interface AiClient {
1208
1383
  ocr(input: OcrInput): Promise<OcrResult>;
1209
1384
  /** Moderation (F016.4) — classify text against safety categories. Mistral. */
1210
1385
  moderate(input: ModerationInput): Promise<ModerationResult>;
1386
+ /** Podcast (F020) — a finished manuscript → one multi-voice audio episode. ElevenLabs. */
1387
+ podcast(input: PodcastInput): Promise<PodcastResult>;
1388
+ /** Single-voice TTS (F020.4) — text → audio. `voice` = curated name or voiceId. ElevenLabs. */
1389
+ tts(input: TtsInput): Promise<PodcastResult>;
1211
1390
  /** Prompt-contract capabilities (F5.5) layered on chat/vision. */
1212
1391
  contracts: Contracts;
1213
1392
  }
@@ -1263,6 +1442,25 @@ declare function mistralAdapter(config?: {
1263
1442
  pricePerPage?: number;
1264
1443
  }): ProviderAdapter;
1265
1444
 
1445
+ /** Curated Danish voices (F020.3) — friendly name → ElevenLabs voiceId. Apps can
1446
+ * pass these names to `ai.podcast`/`ai.tts` instead of raw IDs. */
1447
+ declare const ELEVENLABS_DANISH_VOICES: Record<string, string>;
1448
+ /** Resolve a curated voice name to its voiceId; pass a raw voiceId through unchanged. */
1449
+ declare function resolveVoice(nameOrId: string): string;
1450
+ interface ElevenLabsVoice {
1451
+ voiceId: string;
1452
+ name: string;
1453
+ language?: string;
1454
+ }
1455
+ declare function elevenlabsAdapter(config?: {
1456
+ apiKey?: string;
1457
+ baseUrl?: string;
1458
+ fetch?: typeof fetch;
1459
+ pricePer1kChars?: number;
1460
+ }): ProviderAdapter & {
1461
+ listVoices(): Promise<ElevenLabsVoice[]>;
1462
+ };
1463
+
1266
1464
  interface FalAdapterConfig {
1267
1465
  apiKey?: string;
1268
1466
  /** "sync" (default — fal.run, fast models) or "queue" (queue.fal.run, polled). */
@@ -1310,8 +1508,8 @@ declare const falStubAdapter: ProviderAdapter;
1310
1508
  * wires the live adapters. */
1311
1509
  declare const stubProviders: Record<string, ProviderAdapter>;
1312
1510
 
1313
- declare const VERSION: "0.7.0";
1314
- declare const SDK_TAG: "@broberg/ai-sdk@0.7.0";
1511
+ declare const VERSION: "0.8.0";
1512
+ declare const SDK_TAG: "@broberg/ai-sdk@0.8.0";
1315
1513
 
1316
1514
  /** Built-in defaults. Every entry is overridable via AiConfig.defaults or a
1317
1515
  * per-call override. Model IDs are current at scaffold time; callers pin their
@@ -1504,4 +1702,4 @@ interface StreamTransportRequest extends TransportRequest {
1504
1702
  */
1505
1703
  declare function streamTransport(req: StreamTransportRequest): AsyncIterable<string>;
1506
1704
 
1507
- export { type AiClient, type AiConfig, type BudgetConfig, BudgetExceededError, BudgetGuard, type BudgetStore, type CallOptions, type Capability, type ChatInput, type ChatRequest, type ChatResult, type ChatStreamEvent, type ClassifyInput, type ClassifyResult, type ContentPart, type Contracts, type CostSink, type CostSummary, DEFAULT_TIER_MAP, type DesignInput, type DesignResult, type DiscordSinkConfig, type EmbeddingInput, type EmbeddingRequest, type EmbeddingResult, type ExtractInput, type ExtractResult, type FalAdapterConfig, type HttpResponse, type ImageInput, type ImageRequest, type ImageResult, type Message, type MockupInput, type MockupResult, type ModerationInput, type ModerationItem, type ModerationRequest, type ModerationResult, type OcrInput, type OcrPage, type OcrRequest, type OcrResult, type OpenAICompatibleConfig, type PricingEntry, type ProviderAdapter, type RerankInput, type RerankResult, type Role, SDK_TAG, type SqliteBudgetStoreConfig, type SqliteSinkConfig, StreamHttpError, type SubprocessResponse, type Tier, type TierSpec, type Tool, type ToolCall, type TranscribeInput, type TranscribeRequest, type TranscribeResult, type TranslateInput, type TranslateResult, type Transport, type TransportRequest, type TransportResponse, type UpmetricsSinkConfig, type Usage, VERSION, type VideoInput, type VisionInput, aiConfigSchema, anthropicAdapter, anthropicApiAdapter, anthropicSubprocessAdapter, chatInputSchema, computeCost, createAI, deepinfraAdapter, defaultProviders, discordSink, embeddingInputSchema, falAdapter, falStubAdapter, freshUsage, fromProviderToolCall, geminiAdapter, getCostSummary, getPrice, httpTransport, imageInputSchema, makeContracts, makeOpenAICompatibleAdapter, messageSchema, mistralAdapter, multiSink, noopSink, openaiAdapter, openaiStubAdapter, openrouterAdapter, parseClaudeCliJson, parseJsonLoose, resolveTier, sqliteBudgetStore, sqliteSink, streamTransport, stubProviders, subprocessTransport, tierSpecSchema, toProviderTools, toolSchema, translateInputSchema, upmetricsSink, visionInputSchema };
1705
+ export { type AiClient, type AiConfig, type BudgetConfig, BudgetExceededError, BudgetGuard, type BudgetStore, type CallOptions, type Capability, type ChatInput, type ChatRequest, type ChatResult, type ChatStreamEvent, type ClassifyInput, type ClassifyResult, type ContentPart, type Contracts, type CostSink, type CostSummary, DEFAULT_TIER_MAP, type DesignInput, type DesignResult, type DialogueRequest, type DialogueTurn, type DiscordSinkConfig, ELEVENLABS_DANISH_VOICES, type EmbeddingInput, type EmbeddingRequest, type EmbeddingResult, type ExtractInput, type ExtractResult, type FalAdapterConfig, type HttpResponse, type ImageInput, type ImageRequest, type ImageResult, type Message, type MockupInput, type MockupResult, type ModerationInput, type ModerationItem, type ModerationRequest, type ModerationResult, type OcrInput, type OcrPage, type OcrRequest, type OcrResult, type OpenAICompatibleConfig, type PodcastInput, type PodcastResult, type PricingEntry, type ProviderAdapter, type RerankInput, type RerankResult, type Role, SDK_TAG, type SqliteBudgetStoreConfig, type SqliteSinkConfig, StreamHttpError, type SubprocessResponse, type Tier, type TierSpec, type Tool, type ToolCall, type TranscribeInput, type TranscribeRequest, type TranscribeResult, type TranslateInput, type TranslateResult, type Transport, type TransportRequest, type TransportResponse, type TtsInput, type TtsRequest, type UpmetricsSinkConfig, type Usage, VERSION, type VideoInput, type VisionInput, aiConfigSchema, anthropicAdapter, anthropicApiAdapter, anthropicSubprocessAdapter, chatInputSchema, computeCost, createAI, deepinfraAdapter, defaultProviders, discordSink, elevenlabsAdapter, embeddingInputSchema, falAdapter, falStubAdapter, freshUsage, fromProviderToolCall, geminiAdapter, getCostSummary, getPrice, httpTransport, imageInputSchema, makeContracts, makeOpenAICompatibleAdapter, messageSchema, mistralAdapter, multiSink, noopSink, openaiAdapter, openaiStubAdapter, openrouterAdapter, parseClaudeCliJson, parseJsonLoose, resolveTier, resolveVoice, sqliteBudgetStore, sqliteSink, streamTransport, stubProviders, subprocessTransport, tierSpecSchema, toProviderTools, toolSchema, translateInputSchema, upmetricsSink, visionInputSchema };
package/dist/index.js CHANGED
@@ -1100,6 +1100,79 @@ function mistralAdapter(config = {}) {
1100
1100
  return { ...base, ocr, moderate };
1101
1101
  }
1102
1102
 
1103
+ // src/providers/elevenlabs.ts
1104
+ var ELEVENLABS_PRICE_PER_1K_CHARS = 0.15;
1105
+ var ELEVENLABS_DANISH_VOICES = {
1106
+ soren: "xj6X4BCUsv9oxohm1E8o",
1107
+ jesper: "Bl1YwS3uJac5zEOSNESn",
1108
+ mads: "BIWC0507fYMfhPcAEIRP",
1109
+ noam: "V34B5u5UbLdNJVEkcgXp",
1110
+ camilla: "4RklGmuxoAskAbGXplXN"
1111
+ };
1112
+ function resolveVoice(nameOrId) {
1113
+ return ELEVENLABS_DANISH_VOICES[nameOrId] ?? nameOrId;
1114
+ }
1115
+ function elevenlabsAdapter(config = {}) {
1116
+ const baseUrl = config.baseUrl ?? "https://api.elevenlabs.io/v1";
1117
+ const fetchImpl = config.fetch ?? fetch;
1118
+ function key() {
1119
+ const k = config.apiKey ?? process.env.ELEVENLABS_API_KEY;
1120
+ if (!k) throw new Error("elevenlabs adapter: API key not set (env ELEVENLABS_API_KEY)");
1121
+ return k;
1122
+ }
1123
+ function priceFor(chars, model) {
1124
+ const usage = freshUsage({
1125
+ provider: "elevenlabs",
1126
+ model,
1127
+ transport: "http",
1128
+ capability: "podcast",
1129
+ inputTokens: 0,
1130
+ outputTokens: 0
1131
+ });
1132
+ usage.costUsd = chars / 1e3 * (config.pricePer1kChars ?? ELEVENLABS_PRICE_PER_1K_CHARS);
1133
+ return usage;
1134
+ }
1135
+ async function dialogue(req) {
1136
+ const res = await fetchImpl(`${baseUrl}/text-to-dialogue`, {
1137
+ method: "POST",
1138
+ headers: { "xi-api-key": key(), "content-type": "application/json", accept: "audio/mpeg" },
1139
+ body: JSON.stringify({
1140
+ model_id: req.spec.model,
1141
+ inputs: req.inputs.map((t) => ({ text: t.text, voice_id: t.voiceId })),
1142
+ ...req.format ? { output_format: req.format } : {}
1143
+ })
1144
+ });
1145
+ if (!res.ok) {
1146
+ const body = await res.text().catch(() => "");
1147
+ throw new Error(`elevenlabs dialogue ${res.status}: ${body.slice(0, 300)}`);
1148
+ }
1149
+ const audio = new Uint8Array(await res.arrayBuffer());
1150
+ const chars = req.inputs.reduce((n, t) => n + t.text.length, 0);
1151
+ return { audio, mimeType: "audio/mpeg", usage: priceFor(chars, req.spec.model) };
1152
+ }
1153
+ async function tts(req) {
1154
+ const model = req.spec.model;
1155
+ const res = await fetchImpl(`${baseUrl}/text-to-speech/${req.voiceId}`, {
1156
+ method: "POST",
1157
+ headers: { "xi-api-key": key(), "content-type": "application/json", accept: "audio/mpeg" },
1158
+ body: JSON.stringify({ text: req.text, model_id: model })
1159
+ });
1160
+ if (!res.ok) {
1161
+ const body = await res.text().catch(() => "");
1162
+ throw new Error(`elevenlabs tts ${res.status}: ${body.slice(0, 300)}`);
1163
+ }
1164
+ const audio = new Uint8Array(await res.arrayBuffer());
1165
+ return { audio, mimeType: "audio/mpeg", usage: priceFor(req.text.length, model) };
1166
+ }
1167
+ async function listVoices() {
1168
+ const res = await fetchImpl(`${baseUrl}/voices`, { headers: { "xi-api-key": key() } });
1169
+ if (!res.ok) throw new Error(`elevenlabs voices ${res.status}`);
1170
+ const data = await res.json();
1171
+ return (data.voices ?? []).map((v) => ({ voiceId: v.voice_id, name: v.name, language: v.labels?.language }));
1172
+ }
1173
+ return { name: "elevenlabs", dialogue, tts, listVoices };
1174
+ }
1175
+
1103
1176
  // src/providers/fal.ts
1104
1177
  var FAL_IMAGE_PRICE_ESTIMATE = {
1105
1178
  "fal-ai/flux/schnell": 3e-3,
@@ -1188,6 +1261,7 @@ var defaultProviders = {
1188
1261
  deepinfra: deepinfraAdapter(),
1189
1262
  openrouter: openrouterAdapter(),
1190
1263
  mistral: mistralAdapter(),
1264
+ elevenlabs: elevenlabsAdapter(),
1191
1265
  fal: falAdapter()
1192
1266
  };
1193
1267
 
@@ -1510,6 +1584,17 @@ var moderationInputSchema = z.object({
1510
1584
  input: z.union([z.string(), z.array(z.string())]),
1511
1585
  ...callOptions
1512
1586
  });
1587
+ var podcastInputSchema = z.object({
1588
+ script: z.array(z.object({ speaker: z.string(), text: z.string() })).min(1),
1589
+ voices: z.record(z.string(), z.string()),
1590
+ format: z.string().optional(),
1591
+ ...callOptions
1592
+ });
1593
+ var ttsInputSchema = z.object({
1594
+ text: z.string(),
1595
+ voice: z.string(),
1596
+ ...callOptions
1597
+ });
1513
1598
  var budgetSchema = z.object({
1514
1599
  perCallUsd: z.number().positive().optional(),
1515
1600
  rollingUsd: z.number().positive().optional()
@@ -1531,6 +1616,8 @@ var DEFAULT_IMAGE_SPEC = {
1531
1616
  };
1532
1617
  var DEFAULT_OCR_SPEC = { provider: "mistral", model: "mistral-ocr-latest", transport: "http" };
1533
1618
  var DEFAULT_MODERATION_SPEC = { provider: "mistral", model: "mistral-moderation-latest", transport: "http" };
1619
+ var DEFAULT_PODCAST_SPEC = { provider: "elevenlabs", model: "eleven_v3", transport: "http" };
1620
+ var DEFAULT_TTS_SPEC = { provider: "elevenlabs", model: "eleven_multilingual_v2", transport: "http" };
1534
1621
  function createAI(config = {}) {
1535
1622
  const cfg = aiConfigSchema.parse(config);
1536
1623
  const providers = cfg.providers ?? defaultProviders;
@@ -1810,6 +1897,48 @@ function createAI(config = {}) {
1810
1897
  }
1811
1898
  });
1812
1899
  },
1900
+ async podcast(input) {
1901
+ input = podcastInputSchema.parse(input);
1902
+ const inputs = input.script.map((turn) => {
1903
+ const mapped = input.voices[turn.speaker];
1904
+ if (!mapped) throw new Error(`ai.podcast: no voice mapped for speaker "${turn.speaker}"`);
1905
+ return { text: turn.text, voiceId: resolveVoice(mapped) };
1906
+ });
1907
+ const chars = input.script.reduce((n, t) => n + t.text.length, 0);
1908
+ return runCapability({
1909
+ primary: { ...DEFAULT_PODCAST_SPEC, ...input.override },
1910
+ fallback: input.fallback,
1911
+ capability: "podcast",
1912
+ purpose: input.purpose,
1913
+ labels: input.labels,
1914
+ estIn: chars,
1915
+ // per-character cost (not token-based)
1916
+ estOut: 0,
1917
+ invoke: async (spec) => {
1918
+ const adapter = pickProvider(spec.provider);
1919
+ if (!adapter.dialogue) throw new Error(`createAI: provider "${spec.provider}" does not support podcast/dialogue`);
1920
+ return adapter.dialogue({ inputs, format: input.format, spec });
1921
+ }
1922
+ });
1923
+ },
1924
+ async tts(input) {
1925
+ input = ttsInputSchema.parse(input);
1926
+ return runCapability({
1927
+ primary: { ...DEFAULT_TTS_SPEC, ...input.override },
1928
+ fallback: input.fallback,
1929
+ capability: "tts",
1930
+ purpose: input.purpose,
1931
+ labels: input.labels,
1932
+ estIn: input.text.length,
1933
+ // per-character cost
1934
+ estOut: 0,
1935
+ invoke: async (spec) => {
1936
+ const adapter = pickProvider(spec.provider);
1937
+ if (!adapter.tts) throw new Error(`createAI: provider "${spec.provider}" does not support tts`);
1938
+ return adapter.tts({ text: input.text, voiceId: resolveVoice(input.voice), spec });
1939
+ }
1940
+ });
1941
+ },
1813
1942
  async embedding(input) {
1814
1943
  input = embeddingInputSchema.parse(input);
1815
1944
  const tier = input.tier ?? EMBEDDING_DEFAULT_TIER;
@@ -1936,8 +2065,8 @@ var stubProviders = {
1936
2065
  };
1937
2066
 
1938
2067
  // src/version.ts
1939
- var VERSION = "0.7.0";
1940
- var SDK_TAG = "@broberg/ai-sdk@0.7.0";
2068
+ var VERSION = "0.8.0";
2069
+ var SDK_TAG = "@broberg/ai-sdk@0.8.0";
1941
2070
 
1942
2071
  // src/cost/budget-store.ts
1943
2072
  function sqliteBudgetStore(config) {
@@ -2169,6 +2298,7 @@ export {
2169
2298
  BudgetExceededError,
2170
2299
  BudgetGuard,
2171
2300
  DEFAULT_TIER_MAP,
2301
+ ELEVENLABS_DANISH_VOICES,
2172
2302
  SDK_TAG,
2173
2303
  StreamHttpError,
2174
2304
  VERSION,
@@ -2182,6 +2312,7 @@ export {
2182
2312
  deepinfraAdapter,
2183
2313
  defaultProviders,
2184
2314
  discordSink,
2315
+ elevenlabsAdapter,
2185
2316
  embeddingInputSchema,
2186
2317
  falAdapter,
2187
2318
  falStubAdapter,
@@ -2204,6 +2335,7 @@ export {
2204
2335
  parseClaudeCliJson,
2205
2336
  parseJsonLoose,
2206
2337
  resolveTier,
2338
+ resolveVoice,
2207
2339
  sqliteBudgetStore,
2208
2340
  sqliteSink,
2209
2341
  streamTransport,