From 7ff79aa494d2f6e5b0105eda018acedf29cfd3ce Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Sun, 15 Mar 2026 21:26:50 +0000 Subject: [PATCH] Memory: adopt embedding backend catalog --- .../embedding-runtime-registry.test.ts | 80 +++++++++++++++++++ .../embedding-runtime-registry.ts | 10 +-- 2 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 src/extension-host/embedding-runtime-registry.test.ts diff --git a/src/extension-host/embedding-runtime-registry.test.ts b/src/extension-host/embedding-runtime-registry.test.ts new file mode 100644 index 00000000000..9a6fcf4cc62 --- /dev/null +++ b/src/extension-host/embedding-runtime-registry.test.ts @@ -0,0 +1,80 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const listExtensionHostEmbeddingRemoteRuntimeBackendIds = vi.hoisted(() => + vi.fn(() => ["gemini", "openai"] as const), +); +const createGeminiEmbeddingProvider = vi.hoisted(() => vi.fn()); +const createOpenAiEmbeddingProvider = vi.hoisted(() => vi.fn()); + +vi.mock("./runtime-backend-catalog.js", () => ({ + listExtensionHostEmbeddingRemoteRuntimeBackendIds, +})); + +vi.mock("../memory/embeddings-gemini.js", () => ({ + createGeminiEmbeddingProvider, +})); + +vi.mock("../memory/embeddings-openai.js", () => ({ + createOpenAiEmbeddingProvider, +})); + +vi.mock("../memory/embeddings-mistral.js", () => ({ + createMistralEmbeddingProvider: vi.fn(), +})); + +vi.mock("../memory/embeddings-ollama.js", () => ({ + createOllamaEmbeddingProvider: vi.fn(), +})); + +vi.mock("../memory/embeddings-voyage.js", () => ({ + createVoyageEmbeddingProvider: vi.fn(), +})); + +vi.mock("../memory/node-llama.js", () => ({ + importNodeLlamaCpp: vi.fn(), +})); + +describe("extension host embedding runtime registry", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("uses the runtime-backend catalog for auto provider order", async () => { + createGeminiEmbeddingProvider.mockResolvedValue({ + provider: { + id: "gemini", + model: "text-embedding-004", + embedQuery: vi.fn(), + embedBatch: vi.fn(), + }, + client: { kind: "gemini" }, + }); + + const { createExtensionHostEmbeddingProvider } = + await import("./embedding-runtime-registry.js"); + const result = await createExtensionHostEmbeddingProvider({ + config: {} as never, + provider: "auto", + model: "text-embedding-004", + fallback: "none", + }); + + expect(listExtensionHostEmbeddingRemoteRuntimeBackendIds).toHaveBeenCalledTimes(1); + expect(createGeminiEmbeddingProvider).toHaveBeenCalledTimes(1); + expect(createOpenAiEmbeddingProvider).not.toHaveBeenCalled(); + expect(result.provider?.id).toBe("gemini"); + }); + + it("uses the same catalog order in local setup guidance", async () => { + const { formatExtensionHostLocalEmbeddingSetupError } = + await import("./embedding-runtime-registry.js"); + + const message = formatExtensionHostLocalEmbeddingSetupError( + new Error("Cannot find package 'node-llama-cpp'"), + ); + + expect(listExtensionHostEmbeddingRemoteRuntimeBackendIds).toHaveBeenCalledTimes(1); + expect(message).toContain('agents.defaults.memorySearch.provider = "gemini"'); + expect(message).toContain('agents.defaults.memorySearch.provider = "openai"'); + }); +}); diff --git a/src/extension-host/embedding-runtime-registry.ts b/src/extension-host/embedding-runtime-registry.ts index d6e46d3395b..0b7ffa5735c 100644 --- a/src/extension-host/embedding-runtime-registry.ts +++ b/src/extension-host/embedding-runtime-registry.ts @@ -25,16 +25,14 @@ import { } from "../memory/embeddings-voyage.js"; import { importNodeLlamaCpp } from "../memory/node-llama.js"; import { resolveUserPath } from "../utils.js"; -import { - DEFAULT_EXTENSION_HOST_LOCAL_EMBEDDING_MODEL, - EXTENSION_HOST_REMOTE_EMBEDDING_PROVIDER_IDS, -} from "./embedding-runtime-backends.js"; +import { DEFAULT_EXTENSION_HOST_LOCAL_EMBEDDING_MODEL } from "./embedding-runtime-backends.js"; import type { EmbeddingProvider, EmbeddingProviderId, EmbeddingProviderOptions, EmbeddingProviderResult, } from "./embedding-runtime-types.js"; +import { listExtensionHostEmbeddingRemoteRuntimeBackendIds } from "./runtime-backend-catalog.js"; export type { GeminiEmbeddingClient, @@ -192,7 +190,7 @@ export async function createExtensionHostEmbeddingProvider( } } - for (const provider of EXTENSION_HOST_REMOTE_EMBEDDING_PROVIDER_IDS) { + for (const provider of listExtensionHostEmbeddingRemoteRuntimeBackendIds()) { try { const result = await createExtensionHostEmbeddingProviderById(provider, options); return { ...result, requestedProvider }; @@ -292,7 +290,7 @@ export function formatExtensionHostLocalEmbeddingSetupError(err: unknown): strin ? "2) Reinstall OpenClaw (this should install node-llama-cpp): npm i -g openclaw@latest" : null, "3) If you use pnpm: pnpm approve-builds (select node-llama-cpp), then pnpm rebuild node-llama-cpp", - ...EXTENSION_HOST_REMOTE_EMBEDDING_PROVIDER_IDS.map( + ...listExtensionHostEmbeddingRemoteRuntimeBackendIds().map( (provider) => `Or set agents.defaults.memorySearch.provider = "${provider}" (remote).`, ), ]