mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-31 11:51:22 +00:00
Plugins: share runtime registry resolution
This commit is contained in:
@@ -1,26 +1,23 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const hoisted = vi.hoisted(() => ({
|
||||
loadOpenClawPlugins: vi.fn(),
|
||||
getCompatibleActivePluginRegistry: vi.fn(),
|
||||
resolveRuntimePluginRegistry: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/loader.js", () => ({
|
||||
loadOpenClawPlugins: hoisted.loadOpenClawPlugins,
|
||||
getCompatibleActivePluginRegistry: hoisted.getCompatibleActivePluginRegistry,
|
||||
resolveRuntimePluginRegistry: hoisted.resolveRuntimePluginRegistry,
|
||||
}));
|
||||
|
||||
describe("ensureRuntimePluginsLoaded", () => {
|
||||
beforeEach(() => {
|
||||
hoisted.loadOpenClawPlugins.mockReset();
|
||||
hoisted.getCompatibleActivePluginRegistry.mockReset();
|
||||
hoisted.getCompatibleActivePluginRegistry.mockReturnValue(undefined);
|
||||
hoisted.resolveRuntimePluginRegistry.mockReset();
|
||||
hoisted.resolveRuntimePluginRegistry.mockReturnValue(undefined);
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
it("does not reactivate plugins when a process already has an active registry", async () => {
|
||||
const { ensureRuntimePluginsLoaded } = await import("./runtime-plugins.js");
|
||||
hoisted.getCompatibleActivePluginRegistry.mockReturnValue({});
|
||||
hoisted.resolveRuntimePluginRegistry.mockReturnValue({});
|
||||
|
||||
ensureRuntimePluginsLoaded({
|
||||
config: {} as never,
|
||||
@@ -28,10 +25,10 @@ describe("ensureRuntimePluginsLoaded", () => {
|
||||
allowGatewaySubagentBinding: true,
|
||||
});
|
||||
|
||||
expect(hoisted.loadOpenClawPlugins).not.toHaveBeenCalled();
|
||||
expect(hoisted.resolveRuntimePluginRegistry).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("loads runtime plugins when no compatible active registry exists", async () => {
|
||||
it("resolves runtime plugins through the shared runtime helper", async () => {
|
||||
const { ensureRuntimePluginsLoaded } = await import("./runtime-plugins.js");
|
||||
|
||||
ensureRuntimePluginsLoaded({
|
||||
@@ -40,7 +37,7 @@ describe("ensureRuntimePluginsLoaded", () => {
|
||||
allowGatewaySubagentBinding: true,
|
||||
});
|
||||
|
||||
expect(hoisted.loadOpenClawPlugins).toHaveBeenCalledWith({
|
||||
expect(hoisted.resolveRuntimePluginRegistry).toHaveBeenCalledWith({
|
||||
config: {} as never,
|
||||
workspaceDir: "/tmp/workspace",
|
||||
runtimeOptions: {
|
||||
@@ -58,13 +55,13 @@ describe("ensureRuntimePluginsLoaded", () => {
|
||||
allowGatewaySubagentBinding: true,
|
||||
});
|
||||
|
||||
expect(hoisted.getCompatibleActivePluginRegistry).toHaveBeenCalledWith({
|
||||
expect(hoisted.resolveRuntimePluginRegistry).toHaveBeenCalledWith({
|
||||
config: {} as never,
|
||||
workspaceDir: "/tmp/workspace",
|
||||
runtimeOptions: {
|
||||
allowGatewaySubagentBinding: true,
|
||||
},
|
||||
});
|
||||
expect(hoisted.loadOpenClawPlugins).toHaveBeenCalledTimes(1);
|
||||
expect(hoisted.resolveRuntimePluginRegistry).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { getCompatibleActivePluginRegistry, loadOpenClawPlugins } from "../plugins/loader.js";
|
||||
import { resolveRuntimePluginRegistry } from "../plugins/loader.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
|
||||
export function ensureRuntimePluginsLoaded(params: {
|
||||
@@ -20,8 +20,5 @@ export function ensureRuntimePluginsLoaded(params: {
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
if (getCompatibleActivePluginRegistry(loadOptions)) {
|
||||
return;
|
||||
}
|
||||
loadOpenClawPlugins(loadOptions);
|
||||
resolveRuntimePluginRegistry(loadOptions);
|
||||
}
|
||||
|
||||
@@ -2,16 +2,14 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createEmptyPluginRegistry } from "../plugins/registry.js";
|
||||
import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "../plugins/runtime.js";
|
||||
|
||||
const { loadOpenClawPluginsMock, getCompatibleActivePluginRegistryMock } = vi.hoisted(() => ({
|
||||
loadOpenClawPluginsMock: vi.fn(() => createEmptyPluginRegistry()),
|
||||
getCompatibleActivePluginRegistryMock: vi.fn<
|
||||
const { resolveRuntimePluginRegistryMock } = vi.hoisted(() => ({
|
||||
resolveRuntimePluginRegistryMock: vi.fn<
|
||||
(params?: unknown) => ReturnType<typeof createEmptyPluginRegistry> | undefined
|
||||
>(() => undefined),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/loader.js", () => ({
|
||||
loadOpenClawPlugins: loadOpenClawPluginsMock,
|
||||
getCompatibleActivePluginRegistry: getCompatibleActivePluginRegistryMock,
|
||||
resolveRuntimePluginRegistry: resolveRuntimePluginRegistryMock,
|
||||
}));
|
||||
|
||||
let getImageGenerationProvider: typeof import("./provider-registry.js").getImageGenerationProvider;
|
||||
@@ -19,10 +17,8 @@ let listImageGenerationProviders: typeof import("./provider-registry.js").listIm
|
||||
|
||||
describe("image-generation provider registry", () => {
|
||||
afterEach(() => {
|
||||
loadOpenClawPluginsMock.mockReset();
|
||||
loadOpenClawPluginsMock.mockReturnValue(createEmptyPluginRegistry());
|
||||
getCompatibleActivePluginRegistryMock.mockReset();
|
||||
getCompatibleActivePluginRegistryMock.mockReturnValue(undefined);
|
||||
resolveRuntimePluginRegistryMock.mockReset();
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue(undefined);
|
||||
resetPluginRuntimeStateForTest();
|
||||
});
|
||||
|
||||
@@ -34,7 +30,7 @@ describe("image-generation provider registry", () => {
|
||||
|
||||
it("does not load plugins when listing without config", () => {
|
||||
expect(listImageGenerationProviders()).toEqual([]);
|
||||
expect(loadOpenClawPluginsMock).not.toHaveBeenCalled();
|
||||
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith(undefined);
|
||||
});
|
||||
|
||||
it("uses active plugin providers without loading from disk", () => {
|
||||
@@ -56,12 +52,12 @@ describe("image-generation provider registry", () => {
|
||||
},
|
||||
});
|
||||
setActivePluginRegistry(registry);
|
||||
getCompatibleActivePluginRegistryMock.mockReturnValue(registry);
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue(registry);
|
||||
|
||||
const provider = getImageGenerationProvider("custom-image");
|
||||
|
||||
expect(provider?.id).toBe("custom-image");
|
||||
expect(loadOpenClawPluginsMock).not.toHaveBeenCalled();
|
||||
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith(undefined);
|
||||
});
|
||||
|
||||
it("ignores prototype-like provider ids and aliases", () => {
|
||||
@@ -101,7 +97,7 @@ describe("image-generation provider registry", () => {
|
||||
},
|
||||
);
|
||||
setActivePluginRegistry(registry);
|
||||
getCompatibleActivePluginRegistryMock.mockReturnValue(registry);
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue(registry);
|
||||
|
||||
expect(listImageGenerationProviders().map((provider) => provider.id)).toEqual(["safe-image"]);
|
||||
expect(getImageGenerationProvider("__proto__")).toBeUndefined();
|
||||
|
||||
@@ -13,8 +13,7 @@ function createEmptyMockManifestRegistry(): MockManifestRegistry {
|
||||
}
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
loadOpenClawPlugins: vi.fn(() => createEmptyPluginRegistry()),
|
||||
getCompatibleActivePluginRegistry: vi.fn<
|
||||
resolveRuntimePluginRegistry: vi.fn<
|
||||
(params?: unknown) => ReturnType<typeof createEmptyPluginRegistry> | undefined
|
||||
>(() => undefined),
|
||||
loadPluginManifestRegistry: vi.fn<() => MockManifestRegistry>(() =>
|
||||
@@ -26,8 +25,7 @@ const mocks = vi.hoisted(() => ({
|
||||
}));
|
||||
|
||||
vi.mock("./loader.js", () => ({
|
||||
loadOpenClawPlugins: mocks.loadOpenClawPlugins,
|
||||
getCompatibleActivePluginRegistry: mocks.getCompatibleActivePluginRegistry,
|
||||
resolveRuntimePluginRegistry: mocks.resolveRuntimePluginRegistry,
|
||||
}));
|
||||
|
||||
vi.mock("./manifest-registry.js", () => ({
|
||||
@@ -73,7 +71,7 @@ function expectBundledCompatLoadPath(params: {
|
||||
pluginIds: ["openai"],
|
||||
env: process.env,
|
||||
});
|
||||
expect(mocks.loadOpenClawPlugins).toHaveBeenCalledWith({
|
||||
expect(mocks.resolveRuntimePluginRegistry).toHaveBeenCalledWith({
|
||||
config: params.enablementCompat,
|
||||
});
|
||||
}
|
||||
@@ -112,10 +110,8 @@ describe("resolvePluginCapabilityProviders", () => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
resetPluginRuntimeStateForTest();
|
||||
mocks.loadOpenClawPlugins.mockReset();
|
||||
mocks.loadOpenClawPlugins.mockReturnValue(createEmptyPluginRegistry());
|
||||
mocks.getCompatibleActivePluginRegistry.mockReset();
|
||||
mocks.getCompatibleActivePluginRegistry.mockReturnValue(undefined);
|
||||
mocks.resolveRuntimePluginRegistry.mockReset();
|
||||
mocks.resolveRuntimePluginRegistry.mockReturnValue(undefined);
|
||||
mocks.loadPluginManifestRegistry.mockReset();
|
||||
mocks.loadPluginManifestRegistry.mockReturnValue(createEmptyMockManifestRegistry());
|
||||
mocks.withBundledPluginAllowlistCompat.mockReset();
|
||||
@@ -145,13 +141,13 @@ describe("resolvePluginCapabilityProviders", () => {
|
||||
}),
|
||||
},
|
||||
});
|
||||
mocks.getCompatibleActivePluginRegistry.mockReturnValue(active);
|
||||
mocks.resolveRuntimePluginRegistry.mockReturnValue(active);
|
||||
|
||||
const providers = resolvePluginCapabilityProviders({ key: "speechProviders" });
|
||||
|
||||
expectResolvedCapabilityProviderIds(providers, ["openai"]);
|
||||
expect(mocks.loadPluginManifestRegistry).not.toHaveBeenCalled();
|
||||
expect(mocks.loadOpenClawPlugins).not.toHaveBeenCalled();
|
||||
expect(mocks.resolveRuntimePluginRegistry).toHaveBeenCalledWith(undefined);
|
||||
});
|
||||
|
||||
it.each([
|
||||
@@ -176,7 +172,7 @@ describe("resolvePluginCapabilityProviders", () => {
|
||||
|
||||
it("reuses a compatible active registry even when the capability list is empty", () => {
|
||||
const active = createEmptyPluginRegistry();
|
||||
mocks.getCompatibleActivePluginRegistry.mockReturnValue(active);
|
||||
mocks.resolveRuntimePluginRegistry.mockReturnValue(active);
|
||||
|
||||
const providers = resolvePluginCapabilityProviders({
|
||||
key: "mediaUnderstandingProviders",
|
||||
@@ -184,6 +180,8 @@ describe("resolvePluginCapabilityProviders", () => {
|
||||
});
|
||||
|
||||
expect(providers).toEqual([]);
|
||||
expect(mocks.loadOpenClawPlugins).not.toHaveBeenCalled();
|
||||
expect(mocks.resolveRuntimePluginRegistry).toHaveBeenCalledWith({
|
||||
config: expect.anything(),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
withBundledPluginEnablementCompat,
|
||||
withBundledPluginVitestCompat,
|
||||
} from "./bundled-compat.js";
|
||||
import { getCompatibleActivePluginRegistry, loadOpenClawPlugins } from "./loader.js";
|
||||
import { resolveRuntimePluginRegistry } from "./loader.js";
|
||||
import { loadPluginManifestRegistry } from "./manifest-registry.js";
|
||||
import type { PluginRegistry } from "./registry.js";
|
||||
|
||||
@@ -73,10 +73,7 @@ export function resolvePluginCapabilityProviders<K extends CapabilityProviderReg
|
||||
: {
|
||||
config: resolveCapabilityProviderConfig({ key: params.key, cfg: params.cfg }),
|
||||
};
|
||||
const registry =
|
||||
(loadOptions ? getCompatibleActivePluginRegistry(loadOptions) : undefined) ??
|
||||
(loadOptions ? loadOpenClawPlugins(loadOptions) : undefined) ??
|
||||
getCompatibleActivePluginRegistry();
|
||||
const registry = resolveRuntimePluginRegistry(loadOptions);
|
||||
return (registry?.[params.key] ?? []).map(
|
||||
(entry) => entry.provider,
|
||||
) as CapabilityProviderForKey<K>[];
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
clearPluginLoaderCache,
|
||||
getCompatibleActivePluginRegistry,
|
||||
loadOpenClawPlugins,
|
||||
resolveRuntimePluginRegistry,
|
||||
resolvePluginLoadCacheContext,
|
||||
} from "./loader.js";
|
||||
import { clearPluginManifestRegistryCache } from "./manifest-registry.js";
|
||||
@@ -3594,6 +3595,31 @@ describe("getCompatibleActivePluginRegistry", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveRuntimePluginRegistry", () => {
|
||||
it("reuses the compatible active registry before attempting a fresh load", () => {
|
||||
const registry = createEmptyPluginRegistry();
|
||||
const loadOptions = {
|
||||
config: {
|
||||
plugins: {
|
||||
allow: ["demo"],
|
||||
},
|
||||
},
|
||||
workspaceDir: "/tmp/workspace-a",
|
||||
};
|
||||
const { cacheKey } = resolvePluginLoadCacheContext(loadOptions);
|
||||
setActivePluginRegistry(registry, cacheKey);
|
||||
|
||||
expect(resolveRuntimePluginRegistry(loadOptions)).toBe(registry);
|
||||
});
|
||||
|
||||
it("falls back to the current active runtime when no explicit load context is provided", () => {
|
||||
const registry = createEmptyPluginRegistry();
|
||||
setActivePluginRegistry(registry, "startup-registry");
|
||||
|
||||
expect(resolveRuntimePluginRegistry()).toBe(registry);
|
||||
});
|
||||
});
|
||||
|
||||
describe("clearPluginLoaderCache", () => {
|
||||
it("resets registered memory plugin registries", () => {
|
||||
registerMemoryEmbeddingProvider({
|
||||
|
||||
@@ -317,6 +317,15 @@ export function getCompatibleActivePluginRegistry(
|
||||
: undefined;
|
||||
}
|
||||
|
||||
export function resolveRuntimePluginRegistry(
|
||||
options?: PluginLoadOptions,
|
||||
): PluginRegistry | undefined {
|
||||
if (!options || !hasExplicitCompatibilityInputs(options)) {
|
||||
return getCompatibleActivePluginRegistry();
|
||||
}
|
||||
return getCompatibleActivePluginRegistry(options) ?? loadOpenClawPlugins(options);
|
||||
}
|
||||
|
||||
function validatePluginConfig(params: {
|
||||
schema?: Record<string, unknown>;
|
||||
cacheKey?: string;
|
||||
|
||||
@@ -8,13 +8,11 @@ type MockRegistryToolEntry = {
|
||||
};
|
||||
|
||||
const loadOpenClawPluginsMock = vi.fn();
|
||||
const getCompatibleActivePluginRegistryMock = vi.fn();
|
||||
const resolveRuntimePluginRegistryMock = vi.fn();
|
||||
const applyPluginAutoEnableMock = vi.fn();
|
||||
|
||||
vi.mock("./loader.js", () => ({
|
||||
loadOpenClawPlugins: (params: unknown) => loadOpenClawPluginsMock(params),
|
||||
getCompatibleActivePluginRegistry: (params: unknown) =>
|
||||
getCompatibleActivePluginRegistryMock(params),
|
||||
resolveRuntimePluginRegistry: (params: unknown) => resolveRuntimePluginRegistryMock(params),
|
||||
}));
|
||||
|
||||
vi.mock("../config/plugin-auto-enable.js", () => ({
|
||||
@@ -137,8 +135,10 @@ describe("resolvePluginTools optional tools", () => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
loadOpenClawPluginsMock.mockClear();
|
||||
getCompatibleActivePluginRegistryMock.mockReset();
|
||||
getCompatibleActivePluginRegistryMock.mockReturnValue(undefined);
|
||||
resolveRuntimePluginRegistryMock.mockReset();
|
||||
resolveRuntimePluginRegistryMock.mockImplementation((params) =>
|
||||
loadOpenClawPluginsMock(params),
|
||||
);
|
||||
applyPluginAutoEnableMock.mockReset();
|
||||
applyPluginAutoEnableMock.mockImplementation(({ config }: { config: unknown }) => ({
|
||||
config,
|
||||
@@ -317,7 +317,7 @@ describe("resolvePluginTools optional tools", () => {
|
||||
],
|
||||
diagnostics: [],
|
||||
};
|
||||
getCompatibleActivePluginRegistryMock.mockReturnValue(activeRegistry);
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue(activeRegistry);
|
||||
|
||||
const tools = resolvePluginTools(
|
||||
createResolveToolsParams({
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { AnyAgentTool } from "../agents/tools/common.js";
|
||||
import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { applyTestPluginDefaults, normalizePluginsConfig } from "./config-state.js";
|
||||
import { getCompatibleActivePluginRegistry, loadOpenClawPlugins } from "./loader.js";
|
||||
import { resolveRuntimePluginRegistry } from "./loader.js";
|
||||
import { createPluginLoaderLogger } from "./logger.js";
|
||||
import type { OpenClawPluginToolContext } from "./types.js";
|
||||
|
||||
@@ -79,8 +79,10 @@ export function resolvePluginTools(params: {
|
||||
env,
|
||||
logger: createPluginLoaderLogger(log),
|
||||
};
|
||||
const registry =
|
||||
getCompatibleActivePluginRegistry(loadOptions) ?? loadOpenClawPlugins(loadOptions);
|
||||
const registry = resolveRuntimePluginRegistry(loadOptions);
|
||||
if (!registry) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const tools: AnyAgentTool[] = [];
|
||||
const existing = params.existingToolNames ?? new Set<string>();
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
resolvePluginSnapshotCacheTtlMs,
|
||||
shouldUsePluginSnapshotCache,
|
||||
} from "./cache-controls.js";
|
||||
import { getCompatibleActivePluginRegistry, loadOpenClawPlugins } from "./loader.js";
|
||||
import { loadOpenClawPlugins, resolveRuntimePluginRegistry } from "./loader.js";
|
||||
import type { PluginLoadOptions } from "./loader.js";
|
||||
import { createPluginLoaderLogger } from "./logger.js";
|
||||
import { loadPluginManifestRegistry, type PluginManifestRecord } from "./manifest-registry.js";
|
||||
@@ -202,10 +202,9 @@ export function resolveRuntimeWebSearchProviders(params: {
|
||||
bundledAllowlistCompat?: boolean;
|
||||
onlyPluginIds?: readonly string[];
|
||||
}): PluginWebSearchProviderEntry[] {
|
||||
const runtimeRegistry =
|
||||
params.config === undefined
|
||||
? getCompatibleActivePluginRegistry()
|
||||
: getCompatibleActivePluginRegistry(resolveWebSearchLoadOptions(params));
|
||||
const runtimeRegistry = resolveRuntimePluginRegistry(
|
||||
params.config === undefined ? undefined : resolveWebSearchLoadOptions(params),
|
||||
);
|
||||
if (runtimeRegistry) {
|
||||
return mapRegistryWebSearchProviders({
|
||||
registry: runtimeRegistry,
|
||||
|
||||
@@ -4,15 +4,11 @@ import { createEmptyPluginRegistry } from "../plugins/registry-empty.js";
|
||||
import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "../plugins/runtime.js";
|
||||
import type { SpeechProviderPlugin } from "../plugins/types.js";
|
||||
|
||||
const loadOpenClawPluginsMock = vi.fn();
|
||||
const getCompatibleActivePluginRegistryMock = vi.fn();
|
||||
const resolveRuntimePluginRegistryMock = vi.fn();
|
||||
|
||||
vi.mock("../plugins/loader.js", () => ({
|
||||
loadOpenClawPlugins: (...args: Parameters<typeof loadOpenClawPluginsMock>) =>
|
||||
loadOpenClawPluginsMock(...args),
|
||||
getCompatibleActivePluginRegistry: (
|
||||
...args: Parameters<typeof getCompatibleActivePluginRegistryMock>
|
||||
) => getCompatibleActivePluginRegistryMock(...args),
|
||||
resolveRuntimePluginRegistry: (...args: Parameters<typeof resolveRuntimePluginRegistryMock>) =>
|
||||
resolveRuntimePluginRegistryMock(...args),
|
||||
}));
|
||||
|
||||
let getSpeechProvider: typeof import("./provider-registry.js").getSpeechProvider;
|
||||
@@ -39,10 +35,8 @@ describe("speech provider registry", () => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
resetPluginRuntimeStateForTest();
|
||||
loadOpenClawPluginsMock.mockReset();
|
||||
loadOpenClawPluginsMock.mockReturnValue(createEmptyPluginRegistry());
|
||||
getCompatibleActivePluginRegistryMock.mockReset();
|
||||
getCompatibleActivePluginRegistryMock.mockReturnValue(undefined);
|
||||
resolveRuntimePluginRegistryMock.mockReset();
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue(undefined);
|
||||
({
|
||||
getSpeechProvider,
|
||||
listSpeechProviders,
|
||||
@@ -66,7 +60,7 @@ describe("speech provider registry", () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
getCompatibleActivePluginRegistryMock.mockReturnValue({
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue({
|
||||
...createEmptyPluginRegistry(),
|
||||
speechProviders: [
|
||||
{
|
||||
@@ -79,11 +73,11 @@ describe("speech provider registry", () => {
|
||||
const providers = listSpeechProviders();
|
||||
|
||||
expect(providers.map((provider) => provider.id)).toEqual(["demo-speech"]);
|
||||
expect(loadOpenClawPluginsMock).not.toHaveBeenCalled();
|
||||
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith(undefined);
|
||||
});
|
||||
|
||||
it("loads speech providers from plugins when config is provided", () => {
|
||||
loadOpenClawPluginsMock.mockReturnValue({
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue({
|
||||
...createEmptyPluginRegistry(),
|
||||
speechProviders: [
|
||||
{
|
||||
@@ -98,7 +92,7 @@ describe("speech provider registry", () => {
|
||||
|
||||
expect(listSpeechProviders(cfg).map((provider) => provider.id)).toEqual(["microsoft"]);
|
||||
expect(getSpeechProvider("edge", cfg)?.id).toBe("microsoft");
|
||||
expect(loadOpenClawPluginsMock).toHaveBeenCalledWith({
|
||||
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith({
|
||||
config: {
|
||||
plugins: {
|
||||
entries: {
|
||||
@@ -114,6 +108,7 @@ describe("speech provider registry", () => {
|
||||
it("returns no providers when neither plugins nor active registry provide speech support", () => {
|
||||
expect(listSpeechProviders()).toEqual([]);
|
||||
expect(getSpeechProvider("demo-speech")).toBeUndefined();
|
||||
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith(undefined);
|
||||
});
|
||||
|
||||
it("canonicalizes the legacy edge alias to microsoft", () => {
|
||||
@@ -127,7 +122,7 @@ describe("speech provider registry", () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
getCompatibleActivePluginRegistryMock.mockReturnValue({
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue({
|
||||
...createEmptyPluginRegistry(),
|
||||
speechProviders: [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user