Contracts: harden provider registry loading

This commit is contained in:
Vincent Koc
2026-03-18 01:30:05 -07:00
parent 25011bdb1e
commit d1ef7d64e9
3 changed files with 41 additions and 21 deletions

View File

@@ -1,15 +1,11 @@
import { ensureAuthProfileStore, listProfilesForProvider } from "openclaw/plugin-sdk/agent-runtime";
import {
definePluginEntry,
type ProviderAuthContext,
type ProviderResolveDynamicModelContext,
type ProviderRuntimeModel,
} from "openclaw/plugin-sdk/core";
import {
coerceSecretRef,
ensureAuthProfileStore,
githubCopilotLoginCommand,
listProfilesForProvider,
} from "openclaw/plugin-sdk/provider-auth";
import { coerceSecretRef, githubCopilotLoginCommand } from "openclaw/plugin-sdk/provider-auth";
import { normalizeModelCompat } from "openclaw/plugin-sdk/provider-models";
import { DEFAULT_COPILOT_API_BASE_URL, resolveCopilotApiToken } from "./token.js";
import { fetchCopilotUsage } from "./usage.js";

View File

@@ -1,7 +1,14 @@
import { describe } from "vitest";
import { providerContractRegistry } from "./registry.js";
import { describe, expect, it } from "vitest";
import { providerContractLoadError, providerContractRegistry } from "./registry.js";
import { installProviderPluginContractSuite } from "./suites.js";
describe("provider contract registry load", () => {
it("loads bundled providers without import-time registry failure", () => {
expect(providerContractLoadError).toBeUndefined();
expect(providerContractRegistry.length).toBeGreaterThan(0);
});
});
for (const entry of providerContractRegistry) {
describe(`${entry.pluginId}:${entry.provider.id} provider contract`, () => {
installProviderPluginContractSuite({

View File

@@ -99,19 +99,31 @@ export const providerContractRegistry: ProviderContractEntry[] = buildCapability
select: () => [],
});
const loadedBundledProviderRegistry: ProviderContractEntry[] = resolvePluginProviders({
bundledProviderAllowlistCompat: true,
bundledProviderVitestCompat: true,
cache: false,
activate: false,
})
.filter((provider): provider is ProviderPlugin & { pluginId: string } =>
Boolean(provider.pluginId),
)
.map((provider) => ({
pluginId: provider.pluginId,
provider,
}));
export let providerContractLoadError: Error | undefined;
function loadBundledProviderRegistry(): ProviderContractEntry[] {
try {
providerContractLoadError = undefined;
return resolvePluginProviders({
bundledProviderAllowlistCompat: true,
bundledProviderVitestCompat: true,
cache: false,
activate: false,
})
.filter((provider): provider is ProviderPlugin & { pluginId: string } =>
Boolean(provider.pluginId),
)
.map((provider) => ({
pluginId: provider.pluginId,
provider,
}));
} catch (error) {
providerContractLoadError = error instanceof Error ? error : new Error(String(error));
return [];
}
}
const loadedBundledProviderRegistry: ProviderContractEntry[] = loadBundledProviderRegistry();
providerContractRegistry.splice(
0,
@@ -134,6 +146,11 @@ export const providerContractCompatPluginIds = providerContractPluginIds.map((pl
export function requireProviderContractProvider(providerId: string): ProviderPlugin {
const provider = uniqueProviderContractProviders.find((entry) => entry.id === providerId);
if (!provider) {
if (providerContractLoadError) {
throw new Error(
`provider contract entry missing for ${providerId}; bundled provider registry failed to load: ${providerContractLoadError.message}`,
);
}
throw new Error(`provider contract entry missing for ${providerId}`);
}
return provider;