@ljoukov/llm 7.0.11 → 7.0.13

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/dist/index.cjs CHANGED
@@ -50,6 +50,17 @@ __export(index_exports, {
50
50
  LLM_MODEL_IDS: () => LLM_MODEL_IDS,
51
51
  LLM_TEXT_MODEL_IDS: () => LLM_TEXT_MODEL_IDS,
52
52
  LlmJsonCallError: () => LlmJsonCallError,
53
+ OPENAI_GPT_IMAGE_2_AUTO_RESOLUTION: () => OPENAI_GPT_IMAGE_2_AUTO_RESOLUTION,
54
+ OPENAI_GPT_IMAGE_2_BACKGROUNDS: () => OPENAI_GPT_IMAGE_2_BACKGROUNDS,
55
+ OPENAI_GPT_IMAGE_2_MODERATION_LEVELS: () => OPENAI_GPT_IMAGE_2_MODERATION_LEVELS,
56
+ OPENAI_GPT_IMAGE_2_NUM_IMAGES: () => OPENAI_GPT_IMAGE_2_NUM_IMAGES,
57
+ OPENAI_GPT_IMAGE_2_OUTPUT_FORMATS: () => OPENAI_GPT_IMAGE_2_OUTPUT_FORMATS,
58
+ OPENAI_GPT_IMAGE_2_PARTIAL_IMAGE_COUNTS: () => OPENAI_GPT_IMAGE_2_PARTIAL_IMAGE_COUNTS,
59
+ OPENAI_GPT_IMAGE_2_POPULAR_RESOLUTIONS: () => OPENAI_GPT_IMAGE_2_POPULAR_RESOLUTIONS,
60
+ OPENAI_GPT_IMAGE_2_QUALITY_LEVELS: () => OPENAI_GPT_IMAGE_2_QUALITY_LEVELS,
61
+ OPENAI_GPT_IMAGE_2_RESOLUTIONS: () => OPENAI_GPT_IMAGE_2_RESOLUTIONS,
62
+ OPENAI_GPT_IMAGE_2_SIZE_CONSTRAINTS: () => OPENAI_GPT_IMAGE_2_SIZE_CONSTRAINTS,
63
+ OPENAI_IMAGE_MODEL_IDS: () => OPENAI_IMAGE_MODEL_IDS,
53
64
  OPENAI_MODEL_IDS: () => OPENAI_MODEL_IDS,
54
65
  appendMarkdownSourcesSection: () => appendMarkdownSourcesSection,
55
66
  applyPatch: () => applyPatch,
@@ -99,6 +110,7 @@ __export(index_exports, {
99
110
  isLlmImageModelId: () => isLlmImageModelId,
100
111
  isLlmModelId: () => isLlmModelId,
101
112
  isLlmTextModelId: () => isLlmTextModelId,
113
+ isOpenAiImageModelId: () => isOpenAiImageModelId,
102
114
  isOpenAiModelId: () => isOpenAiModelId,
103
115
  loadEnvFromFile: () => loadEnvFromFile,
104
116
  loadLocalEnv: () => loadLocalEnv,
@@ -118,7 +130,8 @@ __export(index_exports, {
118
130
  streamToolLoop: () => streamToolLoop,
119
131
  stripCodexCitationMarkers: () => stripCodexCitationMarkers,
120
132
  toGeminiJsonSchema: () => toGeminiJsonSchema,
121
- tool: () => tool
133
+ tool: () => tool,
134
+ validateOpenAiGptImage2Resolution: () => validateOpenAiGptImage2Resolution
122
135
  });
123
136
  module.exports = __toCommonJS(index_exports);
124
137
 
@@ -130,6 +143,7 @@ var import_node_path5 = __toESM(require("path"), 1);
130
143
  var import_genai2 = require("@google/genai");
131
144
  var import_zod_to_json_schema = require("@alcyone-labs/zod-to-json-schema");
132
145
  var import_zod3 = require("zod");
146
+ var import_openai3 = require("openai");
133
147
 
134
148
  // src/utils/asyncQueue.ts
135
149
  function createAsyncQueue() {
@@ -331,6 +345,81 @@ var OPENAI_MODEL_IDS = [
331
345
  function isOpenAiModelId(value) {
332
346
  return OPENAI_MODEL_IDS.includes(value);
333
347
  }
348
+ var OPENAI_IMAGE_MODEL_IDS = ["gpt-image-2"];
349
+ function isOpenAiImageModelId(value) {
350
+ return OPENAI_IMAGE_MODEL_IDS.includes(value);
351
+ }
352
+ var OPENAI_GPT_IMAGE_2_POPULAR_RESOLUTIONS = [
353
+ "1024x1024",
354
+ "1536x1024",
355
+ "1024x1536",
356
+ "2048x2048",
357
+ "2048x1152",
358
+ "3840x2160",
359
+ "2160x3840"
360
+ ];
361
+ var OPENAI_GPT_IMAGE_2_AUTO_RESOLUTION = "auto";
362
+ var OPENAI_GPT_IMAGE_2_RESOLUTIONS = [
363
+ ...OPENAI_GPT_IMAGE_2_POPULAR_RESOLUTIONS,
364
+ OPENAI_GPT_IMAGE_2_AUTO_RESOLUTION
365
+ ];
366
+ var OPENAI_GPT_IMAGE_2_SIZE_CONSTRAINTS = {
367
+ maxEdgePixels: 3840,
368
+ edgeMultiplePixels: 16,
369
+ maxLongToShortEdgeRatio: 3,
370
+ minTotalPixels: 655360,
371
+ maxTotalPixels: 8294400,
372
+ experimentalTotalPixelsThreshold: 3686400
373
+ };
374
+ function validateOpenAiGptImage2Resolution(value) {
375
+ if (value === OPENAI_GPT_IMAGE_2_AUTO_RESOLUTION) {
376
+ return { valid: true };
377
+ }
378
+ const match = /^([1-9]\d*)x([1-9]\d*)$/.exec(value);
379
+ if (!match) {
380
+ return { valid: false, reason: 'Expected "auto" or a WIDTHxHEIGHT pixel string.' };
381
+ }
382
+ const width = Number(match[1]);
383
+ const height = Number(match[2]);
384
+ if (!Number.isSafeInteger(width) || !Number.isSafeInteger(height)) {
385
+ return { valid: false, reason: "Width and height must be safe integer pixel counts." };
386
+ }
387
+ const constraints = OPENAI_GPT_IMAGE_2_SIZE_CONSTRAINTS;
388
+ if (width > constraints.maxEdgePixels || height > constraints.maxEdgePixels) {
389
+ return {
390
+ valid: false,
391
+ reason: `Width and height must each be at most ${constraints.maxEdgePixels}px.`
392
+ };
393
+ }
394
+ if (width % constraints.edgeMultiplePixels !== 0 || height % constraints.edgeMultiplePixels !== 0) {
395
+ return {
396
+ valid: false,
397
+ reason: `Width and height must each be multiples of ${constraints.edgeMultiplePixels}px.`
398
+ };
399
+ }
400
+ const totalPixels = width * height;
401
+ if (totalPixels < constraints.minTotalPixels || totalPixels > constraints.maxTotalPixels) {
402
+ return {
403
+ valid: false,
404
+ reason: `Total pixels must be between ${constraints.minTotalPixels} and ${constraints.maxTotalPixels}.`
405
+ };
406
+ }
407
+ const longEdge = Math.max(width, height);
408
+ const shortEdge = Math.min(width, height);
409
+ if (longEdge / shortEdge > constraints.maxLongToShortEdgeRatio) {
410
+ return {
411
+ valid: false,
412
+ reason: `The long edge must be at most ${constraints.maxLongToShortEdgeRatio}:1 relative to the short edge.`
413
+ };
414
+ }
415
+ return { valid: true };
416
+ }
417
+ var OPENAI_GPT_IMAGE_2_QUALITY_LEVELS = ["low", "medium", "high", "auto"];
418
+ var OPENAI_GPT_IMAGE_2_OUTPUT_FORMATS = ["png", "jpeg", "webp"];
419
+ var OPENAI_GPT_IMAGE_2_BACKGROUNDS = ["opaque", "auto"];
420
+ var OPENAI_GPT_IMAGE_2_MODERATION_LEVELS = ["low", "auto"];
421
+ var OPENAI_GPT_IMAGE_2_PARTIAL_IMAGE_COUNTS = [0, 1, 2, 3];
422
+ var OPENAI_GPT_IMAGE_2_NUM_IMAGES = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
334
423
  var CHATGPT_MODEL_IDS = [
335
424
  "chatgpt-gpt-5.5",
336
425
  "chatgpt-gpt-5.5-fast",
@@ -413,6 +502,27 @@ var OPENAI_GPT_54_NANO_PRICING = {
413
502
  cachedRate: 5e-3 / 1e6,
414
503
  outputRate: 0.4 / 1e6
415
504
  };
505
+ var OPENAI_GPT_IMAGE_2_PRICING = {
506
+ defaultQuality: "medium",
507
+ defaultResolution: "1024x1024",
508
+ imagePrices: {
509
+ low: {
510
+ "1024x1024": 6e-3,
511
+ "1024x1536": 5e-3,
512
+ "1536x1024": 5e-3
513
+ },
514
+ medium: {
515
+ "1024x1024": 0.053,
516
+ "1024x1536": 0.041,
517
+ "1536x1024": 0.041
518
+ },
519
+ high: {
520
+ "1024x1024": 0.211,
521
+ "1024x1536": 0.165,
522
+ "1536x1024": 0.165
523
+ }
524
+ }
525
+ };
416
526
  function getOpenAiPricing(modelId) {
417
527
  if (isExperimentalChatGptModelId(modelId)) {
418
528
  return OPENAI_GPT_54_PRICING;
@@ -440,6 +550,9 @@ function getOpenAiPricing(modelId) {
440
550
  }
441
551
  return void 0;
442
552
  }
553
+ function getOpenAiImagePricing(modelId) {
554
+ return isOpenAiImageModelId(modelId) ? OPENAI_GPT_IMAGE_2_PRICING : void 0;
555
+ }
443
556
 
444
557
  // src/utils/cost.ts
445
558
  function resolveUsageNumber(value) {
@@ -452,8 +565,18 @@ function estimateCallCostUsd({
452
565
  modelId,
453
566
  tokens,
454
567
  responseImages,
455
- imageSize
568
+ imageSize,
569
+ imageQuality
456
570
  }) {
571
+ const openAiImagePricing = getOpenAiImagePricing(modelId);
572
+ if (openAiImagePricing) {
573
+ return estimateOpenAiImageCostUsd({
574
+ pricing: openAiImagePricing,
575
+ responseImages,
576
+ imageSize,
577
+ imageQuality
578
+ });
579
+ }
457
580
  if (!tokens) {
458
581
  return 0;
459
582
  }
@@ -515,6 +638,40 @@ function estimateCallCostUsd({
515
638
  }
516
639
  return 0;
517
640
  }
641
+ function estimateOpenAiImageCostUsd({
642
+ pricing,
643
+ responseImages,
644
+ imageSize,
645
+ imageQuality
646
+ }) {
647
+ if (responseImages <= 0) {
648
+ return 0;
649
+ }
650
+ const quality = imageQuality === "low" || imageQuality === "medium" || imageQuality === "high" ? imageQuality : pricing.defaultQuality;
651
+ const resolution = resolveOpenAiImagePriceResolution(imageSize) ?? pricing.defaultResolution;
652
+ return responseImages * pricing.imagePrices[quality][resolution];
653
+ }
654
+ function resolveOpenAiImagePriceResolution(imageSize) {
655
+ if (imageSize === "1024x1024" || imageSize === "1024x1536" || imageSize === "1536x1024") {
656
+ return imageSize;
657
+ }
658
+ if (!imageSize || imageSize === "auto") {
659
+ return void 0;
660
+ }
661
+ const match = /^(\d+)x(\d+)$/.exec(imageSize);
662
+ if (!match) {
663
+ return void 0;
664
+ }
665
+ const width = Number(match[1]);
666
+ const height = Number(match[2]);
667
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
668
+ return void 0;
669
+ }
670
+ if (width === height) {
671
+ return "1024x1024";
672
+ }
673
+ return width > height ? "1536x1024" : "1024x1536";
674
+ }
518
675
 
519
676
  // src/openai/chatgpt-codex.ts
520
677
  var import_node_os2 = __toESM(require("os"), 1);
@@ -4495,13 +4652,13 @@ var LLM_TEXT_MODEL_IDS = [
4495
4652
  ...FIREWORKS_MODEL_IDS,
4496
4653
  ...GEMINI_TEXT_MODEL_IDS
4497
4654
  ];
4498
- var LLM_IMAGE_MODEL_IDS = [...GEMINI_IMAGE_MODEL_IDS];
4655
+ var LLM_IMAGE_MODEL_IDS = [...OPENAI_IMAGE_MODEL_IDS, ...GEMINI_IMAGE_MODEL_IDS];
4499
4656
  var LLM_MODEL_IDS = [...LLM_TEXT_MODEL_IDS, ...LLM_IMAGE_MODEL_IDS];
4500
4657
  function isLlmTextModelId(value) {
4501
4658
  return isOpenAiModelId(value) || isChatGptModelId(value) || isFireworksModelId(value) || isGeminiTextModelId(value);
4502
4659
  }
4503
4660
  function isLlmImageModelId(value) {
4504
- return isGeminiImageModelId(value);
4661
+ return isOpenAiImageModelId(value) || isGeminiImageModelId(value);
4505
4662
  }
4506
4663
  function isLlmModelId(value) {
4507
4664
  return isLlmTextModelId(value) || isLlmImageModelId(value);
@@ -4513,6 +4670,9 @@ var LlmJsonCallError = class extends Error {
4513
4670
  this.name = "LlmJsonCallError";
4514
4671
  }
4515
4672
  };
4673
+ function isOpenAiGenerateImagesRequest(request) {
4674
+ return isOpenAiImageModelId(request.model);
4675
+ }
4516
4676
  function tool(options) {
4517
4677
  return {
4518
4678
  type: "function",
@@ -5103,6 +5263,9 @@ function resolveProvider(model) {
5103
5263
  return { provider: "fireworks", model: fireworksModel };
5104
5264
  }
5105
5265
  }
5266
+ if (isOpenAiImageModelId(model)) {
5267
+ return { provider: "openai", model };
5268
+ }
5106
5269
  if (isOpenAiModelId(model)) {
5107
5270
  return {
5108
5271
  provider: "openai",
@@ -5110,7 +5273,7 @@ function resolveProvider(model) {
5110
5273
  serviceTier: resolveOpenAiServiceTier(model)
5111
5274
  };
5112
5275
  }
5113
- throw new Error(`Unsupported text model: ${model}`);
5276
+ throw new Error(`Unsupported model: ${model}`);
5114
5277
  }
5115
5278
  function isOpenAiCodexModel(modelId) {
5116
5279
  return modelId.includes("codex");
@@ -6197,12 +6360,40 @@ function toGeminiTools(tools) {
6197
6360
  return { googleSearch: {} };
6198
6361
  case "code-execution":
6199
6362
  return { codeExecution: {} };
6363
+ case "shell":
6364
+ throw new Error("Gemini provider does not support the OpenAI shell tool.");
6200
6365
  default:
6201
6366
  throw new Error("Unsupported tool configuration");
6202
6367
  }
6203
6368
  });
6204
6369
  }
6205
- function toOpenAiTools(tools) {
6370
+ function toOpenAiShellEnvironment(environment) {
6371
+ if (environment?.type === "container-reference") {
6372
+ return {
6373
+ type: "container_reference",
6374
+ container_id: environment.containerId
6375
+ };
6376
+ }
6377
+ return {
6378
+ type: "container_auto",
6379
+ ...environment?.fileIds ? { file_ids: Array.from(environment.fileIds) } : {},
6380
+ ...environment?.memoryLimit !== void 0 ? { memory_limit: environment.memoryLimit } : {},
6381
+ ...environment?.networkPolicy ? {
6382
+ network_policy: environment.networkPolicy.type === "allowlist" ? {
6383
+ type: "allowlist",
6384
+ allowed_domains: Array.from(environment.networkPolicy.allowedDomains),
6385
+ ...environment.networkPolicy.domainSecrets ? {
6386
+ domain_secrets: environment.networkPolicy.domainSecrets.map((secret) => ({
6387
+ domain: secret.domain,
6388
+ name: secret.name,
6389
+ value: secret.value
6390
+ }))
6391
+ } : {}
6392
+ } : { type: "disabled" }
6393
+ } : {}
6394
+ };
6395
+ }
6396
+ function toOpenAiTools(tools, options) {
6206
6397
  if (!tools || tools.length === 0) {
6207
6398
  return void 0;
6208
6399
  }
@@ -6215,6 +6406,15 @@ function toOpenAiTools(tools) {
6215
6406
  case "code-execution": {
6216
6407
  return { type: "code_interpreter", container: { type: "auto" } };
6217
6408
  }
6409
+ case "shell": {
6410
+ if (options.provider !== "openai") {
6411
+ throw new Error("OpenAI shell tool is only supported for OpenAI API models.");
6412
+ }
6413
+ return {
6414
+ type: "shell",
6415
+ environment: toOpenAiShellEnvironment(tool2.environment)
6416
+ };
6417
+ }
6218
6418
  default:
6219
6419
  throw new Error("Unsupported tool configuration");
6220
6420
  }
@@ -6229,8 +6429,11 @@ function mergeTokenUpdates(current, next) {
6229
6429
  }
6230
6430
  return {
6231
6431
  promptTokens: next.promptTokens ?? current.promptTokens,
6432
+ promptTextTokens: next.promptTextTokens ?? current.promptTextTokens,
6433
+ promptImageTokens: next.promptImageTokens ?? current.promptImageTokens,
6232
6434
  cachedTokens: next.cachedTokens ?? current.cachedTokens,
6233
6435
  responseTokens: next.responseTokens ?? current.responseTokens,
6436
+ responseTextTokens: next.responseTextTokens ?? current.responseTextTokens,
6234
6437
  responseImageTokens: next.responseImageTokens ?? current.responseImageTokens,
6235
6438
  thinkingTokens: next.thinkingTokens ?? current.thinkingTokens,
6236
6439
  totalTokens: next.totalTokens ?? current.totalTokens,
@@ -6253,8 +6456,11 @@ function sumUsageTokens(current, next) {
6253
6456
  }
6254
6457
  return {
6255
6458
  promptTokens: sumUsageValue(current?.promptTokens, next.promptTokens),
6459
+ promptTextTokens: sumUsageValue(current?.promptTextTokens, next.promptTextTokens),
6460
+ promptImageTokens: sumUsageValue(current?.promptImageTokens, next.promptImageTokens),
6256
6461
  cachedTokens: sumUsageValue(current?.cachedTokens, next.cachedTokens),
6257
6462
  responseTokens: sumUsageValue(current?.responseTokens, next.responseTokens),
6463
+ responseTextTokens: sumUsageValue(current?.responseTextTokens, next.responseTextTokens),
6258
6464
  responseImageTokens: sumUsageValue(current?.responseImageTokens, next.responseImageTokens),
6259
6465
  thinkingTokens: sumUsageValue(current?.thinkingTokens, next.thinkingTokens),
6260
6466
  totalTokens: sumUsageValue(current?.totalTokens, next.totalTokens),
@@ -6369,10 +6575,22 @@ function extractOpenAiUsageTokens(usage) {
6369
6575
  const cachedTokens = toMaybeNumber(
6370
6576
  usage.input_tokens_details?.cached_tokens
6371
6577
  );
6578
+ const promptTextTokens = toMaybeNumber(
6579
+ usage.input_tokens_details?.text_tokens
6580
+ );
6581
+ const promptImageTokens = toMaybeNumber(
6582
+ usage.input_tokens_details?.image_tokens
6583
+ );
6372
6584
  const outputTokensRaw = toMaybeNumber(usage.output_tokens);
6373
6585
  const reasoningTokens = toMaybeNumber(
6374
6586
  usage.output_tokens_details?.reasoning_tokens
6375
6587
  );
6588
+ const responseTextTokens = toMaybeNumber(
6589
+ usage.output_tokens_details?.text_tokens
6590
+ );
6591
+ const responseImageTokens = toMaybeNumber(
6592
+ usage.output_tokens_details?.image_tokens
6593
+ );
6376
6594
  const totalTokens = toMaybeNumber(usage.total_tokens);
6377
6595
  let responseTokens;
6378
6596
  if (outputTokensRaw !== void 0) {
@@ -6384,8 +6602,12 @@ function extractOpenAiUsageTokens(usage) {
6384
6602
  }
6385
6603
  return {
6386
6604
  promptTokens,
6605
+ promptTextTokens,
6606
+ promptImageTokens,
6387
6607
  cachedTokens,
6388
6608
  responseTokens,
6609
+ responseTextTokens,
6610
+ responseImageTokens,
6389
6611
  thinkingTokens: reasoningTokens,
6390
6612
  totalTokens
6391
6613
  };
@@ -7813,6 +8035,8 @@ async function runTextCall(params) {
7813
8035
  let responseRole;
7814
8036
  let latestUsage;
7815
8037
  let responseImages = 0;
8038
+ let sawResponseDelta = false;
8039
+ let sawThoughtDelta = false;
7816
8040
  const pushEvent = (event) => {
7817
8041
  queue.push(event);
7818
8042
  params.onEvent?.(event);
@@ -7823,8 +8047,10 @@ async function runTextCall(params) {
7823
8047
  }
7824
8048
  responseParts.push({ type: "text", text, ...channel === "thought" ? { thought: true } : {} });
7825
8049
  if (channel === "thought") {
8050
+ sawThoughtDelta = true;
7826
8051
  callLogger?.appendThoughtDelta(text);
7827
8052
  } else {
8053
+ sawResponseDelta = true;
7828
8054
  callLogger?.appendResponseDelta(text);
7829
8055
  }
7830
8056
  pushEvent({ type: "delta", channel, text });
@@ -7857,6 +8083,9 @@ async function runTextCall(params) {
7857
8083
  const { result } = await collectFileUploadMetrics(async () => {
7858
8084
  try {
7859
8085
  if (provider === "openai") {
8086
+ if (isOpenAiImageModelId(request.model)) {
8087
+ throw new Error("gpt-image-2 is an image generation model; use generateImages().");
8088
+ }
7860
8089
  const openAiInput = await maybePrepareOpenAiPromptInput(
7861
8090
  toOpenAiInput(contents, {
7862
8091
  defaultMediaResolution: request.mediaResolution,
@@ -7864,7 +8093,7 @@ async function runTextCall(params) {
7864
8093
  }),
7865
8094
  { model: request.model, provider: "openai" }
7866
8095
  );
7867
- const openAiTools = toOpenAiTools(request.tools);
8096
+ const openAiTools = toOpenAiTools(request.tools, { provider: "openai" });
7868
8097
  const reasoningEffort = resolveOpenAiReasoningEffort(
7869
8098
  modelForProvider,
7870
8099
  request.thinkingLevel
@@ -7925,12 +8154,17 @@ async function runTextCall(params) {
7925
8154
  );
7926
8155
  }
7927
8156
  latestUsage = extractOpenAiUsageTokens(finalResponse.usage);
7928
- if (responseParts.length === 0) {
8157
+ if (!sawResponseDelta || !sawThoughtDelta) {
8158
+ const needsResponseFallback = !sawResponseDelta;
8159
+ const needsThoughtFallback = !sawThoughtDelta;
7929
8160
  const fallback = extractOpenAiResponseParts(finalResponse);
7930
8161
  blocked = blocked || fallback.blocked;
7931
8162
  for (const part of fallback.parts) {
7932
8163
  if (part.type === "text") {
7933
- pushDelta(part.thought === true ? "thought" : "response", part.text);
8164
+ const channel = part.thought === true ? "thought" : "response";
8165
+ if (channel === "response" && needsResponseFallback || channel === "thought" && needsThoughtFallback) {
8166
+ pushDelta(channel, part.text);
8167
+ }
7934
8168
  } else if (part.type === "inlineData") {
7935
8169
  pushInline(part.data, part.mimeType);
7936
8170
  }
@@ -7947,7 +8181,7 @@ async function runTextCall(params) {
7947
8181
  provider: "chatgpt"
7948
8182
  });
7949
8183
  const reasoningEffort = resolveOpenAiReasoningEffort(request.model, request.thinkingLevel);
7950
- const openAiTools = toOpenAiTools(request.tools);
8184
+ const openAiTools = toOpenAiTools(request.tools, { provider: "chatgpt" });
7951
8185
  const requestPayload = {
7952
8186
  model: modelForProvider,
7953
8187
  store: false,
@@ -7966,18 +8200,18 @@ async function runTextCall(params) {
7966
8200
  },
7967
8201
  ...openAiTools ? { tools: openAiTools } : {}
7968
8202
  };
7969
- let sawResponseDelta = false;
7970
- let sawThoughtDelta = false;
8203
+ let sawResponseDelta2 = false;
8204
+ let sawThoughtDelta2 = false;
7971
8205
  const result2 = await collectChatGptCodexResponseWithRetry({
7972
8206
  request: requestPayload,
7973
8207
  signal,
7974
8208
  onDelta: (delta) => {
7975
8209
  if (delta.thoughtDelta) {
7976
- sawThoughtDelta = true;
8210
+ sawThoughtDelta2 = true;
7977
8211
  pushDelta("thought", delta.thoughtDelta);
7978
8212
  }
7979
8213
  if (delta.textDelta) {
7980
- sawResponseDelta = true;
8214
+ sawResponseDelta2 = true;
7981
8215
  pushDelta("response", delta.textDelta);
7982
8216
  }
7983
8217
  }
@@ -7993,10 +8227,10 @@ async function runTextCall(params) {
7993
8227
  latestUsage = extractChatGptUsageTokens(result2.usage);
7994
8228
  const fallbackText = typeof result2.text === "string" ? result2.text : "";
7995
8229
  const fallbackThoughts = typeof result2.reasoningSummaryText === "string" && result2.reasoningSummaryText.length > 0 ? result2.reasoningSummaryText : typeof result2.reasoningText === "string" ? result2.reasoningText : "";
7996
- if (!sawThoughtDelta && fallbackThoughts.length > 0) {
8230
+ if (!sawThoughtDelta2 && fallbackThoughts.length > 0) {
7997
8231
  pushDelta("thought", fallbackThoughts);
7998
8232
  }
7999
- if (!sawResponseDelta && fallbackText.length > 0) {
8233
+ if (!sawResponseDelta2 && fallbackText.length > 0) {
8000
8234
  pushDelta("response", fallbackText);
8001
8235
  }
8002
8236
  } else if (provider === "fireworks") {
@@ -8716,7 +8950,7 @@ async function runToolLoop(request) {
8716
8950
  try {
8717
8951
  if (providerInfo.provider === "openai") {
8718
8952
  const openAiAgentTools = buildOpenAiToolsFromToolSet(request.tools);
8719
- const openAiNativeTools = toOpenAiTools(request.modelTools);
8953
+ const openAiNativeTools = toOpenAiTools(request.modelTools, { provider: "openai" });
8720
8954
  const openAiTools = openAiNativeTools ? [...openAiNativeTools, ...openAiAgentTools] : [...openAiAgentTools];
8721
8955
  const reasoningEffort = resolveOpenAiReasoningEffort(
8722
8956
  providerInfo.model,
@@ -9119,7 +9353,7 @@ async function runToolLoop(request) {
9119
9353
  }
9120
9354
  if (providerInfo.provider === "chatgpt") {
9121
9355
  const openAiAgentTools = buildOpenAiToolsFromToolSet(request.tools);
9122
- const openAiNativeTools = toOpenAiTools(request.modelTools);
9356
+ const openAiNativeTools = toOpenAiTools(request.modelTools, { provider: "chatgpt" });
9123
9357
  const openAiTools = openAiNativeTools ? [...openAiNativeTools, ...openAiAgentTools] : [...openAiAgentTools];
9124
9358
  const reasoningEffort = resolveOpenAiReasoningEffort(request.model, request.thinkingLevel);
9125
9359
  const toolLoopInput = toChatGptInput(contents, {
@@ -10217,7 +10451,184 @@ async function gradeGeneratedImage(params) {
10217
10451
  });
10218
10452
  return { grade: value.grade, result };
10219
10453
  }
10454
+ function resolveOpenAiImageMimeType(outputFormat) {
10455
+ switch (outputFormat) {
10456
+ case "jpeg":
10457
+ return "image/jpeg";
10458
+ case "webp":
10459
+ return "image/webp";
10460
+ case "png":
10461
+ case void 0:
10462
+ return "image/png";
10463
+ }
10464
+ }
10465
+ function buildOpenAiImagePrompt(params) {
10466
+ return [
10467
+ "Follow the requested visual style.",
10468
+ "",
10469
+ "Style:",
10470
+ params.stylePrompt.trim(),
10471
+ ...params.hasStyleImages ? [
10472
+ "",
10473
+ "Use the attached reference image or images for palette, lighting, mood, composition, and material feel."
10474
+ ] : [],
10475
+ "",
10476
+ "Image:",
10477
+ params.imagePrompt.trim()
10478
+ ].filter((line) => line.length > 0).join("\n");
10479
+ }
10480
+ function resolveOpenAiImageRequestParams(request) {
10481
+ if (request.partialImages !== void 0) {
10482
+ throw new Error("partialImages is only supported for streaming image generation.");
10483
+ }
10484
+ if (request.outputCompression !== void 0 && (!Number.isInteger(request.outputCompression) || request.outputCompression < 0 || request.outputCompression > 100)) {
10485
+ throw new Error("outputCompression must be an integer from 0 to 100.");
10486
+ }
10487
+ if (request.outputCompression !== void 0 && request.outputFormat !== "jpeg" && request.outputFormat !== "webp") {
10488
+ throw new Error("outputCompression requires outputFormat to be jpeg or webp.");
10489
+ }
10490
+ const size = request.imageResolution ?? "auto";
10491
+ const sizeValidation = validateOpenAiGptImage2Resolution(size);
10492
+ if (!sizeValidation.valid) {
10493
+ throw new Error(
10494
+ `imageResolution ${JSON.stringify(size)} is not supported by gpt-image-2: ${sizeValidation.reason}`
10495
+ );
10496
+ }
10497
+ return {
10498
+ size,
10499
+ quality: request.imageQuality ?? "auto",
10500
+ outputFormat: request.outputFormat,
10501
+ n: request.numImages ?? 1,
10502
+ background: request.background,
10503
+ moderation: request.moderation
10504
+ };
10505
+ }
10506
+ async function createOpenAiStyleImageFiles(styleImages) {
10507
+ if (!styleImages || styleImages.length === 0) {
10508
+ return void 0;
10509
+ }
10510
+ return await Promise.all(
10511
+ styleImages.map(async (image, index) => {
10512
+ const mimeType = image.mimeType ?? "image/png";
10513
+ const extension = resolveAttachmentExtension(mimeType);
10514
+ return await (0, import_openai3.toFile)(image.data, `style-${index + 1}.${extension}`, { type: mimeType });
10515
+ })
10516
+ );
10517
+ }
10518
+ async function generateImagesWithOpenAiImageApi(request) {
10519
+ const promptEntries = Array.from(request.imagePrompts, (rawPrompt, index) => {
10520
+ const prompt = rawPrompt.trim();
10521
+ if (!prompt) {
10522
+ throw new Error(`imagePrompts[${index}] must be a non-empty string`);
10523
+ }
10524
+ return prompt;
10525
+ });
10526
+ if (promptEntries.length === 0) {
10527
+ return [];
10528
+ }
10529
+ const provider = resolveProvider(request.model).provider;
10530
+ const telemetry = createLlmTelemetryEmitter({
10531
+ telemetry: request.telemetry,
10532
+ operation: "generateImages",
10533
+ provider,
10534
+ model: request.model
10535
+ });
10536
+ const startedAtMs = Date.now();
10537
+ const params = resolveOpenAiImageRequestParams(request);
10538
+ const styleImages = await createOpenAiStyleImageFiles(request.styleImages);
10539
+ const hasStyleImages = Boolean(styleImages && styleImages.length > 0);
10540
+ const outputMimeType = resolveOpenAiImageMimeType(params.outputFormat);
10541
+ let totalUsage;
10542
+ let costUsd = 0;
10543
+ let outputImages = 0;
10544
+ telemetry.emit({
10545
+ type: "llm.call.started",
10546
+ imagePromptCount: promptEntries.length,
10547
+ styleImageCount: request.styleImages?.length ?? 0,
10548
+ numImagesPerPrompt: params.n
10549
+ });
10550
+ try {
10551
+ const images = [];
10552
+ for (const imagePrompt of promptEntries) {
10553
+ const prompt = buildOpenAiImagePrompt({
10554
+ stylePrompt: request.stylePrompt,
10555
+ imagePrompt,
10556
+ hasStyleImages
10557
+ });
10558
+ const response = await runOpenAiCall(async (client) => {
10559
+ const payload = {
10560
+ model: request.model,
10561
+ prompt,
10562
+ n: params.n,
10563
+ size: params.size,
10564
+ quality: params.quality,
10565
+ ...params.outputFormat ? { output_format: params.outputFormat } : {},
10566
+ ...request.outputCompression !== void 0 ? { output_compression: request.outputCompression } : {},
10567
+ ...params.background ? { background: params.background } : {},
10568
+ ...params.moderation ? { moderation: params.moderation } : {}
10569
+ };
10570
+ if (styleImages && styleImages.length > 0) {
10571
+ return await client.images.edit(
10572
+ {
10573
+ ...payload,
10574
+ image: styleImages
10575
+ },
10576
+ { signal: request.signal }
10577
+ );
10578
+ }
10579
+ return await client.images.generate(payload, { signal: request.signal });
10580
+ }, request.model);
10581
+ const data = Array.isArray(response.data) ? response.data ?? [] : [];
10582
+ for (const item of data) {
10583
+ if (typeof item.b64_json !== "string" || item.b64_json.length === 0) {
10584
+ continue;
10585
+ }
10586
+ images.push({
10587
+ mimeType: outputMimeType,
10588
+ data: import_node_buffer4.Buffer.from(item.b64_json, "base64")
10589
+ });
10590
+ }
10591
+ outputImages = images.length;
10592
+ const usage = extractOpenAiUsageTokens(response.usage);
10593
+ totalUsage = sumUsageTokens(totalUsage, usage);
10594
+ costUsd += estimateCallCostUsd({
10595
+ modelId: request.model,
10596
+ tokens: usage,
10597
+ responseImages: data.length,
10598
+ imageSize: params.size,
10599
+ imageQuality: params.quality
10600
+ });
10601
+ }
10602
+ telemetry.emit({
10603
+ type: "llm.call.completed",
10604
+ success: true,
10605
+ durationMs: Math.max(0, Date.now() - startedAtMs),
10606
+ usage: totalUsage,
10607
+ costUsd,
10608
+ imageCount: images.length,
10609
+ attempts: promptEntries.length
10610
+ });
10611
+ return images;
10612
+ } catch (error) {
10613
+ const err = error instanceof Error ? error : new Error(String(error));
10614
+ telemetry.emit({
10615
+ type: "llm.call.completed",
10616
+ success: false,
10617
+ durationMs: Math.max(0, Date.now() - startedAtMs),
10618
+ usage: totalUsage,
10619
+ costUsd,
10620
+ imageCount: outputImages,
10621
+ error: err.message
10622
+ });
10623
+ throw err;
10624
+ } finally {
10625
+ await telemetry.flush();
10626
+ }
10627
+ }
10220
10628
  async function generateImages(request) {
10629
+ if (isOpenAiGenerateImagesRequest(request)) {
10630
+ return await generateImagesWithOpenAiImageApi(request);
10631
+ }
10221
10632
  const maxAttempts = Math.max(1, Math.floor(request.maxAttempts ?? 4));
10222
10633
  const promptList = Array.from(request.imagePrompts);
10223
10634
  if (promptList.length === 0) {
@@ -10231,7 +10642,7 @@ async function generateImages(request) {
10231
10642
  }
10232
10643
  return { index: arrayIndex + 1, prompt: trimmedPrompt };
10233
10644
  });
10234
- const gradingPrompt = request.imageGradingPrompt.trim();
10645
+ const gradingPrompt = request.imageGradingPrompt?.trim() ?? "";
10235
10646
  if (!gradingPrompt) {
10236
10647
  throw new Error("imageGradingPrompt must be a non-empty string");
10237
10648
  }
@@ -13529,8 +13940,11 @@ function summarizeResultUsage(result) {
13529
13940
  }
13530
13941
  summary = {
13531
13942
  promptTokens: sumUsageValue2(summary?.promptTokens, usage.promptTokens),
13943
+ promptTextTokens: sumUsageValue2(summary?.promptTextTokens, usage.promptTextTokens),
13944
+ promptImageTokens: sumUsageValue2(summary?.promptImageTokens, usage.promptImageTokens),
13532
13945
  cachedTokens: sumUsageValue2(summary?.cachedTokens, usage.cachedTokens),
13533
13946
  responseTokens: sumUsageValue2(summary?.responseTokens, usage.responseTokens),
13947
+ responseTextTokens: sumUsageValue2(summary?.responseTextTokens, usage.responseTextTokens),
13534
13948
  responseImageTokens: sumUsageValue2(summary?.responseImageTokens, usage.responseImageTokens),
13535
13949
  thinkingTokens: sumUsageValue2(summary?.thinkingTokens, usage.thinkingTokens),
13536
13950
  totalTokens: sumUsageValue2(summary?.totalTokens, usage.totalTokens),
@@ -14262,6 +14676,17 @@ async function runCandidateEvolution(options) {
14262
14676
  LLM_MODEL_IDS,
14263
14677
  LLM_TEXT_MODEL_IDS,
14264
14678
  LlmJsonCallError,
14679
+ OPENAI_GPT_IMAGE_2_AUTO_RESOLUTION,
14680
+ OPENAI_GPT_IMAGE_2_BACKGROUNDS,
14681
+ OPENAI_GPT_IMAGE_2_MODERATION_LEVELS,
14682
+ OPENAI_GPT_IMAGE_2_NUM_IMAGES,
14683
+ OPENAI_GPT_IMAGE_2_OUTPUT_FORMATS,
14684
+ OPENAI_GPT_IMAGE_2_PARTIAL_IMAGE_COUNTS,
14685
+ OPENAI_GPT_IMAGE_2_POPULAR_RESOLUTIONS,
14686
+ OPENAI_GPT_IMAGE_2_QUALITY_LEVELS,
14687
+ OPENAI_GPT_IMAGE_2_RESOLUTIONS,
14688
+ OPENAI_GPT_IMAGE_2_SIZE_CONSTRAINTS,
14689
+ OPENAI_IMAGE_MODEL_IDS,
14265
14690
  OPENAI_MODEL_IDS,
14266
14691
  appendMarkdownSourcesSection,
14267
14692
  applyPatch,
@@ -14311,6 +14736,7 @@ async function runCandidateEvolution(options) {
14311
14736
  isLlmImageModelId,
14312
14737
  isLlmModelId,
14313
14738
  isLlmTextModelId,
14739
+ isOpenAiImageModelId,
14314
14740
  isOpenAiModelId,
14315
14741
  loadEnvFromFile,
14316
14742
  loadLocalEnv,
@@ -14330,6 +14756,7 @@ async function runCandidateEvolution(options) {
14330
14756
  streamToolLoop,
14331
14757
  stripCodexCitationMarkers,
14332
14758
  toGeminiJsonSchema,
14333
- tool
14759
+ tool,
14760
+ validateOpenAiGptImage2Resolution
14334
14761
  });
14335
14762
  //# sourceMappingURL=index.cjs.map