@ljoukov/llm 7.0.16 → 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
@@ -10584,7 +10584,7 @@ function buildOpenAiImagePrompt(params) {
10584
10584
  params.imagePrompt.trim()
10585
10585
  ].filter((line) => line.length > 0).join("\n");
10586
10586
  }
10587
- function resolveOpenAiImageRequestParams(request) {
10587
+ function resolveGptImage2RequestParams(request) {
10588
10588
  if (request.partialImages !== void 0) {
10589
10589
  throw new Error("partialImages is only supported for streaming image generation.");
10590
10590
  }
@@ -10598,7 +10598,7 @@ function resolveOpenAiImageRequestParams(request) {
10598
10598
  const sizeValidation = validateOpenAiGptImage2Resolution(size);
10599
10599
  if (!sizeValidation.valid) {
10600
10600
  throw new Error(
10601
- `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}`
10602
10602
  );
10603
10603
  }
10604
10604
  return {
@@ -10641,7 +10641,7 @@ async function generateImagesWithOpenAiImageApi(request) {
10641
10641
  model: request.model
10642
10642
  });
10643
10643
  const startedAtMs = Date.now();
10644
- const params = resolveOpenAiImageRequestParams(request);
10644
+ const params = resolveGptImage2RequestParams(request);
10645
10645
  const styleImages = await createOpenAiStyleImageFiles(request.styleImages);
10646
10646
  const hasStyleImages = Boolean(styleImages && styleImages.length > 0);
10647
10647
  const outputMimeType = resolveOpenAiImageMimeType(params.outputFormat);
@@ -10769,7 +10769,8 @@ async function generateImagesWithChatGptImageTool(request) {
10769
10769
  model: request.model
10770
10770
  });
10771
10771
  const startedAtMs = Date.now();
10772
- const numImagesPerPrompt = request.numImages ?? 1;
10772
+ const params = resolveGptImage2RequestParams(request);
10773
+ const outputMimeType = resolveOpenAiImageMimeType(params.outputFormat);
10773
10774
  let totalUsage;
10774
10775
  let costUsd = 0;
10775
10776
  let outputImages = 0;
@@ -10777,7 +10778,7 @@ async function generateImagesWithChatGptImageTool(request) {
10777
10778
  type: "llm.call.started",
10778
10779
  imagePromptCount: promptEntries.length,
10779
10780
  styleImageCount: request.styleImages?.length ?? 0,
10780
- numImagesPerPrompt
10781
+ numImagesPerPrompt: params.n
10781
10782
  });
10782
10783
  try {
10783
10784
  const images = [];
@@ -10787,7 +10788,7 @@ async function generateImagesWithChatGptImageTool(request) {
10787
10788
  imagePrompt,
10788
10789
  hasStyleImages: Boolean(request.styleImages && request.styleImages.length > 0)
10789
10790
  });
10790
- for (let imageIndex = 0; imageIndex < numImagesPerPrompt; imageIndex += 1) {
10791
+ for (let imageIndex = 0; imageIndex < params.n; imageIndex += 1) {
10791
10792
  const chatGptInput = toChatGptInput(
10792
10793
  buildChatGptImageInputContent({
10793
10794
  prompt,
@@ -10804,11 +10805,22 @@ async function generateImagesWithChatGptImageTool(request) {
10804
10805
  model: providerInfo.model,
10805
10806
  store: false,
10806
10807
  stream: true,
10807
- 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.",
10808
10809
  input: preparedInput,
10809
10810
  tool_choice: "required",
10810
10811
  parallel_tool_calls: false,
10811
- 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
+ ]
10812
10824
  },
10813
10825
  signal: request.signal
10814
10826
  });
@@ -10820,7 +10832,7 @@ async function generateImagesWithChatGptImageTool(request) {
10820
10832
  }
10821
10833
  for (const call of result.imageGenerationCalls) {
10822
10834
  images.push({
10823
- mimeType: "image/png",
10835
+ mimeType: outputMimeType,
10824
10836
  data: import_node_buffer4.Buffer.from(call.result, "base64")
10825
10837
  });
10826
10838
  }
@@ -10831,8 +10843,8 @@ async function generateImagesWithChatGptImageTool(request) {
10831
10843
  modelId: request.model,
10832
10844
  tokens: usage,
10833
10845
  responseImages: result.imageGenerationCalls.length,
10834
- imageSize: "1024x1024",
10835
- imageQuality: "medium"
10846
+ imageSize: params.size,
10847
+ imageQuality: params.quality
10836
10848
  });
10837
10849
  }
10838
10850
  }
@@ -10844,7 +10856,7 @@ async function generateImagesWithChatGptImageTool(request) {
10844
10856
  usage: totalUsage,
10845
10857
  costUsd,
10846
10858
  imageCount: images.length,
10847
- attempts: promptEntries.length * numImagesPerPrompt
10859
+ attempts: promptEntries.length * params.n
10848
10860
  });
10849
10861
  return images;
10850
10862
  } catch (error) {