From 8d4928b505846f503f99b9ac379bf91155b4b699 Mon Sep 17 00:00:00 2001 From: "clawsweeper[bot]" <274271284+clawsweeper[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 00:27:32 -0700 Subject: [PATCH] fix(sdk): treat terminal wait timeouts as timed out (#74697) * fix: wait-status mapping sdk regression * fix(sdk): treat terminal wait timeouts as timed out --------- Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com> Co-authored-by: clawsweeper-repair --- CHANGELOG.md | 1 + packages/sdk/src/client.ts | 15 +++++++++++++-- packages/sdk/src/index.test.ts | 22 ++++++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42737d8755f..afcbf1f78d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,7 @@ Docs: https://docs.openclaw.ai - Gateway/models: serve the last successful model catalog while stale reloads refresh in the background, so Gateway control-plane and OpenAI-compatible requests no longer block behind model-provider rediscovery after model config changes. Refs #74135, #74630, and #74633. Thanks @DerFlash, @moltar-bot, and @Saboor711. - CLI/status: resolve read-only channel setup runtime fallback from the packaged OpenClaw dist root, so `status --all`, `status --deep`, channel, and doctor paths do not crash when an external channel plugin needs setup metadata. Fixes #74693. Thanks @giangthb. - SDK/events: keep per-run SDK event streams from surfacing duplicate raw chat projection frames, while normalizing chat-only projection frames and preserving raw access through `rawEvents`. Refs #74704. Thanks @BunsDev. +- SDK: report Gateway terminal `agent.wait` timeout snapshots with lifecycle metadata as `timed_out` while keeping bare wait deadlines non-terminal. Thanks @clawsweeper. - Google Meet: block managed Chrome intro/test speech until browser health proves the participant is in-call, and expose `speechReady` diagnostics so login, admission, permission, and audio-bridge blockers no longer look like successful speech. Refs #72478. Thanks @DougButdorf. - Slack/commands: keep native command argument menus on select controls for encoded choice values up to Slack's option limit and truncate fallback button labels to Slack's button-text limit, so long valid choices no longer render invalid Slack blocks. Thanks @slackapi. - Agents/Codex: flush accepted debounced steering messages before normal app-server turn cleanup, so inbound follow-ups acknowledged as queued are not dropped when the turn completes before the debounce fires. Thanks @vincentkoc. diff --git a/packages/sdk/src/client.ts b/packages/sdk/src/client.ts index 9b1dc66a2ab..b04663c4f02 100644 --- a/packages/sdk/src/client.ts +++ b/packages/sdk/src/client.ts @@ -42,10 +42,16 @@ function resolveGatewayUrl(options: OpenClawOptions): string | undefined { function runStatusFromWaitPayload(payload: unknown): RunResult["status"] { const record = typeof payload === "object" && payload !== null - ? (payload as { aborted?: unknown; status?: unknown; stopReason?: unknown }) + ? (payload as Record & { aborted?: unknown; status?: unknown }) : {}; const status = typeof record.status === "string" ? record.status.toLowerCase() : undefined; const stopReason = typeof record.stopReason === "string" ? record.stopReason.toLowerCase() : ""; + const hasTerminalTimeoutMetadata = + readOptionalTimestamp(record.endedAt) !== undefined || + readOptionalString(record.error) !== undefined || + stopReason.length > 0 || + typeof record.livenessState === "string" || + record.yielded === true; if ( status === "aborted" || status === "cancelled" || @@ -65,7 +71,12 @@ function runStatusFromWaitPayload(payload: unknown): RunResult["status"] { return "completed"; } if (status === "timeout") { - if (stopReason === "timeout" || stopReason === "timed_out" || record.aborted === true) { + if ( + stopReason === "timeout" || + stopReason === "timed_out" || + record.aborted === true || + hasTerminalTimeoutMetadata + ) { return "timed_out"; } return "accepted"; diff --git a/packages/sdk/src/index.test.ts b/packages/sdk/src/index.test.ts index e27c1175bcb..adb8e1ee203 100644 --- a/packages/sdk/src/index.test.ts +++ b/packages/sdk/src/index.test.ts @@ -176,6 +176,28 @@ describe("OpenClaw SDK", () => { }); }); + it("maps terminal timeout snapshots without stop reasons to timed_out", async () => { + const transport = new FakeTransport({ + "agent.wait": { + status: "timeout", + runId: "run_timed_out", + startedAt: 123, + endedAt: 456, + }, + }); + const oc = new OpenClaw({ transport }); + + const result = await oc.runs.wait("run_timed_out"); + + expect(result).toMatchObject({ + runId: "run_timed_out", + status: "timed_out", + startedAt: 123, + endedAt: 456, + }); + expect(result.error).toBeUndefined(); + }); + it("splits provider-qualified model refs and rejects unsupported run options", async () => { const transport = new FakeTransport({ agent: { status: "accepted", runId: "run_openrouter" },