mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 22:10:42 +00:00
209 lines
5.8 KiB
TypeScript
209 lines
5.8 KiB
TypeScript
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
|
|
|
export type AutoSelectableProvider = {
|
|
id: string;
|
|
autoSelectOrder?: number;
|
|
};
|
|
|
|
export type ProviderSelection<TProvider> = {
|
|
configuredProviderId?: string;
|
|
missingConfiguredProvider: boolean;
|
|
provider: TProvider | undefined;
|
|
};
|
|
|
|
export type ResolvedConfiguredProvider<TProvider, TConfig> =
|
|
| {
|
|
ok: true;
|
|
configuredProviderId?: string;
|
|
provider: TProvider;
|
|
providerConfig: TConfig;
|
|
}
|
|
| {
|
|
ok: false;
|
|
code: "missing-configured-provider" | "no-registered-provider" | "provider-not-configured";
|
|
configuredProviderId?: string;
|
|
provider?: TProvider;
|
|
};
|
|
|
|
export function selectConfiguredOrAutoProvider<TProvider extends AutoSelectableProvider>(params: {
|
|
configuredProviderId?: string;
|
|
getConfiguredProvider: (providerId: string | undefined) => TProvider | undefined;
|
|
listProviders: () => Iterable<TProvider>;
|
|
}): ProviderSelection<TProvider> {
|
|
const configuredProviderId = normalizeOptionalString(params.configuredProviderId);
|
|
const configuredProvider = configuredProviderId
|
|
? params.getConfiguredProvider(configuredProviderId)
|
|
: undefined;
|
|
|
|
if (configuredProviderId && !configuredProvider) {
|
|
return {
|
|
configuredProviderId,
|
|
missingConfiguredProvider: true,
|
|
provider: undefined,
|
|
};
|
|
}
|
|
|
|
return {
|
|
configuredProviderId,
|
|
missingConfiguredProvider: false,
|
|
provider:
|
|
configuredProvider ?? [...params.listProviders()].toSorted(compareProviderAutoSelectOrder)[0],
|
|
};
|
|
}
|
|
|
|
export function resolveProviderRawConfig(params: {
|
|
providerId: string;
|
|
configuredProviderId?: string;
|
|
providerConfigs?: Record<string, Record<string, unknown> | undefined>;
|
|
}): Record<string, unknown> {
|
|
const canonicalProviderConfig = readProviderConfig(params.providerConfigs, params.providerId);
|
|
const selectedProviderConfig = readProviderConfig(
|
|
params.providerConfigs,
|
|
params.configuredProviderId,
|
|
);
|
|
|
|
return {
|
|
...canonicalProviderConfig,
|
|
...selectedProviderConfig,
|
|
};
|
|
}
|
|
|
|
export function resolveConfiguredCapabilityProvider<
|
|
TConfig,
|
|
TFullConfig,
|
|
TProvider extends AutoSelectableProvider,
|
|
>(params: {
|
|
configuredProviderId?: string;
|
|
providerConfigs?: Record<string, Record<string, unknown> | undefined>;
|
|
cfg: TFullConfig | undefined;
|
|
cfgForResolve: TFullConfig;
|
|
getConfiguredProvider: (providerId: string | undefined) => TProvider | undefined;
|
|
listProviders: () => Iterable<TProvider>;
|
|
resolveProviderConfig: (params: {
|
|
provider: TProvider;
|
|
cfg: TFullConfig;
|
|
rawConfig: Record<string, unknown>;
|
|
}) => TConfig;
|
|
isProviderConfigured: (params: {
|
|
provider: TProvider;
|
|
cfg: TFullConfig | undefined;
|
|
providerConfig: TConfig;
|
|
}) => boolean;
|
|
}): ResolvedConfiguredProvider<TProvider, TConfig> {
|
|
const configuredProviderId = normalizeOptionalString(params.configuredProviderId);
|
|
if (configuredProviderId) {
|
|
const provider = params.getConfiguredProvider(configuredProviderId);
|
|
if (!provider) {
|
|
return {
|
|
ok: false,
|
|
code: "missing-configured-provider",
|
|
configuredProviderId,
|
|
};
|
|
}
|
|
|
|
return resolveProviderCandidate({
|
|
...params,
|
|
configuredProviderId,
|
|
provider,
|
|
});
|
|
}
|
|
|
|
const providers = [...params.listProviders()].toSorted(compareProviderAutoSelectOrder);
|
|
if (providers.length === 0) {
|
|
return {
|
|
ok: false,
|
|
code: "no-registered-provider",
|
|
};
|
|
}
|
|
|
|
let firstUnconfigured: TProvider | undefined;
|
|
for (const provider of providers) {
|
|
const resolution = resolveProviderCandidate({
|
|
...params,
|
|
provider,
|
|
});
|
|
if (resolution.ok) {
|
|
return resolution;
|
|
}
|
|
firstUnconfigured ??= provider;
|
|
}
|
|
|
|
return {
|
|
ok: false,
|
|
code: "provider-not-configured",
|
|
provider: firstUnconfigured,
|
|
};
|
|
}
|
|
|
|
function compareProviderAutoSelectOrder<TProvider extends AutoSelectableProvider>(
|
|
left: TProvider,
|
|
right: TProvider,
|
|
): number {
|
|
return (
|
|
(left.autoSelectOrder ?? Number.MAX_SAFE_INTEGER) -
|
|
(right.autoSelectOrder ?? Number.MAX_SAFE_INTEGER)
|
|
);
|
|
}
|
|
|
|
function readProviderConfig(
|
|
providerConfigs: Record<string, Record<string, unknown> | undefined> | undefined,
|
|
providerId: string | undefined,
|
|
): Record<string, unknown> | undefined {
|
|
if (!providerId) {
|
|
return undefined;
|
|
}
|
|
const providerConfig = providerConfigs?.[providerId];
|
|
return providerConfig && typeof providerConfig === "object" ? providerConfig : undefined;
|
|
}
|
|
|
|
function resolveProviderCandidate<
|
|
TConfig,
|
|
TFullConfig,
|
|
TProvider extends AutoSelectableProvider,
|
|
>(params: {
|
|
configuredProviderId?: string;
|
|
providerConfigs?: Record<string, Record<string, unknown> | undefined>;
|
|
cfg: TFullConfig | undefined;
|
|
cfgForResolve: TFullConfig;
|
|
provider: TProvider;
|
|
resolveProviderConfig: (params: {
|
|
provider: TProvider;
|
|
cfg: TFullConfig;
|
|
rawConfig: Record<string, unknown>;
|
|
}) => TConfig;
|
|
isProviderConfigured: (params: {
|
|
provider: TProvider;
|
|
cfg: TFullConfig | undefined;
|
|
providerConfig: TConfig;
|
|
}) => boolean;
|
|
}): ResolvedConfiguredProvider<TProvider, TConfig> {
|
|
const rawProviderConfig = resolveProviderRawConfig({
|
|
providerId: params.provider.id,
|
|
configuredProviderId: params.configuredProviderId,
|
|
providerConfigs: params.providerConfigs,
|
|
});
|
|
const providerConfig = params.resolveProviderConfig({
|
|
provider: params.provider,
|
|
cfg: params.cfgForResolve,
|
|
rawConfig: rawProviderConfig,
|
|
});
|
|
|
|
if (
|
|
!params.isProviderConfigured({ provider: params.provider, cfg: params.cfg, providerConfig })
|
|
) {
|
|
return {
|
|
ok: false,
|
|
code: "provider-not-configured",
|
|
configuredProviderId: params.configuredProviderId,
|
|
provider: params.provider,
|
|
};
|
|
}
|
|
|
|
return {
|
|
ok: true,
|
|
configuredProviderId: params.configuredProviderId,
|
|
provider: params.provider,
|
|
providerConfig,
|
|
};
|
|
}
|