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

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 +146 -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 +437 -39
  5. package/dist/adapters/index.mjs +437 -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 +20 -36
  13. package/dist/index.d.ts +20 -36
  14. package/dist/index.js +327 -69
  15. package/dist/index.mjs +325 -70
  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 +116 -7
  19. package/dist/providers/anthropic/index.mjs +116 -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 +393 -31
  27. package/dist/providers/fireworks/index.mjs +393 -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 +393 -31
  31. package/dist/providers/google/index.mjs +393 -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 +822 -40
  39. package/dist/providers/openai/index.mjs +821 -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 +393 -31
  43. package/dist/providers/openrouter/index.mjs +393 -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 +393 -31
  47. package/dist/providers/togetherai/index.mjs +393 -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 +393 -31
  51. package/dist/providers/xai/index.mjs +393 -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,137 @@
3
3
  var hono = require('hono');
4
4
  var cors = require('hono/cors');
5
5
 
6
+ // src/core/openai-responses.ts
7
+ function responseReplayMetadata(metadata) {
8
+ const response = metadata?.openai?.response;
9
+ if (!response) return metadata;
10
+ const output = response.output.map((item) => {
11
+ const fields = ["type", "id", "status"];
12
+ switch (item.type) {
13
+ case "reasoning":
14
+ fields.push("encrypted_content");
15
+ break;
16
+ case "message":
17
+ fields.push("role", "phase");
18
+ break;
19
+ case "function_call":
20
+ fields.push("call_id", "name", "namespace", "arguments");
21
+ break;
22
+ case "tool_search_call":
23
+ fields.push("call_id", "execution", "arguments");
24
+ break;
25
+ case "tool_search_output":
26
+ fields.push("call_id", "tools");
27
+ break;
28
+ case "web_search_call":
29
+ fields.push("action");
30
+ break;
31
+ default:
32
+ return stripItemDiagnostics(item);
33
+ }
34
+ const replay = Object.fromEntries(
35
+ fields.filter((key) => item[key] !== void 0).map((key) => [key, item[key]])
36
+ );
37
+ if (item.type === "reasoning") replay.summary = [];
38
+ if (item.type === "message")
39
+ replay.content = Array.isArray(item.content) ? item.content.flatMap(
40
+ (part) => part?.type === "output_text" && typeof part.text === "string" ? [{ type: "output_text", text: part.text, annotations: [] }] : part?.type === "refusal" && typeof part.refusal === "string" ? [{ type: "refusal", refusal: part.refusal }] : []
41
+ ) : [];
42
+ return stripItemDiagnostics(replay);
43
+ });
44
+ return { openai: { response: { output, refusals: [] } } };
45
+ }
46
+ function stripItemDiagnostics(item) {
47
+ const {
48
+ usage: _usage,
49
+ logprobs: _logprobs,
50
+ metadata: _metadata,
51
+ ...state
52
+ } = item;
53
+ return state;
54
+ }
55
+
56
+ // src/core/tool-output.ts
57
+ var imageTypes = /* @__PURE__ */ new Set([
58
+ "image/png",
59
+ "image/jpeg",
60
+ "image/webp",
61
+ "image/gif"
62
+ ]);
63
+ function normalizeToolOutput(value) {
64
+ const output = value;
65
+ if (output?.type !== "content" || !Array.isArray(output.content) || !output.content.length) {
66
+ throw new Error("Tool model output must contain a nonempty content array");
67
+ }
68
+ return {
69
+ type: "content",
70
+ content: output.content.map((part) => {
71
+ if (part?.type === "text" && typeof part.text === "string")
72
+ return { type: "text", text: part.text };
73
+ if (part?.type !== "image")
74
+ throw new Error("Unsupported tool output content type");
75
+ const sources = ["data", "url", "fileId"].filter((key) => key in part);
76
+ if (sources.length !== 1)
77
+ throw new Error(
78
+ "Tool image requires exactly one of data, url, or fileId"
79
+ );
80
+ if ("fileId" in part) {
81
+ if (part.provider !== "openai" || typeof part.fileId !== "string" || !part.fileId.trim())
82
+ throw new Error(
83
+ "Tool image file references must name the openai provider and fileId"
84
+ );
85
+ return { type: "image", fileId: part.fileId, provider: "openai" };
86
+ }
87
+ if ("url" in part) {
88
+ let url;
89
+ try {
90
+ url = new URL(part.url);
91
+ } catch {
92
+ throw new Error("Invalid tool image URL");
93
+ }
94
+ if (!["https:", "http:"].includes(url.protocol) || url.username || url.password)
95
+ throw new Error(
96
+ "Tool image URL must use HTTP(S) without credentials"
97
+ );
98
+ return { type: "image", url: url.href };
99
+ }
100
+ if (!("data" in part) || !imageTypes.has(part.mediaType))
101
+ throw new Error("Unsupported tool image media type");
102
+ let data = part.data instanceof Uint8Array ? Buffer.from(part.data).toString("base64") : part.data;
103
+ if (typeof data !== "string")
104
+ throw new Error("Tool image data must be base64 or bytes");
105
+ if (data.startsWith("data:")) {
106
+ const match = /^data:([^;,]+);base64,(.+)$/.exec(data);
107
+ if (!match || match[1] !== part.mediaType)
108
+ throw new Error(
109
+ "Tool image data URL media type does not match mediaType"
110
+ );
111
+ data = match[2];
112
+ }
113
+ if (!data.length || data.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(data))
114
+ throw new Error("Invalid tool image base64 data");
115
+ if (Buffer.byteLength(data, "base64") > 20 * 1024 * 1024)
116
+ throw new Error("Tool image exceeds 20 MiB");
117
+ if (Buffer.from(data, "base64").toString("base64") !== data)
118
+ throw new Error("Invalid tool image base64 data");
119
+ return { type: "image", data, mediaType: part.mediaType };
120
+ })
121
+ };
122
+ }
123
+ function resolveToolOutput(result, mapped) {
124
+ if (mapped !== void 0) return normalizeToolOutput(mapped);
125
+ const content = result?._aiContent;
126
+ return content !== void 0 ? normalizeToolOutput({ type: "content", content }) : void 0;
127
+ }
128
+
6
129
  // src/core/tool.ts
