@ljoukov/llm 7.0.15 → 7.0.17

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.
package/README.md CHANGED
@@ -209,9 +209,10 @@ console.log(OPENAI_GPT_IMAGE_2_SIZE_CONSTRAINTS);
209
209
  console.log(images[0]?.mimeType, images[0]?.data.byteLength);
210
210
  ```
211
211
 
212
- `generateImages()` is typed as a discriminated union by `model`: `gpt-image-2` requests use
213
- `imageResolution`, while Gemini image requests use `imageSize` (`"1K" | "2K" | "4K"`). For
214
- `gpt-image-2`, `OPENAI_GPT_IMAGE_2_RESOLUTIONS` exposes the documented popular presets plus
212
+ `generateImages()` is typed as a discriminated union by `model`: `gpt-image-2` and
213
+ `chatgpt-gpt-image-2` requests use `imageResolution`, while Gemini image requests use `imageSize`
214
+ (`"1K" | "2K" | "4K"`). For GPT Image 2, `OPENAI_GPT_IMAGE_2_RESOLUTIONS` exposes the documented
215
+ popular presets plus
215
216
  `"auto"`; custom literal `WIDTHxHEIGHT` resolutions are also accepted when they satisfy
216
217
  `OPENAI_GPT_IMAGE_2_SIZE_CONSTRAINTS`: each edge must be at most 3840px, each edge must be a
217
218
  multiple of 16px, the long edge must be at most 3:1 relative to the short edge, and total pixels
@@ -226,14 +227,20 @@ const images = await generateImages({
226
227
  model: "chatgpt-gpt-image-2",
227
228
  stylePrompt: "Warm amber desk light, deep blue night, cinematic laboratory mood.",
228
229
  imagePrompts: ["A compact lab bench still life with glassware and an open notebook"],
230
+ imageResolution: "1024x1536",
231
+ imageQuality: "high",
232
+ outputFormat: "jpeg",
233
+ outputCompression: 50,
234
+ action: "generate",
229
235
  numImages: 1,
230
236
  });
231
237
  ```
232
238
 
233
239
  That path reuses the same ChatGPT auth setup as other `chatgpt-*` models and sends the request
234
- through the ChatGPT/Codex Responses `image_generation` built-in tool. It returns PNG images. The
235
- public Images API controls such as `imageResolution`, `imageQuality`, `outputFormat`, and
236
- `outputCompression` are intentionally only on the `gpt-image-2` request type.
240
+ through the ChatGPT/Codex Responses `image_generation` built-in tool. `imageResolution`,
241
+ `imageQuality`, `outputFormat`, `outputCompression`, `background`, `moderation`, and `action` are
242
+ passed as tool options. `numImages` is implemented as repeated one-image tool calls because the
243
+ ChatGPT/Codex tool rejects `n` on `tools[0]`.
237
244
 
238
245
  ### Streaming (response + thoughts + usage)
239
246
 
package/dist/index.cjs CHANGED
@@ -5334,6 +5334,8 @@ function resolveOpenAiReasoningEffort(modelId, thinkingLevel) {
5334
5334
  case "medium":
5335
5335
  return "medium";
5336
5336
  case "high":
5337
+ return "high";
5338
+ case "xhigh":
5337
5339
  return "xhigh";
5338
5340
  }
5339
5341
  }
@@ -5351,7 +5353,7 @@ function toOpenAiReasoningEffort(effort) {
5351
5353
  case "high":
5352
5354
  return "high";
5353
5355
  case "xhigh":
5354
- return "high";
5356
+ return "xhigh";
5355
5357
  }
5356
5358
  }
5357
5359
  function resolveOpenAiVerbosity(modelId) {
@@ -7644,6 +7646,7 @@ function toGeminiThinkingLevel(thinkingLevel) {
7644
7646
  case "medium":
7645
7647
  return import_genai2.ThinkingLevel.MEDIUM;
7646
7648
  case "high":
7649
+ case "xhigh":
7647
7650
  return import_genai2.ThinkingLevel.HIGH;
7648
7651
  }
7649
7652
  }
@@ -7686,6 +7689,7 @@ function resolveGeminiThinkingBudget(modelId, thinkingLevel) {
7686
7689
  case "medium":
7687
7690
  return 4096;
7688
7691
  case "high":
7692
+ case "xhigh":
7689
7693
  return 32768;
7690
7694
  }
7691
7695
  }
@@ -7696,6 +7700,7 @@ function resolveGeminiThinkingBudget(modelId, thinkingLevel) {
7696
7700
  case "medium":
7697
7701
  return 8192;
7698
7702
  case "high":
7703
+ case "xhigh":
7699
7704
  return 24576;
7700
7705
  }
7701
7706
  }
@@ -7706,6 +7711,7 @@ function resolveGeminiThinkingBudget(modelId, thinkingLevel) {
7706
7711
  case "medium":
7707
7712
  return 8192;
7708
7713
  case "high":
7714
+ case "xhigh":
7709
7715
  return 16384;
7710
7716
  }
7711
7717
  }
@@ -10578,7 +10584,7 @@ function buildOpenAiImagePrompt(params) {
10578
10584
  params.imagePrompt.trim()
10579
10585
  ].filter((line) => line.length > 0).join("\n");
10580
10586
  }
