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

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 +146 -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 +437 -39
  5. package/dist/adapters/index.mjs +437 -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 +20 -36
  13. package/dist/index.d.ts +20 -36
  14. package/dist/index.js +327 -69
  15. package/dist/index.mjs +325 -70
  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 +116 -7
  19. package/dist/providers/anthropic/index.mjs +116 -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 +393 -31
  27. package/dist/providers/fireworks/index.mjs +393 -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 +393 -31
  31. package/dist/providers/google/index.mjs +393 -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 +822 -40
  39. package/dist/providers/openai/index.mjs +821 -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 +393 -31
  43. package/dist/providers/openrouter/index.mjs +393 -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 +393 -31
  47. package/dist/providers/togetherai/index.mjs +393 -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 +393 -31
  51. package/dist/providers/xai/index.mjs +393 -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,7 +639,120 @@ 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 responseReplayMetadata(metadata) {
690
+ const response = metadata?.openai?.response;
691
+ if (!response) return metadata;
692
+ const output = response.output.map((item) => {
693
+ const fields = ["type", "id", "status"];
694
+ switch (item.type) {
695
+ case "reasoning":
696
+ fields.push("encrypted_content");
697
+ break;
698
+ case "message":
699
+ fields.push("role", "phase");
700
+ break;
701
+ case "function_call":
702
+ fields.push("call_id", "name", "namespace", "arguments");
703
+ break;
704
+ case "tool_search_call":
705
+ fields.push("call_id", "execution", "arguments");
706
+ break;
707
+ case "tool_search_output":
708
+ fields.push("call_id", "tools");
709
+ break;
710
+ case "web_search_call":
711
+ fields.push("action");
712
+ break;
713
+ default:
714
+ return stripItemDiagnostics(item);
715
+ }
716
+ const replay = Object.fromEntries(
717
+ fields.filter((key) => item[key] !== void 0).map((key) => [key, item[key]])
718
+ );
719
+ if (item.type === "reasoning") replay.summary = [];
720
+ if (item.type === "message")
721
+ replay.content = Array.isArray(item.content) ? item.content.flatMap(
722
+ (part) => part?.type === "output_text" && typeof part.text === "string" ? [{ type: "output_text", text: part.text, annotations: [] }] : part?.type === "refusal" && typeof part.refusal === "string" ? [{ type: "refusal", refusal: part.refusal }] : []
723
+ ) : [];
724
+ return stripItemDiagnostics(replay);
725
+ });
726
+ return { openai: { response: { output, refusals: [] } } };
727
+ }
728
+ function stripItemDiagnostics(item) {
729
+ const {
730
+ usage: _usage,
731
+ logprobs: _logprobs,
732
+ metadata: _metadata,
733
+ ...state
734
+ } = item;
735
+ return state;
736
+ }
737
+ function getResponseReplay(metadata) {
738
+ const response = metadata?.openai?.response;
739
+ if (response === void 0) return void 0;
740
+ if (!Array.isArray(response.output) || response.output.some((item) => !item || typeof item.type !== "string")) {
741
+ throw new Error(
742
+ "Invalid OpenAI Responses replay metadata: output must contain typed items"
743
+ );
744
+ }
745
+ return responseReplayMetadata(metadata)?.openai?.response?.output;
746
+ }
747
+
537
748
  // src/core/provider-error.ts
749
+ function invalidProviderResponse(message) {
750
+ return Object.assign(new Error(message), {
751
+ name: "InvalidProviderResponseError",
752
+ status: 502,
753
+ code: "INVALID_PROVIDER_RESPONSE"
754
+ });
755
+ }
538
756
  function providerErrorEvent(error, code) {
539
757
  const details = error ?? {};
540
758
  const event = {
@@ -610,13 +828,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
610
828
  }));
611
829
  }
