@yourgpt/llm-sdk 2.6.0-beta.0 → 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 (64) hide show
  1. package/README.md +189 -0
  2. package/dist/adapters/index.d.mts +11 -13
  3. package/dist/adapters/index.d.ts +11 -13
  4. package/dist/adapters/index.js +610 -186
  5. package/dist/adapters/index.mjs +610 -186
  6. package/dist/audio-BBSwnjo8.d.mts +92 -0
  7. package/dist/audio-BBSwnjo8.d.ts +92 -0
  8. package/dist/{base-tNgbBaSo.d.mts → base-BICaQaRS.d.mts} +8 -3
  9. package/dist/{base-C58Dsr9p.d.ts → base-CpRPB8u8.d.ts} +8 -3
  10. package/dist/fallback/index.d.mts +4 -4
  11. package/dist/fallback/index.d.ts +4 -4
  12. package/dist/fallback/index.js +75 -39
  13. package/dist/fallback/index.mjs +75 -39
  14. package/dist/index.d.mts +18 -35
  15. package/dist/index.d.ts +18 -35
  16. package/dist/index.js +304 -88
  17. package/dist/index.mjs +302 -89
  18. package/dist/providers/anthropic/index.d.mts +3 -3
  19. package/dist/providers/anthropic/index.d.ts +3 -3
  20. package/dist/providers/anthropic/index.js +123 -7
  21. package/dist/providers/anthropic/index.mjs +123 -7
  22. package/dist/providers/azure/index.d.mts +3 -3
  23. package/dist/providers/azure/index.d.ts +3 -3
  24. package/dist/providers/azure/index.js +101 -4
  25. package/dist/providers/azure/index.mjs +101 -4
  26. package/dist/providers/fireworks/index.d.mts +3 -3
  27. package/dist/providers/fireworks/index.d.ts +3 -3
  28. package/dist/providers/fireworks/index.js +559 -178
  29. package/dist/providers/fireworks/index.mjs +559 -178
  30. package/dist/providers/google/index.d.mts +3 -3
  31. package/dist/providers/google/index.d.ts +3 -3
  32. package/dist/providers/google/index.js +559 -178
  33. package/dist/providers/google/index.mjs +559 -178
  34. package/dist/providers/ollama/index.d.mts +4 -4
  35. package/dist/providers/ollama/index.d.ts +4 -4
  36. package/dist/providers/ollama/index.js +87 -2
  37. package/dist/providers/ollama/index.mjs +87 -2
  38. package/dist/providers/openai/index.d.mts +25 -23
  39. package/dist/providers/openai/index.d.ts +25 -23
  40. package/dist/providers/openai/index.js +1397 -481
  41. package/dist/providers/openai/index.mjs +1396 -482
  42. package/dist/providers/openrouter/index.d.mts +3 -3
  43. package/dist/providers/openrouter/index.d.ts +3 -3
  44. package/dist/providers/openrouter/index.js +559 -178
  45. package/dist/providers/openrouter/index.mjs +559 -178
  46. package/dist/providers/togetherai/index.d.mts +3 -3
  47. package/dist/providers/togetherai/index.d.ts +3 -3
  48. package/dist/providers/togetherai/index.js +559 -178
  49. package/dist/providers/togetherai/index.mjs +559 -178
  50. package/dist/providers/xai/index.d.mts +3 -3
  51. package/dist/providers/xai/index.d.ts +3 -3
  52. package/dist/providers/xai/index.js +559 -178
  53. package/dist/providers/xai/index.mjs +559 -178
  54. package/dist/{types-B6dhnguR.d.mts → types-C3RgRbEC.d.mts} +11 -4
  55. package/dist/{types-CCxPmkmK.d.ts → types-DCFqkJAy.d.ts} +11 -4
  56. package/dist/{types-BQ31QIsA.d.ts → types-DHQEMFHA.d.mts} +3 -11
  57. package/dist/{types-BkQCSiIt.d.mts → types-Dg1Bcg1k.d.mts} +127 -3
  58. package/dist/{types-BkQCSiIt.d.ts → types-Dg1Bcg1k.d.ts} +127 -3
  59. package/dist/{types-BSSiJW2o.d.mts → types-Dikj3En4.d.ts} +3 -11
  60. package/dist/yourgpt/index.d.mts +1 -1
  61. package/dist/yourgpt/index.d.ts +1 -1
  62. package/docs/multimodal-and-audio.md +170 -0
  63. package/package.json +117 -49
  64. package/LICENSE +0 -21
