mirror of https://github.com/openclaw/openclaw.git
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:
parent
78e2f3d66d
commit
3cec3bd48b
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue