mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 18:10:45 +00:00
fix: stabilize GPT-5.5 release gates
This commit is contained in:
@@ -40,6 +40,7 @@ const providerConfig = {
|
|||||||
secretEnv: "OPENAI_API_KEY",
|
secretEnv: "OPENAI_API_KEY",
|
||||||
authChoice: "openai-api-key",
|
authChoice: "openai-api-key",
|
||||||
model: "openai/gpt-5.5",
|
model: "openai/gpt-5.5",
|
||||||
|
timeoutSeconds: 600,
|
||||||
},
|
},
|
||||||
anthropic: {
|
anthropic: {
|
||||||
extensionId: "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;
|
CROSS_OS_GATEWAY_STATUS_RPC_TIMEOUT_MS + 45_000;
|
||||||
export const CROSS_OS_GATEWAY_READY_TIMEOUT_MS = 3 * 60_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_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()) {
|
if (isMainModule()) {
|
||||||
try {
|
try {
|
||||||
@@ -1840,6 +1841,22 @@ async function runInstalledModelsSet(params) {
|
|||||||
logPath: params.logPath,
|
logPath: params.logPath,
|
||||||
timeoutMs: 2 * 60 * 1000,
|
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({
|
await runInstalledCli({
|
||||||
cliPath: params.cliPath,
|
cliPath: params.cliPath,
|
||||||
args: [
|
args: [
|
||||||
@@ -1875,7 +1892,7 @@ async function runInstalledAgentTurn(params) {
|
|||||||
cwd: params.cwd,
|
cwd: params.cwd,
|
||||||
env: params.env,
|
env: params.env,
|
||||||
logPath: params.logPath,
|
logPath: params.logPath,
|
||||||
timeoutMs: 10 * 60 * 1000,
|
timeoutMs: (CROSS_OS_AGENT_TURN_TIMEOUT_SECONDS + 60) * 1000,
|
||||||
});
|
});
|
||||||
if (!agentOutputHasExpectedOkMarker(result.stdout, { logPath: params.logPath })) {
|
if (!agentOutputHasExpectedOkMarker(result.stdout, { logPath: params.logPath })) {
|
||||||
throw new Error("Agent output did not contain the expected OK marker.");
|
throw new Error("Agent output did not contain the expected OK marker.");
|
||||||
@@ -2616,6 +2633,21 @@ async function runModelsSet(params) {
|
|||||||
logPath: params.logPath,
|
logPath: params.logPath,
|
||||||
timeoutMs: 2 * 60 * 1000,
|
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({
|
await runOpenClaw({
|
||||||
lane: params.lane,
|
lane: params.lane,
|
||||||
env: params.env,
|
env: params.env,
|
||||||
@@ -2648,7 +2680,7 @@ async function runAgentTurn(params) {
|
|||||||
env: params.env,
|
env: params.env,
|
||||||
args: buildReleaseAgentTurnArgs(sessionId),
|
args: buildReleaseAgentTurnArgs(sessionId),
|
||||||
logPath: params.logPath,
|
logPath: params.logPath,
|
||||||
timeoutMs: 10 * 60 * 1000,
|
timeoutMs: (CROSS_OS_AGENT_TURN_TIMEOUT_SECONDS + 60) * 1000,
|
||||||
});
|
});
|
||||||
if (!agentOutputHasExpectedOkMarker(result.stdout, { logPath: params.logPath })) {
|
if (!agentOutputHasExpectedOkMarker(result.stdout, { logPath: params.logPath })) {
|
||||||
throw new Error("Agent output did not contain the expected OK marker.");
|
throw new Error("Agent output did not contain the expected OK marker.");
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ const DEFAULT_MODEL =
|
|||||||
// The cron/MCP live probe now tolerates more cancelled tool-call retries in CI,
|
// 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.
|
// so the outer test budget needs enough headroom to finish those retries.
|
||||||
const CLI_BACKEND_LIVE_TIMEOUT_MS = 20 * 60_000;
|
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(
|
const CLI_BACKEND_AGENT_TIMEOUT_SECONDS = Math.max(
|
||||||
1,
|
1,
|
||||||
Math.ceil(CLI_BACKEND_REQUEST_TIMEOUT_MS / 1000) - 10,
|
Math.ceil(CLI_BACKEND_REQUEST_TIMEOUT_MS / 1000) - 10,
|
||||||
|
|||||||
@@ -129,15 +129,18 @@ function createManager(options?: {
|
|||||||
getRuntimeConfig?: () => Record<string, unknown>;
|
getRuntimeConfig?: () => Record<string, unknown>;
|
||||||
channelIds?: ChannelId[];
|
channelIds?: ChannelId[];
|
||||||
startupTrace?: { measure: <T>(name: string, run: () => T | Promise<T>) => Promise<T> };
|
startupTrace?: { measure: <T>(name: string, run: () => T | Promise<T>) => Promise<T> };
|
||||||
|
fillChannelDependencies?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const log = createSubsystemLogger("gateway/server-channels-test");
|
const log = createSubsystemLogger("gateway/server-channels-test");
|
||||||
const channelLogs = { discord: log } as Record<ChannelId, SubsystemLogger>;
|
const channelLogs = { discord: log } as Record<ChannelId, SubsystemLogger>;
|
||||||
const runtime = runtimeForLogger(log);
|
const runtime = runtimeForLogger(log);
|
||||||
const channelRuntimeEnvs = { discord: runtime } as unknown as Record<ChannelId, RuntimeEnv>;
|
const channelRuntimeEnvs = { discord: runtime } as unknown as Record<ChannelId, RuntimeEnv>;
|
||||||
const channelIds = options?.channelIds ?? ["discord"];
|
const channelIds = options?.channelIds ?? ["discord"];
|
||||||
for (const channelId of channelIds) {
|
if (options?.fillChannelDependencies !== false) {
|
||||||
channelLogs[channelId] ??= log.child(channelId);
|
for (const channelId of channelIds) {
|
||||||
channelRuntimeEnvs[channelId] ??= runtime;
|
channelLogs[channelId] ??= log.child(channelId);
|
||||||
|
channelRuntimeEnvs[channelId] ??= runtime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return createChannelManager({
|
return createChannelManager({
|
||||||
getRuntimeConfig: () => options?.getRuntimeConfig?.() ?? {},
|
getRuntimeConfig: () => options?.getRuntimeConfig?.() ?? {},
|
||||||
@@ -576,6 +579,21 @@ describe("server-channels auto restart", () => {
|
|||||||
expect(succeedingStart).toHaveBeenCalledTimes(1);
|
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 () => {
|
it("emits startup trace spans for channel preflight and handoff", async () => {
|
||||||
const measureMock = vi.fn(async (name: string, run: () => unknown) => await run());
|
const measureMock = vi.fn(async (name: string, run: () => unknown) => await run());
|
||||||
const startupTrace = {
|
const startupTrace = {
|
||||||
|
|||||||
@@ -13,7 +13,11 @@ import { type BackoffPolicy, computeBackoff, sleepWithAbort } from "../infra/bac
|
|||||||
import { createTaskScopedChannelRuntime } from "../infra/channel-runtime-context.js";
|
import { createTaskScopedChannelRuntime } from "../infra/channel-runtime-context.js";
|
||||||
import { formatErrorMessage } from "../infra/errors.js";
|
import { formatErrorMessage } from "../infra/errors.js";
|
||||||
import { resetDirectoryCache } from "../infra/outbound/target-resolver.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 { resolveAccountEntry, resolveNormalizedAccountEntry } from "../routing/account-lookup.js";
|
||||||
import {
|
import {
|
||||||
DEFAULT_ACCOUNT_ID,
|
DEFAULT_ACCOUNT_ID,
|
||||||
@@ -33,8 +37,6 @@ const CHANNEL_RESTART_POLICY: BackoffPolicy = {
|
|||||||
const MAX_RESTART_ATTEMPTS = 10;
|
const MAX_RESTART_ATTEMPTS = 10;
|
||||||
const CHANNEL_STOP_ABORT_TIMEOUT_MS = 5_000;
|
const CHANNEL_STOP_ABORT_TIMEOUT_MS = 5_000;
|
||||||
|
|
||||||
type SubsystemLogger = ReturnType<typeof createSubsystemLogger>;
|
|
||||||
|
|
||||||
type ChannelRuntimeStore = {
|
type ChannelRuntimeStore = {
|
||||||
aborts: Map<string, AbortController>;
|
aborts: Map<string, AbortController>;
|
||||||
starting: Map<string, Promise<void>>;
|
starting: Map<string, Promise<void>>;
|
||||||
@@ -128,8 +130,8 @@ function applyDescribedAccountFields(
|
|||||||
|
|
||||||
type ChannelManagerOptions = {
|
type ChannelManagerOptions = {
|
||||||
getRuntimeConfig: () => OpenClawConfig;
|
getRuntimeConfig: () => OpenClawConfig;
|
||||||
channelLogs: Record<ChannelId, SubsystemLogger>;
|
channelLogs: Partial<Record<ChannelId, SubsystemLogger>>;
|
||||||
channelRuntimeEnvs: Record<ChannelId, RuntimeEnv>;
|
channelRuntimeEnvs: Partial<Record<ChannelId, RuntimeEnv>>;
|
||||||
/**
|
/**
|
||||||
* Optional channel runtime helpers for external channel plugins.
|
* Optional channel runtime helpers for external channel plugins.
|
||||||
*
|
*
|
||||||
@@ -706,7 +708,7 @@ export function createChannelManager(opts: ChannelManagerOptions): ChannelManage
|
|||||||
try {
|
try {
|
||||||
await measureStartup(`channels.${plugin.id}.start`, () => startChannel(plugin.id));
|
await measureStartup(`channels.${plugin.id}.start`, () => startChannel(plugin.id));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
channelLogs[plugin.id]?.error?.(
|
ensureChannelLog(plugin.id).error?.(
|
||||||
`[${plugin.id}] channel startup failed: ${formatErrorMessage(err)}`,
|
`[${plugin.id}] channel startup failed: ${formatErrorMessage(err)}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,11 +160,14 @@ describe("scripts/openclaw-cross-os-release-checks", () => {
|
|||||||
expect(allowlist).not.toContain("web-readability");
|
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");
|
const source = readFileSync("scripts/openclaw-cross-os-release-checks.ts", "utf8");
|
||||||
|
|
||||||
expect(source).toContain('"--thinking",\n "minimal"');
|
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).toContain('"--timeout",\n String(CROSS_OS_AGENT_TURN_TIMEOUT_SECONDS)');
|
||||||
expect(source.match(/buildReleaseAgentTurnArgs\(sessionId\)/g)?.length).toBeGreaterThanOrEqual(
|
expect(source.match(/buildReleaseAgentTurnArgs\(sessionId\)/g)?.length).toBeGreaterThanOrEqual(
|
||||||
2,
|
2,
|
||||||
|
|||||||
Reference in New Issue
Block a user