@cartanova/qgrid-cli 2.10.5 → 2.10.7

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 (96) hide show
  1. package/bundle/dist/application/monit/monit.frame.js +1 -1
  2. package/bundle/dist/application/qgrid/expired-token-reminder.js +1 -1
  3. package/bundle/dist/application/qgrid/oauth.js +1 -1
  4. package/bundle/dist/application/qgrid/qgrid-image-generation.js +7 -11
  5. package/bundle/dist/application/qgrid/qgrid-response-format.js +4 -4
  6. package/bundle/dist/application/qgrid/qgrid-run-lifecycle.js +26 -7
  7. package/bundle/dist/application/qgrid/qgrid.dispatcher.js +12 -7
  8. package/bundle/dist/application/qgrid/qgrid.frame.js +24 -10
  9. package/bundle/dist/application/qgrid/token-death.js +1 -1
  10. package/bundle/dist/application/qgrid/token-window-keepalive.js +1 -1
  11. package/bundle/dist/application/qgrid/tool-emulation.js +1 -1
  12. package/bundle/dist/application/request-log/request-log.model.js +5 -3
  13. package/bundle/dist/application/sonamu.generated.js +4 -1
  14. package/bundle/dist/application/sonamu.generated.sso.js +3 -1
  15. package/bundle/dist/i18n/sd.generated.js +4 -3
  16. package/bundle/dist/migrations/20261016155350_alter_request_logs_add1_alter1.js +15 -0
  17. package/bundle/dist/sonamu.config.js +2 -2
  18. package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +1 -1
  19. package/bundle/dist/utils/providers/anthropic/anthropic-thinking.js +1 -1
  20. package/bundle/dist/utils/providers/common/model-cost.js +14 -3
  21. package/bundle/dist/utils/providers/openai/openai-backend-protocol.js +13 -2
  22. package/bundle/dist/utils/providers/openai/openai-direct-client.js +5 -4
  23. package/bundle/dist/utils/providers/openai/openai-dispatcher.js +111 -57
  24. package/bundle/dist/utils/providers/openai/openai-image-generation.js +25 -17
  25. package/bundle/dist/utils/providers/openai/openai-refresh.js +1 -1
  26. package/bundle/src/application/qgrid/qgrid-image-generation.test.ts +19 -8
  27. package/bundle/src/application/qgrid/qgrid-image-generation.ts +17 -24
  28. package/bundle/src/application/qgrid/qgrid-response-format.test.ts +4 -2
  29. package/bundle/src/application/qgrid/qgrid-response-format.ts +7 -10
  30. package/bundle/src/application/qgrid/qgrid-run-lifecycle.test.ts +105 -9
  31. package/bundle/src/application/qgrid/qgrid-run-lifecycle.ts +47 -5
  32. package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +160 -2
  33. package/bundle/src/application/qgrid/qgrid.dispatcher.ts +40 -18
  34. package/bundle/src/application/qgrid/qgrid.frame.test.ts +74 -0
  35. package/bundle/src/application/qgrid/qgrid.frame.ts +39 -4
  36. package/bundle/src/application/request-log/request-log.entity.json +11 -2
  37. package/bundle/src/application/request-log/request-log.model.ts +4 -0
  38. package/bundle/src/application/sonamu.generated.http +2 -2
  39. package/bundle/src/application/sonamu.generated.sso.ts +2 -0
  40. package/bundle/src/application/sonamu.generated.ts +4 -0
  41. package/bundle/src/i18n/sd.generated.ts +3 -2
  42. package/bundle/src/migrations/20261016155350_alter_request_logs_add1_alter1.ts +15 -0
  43. package/bundle/src/utils/providers/common/model-cost.test.ts +28 -0
  44. package/bundle/src/utils/providers/common/model-cost.ts +19 -2
  45. package/bundle/src/utils/providers/openai/openai-backend-protocol.test.ts +23 -1
  46. package/bundle/src/utils/providers/openai/openai-backend-protocol.ts +24 -2
  47. package/bundle/src/utils/providers/openai/openai-direct-client.test.ts +15 -0
  48. package/bundle/src/utils/providers/openai/openai-direct-client.ts +14 -4
  49. package/bundle/src/utils/providers/openai/openai-dispatcher.test.ts +223 -32
  50. package/bundle/src/utils/providers/openai/openai-dispatcher.ts +174 -72
  51. package/bundle/src/utils/providers/openai/openai-image-generation.test.ts +89 -0
  52. package/bundle/src/utils/providers/openai/openai-image-generation.ts +26 -15
  53. package/bundle/web-dist/client/assets/cost-DH2jZbrw.js +1 -0
  54. package/bundle/web-dist/client/assets/index-Bw2s88Ot.css +1 -0
  55. package/bundle/web-dist/client/assets/{index-Dxw7DiXF.js → index-CwqqPF4F.js} +4 -4
  56. package/bundle/web-dist/client/assets/logs-CZgl1RSu.js +1 -0
  57. package/bundle/web-dist/client/assets/{monit-E8eGW1Sj.js → monit-TarvUWiE.js} +1 -1
  58. package/bundle/web-dist/client/assets/request-model-CojtinqK.js +1 -0
  59. package/bundle/web-dist/client/assets/{routes-7spLfIGZ.js → routes-BXR6OLah.js} +2 -2
  60. package/bundle/web-dist/client/assets/{services.generated-jnPHYMER.js → services.generated-BsieU37H.js} +1 -1
  61. package/bundle/web-dist/client/assets/{settings-BdosZFNC.js → settings-B1y5MNSU.js} +1 -1
  62. package/bundle/web-dist/client/assets/show-CG-BAdhS.js +2 -0
  63. package/bundle/web-dist/client/assets/{tokens-CBdHb2_U.js → tokens-D9tAWBEW.js} +1 -1
  64. package/bundle/web-dist/client/assets/{use-oauth-login-flow-Cyn3YPqW.js → use-oauth-login-flow-DxdOhz4a.js} +1 -1
  65. package/bundle/web-dist/client/assets/{use-update-token-mutation-DQCwCYfR.js → use-update-token-mutation-DAq0F8p-.js} +1 -1
  66. package/bundle/web-dist/client/index.html +3 -3
  67. package/bundle/web-dist/server/assets/{cost-59jBdx-I.js → cost-eEHeTRT5.js} +4 -5
  68. package/bundle/web-dist/server/assets/{lazyRouteComponent-CUR-kWzI.js → lazyRouteComponent-Dtd0NR4r.js} +2 -2
  69. package/bundle/web-dist/server/assets/{logs-CaaWO9-Z.js → logs-l91avYif.js} +33 -21
  70. package/bundle/web-dist/server/assets/{monit-CBil92fJ.js → monit-DvzribSE.js} +4 -4
  71. package/bundle/web-dist/server/assets/{plus-Bvdj8Pwx.js → plus-KZrECewT.js} +1 -1
  72. package/bundle/web-dist/server/assets/{react-dom-CyuShs9K.js → react-dom-B4a6-uuR.js} +1 -1
  73. package/bundle/web-dist/server/assets/{refresh-cw-3QAiSWBd.js → refresh-cw-BND93JrF.js} +1 -1
  74. package/bundle/web-dist/server/assets/{request-model-CnCeaNLE.js → request-model-CbqfnQOJ.js} +19 -1
  75. package/bundle/web-dist/server/assets/{routes-DtVf9yqo.js → routes-BAPWTizT.js} +6 -7
  76. package/bundle/web-dist/server/assets/{services.generated-FPwsG9p3.js → services.generated-CEbGjsI0.js} +3 -2
  77. package/bundle/web-dist/server/assets/{settings-DeHNwoMv.js → settings-BZR5HSAL.js} +3 -3
  78. package/bundle/web-dist/server/assets/{show-8NNdRxhM.js → show-CxVZTAdv.js} +17 -21
  79. package/bundle/web-dist/server/assets/{tokens-odgS2-9q.js → tokens-D1hb4eKk.js} +4 -4
  80. package/bundle/web-dist/server/assets/{use-oauth-login-flow-DTQKdYBO.js → use-oauth-login-flow-Cvdy0zF8.js} +1 -1
  81. package/bundle/web-dist/server/assets/{use-update-token-mutation-xvXbPrCI.js → use-update-token-mutation-CfYmk_4_.js} +1 -1
  82. package/bundle/web-dist/server/entry-server.generated.js +13 -10
  83. package/package.json +1 -1
  84. package/skills/qgrid/SKILL.md +9 -8
  85. package/skills/qgrid/references/ai-sdk-provider-contract.md +27 -17
  86. package/skills/qgrid/references/decision-rationale.md +8 -8
  87. package/skills/qgrid/references/openai-codex-runtime.md +19 -11
  88. package/skills/qgrid/references/prompt-cache-and-usage.md +3 -0
  89. package/skills/qgrid/references/request-log-run-lifecycle.md +14 -2
  90. package/skills/qgrid/references/sonamu-api-web-flow.md +2 -2
  91. package/skills/qgrid/references/verification-and-debugging.md +23 -9
  92. package/bundle/web-dist/client/assets/cost-CY2BJEPC.js +0 -1
  93. package/bundle/web-dist/client/assets/index-CvG4UB9v.css +0 -1
  94. package/bundle/web-dist/client/assets/logs-3n_U4qnI.js +0 -1
  95. package/bundle/web-dist/client/assets/request-model-D4CZPmnG.js +0 -1
  96. package/bundle/web-dist/client/assets/show-b2PFNI3D.js +0 -2
