@vercel/agent-eval 1.1.1 → 1.2.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/lib/agents/claude-code/agent.d.ts +30 -0
- package/dist/lib/agents/claude-code/agent.d.ts.map +1 -0
- package/dist/lib/agents/claude-code/agent.js +80 -0
- package/dist/lib/agents/claude-code/agent.js.map +1 -0
- package/dist/lib/agents/claude-code/run.mjs +217 -0
- package/dist/lib/agents/codex/agent.d.ts +61 -0
- package/dist/lib/agents/codex/agent.d.ts.map +1 -0
- package/dist/lib/agents/codex/agent.js +221 -0
- package/dist/lib/agents/codex/agent.js.map +1 -0
- package/dist/lib/agents/codex/run.mjs +365 -0
- package/dist/lib/agents/cursor/agent.d.ts +32 -0
- package/dist/lib/agents/cursor/agent.d.ts.map +1 -0
- package/dist/lib/agents/cursor/agent.js +86 -0
- package/dist/lib/agents/cursor/agent.js.map +1 -0
- package/dist/lib/agents/cursor/run.mjs +183 -0
- package/dist/lib/agents/eval-helper.mjs +222 -0
- package/dist/lib/agents/gemini/agent.d.ts +27 -0
- package/dist/lib/agents/gemini/agent.d.ts.map +1 -0
- package/dist/lib/agents/gemini/agent.js +69 -0
- package/dist/lib/agents/gemini/agent.js.map +1 -0
- package/dist/lib/agents/gemini/run.mjs +180 -0
- package/dist/lib/agents/index.js +5 -5
- package/dist/lib/agents/index.js.map +1 -1
- package/dist/lib/agents/opencode/agent.d.ts +68 -0
- package/dist/lib/agents/opencode/agent.d.ts.map +1 -0
- package/dist/lib/agents/opencode/agent.js +165 -0
- package/dist/lib/agents/opencode/agent.js.map +1 -0
- package/dist/lib/agents/opencode/run.mjs +308 -0
- package/dist/lib/agents/plugin/contract.d.ts +157 -0
- package/dist/lib/agents/plugin/contract.d.ts.map +1 -0
- package/dist/lib/agents/plugin/contract.js +22 -0
- package/dist/lib/agents/plugin/contract.js.map +1 -0
- package/dist/lib/agents/plugin/orchestrator.d.ts +22 -0
- package/dist/lib/agents/plugin/orchestrator.d.ts.map +1 -0
- package/dist/lib/agents/plugin/orchestrator.js +286 -0
- package/dist/lib/agents/plugin/orchestrator.js.map +1 -0
- package/dist/lib/agents/shared.d.ts +7 -1
- package/dist/lib/agents/shared.d.ts.map +1 -1
- package/dist/lib/agents/shared.js +30 -3
- package/dist/lib/agents/shared.js.map +1 -1
- package/package.json +2 -2
- package/dist/lib/agents/claude-code.d.ts +0 -33
- package/dist/lib/agents/claude-code.d.ts.map +0 -1
- package/dist/lib/agents/claude-code.js +0 -310
- package/dist/lib/agents/claude-code.js.map +0 -1
- package/dist/lib/agents/codex.d.ts +0 -23
- package/dist/lib/agents/codex.d.ts.map +0 -1
- package/dist/lib/agents/codex.js +0 -364
- package/dist/lib/agents/codex.js.map +0 -1
- package/dist/lib/agents/cursor.d.ts +0 -10
- package/dist/lib/agents/cursor.d.ts.map +0 -1
- package/dist/lib/agents/cursor.js +0 -207
- package/dist/lib/agents/cursor.js.map +0 -1
- package/dist/lib/agents/gemini.d.ts +0 -10
- package/dist/lib/agents/gemini.d.ts.map +0 -1
- package/dist/lib/agents/gemini.js +0 -208
- package/dist/lib/agents/gemini.js.map +0 -1
- package/dist/lib/agents/opencode.d.ts +0 -46
- package/dist/lib/agents/opencode.d.ts.map +0 -1
- package/dist/lib/agents/opencode.js +0 -365
- package/dist/lib/agents/opencode.js.map +0 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code agent — host-side definition + the thin Agent wrapper.
|
|
3
|
+
*
|
|
4
|
+
* The definition is pure data/auth; the actual CLI invocation + transcript capture
|
|
5
|
+
* live in ./run.mjs (shipped into the sandbox by the orchestrator). The wrapper
|
|
6
|
+
* keeps the public Agent interface identical so the registry / runner are untouched.
|
|
7
|
+
*/
|
|
8
|
+
import type { Agent } from '../types.js';
|
|
9
|
+
import type { AgentDefinition } from '../plugin/contract.js';
|
|
10
|
+
/**
|
|
11
|
+
* Build the Claude Code plugin definition.
|
|
12
|
+
*
|
|
13
|
+
* Auth has three mutually-exclusive modes, preserved exactly from the old adapter:
|
|
14
|
+
* 1. Vercel AI Gateway → ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN (+ empty ANTHROPIC_API_KEY)
|
|
15
|
+
* 2. OAuth (CLAUDE_CODE_OAUTH_TOKEN present in the host env) → CLAUDE_CODE_OAUTH_TOKEN
|
|
16
|
+
* 3. Direct API (fallback) → ANTHROPIC_API_KEY
|
|
17
|
+
* getApiKeyEnvVar() and authEnv() must agree on the mode — both read process.env at
|
|
18
|
+
* call time, so the host's key resolution and the sandbox env stay consistent.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createClaudeCodeDefinition({ useVercelAiGateway }: {
|
|
21
|
+
useVercelAiGateway: boolean;
|
|
22
|
+
}): AgentDefinition;
|
|
23
|
+
/**
|
|
24
|
+
* Create the Claude Code Agent. Thin wrapper over the generic orchestrator so the
|
|
25
|
+
* Agent interface (and thus registry.ts / index.ts / runner.ts) is unchanged.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createClaudeCodeAgent({ useVercelAiGateway }: {
|
|
28
|
+
useVercelAiGateway: boolean;
|
|
29
|
+
}): Agent;
|
|
30
|
+
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../../src/lib/agents/claude-code/agent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,KAAK,EAAmB,MAAM,aAAa,CAAC;AAG1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAG7D;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,EAAE,kBAAkB,EAAE,EAAE;IAAE,kBAAkB,EAAE,OAAO,CAAA;CAAE,GAAG,eAAe,CA4CnH;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,kBAAkB,EAAE,EAAE;IAAE,kBAAkB,EAAE,OAAO,CAAA;CAAE,GAAG,KAAK,CAWpG"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code agent — host-side definition + the thin Agent wrapper.
|
|
3
|
+
*
|
|
4
|
+
* The definition is pure data/auth; the actual CLI invocation + transcript capture
|
|
5
|
+
* live in ./run.mjs (shipped into the sandbox by the orchestrator). The wrapper
|
|
6
|
+
* keeps the public Agent interface identical so the registry / runner are untouched.
|
|
7
|
+
*/
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
import { AI_GATEWAY, ANTHROPIC_DIRECT } from '../shared.js';
|
|
10
|
+
import { runWithDefinition } from '../plugin/orchestrator.js';
|
|
11
|
+
/**
|
|
12
|
+
* Build the Claude Code plugin definition.
|
|
13
|
+
*
|
|
14
|
+
* Auth has three mutually-exclusive modes, preserved exactly from the old adapter:
|
|
15
|
+
* 1. Vercel AI Gateway → ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN (+ empty ANTHROPIC_API_KEY)
|
|
16
|
+
* 2. OAuth (CLAUDE_CODE_OAUTH_TOKEN present in the host env) → CLAUDE_CODE_OAUTH_TOKEN
|
|
17
|
+
* 3. Direct API (fallback) → ANTHROPIC_API_KEY
|
|
18
|
+
* getApiKeyEnvVar() and authEnv() must agree on the mode — both read process.env at
|
|
19
|
+
* call time, so the host's key resolution and the sandbox env stay consistent.
|
|
20
|
+
*/
|
|
21
|
+
export function createClaudeCodeDefinition({ useVercelAiGateway }) {
|
|
22
|
+
return {
|
|
23
|
+
name: useVercelAiGateway ? 'vercel-ai-gateway/claude-code' : 'claude-code',
|
|
24
|
+
displayName: useVercelAiGateway ? 'Claude Code (Vercel AI Gateway)' : 'Claude Code',
|
|
25
|
+
defaultModel: 'opus',
|
|
26
|
+
o11yAgentName: 'claude-code',
|
|
27
|
+
// Resolve run.mjs next to this file (works in src during dev and in dist after
|
|
28
|
+
// the build copies run.mjs alongside the compiled agent.js).
|
|
29
|
+
runnerPath: fileURLToPath(new URL('./run.mjs', import.meta.url)),
|
|
30
|
+
getApiKeyEnvVar() {
|
|
31
|
+
if (useVercelAiGateway)
|
|
32
|
+
return AI_GATEWAY.apiKeyEnvVar;
|
|
33
|
+
if (process.env.CLAUDE_CODE_OAUTH_TOKEN)
|
|
34
|
+
return 'CLAUDE_CODE_OAUTH_TOKEN';
|
|
35
|
+
return ANTHROPIC_DIRECT.apiKeyEnvVar;
|
|
36
|
+
},
|
|
37
|
+
install(options) {
|
|
38
|
+
// Project deps (retried once), then the Claude Code CLI globally.
|
|
39
|
+
const cliPackage = options.agentOptions?.cliPackage || '@anthropic-ai/claude-code';
|
|
40
|
+
return [
|
|
41
|
+
{ kind: 'command', cmd: 'npm', args: ['install'], retryOnce: true, errorPrefix: 'npm install failed', errorBody: 'last10' },
|
|
42
|
+
{ kind: 'command', cmd: 'npm', args: ['install', '-g', cliPackage], errorPrefix: 'Claude Code install failed', errorBody: 'stderr' },
|
|
43
|
+
];
|
|
44
|
+
},
|
|
45
|
+
// Claude Code is configured purely via env — no config files.
|
|
46
|
+
configFiles() {
|
|
47
|
+
return [];
|
|
48
|
+
},
|
|
49
|
+
authEnv(options) {
|
|
50
|
+
if (useVercelAiGateway) {
|
|
51
|
+
return {
|
|
52
|
+
ANTHROPIC_BASE_URL: AI_GATEWAY.baseUrl,
|
|
53
|
+
ANTHROPIC_AUTH_TOKEN: options.apiKey,
|
|
54
|
+
ANTHROPIC_API_KEY: '',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (process.env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
58
|
+
return { CLAUDE_CODE_OAUTH_TOKEN: options.apiKey };
|
|
59
|
+
}
|
|
60
|
+
return { ANTHROPIC_API_KEY: options.apiKey };
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Create the Claude Code Agent. Thin wrapper over the generic orchestrator so the
|
|
66
|
+
* Agent interface (and thus registry.ts / index.ts / runner.ts) is unchanged.
|
|
67
|
+
*/
|
|
68
|
+
export function createClaudeCodeAgent({ useVercelAiGateway }) {
|
|
69
|
+
const definition = createClaudeCodeDefinition({ useVercelAiGateway });
|
|
70
|
+
return {
|
|
71
|
+
name: definition.name,
|
|
72
|
+
displayName: definition.displayName,
|
|
73
|
+
getApiKeyEnvVar: definition.getApiKeyEnvVar,
|
|
74
|
+
getDefaultModel() {
|
|
75
|
+
return definition.defaultModel;
|
|
76
|
+
},
|
|
77
|
+
run: (fixturePath, options) => runWithDefinition(definition, fixturePath, options),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../../src/lib/agents/claude-code/agent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAIzC,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAE5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D;;;;;;;;;GASG;AACH,MAAM,UAAU,0BAA0B,CAAC,EAAE,kBAAkB,EAAmC;IAChG,OAAO;QACL,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,aAAa;QAC1E,WAAW,EAAE,kBAAkB,CAAC,CAAC,CAAC,iCAAiC,CAAC,CAAC,CAAC,aAAa;QACnF,YAAY,EAAE,MAAM;QACpB,aAAa,EAAE,aAAa;QAC5B,+EAA+E;QAC/E,6DAA6D;QAC7D,UAAU,EAAE,aAAa,CAAC,IAAI,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEhE,eAAe;YACb,IAAI,kBAAkB;gBAAE,OAAO,UAAU,CAAC,YAAY,CAAC;YACvD,IAAI,OAAO,CAAC,GAAG,CAAC,uBAAuB;gBAAE,OAAO,yBAAyB,CAAC;YAC1E,OAAO,gBAAgB,CAAC,YAAY,CAAC;QACvC,CAAC;QAED,OAAO,CAAC,OAAwB;YAC9B,kEAAkE;YAClE,MAAM,UAAU,GAAI,OAAO,CAAC,YAAY,EAAE,UAAqB,IAAI,2BAA2B,CAAC;YAC/F,OAAO;gBACL,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,oBAAoB,EAAE,SAAS,EAAE,QAAQ,EAAE;gBAC3H,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,WAAW,EAAE,4BAA4B,EAAE,SAAS,EAAE,QAAQ,EAAE;aACrI,CAAC;QACJ,CAAC;QAED,8DAA8D;QAC9D,WAAW;YACT,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,OAAO,CAAC,OAAwB;YAC9B,IAAI,kBAAkB,EAAE,CAAC;gBACvB,OAAO;oBACL,kBAAkB,EAAE,UAAU,CAAC,OAAO;oBACtC,oBAAoB,EAAE,OAAO,CAAC,MAAM;oBACpC,iBAAiB,EAAE,EAAE;iBACtB,CAAC;YACJ,CAAC;YACD,IAAI,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,CAAC;gBACxC,OAAO,EAAE,uBAAuB,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;YACrD,CAAC;YACD,OAAO,EAAE,iBAAiB,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;QAC/C,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,EAAE,kBAAkB,EAAmC;IAC3F,MAAM,UAAU,GAAG,0BAA0B,CAAC,EAAE,kBAAkB,EAAE,CAAC,CAAC;IACtE,OAAO;QACL,IAAI,EAAE,UAAU,CAAC,IAAI;QACrB,WAAW,EAAE,UAAU,CAAC,WAAW;QACnC,eAAe,EAAE,UAAU,CAAC,eAAe;QAC3C,eAAe;YACb,OAAO,UAAU,CAAC,YAAY,CAAC;QACjC,CAAC;QACD,GAAG,EAAE,CAAC,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC,iBAAiB,CAAC,UAAU,EAAE,WAAW,EAAE,OAAO,CAAC;KACnF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code in-sandbox runner.
|
|
3
|
+
*
|
|
4
|
+
* This file is shipped INTO the sandbox by the orchestrator and executed there as
|
|
5
|
+
* `node __agent_eval__/run.mjs '<AgentRunInput JSON>'`. It is intentionally
|
|
6
|
+
* ZERO-DEPENDENCY (only `node:*` builtins) because the sandbox only has the
|
|
7
|
+
* fixture's own deps + the installed `claude` CLI — it cannot import anything from
|
|
8
|
+
* the @vercel/agent-eval package.
|
|
9
|
+
*
|
|
10
|
+
* Dual mode:
|
|
11
|
+
* - runnable: invoked directly → reads argv, runs the agent, writes the result
|
|
12
|
+
* file + prints a status line, exits 0.
|
|
13
|
+
* - importable: `import { runAgent } from './run.mjs'` → returns a RunnerResult
|
|
14
|
+
* (no file write, no exit). This is what a future in-sandbox judge reuses.
|
|
15
|
+
*
|
|
16
|
+
* `buildClaudeCodeCliArgs` and `extractObservedModelFromClaudeTranscript` are
|
|
17
|
+
* exported so the host unit tests can verify them directly (the test imports them
|
|
18
|
+
* from this very file, so there is no risk of the tested logic drifting from the
|
|
19
|
+
* logic the sandbox actually runs).
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { spawnSync } from 'node:child_process';
|
|
23
|
+
import { mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
24
|
+
import { homedir } from 'node:os';
|
|
25
|
+
import { dirname, join } from 'node:path';
|
|
26
|
+
import { fileURLToPath } from 'node:url';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Build the Claude Code CLI argument list.
|
|
30
|
+
*
|
|
31
|
+
* Order is regression-sensitive (preserved verbatim from the old adapter):
|
|
32
|
+
* `--allowedTools` is variadic — it keeps consuming positional tokens until the
|
|
33
|
+
* next flag. So (1) the tools must be a single comma-separated value, and (2)
|
|
34
|
+
* `--allowedTools` must be followed by another flag, never directly by the prompt.
|
|
35
|
+
* `--dangerously-skip-permissions` is always emitted and terminates the variadic
|
|
36
|
+
* capture before the trailing positional prompt (the #141 regression).
|
|
37
|
+
*
|
|
38
|
+
* @param {{prompt:string, model?:string, webResearch?:boolean, agentOptions?:Record<string,unknown>}} input
|
|
39
|
+
* @returns {string[]}
|
|
40
|
+
*/
|
|
41
|
+
export function buildClaudeCodeCliArgs(input) {
|
|
42
|
+
const cliArgs = ['--print'];
|
|
43
|
+
if (input.webResearch) {
|
|
44
|
+
cliArgs.push('--allowedTools', 'WebSearch,WebFetch');
|
|
45
|
+
}
|
|
46
|
+
if (input.model) {
|
|
47
|
+
cliArgs.push('--model', input.model);
|
|
48
|
+
}
|
|
49
|
+
cliArgs.push('--dangerously-skip-permissions');
|
|
50
|
+
const effort = input.agentOptions?.effort;
|
|
51
|
+
if (effort) {
|
|
52
|
+
cliArgs.push('--effort', String(effort));
|
|
53
|
+
}
|
|
54
|
+
cliArgs.push(input.prompt);
|
|
55
|
+
return cliArgs;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Scan a Claude Code transcript (JSONL) for the last `message.model` seen.
|
|
60
|
+
* Preserved verbatim from the old adapter. Non-JSON lines are ignored.
|
|
61
|
+
*
|
|
62
|
+
* @param {string|undefined|null} transcript
|
|
63
|
+
* @returns {string|undefined}
|
|
64
|
+
*/
|
|
65
|
+
export function extractObservedModelFromClaudeTranscript(transcript) {
|
|
66
|
+
if (!transcript) return undefined;
|
|
67
|
+
|
|
68
|
+
let observedModel;
|
|
69
|
+
for (const line of transcript.split('\n')) {
|
|
70
|
+
if (!line.trim()) continue;
|
|
71
|
+
try {
|
|
72
|
+
const event = JSON.parse(line);
|
|
73
|
+
if (typeof event.message?.model === 'string') {
|
|
74
|
+
observedModel = event.message.model;
|
|
75
|
+
}
|
|
76
|
+
} catch {
|
|
77
|
+
// Ignore non-JSON transcript lines.
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return observedModel;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Locate + read the Claude Code transcript file.
|
|
85
|
+
*
|
|
86
|
+
* Claude Code writes JSONL transcripts to
|
|
87
|
+
* `~/.claude/projects/{cwd-with-slashes-as-dashes}/{session}.jsonl`. We pick the
|
|
88
|
+
* newest `.jsonl` by mtime — the equivalent of the old adapter's
|
|
89
|
+
* `ls -t ~/.claude/projects/<path>/*.jsonl | head -1`.
|
|
90
|
+
*
|
|
91
|
+
* Best-effort: any failure → null (never throws).
|
|
92
|
+
*
|
|
93
|
+
* @param {string} cwd post-relocation sandbox cwd (e.g. /workspace)
|
|
94
|
+
* @returns {string|null}
|
|
95
|
+
*/
|
|
96
|
+
function captureClaudeTranscript(cwd) {
|
|
97
|
+
try {
|
|
98
|
+
const projectPath = cwd.replace(/\//g, '-');
|
|
99
|
+
const dir = join(homedir(), '.claude', 'projects', projectPath);
|
|
100
|
+
const newest = readdirSync(dir)
|
|
101
|
+
.filter((f) => f.endsWith('.jsonl'))
|
|
102
|
+
.map((f) => {
|
|
103
|
+
const full = join(dir, f);
|
|
104
|
+
return { full, mtime: statSync(full).mtimeMs };
|
|
105
|
+
})
|
|
106
|
+
.sort((a, b) => b.mtime - a.mtime)[0];
|
|
107
|
+
if (!newest) return null;
|
|
108
|
+
return readFileSync(newest.full, 'utf8') || null;
|
|
109
|
+
} catch {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Run Claude Code over the workspace at `input.cwd` and return a RunnerResult.
|
|
116
|
+
*
|
|
117
|
+
* Auth (ANTHROPIC_BASE_URL/ANTHROPIC_AUTH_TOKEN/...) arrives via process.env — the
|
|
118
|
+
* orchestrator sets it on the `node run.mjs` invocation, and we pass process.env
|
|
119
|
+
* straight through to the CLI. The runner never handles secrets itself.
|
|
120
|
+
*
|
|
121
|
+
* @param {import('../plugin/contract.js').AgentRunInput} input
|
|
122
|
+
* @returns {Promise<import('../plugin/contract.js').RunnerResult>}
|
|
123
|
+
*/
|
|
124
|
+
export async function runAgent(input) {
|
|
125
|
+
const args = buildClaudeCodeCliArgs(input);
|
|
126
|
+
|
|
127
|
+
// spawnSync (not a shell string): the prompt is a plain argv element, so there is
|
|
128
|
+
// no shell quoting/escaping to get wrong. Blocking is fine — the runner has
|
|
129
|
+
// nothing else to do while the agent works. The sandbox-level timeout bounds it.
|
|
130
|
+
const res = spawnSync('claude', args, {
|
|
131
|
+
cwd: input.cwd,
|
|
132
|
+
env: process.env,
|
|
133
|
+
encoding: 'utf8',
|
|
134
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const stdout = res.stdout || '';
|
|
138
|
+
const stderr = res.stderr || '';
|
|
139
|
+
// Preserve the old concatenation order: stdout THEN stderr.
|
|
140
|
+
const output = stdout + stderr;
|
|
141
|
+
// spawnSync sets status=null + error when the binary can't be spawned at all.
|
|
142
|
+
const agentExitCode = res.status == null ? -1 : res.status;
|
|
143
|
+
|
|
144
|
+
// Capture transcript + observed model regardless of success (the old adapter did
|
|
145
|
+
// this even on the non-zero-exit path).
|
|
146
|
+
const transcript = captureClaudeTranscript(input.cwd);
|
|
147
|
+
const observedModel = extractObservedModelFromClaudeTranscript(transcript) ?? null;
|
|
148
|
+
|
|
149
|
+
if (res.error || agentExitCode !== 0) {
|
|
150
|
+
// Mirror the old error string: last 5 lines of output, else a coded fallback.
|
|
151
|
+
const errorLines = output.trim().split('\n').slice(-5).join('\n');
|
|
152
|
+
const fallback = res.error
|
|
153
|
+
? `Failed to run claude: ${res.error.message}`
|
|
154
|
+
: `Claude Code exited with code ${agentExitCode}`;
|
|
155
|
+
return {
|
|
156
|
+
ok: false,
|
|
157
|
+
output,
|
|
158
|
+
transcript,
|
|
159
|
+
observedModel,
|
|
160
|
+
error: errorLines || fallback,
|
|
161
|
+
agentExitCode,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return { ok: true, output, transcript, observedModel, error: null, agentExitCode };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* ─────────────────────────── runnable (CLI) entry ─────────────────────────── */
|
|
169
|
+
|
|
170
|
+
// True when this file is executed directly (`node run.mjs ...`), false when imported.
|
|
171
|
+
const isMain = process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1];
|
|
172
|
+
|
|
173
|
+
if (isMain) {
|
|
174
|
+
// argv[2] is the AgentRunInput JSON (never contains secrets).
|
|
175
|
+
const input = JSON.parse(process.argv[2]);
|
|
176
|
+
|
|
177
|
+
// Always produce a RunnerResult, even if the runner itself throws, so the host
|
|
178
|
+
// always has a result file to read (node exit code stays 0 except on a truly
|
|
179
|
+
// unrecoverable crash before we can write).
|
|
180
|
+
let result;
|
|
181
|
+
try {
|
|
182
|
+
result = await runAgent(input);
|
|
183
|
+
} catch (e) {
|
|
184
|
+
result = {
|
|
185
|
+
ok: false,
|
|
186
|
+
output: '',
|
|
187
|
+
transcript: null,
|
|
188
|
+
observedModel: null,
|
|
189
|
+
error: e && e.message ? e.message : String(e),
|
|
190
|
+
agentExitCode: -1,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Source of truth: the result file the host reads back via sandbox.readFile.
|
|
195
|
+
try {
|
|
196
|
+
mkdirSync(dirname(input.resultPath), { recursive: true });
|
|
197
|
+
writeFileSync(input.resultPath, JSON.stringify(result));
|
|
198
|
+
} catch {
|
|
199
|
+
// If the file can't be written, the host falls back to the marker line below.
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Fallback channel: a compact status line (no transcript — it can be huge).
|
|
203
|
+
process.stdout.write(
|
|
204
|
+
'__AGENT_RESULT__ ' +
|
|
205
|
+
JSON.stringify({
|
|
206
|
+
ok: result.ok,
|
|
207
|
+
observedModel: result.observedModel,
|
|
208
|
+
error: result.error,
|
|
209
|
+
agentExitCode: result.agentExitCode,
|
|
210
|
+
}) +
|
|
211
|
+
'\n'
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
// Exit 0: "the runner ran". Agent success/failure is conveyed via result.ok, not
|
|
215
|
+
// the node exit code (the host distinguishes the two).
|
|
216
|
+
process.exit(0);
|
|
217
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI Codex agent — host-side definition + the thin Agent wrapper.
|
|
3
|
+
*
|
|
4
|
+
* The definition is pure data/auth/config; the actual CLI invocation + transcript
|
|
5
|
+
* capture live in ./run.mjs (shipped into the sandbox by the orchestrator). The
|
|
6
|
+
* wrapper keeps the public Agent interface identical so the registry / runner are
|
|
7
|
+
* untouched.
|
|
8
|
+
*
|
|
9
|
+
* Codex is the one agent that needs BOTH a config file (a TOML profile written to
|
|
10
|
+
* the absolute path `~/.codex/default.config.toml`) AND a host-computed value that
|
|
11
|
+
* the runner must reproduce verbatim on the CLI (`-c model_reasoning_effort=...`,
|
|
12
|
+
* `-c model_verbosity=...`, `--model ...`). Those CLI values MUST match the values
|
|
13
|
+
* baked into the TOML, so they are derived ONCE on the host (from parseModelString)
|
|
14
|
+
* and handed to the runner via `runnerExtra()` → `input.extra`. parseModelString
|
|
15
|
+
* stays host-side (and exported) so the unit tests keep importing it.
|
|
16
|
+
*/
|
|
17
|
+
import type { Agent } from '../types.js';
|
|
18
|
+
import type { AgentDefinition } from '../plugin/contract.js';
|
|
19
|
+
/**
|
|
20
|
+
* Parse model string with optional query parameters.
|
|
21
|
+
* e.g. "gpt-5.2-codex?reasoningEffort=high" → { model: "gpt-5.2-codex", reasoningEffort: "high" }
|
|
22
|
+
*
|
|
23
|
+
* Stays host-side (and exported) — the unit tests import it, and the resulting
|
|
24
|
+
* values must be baked into BOTH the TOML config (configFiles) and the runner CLI
|
|
25
|
+
* args (runnerExtra), so it must be computed exactly once on the host.
|
|
26
|
+
*/
|
|
27
|
+
export declare function parseModelString(model: string): {
|
|
28
|
+
model: string;
|
|
29
|
+
reasoningEffort?: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Generate Codex profile config content.
|
|
33
|
+
*
|
|
34
|
+
* `reasoningEffort` and `model_verbosity` are written into the profile so a
|
|
35
|
+
* fresh `codex exec` doesn't pick up the CLI defaults of `"low"`, which are
|
|
36
|
+
* rejected by `gpt-5.2-codex`. Defaults to `"medium"` when `reasoningEffort`
|
|
37
|
+
* is omitted.
|
|
38
|
+
*
|
|
39
|
+
* Stays host-side (and exported) — the unit tests import it directly.
|
|
40
|
+
*/
|
|
41
|
+
export declare function generateCodexConfig(model: string | undefined, useVercelAiGateway: boolean, reasoningEffort?: string, webResearch?: boolean): string;
|
|
42
|
+
/**
|
|
43
|
+
* Build the Codex plugin definition.
|
|
44
|
+
*
|
|
45
|
+
* Auth is two mutually-exclusive modes, preserved exactly from the old adapter:
|
|
46
|
+
* 1. Vercel AI Gateway → AI_GATEWAY_API_KEY (the gateway "vercel" provider's env_key)
|
|
47
|
+
* 2. Direct OpenAI API → OPENAI_API_KEY (the built-in "openai" provider's env_key)
|
|
48
|
+
* The runner additionally pipes the same key into `codex login --with-api-key` over
|
|
49
|
+
* stdin (reading it from process.env, never from the argv JSON).
|
|
50
|
+
*/
|
|
51
|
+
export declare function createCodexDefinition({ useVercelAiGateway }: {
|
|
52
|
+
useVercelAiGateway: boolean;
|
|
53
|
+
}): AgentDefinition;
|
|
54
|
+
/**
|
|
55
|
+
* Create the Codex Agent. Thin wrapper over the generic orchestrator so the Agent
|
|
56
|
+
* interface (and thus registry.ts / index.ts / runner.ts) is unchanged.
|
|
57
|
+
*/
|
|
58
|
+
export declare function createCodexAgent({ useVercelAiGateway }: {
|
|
59
|
+
useVercelAiGateway: boolean;
|
|
60
|
+
}): Agent;
|
|
61
|
+
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../../src/lib/agents/codex/agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,KAAK,EAAE,KAAK,EAAmB,MAAM,aAAa,CAAC;AAG1D,OAAO,KAAK,EAAE,eAAe,EAA2B,MAAM,uBAAuB,CAAC;AAGtF;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,CAmB3F;AA+BD;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,kBAAkB,EAAE,OAAO,EAC3B,eAAe,CAAC,EAAE,MAAM,EACxB,WAAW,CAAC,EAAE,OAAO,GACpB,MAAM,CA4BR;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,kBAAkB,EAAE,EAAE;IAAE,kBAAkB,EAAE,OAAO,CAAA;CAAE,GAAG,eAAe,CAsF9G;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,kBAAkB,EAAE,EAAE;IAAE,kBAAkB,EAAE,OAAO,CAAA;CAAE,GAAG,KAAK,CAW/F"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI Codex agent — host-side definition + the thin Agent wrapper.
|
|
3
|
+
*
|
|
4
|
+
* The definition is pure data/auth/config; the actual CLI invocation + transcript
|
|
5
|
+
* capture live in ./run.mjs (shipped into the sandbox by the orchestrator). The
|
|
6
|
+
* wrapper keeps the public Agent interface identical so the registry / runner are
|
|
7
|
+
* untouched.
|
|
8
|
+
*
|
|
9
|
+
* Codex is the one agent that needs BOTH a config file (a TOML profile written to
|
|
10
|
+
* the absolute path `~/.codex/default.config.toml`) AND a host-computed value that
|
|
11
|
+
* the runner must reproduce verbatim on the CLI (`-c model_reasoning_effort=...`,
|
|
12
|
+
* `-c model_verbosity=...`, `--model ...`). Those CLI values MUST match the values
|
|
13
|
+
* baked into the TOML, so they are derived ONCE on the host (from parseModelString)
|
|
14
|
+
* and handed to the runner via `runnerExtra()` → `input.extra`. parseModelString
|
|
15
|
+
* stays host-side (and exported) so the unit tests keep importing it.
|
|
16
|
+
*/
|
|
17
|
+
import { fileURLToPath } from 'node:url';
|
|
18
|
+
import { AI_GATEWAY, OPENAI_DIRECT } from '../shared.js';
|
|
19
|
+
import { runWithDefinition } from '../plugin/orchestrator.js';
|
|
20
|
+
/**
|
|
21
|
+
* Parse model string with optional query parameters.
|
|
22
|
+
* e.g. "gpt-5.2-codex?reasoningEffort=high" → { model: "gpt-5.2-codex", reasoningEffort: "high" }
|
|
23
|
+
*
|
|
24
|
+
* Stays host-side (and exported) — the unit tests import it, and the resulting
|
|
25
|
+
* values must be baked into BOTH the TOML config (configFiles) and the runner CLI
|
|
26
|
+
* args (runnerExtra), so it must be computed exactly once on the host.
|
|
27
|
+
*/
|
|
28
|
+
export function parseModelString(model) {
|
|
29
|
+
const qIndex = model.indexOf('?');
|
|
30
|
+
if (qIndex === -1)
|
|
31
|
+
return { model };
|
|
32
|
+
const base = model.slice(0, qIndex);
|
|
33
|
+
const query = model.slice(qIndex + 1);
|
|
34
|
+
let reasoningEffort;
|
|
35
|
+
for (const pair of query.split('&')) {
|
|
36
|
+
const eqIndex = pair.indexOf('=');
|
|
37
|
+
if (eqIndex === -1)
|
|
38
|
+
continue;
|
|
39
|
+
const key = pair.slice(0, eqIndex);
|
|
40
|
+
const value = decodeURIComponent(pair.slice(eqIndex + 1));
|
|
41
|
+
if (key === 'reasoningEffort') {
|
|
42
|
+
reasoningEffort = value;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return { model: base, reasoningEffort };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Parse the run's model option into { model, reasoningEffort }, or all-undefined
|
|
49
|
+
* for native-default runs. Used by BOTH configFiles() (the TOML profile) and
|
|
50
|
+
* runnerExtra() (the CLI args), which MUST agree — so the parse happens once.
|
|
51
|
+
*/
|
|
52
|
+
function parseOptionsModel(options) {
|
|
53
|
+
return options.model ? parseModelString(options.model) : { model: undefined, reasoningEffort: undefined };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Default reasoning effort and verbosity baked into the generated Codex
|
|
57
|
+
* profile.
|
|
58
|
+
*
|
|
59
|
+
* The Codex CLI itself defaults both `model_reasoning_effort` and
|
|
60
|
+
* `model_verbosity` to `"low"`, but the default Codex model
|
|
61
|
+
* (`gpt-5.2-codex`) only accepts `"medium"` for both — so an out-of-the-box
|
|
62
|
+
* `codex exec` against the AI Gateway fails with:
|
|
63
|
+
* "Unsupported value: 'low' is not supported with the 'gpt-5.2-codex'
|
|
64
|
+
* model. Supported values are: 'medium'."
|
|
65
|
+
* (the error covers both the `reasoning.effort` and `text.verbosity` request
|
|
66
|
+
* parameters, depending on which the model rejected first).
|
|
67
|
+
*
|
|
68
|
+
* `"medium"` is also a valid value for the non-codex GPT-5.x models, so it's
|
|
69
|
+
* a safe default. Callers can override reasoning effort per-run via
|
|
70
|
+
* `model: "gpt-5.2-codex?reasoningEffort=high"`.
|
|
71
|
+
*/
|
|
72
|
+
const DEFAULT_REASONING_EFFORT = 'medium';
|
|
73
|
+
const DEFAULT_MODEL_VERBOSITY = 'medium';
|
|
74
|
+
/**
|
|
75
|
+
* Generate Codex profile config content.
|
|
76
|
+
*
|
|
77
|
+
* `reasoningEffort` and `model_verbosity` are written into the profile so a
|
|
78
|
+
* fresh `codex exec` doesn't pick up the CLI defaults of `"low"`, which are
|
|
79
|
+
* rejected by `gpt-5.2-codex`. Defaults to `"medium"` when `reasoningEffort`
|
|
80
|
+
* is omitted.
|
|
81
|
+
*
|
|
82
|
+
* Stays host-side (and exported) — the unit tests import it directly.
|
|
83
|
+
*/
|
|
84
|
+
export function generateCodexConfig(model, useVercelAiGateway, reasoningEffort, webResearch) {
|
|
85
|
+
// Opt-in web research. Note: through the AI Gateway (`wire_api =
|
|
86
|
+
// "responses"`), no `web_search` items have been observed — Codex instead
|
|
87
|
+
// researches via shell commands when it decides to. The setting is still
|
|
88
|
+
// written so direct-OpenAI runs and future gateway support pick it up; it
|
|
89
|
+
// is harmless when the server-side tool is unavailable.
|
|
90
|
+
const toolsSection = webResearch ? `\n[tools]\nweb_search = true\n` : '';
|
|
91
|
+
if (useVercelAiGateway) {
|
|
92
|
+
// AI Gateway uses prefixed model names like "openai/gpt-5.2-codex".
|
|
93
|
+
// Native-default runs intentionally omit model and reasoning overrides.
|
|
94
|
+
const fullModel = model ? (model.includes('/') ? model : `openai/${model}`) : undefined;
|
|
95
|
+
return `# Codex configuration for Vercel AI Gateway
|
|
96
|
+
model_provider = "vercel"
|
|
97
|
+
${fullModel ? `model = "${fullModel}"\n` : ''}${model ? `model_reasoning_effort = "${reasoningEffort ?? DEFAULT_REASONING_EFFORT}"\nmodel_verbosity = "${DEFAULT_MODEL_VERBOSITY}"\n` : ''}
|
|
98
|
+
[model_providers.vercel]
|
|
99
|
+
name = "Vercel AI Gateway"
|
|
100
|
+
base_url = "${AI_GATEWAY.openAiBaseUrl}"
|
|
101
|
+
env_key = "${AI_GATEWAY.apiKeyEnvVar}"
|
|
102
|
+
wire_api = "responses"
|
|
103
|
+
${toolsSection}`;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
// Direct OpenAI API — use the built-in "openai" provider (no custom provider needed).
|
|
107
|
+
// Native-default runs intentionally omit model and reasoning overrides.
|
|
108
|
+
const directModel = model ? (model.includes('/') ? model.split('/').pop() : model) : undefined;
|
|
109
|
+
return `# Direct OpenAI API configuration
|
|
110
|
+
model_provider = "openai"
|
|
111
|
+
${directModel ? `model = "${directModel}"\n` : ''}${model ? `model_reasoning_effort = "${reasoningEffort ?? DEFAULT_REASONING_EFFORT}"\nmodel_verbosity = "${DEFAULT_MODEL_VERBOSITY}"\n` : ''}${toolsSection}`;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Build the Codex plugin definition.
|
|
116
|
+
*
|
|
117
|
+
* Auth is two mutually-exclusive modes, preserved exactly from the old adapter:
|
|
118
|
+
* 1. Vercel AI Gateway → AI_GATEWAY_API_KEY (the gateway "vercel" provider's env_key)
|
|
119
|
+
* 2. Direct OpenAI API → OPENAI_API_KEY (the built-in "openai" provider's env_key)
|
|
120
|
+
* The runner additionally pipes the same key into `codex login --with-api-key` over
|
|
121
|
+
* stdin (reading it from process.env, never from the argv JSON).
|
|
122
|
+
*/
|
|
123
|
+
export function createCodexDefinition({ useVercelAiGateway }) {
|
|
124
|
+
return {
|
|
125
|
+
name: useVercelAiGateway ? 'vercel-ai-gateway/codex' : 'codex',
|
|
126
|
+
displayName: useVercelAiGateway ? 'OpenAI Codex (Vercel AI Gateway)' : 'OpenAI Codex',
|
|
127
|
+
defaultModel: 'openai/gpt-5.2-codex',
|
|
128
|
+
o11yAgentName: 'codex',
|
|
129
|
+
// Resolve run.mjs next to this file (works in src during dev and in dist after
|
|
130
|
+
// the build copies run.mjs alongside the compiled agent.js).
|
|
131
|
+
runnerPath: fileURLToPath(new URL('./run.mjs', import.meta.url)),
|
|
132
|
+
getApiKeyEnvVar() {
|
|
133
|
+
return useVercelAiGateway ? AI_GATEWAY.apiKeyEnvVar : OPENAI_DIRECT.apiKeyEnvVar;
|
|
134
|
+
},
|
|
135
|
+
install(_options) {
|
|
136
|
+
// Project deps (retried once), then the Codex CLI globally. Error wording is
|
|
137
|
+
// preserved verbatim: 'npm install failed (exit code N):\n<last 10>' and
|
|
138
|
+
// 'Codex CLI install failed: <stderr>'.
|
|
139
|
+
return [
|
|
140
|
+
{ kind: 'command', cmd: 'npm', args: ['install'], retryOnce: true, errorPrefix: 'npm install failed', errorBody: 'last10' },
|
|
141
|
+
{ kind: 'command', cmd: 'npm', args: ['install', '-g', '@openai/codex'], errorPrefix: 'Codex CLI install failed', errorBody: 'stderr' },
|
|
142
|
+
];
|
|
143
|
+
},
|
|
144
|
+
configFiles(options) {
|
|
145
|
+
// Recent Codex CLI versions reject the old top-level `profile = "default"`
|
|
146
|
+
// key in config.toml and instead load `$CODEX_HOME/<profile>.config.toml`
|
|
147
|
+
// when `--profile <profile>` is set. For explicit models, reasoning_effort
|
|
148
|
+
// is baked into the profile (rather than passed via -c at runtime) so the
|
|
149
|
+
// value is visible in saved configs and so the CLI's own default of "low"
|
|
150
|
+
// can't sneak through. For native-default runs we omit these settings.
|
|
151
|
+
const parsed = parseOptionsModel(options);
|
|
152
|
+
const configContent = generateCodexConfig(parsed.model, useVercelAiGateway, parsed.reasoningEffort, options.webResearch);
|
|
153
|
+
// Absolute `~` path writeFiles can't target → heredoc via shell. Combines the
|
|
154
|
+
// old `mkdir -p ~/.codex` + `cat > ~/.codex/default.config.toml << 'EOF'`.
|
|
155
|
+
return [
|
|
156
|
+
{
|
|
157
|
+
viaShell: `mkdir -p ~/.codex && cat > ~/.codex/default.config.toml << 'EOF'\n${configContent}\nEOF`,
|
|
158
|
+
},
|
|
159
|
+
];
|
|
160
|
+
},
|
|
161
|
+
authEnv(options) {
|
|
162
|
+
// env_key the generated TOML expects: AI_GATEWAY_API_KEY for the "vercel"
|
|
163
|
+
// provider, OPENAI_API_KEY for the built-in "openai" provider. The runner
|
|
164
|
+
// also reads this same env to pipe the key into `codex login`.
|
|
165
|
+
const envVar = useVercelAiGateway ? AI_GATEWAY.apiKeyEnvVar : OPENAI_DIRECT.apiKeyEnvVar;
|
|
166
|
+
return { [envVar]: options.apiKey };
|
|
167
|
+
},
|
|
168
|
+
/**
|
|
169
|
+
* Host-computed values the runner must reproduce verbatim on the CLI. These
|
|
170
|
+
* derive from parseModelString and MUST match the TOML written in
|
|
171
|
+
* configFiles(), so they are computed here (host-side) and threaded into the
|
|
172
|
+
* runner via input.extra rather than re-deriving parseModelString in run.mjs.
|
|
173
|
+
*
|
|
174
|
+
* - cliModel: value for `--model` (gateway keeps the prefix,
|
|
175
|
+
* direct OpenAI strips it), or null to omit.
|
|
176
|
+
* - reasoningEffort: value for `-c model_reasoning_effort=...`, or null.
|
|
177
|
+
* - verbosity: value for `-c model_verbosity=...` (only when a
|
|
178
|
+
* model is set), or null to omit.
|
|
179
|
+
*
|
|
180
|
+
* (The login env var is chosen inside run.mjs from process.env — AI_GATEWAY_API_KEY
|
|
181
|
+
* else OPENAI_API_KEY — since authEnv() sets exactly one, so no flag is needed here.)
|
|
182
|
+
*/
|
|
183
|
+
runnerExtra(options) {
|
|
184
|
+
const parsed = parseOptionsModel(options);
|
|
185
|
+
const baseModel = parsed.model;
|
|
186
|
+
// Direct OpenAI API needs unprefixed model names (e.g. "gpt-5.2-codex" not
|
|
187
|
+
// "openai/gpt-5.2-codex"); the gateway keeps the prefix as-is.
|
|
188
|
+
const cliModel = baseModel
|
|
189
|
+
? (useVercelAiGateway ? baseModel : (baseModel.includes('/') ? baseModel.split('/').pop() : baseModel))
|
|
190
|
+
: undefined;
|
|
191
|
+
// Pass reasoning effort and verbosity via -c too; CLI flags have the highest
|
|
192
|
+
// precedence and we've observed Codex CLI silently falling back to its "low"
|
|
193
|
+
// defaults for both fields even when the profile sets them. Both default to
|
|
194
|
+
// "medium" for compatibility with gpt-5.2-codex. Omitted on native-default.
|
|
195
|
+
const reasoningEffort = baseModel ? (parsed.reasoningEffort ?? DEFAULT_REASONING_EFFORT) : undefined;
|
|
196
|
+
const verbosity = baseModel ? DEFAULT_MODEL_VERBOSITY : undefined;
|
|
197
|
+
return {
|
|
198
|
+
cliModel: cliModel ?? null,
|
|
199
|
+
reasoningEffort: reasoningEffort ?? null,
|
|
200
|
+
verbosity: verbosity ?? null,
|
|
201
|
+
};
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Create the Codex Agent. Thin wrapper over the generic orchestrator so the Agent
|
|
207
|
+
* interface (and thus registry.ts / index.ts / runner.ts) is unchanged.
|
|
208
|
+
*/
|
|
209
|
+
export function createCodexAgent({ useVercelAiGateway }) {
|
|
210
|
+
const definition = createCodexDefinition({ useVercelAiGateway });
|
|
211
|
+
return {
|
|
212
|
+
name: definition.name,
|
|
213
|
+
displayName: definition.displayName,
|
|
214
|
+
getApiKeyEnvVar: definition.getApiKeyEnvVar,
|
|
215
|
+
getDefaultModel() {
|
|
216
|
+
return definition.defaultModel;
|
|
217
|
+
},
|
|
218
|
+
run: (fixturePath, options) => runWithDefinition(definition, fixturePath, options),
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../../src/lib/agents/codex/agent.ts"],"names":[],"mappings":"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"}
|