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