10581
- function resolveOpenAiImageRequestParams(request) {
10587
+ function resolveGptImage2RequestParams(request) {
10582
10588
  if (request.partialImages !== void 0) {
10583
10589
  throw new Error("partialImages is only supported for streaming image generation.");
10584
10590
  }
@@ -10592,7 +10598,7 @@ function resolveOpenAiImageRequestParams(request) {
10592
10598
  const sizeValidation = validateOpenAiGptImage2Resolution(size);
10593
10599
  if (!sizeValidation.valid) {
10594
10600
  throw new Error(
10595
- `imageResolution ${JSON.stringify(size)} is not supported by gpt-image-2: ${sizeValidation.reason}`
10601
+ `imageResolution ${JSON.stringify(size)} is not supported by ${request.model}: ${sizeValidation.reason}`
10596
10602
  );
10597
10603
  }
10598
10604
  return {
@@ -10635,7 +10641,7 @@ async function generateImagesWithOpenAiImageApi(request) {
10635
10641
  model: request.model
10636
10642
  });
10637
10643
  const startedAtMs = Date.now();
10638
- const params = resolveOpenAiImageRequestParams(request);
10644
+ const params = resolveGptImage2RequestParams(request);
10639
10645
  const styleImages = await createOpenAiStyleImageFiles(request.styleImages);
10640
10646
  const hasStyleImages = Boolean(styleImages && styleImages.length > 0);
10641
10647
  const outputMimeType = resolveOpenAiImageMimeType(params.outputFormat);
@@ -10763,7 +10769,8 @@ async function generateImagesWithChatGptImageTool(request) {
10763
10769
  model: request.model
10764
10770
  });
10765
10771
  const startedAtMs = Date.now();
10766
- const numImagesPerPrompt = request.numImages ?? 1;
10772
+ const params = resolveGptImage2RequestParams(request);
10773
+ const outputMimeType = resolveOpenAiImageMimeType(params.outputFormat);
10767
10774
  let totalUsage;
10768
10775
  let costUsd = 0;
10769
10776
  let outputImages = 0;
@@ -10771,7 +10778,7 @@ async function generateImagesWithChatGptImageTool(request) {
10771
10778
  type: "llm.call.started",
10772
10779
  imagePromptCount: promptEntries.length,
10773
10780
  styleImageCount: request.styleImages?.length ?? 0,
10774
- numImagesPerPrompt
10781
+ numImagesPerPrompt: params.n
10775
10782
  });
10776
10783
  try {
10777
10784
  const images = [];
@@ -10781,7 +10788,7 @@ async function generateImagesWithChatGptImageTool(request) {
10781
10788
  imagePrompt,
10782
10789
  hasStyleImages: Boolean(request.styleImages && request.styleImages.length > 0)
10783
10790
  });
10784
- for (let imageIndex = 0; imageIndex < numImagesPerPrompt; imageIndex += 1) {
10791
+ for (let imageIndex = 0; imageIndex < params.n; imageIndex += 1) {
10785
10792
  const chatGptInput = toChatGptInput(
10786
10793
  buildChatGptImageInputContent({
10787
10794
  prompt,
@@ -10798,11 +10805,22 @@ async function generateImagesWithChatGptImageTool(request) {
10798
10805
  model: providerInfo.model,
10799
10806
  store: false,
10800
10807
  stream: true,
10801
- instructions: chatGptInput.instructions ?? "Use the image_generation tool to generate exactly one PNG image. Do not return prose instead of the image.",
10808
+ instructions: chatGptInput.instructions ?? "Use the image_generation tool to generate exactly one image. Do not return prose instead of the image.",
10802
10809
  input: preparedInput,
10803
10810
  tool_choice: "required",
10804
10811
  parallel_tool_calls: false,
10805
- tools: [{ type: "image_generation", output_format: "png" }]
10812
+ tools: [
10813
+ {
10814
+ type: "image_generation",
10815
+ size: params.size,
10816
+ quality: params.quality,
10817
+ output_format: params.outputFormat ?? "png",
10818
+ ...request.outputCompression !== void 0 ? { output_compression: request.outputCompression } : {},
10819
+ ...params.background ? { background: params.background } : {},
10820
+ ...params.moderation ? { moderation: params.moderation } : {},
10821
+ ...request.action ? { action: request.action } : {}
10822
+ }
10823
+ ]
10806
10824
  },
10807
10825
  signal: request.signal
10808
10826
  });
@@ -10814,7 +10832,7 @@ async function generateImagesWithChatGptImageTool(request) {
10814
10832
  }
10815
10833
  for (const call of result.imageGenerationCalls) {
10816
10834
  images.push({
10817
- mimeType: "image/png",
10835
+ mimeType: outputMimeType,
10818
10836
  data: import_node_buffer4.Buffer.from(call.result, "base64")
10819
10837
  });
10820
10838
  }
@@ -10825,8 +10843,8 @@ async function generateImagesWithChatGptImageTool(request) {
10825
10843
  modelId: request.model,
10826
10844
  tokens: usage,
10827
10845
  responseImages: result.imageGenerationCalls.length,
10828
- imageSize: "1024x1024",
10829
- imageQuality: "medium"
10846
+ imageSize: params.size,
10847
+ imageQuality: params.quality
10830
10848
  });
10831
10849
  }
10832
10850
  }
@@ -10838,7 +10856,7 @@ async function generateImagesWithChatGptImageTool(request) {
10838
10856
  usage: totalUsage,
10839
10857
  costUsd,
10840
10858
  imageCount: images.length,
10841
- attempts: promptEntries.length * numImagesPerPrompt
10859
+ attempts: promptEntries.length * params.n
10842
10860
  });
10843
10861
  return images;
10844
10862
  } catch (error) {