@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
  }
@@ -478,7 +583,7 @@ function formatMessages(messages) {
478
583
  return {
479
584
  role: "tool",
480
585
  tool_call_id: msg.toolCallId,
481
- content: msg.content
586
+ content: textToolOutput(msg.modelOutput, msg.content)
482
587
  };
483
588
  default:
484
589
  return msg;
@@ -486,6 +591,64 @@ function formatMessages(messages) {
486
591
  });
487
592
  }
488
593
 
594
+ // src/core/openai-responses.ts
595
+ function resolveOpenAITransport(defaults, overrides) {
596
+ return {
597
+ api: overrides?.api ?? defaults.api ?? "auto",
598
+ responses: defaults.responses !== void 0 || overrides?.responses !== void 0 ? { ...defaults.responses, ...overrides?.responses } : void 0
599
+ };
600
+ }
601
+ function useOpenAIResponses(model, baseURL, parameters, transport, hasTools, hasReplay, nativeToolSearch = false) {
602
+ const api = transport.api ?? "auto";
603
+ if (!["auto", "chat", "responses"].includes(api)) {
604
+ throw new Error(`Unknown OpenAI API selection: ${api}`);
605
+ }
606
+ if (api === "chat") {
607
+ if (transport.responses !== void 0 || nativeToolSearch) {
608
+ throw new Error(
609
+ "Responses options and native tool search require the Responses API"
610
+ );
611
+ }
612
+ return false;
613
+ }
614
+ let officialEndpoint = !baseURL;
615
+ try {
616
+ officialEndpoint = !baseURL || new URL(baseURL).hostname === "api.openai.com";
617
+ } catch {
618
+ }
619
+ return api === "responses" || transport.responses !== void 0 || hasReplay && officialEndpoint || nativeToolSearch || hasTools && requiresOpenAIResponses(model, baseURL, parameters);
620
+ }
621
+ function responseMetadata(response) {
622
+ const output = Array.isArray(response?.output) ? response.output : [];
623
+ return {
624
+ openai: {
625
+ response: {
626
+ id: response?.id,
627
+ model: response?.model,
628
+ status: response?.status,
629
+ output,
630
+ usage: response?.usage,
631
+ store: response?.store,
632
+ refusals: output.flatMap(
633
+ (item) => item?.type === "message" && Array.isArray(item.content) ? item.content.filter(
634
+ (part) => part?.type === "refusal" && typeof part.refusal === "string"
635
+ ).map((part) => part.refusal) : []
636
+ )
637
+ }
638
+ }
639
+ };
640
+ }
641
+ function getResponseReplay(metadata) {
642
+ const response = metadata?.openai?.response;
643
+ if (response === void 0) return void 0;
644
+ if (!Array.isArray(response.output) || response.output.some((item) => !item || typeof item.type !== "string")) {
645
+ throw new Error(
646
+ "Invalid OpenAI Responses replay metadata: output must contain typed items"
647
+ );
648
+ }
649
+ return response.output;
650
+ }
651
+
489
652
  // src/core/provider-error.ts
490
653
  function providerErrorEvent(error, code) {
491
654
  const details = error ?? {};
@@ -562,13 +725,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
562
725
  }));
563
726
  }
