Compare commits

..

1 Commits

Author SHA1 Message Date
zhi
de04e21aa1 fix: wait for gateway ready before post-install model validation
Root cause: gateway restart is async (systemd), but validateNoReplyModelAvailable()
ran immediately after, hitting a race condition where the new gateway process
hadn't finished initializing yet. This caused 'model not listed' validation
failures, triggering config rollback even though the config was correct.

Changes:
- Add waitForGatewayReady() that polls 'openclaw gateway status' for RPC probe
- Add retry loop (5 attempts, 2s interval) to validateNoReplyModelAvailable()
- Fix CONFIG.example.json: contextWindow 4096->200000, maxTokens 64->8192
  (OpenClaw requires minimum 16000 contextWindow)
2026-02-26 08:45:37 +00:00

View File

@@ -45,6 +45,42 @@ function runOpenclaw(args, { allowFail = false } = {}) {
} }
} }
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function waitForGatewayReady(maxWaitMs = 30000) {
const start = Date.now();
const interval = 1500;
while (Date.now() - start < maxWaitMs) {
const probe = runOpenclaw(["gateway", "status"], { allowFail: true }) || "";
if (probe.includes("RPC probe: ok")) return true;
console.log(`[whispergate] waiting for gateway ready... (${Math.round((Date.now() - start) / 1000)}s)`);
await sleep(interval);
}
return false;
}
async function validateNoReplyModelAvailable(retries = 5, delayMs = 2000) {
const modelRef = `${NO_REPLY_PROVIDER_ID}/${NO_REPLY_MODEL_ID}`;
for (let attempt = 1; attempt <= retries; attempt++) {
const list = runOpenclaw(["models", "list"], { allowFail: true }) || "";
if (list.includes(modelRef)) {
const status = runOpenclaw(["models", "status", "--json"], { allowFail: true }) || "";
if (status.includes(NO_REPLY_PROVIDER_ID)) {
console.log(`[whispergate] model validation passed on attempt ${attempt}`);
return;
}
}
if (attempt < retries) {
console.log(`[whispergate] model not yet visible (attempt ${attempt}/${retries}), retrying in ${delayMs}ms...`);
await sleep(delayMs);
}
}
throw new Error(`post-install validation failed: model not listed after ${retries} attempts: ${modelRef}`);
}
function getJson(pathKey) { function getJson(pathKey) {
const out = runOpenclaw(["config", "get", pathKey, "--json"], { allowFail: true }); const out = runOpenclaw(["config", "get", pathKey, "--json"], { allowFail: true });
@@ -162,15 +198,23 @@ if (mode === "install") {
}; };
setJson(PATH_PROVIDERS, providers); setJson(PATH_PROVIDERS, providers);
runOpenclaw(["gateway", "restart"]);
console.log("[whispergate] gateway restart issued, waiting for ready...");
const ready = await waitForGatewayReady();
if (!ready) {
throw new Error("gateway did not become ready within 30s after restart");
}
console.log("[whispergate] gateway ready, validating model...");
await validateNoReplyModelAvailable();
const after = { const after = {
[PATH_PLUGINS_LOAD]: getJson(PATH_PLUGINS_LOAD), [PATH_PLUGINS_LOAD]: getJson(PATH_PLUGINS_LOAD),
[PATH_PLUGIN_ENTRY]: getJson(PATH_PLUGIN_ENTRY), [PATH_PLUGIN_ENTRY]: getJson(PATH_PLUGIN_ENTRY),
[PATH_PROVIDERS]: getJson(PATH_PROVIDERS), [PATH_PROVIDERS]: getJson(PATH_PROVIDERS),
}; };
writeRecord("install", before, after); writeRecord("install", before, after);
console.log("[whispergate] install ok (config written)"); console.log("[whispergate] install ok");
console.log(`[whispergate] record: ${RECORD_PATH}`); console.log(`[whispergate] record: ${RECORD_PATH}`);
console.log("[whispergate] >>> restart gateway to apply: openclaw gateway restart");
} catch (e) { } catch (e) {
fs.copyFileSync(BACKUP_PATH, OPENCLAW_CONFIG_PATH); fs.copyFileSync(BACKUP_PATH, OPENCLAW_CONFIG_PATH);
console.error(`[whispergate] install failed; rollback complete: ${String(e)}`); console.error(`[whispergate] install failed; rollback complete: ${String(e)}`);