refactor(memory): collapse legacy memory registration state

This commit is contained in:
Peter Steinberger
2026-05-02 16:15:03 +01:00
parent 2c272e271a
commit 0cf51b77fb
13 changed files with 130 additions and 176 deletions

View File

@@ -1689,53 +1689,6 @@ describe("resolveModel", () => {
});
});
it("lets official openai-codex metadata override legacy unmarked models-add rows", () => {
mockDiscoveredModel(discoverModels, {
provider: "openai-codex",
modelId: "gpt-5.5",
templateModel: {
...buildOpenAICodexForwardCompatExpectation("gpt-5.5"),
name: "GPT-5.5",
cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 },
contextWindow: 400_000,
},
});
const cfg = {
models: {
providers: {
"openai-codex": {
baseUrl: "https://chatgpt.com/backend-api",
api: "openai-codex-responses",
models: [
{
...makeModel("gpt-5.5"),
api: "openai-codex-responses",
reasoning: true,
input: ["text", "image"],
cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 },
contextWindow: 400_000,
contextTokens: 272_000,
maxTokens: 128_000,
},
],
},
},
},
} as unknown as OpenClawConfig;
const result = resolveModelForTest("openai-codex", "gpt-5.5", "/tmp/agent", cfg);
expect(result.error).toBeUndefined();
expect(result.model).toMatchObject({
provider: "openai-codex",
id: "gpt-5.5",
cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 },
contextWindow: 400_000,
maxTokens: 128_000,
});
});
it("resolves openai-codex gpt-5.5 even when discovery omits the OAuth catalog row", () => {
const result = resolveModelForTest("openai-codex", "gpt-5.5");

View File

@@ -27,7 +27,6 @@ import {
shouldSuppressBuiltInModel,
shouldUnconditionallySuppress,
} from "../model-suppression.js";
import { isLegacyModelsAddCodexMetadataModel } from "../openai-codex-models-add-legacy.js";
import { discoverAuthStorage, discoverModels } from "../pi-model-discovery.js";
import {
attachModelProviderRequestTransport,
@@ -397,12 +396,10 @@ function resolveConfiguredProviderConfig(
}
function isModelsAddMetadataModel(params: {
provider: string;
model: NonNullable<InlineProviderConfig["models"]>[number] | undefined;
}) {
return (
(params.model as { metadataSource?: unknown } | undefined)?.metadataSource === "models-add" ||
isLegacyModelsAddCodexMetadataModel(params)
(params.model as { metadataSource?: unknown } | undefined)?.metadataSource === "models-add"
);
}
@@ -528,8 +525,7 @@ function applyConfiguredProviderOverrides(params: {
? findConfiguredProviderModel(providerConfig, params.provider, discoveredModel.id)
: undefined);
const metadataOverrideModel =
params.preferDiscoveredModelMetadata &&
isModelsAddMetadataModel({ provider: params.provider, model: configuredModel })
params.preferDiscoveredModelMetadata && isModelsAddMetadataModel({ model: configuredModel })
? undefined
: configuredModel;
const discoveredHeaders = sanitizeModelHeaders(discoveredModel.headers, {

View File

@@ -5,7 +5,8 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { SessionEntry } from "../../config/sessions.js";
import {
clearMemoryPluginState,
registerMemoryFlushPlanResolver,
registerMemoryCapability,
type MemoryFlushPlanResolver,
} from "../../plugins/memory-state.js";
import type { TemplateContext } from "../templating.js";
import {
@@ -21,6 +22,10 @@ const runEmbeddedPiAgentMock = vi.fn();
const refreshQueuedFollowupSessionMock = vi.fn();
const incrementCompactionCountMock = vi.fn();
function registerMemoryFlushPlanResolverForTest(resolver: MemoryFlushPlanResolver): void {
registerMemoryCapability("memory-core", { flushPlanResolver: resolver });
}
function createReplyOperation() {
return {
abortSignal: new AbortController().signal,
@@ -34,7 +39,7 @@ describe("runMemoryFlushIfNeeded", () => {
beforeEach(async () => {
rootDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-memory-unit-"));
registerMemoryFlushPlanResolver(() => ({
registerMemoryFlushPlanResolverForTest(() => ({
softThresholdTokens: 4_000,
forceFlushTranscriptBytes: 1_000_000_000,
reserveTokensFloor: 20_000,
@@ -180,7 +185,7 @@ describe("runMemoryFlushIfNeeded", () => {
});
it("runs memory flush on the configured maintenance model without active fallbacks", async () => {
registerMemoryFlushPlanResolver(() => ({
registerMemoryFlushPlanResolverForTest(() => ({
softThresholdTokens: 4_000,
forceFlushTranscriptBytes: 1_000_000_000,
reserveTokensFloor: 20_000,
@@ -317,7 +322,7 @@ describe("runMemoryFlushIfNeeded", () => {
`${JSON.stringify({ message: { role: "user", content: "x".repeat(5_000) } })}\n`,
"utf8",
);
registerMemoryFlushPlanResolver(() => ({
registerMemoryFlushPlanResolverForTest(() => ({
softThresholdTokens: 1,
forceFlushTranscriptBytes: 1_000_000_000,
reserveTokensFloor: 0,
@@ -367,7 +372,7 @@ describe("runMemoryFlushIfNeeded", () => {
`${JSON.stringify({ message: { role: "user", content: "x".repeat(5_000) } })}\n`,
"utf8",
);
registerMemoryFlushPlanResolver(() => ({
registerMemoryFlushPlanResolverForTest(() => ({
softThresholdTokens: 1,
forceFlushTranscriptBytes: 1_000_000_000,
reserveTokensFloor: 0,
@@ -442,7 +447,7 @@ describe("runMemoryFlushIfNeeded", () => {
})}\n`,
"utf8",
);
registerMemoryFlushPlanResolver(() => ({
registerMemoryFlushPlanResolverForTest(() => ({
softThresholdTokens: 4_000,
forceFlushTranscriptBytes: 1_000_000_000,
reserveTokensFloor: 0,
@@ -493,7 +498,7 @@ describe("runMemoryFlushIfNeeded", () => {
})}\n`,
"utf8",
);
registerMemoryFlushPlanResolver(() => ({
registerMemoryFlushPlanResolverForTest(() => ({
softThresholdTokens: 4_000,
forceFlushTranscriptBytes: 1_000_000_000,
reserveTokensFloor: 0,
@@ -553,7 +558,7 @@ describe("runMemoryFlushIfNeeded", () => {
].join("\n"),
"utf8",
);
registerMemoryFlushPlanResolver(() => ({
registerMemoryFlushPlanResolverForTest(() => ({
softThresholdTokens: 4_000,
forceFlushTranscriptBytes: 1_000_000_000,
reserveTokensFloor: 0,
@@ -725,7 +730,7 @@ describe("runMemoryFlushIfNeeded", () => {
},
},
};
registerMemoryFlushPlanResolver(() => ({
registerMemoryFlushPlanResolverForTest(() => ({
softThresholdTokens: 4_000,
forceFlushTranscriptBytes: 1_000_000_000,
reserveTokensFloor: 20_000,

View File

@@ -17,7 +17,8 @@ import {
} from "../../infra/diagnostic-events.js";
import {
clearMemoryPluginState,
registerMemoryFlushPlanResolver,
registerMemoryCapability,
type MemoryFlushPlanResolver,
} from "../../plugins/memory-state.js";
import type { TemplateContext } from "../templating.js";
import type { FollowupRun, QueueSettings } from "./queue.js";
@@ -37,6 +38,10 @@ function createCliBackendTestConfig() {
};
}
function registerMemoryFlushPlanResolverForTest(resolver: MemoryFlushPlanResolver): void {
registerMemoryCapability("memory-core", { flushPlanResolver: resolver });
}
const runEmbeddedPiAgentMock = vi.fn();
const runCliAgentMock = vi.fn();
const runWithModelFallbackMock = vi.fn();
@@ -2140,7 +2145,7 @@ describe("runReplyAgent fallback reasoning tags", () => {
});
it("enforces <final> during memory flush on fallback providers", async () => {
registerMemoryFlushPlanResolver(() => ({
registerMemoryFlushPlanResolverForTest(() => ({
softThresholdTokens: 1_000,
forceFlushTranscriptBytes: 1_000_000_000,
reserveTokensFloor: 20_000,

View File

@@ -1,5 +1,4 @@
import { migrateLegacyRuntimeModelRef } from "../../../agents/model-runtime-aliases.js";
import { isLegacyModelsAddCodexMetadataModel } from "../../../agents/openai-codex-models-add-legacy.js";
import { normalizeProviderId } from "../../../agents/provider-id.js";
import { resolveSingleAccountKeysToMove } from "../../../channels/plugins/setup-promotion-helpers.js";
import { resolveNormalizedProviderModelMaxTokens } from "../../../config/defaults.js";
@@ -12,6 +11,7 @@ import {
} from "../../../shared/string-coerce.js";
import { sanitizeForLog } from "../../../terminal/ansi.js";
import { isRecord } from "./legacy-config-record-shared.js";
import { isLegacyModelsAddCodexMetadataModel } from "./legacy-models-add-metadata.js";
export { normalizeLegacyTalkConfig } from "./legacy-talk-config-normalizer.js";
export function normalizeLegacyCommandsConfig(

View File

@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import type { ModelDefinitionConfig } from "../config/types.models.js";
import { isLegacyModelsAddCodexMetadataModel } from "./openai-codex-models-add-legacy.js";
import type { ModelDefinitionConfig } from "../../../config/types.models.js";
import { isLegacyModelsAddCodexMetadataModel } from "./legacy-models-add-metadata.js";
function buildLegacyModel(id: string): Partial<ModelDefinitionConfig> {
return {

View File

@@ -1,5 +1,5 @@
import type { ModelDefinitionConfig } from "../config/types.models.js";
import { normalizeProviderId } from "./provider-id.js";
import { normalizeProviderId } from "../../../agents/provider-id.js";
import type { ModelDefinitionConfig } from "../../../config/types.models.js";
const LEGACY_MODELS_ADD_CODEX_MODEL_IDS = new Set(["gpt-5.5", "gpt-5.5-pro"]);

View File

@@ -16,11 +16,9 @@ import {
buildMemoryPromptSection,
getMemoryRuntime,
listMemoryCorpusSupplements,
registerMemoryCapability,
registerMemoryCorpusSupplement,
registerMemoryFlushPlanResolver,
registerMemoryPromptSupplement,
registerMemoryPromptSection,
registerMemoryRuntime,
resolveMemoryFlushPlan,
} from "./memory-state.js";
import type { PluginRecord } from "./registry-types.js";
@@ -590,22 +588,24 @@ describe("clearPluginLoaderCache", () => {
search: async () => [],
get: async () => null,
});
registerMemoryPromptSection(() => ["stale memory section"]);
registerMemoryPromptSupplement("memory-wiki", () => ["stale wiki supplement"]);
registerMemoryFlushPlanResolver(() => ({
softThresholdTokens: 1,
forceFlushTranscriptBytes: 2,
reserveTokensFloor: 3,
prompt: "stale",
systemPrompt: "stale",
relativePath: "memory/stale.md",
}));
registerMemoryRuntime({
async getMemorySearchManager() {
return { manager: null };
},
resolveMemoryBackendConfig() {
return { backend: "builtin" as const };
registerMemoryCapability("memory-core", {
promptBuilder: () => ["stale memory section"],
flushPlanResolver: () => ({
softThresholdTokens: 1,
forceFlushTranscriptBytes: 2,
reserveTokensFloor: 3,
prompt: "stale",
systemPrompt: "stale",
relativePath: "memory/stale.md",
}),
runtime: {
async getMemorySearchManager() {
return { manager: null };
},
resolveMemoryBackendConfig() {
return { backend: "builtin" as const };
},
},
});
expect(buildMemoryPromptSection({ availableTools: new Set() })).toEqual([
@@ -652,7 +652,9 @@ describe("clearPluginRegistryLoadCache", () => {
id: "still-live",
create: async () => ({ provider: null }),
});
registerMemoryPromptSection(() => ["still live"]);
registerMemoryCapability("memory-core", {
promptBuilder: () => ["still live"],
});
clearPluginRegistryLoadCache();

View File

@@ -73,11 +73,9 @@ import {
listActiveMemoryPublicArtifacts,
listMemoryCorpusSupplements,
listMemoryPromptSupplements,
registerMemoryCapability,
registerMemoryCorpusSupplement,
registerMemoryFlushPlanResolver,
registerMemoryPromptSupplement,
registerMemoryPromptSection,
registerMemoryRuntime,
resolveMemoryFlushPlan,
} from "./memory-state.js";
import { ensureOpenClawPluginSdkAlias } from "./plugin-sdk-dist-alias.js";
@@ -2388,16 +2386,7 @@ module.exports = { id: "throws-after-import", register() {} };`,
search: async () => [],
get: async () => null,
});
registerMemoryPromptSection(() => ["active memory section"]);
registerMemoryPromptSupplement("memory-wiki", () => ["active wiki supplement"]);
registerMemoryFlushPlanResolver(() => ({
softThresholdTokens: 1,
forceFlushTranscriptBytes: 2,
reserveTokensFloor: 3,
prompt: "active",
systemPrompt: "active",
relativePath: "memory/active.md",
}));
const activeRuntime = {
async getMemorySearchManager() {
return { manager: null, error: "active" };
@@ -2406,7 +2395,18 @@ module.exports = { id: "throws-after-import", register() {} };`,
return { backend: "builtin" as const };
},
};
registerMemoryRuntime(activeRuntime);
registerMemoryCapability("memory-core", {
promptBuilder: () => ["active memory section"],
flushPlanResolver: () => ({
softThresholdTokens: 1,
forceFlushTranscriptBytes: 2,
reserveTokensFloor: 3,
prompt: "active",
systemPrompt: "active",
relativePath: "memory/active.md",
}),
runtime: activeRuntime,
});
const plugin = writePlugin({
id: "snapshot-memory",
filename: "snapshot-memory.cjs",

View File

@@ -93,9 +93,6 @@ import {
import {
clearMemoryPluginState,
getMemoryCapabilityRegistration,
getMemoryFlushPlanResolver,
getMemoryPromptSectionBuilder,
getMemoryRuntime,
listMemoryCorpusSupplements,
listMemoryPromptSupplements,
restoreMemoryPluginState,
@@ -245,10 +242,7 @@ type CachedPluginState = {
agentHarnesses: ReturnType<typeof listRegisteredAgentHarnesses>;
compactionProviders: ReturnType<typeof listRegisteredCompactionProviders>;
memoryEmbeddingProviders: ReturnType<typeof listRegisteredMemoryEmbeddingProviders>;
memoryFlushPlanResolver: ReturnType<typeof getMemoryFlushPlanResolver>;
memoryPromptBuilder: ReturnType<typeof getMemoryPromptSectionBuilder>;
memoryPromptSupplements: ReturnType<typeof listMemoryPromptSupplements>;
memoryRuntime: ReturnType<typeof getMemoryRuntime>;
};
const MAX_PLUGIN_REGISTRY_CACHE_ENTRIES = 128;
@@ -1487,10 +1481,7 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
restoreMemoryPluginState({
capability: cached.state.memoryCapability,
corpusSupplements: cached.state.memoryCorpusSupplements,
promptBuilder: cached.state.memoryPromptBuilder,
promptSupplements: cached.state.memoryPromptSupplements,
flushPlanResolver: cached.state.memoryFlushPlanResolver,
runtime: cached.state.memoryRuntime,
});
activatePluginRegistry(
cached.state.registry,
@@ -2303,11 +2294,8 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
const previousDetachedTaskRuntimeRegistration = getDetachedTaskLifecycleRuntimeRegistration();
const previousMemoryCapability = getMemoryCapabilityRegistration();
const previousMemoryEmbeddingProviders = listRegisteredMemoryEmbeddingProviders();
const previousMemoryFlushPlanResolver = getMemoryFlushPlanResolver();
const previousMemoryPromptBuilder = getMemoryPromptSectionBuilder();
const previousMemoryCorpusSupplements = listMemoryCorpusSupplements();
const previousMemoryPromptSupplements = listMemoryPromptSupplements();
const previousMemoryRuntime = getMemoryRuntime();
try {
withProfile(
@@ -2324,10 +2312,7 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
restoreMemoryPluginState({
capability: previousMemoryCapability,
corpusSupplements: previousMemoryCorpusSupplements,
promptBuilder: previousMemoryPromptBuilder,
promptSupplements: previousMemoryPromptSupplements,
flushPlanResolver: previousMemoryFlushPlanResolver,
runtime: previousMemoryRuntime,
});
}
registry.plugins.push(record);
@@ -2342,10 +2327,7 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
restoreMemoryPluginState({
capability: previousMemoryCapability,
corpusSupplements: previousMemoryCorpusSupplements,
promptBuilder: previousMemoryPromptBuilder,
promptSupplements: previousMemoryPromptSupplements,
flushPlanResolver: previousMemoryFlushPlanResolver,
runtime: previousMemoryRuntime,
});
recordPluginError({
logger,
@@ -2413,10 +2395,7 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
agentHarnesses: listRegisteredAgentHarnesses(),
compactionProviders: listRegisteredCompactionProviders(),
memoryEmbeddingProviders: listRegisteredMemoryEmbeddingProviders(),
memoryFlushPlanResolver: getMemoryFlushPlanResolver(),
memoryPromptBuilder: getMemoryPromptSectionBuilder(),
memoryPromptSupplements: listMemoryPromptSupplements(),
memoryRuntime: getMemoryRuntime(),
},
onlyPluginIds,
);

View File

@@ -4,8 +4,6 @@ import {
buildMemoryPromptSection,
clearMemoryPluginState,
getMemoryCapabilityRegistration,
getMemoryFlushPlanResolver,
getMemoryPromptSectionBuilder,
getMemoryRuntime,
hasMemoryRuntime,
listMemoryCorpusSupplements,
@@ -54,10 +52,7 @@ function createMemoryStateSnapshot() {
return {
capability: getMemoryCapabilityRegistration(),
corpusSupplements: listMemoryCorpusSupplements(),
promptBuilder: getMemoryPromptSectionBuilder(),
promptSupplements: listMemoryPromptSupplements(),
flushPlanResolver: getMemoryFlushPlanResolver(),
runtime: getMemoryRuntime(),
};
}
@@ -66,16 +61,13 @@ function registerMemoryState(params: {
relativePath?: string;
runtime?: ReturnType<typeof createMemoryRuntime>;
}) {
if (params.promptSection) {
registerMemoryPromptSection(() => params.promptSection ?? []);
}
if (params.relativePath) {
const relativePath = params.relativePath;
registerMemoryFlushPlanResolver(() => createMemoryFlushPlan(relativePath));
}
if (params.runtime) {
registerMemoryRuntime(params.runtime);
}
registerMemoryCapability("memory-core", {
...(params.promptSection ? { promptBuilder: () => params.promptSection ?? [] } : {}),
...(params.relativePath
? { flushPlanResolver: () => createMemoryFlushPlan(params.relativePath ?? "") }
: {}),
...(params.runtime ? { runtime: params.runtime } : {}),
});
}
describe("memory plugin state", () => {
@@ -102,7 +94,22 @@ describe("memory plugin state", () => {
]);
});
it("prefers the registered memory capability over legacy split state", async () => {
it("adapts deprecated split registration to the unified memory capability", async () => {
const runtime = createMemoryRuntime();
registerMemoryPromptSection(() => ["legacy prompt"]);
registerMemoryFlushPlanResolver(() => createMemoryFlushPlan("memory/legacy.md"));
registerMemoryRuntime(runtime);
expect(buildMemoryPromptSection({ availableTools: new Set() })).toEqual(["legacy prompt"]);
expect(resolveMemoryFlushPlan({})?.relativePath).toBe("memory/legacy.md");
expect(getMemoryRuntime()).toBe(runtime);
expect(getMemoryCapabilityRegistration()).toMatchObject({
pluginId: "legacy-memory-v1",
});
});
it("prefers the registered memory capability over earlier legacy split state", async () => {
const runtime = createMemoryRuntime();
registerMemoryPromptSection(() => ["legacy prompt"]);

View File

@@ -137,19 +137,12 @@ export type MemoryPluginCapabilityRegistration = {
capability: MemoryPluginCapability;
};
const LEGACY_MEMORY_COMPAT_PLUGIN_ID = "legacy-memory-v1";
type MemoryPluginState = {
capability?: MemoryPluginCapabilityRegistration;
corpusSupplements: MemoryCorpusSupplementRegistration[];
promptSupplements: MemoryPromptSupplementRegistration[];
// LEGACY(memory-v1): kept for external plugins still registering the older
// split memory surfaces. Prefer `registerMemoryCapability(...)`.
promptBuilder?: MemoryPromptSectionBuilder;
// LEGACY(memory-v1): remove after external memory plugins migrate to the
// unified capability registration path.
flushPlanResolver?: MemoryFlushPlanResolver;
// LEGACY(memory-v1): remove after external memory plugins migrate to the
// unified capability registration path.
runtime?: MemoryPluginRuntime;
};
const memoryPluginState: MemoryPluginState = {
@@ -175,6 +168,14 @@ export function registerMemoryCapability(
memoryPluginState.capability = { pluginId, capability: { ...capability } };
}
function patchMemoryCapability(pluginId: string, patch: MemoryPluginCapability): void {
const current =
memoryPluginState.capability?.pluginId === pluginId
? memoryPluginState.capability.capability
: {};
registerMemoryCapability(pluginId, { ...current, ...patch });
}
export function getMemoryCapabilityRegistration(): MemoryPluginCapabilityRegistration | undefined {
return memoryPluginState.capability
? {
@@ -190,7 +191,14 @@ export function listMemoryCorpusSupplements(): MemoryCorpusSupplementRegistratio
/** @deprecated Use registerMemoryCapability(pluginId, { promptBuilder }) instead. */
export function registerMemoryPromptSection(builder: MemoryPromptSectionBuilder): void {
memoryPluginState.promptBuilder = builder;
registerMemoryPromptSectionForPlugin(LEGACY_MEMORY_COMPAT_PLUGIN_ID, builder);
}
export function registerMemoryPromptSectionForPlugin(
pluginId: string,
builder: MemoryPromptSectionBuilder,
): void {
patchMemoryCapability(pluginId, { promptBuilder: builder });
}
export function registerMemoryPromptSupplement(
@@ -209,9 +217,7 @@ export function buildMemoryPromptSection(params: {
citationsMode?: MemoryCitationsMode;
}): string[] {
const primary = normalizeMemoryPromptLines(
memoryPluginState.capability?.capability.promptBuilder?.(params) ??
memoryPluginState.promptBuilder?.(params) ??
[],
memoryPluginState.capability?.capability.promptBuilder?.(params) ?? [],
);
const supplements = memoryPluginState.promptSupplements
// Keep supplement order stable even if plugin registration order changes.
@@ -228,7 +234,7 @@ function normalizeMemoryPromptLines(value: unknown): string[] {
}
export function getMemoryPromptSectionBuilder(): MemoryPromptSectionBuilder | undefined {
return memoryPluginState.capability?.capability.promptBuilder ?? memoryPluginState.promptBuilder;
return memoryPluginState.capability?.capability.promptBuilder;
}
export function listMemoryPromptSupplements(): MemoryPromptSupplementRegistration[] {
@@ -237,34 +243,41 @@ export function listMemoryPromptSupplements(): MemoryPromptSupplementRegistratio
/** @deprecated Use registerMemoryCapability(pluginId, { flushPlanResolver }) instead. */
export function registerMemoryFlushPlanResolver(resolver: MemoryFlushPlanResolver): void {
memoryPluginState.flushPlanResolver = resolver;
registerMemoryFlushPlanResolverForPlugin(LEGACY_MEMORY_COMPAT_PLUGIN_ID, resolver);
}
export function registerMemoryFlushPlanResolverForPlugin(
pluginId: string,
resolver: MemoryFlushPlanResolver,
): void {
patchMemoryCapability(pluginId, { flushPlanResolver: resolver });
}
export function resolveMemoryFlushPlan(params: {
cfg?: OpenClawConfig;
nowMs?: number;
}): MemoryFlushPlan | null {
return (
memoryPluginState.capability?.capability.flushPlanResolver?.(params) ??
memoryPluginState.flushPlanResolver?.(params) ??
null
);
return memoryPluginState.capability?.capability.flushPlanResolver?.(params) ?? null;
}
export function getMemoryFlushPlanResolver(): MemoryFlushPlanResolver | undefined {
return (
memoryPluginState.capability?.capability.flushPlanResolver ??
memoryPluginState.flushPlanResolver
);
return memoryPluginState.capability?.capability.flushPlanResolver;
}
/** @deprecated Use registerMemoryCapability(pluginId, { runtime }) instead. */
export function registerMemoryRuntime(runtime: MemoryPluginRuntime): void {
memoryPluginState.runtime = runtime;
registerMemoryRuntimeForPlugin(LEGACY_MEMORY_COMPAT_PLUGIN_ID, runtime);
}
export function registerMemoryRuntimeForPlugin(
pluginId: string,
runtime: MemoryPluginRuntime,
): void {
patchMemoryCapability(pluginId, { runtime });
}
export function getMemoryRuntime(): MemoryPluginRuntime | undefined {
return memoryPluginState.capability?.capability.runtime ?? memoryPluginState.runtime;
return memoryPluginState.capability?.capability.runtime;
}
export function hasMemoryRuntime(): boolean {
@@ -318,19 +331,13 @@ export function restoreMemoryPluginState(state: MemoryPluginState): void {
}
: undefined;
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.capability = undefined;
memoryPluginState.corpusSupplements = [];
memoryPluginState.promptBuilder = undefined;
memoryPluginState.promptSupplements = [];
memoryPluginState.flushPlanResolver = undefined;
memoryPluginState.runtime = undefined;
}
export const _resetMemoryPluginState = clearMemoryPluginState;

View File

@@ -92,10 +92,10 @@ import {
import {
registerMemoryCapability,
registerMemoryCorpusSupplement,
registerMemoryFlushPlanResolver,
registerMemoryFlushPlanResolverForPlugin,
registerMemoryPromptSupplement,
registerMemoryPromptSection,
registerMemoryRuntime,
registerMemoryPromptSectionForPlugin,
registerMemoryRuntimeForPlugin,
} from "./memory-state.js";
import { normalizeRegisteredProvider } from "./provider-validation.js";
import { createEmptyPluginRegistry } from "./registry-empty.js";
@@ -2380,7 +2380,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
});
return;
}
registerMemoryPromptSection(builder);
registerMemoryPromptSectionForPlugin(record.id, builder);
},
registerMemoryPromptSupplement: (builder) => {
if (typeof builder !== "function") {
@@ -2415,7 +2415,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
});
return;
}
registerMemoryFlushPlanResolver(resolver);
registerMemoryFlushPlanResolverForPlugin(record.id, resolver);
},
registerMemoryRuntime: (runtime) => {
if (!hasKind(record.kind, "memory")) {
@@ -2435,7 +2435,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
});
return;
}
registerMemoryRuntime(runtime);
registerMemoryRuntimeForPlugin(record.id, runtime);
},
registerMemoryEmbeddingProvider: (adapter) => {
if (hasKind(record.kind, "memory")) {