mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:50:43 +00:00
fix: keep live catalog providers on registry path
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"id": "chutes",
|
||||
"enabledByDefault": true,
|
||||
"providerDiscoveryEntry": "./provider-discovery.ts",
|
||||
"providers": ["chutes"],
|
||||
"providerAuthEnvVars": {
|
||||
"chutes": ["CHUTES_API_KEY", "CHUTES_OAUTH_TOKEN"]
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import type { ProviderPlugin } from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import { buildStaticChutesProvider } from "./provider-catalog.js";
|
||||
|
||||
export const chutesProviderDiscovery: ProviderPlugin = {
|
||||
id: "chutes",
|
||||
label: "Chutes",
|
||||
docsPath: "/providers/models",
|
||||
auth: [],
|
||||
staticCatalog: {
|
||||
order: "profile",
|
||||
run: async () => ({
|
||||
provider: buildStaticChutesProvider(),
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
export default chutesProviderDiscovery;
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"id": "kilocode",
|
||||
"enabledByDefault": true,
|
||||
"providerDiscoveryEntry": "./provider-discovery.ts",
|
||||
"providers": ["kilocode"],
|
||||
"providerAuthEnvVars": {
|
||||
"kilocode": ["KILOCODE_API_KEY"]
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import type { ProviderPlugin } from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import { buildKilocodeProvider } from "./provider-catalog.js";
|
||||
|
||||
export const kilocodeProviderDiscovery: ProviderPlugin = {
|
||||
id: "kilocode",
|
||||
label: "Kilo Code",
|
||||
docsPath: "/providers/models",
|
||||
auth: [],
|
||||
staticCatalog: {
|
||||
order: "simple",
|
||||
run: async () => ({
|
||||
provider: buildKilocodeProvider(),
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
export default kilocodeProviderDiscovery;
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"id": "vercel-ai-gateway",
|
||||
"enabledByDefault": true,
|
||||
"providerDiscoveryEntry": "./provider-discovery.ts",
|
||||
"providers": ["vercel-ai-gateway"],
|
||||
"providerAuthEnvVars": {
|
||||
"vercel-ai-gateway": ["AI_GATEWAY_API_KEY"]
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import type { ProviderPlugin } from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import { buildStaticVercelAiGatewayProvider } from "./provider-catalog.js";
|
||||
|
||||
export const vercelAiGatewayProviderDiscovery: ProviderPlugin = {
|
||||
id: "vercel-ai-gateway",
|
||||
label: "Vercel AI Gateway",
|
||||
docsPath: "/providers/models",
|
||||
auth: [],
|
||||
staticCatalog: {
|
||||
order: "simple",
|
||||
run: async () => ({
|
||||
provider: buildStaticVercelAiGatewayProvider(),
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
export default vercelAiGatewayProviderDiscovery;
|
||||
@@ -187,6 +187,18 @@ describe("loadProviderCatalogModelsForList", () => {
|
||||
);
|
||||
});
|
||||
|
||||
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",
|
||||
|
||||
@@ -84,6 +84,26 @@ describe("resolvePluginDiscoveryProvidersRuntime", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("falls back to full provider plugins for mixed live and static-only entries", () => {
|
||||
const fullProviders = [
|
||||
createProvider({ id: "codex", mode: "catalog" }),
|
||||
createProvider({ id: "deepseek", mode: "catalog" }),
|
||||
];
|
||||
mocks.resolveDiscoveredProviderPluginIds.mockReturnValue(["codex", "deepseek"]);
|
||||
mocks.loadPluginManifestRegistry.mockReturnValue({
|
||||
plugins: [createManifestPlugin("codex"), createManifestPlugin("deepseek")],
|
||||
diagnostics: [],
|
||||
});
|
||||
mocks.loadSource.mockImplementation((modulePath: string) =>
|
||||
modulePath.includes("/codex/")
|
||||
? createProvider({ id: "codex", mode: "catalog" })
|
||||
: createProvider({ id: "deepseek", mode: "static" }),
|
||||
);
|
||||
mocks.resolvePluginProviders.mockReturnValue(fullProviders);
|
||||
|
||||
expect(resolvePluginDiscoveryProvidersRuntime({})).toEqual(fullProviders);
|
||||
});
|
||||
|
||||
it("returns static-only discovery entries for callers that explicitly request them", () => {
|
||||
const staticProvider = createProvider({ id: "deepseek", mode: "static" });
|
||||
mocks.loadSource.mockReturnValue(staticProvider);
|
||||
|
||||
@@ -14,6 +14,11 @@ type ProviderDiscoveryModule =
|
||||
provider?: ProviderPlugin;
|
||||
};
|
||||
|
||||
type ProviderDiscoveryEntryResult = {
|
||||
providers: ProviderPlugin[];
|
||||
complete: boolean;
|
||||
};
|
||||
|
||||
function normalizeDiscoveryModule(value: ProviderDiscoveryModule): ProviderPlugin[] {
|
||||
const resolved =
|
||||
value && typeof value === "object" && "default" in value && value.default !== undefined
|
||||
@@ -51,17 +56,18 @@ function resolveProviderDiscoveryEntryPlugins(params: {
|
||||
includeUntrustedWorkspacePlugins?: boolean;
|
||||
requireCompleteDiscoveryEntryCoverage?: boolean;
|
||||
discoveryEntriesOnly?: boolean;
|
||||
}): ProviderPlugin[] {
|
||||
}): ProviderDiscoveryEntryResult {
|
||||
const pluginIds = resolveDiscoveredProviderPluginIds(params);
|
||||
const pluginIdSet = new Set(pluginIds);
|
||||
const records = loadPluginManifestRegistry(params).plugins.filter(
|
||||
(plugin) => plugin.providerDiscoverySource && pluginIdSet.has(plugin.id),
|
||||
);
|
||||
if (records.length === 0) {
|
||||
return [];
|
||||
return { providers: [], complete: false };
|
||||
}
|
||||
if (params.requireCompleteDiscoveryEntryCoverage && records.length < pluginIdSet.size) {
|
||||
return [];
|
||||
const complete = records.length === pluginIdSet.size;
|
||||
if (params.requireCompleteDiscoveryEntryCoverage && !complete) {
|
||||
return { providers: [], complete: false };
|
||||
}
|
||||
const loadSource = createPluginSourceLoader();
|
||||
const providers: ProviderPlugin[] = [];
|
||||
@@ -76,10 +82,10 @@ function resolveProviderDiscoveryEntryPlugins(params: {
|
||||
} catch {
|
||||
// Discovery fast path is optional. Fall back to the full plugin loader
|
||||
// below so existing plugin diagnostics/load behavior remains canonical.
|
||||
return [];
|
||||
return { providers: [], complete: false };
|
||||
}
|
||||
}
|
||||
return providers;
|
||||
return { providers, complete };
|
||||
}
|
||||
|
||||
export function resolvePluginDiscoveryProvidersRuntime(params: {
|
||||
@@ -91,13 +97,16 @@ export function resolvePluginDiscoveryProvidersRuntime(params: {
|
||||
requireCompleteDiscoveryEntryCoverage?: boolean;
|
||||
discoveryEntriesOnly?: boolean;
|
||||
}): ProviderPlugin[] {
|
||||
const entryProviders = resolveProviderDiscoveryEntryPlugins(params);
|
||||
const entryResult = resolveProviderDiscoveryEntryPlugins(params);
|
||||
if (params.discoveryEntriesOnly === true) {
|
||||
return entryProviders;
|
||||
return entryResult.providers;
|
||||
}
|
||||
const liveEntryProviders = entryProviders.filter(hasLiveProviderDiscoveryHook);
|
||||
if (liveEntryProviders.length > 0) {
|
||||
return liveEntryProviders;
|
||||
if (
|
||||
entryResult.complete &&
|
||||
entryResult.providers.length > 0 &&
|
||||
entryResult.providers.every(hasLiveProviderDiscoveryHook)
|
||||
) {
|
||||
return entryResult.providers;
|
||||
}
|
||||
return resolvePluginProviders({
|
||||
...params,
|
||||
|
||||
Reference in New Issue
Block a user