@yourgpt/llm-sdk 2.6.0-beta.2 → 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.
@@ -713,6 +713,54 @@ function responseMetadata(response) {
713
713
  }
714
714
  };
715
715
  }
716
+ function responseReplayMetadata(metadata) {
717
+ const response = metadata?.openai?.response;
718
+ if (!response) return metadata;
719
+ const output = response.output.map((item) => {
720
+ const fields = ["type", "id", "status"];
721
+ switch (item.type) {
722
+ case "reasoning":
723
+ fields.push("encrypted_content");
724
+ break;
725
+ case "message":
726
+ fields.push("role", "phase");
727
+ break;
728
+ case "function_call":
729
+ fields.push("call_id", "name", "namespace", "arguments");
730
+ break;
731
+ case "tool_search_call":
732
+ fields.push("call_id", "execution", "arguments");
733
+ break;
734
+ case "tool_search_output":
735
+ fields.push("call_id", "tools");
736
+ break;
737
+ case "web_search_call":
738
+ fields.push("action");
739
+ break;
740
+ default:
741
+ return stripItemDiagnostics(item);
742
+ }
743
+ const replay = Object.fromEntries(
744
+ fields.filter((key) => item[key] !== void 0).map((key) => [key, item[key]])
745
+ );
746
+ if (item.type === "reasoning") replay.summary = [];
747
+ if (item.type === "message")
748
+ replay.content = Array.isArray(item.content) ? item.content.flatMap(
749
+ (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 }] : []
750
+ ) : [];
751
+ return stripItemDiagnostics(replay);
752
+ });
753
+ return { openai: { response: { output, refusals: [] } } };
754
+ }
755
+ function stripItemDiagnostics(item) {
756
+ const {
757
+ usage: _usage,
758
+ logprobs: _logprobs,
759
+ metadata: _metadata,
760
+ ...state
761
+ } = item;
762
+ return state;
763
+ }
716
764
  function getResponseReplay(metadata) {
717
765
  const response = metadata?.openai?.response;
718
766
  if (response === void 0) return void 0;
@@ -721,10 +769,17 @@ function getResponseReplay(metadata) {
721
769
  "Invalid OpenAI Responses replay metadata: output must contain typed items"
722
770
  );
723
771
  }
724
- return response.output;
772
+ return responseReplayMetadata(metadata)?.openai?.response?.output;
725
773
  }
726
774
 
727
775
  // src/core/provider-error.ts
