diff --git a/src/tool-surfaces/codex.test.ts b/src/tool-surfaces/codex.test.ts new file mode 100644 index 000000000..6cd1b393d --- /dev/null +++ b/src/tool-surfaces/codex.test.ts @@ -0,0 +1,48 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { processLogFields } from "./codex.js"; + +test("process logging keeps a running command successful", () => { + assert.deepEqual( + processLogFields({ + sessionId: 7, + output: "", + outputTruncated: false, + running: true, + wallTimeMs: 10, + }), + { sessionId: 7, running: true, exitCode: undefined, success: true }, + ); +}); + +test("process logging marks a zero exit code successful", () => { + assert.deepEqual( + processLogFields({ + output: "done", + outputTruncated: false, + running: false, + exitCode: 0, + wallTimeMs: 20, + }), + { sessionId: undefined, running: false, exitCode: 0, success: true }, + ); +}); + +test("process logging marks a non-zero exit code failed", () => { + assert.deepEqual( + processLogFields({ + output: "failed", + outputTruncated: false, + running: false, + exitCode: 1, + wallTimeMs: 30, + }), + { + sessionId: undefined, + running: false, + exitCode: 1, + success: false, + error: "Process exited with code 1.", + }, + ); +}); diff --git a/src/tool-surfaces/codex.ts b/src/tool-surfaces/codex.ts index 526e175bb..3d19fb172 100644 --- a/src/tool-surfaces/codex.ts +++ b/src/tool-surfaces/codex.ts @@ -6,6 +6,7 @@ import { SHELL_TOOL_ANNOTATIONS, toolNames, workspaceIdDescription, + type ToolLogFields, type ToolRegistrationContext, } from "./types.js"; import { @@ -228,6 +229,7 @@ function registerCodexProcessTools(context: ToolRegistrationContext): void { maxOutputTokens, }); }, + processLogFields, ); return processToolResponse(snapshot); @@ -313,9 +315,24 @@ function registerCodexProcessTools(context: ToolRegistrationContext): void { maxOutputTokens, }); }, + processLogFields, ); return processToolResponse(snapshot); }, ); } + +export function processLogFields(result: ProcessSnapshot): Partial { + const success = result.running || result.exitCode === 0; + const termination = result.signal + ? `Process terminated by signal ${result.signal}.` + : `Process exited with code ${result.exitCode ?? "unknown"}.`; + return { + sessionId: result.sessionId, + running: result.running, + exitCode: result.exitCode, + success, + ...(success ? {} : { error: termination }), + }; +} diff --git a/src/tool-surfaces/shared.ts b/src/tool-surfaces/shared.ts index abfc0ba3a..1366d5a97 100644 --- a/src/tool-surfaces/shared.ts +++ b/src/tool-surfaces/shared.ts @@ -51,12 +51,15 @@ export async function runLoggedToolOperation( fields: Omit, startedAt: number, operation: () => Promise, + resultFields?: (result: T) => Partial, ): Promise { try { const result = await operation(); + const resultMetadata = resultFields?.(result); logToolCall(config, { ...fields, - success: true, + ...resultMetadata, + success: resultMetadata?.success ?? true, durationMs: Math.round(performance.now() - startedAt), }); return result; diff --git a/src/tool-surfaces/types.ts b/src/tool-surfaces/types.ts index a9d8131b8..7904d6666 100644 --- a/src/tool-surfaces/types.ts +++ b/src/tool-surfaces/types.ts @@ -48,6 +48,9 @@ export interface ToolLogFields { workingDirectory?: string; command?: string; commandLength?: number; + sessionId?: number; + running?: boolean; + exitCode?: number; success: boolean; durationMs: number; error?: string;