564
727
  shouldUseResponsesApi(request) {
565
- if (this.toolDefinitions(request).length === 0) return false;
566
- if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
567
- return true;
568
- return requiresOpenAIResponses(
728
+ return useOpenAIResponses(
569
729
  request.config?.model || this.model,
570
730
  this.config.baseUrl,
571
- this.parameterOptions(request)
731
+ this.parameterOptions(request),
732
+ resolveOpenAITransport(this.config, request.config?.openai),
733
+ this.toolDefinitions(request).length > 0,
734
+ !!(request.rawMessages ?? request.messages)?.some(
735
+ (message) => message.providerMetadata?.openai?.response
736
+ ),
737
+ request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false
572
738
  );
573
739
  }
574
740
  /**
@@ -601,11 +767,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
601
767
  });
602
768
  }
603
769
  buildResponsesInput(request) {
604
- const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
770
+ const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages, true) : formatMessagesForOpenAI(request.messages, void 0, true);
605
771
  const input = [];
606
772
  for (const message of sourceMessages) {
607
773
  if (message.role === "system") {
608
- if (!request.systemPrompt && message.content) {
774
+ if (message.content && message.content !== request.systemPrompt) {
609
775
  input.push({
610
776
  type: "message",
611
777
  role: "developer",
@@ -615,6 +781,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
615
781
  continue;
616
782
  }
617
783
  if (message.role === "assistant") {
784
+ const replay = getResponseReplay(message.providerMetadata);
785
+ if (replay) {
786
+ input.push(...replay);
787
+ continue;
788
+ }
618
789
  const content = this.toResponsesContent(message.content, "assistant");
619
790
  if (typeof content === "string" ? content : Array.isArray(content) && content.length > 0) {
620
791
  input.push({
@@ -638,7 +809,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
638
809
  input.push({
639
810
  type: "function_call_output",
640
811
  call_id: message.tool_call_id,
641
- output: typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
812
+ output: message.modelOutput ? toolOutputForProvider(message.modelOutput, "responses") : typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
642
813
  });
643
814
  continue;
644
815
  }
@@ -652,10 +823,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
652
823
  return input;
653
824
  }
654
825
  /** Preserve Copilot screenshot attachments on every OpenAI transport. */
655
- formatRawMessages(messages) {
826
+ formatRawMessages(messages, preserveProviderMetadata = false) {
656
827
  return messages.map((message) => {
657
- const { attachments, ...rest } = message;
658
- let content = message.content;
828
+ const { attachments, providerMetadata, modelOutput, ...rest } = message;
829
+ let content = message.role === "tool" && !preserveProviderMetadata ? textToolOutput(modelOutput, String(message.content ?? "")) : message.content;
830
+ if (preserveProviderMetadata && modelOutput)
831
+ rest.modelOutput = modelOutput;
659
832
  if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
660
833
  content = null;
661
834
  }
@@ -668,7 +841,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
668
841
  content = [...parts, ...images];
669
842
  }
670
843
  }
671
- return { ...rest, content };
844
+ return {
845
+ ...rest,
846
+ content,
847
+ ...preserveProviderMetadata && providerMetadata ? { providerMetadata } : {}
848
+ };
672
849
  });
673
850
  }
