From 0530596eef512095963f3e7f00a06d3128768b7e Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 30 May 2026 15:56:29 -0400 Subject: [PATCH] fix(codex): clamp turn collector timeout --- .../src/conversation-turn-collector.test.ts | 21 +++++++++++++++++++ .../codex/src/conversation-turn-collector.ts | 3 ++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/extensions/codex/src/conversation-turn-collector.test.ts b/extensions/codex/src/conversation-turn-collector.test.ts index 47f4018dea0..288ba2a6363 100644 --- a/extensions/codex/src/conversation-turn-collector.test.ts +++ b/extensions/codex/src/conversation-turn-collector.test.ts @@ -1,3 +1,4 @@ +import { MAX_TIMER_TIMEOUT_MS } from "openclaw/plugin-sdk/number-runtime"; import { describe, expect, it, vi } from "vitest"; import { createCodexConversationTurnCollector } from "./conversation-turn-collector.js"; @@ -188,4 +189,24 @@ describe("codex conversation turn collector", () => { vi.useRealTimers(); } }); + + it("clamps oversized turn wait timers", async () => { + vi.useFakeTimers(); + try { + const setTimeoutSpy = vi.spyOn(globalThis, "setTimeout"); + const collector = createCodexConversationTurnCollector("thread-1"); + collector.setTurnId("turn-1"); + const completion = collector.wait({ timeoutMs: MAX_TIMER_TIMEOUT_MS + 1 }); + + expect(setTimeoutSpy).toHaveBeenCalledWith(expect.any(Function), MAX_TIMER_TIMEOUT_MS); + collector.handleNotification({ + method: "turn/completed", + params: { threadId: "thread-1", turn: { id: "turn-1", status: "completed", items: [] } }, + }); + + await expect(completion).resolves.toEqual({ replyText: "" }); + } finally { + vi.useRealTimers(); + } + }); }); diff --git a/extensions/codex/src/conversation-turn-collector.ts b/extensions/codex/src/conversation-turn-collector.ts index c9911b6f967..859745ea39f 100644 --- a/extensions/codex/src/conversation-turn-collector.ts +++ b/extensions/codex/src/conversation-turn-collector.ts @@ -1,3 +1,4 @@ +import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime"; import { asOptionalRecord as readRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import { readCodexNotificationThreadId, @@ -143,7 +144,7 @@ export function createCodexConversationTurnCollector(threadId: string) { reject(new Error("codex app-server bound turn timed out")); clearWaitState(); }, - Math.max(100, params.timeoutMs), + resolveTimerTimeoutMs(params.timeoutMs, 100, 100), ); timeout.unref?.(); });