From 8dcfc9cb69b3cc8f7265be9cad245843e4c52d14 Mon Sep 17 00:00:00 2001 From: Kelaw - Keshav's Agent Date: Wed, 6 May 2026 01:53:15 +0530 Subject: [PATCH] Mark declined Codex tools as blocked --- .../src/app-server/event-projector.test.ts | 46 +++++++++++++++++++ .../codex/src/app-server/event-projector.ts | 11 ++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/extensions/codex/src/app-server/event-projector.test.ts b/extensions/codex/src/app-server/event-projector.test.ts index a553459e3c9..de01d314803 100644 --- a/extensions/codex/src/app-server/event-projector.test.ts +++ b/extensions/codex/src/app-server/event-projector.test.ts @@ -733,6 +733,52 @@ describe("CodexAppServerEventProjector", () => { }); }); + it("marks declined Codex-native tool results as non-success", async () => { + const onAgentEvent = vi.fn(); + const projector = await createProjector({ ...(await createParams()), onAgentEvent }); + + await projector.handleNotification( + forCurrentTurn("item/completed", { + item: { + type: "commandExecution", + id: "cmd-declined", + command: "pnpm test extensions/codex", + cwd: "/workspace", + processId: null, + source: "agent", + status: "declined", + commandActions: [], + aggregatedOutput: null, + exitCode: null, + durationMs: null, + }, + }), + ); + + expect(onAgentEvent).toHaveBeenCalledWith({ + stream: "item", + data: expect.objectContaining({ + phase: "end", + kind: "command", + name: "bash", + itemId: "cmd-declined", + status: "blocked", + suppressChannelProgress: true, + }), + }); + expect(onAgentEvent).toHaveBeenCalledWith({ + stream: "tool", + data: expect.objectContaining({ + phase: "result", + name: "bash", + itemId: "cmd-declined", + toolCallId: "cmd-declined", + status: "blocked", + isError: true, + }), + }); + }); + it("leaves Codex dynamic tool item progress to item/tool/call normalization", async () => { const onAgentEvent = vi.fn(); const projector = await createProjector({ ...(await createParams()), onAgentEvent }); diff --git a/extensions/codex/src/app-server/event-projector.ts b/extensions/codex/src/app-server/event-projector.ts index 0a3a86f764e..36bc732d808 100644 --- a/extensions/codex/src/app-server/event-projector.ts +++ b/extensions/codex/src/app-server/event-projector.ts @@ -706,7 +706,7 @@ export class CodexAppServerEventProjector { ...(params.phase === "result" ? { status, - isError: status === "failed", + isError: isNonSuccessItemStatus(status), ...itemToolResult(item), } : {}), @@ -1118,17 +1118,24 @@ function itemTitle(item: CodexThreadItem): string { } } -function itemStatus(item: CodexThreadItem): "completed" | "failed" | "running" { +function itemStatus(item: CodexThreadItem): "completed" | "failed" | "running" | "blocked" { const status = readItemString(item, "status"); if (status === "failed") { return "failed"; } + if (status === "declined") { + return "blocked"; + } if (status === "inProgress" || status === "running") { return "running"; } return "completed"; } +function isNonSuccessItemStatus(status: ReturnType): boolean { + return status === "failed" || status === "blocked"; +} + function itemName(item: CodexThreadItem): string | undefined { if (item.type === "dynamicToolCall" && typeof item.tool === "string") { return item.tool;