@providerprotocol/ai 0.0.21 → 0.0.23

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 (53) hide show
  1. package/README.md +188 -6
  2. package/dist/anthropic/index.d.ts +1 -1
  3. package/dist/anthropic/index.js +115 -39
  4. package/dist/anthropic/index.js.map +1 -1
  5. package/dist/{chunk-Y3GBJNA2.js → chunk-55X3W2MN.js} +4 -3
  6. package/dist/chunk-55X3W2MN.js.map +1 -0
  7. package/dist/chunk-73IIE3QT.js +120 -0
  8. package/dist/chunk-73IIE3QT.js.map +1 -0
  9. package/dist/{chunk-M4BMM5IB.js → chunk-MF5ETY5O.js} +13 -4
  10. package/dist/chunk-MF5ETY5O.js.map +1 -0
  11. package/dist/{chunk-SKY2JLA7.js → chunk-MKDLXV4O.js} +1 -1
  12. package/dist/chunk-MKDLXV4O.js.map +1 -0
  13. package/dist/{chunk-Z7RBRCRN.js → chunk-NWS5IKNR.js} +37 -11
  14. package/dist/chunk-NWS5IKNR.js.map +1 -0
  15. package/dist/{chunk-EDENPF3E.js → chunk-QNJO7DSD.js} +152 -53
  16. package/dist/chunk-QNJO7DSD.js.map +1 -0
  17. package/dist/{chunk-Z4ILICF5.js → chunk-SBCATNHA.js} +43 -14
  18. package/dist/chunk-SBCATNHA.js.map +1 -0
  19. package/dist/chunk-Z6DKC37J.js +50 -0
  20. package/dist/chunk-Z6DKC37J.js.map +1 -0
  21. package/dist/google/index.d.ts +22 -7
  22. package/dist/google/index.js +286 -85
  23. package/dist/google/index.js.map +1 -1
  24. package/dist/http/index.d.ts +3 -3
  25. package/dist/http/index.js +4 -4
  26. package/dist/index.d.ts +10 -6
  27. package/dist/index.js +331 -204
  28. package/dist/index.js.map +1 -1
  29. package/dist/ollama/index.d.ts +5 -2
  30. package/dist/ollama/index.js +87 -28
  31. package/dist/ollama/index.js.map +1 -1
  32. package/dist/openai/index.d.ts +1 -1
  33. package/dist/openai/index.js +226 -81
  34. package/dist/openai/index.js.map +1 -1
  35. package/dist/openrouter/index.d.ts +1 -1
  36. package/dist/openrouter/index.js +199 -64
  37. package/dist/openrouter/index.js.map +1 -1
  38. package/dist/{provider-DGQHYE6I.d.ts → provider-DR1yins0.d.ts} +159 -53
  39. package/dist/proxy/index.d.ts +2 -2
  40. package/dist/proxy/index.js +178 -17
  41. package/dist/proxy/index.js.map +1 -1
  42. package/dist/{retry-Pcs3hnbu.d.ts → retry-DJiqAslw.d.ts} +11 -2
  43. package/dist/{stream-Di9acos2.d.ts → stream-BuTrqt_j.d.ts} +103 -41
  44. package/dist/xai/index.d.ts +1 -1
  45. package/dist/xai/index.js +189 -75
  46. package/dist/xai/index.js.map +1 -1
  47. package/package.json +1 -1
  48. package/dist/chunk-EDENPF3E.js.map +0 -1
  49. package/dist/chunk-M4BMM5IB.js.map +0 -1
  50. package/dist/chunk-SKY2JLA7.js.map +0 -1
  51. package/dist/chunk-Y3GBJNA2.js.map +0 -1
  52. package/dist/chunk-Z4ILICF5.js.map +0 -1
  53. package/dist/chunk-Z7RBRCRN.js.map +0 -1
@@ -1,25 +1,35 @@
1
1
  import {
2
2
  Image
3
3
  } from "../chunk-WAKD3OO5.js";
4
+ import {
5
+ parseJsonResponse
6
+ } from "../chunk-Z6DKC37J.js";
7
+ import {
8
+ StreamEventType
9
+ } from "../chunk-73IIE3QT.js";
4
10
  import {
5
11
  AssistantMessage,
6
12
  createProvider,
13
+ generateId,
7
14
  isAssistantMessage,
8
15
  isToolResultMessage,
9
16
  isUserMessage
10
- } from "../chunk-M4BMM5IB.js";
17
+ } from "../chunk-MF5ETY5O.js";
11
18
  import {
12
19
  parseSSEStream
13
- } from "../chunk-Z7RBRCRN.js";
20
+ } from "../chunk-NWS5IKNR.js";
14
21
  import {
15
22
  resolveApiKey
16
- } from "../chunk-Y3GBJNA2.js";
23
+ } from "../chunk-55X3W2MN.js";
17
24
  import {
25
+ ErrorCode,
26
+ ModalityType,
18
27
  UPPError,
19
28
  doFetch,
20
29
  doStreamFetch,
21
- normalizeHttpError
22
- } from "../chunk-EDENPF3E.js";
30
+ normalizeHttpError,
31
+ toError
32
+ } from "../chunk-QNJO7DSD.js";
23
33
 
24
34
  // src/providers/openai/transform.completions.ts