7
130
  function tool(config) {
8
131
  return {
9
132
  description: config.description,
10
133
  parameters: config.parameters,
11
134
  execute: config.execute,
12
- hidden: config.hidden
135
+ hidden: config.hidden,
136
+ toModelOutput: config.toModelOutput
13
137
  };
14
138
  }
15
139
  function toolToJsonSchema(toolDef) {
@@ -157,6 +281,7 @@ async function generateText(params) {
157
281
  const formattedTools = tools ? formatToolsForProvider(tools, model.provider) : void 0;
158
282
  const result = await model.doGenerate({
159
283
  messages,
284
+ openai: params.openai,
160
285
  tools: formattedTools,
161
286
  temperature: params.temperature,
162
287
  reasoningEffort: params.reasoningEffort,
@@ -165,10 +290,11 @@ async function generateText(params) {
165
290
  signal
166
291
  });
167
292
  throwIfAborted(signal);
293
+ const toolCalls = result.toolCalls ?? [];
168
294
  const stepToolResults = [];
169
- if (result.toolCalls && result.toolCalls.length > 0 && tools) {
170
- allToolCalls.push(...result.toolCalls);
171
- for (const call of result.toolCalls) {
295
+ if (toolCalls.length > 0 && tools) {
296
+ allToolCalls.push(...toolCalls);
297
+ for (const call of toolCalls) {
172
298
  throwIfAborted(signal);
173
299
  const toolDef = tools[call.name];
174
300
  if (!toolDef) {
@@ -190,7 +316,11 @@ async function generateText(params) {
190
316
  throwIfAborted(signal);
191
317
  const result2 = {
192
318
  toolCallId: call.id,
193
- result: toolResult
319
+ result: toolResult,
320
+ modelOutput: resolveToolOutput(
321
+ toolResult,
322
+ toolDef.toModelOutput?.(toolResult)
323
+ )
194
324
  };
195
325
  stepToolResults.push(result2);
196
326
  allToolResults.push(result2);
@@ -209,25 +339,26 @@ async function generateText(params) {
209
339
  }
210
340
  steps.push({
211
341
  text: result.text,
212
- toolCalls: result.toolCalls,
342
+ toolCalls,
213
343
  toolResults: stepToolResults,
214
344
  finishReason: result.finishReason,
215
- usage: result.usage
345
+ usage: result.usage,
346
+ providerMetadata: result.providerMetadata
216
347
  });
217
- if (!result.toolCalls || result.toolCalls.length === 0) {
218
- break;
219
- }
220
348
  const assistantMessage = {
221
349
  role: "assistant",
222
350
  content: result.text || null,
223
- toolCalls: result.toolCalls
351
+ ...toolCalls.length ? { toolCalls } : {},
352
+ ...result.providerMetadata ? { providerMetadata: responseReplayMetadata(result.providerMetadata) } : {}
224
353
  };
225
354
  messages = [...messages, assistantMessage];
355
+ if (toolCalls.length === 0) break;
226
356
  for (const tr of stepToolResults) {
227
357
  const toolMessage = {
228
358
  role: "tool",
229
359
  toolCallId: tr.toolCallId,
230
- content: JSON.stringify(tr.result)
360
+ content: tr.modelOutput ? "[Tool returned content]" : JSON.stringify(tr.result),
361
+ ...tr.modelOutput ? { modelOutput: tr.modelOutput } : {}
231
362
  };
232
363
  messages = [...messages, toolMessage];
233
364
  }
@@ -235,6 +366,7 @@ async function generateText(params) {
235
366
  const lastStep = steps[steps.length - 1];
236
367
  return {
237
368
  text: lastStep?.text ?? "",
369
+ providerMetadata: lastStep?.providerMetadata,
238
370
  usage: sumUsage(steps),
239
371
  finishReason: lastStep?.finishReason ?? "stop",
240
372
  steps,
@@ -288,6 +420,8 @@ async function streamText(params) {
288
420
  `[llm-sdk] ${model.provider}/${model.modelId} does not support structured output (responseFormat); the request will be sent but the provider may ignore it.`
289
421
  );
290
422
  }
423
+ let messages = buildMessages2(params);
424
+ let finalProviderMetadata;
291
425
  let fullText = "";
292
426
  let finalUsage = {
293
427
  promptTokens: 0,
@@ -296,7 +430,6 @@ async function streamText(params) {
296
430
  };
297
431
  let finalFinishReason = "stop";
298
432
  async function* createFullStream() {
299
- let messages = buildMessages2(params);
300
433
  for (let step = 0; step < maxSteps; step++) {
301
434
  yield { type: "step-start", step };
302
435
  if (signal?.aborted) {
@@ -305,11 +438,13 @@ async function streamText(params) {
305
438
  }
306
439
  const formattedTools = tools ? formatToolsForProvider2(tools, model.provider) : void 0;
307
440
  let stepText = "";
441
+ let stepProviderMetadata;
308
442
  const toolCalls = [];
309
443
  let stepFinishReason = "stop";
310
444
  try {
311
445
  for await (const chunk of model.doStream({
312
446
  messages,
447
+ openai: params.openai,
313
448
  tools: formattedTools,
314
449
  temperature: params.temperature,
315
450
  reasoningEffort: params.reasoningEffort,
@@ -332,6 +467,8 @@ async function streamText(params) {
332
467
  };
333
468
  break;
334
469
  case "finish":
470
+ stepProviderMetadata = chunk.providerMetadata;
471
+ finalProviderMetadata = chunk.providerMetadata;
335
472
  stepFinishReason = chunk.finishReason;
336
473
  finalFinishReason = chunk.finishReason;
337
474
  if (chunk.usage) {
@@ -354,16 +491,22 @@ async function streamText(params) {
354
491
  };
355
492
  return;
356
493
  }
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
494
+ yield {
495
+ type: "step-finish",
496
+ step,
497
+ finishReason: stepFinishReason,
498
+ providerMetadata: stepProviderMetadata
365
499
  };
366
- messages = [...messages, assistantMessage];
500
+ messages = [
501
+ ...messages,
502
+ {
503
+ role: "assistant",
504
+ content: stepText || null,
505
+ ...toolCalls.length ? { toolCalls } : {},
506
+ ...stepProviderMetadata ? { providerMetadata: responseReplayMetadata(stepProviderMetadata) } : {}
507
+ }
508
+ ];
509
+ if (toolCalls.length === 0 || !tools) break;
367
510
  for (const call of toolCalls) {
368
511
  throwIfAborted(signal);
369
512
  const toolDef = tools[call.name];
@@ -392,13 +535,23 @@ async function streamText(params) {
392
535
  messages
393
536
  });
394
537
  throwIfAborted(signal);
395
- yield { type: "tool-result", toolCallId: call.id, result };
538
+ const modelOutput = resolveToolOutput(
539
+ result,
540
+ toolDef.toModelOutput?.(result)
541
+ );
542
+ yield {
543
+ type: "tool-result",
544
+ toolCallId: call.id,
545
+ result,
546
+ modelOutput
547
+ };
396
548
  messages = [
397
549
  ...messages,
398
550
  {
399
551
  role: "tool",
400
552
  toolCallId: call.id,
401
- content: JSON.stringify(result)
553
+ content: modelOutput ? "[Tool returned content]" : JSON.stringify(result),
554
+ ...modelOutput ? { modelOutput } : {}
402
555
  }
403
556
  ];
404
557
  } catch (error) {
@@ -425,7 +578,8 @@ async function streamText(params) {
425
578
  yield {
426
579
  type: "finish",
427
580
  finishReason: finalFinishReason,
428
- usage: finalUsage
581
+ usage: finalUsage,
582
+ providerMetadata: finalProviderMetadata
429
583
  };
430
584
  }
431
585
  const source = createFullStream();
@@ -477,6 +631,12 @@ async function streamText(params) {
477
631
  return {
478
632
  textStream: createTextStream(),
479
633
  fullStream: sharedStream(),
634
+ get response() {
635
+ return consumeStream().then(() => ({ messages }));
636
+ },
637
+ get providerMetadata() {
638
+ return consumeStream().then(() => finalProviderMetadata);
639
+ },
480
640
  get text() {
481
641
  return consumeStream().then(() => fullText);
482
642
  },
@@ -600,6 +760,7 @@ function createMessage(partial) {
600
760
  tool_calls: partial.tool_calls,
601
761
  tool_call_id: partial.tool_call_id,
602
762
  metadata: partial.metadata,
763
+ providerMetadata: partial.providerMetadata,
603
764
  created_at: partial.created_at ?? /* @__PURE__ */ new Date()
604
765
  };
605
766
  }
@@ -648,7 +809,13 @@ function mapOutputMessages(resultMessages) {
648
809
  role: m.role,
649
810
  content: m.content ?? "",
650
811
  toolCalls: m.tool_calls,
651
- toolCallId: m.tool_call_id
812
+ toolCallId: m.tool_call_id,
813
+ ...m.providerMetadata || m.modelOutput ? {
814
+ metadata: {
815
+ ...m.providerMetadata ? { providerMetadata: m.providerMetadata } : {},
816
+ ...m.modelOutput ? { modelOutput: m.modelOutput } : {}
817
+ }
818
+ } : {}
652
819
  }));
653
820
  }
654
821
 
@@ -668,17 +835,32 @@ function createTextStreamHeaders() {
668
835
  };
669
836
  }
670
837
  function formatSSEData(event) {
671
- return `data: ${JSON.stringify(event)}
838
+ const safeEvent = { ...event };
839
+ if ("providerMetadata" in safeEvent)
840
+ safeEvent.providerMetadata = responseReplayMetadata(
841
+ safeEvent.providerMetadata
842
+ );
843
+ if (safeEvent.type === "done" && safeEvent.messages)
844
+ safeEvent.messages = safeEvent.messages.map((message) => ({
845
+ ...message,
846
+ ...message.providerMetadata ? { providerMetadata: responseReplayMetadata(message.providerMetadata) } : {}
847
+ }));
848
+ return `data: ${JSON.stringify(safeEvent)}
672
849
 
673
850
  `;
674
851
  }
675
- function createEventStream(generator) {
852
+ function createEventStream(generator, options) {
676
853
  const encoder = new TextEncoder();
677
854
  return new ReadableStream({
678
855
  async start(controller) {
679
856
  try {
680
857
  for await (const event of generator) {
681
- const data = formatSSEData(event);
858
+ let clientEvent = event;
859
+ if (event.type === "done" && !options?.includeUsage) {
860
+ const { usage: _usage, ...withoutUsage } = event;
861
+ clientEvent = withoutUsage;
862
+ }
863
+ const data = formatSSEData(clientEvent);
682
864
  controller.enqueue(encoder.encode(data));
683
865
  }
684
866
  } catch (error) {
@@ -819,7 +1001,9 @@ var StreamResult = class {
819
1001
  ...createSSEHeaders(),
820
1002
  ...options?.headers
821
1003
  };
822
- return new Response(createEventStream(this.generator), { headers });
1004
+ return new Response(createEventStream(this.generator, options), {
1005
+ headers
1006
+ });
823
1007
  }
824
1008
  /**
825
1009
  * Alias for toResponse() - returns SSE Response
@@ -1538,9 +1722,6 @@ function buildProviderToolOptions(params) {
1538
1722
  function buildToolResultForAI(tool2, result, args) {
1539
1723
  const typedResult = result;
1540
1724
  const responseMode = typedResult?._aiResponseMode ?? tool2?.aiResponseMode ?? "full";
1541
- if (typedResult?._aiContent && typedResult._aiContent.length > 0) {
1542
- return typedResult._aiContent;
1543
- }
1544
1725
  let aiContext;
1545
1726
  if (typedResult?._aiContext) {
1546
1727
  aiContext = typedResult._aiContext;
@@ -1560,25 +1741,6 @@ function buildToolResultForAI(tool2, result, args) {
1560
1741
  Full data: ${fullData}` : fullData;
1561
1742
  }
1562
1743
  }
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
1744
  function extractHeaders(request) {
1583
1745
  if (!request) return {};
1584
1746
  const headers = {};
@@ -1635,7 +1797,11 @@ var Runtime = class {
1635
1797
  const messages = request.messages.map(
1636
1798
  (m, i) => createMessage({
1637
1799
  role: m.role,
1638
- content: m.content
1800
+ content: m.content,
1801
+ providerMetadata: m.providerMetadata,
1802
+ modelOutput: m.modelOutput,
1803
+ tool_calls: m.tool_calls,
1804
+ tool_call_id: m.tool_call_id
1639
1805
  })
1640
1806
  );
1641
1807
  const allActions = [...this.actions.values()];
@@ -2252,6 +2418,7 @@ var Runtime = class {
2252
2418
  let currentToolCall = null;
2253
2419
  const serverToolResults = [];
2254
2420
  const toolContextData = "toolContext" in this.config ? this.config.toolContext : void 0;
2421
+ let adapterProviderMetadata;
2255
2422
  let adapterUsage;
2256
2423
  const completionRequest = {
2257
2424
  messages: [],
@@ -2279,7 +2446,10 @@ var Runtime = class {
2279
2446
  yield event;
2280
2447
  break;
2281
2448
  case "message:end":
2282
- yield event;
2449
+ yield {
2450
+ ...event,
2451
+ providerMetadata: responseReplayMetadata(event.providerMetadata)
2452
+ };
2283
2453
  break;
2284
2454
  case "message:delta":
2285
2455
  accumulatedText += event.content;
@@ -2350,18 +2520,24 @@ var Runtime = class {
2350
2520
  );
2351
2521
  try {
2352
2522
  const result = await tool2.handler(args, toolContext);
2523
+ const modelOutput = resolveToolOutput(
2524
+ result,
2525
+ tool2.toModelOutput?.(result)
2526
+ );
2353
2527
  serverToolResults.push({
2354
2528
  id: event.id,
2355
2529
  name: toolName,
2356
2530
  args,
2357
2531
  result,
2532
+ modelOutput,
2358
2533
  tool: tool2
2359
2534
  });
2360
2535
  yield {
2361
2536
  type: "action:end",
2362
2537
  id: event.id,
2363
2538
  name: toolName,
2364
- result
2539
+ result,
2540
+ modelOutput
2365
2541
  };
2366
2542
  } catch (error) {
2367
2543
  const errorResult = {
@@ -2395,6 +2571,9 @@ var Runtime = class {
2395
2571
  return;
2396
2572
  // Exit on error
2397
2573
  case "done":
2574
+ adapterProviderMetadata = responseReplayMetadata(
2575
+ event.providerMetadata
2576
+ );
2398
2577
  if (event.usage) {
2399
2578
  adapterUsage = event.usage;
2400
2579
  }
@@ -2415,11 +2594,11 @@ var Runtime = class {
2415
2594
  (tc) => !serverToolIds.has(tc.id)
2416
2595
  );
2417
2596
  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));
2597
+ const content = tr.modelOutput ? "[Tool returned content]" : buildToolResultForAI(tr.tool, tr.result, tr.args);
2420
2598
  return {
2421
2599
  role: "tool",
2422
2600
  content,
2601
+ ...tr.modelOutput ? { modelOutput: tr.modelOutput } : {},
2423
2602
  tool_call_id: tr.id
2424
2603
  };
2425
2604
  });
@@ -2432,6 +2611,7 @@ var Runtime = class {
2432
2611
  const assistantMessage = {
2433
2612
  role: "assistant",
2434
2613
  content: accumulatedText || null,
2614
+ ...adapterProviderMetadata ? { providerMetadata: adapterProviderMetadata } : {},
2435
2615
  tool_calls: toolCalls.map((tc) => ({
2436
2616
  id: tc.id,
2437
2617
  type: "function",
@@ -2466,6 +2646,7 @@ var Runtime = class {
2466
2646
  const assistantWithToolCalls = {
2467
2647
  role: "assistant",
2468
2648
  content: accumulatedText || null,
2649
+ ...adapterProviderMetadata ? { providerMetadata: adapterProviderMetadata } : {},
2469
2650
  tool_calls: serverToolResults.map((tr) => {
2470
2651
  const tc = toolCalls.find((t) => t.id === tr.id);
2471
2652
  return {
@@ -2516,6 +2697,7 @@ var Runtime = class {
2516
2697
  const assistantMessage = {
2517
2698
  role: "assistant",
2518
2699
  content: accumulatedText || null,
2700
+ ...adapterProviderMetadata ? { providerMetadata: adapterProviderMetadata } : {},
2519
2701
  tool_calls: clientToolCalls.map((tc) => ({
2520
2702
  id: tc.id,
2521
2703
  type: "function",
@@ -2541,10 +2723,11 @@ var Runtime = class {
2541
2723
  return;
2542
2724
  }
2543
2725
  }
2544
- if (accumulatedText) {
2726
+ if (accumulatedText || adapterProviderMetadata) {
2545
2727
  newMessages.push({
2546
2728
  role: "assistant",
2547
- content: accumulatedText
2729
+ content: accumulatedText,
2730
+ ...adapterProviderMetadata ? { providerMetadata: adapterProviderMetadata } : {}
2548
2731
  });
2549
2732
  }
2550
2733
  if (debug) {
@@ -2659,7 +2842,10 @@ var Runtime = class {
2659
2842
  content: result.content
2660
2843
  };
2661
2844
  }
2662
- yield { type: "message:end" };
2845
+ yield {
2846
+ type: "message:end",
2847
+ providerMetadata: responseReplayMetadata(result.providerMetadata)
2848
+ };
2663
2849
  if (result.toolCalls.length > 0) {
2664
2850
  const serverToolCalls = [];
2665
2851
  const clientToolCalls = [];
@@ -2706,18 +2892,24 @@ var Runtime = class {
2706
2892
  );
2707
2893
  try {
2708
2894
  const toolResult = await tool2.handler(tc.args, toolContext);
2895
+ const modelOutput = resolveToolOutput(
2896
+ toolResult,
2897
+ tool2.toModelOutput?.(toolResult)
2898
+ );
2709
2899
  serverToolResults.push({
2710
2900
  id: tc.id,
2711
2901
  name: tc.name,
2712
2902
  args: tc.args,
2713
2903
  result: toolResult,
2904
+ modelOutput,
2714
2905
  tool: tool2
2715
2906
  });
2716
2907
  yield {
2717
2908
  type: "action:end",
2718
2909
  id: tc.id,
2719
2910
  name: tc.name,
2720
- result: toolResult
2911
+ result: toolResult,
2912
+ modelOutput
2721
2913
  };
2722
2914
  } catch (error) {
2723
2915
  const errorResult = {
@@ -2741,15 +2933,11 @@ var Runtime = class {
2741
2933
  }
2742
2934
  }
2743
2935
  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));
2936
+ const content = tr.modelOutput ? "[Tool returned content]" : buildToolResultForAI(tr.tool, tr.result, tr.args);
2750
2937
  return {
2751
2938
  role: "tool",
2752
2939
  content,
2940
+ ...tr.modelOutput ? { modelOutput: tr.modelOutput } : {},
2753
2941
  tool_call_id: tr.id
2754
2942
  };
2755
2943
  });
@@ -2757,6 +2945,11 @@ var Runtime = class {
2757
2945
  const assistantMessage = {
2758
2946
  role: "assistant",
2759
2947
  content: result.content || null,
2948
+ ...result.providerMetadata ? {
2949
+ providerMetadata: responseReplayMetadata(
2950
+ result.providerMetadata
2951
+ )
2952
+ } : {},
2760
2953
  tool_calls: result.toolCalls.map((tc) => ({
2761
2954
  id: tc.id,
2762
2955
  type: "function",
@@ -2786,6 +2979,11 @@ var Runtime = class {
2786
2979
  const assistantWithToolCalls = {
2787
2980
  role: "assistant",
2788
2981
  content: result.content || null,
2982
+ ...result.providerMetadata ? {
2983
+ providerMetadata: responseReplayMetadata(
2984
+ result.providerMetadata
2985
+ )
2986
+ } : {},
2789
2987
  tool_calls: result.toolCalls.map((tc) => ({
2790
2988
  id: tc.id,
2791
2989
  type: "function",
@@ -2817,6 +3015,11 @@ var Runtime = class {
2817
3015
  const assistantMessage = {
2818
3016
  role: "assistant",
2819
3017
  content: result.content || null,
3018
+ ...result.providerMetadata ? {
3019
+ providerMetadata: responseReplayMetadata(
3020
+ result.providerMetadata
3021
+ )
3022
+ } : {},
2820
3023
  tool_calls: clientToolCalls.map((tc) => ({
2821
3024
  id: tc.id,
2822
3025
  type: "function",
@@ -2842,10 +3045,15 @@ var Runtime = class {
2842
3045
  return;
2843
3046
  }
2844
3047
  }
2845
- if (result.content) {
3048
+ if (result.content || result.providerMetadata) {
2846
3049
  newMessages.push({
2847
3050
  role: "assistant",
2848
- content: result.content
3051
+ content: result.content,
3052
+ ...result.providerMetadata ? {
3053
+ providerMetadata: responseReplayMetadata(
3054
+ result.providerMetadata
3055
+ )
3056
+ } : {}
2849
3057
  });
2850
3058
  }
2851
3059
  if (debug) {
@@ -3997,6 +4205,54 @@ async function executeToolCalls(toolCalls, tools, executeServerTool, waitForClie
3997
4205
  return results;
3998
4206
  }
3999
4207
 
4208
+ // src/core/audio.ts
4209
+ var audioErrorMarker = /* @__PURE__ */ Symbol.for("@yourgpt/llm-sdk/AudioAPIError");
4210
+ var _a;
4211
+ var AudioAPIError = class extends Error {
4212
+ constructor(message, code, status, requestId) {
4213
+ super(message);
4214
+ this.code = code;
4215
+ this.status = status;
4216
+ this.requestId = requestId;
4217
+ this[_a] = true;
4218
+ this.name = "AudioAPIError";
4219
+ }
4220
+ static [(_a = audioErrorMarker, Symbol.hasInstance)](value) {
4221
+ return !!value && typeof value === "object" && value[audioErrorMarker] === true;
4222
+ }
4223
+ };
4224
+ async function generateSpeech({
4225
+ model,
4226
+ ...options
4227
+ }) {
4228
+ options.signal?.throwIfAborted();
4229
+ if (typeof options.text !== "string" || !options.text.trim())
4230
+ throw new AudioAPIError("Speech text must not be empty", "invalid_input");
4231
+ const result = await model.doGenerate(options);
4232
+ options.signal?.throwIfAborted();
4233
+ if (!(result.audio?.uint8Array instanceof Uint8Array) || !result.audio.uint8Array.length)
4234
+ throw new AudioAPIError(
4235
+ "Speech provider returned empty audio",
4236
+ "invalid_response"
4237
+ );
4238
+ return result;
4239
+ }
4240
+ async function transcribe({
4241
+ model,
4242
+ ...options
4243
+ }) {
4244
+ options.signal?.throwIfAborted();
4245
+ const result = await model.doTranscribe(options);
4246
+ options.signal?.throwIfAborted();
4247
+ if (typeof result.text !== "string")
4248
+ throw new AudioAPIError(
4249
+ "Transcription provider returned an invalid transcript",
4250
+ "invalid_response"
4251
+ );
4252
+ return result;
4253
+ }
4254
+
4255
+ exports.AudioAPIError = AudioAPIError;
4000
4256
  exports.DEFAULT_CAPABILITIES = DEFAULT_CAPABILITIES;
4001
4257
  exports.DEFAULT_MAX_ITERATIONS = DEFAULT_MAX_ITERATIONS;
4002
4258
  exports.GenerateResult = GenerateResult;
@@ -4021,6 +4277,7 @@ exports.formatToolsForAnthropic = formatToolsForAnthropic;
4021
4277
  exports.formatToolsForGoogle = formatToolsForGoogle;
4022
4278
  exports.formatToolsForOpenAI = formatToolsForOpenAI;
4023
4279
  exports.generateMessageId = generateMessageId;
4280
+ exports.generateSpeech = generateSpeech;
4024
4281
  exports.generateText = generateText;
4025
4282
  exports.generateThreadId = generateThreadId;
4026
4283
  exports.generateToolCallId = generateToolCallId;
@@ -4033,5 +4290,6 @@ exports.selectTools = selectTools;
4033
4290
  exports.shouldExposeToolSearch = shouldExposeToolSearch;
4034
4291
  exports.streamText = streamText;
4035
4292
  exports.tool = tool;
4293
+ exports.transcribe = transcribe;
4036
4294
  //# sourceMappingURL=index.js.map
4037
4295
  //# sourceMappingURL=index.js.map