revert(memory-wiki): back out llm wiki stack

This commit is contained in:
Vincent Koc
2026-04-05 22:43:13 +01:00
parent e29d370969
commit 94256ea1a0
82 changed files with 94 additions and 8846 deletions

View File

@@ -41,8 +41,6 @@ export type BuildPluginApiParams = {
| "registerCommand"
| "registerContextEngine"
| "registerMemoryPromptSection"
| "registerMemoryPromptSupplement"
| "registerMemoryCorpusSupplement"
| "registerMemoryFlushPlan"
| "registerMemoryRuntime"
| "registerMemoryEmbeddingProvider"
@@ -80,10 +78,6 @@ const noopOnConversationBindingResolved: OpenClawPluginApi["onConversationBindin
const noopRegisterCommand: OpenClawPluginApi["registerCommand"] = () => {};
const noopRegisterContextEngine: OpenClawPluginApi["registerContextEngine"] = () => {};
const noopRegisterMemoryPromptSection: OpenClawPluginApi["registerMemoryPromptSection"] = () => {};
const noopRegisterMemoryPromptSupplement: OpenClawPluginApi["registerMemoryPromptSupplement"] =
() => {};
const noopRegisterMemoryCorpusSupplement: OpenClawPluginApi["registerMemoryCorpusSupplement"] =
() => {};
const noopRegisterMemoryFlushPlan: OpenClawPluginApi["registerMemoryFlushPlan"] = () => {};
const noopRegisterMemoryRuntime: OpenClawPluginApi["registerMemoryRuntime"] = () => {};
const noopRegisterMemoryEmbeddingProvider: OpenClawPluginApi["registerMemoryEmbeddingProvider"] =
@@ -135,10 +129,6 @@ export function buildPluginApi(params: BuildPluginApiParams): OpenClawPluginApi
registerContextEngine: handlers.registerContextEngine ?? noopRegisterContextEngine,
registerMemoryPromptSection:
handlers.registerMemoryPromptSection ?? noopRegisterMemoryPromptSection,
registerMemoryPromptSupplement:
handlers.registerMemoryPromptSupplement ?? noopRegisterMemoryPromptSupplement,
registerMemoryCorpusSupplement:
handlers.registerMemoryCorpusSupplement ?? noopRegisterMemoryCorpusSupplement,
registerMemoryFlushPlan: handlers.registerMemoryFlushPlan ?? noopRegisterMemoryFlushPlan,
registerMemoryRuntime: handlers.registerMemoryRuntime ?? noopRegisterMemoryRuntime,
registerMemoryEmbeddingProvider:

View File

@@ -8,10 +8,7 @@ import {
import {
buildMemoryPromptSection,
getMemoryRuntime,
listMemoryCorpusSupplements,
registerMemoryCorpusSupplement,
registerMemoryFlushPlanResolver,
registerMemoryPromptSupplement,
registerMemoryPromptSection,
registerMemoryRuntime,
resolveMemoryFlushPlan,
@@ -158,12 +155,7 @@ describe("clearPluginLoaderCache", () => {
id: "stale",
create: async () => ({ provider: null }),
});
registerMemoryCorpusSupplement("memory-wiki", {
search: async () => [],
get: async () => null,
});
registerMemoryPromptSection(() => ["stale memory section"]);
registerMemoryPromptSupplement("memory-wiki", () => ["stale wiki supplement"]);
registerMemoryFlushPlanResolver(() => ({
softThresholdTokens: 1,
forceFlushTranscriptBytes: 2,
@@ -182,9 +174,7 @@ describe("clearPluginLoaderCache", () => {
});
expect(buildMemoryPromptSection({ availableTools: new Set() })).toEqual([
"stale memory section",
"stale wiki supplement",
]);
expect(listMemoryCorpusSupplements()).toHaveLength(1);
expect(resolveMemoryFlushPlan({})?.relativePath).toBe("memory/stale.md");
expect(getMemoryRuntime()).toBeDefined();
expect(getMemoryEmbeddingProvider("stale")).toBeDefined();
@@ -192,7 +182,6 @@ describe("clearPluginLoaderCache", () => {
clearPluginLoaderCache();
expect(buildMemoryPromptSection({ availableTools: new Set() })).toEqual([]);
expect(listMemoryCorpusSupplements()).toEqual([]);
expect(resolveMemoryFlushPlan({})).toBeNull();
expect(getMemoryRuntime()).toBeUndefined();
expect(getMemoryEmbeddingProvider("stale")).toBeUndefined();

View File

@@ -28,10 +28,7 @@ import {
import {
buildMemoryPromptSection,
getMemoryRuntime,
listMemoryCorpusSupplements,
registerMemoryCorpusSupplement,
registerMemoryFlushPlanResolver,
registerMemoryPromptSupplement,
registerMemoryPromptSection,
registerMemoryRuntime,
resolveMemoryFlushPlan,
@@ -1384,12 +1381,7 @@ module.exports = { id: "throws-after-import", register() {} };`,
id: "active",
create: async () => ({ provider: null }),
});
registerMemoryCorpusSupplement("memory-wiki", {
search: async () => [],
get: async () => null,
});
registerMemoryPromptSection(() => ["active memory section"]);
registerMemoryPromptSupplement("memory-wiki", () => ["active wiki supplement"]);
registerMemoryFlushPlanResolver(() => ({
softThresholdTokens: 1,
forceFlushTranscriptBytes: 2,
@@ -1456,9 +1448,7 @@ module.exports = { id: "throws-after-import", register() {} };`,
expect(scoped.plugins.find((entry) => entry.id === "snapshot-memory")?.status).toBe("loaded");
expect(buildMemoryPromptSection({ availableTools: new Set() })).toEqual([
"active memory section",
"active wiki supplement",
]);
expect(listMemoryCorpusSupplements()).toHaveLength(1);
expect(resolveMemoryFlushPlan({})?.relativePath).toBe("memory/active.md");
expect(getMemoryRuntime()).toBe(activeRuntime);
expect(listMemoryEmbeddingProviders().map((adapter) => adapter.id)).toEqual(["active"]);
@@ -1478,11 +1468,6 @@ module.exports = { id: "throws-after-import", register() {} };`,
create: async () => ({ provider: null }),
});
api.registerMemoryPromptSection(() => ["stale failure section"]);
api.registerMemoryPromptSupplement(() => ["stale failure supplement"]);
api.registerMemoryCorpusSupplement({
search: async () => [],
get: async () => null,
});
api.registerMemoryFlushPlan(() => ({
softThresholdTokens: 10,
forceFlushTranscriptBytes: 20,
@@ -1519,7 +1504,6 @@ module.exports = { id: "throws-after-import", register() {} };`,
expect(registry.plugins.find((entry) => entry.id === "failing-memory")?.status).toBe("error");
expect(buildMemoryPromptSection({ availableTools: new Set() })).toEqual([]);
expect(listMemoryCorpusSupplements()).toEqual([]);
expect(resolveMemoryFlushPlan({})).toBeNull();
expect(getMemoryRuntime()).toBeUndefined();
expect(listMemoryEmbeddingProviders()).toEqual([]);

View File

@@ -39,8 +39,6 @@ import {
getMemoryFlushPlanResolver,
getMemoryPromptSectionBuilder,
getMemoryRuntime,
listMemoryCorpusSupplements,
listMemoryPromptSupplements,
restoreMemoryPluginState,
} from "./memory-state.js";
import { isPathInside, safeStatSync } from "./path-safety.js";
@@ -131,11 +129,9 @@ export class PluginLoadFailureError extends Error {
type CachedPluginState = {
registry: PluginRegistry;
memoryCorpusSupplements: ReturnType<typeof listMemoryCorpusSupplements>;
memoryEmbeddingProviders: ReturnType<typeof listRegisteredMemoryEmbeddingProviders>;
memoryFlushPlanResolver: ReturnType<typeof getMemoryFlushPlanResolver>;
memoryPromptBuilder: ReturnType<typeof getMemoryPromptSectionBuilder>;
memoryPromptSupplements: ReturnType<typeof listMemoryPromptSupplements>;
memoryRuntime: ReturnType<typeof getMemoryRuntime>;
};
@@ -996,9 +992,7 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
if (cached) {
restoreRegisteredMemoryEmbeddingProviders(cached.memoryEmbeddingProviders);
restoreMemoryPluginState({
corpusSupplements: cached.memoryCorpusSupplements,
promptBuilder: cached.memoryPromptBuilder,
promptSupplements: cached.memoryPromptSupplements,
flushPlanResolver: cached.memoryFlushPlanResolver,
runtime: cached.memoryRuntime,
});
@@ -1563,8 +1557,6 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
const previousMemoryEmbeddingProviders = listRegisteredMemoryEmbeddingProviders();
const previousMemoryFlushPlanResolver = getMemoryFlushPlanResolver();
const previousMemoryPromptBuilder = getMemoryPromptSectionBuilder();
const previousMemoryCorpusSupplements = listMemoryCorpusSupplements();
const previousMemoryPromptSupplements = listMemoryPromptSupplements();
const previousMemoryRuntime = getMemoryRuntime();
try {
@@ -1581,9 +1573,7 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
if (!shouldActivate) {
restoreRegisteredMemoryEmbeddingProviders(previousMemoryEmbeddingProviders);
restoreMemoryPluginState({
corpusSupplements: previousMemoryCorpusSupplements,
promptBuilder: previousMemoryPromptBuilder,
promptSupplements: previousMemoryPromptSupplements,
flushPlanResolver: previousMemoryFlushPlanResolver,
runtime: previousMemoryRuntime,
});
@@ -1593,9 +1583,7 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
} catch (err) {
restoreRegisteredMemoryEmbeddingProviders(previousMemoryEmbeddingProviders);
restoreMemoryPluginState({
corpusSupplements: previousMemoryCorpusSupplements,
promptBuilder: previousMemoryPromptBuilder,
promptSupplements: previousMemoryPromptSupplements,
flushPlanResolver: previousMemoryFlushPlanResolver,
runtime: previousMemoryRuntime,
});
@@ -1647,12 +1635,10 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
if (cacheEnabled) {
setCachedPluginRegistry(cacheKey, {
memoryCorpusSupplements: listMemoryCorpusSupplements(),
registry,
memoryEmbeddingProviders: listRegisteredMemoryEmbeddingProviders(),
memoryFlushPlanResolver: getMemoryFlushPlanResolver(),
memoryPromptBuilder: getMemoryPromptSectionBuilder(),
memoryPromptSupplements: listMemoryPromptSupplements(),
memoryRuntime: getMemoryRuntime(),
});
}

View File

@@ -6,11 +6,7 @@ import {
getMemoryFlushPlanResolver,
getMemoryPromptSectionBuilder,
getMemoryRuntime,
listMemoryCorpusSupplements,
listMemoryPromptSupplements,
registerMemoryCorpusSupplement,
registerMemoryFlushPlanResolver,
registerMemoryPromptSupplement,
registerMemoryPromptSection,
registerMemoryRuntime,
resolveMemoryFlushPlan,
@@ -42,15 +38,12 @@ function createMemoryFlushPlan(relativePath: string) {
function expectClearedMemoryState() {
expect(resolveMemoryFlushPlan({})).toBeNull();
expect(buildMemoryPromptSection({ availableTools: new Set(["memory_search"]) })).toEqual([]);
expect(listMemoryCorpusSupplements()).toEqual([]);
expect(getMemoryRuntime()).toBeUndefined();
}
function createMemoryStateSnapshot() {
return {
corpusSupplements: listMemoryCorpusSupplements(),
promptBuilder: getMemoryPromptSectionBuilder(),
promptSupplements: listMemoryPromptSupplements(),
flushPlanResolver: getMemoryFlushPlanResolver(),
runtime: getMemoryRuntime(),
};
@@ -110,32 +103,6 @@ describe("memory plugin state", () => {
).toEqual(["citations: off"]);
});
it("appends prompt supplements in plugin-id order", () => {
registerMemoryPromptSection(() => ["primary"]);
registerMemoryPromptSupplement("memory-wiki", () => ["wiki"]);
registerMemoryPromptSupplement("alpha-helper", () => ["alpha"]);
expect(buildMemoryPromptSection({ availableTools: new Set() })).toEqual([
"primary",
"alpha",
"wiki",
]);
});
it("stores memory corpus supplements", async () => {
const supplement = {
search: async () => [{ corpus: "wiki", path: "sources/alpha.md", score: 1, snippet: "x" }],
get: async () => null,
};
registerMemoryCorpusSupplement("memory-wiki", supplement);
expect(listMemoryCorpusSupplements()).toHaveLength(1);
await expect(
listMemoryCorpusSupplements()[0]?.supplement.search({ query: "alpha" }),
).resolves.toEqual([{ corpus: "wiki", path: "sources/alpha.md", score: 1, snippet: "x" }]);
});
it("uses the registered flush plan resolver", () => {
registerMemoryFlushPlanResolver(() => ({
softThresholdTokens: 1,
@@ -170,23 +137,14 @@ describe("memory plugin state", () => {
relativePath: "memory/first.md",
runtime,
});
registerMemoryPromptSupplement("memory-wiki", () => ["wiki supplement"]);
registerMemoryCorpusSupplement("memory-wiki", {
search: async () => [{ corpus: "wiki", path: "sources/alpha.md", score: 1, snippet: "x" }],
get: async () => null,
});
const snapshot = createMemoryStateSnapshot();
_resetMemoryPluginState();
expectClearedMemoryState();
restoreMemoryPluginState(snapshot);
expect(buildMemoryPromptSection({ availableTools: new Set() })).toEqual([
"first",
"wiki supplement",
]);
expect(buildMemoryPromptSection({ availableTools: new Set() })).toEqual(["first"]);
expect(resolveMemoryFlushPlan({})?.relativePath).toBe("memory/first.md");
expect(listMemoryCorpusSupplements()).toHaveLength(1);
expect(getMemoryRuntime()).toBe(runtime);
});

View File

@@ -1,69 +1,16 @@
import type { OpenClawConfig } from "../config/config.js";
import type { MemoryCitationsMode } from "../config/types.memory.js";
import type { MemorySearchManager } from "../memory-host-sdk/runtime-files.js";
import type {
MemoryEmbeddingProbeResult,
MemoryProviderStatus,
MemorySyncProgressUpdate,
} from "../memory-host-sdk/engine-storage.js";
export type MemoryPromptSectionBuilder = (params: {
availableTools: Set<string>;
citationsMode?: MemoryCitationsMode;
}) => string[];
export type MemoryCorpusSearchResult = {
corpus: string;
path: string;
title?: string;
kind?: string;
score: number;
snippet: string;
id?: string;
startLine?: number;
endLine?: number;
citation?: string;
source?: string;
provenanceLabel?: string;
sourceType?: string;
sourcePath?: string;
updatedAt?: string;
};
export type MemoryCorpusGetResult = {
corpus: string;
path: string;
title?: string;
kind?: string;
content: string;
fromLine: number;
lineCount: number;
id?: string;
provenanceLabel?: string;
sourceType?: string;
sourcePath?: string;
updatedAt?: string;
};
export type MemoryCorpusSupplement = {
search(params: {
query: string;
maxResults?: number;
agentSessionKey?: string;
}): Promise<MemoryCorpusSearchResult[]>;
get(params: {
lookup: string;
fromLine?: number;
lineCount?: number;
agentSessionKey?: string;
}): Promise<MemoryCorpusGetResult | null>;
};
export type MemoryCorpusSupplementRegistration = {
pluginId: string;
supplement: MemoryCorpusSupplement;
};
export type MemoryPromptSupplementRegistration = {
pluginId: string;
builder: MemoryPromptSectionBuilder;
};
export type MemoryFlushPlan = {
softThresholdTokens: number;
forceFlushTranscriptBytes: number;
@@ -78,7 +25,18 @@ export type MemoryFlushPlanResolver = (params: {
nowMs?: number;
}) => MemoryFlushPlan | null;
export type RegisteredMemorySearchManager = MemorySearchManager;
export type RegisteredMemorySearchManager = {
status(): MemoryProviderStatus;
probeEmbeddingAvailability(): Promise<MemoryEmbeddingProbeResult>;
probeVectorAvailability(): Promise<boolean>;
sync?(params?: {
reason?: string;
force?: boolean;
sessionFiles?: string[];
progress?: (update: MemorySyncProgressUpdate) => void;
}): Promise<void>;
close?(): Promise<void>;
};
export type MemoryRuntimeQmdConfig = {
command?: string;
@@ -110,68 +68,28 @@ export type MemoryPluginRuntime = {
};
type MemoryPluginState = {
corpusSupplements: MemoryCorpusSupplementRegistration[];
promptBuilder?: MemoryPromptSectionBuilder;
promptSupplements: MemoryPromptSupplementRegistration[];
flushPlanResolver?: MemoryFlushPlanResolver;
runtime?: MemoryPluginRuntime;
};
const memoryPluginState: MemoryPluginState = {
corpusSupplements: [],
promptSupplements: [],
};
export function registerMemoryCorpusSupplement(
pluginId: string,
supplement: MemoryCorpusSupplement,
): void {
const next = memoryPluginState.corpusSupplements.filter(
(registration) => registration.pluginId !== pluginId,
);
next.push({ pluginId, supplement });
memoryPluginState.corpusSupplements = next;
}
export function listMemoryCorpusSupplements(): MemoryCorpusSupplementRegistration[] {
return [...memoryPluginState.corpusSupplements];
}
const memoryPluginState: MemoryPluginState = {};
export function registerMemoryPromptSection(builder: MemoryPromptSectionBuilder): void {
memoryPluginState.promptBuilder = builder;
}
export function registerMemoryPromptSupplement(
pluginId: string,
builder: MemoryPromptSectionBuilder,
): void {
const next = memoryPluginState.promptSupplements.filter(
(registration) => registration.pluginId !== pluginId,
);
next.push({ pluginId, builder });
memoryPluginState.promptSupplements = next;
}
export function buildMemoryPromptSection(params: {
availableTools: Set<string>;
citationsMode?: MemoryCitationsMode;
}): string[] {
const primary = memoryPluginState.promptBuilder?.(params) ?? [];
const supplements = memoryPluginState.promptSupplements
// Keep supplement order stable even if plugin registration order changes.
.toSorted((left, right) => left.pluginId.localeCompare(right.pluginId))
.flatMap((registration) => registration.builder(params));
return [...primary, ...supplements];
return memoryPluginState.promptBuilder?.(params) ?? [];
}
export function getMemoryPromptSectionBuilder(): MemoryPromptSectionBuilder | undefined {
return memoryPluginState.promptBuilder;
}
export function listMemoryPromptSupplements(): MemoryPromptSupplementRegistration[] {
return [...memoryPluginState.promptSupplements];
}
export function registerMemoryFlushPlanResolver(resolver: MemoryFlushPlanResolver): void {
memoryPluginState.flushPlanResolver = resolver;
}
@@ -200,17 +118,13 @@ export function hasMemoryRuntime(): boolean {
}
export function restoreMemoryPluginState(state: MemoryPluginState): void {
memoryPluginState.corpusSupplements = [...state.corpusSupplements];
memoryPluginState.promptBuilder = state.promptBuilder;
memoryPluginState.promptSupplements = [...state.promptSupplements];
memoryPluginState.flushPlanResolver = state.flushPlanResolver;
memoryPluginState.runtime = state.runtime;
}
export function clearMemoryPluginState(): void {
memoryPluginState.corpusSupplements = [];
memoryPluginState.promptBuilder = undefined;
memoryPluginState.promptSupplements = [];
memoryPluginState.flushPlanResolver = undefined;
memoryPluginState.runtime = undefined;
}

View File

@@ -24,9 +24,7 @@ import {
registerMemoryEmbeddingProvider,
} from "./memory-embedding-providers.js";
import {
registerMemoryCorpusSupplement,
registerMemoryFlushPlanResolver,
registerMemoryPromptSupplement,
registerMemoryPromptSection,
registerMemoryRuntime,
} from "./memory-state.js";
@@ -1118,12 +1116,6 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
}
registerMemoryPromptSection(builder);
},
registerMemoryPromptSupplement: (builder) => {
registerMemoryPromptSupplement(record.id, builder);
},
registerMemoryCorpusSupplement: (supplement) => {
registerMemoryCorpusSupplement(record.id, supplement);
},
registerMemoryFlushPlan: (resolver) => {
if (!hasKind(record.kind, "memory")) {
pushDiagnostic({

View File

@@ -2082,14 +2082,6 @@ export type OpenClawPluginApi = {
registerMemoryPromptSection: (
builder: import("./memory-state.js").MemoryPromptSectionBuilder,
) => void;
/** Register an additive memory-adjacent prompt section (non-exclusive). */
registerMemoryPromptSupplement: (
builder: import("./memory-state.js").MemoryPromptSectionBuilder,
) => void;
/** Register an additive memory-adjacent search/read corpus supplement (non-exclusive). */
registerMemoryCorpusSupplement: (
supplement: import("./memory-state.js").MemoryCorpusSupplement,
) => void;
/** Register the pre-compaction flush plan resolver for this memory plugin (exclusive slot). */
registerMemoryFlushPlan: (resolver: import("./memory-state.js").MemoryFlushPlanResolver) => void;
/** Register the active memory runtime adapter for this memory plugin (exclusive slot). */