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/README.md +70 -0
- package/dist/index.cjs +322 -38
- package/dist/index.d.cts +79 -0
- package/dist/index.d.ts +79 -0
- package/dist/index.js +322 -38
- package/package.json +1 -1
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
|
|
169
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
803
|
-
|
|
804
|
-
|
|
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
|
-
|
|
970
|
-
|
|
971
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1347
|
+
cleanupTempFiles();
|
|
1064
1348
|
setImmediate(() => finishStream(code));
|
|
1065
1349
|
});
|
|
1066
1350
|
},
|