mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 09:40:43 +00:00
fix(ui): stop unsupported wiki RPC probes during startup (#67905)
* UI: gate wiki method probes by advertised methods * test(ui): cover legacy wiki method fallback
This commit is contained in:
@@ -22,6 +22,7 @@ function createState(): { state: DreamingState; request: ReturnType<typeof vi.fn
|
||||
request,
|
||||
} as unknown as DreamingState["client"],
|
||||
connected: true,
|
||||
hello: null,
|
||||
configSnapshot: { hash: "hash-1" },
|
||||
applySessionKey: "main",
|
||||
dreamingStatusLoading: false,
|
||||
@@ -227,6 +228,11 @@ describe("dreaming controller", () => {
|
||||
|
||||
it("loads and normalizes wiki import insights", async () => {
|
||||
const { state, request } = createState();
|
||||
state.hello = {
|
||||
type: "hello-ok",
|
||||
protocol: 3,
|
||||
features: { methods: ["wiki.importInsights"] },
|
||||
};
|
||||
state.configSnapshot = {
|
||||
hash: "hash-1",
|
||||
config: {
|
||||
@@ -297,6 +303,40 @@ describe("dreaming controller", () => {
|
||||
expect(state.wikiImportInsightsLoading).toBe(false);
|
||||
});
|
||||
|
||||
it("falls back to config gating for wiki import insights when methods are not advertised", async () => {
|
||||
const { state, request } = createState();
|
||||
state.configSnapshot = {
|
||||
hash: "hash-1",
|
||||
config: {
|
||||
plugins: {
|
||||
entries: {
|
||||
"memory-wiki": {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
request.mockResolvedValue({
|
||||
sourceType: "chatgpt",
|
||||
totalItems: 1,
|
||||
totalClusters: 1,
|
||||
clusters: [],
|
||||
});
|
||||
|
||||
await loadWikiImportInsights(state);
|
||||
|
||||
expect(request).toHaveBeenCalledWith("wiki.importInsights", {});
|
||||
expect(state.wikiImportInsights).toEqual(
|
||||
expect.objectContaining({
|
||||
totalItems: 1,
|
||||
totalClusters: 1,
|
||||
}),
|
||||
);
|
||||
expect(state.wikiImportInsightsError).toBeNull();
|
||||
expect(state.wikiImportInsightsLoading).toBe(false);
|
||||
});
|
||||
|
||||
it("skips wiki import insights when memory-wiki is not enabled", async () => {
|
||||
const { state, request } = createState();
|
||||
state.configSnapshot = {
|
||||
@@ -321,8 +361,48 @@ describe("dreaming controller", () => {
|
||||
expect(state.wikiImportInsightsLoading).toBe(false);
|
||||
});
|
||||
|
||||
it("skips wiki import insights when the gateway does not advertise the method", async () => {
|
||||
const { state, request } = createState();
|
||||
state.hello = {
|
||||
type: "hello-ok",
|
||||
protocol: 3,
|
||||
features: { methods: ["doctor.memory.status"] },
|
||||
};
|
||||
state.configSnapshot = {
|
||||
hash: "hash-1",
|
||||
config: {
|
||||
plugins: {
|
||||
entries: {
|
||||
"memory-wiki": {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
state.wikiImportInsights = {
|
||||
sourceType: "chatgpt",
|
||||
totalItems: 1,
|
||||
totalClusters: 1,
|
||||
clusters: [],
|
||||
};
|
||||
state.wikiImportInsightsError = "unknown method: wiki.importInsights";
|
||||
|
||||
await loadWikiImportInsights(state);
|
||||
|
||||
expect(request).not.toHaveBeenCalled();
|
||||
expect(state.wikiImportInsights).toBeNull();
|
||||
expect(state.wikiImportInsightsError).toBeNull();
|
||||
expect(state.wikiImportInsightsLoading).toBe(false);
|
||||
});
|
||||
|
||||
it("loads and normalizes the wiki memory palace", async () => {
|
||||
const { state, request } = createState();
|
||||
state.hello = {
|
||||
type: "hello-ok",
|
||||
protocol: 3,
|
||||
features: { methods: ["wiki.palace"] },
|
||||
};
|
||||
state.configSnapshot = {
|
||||
hash: "hash-1",
|
||||
config: {
|
||||
@@ -391,6 +471,41 @@ describe("dreaming controller", () => {
|
||||
expect(state.wikiMemoryPalaceLoading).toBe(false);
|
||||
});
|
||||
|
||||
it("falls back to config gating for wiki memory palace when methods are not advertised", async () => {
|
||||
const { state, request } = createState();
|
||||
state.configSnapshot = {
|
||||
hash: "hash-1",
|
||||
config: {
|
||||
plugins: {
|
||||
entries: {
|
||||
"memory-wiki": {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
request.mockResolvedValue({
|
||||
totalItems: 1,
|
||||
totalClaims: 2,
|
||||
totalQuestions: 0,
|
||||
totalContradictions: 0,
|
||||
clusters: [],
|
||||
});
|
||||
|
||||
await loadWikiMemoryPalace(state);
|
||||
|
||||
expect(request).toHaveBeenCalledWith("wiki.palace", {});
|
||||
expect(state.wikiMemoryPalace).toEqual(
|
||||
expect.objectContaining({
|
||||
totalItems: 1,
|
||||
totalClaims: 2,
|
||||
}),
|
||||
);
|
||||
expect(state.wikiMemoryPalaceError).toBeNull();
|
||||
expect(state.wikiMemoryPalaceLoading).toBe(false);
|
||||
});
|
||||
|
||||
it("skips wiki memory palace when memory-wiki is not enabled", async () => {
|
||||
const { state, request } = createState();
|
||||
state.configSnapshot = {
|
||||
@@ -416,6 +531,42 @@ describe("dreaming controller", () => {
|
||||
expect(state.wikiMemoryPalaceLoading).toBe(false);
|
||||
});
|
||||
|
||||
it("skips wiki memory palace when the gateway does not advertise the method", async () => {
|
||||
const { state, request } = createState();
|
||||
state.hello = {
|
||||
type: "hello-ok",
|
||||
protocol: 3,
|
||||
features: { methods: ["doctor.memory.status"] },
|
||||
};
|
||||
state.configSnapshot = {
|
||||
hash: "hash-1",
|
||||
config: {
|
||||
plugins: {
|
||||
entries: {
|
||||
"memory-wiki": {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
state.wikiMemoryPalace = {
|
||||
totalItems: 1,
|
||||
totalClaims: 1,
|
||||
totalQuestions: 0,
|
||||
totalContradictions: 0,
|
||||
clusters: [],
|
||||
};
|
||||
state.wikiMemoryPalaceError = "unknown method: wiki.palace";
|
||||
|
||||
await loadWikiMemoryPalace(state);
|
||||
|
||||
expect(request).not.toHaveBeenCalled();
|
||||
expect(state.wikiMemoryPalace).toBeNull();
|
||||
expect(state.wikiMemoryPalaceError).toBeNull();
|
||||
expect(state.wikiMemoryPalaceLoading).toBe(false);
|
||||
});
|
||||
|
||||
it("patches config to update global dreaming enablement", async () => {
|
||||
const { state, request } = createState();
|
||||
state.configSnapshot = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { GatewayBrowserClient } from "../gateway.ts";
|
||||
import type { GatewayBrowserClient, GatewayHelloOk } from "../gateway.ts";
|
||||
import { isPluginEnabledInConfigSnapshot } from "../plugin-activation.ts";
|
||||
import type { ConfigSnapshot } from "../types.ts";
|
||||
|
||||
@@ -201,6 +201,7 @@ type WikiMemoryPalacePayload = {
|
||||
export type DreamingState = {
|
||||
client: GatewayBrowserClient | null;
|
||||
connected: boolean;
|
||||
hello: GatewayHelloOk | null;
|
||||
configSnapshot: ConfigSnapshot | null;
|
||||
applySessionKey: string;
|
||||
dreamingStatusLoading: boolean;
|
||||
@@ -236,6 +237,22 @@ function isMemoryWikiEnabled(state: DreamingState): boolean {
|
||||
});
|
||||
}
|
||||
|
||||
function hasGatewayMethod(state: DreamingState, method: string): boolean | null {
|
||||
const methods = state.hello?.features?.methods;
|
||||
if (!Array.isArray(methods)) {
|
||||
return null;
|
||||
}
|
||||
return methods.includes(method);
|
||||
}
|
||||
|
||||
function canCallMemoryWikiMethod(state: DreamingState, method: string): boolean {
|
||||
const available = hasGatewayMethod(state, method);
|
||||
if (available !== null) {
|
||||
return available;
|
||||
}
|
||||
return isMemoryWikiEnabled(state);
|
||||
}
|
||||
|
||||
function buildDreamDiaryActionSuccessMessage(
|
||||
method:
|
||||
| "doctor.memory.backfillDreamDiary"
|
||||
@@ -748,7 +765,7 @@ export async function loadWikiImportInsights(state: DreamingState): Promise<void
|
||||
if (!state.client || !state.connected || state.wikiImportInsightsLoading) {
|
||||
return;
|
||||
}
|
||||
if (!isMemoryWikiEnabled(state)) {
|
||||
if (!canCallMemoryWikiMethod(state, "wiki.importInsights")) {
|
||||
state.wikiImportInsights = null;
|
||||
state.wikiImportInsightsError = null;
|
||||
return;
|
||||
@@ -772,7 +789,7 @@ export async function loadWikiMemoryPalace(state: DreamingState): Promise<void>
|
||||
if (!state.client || !state.connected || state.wikiMemoryPalaceLoading) {
|
||||
return;
|
||||
}
|
||||
if (!isMemoryWikiEnabled(state)) {
|
||||
if (!canCallMemoryWikiMethod(state, "wiki.palace")) {
|
||||
state.wikiMemoryPalace = null;
|
||||
state.wikiMemoryPalaceError = null;
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user