@yourgpt/llm-sdk 2.6.0-beta.1 → 2.6.0-beta.2

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.
Files changed (61) hide show
  1. package/README.md +112 -0
  2. package/dist/adapters/index.d.mts +5 -5
  3. package/dist/adapters/index.d.ts +5 -5
  4. package/dist/adapters/index.js +372 -39
  5. package/dist/adapters/index.mjs +372 -39
  6. package/dist/audio-BBSwnjo8.d.mts +92 -0
  7. package/dist/audio-BBSwnjo8.d.ts +92 -0
  8. package/dist/{base-CkeT7u-O.d.mts → base-BICaQaRS.d.mts} +7 -3
  9. package/dist/{base-BdTpUAWI.d.ts → base-CpRPB8u8.d.ts} +7 -3
  10. package/dist/fallback/index.d.mts +4 -4
  11. package/dist/fallback/index.d.ts +4 -4
  12. package/dist/index.d.mts +17 -35
  13. package/dist/index.d.ts +17 -35
  14. package/dist/index.js +229 -60
  15. package/dist/index.mjs +227 -61
  16. package/dist/providers/anthropic/index.d.mts +3 -3
  17. package/dist/providers/anthropic/index.d.ts +3 -3
  18. package/dist/providers/anthropic/index.js +123 -7
  19. package/dist/providers/anthropic/index.mjs +123 -7
  20. package/dist/providers/azure/index.d.mts +3 -3
  21. package/dist/providers/azure/index.d.ts +3 -3
  22. package/dist/providers/azure/index.js +101 -4
  23. package/dist/providers/azure/index.mjs +101 -4
  24. package/dist/providers/fireworks/index.d.mts +3 -3
  25. package/dist/providers/fireworks/index.d.ts +3 -3
  26. package/dist/providers/fireworks/index.js +321 -31
  27. package/dist/providers/fireworks/index.mjs +321 -31
  28. package/dist/providers/google/index.d.mts +3 -3
  29. package/dist/providers/google/index.d.ts +3 -3
  30. package/dist/providers/google/index.js +321 -31
  31. package/dist/providers/google/index.mjs +321 -31
  32. package/dist/providers/ollama/index.d.mts +4 -4
  33. package/dist/providers/ollama/index.d.ts +4 -4
  34. package/dist/providers/ollama/index.js +87 -2
  35. package/dist/providers/ollama/index.mjs +87 -2
  36. package/dist/providers/openai/index.d.mts +25 -6
  37. package/dist/providers/openai/index.d.ts +25 -6
  38. package/dist/providers/openai/index.js +750 -40
  39. package/dist/providers/openai/index.mjs +749 -41
  40. package/dist/providers/openrouter/index.d.mts +3 -3
  41. package/dist/providers/openrouter/index.d.ts +3 -3
  42. package/dist/providers/openrouter/index.js +321 -31
  43. package/dist/providers/openrouter/index.mjs +321 -31
  44. package/dist/providers/togetherai/index.d.mts +3 -3
  45. package/dist/providers/togetherai/index.d.ts +3 -3
  46. package/dist/providers/togetherai/index.js +321 -31
  47. package/dist/providers/togetherai/index.mjs +321 -31
  48. package/dist/providers/xai/index.d.mts +3 -3
  49. package/dist/providers/xai/index.d.ts +3 -3
  50. package/dist/providers/xai/index.js +321 -31
  51. package/dist/providers/xai/index.mjs +321 -31
  52. package/dist/{types-BWRYIvl_.d.mts → types-C3RgRbEC.d.mts} +1 -1
  53. package/dist/{types-CpXcT-tY.d.ts → types-DCFqkJAy.d.ts} +1 -1
  54. package/dist/{types-NOswlhm9.d.mts → types-DHQEMFHA.d.mts} +3 -3
  55. package/dist/{types-BW3csYo5.d.mts → types-Dg1Bcg1k.d.mts} +106 -3
  56. package/dist/{types-BW3csYo5.d.ts → types-Dg1Bcg1k.d.ts} +106 -3
  57. package/dist/{types-DA54bSmX.d.ts → types-Dikj3En4.d.ts} +3 -3
  58. package/dist/yourgpt/index.d.mts +1 -1
  59. package/dist/yourgpt/index.d.ts +1 -1
  60. package/docs/multimodal-and-audio.md +170 -0
  61. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -3,13 +3,87 @@
