@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
  }
@@ -503,7 +608,7 @@ function formatMessagesForOpenRouter(messages) {
503
608
  return {
504
609
  role: "tool",
505
610
  tool_call_id: msg.toolCallId,
506
- content: msg.content
611
+ content: textToolOutput(msg.modelOutput, msg.content)
507
612
  };
508
613
  default:
509
614
  return msg;
@@ -534,6 +639,64 @@ async function searchOpenRouterModels(query, apiKey) {
534
639
  );
535
640
  }
536
641
 
642
+ // src/core/openai-responses.ts
643
+ function resolveOpenAITransport(defaults, overrides) {
644
+ return {
645
+ api: overrides?.api ?? defaults.api ?? "auto",
646
+ responses: defaults.responses !== void 0 || overrides?.responses !== void 0 ? { ...defaults.responses, ...overrides?.responses } : void 0
647
+ };
648
+ }
649
+ function useOpenAIResponses(model, baseURL, parameters, transport, hasTools, hasReplay, nativeToolSearch = false) {
650
+ const api = transport.api ?? "auto";
651
+ if (!["auto", "chat", "responses"].includes(api)) {
652
+ throw new Error(`Unknown OpenAI API selection: ${api}`);
653
+ }
654
+ if (api === "chat") {
655
+ if (transport.responses !== void 0 || nativeToolSearch) {
656
+ throw new Error(
657
+ "Responses options and native tool search require the Responses API"
658
+ );
659
+ }
660
+ return false;
661
+ }
662
+ let officialEndpoint = !baseURL;
663
+ try {
664
+ officialEndpoint = !baseURL || new URL(baseURL).hostname === "api.openai.com";
665
+ } catch {
666
+ }
667
+ return api === "responses" || transport.responses !== void 0 || hasReplay && officialEndpoint || nativeToolSearch || hasTools && requiresOpenAIResponses(model, baseURL, parameters);
668
+ }
669
+ function responseMetadata(response) {
670
+ const output = Array.isArray(response?.output) ? response.output : [];
671
+ return {
672
+ openai: {
673
+ response: {
674
+ id: response?.id,
675
+ model: response?.model,
676
+ status: response?.status,
677
+ output,
678
+ usage: response?.usage,
679
+ store: response?.store,
680
+ refusals: output.flatMap(
681
+ (item) => item?.type === "message" && Array.isArray(item.content) ? item.content.filter(
682
+ (part) => part?.type === "refusal" && typeof part.refusal === "string"
683
+ ).map((part) => part.refusal) : []
684
+ )
685
+ }
686
+ }
687
+ };
688
+ }
689
+ function getResponseReplay(metadata) {
690
+ const response = metadata?.openai?.response;
691
+ if (response === void 0) return void 0;
692
+ if (!Array.isArray(response.output) || response.output.some((item) => !item || typeof item.type !== "string")) {
693
+ throw new Error(
694
+ "Invalid OpenAI Responses replay metadata: output must contain typed items"
695
+ );
696
+ }
697
+ return response.output;
698
+ }
699
+
537
700
  // src/core/provider-error.ts
538
701
  function providerErrorEvent(error, code) {
539
702
  const details = error ?? {};
@@ -610,13 +773,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
610
773
  }));
611
774
  }