package/dist/index.mjs CHANGED
@@ -1,13 +1,87 @@
1
1
  import { Hono } from 'hono';
2
2
  import { cors } from 'hono/cors';
3
3
 
4
+ // src/core/tool-output.ts
5
+ var imageTypes = /* @__PURE__ */ new Set([
6
+ "image/png",
7
+ "image/jpeg",
8
+ "image/webp",
9
+ "image/gif"
10
+ ]);
11
+ function normalizeToolOutput(value) {
12
+ const output = value;
13
+ if (output?.type !== "content" || !Array.isArray(output.content) || !output.content.length) {
14
+ throw new Error("Tool model output must contain a nonempty content array");
15
+ }
16
+ return {
17
+ type: "content",
18
+ content: output.content.map((part) => {
19
+ if (part?.type === "text" && typeof part.text === "string")
20
+ return { type: "text", text: part.text };
21
+ if (part?.type !== "image")
22
+ throw new Error("Unsupported tool output content type");
23
+ const sources = ["data", "url", "fileId"].filter((key) => key in part);
24
+ if (sources.length !== 1)
25
+ throw new Error(
26
+ "Tool image requires exactly one of data, url, or fileId"
27
+ );
28
+ if ("fileId" in part) {
29
+ if (part.provider !== "openai" || typeof part.fileId !== "string" || !part.fileId.trim())
30
+ throw new Error(
31
+ "Tool image file references must name the openai provider and fileId"
32
+ );
33
+ return { type: "image", fileId: part.fileId, provider: "openai" };
34
+ }
35
+ if ("url" in part) {
36
+ let url;
37
+ try {
38
+ url = new URL(part.url);
39
+ } catch {
40
+ throw new Error("Invalid tool image URL");
41
+ }
42
+ if (!["https:", "http:"].includes(url.protocol) || url.username || url.password)
43
+ throw new Error(
44
+ "Tool image URL must use HTTP(S) without credentials"
45
+ );
46
+ return { type: "image", url: url.href };
47
+ }
48
+ if (!("data" in part) || !imageTypes.has(part.mediaType))
49
+ throw new Error("Unsupported tool image media type");
50
+ let data = part.data instanceof Uint8Array ? Buffer.from(part.data).toString("base64") : part.data;
51
+ if (typeof data !== "string")
52
+ throw new Error("Tool image data must be base64 or bytes");
53
+ if (data.startsWith("data:")) {
54
+ const match = /^data:([^;,]+);base64,(.+)$/.exec(data);
55
+ if (!match || match[1] !== part.mediaType)
56
+ throw new Error(
57
+ "Tool image data URL media type does not match mediaType"
58
+ );
59
+ data = match[2];
60
+ }
61
+ if (!data.length || data.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(data))
62
+ throw new Error("Invalid tool image base64 data");
63
+ if (Buffer.byteLength(data, "base64") > 20 * 1024 * 1024)
64
+ throw new Error("Tool image exceeds 20 MiB");
65
+ if (Buffer.from(data, "base64").toString("base64") !== data)
66
+ throw new Error("Invalid tool image base64 data");
67
+ return { type: "image", data, mediaType: part.mediaType };
68
+ })
69
+ };
70
+ }
71
+ function resolveToolOutput(result, mapped) {
72
+ if (mapped !== void 0) return normalizeToolOutput(mapped);
73
+ const content = result?._aiContent;
74
+ return content !== void 0 ? normalizeToolOutput({ type: "content", content }) : void 0;
75
+ }
76
+
4
77
  // src/core/tool.ts
5
78
  function tool(config) {
6
79
  return {
7
80
  description: config.description,
8
81
  parameters: config.parameters,
9
82
  execute: config.execute,
10
- hidden: config.hidden
83
+ hidden: config.hidden,
84
+ toModelOutput: config.toModelOutput
11
85
  };
12
86
  }
13
87
  function toolToJsonSchema(toolDef) {
@@ -130,6 +204,14 @@ function formatToolsForGoogle(tools) {
130
204
  ];
131
205
  }
132
206
 
207
+ // src/core/provider-error.ts
208
+ function throwIfAborted(signal) {
209
+ if (!signal?.aborted) return;
210
+ const error = new Error("The operation was aborted");
211
+ error.name = "AbortError";
212
+ throw error;
213
+ }
214
+
133
215
  // src/core/generate-text.ts
