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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +112 -0
  2. package/dist/adapters/index.d.mts +5 -5
  3. package/dist/adapters/index.d.ts +5 -5
  4. package/dist/adapters/index.js +372 -39
  5. package/dist/adapters/index.mjs +372 -39
  6. package/dist/audio-BBSwnjo8.d.mts +92 -0
  7. package/dist/audio-BBSwnjo8.d.ts +92 -0
  8. package/dist/{base-CkeT7u-O.d.mts → base-BICaQaRS.d.mts} +7 -3
  9. package/dist/{base-BdTpUAWI.d.ts → base-CpRPB8u8.d.ts} +7 -3
  10. package/dist/fallback/index.d.mts +4 -4
  11. package/dist/fallback/index.d.ts +4 -4
  12. package/dist/index.d.mts +17 -35
  13. package/dist/index.d.ts +17 -35
  14. package/dist/index.js +229 -60
  15. package/dist/index.mjs +227 -61
  16. package/dist/providers/anthropic/index.d.mts +3 -3
  17. package/dist/providers/anthropic/index.d.ts +3 -3
  18. package/dist/providers/anthropic/index.js +123 -7
  19. package/dist/providers/anthropic/index.mjs +123 -7
  20. package/dist/providers/azure/index.d.mts +3 -3
  21. package/dist/providers/azure/index.d.ts +3 -3
  22. package/dist/providers/azure/index.js +101 -4
  23. package/dist/providers/azure/index.mjs +101 -4
  24. package/dist/providers/fireworks/index.d.mts +3 -3
  25. package/dist/providers/fireworks/index.d.ts +3 -3
  26. package/dist/providers/fireworks/index.js +321 -31
  27. package/dist/providers/fireworks/index.mjs +321 -31
  28. package/dist/providers/google/index.d.mts +3 -3
  29. package/dist/providers/google/index.d.ts +3 -3
  30. package/dist/providers/google/index.js +321 -31
  31. package/dist/providers/google/index.mjs +321 -31
  32. package/dist/providers/ollama/index.d.mts +4 -4
  33. package/dist/providers/ollama/index.d.ts +4 -4
  34. package/dist/providers/ollama/index.js +87 -2
  35. package/dist/providers/ollama/index.mjs +87 -2
  36. package/dist/providers/openai/index.d.mts +25 -6
  37. package/dist/providers/openai/index.d.ts +25 -6
  38. package/dist/providers/openai/index.js +750 -40
  39. package/dist/providers/openai/index.mjs +749 -41
  40. package/dist/providers/openrouter/index.d.mts +3 -3
  41. package/dist/providers/openrouter/index.d.ts +3 -3
  42. package/dist/providers/openrouter/index.js +321 -31
  43. package/dist/providers/openrouter/index.mjs +321 -31
  44. package/dist/providers/togetherai/index.d.mts +3 -3
  45. package/dist/providers/togetherai/index.d.ts +3 -3
  46. package/dist/providers/togetherai/index.js +321 -31
  47. package/dist/providers/togetherai/index.mjs +321 -31
  48. package/dist/providers/xai/index.d.mts +3 -3
  49. package/dist/providers/xai/index.d.ts +3 -3
  50. package/dist/providers/xai/index.js +321 -31
  51. package/dist/providers/xai/index.mjs +321 -31
  52. package/dist/{types-BWRYIvl_.d.mts → types-C3RgRbEC.d.mts} +1 -1
  53. package/dist/{types-CpXcT-tY.d.ts → types-DCFqkJAy.d.ts} +1 -1
  54. package/dist/{types-NOswlhm9.d.mts → types-DHQEMFHA.d.mts} +3 -3
  55. package/dist/{types-BW3csYo5.d.mts → types-Dg1Bcg1k.d.mts} +106 -3
  56. package/dist/{types-BW3csYo5.d.ts → types-Dg1Bcg1k.d.ts} +106 -3
  57. package/dist/{types-DA54bSmX.d.ts → types-Dikj3En4.d.ts} +3 -3
  58. package/dist/yourgpt/index.d.mts +1 -1
  59. package/dist/yourgpt/index.d.ts +1 -1
  60. package/docs/multimodal-and-audio.md +170 -0
  61. package/package.json +3 -2
