fix(codex): settle declined commands and file edits as failed (#5717)

Codex completes a command or file change with status "declined" when its
approval is denied. The shared status normalizer did not know that word
and fell back to "running", so the denied command kept a spinner after
the turn ended.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: Bae Seongmin <83870598+3ae3ae@users.noreply.github.com>
This commit is contained in:
paseo-bot[bot]
2026-09-30 00:06:21 +02:00
committed by GitHub
co-authored by Bae Seongmin
parent 767b0e970b
commit 53ee9cd993
2 changed files with 24 additions and 0 deletions
@@ -656,6 +656,29 @@ describe("codex tool-call mapper", () => {
});
});
it.each([
{
type: "commandExecution",
id: "codex-declined-command",
status: "declined",
command: "printf ok > /outside/permission.txt",
cwd: "/tmp/repo",
aggregatedOutput: null,
exitCode: null,
},
{
type: "fileChange",
id: "codex-declined-patch",
status: "declined",
changes: [],
},
])("settles a declined $type as failed instead of running", (threadItem) => {
const item = expectMapped(mapCodexToolCallFromThreadItem(threadItem));
expect(item.callId).toBe(threadItem.id);
expect(item.status).toBe("failed");
});
it("maps unknown tools to unknown detail with raw payloads", () => {
const item = expectMapped(
mapCodexToolCallEnvelope({
@@ -7,6 +7,7 @@ const FAILED_STATUS_VOCAB = new Set([
"errored",
"rejected",
"denied",
"declined",
]);
const CANCELED_STATUS_VOCAB = new Set(["canceled", "cancelled", "interrupted", "aborted"]);
const COMPLETED_STATUS_VOCAB = new Set(["completed", "complete", "done", "success", "succeeded"]);