mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 07:10:43 +00:00
fix: preserve external auth hook compatibility
This commit is contained in:
@@ -22,12 +22,20 @@ type IsPluginProvidersLoadInFlight =
|
||||
typeof import("./providers.runtime.js").isPluginProvidersLoadInFlight;
|
||||
type ResolveCatalogHookProviderPluginIds =
|
||||
typeof import("./providers.js").resolveCatalogHookProviderPluginIds;
|
||||
type ResolveExternalAuthProfileCompatFallbackPluginIds =
|
||||
typeof import("./providers.js").resolveExternalAuthProfileCompatFallbackPluginIds;
|
||||
type ResolveExternalAuthProfileProviderPluginIds =
|
||||
typeof import("./providers.js").resolveExternalAuthProfileProviderPluginIds;
|
||||
|
||||
const resolvePluginProvidersMock = vi.fn<ResolvePluginProviders>((_) => [] as ProviderPlugin[]);
|
||||
const isPluginProvidersLoadInFlightMock = vi.fn<IsPluginProvidersLoadInFlight>((_) => false);
|
||||
const resolveCatalogHookProviderPluginIdsMock = vi.fn<ResolveCatalogHookProviderPluginIds>(
|
||||
(_) => [] as string[],
|
||||
);
|
||||
const resolveExternalAuthProfileCompatFallbackPluginIdsMock =
|
||||
vi.fn<ResolveExternalAuthProfileCompatFallbackPluginIds>((_) => [] as string[]);
|
||||
const resolveExternalAuthProfileProviderPluginIdsMock =
|
||||
vi.fn<ResolveExternalAuthProfileProviderPluginIds>((_) => [] as string[]);
|
||||
|
||||
let augmentModelCatalogWithProviderPlugins: typeof import("./provider-runtime.js").augmentModelCatalogWithProviderPlugins;
|
||||
let buildProviderAuthDoctorHintWithPlugin: typeof import("./provider-runtime.js").buildProviderAuthDoctorHintWithPlugin;
|
||||
@@ -238,6 +246,10 @@ describe("provider-runtime", () => {
|
||||
vi.doMock("./providers.js", () => ({
|
||||
resolveCatalogHookProviderPluginIds: (params: unknown) =>
|
||||
resolveCatalogHookProviderPluginIdsMock(params as never),
|
||||
resolveExternalAuthProfileCompatFallbackPluginIds: (params: unknown) =>
|
||||
resolveExternalAuthProfileCompatFallbackPluginIdsMock(params as never),
|
||||
resolveExternalAuthProfileProviderPluginIds: (params: unknown) =>
|
||||
resolveExternalAuthProfileProviderPluginIdsMock(params as never),
|
||||
}));
|
||||
vi.doMock("./providers.runtime.js", () => ({
|
||||
resolvePluginProviders: (params: unknown) => resolvePluginProvidersMock(params as never),
|
||||
@@ -301,6 +313,10 @@ describe("provider-runtime", () => {
|
||||
isPluginProvidersLoadInFlightMock.mockReturnValue(false);
|
||||
resolveCatalogHookProviderPluginIdsMock.mockReset();
|
||||
resolveCatalogHookProviderPluginIdsMock.mockReturnValue([]);
|
||||
resolveExternalAuthProfileCompatFallbackPluginIdsMock.mockReset();
|
||||
resolveExternalAuthProfileCompatFallbackPluginIdsMock.mockReturnValue([]);
|
||||
resolveExternalAuthProfileProviderPluginIdsMock.mockReset();
|
||||
resolveExternalAuthProfileProviderPluginIdsMock.mockReturnValue([]);
|
||||
});
|
||||
|
||||
it("matches providers by alias for runtime hook lookup", () => {
|
||||
@@ -355,6 +371,19 @@ describe("provider-runtime", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("skips provider runtime loading when no plugin declares external auth hooks", () => {
|
||||
expect(
|
||||
resolveExternalAuthProfilesWithPlugins({
|
||||
env: process.env,
|
||||
context: {
|
||||
env: process.env,
|
||||
store: { version: 1, profiles: {} },
|
||||
},
|
||||
}),
|
||||
).toEqual([]);
|
||||
expect(resolvePluginProvidersMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns provider-prepared runtime auth for the matched provider", async () => {
|
||||
const prepareRuntimeAuth = vi.fn(async () => ({
|
||||
apiKey: "runtime-token",
|
||||
@@ -679,6 +708,7 @@ describe("provider-runtime", () => {
|
||||
|
||||
it("dispatches runtime hooks for the matched provider", async () => {
|
||||
resolveCatalogHookProviderPluginIdsMock.mockReturnValue(["openai"]);
|
||||
resolveExternalAuthProfileProviderPluginIdsMock.mockReturnValue(["demo"]);
|
||||
const prepareDynamicModel = vi.fn(async () => undefined);
|
||||
const createStreamFn = vi.fn(() => vi.fn());
|
||||
const createEmbeddingProvider = vi.fn(async () => ({
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
import type { ProviderSystemPromptContribution } from "../agents/system-prompt-contribution.js";
|
||||
import type { ModelProviderConfig } from "../config/types.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import {
|
||||
__testing as providerHookRuntimeTesting,
|
||||
@@ -21,7 +22,11 @@ import {
|
||||
import { resolveBundledProviderPolicySurface } from "./provider-public-artifacts.js";
|
||||
import type { ProviderRuntimeModel } from "./provider-runtime-model.types.js";
|
||||
import type { ProviderThinkingProfile } from "./provider-thinking.types.js";
|
||||
import { resolveCatalogHookProviderPluginIds } from "./providers.js";
|
||||
import {
|
||||
resolveCatalogHookProviderPluginIds,
|
||||
resolveExternalAuthProfileCompatFallbackPluginIds,
|
||||
resolveExternalAuthProfileProviderPluginIds,
|
||||
} from "./providers.js";
|
||||
import { getActivePluginRegistryWorkspaceDirFromState } from "./runtime-state.js";
|
||||
import { resolveRuntimeTextTransforms } from "./text-transforms.runtime.js";
|
||||
import type {
|
||||
@@ -70,6 +75,9 @@ import type {
|
||||
ProviderWebSocketSessionPolicy,
|
||||
PluginTextTransforms,
|
||||
} from "./types.js";
|
||||
|
||||
const log = createSubsystemLogger("plugins/provider-runtime");
|
||||
const warnedExternalAuthFallbackPluginIds = new Set<string>();
|
||||
export {
|
||||
clearProviderRuntimeHookCache,
|
||||
prepareProviderExtraParams,
|
||||
@@ -755,14 +763,47 @@ export function resolveExternalAuthProfilesWithPlugins(params: {
|
||||
env?: NodeJS.ProcessEnv;
|
||||
context: ProviderResolveExternalAuthProfilesContext;
|
||||
}): ProviderExternalAuthProfile[] {
|
||||
const workspaceDir = params.workspaceDir ?? getActivePluginRegistryWorkspaceDirFromState();
|
||||
const env = params.env ?? process.env;
|
||||
const externalAuthPluginIds = resolveExternalAuthProfileProviderPluginIds({
|
||||
config: params.config,
|
||||
workspaceDir,
|
||||
env,
|
||||
});
|
||||
const fallbackPluginIds = resolveExternalAuthProfileCompatFallbackPluginIds({
|
||||
config: params.config,
|
||||
workspaceDir,
|
||||
env,
|
||||
});
|
||||
const pluginIds = [...new Set([...externalAuthPluginIds, ...fallbackPluginIds])].toSorted(
|
||||
(left, right) => left.localeCompare(right),
|
||||
);
|
||||
if (pluginIds.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const declaredPluginIds = new Set(externalAuthPluginIds);
|
||||
const matches: ProviderExternalAuthProfile[] = [];
|
||||
for (const plugin of resolveProviderPluginsForHooks(params)) {
|
||||
for (const plugin of resolveProviderPluginsForHooks({
|
||||
...params,
|
||||
workspaceDir,
|
||||
env,
|
||||
onlyPluginIds: pluginIds,
|
||||
})) {
|
||||
const profiles =
|
||||
plugin.resolveExternalAuthProfiles?.(params.context) ??
|
||||
plugin.resolveExternalOAuthProfiles?.(params.context);
|
||||
if (!profiles || profiles.length === 0) {
|
||||
continue;
|
||||
}
|
||||
if (!declaredPluginIds.has(plugin.id) && !warnedExternalAuthFallbackPluginIds.has(plugin.id)) {
|
||||
warnedExternalAuthFallbackPluginIds.add(plugin.id);
|
||||
// Deprecated compatibility path for plugins that predate the manifest
|
||||
// contract. Remove this warning with the fallback resolver after the
|
||||
// externalAuthProviders migration window closes.
|
||||
log.warn(
|
||||
`Provider plugin "${plugin.id}" uses external auth hooks without declaring contracts.externalAuthProviders. This compatibility fallback is deprecated and will be removed in a future release.`,
|
||||
);
|
||||
}
|
||||
matches.push(...profiles);
|
||||
}
|
||||
return matches;
|
||||
|
||||
Reference in New Issue
Block a user