3
3
  var hono = require('hono');
4
4
  var cors = require('hono/cors');
5
5
 
6
+ // src/core/tool-output.ts
7
+ var imageTypes = /* @__PURE__ */ new Set([
8
+ "image/png",
9
+ "image/jpeg",
10
+ "image/webp",
11
+ "image/gif"
12
+ ]);
13
+ function normalizeToolOutput(value) {
14
+ const output = value;
15
+ if (output?.type !== "content" || !Array.isArray(output.content) || !output.content.length) {
16
+ throw new Error("Tool model output must contain a nonempty content array");
17
+ }
18
+ return {
19
+ type: "content",
20
+ content: output.content.map((part) => {
21
+ if (part?.type === "text" && typeof part.text === "string")
22
+ return { type: "text", text: part.text };
23
+ if (part?.type !== "image")
24
+ throw new Error("Unsupported tool output content type");
25
+ const sources = ["data", "url", "fileId"].filter((key) => key in part);
26
+ if (sources.length !== 1)
27
+ throw new Error(
28
+ "Tool image requires exactly one of data, url, or fileId"
29
+ );
30
+ if ("fileId" in part) {
31
+ if (part.provider !== "openai" || typeof part.fileId !== "string" || !part.fileId.trim())
32
+ throw new Error(
33
+ "Tool image file references must name the openai provider and fileId"
34
+ );
35
+ return { type: "image", fileId: part.fileId, provider: "openai" };
36
+ }
37
+ if ("url" in part) {
38
+ let url;
39
+ try {
40
+ url = new URL(part.url);
41
+ } catch {
42
+ throw new Error("Invalid tool image URL");
43
+ }
44
+ if (!["https:", "http:"].includes(url.protocol) || url.username || url.password)
45
+ throw new Error(
46
+ "Tool image URL must use HTTP(S) without credentials"
47
+ );
48
+ return { type: "image", url: url.href };
49
+ }
50
+ if (!("data" in part) || !imageTypes.has(part.mediaType))
51
+ throw new Error("Unsupported tool image media type");
52
+ let data = part.data instanceof Uint8Array ? Buffer.from(part.data).toString("base64") : part.data;
53
+ if (typeof data !== "string")
54
+ throw new Error("Tool image data must be base64 or bytes");
55
+ if (data.startsWith("data:")) {
56
+ const match = /^data:([^;,]+);base64,(.+)$/.exec(data);
57
+ if (!match || match[1] !== part.mediaType)
58
+ throw new Error(
59
+ "Tool image data URL media type does not match mediaType"
60
+ );
61
+ data = match[2];
62
+ }
63
+ if (!data.length || data.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(data))
64
+ throw new Error("Invalid tool image base64 data");
65
+ if (Buffer.byteLength(data, "base64") > 20 * 1024 * 1024)
66
+ throw new Error("Tool image exceeds 20 MiB");
67
+ if (Buffer.from(data, "base64").toString("base64") !== data)
68
+ throw new Error("Invalid tool image base64 data");
69
+ return { type: "image", data, mediaType: part.mediaType };
70
+ })
71
+ };
72
+ }
73
+ function resolveToolOutput(result, mapped) {
74
+ if (mapped !== void 0) return normalizeToolOutput(mapped);
75
+ const content = result?._aiContent;
76
+ return content !== void 0 ? normalizeToolOutput({ type: "content", content }) : void 0;
77
+ }
78
+
6
79
  // src/core/tool.ts
7
80
  function tool(config) {
8
81
  return {
9
82
  description: config.description,
10
83
  parameters: config.parameters,
11
84
  execute: config.execute,
12
- hidden: config.hidden
85
+ hidden: config.hidden,
86
+ toModelOutput: config.toModelOutput
13
87
  };
14
88
  }