674
851
  /**
@@ -749,14 +926,25 @@ var OpenAIAdapter = class _OpenAIAdapter {
749
926
  ).map((part) => part.text) : []
750
927
  ).join("") : "";
751
928
  const content = textFromOutput || (typeof response?.output_text === "string" ? response.output_text : "");
752
- const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => ({
753
- id: item.call_id ?? item.id ?? generateToolCallId(),
754
- name: item.name,
755
- args: JSON.parse(item.arguments ?? "{}")
756
- })) : [];
929
+ const seenCallIds = /* @__PURE__ */ new Set();
930
+ const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
931
+ if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
932
+ throw new Error("Responses contains an incomplete function call");
933
+ }
934
+ if (seenCallIds.has(item.call_id))
935
+ throw new Error("Responses contains duplicate function call IDs");
936
+ seenCallIds.add(item.call_id);
937
+ const args = JSON.parse(item.arguments);
938
+ if (!args || typeof args !== "object" || Array.isArray(args))
939
+ throw new Error(
940
+ "Responses function arguments must be a JSON object"
941
+ );
942
+ return { id: item.call_id, name: item.name, args };
943
+ }) : [];
757
944
  return {
758
945
  content,
759
946
  toolCalls,
947
+ providerMetadata: responseMetadata(response),
760
948
  usage: response?.usage ? {
761
949
  promptTokens: response.usage.input_tokens ?? 0,
762
950
  completionTokens: response.usage.output_tokens ?? 0,
@@ -767,6 +955,17 @@ var OpenAIAdapter = class _OpenAIAdapter {
767
955
  }
768
956
  buildResponsesPayload(request, stream) {
769
957
  const openaiToolOptions = request.providerToolOptions?.openai;
958
+ const options = resolveOpenAITransport(
959
+ this.config,
960
+ request.config?.openai
961
+ ).responses;
962
+ const parameters = buildOpenAIParameters(
963
+ request.config?.model || this.model,
964
+ request.config?.maxTokens ?? this.config.maxTokens,
965
+ request.config?.temperature ?? this.config.temperature,
966
+ this.parameterOptions(request),
967
+ "responses"
968
+ );
770
969
  const responsesTextFormat = toOpenAIResponsesTextFormat(
771
970
  request.config?.responseFormat
772
971
  );
@@ -782,13 +981,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
782
981
  ),
783
982
  tool_choice: openaiToolOptions?.toolChoice,
784
983
  parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
785
- ...buildOpenAIParameters(
786
- modelIdForPayload,
787
- request.config?.maxTokens ?? this.config.maxTokens,
788
- request.config?.temperature ?? this.config.temperature,
789
- this.parameterOptions(request),
790
- "responses"
791
- ),
984
+ ...parameters,
985
+ ...options?.reasoningSummary ? {
986
+ reasoning: {
987
+ ...parameters.reasoning,
988
+ summary: options.reasoningSummary
989
+ }
990
+ } : {},
991
+ ...options?.store !== void 0 ? { store: options.store } : {},
992
+ ...options?.previousResponseId !== void 0 ? { previous_response_id: options.previousResponseId } : {},
993
+ ...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
994
+ ...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
995
+ ...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
996
+ ...options?.store === false || options?.include ? {
997
+ include: [
998
+ .../* @__PURE__ */ new Set([
999
+ ...options?.include ?? [],
1000
+ ...options?.store === false ? ["reasoning.encrypted_content"] : []
1001
+ ])
1002
+ ]
1003
+ } : {},
792
1004
  ...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
793
1005
  stream
794
1006
  };
@@ -847,6 +1059,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
847
1059
  let usage;
848
1060
  const citations = [];
849
1061
  let completed = false;
1062
+ let terminalResponse;
1063
+ let responseIdentity = {};
1064
+ const outputItems = /* @__PURE__ */ new Map();
1065
+ let streamedText = "";
850
1066
  function* flushToolCalls() {
851
1067
  for (const call of toolCalls.values()) {
852
1068
  if (!call.name)
@@ -863,17 +1079,36 @@ var OpenAIAdapter = class _OpenAIAdapter {
863
1079
  for await (const event of stream) {
864
1080
  throwIfAborted(request.signal);
865
1081
  logProviderPayload("openai", "stream chunk", event, request.debug);
1082
+ if (completed)
1083
+ throw new Error("Responses stream emitted an event after completion");
866
1084
  const index = event?.output_index ?? 0;
867
1085
  switch (event?.type) {
1086
+ case "response.created":
1087
+ responseIdentity = {
1088
+ id: event.response?.id,
1089
+ model: event.response?.model
1090
+ };
1091
+ break;
1092
+ case "response.output_item.done":
1093
+ if (event.item) outputItems.set(index, event.item);
1094
+ if (event.item?.type === "function_call") {
1095
+ toolCalls.set(index, {
1096
+ id: event.item.call_id,
1097
+ name: event.item.name,
1098
+ arguments: event.item.arguments
1099
+ });
1100
+ }
1101
+ break;
868
1102
  case "response.output_text.delta":
869
1103
  if (event.delta) {
1104
+ streamedText += event.delta;
870
1105
  yield { type: "message:delta", content: event.delta };
871
1106
  }
872
1107
  break;
873
1108
  case "response.output_item.added":
874
1109
  if (event.item?.type === "function_call") {
875
1110
  toolCalls.set(index, {
876
- id: event.item.call_id ?? event.item.id ?? generateToolCallId(),
1111
+ id: event.item.call_id ?? "",
877
1112
  name: event.item.name ?? "",
878
1113
  arguments: event.item.arguments ?? ""
879
1114
  });
@@ -892,7 +1127,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
892
1127
  break;
893
1128
  }
894
1129
  case "response.completed": {
1130
+ if (event.response?.status && event.response.status !== "completed")
1131
+ throw new Error(`Responses stream ${event.response.status}`);
895
1132
  completed = true;
1133
+ terminalResponse = { ...responseIdentity, ...event.response };
896
1134
  const found = this.collectResponsesCitations(
897
1135
  event.response?.output,
898
1136
  citations.length
@@ -929,12 +1167,64 @@ var OpenAIAdapter = class _OpenAIAdapter {
929
1167
  throwIfAborted(request.signal);
930
1168
  if (!completed)
931
1169
  throw new Error("Responses stream ended without a completed response");
1170
+ const output = terminalResponse.output?.length ? terminalResponse.output : [...outputItems.entries()].sort(([a], [b]) => a - b).map(([, item]) => item);
1171
+ if (output.some((item) => item.type === "function_call"))
1172
+ toolCalls.clear();
1173
+ for (const [index, item] of output.entries()) {
1174
+ if (item.type === "function_call") {
1175
+ toolCalls.set(index, {
1176
+ id: item.call_id,
1177
+ name: item.name,
1178
+ arguments: item.arguments
1179
+ });
1180
+ }
1181
+ }
1182
+ const uniqueCalls = /* @__PURE__ */ new Map();
1183
+ for (const call of toolCalls.values()) {
1184
+ if (!call.id || !call.name)
1185
+ throw new Error("Responses stream contains an incomplete tool call");
1186
+ uniqueCalls.set(call.id, call);
1187
+ }
1188
+ toolCalls.clear();
1189
+ [...uniqueCalls.values()].forEach(
1190
+ (call, index) => toolCalls.set(index, call)
1191
+ );
1192
+ if (!output.length && toolCalls.size) {
1193
+ for (const call of toolCalls.values())
1194
+ output.push({
1195
+ type: "function_call",
1196
+ call_id: call.id,
1197
+ name: call.name,
1198
+ arguments: call.arguments
1199
+ });
1200
+ }
1201
+ if (!output.length && streamedText)
1202
+ output.push({
1203
+ type: "message",
1204
+ role: "assistant",
1205
+ content: [{ type: "output_text", text: streamedText, annotations: [] }]
1206
+ });
1207
+ terminalResponse.output = output;
1208
+ const finalText = this.parseResponsesResult(terminalResponse).content;
1209
+ if (finalText.startsWith(streamedText) && finalText.length > streamedText.length) {
1210
+ yield {
1211
+ type: "message:delta",
1212
+ content: finalText.slice(streamedText.length)
1213
+ };
1214
+ }
932
1215
  yield* flushToolCalls();
933
1216
  if (citations.length > 0) {
934
1217
  yield { type: "citation", citations: deduplicateCitations(citations) };
935
1218
  }
936
- yield { type: "message:end" };
937
- yield { type: "done", usage };
1219
+ yield {
1220
+ type: "message:end",
1221
+ providerMetadata: responseMetadata(terminalResponse)
1222
+ };
1223
+ yield {
1224
+ type: "done",
1225
+ usage,
1226
+ providerMetadata: responseMetadata(terminalResponse)
1227
+ };
938
1228
  }
939
1229
  async *stream(request) {
940
1230
  throwIfAborted(request.signal);
@@ -1,7 +1,7 @@
1
- import { L as LanguageModel } from '../../types-BW3csYo5.mjs';
2
- import { X as XAIProviderConfig, A as AIProvider } from '../../types-NOswlhm9.mjs';
1
+ import { L as LanguageModel } from '../../types-Dg1Bcg1k.mjs';
2
+ import { X as XAIProviderConfig, 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
  * xAI Provider - Modern Pattern
@@ -1,7 +1,7 @@
1
- import { L as LanguageModel } from '../../types-BW3csYo5.js';
2
- import { X as XAIProviderConfig, A as AIProvider } from '../../types-DA54bSmX.js';
1
+ import { L as LanguageModel } from '../../types-Dg1Bcg1k.js';
2
+ import { X as XAIProviderConfig, 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
  * xAI Provider - Modern Pattern