134
216
  async function generateText(params) {
135
217
  const { model, tools, maxSteps = 1, signal } = params;
@@ -143,22 +225,24 @@ async function generateText(params) {
143
225
  const allToolCalls = [];
144
226
  const allToolResults = [];
145
227
  for (let step = 0; step < maxSteps; step++) {
146
- if (signal?.aborted) {
147
- throw new Error("Generation aborted");
148
- }
228
+ throwIfAborted(signal);
149
229
  const formattedTools = tools ? formatToolsForProvider(tools, model.provider) : void 0;
150
230
  const result = await model.doGenerate({
151
231
  messages,
232
+ openai: params.openai,
152
233
  tools: formattedTools,
153
234
  temperature: params.temperature,
235
+ reasoningEffort: params.reasoningEffort,
154
236
  maxTokens: params.maxTokens,
155
237
  responseFormat: params.responseFormat,
156
238
  signal
157
239
  });
240
+ throwIfAborted(signal);
158
241
  const stepToolResults = [];
159
242
  if (result.toolCalls && result.toolCalls.length > 0 && tools) {
160
243
  allToolCalls.push(...result.toolCalls);
161
244
  for (const call of result.toolCalls) {
245
+ throwIfAborted(signal);
162
246
  const toolDef = tools[call.name];
163
247
  if (!toolDef) {
164
248
  const errorResult = {
@@ -176,13 +260,19 @@ async function generateText(params) {
176
260
  abortSignal: signal,
177
261
  messages
178
262
  });
263
+ throwIfAborted(signal);
179
264
  const result2 = {
180
265
  toolCallId: call.id,
181
- result: toolResult
266
+ result: toolResult,
267
+ modelOutput: resolveToolOutput(
268
+ toolResult,
269
+ toolDef.toModelOutput?.(toolResult)
270
+ )
182
271
  };
183
272
  stepToolResults.push(result2);
184
273
  allToolResults.push(result2);
185
274
  } catch (error) {
275
+ throwIfAborted(signal);
186
276
  const errorResult = {
187
277
  toolCallId: call.id,
188
278
  result: {
@@ -199,22 +289,23 @@ async function generateText(params) {
199
289
  toolCalls: result.toolCalls,
200
290
  toolResults: stepToolResults,
201
291
  finishReason: result.finishReason,
202
- usage: result.usage
292
+ usage: result.usage,
293
+ providerMetadata: result.providerMetadata
203
294
  });
204
- if (!result.toolCalls || result.toolCalls.length === 0) {
205
- break;
206
- }
207
295
  const assistantMessage = {
208
296
  role: "assistant",
209
297
  content: result.text || null,
210
- toolCalls: result.toolCalls
298
+ ...result.toolCalls.length ? { toolCalls: result.toolCalls } : {},
299
+ ...result.providerMetadata ? { providerMetadata: result.providerMetadata } : {}
211
300
  };
212
301
  messages = [...messages, assistantMessage];
302
+ if (!result.toolCalls || result.toolCalls.length === 0) break;
213
303
  for (const tr of stepToolResults) {
214
304
  const toolMessage = {
215
305
  role: "tool",
216
306
  toolCallId: tr.toolCallId,
217
- content: JSON.stringify(tr.result)
307
+ content: tr.modelOutput ? "[Tool returned content]" : JSON.stringify(tr.result),
308
+ ...tr.modelOutput ? { modelOutput: tr.modelOutput } : {}
218
309
  };
219
310
  messages = [...messages, toolMessage];
220
311
  }
@@ -222,6 +313,7 @@ async function generateText(params) {
222
313
  const lastStep = steps[steps.length - 1];
223
314
  return {
224
315
  text: lastStep?.text ?? "",
316
+ providerMetadata: lastStep?.providerMetadata,
225
317
  usage: sumUsage(steps),
226
318
  finishReason: lastStep?.finishReason ?? "stop",
227
319
  steps,
@@ -275,6 +367,8 @@ async function streamText(params) {
275
367
  `[llm-sdk] ${model.provider}/${model.modelId} does not support structured output (responseFormat); the request will be sent but the provider may ignore it.`
276
368
  );
277
369
  }
370
+ let messages = buildMessages2(params);
371
+ let finalProviderMetadata;
278
372
  let fullText = "";
279
373
  let finalUsage = {
280
374
  promptTokens: 0,
@@ -283,7 +377,6 @@ async function streamText(params) {
283
377
  };
284
378
  let finalFinishReason = "stop";
285
379
  async function* createFullStream() {
286
- let messages = buildMessages2(params);
287
380
  for (let step = 0; step < maxSteps; step++) {
288
381
  yield { type: "step-start", step };
289
382
  if (signal?.aborted) {
@@ -292,17 +385,21 @@ async function streamText(params) {
292
385
  }
293
386
  const formattedTools = tools ? formatToolsForProvider2(tools, model.provider) : void 0;
294
387
  let stepText = "";
388
+ let stepProviderMetadata;
295
389
  const toolCalls = [];
296
390
  let stepFinishReason = "stop";
297
391
  try {
298
392
  for await (const chunk of model.doStream({
299
393
  messages,
394
+ openai: params.openai,
300
395
  tools: formattedTools,
301
396
  temperature: params.temperature,
397
+ reasoningEffort: params.reasoningEffort,
302
398
  maxTokens: params.maxTokens,
303
399
  responseFormat: params.responseFormat,
304
400
  signal
305
401
  })) {
402
+ throwIfAborted(signal);
306
403
  switch (chunk.type) {
307
404
  case "text-delta":
308
405
  stepText += chunk.text;
@@ -317,6 +414,8 @@ async function streamText(params) {
317
414
  };
318
415
  break;
319
416
  case "finish":
417
+ stepProviderMetadata = chunk.providerMetadata;
418
+ finalProviderMetadata = chunk.providerMetadata;
320
419
  stepFinishReason = chunk.finishReason;
321
420
  finalFinishReason = chunk.finishReason;
322
421
  if (chunk.usage) {
@@ -339,17 +438,24 @@ async function streamText(params) {
339
438
  };
340
439
  return;
341
440
  }
342
- yield { type: "step-finish", step, finishReason: stepFinishReason };
343
- if (toolCalls.length === 0 || !tools) {
344
- break;
345
- }
346
- const assistantMessage = {
347
- role: "assistant",
348
- content: stepText || null,
349
- toolCalls
441
+ yield {
442
+ type: "step-finish",
443
+ step,
444
+ finishReason: stepFinishReason,
445
+ providerMetadata: stepProviderMetadata
350
446
  };
351
- messages = [...messages, assistantMessage];
447
+ messages = [
448
+ ...messages,
449
+ {
450
+ role: "assistant",
451
+ content: stepText || null,
452
+ ...toolCalls.length ? { toolCalls } : {},
453
+ ...stepProviderMetadata ? { providerMetadata: stepProviderMetadata } : {}
454
+ }
455
+ ];
456
+ if (toolCalls.length === 0 || !tools) break;
352
457
  for (const call of toolCalls) {
458
+ throwIfAborted(signal);
353
459
  const toolDef = tools[call.name];
354
460
  if (!toolDef) {
355
461
  const errorResult = { error: `Tool not found: ${call.name}` };
@@ -375,16 +481,28 @@ async function streamText(params) {
375
481
  abortSignal: signal,
376
482
  messages
377
483
  });
378
- yield { type: "tool-result", toolCallId: call.id, result };
484
+ throwIfAborted(signal);
485
+ const modelOutput = resolveToolOutput(
486
+ result,
487
+ toolDef.toModelOutput?.(result)
488
+ );
489
+ yield {
490
+ type: "tool-result",
491
+ toolCallId: call.id,
492
+ result,
493
+ modelOutput
494
+ };
379
495
  messages = [
380
496
  ...messages,
381
497
  {
382
498
  role: "tool",
383
499
  toolCallId: call.id,
384
- content: JSON.stringify(result)
500
+ content: modelOutput ? "[Tool returned content]" : JSON.stringify(result),
501
+ ...modelOutput ? { modelOutput } : {}
385
502
  }
386
503
  ];
387
504
  } catch (error) {
505
+ throwIfAborted(signal);
388
506
  const errorResult = {
389
507
  error: error instanceof Error ? error.message : "Tool execution failed"
390
508
  };
@@ -407,43 +525,73 @@ async function streamText(params) {
407
525
  yield {
408
526
  type: "finish",
409
527
  finishReason: finalFinishReason,
410
- usage: finalUsage
528
+ usage: finalUsage,
529
+ providerMetadata: finalProviderMetadata
411
530
  };
412
531
  }
413
- async function* createTextStream() {
414
- for await (const part of createFullStream()) {
415
- if (part.type === "text-delta") {
416
- yield part.text;
417
- }
532
+ const source = createFullStream();
533
+ const parts = [];
534
+ let finished = false;
535
+ let failure;
536
+ let pending;
537
+ async function advance() {
538
+ if (!pending) {
539
+ pending = (async () => {
540
+ try {
541
+ const next = await source.next();
542
+ if (next.done) finished = true;
543
+ else parts.push(next.value);
544
+ } catch (error) {
545
+ failure = error;
546
+ finished = true;
547
+ }
548
+ })();
418
549
  }
550
+ const current = pending;
551
+ await current;
552
+ if (pending === current) pending = void 0;
419
553
  }
420
- let textPromise;
421
- let usagePromise;
422
- let finishReasonPromise;
423
- async function consumeStream() {
424
- for await (const _ of createFullStream()) {
554
+ async function* sharedStream() {
555
+ let index = 0;
556
+ while (true) {
557
+ if (index < parts.length) yield parts[index++];
558
+ else if (finished) {
559
+ if (failure) throw failure;
560
+ return;
561
+ } else await advance();
425
562
  }
426
563
  }
564
+ async function* createTextStream() {
565
+ for await (const part of sharedStream()) {
566
+ if (part.type === "error") throw part.error;
567
+ if (part.type === "text-delta") yield part.text;
568
+ }
569
+ }
570
+ let completion;
571
+ function consumeStream() {
572
+ return completion ?? (completion = (async () => {
573
+ for await (const part of sharedStream()) {
574
+ if (part.type === "error") throw part.error;
575
+ }
576
+ })());
577
+ }
427
578
  return {
428
579
  textStream: createTextStream(),
429
- fullStream: createFullStream(),
580
+ fullStream: sharedStream(),
581
+ get response() {
582
+ return consumeStream().then(() => ({ messages }));
583
+ },
584
+ get providerMetadata() {
585
+ return consumeStream().then(() => finalProviderMetadata);
586
+ },
430
587
  get text() {
431
- if (!textPromise) {
432
- textPromise = consumeStream().then(() => fullText);
433
- }
434
- return textPromise;
588
+ return consumeStream().then(() => fullText);
435
589
  },
436
590
  get usage() {
437
- if (!usagePromise) {
438
- usagePromise = consumeStream().then(() => finalUsage);
439
- }
440
- return usagePromise;
591
+ return consumeStream().then(() => finalUsage);
441
592
  },
442
593
  get finishReason() {
443
- if (!finishReasonPromise) {
444
- finishReasonPromise = consumeStream().then(() => finalFinishReason);
445
- }
446
- return finishReasonPromise;
594
+ return consumeStream().then(() => finalFinishReason);
447
595
  },
448
596
  toTextStreamResponse(options) {
449
597
  const stream = createTextStreamReadable(createTextStream());
@@ -458,7 +606,7 @@ async function streamText(params) {
458
606
  });
459
607
  },
460
608
  toDataStreamResponse(options) {
461
- const stream = createDataStreamReadable(createFullStream());
609
+ const stream = createDataStreamReadable(sharedStream());
462
610
  return new Response(stream, {
463
611
  status: options?.status ?? 200,
464
612
  headers: {
@@ -559,6 +707,7 @@ function createMessage(partial) {
559
707
  tool_calls: partial.tool_calls,
560
708
  tool_call_id: partial.tool_call_id,
561
709
  metadata: partial.metadata,
710
+ providerMetadata: partial.providerMetadata,
562
711
  created_at: partial.created_at ?? /* @__PURE__ */ new Date()
563
712
  };
564
713
  }
@@ -607,7 +756,13 @@ function mapOutputMessages(resultMessages) {
607
756
  role: m.role,
608
757
  content: m.content ?? "",
609
758
  toolCalls: m.tool_calls,
610
- toolCallId: m.tool_call_id
759
+ toolCallId: m.tool_call_id,
760
+ ...m.providerMetadata || m.modelOutput ? {
761
+ metadata: {
762
+ ...m.providerMetadata ? { providerMetadata: m.providerMetadata } : {},
763
+ ...m.modelOutput ? { modelOutput: m.modelOutput } : {}
764
+ }
765
+ } : {}
611
766
  }));
612
767
  }
613
768
 
@@ -1497,9 +1652,6 @@ function buildProviderToolOptions(params) {
1497
1652
  function buildToolResultForAI(tool2, result, args) {
1498
1653
  const typedResult = result;
1499
1654
  const responseMode = typedResult?._aiResponseMode ?? tool2?.aiResponseMode ?? "full";
1500
- if (typedResult?._aiContent && typedResult._aiContent.length > 0) {
1501
- return typedResult._aiContent;
1502
- }
1503
1655
  let aiContext;
1504
1656
  if (typedResult?._aiContext) {
1505
1657
  aiContext = typedResult._aiContext;
@@ -1519,25 +1671,6 @@ function buildToolResultForAI(tool2, result, args) {
1519
1671
  Full data: ${fullData}` : fullData;
1520
1672
  }
1521
1673
  }
1522
- function serializeToolResultContent(content) {
1523
- if (typeof content === "string") {
1524
- return content;
1525
- }
1526
- return content.map((item) => {
1527
- if (item.type === "image") {
1528
- return {
1529
- type: "image_url",
1530
- image_url: {
1531
- url: `data:${item.mediaType};base64,${item.data}`
1532
- }
1533
- };
1534
- }
1535
- return {
1536
- type: "text",
1537
- text: item.text
1538
- };
1539
- });
1540
- }
1541
1674
  function extractHeaders(request) {
1542
1675
  if (!request) return {};
1543
1676
  const headers = {};
@@ -1594,7 +1727,11 @@ var Runtime = class {
1594
1727
  const messages = request.messages.map(
1595
1728
  (m, i) => createMessage({
1596
1729
  role: m.role,
1597
- content: m.content
1730
+ content: m.content,
1731
+ providerMetadata: m.providerMetadata,
1732
+ modelOutput: m.modelOutput,
1733
+ tool_calls: m.tool_calls,
1734
+ tool_call_id: m.tool_call_id
1598
1735
  })
1599
1736
  );
1600
1737
  const allActions = [...this.actions.values()];
@@ -1838,14 +1975,21 @@ var Runtime = class {
1838
1975
  );
1839
1976
  }
1840
1977
  }
1978
+ const resolvedToolIds = new Set(
1979
+ (messages ?? []).filter((message) => message.role === "tool" && message.tool_call_id).map((message) => message.tool_call_id)
1980
+ );
1981
+ const responseToolCalls = requiresAction ? toolCalls.filter((call) => !resolvedToolIds.has(call.id)) : toolCalls;
1841
1982
  const response = {
1842
1983
  success: !error,
1843
1984
  content,
1844
- toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
1985
+ toolCalls: responseToolCalls.length > 0 ? responseToolCalls : void 0,
1845
1986
  toolResults: toolResults.length > 0 ? toolResults : void 0,
1846
1987
  messages,
1847
1988
  requiresAction,
1848
1989
  error,
1990
+ // Copilot's HTTP transport reads a top-level message for HTTP errors.
1991
+ // Retain the structured error as well for existing API consumers.
1992
+ ...error ? { message: error.message } : {},
1849
1993
  // Include raw events for debugging
1850
1994
  _events: this.config.debug ? events : void 0
1851
1995
  };
@@ -1869,6 +2013,7 @@ var Runtime = class {
1869
2013
  return new Response(
1870
2014
  JSON.stringify({
1871
2015
  success: false,
2016
+ message: err instanceof Error ? err.message : "Unknown error",
1872
2017
  error: {
1873
2018
  message: err instanceof Error ? err.message : "Unknown error"
1874
2019
  }
@@ -2203,6 +2348,7 @@ var Runtime = class {
2203
2348
  let currentToolCall = null;
2204
2349
  const serverToolResults = [];
2205
2350
  const toolContextData = "toolContext" in this.config ? this.config.toolContext : void 0;
2351
+ let adapterProviderMetadata;
2206
2352
  let adapterUsage;
2207
2353
  const completionRequest = {
2208
2354
  messages: [],
@@ -2301,18 +2447,24 @@ var Runtime = class {
2301
2447
  );
2302
2448
  try {
2303
2449
  const result = await tool2.handler(args, toolContext);
2450
+ const modelOutput = resolveToolOutput(
2451
+ result,
2452
+ tool2.toModelOutput?.(result)
2453
+ );
2304
2454
  serverToolResults.push({
2305
2455
  id: event.id,
2306
2456
  name: toolName,
2307
2457
  args,
2308
2458
  result,
2459
+ modelOutput,
2309
2460
  tool: tool2
2310
2461
  });
2311
2462
  yield {
2312
2463
  type: "action:end",
2313
2464
  id: event.id,
2314
2465
  name: toolName,
2315
- result
2466
+ result,
2467
+ modelOutput
2316
2468
  };
2317
2469
  } catch (error) {
2318
2470
  const errorResult = {
@@ -2346,6 +2498,7 @@ var Runtime = class {
2346
2498
  return;
2347
2499
  // Exit on error
2348
2500
  case "done":
2501
+ adapterProviderMetadata = event.providerMetadata;
2349
2502
  if (event.usage) {
2350
2503
  adapterUsage = event.usage;
2351
2504
  }
@@ -2366,11 +2519,11 @@ var Runtime = class {
2366
2519
  (tc) => !serverToolIds.has(tc.id)
2367
2520
  );
2368
2521
  const serverToolResultMessages = serverToolResults.map((tr) => {
2369
- const aiContent = buildToolResultForAI(tr.tool, tr.result, tr.args);
2370
- const content = typeof aiContent === "string" ? aiContent : JSON.stringify(serializeToolResultContent(aiContent));
2522
+ const content = tr.modelOutput ? "[Tool returned content]" : buildToolResultForAI(tr.tool, tr.result, tr.args);
2371
2523
  return {
2372
2524
  role: "tool",
2373
2525
  content,
2526
+ ...tr.modelOutput ? { modelOutput: tr.modelOutput } : {},
2374
2527
  tool_call_id: tr.id
2375
2528
  };
2376
2529
  });
@@ -2383,6 +2536,7 @@ var Runtime = class {
2383
2536
  const assistantMessage = {
2384
2537
  role: "assistant",
2385
2538
  content: accumulatedText || null,
2539
+ ...adapterProviderMetadata ? { providerMetadata: adapterProviderMetadata } : {},
2386
2540
  tool_calls: toolCalls.map((tc) => ({
2387
2541
  id: tc.id,
2388
2542
  type: "function",
@@ -2417,6 +2571,7 @@ var Runtime = class {
2417
2571
  const assistantWithToolCalls = {
2418
2572
  role: "assistant",
2419
2573
  content: accumulatedText || null,
2574
+ ...adapterProviderMetadata ? { providerMetadata: adapterProviderMetadata } : {},
2420
2575
  tool_calls: serverToolResults.map((tr) => {
2421
2576
  const tc = toolCalls.find((t) => t.id === tr.id);
2422
2577
  return {
@@ -2467,6 +2622,7 @@ var Runtime = class {
2467
2622
  const assistantMessage = {
2468
2623
  role: "assistant",
2469
2624
  content: accumulatedText || null,
2625
+ ...adapterProviderMetadata ? { providerMetadata: adapterProviderMetadata } : {},
2470
2626
  tool_calls: clientToolCalls.map((tc) => ({
2471
2627
  id: tc.id,
2472
2628
  type: "function",
@@ -2492,10 +2648,11 @@ var Runtime = class {
2492
2648
  return;
2493
2649
  }
2494
2650
  }
2495
- if (accumulatedText) {
2651
+ if (accumulatedText || adapterProviderMetadata) {
2496
2652
  newMessages.push({
2497
2653
  role: "assistant",
2498
- content: accumulatedText
2654
+ content: accumulatedText,
2655
+ ...adapterProviderMetadata ? { providerMetadata: adapterProviderMetadata } : {}
2499
2656
  });
2500
2657
  }
2501
2658
  if (debug) {
@@ -2610,7 +2767,10 @@ var Runtime = class {
2610
2767
  content: result.content
2611
2768
  };
2612
2769
  }
2613
- yield { type: "message:end" };
2770
+ yield {
2771
+ type: "message:end",
2772
+ providerMetadata: result.providerMetadata
2773
+ };
2614
2774
  if (result.toolCalls.length > 0) {
2615
2775
  const serverToolCalls = [];
2616
2776
  const clientToolCalls = [];
@@ -2657,18 +2817,24 @@ var Runtime = class {
2657
2817
  );
2658
2818
  try {
2659
2819
  const toolResult = await tool2.handler(tc.args, toolContext);
2820
+ const modelOutput = resolveToolOutput(
2821
+ toolResult,
2822
+ tool2.toModelOutput?.(toolResult)
2823
+ );
2660
2824
  serverToolResults.push({
2661
2825
  id: tc.id,
2662
2826
  name: tc.name,
2663
2827
  args: tc.args,
2664
2828
  result: toolResult,
2829
+ modelOutput,
2665
2830
  tool: tool2
2666
2831
  });
2667
2832
  yield {
2668
2833
  type: "action:end",
2669
2834
  id: tc.id,
2670
2835
  name: tc.name,
2671
- result: toolResult
2836
+ result: toolResult,
2837
+ modelOutput
2672
2838
  };
2673
2839
  } catch (error) {
2674
2840
  const errorResult = {
@@ -2692,15 +2858,11 @@ var Runtime = class {
2692
2858
  }
2693
2859
  }
2694
2860
  const serverToolResultMessages = serverToolResults.map((tr) => {
2695
- const aiContent = buildToolResultForAI(
2696
- tr.tool,
2697
- tr.result,
2698
- tr.args
2699
- );
2700
- const content = typeof aiContent === "string" ? aiContent : JSON.stringify(serializeToolResultContent(aiContent));
2861
+ const content = tr.modelOutput ? "[Tool returned content]" : buildToolResultForAI(tr.tool, tr.result, tr.args);
2701
2862
  return {
2702
2863
  role: "tool",
2703
2864
  content,
2865
+ ...tr.modelOutput ? { modelOutput: tr.modelOutput } : {},
2704
2866
  tool_call_id: tr.id
2705
2867
  };
2706
2868
  });
@@ -2708,6 +2870,7 @@ var Runtime = class {
2708
2870
  const assistantMessage = {
2709
2871
  role: "assistant",
2710
2872
  content: result.content || null,
2873
+ ...result.providerMetadata ? { providerMetadata: result.providerMetadata } : {},
2711
2874
  tool_calls: result.toolCalls.map((tc) => ({
2712
2875
  id: tc.id,
2713
2876
  type: "function",
@@ -2737,6 +2900,7 @@ var Runtime = class {
2737
2900
  const assistantWithToolCalls = {
2738
2901
  role: "assistant",
2739
2902
  content: result.content || null,
2903
+ ...result.providerMetadata ? { providerMetadata: result.providerMetadata } : {},
2740
2904
  tool_calls: result.toolCalls.map((tc) => ({
2741
2905
  id: tc.id,
2742
2906
  type: "function",
@@ -2768,6 +2932,7 @@ var Runtime = class {
2768
2932
  const assistantMessage = {
2769
2933
  role: "assistant",
2770
2934
  content: result.content || null,
2935
+ ...result.providerMetadata ? { providerMetadata: result.providerMetadata } : {},
2771
2936
  tool_calls: clientToolCalls.map((tc) => ({
2772
2937
  id: tc.id,
2773
2938
  type: "function",
@@ -2793,10 +2958,11 @@ var Runtime = class {
2793
2958
  return;
2794
2959
  }
2795
2960
  }
2796
- if (result.content) {
2961
+ if (result.content || result.providerMetadata) {
2797
2962
  newMessages.push({
2798
2963
  role: "assistant",
2799
- content: result.content
2964
+ content: result.content,
2965
+ ...result.providerMetadata ? { providerMetadata: result.providerMetadata } : {}
2800
2966
  });
2801
2967
  }
2802
2968
  if (debug) {
@@ -3948,6 +4114,53 @@ async function executeToolCalls(toolCalls, tools, executeServerTool, waitForClie
3948
4114
  return results;
3949
4115
  }
3950
4116
 
3951
- 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 };
4117
+ // src/core/audio.ts
4118
+ var audioErrorMarker = /* @__PURE__ */ Symbol.for("@yourgpt/llm-sdk/AudioAPIError");
4119
+ var _a;
4120
+ var AudioAPIError = class extends Error {
4121
+ constructor(message, code, status, requestId) {
4122
+ super(message);
4123
+ this.code = code;
4124
+ this.status = status;
4125
+ this.requestId = requestId;
4126
+ this[_a] = true;
4127
+ this.name = "AudioAPIError";
4128
+ }
4129
+ static [(_a = audioErrorMarker, Symbol.hasInstance)](value) {
4130
+ return !!value && typeof value === "object" && value[audioErrorMarker] === true;
4131
+ }
4132
+ };
4133
+ async function generateSpeech({
4134
+ model,
4135
+ ...options
4136
+ }) {
4137
+ options.signal?.throwIfAborted();
4138
+ if (typeof options.text !== "string" || !options.text.trim())
4139
+ throw new AudioAPIError("Speech text must not be empty", "invalid_input");
4140
+ const result = await model.doGenerate(options);
4141
+ options.signal?.throwIfAborted();
4142
+ if (!(result.audio?.uint8Array instanceof Uint8Array) || !result.audio.uint8Array.length)
4143
+ throw new AudioAPIError(
4144
+ "Speech provider returned empty audio",
4145
+ "invalid_response"
4146
+ );
4147
+ return result;
4148
+ }
4149
+ async function transcribe({
4150
+ model,
4151
+ ...options
4152
+ }) {
4153
+ options.signal?.throwIfAborted();
4154
+ const result = await model.doTranscribe(options);
4155
+ options.signal?.throwIfAborted();
4156
+ if (typeof result.text !== "string")
4157
+ throw new AudioAPIError(
4158
+ "Transcription provider returned an invalid transcript",
4159
+ "invalid_response"
4160
+ );
4161
+ return result;
4162
+ }
4163
+
4164
+ 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 };
3952
4165
  //# sourceMappingURL=index.mjs.map
3953
4166
  //# sourceMappingURL=index.mjs.map