fix(codex): classify get_goal read statuses as successful dynamic tool calls (#98659)

isCodexToolResultError fail-closes any dynamic-tool result whose
details.status is absent from its non-error allowlist. get_goal returns
details.status "found" or "missing" (a successful read of the thread
goal, or its absence), neither of which was in the allowlist, so every
get_goal call was classified as an error: reported to codex as
success: false and persisted on the transcript with isError: true.

Sibling #96856 added the write-side goal statuses (created/updated) and
the accepted spawn status but missed the read-side get_goal statuses.
This adds found/missing alongside them. Genuinely failed statuses stay
fail-closed.
This commit is contained in:
Yuval Dinodia
2026-07-01 11:36:38 -04:00
committed by GitHub
parent 9541f4e8bd
commit adcfebc276
2 changed files with 49 additions and 0 deletions
@@ -402,6 +402,53 @@ describe("createCodexDynamicToolBridge", () => {
expect(updatedResult.success).toBe(true);
});
it("treats get_goal read statuses (found / missing) as successful dynamic tool calls", async () => {
const onFoundResult = vi.fn();
const foundBridge = createBridgeWithToolResult(
"get_goal",
textToolResult('{\n "status": "found"\n}', {
status: "found",
goal: { objective: "ship the fix", status: "active" },
}),
);
const foundResult = await foundBridge.handleToolCall(
{
threadId: "thread-1",
turnId: "turn-1",
callId: "call-found",
namespace: null,
tool: "get_goal",
arguments: {},
},
{ onAgentToolResult: onFoundResult },
);
expect(foundResult.success).toBe(true);
expect(onFoundResult).toHaveBeenCalledWith(
expect.objectContaining({ toolName: "get_goal", isError: false }),
);
const onMissingResult = vi.fn();
const missingBridge = createBridgeWithToolResult(
"get_goal",
textToolResult('{\n "status": "missing"\n}', { status: "missing" }),
);
const missingResult = await missingBridge.handleToolCall(
{
threadId: "thread-1",
turnId: "turn-1",
callId: "call-missing",
namespace: null,
tool: "get_goal",
arguments: {},
},
{ onAgentToolResult: onMissingResult },
);
expect(missingResult.success).toBe(true);
expect(onMissingResult).toHaveBeenCalledWith(
expect.objectContaining({ toolName: "get_goal", isError: false }),
);
});
it("keeps available and registered schemas paired with their tools", () => {
const bridge = createCodexDynamicToolBridge({
tools: [
@@ -1187,6 +1187,8 @@ function isCodexToolResultError(result: AgentToolResult<unknown>): boolean {
status !== "created" &&
status !== "updated" &&
status !== "accepted" &&
status !== "found" &&
status !== "missing" &&
status !== "pending" &&
status !== "started" &&
status !== "running" &&