ai-sdk-provider-codex-cli 0.5.2 → 0.7.0

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.js CHANGED
@@ -65,9 +65,37 @@ var loggerFunctionSchema = z.object({
65
65
  message: "error must be a function"
66
66
  })
67
67
  });
68
+ var mcpServerBaseSchema = z.object({
69
+ enabled: z.boolean().optional(),
70
+ startupTimeoutSec: z.number().int().positive().optional(),
71
+ toolTimeoutSec: z.number().int().positive().optional(),
72
+ enabledTools: z.array(z.string()).optional(),
73
+ disabledTools: z.array(z.string()).optional()
74
+ });
75
+ var mcpServerStdioSchema = mcpServerBaseSchema.extend({
76
+ transport: z.literal("stdio"),
77
+ command: z.string().min(1),
78
+ args: z.array(z.string()).optional(),
79
+ env: z.record(z.string(), z.string()).optional(),
80
+ cwd: z.string().optional()
81
+ });
82
+ var mcpServerHttpSchema = mcpServerBaseSchema.extend({
83
+ transport: z.literal("http"),
84
+ url: z.string().min(1),
85
+ bearerToken: z.string().optional(),
86
+ bearerTokenEnvVar: z.string().optional(),
87
+ httpHeaders: z.record(z.string(), z.string()).optional(),
88
+ envHttpHeaders: z.record(z.string(), z.string()).optional()
89
+ });
90
+ var mcpServerSchema = z.discriminatedUnion("transport", [
91
+ mcpServerStdioSchema,
92
+ mcpServerHttpSchema
93
+ ]);
94
+ var mcpServersSchema = z.record(z.string(), mcpServerSchema);
68
95
  var settingsSchema = z.object({
69
96
  codexPath: z.string().optional(),
70
97
  cwd: z.string().optional(),
98
+ addDirs: z.array(z.string().min(1)).optional(),
71
99
  approvalMode: z.enum(["untrusted", "on-failure", "on-request", "never"]).optional(),
72
100
  sandboxMode: z.enum(["read-only", "workspace-write", "danger-full-access"]).optional(),
73
101
  fullAuto: z.boolean().optional(),
@@ -75,6 +103,7 @@ var settingsSchema = z.object({
75
103
  skipGitRepoCheck: z.boolean().optional(),
76
104
  color: z.enum(["always", "never", "auto"]).optional(),
77
105
  allowNpx: z.boolean().optional(),
106
+ outputLastMessageFile: z.string().optional(),
78
107
  env: z.record(z.string(), z.string()).optional(),
79
108
  verbose: z.boolean().optional(),
80
109
  logger: z.union([z.literal(false), loggerFunctionSchema]).optional(),
@@ -89,6 +118,8 @@ var settingsSchema = z.object({
89
118
  profile: z.string().optional(),
90
119
  oss: z.boolean().optional(),
91
120
  webSearch: z.boolean().optional(),
121
+ mcpServers: mcpServersSchema.optional(),
122
+ rmcpClient: z.boolean().optional(),
92
123
  // NEW: Generic overrides
93
124
  configOverrides: z.record(
94
125
  z.string(),
@@ -133,6 +164,94 @@ function validateModelId(modelId) {
133
164
  if (!modelId || modelId.trim() === "") return "Model ID cannot be empty";
134
165
  return void 0;
135
166
  }
167
+ function extractImageData(part) {
168
+ if (typeof part !== "object" || part === null) return null;
169
+ const p = part;
170
+ const mimeType = p.mimeType || "image/png";
171
+ if (typeof p.image === "string") {
172
+ return extractFromString(p.image, mimeType);
173
+ }
174
+ if (p.image instanceof URL) {
175
+ if (p.image.protocol === "data:") {
176
+ const dataUrlStr = p.image.toString();
177
+ const match = dataUrlStr.match(/^data:([^;,]+)/);
178
+ const extractedMimeType = match?.[1] || mimeType;
179
+ return { data: dataUrlStr, mimeType: extractedMimeType };
180
+ }
181
+ return null;
182
+ }
183
+ if (Buffer.isBuffer(p.image)) {
184
+ const base64 = p.image.toString("base64");
185
+ return { data: `data:${mimeType};base64,${base64}`, mimeType };
186
+ }
187
+ if (p.image instanceof ArrayBuffer || p.image instanceof Uint8Array) {
188
+ const buffer = Buffer.from(p.image);
189
+ const base64 = buffer.toString("base64");
190
+ return { data: `data:${mimeType};base64,${base64}`, mimeType };
191
+ }
192
+ if (typeof p.data === "string") {
193
+ return extractFromString(p.data, mimeType);
194
+ }
195
+ if (typeof p.url === "string") {
196
+ return extractFromString(p.url, mimeType);
197
+ }
198
+ return null;
199
+ }
200
+ function extractFromString(value, fallbackMimeType) {
201
+ const trimmed = value.trim();
202
+ if (/^https?:\/\//i.test(trimmed)) {
203
+ return null;
204
+ }
205
+ if (trimmed.startsWith("data:")) {
206
+ if (!trimmed.includes(";base64,")) {
207
+ return null;
208
+ }
209
+ const match = trimmed.match(/^data:([^;,]+)/);
210
+ const mimeType = match?.[1] || fallbackMimeType;
211
+ return { data: trimmed, mimeType };
212
+ }
213
+ return {
214
+ data: `data:${fallbackMimeType};base64,${trimmed}`,
215
+ mimeType: fallbackMimeType
216
+ };
217
+ }
218
+ function writeImageToTempFile(imageData) {
219
+ const dir = mkdtempSync(join(tmpdir(), "codex-img-"));
220
+ const ext = getExtensionFromMimeType(imageData.mimeType);
221
+ const filePath = join(dir, `image.${ext}`);
222
+ const base64Match = imageData.data.match(/^data:[^;]+;base64,(.+)$/);
223
+ if (!base64Match) {
224
+ throw new Error("Invalid data URL format: expected data:[type];base64,[data]");
225
+ }
226
+ const buffer = Buffer.from(base64Match[1], "base64");
227
+ writeFileSync(filePath, buffer);
228
+ return filePath;
229
+ }
230
+ function cleanupTempImages(paths) {
231
+ for (const filePath of paths) {
232
+ try {
233
+ rmSync(filePath, { force: true });
234
+ const dir = filePath.replace(/[/\\][^/\\]+$/, "");
235
+ if (dir.includes("codex-img-")) {
236
+ rmSync(dir, { force: true, recursive: true });
237
+ }
238
+ } catch {
239
+ }
240
+ }
241
+ }
242
+ function getExtensionFromMimeType(mimeType) {
243
+ if (!mimeType) return "png";
244
+ const mapping = {
245
+ "image/png": "png",
246
+ "image/jpeg": "jpg",
247
+ "image/jpg": "jpg",
248
+ "image/gif": "gif",
249
+ "image/webp": "webp",
250
+ "image/bmp": "bmp",
251
+ "image/svg+xml": "svg"
252
+ };
253
+ return mapping[mimeType.toLowerCase()] || mimeType.split("/")[1] || "png";
254
+ }
136
255
 
137
256
  // src/message-mapper.ts
138
257
  function isTextPart(p) {
@@ -153,6 +272,7 @@ function isToolItem(p) {
153
272
  function mapMessagesToPrompt(prompt) {
154
273
  const warnings = [];
155
274
  const parts = [];
275
+ const images = [];
156
276
  let systemText;
157
277
  for (const msg of prompt) {
158
278
  if (msg.role === "system") {
@@ -165,8 +285,14 @@ function mapMessagesToPrompt(prompt) {
165
285
  } else if (Array.isArray(msg.content)) {
166
286
  const text = msg.content.filter(isTextPart).map((p) => p.text).join("\n");
167
287
  if (text) parts.push(`Human: ${text}`);
168
- const images = msg.content.filter(isImagePart);
169
- if (images.length) warnings.push("Image inputs ignored by Codex CLI integration.");
288
+ for (const part of msg.content.filter(isImagePart)) {
289
+ const imageData = extractImageData(part);
290
+ if (imageData) {
291
+ images.push(imageData);
292
+ } else {
293
+ warnings.push("Unsupported image format in message (HTTP URLs not supported)");
294
+ }
295
+ }
170
296
  }
171
297
  continue;
172
298
  }
@@ -193,7 +319,7 @@ function mapMessagesToPrompt(prompt) {
193
319
  let promptText = "";
194
320
  if (systemText) promptText += systemText + "\n\n";
195
321
  promptText += parts.join("\n\n");
196
- return { promptText, ...warnings.length ? { warnings } : {} };
322
+ return { promptText, images, ...warnings.length ? { warnings } : {} };
197
323
  }
198
324
  function createAPICallError({
199
325
  message,
@@ -232,6 +358,7 @@ var codexCliProviderOptionsSchema = z.object({
232
358
  reasoningSummary: z.enum(["auto", "detailed"]).optional(),
233
359
  reasoningSummaryFormat: z.enum(["none", "experimental"]).optional(),
234
360
  textVerbosity: z.enum(["low", "medium", "high"]).optional(),
361
+ addDirs: z.array(z.string().min(1)).optional(),
235
362
  configOverrides: z.record(
236
363
  z.string(),
237
364
  z.union([
@@ -241,7 +368,9 @@ var codexCliProviderOptionsSchema = z.object({
241
368
  z.object({}).passthrough(),
242
369
  z.array(z.any())
243
370
  ])
244
- ).optional()
371
+ ).optional(),
372
+ mcpServers: mcpServersSchema.optional(),
373
+ rmcpClient: z.boolean().optional()
245
374
  }).strict();
246
375
  function resolveCodexPath(explicitPath, allowNpx) {
247
376
  if (explicitPath) return { cmd: "node", args: [explicitPath] };
@@ -283,14 +412,79 @@ var CodexCliLanguageModel = class {
283
412
  ...this.settings.configOverrides ?? {},
284
413
  ...providerOptions.configOverrides ?? {}
285
414
  } : void 0;
415
+ const mergedAddDirs = providerOptions.addDirs || this.settings.addDirs ? [...this.settings.addDirs ?? [], ...providerOptions.addDirs ?? []] : void 0;
416
+ const mergedMcpServers = this.mergeMcpServers(
417
+ this.settings.mcpServers,
418
+ providerOptions.mcpServers
419
+ );
286
420
  return {
287
421
  ...this.settings,
288
422
  reasoningEffort: providerOptions.reasoningEffort ?? this.settings.reasoningEffort,
289
423
  reasoningSummary: providerOptions.reasoningSummary ?? this.settings.reasoningSummary,
290
424
  reasoningSummaryFormat: providerOptions.reasoningSummaryFormat ?? this.settings.reasoningSummaryFormat,
291
425
  modelVerbosity: providerOptions.textVerbosity ?? this.settings.modelVerbosity,
292
- configOverrides: mergedConfigOverrides
426
+ configOverrides: mergedConfigOverrides,
427
+ addDirs: mergedAddDirs,
428
+ mcpServers: mergedMcpServers,
429
+ rmcpClient: providerOptions.rmcpClient ?? this.settings.rmcpClient
430
+ };
431
+ }
432
+ mergeMcpServers(base, override) {
433
+ if (!base) return override;
434
+ if (!override) return base;
435
+ const merged = { ...base };
436
+ for (const [name, incoming] of Object.entries(override)) {
437
+ const existing = base[name];
438
+ merged[name] = this.mergeSingleMcpServer(existing, incoming);
439
+ }
440
+ return merged;
441
+ }
442
+ mergeSingleMcpServer(existing, incoming) {
443
+ if (!existing || existing.transport !== incoming.transport) {
444
+ return { ...incoming };
445
+ }
446
+ if (incoming.transport === "stdio") {
447
+ const baseStdio = existing;
448
+ const result2 = {
449
+ transport: "stdio",
450
+ command: incoming.command,
451
+ args: incoming.args ?? baseStdio.args,
452
+ env: this.mergeStringRecord(baseStdio.env, incoming.env),
453
+ cwd: incoming.cwd ?? baseStdio.cwd,
454
+ enabled: incoming.enabled ?? existing.enabled,
455
+ startupTimeoutSec: incoming.startupTimeoutSec ?? existing.startupTimeoutSec,
456
+ toolTimeoutSec: incoming.toolTimeoutSec ?? existing.toolTimeoutSec,
457
+ enabledTools: incoming.enabledTools ?? existing.enabledTools,
458
+ disabledTools: incoming.disabledTools ?? existing.disabledTools
459
+ };
460
+ return result2;
461
+ }
462
+ const baseHttp = existing;
463
+ const hasIncomingAuth = incoming.bearerToken !== void 0 || incoming.bearerTokenEnvVar !== void 0;
464
+ const bearerToken = hasIncomingAuth ? incoming.bearerToken : baseHttp.bearerToken;
465
+ const bearerTokenEnvVar = hasIncomingAuth ? incoming.bearerTokenEnvVar : baseHttp.bearerTokenEnvVar;
466
+ const result = {
467
+ transport: "http",
468
+ url: incoming.url,
469
+ bearerToken,
470
+ bearerTokenEnvVar,
471
+ httpHeaders: this.mergeStringRecord(baseHttp.httpHeaders, incoming.httpHeaders),
472
+ envHttpHeaders: this.mergeStringRecord(baseHttp.envHttpHeaders, incoming.envHttpHeaders),
473
+ enabled: incoming.enabled ?? existing.enabled,
474
+ startupTimeoutSec: incoming.startupTimeoutSec ?? existing.startupTimeoutSec,
475
+ toolTimeoutSec: incoming.toolTimeoutSec ?? existing.toolTimeoutSec,
476
+ enabledTools: incoming.enabledTools ?? existing.enabledTools,
477
+ disabledTools: incoming.disabledTools ?? existing.disabledTools
293
478
  };
479
+ return result;
480
+ }
481
+ mergeStringRecord(base, override) {
482
+ if (override !== void 0) {
483
+ if (Object.keys(override).length === 0) return {};
484
+ return { ...base ?? {}, ...override };
485
+ }
486
+ if (base) return { ...base };
487
+ return void 0;
294
488
  }
295
489
  // Codex JSONL items use `type` for the item discriminator, but some
296
490
  // earlier fixtures (and defensive parsing) might still surface `item_type`.
@@ -302,7 +496,7 @@ var CodexCliLanguageModel = class {
302
496
  const current = typeof data.type === "string" ? data.type : void 0;
303
497
  return legacy ?? current;
304
498
  }
305
- buildArgs(promptText, responseFormat, settings = this.settings) {
499
+ buildArgs(promptText, images = [], responseFormat, settings = this.settings) {
306
500
  const base = resolveCodexPath(settings.codexPath, settings.allowNpx);
307
501
  const args = [...base.args, "exec", "--experimental-json"];
308
502
  if (settings.fullAuto) {
@@ -342,12 +536,20 @@ var CodexCliLanguageModel = class {
342
536
  if (settings.webSearch) {
343
537
  args.push("-c", "tools.web_search=true");
344
538
  }
539
+ this.applyMcpSettings(args, settings);
345
540
  if (settings.color) {
346
541
  args.push("--color", settings.color);
347
542
  }
348
543
  if (this.modelId) {
349
544
  args.push("-m", this.modelId);
350
545
  }
546
+ if (settings.addDirs?.length) {
547
+ for (const dir of settings.addDirs) {
548
+ if (typeof dir === "string" && dir.trim().length > 0) {
549
+ args.push("--add-dir", dir);
550
+ }
551
+ }
552
+ }
351
553
  if (settings.configOverrides) {
352
554
  for (const [key, value] of Object.entries(settings.configOverrides)) {
353
555
  this.addConfigOverride(args, key, value);
@@ -369,6 +571,16 @@ var CodexCliLanguageModel = class {
369
571
  args.push("--output-schema", schemaPath);
370
572
  }
371
573
  }
574
+ const tempImagePaths = [];
575
+ for (const img of images) {
576
+ try {
577
+ const tempPath = writeImageToTempFile(img);
578
+ tempImagePaths.push(tempPath);
579
+ args.push("--image", tempPath);
580
+ } catch (e) {
581
+ this.logger.warn(`[codex-cli] Failed to write image to temp file: ${String(e)}`);
582
+ }
583
+ }
372
584
  args.push(promptText);
373
585
  const env = {
374
586
  ...process.env,
@@ -376,16 +588,74 @@ var CodexCliLanguageModel = class {
376
588
  RUST_LOG: process.env.RUST_LOG || "error"
377
589
  };
378
590
  let lastMessagePath = settings.outputLastMessageFile;
591
+ let lastMessageIsTemp = false;
379
592
  if (!lastMessagePath) {
380
593
  const dir = mkdtempSync(join(tmpdir(), "codex-cli-"));
381
594
  lastMessagePath = join(dir, "last-message.txt");
595
+ lastMessageIsTemp = true;
382
596
  }
383
597
  args.push("--output-last-message", lastMessagePath);
384
- return { cmd: base.cmd, args, env, cwd: settings.cwd, lastMessagePath, schemaPath };
598
+ return {
599
+ cmd: base.cmd,
600
+ args,
601
+ env,
602
+ cwd: settings.cwd,
603
+ lastMessagePath,
604
+ lastMessageIsTemp,
605
+ schemaPath,
606
+ tempImagePaths: tempImagePaths.length > 0 ? tempImagePaths : void 0
607
+ };
608
+ }
609
+ applyMcpSettings(args, settings) {
610
+ if (settings.rmcpClient) {
611
+ this.addConfigOverride(args, "features.rmcp_client", true);
612
+ }
613
+ if (!settings.mcpServers) return;
614
+ for (const [rawName, server] of Object.entries(settings.mcpServers)) {
615
+ const name = rawName.trim();
616
+ if (!name) continue;
617
+ const prefix = `mcp_servers.${name}`;
618
+ if (server.enabled !== void 0) {
619
+ this.addConfigOverride(args, `${prefix}.enabled`, server.enabled);
620
+ }
621
+ if (server.startupTimeoutSec !== void 0) {
622
+ this.addConfigOverride(args, `${prefix}.startup_timeout_sec`, server.startupTimeoutSec);
623
+ }
624
+ if (server.toolTimeoutSec !== void 0) {
625
+ this.addConfigOverride(args, `${prefix}.tool_timeout_sec`, server.toolTimeoutSec);
626
+ }
627
+ if (server.enabledTools !== void 0) {
628
+ this.addConfigOverride(args, `${prefix}.enabled_tools`, server.enabledTools);
629
+ }
630
+ if (server.disabledTools !== void 0) {
631
+ this.addConfigOverride(args, `${prefix}.disabled_tools`, server.disabledTools);
632
+ }
633
+ if (server.transport === "stdio") {
634
+ this.addConfigOverride(args, `${prefix}.command`, server.command);
635
+ if (server.args !== void 0) this.addConfigOverride(args, `${prefix}.args`, server.args);
636
+ if (server.env !== void 0) this.addConfigOverride(args, `${prefix}.env`, server.env);
637
+ if (server.cwd) this.addConfigOverride(args, `${prefix}.cwd`, server.cwd);
638
+ } else {
639
+ this.addConfigOverride(args, `${prefix}.url`, server.url);
640
+ if (server.bearerToken !== void 0)
641
+ this.addConfigOverride(args, `${prefix}.bearer_token`, server.bearerToken);
642
+ if (server.bearerTokenEnvVar)
643
+ this.addConfigOverride(args, `${prefix}.bearer_token_env_var`, server.bearerTokenEnvVar);
644
+ if (server.httpHeaders !== void 0)
645
+ this.addConfigOverride(args, `${prefix}.http_headers`, server.httpHeaders);
646
+ if (server.envHttpHeaders !== void 0)
647
+ this.addConfigOverride(args, `${prefix}.env_http_headers`, server.envHttpHeaders);
648
+ }
649
+ }
385
650
  }
386
651
  addConfigOverride(args, key, value) {
387
652
  if (this.isPlainObject(value)) {
388
- for (const [childKey, childValue] of Object.entries(value)) {
653
+ const entries = Object.entries(value);
654
+ if (entries.length === 0) {
655
+ args.push("-c", `${key}={}`);
656
+ return;
657
+ }
658
+ for (const [childKey, childValue] of entries) {
389
659
  this.addConfigOverride(
390
660
  args,
391
661
  `${key}.${childKey}`,
@@ -663,14 +933,14 @@ var CodexCliLanguageModel = class {
663
933
  }
664
934
  async doGenerate(options) {
665
935
  this.logger.debug(`[codex-cli] Starting doGenerate request with model: ${this.modelId}`);
666
- const { promptText, warnings: mappingWarnings } = mapMessagesToPrompt(options.prompt);
936
+ const { promptText, images, warnings: mappingWarnings } = mapMessagesToPrompt(options.prompt);
667
937
  const promptExcerpt = promptText.slice(0, 200);
668
938
  const warnings = [
669
939
  ...this.mapWarnings(options),
670
940
  ...mappingWarnings?.map((m) => ({ type: "other", message: m })) || []
671
941
  ];
672
942
  this.logger.debug(
673
- `[codex-cli] Converted ${options.prompt.length} messages, response format: ${options.responseFormat?.type ?? "none"}`
943
+ `[codex-cli] Converted ${options.prompt.length} messages (${images.length} images), response format: ${options.responseFormat?.type ?? "none"}`
674
944
  );
675
945
  const providerOptions = await parseProviderOptions({
676
946
  provider: this.provider,
@@ -679,11 +949,7 @@ var CodexCliLanguageModel = class {
679
949
  });
680
950
  const effectiveSettings = this.mergeSettings(providerOptions);
681
951
  const responseFormat = options.responseFormat?.type === "json" ? { type: "json", schema: options.responseFormat.schema } : void 0;
682
- const { cmd, args, env, cwd, lastMessagePath, schemaPath } = this.buildArgs(
683
- promptText,
684
- responseFormat,
685
- effectiveSettings
686
- );
952
+ const { cmd, args, env, cwd, lastMessagePath, lastMessageIsTemp, schemaPath, tempImagePaths } = this.buildArgs(promptText, images, responseFormat, effectiveSettings);
687
953
  this.logger.debug(
688
954
  `[codex-cli] Executing Codex CLI: ${cmd} with ${args.length} arguments, cwd: ${cwd ?? "default"}`
689
955
  );
@@ -696,6 +962,16 @@ var CodexCliLanguageModel = class {
696
962
  if (options.abortSignal) {
697
963
  if (options.abortSignal.aborted) {
698
964
  child.kill("SIGTERM");
965
+ if (schemaPath) {
966
+ try {
967
+ const schemaDir = dirname(schemaPath);
968
+ rmSync(schemaDir, { recursive: true, force: true });
969
+ } catch {
970
+ }
971
+ }
972
+ if (tempImagePaths?.length) {
973
+ cleanupTempImages(tempImagePaths);
974
+ }
699
975
  throw options.abortSignal.reason ?? new Error("Request aborted");
700
976
  }
701
977
  onAbort = () => child.kill("SIGTERM");
@@ -790,6 +1066,9 @@ var CodexCliLanguageModel = class {
790
1066
  } catch {
791
1067
  }
792
1068
  }
1069
+ if (tempImagePaths?.length) {
1070
+ cleanupTempImages(tempImagePaths);
1071
+ }
793
1072
  }
794
1073
  if (!text && lastMessagePath) {
795
1074
  try {
@@ -799,9 +1078,11 @@ var CodexCliLanguageModel = class {
799
1078
  }
800
1079
  } catch {
801
1080
  }
802
- try {
803
- rmSync(lastMessagePath, { force: true });
804
- } catch {
1081
+ if (lastMessageIsTemp) {
1082
+ try {
1083
+ rmSync(lastMessagePath, { force: true });
1084
+ } catch {
1085
+ }
805
1086
  }
806
1087
  }
807
1088
  const content = [{ type: "text", text }];
@@ -819,14 +1100,14 @@ var CodexCliLanguageModel = class {
819
1100
  }
820
1101
  async doStream(options) {
821
1102
  this.logger.debug(`[codex-cli] Starting doStream request with model: ${this.modelId}`);
822
- const { promptText, warnings: mappingWarnings } = mapMessagesToPrompt(options.prompt);
1103
+ const { promptText, images, warnings: mappingWarnings } = mapMessagesToPrompt(options.prompt);
823
1104
  const promptExcerpt = promptText.slice(0, 200);
824
1105
  const warnings = [
825
1106
  ...this.mapWarnings(options),
826
1107
  ...mappingWarnings?.map((m) => ({ type: "other", message: m })) || []
827
1108
  ];
828
1109
  this.logger.debug(
829
- `[codex-cli] Converted ${options.prompt.length} messages for streaming, response format: ${options.responseFormat?.type ?? "none"}`
1110
+ `[codex-cli] Converted ${options.prompt.length} messages (${images.length} images) for streaming, response format: ${options.responseFormat?.type ?? "none"}`
830
1111
  );
831
1112
  const providerOptions = await parseProviderOptions({
832
1113
  provider: this.provider,
@@ -835,11 +1116,7 @@ var CodexCliLanguageModel = class {
835
1116
  });
836
1117
  const effectiveSettings = this.mergeSettings(providerOptions);
837
1118
  const responseFormat = options.responseFormat?.type === "json" ? { type: "json", schema: options.responseFormat.schema } : void 0;
838
- const { cmd, args, env, cwd, lastMessagePath, schemaPath } = this.buildArgs(
839
- promptText,
840
- responseFormat,
841
- effectiveSettings
842
- );
1119
+ const { cmd, args, env, cwd, lastMessagePath, lastMessageIsTemp, schemaPath, tempImagePaths } = this.buildArgs(promptText, images, responseFormat, effectiveSettings);
843
1120
  this.logger.debug(
844
1121
  `[codex-cli] Executing Codex CLI for streaming: ${cmd} with ${args.length} arguments`
845
1122
  );
@@ -854,6 +1131,18 @@ var CodexCliLanguageModel = class {
854
1131
  let responseMetadataSent = false;
855
1132
  let lastUsage;
856
1133
  let turnFailureMessage;
1134
+ const cleanupTempFiles = () => {
1135
+ if (schemaPath) {
1136
+ try {
1137
+ const schemaDir = dirname(schemaPath);
1138
+ rmSync(schemaDir, { recursive: true, force: true });
1139
+ } catch {
1140
+ }
1141
+ }
1142
+ if (tempImagePaths?.length) {
1143
+ cleanupTempImages(tempImagePaths);
1144
+ }
1145
+ };
857
1146
  const sendMetadata = (meta = {}) => {
858
1147
  controller.enqueue({
859
1148
  type: "response-metadata",
@@ -927,6 +1216,7 @@ var CodexCliLanguageModel = class {
927
1216
  if (options.abortSignal) {
928
1217
  if (options.abortSignal.aborted) {
929
1218
  child.kill("SIGTERM");
1219
+ cleanupTempFiles();
930
1220
  controller.error(options.abortSignal.reason ?? new Error("Request aborted"));
931
1221
  return;
932
1222
  }
@@ -966,9 +1256,11 @@ var CodexCliLanguageModel = class {
966
1256
  if (fileText) finalText = fileText.trim();
967
1257
  } catch {
968
1258
  }
969
- try {
970
- rmSync(lastMessagePath, { force: true });
971
- } catch {
1259
+ if (lastMessageIsTemp) {
1260
+ try {
1261
+ rmSync(lastMessagePath, { force: true });
1262
+ } catch {
1263
+ }
972
1264
  }
973
1265
  }
974
1266
  if (finalText) {
@@ -1044,23 +1336,15 @@ var CodexCliLanguageModel = class {
1044
1336
  }
1045
1337
  }
1046
1338
  });
1047
- const cleanupSchema = () => {
1048
- if (!schemaPath) return;
1049
- try {
1050
- const schemaDir = dirname(schemaPath);
1051
- rmSync(schemaDir, { recursive: true, force: true });
1052
- } catch {
1053
- }
1054
- };
1055
1339
  child.on("error", (e) => {
1056
1340
  this.logger.error(`[codex-cli] Stream spawn error: ${String(e)}`);
1057
1341
  if (options.abortSignal) options.abortSignal.removeEventListener("abort", onAbort);
1058
- cleanupSchema();
1342
+ cleanupTempFiles();
1059
1343
  controller.error(this.handleSpawnError(e, promptExcerpt));
1060
1344
  });
1061
1345
  child.on("close", (code) => {
1062
1346
  if (options.abortSignal) options.abortSignal.removeEventListener("abort", onAbort);
1063
- cleanupSchema();
1347
+ cleanupTempFiles();
1064
1348
  setImmediate(() => finishStream(code));
1065
1349
  });
1066
1350
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-sdk-provider-codex-cli",
3
- "version": "0.5.2",
3
+ "version": "0.7.0",
4
4
  "description": "AI SDK v5 provider for OpenAI Codex CLI with native JSON Schema support",
5
5
  "keywords": [
6
6
  "ai-sdk",