@@ -43,6 +43,7 @@ export const requestLogSubsetQueries = {
43
43
  image_cost_usd: "request_logs.image_cost_usd",
44
44
  image_cost_method: "request_logs.image_cost_method",
45
45
  effort: "request_logs.effort",
46
+ service_tier: "request_logs.service_tier",
46
47
  history: "request_logs.history",
47
48
  tools: "request_logs.tools",
48
49
  status: "request_logs.status",
@@ -75,6 +76,7 @@ export const requestLogSubsetQueries = {
75
76
  image_cost_usd: "request_logs.image_cost_usd",
76
77
  image_cost_method: "request_logs.image_cost_method",
77
78
  effort: "request_logs.effort",
79
+ service_tier: "request_logs.service_tier",
78
80
  status: "request_logs.status",
79
81
  response_json_ok: "request_logs.response_json_ok",
80
82
  tool_call_count: "request_logs.tool_call_count",
@@ -167,6 +167,7 @@ export const RequestLogBaseSchema = z.object({
167
167
  cost_source: z.string().max(20).nullable(),
168
168
  image_cost_usd: z.int().nullable(),
169
169
  image_cost_method: z.string().max(100).nullable(),
170
+ service_tier: z.string().max(20).nullable(),
170
171
  effort: z.string().max(10).nullable(),
171
172
  history: HistoryItems.nullable(),
172
173
  tools: ToolDefinitions.nullable(),
@@ -201,6 +202,7 @@ export type RequestLogBaseSchema = z.infer<typeof RequestLogBaseSchema> & {
201
202
  "cost_source",
202
203
  "image_cost_usd",
203
204
  "image_cost_method",
205
+ "service_tier",
204
206
  "effort",
205
207
  "history",
206
208
  "tools",
@@ -405,6 +407,7 @@ export const RequestLogSubsetA = z.object({
405
407
  image_cost_usd: z.int().nullable(),
406
408
  image_cost_method: z.string().max(100).nullable(),
407
409
  effort: z.string().max(10).nullable(),
410
+ service_tier: z.string().max(20).nullable(),
408
411
  history: HistoryItems.nullable(),
409
412
  tools: ToolDefinitions.nullable(),
410
413
  status: RequestLogStatus,
@@ -436,6 +439,7 @@ export const RequestLogSubsetP = z.object({
436
439
  image_cost_usd: z.int().nullable(),
437
440
  image_cost_method: z.string().max(100).nullable(),
438
441
  effort: z.string().max(10).nullable(),
442
+ service_tier: z.string().max(20).nullable(),
439
443
  status: RequestLogStatus,
440
444
  response_json_ok: z.boolean().nullable(),
441
445
  tool_call_count: z.int(),
@@ -230,8 +230,9 @@ const entityLabels = {
230
230
  "entity.RequestLog.ttft_ms": "first gen TTFT(ms)",
231
231
  "entity.RequestLog.cost_usd": "API 비용",
232
232
  "entity.RequestLog.cost_source": "비용 출처(provider/pricing_table/mixed)",
233
- "entity.RequestLog.image_cost_usd": "이미지 생성 추정 비용",
234
- "entity.RequestLog.image_cost_method": "이미지 비용 추정 방식",
233
+ "entity.RequestLog.image_cost_usd": "이미지 생성 비용",
234
+ "entity.RequestLog.image_cost_method": "이미지 비용 계산 방식",
235
+ "entity.RequestLog.service_tier": "Requested OpenAI service tier",
235
236
  "entity.RequestLog.effort": "effort level",
236
237
  "entity.RequestLog.history": "inject_items 히스토리",
237
238
  "entity.RequestLog.tools": "요청에 장착된 tool 정의 목록",
@@ -0,0 +1,15 @@
1
+ import { type Knex } from "knex";
2
+
3
+ export async function up(knex: Knex): Promise<void> {
4
+ await knex.schema.alterTable("request_logs", (table) => {
5
+ // add
6
+ table.string("service_tier", 20).nullable();
7
+ });
8
+ }
9
+
10
+ export async function down(knex: Knex): Promise<void> {
11
+ await knex.schema.alterTable("request_logs", (table) => {
12
+ // rollback - add
13
+ table.dropColumns("service_tier");
14
+ });
15
+ }
@@ -3,6 +3,34 @@ import { describe, expect, it } from "vitest";
3
3
  import { calculateCostUsd, getModelCosts } from "./model-cost";
4
4
 
5
5
  describe("calculateCostUsd", () => {
6
+ it.each([
7
+ ["gpt-6-astra", 2.6],
8
+ ["gpt-6.1-sol", 0.5],
9
+ ["gpt-6-sol", 0.52],
10
+ ["gpt-6-luna", 0.026],
11
+ ["gpt-5.6-sol", 1.04],
12
+ ["gpt-5.6-terra", 0.56],
13
+ ["gpt-5.6-luna", 0.056],
14
+ ])("prices %s fast input, cached input, cache writes and output", (model, expected) => {
15
+ expect(calculateCostUsd(`openai/${model}`, {
16
+ inputTokens: 160_000, cachedInputTokens: 100_000,
17
+ cacheCreationInputTokens: 40_000, outputTokens: 10_000,
18
+ }, "fast")).toBeCloseTo(expected, 10);
19
+ });
20
+
21
+ it("combines Fast API rates with long-context rates, not subscription usage multipliers", () => {
22
+ expect(calculateCostUsd("openai/gpt-6.1-sol", {
23
+ inputTokens: 300_000, cachedInputTokens: 200_000, outputTokens: 10_000,
24
+ }, "fast")).toBeCloseTo(1.18, 10);
25
+ });
26
+
27
+ it("keeps standard pricing for omitted/flex tiers and Anthropic", () => {
28
+ const usage = { inputTokens: 1_000, outputTokens: 1_000 };
29
+ expect(calculateCostUsd("gpt-6.1-sol", usage)).toBeCloseTo(0.012, 10);
30
+ expect(calculateCostUsd("gpt-6.1-sol", usage, "flex")).toBeCloseTo(0.012, 10);
31
+ expect(calculateCostUsd("claude-sonnet-5-5", usage, "fast")).toBeCloseTo(0.012, 10);
32
+ });
33
+
6
34
  it.each([
7
35
  [272_000, 2.77],
8
36
  [272_001, 5.51502],
@@ -237,6 +237,19 @@ export function getModelCosts(model: string): ModelCosts {
237
237
  return OPENAI_COSTS[normalizedModel] ?? ANTHROPIC_COSTS[normalizedModel] ?? DEFAULT_COSTS;
238
238
  }
239
239
 
240
+ // Verified Fast API rates for the currently served Codex models (2026-10-16).
241
+ // Applies to all token categories and long context; not the 2.5x subscription quota multiplier.
242
+ // https://developers.openai.com/api/docs/pricing
243
+ const OPENAI_FAST_MULTIPLIERS: Record<string, number> = {
244
+ "gpt-6-astra": 2,
245
+ "gpt-6.1-sol": 2,
246
+ "gpt-6-sol": 2,
247
+ "gpt-6-luna": 2,
248
+ "gpt-5.6-sol": 2,
249
+ "gpt-5.6-terra": 2,
250
+ "gpt-5.6-luna": 2,
251
+ };
252
+
240
253
  export function calculateCostUsd(
241
254
  model: string,
242
255
  usage: {
@@ -247,6 +260,7 @@ export function calculateCostUsd(
247
260
  cacheCreationInputTokens5m?: number;
248
261
  cacheCreationInputTokens1h?: number;
249
262
  },
263
+ serviceTier?: string,
250
264
  ): number {
251
265
  const costs = getModelCosts(model);
252
266
  const cachedInput = usage.cachedInputTokens ?? 0;
@@ -281,12 +295,15 @@ export function calculateCostUsd(
281
295
  (isLongContext ? lc.inputMultiplier : 1);
282
296
  const outputRate = costs.outputTokens * (isLongContext ? lc.outputMultiplier : 1);
283
297
 
284
- return (
298
+ const standardCost =
285
299
  (nonCachedInput / 1_000_000) * inputRate +
286
300
  (usage.outputTokens / 1_000_000) * outputRate +
287
301
  (cachedInput / 1_000_000) * cachedRate +
288
302
  (unclassifiedCacheCreationInput / 1_000_000) * cacheCreationFallbackRate +
289
303
  (classifiedCacheCreationInput5m / 1_000_000) * cacheCreation5mRate +
290
- (classifiedCacheCreationInput1h / 1_000_000) * cacheCreation1hRate
304
+ (classifiedCacheCreationInput1h / 1_000_000) * cacheCreation1hRate;
305
+ const normalizedModel = model.split("/").pop() ?? model;
306
+ return (
307
+ standardCost * (serviceTier === "fast" ? (OPENAI_FAST_MULTIPLIERS[normalizedModel] ?? 1) : 1)
291
308
  );
292
309
  }
@@ -27,7 +27,7 @@ describe("OpenAI Codex backend protocol", () => {
27
27
  } })).toMatchObject({ generation: { route: "codex-responses", size: "841x1870" } });
28
28
  });
29
29
  it("distinguishes partial function items from completed arguments", () => {
30
- const item = { type: "function_call", call_id: "call", name: "generate_transparent_image", arguments: "{}" };
30
+ const item = { type: "function_call", call_id: "call", name: "generate_image", arguments: "{}" };
31
31
  expect(normalizeOpenAIEvent({ type: "response.output_item.added", item })).toEqual({ type: "output-item", item, completed: false });
32
32
  expect(normalizeOpenAIEvent({ type: "response.output_item.done", item })).toEqual({ type: "output-item", item, completed: true });
33
33
  });
@@ -149,4 +149,26 @@ describe("OpenAI Codex backend protocol", () => {
149
149
  }),
150
150
  ).toEqual({ type: "image", id: "img", base64: "aGVsbG8=", mimeType: "image/png", revisedPrompt: "better", generation: { route: "codex-responses" } });
151
151
  });
152
+
153
+ it("preserves zero image-tool usage without treating it as missing", () => {
154
+ const usage = { input_tokens: 0, output_tokens: 0, total_tokens: 0 };
155
+ expect(normalizeOpenAIEvent({ type: "response.completed", response: {
156
+ id: "r", tool_usage: { image_gen: usage },
157
+ } })).toEqual({
158
+ type: "completed", responseId: "r",
159
+ imageGeneration: { route: "codex-responses", usage },
160
+ });
161
+ });
162
+
163
+ it.each([undefined, null, {}, { input_tokens: "4", output_tokens: 1, total_tokens: 5 }, { input_tokens: -1, output_tokens: 1, total_tokens: 0 }])(
164
+ "ignores missing or malformed image-tool usage: %j", (usage) => {
165
+ expect(normalizeOpenAIEvent({ type: "response.completed", response: {
166
+ id: "r", tool_usage: { image_gen: usage },
167
+ tools: [{ type: "image_generation", model: "gpt-image-2-codex", size: "auto", quality: "auto" }],
168
+ } })).toEqual({
169
+ type: "completed", responseId: "r",
170
+ imageGeneration: { route: "codex-responses", model: "gpt-image-2-codex" },
171
+ });
172
+ },
173
+ );
152
174
  });
@@ -1,6 +1,6 @@
1
1
  import os from "node:os";
2
2
 
3
- import { type ImageGenerationMetadata } from "../../../application/qgrid/qgrid.types";
3
+ import { ImageGenerationMetadata } from "../../../application/qgrid/qgrid.types";
4
4
  import { type OpenAIEffort } from "../common/effort";
5
5
 
6
6
  export const CHATGPT_CODEX_RESPONSES_URL =
@@ -180,7 +180,13 @@ export type OpenAINormalizedEvent =
180
180
  generation?: ImageGenerationMetadata;
181
181
  }
182
182
  | { type: "output-item"; item: OpenAIResponseItem; completed?: boolean }
183
- | { type: "completed"; responseId: string; usage?: OpenAIUsage; model?: string }
183
+ | {
184
+ type: "completed";
185
+ responseId: string;
186
+ usage?: OpenAIUsage;
187
+ model?: string;
188
+ imageGeneration?: ImageGenerationMetadata;
189
+ }
184
190
  | { type: "error"; error: OpenAIProtocolError };
185
191
 
186
192
  export class OpenAIProtocolError extends Error {
@@ -286,11 +292,27 @@ export function normalizeOpenAIEvent(raw: unknown): OpenAINormalizedEvent | unde
286
292
  }
287
293
  if (type === "response.completed") {
288
294
  const response = (event.response ?? {}) as Record<string, unknown>;
295
+ const toolUsage = response.tool_usage as Record<string, unknown> | undefined;
296
+ const parsedImageUsage = ImageGenerationMetadata.shape.usage.safeParse(toolUsage?.image_gen);
297
+ const imageUsage = parsedImageUsage.success ? parsedImageUsage.data : undefined;
298
+ const imageTool = Array.isArray(response.tools)
299
+ ? response.tools.find((tool) => tool?.type === "image_generation")
300
+ : undefined;
301
+ const imageModel = typeof imageTool?.model === "string" ? imageTool.model : undefined;
289
302
  return {
290
303
  type: "completed",
291
304
  responseId: String(response.id ?? ""),
292
305
  ...(response.usage ? { usage: usageFrom(response.usage) } : {}),
293
306
  ...(typeof response.model === "string" ? { model: response.model } : {}),
307
+ ...(imageUsage || imageModel
308
+ ? {
309
+ imageGeneration: {
310
+ route: "codex-responses" as const,
311
+ ...(imageModel ? { model: imageModel } : {}),
312
+ ...(imageUsage ? { usage: imageUsage } : {}),
313
+ },
314
+ }
315
+ : {}),
294
316
  };
295
317
  }
296
318
  if (type === "error" || type === "response.failed" || type === "response.incomplete") {
@@ -29,6 +29,21 @@ async function collect<T>(iterable: AsyncIterable<T>): Promise<T[]> {
29
29
  }
30
30
 
31
31
  describe("OpenAI direct HTTPS client", () => {
32
+ it.each([true, { background: "opaque" }])("keeps chat-model images on Responses (%j)", async (imageGeneration) => {
33
+ const fetchMock = vi.fn<typeof fetch>(async () =>
34
+ sse({ type: "response.completed", response: { id: "hosted-image" } }),
35
+ );
36
+ const client = new OpenAIDirectClient({
37
+ credentials: { accessToken: "access", accountId: "acct" }, fetch: fetchMock,
38
+ });
39
+ await collect(client.responses({ model: "gpt-6-luna", history: [], imageGeneration }));
40
+ expect(fetchMock).toHaveBeenCalledTimes(1);
41
+ expect(fetchMock.mock.calls[0]?.[0]).toBe(CHATGPT_CODEX_RESPONSES_URL);
42
+ expect(JSON.parse(String(fetchMock.mock.calls[0]?.[1]?.body))).toMatchObject({
43
+ model: "gpt-6-luna", tools: [expect.objectContaining({ type: "image_generation" })],
44
+ });
45
+ });
46
+
32
47
  it("posts the pinned body and Codex identity without live calls", async () => {
33
48
  const fetchMock = vi.fn<typeof fetch>(async () =>
34
49
  sse(
@@ -450,8 +450,9 @@ export class OpenAIDirectClient {
450
450
 
451
451
  responses(options: OpenAIResponsesOptions, signal?: AbortSignal): OpenAIEventStream {
452
452
  if (
453
- typeof options.imageGeneration === "object" &&
454
- options.imageGeneration.background === "transparent"
453
+ options.model === "gpt-image-2" ||
454
+ (typeof options.imageGeneration === "object" &&
455
+ options.imageGeneration.background === "transparent")
455
456
  ) {
456
457
  return this.standaloneImages(options, signal);
457
458
  }
@@ -498,10 +499,19 @@ export class OpenAIDirectClient {
498
499
  continue;
499
500
  }
500
501
  if (!response.ok) throw await responseError(response);
501
- const images = await readStandaloneImageResponse(response);
502
+ const images = await readStandaloneImageResponse(
503
+ response,
504
+ typeof options.imageGeneration === "object" &&
505
+ options.imageGeneration.background === "transparent",
506
+ );
502
507
  signal?.throwIfAborted();
503
508
  yield* images;
504
- yield { type: "completed", responseId: requestId, model: "gpt-image-2" };
509
+ const firstImage = images[0];
510
+ yield {
511
+ type: "completed",
512
+ responseId: requestId,
513
+ model: firstImage?.type === "image" ? firstImage.generation?.model : "gpt-image-2",
514
+ };
505
515
  return;
506
516
  }
507
517
  }