612
775
  shouldUseResponsesApi(request) {
613
- if (this.toolDefinitions(request).length === 0) return false;
614
- if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
615
- return true;
616
- return requiresOpenAIResponses(
776
+ return useOpenAIResponses(
617
777
  request.config?.model || this.model,
618
778
  this.config.baseUrl,
619
- this.parameterOptions(request)
779
+ this.parameterOptions(request),
780
+ resolveOpenAITransport(this.config, request.config?.openai),
781
+ this.toolDefinitions(request).length > 0,
782
+ !!(request.rawMessages ?? request.messages)?.some(
783
+ (message) => message.providerMetadata?.openai?.response
784
+ ),
785
+ request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false
620
786
  );
621
787
  }
622
788
  /**
@@ -649,11 +815,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
649
815
  });
650
816
  }
651
817
  buildResponsesInput(request) {
652
- const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
818
+ const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages, true) : formatMessagesForOpenAI(request.messages, void 0, true);
653
819
  const input = [];
654
820
  for (const message of sourceMessages) {
655
821
  if (message.role === "system") {
656
- if (!request.systemPrompt && message.content) {
822
+ if (message.content && message.content !== request.systemPrompt) {
657
823
  input.push({
658
824
  type: "message",
659
825
  role: "developer",
@@ -663,6 +829,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
663
829
  continue;
664
830
  }
665
831
  if (message.role === "assistant") {
832
+ const replay = getResponseReplay(message.providerMetadata);
833
+ if (replay) {
834
+ input.push(...replay);
835
+ continue;
836
+ }
666
837
  const content = this.toResponsesContent(message.content, "assistant");
667
838
  if (typeof content === "string" ? content : Array.isArray(content) && content.length > 0) {
668
839
  input.push({
@@ -686,7 +857,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
686
857
  input.push({
687
858
  type: "function_call_output",
688
859
  call_id: message.tool_call_id,
689
- output: typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
860
+ output: message.modelOutput ? toolOutputForProvider(message.modelOutput, "responses") : typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
690
861
  });
691
862
  continue;
692
863
  }
@@ -700,10 +871,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
700
871
  return input;
701
872
  }
702
873
  /** Preserve Copilot screenshot attachments on every OpenAI transport. */
703
- formatRawMessages(messages) {
874
+ formatRawMessages(messages, preserveProviderMetadata = false) {
704
875
  return messages.map((message) => {
705
- const { attachments, ...rest } = message;
706
- let content = message.content;
876
+ const { attachments, providerMetadata, modelOutput, ...rest } = message;
877
+ let content = message.role === "tool" && !preserveProviderMetadata ? textToolOutput(modelOutput, String(message.content ?? "")) : message.content;
878
+ if (preserveProviderMetadata && modelOutput)
879
+ rest.modelOutput = modelOutput;
707
880
  if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
708
881
  content = null;
709
882
  }
@@ -716,7 +889,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
716
889
  content = [...parts, ...images];
717
890
  }
718
891
  }
719
- return { ...rest, content };
892
+ return {
893
+ ...rest,
894
+ content,
895
+ ...preserveProviderMetadata && providerMetadata ? { providerMetadata } : {}
896
+ };
720
897
  });
721
898
  }
722
899
  /**
@@ -797,14 +974,25 @@ var OpenAIAdapter = class _OpenAIAdapter {
797
974
  ).map((part) => part.text) : []
798
975
  ).join("") : "";
799
976
  const content = textFromOutput || (typeof response?.output_text === "string" ? response.output_text : "");
800
- const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => ({
801
- id: item.call_id ?? item.id ?? generateToolCallId(),
802
- name: item.name,
803
- args: JSON.parse(item.arguments ?? "{}")
804
- })) : [];
977
+ const seenCallIds = /* @__PURE__ */ new Set();
978
+ const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
979
+ if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
980
+ throw new Error("Responses contains an incomplete function call");
981
+ }
982
+ if (seenCallIds.has(item.call_id))
983
+ throw new Error("Responses contains duplicate function call IDs");
984
+ seenCallIds.add(item.call_id);
985
+ const args = JSON.parse(item.arguments);
986
+ if (!args || typeof args !== "object" || Array.isArray(args))
987
+ throw new Error(
988
+ "Responses function arguments must be a JSON object"
989
+ );
990
+ return { id: item.call_id, name: item.name, args };
991
+ }) : [];
805
992
  return {
806
993
  content,
807
994
  toolCalls,
995
+ providerMetadata: responseMetadata(response),
808
996
  usage: response?.usage ? {
809
997
  promptTokens: response.usage.input_tokens ?? 0,
810
998
  completionTokens: response.usage.output_tokens ?? 0,
@@ -815,6 +1003,17 @@ var OpenAIAdapter = class _OpenAIAdapter {
815
1003
  }
816
1004
  buildResponsesPayload(request, stream) {
817
1005
  const openaiToolOptions = request.providerToolOptions?.openai;
1006
+ const options = resolveOpenAITransport(
1007
+ this.config,
1008
+ request.config?.openai
1009
+ ).responses;
1010
+ const parameters = buildOpenAIParameters(
1011
+ request.config?.model || this.model,
1012
+ request.config?.maxTokens ?? this.config.maxTokens,
1013
+ request.config?.temperature ?? this.config.temperature,
1014
+ this.parameterOptions(request),
1015
+ "responses"
1016
+ );
818
1017
  const responsesTextFormat = toOpenAIResponsesTextFormat(
819
1018
  request.config?.responseFormat
820
1019
  );
@@ -830,13 +1029,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
830
1029
  ),
831
1030
  tool_choice: openaiToolOptions?.toolChoice,
832
1031
  parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
833
- ...buildOpenAIParameters(
834
- modelIdForPayload,
835
- request.config?.maxTokens ?? this.config.maxTokens,
836
- request.config?.temperature ?? this.config.temperature,
837
- this.parameterOptions(request),
838
- "responses"
839
- ),
1032
+ ...parameters,
1033
+ ...options?.reasoningSummary ? {
1034
+ reasoning: {
1035
+ ...parameters.reasoning,
1036
+ summary: options.reasoningSummary
1037
+ }
1038
+ } : {},
1039
+ ...options?.store !== void 0 ? { store: options.store } : {},
1040
+ ...options?.previousResponseId !== void 0 ? { previous_response_id: options.previousResponseId } : {},
1041
+ ...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
1042
+ ...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
1043
+ ...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
1044
+ ...options?.store === false || options?.include ? {
1045
+ include: [
1046
+ .../* @__PURE__ */ new Set([
1047
+ ...options?.include ?? [],
1048
+ ...options?.store === false ? ["reasoning.encrypted_content"] : []
1049
+ ])
1050
+ ]
1051
+ } : {},
840
1052
  ...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
841
1053
  stream
842
1054
  };
@@ -895,6 +1107,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
895
1107
  let usage;
896
1108
  const citations = [];
897
1109
  let completed = false;
1110
+ let terminalResponse;
1111
+ let responseIdentity = {};
1112
+ const outputItems = /* @__PURE__ */ new Map();
1113
+ let streamedText = "";
898
1114
  function* flushToolCalls() {
899
1115
  for (const call of toolCalls.values()) {
900
1116
  if (!call.name)
@@ -911,17 +1127,36 @@ var OpenAIAdapter = class _OpenAIAdapter {
911
1127
  for await (const event of stream) {
912
1128
  throwIfAborted(request.signal);
913
1129
  logProviderPayload("openai", "stream chunk", event, request.debug);
1130
+ if (completed)
1131
+ throw new Error("Responses stream emitted an event after completion");
914
1132
  const index = event?.output_index ?? 0;
915
1133
  switch (event?.type) {
1134
+ case "response.created":
1135
+ responseIdentity = {
1136
+ id: event.response?.id,
1137
+ model: event.response?.model
1138
+ };
1139
+ break;
1140
+ case "response.output_item.done":
1141
+ if (event.item) outputItems.set(index, event.item);
1142
+ if (event.item?.type === "function_call") {
1143
+ toolCalls.set(index, {
1144
+ id: event.item.call_id,
1145
+ name: event.item.name,
1146
+ arguments: event.item.arguments
1147
+ });
1148
+ }
1149
+ break;
916
1150
  case "response.output_text.delta":
917
1151
  if (event.delta) {
1152
+ streamedText += event.delta;
918
1153
  yield { type: "message:delta", content: event.delta };
919
1154
  }
920
1155
  break;
921
1156
  case "response.output_item.added":
922
1157
  if (event.item?.type === "function_call") {
923
1158
  toolCalls.set(index, {
924
- id: event.item.call_id ?? event.item.id ?? generateToolCallId(),
1159
+ id: event.item.call_id ?? "",
925
1160
  name: event.item.name ?? "",
926
1161
  arguments: event.item.arguments ?? ""
927
1162
  });
@@ -940,7 +1175,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
940
1175
  break;
941
1176
  }
942
1177
  case "response.completed": {
1178
+ if (event.response?.status && event.response.status !== "completed")
1179
+ throw new Error(`Responses stream ${event.response.status}`);
943
1180
  completed = true;
1181
+ terminalResponse = { ...responseIdentity, ...event.response };
944
1182
  const found = this.collectResponsesCitations(
945
1183
  event.response?.output,
946
1184
  citations.length
@@ -977,12 +1215,64 @@ var OpenAIAdapter = class _OpenAIAdapter {
977
1215
  throwIfAborted(request.signal);
978
1216
  if (!completed)
979
1217
  throw new Error("Responses stream ended without a completed response");
1218
+ const output = terminalResponse.output?.length ? terminalResponse.output : [...outputItems.entries()].sort(([a], [b]) => a - b).map(([, item]) => item);
1219
+ if (output.some((item) => item.type === "function_call"))
1220
+ toolCalls.clear();
1221
+ for (const [index, item] of output.entries()) {
1222
+ if (item.type === "function_call") {
1223
+ toolCalls.set(index, {
1224
+ id: item.call_id,
1225
+ name: item.name,
1226
+ arguments: item.arguments
1227
+ });
1228
+ }
1229
+ }
1230
+ const uniqueCalls = /* @__PURE__ */ new Map();
1231
+ for (const call of toolCalls.values()) {
1232
+ if (!call.id || !call.name)
1233
+ throw new Error("Responses stream contains an incomplete tool call");
1234
+ uniqueCalls.set(call.id, call);
1235
+ }
1236
+ toolCalls.clear();
1237
+ [...uniqueCalls.values()].forEach(
1238
+ (call, index) => toolCalls.set(index, call)
1239
+ );
1240
+ if (!output.length && toolCalls.size) {
1241
+ for (const call of toolCalls.values())
1242
+ output.push({
1243
+ type: "function_call",
1244
+ call_id: call.id,
1245
+ name: call.name,
1246
+ arguments: call.arguments
1247
+ });
1248
+ }
1249
+ if (!output.length && streamedText)
1250
+ output.push({
1251
+ type: "message",
1252
+ role: "assistant",
1253
+ content: [{ type: "output_text", text: streamedText, annotations: [] }]
1254
+ });
1255
+ terminalResponse.output = output;
1256
+ const finalText = this.parseResponsesResult(terminalResponse).content;
1257
+ if (finalText.startsWith(streamedText) && finalText.length > streamedText.length) {
1258
+ yield {
1259
+ type: "message:delta",
1260
+ content: finalText.slice(streamedText.length)
1261
+ };
1262
+ }
980
1263
  yield* flushToolCalls();
981
1264
  if (citations.length > 0) {
982
1265
  yield { type: "citation", citations: deduplicateCitations(citations) };
983
1266
  }
984
- yield { type: "message:end" };
985
- yield { type: "done", usage };
1267
+ yield {
1268
+ type: "message:end",
1269
+ providerMetadata: responseMetadata(terminalResponse)
1270
+ };
1271
+ yield {
1272
+ type: "done",
1273
+ usage,
1274
+ providerMetadata: responseMetadata(terminalResponse)
1275
+ };
986
1276
  }
987
1277
  async *stream(request) {
988
1278
  throwIfAborted(request.signal);
@@ -1,7 +1,7 @@
1
- import { L as LanguageModel } from '../../types-BW3csYo5.mjs';
2
- import { A as AIProvider } from '../../types-NOswlhm9.mjs';
1
+ import { L as LanguageModel } from '../../types-Dg1Bcg1k.mjs';
2
+ import { 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
  * Together AI Provider
@@ -1,7 +1,7 @@
1
- import { L as LanguageModel } from '../../types-BW3csYo5.js';
2
- import { A as AIProvider } from '../../types-DA54bSmX.js';
1
+ import { L as LanguageModel } from '../../types-Dg1Bcg1k.js';
2
+ import { 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
  * Together AI Provider