25
35
  function transformRequest(request, modelId) {
@@ -55,9 +65,40 @@ function transformRequest(request, modelId) {
55
65
  return openaiRequest;
56
66
  }
57
67
  function normalizeSystem(system) {
58
- if (!system) return void 0;
68
+ if (system === void 0 || system === null) return void 0;
59
69
  if (typeof system === "string") return system;
60
- return system.map((block) => block.text ?? "").filter((text) => text.length > 0).join("\n\n");
70
+ if (!Array.isArray(system)) {
71
+ throw new UPPError(
72
+ "System prompt must be a string or an array of text blocks",
73
+ ErrorCode.InvalidRequest,
74
+ "openai",
75
+ ModalityType.LLM
76
+ );
77
+ }
78
+ const texts = [];
79
+ for (const block of system) {
80
+ if (!block || typeof block !== "object" || !("text" in block)) {
81
+ throw new UPPError(
82
+ "System prompt array must contain objects with a text field",
83
+ ErrorCode.InvalidRequest,
84
+ "openai",
85
+ ModalityType.LLM
86
+ );
87
+ }
88
+ const textValue = block.text;
89
+ if (typeof textValue !== "string") {
90
+ throw new UPPError(
91
+ "System prompt text must be a string",
92
+ ErrorCode.InvalidRequest,
93
+ "openai",
94
+ ModalityType.LLM
95
+ );
96
+ }
97
+ if (textValue.length > 0) {
98
+ texts.push(textValue);
99
+ }
100
+ }
101
+ return texts.length > 0 ? texts.join("\n\n") : void 0;
61
102
  }
62
103
  function transformMessages(messages, system) {
63
104
  const result = [];
@@ -225,7 +266,7 @@ function transformResponse(data) {
225
266
  textContent,
226
267
  toolCalls.length > 0 ? toolCalls : void 0,
227
268
  {
228
- id: data.id,
269
+ id: data.id || generateId(),
229
270
  metadata: {
230
271
  openai: {
231
272
  model: data.model,
@@ -285,7 +326,7 @@ function transformStreamEvent(chunk, state) {
285
326
  const events = [];
286
327
  if (chunk.id && !state.id) {
287
328
  state.id = chunk.id;
288
- events.push({ type: "message_start", index: 0, delta: {} });
329
+ events.push({ type: StreamEventType.MessageStart, index: 0, delta: {} });
289
330
  }
290
331
  if (chunk.model) {
291
332
  state.model = chunk.model;
@@ -295,7 +336,7 @@ function transformStreamEvent(chunk, state) {
295
336
  if (choice.delta.content) {
296
337
  state.text += choice.delta.content;
297
338
  events.push({
298
- type: "text_delta",
339
+ type: StreamEventType.TextDelta,
299
340
  index: 0,
300
341
  delta: { text: choice.delta.content }
301
342
  });
@@ -304,7 +345,7 @@ function transformStreamEvent(chunk, state) {
304
345
  state.hadRefusal = true;
305
346
  state.text += choice.delta.refusal;
306
347
  events.push({
307
- type: "text_delta",
348
+ type: StreamEventType.TextDelta,
308
349
  index: 0,
309
350
  delta: { text: choice.delta.refusal }
310
351
  });
@@ -326,7 +367,7 @@ function transformStreamEvent(chunk, state) {
326
367
  if (toolCallDelta.function?.arguments) {
327
368
  toolCall.arguments += toolCallDelta.function.arguments;
328
369
  events.push({
329
- type: "tool_call_delta",
370
+ type: StreamEventType.ToolCallDelta,
330
371
  index,
331
372
  delta: {
332
373
  toolCallId: toolCall.id,
@@ -339,7 +380,7 @@ function transformStreamEvent(chunk, state) {
339
380
  }
340
381
  if (choice.finish_reason) {
341
382
  state.finishReason = choice.finish_reason;
342
- events.push({ type: "message_stop", index: 0, delta: {} });
383
+ events.push({ type: StreamEventType.MessageStop, index: 0, delta: {} });
343
384
  }
344
385
  }
345
386
  if (chunk.usage) {
@@ -374,11 +415,12 @@ function buildResponseFromState(state) {
374
415
  arguments: args
375
416
  });
376
417
  }
418
+ const messageId = state.id || generateId();
377
419
  const message = new AssistantMessage(
378
420
  textContent,
379
421
  toolCalls.length > 0 ? toolCalls : void 0,
380
422
  {
381
- id: state.id,
423
+ id: messageId,
382
424
  metadata: {
383
425
  openai: {
384
426
  model: state.model,
@@ -440,9 +482,9 @@ function createCompletionsLLMHandler() {
440
482
  if (!providerRef) {
441
483
  throw new UPPError(
442
484
  "Provider reference not set. Handler must be used with createProvider() or have _setProvider called.",
443
- "INVALID_REQUEST",
485
+ ErrorCode.InvalidRequest,
444
486
  "openai",
445
- "llm"
487
+ ModalityType.LLM
446
488
  );
447
489
  }
448
490
  const model = {
@@ -483,7 +525,7 @@ function createCompletionsLLMHandler() {
483
525
  "openai",
484
526
  "llm"
485
527
  );
486
- const data = await response.json();
528
+ const data = await parseJsonResponse(response, "openai", "llm");
487
529
  return transformResponse(data);
488
530
  },
489
531
  stream(request) {
@@ -508,7 +550,8 @@ function createCompletionsLLMHandler() {
508
550
  body.stream_options = { include_usage: true };
509
551
  const headers = {
510
552
  "Content-Type": "application/json",
511
- Authorization: `Bearer ${apiKey}`
553
+ Authorization: `Bearer ${apiKey}`,
554
+ Accept: "text/event-stream"
512
555
  };
513
556
  if (request.config.headers) {
514
557
  for (const [key, value] of Object.entries(request.config.headers)) {
@@ -537,9 +580,9 @@ function createCompletionsLLMHandler() {
537
580
  if (!response.body) {
538
581
  const error = new UPPError(
539
582
  "No response body for streaming request",
540
- "PROVIDER_ERROR",
583
+ ErrorCode.ProviderError,
541
584
  "openai",
542
- "llm"
585
+ ModalityType.LLM
543
586
  );
544
587
  responseReject(error);
545
588
  throw error;
@@ -554,9 +597,9 @@ function createCompletionsLLMHandler() {
554
597
  const errorData = chunk.error;
555
598
  const error = new UPPError(
556
599
  errorData.message ?? "Unknown error",
557
- "PROVIDER_ERROR",
600
+ ErrorCode.ProviderError,
558
601
  "openai",
559
- "llm"
602
+ ModalityType.LLM
560
603
  );
561
604
  responseReject(error);
562
605
  throw error;
@@ -569,8 +612,9 @@ function createCompletionsLLMHandler() {
569
612
  }
570
613
  responseResolve(buildResponseFromState(state));
571
614
  } catch (error) {
572
- responseReject(error);
573
- throw error;
615
+ const err = toError(error);
616
+ responseReject(err);
617
+ throw err;
574
618
  }
575
619
  }
576
620
  return {
@@ -626,9 +670,40 @@ function transformRequest2(request, modelId) {
626
670
  return openaiRequest;
627
671
  }
628
672
  function normalizeSystem2(system) {
629
- if (!system) return void 0;
673
+ if (system === void 0 || system === null) return void 0;
630
674
  if (typeof system === "string") return system;
631
- return system.map((block) => block.text ?? "").filter((text) => text.length > 0).join("\n\n");
675
+ if (!Array.isArray(system)) {
676
+ throw new UPPError(
677
+ "System prompt must be a string or an array of text blocks",
678
+ ErrorCode.InvalidRequest,
679
+ "openai",
680
+ ModalityType.LLM
681
+ );
682
+ }
683
+ const texts = [];
684
+ for (const block of system) {
685
+ if (!block || typeof block !== "object" || !("text" in block)) {
686
+ throw new UPPError(
687
+ "System prompt array must contain objects with a text field",
688
+ ErrorCode.InvalidRequest,
689
+ "openai",
690
+ ModalityType.LLM
691
+ );
692
+ }
693
+ const textValue = block.text;
694
+ if (typeof textValue !== "string") {
695
+ throw new UPPError(
696
+ "System prompt text must be a string",
697
+ ErrorCode.InvalidRequest,
698
+ "openai",
699
+ ModalityType.LLM
700
+ );
701
+ }
702
+ if (textValue.length > 0) {
703
+ texts.push(textValue);
704
+ }
705
+ }
706
+ return texts.length > 0 ? texts.join("\n\n") : void 0;
632
707
  }
633
708
  function transformInputItems(messages, system) {
634
709
  const result = [];
@@ -819,24 +894,26 @@ function transformResponse2(data) {
819
894
  } else if (item.type === "image_generation_call") {
820
895
  const imageGen = item;
821
896
  if (imageGen.result) {
897
+ const mimeType = imageGen.mime_type ?? "image/png";
822
898
  content.push({
823
899
  type: "image",
824
- mimeType: "image/png",
900
+ mimeType,
825
901
  source: { type: "base64", data: imageGen.result }
826
902
  });
827
903
  }
828
904
  }
829
905
  }
906
+ const responseId = data.id || generateId();
830
907
  const message = new AssistantMessage(
831
908
  content,
832
909
  toolCalls.length > 0 ? toolCalls : void 0,
833
910
  {
834
- id: data.id,
911
+ id: responseId,
835
912
  metadata: {
836
913
  openai: {
837
914
  model: data.model,
838
915
  status: data.status,
839
- response_id: data.id,
916
+ response_id: responseId,
840
917
  functionCallItems: functionCallItems.length > 0 ? functionCallItems : void 0
841
918
  }
842
919
  }
@@ -875,6 +952,7 @@ function createStreamState2() {
875
952
  toolCalls: /* @__PURE__ */ new Map(),
876
953
  images: [],
877
954
  status: "in_progress",
955
+ incompleteReason: void 0,
878
956
  inputTokens: 0,
879
957
  outputTokens: 0,
880
958
  cacheReadTokens: 0,
@@ -883,27 +961,36 @@ function createStreamState2() {
883
961
  }
884
962
  function transformStreamEvent2(event, state) {
885
963
  const events = [];
964
+ const updateFromResponse = (response) => {
965
+ state.id = response.id || state.id;
966
+ state.model = response.model || state.model;
967
+ state.status = response.status;
968
+ if (response.incomplete_details?.reason) {
969
+ state.incompleteReason = response.incomplete_details.reason;
970
+ } else if (response.status !== "incomplete") {
971
+ state.incompleteReason = void 0;
972
+ }
973
+ if (response.usage) {
974
+ state.inputTokens = response.usage.input_tokens;
975
+ state.outputTokens = response.usage.output_tokens;
976
+ state.cacheReadTokens = response.usage.input_tokens_details?.cached_tokens ?? 0;
977
+ }
978
+ };
886
979
  switch (event.type) {
887
980
  case "response.created":
888
- state.id = event.response.id;
889
- state.model = event.response.model;
890
- events.push({ type: "message_start", index: 0, delta: {} });
981
+ updateFromResponse(event.response);
982
+ events.push({ type: StreamEventType.MessageStart, index: 0, delta: {} });
891
983
  break;
892
984
  case "response.in_progress":
893
- state.status = "in_progress";
985
+ updateFromResponse(event.response);
894
986
  break;
895
987
  case "response.completed":
896
- state.status = "completed";
897
- if (event.response.usage) {
898
- state.inputTokens = event.response.usage.input_tokens;
899
- state.outputTokens = event.response.usage.output_tokens;
900
- state.cacheReadTokens = event.response.usage.input_tokens_details?.cached_tokens ?? 0;
901
- }
902
- events.push({ type: "message_stop", index: 0, delta: {} });
988
+ updateFromResponse(event.response);
989
+ events.push({ type: StreamEventType.MessageStop, index: 0, delta: {} });
903
990
  break;
904
991
  case "response.failed":
905
- state.status = "failed";
906
- events.push({ type: "message_stop", index: 0, delta: {} });
992
+ updateFromResponse(event.response);
993
+ events.push({ type: StreamEventType.MessageStop, index: 0, delta: {} });
907
994
  break;
908
995
  case "response.output_item.added":
909
996
  if (event.item.type === "function_call") {
@@ -920,7 +1007,7 @@ function transformStreamEvent2(event, state) {
920
1007
  state.toolCalls.set(event.output_index, existing);
921
1008
  }
922
1009
  events.push({
923
- type: "content_block_start",
1010
+ type: StreamEventType.ContentBlockStart,
924
1011
  index: event.output_index,
925
1012
  delta: {}
926
1013
  });
@@ -941,11 +1028,14 @@ function transformStreamEvent2(event, state) {
941
1028
  } else if (event.item.type === "image_generation_call") {
942
1029
  const imageGen = event.item;
943
1030
  if (imageGen.result) {
944
- state.images.push(imageGen.result);
1031
+ state.images.push({
1032
+ data: imageGen.result,
1033
+ mimeType: imageGen.mime_type ?? "image/png"
1034
+ });
945
1035
  }
946
1036
  }
947
1037
  events.push({
948
- type: "content_block_stop",
1038
+ type: StreamEventType.ContentBlockStop,
949
1039
  index: event.output_index,
950
1040
  delta: {}
951
1041
  });
@@ -954,7 +1044,7 @@ function transformStreamEvent2(event, state) {
954
1044
  const currentText = state.textByIndex.get(event.output_index) ?? "";
955
1045
  state.textByIndex.set(event.output_index, currentText + event.delta);
956
1046
  events.push({
957
- type: "text_delta",
1047
+ type: StreamEventType.TextDelta,
958
1048
  index: event.output_index,
959
1049
  delta: { text: event.delta }
960
1050
  });
@@ -968,7 +1058,7 @@ function transformStreamEvent2(event, state) {
968
1058
  const currentRefusal = state.textByIndex.get(event.output_index) ?? "";
969
1059
  state.textByIndex.set(event.output_index, currentRefusal + event.delta);
970
1060
  events.push({
971
- type: "text_delta",
1061
+ type: StreamEventType.TextDelta,
972
1062
  index: event.output_index,
973
1063
  delta: { text: event.delta }
974
1064
  });
@@ -992,7 +1082,7 @@ function transformStreamEvent2(event, state) {
992
1082
  }
993
1083
  toolCall.arguments += event.delta;
994
1084
  events.push({
995
- type: "tool_call_delta",
1085
+ type: StreamEventType.ToolCallDelta,
996
1086
  index: event.output_index,
997
1087
  delta: {
998
1088
  toolCallId: toolCall.callId ?? toolCall.itemId ?? "",
@@ -1028,7 +1118,10 @@ function transformStreamEvent2(event, state) {
1028
1118
  function buildResponseFromState2(state) {
1029
1119
  const content = [];
1030
1120
  let structuredData;
1031
- for (const [, text] of state.textByIndex) {
1121
+ const orderedTextEntries = [...state.textByIndex.entries()].sort(
1122
+ ([leftIndex], [rightIndex]) => leftIndex - rightIndex
1123
+ );
1124
+ for (const [, text] of orderedTextEntries) {
1032
1125
  if (text) {
1033
1126
  content.push({ type: "text", text });
1034
1127
  if (structuredData === void 0) {
@@ -1042,13 +1135,16 @@ function buildResponseFromState2(state) {
1042
1135
  for (const imageData of state.images) {
1043
1136
  content.push({
1044
1137
  type: "image",
1045
- mimeType: "image/png",
1046
- source: { type: "base64", data: imageData }
1138
+ mimeType: imageData.mimeType,
1139
+ source: { type: "base64", data: imageData.data }
1047
1140
  });
1048
1141
  }
1049
1142
  const toolCalls = [];
1050
1143
  const functionCallItems = [];
1051
- for (const [, toolCall] of state.toolCalls) {
1144
+ const orderedToolEntries = [...state.toolCalls.entries()].sort(
1145
+ ([leftIndex], [rightIndex]) => leftIndex - rightIndex
1146
+ );
1147
+ for (const [, toolCall] of orderedToolEntries) {
1052
1148
  let args = {};
1053
1149
  if (toolCall.arguments) {
1054
1150
  try {
@@ -1059,6 +1155,9 @@ function buildResponseFromState2(state) {
1059
1155
  const itemId = toolCall.itemId ?? "";
1060
1156
  const callId = toolCall.callId ?? toolCall.itemId ?? "";
1061
1157
  const name = toolCall.name ?? "";
1158
+ if (!name || !callId) {
1159
+ continue;
1160
+ }
1062
1161
  toolCalls.push({
1063
1162
  toolCallId: callId,
1064
1163
  toolName: name,
@@ -1073,16 +1172,17 @@ function buildResponseFromState2(state) {
1073
1172
  });
1074
1173
  }
1075
1174
  }
1175
+ const responseId = state.id || generateId();
1076
1176
  const message = new AssistantMessage(
1077
1177
  content,
1078
1178
  toolCalls.length > 0 ? toolCalls : void 0,
1079
1179
  {
1080
- id: state.id,
1180
+ id: responseId,
1081
1181
  metadata: {
1082
1182
  openai: {
1083
1183
  model: state.model,
1084
1184
  status: state.status,
1085
- response_id: state.id,
1185
+ response_id: responseId,
1086
1186
  functionCallItems: functionCallItems.length > 0 ? functionCallItems : void 0
1087
1187
  }
1088
1188
  }
@@ -1098,6 +1198,8 @@ function buildResponseFromState2(state) {
1098
1198
  let stopReason = "end_turn";
1099
1199
  if (state.status === "completed") {
1100
1200
  stopReason = toolCalls.length > 0 ? "tool_use" : "end_turn";
1201
+ } else if (state.status === "incomplete") {
1202
+ stopReason = state.incompleteReason === "max_output_tokens" ? "max_tokens" : "end_turn";
1101
1203
  } else if (state.status === "failed") {
1102
1204
  stopReason = "error";
1103
1205
  }
@@ -1132,9 +1234,9 @@ function createResponsesLLMHandler() {
1132
1234
  if (!providerRef) {
1133
1235
  throw new UPPError(
1134
1236
  "Provider reference not set. Handler must be used with createProvider() or have _setProvider called.",
1135
- "INVALID_REQUEST",
1237
+ ErrorCode.InvalidRequest,
1136
1238
  "openai",
1137
- "llm"
1239
+ ModalityType.LLM
1138
1240
  );
1139
1241
  }
1140
1242
  const model = {
@@ -1175,13 +1277,13 @@ function createResponsesLLMHandler() {
1175
1277
  "openai",
1176
1278
  "llm"
1177
1279
  );
1178
- const data = await response.json();
1280
+ const data = await parseJsonResponse(response, "openai", "llm");
1179
1281
  if (data.status === "failed" && data.error) {
1180
1282
  throw new UPPError(
1181
1283
  data.error.message,
1182
- "PROVIDER_ERROR",
1284
+ ErrorCode.ProviderError,
1183
1285
  "openai",
1184
- "llm"
1286
+ ModalityType.LLM
1185
1287
  );
1186
1288
  }
1187
1289
  return transformResponse2(data);
@@ -1207,7 +1309,8 @@ function createResponsesLLMHandler() {
1207
1309
  body.stream = true;
1208
1310
  const headers = {
1209
1311
  "Content-Type": "application/json",
1210
- Authorization: `Bearer ${apiKey}`
1312
+ Authorization: `Bearer ${apiKey}`,
1313
+ Accept: "text/event-stream"
1211
1314
  };
1212
1315
  if (request.config.headers) {
1213
1316
  for (const [key, value] of Object.entries(request.config.headers)) {
@@ -1236,9 +1339,9 @@ function createResponsesLLMHandler() {
1236
1339
  if (!response.body) {
1237
1340
  const error = new UPPError(
1238
1341
  "No response body for streaming request",
1239
- "PROVIDER_ERROR",
1342
+ ErrorCode.ProviderError,
1240
1343
  "openai",
1241
- "llm"
1344
+ ModalityType.LLM
1242
1345
  );
1243
1346
  responseReject(error);
1244
1347
  throw error;
@@ -1253,9 +1356,9 @@ function createResponsesLLMHandler() {
1253
1356
  const errorEvent = event;
1254
1357
  const error = new UPPError(
1255
1358
  errorEvent.error.message,
1256
- "PROVIDER_ERROR",
1359
+ ErrorCode.ProviderError,
1257
1360
  "openai",
1258
- "llm"
1361
+ ModalityType.LLM
1259
1362
  );
1260
1363
  responseReject(error);
1261
1364
  throw error;
@@ -1268,8 +1371,9 @@ function createResponsesLLMHandler() {
1268
1371
  }
1269
1372
  responseResolve(buildResponseFromState2(state));
1270
1373
  } catch (error) {
1271
- responseReject(error);
1272
- throw error;
1374
+ const err = toError(error);
1375
+ responseReject(err);
1376
+ throw err;
1273
1377
  }
1274
1378
  }
1275
1379
  return {
@@ -1307,9 +1411,9 @@ function createEmbeddingHandler() {
1307
1411
  if (!providerRef) {
1308
1412
  throw new UPPError(
1309
1413
  "Provider reference not set. Handler must be used with createProvider().",
1310
- "INVALID_REQUEST",
1414
+ ErrorCode.InvalidRequest,
1311
1415
  "openai",
1312
- "embedding"
1416
+ ModalityType.Embedding
1313
1417
  );
1314
1418
  }
1315
1419
  const model = {
@@ -1337,9 +1441,9 @@ function createEmbeddingHandler() {
1337
1441
  }
1338
1442
  throw new UPPError(
1339
1443
  "OpenAI embeddings only support text input",
1340
- "INVALID_REQUEST",
1444
+ ErrorCode.InvalidRequest,
1341
1445
  "openai",
1342
- "embedding"
1446
+ ModalityType.Embedding
1343
1447
  );
1344
1448
  });
1345
1449
  const body = {
@@ -1364,7 +1468,7 @@ function createEmbeddingHandler() {
1364
1468
  body: JSON.stringify(body),
1365
1469
  signal: request.signal
1366
1470
  }, request.config, "openai", "embedding");
1367
- const data = await response.json();
1471
+ const data = await parseJsonResponse(response, "openai", "embedding");
1368
1472
  return {
1369
1473
  embeddings: data.data.map((d) => ({
1370
1474
  vector: d.embedding,
@@ -1402,9 +1506,9 @@ function createImageHandler() {
1402
1506
  if (!providerRef) {
1403
1507
  throw new UPPError(
1404
1508
  "Provider reference not set. Handler must be used with createProvider().",
1405
- "INVALID_REQUEST",
1509
+ ErrorCode.InvalidRequest,
1406
1510
  "openai",
1407
- "image"
1511
+ ModalityType.Image
1408
1512
  );
1409
1513
  }
1410
1514
  const capabilities = getCapabilities(modelId);
@@ -1460,7 +1564,7 @@ async function executeGenerate(modelId, request) {
1460
1564
  body: JSON.stringify(body),
1461
1565
  signal: request.signal
1462
1566
  }, request.config, "openai", "image");
1463
- const data = await response.json();
1567
+ const data = await parseJsonResponse(response, "openai", "image");
1464
1568
  return transformResponse3(data);
1465
1569
  }
1466
1570
  async function executeEdit(modelId, request) {
@@ -1505,7 +1609,7 @@ async function executeEdit(modelId, request) {
1505
1609
  body: formData,
1506
1610
  signal: request.signal
1507
1611
  }, request.config, "openai", "image");
1508
- const data = await response.json();
1612
+ const data = await parseJsonResponse(response, "openai", "image");
1509
1613
  return transformResponse3(data);
1510
1614
  }
1511
1615
  function executeStream(modelId, request) {
@@ -1554,9 +1658,9 @@ function executeStream(modelId, request) {
1554
1658
  if (!reader) {
1555
1659
  throw new UPPError(
1556
1660
  "No response body for streaming",
1557
- "PROVIDER_ERROR",
1661
+ ErrorCode.ProviderError,
1558
1662
  "openai",
1559
- "image"
1663
+ ModalityType.Image
1560
1664
  );
1561
1665
  }
1562
1666
  const decoder = new TextDecoder();
@@ -1604,6 +1708,46 @@ function executeStream(modelId, request) {
1604
1708
  }
1605
1709
  }
1606
1710
  }
1711
+ const remaining = decoder.decode();
1712
+ if (remaining) {
1713
+ buffer += remaining;
1714
+ const lines = buffer.split("\n");
1715
+ buffer = lines.pop() ?? "";
1716
+ for (const line of lines) {
1717
+ if (line.startsWith("data: ")) {
1718
+ const data = line.slice(6);
1719
+ if (data === "[DONE]") {
1720
+ continue;
1721
+ }
1722
+ try {
1723
+ const chunk = JSON.parse(data);
1724
+ if (chunk.type === "image_generation.partial_image" && chunk.data?.b64_json) {
1725
+ const previewImage = Image.fromBase64(chunk.data.b64_json, "image/png");
1726
+ yield {
1727
+ type: "preview",
1728
+ image: previewImage,
1729
+ index: chunk.index ?? 0
1730
+ };
1731
+ } else if (chunk.type === "image_generation.completed" && chunk.data) {
1732
+ const image = chunk.data.b64_json ? Image.fromBase64(chunk.data.b64_json, "image/png") : Image.fromUrl(chunk.data.url ?? "", "image/png");
1733
+ const genImage = {
1734
+ image,
1735
+ metadata: chunk.data.revised_prompt ? { revised_prompt: chunk.data.revised_prompt } : void 0
1736
+ };
1737
+ generatedImages.push(genImage);
1738
+ yield {
1739
+ type: "complete",
1740
+ image: genImage,
1741
+ index: chunk.index ?? generatedImages.length - 1
1742
+ };
1743
+ } else if (chunk.type === "response.done") {
1744
+ responseMetadata = chunk.data;
1745
+ }
1746
+ } catch {
1747
+ }
1748
+ }
1749
+ }
1750
+ }
1607
1751
  resolveResponse({
1608
1752
  images: generatedImages,
1609
1753
  metadata: responseMetadata,
@@ -1612,8 +1756,9 @@ function executeStream(modelId, request) {
1612
1756
  }
1613
1757
  });
1614
1758
  } catch (error) {
1615
- rejectResponse(error);
1616
- throw error;
1759
+ const err = toError(error);
1760
+ rejectResponse(err);
1761
+ throw err;
1617
1762
  }
1618
1763
  }
1619
1764
  const generator = generateStream();
@@ -1632,9 +1777,9 @@ function transformResponse3(data) {
1632
1777
  } else {
1633
1778
  throw new UPPError(
1634
1779
  "No image data in response",
1635
- "PROVIDER_ERROR",
1780
+ ErrorCode.ProviderError,
1636
1781
  "openai",
1637
- "image"
1782
+ ModalityType.Image
1638
1783
  );
1639
1784
  }
1640
1785
  return {