fix(memory): share embedding providers across plugin runtime splits (#55945)

Merged via squash.

Prepared head SHA: e913806211
Co-authored-by: glitch418x <189487110+glitch418x@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
This commit is contained in:
glitch 2026-03-27 21:40:19 +03:00 committed by GitHub
parent 78e2f3d66d
commit 3cec3bd48b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 36 additions and 8 deletions

View File

@ -88,6 +88,7 @@ Docs: https://docs.openclaw.ai
- TUI/activation: validate `/activation` arguments in the TUI and reject invalid values instead of silently coercing them to `mention`. (#55733) Thanks @shakkernerd.
- Agents/model switching: apply `/model` changes to active embedded runs at the next safe retry boundary, so overloaded or retrying turns switch to the newly selected model instead of staying pinned to the old provider.
- Agents/Codex fallback: classify Codex `server_error` payloads as failoverable, sanitize `Codex error:` payloads before they reach chat, preserve context-overflow guidance for prefixed `invalid_request_error` payloads, and omit provider `request_id` values from user-facing UI copy. (#42892) Thanks @xaeon2026.
- Memory/search: share memory embedding provider registrations across split plugin runtimes so memory search no longer fails with unknown provider errors after memory-core registers built-in adapters. (#55945) Thanks @glitch418x.
## 2026.3.24

View File

@ -11,6 +11,8 @@ import {
type MemoryEmbeddingProviderAdapter,
} from "./memory-embedding-providers.js";
const MEMORY_EMBEDDING_PROVIDERS_KEY = Symbol.for("openclaw.memoryEmbeddingProviders");
function createAdapter(id: string): MemoryEmbeddingProviderAdapter {
return {
id,
@ -81,4 +83,18 @@ describe("memory embedding provider registry", () => {
expect(listMemoryEmbeddingProviders()).toEqual([]);
});
it("stores adapters in a process-global singleton map", () => {
const alpha = createAdapter("alpha");
registerMemoryEmbeddingProvider(alpha, { ownerPluginId: "memory-core" });
const globalRegistry = (globalThis as Record<PropertyKey, unknown>)[
MEMORY_EMBEDDING_PROVIDERS_KEY
] as Map<string, { adapter: MemoryEmbeddingProviderAdapter; ownerPluginId?: string }>;
expect(globalRegistry.get("alpha")).toEqual({
adapter: alpha,
ownerPluginId: "memory-core",
});
});
});

View File

@ -72,13 +72,24 @@ export type RegisteredMemoryEmbeddingProvider = {
ownerPluginId?: string;
};
const memoryEmbeddingProviders = new Map<string, RegisteredMemoryEmbeddingProvider>();
const MEMORY_EMBEDDING_PROVIDERS_KEY = Symbol.for("openclaw.memoryEmbeddingProviders");
function getMemoryEmbeddingProviders(): Map<string, RegisteredMemoryEmbeddingProvider> {
const globalStore = globalThis as Record<PropertyKey, unknown>;
const existing = globalStore[MEMORY_EMBEDDING_PROVIDERS_KEY];
if (existing instanceof Map) {
return existing as Map<string, RegisteredMemoryEmbeddingProvider>;
}
const created = new Map<string, RegisteredMemoryEmbeddingProvider>();
globalStore[MEMORY_EMBEDDING_PROVIDERS_KEY] = created;
return created;
}
export function registerMemoryEmbeddingProvider(
adapter: MemoryEmbeddingProviderAdapter,
options?: { ownerPluginId?: string },
): void {
memoryEmbeddingProviders.set(adapter.id, {
getMemoryEmbeddingProviders().set(adapter.id, {
adapter,
ownerPluginId: options?.ownerPluginId,
});
@ -87,15 +98,15 @@ export function registerMemoryEmbeddingProvider(
export function getRegisteredMemoryEmbeddingProvider(
id: string,
): RegisteredMemoryEmbeddingProvider | undefined {
return memoryEmbeddingProviders.get(id);
return getMemoryEmbeddingProviders().get(id);
}
export function getMemoryEmbeddingProvider(id: string): MemoryEmbeddingProviderAdapter | undefined {
return memoryEmbeddingProviders.get(id)?.adapter;
return getMemoryEmbeddingProviders().get(id)?.adapter;
}
export function listRegisteredMemoryEmbeddingProviders(): RegisteredMemoryEmbeddingProvider[] {
return Array.from(memoryEmbeddingProviders.values());
return Array.from(getMemoryEmbeddingProviders().values());
}
export function listMemoryEmbeddingProviders(): MemoryEmbeddingProviderAdapter[] {
@ -103,7 +114,7 @@ export function listMemoryEmbeddingProviders(): MemoryEmbeddingProviderAdapter[]
}
export function restoreMemoryEmbeddingProviders(adapters: MemoryEmbeddingProviderAdapter[]): void {
memoryEmbeddingProviders.clear();
getMemoryEmbeddingProviders().clear();
for (const adapter of adapters) {
registerMemoryEmbeddingProvider(adapter);
}
@ -112,7 +123,7 @@ export function restoreMemoryEmbeddingProviders(adapters: MemoryEmbeddingProvide
export function restoreRegisteredMemoryEmbeddingProviders(
entries: RegisteredMemoryEmbeddingProvider[],
): void {
memoryEmbeddingProviders.clear();
getMemoryEmbeddingProviders().clear();
for (const entry of entries) {
registerMemoryEmbeddingProvider(entry.adapter, {
ownerPluginId: entry.ownerPluginId,
@ -121,7 +132,7 @@ export function restoreRegisteredMemoryEmbeddingProviders(
}
export function clearMemoryEmbeddingProviders(): void {
memoryEmbeddingProviders.clear();
getMemoryEmbeddingProviders().clear();
}
export const _resetMemoryEmbeddingProviders = clearMemoryEmbeddingProviders;