@providerprotocol/ai 0.0.15 → 0.0.16

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.
@@ -1,4 +1,4 @@
1
- import { b as Provider, M as ModelReference, a as LLMHandler } from '../provider-Bi0nyNhA.js';
1
+ import { b as Provider, d as ModelReference, a as LLMHandler } from '../provider-vTZ74u-w.js';
2
2
 
3
3
  /**
4
4
  * OpenRouter-specific types for the Unified Provider Protocol.
@@ -53,6 +53,18 @@ interface OpenRouterCompletionsParams {
53
53
  parallel_tool_calls?: boolean;
54
54
  /** Response format for structured output */
55
55
  response_format?: OpenRouterResponseFormat;
56
+ /**
57
+ * Output modalities for multimodal generation.
58
+ * Set to `['text', 'image']` to enable image generation with compatible models.
59
+ * @see {@link https://openrouter.ai/docs/guides/overview/multimodal/image-generation}
60
+ */
61
+ modalities?: Array<'text' | 'image'>;
62
+ /**
63
+ * Image generation configuration for Gemini models.
64
+ * Only applies when `modalities` includes 'image'.
65
+ * @see {@link https://openrouter.ai/docs/guides/overview/multimodal/image-generation}
66
+ */
67
+ image_config?: OpenRouterImageConfig;
56
68
  /**
57
69
  * Prompt transforms to apply
58
70
  * See: https://openrouter.ai/docs/guides/features/message-transforms
@@ -87,6 +99,27 @@ interface OpenRouterCompletionsParams {
87
99
  echo_upstream_body?: boolean;
88
100
  };
89
101
  }
102
+ /**
103
+ * Image generation configuration for OpenRouter.
104
+ *
105
+ * Used with Gemini image generation models to control output dimensions.
106
+ *
107
+ * @see {@link https://openrouter.ai/docs/guides/overview/multimodal/image-generation}
108
+ */
109
+ interface OpenRouterImageConfig {
110
+ /**
111
+ * Aspect ratio for generated images.
112
+ * Supported values range from '1:1' (1024×1024) to '21:9' (1536×672).
113
+ */
114
+ aspect_ratio?: string;
115
+ /**
116
+ * Resolution level for generated images.
117
+ * - '1K': Standard resolution
118
+ * - '2K': Higher resolution
119
+ * - '4K': Highest resolution
120
+ */
121
+ image_size?: '1K' | '2K' | '4K';
122
+ }
90
123
  /**
91
124
  * Parameters for OpenRouter's Responses API (beta).
92
125
  *
@@ -111,6 +144,18 @@ interface OpenRouterResponsesParams {
111
144
  reasoning?: {
112
145
  effort?: 'low' | 'medium' | 'high';
113
146
  };
147
+ /**
148
+ * Output modalities for multimodal generation.
149
+ * Set to `['text', 'image']` to enable image generation with compatible models.
150
+ * @see {@link https://openrouter.ai/docs/guides/overview/multimodal/image-generation}
151
+ */
152
+ modalities?: Array<'text' | 'image'>;
153
+ /**
154
+ * Image generation configuration.
155
+ * Only applies when `modalities` includes 'image'.
156
+ * @see {@link https://openrouter.ai/docs/guides/overview/multimodal/image-generation}
157
+ */
158
+ image_config?: OpenRouterImageConfig;
114
159
  }