612
830
  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(
831
+ return useOpenAIResponses(
617
832
  request.config?.model || this.model,
618
833
  this.config.baseUrl,
619
- this.parameterOptions(request)
834
+ this.parameterOptions(request),
835
+ resolveOpenAITransport(this.config, request.config?.openai),
836
+ this.toolDefinitions(request).length > 0,
837
+ !!(request.rawMessages ?? request.messages)?.some(
838
+ (message) => message.providerMetadata?.openai?.response
839
+ ),
840
+ request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false
620
841
  );
621
842
  }
622
843
  /**
@@ -649,11 +870,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
649
870
  });
650
871
  }
651
872
  buildResponsesInput(request) {
652
- const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
873
+ const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages, true) : formatMessagesForOpenAI(request.messages, void 0, true);
653
874
  const input = [];
654
875
  for (const message of sourceMessages) {
655
876
  if (message.role === "system") {
656
- if (!request.systemPrompt && message.content) {
877
+ if (message.content && message.content !== request.systemPrompt) {
657
878
  input.push({
658
879
  type: "message",
659
880
  role: "developer",
@@ -663,6 +884,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
663
884
  continue;
664
885
  }
665
886
  if (message.role === "assistant") {
887
+ const replay = getResponseReplay(message.providerMetadata);
888
+ if (replay) {
889
+ input.push(...replay);
890
+ continue;
891
+ }
666
892
  const content = this.toResponsesContent(message.content, "assistant");
667
893
  if (typeof content === "string" ? content : Array.isArray(content) && content.length > 0) {
668
894
  input.push({
@@ -686,7 +912,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
686
912
  input.push({
687
913
  type: "function_call_output",
688
914
  call_id: message.tool_call_id,
689
- output: typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
915
+ output: message.modelOutput ? toolOutputForProvider(message.modelOutput, "responses") : typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
690
916
  });
691
917
  continue;
692
918
  }
@@ -700,10 +926,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
700
926
  return input;
701
927
  }
702
928
  /** Preserve Copilot screenshot attachments on every OpenAI transport. */
703
- formatRawMessages(messages) {
929
+ formatRawMessages(messages, preserveProviderMetadata = false) {
704
930
  return messages.map((message) => {
705
- const { attachments, ...rest } = message;
706
- let content = message.content;
931
+ const { attachments, providerMetadata, modelOutput, ...rest } = message;
932
+ let content = message.role === "tool" && !preserveProviderMetadata && modelOutput !== void 0 ? textToolOutput(modelOutput, "") : message.content;
933
+ if (preserveProviderMetadata && modelOutput)
934
+ rest.modelOutput = modelOutput;
707
935
  if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
708
936
  content = null;
709
937
  }
@@ -716,7 +944,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
716
944
  content = [...parts, ...images];
717
945
  }
718
946
  }
719
- return { ...rest, content };
947
+ return {
948
+ ...rest,
949
+ content,
950
+ ...preserveProviderMetadata && providerMetadata ? { providerMetadata } : {}
951
+ };
720
952
  });
721
953
  }