@@ -1,3 +1,106 @@
1
+ // src/core/tool-output.ts
2
+ var imageTypes = /* @__PURE__ */ new Set([
3
+ "image/png",
4
+ "image/jpeg",
5
+ "image/webp",
6
+ "image/gif"
7
+ ]);
8
+ function normalizeToolOutput(value) {
9
+ const output = value;
10
+ if (output?.type !== "content" || !Array.isArray(output.content) || !output.content.length) {
11
+ throw new Error("Tool model output must contain a nonempty content array");
12
+ }
13
+ return {
14
+ type: "content",
15
+ content: output.content.map((part) => {
16
+ if (part?.type === "text" && typeof part.text === "string")
17
+ return { type: "text", text: part.text };
18
+ if (part?.type !== "image")
19
+ throw new Error("Unsupported tool output content type");
20
+ const sources = ["data", "url", "fileId"].filter((key) => key in part);
21
+ if (sources.length !== 1)
22
+ throw new Error(
23
+ "Tool image requires exactly one of data, url, or fileId"
24
+ );
25
+ if ("fileId" in part) {
26
+ if (part.provider !== "openai" || typeof part.fileId !== "string" || !part.fileId.trim())
27
+ throw new Error(
28
+ "Tool image file references must name the openai provider and fileId"
29
+ );
30
+ return { type: "image", fileId: part.fileId, provider: "openai" };
31
+ }
32
+ if ("url" in part) {
33
+ let url;
34
+ try {
35
+ url = new URL(part.url);
36
+ } catch {
37
+ throw new Error("Invalid tool image URL");
38
+ }
39
+ if (!["https:", "http:"].includes(url.protocol) || url.username || url.password)
40
+ throw new Error(
41
+ "Tool image URL must use HTTP(S) without credentials"
42
+ );
43
+ return { type: "image", url: url.href };
44
+ }
45
+ if (!("data" in part) || !imageTypes.has(part.mediaType))
46
+ throw new Error("Unsupported tool image media type");
47
+ let data = part.data instanceof Uint8Array ? Buffer.from(part.data).toString("base64") : part.data;
48
+ if (typeof data !== "string")
49
+ throw new Error("Tool image data must be base64 or bytes");
50
+ if (data.startsWith("data:")) {
51
+ const match = /^data:([^;,]+);base64,(.+)$/.exec(data);
52
+ if (!match || match[1] !== part.mediaType)
53
+ throw new Error(
54
+ "Tool image data URL media type does not match mediaType"
55
+ );
56
+ data = match[2];
57
+ }
58
+ if (!data.length || data.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(data))
59
+ throw new Error("Invalid tool image base64 data");
60
+ if (Buffer.byteLength(data, "base64") > 20 * 1024 * 1024)
61
+ throw new Error("Tool image exceeds 20 MiB");
62
+ if (Buffer.from(data, "base64").toString("base64") !== data)
63
+ throw new Error("Invalid tool image base64 data");
64
+ return { type: "image", data, mediaType: part.mediaType };
65
+ })
66
+ };
67
+ }
68
+ function toolOutputForProvider(value, provider) {
69
+ const output = normalizeToolOutput(value);
70
+ return output.content.map((part) => {
71
+ if (part.type === "text")
72
+ return {
73
+ type: provider === "responses" ? "input_text" : "text",
74
+ text: part.text
75
+ };
76
+ if (provider === "unsupported")
77
+ throw new Error(
78
+ "Image tool results require OpenAI Responses or Anthropic; this endpoint is not supported"
79
+ );
80
+ if ("fileId" in part) {
81
+ if (provider !== "responses")
82
+ throw new Error(
83
+ "OpenAI image file references cannot be sent to another provider"
84
+ );
85
+ return { type: "input_image", file_id: part.fileId, detail: "auto" };
86
+ }
87
+ if (provider === "responses")
88
+ return {
89
+ type: "input_image",
90
+ image_url: "url" in part ? part.url : `data:${part.mediaType};base64,${part.data}`,
91
+ detail: "auto"
92
+ };
93
+ return {
94
+ type: "image",
95
+ source: "url" in part ? { type: "url", url: part.url } : { type: "base64", media_type: part.mediaType, data: part.data }
96
+ };
97
+ });
98
+ }
99
+ function textToolOutput(value, fallback) {
100
+ if (value === void 0) return fallback;
101
+ return toolOutputForProvider(value, "unsupported").map((part) => part.text).join("\n");
102
+ }
103
+
1
104
  // src/core/openai-parameters.ts