15
89
  function toolToJsonSchema(toolDef) {
@@ -157,6 +231,7 @@ async function generateText(params) {
157
231
  const formattedTools = tools ? formatToolsForProvider(tools, model.provider) : void 0;
158
232
  const result = await model.doGenerate({
159
233
  messages,
234
+ openai: params.openai,
160
235
  tools: formattedTools,
161
236
  temperature: params.temperature,
162
237
  reasoningEffort: params.reasoningEffort,
@@ -190,7 +265,11 @@ async function generateText(params) {
190
265
  throwIfAborted(signal);
191
266
  const result2 = {
192
267
  toolCallId: call.id,
193
- result: toolResult
268
+ result: toolResult,
269
+ modelOutput: resolveToolOutput(
270
+ toolResult,
271
+ toolDef.toModelOutput?.(toolResult)
272
+ )
194
273
  };
195
274
  stepToolResults.push(result2);
196
275
  allToolResults.push(result2);
@@ -212,22 +291,23 @@ async function generateText(params) {
212
291
  toolCalls: result.toolCalls,
213
292
  toolResults: stepToolResults,
214
293
  finishReason: result.finishReason,
215
- usage: result.usage
294
+ usage: result.usage,
295
+ providerMetadata: result.providerMetadata
216
296
  });
217
- if (!result.toolCalls || result.toolCalls.length === 0) {
218
- break;
219
- }
220
297
  const assistantMessage = {
221
298
  role: "assistant",
222
299
  content: result.text || null,
223
- toolCalls: result.toolCalls
300
+ ...result.toolCalls.length ? { toolCalls: result.toolCalls } : {},
301
+ ...result.providerMetadata ? { providerMetadata: result.providerMetadata } : {}
224
302
  };
225
303
  messages = [...messages, assistantMessage];
304
+ if (!result.toolCalls || result.toolCalls.length === 0) break;
226
305
  for (const tr of stepToolResults) {
227
306
  const toolMessage = {
228
307
  role: "tool",
229
308
  toolCallId: tr.toolCallId,
230
- content: JSON.stringify(tr.result)
309
+ content: tr.modelOutput ? "[Tool returned content]" : JSON.stringify(tr.result),
310
+ ...tr.modelOutput ? { modelOutput: tr.modelOutput } : {}
231
311
  };
232
312
  messages = [...messages, toolMessage];
233
313
  }
@@ -235,6 +315,7 @@ async function generateText(params) {
235
315
  const lastStep = steps[steps.length - 1];
236
316
  return {
237
317
  text: lastStep?.text ?? "",
318
+ providerMetadata: lastStep?.providerMetadata,
238
319
  usage: sumUsage(steps),
239
320
  finishReason: lastStep?.finishReason ?? "stop",
240
321
  steps,
@@ -288,6 +369,8 @@ async function streamText(params) {
288
369
  `[llm-sdk] ${model.provider}/${model.modelId} does not support structured output (responseFormat); the request will be sent but the provider may ignore it.`
289
370
  );
290
371
  }
372
+ let messages = buildMessages2(params);
373
+ let finalProviderMetadata;
291
374
  let fullText = "";
292
375
  let finalUsage = {
293
376
  promptTokens: 0,
@@ -296,7 +379,6 @@ async function streamText(params) {
296
379
  };
297
380
  let finalFinishReason = "stop";
298
381
  async function* createFullStream() {
299
- let messages = buildMessages2(params);
300
382
  for (let step = 0; step < maxSteps; step++) {
301
383
  yield { type: "step-start", step };
302
384
  if (signal?.aborted) {
@@ -305,11 +387,13 @@ async function streamText(params) {
305
387
  }
306
388
  const formattedTools = tools ? formatToolsForProvider2(tools, model.provider) : void 0;
307
389
  let stepText = "";
390
+ let stepProviderMetadata;
308
391
  const toolCalls = [];
309
392
  let stepFinishReason = "stop";
310
393
  try {
311
394
  for await (const chunk of model.doStream({
312
395
  messages,
396
+ openai: params.openai,
313
397
  tools: formattedTools,
314
398
  temperature: params.temperature,
315
399
  reasoningEffort: params.reasoningEffort,
@@ -332,6 +416,8 @@ async function streamText(params) {
332
416
  };
333
417
  break;
334
418
  case "finish":
419
+ stepProviderMetadata = chunk.providerMetadata;
420
+ finalProviderMetadata = chunk.providerMetadata;
335
421
  stepFinishReason = chunk.finishReason;
336
422
  finalFinishReason = chunk.finishReason;
337
423
  if (chunk.usage) {
@@ -354,16 +440,22 @@ async function streamText(params) {
354
440
  };
355
441
  return;
356
442
  }
357
- yield { type: "step-finish", step, finishReason: stepFinishReason };
358
- if (toolCalls.length === 0 || !tools) {
359
- break;
360
- }
361
- const assistantMessage = {
362
- role: "assistant",
363
- content: stepText || null,
364
- toolCalls
443
+ yield {
444
+ type: "step-finish",
445
+ step,
446
+ finishReason: stepFinishReason,
447
+ providerMetadata: stepProviderMetadata
365
448
  };
366
- messages = [...messages, assistantMessage];
449
+ messages = [
450
+ ...messages,
451
+ {
452
+ role: "assistant",
453
+ content: stepText || null,
454
+ ...toolCalls.length ? { toolCalls } : {},
455
+ ...stepProviderMetadata ? { providerMetadata: stepProviderMetadata } : {}
456
+ }
457
+ ];
458
+ if (toolCalls.length === 0 || !tools) break;
367
459
  for (const call of toolCalls) {
368
460
  throwIfAborted(signal);
369
461
  const toolDef = tools[call.name];
@@ -392,13 +484,23 @@ async function streamText(params) {
392
484
  messages
393
485
  });
394
486
  throwIfAborted(signal);
395
- yield { type: "tool-result", toolCallId: call.id, result };
487
+ const modelOutput = resolveToolOutput(
488
+ result,
489
+ toolDef.toModelOutput?.(result)
490
+ );
491
+ yield {
492
+ type: "tool-result",
493
+ toolCallId: call.id,
494
+ result,
495
+ modelOutput
496
+ };
396
497
  messages = [
397
498
  ...messages,
398
499
  {
399
500
  role: "tool",
400
501
  toolCallId: call.id,
401
- content: JSON.stringify(result)
502
+ content: modelOutput ? "[Tool returned content]" : JSON.stringify(result),
503
+ ...modelOutput ? { modelOutput } : {}
402
504
  }
403
505
  ];
404
506
  } catch (error) {
@@ -425,7 +527,8 @@ async function streamText(params) {
425
527
  yield {
426
528
  type: "finish",
427
529
  finishReason: finalFinishReason,
428
- usage: finalUsage
530
+ usage: finalUsage,
531
+ providerMetadata: finalProviderMetadata
429
532
  };
430
533
  }
431
534
  const source = createFullStream();
@@ -477,6 +580,12 @@ async function streamText(params) {
477
580
  return {
478
581
  textStream: createTextStream(),
479
582
  fullStream: sharedStream(),
583
+ get response() {
584
+ return consumeStream().then(() => ({ messages }));
585
+ },
586
+ get providerMetadata() {
587
+ return consumeStream().then(() => finalProviderMetadata);
588
+ },
480
589
  get text() {
481
590
  return consumeStream().then(() => fullText);
482
591
  },
@@ -600,6 +709,7 @@ function createMessage(partial) {
600
709
  tool_calls: partial.tool_calls,
601
710
  tool_call_id: partial.tool_call_id,
602
711
  metadata: partial.metadata,
712
+ providerMetadata: partial.providerMetadata,
603
713
  created_at: partial.created_at ?? /* @__PURE__ */ new Date()
604
714
  };
605
715
  }
@@ -648,7 +758,13 @@ function mapOutputMessages(resultMessages) {
648
758
  role: m.role,
649
759
  content: m.content ?? "",
650
760
  toolCalls: m.tool_calls,
651
- toolCallId: m.tool_call_id
761
+ toolCallId: m.tool_call_id,
762
+ ...m.providerMetadata || m.modelOutput ? {
763
+ metadata: {
764
+ ...m.providerMetadata ? { providerMetadata: m.providerMetadata } : {},
765
+ ...m.modelOutput ? { modelOutput: m.modelOutput } : {}
766
+ }
767
+ } : {}
652
768
  }));
653
769
  }
654
770
 
@@ -1538,9 +1654,6 @@ function buildProviderToolOptions(params) {
1538
1654
  function buildToolResultForAI(tool2, result, args) {
1539
1655
  const typedResult = result;
1540
1656
  const responseMode = typedResult?._aiResponseMode ?? tool2?.aiResponseMode ?? "full";
1541
- if (typedResult?._aiContent && typedResult._aiContent.length > 0) {
1542
- return typedResult._aiContent;
1543
- }
1544
1657
  let aiContext;
1545
1658
  if (typedResult?._aiContext) {
1546
1659
  aiContext = typedResult._aiContext;
@@ -1560,25 +1673,6 @@ function buildToolResultForAI(tool2, result, args) {
1560
1673
  Full data: ${fullData}` : fullData;
1561
1674
  }
1562
1675
  }
1563
- function serializeToolResultContent(content) {
1564
- if (typeof content === "string") {
1565
- return content;
1566
- }
1567
- return content.map((item) => {
1568
- if (item.type === "image") {
1569
- return {
1570
- type: "image_url",
1571
- image_url: {
1572
- url: `data:${item.mediaType};base64,${item.data}`
1573
- }
1574
- };
1575
- }
1576
- return {
1577
- type: "text",
1578
- text: item.text
1579
- };
1580
- });
1581
- }
1582
1676
  function extractHeaders(request) {
1583
1677
  if (!request) return {};
1584
1678
  const headers = {};
@@ -1635,7 +1729,11 @@ var Runtime = class {
1635
1729
  const messages = request.messages.map(
1636
1730
  (m, i) => createMessage({
1637
1731
  role: m.role,
1638
- content: m.content
1732
+ content: m.content,
1733
+ providerMetadata: m.providerMetadata,
1734
+ modelOutput: m.modelOutput,
1735
+ tool_calls: m.tool_calls,
1736
+ tool_call_id: m.tool_call_id
1639
1737
  })
1640
1738
  );
1641
1739
  const allActions = [...this.actions.values()];
@@ -2252,6 +2350,7 @@ var Runtime = class {
2252
2350
  let currentToolCall = null;
2253
2351
  const serverToolResults = [];
2254
2352
  const toolContextData = "toolContext" in this.config ? this.config.toolContext : void 0;
2353
+ let adapterProviderMetadata;
2255
2354
  let adapterUsage;
2256
2355
  const completionRequest = {
2257
2356
  messages: [],
@@ -2350,18 +2449,24 @@ var Runtime = class {
2350
2449
  );
2351
2450
  try {
2352
2451
  const result = await tool2.handler(args, toolContext);
2452
+ const modelOutput = resolveToolOutput(
2453
+ result,
2454
+ tool2.toModelOutput?.(result)
2455
+ );
2353
2456
  serverToolResults.push({
2354
2457
  id: event.id,
2355
2458
  name: toolName,
2356
2459
  args,
2357
2460
  result,
2461
+ modelOutput,
2358
2462
  tool: tool2
2359
2463
  });
2360
2464
  yield {
2361
2465
  type: "action:end",
2362
2466
  id: event.id,
2363
2467
  name: toolName,
2364
- result
2468
+ result,
2469
+ modelOutput
2365
2470
  };
2366
2471
  } catch (error) {
2367
2472
  const errorResult = {
@@ -2395,6 +2500,7 @@ var Runtime = class {
2395
2500
  return;
2396
2501
  // Exit on error
2397
2502
  case "done":
2503
+ adapterProviderMetadata = event.providerMetadata;
2398
2504
  if (event.usage) {
2399
2505
  adapterUsage = event.usage;
2400
2506
  }
@@ -2415,11 +2521,11 @@ var Runtime = class {
2415
2521
  (tc) => !serverToolIds.has(tc.id)
2416
2522
  );
2417
2523
  const serverToolResultMessages = serverToolResults.map((tr) => {
2418
- const aiContent = buildToolResultForAI(tr.tool, tr.result, tr.args);
2419
- const content = typeof aiContent === "string" ? aiContent : JSON.stringify(serializeToolResultContent(aiContent));
2524
+ const content = tr.modelOutput ? "[Tool returned content]" : buildToolResultForAI(tr.tool, tr.result, tr.args);
2420
2525
  return {
2421
2526
  role: "tool",
2422
2527
  content,
2528
+ ...tr.modelOutput ? { modelOutput: tr.modelOutput } : {},
2423
2529
  tool_call_id: tr.id
2424
2530
  };
2425
2531
  });
@@ -2432,6 +2538,7 @@ var Runtime = class {
2432
2538
  const assistantMessage = {
2433
2539
  role: "assistant",
2434
2540
  content: accumulatedText || null,
2541
+ ...adapterProviderMetadata ? { providerMetadata: adapterProviderMetadata } : {},
2435
2542
  tool_calls: toolCalls.map((tc) => ({
2436
2543
  id: tc.id,
2437
2544
  type: "function",
@@ -2466,6 +2573,7 @@ var Runtime = class {
2466
2573
  const assistantWithToolCalls = {
2467
2574
  role: "assistant",
2468
2575
  content: accumulatedText || null,
2576
+ ...adapterProviderMetadata ? { providerMetadata: adapterProviderMetadata } : {},
2469
2577
  tool_calls: serverToolResults.map((tr) => {
2470
2578
  const tc = toolCalls.find((t) => t.id === tr.id);
2471
2579
  return {
@@ -2516,6 +2624,7 @@ var Runtime = class {
2516
2624
  const assistantMessage = {
2517
2625
  role: "assistant",
2518
2626
  content: accumulatedText || null,
2627
+ ...adapterProviderMetadata ? { providerMetadata: adapterProviderMetadata } : {},
2519
2628
  tool_calls: clientToolCalls.map((tc) => ({
2520
2629
  id: tc.id,
2521
2630
  type: "function",
@@ -2541,10 +2650,11 @@ var Runtime = class {
2541
2650
  return;
2542
2651
  }
2543
2652
  }
2544
- if (accumulatedText) {
2653
+ if (accumulatedText || adapterProviderMetadata) {
2545
2654
  newMessages.push({
2546
2655
  role: "assistant",
2547
- content: accumulatedText
2656
+ content: accumulatedText,
2657
+ ...adapterProviderMetadata ? { providerMetadata: adapterProviderMetadata } : {}
2548
2658
  });
2549
2659
  }
2550
2660
  if (debug) {
@@ -2659,7 +2769,10 @@ var Runtime = class {
2659
2769
  content: result.content
2660
2770
  };
2661
2771
  }
2662
- yield { type: "message:end" };
2772
+ yield {
2773
+ type: "message:end",
2774
+ providerMetadata: result.providerMetadata
2775
+ };
2663
2776
  if (result.toolCalls.length > 0) {
2664
2777
  const serverToolCalls = [];
2665
2778
  const clientToolCalls = [];
@@ -2706,18 +2819,24 @@ var Runtime = class {
2706
2819
  );
2707
2820
  try {
2708
2821
  const toolResult = await tool2.handler(tc.args, toolContext);
2822
+ const modelOutput = resolveToolOutput(
2823
+ toolResult,
2824
+ tool2.toModelOutput?.(toolResult)
2825
+ );
2709
2826
  serverToolResults.push({
2710
2827
  id: tc.id,
2711
2828
  name: tc.name,
2712
2829
  args: tc.args,
2713
2830
  result: toolResult,
2831
+ modelOutput,
2714
2832
  tool: tool2
2715
2833
  });
2716
2834
  yield {
2717
2835
  type: "action:end",
2718
2836
  id: tc.id,
2719
2837
  name: tc.name,
2720
- result: toolResult
2838
+ result: toolResult,
2839
+ modelOutput
2721
2840
  };
2722
2841
  } catch (error) {
2723
2842
  const errorResult = {
@@ -2741,15 +2860,11 @@ var Runtime = class {
2741
2860
  }
2742
2861
  }
2743
2862
  const serverToolResultMessages = serverToolResults.map((tr) => {
2744
- const aiContent = buildToolResultForAI(
2745
- tr.tool,
2746
- tr.result,
2747
- tr.args
2748
- );
2749
- const content = typeof aiContent === "string" ? aiContent : JSON.stringify(serializeToolResultContent(aiContent));
2863
+ const content = tr.modelOutput ? "[Tool returned content]" : buildToolResultForAI(tr.tool, tr.result, tr.args);
2750
2864
  return {
2751
2865
  role: "tool",
2752
2866
  content,
2867
+ ...tr.modelOutput ? { modelOutput: tr.modelOutput } : {},
2753
2868
  tool_call_id: tr.id
2754
2869
  };
2755
2870
  });
@@ -2757,6 +2872,7 @@ var Runtime = class {
2757
2872
  const assistantMessage = {
2758
2873
  role: "assistant",
2759
2874
  content: result.content || null,
2875
+ ...result.providerMetadata ? { providerMetadata: result.providerMetadata } : {},
2760
2876
  tool_calls: result.toolCalls.map((tc) => ({
2761
2877
  id: tc.id,
2762
2878
  type: "function",
@@ -2786,6 +2902,7 @@ var Runtime = class {
2786
2902
  const assistantWithToolCalls = {
2787
2903
  role: "assistant",
2788
2904
  content: result.content || null,
2905
+ ...result.providerMetadata ? { providerMetadata: result.providerMetadata } : {},
2789
2906
  tool_calls: result.toolCalls.map((tc) => ({
2790
2907
  id: tc.id,
2791
2908
  type: "function",
@@ -2817,6 +2934,7 @@ var Runtime = class {
2817
2934
  const assistantMessage = {
2818
2935
  role: "assistant",
2819
2936
  content: result.content || null,
2937
+ ...result.providerMetadata ? { providerMetadata: result.providerMetadata } : {},
2820
2938
  tool_calls: clientToolCalls.map((tc) => ({
2821
2939
  id: tc.id,
2822
2940
  type: "function",
@@ -2842,10 +2960,11 @@ var Runtime = class {
2842
2960
  return;
2843
2961
  }
2844
2962
  }
2845
- if (result.content) {
2963
+ if (result.content || result.providerMetadata) {
2846
2964
  newMessages.push({
2847
2965
  role: "assistant",
2848
- content: result.content
2966
+ content: result.content,
2967
+ ...result.providerMetadata ? { providerMetadata: result.providerMetadata } : {}
2849
2968
  });
2850
2969
  }
2851
2970
  if (debug) {
@@ -3997,6 +4116,54 @@ async function executeToolCalls(toolCalls, tools, executeServerTool, waitForClie
3997
4116
  return results;
3998
4117
  }
3999
4118
 
4119
+ // src/core/audio.ts
4120
+ var audioErrorMarker = /* @__PURE__ */ Symbol.for("@yourgpt/llm-sdk/AudioAPIError");
4121
+ var _a;
4122
+ var AudioAPIError = class extends Error {
4123
+ constructor(message, code, status, requestId) {
4124
+ super(message);
4125
+ this.code = code;
4126
+ this.status = status;
4127
+ this.requestId = requestId;
4128
+ this[_a] = true;
4129
+ this.name = "AudioAPIError";
4130
+ }
4131
+ static [(_a = audioErrorMarker, Symbol.hasInstance)](value) {
4132
+ return !!value && typeof value === "object" && value[audioErrorMarker] === true;
4133
+ }
4134
+ };
4135
+ async function generateSpeech({
4136
+ model,
4137
+ ...options
4138
+ }) {
4139
+ options.signal?.throwIfAborted();
4140
+ if (typeof options.text !== "string" || !options.text.trim())
4141
+ throw new AudioAPIError("Speech text must not be empty", "invalid_input");
4142
+ const result = await model.doGenerate(options);
4143
+ options.signal?.throwIfAborted();
4144
+ if (!(result.audio?.uint8Array instanceof Uint8Array) || !result.audio.uint8Array.length)
4145
+ throw new AudioAPIError(
4146
+ "Speech provider returned empty audio",
4147
+ "invalid_response"
4148
+ );
4149
+ return result;
4150
+ }
4151
+ async function transcribe({
4152
+ model,
4153
+ ...options
4154
+ }) {
4155
+ options.signal?.throwIfAborted();
4156
+ const result = await model.doTranscribe(options);
4157
+ options.signal?.throwIfAborted();
4158
+ if (typeof result.text !== "string")
4159
+ throw new AudioAPIError(
4160
+ "Transcription provider returned an invalid transcript",
4161
+ "invalid_response"
4162
+ );
4163
+ return result;
4164
+ }
4165
+
4166
+ exports.AudioAPIError = AudioAPIError;
4000
4167
  exports.DEFAULT_CAPABILITIES = DEFAULT_CAPABILITIES;
4001
4168
  exports.DEFAULT_MAX_ITERATIONS = DEFAULT_MAX_ITERATIONS;
4002
4169
  exports.GenerateResult = GenerateResult;
@@ -4021,6 +4188,7 @@ exports.formatToolsForAnthropic = formatToolsForAnthropic;
4021
4188
  exports.formatToolsForGoogle = formatToolsForGoogle;
4022
4189
  exports.formatToolsForOpenAI = formatToolsForOpenAI;
4023
4190
  exports.generateMessageId = generateMessageId;
4191
+ exports.generateSpeech = generateSpeech;
4024
4192
  exports.generateText = generateText;
4025
4193
  exports.generateThreadId = generateThreadId;
4026
4194
  exports.generateToolCallId = generateToolCallId;
@@ -4033,5 +4201,6 @@ exports.selectTools = selectTools;
4033
4201
  exports.shouldExposeToolSearch = shouldExposeToolSearch;
4034
4202
  exports.streamText = streamText;
4035
4203
  exports.tool = tool;
4204
+ exports.transcribe = transcribe;
4036
4205
  //# sourceMappingURL=index.js.map
4037
4206
  //# sourceMappingURL=index.js.map