ai-sdk-provider-codex-cli 0.5.1 → 0.6.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 +31 -3
- package/dist/index.cjs +182 -14
- package/dist/index.d.cts +83 -4
- package/dist/index.d.ts +83 -4
- package/dist/index.js +182 -14
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
[](https://github.com/ben-vargas/ai-sdk-provider-codex-cli/issues)
|
|
11
11
|
[](https://github.com/ben-vargas/ai-sdk-provider-codex-cli/releases/latest)
|
|
12
12
|
|
|
13
|
-
A community provider for Vercel AI SDK v5 that uses OpenAI’s Codex CLI (non‑interactive `codex exec`) to talk to GPT‑5.1 class models (`gpt-5.1`, the Codex-specific `gpt-5.1-codex`, and the lightweight `gpt-5.1-codex-mini` slugs) with your ChatGPT Plus/Pro subscription. The provider spawns the Codex CLI process, parses its JSONL output, and adapts it to the AI SDK LanguageModelV2 interface. Legacy GPT-5 / GPT-5-codex slugs remain compatible for existing workflows.
|
|
13
|
+
A community provider for Vercel AI SDK v5 that uses OpenAI’s Codex CLI (non‑interactive `codex exec`) to talk to GPT‑5.1 class models (`gpt-5.1`, the Codex-specific `gpt-5.1-codex`, the flagship `gpt-5.1-codex-max`, and the lightweight `gpt-5.1-codex-mini` slugs) with your ChatGPT Plus/Pro subscription. The provider spawns the Codex CLI process, parses its JSONL output, and adapts it to the AI SDK LanguageModelV2 interface. Legacy GPT-5 / GPT-5-codex slugs remain compatible for existing workflows.
|
|
14
14
|
|
|
15
15
|
- Works with `generateText`, `streamText`, and `generateObject` (native JSON Schema support via `--output-schema`)
|
|
16
16
|
- Uses ChatGPT OAuth from `codex login` (tokens in `~/.codex/auth.json`) or `OPENAI_API_KEY`
|
|
@@ -28,7 +28,7 @@ npm i -g @openai/codex
|
|
|
28
28
|
codex login # or set OPENAI_API_KEY
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
> **⚠️ Version Requirement**: Requires Codex CLI **>= 0.42.0** for `--experimental-json` and `--output-schema` support. **>= 0.
|
|
31
|
+
> **⚠️ Version Requirement**: Requires Codex CLI **>= 0.42.0** for `--experimental-json` and `--output-schema` support. **>= 0.60.0 recommended** for `gpt-5.1-codex-max` and `xhigh` reasoning effort. If you supply your own Codex CLI (global install or custom `codexPath`/`allowNpx`), check it with `codex --version` and upgrade if needed. The optional dependency `@openai/codex` in this package pulls a compatible version automatically.
|
|
32
32
|
>
|
|
33
33
|
> ```bash
|
|
34
34
|
> npm i -g @openai/codex@latest
|
|
@@ -223,6 +223,7 @@ When OpenAI adds streaming support, this provider will be updated to handle thos
|
|
|
223
223
|
|
|
224
224
|
- `allowNpx`: If true, falls back to `npx -y @openai/codex` when Codex is not on PATH
|
|
225
225
|
- `cwd`: Working directory for Codex
|
|
226
|
+
- `addDirs`: Extra directories Codex may read/write (repeats `--add-dir`)
|
|
226
227
|
- Autonomy/sandbox:
|
|
227
228
|
- `fullAuto` (equivalent to `--full-auto`)
|
|
228
229
|
- `dangerouslyBypassApprovalsAndSandbox` (bypass approvals and sandbox; dangerous)
|
|
@@ -246,9 +247,10 @@ import { codexCli } from 'ai-sdk-provider-codex-cli';
|
|
|
246
247
|
const model = codexCli('gpt-5.1-codex', {
|
|
247
248
|
allowNpx: true,
|
|
248
249
|
skipGitRepoCheck: true,
|
|
250
|
+
addDirs: ['../shared'],
|
|
249
251
|
|
|
250
252
|
// Reasoning & verbosity
|
|
251
|
-
reasoningEffort: 'medium', // minimal | low | medium | high
|
|
253
|
+
reasoningEffort: 'medium', // minimal | low | medium | high | xhigh (xhigh only on gpt-5.1-codex-max)
|
|
252
254
|
reasoningSummary: 'auto', // auto | detailed (Note: 'concise' and 'none' are rejected by API)
|
|
253
255
|
reasoningSummaryFormat: 'none', // none | experimental
|
|
254
256
|
modelVerbosity: 'high', // low | medium | high
|
|
@@ -259,6 +261,23 @@ const model = codexCli('gpt-5.1-codex', {
|
|
|
259
261
|
oss: false, // adds --oss when true
|
|
260
262
|
webSearch: true, // maps to -c tools.web_search=true
|
|
261
263
|
|
|
264
|
+
// MCP servers (stdio + HTTP/RMCP)
|
|
265
|
+
rmcpClient: true, // enables HTTP-based MCP clients (features.rmcp_client=true)
|
|
266
|
+
mcpServers: {
|
|
267
|
+
local: {
|
|
268
|
+
transport: 'stdio',
|
|
269
|
+
command: 'node',
|
|
270
|
+
args: ['tools/mcp.js'],
|
|
271
|
+
env: { API_KEY: process.env.MCP_API_KEY ?? '' },
|
|
272
|
+
},
|
|
273
|
+
docs: {
|
|
274
|
+
transport: 'http',
|
|
275
|
+
url: 'https://mcp.my-org.com',
|
|
276
|
+
bearerTokenEnvVar: 'MCP_BEARER',
|
|
277
|
+
httpHeaders: { 'x-tenant': 'acme' },
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
|
|
262
281
|
// Generic overrides (maps to -c key=value)
|
|
263
282
|
configOverrides: {
|
|
264
283
|
experimental_resume: '/tmp/session.jsonl',
|
|
@@ -269,6 +288,7 @@ const model = codexCli('gpt-5.1-codex', {
|
|
|
269
288
|
|
|
270
289
|
Nested override objects are flattened to dotted keys (e.g., the example above emits
|
|
271
290
|
`-c sandbox_workspace_write.network_access=true`). Arrays are serialized to JSON strings.
|
|
291
|
+
MCP server env/header objects flatten the same way (e.g., `mcp_servers.docs.http_headers.x-tenant=acme`).
|
|
272
292
|
|
|
273
293
|
### Per-call overrides via `providerOptions` (v0.4.0+)
|
|
274
294
|
|
|
@@ -293,6 +313,14 @@ const response = await generateText({
|
|
|
293
313
|
reasoningEffort: 'high',
|
|
294
314
|
reasoningSummary: 'detailed',
|
|
295
315
|
textVerbosity: 'high', // AI SDK naming; maps to model_verbosity
|
|
316
|
+
rmcpClient: true,
|
|
317
|
+
mcpServers: {
|
|
318
|
+
scratch: {
|
|
319
|
+
transport: 'stdio',
|
|
320
|
+
command: 'pnpm',
|
|
321
|
+
args: ['mcp', 'serve'],
|
|
322
|
+
},
|
|
323
|
+
},
|
|
296
324
|
configOverrides: {
|
|
297
325
|
experimental_resume: '/tmp/resume.jsonl',
|
|
298
326
|
},
|
package/dist/index.cjs
CHANGED
|
@@ -68,9 +68,37 @@ var loggerFunctionSchema = zod.z.object({
|
|
|
68
68
|
message: "error must be a function"
|
|
69
69
|
})
|
|
70
70
|
});
|
|
71
|
+
var mcpServerBaseSchema = zod.z.object({
|
|
72
|
+
enabled: zod.z.boolean().optional(),
|
|
73
|
+
startupTimeoutSec: zod.z.number().int().positive().optional(),
|
|
74
|
+
toolTimeoutSec: zod.z.number().int().positive().optional(),
|
|
75
|
+
enabledTools: zod.z.array(zod.z.string()).optional(),
|
|
76
|
+
disabledTools: zod.z.array(zod.z.string()).optional()
|
|
77
|
+
});
|
|
78
|
+
var mcpServerStdioSchema = mcpServerBaseSchema.extend({
|
|
79
|
+
transport: zod.z.literal("stdio"),
|
|
80
|
+
command: zod.z.string().min(1),
|
|
81
|
+
args: zod.z.array(zod.z.string()).optional(),
|
|
82
|
+
env: zod.z.record(zod.z.string(), zod.z.string()).optional(),
|
|
83
|
+
cwd: zod.z.string().optional()
|
|
84
|
+
});
|
|
85
|
+
var mcpServerHttpSchema = mcpServerBaseSchema.extend({
|
|
86
|
+
transport: zod.z.literal("http"),
|
|
87
|
+
url: zod.z.string().min(1),
|
|
88
|
+
bearerToken: zod.z.string().optional(),
|
|
89
|
+
bearerTokenEnvVar: zod.z.string().optional(),
|
|
90
|
+
httpHeaders: zod.z.record(zod.z.string(), zod.z.string()).optional(),
|
|
91
|
+
envHttpHeaders: zod.z.record(zod.z.string(), zod.z.string()).optional()
|
|
92
|
+
});
|
|
93
|
+
var mcpServerSchema = zod.z.discriminatedUnion("transport", [
|
|
94
|
+
mcpServerStdioSchema,
|
|
95
|
+
mcpServerHttpSchema
|
|
96
|
+
]);
|
|
97
|
+
var mcpServersSchema = zod.z.record(zod.z.string(), mcpServerSchema);
|
|
71
98
|
var settingsSchema = zod.z.object({
|
|
72
99
|
codexPath: zod.z.string().optional(),
|
|
73
100
|
cwd: zod.z.string().optional(),
|
|
101
|
+
addDirs: zod.z.array(zod.z.string().min(1)).optional(),
|
|
74
102
|
approvalMode: zod.z.enum(["untrusted", "on-failure", "on-request", "never"]).optional(),
|
|
75
103
|
sandboxMode: zod.z.enum(["read-only", "workspace-write", "danger-full-access"]).optional(),
|
|
76
104
|
fullAuto: zod.z.boolean().optional(),
|
|
@@ -78,11 +106,12 @@ var settingsSchema = zod.z.object({
|
|
|
78
106
|
skipGitRepoCheck: zod.z.boolean().optional(),
|
|
79
107
|
color: zod.z.enum(["always", "never", "auto"]).optional(),
|
|
80
108
|
allowNpx: zod.z.boolean().optional(),
|
|
109
|
+
outputLastMessageFile: zod.z.string().optional(),
|
|
81
110
|
env: zod.z.record(zod.z.string(), zod.z.string()).optional(),
|
|
82
111
|
verbose: zod.z.boolean().optional(),
|
|
83
112
|
logger: zod.z.union([zod.z.literal(false), loggerFunctionSchema]).optional(),
|
|
84
113
|
// NEW: Reasoning & Verbosity
|
|
85
|
-
reasoningEffort: zod.z.enum(["minimal", "low", "medium", "high"]).optional(),
|
|
114
|
+
reasoningEffort: zod.z.enum(["minimal", "low", "medium", "high", "xhigh"]).optional(),
|
|
86
115
|
// Note: API rejects 'concise' and 'none' despite error messages claiming they're valid
|
|
87
116
|
reasoningSummary: zod.z.enum(["auto", "detailed"]).optional(),
|
|
88
117
|
reasoningSummaryFormat: zod.z.enum(["none", "experimental"]).optional(),
|
|
@@ -92,6 +121,8 @@ var settingsSchema = zod.z.object({
|
|
|
92
121
|
profile: zod.z.string().optional(),
|
|
93
122
|
oss: zod.z.boolean().optional(),
|
|
94
123
|
webSearch: zod.z.boolean().optional(),
|
|
124
|
+
mcpServers: mcpServersSchema.optional(),
|
|
125
|
+
rmcpClient: zod.z.boolean().optional(),
|
|
95
126
|
// NEW: Generic overrides
|
|
96
127
|
configOverrides: zod.z.record(
|
|
97
128
|
zod.z.string(),
|
|
@@ -231,10 +262,11 @@ function isAuthenticationError(err) {
|
|
|
231
262
|
|
|
232
263
|
// src/codex-cli-language-model.ts
|
|
233
264
|
var codexCliProviderOptionsSchema = zod.z.object({
|
|
234
|
-
reasoningEffort: zod.z.enum(["minimal", "low", "medium", "high"]).optional(),
|
|
265
|
+
reasoningEffort: zod.z.enum(["minimal", "low", "medium", "high", "xhigh"]).optional(),
|
|
235
266
|
reasoningSummary: zod.z.enum(["auto", "detailed"]).optional(),
|
|
236
267
|
reasoningSummaryFormat: zod.z.enum(["none", "experimental"]).optional(),
|
|
237
268
|
textVerbosity: zod.z.enum(["low", "medium", "high"]).optional(),
|
|
269
|
+
addDirs: zod.z.array(zod.z.string().min(1)).optional(),
|
|
238
270
|
configOverrides: zod.z.record(
|
|
239
271
|
zod.z.string(),
|
|
240
272
|
zod.z.union([
|
|
@@ -244,7 +276,9 @@ var codexCliProviderOptionsSchema = zod.z.object({
|
|
|
244
276
|
zod.z.object({}).passthrough(),
|
|
245
277
|
zod.z.array(zod.z.any())
|
|
246
278
|
])
|
|
247
|
-
).optional()
|
|
279
|
+
).optional(),
|
|
280
|
+
mcpServers: mcpServersSchema.optional(),
|
|
281
|
+
rmcpClient: zod.z.boolean().optional()
|
|
248
282
|
}).strict();
|
|
249
283
|
function resolveCodexPath(explicitPath, allowNpx) {
|
|
250
284
|
if (explicitPath) return { cmd: "node", args: [explicitPath] };
|
|
@@ -286,15 +320,80 @@ var CodexCliLanguageModel = class {
|
|
|
286
320
|
...this.settings.configOverrides ?? {},
|
|
287
321
|
...providerOptions.configOverrides ?? {}
|
|
288
322
|
} : void 0;
|
|
323
|
+
const mergedAddDirs = providerOptions.addDirs || this.settings.addDirs ? [...this.settings.addDirs ?? [], ...providerOptions.addDirs ?? []] : void 0;
|
|
324
|
+
const mergedMcpServers = this.mergeMcpServers(
|
|
325
|
+
this.settings.mcpServers,
|
|
326
|
+
providerOptions.mcpServers
|
|
327
|
+
);
|
|
289
328
|
return {
|
|
290
329
|
...this.settings,
|
|
291
330
|
reasoningEffort: providerOptions.reasoningEffort ?? this.settings.reasoningEffort,
|
|
292
331
|
reasoningSummary: providerOptions.reasoningSummary ?? this.settings.reasoningSummary,
|
|
293
332
|
reasoningSummaryFormat: providerOptions.reasoningSummaryFormat ?? this.settings.reasoningSummaryFormat,
|
|
294
333
|
modelVerbosity: providerOptions.textVerbosity ?? this.settings.modelVerbosity,
|
|
295
|
-
configOverrides: mergedConfigOverrides
|
|
334
|
+
configOverrides: mergedConfigOverrides,
|
|
335
|
+
addDirs: mergedAddDirs,
|
|
336
|
+
mcpServers: mergedMcpServers,
|
|
337
|
+
rmcpClient: providerOptions.rmcpClient ?? this.settings.rmcpClient
|
|
296
338
|
};
|
|
297
339
|
}
|
|
340
|
+
mergeMcpServers(base, override) {
|
|
341
|
+
if (!base) return override;
|
|
342
|
+
if (!override) return base;
|
|
343
|
+
const merged = { ...base };
|
|
344
|
+
for (const [name, incoming] of Object.entries(override)) {
|
|
345
|
+
const existing = base[name];
|
|
346
|
+
merged[name] = this.mergeSingleMcpServer(existing, incoming);
|
|
347
|
+
}
|
|
348
|
+
return merged;
|
|
349
|
+
}
|
|
350
|
+
mergeSingleMcpServer(existing, incoming) {
|
|
351
|
+
if (!existing || existing.transport !== incoming.transport) {
|
|
352
|
+
return { ...incoming };
|
|
353
|
+
}
|
|
354
|
+
if (incoming.transport === "stdio") {
|
|
355
|
+
const baseStdio = existing;
|
|
356
|
+
const result2 = {
|
|
357
|
+
transport: "stdio",
|
|
358
|
+
command: incoming.command,
|
|
359
|
+
args: incoming.args ?? baseStdio.args,
|
|
360
|
+
env: this.mergeStringRecord(baseStdio.env, incoming.env),
|
|
361
|
+
cwd: incoming.cwd ?? baseStdio.cwd,
|
|
362
|
+
enabled: incoming.enabled ?? existing.enabled,
|
|
363
|
+
startupTimeoutSec: incoming.startupTimeoutSec ?? existing.startupTimeoutSec,
|
|
364
|
+
toolTimeoutSec: incoming.toolTimeoutSec ?? existing.toolTimeoutSec,
|
|
365
|
+
enabledTools: incoming.enabledTools ?? existing.enabledTools,
|
|
366
|
+
disabledTools: incoming.disabledTools ?? existing.disabledTools
|
|
367
|
+
};
|
|
368
|
+
return result2;
|
|
369
|
+
}
|
|
370
|
+
const baseHttp = existing;
|
|
371
|
+
const hasIncomingAuth = incoming.bearerToken !== void 0 || incoming.bearerTokenEnvVar !== void 0;
|
|
372
|
+
const bearerToken = hasIncomingAuth ? incoming.bearerToken : baseHttp.bearerToken;
|
|
373
|
+
const bearerTokenEnvVar = hasIncomingAuth ? incoming.bearerTokenEnvVar : baseHttp.bearerTokenEnvVar;
|
|
374
|
+
const result = {
|
|
375
|
+
transport: "http",
|
|
376
|
+
url: incoming.url,
|
|
377
|
+
bearerToken,
|
|
378
|
+
bearerTokenEnvVar,
|
|
379
|
+
httpHeaders: this.mergeStringRecord(baseHttp.httpHeaders, incoming.httpHeaders),
|
|
380
|
+
envHttpHeaders: this.mergeStringRecord(baseHttp.envHttpHeaders, incoming.envHttpHeaders),
|
|
381
|
+
enabled: incoming.enabled ?? existing.enabled,
|
|
382
|
+
startupTimeoutSec: incoming.startupTimeoutSec ?? existing.startupTimeoutSec,
|
|
383
|
+
toolTimeoutSec: incoming.toolTimeoutSec ?? existing.toolTimeoutSec,
|
|
384
|
+
enabledTools: incoming.enabledTools ?? existing.enabledTools,
|
|
385
|
+
disabledTools: incoming.disabledTools ?? existing.disabledTools
|
|
386
|
+
};
|
|
387
|
+
return result;
|
|
388
|
+
}
|
|
389
|
+
mergeStringRecord(base, override) {
|
|
390
|
+
if (override !== void 0) {
|
|
391
|
+
if (Object.keys(override).length === 0) return {};
|
|
392
|
+
return { ...base ?? {}, ...override };
|
|
393
|
+
}
|
|
394
|
+
if (base) return { ...base };
|
|
395
|
+
return void 0;
|
|
396
|
+
}
|
|
298
397
|
// Codex JSONL items use `type` for the item discriminator, but some
|
|
299
398
|
// earlier fixtures (and defensive parsing) might still surface `item_type`.
|
|
300
399
|
// This helper returns whichever is present.
|
|
@@ -345,12 +444,20 @@ var CodexCliLanguageModel = class {
|
|
|
345
444
|
if (settings.webSearch) {
|
|
346
445
|
args.push("-c", "tools.web_search=true");
|
|
347
446
|
}
|
|
447
|
+
this.applyMcpSettings(args, settings);
|
|
348
448
|
if (settings.color) {
|
|
349
449
|
args.push("--color", settings.color);
|
|
350
450
|
}
|
|
351
451
|
if (this.modelId) {
|
|
352
452
|
args.push("-m", this.modelId);
|
|
353
453
|
}
|
|
454
|
+
if (settings.addDirs?.length) {
|
|
455
|
+
for (const dir of settings.addDirs) {
|
|
456
|
+
if (typeof dir === "string" && dir.trim().length > 0) {
|
|
457
|
+
args.push("--add-dir", dir);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
354
461
|
if (settings.configOverrides) {
|
|
355
462
|
for (const [key, value] of Object.entries(settings.configOverrides)) {
|
|
356
463
|
this.addConfigOverride(args, key, value);
|
|
@@ -379,16 +486,73 @@ var CodexCliLanguageModel = class {
|
|
|
379
486
|
RUST_LOG: process.env.RUST_LOG || "error"
|
|
380
487
|
};
|
|
381
488
|
let lastMessagePath = settings.outputLastMessageFile;
|
|
489
|
+
let lastMessageIsTemp = false;
|
|
382
490
|
if (!lastMessagePath) {
|
|
383
491
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "codex-cli-"));
|
|
384
492
|
lastMessagePath = path.join(dir, "last-message.txt");
|
|
493
|
+
lastMessageIsTemp = true;
|
|
385
494
|
}
|
|
386
495
|
args.push("--output-last-message", lastMessagePath);
|
|
387
|
-
return {
|
|
496
|
+
return {
|
|
497
|
+
cmd: base.cmd,
|
|
498
|
+
args,
|
|
499
|
+
env,
|
|
500
|
+
cwd: settings.cwd,
|
|
501
|
+
lastMessagePath,
|
|
502
|
+
lastMessageIsTemp,
|
|
503
|
+
schemaPath
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
applyMcpSettings(args, settings) {
|
|
507
|
+
if (settings.rmcpClient) {
|
|
508
|
+
this.addConfigOverride(args, "features.rmcp_client", true);
|
|
509
|
+
}
|
|
510
|
+
if (!settings.mcpServers) return;
|
|
511
|
+
for (const [rawName, server] of Object.entries(settings.mcpServers)) {
|
|
512
|
+
const name = rawName.trim();
|
|
513
|
+
if (!name) continue;
|
|
514
|
+
const prefix = `mcp_servers.${name}`;
|
|
515
|
+
if (server.enabled !== void 0) {
|
|
516
|
+
this.addConfigOverride(args, `${prefix}.enabled`, server.enabled);
|
|
517
|
+
}
|
|
518
|
+
if (server.startupTimeoutSec !== void 0) {
|
|
519
|
+
this.addConfigOverride(args, `${prefix}.startup_timeout_sec`, server.startupTimeoutSec);
|
|
520
|
+
}
|
|
521
|
+
if (server.toolTimeoutSec !== void 0) {
|
|
522
|
+
this.addConfigOverride(args, `${prefix}.tool_timeout_sec`, server.toolTimeoutSec);
|
|
523
|
+
}
|
|
524
|
+
if (server.enabledTools !== void 0) {
|
|
525
|
+
this.addConfigOverride(args, `${prefix}.enabled_tools`, server.enabledTools);
|
|
526
|
+
}
|
|
527
|
+
if (server.disabledTools !== void 0) {
|
|
528
|
+
this.addConfigOverride(args, `${prefix}.disabled_tools`, server.disabledTools);
|
|
529
|
+
}
|
|
530
|
+
if (server.transport === "stdio") {
|
|
531
|
+
this.addConfigOverride(args, `${prefix}.command`, server.command);
|
|
532
|
+
if (server.args !== void 0) this.addConfigOverride(args, `${prefix}.args`, server.args);
|
|
533
|
+
if (server.env !== void 0) this.addConfigOverride(args, `${prefix}.env`, server.env);
|
|
534
|
+
if (server.cwd) this.addConfigOverride(args, `${prefix}.cwd`, server.cwd);
|
|
535
|
+
} else {
|
|
536
|
+
this.addConfigOverride(args, `${prefix}.url`, server.url);
|
|
537
|
+
if (server.bearerToken !== void 0)
|
|
538
|
+
this.addConfigOverride(args, `${prefix}.bearer_token`, server.bearerToken);
|
|
539
|
+
if (server.bearerTokenEnvVar)
|
|
540
|
+
this.addConfigOverride(args, `${prefix}.bearer_token_env_var`, server.bearerTokenEnvVar);
|
|
541
|
+
if (server.httpHeaders !== void 0)
|
|
542
|
+
this.addConfigOverride(args, `${prefix}.http_headers`, server.httpHeaders);
|
|
543
|
+
if (server.envHttpHeaders !== void 0)
|
|
544
|
+
this.addConfigOverride(args, `${prefix}.env_http_headers`, server.envHttpHeaders);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
388
547
|
}
|
|
389
548
|
addConfigOverride(args, key, value) {
|
|
390
549
|
if (this.isPlainObject(value)) {
|
|
391
|
-
|
|
550
|
+
const entries = Object.entries(value);
|
|
551
|
+
if (entries.length === 0) {
|
|
552
|
+
args.push("-c", `${key}={}`);
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
for (const [childKey, childValue] of entries) {
|
|
392
556
|
this.addConfigOverride(
|
|
393
557
|
args,
|
|
394
558
|
`${key}.${childKey}`,
|
|
@@ -682,7 +846,7 @@ var CodexCliLanguageModel = class {
|
|
|
682
846
|
});
|
|
683
847
|
const effectiveSettings = this.mergeSettings(providerOptions);
|
|
684
848
|
const responseFormat = options.responseFormat?.type === "json" ? { type: "json", schema: options.responseFormat.schema } : void 0;
|
|
685
|
-
const { cmd, args, env, cwd, lastMessagePath, schemaPath } = this.buildArgs(
|
|
849
|
+
const { cmd, args, env, cwd, lastMessagePath, lastMessageIsTemp, schemaPath } = this.buildArgs(
|
|
686
850
|
promptText,
|
|
687
851
|
responseFormat,
|
|
688
852
|
effectiveSettings
|
|
@@ -802,9 +966,11 @@ var CodexCliLanguageModel = class {
|
|
|
802
966
|
}
|
|
803
967
|
} catch {
|
|
804
968
|
}
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
969
|
+
if (lastMessageIsTemp) {
|
|
970
|
+
try {
|
|
971
|
+
fs.rmSync(lastMessagePath, { force: true });
|
|
972
|
+
} catch {
|
|
973
|
+
}
|
|
808
974
|
}
|
|
809
975
|
}
|
|
810
976
|
const content = [{ type: "text", text }];
|
|
@@ -838,7 +1004,7 @@ var CodexCliLanguageModel = class {
|
|
|
838
1004
|
});
|
|
839
1005
|
const effectiveSettings = this.mergeSettings(providerOptions);
|
|
840
1006
|
const responseFormat = options.responseFormat?.type === "json" ? { type: "json", schema: options.responseFormat.schema } : void 0;
|
|
841
|
-
const { cmd, args, env, cwd, lastMessagePath, schemaPath } = this.buildArgs(
|
|
1007
|
+
const { cmd, args, env, cwd, lastMessagePath, lastMessageIsTemp, schemaPath } = this.buildArgs(
|
|
842
1008
|
promptText,
|
|
843
1009
|
responseFormat,
|
|
844
1010
|
effectiveSettings
|
|
@@ -969,9 +1135,11 @@ var CodexCliLanguageModel = class {
|
|
|
969
1135
|
if (fileText) finalText = fileText.trim();
|
|
970
1136
|
} catch {
|
|
971
1137
|
}
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1138
|
+
if (lastMessageIsTemp) {
|
|
1139
|
+
try {
|
|
1140
|
+
fs.rmSync(lastMessagePath, { force: true });
|
|
1141
|
+
} catch {
|
|
1142
|
+
}
|
|
975
1143
|
}
|
|
976
1144
|
}
|
|
977
1145
|
if (finalText) {
|
package/dist/index.d.cts
CHANGED
|
@@ -37,7 +37,7 @@ interface Logger {
|
|
|
37
37
|
}
|
|
38
38
|
type ApprovalMode = 'untrusted' | 'on-failure' | 'on-request' | 'never';
|
|
39
39
|
type SandboxMode = 'read-only' | 'workspace-write' | 'danger-full-access';
|
|
40
|
-
type ReasoningEffort = 'minimal' | 'low' | 'medium' | 'high';
|
|
40
|
+
type ReasoningEffort = 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
|
|
41
41
|
/**
|
|
42
42
|
* Reasoning summary detail level.
|
|
43
43
|
* Note: The API error messages claim 'concise' and 'none' are valid, but they are
|
|
@@ -46,9 +46,60 @@ type ReasoningEffort = 'minimal' | 'low' | 'medium' | 'high';
|
|
|
46
46
|
type ReasoningSummary = 'auto' | 'detailed';
|
|
47
47
|
type ReasoningSummaryFormat = 'none' | 'experimental';
|
|
48
48
|
type ModelVerbosity = 'low' | 'medium' | 'high';
|
|
49
|
+
interface McpServerBase {
|
|
50
|
+
/**
|
|
51
|
+
* Enable/disable this MCP server without removing its definition.
|
|
52
|
+
* Maps to: `mcp_servers.<name>.enabled`
|
|
53
|
+
*/
|
|
54
|
+
enabled?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Time allowed for the MCP server to start (in seconds).
|
|
57
|
+
* Maps to: `mcp_servers.<name>.startup_timeout_sec`
|
|
58
|
+
*/
|
|
59
|
+
startupTimeoutSec?: number;
|
|
60
|
+
/**
|
|
61
|
+
* Max time a single MCP tool call may run (in seconds).
|
|
62
|
+
* Maps to: `mcp_servers.<name>.tool_timeout_sec`
|
|
63
|
+
*/
|
|
64
|
+
toolTimeoutSec?: number;
|
|
65
|
+
/**
|
|
66
|
+
* Explicit allow/deny lists for tools exposed by the server.
|
|
67
|
+
* Maps to: `mcp_servers.<name>.enabled_tools` / `disabled_tools`
|
|
68
|
+
*/
|
|
69
|
+
enabledTools?: string[];
|
|
70
|
+
disabledTools?: string[];
|
|
71
|
+
}
|
|
72
|
+
interface McpServerStdio extends McpServerBase {
|
|
73
|
+
/** Execute an MCP server over stdio */
|
|
74
|
+
transport: 'stdio';
|
|
75
|
+
/** Command to start the MCP server (e.g., `node`, `python`, or a binary path). */
|
|
76
|
+
command: string;
|
|
77
|
+
/** Arguments passed to the command. */
|
|
78
|
+
args?: string[];
|
|
79
|
+
/** Environment variables passed to the MCP process. */
|
|
80
|
+
env?: Record<string, string>;
|
|
81
|
+
/** Optional working directory for the MCP server process. */
|
|
82
|
+
cwd?: string;
|
|
83
|
+
}
|
|
84
|
+
interface McpServerHttp extends McpServerBase {
|
|
85
|
+
/** Use an HTTP-based MCP server (RMCP). */
|
|
86
|
+
transport: 'http';
|
|
87
|
+
/** Base URL for the MCP server. */
|
|
88
|
+
url: string;
|
|
89
|
+
/** Bearer token supplied inline (use env var variant to avoid embedding secrets). */
|
|
90
|
+
bearerToken?: string;
|
|
91
|
+
/** Name of env var that holds the bearer token. */
|
|
92
|
+
bearerTokenEnvVar?: string;
|
|
93
|
+
/** Static HTTP headers to send with each MCP request. */
|
|
94
|
+
httpHeaders?: Record<string, string>;
|
|
95
|
+
/** Names of env vars whose values should be sent as HTTP headers. */
|
|
96
|
+
envHttpHeaders?: Record<string, string>;
|
|
97
|
+
}
|
|
98
|
+
type McpServerConfig = McpServerStdio | McpServerHttp;
|
|
49
99
|
interface CodexCliSettings {
|
|
50
100
|
codexPath?: string;
|
|
51
101
|
cwd?: string;
|
|
102
|
+
addDirs?: string[];
|
|
52
103
|
approvalMode?: ApprovalMode;
|
|
53
104
|
sandboxMode?: SandboxMode;
|
|
54
105
|
fullAuto?: boolean;
|
|
@@ -64,9 +115,9 @@ interface CodexCliSettings {
|
|
|
64
115
|
* Controls reasoning effort for reasoning-capable models (o3, o4-mini, the GPT-5.1 family,
|
|
65
116
|
* and legacy GPT-5 slugs). Higher effort produces more thorough reasoning at the cost of latency.
|
|
66
117
|
*
|
|
67
|
-
* Codex CLI model presets currently expose `low`/`medium`/`high` for `gpt-5.1` and `gpt-5.1-codex
|
|
68
|
-
*
|
|
69
|
-
* `minimal`, but GPT-5.1 rejects it.
|
|
118
|
+
* Codex CLI model presets currently expose `low`/`medium`/`high` for `gpt-5.1` and `gpt-5.1-codex`.
|
|
119
|
+
* `gpt-5.1-codex-max` additionally supports `xhigh`. `gpt-5.1-codex-mini` only offers `medium`/`high`.
|
|
120
|
+
* The legacy `gpt-5` slug still allowed `minimal`, but GPT-5.1 rejects it.
|
|
70
121
|
*
|
|
71
122
|
* Maps to: `-c model_reasoning_effort=<value>`
|
|
72
123
|
* @see https://platform.openai.com/docs/guides/reasoning
|
|
@@ -97,6 +148,16 @@ interface CodexCliSettings {
|
|
|
97
148
|
* Maps to: `-c model_verbosity=<value>`
|
|
98
149
|
*/
|
|
99
150
|
modelVerbosity?: ModelVerbosity;
|
|
151
|
+
/**
|
|
152
|
+
* Configure MCP servers (stdio or HTTP/RMCP). Keys are server names.
|
|
153
|
+
* Each entry maps to the Codex CLI `mcp_servers.<name>` table.
|
|
154
|
+
*/
|
|
155
|
+
mcpServers?: Record<string, McpServerConfig>;
|
|
156
|
+
/**
|
|
157
|
+
* Enable the RMCP client so HTTP-based MCP servers can be contacted.
|
|
158
|
+
* Maps to: `-c features.rmcp_client=true`
|
|
159
|
+
*/
|
|
160
|
+
rmcpClient?: boolean;
|
|
100
161
|
/**
|
|
101
162
|
* Include experimental plan tool that the model can use to update its current plan.
|
|
102
163
|
*
|
|
@@ -169,11 +230,25 @@ interface CodexCliProviderOptions {
|
|
|
169
230
|
* Maps to Codex `model_verbosity`.
|
|
170
231
|
*/
|
|
171
232
|
textVerbosity?: ModelVerbosity;
|
|
233
|
+
/**
|
|
234
|
+
* Per-call override for extra directories Codex can access.
|
|
235
|
+
* Maps to repeated `--add-dir` flags.
|
|
236
|
+
*/
|
|
237
|
+
addDirs?: string[];
|
|
172
238
|
/**
|
|
173
239
|
* Per-call Codex CLI config overrides. These are merged with
|
|
174
240
|
* constructor-level overrides with per-call values taking precedence.
|
|
175
241
|
*/
|
|
176
242
|
configOverrides?: Record<string, string | number | boolean | object>;
|
|
243
|
+
/**
|
|
244
|
+
* Per-call MCP server definitions. Merged with constructor definitions
|
|
245
|
+
* (per-call servers and fields take precedence).
|
|
246
|
+
*/
|
|
247
|
+
mcpServers?: Record<string, McpServerConfig>;
|
|
248
|
+
/**
|
|
249
|
+
* Per-call override for RMCP client enablement.
|
|
250
|
+
*/
|
|
251
|
+
rmcpClient?: boolean;
|
|
177
252
|
}
|
|
178
253
|
|
|
179
254
|
interface CodexCliProvider extends ProviderV2 {
|
|
@@ -203,8 +278,12 @@ declare class CodexCliLanguageModel implements LanguageModelV2 {
|
|
|
203
278
|
private sessionId?;
|
|
204
279
|
constructor(options: CodexLanguageModelOptions);
|
|
205
280
|
private mergeSettings;
|
|
281
|
+
private mergeMcpServers;
|
|
282
|
+
private mergeSingleMcpServer;
|
|
283
|
+
private mergeStringRecord;
|
|
206
284
|
private getItemType;
|
|
207
285
|
private buildArgs;
|
|
286
|
+
private applyMcpSettings;
|
|
208
287
|
private addConfigOverride;
|
|
209
288
|
/**
|
|
210
289
|
* Serialize a config override value into a CLI-safe string.
|
package/dist/index.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ interface Logger {
|
|
|
37
37
|
}
|
|
38
38
|
type ApprovalMode = 'untrusted' | 'on-failure' | 'on-request' | 'never';
|
|
39
39
|
type SandboxMode = 'read-only' | 'workspace-write' | 'danger-full-access';
|
|
40
|
-
type ReasoningEffort = 'minimal' | 'low' | 'medium' | 'high';
|
|
40
|
+
type ReasoningEffort = 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
|
|
41
41
|
/**
|
|
42
42
|
* Reasoning summary detail level.
|
|
43
43
|
* Note: The API error messages claim 'concise' and 'none' are valid, but they are
|
|
@@ -46,9 +46,60 @@ type ReasoningEffort = 'minimal' | 'low' | 'medium' | 'high';
|
|
|
46
46
|
type ReasoningSummary = 'auto' | 'detailed';
|
|
47
47
|
type ReasoningSummaryFormat = 'none' | 'experimental';
|
|
48
48
|
type ModelVerbosity = 'low' | 'medium' | 'high';
|
|
49
|
+
interface McpServerBase {
|
|
50
|
+
/**
|
|
51
|
+
* Enable/disable this MCP server without removing its definition.
|
|
52
|
+
* Maps to: `mcp_servers.<name>.enabled`
|
|
53
|
+
*/
|
|
54
|
+
enabled?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Time allowed for the MCP server to start (in seconds).
|
|
57
|
+
* Maps to: `mcp_servers.<name>.startup_timeout_sec`
|
|
58
|
+
*/
|
|
59
|
+
startupTimeoutSec?: number;
|
|
60
|
+
/**
|
|
61
|
+
* Max time a single MCP tool call may run (in seconds).
|
|
62
|
+
* Maps to: `mcp_servers.<name>.tool_timeout_sec`
|
|
63
|
+
*/
|
|
64
|
+
toolTimeoutSec?: number;
|
|
65
|
+
/**
|
|
66
|
+
* Explicit allow/deny lists for tools exposed by the server.
|
|
67
|
+
* Maps to: `mcp_servers.<name>.enabled_tools` / `disabled_tools`
|
|
68
|
+
*/
|
|
69
|
+
enabledTools?: string[];
|
|
70
|
+
disabledTools?: string[];
|
|
71
|
+
}
|
|
72
|
+
interface McpServerStdio extends McpServerBase {
|
|
73
|
+
/** Execute an MCP server over stdio */
|
|
74
|
+
transport: 'stdio';
|
|
75
|
+
/** Command to start the MCP server (e.g., `node`, `python`, or a binary path). */
|
|
76
|
+
command: string;
|
|
77
|
+
/** Arguments passed to the command. */
|
|
78
|
+
args?: string[];
|
|
79
|
+
/** Environment variables passed to the MCP process. */
|
|
80
|
+
env?: Record<string, string>;
|
|
81
|
+
/** Optional working directory for the MCP server process. */
|
|
82
|
+
cwd?: string;
|
|
83
|
+
}
|
|
84
|
+
interface McpServerHttp extends McpServerBase {
|
|
85
|
+
/** Use an HTTP-based MCP server (RMCP). */
|
|
86
|
+
transport: 'http';
|
|
87
|
+
/** Base URL for the MCP server. */
|
|
88
|
+
url: string;
|
|
89
|
+
/** Bearer token supplied inline (use env var variant to avoid embedding secrets). */
|
|
90
|
+
bearerToken?: string;
|
|
91
|
+
/** Name of env var that holds the bearer token. */
|
|
92
|
+
bearerTokenEnvVar?: string;
|
|
93
|
+
/** Static HTTP headers to send with each MCP request. */
|
|
94
|
+
httpHeaders?: Record<string, string>;
|
|
95
|
+
/** Names of env vars whose values should be sent as HTTP headers. */
|
|
96
|
+
envHttpHeaders?: Record<string, string>;
|
|
97
|
+
}
|
|
98
|
+
type McpServerConfig = McpServerStdio | McpServerHttp;
|
|
49
99
|
interface CodexCliSettings {
|
|
50
100
|
codexPath?: string;
|
|
51
101
|
cwd?: string;
|
|
102
|
+
addDirs?: string[];
|
|
52
103
|
approvalMode?: ApprovalMode;
|
|
53
104
|
sandboxMode?: SandboxMode;
|
|
54
105
|
fullAuto?: boolean;
|
|
@@ -64,9 +115,9 @@ interface CodexCliSettings {
|
|
|
64
115
|
* Controls reasoning effort for reasoning-capable models (o3, o4-mini, the GPT-5.1 family,
|
|
65
116
|
* and legacy GPT-5 slugs). Higher effort produces more thorough reasoning at the cost of latency.
|
|
66
117
|
*
|
|
67
|
-
* Codex CLI model presets currently expose `low`/`medium`/`high` for `gpt-5.1` and `gpt-5.1-codex
|
|
68
|
-
*
|
|
69
|
-
* `minimal`, but GPT-5.1 rejects it.
|
|
118
|
+
* Codex CLI model presets currently expose `low`/`medium`/`high` for `gpt-5.1` and `gpt-5.1-codex`.
|
|
119
|
+
* `gpt-5.1-codex-max` additionally supports `xhigh`. `gpt-5.1-codex-mini` only offers `medium`/`high`.
|
|
120
|
+
* The legacy `gpt-5` slug still allowed `minimal`, but GPT-5.1 rejects it.
|
|
70
121
|
*
|
|
71
122
|
* Maps to: `-c model_reasoning_effort=<value>`
|
|
72
123
|
* @see https://platform.openai.com/docs/guides/reasoning
|
|
@@ -97,6 +148,16 @@ interface CodexCliSettings {
|
|
|
97
148
|
* Maps to: `-c model_verbosity=<value>`
|
|
98
149
|
*/
|
|
99
150
|
modelVerbosity?: ModelVerbosity;
|
|
151
|
+
/**
|
|
152
|
+
* Configure MCP servers (stdio or HTTP/RMCP). Keys are server names.
|
|
153
|
+
* Each entry maps to the Codex CLI `mcp_servers.<name>` table.
|
|
154
|
+
*/
|
|
155
|
+
mcpServers?: Record<string, McpServerConfig>;
|
|
156
|
+
/**
|
|
157
|
+
* Enable the RMCP client so HTTP-based MCP servers can be contacted.
|
|
158
|
+
* Maps to: `-c features.rmcp_client=true`
|
|
159
|
+
*/
|
|
160
|
+
rmcpClient?: boolean;
|
|
100
161
|
/**
|
|
101
162
|
* Include experimental plan tool that the model can use to update its current plan.
|
|
102
163
|
*
|
|
@@ -169,11 +230,25 @@ interface CodexCliProviderOptions {
|
|
|
169
230
|
* Maps to Codex `model_verbosity`.
|
|
170
231
|
*/
|
|
171
232
|
textVerbosity?: ModelVerbosity;
|
|
233
|
+
/**
|
|
234
|
+
* Per-call override for extra directories Codex can access.
|
|
235
|
+
* Maps to repeated `--add-dir` flags.
|
|
236
|
+
*/
|
|
237
|
+
addDirs?: string[];
|
|
172
238
|
/**
|
|
173
239
|
* Per-call Codex CLI config overrides. These are merged with
|
|
174
240
|
* constructor-level overrides with per-call values taking precedence.
|
|
175
241
|
*/
|
|
176
242
|
configOverrides?: Record<string, string | number | boolean | object>;
|
|
243
|
+
/**
|
|
244
|
+
* Per-call MCP server definitions. Merged with constructor definitions
|
|
245
|
+
* (per-call servers and fields take precedence).
|
|
246
|
+
*/
|
|
247
|
+
mcpServers?: Record<string, McpServerConfig>;
|
|
248
|
+
/**
|
|
249
|
+
* Per-call override for RMCP client enablement.
|
|
250
|
+
*/
|
|
251
|
+
rmcpClient?: boolean;
|
|
177
252
|
}
|
|
178
253
|
|
|
179
254
|
interface CodexCliProvider extends ProviderV2 {
|
|
@@ -203,8 +278,12 @@ declare class CodexCliLanguageModel implements LanguageModelV2 {
|
|
|
203
278
|
private sessionId?;
|
|
204
279
|
constructor(options: CodexLanguageModelOptions);
|
|
205
280
|
private mergeSettings;
|
|
281
|
+
private mergeMcpServers;
|
|
282
|
+
private mergeSingleMcpServer;
|
|
283
|
+
private mergeStringRecord;
|
|
206
284
|
private getItemType;
|
|
207
285
|
private buildArgs;
|
|
286
|
+
private applyMcpSettings;
|
|
208
287
|
private addConfigOverride;
|
|
209
288
|
/**
|
|
210
289
|
* Serialize a config override value into a CLI-safe string.
|
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,11 +103,12 @@ 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(),
|
|
81
110
|
// NEW: Reasoning & Verbosity
|
|
82
|
-
reasoningEffort: z.enum(["minimal", "low", "medium", "high"]).optional(),
|
|
111
|
+
reasoningEffort: z.enum(["minimal", "low", "medium", "high", "xhigh"]).optional(),
|
|
83
112
|
// Note: API rejects 'concise' and 'none' despite error messages claiming they're valid
|
|
84
113
|
reasoningSummary: z.enum(["auto", "detailed"]).optional(),
|
|
85
114
|
reasoningSummaryFormat: z.enum(["none", "experimental"]).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(),
|
|
@@ -228,10 +259,11 @@ function isAuthenticationError(err) {
|
|
|
228
259
|
|
|
229
260
|
// src/codex-cli-language-model.ts
|
|
230
261
|
var codexCliProviderOptionsSchema = z.object({
|
|
231
|
-
reasoningEffort: z.enum(["minimal", "low", "medium", "high"]).optional(),
|
|
262
|
+
reasoningEffort: z.enum(["minimal", "low", "medium", "high", "xhigh"]).optional(),
|
|
232
263
|
reasoningSummary: z.enum(["auto", "detailed"]).optional(),
|
|
233
264
|
reasoningSummaryFormat: z.enum(["none", "experimental"]).optional(),
|
|
234
265
|
textVerbosity: z.enum(["low", "medium", "high"]).optional(),
|
|
266
|
+
addDirs: z.array(z.string().min(1)).optional(),
|
|
235
267
|
configOverrides: z.record(
|
|
236
268
|
z.string(),
|
|
237
269
|
z.union([
|
|
@@ -241,7 +273,9 @@ var codexCliProviderOptionsSchema = z.object({
|
|
|
241
273
|
z.object({}).passthrough(),
|
|
242
274
|
z.array(z.any())
|
|
243
275
|
])
|
|
244
|
-
).optional()
|
|
276
|
+
).optional(),
|
|
277
|
+
mcpServers: mcpServersSchema.optional(),
|
|
278
|
+
rmcpClient: z.boolean().optional()
|
|
245
279
|
}).strict();
|
|
246
280
|
function resolveCodexPath(explicitPath, allowNpx) {
|
|
247
281
|
if (explicitPath) return { cmd: "node", args: [explicitPath] };
|
|
@@ -283,15 +317,80 @@ var CodexCliLanguageModel = class {
|
|
|
283
317
|
...this.settings.configOverrides ?? {},
|
|
284
318
|
...providerOptions.configOverrides ?? {}
|
|
285
319
|
} : void 0;
|
|
320
|
+
const mergedAddDirs = providerOptions.addDirs || this.settings.addDirs ? [...this.settings.addDirs ?? [], ...providerOptions.addDirs ?? []] : void 0;
|
|
321
|
+
const mergedMcpServers = this.mergeMcpServers(
|
|
322
|
+
this.settings.mcpServers,
|
|
323
|
+
providerOptions.mcpServers
|
|
324
|
+
);
|
|
286
325
|
return {
|
|
287
326
|
...this.settings,
|
|
288
327
|
reasoningEffort: providerOptions.reasoningEffort ?? this.settings.reasoningEffort,
|
|
289
328
|
reasoningSummary: providerOptions.reasoningSummary ?? this.settings.reasoningSummary,
|
|
290
329
|
reasoningSummaryFormat: providerOptions.reasoningSummaryFormat ?? this.settings.reasoningSummaryFormat,
|
|
291
330
|
modelVerbosity: providerOptions.textVerbosity ?? this.settings.modelVerbosity,
|
|
292
|
-
configOverrides: mergedConfigOverrides
|
|
331
|
+
configOverrides: mergedConfigOverrides,
|
|
332
|
+
addDirs: mergedAddDirs,
|
|
333
|
+
mcpServers: mergedMcpServers,
|
|
334
|
+
rmcpClient: providerOptions.rmcpClient ?? this.settings.rmcpClient
|
|
293
335
|
};
|
|
294
336
|
}
|
|
337
|
+
mergeMcpServers(base, override) {
|
|
338
|
+
if (!base) return override;
|
|
339
|
+
if (!override) return base;
|
|
340
|
+
const merged = { ...base };
|
|
341
|
+
for (const [name, incoming] of Object.entries(override)) {
|
|
342
|
+
const existing = base[name];
|
|
343
|
+
merged[name] = this.mergeSingleMcpServer(existing, incoming);
|
|
344
|
+
}
|
|
345
|
+
return merged;
|
|
346
|
+
}
|
|
347
|
+
mergeSingleMcpServer(existing, incoming) {
|
|
348
|
+
if (!existing || existing.transport !== incoming.transport) {
|
|
349
|
+
return { ...incoming };
|
|
350
|
+
}
|
|
351
|
+
if (incoming.transport === "stdio") {
|
|
352
|
+
const baseStdio = existing;
|
|
353
|
+
const result2 = {
|
|
354
|
+
transport: "stdio",
|
|
355
|
+
command: incoming.command,
|
|
356
|
+
args: incoming.args ?? baseStdio.args,
|
|
357
|
+
env: this.mergeStringRecord(baseStdio.env, incoming.env),
|
|
358
|
+
cwd: incoming.cwd ?? baseStdio.cwd,
|
|
359
|
+
enabled: incoming.enabled ?? existing.enabled,
|
|
360
|
+
startupTimeoutSec: incoming.startupTimeoutSec ?? existing.startupTimeoutSec,
|
|
361
|
+
toolTimeoutSec: incoming.toolTimeoutSec ?? existing.toolTimeoutSec,
|
|
362
|
+
enabledTools: incoming.enabledTools ?? existing.enabledTools,
|
|
363
|
+
disabledTools: incoming.disabledTools ?? existing.disabledTools
|
|
364
|
+
};
|
|
365
|
+
return result2;
|
|
366
|
+
}
|
|
367
|
+
const baseHttp = existing;
|
|
368
|
+
const hasIncomingAuth = incoming.bearerToken !== void 0 || incoming.bearerTokenEnvVar !== void 0;
|
|
369
|
+
const bearerToken = hasIncomingAuth ? incoming.bearerToken : baseHttp.bearerToken;
|
|
370
|
+
const bearerTokenEnvVar = hasIncomingAuth ? incoming.bearerTokenEnvVar : baseHttp.bearerTokenEnvVar;
|
|
371
|
+
const result = {
|
|
372
|
+
transport: "http",
|
|
373
|
+
url: incoming.url,
|
|
374
|
+
bearerToken,
|
|
375
|
+
bearerTokenEnvVar,
|
|
376
|
+
httpHeaders: this.mergeStringRecord(baseHttp.httpHeaders, incoming.httpHeaders),
|
|
377
|
+
envHttpHeaders: this.mergeStringRecord(baseHttp.envHttpHeaders, incoming.envHttpHeaders),
|
|
378
|
+
enabled: incoming.enabled ?? existing.enabled,
|
|
379
|
+
startupTimeoutSec: incoming.startupTimeoutSec ?? existing.startupTimeoutSec,
|
|
380
|
+
toolTimeoutSec: incoming.toolTimeoutSec ?? existing.toolTimeoutSec,
|
|
381
|
+
enabledTools: incoming.enabledTools ?? existing.enabledTools,
|
|
382
|
+
disabledTools: incoming.disabledTools ?? existing.disabledTools
|
|
383
|
+
};
|
|
384
|
+
return result;
|
|
385
|
+
}
|
|
386
|
+
mergeStringRecord(base, override) {
|
|
387
|
+
if (override !== void 0) {
|
|
388
|
+
if (Object.keys(override).length === 0) return {};
|
|
389
|
+
return { ...base ?? {}, ...override };
|
|
390
|
+
}
|
|
391
|
+
if (base) return { ...base };
|
|
392
|
+
return void 0;
|
|
393
|
+
}
|
|
295
394
|
// Codex JSONL items use `type` for the item discriminator, but some
|
|
296
395
|
// earlier fixtures (and defensive parsing) might still surface `item_type`.
|
|
297
396
|
// This helper returns whichever is present.
|
|
@@ -342,12 +441,20 @@ var CodexCliLanguageModel = class {
|
|
|
342
441
|
if (settings.webSearch) {
|
|
343
442
|
args.push("-c", "tools.web_search=true");
|
|
344
443
|
}
|
|
444
|
+
this.applyMcpSettings(args, settings);
|
|
345
445
|
if (settings.color) {
|
|
346
446
|
args.push("--color", settings.color);
|
|
347
447
|
}
|
|
348
448
|
if (this.modelId) {
|
|
349
449
|
args.push("-m", this.modelId);
|
|
350
450
|
}
|
|
451
|
+
if (settings.addDirs?.length) {
|
|
452
|
+
for (const dir of settings.addDirs) {
|
|
453
|
+
if (typeof dir === "string" && dir.trim().length > 0) {
|
|
454
|
+
args.push("--add-dir", dir);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
351
458
|
if (settings.configOverrides) {
|
|
352
459
|
for (const [key, value] of Object.entries(settings.configOverrides)) {
|
|
353
460
|
this.addConfigOverride(args, key, value);
|
|
@@ -376,16 +483,73 @@ var CodexCliLanguageModel = class {
|
|
|
376
483
|
RUST_LOG: process.env.RUST_LOG || "error"
|
|
377
484
|
};
|
|
378
485
|
let lastMessagePath = settings.outputLastMessageFile;
|
|
486
|
+
let lastMessageIsTemp = false;
|
|
379
487
|
if (!lastMessagePath) {
|
|
380
488
|
const dir = mkdtempSync(join(tmpdir(), "codex-cli-"));
|
|
381
489
|
lastMessagePath = join(dir, "last-message.txt");
|
|
490
|
+
lastMessageIsTemp = true;
|
|
382
491
|
}
|
|
383
492
|
args.push("--output-last-message", lastMessagePath);
|
|
384
|
-
return {
|
|
493
|
+
return {
|
|
494
|
+
cmd: base.cmd,
|
|
495
|
+
args,
|
|
496
|
+
env,
|
|
497
|
+
cwd: settings.cwd,
|
|
498
|
+
lastMessagePath,
|
|
499
|
+
lastMessageIsTemp,
|
|
500
|
+
schemaPath
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
applyMcpSettings(args, settings) {
|
|
504
|
+
if (settings.rmcpClient) {
|
|
505
|
+
this.addConfigOverride(args, "features.rmcp_client", true);
|
|
506
|
+
}
|
|
507
|
+
if (!settings.mcpServers) return;
|
|
508
|
+
for (const [rawName, server] of Object.entries(settings.mcpServers)) {
|
|
509
|
+
const name = rawName.trim();
|
|
510
|
+
if (!name) continue;
|
|
511
|
+
const prefix = `mcp_servers.${name}`;
|
|
512
|
+
if (server.enabled !== void 0) {
|
|
513
|
+
this.addConfigOverride(args, `${prefix}.enabled`, server.enabled);
|
|
514
|
+
}
|
|
515
|
+
if (server.startupTimeoutSec !== void 0) {
|
|
516
|
+
this.addConfigOverride(args, `${prefix}.startup_timeout_sec`, server.startupTimeoutSec);
|
|
517
|
+
}
|
|
518
|
+
if (server.toolTimeoutSec !== void 0) {
|
|
519
|
+
this.addConfigOverride(args, `${prefix}.tool_timeout_sec`, server.toolTimeoutSec);
|
|
520
|
+
}
|
|
521
|
+
if (server.enabledTools !== void 0) {
|
|
522
|
+
this.addConfigOverride(args, `${prefix}.enabled_tools`, server.enabledTools);
|
|
523
|
+
}
|
|
524
|
+
if (server.disabledTools !== void 0) {
|
|
525
|
+
this.addConfigOverride(args, `${prefix}.disabled_tools`, server.disabledTools);
|
|
526
|
+
}
|
|
527
|
+
if (server.transport === "stdio") {
|
|
528
|
+
this.addConfigOverride(args, `${prefix}.command`, server.command);
|
|
529
|
+
if (server.args !== void 0) this.addConfigOverride(args, `${prefix}.args`, server.args);
|
|
530
|
+
if (server.env !== void 0) this.addConfigOverride(args, `${prefix}.env`, server.env);
|
|
531
|
+
if (server.cwd) this.addConfigOverride(args, `${prefix}.cwd`, server.cwd);
|
|
532
|
+
} else {
|
|
533
|
+
this.addConfigOverride(args, `${prefix}.url`, server.url);
|
|
534
|
+
if (server.bearerToken !== void 0)
|
|
535
|
+
this.addConfigOverride(args, `${prefix}.bearer_token`, server.bearerToken);
|
|
536
|
+
if (server.bearerTokenEnvVar)
|
|
537
|
+
this.addConfigOverride(args, `${prefix}.bearer_token_env_var`, server.bearerTokenEnvVar);
|
|
538
|
+
if (server.httpHeaders !== void 0)
|
|
539
|
+
this.addConfigOverride(args, `${prefix}.http_headers`, server.httpHeaders);
|
|
540
|
+
if (server.envHttpHeaders !== void 0)
|
|
541
|
+
this.addConfigOverride(args, `${prefix}.env_http_headers`, server.envHttpHeaders);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
385
544
|
}
|
|
386
545
|
addConfigOverride(args, key, value) {
|
|
387
546
|
if (this.isPlainObject(value)) {
|
|
388
|
-
|
|
547
|
+
const entries = Object.entries(value);
|
|
548
|
+
if (entries.length === 0) {
|
|
549
|
+
args.push("-c", `${key}={}`);
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
for (const [childKey, childValue] of entries) {
|
|
389
553
|
this.addConfigOverride(
|
|
390
554
|
args,
|
|
391
555
|
`${key}.${childKey}`,
|
|
@@ -679,7 +843,7 @@ var CodexCliLanguageModel = class {
|
|
|
679
843
|
});
|
|
680
844
|
const effectiveSettings = this.mergeSettings(providerOptions);
|
|
681
845
|
const responseFormat = options.responseFormat?.type === "json" ? { type: "json", schema: options.responseFormat.schema } : void 0;
|
|
682
|
-
const { cmd, args, env, cwd, lastMessagePath, schemaPath } = this.buildArgs(
|
|
846
|
+
const { cmd, args, env, cwd, lastMessagePath, lastMessageIsTemp, schemaPath } = this.buildArgs(
|
|
683
847
|
promptText,
|
|
684
848
|
responseFormat,
|
|
685
849
|
effectiveSettings
|
|
@@ -799,9 +963,11 @@ var CodexCliLanguageModel = class {
|
|
|
799
963
|
}
|
|
800
964
|
} catch {
|
|
801
965
|
}
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
966
|
+
if (lastMessageIsTemp) {
|
|
967
|
+
try {
|
|
968
|
+
rmSync(lastMessagePath, { force: true });
|
|
969
|
+
} catch {
|
|
970
|
+
}
|
|
805
971
|
}
|
|
806
972
|
}
|
|
807
973
|
const content = [{ type: "text", text }];
|
|
@@ -835,7 +1001,7 @@ var CodexCliLanguageModel = class {
|
|
|
835
1001
|
});
|
|
836
1002
|
const effectiveSettings = this.mergeSettings(providerOptions);
|
|
837
1003
|
const responseFormat = options.responseFormat?.type === "json" ? { type: "json", schema: options.responseFormat.schema } : void 0;
|
|
838
|
-
const { cmd, args, env, cwd, lastMessagePath, schemaPath } = this.buildArgs(
|
|
1004
|
+
const { cmd, args, env, cwd, lastMessagePath, lastMessageIsTemp, schemaPath } = this.buildArgs(
|
|
839
1005
|
promptText,
|
|
840
1006
|
responseFormat,
|
|
841
1007
|
effectiveSettings
|
|
@@ -966,9 +1132,11 @@ var CodexCliLanguageModel = class {
|
|
|
966
1132
|
if (fileText) finalText = fileText.trim();
|
|
967
1133
|
} catch {
|
|
968
1134
|
}
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
1135
|
+
if (lastMessageIsTemp) {
|
|
1136
|
+
try {
|
|
1137
|
+
rmSync(lastMessagePath, { force: true });
|
|
1138
|
+
} catch {
|
|
1139
|
+
}
|
|
972
1140
|
}
|
|
973
1141
|
}
|
|
974
1142
|
if (finalText) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-sdk-provider-codex-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "AI SDK v5 provider for OpenAI Codex CLI with native JSON Schema support",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-sdk",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"gpt-5",
|
|
12
12
|
"gpt-5.1",
|
|
13
13
|
"gpt-5.1-codex",
|
|
14
|
+
"gpt-5.1-codex-max",
|
|
14
15
|
"provider"
|
|
15
16
|
],
|
|
16
17
|
"homepage": "https://github.com/ben-vargas/ai-sdk-provider-codex-cli",
|
|
@@ -63,7 +64,7 @@
|
|
|
63
64
|
"jsonc-parser": "^3.3.1"
|
|
64
65
|
},
|
|
65
66
|
"optionalDependencies": {
|
|
66
|
-
"@openai/codex": "^0.
|
|
67
|
+
"@openai/codex": "^0.60.1"
|
|
67
68
|
},
|
|
68
69
|
"devDependencies": {
|
|
69
70
|
"@eslint/js": "^9.14.0",
|