mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:20:43 +00:00
fix(gateway): log canvas host mount after bind
This commit is contained in:
@@ -65,6 +65,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Control UI/Talk: retry from a failed realtime Talk session on the next Talk click instead of requiring a separate stale-session stop click first. Thanks @vincentkoc.
|
||||
- Google Chat: create an isolated Google auth transport per auth client, so google-auth-library interceptor mutations do not accumulate across webhook verification and access-token clients. Thanks @vincentkoc.
|
||||
- Control UI/performance: cap long-task and long-animation-frame diagnostics in the shared event log, so slow-render telemetry does not evict gateway/plugin events from the Debug and Overview views. Thanks @vincentkoc.
|
||||
- Gateway/startup: log the canvas host mount only after the HTTP server has bound, so startup logs no longer report the canvas host as mounted before it can serve requests.
|
||||
- Web fetch: late-bind `web_fetch` config and provider fallback metadata from the active runtime snapshot, matching `web_search` so long-lived tools do not use stale fetch provider settings. Thanks @vincentkoc.
|
||||
- Discord: clear stale startup probe bot/application status when the async bot probe throws, not just when it returns a degraded probe result. Thanks @vincentkoc.
|
||||
- Web search: scope explicit bundled `web_search` provider runtime loading through manifest ownership, so selecting DuckDuckGo/Gemini/etc. does not import unrelated bundled providers or log their optional dependency failures. Thanks @vincentkoc.
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { mkdtemp, rm } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { createEmptyPluginRegistry } from "../plugins/registry.js";
|
||||
import {
|
||||
getActivePluginChannelRegistry,
|
||||
@@ -26,10 +29,13 @@ function createRegistryWithRoute(path: string) {
|
||||
}
|
||||
|
||||
describe("createGatewayRuntimeState", () => {
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
afterEach(() => {
|
||||
releasePinnedPluginHttpRouteRegistry();
|
||||
releasePinnedPluginChannelRegistry();
|
||||
resetPluginRuntimeStateForTest();
|
||||
return Promise.all(tempDirs.splice(0).map((dir) => rm(dir, { recursive: true, force: true })));
|
||||
});
|
||||
|
||||
it("releases post-bootstrap repinned plugin registries on cleanup", async () => {
|
||||
@@ -70,4 +76,38 @@ describe("createGatewayRuntimeState", () => {
|
||||
expect(resolveActivePluginHttpRouteRegistry(fallbackRegistry)).toBe(startupRegistry);
|
||||
expect(getActivePluginChannelRegistry()).toBe(startupRegistry);
|
||||
});
|
||||
|
||||
it("creates the canvas host without logging it before HTTP bind", async () => {
|
||||
const root = await mkdtemp(path.join(os.tmpdir(), "openclaw-canvas-runtime-"));
|
||||
tempDirs.push(root);
|
||||
const registry = createEmptyPluginRegistry();
|
||||
const logCanvas = { info: vi.fn(), warn: vi.fn() };
|
||||
|
||||
const runtimeState = await createGatewayRuntimeState({
|
||||
cfg: { canvasHost: { root, liveReload: false } },
|
||||
bindHost: "127.0.0.1",
|
||||
port: 18789,
|
||||
controlUiEnabled: false,
|
||||
controlUiBasePath: "/",
|
||||
openAiChatCompletionsEnabled: false,
|
||||
openResponsesEnabled: false,
|
||||
resolvedAuth: {} as never,
|
||||
getResolvedAuth: () => ({}) as never,
|
||||
hooksConfig: () => null,
|
||||
getHookClientIpConfig: () => ({}) as never,
|
||||
pluginRegistry: registry,
|
||||
deps: {} as never,
|
||||
canvasRuntime: { log: () => {} } as never,
|
||||
canvasHostEnabled: true,
|
||||
allowCanvasHostInTests: true,
|
||||
logCanvas,
|
||||
log: { info: () => {}, warn: () => {} },
|
||||
logHooks: { info: () => {}, warn: () => {}, error: () => {}, debug: () => {} } as never,
|
||||
logPlugins: { info: () => {}, warn: () => {}, error: () => {}, debug: () => {} } as never,
|
||||
});
|
||||
|
||||
expect(runtimeState.canvasHost?.rootDir).toBe(root);
|
||||
expect(logCanvas.info).not.toHaveBeenCalled();
|
||||
await runtimeState.canvasHost?.close();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -130,9 +130,6 @@ export async function createGatewayRuntimeState(params: {
|
||||
});
|
||||
if (handler.rootDir) {
|
||||
canvasHost = handler;
|
||||
params.logCanvas.info(
|
||||
`canvas host mounted at http://${params.bindHost}:${params.port}${CANVAS_HOST_PATH}/ (root ${handler.rootDir})`,
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
params.logCanvas.warn(`canvas host failed to start: ${String(err)}`);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { monitorEventLoopDelay, performance } from "node:perf_hooks";
|
||||
import { getActiveEmbeddedRunCount } from "../agents/pi-embedded-runner/run-state.js";
|
||||
import { getTotalPendingReplies } from "../auto-reply/reply/dispatcher-registry.js";
|
||||
import { CANVAS_HOST_PATH } from "../canvas-host/a2ui-shared.js";
|
||||
import type { CanvasHostServer } from "../canvas-host/server.js";
|
||||
import type { ChannelRuntimeSurface } from "../channels/plugins/channel-runtime-surface.types.js";
|
||||
import {
|
||||
@@ -1354,6 +1355,11 @@ export async function startGatewayServer(
|
||||
context: gatewayRequestContext,
|
||||
});
|
||||
await startListening();
|
||||
if (canvasHost?.rootDir) {
|
||||
logCanvas.info(
|
||||
`canvas host mounted at http://${bindHost}:${port}${CANVAS_HOST_PATH}/ (root ${canvasHost.rootDir})`,
|
||||
);
|
||||
}
|
||||
startupTrace.mark("http.bound");
|
||||
const sessionDeliveryRecoveryMaxEnqueuedAt = Date.now();
|
||||
let postAttachRuntimeReturned = false;
|
||||
|
||||
Reference in New Issue
Block a user