Update agent SDKs and add gated Codex goals support (#114)
* add gated codex goals support * sync README SDK versions * bump claude agent sdk * add codex goals settings toggle
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
"": {
|
||||
"name": "ejclaw-agent-runner",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/claude-agent-sdk": "0.2.114",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.2.126",
|
||||
"@modelcontextprotocol/sdk": "^1.12.1",
|
||||
"cron-parser": "^5.0.0",
|
||||
"ejclaw-runners-shared": "file:../shared",
|
||||
@@ -18,23 +18,23 @@
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.2.114", "", { "dependencies": { "@anthropic-ai/sdk": "^0.81.0", "@modelcontextprotocol/sdk": "^1.29.0" }, "optionalDependencies": { "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.2.114", "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.2.114", "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.2.114", "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.2.114", "@anthropic-ai/claude-agent-sdk-linux-x64": "0.2.114", "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.2.114", "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.2.114", "@anthropic-ai/claude-agent-sdk-win32-x64": "0.2.114" }, "peerDependencies": { "zod": "^4.0.0" } }, "sha512-plJ+j17jew9tDMHir/90hXrwoB8cZ9GrIyG19zIJcFyQ8pVhRXjZRJCtF2ElfPoiwkxMmNu1Klqyui4xP4shPg=="],
|
||||
"@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.2.126", "", { "dependencies": { "@anthropic-ai/sdk": "^0.81.0", "@modelcontextprotocol/sdk": "^1.29.0" }, "optionalDependencies": { "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.2.126", "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.2.126", "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.2.126", "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.2.126", "@anthropic-ai/claude-agent-sdk-linux-x64": "0.2.126", "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.2.126", "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.2.126", "@anthropic-ai/claude-agent-sdk-win32-x64": "0.2.126" }, "peerDependencies": { "zod": "^4.0.0" } }, "sha512-4ZrVu0XUEwNG6wxvsLgppRAmSfAf3oeEMEUPhgazb0AXUUe/7W8MxwZKJWOffqSLWaNYzOt3ZCIL7NJY6toqWw=="],
|
||||
|
||||
"@anthropic-ai/claude-agent-sdk-darwin-arm64": ["@anthropic-ai/claude-agent-sdk-darwin-arm64@0.2.114", "", { "os": "darwin", "cpu": "arm64" }, "sha512-0/6LWrNilWpmiX6Xrj5plsBmCrCdKGERgAlKUZQEJZplnfuweFAJu7WXZB4KBaUpGlPO91zB/yqDh6kp5aZFbA=="],
|
||||
"@anthropic-ai/claude-agent-sdk-darwin-arm64": ["@anthropic-ai/claude-agent-sdk-darwin-arm64@0.2.126", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JFlJBbeAlx7Ic5s4lGUN9SppobryXk/lIqPCvhp6KrJTQIerh3MIBzxsVIJ0MaDut7jVni/oYgsvDni7NIyqHA=="],
|
||||
|
||||
"@anthropic-ai/claude-agent-sdk-darwin-x64": ["@anthropic-ai/claude-agent-sdk-darwin-x64@0.2.114", "", { "os": "darwin", "cpu": "x64" }, "sha512-sOHxq1rEO/KZg2iEZILTPn62lMRRMPqtxKx41uGLi3xjVDrAej6Ury9dDZjYBKkK9n4kBylXV0Oom2CZ14dDYw=="],
|
||||
"@anthropic-ai/claude-agent-sdk-darwin-x64": ["@anthropic-ai/claude-agent-sdk-darwin-x64@0.2.126", "", { "os": "darwin", "cpu": "x64" }, "sha512-J8BpMj16NK9FUaG3HnHSivyp4Xww9DKWHiC8QSHT9oiT8pH5IG7nl0jxyjIq/lY79evlTY+ubgDVWlMUhUAN/g=="],
|
||||
|
||||
"@anthropic-ai/claude-agent-sdk-linux-arm64": ["@anthropic-ai/claude-agent-sdk-linux-arm64@0.2.114", "", { "os": "linux", "cpu": "arm64" }, "sha512-j/SfEoN6+fyEsp8EuPe+xKcGfsZtaBmdUUH+YSRk5H/lYgy38yNsDhdt+AJMQcdMKfHsiwZ3Y9Ajoe9G9wNwHQ=="],
|
||||
"@anthropic-ai/claude-agent-sdk-linux-arm64": ["@anthropic-ai/claude-agent-sdk-linux-arm64@0.2.126", "", { "os": "linux", "cpu": "arm64" }, "sha512-LM+mnfQsgI+1i5mYZwIPDDf14NGBu5wbhzm5U8P11dCa2p8sXmKoWpkbO16BFM2NxeW44I/RXCxE5qFsbz4zcg=="],
|
||||
|
||||
"@anthropic-ai/claude-agent-sdk-linux-arm64-musl": ["@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.2.114", "", { "os": "linux", "cpu": "arm64" }, "sha512-Mhd7bumTwWvkgjSJnYvCgyt8DfmLiUoK92mfvAKxHX7i5YSw+h5Kprqh2Cap+2SBbpwZvnwIoEYGCxhGwE5ddg=="],
|
||||
"@anthropic-ai/claude-agent-sdk-linux-arm64-musl": ["@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.2.126", "", { "os": "linux", "cpu": "arm64" }, "sha512-GO0BnIUw3LQ3XAy+nipAabkN0GwQGPhHB6ITI4XLoR99fLHB3TA6WfyvTf0fnpxd25A+c/+UsAoxz4zBQaHlhA=="],
|
||||
|
||||
"@anthropic-ai/claude-agent-sdk-linux-x64": ["@anthropic-ai/claude-agent-sdk-linux-x64@0.2.114", "", { "os": "linux", "cpu": "x64" }, "sha512-wbaExKDleLlm2zHEhb74GKMLVhtO0IUmFhdimQcdL6CdTkmDE8ZJi53tYWE9+jq+XWNRXoM2yEmKPzXoUmsJng=="],
|
||||
"@anthropic-ai/claude-agent-sdk-linux-x64": ["@anthropic-ai/claude-agent-sdk-linux-x64@0.2.126", "", { "os": "linux", "cpu": "x64" }, "sha512-yaOTDcYCdscxC0LKg9w8IwSa5g+993WggFZJBTZpqvflA2+WMQeTarDnKlsFTCw9XUZkL8XZeBALYJGx0HutuA=="],
|
||||
|
||||
"@anthropic-ai/claude-agent-sdk-linux-x64-musl": ["@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.2.114", "", { "os": "linux", "cpu": "x64" }, "sha512-c1URsameGHAcghen+mY6jvr2oypiAPHXJIdP4huxR25zPdXWv2x+BCy+vcRVeajsq4VmFzAyQJwaM+BXkmXjAw=="],
|
||||
"@anthropic-ai/claude-agent-sdk-linux-x64-musl": ["@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.2.126", "", { "os": "linux", "cpu": "x64" }, "sha512-ByJGO0+mu7EplxSFSCIHd7QWsXdrF3qgtzQ177o/j+oSppLoqR1ot5ktf8aw5oR3CC5lFHg4tqd6TnneQpEoIg=="],
|
||||
|
||||
"@anthropic-ai/claude-agent-sdk-win32-arm64": ["@anthropic-ai/claude-agent-sdk-win32-arm64@0.2.114", "", { "os": "win32", "cpu": "arm64" }, "sha512-qeWdUpQymcKCA92osPmffG4QogrOSvuffPvm6c2OlMDjCPYs8vKG7bSe1Vq5tP9tfBszKPVJWBDh+2ANkNissQ=="],
|
||||
"@anthropic-ai/claude-agent-sdk-win32-arm64": ["@anthropic-ai/claude-agent-sdk-win32-arm64@0.2.126", "", { "os": "win32", "cpu": "arm64" }, "sha512-gv3MOsOBkCx3LajOOIjD7AKsOtz/qNHsS2oshGt2GVoy7JA3XbCDeCetDjM6SorV4SE+7F/IH0UJdXe5ejI/Zg=="],
|
||||
|
||||
"@anthropic-ai/claude-agent-sdk-win32-x64": ["@anthropic-ai/claude-agent-sdk-win32-x64@0.2.114", "", { "os": "win32", "cpu": "x64" }, "sha512-nVr43WwsKvWA6rojw15qBS/f31srukdLxy1KwKzpftlpmkzQ9Lh8uhIafOmoIPzz67f8VJ8JqHE0caA5YrhX9A=="],
|
||||
"@anthropic-ai/claude-agent-sdk-win32-x64": ["@anthropic-ai/claude-agent-sdk-win32-x64@0.2.126", "", { "os": "win32", "cpu": "x64" }, "sha512-oRV75HwyoOd1/t5+kipAM2g62CaElpKGvSBx3Ys4lCwCiFUyOnmet/O+hRXENsY6ShDeQZEcJL2UWljr2d5NQw=="],
|
||||
|
||||
"@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.81.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-D4K5PvEV6wPiRtVlVsJHIUhHAmOZ6IT/I9rKlTf84gR7GyyAurPJK7z9BOf/AZqC5d1DhYQGJNKRmV+q8dGhgw=="],
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"start": "bun dist/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/claude-agent-sdk": "0.2.114",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.2.126",
|
||||
"@modelcontextprotocol/sdk": "^1.12.1",
|
||||
"cron-parser": "^5.0.0",
|
||||
"ejclaw-runners-shared": "file:../shared",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"": {
|
||||
"name": "ejclaw-codex-runner",
|
||||
"dependencies": {
|
||||
"@openai/codex": "^0.124.0",
|
||||
"@openai/codex": "0.128.0",
|
||||
"ejclaw-runners-shared": "file:../shared",
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -15,19 +15,19 @@
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@openai/codex": ["@openai/codex@0.124.0", "", { "optionalDependencies": { "@openai/codex-darwin-arm64": "npm:@openai/codex@0.124.0-darwin-arm64", "@openai/codex-darwin-x64": "npm:@openai/codex@0.124.0-darwin-x64", "@openai/codex-linux-arm64": "npm:@openai/codex@0.124.0-linux-arm64", "@openai/codex-linux-x64": "npm:@openai/codex@0.124.0-linux-x64", "@openai/codex-win32-arm64": "npm:@openai/codex@0.124.0-win32-arm64", "@openai/codex-win32-x64": "npm:@openai/codex@0.124.0-win32-x64" }, "bin": { "codex": "bin/codex.js" } }, "sha512-1EVAuPyAQZ8zIVMw3bPJ6a4R8ifLAZ7LGsOyknj5c2he9AFXVRCmWx12WrdZJ25wcBvOEKt1n1Zx+QAj0EVGbQ=="],
|
||||
"@openai/codex": ["@openai/codex@0.128.0", "", { "optionalDependencies": { "@openai/codex-darwin-arm64": "npm:@openai/codex@0.128.0-darwin-arm64", "@openai/codex-darwin-x64": "npm:@openai/codex@0.128.0-darwin-x64", "@openai/codex-linux-arm64": "npm:@openai/codex@0.128.0-linux-arm64", "@openai/codex-linux-x64": "npm:@openai/codex@0.128.0-linux-x64", "@openai/codex-win32-arm64": "npm:@openai/codex@0.128.0-win32-arm64", "@openai/codex-win32-x64": "npm:@openai/codex@0.128.0-win32-x64" }, "bin": { "codex": "bin/codex.js" } }, "sha512-+xp6ODmFfBNnexIWRHApEaPXot2j6gyM8A5we/5IS/uY4eYHj4arETct4hQ5M4eO+MK7JY3ZU4xhuobhlysr0A=="],
|
||||
|
||||
"@openai/codex-darwin-arm64": ["@openai/codex@0.124.0-darwin-arm64", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lnuqeAdl+RjPWsqVZ8rrPskRIOZmzlyr8e5q/wFVEnMPsm9dWgjRW1PKa84UmDSQVOuz9GObF28DEHFyC4A8NA=="],
|
||||
"@openai/codex-darwin-arm64": ["@openai/codex@0.128.0-darwin-arm64", "", { "os": "darwin", "cpu": "arm64" }, "sha512-w+6zohfHx/kHBdles/CyFKaY57u9I3nK8QI9+NrdwMliKA0b7xn13yblRNkMpe09j6vL1oAWoxYsMOQ/vjBGug=="],
|
||||
|
||||
"@openai/codex-darwin-x64": ["@openai/codex@0.124.0-darwin-x64", "", { "os": "darwin", "cpu": "x64" }, "sha512-Br+VlL83IOu96Urw+mkZ1PQXLsQXGAYEH6kXNt4ULuVt7qAdQY2FKYwIgLLVLl0vpMk8qWxdfdVMqhiu2uCHlg=="],
|
||||
"@openai/codex-darwin-x64": ["@openai/codex@0.128.0-darwin-x64", "", { "os": "darwin", "cpu": "x64" }, "sha512-SDbn6fO22Puy8xmMIbZi4f2znMrUEPwABApke4mo+4ihaauwuVjeqzXvW5SPJz5ty/bG11/mSupQgReT7T8BBw=="],
|
||||
|
||||
"@openai/codex-linux-arm64": ["@openai/codex@0.124.0-linux-arm64", "", { "os": "linux", "cpu": "arm64" }, "sha512-QXafFVQJxPfU1LSCI5afuHsF5evKAcbQpFuKou0Kl241/HG/zYHdwoWj546zH844gJgegIPAxPf36+RSkUsbbA=="],
|
||||
"@openai/codex-linux-arm64": ["@openai/codex@0.128.0-linux-arm64", "", { "os": "linux", "cpu": "arm64" }, "sha512-+SvH73H60qvCXFuQGP/EsmR//s1hHMBR22PvJkXvM/hdnTIGucx+JqRUjAWdmmQ1IU6j3kgwVvdLW/6ICB+M6w=="],
|
||||
|
||||
"@openai/codex-linux-x64": ["@openai/codex@0.124.0-linux-x64", "", { "os": "linux", "cpu": "x64" }, "sha512-cJ4QfQIrz2gkXVWephiGo9JDyD3qLKhvkTTLk7gI8rKd7MZpVXn9/1e7pZCQnJVA7Dk6ocA5G+sxnR78SoIejw=="],
|
||||
"@openai/codex-linux-x64": ["@openai/codex@0.128.0-linux-x64", "", { "os": "linux", "cpu": "x64" }, "sha512-2lnSPA05CRRuKAzFW8BCmmNCSieDcToLwfC2ALLbBYilGLgzhRibjlDglK9F1BkEzfohSSWJu4PBbRu/aG60lQ=="],
|
||||
|
||||
"@openai/codex-win32-arm64": ["@openai/codex@0.124.0-win32-arm64", "", { "os": "win32", "cpu": "arm64" }, "sha512-oDSI/CQh0kagBwWVPG9EiUBfHiY27ju3LPrjTVZg4VMpVJVNA31JTK8rHMZ6G/2gfNmOl6DMBA6+0ICxSkkshg=="],
|
||||
"@openai/codex-win32-arm64": ["@openai/codex@0.128.0-win32-arm64", "", { "os": "win32", "cpu": "arm64" }, "sha512-ECJvsqmYFdA9pn42xxK3Odp/G16AjmBW0BglX8L0PwPjqbstbmlew9bfHf7xvL+SNfNl4NmyotW0+RNo1phgaA=="],
|
||||
|
||||
"@openai/codex-win32-x64": ["@openai/codex@0.124.0-win32-x64", "", { "os": "win32", "cpu": "x64" }, "sha512-t+lAwmCWwIWQKk6dKaYetRhQsmA+uDmQy1NLka1xAAv3PlNOH8iNz9Lsisr3qYkBR8Tf7tbQlt+pl9tw/A5mfA=="],
|
||||
"@openai/codex-win32-x64": ["@openai/codex@0.128.0-win32-x64", "", { "os": "win32", "cpu": "x64" }, "sha512-k3jmUAFrzkUtvjGTXvSKjQqJLLlzjxp/VoHJDYedgmXUn6j70HxK38IwapzmnYfiBiTuzETvGwjXHzZgzKjhoQ=="],
|
||||
|
||||
"@types/node": ["@types/node@22.19.15", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg=="],
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
"start": "bun dist/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"ejclaw-runners-shared": "file:../shared",
|
||||
"@openai/codex": "^0.124.0"
|
||||
"@openai/codex": "0.128.0",
|
||||
"ejclaw-runners-shared": "file:../shared"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.10.7",
|
||||
|
||||
@@ -42,6 +42,53 @@ export interface CodexAppServerTurnResult {
|
||||
result: string | null;
|
||||
}
|
||||
|
||||
export interface CodexThreadGoal {
|
||||
threadId: string;
|
||||
objective: string;
|
||||
status: string;
|
||||
tokenBudget: number | null;
|
||||
tokensUsed: number;
|
||||
timeUsedSeconds: number;
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
}
|
||||
|
||||
export function buildCodexAppServerArgs(args: {
|
||||
codexBin: string;
|
||||
enableGoals?: boolean;
|
||||
}): string[] {
|
||||
return args.enableGoals === true
|
||||
? [args.codexBin, '--enable', 'goals', 'app-server']
|
||||
: [args.codexBin, 'app-server'];
|
||||
}
|
||||
|
||||
function isCodexThreadGoal(value: unknown): value is CodexThreadGoal {
|
||||
if (!value || typeof value !== 'object') return false;
|
||||
const goal = value as Partial<CodexThreadGoal>;
|
||||
return (
|
||||
typeof goal.threadId === 'string' &&
|
||||
typeof goal.objective === 'string' &&
|
||||
typeof goal.status === 'string'
|
||||
);
|
||||
}
|
||||
|
||||
function extractOptionalGoalResult(result: unknown): CodexThreadGoal | null {
|
||||
const goal = (result as { goal?: unknown } | null)?.goal ?? null;
|
||||
if (goal === null) return null;
|
||||
if (!isCodexThreadGoal(goal)) {
|
||||
throw new Error('Codex app-server returned an invalid goal payload.');
|
||||
}
|
||||
return goal;
|
||||
}
|
||||
|
||||
function extractGoalResult(result: unknown, method: string): CodexThreadGoal {
|
||||
const goal = extractOptionalGoalResult(result);
|
||||
if (!goal) {
|
||||
throw new Error(`Codex app-server ${method} did not return a goal.`);
|
||||
}
|
||||
return goal;
|
||||
}
|
||||
|
||||
interface JsonRpcResponse {
|
||||
id: number;
|
||||
result?: unknown;
|
||||
@@ -79,12 +126,14 @@ export interface CodexAppServerClientOptions {
|
||||
cwd: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
log: (message: string) => void;
|
||||
enableGoals?: boolean;
|
||||
}
|
||||
|
||||
export class CodexAppServerClient {
|
||||
private readonly cwd: string;
|
||||
private readonly env: NodeJS.ProcessEnv;
|
||||
private readonly log: (message: string) => void;
|
||||
private readonly enableGoals: boolean;
|
||||
private readonly pending = new Map<number, PendingRequest>();
|
||||
private readonly require = createRequire(import.meta.url);
|
||||
private nextId = 1;
|
||||
@@ -96,6 +145,7 @@ export class CodexAppServerClient {
|
||||
this.cwd = options.cwd;
|
||||
this.env = options.env || process.env;
|
||||
this.log = options.log;
|
||||
this.enableGoals = options.enableGoals === true;
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
@@ -108,11 +158,18 @@ export class CodexAppServerClient {
|
||||
'codex.js',
|
||||
);
|
||||
|
||||
this.proc = spawn(process.execPath, [codexBin, 'app-server'], {
|
||||
cwd: this.cwd,
|
||||
env: this.env,
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
});
|
||||
this.proc = spawn(
|
||||
process.execPath,
|
||||
buildCodexAppServerArgs({
|
||||
codexBin,
|
||||
enableGoals: this.enableGoals,
|
||||
}),
|
||||
{
|
||||
cwd: this.cwd,
|
||||
env: this.env,
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
},
|
||||
);
|
||||
|
||||
this.proc.stdout.setEncoding('utf8');
|
||||
this.proc.stdout.on('data', (chunk: string) => {
|
||||
@@ -312,6 +369,27 @@ export class CodexAppServerClient {
|
||||
return turnPromise;
|
||||
}
|
||||
|
||||
async threadGoalSet(
|
||||
threadId: string,
|
||||
objective: string,
|
||||
): Promise<CodexThreadGoal> {
|
||||
const result = await this.request('thread/goal/set', {
|
||||
threadId,
|
||||
objective,
|
||||
});
|
||||
return extractGoalResult(result, 'thread/goal/set');
|
||||
}
|
||||
|
||||
async threadGoalGet(threadId: string): Promise<CodexThreadGoal | null> {
|
||||
const result = await this.request('thread/goal/get', { threadId });
|
||||
return extractOptionalGoalResult(result);
|
||||
}
|
||||
|
||||
async threadGoalClear(threadId: string): Promise<boolean> {
|
||||
const result = await this.request('thread/goal/clear', { threadId });
|
||||
return (result as { cleared?: boolean } | null)?.cleared === true;
|
||||
}
|
||||
|
||||
private handleStdoutLine(line: string): void {
|
||||
let message: JsonRpcResponse | JsonRpcNotification | JsonRpcServerRequest;
|
||||
try {
|
||||
|
||||
@@ -52,6 +52,7 @@ interface RunnerInput {
|
||||
isScheduledTask?: boolean;
|
||||
assistantName?: string;
|
||||
agentType?: string;
|
||||
codexGoals?: boolean;
|
||||
roomRoleContext?: RoomRoleContext;
|
||||
}
|
||||
|
||||
@@ -95,6 +96,10 @@ function log(message: string): void {
|
||||
console.error(`[codex-runner] ${message}`);
|
||||
}
|
||||
|
||||
function isCodexGoalsEnabled(runnerInput: RunnerInput): boolean {
|
||||
return runnerInput.codexGoals === true || process.env.CODEX_GOALS === 'true';
|
||||
}
|
||||
|
||||
async function readStdin(): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let data = '';
|
||||
@@ -343,6 +348,7 @@ async function runAppServerSession(
|
||||
cwd: EFFECTIVE_CWD,
|
||||
env: clientEnv,
|
||||
log,
|
||||
enableGoals: isCodexGoalsEnabled(runnerInput),
|
||||
});
|
||||
|
||||
await client.start();
|
||||
|
||||
87
runners/codex-runner/test/app-server-client.test.ts
Normal file
87
runners/codex-runner/test/app-server-client.test.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import {
|
||||
CodexAppServerClient,
|
||||
buildCodexAppServerArgs,
|
||||
} from '../src/app-server-client.js';
|
||||
|
||||
describe('codex app-server client goals', () => {
|
||||
it('does not enable goals by default when spawning app-server', () => {
|
||||
expect(
|
||||
buildCodexAppServerArgs({
|
||||
codexBin: '/opt/codex/bin/codex.js',
|
||||
}),
|
||||
).toEqual(['/opt/codex/bin/codex.js', 'app-server']);
|
||||
});
|
||||
|
||||
it('adds the under-development goals feature only when explicitly enabled', () => {
|
||||
expect(
|
||||
buildCodexAppServerArgs({
|
||||
codexBin: '/opt/codex/bin/codex.js',
|
||||
enableGoals: true,
|
||||
}),
|
||||
).toEqual(['/opt/codex/bin/codex.js', '--enable', 'goals', 'app-server']);
|
||||
});
|
||||
|
||||
it('wraps thread goal JSON-RPC methods with the upstream objective field', async () => {
|
||||
const client = new CodexAppServerClient({
|
||||
cwd: '/repo',
|
||||
log: () => undefined,
|
||||
});
|
||||
const request = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce({
|
||||
goal: {
|
||||
threadId: 'thread-1',
|
||||
objective: 'ship the release',
|
||||
status: 'active',
|
||||
tokenBudget: null,
|
||||
tokensUsed: 0,
|
||||
timeUsedSeconds: 0,
|
||||
createdAt: 1,
|
||||
updatedAt: 1,
|
||||
},
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
goal: {
|
||||
threadId: 'thread-1',
|
||||
objective: 'ship the release',
|
||||
status: 'active',
|
||||
tokenBudget: null,
|
||||
tokensUsed: 0,
|
||||
timeUsedSeconds: 0,
|
||||
createdAt: 1,
|
||||
updatedAt: 1,
|
||||
},
|
||||
})
|
||||
.mockResolvedValueOnce({ cleared: true });
|
||||
(
|
||||
client as unknown as {
|
||||
request: (method: string, params?: unknown) => Promise<unknown>;
|
||||
}
|
||||
).request = request;
|
||||
|
||||
await expect(
|
||||
client.threadGoalSet('thread-1', 'ship the release'),
|
||||
).resolves.toMatchObject({
|
||||
threadId: 'thread-1',
|
||||
objective: 'ship the release',
|
||||
status: 'active',
|
||||
});
|
||||
await expect(client.threadGoalGet('thread-1')).resolves.toMatchObject({
|
||||
objective: 'ship the release',
|
||||
});
|
||||
await expect(client.threadGoalClear('thread-1')).resolves.toBe(true);
|
||||
|
||||
expect(request).toHaveBeenNthCalledWith(1, 'thread/goal/set', {
|
||||
threadId: 'thread-1',
|
||||
objective: 'ship the release',
|
||||
});
|
||||
expect(request).toHaveBeenNthCalledWith(2, 'thread/goal/get', {
|
||||
threadId: 'thread-1',
|
||||
});
|
||||
expect(request).toHaveBeenNthCalledWith(3, 'thread/goal/clear', {
|
||||
threadId: 'thread-1',
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user