115
160
  /**
116
161
  * API mode selection for OpenRouter provider.
@@ -190,15 +190,23 @@ function transformResponse(data) {
190
190
  if (!choice) {
191
191
  throw new Error("No choices in OpenRouter response");
192
192
  }
193
- const textContent = [];
193
+ const content = [];
194
194
  let structuredData;
195
195
  if (choice.message.content) {
196
- textContent.push({ type: "text", text: choice.message.content });
196
+ content.push({ type: "text", text: choice.message.content });
197
197
  try {
198
198
  structuredData = JSON.parse(choice.message.content);
199
199
  } catch {
200
200
  }
201
201
  }
202
+ if (choice.message.images && choice.message.images.length > 0) {
203
+ for (const image of choice.message.images) {
204
+ const imageBlock = parseGeneratedImage(image.image_url.url);
205
+ if (imageBlock) {
206
+ content.push(imageBlock);
207
+ }
208
+ }
209
+ }
202
210
  const toolCalls = [];
203
211
  if (choice.message.tool_calls) {
204
212
  for (const call of choice.message.tool_calls) {
@@ -215,7 +223,7 @@ function transformResponse(data) {
215
223
  }
216
224
  }
217
225
  const message = new AssistantMessage(
218
- textContent,
226
+ content,
219
227
  toolCalls.length > 0 ? toolCalls : void 0,
220
228
  {
221
229
  id: data.id,
@@ -257,12 +265,28 @@ function transformResponse(data) {
257
265
  data: structuredData
258
266
  };
259
267
  }
268
+ function parseGeneratedImage(dataUrl) {
269
+ const match = dataUrl.match(/^data:(image\/[^;]+);base64,(.+)$/);
270
+ if (!match) {
271
+ return null;
272
+ }
273
+ const [, mimeType, data] = match;
274
+ if (!mimeType || !data) {
275
+ return null;
276
+ }
277
+ return {
278
+ type: "image",
279
+ mimeType,
280
+ source: { type: "base64", data }
281
+ };
282
+ }
260
283
  function createStreamState() {
261
284
  return {
262
285
  id: "",
263
286
  model: "",
264
287
  text: "",
265
288
  toolCalls: /* @__PURE__ */ new Map(),
289
+ images: [],
266
290
  finishReason: null,
267
291
  inputTokens: 0,
268
292
  outputTokens: 0,
@@ -316,6 +340,11 @@ function transformStreamEvent(chunk, state) {
316
340
  }
317
341
  }
318
342
  }
