mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 01:31:08 +00:00
chore(ui): guard dreaming toggle for strict plugin schemas
This commit is contained in:
@@ -193,6 +193,48 @@ describe("dreaming controller", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("blocks dreaming patch when selected plugin config rejects unknown keys", async () => {
|
||||
const { state, request } = createState();
|
||||
state.configSnapshot = {
|
||||
hash: "hash-1",
|
||||
config: {
|
||||
plugins: {
|
||||
slots: {
|
||||
memory: "memory-lancedb",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
request.mockImplementation(async (method: string) => {
|
||||
if (method === "config.schema.lookup") {
|
||||
return {
|
||||
path: "plugins.entries.memory-lancedb.config",
|
||||
schema: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
},
|
||||
children: [
|
||||
{ key: "retentionDays", path: "plugins.entries.memory-lancedb.config.retentionDays" },
|
||||
],
|
||||
};
|
||||
}
|
||||
if (method === "config.patch") {
|
||||
return { ok: true };
|
||||
}
|
||||
return {};
|
||||
});
|
||||
|
||||
const ok = await updateDreamingEnabled(state, true);
|
||||
|
||||
expect(ok).toBe(false);
|
||||
expect(request).toHaveBeenCalledWith("config.schema.lookup", {
|
||||
path: "plugins.entries.memory-lancedb.config",
|
||||
});
|
||||
expect(request).not.toHaveBeenCalledWith("config.patch", expect.anything());
|
||||
expect(state.dreamingStatusError).toContain("memory-lancedb");
|
||||
expect(state.dreamingStatusError).toContain("does not support dreaming settings");
|
||||
});
|
||||
|
||||
it("reads dreaming enabled state from the selected memory slot plugin", () => {
|
||||
expect(
|
||||
resolveConfiguredDreaming({
|
||||
|
||||
@@ -309,11 +309,65 @@ async function writeDreamingPatch(
|
||||
}
|
||||
}
|
||||
|
||||
function lookupIncludesDreamingProperty(value: unknown): boolean {
|
||||
const lookup = asRecord(value);
|
||||
const children = Array.isArray(lookup?.children) ? lookup.children : [];
|
||||
for (const child of children) {
|
||||
const childRecord = asRecord(child);
|
||||
if (normalizeTrimmedString(childRecord?.key) === "dreaming") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function lookupDisallowsUnknownProperties(value: unknown): boolean {
|
||||
const lookup = asRecord(value);
|
||||
const schema = asRecord(lookup?.schema);
|
||||
return schema?.additionalProperties === false;
|
||||
}
|
||||
|
||||
async function ensureDreamingPathSupported(
|
||||
state: DreamingState,
|
||||
pluginId: string,
|
||||
): Promise<boolean> {
|
||||
if (!state.client || !state.connected) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
const lookup = await state.client.request("config.schema.lookup", {
|
||||
path: `plugins.entries.${pluginId}.config`,
|
||||
});
|
||||
if (lookupIncludesDreamingProperty(lookup)) {
|
||||
return true;
|
||||
}
|
||||
if (lookupDisallowsUnknownProperties(lookup)) {
|
||||
const message = `Selected memory plugin "${pluginId}" does not support dreaming settings.`;
|
||||
state.dreamingStatusError = message;
|
||||
state.lastError = message;
|
||||
return false;
|
||||
}
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function updateDreamingEnabled(
|
||||
state: DreamingState,
|
||||
enabled: boolean,
|
||||
): Promise<boolean> {
|
||||
if (state.dreamingModeSaving) {
|
||||
return false;
|
||||
}
|
||||
if (!state.configSnapshot?.hash) {
|
||||
state.dreamingStatusError = "Config hash missing; refresh and retry.";
|
||||
return false;
|
||||
}
|
||||
const { pluginId } = resolveConfiguredDreaming(asRecord(state.configSnapshot?.config) ?? null);
|
||||
if (!(await ensureDreamingPathSupported(state, pluginId))) {
|
||||
return false;
|
||||
}
|
||||
const ok = await writeDreamingPatch(state, {
|
||||
plugins: {
|
||||
entries: {
|
||||
|
||||
Reference in New Issue
Block a user