722
954
  /**
@@ -797,14 +1029,40 @@ var OpenAIAdapter = class _OpenAIAdapter {
797
1029
  ).map((part) => part.text) : []
798
1030
  ).join("") : "";
799
1031
  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
- })) : [];
1032
+ const seenCallIds = /* @__PURE__ */ new Set();
1033
+ const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
1034
+ if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
1035
+ throw invalidProviderResponse(
1036
+ "Responses contains an incomplete function call"
1037
+ );
1038
+ }
1039
+ if (seenCallIds.has(item.call_id))
1040
+ throw invalidProviderResponse(
1041
+ "Responses contains duplicate function call IDs"
1042
+ );
1043
+ seenCallIds.add(item.call_id);
1044
+ let args;
1045
+ try {
1046
+ args = JSON.parse(item.arguments);
1047
+ } catch {
1048
+ throw invalidProviderResponse(
1049
+ "Responses function arguments must be valid JSON"
1050
+ );
1051
+ }
1052
+ if (!args || typeof args !== "object" || Array.isArray(args))
1053
+ throw invalidProviderResponse(
1054
+ "Responses function arguments must be a JSON object"
1055
+ );
1056
+ return {
1057
+ id: item.call_id,
1058
+ name: item.name,
1059
+ args
1060
+ };
1061
+ }) : [];
805
1062
  return {
806
1063
  content,
807
1064
  toolCalls,
1065
+ providerMetadata: responseMetadata(response),
808
1066
  usage: response?.usage ? {
809
1067
  promptTokens: response.usage.input_tokens ?? 0,
810
1068
  completionTokens: response.usage.output_tokens ?? 0,
@@ -815,6 +1073,17 @@ var OpenAIAdapter = class _OpenAIAdapter {
815
1073
  }
816
1074
  buildResponsesPayload(request, stream) {
817
1075
  const openaiToolOptions = request.providerToolOptions?.openai;
1076
+ const options = resolveOpenAITransport(
1077
+ this.config,
1078
+ request.config?.openai
1079
+ ).responses;
1080
+ const parameters = buildOpenAIParameters(
1081
+ request.config?.model || this.model,
1082
+ request.config?.maxTokens ?? this.config.maxTokens,
1083
+ request.config?.temperature ?? this.config.temperature,
1084
+ this.parameterOptions(request),
1085
+ "responses"
1086
+ );
818
1087
  const responsesTextFormat = toOpenAIResponsesTextFormat(
819
1088
  request.config?.responseFormat
820
1089
  );
@@ -830,13 +1099,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
830
1099
  ),
831
1100
  tool_choice: openaiToolOptions?.toolChoice,
832
1101
  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
- ),
1102
+ ...parameters,
1103
+ ...options?.reasoningSummary ? {
1104
+ reasoning: {
1105
+ ...parameters.reasoning,
1106
+ summary: options.reasoningSummary
1107
+ }
1108
+ } : {},
1109
+ ...options?.store !== void 0 ? { store: options.store } : {},
1110
+ ...options?.previousResponseId !== void 0 ? { previous_response_id: options.previousResponseId } : {},
1111
+ ...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
1112
+ ...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
1113
+ ...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
1114
+ ...options?.store === false || options?.include ? {
1115
+ include: [
1116
+ .../* @__PURE__ */ new Set([
1117
+ ...options?.include ?? [],
1118
+ ...options?.store === false ? ["reasoning.encrypted_content"] : []
1119
+ ])
1120
+ ]
1121
+ } : {},
840
1122
  ...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
841
1123
  stream
842
1124
  };
@@ -895,6 +1177,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
895
1177
  let usage;
896
1178
  const citations = [];
897
1179
  let completed = false;