2
105
  function capabilities(model) {
3
106
  const gpt = /^gpt-(\d+)(?:\.(\d+))?(?:-(.+))?$/i.exec(model);
@@ -239,7 +342,7 @@ function messageToOpenAIContent(message) {
239
342
  }
240
343
  return blocks;
241
344
  }
242
- function formatMessagesForOpenAI(messages, systemPrompt) {
345
+ function formatMessagesForOpenAI(messages, systemPrompt, preserveProviderMetadata = false) {
243
346
  const formatted = [];
244
347
  if (systemPrompt) {
245
348
  formatted.push({ role: "system", content: systemPrompt });
@@ -257,7 +360,8 @@ function formatMessagesForOpenAI(messages, systemPrompt) {
257
360
  const assistantMsg = {
258
361
  role: "assistant",
259
362
  // Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
260
- content: hasToolCalls ? msg.content || null : msg.content
363
+ content: hasToolCalls ? msg.content || null : msg.content,
364
+ ...preserveProviderMetadata && msg.providerMetadata ? { providerMetadata: msg.providerMetadata } : {}
261
365
  };
262
366
  if (hasToolCalls) {
263
367
  assistantMsg.tool_calls = msg.tool_calls;
@@ -266,7 +370,8 @@ function formatMessagesForOpenAI(messages, systemPrompt) {
266
370
  } else if (msg.role === "tool" && msg.tool_call_id) {
267
371
  formatted.push({
268
372
  role: "tool",
269
- content: msg.content ?? "",
373
+ content: preserveProviderMetadata ? msg.content ?? "" : textToolOutput(msg.modelOutput, msg.content ?? ""),
374
+ ...preserveProviderMetadata && msg.modelOutput ? { modelOutput: msg.modelOutput } : {},
270
375
  tool_call_id: msg.tool_call_id
271
376
  });
272
377
  }
@@ -473,7 +578,7 @@ function formatMessages(messages) {
473
578
  return {
474
579
  role: "tool",
475
580
  tool_call_id: msg.toolCallId,
476
- content: msg.content
581
+ content: textToolOutput(msg.modelOutput, msg.content)
477
582
  };
478
583
  default:
479
584
  return msg;
@@ -481,6 +586,64 @@ function formatMessages(messages) {
481
586
  });
482
587
  }
483
588
 
589
+ // src/core/openai-responses.ts
590
+ function resolveOpenAITransport(defaults, overrides) {
591
+ return {
592
+ api: overrides?.api ?? defaults.api ?? "auto",
593
+ responses: defaults.responses !== void 0 || overrides?.responses !== void 0 ? { ...defaults.responses, ...overrides?.responses } : void 0
594
+ };
595
+ }
596
+ function useOpenAIResponses(model, baseURL, parameters, transport, hasTools, hasReplay, nativeToolSearch = false) {
597
+ const api = transport.api ?? "auto";
598
+ if (!["auto", "chat", "responses"].includes(api)) {
599
+ throw new Error(`Unknown OpenAI API selection: ${api}`);
600
+ }
601
+ if (api === "chat") {
602
+ if (transport.responses !== void 0 || nativeToolSearch) {
603
+ throw new Error(
604
+ "Responses options and native tool search require the Responses API"
605
+ );
606
+ }
607
+ return false;
608
+ }
609
+ let officialEndpoint = !baseURL;
610
+ try {
611
+ officialEndpoint = !baseURL || new URL(baseURL).hostname === "api.openai.com";
612
+ } catch {
613
+ }
614
+ return api === "responses" || transport.responses !== void 0 || hasReplay && officialEndpoint || nativeToolSearch || hasTools && requiresOpenAIResponses(model, baseURL, parameters);
615
+ }
616
+ function responseMetadata(response) {
617
+ const output = Array.isArray(response?.output) ? response.output : [];
618
+ return {
619
+ openai: {
620
+ response: {
621
+ id: response?.id,
622
+ model: response?.model,
623
+ status: response?.status,
624
+ output,
625
+ usage: response?.usage,
626
+ store: response?.store,
627
+ refusals: output.flatMap(
628
+ (item) => item?.type === "message" && Array.isArray(item.content) ? item.content.filter(
629
+ (part) => part?.type === "refusal" && typeof part.refusal === "string"
630
+ ).map((part) => part.refusal) : []
631
+ )
632
+ }
633
+ }
634
+ };
635
+ }
636
+ function getResponseReplay(metadata) {
637
+ const response = metadata?.openai?.response;
638
+ if (response === void 0) return void 0;
639
+ if (!Array.isArray(response.output) || response.output.some((item) => !item || typeof item.type !== "string")) {
640
+ throw new Error(
641
+ "Invalid OpenAI Responses replay metadata: output must contain typed items"
642
+ );
643
+ }
644
+ return response.output;
645
+ }
646
+
484
647
  // src/core/provider-error.ts
485
648
  function providerErrorEvent(error, code) {
486
649
  const details = error ?? {};
@@ -557,13 +720,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
557
720
  }));
558
721
  }
559
722
  shouldUseResponsesApi(request) {
560
- if (this.toolDefinitions(request).length === 0) return false;
561
- if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
562
- return true;
563
- return requiresOpenAIResponses(
723
+ return useOpenAIResponses(
564
724
  request.config?.model || this.model,
565
725
  this.config.baseUrl,
566
- this.parameterOptions(request)
726
+ this.parameterOptions(request),
727
+ resolveOpenAITransport(this.config, request.config?.openai),
728
+ this.toolDefinitions(request).length > 0,
729
+ !!(request.rawMessages ?? request.messages)?.some(
730
+ (message) => message.providerMetadata?.openai?.response
731
+ ),
732
+ request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false
567
733
  );
568
734
  }
569
735
  /**
@@ -596,11 +762,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
596
762
  });
597
763
  }
598
764
  buildResponsesInput(request) {
599
- const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
765
+ const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages, true) : formatMessagesForOpenAI(request.messages, void 0, true);
600
766
  const input = [];
601
767
  for (const message of sourceMessages) {
602
768
  if (message.role === "system") {
603
- if (!request.systemPrompt && message.content) {
769
+ if (message.content && message.content !== request.systemPrompt) {
604
770
  input.push({
605
771
  type: "message",
606
772
  role: "developer",
@@ -610,6 +776,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
610
776
  continue;
611
777
  }
612
778
  if (message.role === "assistant") {
779
+ const replay = getResponseReplay(message.providerMetadata);
780
+ if (replay) {
781
+ input.push(...replay);
782
+ continue;
783
+ }
613
784
  const content = this.toResponsesContent(message.content, "assistant");
614
785
  if (typeof content === "string" ? content : Array.isArray(content) && content.length > 0) {
615
786
  input.push({
@@ -633,7 +804,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
633
804
  input.push({
634
805
  type: "function_call_output",
635
806
  call_id: message.tool_call_id,
636
- output: typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
807
+ output: message.modelOutput ? toolOutputForProvider(message.modelOutput, "responses") : typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
637
808
  });
638
809
  continue;
639
810
  }
@@ -647,10 +818,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
647
818
  return input;
648
819
  }
649
820
  /** Preserve Copilot screenshot attachments on every OpenAI transport. */
650
- formatRawMessages(messages) {
821
+ formatRawMessages(messages, preserveProviderMetadata = false) {
651
822
  return messages.map((message) => {
652
- const { attachments, ...rest } = message;
653
- let content = message.content;
823
+ const { attachments, providerMetadata, modelOutput, ...rest } = message;
824
+ let content = message.role === "tool" && !preserveProviderMetadata ? textToolOutput(modelOutput, String(message.content ?? "")) : message.content;
825
+ if (preserveProviderMetadata && modelOutput)
826
+ rest.modelOutput = modelOutput;
654
827
  if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
655
828
  content = null;
656
829
  }
@@ -663,7 +836,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
663
836
  content = [...parts, ...images];
664
837
  }
665
838
  }
666
- return { ...rest, content };
839
+ return {
840
+ ...rest,
841
+ content,
842
+ ...preserveProviderMetadata && providerMetadata ? { providerMetadata } : {}
843
+ };
667
844
  });
668
845
  }
