From de1c534c07f268e1d17de388f6d94617326ffd54 Mon Sep 17 00:00:00 2001 From: David699 <33142294+David699@users.noreply.github.com> Date: Wed, 2 Sep 2026 23:57:36 +0800 Subject: [PATCH] fix: report non-zero process exits in tool logs Allow logged tool operations to derive result metadata from successful return values. Process tools now record running state and exit codes, and mark completed non-zero or signal exits as failed instead of reporting every resolved operation as successful. --- src/tool-surfaces/codex.test.ts | 48 +++++++++++++++++++++++++++++++++ src/tool-surfaces/codex.ts | 17 ++++++++++++ src/tool-surfaces/shared.ts | 5 +++- src/tool-surfaces/types.ts | 3 +++ 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 src/tool-surfaces/codex.test.ts 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;