From e052bdcfb686ece24d0ffb7e0d228712ebcdf554 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 2 May 2026 06:35:44 +0100 Subject: [PATCH] fix: stabilize GPT-5.5 release gates --- scripts/openclaw-cross-os-release-checks.ts | 38 +++++++++++++++++-- src/gateway/gateway-cli-backend.live.test.ts | 2 +- src/gateway/server-channels.test.ts | 24 ++++++++++-- src/gateway/server-channels.ts | 14 ++++--- .../openclaw-cross-os-release-checks.test.ts | 7 +++- 5 files changed, 70 insertions(+), 15 deletions(-) diff --git a/scripts/openclaw-cross-os-release-checks.ts b/scripts/openclaw-cross-os-release-checks.ts index 1ecc852d531..bc365caf596 100644 --- a/scripts/openclaw-cross-os-release-checks.ts +++ b/scripts/openclaw-cross-os-release-checks.ts @@ -40,6 +40,7 @@ const providerConfig = { secretEnv: "OPENAI_API_KEY", authChoice: "openai-api-key", model: "openai/gpt-5.5", + timeoutSeconds: 600, }, anthropic: { extensionId: "anthropic", @@ -91,7 +92,7 @@ export const CROSS_OS_GATEWAY_STATUS_COMMAND_TIMEOUT_MS = CROSS_OS_GATEWAY_STATUS_RPC_TIMEOUT_MS + 45_000; export const CROSS_OS_GATEWAY_READY_TIMEOUT_MS = 3 * 60_000; export const CROSS_OS_WINDOWS_GATEWAY_READY_TIMEOUT_MS = 5 * 60_000; -export const CROSS_OS_AGENT_TURN_TIMEOUT_SECONDS = 360; +export const CROSS_OS_AGENT_TURN_TIMEOUT_SECONDS = 600; if (isMainModule()) { try { @@ -1840,6 +1841,22 @@ async function runInstalledModelsSet(params) { logPath: params.logPath, timeoutMs: 2 * 60 * 1000, }); + if (typeof params.providerConfig.timeoutSeconds === "number") { + await runInstalledCli({ + cliPath: params.cliPath, + args: [ + "config", + "set", + `models.providers.${params.providerConfig.extensionId}.timeoutSeconds`, + String(params.providerConfig.timeoutSeconds), + "--strict-json", + ], + cwd: params.cwd, + env: params.env, + logPath: params.logPath, + timeoutMs: 2 * 60 * 1000, + }); + } await runInstalledCli({ cliPath: params.cliPath, args: [ @@ -1875,7 +1892,7 @@ async function runInstalledAgentTurn(params) { cwd: params.cwd, env: params.env, logPath: params.logPath, - timeoutMs: 10 * 60 * 1000, + timeoutMs: (CROSS_OS_AGENT_TURN_TIMEOUT_SECONDS + 60) * 1000, }); if (!agentOutputHasExpectedOkMarker(result.stdout, { logPath: params.logPath })) { throw new Error("Agent output did not contain the expected OK marker."); @@ -2616,6 +2633,21 @@ async function runModelsSet(params) { logPath: params.logPath, timeoutMs: 2 * 60 * 1000, }); + if (typeof params.providerConfig.timeoutSeconds === "number") { + await runOpenClaw({ + lane: params.lane, + env: params.env, + args: [ + "config", + "set", + `models.providers.${params.providerConfig.extensionId}.timeoutSeconds`, + String(params.providerConfig.timeoutSeconds), + "--strict-json", + ], + logPath: params.logPath, + timeoutMs: 2 * 60 * 1000, + }); + } await runOpenClaw({ lane: params.lane, env: params.env, @@ -2648,7 +2680,7 @@ async function runAgentTurn(params) { env: params.env, args: buildReleaseAgentTurnArgs(sessionId), logPath: params.logPath, - timeoutMs: 10 * 60 * 1000, + timeoutMs: (CROSS_OS_AGENT_TURN_TIMEOUT_SECONDS + 60) * 1000, }); if (!agentOutputHasExpectedOkMarker(result.stdout, { logPath: params.logPath })) { throw new Error("Agent output did not contain the expected OK marker."); diff --git a/src/gateway/gateway-cli-backend.live.test.ts b/src/gateway/gateway-cli-backend.live.test.ts index c90bd9c7a28..49c1aeeb810 100644 --- a/src/gateway/gateway-cli-backend.live.test.ts +++ b/src/gateway/gateway-cli-backend.live.test.ts @@ -56,7 +56,7 @@ const DEFAULT_MODEL = // The cron/MCP live probe now tolerates more cancelled tool-call retries in CI, // so the outer test budget needs enough headroom to finish those retries. const CLI_BACKEND_LIVE_TIMEOUT_MS = 20 * 60_000; -const CLI_BACKEND_REQUEST_TIMEOUT_MS = 240_000; +const CLI_BACKEND_REQUEST_TIMEOUT_MS = 600_000; const CLI_BACKEND_AGENT_TIMEOUT_SECONDS = Math.max( 1, Math.ceil(CLI_BACKEND_REQUEST_TIMEOUT_MS / 1000) - 10, diff --git a/src/gateway/server-channels.test.ts b/src/gateway/server-channels.test.ts index 60b7773e9ad..2722c97afa6 100644 --- a/src/gateway/server-channels.test.ts +++ b/src/gateway/server-channels.test.ts @@ -129,15 +129,18 @@ function createManager(options?: { getRuntimeConfig?: () => Record; channelIds?: ChannelId[]; startupTrace?: { measure: (name: string, run: () => T | Promise) => Promise }; + fillChannelDependencies?: boolean; }) { const log = createSubsystemLogger("gateway/server-channels-test"); const channelLogs = { discord: log } as Record; const runtime = runtimeForLogger(log); const channelRuntimeEnvs = { discord: runtime } as unknown as Record; const channelIds = options?.channelIds ?? ["discord"]; - for (const channelId of channelIds) { - channelLogs[channelId] ??= log.child(channelId); - channelRuntimeEnvs[channelId] ??= runtime; + if (options?.fillChannelDependencies !== false) { + for (const channelId of channelIds) { + channelLogs[channelId] ??= log.child(channelId); + channelRuntimeEnvs[channelId] ??= runtime; + } } return createChannelManager({ getRuntimeConfig: () => options?.getRuntimeConfig?.() ?? {}, @@ -576,6 +579,21 @@ describe("server-channels auto restart", () => { expect(succeedingStart).toHaveBeenCalledTimes(1); }); + it("uses fallback logger and runtime when a channel is missing startup wiring", async () => { + const startAccount = vi.fn(async () => { + throw new Error("invalid_auth"); + }); + installTestRegistry(createTestPlugin({ id: "slack", startAccount })); + const manager = createManager({ channelIds: ["slack"], fillChannelDependencies: false }); + + await manager.startChannels(); + await vi.advanceTimersByTimeAsync(0); + + expect(startAccount).toHaveBeenCalledTimes(1); + const account = manager.getRuntimeSnapshot().channelAccounts.slack?.[DEFAULT_ACCOUNT_ID]; + expect(account?.lastError).toBe("invalid_auth"); + }); + it("emits startup trace spans for channel preflight and handoff", async () => { const measureMock = vi.fn(async (name: string, run: () => unknown) => await run()); const startupTrace = { diff --git a/src/gateway/server-channels.ts b/src/gateway/server-channels.ts index 2c550789f26..fa7764b17e4 100644 --- a/src/gateway/server-channels.ts +++ b/src/gateway/server-channels.ts @@ -13,7 +13,11 @@ import { type BackoffPolicy, computeBackoff, sleepWithAbort } from "../infra/bac import { createTaskScopedChannelRuntime } from "../infra/channel-runtime-context.js"; import { formatErrorMessage } from "../infra/errors.js"; import { resetDirectoryCache } from "../infra/outbound/target-resolver.js"; -import { createSubsystemLogger, runtimeForLogger } from "../logging/subsystem.js"; +import { + createSubsystemLogger, + runtimeForLogger, + type SubsystemLogger, +} from "../logging/subsystem.js"; import { resolveAccountEntry, resolveNormalizedAccountEntry } from "../routing/account-lookup.js"; import { DEFAULT_ACCOUNT_ID, @@ -33,8 +37,6 @@ const CHANNEL_RESTART_POLICY: BackoffPolicy = { const MAX_RESTART_ATTEMPTS = 10; const CHANNEL_STOP_ABORT_TIMEOUT_MS = 5_000; -type SubsystemLogger = ReturnType; - type ChannelRuntimeStore = { aborts: Map; starting: Map>; @@ -128,8 +130,8 @@ function applyDescribedAccountFields( type ChannelManagerOptions = { getRuntimeConfig: () => OpenClawConfig; - channelLogs: Record; - channelRuntimeEnvs: Record; + channelLogs: Partial>; + channelRuntimeEnvs: Partial>; /** * Optional channel runtime helpers for external channel plugins. * @@ -706,7 +708,7 @@ export function createChannelManager(opts: ChannelManagerOptions): ChannelManage try { await measureStartup(`channels.${plugin.id}.start`, () => startChannel(plugin.id)); } catch (err) { - channelLogs[plugin.id]?.error?.( + ensureChannelLog(plugin.id).error?.( `[${plugin.id}] channel startup failed: ${formatErrorMessage(err)}`, ); } diff --git a/test/scripts/openclaw-cross-os-release-checks.test.ts b/test/scripts/openclaw-cross-os-release-checks.test.ts index 632971b39d9..5af1be2de6e 100644 --- a/test/scripts/openclaw-cross-os-release-checks.test.ts +++ b/test/scripts/openclaw-cross-os-release-checks.test.ts @@ -160,11 +160,14 @@ describe("scripts/openclaw-cross-os-release-checks", () => { expect(allowlist).not.toContain("web-readability"); }); - it("keeps cross-OS live smoke agent turns on minimal thinking", () => { + it("keeps cross-OS live smoke agent turns on GPT-5.5-safe timeouts and minimal thinking", () => { const source = readFileSync("scripts/openclaw-cross-os-release-checks.ts", "utf8"); expect(source).toContain('"--thinking",\n "minimal"'); - expect(CROSS_OS_AGENT_TURN_TIMEOUT_SECONDS).toBeLessThanOrEqual(360); + expect(CROSS_OS_AGENT_TURN_TIMEOUT_SECONDS).toBeGreaterThanOrEqual(600); + expect(source).toContain( + "models.providers.${params.providerConfig.extensionId}.timeoutSeconds", + ); expect(source).toContain('"--timeout",\n String(CROSS_OS_AGENT_TURN_TIMEOUT_SECONDS)'); expect(source.match(/buildReleaseAgentTurnArgs\(sessionId\)/g)?.length).toBeGreaterThanOrEqual( 2,