669
846
  /**
@@ -744,14 +921,25 @@ var OpenAIAdapter = class _OpenAIAdapter {
744
921
  ).map((part) => part.text) : []
745
922
  ).join("") : "";
746
923
  const content = textFromOutput || (typeof response?.output_text === "string" ? response.output_text : "");
747
- const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => ({
748
- id: item.call_id ?? item.id ?? generateToolCallId(),
749
- name: item.name,
750
- args: JSON.parse(item.arguments ?? "{}")
751
- })) : [];
924
+ const seenCallIds = /* @__PURE__ */ new Set();
925
+ const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
926
+ if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
927
+ throw new Error("Responses contains an incomplete function call");
928
+ }
929
+ if (seenCallIds.has(item.call_id))
930
+ throw new Error("Responses contains duplicate function call IDs");
931
+ seenCallIds.add(item.call_id);
932
+ const args = JSON.parse(item.arguments);
933
+ if (!args || typeof args !== "object" || Array.isArray(args))
934
+ throw new Error(
935
+ "Responses function arguments must be a JSON object"
936
+ );
937
+ return { id: item.call_id, name: item.name, args };
938
+ }) : [];
752
939
  return {
753
940
  content,
754
941
  toolCalls,
942
+ providerMetadata: responseMetadata(response),
755
943
  usage: response?.usage ? {
756
944
  promptTokens: response.usage.input_tokens ?? 0,
757
945
  completionTokens: response.usage.output_tokens ?? 0,
@@ -762,6 +950,17 @@ var OpenAIAdapter = class _OpenAIAdapter {
762
950
  }
763
951
  buildResponsesPayload(request, stream) {
764
952
  const openaiToolOptions = request.providerToolOptions?.openai;
953
+ const options = resolveOpenAITransport(
954
+ this.config,
955
+ request.config?.openai
956
+ ).responses;
957
+ const parameters = buildOpenAIParameters(
958
+ request.config?.model || this.model,
959
+ request.config?.maxTokens ?? this.config.maxTokens,
960
+ request.config?.temperature ?? this.config.temperature,
961
+ this.parameterOptions(request),
962
+ "responses"
963
+ );
765
964
  const responsesTextFormat = toOpenAIResponsesTextFormat(
766
965
  request.config?.responseFormat
767
966
  );
@@ -777,13 +976,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
777
976
  ),
778
977
  tool_choice: openaiToolOptions?.toolChoice,
779
978
  parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
780
- ...buildOpenAIParameters(
781
- modelIdForPayload,
782
- request.config?.maxTokens ?? this.config.maxTokens,
783
- request.config?.temperature ?? this.config.temperature,
784
- this.parameterOptions(request),
785
- "responses"
786
- ),
979
+ ...parameters,
980
+ ...options?.reasoningSummary ? {
981
+ reasoning: {
982
+ ...parameters.reasoning,
983
+ summary: options.reasoningSummary
984
+ }
985
+ } : {},
986
+ ...options?.store !== void 0 ? { store: options.store } : {},
987
+ ...options?.previousResponseId !== void 0 ? { previous_response_id: options.previousResponseId } : {},
988
+ ...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
989
+ ...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
990
+ ...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
991
+ ...options?.store === false || options?.include ? {
992
+ include: [
993
+ .../* @__PURE__ */ new Set([
994
+ ...options?.include ?? [],
995
+ ...options?.store === false ? ["reasoning.encrypted_content"] : []
996
+ ])
997
+ ]
998
+ } : {},
787
999
  ...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
788
1000
  stream
789
1001
  };
@@ -842,6 +1054,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
842
1054
  let usage;
843
1055
  const citations = [];
844
1056
  let completed = false;
1057
+ let terminalResponse;
1058
+ let responseIdentity = {};
1059
+ const outputItems = /* @__PURE__ */ new Map();
1060
+ let streamedText = "";
845
1061
  function* flushToolCalls() {
846
1062
  for (const call of toolCalls.values()) {
847
1063
  if (!call.name)
@@ -858,17 +1074,36 @@ var OpenAIAdapter = class _OpenAIAdapter {
858
1074
  for await (const event of stream) {
859
1075
  throwIfAborted(request.signal);
860
1076
  logProviderPayload("openai", "stream chunk", event, request.debug);
1077
+ if (completed)
1078
+ throw new Error("Responses stream emitted an event after completion");
861
1079
  const index = event?.output_index ?? 0;
862
1080
  switch (event?.type) {
1081
+ case "response.created":
1082
+ responseIdentity = {
1083
+ id: event.response?.id,
1084
+ model: event.response?.model
1085
+ };
1086
+ break;
1087
+ case "response.output_item.done":
1088
+ if (event.item) outputItems.set(index, event.item);
1089
+ if (event.item?.type === "function_call") {
1090
+ toolCalls.set(index, {
1091
+ id: event.item.call_id,
1092
+ name: event.item.name,
1093
+ arguments: event.item.arguments
1094
+ });
1095
+ }
1096
+ break;
863
1097
  case "response.output_text.delta":
864
1098
  if (event.delta) {
1099
+ streamedText += event.delta;
865
1100
  yield { type: "message:delta", content: event.delta };
866
1101
  }
867
1102
  break;
868
1103
  case "response.output_item.added":
869
1104
  if (event.item?.type === "function_call") {
870
1105
  toolCalls.set(index, {
871
- id: event.item.call_id ?? event.item.id ?? generateToolCallId(),
1106
+ id: event.item.call_id ?? "",
872
1107
  name: event.item.name ?? "",
873
1108
  arguments: event.item.arguments ?? ""
874
1109
  });
@@ -887,7 +1122,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
887
1122
  break;
888
1123
  }
889
1124
  case "response.completed": {
1125
+ if (event.response?.status && event.response.status !== "completed")
1126
+ throw new Error(`Responses stream ${event.response.status}`);
890
1127
  completed = true;
1128
+ terminalResponse = { ...responseIdentity, ...event.response };
891
1129
  const found = this.collectResponsesCitations(
892
1130
  event.response?.output,
893
1131
  citations.length
@@ -924,12 +1162,64 @@ var OpenAIAdapter = class _OpenAIAdapter {
924
1162
  throwIfAborted(request.signal);
925
1163
  if (!completed)
926
1164
  throw new Error("Responses stream ended without a completed response");
1165
+ const output = terminalResponse.output?.length ? terminalResponse.output : [...outputItems.entries()].sort(([a], [b]) => a - b).map(([, item]) => item);
1166
+ if (output.some((item) => item.type === "function_call"))
1167
+ toolCalls.clear();
1168
+ for (const [index, item] of output.entries()) {
1169
+ if (item.type === "function_call") {
1170
+ toolCalls.set(index, {
1171
+ id: item.call_id,
1172
+ name: item.name,
1173
+ arguments: item.arguments
1174
+ });
1175
+ }
1176
+ }
1177
+ const uniqueCalls = /* @__PURE__ */ new Map();
1178
+ for (const call of toolCalls.values()) {
1179
+ if (!call.id || !call.name)
1180
+ throw new Error("Responses stream contains an incomplete tool call");
1181
+ uniqueCalls.set(call.id, call);
1182
+ }
1183
+ toolCalls.clear();
1184
+ [...uniqueCalls.values()].forEach(
1185
+ (call, index) => toolCalls.set(index, call)
1186
+ );
1187
+ if (!output.length && toolCalls.size) {
1188
+ for (const call of toolCalls.values())
1189
+ output.push({
1190
+ type: "function_call",
1191
+ call_id: call.id,
1192
+ name: call.name,
1193
+ arguments: call.arguments
1194
+ });
1195
+ }
1196
+ if (!output.length && streamedText)
1197
+ output.push({
1198
+ type: "message",
1199
+ role: "assistant",
1200
+ content: [{ type: "output_text", text: streamedText, annotations: [] }]
1201
+ });
1202
+ terminalResponse.output = output;
1203
+ const finalText = this.parseResponsesResult(terminalResponse).content;
1204
+ if (finalText.startsWith(streamedText) && finalText.length > streamedText.length) {
1205
+ yield {
1206
+ type: "message:delta",
1207
+ content: finalText.slice(streamedText.length)
1208
+ };
1209
+ }
927
1210
  yield* flushToolCalls();
928
1211
  if (citations.length > 0) {
929
1212
  yield { type: "citation", citations: deduplicateCitations(citations) };
930
1213
  }
931
- yield { type: "message:end" };
932
- yield { type: "done", usage };
1214
+ yield {
1215
+ type: "message:end",
1216
+ providerMetadata: responseMetadata(terminalResponse)
1217
+ };
1218
+ yield {
1219
+ type: "done",
1220
+ usage,
1221
+ providerMetadata: responseMetadata(terminalResponse)
1222
+ };
933
1223
  }
934
1224
  async *stream(request) {
935
1225
  throwIfAborted(request.signal);
@@ -1,7 +1,7 @@
1
- import { L as LanguageModel } from '../../types-BW3csYo5.mjs';
2
- import { G as GoogleProviderConfig, A as AIProvider } from '../../types-NOswlhm9.mjs';
1
+ import { L as LanguageModel } from '../../types-Dg1Bcg1k.mjs';
2
+ import { G as GoogleProviderConfig, A as AIProvider } from '../../types-DHQEMFHA.mjs';
3
3
  import 'zod';
4
- import '../../base-CkeT7u-O.mjs';
4
+ import '../../base-BICaQaRS.mjs';
5
5
 
6
6
  /**
7
7
  * Google Provider - OpenAI-Compatible
@@ -1,7 +1,7 @@
1
- import { L as LanguageModel } from '../../types-BW3csYo5.js';
2
- import { G as GoogleProviderConfig, A as AIProvider } from '../../types-DA54bSmX.js';
1
+ import { L as LanguageModel } from '../../types-Dg1Bcg1k.js';
2
+ import { G as GoogleProviderConfig, A as AIProvider } from '../../types-Dikj3En4.js';
3
3
  import 'zod';
4
- import '../../base-BdTpUAWI.js';
4
+ import '../../base-CpRPB8u8.js';
5
5
 
6
6
  /**
7
7
  * Google Provider - OpenAI-Compatible