@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.mjs CHANGED
@@ -1,13 +1,137 @@
1
1
  import { Hono } from 'hono';
2
2
  import { cors } from 'hono/cors';
3
3
 
4
+ // src/core/openai-responses.ts
5
+ function responseReplayMetadata(metadata) {
6
+ const response = metadata?.openai?.response;
7
+ if (!response) return metadata;
8
+ const output = response.output.map((item) => {
9
+ const fields = ["type", "id", "status"];
10
+ switch (item.type) {
11
+ case "reasoning":
12
+ fields.push("encrypted_content");
13
+ break;
14
+ case "message":
15
+ fields.push("role", "phase");
16
+ break;
17
+ case "function_call":
18
+ fields.push("call_id", "name", "namespace", "arguments");
19
+ break;
20
+ case "tool_search_call":
21
+ fields.push("call_id", "execution", "arguments");
22
+ break;
23
+ case "tool_search_output":
24
+ fields.push("call_id", "tools");
25
+ break;
26
+ case "web_search_call":
27
+ fields.push("action");
28
+ break;
29
+ default:
30
+ return stripItemDiagnostics(item);
31
+ }
32
+ const replay = Object.fromEntries(
33
+ fields.filter((key) => item[key] !== void 0).map((key) => [key, item[key]])
34
+ );
35
+ if (item.type === "reasoning") replay.summary = [];
36
+ if (item.type === "message")
37
+ replay.content = Array.isArray(item.content) ? item.content.flatMap(
38
+ (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 }] : []
39
+ ) : [];
40
+ return stripItemDiagnostics(replay);
41
+ });
42
+ return { openai: { response: { output, refusals: [] } } };
43
+ }
44
+ function stripItemDiagnostics(item) {
45
+ const {
46
+ usage: _usage,
47
+ logprobs: _logprobs,
48
+ metadata: _metadata,
49
+ ...state
50
+ } = item;
51
+ return state;
52
+ }
53
+
54
+ // src/core/tool-output.ts
55
+ var imageTypes = /* @__PURE__ */ new Set([
56
+ "image/png",
57
+ "image/jpeg",
58
+ "image/webp",
59
+ "image/gif"
60
+ ]);
61
+ function normalizeToolOutput(value) {
62
+ const output = value;
63
+ if (output?.type !== "content" || !Array.isArray(output.content) || !output.content.length) {
64
+ throw new Error("Tool model output must contain a nonempty content array");
65
+ }
66
+ return {
67
+ type: "content",
68
+ content: output.content.map((part) => {
69
+ if (part?.type === "text" && typeof part.text === "string")
70
+ return { type: "text", text: part.text };
71
+ if (part?.type !== "image")
72
+ throw new Error("Unsupported tool output content type");
73
+ const sources = ["data", "url", "fileId"].filter((key) => key in part);
74
+ if (sources.length !== 1)
75
+ throw new Error(
76
+ "Tool image requires exactly one of data, url, or fileId"
77
+ );
78
+ if ("fileId" in part) {
79
+ if (part.provider !== "openai" || typeof part.fileId !== "string" || !part.fileId.trim())
80
+ throw new Error(
81
+ "Tool image file references must name the openai provider and fileId"
82
+ );
83
+ return { type: "image", fileId: part.fileId, provider: "openai" };
84
+ }
85
+ if ("url" in part) {
86
+ let url;
87
+ try {
88
+ url = new URL(part.url);
89
+ } catch {
90
+ throw new Error("Invalid tool image URL");
91
+ }
92
+ if (!["https:", "http:"].includes(url.protocol) || url.username || url.password)
93
+ throw new Error(
94
+ "Tool image URL must use HTTP(S) without credentials"
95
+ );
96
+ return { type: "image", url: url.href };
97
+ }
98
+ if (!("data" in part) || !imageTypes.has(part.mediaType))
99
+ throw new Error("Unsupported tool image media type");
100
+ let data = part.data instanceof Uint8Array ? Buffer.from(part.data).toString("base64") : part.data;
101
+ if (typeof data !== "string")
102
+ throw new Error("Tool image data must be base64 or bytes");
103
+ if (data.startsWith("data:")) {
104
+ const match = /^data:([^;,]+);base64,(.+)$/.exec(data);
105
+ if (!match || match[1] !== part.mediaType)
106
+ throw new Error(
107
+ "Tool image data URL media type does not match mediaType"
108
+ );
109
+ data = match[2];
110
+ }
111
+ if (!data.length || data.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(data))
112
+ throw new Error("Invalid tool image base64 data");
113
+ if (Buffer.byteLength(data, "base64") > 20 * 1024 * 1024)
114
+ throw new Error("Tool image exceeds 20 MiB");
115
+ if (Buffer.from(data, "base64").toString("base64") !== data)
116
+ throw new Error("Invalid tool image base64 data");
117
+ return { type: "image", data, mediaType: part.mediaType };
118
+ })
119
+ };
120
+ }
121
+ function resolveToolOutput(result, mapped) {
122
+ if (mapped !== void 0) return normalizeToolOutput(mapped);
123
+ const content = result?._aiContent;
124
+ return content !== void 0 ? normalizeToolOutput({ type: "content", content }) : void 0;
125
+ }
126
+
4
127
  // src/core/tool.ts
