Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
import { beforeEach, describe, expect, it, vi } from "vitest";
import {
hasProviderStaticCatalogForFilter,
loadProviderCatalogModelsForList,
resolveProviderCatalogPluginIdsForFilter,
} from "./list.provider-catalog.js";
const providerDiscoveryMocks = vi.hoisted(() => ({
resolveBundledProviderCompatPluginIds: vi.fn(),
resolveOwningPluginIdsForProvider: vi.fn(),
resolvePluginDiscoveryProviders: vi.fn(),
resolveProviderContractPluginIdsForProviderAlias: vi.fn(),
}));
vi.mock("../../plugins/providers.js", () => ({
resolveBundledProviderCompatPluginIds:
providerDiscoveryMocks.resolveBundledProviderCompatPluginIds,
resolveOwningPluginIdsForProvider: providerDiscoveryMocks.resolveOwningPluginIdsF orProvider,
}));
vi.mock("../../plugins/contracts/registry.js", () => ({
resolveProviderContractPluginIdsForProviderAlias:
providerDiscoveryMocks.resolveProviderContractPluginIdsForProviderAlias,
}));
vi.mock("../../plugins/provider-discovery.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../plugins/provider-discovery.js")>();
return {
...actual,
resolvePluginDiscoveryProviders: providerDiscoveryMocks.resolvePluginDiscoveryProviders,
};
});
const baseParams = {
cfg: {
plugins: {
entries: {
chutes: { enabled: true },
moonshot: { enabled: true },
},
},
},
agentDir: "/tmp/openclaw-provider-catalog-test",
env: {
...process.env,
CHUTES_API_KEY: "",
MOONSHOT_API_KEY: "",
},
};
const chutesProvider = {
id: "chutes",
pluginId: "chutes",
label: "Chutes",
auth: [],
staticCatalog: {
run: async () => ({
provider: { baseUrl: "https://chutes.example/v1", models: [] },
}),
},
};
const moonshotProvider = {
id: "moonshot",
pluginId: "moonshot",
label: "Moonshot",
auth: [],
staticCatalog: {
run: async () => ({
provider: {
baseUrl: "https://api.moonshot.ai/v1",
models: [{ id: "kimi-k2.6", name: "Kimi K2.6" }],
},
}),
},
};
const openaiProvider = {
id: "openai",
pluginId: "openai",
label: "OpenAI",
aliases: ["azure-openai-responses"],
auth: [],
staticCatalog: {
run: async () => ({
provider: { baseUrl: "https://api.openai.com/v1", models: [] },
}),
},
};
const catalogOnlyProvider = {
id: "ollama",
pluginId: "ollama",
label: "Ollama",
auth: [],
catalog: {
run: async () => ({
provider: { baseUrl: "http://127.0.0.1:11434", models: [] },
}),
},
};
const defaultProviders = [chutesProvider, moonshotProvider, openaiProvider];
describe("loadProviderCatalogModelsForList", () => {
beforeEach(() => {
vi.clearAllMocks();
providerDiscoveryMocks.resolveBundledProviderCompatPluginIds.mockReturnValue([
"chutes",
"moonshot",
"openai",
"ollama",
]);
providerDiscoveryMocks.resolveOwningPluginIdsForProvider.mockImplementation(
({ provider }: { provider: string }) =>
[...defaultProviders, catalogOnlyProvider].some((entry) => entry.id === provider)
? [provider]
: undefined,
);
providerDiscoveryMocks.resolveProviderContractPluginIdsForProviderAlias.mockImplementation(
(provider: string) => (provider === "azure-openai-responses" ? ["openai"] : undefined),
);
providerDiscoveryMocks.resolvePluginDiscoveryProviders.mockImplementation(
async ({ onlyPluginIds }: { onlyPluginIds?: string[] }) =>
defaultProviders.filter((provider) => onlyPluginIds?.includes(provider.pluginId)),
);
});
it("does not use live provider discovery for display-only rows", async () => {
const fetchMock = vi.spyOn(globalThis, "fetch").mockRejectedValue(new Error("blocked fetch"));
await loadProviderCatalogModelsForList({
...baseParams,
providerFilter: "chutes",
});
expect(fetchMock).not.toHaveBeenCalled();
});
it("includes unauthenticated Moonshot static catalog rows", async () => {
const fetchMock = vi.spyOn(globalThis, "fetch").mockRejectedValue(new Error("blocked fetch"));
const rows = await loadProviderCatalogModelsForList({
...baseParams,
providerFilter: "moonshot",
});
expect(fetchMock).not.toHaveBeenCalled();
expect(rows.map((row) => `${row.provider}/${row.id}`)).toEqual(
expect.arrayContaining(["moonshot/kimi-k2.6"]),
);
});
it("requires complete discovery-entry coverage for static-only loads", async () => {
await loadProviderCatalogModelsForList({
...baseParams,
providerFilter: "moonshot",
staticOnly: true,
});
expect(providerDiscoveryMocks.resolvePluginDiscoveryProviders).toHaveBeenCalledWith(
expect.objectContaining({
onlyPluginIds: ["moonshot"],
requireCompleteDiscoveryEntryCoverage: true,
discoveryEntriesOnly: true,
}),
);
});
it("returns an empty catalog when a static provider catalog throws", async () => {
providerDiscoveryMocks.resolvePluginDiscoveryProviders.mockResolvedValueOnce([
{
id: "moonshot",
pluginId: "moonshot",
label: "Moonshot",
auth: [],
staticCatalog: {
run: async () => {
throw new Error("catalog offline");
},
},
},
]);
await expect(
loadProviderCatalogModelsForList({
...baseParams,
providerFilter: "moonshot",
staticOnly: true,
}),
).resolves.toEqual([]);
});
it("only skips registry for providers with actual static catalogs", async () => {
providerDiscoveryMocks.resolvePluginDiscoveryProviders.mockResolvedValue([catalogOnlyProvider]);
await expect(
hasProviderStaticCatalogForFilter({
cfg: baseParams.cfg,
env: baseParams.env,
providerFilter: "ollama",
}),
).resolves.toBe(false);
expect(providerDiscoveryMocks.resolvePluginDiscoveryProviders).toHaveBeenCalledWith(
expect.objectContaining({
onlyPluginIds: ["ollama"],
requireCompleteDiscoveryEntryCoverage: true,
discoveryEntriesOnly: true,
}),
);
});
it("does not skip registry when a bundled provider has no lightweight static entry", async () => {
providerDiscoveryMocks.resolvePluginDiscoveryProviders.mockResolvedValueOnce([]);
await expect(
hasProviderStaticCatalogForFilter({
cfg: baseParams.cfg,
env: baseParams.env,
providerFilter: "chutes",
}),
).resolves.toBe(false);
});
it("does not skip registry for non-bundled static catalog owners", async () => {
providerDiscoveryMocks.resolveOwningPluginIdsForProvider.mockReturnValueOnce([
"workspace-static-provider",
]);
providerDiscoveryMocks.resolveBundledProviderCompatPluginIds.mockReturnValueOnce(["moonshot"]);
await expect(
hasProviderStaticCatalogForFilter({
cfg: baseParams.cfg,
env: baseParams.env,
providerFilter: "workspace-static-provider",
}),
).resolves.toBe(false);
expect(providerDiscoveryMocks.resolvePluginDiscoveryProviders).not.toHaveBeenCalled();
});
it("recognizes bundled provider hook aliases before the unknown-provider short-circuit", async () => {
await expect(
resolveProviderCatalogPluginIdsForFilter({
cfg: baseParams.cfg,
env: baseParams.env,
providerFilter: "azure-openai-responses",
}),
).resolves.toEqual(["openai"]);
});
it("does not execute workspace provider static catalogs", async () => {
const workspaceStaticCatalog = vi.fn(async () => ({
provider: { baseUrl: "https://workspace.example/v1", models: [] },
}));
providerDiscoveryMocks.resolveBundledProviderCompatPluginIds.mockReturnValue(["bundled-demo"]);
providerDiscoveryMocks.resolvePluginDiscoveryProviders.mockResolvedValue([
{
id: "bundled-demo",
pluginId: "bundled-demo",
label: "Bundled Demo",
auth: [],
staticCatalog: {
run: async () => null,
},
},
{
id: "workspace-demo",
pluginId: "workspace-demo",
label: "Workspace Demo",
auth: [],
staticCatalog: {
run: workspaceStaticCatalog,
},
},
]);
const rows = await loadProviderCatalogModelsForList({
...baseParams,
});
expect(providerDiscoveryMocks.resolvePluginDiscoveryProviders).toHaveBeenCalledWith(
expect.objectContaining({
onlyPluginIds: ["bundled-demo"],
includeUntrustedWorkspacePlugins: false,
}),
);
expect(workspaceStaticCatalog).not.toHaveBeenCalled();
expect(rows).toEqual([]);
});
it("keeps unknown provider filters eligible for early empty results", async () => {
await expect(
resolveProviderCatalogPluginIdsForFilter({
cfg: baseParams.cfg,
env: baseParams.env,
providerFilter: "unknown-provider-for-catalog-test",
}),
).resolves.toBeUndefined();
});
});
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet am 2026-04-27)
¤
*© Formatika GbR, Deutschland
|
|