Files
openclaw/src/plugins/providers.ts
Peter Steinberger bb46b79d3c refactor: internalize OpenClaw agent runtime (#85341)
* refactor: extract agent core package

Introduce packages/agent-core as the OpenClaw-owned home for reusable agent loop, harness, session, prompt, and runtime dependency contracts.

* refactor: extract shared llm runtime

Move provider model registries, stream wrappers, OAuth helpers, and LLM utilities into src/llm with plugin-sdk barrels instead of depending on the old embedded runtime layout.

* refactor: remove pi runtime internals

Rename remaining Pi-shaped agent surfaces to OpenClaw agent runtime names, delete obsolete Pi docs and package graph checks, and add the third-party notice for incorporated code.

* refactor: tighten agent session runtime

Make agent-core/runtime dependencies explicit, consolidate compaction and session transcript helpers, and move model/session helpers behind OpenClaw-owned contracts.

* refactor: remove static model and pi auth paths

Drop static model catalogs and Pi auth bridges, move model/provider facts to manifest-owned runtime contracts, and harden internal embedded-agent utilities.

* refactor: remove legacy provider compat paths

* docs: remove agent parity notes

* fix: skip provider wildcard metadata parsing

* refactor: share session extension sdk loading

* refactor: inline acpx proxy error formatter

* refactor: fold edit recovery into edit tool

* fix: accept extension batch separator

* test: align startup provider plugin expectations

* fix: restore provider-scoped release discovery

* test: align static asset packaging expectations

* fix: run static provider catalogs during scoped discovery

* fix: add provider entry catalogs for scoped live discovery

* fix: load lightweight provider catalog entries

* fix: refresh provider-scoped plugin metadata

* fix: keep provider catalog entries on release live path

* fix: keep static manifest models in release live checks

* fix: harden release model discovery

* fix: reduce OpenAI live cache probe reasoning

* fix: disable OpenAI cache probe reasoning

* ci: extend OpenAI gateway live timeout

* fix: extend live gateway model budget

* fix: stabilize release validation regressions

* fix: honor provider aliases in model rows

* fix: stabilize release validation lanes

* fix: stabilize release memory qa

* ci: stabilize release validation lanes

* ci: prefer ipv4 for live docker node calls

* fix: restore shared tool-call stream wrapper

* ci: remove legacy pi test shard alias

* fix: clean up embedded agent test drift

* fix: stabilize runtime alias status

* fix: clean up embedded agent ci drift

* fix: restore release ci invariants

* fix: clean up post-rebase runtime drift

* fix: restore release ci checks

* fix: restore release ci after rebase

* fix: remove stale pi runtime path

* test: align compaction runtime expectations

* test: update plugin prerelease expectations

* fix: handle claude live tool approvals

* fix: stabilize release validation gates

* fix: finish agent runtime import

* test: finish post-rebase agent runtime mocks

* fix: keep codex compaction native

* fix: stabilize codex app-server hook tests

* test: isolate codex diagnostic active run

* test: remove codex diagnostic completion race

# Conflicts:
#	extensions/codex/src/app-server/run-attempt.test.ts

* ci: fix full release manifest performance run id

* refactor: narrow llm plugin sdk boundary

* chore: drop generated google boundary stamps

* fix: repair rebase fallout

* fix: clean up rebased runtime references

* fix: decode codex jwt payloads as base64url

* fix: preserve shipped pi runtime alias

* fix: add scoped sdk virtual modules

* fix: decode llm codex oauth jwt as base64url

* fix: avoid stale vertex adc negative cache

* fix: harden tool arg decoding and codeql path

* fix: keep vertex adc negative checks live

* refactor: consolidate codex jwt and edit helpers

* fix: await codex oauth node runtime imports

* fix: preserve sdk tool and notice contracts

* fix: preserve shipped compat config boundaries

* fix: align codex oauth callback host

* fix: terminate agent-core loop streams on failure

* fix: keep codex oauth callback alive during fallback

* ci: include session tools in critical codeql scans

* fix: keep Cloudflare Anthropic provider auth header

* docs: redirect legacy pi runtime pages

* fix: honor bundled web provider compat discovery

* fix: protect session output spill files

* fix: keep legacy agent dir env blocked

* fix: contain auto-discovered skill symlinks

* fix: harden agent core sdk proxy surfaces

* fix: restore approval reaction sdk compat

* fix: keep live docker runs bounded

* fix: keep codex oauth redirect host aligned

* fix: resolve post-rebase agent runtime drift

* fix: redact anthropic oauth parse failures

* fix: preserve responses strict tool shaping

* fix: repair agent runtime rebase cleanup

* docs: redirect retired parity pages

* fix: bound auto-discovered resources to roots

* fix: repair post-rebase agent test drift

* fix: preserve bundled provider allowlist migration

* fix: preserve manifest-owned provider aliases

* fix: declare photon image dependency

* fix: keep provider headers out of proxy body

* fix: preserve shipped env aliases

* fix: refresh control ui i18n generated state

* fix: quote read fallback paths

* fix: preview edits through configured backend

* test: satisfy core test typecheck

* fix: preserve ZAI usage auth fallback

* test: repair codex diagnostic test

* fix: repair agent runtime rebase drift

* test: finish embedded runner import rename

* fix: repair agent runtime rebase integrations

* test: align compaction oauth fallback expectations

* fix: allow sdk-auth session models

* fix: update doctor tool schema import

* fix: preserve bedrock plugin region

* fix: stream harmony-like prose immediately

* ci: include session runtime in codeql shards

* fix: repair latest rebase integrations

* fix: honor explicit codex websocket transport

* fix: keep openai-compatible credentials provider-scoped

* fix: refresh sdk api baseline after rebase

* fix: route cli runtime aliases through openclaw harness

* test: rename stale harness mock expectation

* test: rename embedded agent overflow calls

* test: clean embedded auth test wording

* test: use openclaw stream types in deepinfra cache test

* fix: refresh sdk api baseline on latest main

* fix: honor bundled discovery compat allowlists

* fix: refresh sdk api baseline after latest rebase

* fix: remove stale rebase imports

* test: rename stale model catalog mock

* test: mock renamed doctor runtime modules

* fix: map canonical kimi env auth

* fix: use internal model registry in bench script

* fix: migrate deepinfra provider catalog entry

* fix: enforce builtin tool suppression

* fix: route compaction auth and proxy payloads safely

* refactor: prune unused llm registry leftovers

* test: update codex hooks session import

* test: fix model picker ci coverage

* test: align model picker auth mock types
2026-05-27 19:24:04 +01:00

733 lines
23 KiB
TypeScript

import { splitTrailingAuthProfile } from "../agents/model-ref-profile.js";
import { normalizeProviderId } from "../agents/provider-id.js";
import { compileSafeRegex } from "../security/safe-regex.js";
import { sortUniqueStrings } from "../shared/string-normalization.js";
import { withBundledPluginVitestCompat } from "./bundled-compat.js";
import { resolveEffectivePluginActivationState } from "./config-state.js";
import { isPluginEnabledByDefaultForPlatform } from "./default-enablement.js";
import type { PluginLoadOptions } from "./loader.js";
import {
isActivatedManifestOwner,
passesManifestOwnerBasePolicy,
} from "./manifest-owner-policy.js";
import { loadPluginManifestRegistryForInstalledIndex } from "./manifest-registry-installed.js";
import type { PluginManifestRecord, PluginManifestRegistry } from "./manifest-registry.js";
import { loadPluginMetadataSnapshot } from "./plugin-metadata-snapshot.js";
import {
loadPluginRegistrySnapshot,
normalizePluginsConfigWithRegistry,
type PluginRegistryRecord,
type PluginRegistrySnapshot,
} from "./plugin-registry.js";
import { createPluginIdScopeSet } from "./plugin-scope.js";
type ProviderManifestLoadParams = {
config?: PluginLoadOptions["config"];
workspaceDir?: string;
env?: PluginLoadOptions["env"];
registry?: PluginRegistrySnapshot;
manifestRegistry?: PluginManifestRegistry;
};
type NormalizedPluginsConfig = ReturnType<typeof normalizePluginsConfigWithRegistry>;
type ProviderRegistryLoadParams = ProviderManifestLoadParams & {
onlyPluginIds?: readonly string[];
};
function loadProviderRegistrySnapshot(params: ProviderManifestLoadParams): PluginRegistrySnapshot {
if (params.registry) {
return params.registry;
}
return loadPluginRegistrySnapshot({
config: params.config,
workspaceDir: params.workspaceDir,
env: params.env,
});
}
function loadScopedProviderRegistry(params: ProviderRegistryLoadParams): {
registry: PluginRegistrySnapshot;
onlyPluginIdSet: ReturnType<typeof createPluginIdScopeSet>;
} {
return {
registry: loadProviderRegistrySnapshot(params),
onlyPluginIdSet: createPluginIdScopeSet(params.onlyPluginIds),
};
}
function listRegistryPluginIds(
registry: PluginRegistrySnapshot,
predicate: (plugin: PluginRegistryRecord) => boolean,
): string[] {
return registry.plugins
.filter(predicate)
.map((plugin) => plugin.pluginId)
.toSorted((left, right) => left.localeCompare(right));
}
function resolveProviderSurfacePluginIdSet(
params: ProviderManifestLoadParams & {
registry: PluginRegistrySnapshot;
},
): ReadonlySet<string> {
return new Set(
resolveManifestRegistry({
...params,
includeDisabled: true,
}).plugins.flatMap((plugin) => (plugin.providers.length > 0 ? [plugin.id] : [])),
);
}
function pluginOwnsProviderRef(plugin: PluginManifestRecord, normalizedProvider: string): boolean {
if (
plugin.providers.some((providerId) => normalizeProviderId(providerId) === normalizedProvider)
) {
return true;
}
for (const [rawAlias, target] of Object.entries(plugin.modelCatalog?.aliases ?? {})) {
const alias = normalizeProviderId(rawAlias);
const targetProvider = normalizeProviderId(target.provider);
if (
alias === normalizedProvider &&
targetProvider &&
plugin.providers.some((providerId) => normalizeProviderId(providerId) === targetProvider)
) {
return true;
}
}
return false;
}
function resolvesRuntimeModelCatalogAugment(plugin: PluginManifestRecord): boolean {
return (
plugin.modelCatalog?.runtimeAugment === true ||
(plugin.origin !== "bundled" && plugin.providers.length > 0)
);
}
function resolveProviderOwnerPluginIds(
params: ProviderRegistryLoadParams & {
pluginIds: readonly string[];
isEligible: (
plugin: PluginRegistryRecord,
normalizedConfig: NormalizedPluginsConfig,
) => boolean;
},
): string[] {
if (params.pluginIds.length === 0) {
return [];
}
const pluginIdSet = new Set(params.pluginIds);
const registry = loadProviderRegistrySnapshot(params);
const normalizedConfig = normalizePluginsConfigWithRegistry(params.config?.plugins, registry, {
manifestRegistry: params.manifestRegistry,
});
return listRegistryPluginIds(
registry,
(plugin) => pluginIdSet.has(plugin.pluginId) && params.isEligible(plugin, normalizedConfig),
);
}
function resolveEffectiveRegistryPluginActivation(params: {
plugin: PluginRegistryRecord;
normalizedConfig: NormalizedPluginsConfig;
rootConfig?: PluginLoadOptions["config"];
}) {
return resolveEffectivePluginActivationState({
id: params.plugin.pluginId,
origin: params.plugin.origin,
config: params.normalizedConfig,
rootConfig: params.rootConfig,
enabledByDefault: isPluginEnabledByDefaultForPlatform(params.plugin),
});
}
function toManifestOwnerRecord(plugin: PluginRegistryRecord) {
return {
id: plugin.pluginId,
origin: plugin.origin,
enabledByDefault: isPluginEnabledByDefaultForPlatform(plugin),
};
}
export function withBundledProviderVitestCompat(params: {
config: PluginLoadOptions["config"];
pluginIds: readonly string[];
env?: PluginLoadOptions["env"];
}): PluginLoadOptions["config"] {
return withBundledPluginVitestCompat(params);
}
export function resolveBundledProviderCompatPluginIds(params: {
config?: PluginLoadOptions["config"];
workspaceDir?: string;
env?: PluginLoadOptions["env"];
onlyPluginIds?: readonly string[];
manifestRegistry?: PluginManifestRegistry;
}): string[] {
if (params.manifestRegistry) {
const onlyPluginIdSet = createPluginIdScopeSet(params.onlyPluginIds);
return params.manifestRegistry.plugins
.filter(
(plugin) =>
plugin.origin === "bundled" &&
plugin.providers.length > 0 &&
(!onlyPluginIdSet || onlyPluginIdSet.has(plugin.id)),
)
.map((plugin) => plugin.id)
.toSorted((left, right) => left.localeCompare(right));
}
const { registry, onlyPluginIdSet } = loadScopedProviderRegistry(params);
const providerSurfacePluginIds = resolveProviderSurfacePluginIdSet({ ...params, registry });
return listRegistryPluginIds(
registry,
(plugin) =>
plugin.origin === "bundled" &&
providerSurfacePluginIds.has(plugin.pluginId) &&
(!onlyPluginIdSet || onlyPluginIdSet.has(plugin.pluginId)),
);
}
export function resolveEnabledProviderPluginIds(params: ProviderRegistryLoadParams): string[] {
const { registry, onlyPluginIdSet } = loadScopedProviderRegistry(params);
const providerSurfacePluginIds = resolveProviderSurfacePluginIdSet({ ...params, registry });
const normalizedConfig = normalizePluginsConfigWithRegistry(params.config?.plugins, registry, {
manifestRegistry: params.manifestRegistry,
});
return listRegistryPluginIds(
registry,
(plugin) =>
providerSurfacePluginIds.has(plugin.pluginId) &&
(!onlyPluginIdSet || onlyPluginIdSet.has(plugin.pluginId)) &&
resolveEffectiveRegistryPluginActivation({
plugin,
normalizedConfig,
rootConfig: params.config,
}).activated,
);
}
export function resolveExternalAuthProfileProviderPluginIds(params: {
config?: PluginLoadOptions["config"];
workspaceDir?: string;
env?: PluginLoadOptions["env"];
manifestRegistry?: PluginManifestRegistry;
}): string[] {
return resolveRegistryManifestContractPluginIds({
...params,
contract: "externalAuthProviders",
});
}
function resolveRegistryManifestContractPluginIds(params: {
contract: string;
config?: PluginLoadOptions["config"];
workspaceDir?: string;
env?: PluginLoadOptions["env"];
origin?: PluginRegistryRecord["origin"];
onlyPluginIds?: readonly string[];
manifestRegistry?: PluginManifestRegistry;
}): string[] {
const { registry, onlyPluginIdSet } = loadScopedProviderRegistry(params);
return resolveManifestRegistry({
...params,
registry,
includeDisabled: true,
})
.plugins.filter((plugin) => {
if (params.origin && plugin.origin !== params.origin) {
return false;
}
if (onlyPluginIdSet && !onlyPluginIdSet.has(plugin.id)) {
return false;
}
return (
(plugin.contracts?.[params.contract as keyof NonNullable<typeof plugin.contracts>] ?? [])
.length > 0
);
})
.map((plugin) => plugin.id)
.toSorted((left, right) => left.localeCompare(right));
}
export function resolveExternalAuthProfileCompatFallbackPluginIds(params: {
config?: PluginLoadOptions["config"];
workspaceDir?: string;
env?: PluginLoadOptions["env"];
declaredPluginIds?: ReadonlySet<string>;
manifestRegistry?: PluginManifestRegistry;
}): string[] {
const declaredPluginIds =
params.declaredPluginIds ?? new Set(resolveExternalAuthProfileProviderPluginIds(params));
const registry = loadProviderRegistrySnapshot(params);
const providerSurfacePluginIds = resolveProviderSurfacePluginIdSet({ ...params, registry });
const normalizedConfig = normalizePluginsConfigWithRegistry(params.config?.plugins, registry, {
manifestRegistry: params.manifestRegistry,
});
return listRegistryPluginIds(
registry,
(plugin) =>
plugin.origin !== "bundled" &&
providerSurfacePluginIds.has(plugin.pluginId) &&
!declaredPluginIds.has(plugin.pluginId) &&
isProviderPluginEligibleForRuntimeOwnerActivation({
plugin,
normalizedConfig,
rootConfig: params.config,
}),
);
}
export function resolveDiscoveredProviderPluginIds(params: {
config?: PluginLoadOptions["config"];
workspaceDir?: string;
env?: PluginLoadOptions["env"];
registry?: PluginRegistrySnapshot;
manifestRegistry?: PluginManifestRegistry;
onlyPluginIds?: readonly string[];
includeUntrustedWorkspacePlugins?: boolean;
}): string[] {
const { registry, onlyPluginIdSet } = loadScopedProviderRegistry(params);
const providerSurfacePluginIds = resolveProviderSurfacePluginIdSet({ ...params, registry });
const shouldFilterUntrustedWorkspacePlugins = params.includeUntrustedWorkspacePlugins !== true;
const normalizedConfig = normalizePluginsConfigWithRegistry(params.config?.plugins, registry, {
manifestRegistry: params.manifestRegistry,
});
return listRegistryPluginIds(registry, (plugin) => {
if (
!(
providerSurfacePluginIds.has(plugin.pluginId) &&
(!onlyPluginIdSet || onlyPluginIdSet.has(plugin.pluginId))
)
) {
return false;
}
return isProviderPluginEligibleForSetupDiscovery({
plugin,
shouldFilterUntrustedWorkspacePlugins,
normalizedConfig,
rootConfig: params.config,
});
});
}
function isProviderPluginEligibleForSetupDiscovery(params: {
plugin: PluginRegistryRecord;
shouldFilterUntrustedWorkspacePlugins: boolean;
normalizedConfig: NormalizedPluginsConfig;
rootConfig?: PluginLoadOptions["config"];
}): boolean {
if (params.plugin.origin === "workspace") {
if (!params.shouldFilterUntrustedWorkspacePlugins) {
return true;
}
}
if (
!passesManifestOwnerBasePolicy({
plugin: toManifestOwnerRecord(params.plugin),
normalizedConfig: params.normalizedConfig,
})
) {
return false;
}
if (params.plugin.origin === "bundled") {
return true;
}
return isActivatedManifestOwner({
plugin: toManifestOwnerRecord(params.plugin),
normalizedConfig: params.normalizedConfig,
rootConfig: params.rootConfig,
});
}
export function resolveDiscoverableProviderOwnerPluginIds(params: {
pluginIds: readonly string[];
config?: PluginLoadOptions["config"];
workspaceDir?: string;
env?: PluginLoadOptions["env"];
registry?: PluginRegistrySnapshot;
manifestRegistry?: PluginManifestRegistry;
includeUntrustedWorkspacePlugins?: boolean;
}): string[] {
const shouldFilterUntrustedWorkspacePlugins = params.includeUntrustedWorkspacePlugins !== true;
return resolveProviderOwnerPluginIds({
...params,
isEligible: (plugin, normalizedConfig) =>
isProviderPluginEligibleForSetupDiscovery({
plugin,
shouldFilterUntrustedWorkspacePlugins,
normalizedConfig,
rootConfig: params.config,
}),
});
}
function isProviderPluginEligibleForRuntimeOwnerActivation(params: {
plugin: PluginRegistryRecord;
normalizedConfig: NormalizedPluginsConfig;
rootConfig?: PluginLoadOptions["config"];
}): boolean {
if (
!passesManifestOwnerBasePolicy({
plugin: toManifestOwnerRecord(params.plugin),
normalizedConfig: params.normalizedConfig,
})
) {
return false;
}
if (params.plugin.origin !== "workspace") {
return true;
}
return isActivatedManifestOwner({
plugin: toManifestOwnerRecord(params.plugin),
normalizedConfig: params.normalizedConfig,
rootConfig: params.rootConfig,
});
}
export function resolveActivatableProviderOwnerPluginIds(params: {
pluginIds: readonly string[];
config?: PluginLoadOptions["config"];
workspaceDir?: string;
env?: PluginLoadOptions["env"];
registry?: PluginRegistrySnapshot;
manifestRegistry?: PluginManifestRegistry;
includeUntrustedWorkspacePlugins?: boolean;
}): string[] {
return resolveProviderOwnerPluginIds({
...params,
isEligible: (plugin, normalizedConfig) =>
isProviderPluginEligibleForRuntimeOwnerActivation({
plugin,
normalizedConfig,
rootConfig: params.config,
}),
});
}
export const testing = {
resolveActivatableProviderOwnerPluginIds,
resolveEnabledProviderPluginIds,
resolveExternalAuthProfileCompatFallbackPluginIds,
resolveExternalAuthProfileProviderPluginIds,
resolveDiscoveredProviderPluginIds,
resolveDiscoverableProviderOwnerPluginIds,
resolveBundledProviderCompatPluginIds,
withBundledProviderVitestCompat,
} as const;
type ModelSupportMatchKind = "pattern" | "prefix";
function resolveManifestRegistry(params: {
config?: PluginLoadOptions["config"];
workspaceDir?: string;
env?: PluginLoadOptions["env"];
manifestRegistry?: PluginManifestRegistry;
registry?: PluginRegistrySnapshot;
includeDisabled?: boolean;
}): PluginManifestRegistry {
if (params.manifestRegistry) {
return params.manifestRegistry;
}
const registry = params.registry ?? loadProviderRegistrySnapshot(params);
return loadPluginManifestRegistryForInstalledIndex({
index: registry,
config: params.config,
workspaceDir: params.workspaceDir,
env: params.env,
includeDisabled: params.includeDisabled,
});
}
function stripModelProfileSuffix(value: string): string {
return splitTrailingAuthProfile(value).model;
}
function splitExplicitModelRef(rawModel: string): { provider?: string; modelId: string } | null {
const trimmed = rawModel.trim();
if (!trimmed) {
return null;
}
const slash = trimmed.indexOf("/");
if (slash === -1) {
const modelId = stripModelProfileSuffix(trimmed);
return modelId ? { modelId } : null;
}
const provider = normalizeProviderId(trimmed.slice(0, slash));
const modelId = stripModelProfileSuffix(trimmed.slice(slash + 1));
if (!provider || !modelId) {
return null;
}
return { provider, modelId };
}
function resolveModelSupportMatchKind(
plugin: PluginManifestRecord,
modelId: string,
): ModelSupportMatchKind | undefined {
const patterns = plugin.modelSupport?.modelPatterns ?? [];
for (const patternSource of patterns) {
// compileSafeRegex rejects patterns with nested repetition (ReDoS risk)
// and returns null. Rejected patterns are silently skipped: the plugin
// will not match via that pattern but other patterns/prefixes still apply.
const regex = compileSafeRegex(patternSource, "u");
if (regex?.test(modelId)) {
return "pattern";
}
}
const prefixes = plugin.modelSupport?.modelPrefixes ?? [];
for (const prefix of prefixes) {
if (modelId.startsWith(prefix)) {
return "prefix";
}
}
return undefined;
}
function dedupeSortedPluginIds(values: Iterable<string>): string[] {
return sortUniqueStrings(values);
}
function resolvePreferredManifestPluginIds(
registry: PluginManifestRegistry,
matchedPluginIds: readonly string[],
): string[] | undefined {
if (matchedPluginIds.length === 0) {
return undefined;
}
const uniquePluginIds = dedupeSortedPluginIds(matchedPluginIds);
if (uniquePluginIds.length <= 1) {
return uniquePluginIds;
}
const nonBundledPluginIds = uniquePluginIds.filter((pluginId) => {
const plugin = registry.plugins.find((entry) => entry.id === pluginId);
return plugin?.origin !== "bundled";
});
if (nonBundledPluginIds.length === 1) {
return nonBundledPluginIds;
}
if (nonBundledPluginIds.length > 1) {
return undefined;
}
return undefined;
}
export function resolveOwningPluginIdsForProvider(params: {
provider: string;
config?: PluginLoadOptions["config"];
workspaceDir?: string;
env?: PluginLoadOptions["env"];
manifestRegistry?: PluginManifestRegistry;
}): string[] | undefined {
const normalizedProvider = normalizeProviderId(params.provider);
if (!normalizedProvider) {
return undefined;
}
const manifestRegistry =
params.manifestRegistry ??
loadPluginMetadataSnapshot({
config: params.config ?? {},
workspaceDir: params.workspaceDir,
env: params.env ?? process.env,
}).manifestRegistry;
const pluginIds = manifestRegistry.plugins
.filter((plugin) => pluginOwnsProviderRef(plugin, normalizedProvider))
.map((plugin) => plugin.id);
return pluginIds.length > 0 ? pluginIds : undefined;
}
function resolveOwningPluginIdsForCliBackend(params: {
backend: string;
config?: PluginLoadOptions["config"];
workspaceDir?: string;
env?: PluginLoadOptions["env"];
manifestRegistry?: PluginManifestRegistry;
}): string[] | undefined {
const normalizedBackend = normalizeProviderId(params.backend);
if (!normalizedBackend) {
return undefined;
}
const manifestRegistry =
params.manifestRegistry ??
loadPluginMetadataSnapshot({
config: params.config ?? {},
workspaceDir: params.workspaceDir,
env: params.env ?? process.env,
}).manifestRegistry;
const pluginIds = manifestRegistry.plugins
.filter(
(plugin) =>
plugin.cliBackends.some(
(backendId) => normalizeProviderId(backendId) === normalizedBackend,
) ||
(plugin.setup?.cliBackends ?? []).some(
(backendId) => normalizeProviderId(backendId) === normalizedBackend,
),
)
.map((plugin) => plugin.id);
const deduped = dedupeSortedPluginIds(pluginIds);
return deduped.length > 0 ? deduped : undefined;
}
export function resolveOwningPluginIdsForProviderRef(params: {
provider: string;
config?: PluginLoadOptions["config"];
workspaceDir?: string;
env?: PluginLoadOptions["env"];
manifestRegistry?: PluginManifestRegistry;
}): string[] | undefined {
return (
resolveOwningPluginIdsForProvider(params) ??
resolveOwningPluginIdsForCliBackend({
backend: params.provider,
config: params.config,
workspaceDir: params.workspaceDir,
env: params.env,
manifestRegistry: params.manifestRegistry,
})
);
}
export function resolveOwningPluginIdsForModelRef(params: {
model: string;
config?: PluginLoadOptions["config"];
workspaceDir?: string;
env?: PluginLoadOptions["env"];
manifestRegistry?: PluginManifestRegistry;
registry?: PluginRegistrySnapshot;
}): string[] | undefined {
const parsed = splitExplicitModelRef(params.model);
if (!parsed) {
return undefined;
}
if (parsed.provider) {
const providerOwners = resolveOwningPluginIdsForProvider({
provider: parsed.provider,
config: params.config,
workspaceDir: params.workspaceDir,
env: params.env,
manifestRegistry: params.manifestRegistry,
});
return (
providerOwners ??
resolveOwningPluginIdsForCliBackend({
backend: parsed.provider,
config: params.config,
workspaceDir: params.workspaceDir,
env: params.env,
manifestRegistry: params.manifestRegistry,
})
);
}
const manifestRegistry = resolveManifestRegistry({
...params,
includeDisabled: true,
});
const matchedByPattern = manifestRegistry.plugins
.filter((plugin) => resolveModelSupportMatchKind(plugin, parsed.modelId) === "pattern")
.map((plugin) => plugin.id);
const preferredPatternPluginIds = resolvePreferredManifestPluginIds(
manifestRegistry,
matchedByPattern,
);
if (preferredPatternPluginIds) {
return preferredPatternPluginIds;
}
const matchedByPrefix = manifestRegistry.plugins
.filter((plugin) => resolveModelSupportMatchKind(plugin, parsed.modelId) === "prefix")
.map((plugin) => plugin.id);
return resolvePreferredManifestPluginIds(manifestRegistry, matchedByPrefix);
}
export function resolveOwningPluginIdsForModelRefs(params: {
models: readonly string[];
config?: PluginLoadOptions["config"];
workspaceDir?: string;
env?: PluginLoadOptions["env"];
manifestRegistry?: PluginManifestRegistry;
}): string[] {
const registry = params.manifestRegistry ? undefined : loadProviderRegistrySnapshot(params);
const manifestRegistry = params.manifestRegistry;
return dedupeSortedPluginIds(
params.models.flatMap(
(model) =>
resolveOwningPluginIdsForModelRef({
model,
config: params.config,
workspaceDir: params.workspaceDir,
env: params.env,
...(manifestRegistry ? { manifestRegistry } : {}),
...(registry ? { registry } : {}),
}) ?? [],
),
);
}
export function resolveNonBundledProviderPluginIds(params: {
config?: PluginLoadOptions["config"];
workspaceDir?: string;
env?: PluginLoadOptions["env"];
}): string[] {
const registry = loadProviderRegistrySnapshot(params);
const providerSurfacePluginIds = resolveProviderSurfacePluginIdSet({ ...params, registry });
const normalizedConfig = normalizePluginsConfigWithRegistry(params.config?.plugins, registry);
return listRegistryPluginIds(
registry,
(plugin) =>
plugin.origin !== "bundled" &&
providerSurfacePluginIds.has(plugin.pluginId) &&
resolveEffectiveRegistryPluginActivation({
plugin,
normalizedConfig,
rootConfig: params.config,
}).activated,
);
}
export function resolveCatalogHookProviderPluginIds(params: {
config?: PluginLoadOptions["config"];
workspaceDir?: string;
env?: PluginLoadOptions["env"];
}): string[] {
const registry = loadProviderRegistrySnapshot(params);
const manifestRegistry = resolveManifestRegistry({
...params,
registry,
includeDisabled: true,
});
const providerSurfacePluginIds = new Set(
manifestRegistry.plugins.flatMap((plugin) => (plugin.providers.length > 0 ? [plugin.id] : [])),
);
const runtimeAugmentPluginIds = new Set(
manifestRegistry.plugins.flatMap((plugin) =>
resolvesRuntimeModelCatalogAugment(plugin) ? [plugin.id] : [],
),
);
const normalizedConfig = normalizePluginsConfigWithRegistry(params.config?.plugins, registry);
const enabledProviderPluginIds = listRegistryPluginIds(
registry,
(plugin) =>
providerSurfacePluginIds.has(plugin.pluginId) &&
runtimeAugmentPluginIds.has(plugin.pluginId) &&
resolveEffectiveRegistryPluginActivation({
plugin,
normalizedConfig,
rootConfig: params.config,
}).activated,
);
const bundledCompatPluginIds = resolveBundledProviderCompatPluginIds({
...params,
manifestRegistry,
}).filter((pluginId) => runtimeAugmentPluginIds.has(pluginId));
return dedupeSortedPluginIds([...enabledProviderPluginIds, ...bundledCompatPluginIds]);
}
export { testing as __testing };