5
128
  function tool(config) {
6
129
  return {
7
130
  description: config.description,
8
131
  parameters: config.parameters,
9
132
  execute: config.execute,
10
- hidden: config.hidden
133
+ hidden: config.hidden,
134
+ toModelOutput: config.toModelOutput
11
135
  };
12
136
  }
13
137
  function toolToJsonSchema(toolDef) {
@@ -155,6 +279,7 @@ async function generateText(params) {
155
279
  const formattedTools = tools ? formatToolsForProvider(tools, model.provider) : void 0;
156
280
  const result = await model.doGenerate({
157
281
  messages,
282
+ openai: params.openai,
158
283
  tools: formattedTools,
159
284
  temperature: params.temperature,
160
285
  reasoningEffort: params.reasoningEffort,
@@ -163,10 +288,11 @@ async function generateText(params) {
163
288
  signal
164
289
  });
165
290
  throwIfAborted(signal);
291
+ const toolCalls = result.toolCalls ?? [];
166
292
  const stepToolResults = [];
167
- if (result.toolCalls && result.toolCalls.length > 0 && tools) {
168
- allToolCalls.push(...result.toolCalls);
169
- for (const call of result.toolCalls) {
293
+ if (toolCalls.length > 0 && tools) {
294
+ allToolCalls.push(...toolCalls);
295
+ for (const call of toolCalls) {
170
296
  throwIfAborted(signal);
171
297
  const toolDef = tools[call.name];
172
298
  if (!toolDef) {
@@ -188,7 +314,11 @@ async function generateText(params) {
188
314
  throwIfAborted(signal);
189
315
  const result2 = {
190
316
  toolCallId: call.id,
191
- result: toolResult
317
+ result: toolResult,
318
+ modelOutput: resolveToolOutput(
319
+ toolResult,
320
+ toolDef.toModelOutput?.(toolResult)
321
+ )
192
322
  };
193
323
  stepToolResults.push(result2);
194
324
  allToolResults.push(result2);
@@ -207,25 +337,26 @@ async function generateText(params) {
207
337
  }
208
338
  steps.push({
209
339
  text: result.text,
210
- toolCalls: result.toolCalls,
340
+ toolCalls,
211
341
  toolResults: stepToolResults,
212
342
  finishReason: result.finishReason,
213
- usage: result.usage
343
+ usage: result.usage,
344
+ providerMetadata: result.providerMetadata
214
345
  });
215
- if (!result.toolCalls || result.toolCalls.length === 0) {
216
- break;
217
- }
218
346
  const assistantMessage = {
219
347
  role: "assistant",
220
348
  content: result.text || null,
221
- toolCalls: result.toolCalls
349
+ ...toolCalls.length ? { toolCalls } : {},
350
+ ...result.providerMetadata ? { providerMetadata: responseReplayMetadata(result.providerMetadata) } : {}
222
351
  };
223
352
  messages = [...messages, assistantMessage];
353
+ if (toolCalls.length === 0) break;
224
354
  for (const tr of stepToolResults) {
225
355
  const toolMessage = {
226
356
  role: "tool",
227
357
  toolCallId: tr.toolCallId,
228
- content: JSON.stringify(tr.result)
358
+ content: tr.modelOutput ? "[Tool returned content]" : JSON.stringify(tr.result),
359
+ ...tr.modelOutput ? { modelOutput: tr.modelOutput } : {}
229
360
  };
230
361
  messages = [...messages, toolMessage];
231
362
  }
@@ -233,6 +364,7 @@ async function generateText(params) {
233
364
  const lastStep = steps[steps.length - 1];
234
365
  return {
235
366
  text: lastStep?.text ?? "",
367
+ providerMetadata: lastStep?.providerMetadata,
236
368
  usage: sumUsage(steps),
237
369
  finishReason: lastStep?.finishReason ?? "stop",
238
370
  steps,
@@ -286,6 +418,8 @@ async function streamText(params) {
286
418
  `[llm-sdk] ${model.provider}/${model.modelId} does not support structured output (responseFormat); the request will be sent but the provider may ignore it.`
287
419
  );
288
420
  }
421
+ let messages = buildMessages2(params);
422
+ let finalProviderMetadata;
289
423
  let fullText = "";
290
424
  let finalUsage = {
291
425
  promptTokens: 0,
@@ -294,7 +428,6 @@ async function streamText(params) {
294
428
  };
295
429
  let finalFinishReason = "stop";
296
430
  async function* createFullStream() {
297
- let messages = buildMessages2(params);
298
431
  for (let step = 0; step < maxSteps; step++) {
299
432
  yield { type: "step-start", step };
300
433
  if (signal?.aborted) {
@@ -303,11 +436,13 @@ async function streamText(params) {
303
436
  }
304
437
  const formattedTools = tools ? formatToolsForProvider2(tools, model.provider) : void 0;
305
438
  let stepText = "";
439
+ let stepProviderMetadata;
306
440
  const toolCalls = [];
307
441
  let stepFinishReason = "stop";
308
442
  try {
309
443
  for await (const chunk of model.doStream({
310
444
  messages,
445
+ openai: params.openai,
311
446
  tools: formattedTools,
312
447
  temperature: params.temperature,
313
448
  reasoningEffort: params.reasoningEffort,
@@ -330,6 +465,8 @@ async function streamText(params) {
330
465
  };
331
466
  break;
332
467
  case "finish":
468
+ stepProviderMetadata = chunk.providerMetadata;
469
+ finalProviderMetadata = chunk.providerMetadata;
333
470
  stepFinishReason = chunk.finishReason;
334
471
  finalFinishReason = chunk.finishReason;
335
472
  if (chunk.usage) {
@@ -352,16 +489,22 @@ async function streamText(params) {
352
489
  };
353
490
  return;
354
491
  }
355
- yield { type: "step-finish", step, finishReason: stepFinishReason };
356
- if (toolCalls.length === 0 || !tools) {
357
- break;
358
- }
359
- const assistantMessage = {
360
- role: "assistant",
361
- content: stepText || null,
362
- toolCalls
492
+ yield {
493
+ type: "step-finish",
494
+ step,
495
+ finishReason: stepFinishReason,
496
+ providerMetadata: stepProviderMetadata
363
497
  };
364
- messages = [...messages, assistantMessage];
498
+ messages = [
499
+ ...messages,
500
+ {
501
+ role: "assistant",
502
+ content: stepText || null,
503
+ ...toolCalls.length ? { toolCalls } : {},
504
+ ...stepProviderMetadata ? { providerMetadata: responseReplayMetadata(stepProviderMetadata) } : {}
505
+ }
506
+ ];
507
+ if (toolCalls.length === 0 || !tools) break;
365
508
  for (const call of toolCalls) {
366
509
  throwIfAborted(signal);
367
510
  const toolDef = tools[call.name];
@@ -390,13 +533,23 @@ async function streamText(params) {
390
533
  messages
391
534
  });
392
535
  throwIfAborted(signal);
393
- yield { type: "tool-result", toolCallId: call.id, result };
536
+ const modelOutput = resolveToolOutput(
537
+ result,
538
+ toolDef.toModelOutput?.(result)
539
+ );
540
+ yield {
541
+ type: "tool-result",
542
+ toolCallId: call.id,
543
+ result,
544
+ modelOutput
545
+ };
394
546
  messages = [
395
547
  ...messages,
396
548
  {
397
549
  role: "tool",
398
550
  toolCallId: call.id,
399
- content: JSON.stringify(result)
551
+ content: modelOutput ? "[Tool returned content]" : JSON.stringify(result),
552
+ ...modelOutput ? { modelOutput } : {}
400
553
  }
401
554
  ];
402
555
  } catch (error) {
@@ -423,7 +576,8 @@ async function streamText(params) {
423
576
  yield {
424
577
  type: "finish",
425
578
  finishReason: finalFinishReason,
426
- usage: finalUsage
579
+ usage: finalUsage,
580
+ providerMetadata: finalProviderMetadata
427
581
  };
428
582
  }
429
583
  const source = createFullStream();
@@ -475,6 +629,12 @@ async function streamText(params) {
475
629
  return {
476
630
  textStream: createTextStream(),
477
631
  fullStream: sharedStream(),
632
+ get response() {
633
+ return consumeStream().then(() => ({ messages }));
634
+ },
635
+ get providerMetadata() {
636
+ return consumeStream().then(() => finalProviderMetadata);
637
+ },
478
638
  get text() {
479
639
  return consumeStream().then(() => fullText);
480
640
  },
@@ -598,6 +758,7 @@ function createMessage(partial) {
598
758
  tool_calls: partial.tool_calls,
599
759
  tool_call_id: partial.tool_call_id,
600
760
  metadata: partial.metadata,
761
+ providerMetadata: partial.providerMetadata,
601
762
  created_at: partial.created_at ?? /* @__PURE__ */ new Date()
602
763
  };
603
764
  }
@@ -646,7 +807,13 @@ function mapOutputMessages(resultMessages) {
646
807
  role: m.role,
647
808
  content: m.content ?? "",
648
809
  toolCalls: m.tool_calls,
649
- toolCallId: m.tool_call_id
810
+ toolCallId: m.tool_call_id,
811
+ ...m.providerMetadata || m.modelOutput ? {
812
+ metadata: {
813
+ ...m.providerMetadata ? { providerMetadata: m.providerMetadata } : {},
814
+ ...m.modelOutput ? { modelOutput: m.modelOutput } : {}
815
+ }
816
+ } : {}
650
817
  }));
651
818
  }
652
819
 
@@ -666,17 +833,32 @@ function createTextStreamHeaders() {
666
833
  };
667
834
  }
668
835
  function formatSSEData(event) {
669
- return `data: ${JSON.stringify(event)}
836
+ const safeEvent = { ...event };
837
+ if ("providerMetadata" in safeEvent)
838
+ safeEvent.providerMetadata = responseReplayMetadata(
839
+ safeEvent.providerMetadata
840
+ );
841
+ if (safeEvent.type === "done" && safeEvent.messages)
842
+ safeEvent.messages = safeEvent.messages.map((message) => ({
843
+ ...message,
844
+ ...message.providerMetadata ? { providerMetadata: responseReplayMetadata(message.providerMetadata) } : {}
845
+ }));
846
+ return `data: ${JSON.stringify(safeEvent)}
670
847
 
671
848
  `;
672
849
  }
673
- function createEventStream(generator) {
850
+ function createEventStream(generator, options) {
674
851
  const encoder = new TextEncoder();
675
852
  return new ReadableStream({
676
853
  async start(controller) {
677
854
  try {
678
855
  for await (const event of generator) {
679
- const data = formatSSEData(event);
856
+ let clientEvent = event;
857
+ if (event.type === "done" && !options?.includeUsage) {
858
+ const { usage: _usage, ...withoutUsage } = event;
859
+ clientEvent = withoutUsage;
860
+ }
861
+ const data = formatSSEData(clientEvent);
680
862
  controller.enqueue(encoder.encode(data));
681
863
  }
682
864
  } catch (error) {
@@ -817,7 +999,9 @@ var StreamResult = class {
817
999
  ...createSSEHeaders(),
818
1000
  ...options?.headers
819
1001
  };
820
- return new Response(createEventStream(this.generator), { headers });
1002
+ return new Response(createEventStream(this.generator, options), {
1003
+ headers
1004
+ });
821
1005
  }
822
1006
  /**
823
1007
  * Alias for toResponse() - returns SSE Response
@@ -1536,9 +1720,6 @@ function buildProviderToolOptions(params) {
1536
1720
  function buildToolResultForAI(tool2, result, args) {
1537
1721
  const typedResult = result;
1538
1722
  const responseMode = typedResult?._aiResponseMode ?? tool2?.aiResponseMode ?? "full";
1539
- if (typedResult?._aiContent && typedResult._aiContent.length > 0) {
1540
- return typedResult._aiContent;
1541
- }
1542
1723
  let aiContext;
1543
1724
  if (typedResult?._aiContext) {
1544
1725
  aiContext = typedResult._aiContext;
@@ -1558,25 +1739,6 @@ function buildToolResultForAI(tool2, result, args) {
1558
1739
  Full data: ${fullData}` : fullData;
1559
1740
  }
1560
1741
  }
1561
- function serializeToolResultContent(content) {
1562
- if (typeof content === "string") {
1563
- return content;
1564
- }
1565
- return content.map((item) => {
1566
- if (item.type === "image") {
1567
- return {
1568
- type: "image_url",
1569
- image_url: {
1570
- url: `data:${item.mediaType};base64,${item.data}`
1571
- }
1572
- };
1573
- }
1574
- return {
1575
- type: "text",
1576
- text: item.text
1577
- };
1578
- });
1579
- }
1580
1742
  function extractHeaders(request) {
1581
1743
  if (!request) return {};
1582
1744
  const headers = {};
@@ -1633,7 +1795,11 @@ var Runtime = class {
1633
1795
  const messages = request.messages.map(
1634
1796
  (m, i) => createMessage({
1635
1797
  role: m.role,
1636
- content: m.content
1798
+ content: m.content,
1799
+ providerMetadata: m.providerMetadata,
1800
+ modelOutput: m.modelOutput,
1801
+ tool_calls: m.tool_calls,
1802
+ tool_call_id: m.tool_call_id
1637
1803
  })
1638
1804
  );
1639
1805
  const allActions = [...this.actions.values()];
@@ -2250,6 +2416,7 @@ var Runtime = class {
2250
2416
  let currentToolCall = null;
2251
2417
  const serverToolResults = [];
2252
2418
  const toolContextData = "toolContext" in this.config ? this.config.toolContext : void 0;
2419
+ let adapterProviderMetadata;
2253
2420
  let adapterUsage;
2254
2421
  const completionRequest = {
2255
2422
  messages: [],
@@ -2277,7 +2444,10 @@ var Runtime = class {
2277
2444
  yield event;
2278
2445
  break;
2279
2446
  case "message:end":
2280
- yield event;
2447
+ yield {
2448
+ ...event,
2449
+ providerMetadata: responseReplayMetadata(event.providerMetadata)
2450
+ };
2281
2451
  break;
2282
2452
  case "message:delta":
2283
2453
  accumulatedText += event.content;
@@ -2348,18 +2518,24 @@ var Runtime = class {
2348
2518
  );
2349
2519
  try {
2350
2520
  const result = await tool2.handler(args, toolContext);
2521
+ const modelOutput = resolveToolOutput(
2522
+ result,
2523
+ tool2.toModelOutput?.(result)
2524
+ );
2351
2525
  serverToolResults.push({
2352
2526
  id: event.id,
2353
2527
  name: toolName,
2354
2528
  args,
2355
2529
  result,
2530
+ modelOutput,
2356
2531
  tool: tool2
2357
2532
  });
2358
2533
  yield {
2359
2534
  type: "action:end",
2360
2535
  id: event.id,
2361
2536
  name: toolName,
2362
- result
2537
+ result,
2538
+ modelOutput
2363
2539
  };
2364
2540
  } catch (error) {
2365
2541
  const errorResult = {
@@ -2393,6 +2569,9 @@ var Runtime = class {
2393
2569
  return;
2394
2570
  // Exit on error
2395
2571
  case "done":
2572
+ adapterProviderMetadata = responseReplayMetadata(
2573
+ event.providerMetadata
2574
+ );
2396
2575
  if (event.usage) {
2397
2576
  adapterUsage = event.usage;
2398
2577
  }
@@ -2413,11 +2592,11 @@ var Runtime = class {
2413
2592
  (tc) => !serverToolIds.has(tc.id)
2414
2593
  );
2415
2594
  const serverToolResultMessages = serverToolResults.map((tr) => {
2416
- const aiContent = buildToolResultForAI(tr.tool, tr.result, tr.args);
2417
- const content = typeof aiContent === "string" ? aiContent : JSON.stringify(serializeToolResultContent(aiContent));
2595
+ const content = tr.modelOutput ? "[Tool returned content]" : buildToolResultForAI(tr.tool, tr.result, tr.args);
2418
2596
  return {
2419
2597
  role: "tool",
2420
2598
  content,
2599
+ ...tr.modelOutput ? { modelOutput: tr.modelOutput } : {},
2421
2600
  tool_call_id: tr.id
2422
2601
  };
2423
2602
  });
@@ -2430,6 +2609,7 @@ var Runtime = class {
2430
2609
  const assistantMessage = {
2431
2610
  role: "assistant",
2432
2611
  content: accumulatedText || null,
2612
+ ...adapterProviderMetadata ? { providerMetadata: adapterProviderMetadata } : {},
2433
2613
  tool_calls: toolCalls.map((tc) => ({
2434
2614
  id: tc.id,
2435
2615
  type: "function",
@@ -2464,6 +2644,7 @@ var Runtime = class {
2464
2644
  const assistantWithToolCalls = {
2465
2645
  role: "assistant",
2466
2646
  content: accumulatedText || null,
2647
+ ...adapterProviderMetadata ? { providerMetadata: adapterProviderMetadata } : {},
2467
2648
  tool_calls: serverToolResults.map((tr) => {
2468
2649
  const tc = toolCalls.find((t) => t.id === tr.id);
2469
2650
  return {
@@ -2514,6 +2695,7 @@ var Runtime = class {
2514
2695
  const assistantMessage = {
2515
2696
  role: "assistant",
2516
2697
  content: accumulatedText || null,
2698
+ ...adapterProviderMetadata ? { providerMetadata: adapterProviderMetadata } : {},
2517
2699
  tool_calls: clientToolCalls.map((tc) => ({
2518
2700
  id: tc.id,
2519
2701
  type: "function",
@@ -2539,10 +2721,11 @@ var Runtime = class {
2539
2721
  return;
2540
2722
  }
2541
2723
  }
2542
- if (accumulatedText) {
2724
+ if (accumulatedText || adapterProviderMetadata) {
2543
2725
  newMessages.push({
2544
2726
  role: "assistant",
2545
- content: accumulatedText
2727
+ content: accumulatedText,
2728
+ ...adapterProviderMetadata ? { providerMetadata: adapterProviderMetadata } : {}
2546
2729
  });
2547
2730
  }
2548
2731
  if (debug) {
@@ -2657,7 +2840,10 @@ var Runtime = class {
2657
2840
  content: result.content
2658
2841
  };
2659
2842
  }
2660
- yield { type: "message:end" };
2843
+ yield {
2844
+ type: "message:end",
2845
+ providerMetadata: responseReplayMetadata(result.providerMetadata)
2846
+ };
2661
2847
  if (result.toolCalls.length > 0) {
2662
2848
  const serverToolCalls = [];
2663
2849
  const clientToolCalls = [];
@@ -2704,18 +2890,24 @@ var Runtime = class {
2704
2890
  );
2705
2891
  try {
2706
2892
  const toolResult = await tool2.handler(tc.args, toolContext);
2893
+ const modelOutput = resolveToolOutput(
2894
+ toolResult,
2895
+ tool2.toModelOutput?.(toolResult)
2896
+ );
2707
2897
  serverToolResults.push({
2708
2898
  id: tc.id,
2709
2899
  name: tc.name,
2710
2900
  args: tc.args,
2711
2901
  result: toolResult,
2902
+ modelOutput,
2712
2903
  tool: tool2
2713
2904
  });
2714
2905
  yield {
2715
2906
  type: "action:end",
2716
2907
  id: tc.id,
2717
2908
  name: tc.name,
2718
- result: toolResult
2909
+ result: toolResult,
2910
+ modelOutput
2719
2911
  };
2720
2912
  } catch (error) {
2721
2913
  const errorResult = {
@@ -2739,15 +2931,11 @@ var Runtime = class {
2739
2931
  }
2740
2932
  }
2741
2933
  const serverToolResultMessages = serverToolResults.map((tr) => {
2742
- const aiContent = buildToolResultForAI(
2743
- tr.tool,
2744
- tr.result,
2745
- tr.args
2746
- );
2747
- const content = typeof aiContent === "string" ? aiContent : JSON.stringify(serializeToolResultContent(aiContent));
2934
+ const content = tr.modelOutput ? "[Tool returned content]" : buildToolResultForAI(tr.tool, tr.result, tr.args);
2748
2935
  return {
2749
2936
  role: "tool",
2750
2937
  content,
2938
+ ...tr.modelOutput ? { modelOutput: tr.modelOutput } : {},
2751
2939
  tool_call_id: tr.id
2752
2940
  };
2753
2941
  });
@@ -2755,6 +2943,11 @@ var Runtime = class {
2755
2943
  const assistantMessage = {
2756
2944
  role: "assistant",
2757
2945
  content: result.content || null,
2946
+ ...result.providerMetadata ? {
2947
+ providerMetadata: responseReplayMetadata(
2948
+ result.providerMetadata
2949
+ )
2950
+ } : {},
2758
2951
  tool_calls: result.toolCalls.map((tc) => ({
2759
2952
  id: tc.id,
2760
2953
  type: "function",
@@ -2784,6 +2977,11 @@ var Runtime = class {
2784
2977
  const assistantWithToolCalls = {
2785
2978
  role: "assistant",
2786
2979
  content: result.content || null,
2980
+ ...result.providerMetadata ? {
2981
+ providerMetadata: responseReplayMetadata(
2982
+ result.providerMetadata
2983
+ )
2984
+ } : {},
2787
2985
  tool_calls: result.toolCalls.map((tc) => ({
2788
2986
  id: tc.id,
2789
2987
  type: "function",
@@ -2815,6 +3013,11 @@ var Runtime = class {
2815
3013
  const assistantMessage = {
2816
3014
  role: "assistant",
2817
3015
  content: result.content || null,
3016
+ ...result.providerMetadata ? {
3017
+ providerMetadata: responseReplayMetadata(
3018
+ result.providerMetadata
3019
+ )
3020
+ } : {},
2818
3021
  tool_calls: clientToolCalls.map((tc) => ({
2819
3022
  id: tc.id,
2820
3023
  type: "function",
@@ -2840,10 +3043,15 @@ var Runtime = class {
2840
3043
  return;
2841
3044
  }
2842
3045
  }
2843
- if (result.content) {
3046
+ if (result.content || result.providerMetadata) {
2844
3047
  newMessages.push({
2845
3048
  role: "assistant",
2846
- content: result.content
3049
+ content: result.content,
3050
+ ...result.providerMetadata ? {
3051
+ providerMetadata: responseReplayMetadata(
3052
+ result.providerMetadata
3053
+ )
3054
+ } : {}
2847
3055
  });
2848
3056
  }
2849
3057
  if (debug) {
@@ -3995,6 +4203,53 @@ async function executeToolCalls(toolCalls, tools, executeServerTool, waitForClie
3995
4203
  return results;
3996
4204
  }
3997
4205
 
3998
- export { DEFAULT_CAPABILITIES, DEFAULT_MAX_ITERATIONS, GenerateResult, Runtime, StreamResult, buildProviderToolOptions, createEventStream, createExpressHandler, createExpressMiddleware, createHonoApp, createNextHandler, createNodeHandler, createRuntime, createSSEHeaders, createSSEResponse, createStreamResult, createTextStreamHeaders, createTextStreamResponse, extractInputMessages, formatSSEData, formatToolsForAnthropic, formatToolsForGoogle, formatToolsForOpenAI, generateMessageId, generateText, generateThreadId, generateToolCallId, mapOutputMessages, pipeSSEToResponse, pipeTextToResponse, runAgentLoop, searchTools, selectTools, shouldExposeToolSearch, streamText, tool };
4206
+ // src/core/audio.ts
4207
+ var audioErrorMarker = /* @__PURE__ */ Symbol.for("@yourgpt/llm-sdk/AudioAPIError");
4208
+ var _a;
4209
+ var AudioAPIError = class extends Error {
4210
+ constructor(message, code, status, requestId) {
4211
+ super(message);
4212
+ this.code = code;
4213
+ this.status = status;
4214
+ this.requestId = requestId;
4215
+ this[_a] = true;
4216
+ this.name = "AudioAPIError";
4217
+ }
4218
+ static [(_a = audioErrorMarker, Symbol.hasInstance)](value) {
4219
+ return !!value && typeof value === "object" && value[audioErrorMarker] === true;
4220
+ }
4221
+ };
4222
+ async function generateSpeech({
4223
+ model,
4224
+ ...options
4225
+ }) {
4226
+ options.signal?.throwIfAborted();
4227
+ if (typeof options.text !== "string" || !options.text.trim())
4228
+ throw new AudioAPIError("Speech text must not be empty", "invalid_input");
4229
+ const result = await model.doGenerate(options);
4230
+ options.signal?.throwIfAborted();
4231
+ if (!(result.audio?.uint8Array instanceof Uint8Array) || !result.audio.uint8Array.length)
4232
+ throw new AudioAPIError(
4233
+ "Speech provider returned empty audio",
4234
+ "invalid_response"
4235
+ );
4236
+ return result;
4237
+ }
4238
+ async function transcribe({
4239
+ model,
4240
+ ...options
4241
+ }) {
4242
+ options.signal?.throwIfAborted();
4243
+ const result = await model.doTranscribe(options);
4244
+ options.signal?.throwIfAborted();
4245
+ if (typeof result.text !== "string")
4246
+ throw new AudioAPIError(
4247
+ "Transcription provider returned an invalid transcript",
4248
+ "invalid_response"
4249
+ );
4250
+ return result;
4251
+ }
4252
+
4253
+ export { AudioAPIError, DEFAULT_CAPABILITIES, DEFAULT_MAX_ITERATIONS, GenerateResult, Runtime, StreamResult, buildProviderToolOptions, createEventStream, createExpressHandler, createExpressMiddleware, createHonoApp, createNextHandler, createNodeHandler, createRuntime, createSSEHeaders, createSSEResponse, createStreamResult, createTextStreamHeaders, createTextStreamResponse, extractInputMessages, formatSSEData, formatToolsForAnthropic, formatToolsForGoogle, formatToolsForOpenAI, generateMessageId, generateSpeech, generateText, generateThreadId, generateToolCallId, mapOutputMessages, pipeSSEToResponse, pipeTextToResponse, runAgentLoop, searchTools, selectTools, shouldExposeToolSearch, streamText, tool, transcribe };
3999
4254
  //# sourceMappingURL=index.mjs.map
4000
4255
  //# sourceMappingURL=index.mjs.map