343
+ if (choice.delta.images) {
344
+ for (const image of choice.delta.images) {
345
+ state.images.push(image.image_url.url);
346
+ }
347
+ }
319
348
  if (choice.finish_reason) {
320
349
  state.finishReason = choice.finish_reason;
321
350
  events.push({ type: "message_stop", index: 0, delta: {} });
@@ -329,15 +358,21 @@ function transformStreamEvent(chunk, state) {
329
358
  return events;
330
359
  }
331
360
  function buildResponseFromState(state) {
332
- const textContent = [];
361
+ const content = [];
333
362
  let structuredData;
334
363
  if (state.text) {
335
- textContent.push({ type: "text", text: state.text });
364
+ content.push({ type: "text", text: state.text });
336
365
  try {
337
366
  structuredData = JSON.parse(state.text);
338
367
  } catch {
339
368
  }
340
369
  }
370
+ for (const imageUrl of state.images) {
371
+ const imageBlock = parseGeneratedImage(imageUrl);
372
+ if (imageBlock) {
373
+ content.push(imageBlock);
374
+ }
375
+ }
341
376
  const toolCalls = [];
342
377
  for (const [, toolCall] of state.toolCalls) {
343
378
  let args = {};
@@ -354,7 +389,7 @@ function buildResponseFromState(state) {
354
389
  });
355
390
  }
356
391
  const message = new AssistantMessage(
357
- textContent,
392
+ content,
358
393
  toolCalls.length > 0 ? toolCalls : void 0,
359
394
  {
360
395
  id: state.id,
@@ -403,6 +438,7 @@ var OPENROUTER_CAPABILITIES = {
403
438
  tools: true,
404
439
  structuredOutput: true,
405
440
  imageInput: true,
441
+ imageOutput: true,
406
442
  videoInput: false,
407
443
  audioInput: false
408
444
  };
@@ -742,7 +778,7 @@ function transformTool2(tool) {
742
778
  };
743
779
  }
744
780
  function transformResponse2(data) {
745
- const textContent = [];
781
+ const content = [];
746
782
  const toolCalls = [];
747
783
  const functionCallItems = [];
748
784
  let hadRefusal = false;
@@ -750,17 +786,17 @@ function transformResponse2(data) {
750
786
  for (const item of data.output) {
751
787
  if (item.type === "message") {
752
788
  const messageItem = item;
753
- for (const content of messageItem.content) {
754
- if (content.type === "output_text") {
755
- textContent.push({ type: "text", text: content.text });
789
+ for (const part of messageItem.content) {
790
+ if (part.type === "output_text") {
791
+ content.push({ type: "text", text: part.text });
756
792
  if (structuredData === void 0) {
757
793
  try {
758
- structuredData = JSON.parse(content.text);
794
+ structuredData = JSON.parse(part.text);
759
795
  } catch {
760
796
  }
761
797
  }
762
- } else if (content.type === "refusal") {
763
- textContent.push({ type: "text", text: content.refusal });
798
+ } else if (part.type === "refusal") {
799
+ content.push({ type: "text", text: part.refusal });
764
800
  hadRefusal = true;
765
801
  }
766
802
  }
@@ -782,10 +818,19 @@ function transformResponse2(data) {
782
818
  name: functionCall.name,
783
819
  arguments: functionCall.arguments
784
820
  });
821
+ } else if (item.type === "image_generation_call") {
822
+ const imageGen = item;
823
+ if (imageGen.result) {
824
+ content.push({
825
+ type: "image",
826
+ mimeType: "image/png",
827
+ source: { type: "base64", data: imageGen.result }
828
+ });
829
+ }
785
830
  }
786
831
  }
787
832
  const message = new AssistantMessage(
788
- textContent,
833
+ content,
789
834
  toolCalls.length > 0 ? toolCalls : void 0,
790
835
  {
791
836
  id: data.id,
@@ -831,6 +876,7 @@ function createStreamState2() {
831
876
  model: "",
832
877
  textByIndex: /* @__PURE__ */ new Map(),
833
878
  toolCalls: /* @__PURE__ */ new Map(),
879
+ images: /* @__PURE__ */ new Map(),
834
880
  status: "in_progress",
835
881
  inputTokens: 0,
836
882
  outputTokens: 0,
@@ -927,6 +973,11 @@ function transformStreamEvent2(event, state) {
927
973
  }
928
974
  }
929
975
  }
976
+ } else if (event.item.type === "image_generation_call") {
977
+ const imageGen = event.item;
978
+ if (imageGen.result) {
979
+ state.images.set(event.output_index, imageGen.result);
980
+ }
930
981
  }
931
982
  events.push({
932
983
  type: "content_block_stop",
@@ -1022,11 +1073,11 @@ function transformStreamEvent2(event, state) {
1022
1073
  return events;
1023
1074
  }
1024
1075
  function buildResponseFromState2(state) {
1025
- const textContent = [];
1076
+ const content = [];
1026
1077
  let structuredData;
1027
1078
  for (const [, text] of state.textByIndex) {
1028
1079
  if (text) {
1029
- textContent.push({ type: "text", text });
1080
+ content.push({ type: "text", text });
1030
1081
  if (structuredData === void 0) {
1031
1082
  try {
1032
1083
  structuredData = JSON.parse(text);
@@ -1035,6 +1086,15 @@ function buildResponseFromState2(state) {
1035
1086
  }
1036
1087
  }
1037
1088
  }
1089
+ for (const [, imageData] of state.images) {
1090
+ if (imageData) {
1091
+ content.push({
1092
+ type: "image",
1093
+ mimeType: "image/png",
1094
+ source: { type: "base64", data: imageData }
1095
+ });
1096
+ }
1097
+ }
1038
1098
  const toolCalls = [];
1039
1099
  const functionCallItems = [];
1040
1100
  for (const [, toolCall] of state.toolCalls) {
@@ -1063,7 +1123,7 @@ function buildResponseFromState2(state) {
1063
1123
  }
1064
1124
  }
1065
1125
  const message = new AssistantMessage(
1066
- textContent,
1126
+ content,
1067
1127
  toolCalls.length > 0 ? toolCalls : void 0,
1068
1128
  {
1069
1129
  id: state.id,
@@ -1109,6 +1169,7 @@ var OPENROUTER_CAPABILITIES2 = {
1109
1169
  tools: true,
1110
1170
  structuredOutput: true,
1111
1171
  imageInput: true,
1172
+ imageOutput: true,
1112
1173
  videoInput: false,
1113
1174
  audioInput: false
1114
1175
  };