From eb814b021648cc310a88b885f3cd190a98e99ee5 Mon Sep 17 00:00:00 2001 From: "clawsweeper[bot]" <274271284+clawsweeper[bot]@users.noreply.github.com> Date: Wed, 20 May 2026 02:29:49 +0000 Subject: [PATCH] Fix Codex image generation tool timeout (#84369) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: - The branch gives Codex `image_generate` dynamic-tool calls a 120s default watchdog in main and side-thread paths and updates docs, tests, and changelog. - Reproducibility: yes. Source inspection on current main shows unconfigured Codex `image_generate` calls fall ... -tool default, and the linked source PR includes live Gateway before/after output for the timeout behavior. Automerge notes: - PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8425… - PR branch already contained follow-up commit before automerge: Fix Codex image generation tool timeout Validation: - ClawSweeper review passed for head 10c7f87023c824280bd92b75483b4ef46d082937. - Required merge gates passed before the squash merge. Prepared head SHA: 10c7f87023c824280bd92b75483b4ef46d082937 Review: https://github.com/openclaw/openclaw/pull/84369#issuecomment-4493288493 Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com> Co-authored-by: moritzmmayerhofer <254141390+moritzmmayerhofer@users.noreply.github.com> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com> --- CHANGELOG.md | 1 + docs/plugins/codex-harness-reference.md | 2 ++ docs/plugins/codex-harness.md | 5 +++-- docs/tools/image-generation.md | 5 +++-- .../codex/src/app-server/run-attempt.test.ts | 16 ++++++++++++++++ extensions/codex/src/app-server/run-attempt.ts | 8 ++++++-- .../codex/src/app-server/side-question.test.ts | 14 ++++++++++++++ extensions/codex/src/app-server/side-question.ts | 4 +++- 8 files changed, 48 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6a4ec05da06..95473a2a1e5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ Docs: https://docs.openclaw.ai ### Fixes - Agents/code mode: spell out the `exec` tool's JavaScript/TypeScript, no Node module, and catalog-bridge constraints in model-visible schema text so agents can use enabled tools without trial-and-error. (#84269) Thanks @Kaspre. +- Codex: give `image_generate` dynamic-tool calls a 120s default watchdog when no per-call or configured image timeout is set, so image generation no longer falls back to the generic 30s bridge timeout. (#84254) Thanks @moritzmmayerhofer. - CLI/message: include a stable top-level `messageId` in `openclaw message --json` output when channel sends return one. (#84191) Thanks @100menotu001. - Gateway/agents: use an agent's `identity.name` in Gateway agent summaries when `agents.list[].name` is unset, so configured agent labels remain visible in clients. (#84355; refs #57835) Thanks @luoyanglang. - Plugins/hooks: apply a default 30-second timeout to `before_compaction` and `after_compaction` hooks so a hung plugin handler no longer blocks compaction completion. (#84153) diff --git a/docs/plugins/codex-harness-reference.md b/docs/plugins/codex-harness-reference.md index 9c930071eaad..199b14d13a48 100644 --- a/docs/plugins/codex-harness-reference.md +++ b/docs/plugins/codex-harness-reference.md @@ -256,6 +256,8 @@ available timeout in this order: - A positive per-call `timeoutMs` argument. - For `image_generate`, `agents.defaults.imageGenerationModel.timeoutMs`. +- For `image_generate` without a configured timeout, the 120 second + image-generation default. - For the media-understanding `image` tool, `tools.media.image.timeoutSeconds` converted to milliseconds, or the 60 second media default. - The 30 second dynamic-tool default. diff --git a/docs/plugins/codex-harness.md b/docs/plugins/codex-harness.md index 4fa60a9132ef..da5a559013bf 100644 --- a/docs/plugins/codex-harness.md +++ b/docs/plugins/codex-harness.md @@ -532,9 +532,10 @@ Supported `appServer` fields: OpenClaw-owned dynamic tool calls are bounded independently from `appServer.requestTimeoutMs`: Codex `item/tool/call` requests use a 30 second OpenClaw watchdog by default. A positive per-call `timeoutMs` argument extends -or shortens that specific tool budget. The `image_generate` tool also uses +or shortens that specific tool budget. The `image_generate` tool uses `agents.defaults.imageGenerationModel.timeoutMs` when the tool call does not -provide its own timeout, and the media-understanding `image` tool uses +provide its own timeout, or a 120 second image-generation default otherwise. +The media-understanding `image` tool uses `tools.media.image.timeoutSeconds` or its 60 second media default. Dynamic tool budgets are capped at 600000 ms. On timeout, OpenClaw aborts the tool signal where supported and returns a failed dynamic-tool response to Codex so the turn diff --git a/docs/tools/image-generation.md b/docs/tools/image-generation.md index 83f34680e456..5108467413ca 100644 --- a/docs/tools/image-generation.md +++ b/docs/tools/image-generation.md @@ -237,8 +237,9 @@ from each attempt. backends. A per-call `timeoutMs` tool parameter overrides the configured default. Google, OpenRouter, and xAI hosted image providers use 180 second defaults; Azure OpenAI image generation uses 600 seconds. Codex dynamic-tool - calls honor the same timeout budget, bounded by OpenClaw's 600000 ms - dynamic-tool bridge maximum. + calls use a 120 second `image_generate` bridge default and honor the same + timeout budget when configured, bounded by OpenClaw's 600000 ms dynamic-tool + bridge maximum. Use `action: "list"` to inspect the currently registered providers, diff --git a/extensions/codex/src/app-server/run-attempt.test.ts b/extensions/codex/src/app-server/run-attempt.test.ts index 75589e3ea2e4..c9b9268a199d 100644 --- a/extensions/codex/src/app-server/run-attempt.test.ts +++ b/extensions/codex/src/app-server/run-attempt.test.ts @@ -1903,6 +1903,22 @@ describe("runCodexAppServerAttempt", () => { ).toBe(180_000); }); + it("uses a 120 second default for Codex image generation dynamic tool calls", () => { + expect( + testing.resolveDynamicToolCallTimeoutMs({ + call: { + threadId: "thread-1", + turnId: "turn-1", + callId: "call-image-generate-default", + namespace: null, + tool: "image_generate", + arguments: { prompt: "cat" }, + }, + config: undefined, + }), + ).toBe(120_000); + }); + it("uses the media image timeout for Codex image dynamic tool calls", () => { expect( testing.resolveDynamicToolCallTimeoutMs({ diff --git a/extensions/codex/src/app-server/run-attempt.ts b/extensions/codex/src/app-server/run-attempt.ts index 80d0c55fb9ad..c28e0c3e8a43 100644 --- a/extensions/codex/src/app-server/run-attempt.ts +++ b/extensions/codex/src/app-server/run-attempt.ts @@ -181,6 +181,7 @@ import { filterToolsForVisionInputs } from "./vision-tools.js"; const CODEX_DYNAMIC_TOOL_TIMEOUT_MS = 30_000; const CODEX_DYNAMIC_TOOL_MAX_TIMEOUT_MS = 600_000; +const CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS = 120_000; const CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS = 60_000; const CODEX_APP_SERVER_STARTUP_CONNECTION_CLOSE_MAX_ATTEMPTS = 3; const CODEX_APP_SERVER_STARTUP_TIMEOUT_FLOOR_MS = 100; @@ -3020,9 +3021,12 @@ function readConfiguredDynamicToolTimeoutMs( if (toolName === "image_generate") { const imageGenerationModel = config?.agents?.defaults?.imageGenerationModel; if (!imageGenerationModel || typeof imageGenerationModel !== "object") { - return undefined; + return CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS; } - return readPositiveFiniteTimeoutMs(imageGenerationModel.timeoutMs); + return ( + readPositiveFiniteTimeoutMs(imageGenerationModel.timeoutMs) ?? + CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS + ); } if (toolName === "image") { diff --git a/extensions/codex/src/app-server/side-question.test.ts b/extensions/codex/src/app-server/side-question.test.ts index 330e54d7d285..c9099b76bc1a 100644 --- a/extensions/codex/src/app-server/side-question.test.ts +++ b/extensions/codex/src/app-server/side-question.test.ts @@ -1072,6 +1072,20 @@ describe("runCodexAppServerSideQuestion", () => { expect(timeoutMs).toBe(123_456); }); + it("uses a 120 second default for side-thread image_generate calls", () => { + const timeoutMs = testing.resolveSideDynamicToolCallTimeoutMs({ + call: { + threadId: "side-thread", + turnId: "turn-1", + callId: "tool-1", + tool: "image_generate", + }, + config: {} as never, + }); + + expect(timeoutMs).toBe(120_000); + }); + it("cleans up notification handlers when side tool setup fails", async () => { const client = createFakeClient(); createOpenClawCodingToolsMock.mockImplementation(() => { diff --git a/extensions/codex/src/app-server/side-question.ts b/extensions/codex/src/app-server/side-question.ts index 92051d834ca7..fd616317ba01 100644 --- a/extensions/codex/src/app-server/side-question.ts +++ b/extensions/codex/src/app-server/side-question.ts @@ -66,6 +66,7 @@ import { filterToolsForVisionInputs } from "./vision-tools.js"; const CODEX_SIDE_DYNAMIC_TOOL_TIMEOUT_MS = 30_000; const CODEX_SIDE_DYNAMIC_TOOL_MAX_TIMEOUT_MS = 600_000; +const CODEX_SIDE_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS = 120_000; const CODEX_SIDE_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS = 60_000; const SIDE_QUESTION_COMPLETION_TIMEOUT_MS = 600_000; const CODEX_SIDE_NATIVE_HOOK_RELAY_MIN_TTL_MS = 30 * 60_000; @@ -671,7 +672,8 @@ function resolveSideDynamicToolCallTimeoutMs(params: { const configured = readSideDynamicToolCallTimeoutMs(params.call.arguments) ?? (params.call.tool === "image_generate" - ? readSideImageGenerationModelTimeoutMs(params.config) + ? (readSideImageGenerationModelTimeoutMs(params.config) ?? + CODEX_SIDE_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS) : undefined) ?? (params.call.tool === "image" ? (readSideTimeoutSecondsAsMs(params.config?.tools?.media?.image?.timeoutSeconds) ??