Files
openclaw/src/plugins/embedding-provider-runtime.test.ts
Bob ae4806ed9a feat(plugins): add embedding provider contract (#84947)
Summary:
- Merged feat(plugins): add embedding provider contract after ClawSweeper review.

Automerge notes:
- PR branch already contained follow-up commit before automerge: chore(plugins): refresh embedding provider sdk baseline
- PR branch already contained follow-up commit before automerge: docs(plugins): document embedding provider contract
- PR branch already contained follow-up commit before automerge: fix(plugins): restore embedding providers after snapshot loads
- PR branch already contained follow-up commit before automerge: fix(plugins): resolve embedding providers from manifests
- PR branch already contained follow-up commit before automerge: fix(plugin-sdk): keep embedding provider registry mutators internal
- PR branch already contained follow-up commit before automerge: chore(plugin-sdk): refresh embedding provider API baseline

Validation:
- ClawSweeper review passed for head 41ebd66ab4.
- Required merge gates passed before the squash merge.

Prepared head SHA: 41ebd66ab4
Review: https://github.com/openclaw/openclaw/pull/84947#issuecomment-4514762026

Co-authored-by: Bob <dutifulbob@gmail.com>
Co-authored-by: Mariano Belinky <mbelinky@gmail.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: osolmaz
Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com>
2026-05-22 03:36:51 +00:00

89 lines
3.3 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import {
clearEmbeddingProviders,
registerEmbeddingProvider,
type EmbeddingProviderAdapter,
} from "./embedding-providers.js";
const mocks = vi.hoisted(() => ({
resolvePluginCapabilityProviders: vi.fn<
typeof import("./capability-provider-runtime.js").resolvePluginCapabilityProviders
>(() => []),
resolvePluginCapabilityProvider: vi.fn<
typeof import("./capability-provider-runtime.js").resolvePluginCapabilityProvider
>(() => undefined),
}));
vi.mock("./capability-provider-runtime.js", () => ({
resolvePluginCapabilityProvider: mocks.resolvePluginCapabilityProvider,
resolvePluginCapabilityProviders: mocks.resolvePluginCapabilityProviders,
}));
let runtimeModule: typeof import("./embedding-provider-runtime.js");
function createCapabilityAdapter(id: string): EmbeddingProviderAdapter {
return {
id,
create: async () => ({ provider: null }),
};
}
beforeEach(async () => {
clearEmbeddingProviders();
mocks.resolvePluginCapabilityProviders.mockReset();
mocks.resolvePluginCapabilityProviders.mockReturnValue([]);
mocks.resolvePluginCapabilityProvider.mockReset();
mocks.resolvePluginCapabilityProvider.mockReturnValue(undefined);
runtimeModule = await import("./embedding-provider-runtime.js");
});
afterEach(() => {
clearEmbeddingProviders();
});
describe("embedding provider runtime resolution", () => {
it("merges registered and declared capability fallback adapters", () => {
registerEmbeddingProvider({
id: "registered",
create: async () => ({ provider: null }),
});
mocks.resolvePluginCapabilityProviders.mockReturnValue([createCapabilityAdapter("capability")]);
expect(runtimeModule.listEmbeddingProviders().map((adapter) => adapter.id)).toEqual([
"registered",
"capability",
]);
expect(runtimeModule.getEmbeddingProvider("registered")?.id).toBe("registered");
expect(mocks.resolvePluginCapabilityProviders).toHaveBeenCalledTimes(1);
});
it("falls back to declared capability adapters when the registry is cold", () => {
mocks.resolvePluginCapabilityProviders.mockReturnValue([createCapabilityAdapter("ollama")]);
mocks.resolvePluginCapabilityProvider.mockReturnValue(createCapabilityAdapter("ollama"));
expect(runtimeModule.listEmbeddingProviders().map((adapter) => adapter.id)).toEqual(["ollama"]);
expect(runtimeModule.getEmbeddingProvider("ollama")?.id).toBe("ollama");
expect(mocks.resolvePluginCapabilityProviders).toHaveBeenCalledTimes(1);
expect(mocks.resolvePluginCapabilityProvider).toHaveBeenCalledWith({
key: "embeddingProviders",
providerId: "ollama",
cfg: undefined,
});
});
it("prefers registered adapters over declared capability fallback adapters with the same id", () => {
const registered = {
id: "openai",
create: async () => ({ provider: null }),
} satisfies EmbeddingProviderAdapter;
registerEmbeddingProvider({
...registered,
});
mocks.resolvePluginCapabilityProviders.mockReturnValue([createCapabilityAdapter("openai")]);
expect(runtimeModule.getEmbeddingProvider("openai")).toStrictEqual(registered);
expect(runtimeModule.listEmbeddingProviders().map((adapter) => adapter.id)).toEqual(["openai"]);
expect(mocks.resolvePluginCapabilityProviders).toHaveBeenCalledTimes(1);
});
});