mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-21 05:32:53 +00:00
fix(memory): avoid recursive provider discovery during register (#61402)
* fix(memory): avoid recursive provider discovery during register * test(memory): remove resetModules from provider adapter regression * fix: avoid recursive provider discovery during register (#61402) (thanks @ngutman)
This commit is contained in:
@@ -78,6 +78,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Feishu/reasoning: only expose streamed reasoning previews when the session is explicitly `reasoning:stream`, so hidden reasoning traces do not surface on normal streaming sessions. Thanks @vincentkoc.
|
||||
- Discord: keep REST, webhook, and monitor traffic on the configured proxy, preserve component-only media sends, honor `@everyone` and `@here` mention gates, keep ACK reactions on the active account, and split voice connect/playback timeouts so auto-join is more reliable. (#57465, #60361, #60345) Thanks @geekhuashan.
|
||||
- WhatsApp: restore `channels.whatsapp.blockStreaming` and reset watchdog timeouts after reconnect so quiet chats stop falling into reconnect loops. (#60007, #60069) Thanks @MonkeyLeeT and @mcaxtr.
|
||||
- Memory: keep `memory-core` builtin embedding registration on the already-registered path so selecting `memory-core` no longer recurses through plugin discovery and crashes during startup. (#61402) Thanks @ngutman.
|
||||
- MS Teams: download inline DM images via Graph API and preserve channel reply threading in proactive fallback. (#52212, #55198) Thanks @Ted-developer and @hyojin.
|
||||
- MS Teams: replace the deprecated Teams SDK HttpPlugin stub with `httpServerAdapter` so recurring gateway deprecation warnings stop firing and the Express 5 compatibility workaround stays on the supported SDK path. (#60939) Thanks @coolramukaka-sys.
|
||||
- Matrix/exec approvals: anchor seeded approval reactions to the primary Matrix prompt event, resolve them from event metadata instead of prompt text, and clean up chunked approval prompts correctly. (#60931) Thanks @gumadeiras.
|
||||
|
||||
63
extensions/memory-core/src/memory/provider-adapters.test.ts
Normal file
63
extensions/memory-core/src/memory/provider-adapters.test.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import type { MemoryEmbeddingProviderAdapter } from "openclaw/plugin-sdk/memory-core-host-engine-embeddings";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { registerBuiltInMemoryEmbeddingProviders } from "./provider-adapters.js";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
listRegisteredMemoryEmbeddingProviderAdapters: vi.fn<() => MemoryEmbeddingProviderAdapter[]>(
|
||||
() => [],
|
||||
),
|
||||
listMemoryEmbeddingProviders: vi.fn(() => {
|
||||
throw new Error("fallback capability loading should stay cold during memory-core register");
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("openclaw/plugin-sdk/memory-core-host-engine-embeddings", async () => {
|
||||
const actual = await vi.importActual<
|
||||
typeof import("openclaw/plugin-sdk/memory-core-host-engine-embeddings")
|
||||
>("openclaw/plugin-sdk/memory-core-host-engine-embeddings");
|
||||
return {
|
||||
...actual,
|
||||
listRegisteredMemoryEmbeddingProviderAdapters:
|
||||
mocks.listRegisteredMemoryEmbeddingProviderAdapters,
|
||||
listMemoryEmbeddingProviders: mocks.listMemoryEmbeddingProviders,
|
||||
};
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
mocks.listRegisteredMemoryEmbeddingProviderAdapters.mockReset();
|
||||
mocks.listRegisteredMemoryEmbeddingProviderAdapters.mockReturnValue([]);
|
||||
mocks.listMemoryEmbeddingProviders.mockClear();
|
||||
});
|
||||
|
||||
describe("registerBuiltInMemoryEmbeddingProviders", () => {
|
||||
it("uses only already-registered providers when avoiding duplicates", () => {
|
||||
const ids: string[] = [];
|
||||
|
||||
registerBuiltInMemoryEmbeddingProviders({
|
||||
registerMemoryEmbeddingProvider(adapter) {
|
||||
ids.push(adapter.id);
|
||||
},
|
||||
});
|
||||
|
||||
expect(ids).toEqual(["local", "openai", "gemini", "voyage", "mistral"]);
|
||||
expect(mocks.listRegisteredMemoryEmbeddingProviderAdapters).toHaveBeenCalledTimes(1);
|
||||
expect(mocks.listMemoryEmbeddingProviders).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("skips builtin adapters that are already registered in the current load", () => {
|
||||
mocks.listRegisteredMemoryEmbeddingProviderAdapters.mockReturnValue([
|
||||
{ id: "local", create: vi.fn() } as MemoryEmbeddingProviderAdapter,
|
||||
{ id: "gemini", create: vi.fn() } as MemoryEmbeddingProviderAdapter,
|
||||
]);
|
||||
const ids: string[] = [];
|
||||
|
||||
registerBuiltInMemoryEmbeddingProviders({
|
||||
registerMemoryEmbeddingProvider(adapter) {
|
||||
ids.push(adapter.id);
|
||||
},
|
||||
});
|
||||
|
||||
expect(ids).toEqual(["openai", "voyage", "mistral"]);
|
||||
expect(mocks.listMemoryEmbeddingProviders).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
createOpenAiEmbeddingProvider,
|
||||
createVoyageEmbeddingProvider,
|
||||
hasNonTextEmbeddingParts,
|
||||
listMemoryEmbeddingProviders,
|
||||
listRegisteredMemoryEmbeddingProviderAdapters,
|
||||
runGeminiEmbeddingBatches,
|
||||
runOpenAiEmbeddingBatches,
|
||||
runVoyageEmbeddingBatches,
|
||||
@@ -334,7 +334,12 @@ export function getBuiltinMemoryEmbeddingProviderAdapter(
|
||||
export function registerBuiltInMemoryEmbeddingProviders(register: {
|
||||
registerMemoryEmbeddingProvider: (adapter: MemoryEmbeddingProviderAdapter) => void;
|
||||
}): void {
|
||||
const existingIds = new Set(listMemoryEmbeddingProviders().map((adapter) => adapter.id));
|
||||
// Only inspect providers already registered in the current load. Falling back
|
||||
// to capability discovery here can recursively trigger plugin loading while
|
||||
// memory-core itself is still registering.
|
||||
const existingIds = new Set(
|
||||
listRegisteredMemoryEmbeddingProviderAdapters().map((adapter) => adapter.id),
|
||||
);
|
||||
for (const adapter of builtinMemoryEmbeddingProviderAdapters) {
|
||||
if (existingIds.has(adapter.id)) {
|
||||
continue;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
export {
|
||||
getMemoryEmbeddingProvider,
|
||||
listMemoryEmbeddingProviders,
|
||||
listRegisteredMemoryEmbeddingProviderAdapters,
|
||||
} from "../plugins/memory-embedding-provider-runtime.js";
|
||||
export type {
|
||||
MemoryEmbeddingBatchChunk,
|
||||
|
||||
@@ -6,12 +6,16 @@ import {
|
||||
type MemoryEmbeddingProviderAdapter,
|
||||
} from "./memory-embedding-providers.js";
|
||||
|
||||
export function listRegisteredMemoryEmbeddingProviderAdapters(): MemoryEmbeddingProviderAdapter[] {
|
||||
return listRegisteredMemoryEmbeddingProviders().map((entry) => entry.adapter);
|
||||
}
|
||||
|
||||
export function listMemoryEmbeddingProviders(
|
||||
cfg?: OpenClawConfig,
|
||||
): MemoryEmbeddingProviderAdapter[] {
|
||||
const registered = listRegisteredMemoryEmbeddingProviders();
|
||||
const registered = listRegisteredMemoryEmbeddingProviderAdapters();
|
||||
if (registered.length > 0) {
|
||||
return registered.map((entry) => entry.adapter);
|
||||
return registered;
|
||||
}
|
||||
return resolvePluginCapabilityProviders({
|
||||
key: "memoryEmbeddingProviders",
|
||||
|
||||
Reference in New Issue
Block a user