1180
+ let terminalResponse;
1181
+ let responseIdentity = {};
1182
+ const outputItems = /* @__PURE__ */ new Map();
1183
+ let streamedText = "";
898
1184
  function* flushToolCalls() {
899
1185
  for (const call of toolCalls.values()) {
900
1186
  if (!call.name)
@@ -911,17 +1197,36 @@ var OpenAIAdapter = class _OpenAIAdapter {
911
1197
  for await (const event of stream) {
912
1198
  throwIfAborted(request.signal);
913
1199
  logProviderPayload("openai", "stream chunk", event, request.debug);
1200
+ if (completed)
1201
+ throw new Error("Responses stream emitted an event after completion");
914
1202
  const index = event?.output_index ?? 0;
915
1203
  switch (event?.type) {
1204
+ case "response.created":
1205
+ responseIdentity = {
1206
+ id: event.response?.id,
1207
+ model: event.response?.model
1208
+ };
1209
+ break;
1210
+ case "response.output_item.done":
1211
+ if (event.item) outputItems.set(index, event.item);
1212
+ if (event.item?.type === "function_call") {
1213
+ toolCalls.set(index, {
1214
+ id: event.item.call_id,
1215
+ name: event.item.name,
1216
+ arguments: event.item.arguments
1217
+ });
1218
+ }
1219
+ break;
916
1220
  case "response.output_text.delta":
917
1221
  if (event.delta) {
1222
+ streamedText += event.delta;
918
1223
  yield { type: "message:delta", content: event.delta };
919
1224
  }
920
1225
  break;
921
1226
  case "response.output_item.added":
922
1227
  if (event.item?.type === "function_call") {
923
1228
  toolCalls.set(index, {
924
- id: event.item.call_id ?? event.item.id ?? generateToolCallId(),
1229
+ id: event.item.call_id ?? "",
925
1230
  name: event.item.name ?? "",
926
1231
  arguments: event.item.arguments ?? ""
927
1232
  });
@@ -940,7 +1245,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
940
1245
  break;
941
1246
  }
942
1247
  case "response.completed": {
1248
+ if (event.response?.status && event.response.status !== "completed")
1249
+ throw new Error(`Responses stream ${event.response.status}`);
943
1250
  completed = true;
1251
+ terminalResponse = { ...responseIdentity, ...event.response };
944
1252
  const found = this.collectResponsesCitations(
945
1253
  event.response?.output,
946
1254
  citations.length
@@ -977,12 +1285,66 @@ var OpenAIAdapter = class _OpenAIAdapter {
977
1285
  throwIfAborted(request.signal);
978
1286
  if (!completed)
979
1287
  throw new Error("Responses stream ended without a completed response");
1288
+ const output = terminalResponse.output?.length ? terminalResponse.output : [...outputItems.entries()].sort(([a], [b]) => a - b).map(([, item]) => item);
1289
+ if (output.some((item) => item.type === "function_call"))
1290
+ toolCalls.clear();
1291
+ for (const [index, item] of output.entries()) {
1292
+ if (item.type === "function_call") {
1293
+ toolCalls.set(index, {
1294
+ id: item.call_id,
1295
+ name: item.name,
1296
+ arguments: item.arguments
1297
+ });
1298
+ }
1299
+ }
1300
+ const uniqueCalls = /* @__PURE__ */ new Map();
1301
+ for (const call of toolCalls.values()) {
1302
+ if (!call.id || !call.name)
1303
+ throw invalidProviderResponse(
1304
+ "Responses stream contains an incomplete tool call"
1305
+ );
1306
+ uniqueCalls.set(call.id, call);
1307
+ }
1308
+ toolCalls.clear();
1309
+ [...uniqueCalls.values()].forEach(
1310
+ (call, index) => toolCalls.set(index, call)
1311
+ );
1312
+ if (!output.length && toolCalls.size) {
1313
+ for (const call of toolCalls.values())
1314
+ output.push({
1315
+ type: "function_call",
1316
+ call_id: call.id,
1317
+ name: call.name,
1318
+ arguments: call.arguments
1319
+ });
1320
+ }
1321
+ if (!output.length && streamedText)
1322
+ output.push({
1323
+ type: "message",
1324
+ role: "assistant",
1325
+ content: [{ type: "output_text", text: streamedText, annotations: [] }]
1326
+ });
1327
+ terminalResponse.output = output;
1328
+ const finalText = this.parseResponsesResult(terminalResponse).content;
1329
+ if (finalText.startsWith(streamedText) && finalText.length > streamedText.length) {
1330
+ yield {
1331
+ type: "message:delta",
1332
+ content: finalText.slice(streamedText.length)
1333
+ };
1334
+ }
980
1335
  yield* flushToolCalls();
981
1336
  if (citations.length > 0) {
982
1337
  yield { type: "citation", citations: deduplicateCitations(citations) };
983
1338
  }
984
- yield { type: "message:end" };
985
- yield { type: "done", usage };
1339
+ yield {
1340
+ type: "message:end",
1341
+ providerMetadata: responseMetadata(terminalResponse)
1342
+ };
1343
+ yield {
1344
+ type: "done",
1345
+ usage,
1346
+ providerMetadata: responseMetadata(terminalResponse)
1347
+ };
986
1348
  }
987
1349
  async *stream(request) {
988
1350
  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