776
+ function invalidProviderResponse(message) {
777
+ return Object.assign(new Error(message), {
778
+ name: "InvalidProviderResponseError",
779
+ status: 502,
780
+ code: "INVALID_PROVIDER_RESPONSE"
781
+ });
782
+ }
728
783
  function providerErrorEvent(error, code) {
729
784
  const details = error ?? {};
730
785
  const event = {
@@ -901,7 +956,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
901
956
  formatRawMessages(messages, preserveProviderMetadata = false) {
902
957
  return messages.map((message) => {
903
958
  const { attachments, providerMetadata, modelOutput, ...rest } = message;
904
- let content = message.role === "tool" && !preserveProviderMetadata ? textToolOutput(modelOutput, String(message.content ?? "")) : message.content;
959
+ let content = message.role === "tool" && !preserveProviderMetadata && modelOutput !== void 0 ? textToolOutput(modelOutput, "") : message.content;
905
960
  if (preserveProviderMetadata && modelOutput)
906
961
  rest.modelOutput = modelOutput;
907
962
  if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
@@ -1004,17 +1059,32 @@ var OpenAIAdapter = class _OpenAIAdapter {
1004
1059
  const seenCallIds = /* @__PURE__ */ new Set();
1005
1060
  const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
1006
1061
  if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
1007
- throw new Error("Responses contains an incomplete function call");
1062
+ throw invalidProviderResponse(
1063
+ "Responses contains an incomplete function call"
1064
+ );
1008
1065
  }
1009
1066
  if (seenCallIds.has(item.call_id))
1010
- throw new Error("Responses contains duplicate function call IDs");
1067
+ throw invalidProviderResponse(
1068
+ "Responses contains duplicate function call IDs"
1069
+ );
1011
1070
  seenCallIds.add(item.call_id);
1012
- const args = JSON.parse(item.arguments);
1071
+ let args;
1072
+ try {
1073
+ args = JSON.parse(item.arguments);
1074
+ } catch {
1075
+ throw invalidProviderResponse(
1076
+ "Responses function arguments must be valid JSON"
1077
+ );
1078
+ }
1013
1079
  if (!args || typeof args !== "object" || Array.isArray(args))
1014
- throw new Error(
1080
+ throw invalidProviderResponse(
1015
1081
  "Responses function arguments must be a JSON object"
1016
1082
  );
1017
- return { id: item.call_id, name: item.name, args };
1083
+ return {
1084
+ id: item.call_id,
1085
+ name: item.name,
1086
+ args
1087
+ };
1018
1088
  }) : [];
1019
1089
  return {
1020
1090
  content,
@@ -1257,7 +1327,9 @@ var OpenAIAdapter = class _OpenAIAdapter {
1257
1327
  const uniqueCalls = /* @__PURE__ */ new Map();
1258
1328
  for (const call of toolCalls.values()) {
1259
1329
  if (!call.id || !call.name)
1260
- throw new Error("Responses stream contains an incomplete tool call");
1330
+ throw invalidProviderResponse(
1331
+ "Responses stream contains an incomplete tool call"
1332
+ );
1261
1333
  uniqueCalls.set(call.id, call);
1262
1334
  }
1263
1335
  toolCalls.clear();
@@ -201,6 +201,54 @@ function responseMetadata(response) {
201
201
  }
202
202
  };
203
203
  }
204
+ function responseReplayMetadata(metadata) {
205
+ const response = metadata?.openai?.response;
206
+ if (!response) return metadata;
207
+ const output = response.output.map((item) => {
208
+ const fields = ["type", "id", "status"];
209
+ switch (item.type) {
210
+ case "reasoning":
211
+ fields.push("encrypted_content");
212
+ break;
213
+ case "message":
214
+ fields.push("role", "phase");
215
+ break;
216
+ case "function_call":
217
+ fields.push("call_id", "name", "namespace", "arguments");
218
+ break;
219
+ case "tool_search_call":
220
+ fields.push("call_id", "execution", "arguments");
221
+ break;
222
+ case "tool_search_output":
223
+ fields.push("call_id", "tools");
224
+ break;
225
+ case "web_search_call":
226
+ fields.push("action");
227
+ break;
228
+ default:
229
+ return stripItemDiagnostics(item);
230
+ }
231
+ const replay = Object.fromEntries(
232
+ fields.filter((key) => item[key] !== void 0).map((key) => [key, item[key]])
233
+ );
234
+ if (item.type === "reasoning") replay.summary = [];
235
+ if (item.type === "message")
236
+ replay.content = Array.isArray(item.content) ? item.content.flatMap(
237
+ (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 }] : []
238
+ ) : [];
239
+ return stripItemDiagnostics(replay);
240
+ });
241
+ return { openai: { response: { output, refusals: [] } } };
242
+ }
243
+ function stripItemDiagnostics(item) {
244
+ const {
245
+ usage: _usage,
246
+ logprobs: _logprobs,
247
+ metadata: _metadata,
248
+ ...state
249
+ } = item;
250
+ return state;
251
+ }
204
252
  function getResponseReplay(metadata) {
205
253
  const response = metadata?.openai?.response;
206
254
  if (response === void 0) return void 0;
@@ -209,10 +257,17 @@ function getResponseReplay(metadata) {
209
257
  "Invalid OpenAI Responses replay metadata: output must contain typed items"
210
258
  );
211
259
  }
212
- return response.output;
260
+ return responseReplayMetadata(metadata)?.openai?.response?.output;
213
261
  }
214
262
 
215
263
  // src/core/provider-error.ts
264
+ function invalidProviderResponse(message) {
265
+ return Object.assign(new Error(message), {
266
+ name: "InvalidProviderResponseError",
267
+ status: 502,
268
+ code: "INVALID_PROVIDER_RESPONSE"
269
+ });
270
+ }
216
271
  function providerErrorEvent(error, code) {
217
272
  const details = error ?? {};
218
273
  const event = {
@@ -625,7 +680,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
625
680
  formatRawMessages(messages, preserveProviderMetadata = false) {
626
681
  return messages.map((message) => {
627
682
  const { attachments, providerMetadata, modelOutput, ...rest } = message;
628
- let content = message.role === "tool" && !preserveProviderMetadata ? textToolOutput(modelOutput, String(message.content ?? "")) : message.content;
683
+ let content = message.role === "tool" && !preserveProviderMetadata && modelOutput !== void 0 ? textToolOutput(modelOutput, "") : message.content;
629
684
  if (preserveProviderMetadata && modelOutput)
630
685
  rest.modelOutput = modelOutput;
631
686
  if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
@@ -728,17 +783,32 @@ var OpenAIAdapter = class _OpenAIAdapter {
728
783
  const seenCallIds = /* @__PURE__ */ new Set();
729
784
  const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
730
785
  if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
731
- throw new Error("Responses contains an incomplete function call");
786
+ throw invalidProviderResponse(
787
+ "Responses contains an incomplete function call"
788
+ );
732
789
  }
733
790
  if (seenCallIds.has(item.call_id))
734
- throw new Error("Responses contains duplicate function call IDs");
791
+ throw invalidProviderResponse(
792
+ "Responses contains duplicate function call IDs"
793
+ );
735
794
  seenCallIds.add(item.call_id);
736
- const args = JSON.parse(item.arguments);
795
+ let args;
796
+ try {
797
+ args = JSON.parse(item.arguments);
798
+ } catch {
799
+ throw invalidProviderResponse(
800
+ "Responses function arguments must be valid JSON"
801
+ );
802
+ }
737
803
  if (!args || typeof args !== "object" || Array.isArray(args))
738
- throw new Error(
804
+ throw invalidProviderResponse(
739
805
  "Responses function arguments must be a JSON object"
740
806
  );
741
- return { id: item.call_id, name: item.name, args };
807
+ return {
808
+ id: item.call_id,
809
+ name: item.name,
810
+ args
811
+ };
742
812
  }) : [];
743
813
  return {
744
814
  content,
@@ -981,7 +1051,9 @@ var OpenAIAdapter = class _OpenAIAdapter {
981
1051
  const uniqueCalls = /* @__PURE__ */ new Map();
982
1052
  for (const call of toolCalls.values()) {
983
1053
  if (!call.id || !call.name)
984
- throw new Error("Responses stream contains an incomplete tool call");
1054
+ throw invalidProviderResponse(
1055
+ "Responses stream contains an incomplete tool call"
1056
+ );
985
1057
  uniqueCalls.set(call.id, call);
986
1058
  }
987
1059
  toolCalls.clear();
@@ -199,6 +199,54 @@ function responseMetadata(response) {
199
199
  }
200
200
  };
201
201
  }
202
+ function responseReplayMetadata(metadata) {
203
+ const response = metadata?.openai?.response;
204
+ if (!response) return metadata;
205
+ const output = response.output.map((item) => {
206
+ const fields = ["type", "id", "status"];
207
+ switch (item.type) {
208
+ case "reasoning":
209
+ fields.push("encrypted_content");
210
+ break;
211
+ case "message":
212
+ fields.push("role", "phase");
213
+ break;
214
+ case "function_call":
215
+ fields.push("call_id", "name", "namespace", "arguments");
216
+ break;
217
+ case "tool_search_call":
218
+ fields.push("call_id", "execution", "arguments");
219
+ break;
220
+ case "tool_search_output":
221
+ fields.push("call_id", "tools");
222
+ break;
223
+ case "web_search_call":
224
+ fields.push("action");
225
+ break;
226
+ default:
227
+ return stripItemDiagnostics(item);
228
+ }
229
+ const replay = Object.fromEntries(
230
+ fields.filter((key) => item[key] !== void 0).map((key) => [key, item[key]])
231
+ );
232
+ if (item.type === "reasoning") replay.summary = [];
233
+ if (item.type === "message")
234
+ replay.content = Array.isArray(item.content) ? item.content.flatMap(
235
+ (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 }] : []
236
+ ) : [];
237
+ return stripItemDiagnostics(replay);
238
+ });
239
+ return { openai: { response: { output, refusals: [] } } };
240
+ }
241
+ function stripItemDiagnostics(item) {
242
+ const {
243
+ usage: _usage,
244
+ logprobs: _logprobs,
245
+ metadata: _metadata,
246
+ ...state
247
+ } = item;
248
+ return state;
249
+ }
202
250
  function getResponseReplay(metadata) {
203
251
  const response = metadata?.openai?.response;
204
252
  if (response === void 0) return void 0;
@@ -207,10 +255,17 @@ function getResponseReplay(metadata) {
207
255
  "Invalid OpenAI Responses replay metadata: output must contain typed items"
208
256
  );
209
257
  }
210
- return response.output;
258
+ return responseReplayMetadata(metadata)?.openai?.response?.output;
211
259
  }
212
260
 
213
261
  // src/core/provider-error.ts
262
+ function invalidProviderResponse(message) {
263
+ return Object.assign(new Error(message), {
264
+ name: "InvalidProviderResponseError",
265
+ status: 502,
266
+ code: "INVALID_PROVIDER_RESPONSE"
267
+ });
268
+ }
214
269
  function providerErrorEvent(error, code) {
215
270
  const details = error ?? {};
216
271
  const event = {
@@ -623,7 +678,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
623
678
  formatRawMessages(messages, preserveProviderMetadata = false) {
624
679
  return messages.map((message) => {
625
680
  const { attachments, providerMetadata, modelOutput, ...rest } = message;
626
- let content = message.role === "tool" && !preserveProviderMetadata ? textToolOutput(modelOutput, String(message.content ?? "")) : message.content;
681
+ let content = message.role === "tool" && !preserveProviderMetadata && modelOutput !== void 0 ? textToolOutput(modelOutput, "") : message.content;
627
682
  if (preserveProviderMetadata && modelOutput)
628
683
  rest.modelOutput = modelOutput;
629
684
  if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
@@ -726,17 +781,32 @@ var OpenAIAdapter = class _OpenAIAdapter {
726
781
  const seenCallIds = /* @__PURE__ */ new Set();
727
782
  const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
728
783
  if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
729
- throw new Error("Responses contains an incomplete function call");
784
+ throw invalidProviderResponse(
785
+ "Responses contains an incomplete function call"
786
+ );
730
787
  }
731
788
  if (seenCallIds.has(item.call_id))
732
- throw new Error("Responses contains duplicate function call IDs");
789
+ throw invalidProviderResponse(
790
+ "Responses contains duplicate function call IDs"
791
+ );
733
792
  seenCallIds.add(item.call_id);
734
- const args = JSON.parse(item.arguments);
793
+ let args;
794
+ try {
795
+ args = JSON.parse(item.arguments);
796
+ } catch {
797
+ throw invalidProviderResponse(
798
+ "Responses function arguments must be valid JSON"
799
+ );
800
+ }
735
801
  if (!args || typeof args !== "object" || Array.isArray(args))
736
- throw new Error(
802
+ throw invalidProviderResponse(
737
803
  "Responses function arguments must be a JSON object"
738
804
  );
739
- return { id: item.call_id, name: item.name, args };
805
+ return {
806
+ id: item.call_id,
807
+ name: item.name,
808
+ args
809
+ };
740
810
  }) : [];
741
811
  return {
742
812
  content,
@@ -979,7 +1049,9 @@ var OpenAIAdapter = class _OpenAIAdapter {
979
1049
  const uniqueCalls = /* @__PURE__ */ new Map();
980
1050
  for (const call of toolCalls.values()) {
981
1051
  if (!call.id || !call.name)
982
- throw new Error("Responses stream contains an incomplete tool call");
1052
+ throw invalidProviderResponse(
1053
+ "Responses stream contains an incomplete tool call"
1054
+ );
983
1055
  uniqueCalls.set(call.id, call);
984
1056
  }
985
1057
  toolCalls.clear();
@@ -688,6 +688,54 @@ function responseMetadata(response) {
688
688
  }
689
689
  };
690
690
  }
691
+ function responseReplayMetadata(metadata) {
692
+ const response = metadata?.openai?.response;
693
+ if (!response) return metadata;
694
+ const output = response.output.map((item) => {
695
+ const fields = ["type", "id", "status"];
696
+ switch (item.type) {
697
+ case "reasoning":
698
+ fields.push("encrypted_content");
699
+ break;
700
+ case "message":
701
+ fields.push("role", "phase");
702
+ break;
703
+ case "function_call":
704
+ fields.push("call_id", "name", "namespace", "arguments");
705
+ break;
706
+ case "tool_search_call":
707
+ fields.push("call_id", "execution", "arguments");
708
+ break;
709
+ case "tool_search_output":
710
+ fields.push("call_id", "tools");
711
+ break;
712
+ case "web_search_call":
713
+ fields.push("action");
714
+ break;
715
+ default:
716
+ return stripItemDiagnostics(item);
717
+ }
718
+ const replay = Object.fromEntries(
719
+ fields.filter((key) => item[key] !== void 0).map((key) => [key, item[key]])
720
+ );
721
+ if (item.type === "reasoning") replay.summary = [];
722
+ if (item.type === "message")
723
+ replay.content = Array.isArray(item.content) ? item.content.flatMap(
724
+ (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 }] : []
725
+ ) : [];
726
+ return stripItemDiagnostics(replay);
727
+ });
728
+ return { openai: { response: { output, refusals: [] } } };
729
+ }
730
+ function stripItemDiagnostics(item) {
731
+ const {
732
+ usage: _usage,
733
+ logprobs: _logprobs,
734
+ metadata: _metadata,
735
+ ...state
736
+ } = item;
737
+ return state;
738
+ }
691
739
  function getResponseReplay(metadata) {
692
740
  const response = metadata?.openai?.response;
693
741
  if (response === void 0) return void 0;
@@ -696,10 +744,17 @@ function getResponseReplay(metadata) {
696
744
  "Invalid OpenAI Responses replay metadata: output must contain typed items"
697
745
  );
698
746
  }
699
- return response.output;
747
+ return responseReplayMetadata(metadata)?.openai?.response?.output;
700
748
  }
701
749
 
702
750
  // src/core/provider-error.ts
751
+ function invalidProviderResponse(message) {
752
+ return Object.assign(new Error(message), {
753
+ name: "InvalidProviderResponseError",
754
+ status: 502,
755
+ code: "INVALID_PROVIDER_RESPONSE"
756
+ });
757
+ }
703
758
  function providerErrorEvent(error, code) {
704
759
  const details = error ?? {};
705
760
  const event = {
@@ -876,7 +931,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
876
931
  formatRawMessages(messages, preserveProviderMetadata = false) {
877
932
  return messages.map((message) => {
878
933
  const { attachments, providerMetadata, modelOutput, ...rest } = message;
879
- let content = message.role === "tool" && !preserveProviderMetadata ? textToolOutput(modelOutput, String(message.content ?? "")) : message.content;
934
+ let content = message.role === "tool" && !preserveProviderMetadata && modelOutput !== void 0 ? textToolOutput(modelOutput, "") : message.content;
880
935
  if (preserveProviderMetadata && modelOutput)
881
936
  rest.modelOutput = modelOutput;
882
937
  if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
@@ -979,17 +1034,32 @@ var OpenAIAdapter = class _OpenAIAdapter {
979
1034
  const seenCallIds = /* @__PURE__ */ new Set();
980
1035
  const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
981
1036
  if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
982
- throw new Error("Responses contains an incomplete function call");
1037
+ throw invalidProviderResponse(
1038
+ "Responses contains an incomplete function call"
1039
+ );
983
1040
  }
984
1041
  if (seenCallIds.has(item.call_id))
985
- throw new Error("Responses contains duplicate function call IDs");
1042
+ throw invalidProviderResponse(
1043
+ "Responses contains duplicate function call IDs"
1044
+ );
986
1045
  seenCallIds.add(item.call_id);
987
- const args = JSON.parse(item.arguments);
1046
+ let args;
1047
+ try {
1048
+ args = JSON.parse(item.arguments);
1049
+ } catch {
1050
+ throw invalidProviderResponse(
1051
+ "Responses function arguments must be valid JSON"
1052
+ );
1053
+ }
988
1054
  if (!args || typeof args !== "object" || Array.isArray(args))
989
- throw new Error(
1055
+ throw invalidProviderResponse(
990
1056
  "Responses function arguments must be a JSON object"
991
1057
  );
992
- return { id: item.call_id, name: item.name, args };
1058
+ return {
1059
+ id: item.call_id,
1060
+ name: item.name,
1061
+ args
1062
+ };
993
1063
  }) : [];
994
1064
  return {
995
1065
  content,
@@ -1232,7 +1302,9 @@ var OpenAIAdapter = class _OpenAIAdapter {
1232
1302
  const uniqueCalls = /* @__PURE__ */ new Map();
1233
1303
  for (const call of toolCalls.values()) {
1234
1304
  if (!call.id || !call.name)
1235
- throw new Error("Responses stream contains an incomplete tool call");
1305
+ throw invalidProviderResponse(
1306
+ "Responses stream contains an incomplete tool call"
1307
+ );
1236
1308
  uniqueCalls.set(call.id, call);
1237
1309
  }
1238
1310
  toolCalls.clear();
@@ -686,6 +686,54 @@ function responseMetadata(response) {
686
686
  }
687
687
  };
688
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
+ }
689
737
  function getResponseReplay(metadata) {
690
738
  const response = metadata?.openai?.response;
691
739
  if (response === void 0) return void 0;
@@ -694,10 +742,17 @@ function getResponseReplay(metadata) {
694
742
  "Invalid OpenAI Responses replay metadata: output must contain typed items"
695
743
  );
696
744
  }
697
- return response.output;
745
+ return responseReplayMetadata(metadata)?.openai?.response?.output;
698
746
  }
699
747
 
700
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
+ }
701
756
  function providerErrorEvent(error, code) {
702
757
  const details = error ?? {};
703
758
  const event = {
@@ -874,7 +929,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
874
929
  formatRawMessages(messages, preserveProviderMetadata = false) {
875
930
  return messages.map((message) => {
876
931
  const { attachments, providerMetadata, modelOutput, ...rest } = message;
877
- let content = message.role === "tool" && !preserveProviderMetadata ? textToolOutput(modelOutput, String(message.content ?? "")) : message.content;
932
+ let content = message.role === "tool" && !preserveProviderMetadata && modelOutput !== void 0 ? textToolOutput(modelOutput, "") : message.content;
878
933
  if (preserveProviderMetadata && modelOutput)
879
934
  rest.modelOutput = modelOutput;
880
935
  if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
@@ -977,17 +1032,32 @@ var OpenAIAdapter = class _OpenAIAdapter {
977
1032
  const seenCallIds = /* @__PURE__ */ new Set();
978
1033
  const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
979
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") {
980
- throw new Error("Responses contains an incomplete function call");
1035
+ throw invalidProviderResponse(
1036
+ "Responses contains an incomplete function call"
1037
+ );
981
1038
  }
982
1039
  if (seenCallIds.has(item.call_id))
983
- throw new Error("Responses contains duplicate function call IDs");
1040
+ throw invalidProviderResponse(
1041
+ "Responses contains duplicate function call IDs"
1042
+ );
984
1043
  seenCallIds.add(item.call_id);
985
- const args = JSON.parse(item.arguments);
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
+ }
986
1052
  if (!args || typeof args !== "object" || Array.isArray(args))
987
- throw new Error(
1053
+ throw invalidProviderResponse(
988
1054
  "Responses function arguments must be a JSON object"
989
1055
  );
990
- return { id: item.call_id, name: item.name, args };
1056
+ return {
1057
+ id: item.call_id,
1058
+ name: item.name,
1059
+ args
1060
+ };
991
1061
  }) : [];
992
1062
  return {
993
1063
  content,
@@ -1230,7 +1300,9 @@ var OpenAIAdapter = class _OpenAIAdapter {
1230
1300
  const uniqueCalls = /* @__PURE__ */ new Map();
1231
1301
  for (const call of toolCalls.values()) {
1232
1302
  if (!call.id || !call.name)
1233
- throw new Error("Responses stream contains an incomplete tool call");
1303
+ throw invalidProviderResponse(
1304
+ "Responses stream contains an incomplete tool call"
1305
+ );
1234
1306
  uniqueCalls.set(call.id, call);
1235
1307
  }
1236
1308
  toolCalls.clear();