From 2f2aee5fe8810c15259388eab9c10fab6b43c45e Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 28 Apr 2026 06:50:53 +0100 Subject: [PATCH] ci: retry cross-os agent runtime deps staging --- scripts/openclaw-cross-os-release-checks.ts | 65 +++++++++++++------ .../openclaw-cross-os-release-checks.test.ts | 17 +++++ 2 files changed, 62 insertions(+), 20 deletions(-) diff --git a/scripts/openclaw-cross-os-release-checks.ts b/scripts/openclaw-cross-os-release-checks.ts index 948ce5ddd96..b4214b929f6 100644 --- a/scripts/openclaw-cross-os-release-checks.ts +++ b/scripts/openclaw-cross-os-release-checks.ts @@ -4,6 +4,7 @@ import { spawn } from "node:child_process"; import { + appendFileSync, chmodSync, createWriteStream, existsSync, @@ -2552,27 +2553,51 @@ async function runModelsSet(params) { } async function runAgentTurn(params) { - const sessionId = `cross-os-release-check-${params.label}-${Date.now()}`; - const result = await runOpenClaw({ - lane: params.lane, - env: params.env, - args: [ - "agent", - "--agent", - "main", - "--session-id", - sessionId, - "--message", - "Reply with exact ASCII text OK only.", - "--json", - ], - logPath: params.logPath, - timeoutMs: 10 * 60 * 1000, - }); - if (!agentOutputHasExpectedOkMarker(result.stdout, { logPath: params.logPath })) { - throw new Error("Agent output did not contain the expected OK marker."); + let lastError; + for (let attempt = 1; attempt <= 2; attempt += 1) { + const sessionId = `cross-os-release-check-${params.label}-${Date.now()}-${attempt}`; + try { + const result = await runOpenClaw({ + lane: params.lane, + env: params.env, + args: [ + "agent", + "--agent", + "main", + "--session-id", + sessionId, + "--message", + "Reply with exact ASCII text OK only.", + "--json", + ], + logPath: params.logPath, + timeoutMs: 10 * 60 * 1000, + }); + if (!agentOutputHasExpectedOkMarker(result.stdout, { logPath: params.logPath })) { + throw new Error("Agent output did not contain the expected OK marker."); + } + return result; + } catch (error) { + lastError = error; + if (attempt >= 2 || !shouldRetryCrossOsAgentTurnError(error)) { + throw error; + } + appendFileSync( + params.logPath, + `\n[release-checks] retrying agent turn after bundled runtime deps staging failure: ${ + error instanceof Error ? error.message : String(error) + }\n`, + ); + } } - return result; + throw lastError; +} + +export function shouldRetryCrossOsAgentTurnError(error) { + const message = error instanceof Error ? error.message : String(error); + return /failed to (?:install|stage) bundled runtime deps|failed to stage bundled runtime deps after/u.test( + message, + ); } export function agentOutputHasExpectedOkMarker(stdout, options = {}) { diff --git a/test/scripts/openclaw-cross-os-release-checks.test.ts b/test/scripts/openclaw-cross-os-release-checks.test.ts index 69d027c7ea4..1ea1149f9d2 100644 --- a/test/scripts/openclaw-cross-os-release-checks.test.ts +++ b/test/scripts/openclaw-cross-os-release-checks.test.ts @@ -41,6 +41,7 @@ import { shouldSkipInstallerDaemonHealthCheck, shouldStopManagedGatewayBeforeManualFallback, shouldRunMainChannelDevUpdate, + shouldRetryCrossOsAgentTurnError, shouldUseManagedGatewayForInstallerRuntime, shouldUseManagedGatewayService, verifyDevUpdateStatus, @@ -83,6 +84,22 @@ describe("scripts/openclaw-cross-os-release-checks", () => { } }); + it("retries transient bundled runtime deps staging failures during agent turns", () => { + expect( + shouldRetryCrossOsAgentTurnError( + new Error("document-extract: failed to install bundled runtime deps: npm install failed"), + ), + ).toBe(true); + expect( + shouldRetryCrossOsAgentTurnError( + new Error("document-extract failed to stage bundled runtime deps after 463ms"), + ), + ).toBe(true); + expect(shouldRetryCrossOsAgentTurnError(new Error("Agent output did not contain OK."))).toBe( + false, + ); + }); + it("treats explicit empty-string args as values instead of boolean flags", () => { expect(parseArgs(["--ubuntu-runner", "", "--mode", "both"])).toEqual({ "ubuntu-runner": "",