refactor(cli): remove bundled cli text providers

This commit is contained in:
Peter Steinberger
2026-04-05 18:42:59 +01:00
parent 79d6713d81
commit 05d351c430
127 changed files with 87 additions and 8258 deletions

View File

@@ -25,7 +25,6 @@ export type BuildPluginApiParams = {
| "registerGatewayMethod"
| "registerCli"
| "registerService"
| "registerCliBackend"
| "registerConfigMigration"
| "registerAutoEnableProbe"
| "registerProvider"
@@ -57,7 +56,6 @@ const noopRegisterChannel: OpenClawPluginApi["registerChannel"] = () => {};
const noopRegisterGatewayMethod: OpenClawPluginApi["registerGatewayMethod"] = () => {};
const noopRegisterCli: OpenClawPluginApi["registerCli"] = () => {};
const noopRegisterService: OpenClawPluginApi["registerService"] = () => {};
const noopRegisterCliBackend: OpenClawPluginApi["registerCliBackend"] = () => {};
const noopRegisterConfigMigration: OpenClawPluginApi["registerConfigMigration"] = () => {};
const noopRegisterAutoEnableProbe: OpenClawPluginApi["registerAutoEnableProbe"] = () => {};
const noopRegisterProvider: OpenClawPluginApi["registerProvider"] = () => {};
@@ -107,7 +105,6 @@ export function buildPluginApi(params: BuildPluginApiParams): OpenClawPluginApi
registerGatewayMethod: handlers.registerGatewayMethod ?? noopRegisterGatewayMethod,
registerCli: handlers.registerCli ?? noopRegisterCli,
registerService: handlers.registerService ?? noopRegisterService,
registerCliBackend: handlers.registerCliBackend ?? noopRegisterCliBackend,
registerConfigMigration: handlers.registerConfigMigration ?? noopRegisterConfigMigration,
registerAutoEnableProbe: handlers.registerAutoEnableProbe ?? noopRegisterAutoEnableProbe,
registerProvider: handlers.registerProvider ?? noopRegisterProvider,

View File

@@ -2,7 +2,6 @@ import { listBundledPluginMetadata } from "./bundled-plugin-metadata.js";
export type BundledPluginContractSnapshot = {
pluginId: string;
cliBackendIds: string[];
providerIds: string[];
speechProviderIds: string[];
realtimeTranscriptionProviderIds: string[];
@@ -37,7 +36,6 @@ const BUNDLED_PLUGIN_METADATA_FOR_CAPABILITIES = listBundledPluginMetadata({
export const BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS: readonly BundledPluginContractSnapshot[] =
BUNDLED_PLUGIN_METADATA_FOR_CAPABILITIES.map(({ manifest }) => ({
pluginId: manifest.id,
cliBackendIds: uniqueStrings(manifest.cliBackends),
providerIds: uniqueStrings(manifest.providers),
speechProviderIds: uniqueStrings(manifest.contracts?.speechProviders),
realtimeTranscriptionProviderIds: uniqueStrings(
@@ -53,7 +51,6 @@ export const BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS: readonly BundledPluginContractSn
}))
.filter(
(entry) =>
entry.cliBackendIds.length > 0 ||
entry.providerIds.length > 0 ||
entry.speechProviderIds.length > 0 ||
entry.realtimeTranscriptionProviderIds.length > 0 ||

View File

@@ -119,7 +119,6 @@ function createCapabilityPluginRecord(params: {
toolNames: [],
hookNames: [],
channelIds: [],
cliBackendIds: [],
providerIds: [],
speechProviderIds: [],
realtimeTranscriptionProviderIds: [],
@@ -273,7 +272,6 @@ export function loadBundledCapabilityRuntimeRegistry(params: {
try {
const captured = createCapturedPluginRegistration();
void register(captured.api);
record.cliBackendIds.push(...captured.cliBackends.map((entry) => entry.id));
record.providerIds.push(...captured.providers.map((entry) => entry.id));
record.speechProviderIds.push(...captured.speechProviders.map((entry) => entry.id));
record.realtimeTranscriptionProviderIds.push(
@@ -298,15 +296,6 @@ export function loadBundledCapabilityRuntimeRegistry(params: {
);
record.toolNames.push(...captured.tools.map((entry) => entry.name));
registry.cliBackends?.push(
...captured.cliBackends.map((backend) => ({
pluginId: record.id,
pluginName: record.name,
backend,
source: record.source,
rootDir: record.rootDir,
})),
);
registry.providers.push(
...captured.providers.map((provider) => ({
pluginId: record.id,

View File

@@ -4,7 +4,6 @@ import type { MemoryEmbeddingProviderAdapter } from "./memory-embedding-provider
import type { PluginRuntime } from "./runtime/types.js";
import type {
AnyAgentTool,
CliBackendPlugin,
ImageGenerationProviderPlugin,
MediaUnderstandingProviderPlugin,
OpenClawPluginApi,
@@ -29,7 +28,6 @@ export type CapturedPluginRegistration = {
api: OpenClawPluginApi;
providers: ProviderPlugin[];
cliRegistrars: CapturedPluginCliRegistration[];
cliBackends: CliBackendPlugin[];
speechProviders: SpeechProviderPlugin[];
realtimeTranscriptionProviders: RealtimeTranscriptionProviderPlugin[];
realtimeVoiceProviders: RealtimeVoiceProviderPlugin[];
@@ -48,7 +46,6 @@ export function createCapturedPluginRegistration(params?: {
}): CapturedPluginRegistration {
const providers: ProviderPlugin[] = [];
const cliRegistrars: CapturedPluginCliRegistration[] = [];
const cliBackends: CliBackendPlugin[] = [];
const speechProviders: SpeechProviderPlugin[] = [];
const realtimeTranscriptionProviders: RealtimeTranscriptionProviderPlugin[] = [];
const realtimeVoiceProviders: RealtimeVoiceProviderPlugin[] = [];
@@ -69,7 +66,6 @@ export function createCapturedPluginRegistration(params?: {
return {
providers,
cliRegistrars,
cliBackends,
speechProviders,
realtimeTranscriptionProviders,
realtimeVoiceProviders,
@@ -116,9 +112,6 @@ export function createCapturedPluginRegistration(params?: {
registerProvider(provider: ProviderPlugin) {
providers.push(provider);
},
registerCliBackend(backend: CliBackendPlugin) {
cliBackends.push(backend);
},
registerSpeechProvider(provider: SpeechProviderPlugin) {
speechProviders.push(provider);
},

View File

@@ -11,7 +11,6 @@ import { hasKind } from "./slots.js";
function hasRuntimeContractSurface(plugin: PluginManifestRecord): boolean {
return Boolean(
plugin.providers.length > 0 ||
plugin.cliBackends.length > 0 ||
plugin.contracts?.speechProviders?.length ||
plugin.contracts?.mediaUnderstandingProviders?.length ||
plugin.contracts?.imageGenerationProviders?.length ||

View File

@@ -1,13 +0,0 @@
import { getActivePluginRegistry } from "./runtime.js";
import type { CliBackendPlugin } from "./types.js";
export type PluginCliBackendEntry = CliBackendPlugin & {
pluginId: string;
};
export function resolveRuntimeCliBackends(): PluginCliBackendEntry[] {
return (getActivePluginRegistry()?.cliBackends ?? []).map((entry) => ({
...entry.backend,
pluginId: entry.pluginId,
}));
}

View File

@@ -57,7 +57,6 @@ type VideoGenerationProviderContractEntry = CapabilityContractEntry<VideoGenerat
type PluginRegistrationContractEntry = {
pluginId: string;
cliBackendIds: string[];
providerIds: string[];
speechProviderIds: string[];
realtimeTranscriptionProviderIds: string[];
@@ -604,7 +603,6 @@ export const videoGenerationProviderContractRegistry: VideoGenerationProviderCon
function loadPluginRegistrationContractRegistry(): PluginRegistrationContractEntry[] {
return BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.map((entry) => ({
pluginId: entry.pluginId,
cliBackendIds: uniqueStrings(entry.cliBackendIds),
providerIds: uniqueStrings(entry.providerIds),
speechProviderIds: uniqueStrings(entry.speechProviderIds),
realtimeTranscriptionProviderIds: uniqueStrings(entry.realtimeTranscriptionProviderIds),

View File

@@ -589,7 +589,6 @@ function createPluginRecord(params: {
toolNames: [],
hookNames: [],
channelIds: [],
cliBackendIds: [],
providerIds: [],
speechProviderIds: [],
realtimeTranscriptionProviderIds: [],

View File

@@ -63,7 +63,6 @@ export type PluginManifestRecord = {
channels: string[];
providers: string[];
modelSupport?: PluginManifestModelSupport;
cliBackends: string[];
providerAuthEnvVars?: Record<string, string[]>;
providerAuthChoices?: PluginManifest["providerAuthChoices"];
skills: string[];
@@ -281,7 +280,6 @@ function buildRecord(params: {
channels: params.manifest.channels ?? [],
providers: params.manifest.providers ?? [],
modelSupport: params.manifest.modelSupport,
cliBackends: params.manifest.cliBackends ?? [],
providerAuthEnvVars: params.manifest.providerAuthEnvVars,
providerAuthChoices: params.manifest.providerAuthChoices,
skills: params.manifest.skills ?? [],
@@ -344,7 +342,6 @@ function buildBundleRecord(params: {
bundleCapabilities: params.manifest.capabilities,
channels: [],
providers: [],
cliBackends: [],
skills: params.manifest.skills ?? [],
settingsFiles: params.manifest.settingsFiles ?? [],
hooks: params.manifest.hooks ?? [],

View File

@@ -48,8 +48,6 @@ export type PluginManifest = {
* Use this for shorthand model refs that omit an explicit provider prefix.
*/
modelSupport?: PluginManifestModelSupport;
/** Cheap startup activation lookup for plugin-owned CLI inference backends. */
cliBackends?: string[];
/** Cheap provider-auth env lookup without booting plugin runtime. */
providerAuthEnvVars?: Record<string, string[]>;
/**
@@ -374,7 +372,6 @@ export function loadPluginManifest(
const channels = normalizeStringList(raw.channels);
const providers = normalizeStringList(raw.providers);
const modelSupport = normalizeManifestModelSupport(raw.modelSupport);
const cliBackends = normalizeStringList(raw.cliBackends);
const providerAuthEnvVars = normalizeStringListRecord(raw.providerAuthEnvVars);
const providerAuthChoices = normalizeProviderAuthChoices(raw.providerAuthChoices);
const skills = normalizeStringList(raw.skills);
@@ -400,7 +397,6 @@ export function loadPluginManifest(
channels,
providers,
modelSupport,
cliBackends,
providerAuthEnvVars,
providerAuthChoices,
skills,

View File

@@ -203,14 +203,8 @@ export function resolveOwningPluginIdsForProvider(params: {
const registry = resolveManifestRegistry(params);
const pluginIds = registry.plugins
.filter(
(plugin) =>
plugin.providers.some(
(providerId) => normalizeProviderId(providerId) === normalizedProvider,
) ||
plugin.cliBackends.some(
(backendId) => normalizeProviderId(backendId) === normalizedProvider,
),
.filter((plugin) =>
plugin.providers.some((providerId) => normalizeProviderId(providerId) === normalizedProvider),
)
.map((plugin) => plugin.id);

View File

@@ -9,7 +9,6 @@ export function createEmptyPluginRegistry(): PluginRegistry {
channels: [],
channelSetups: [],
providers: [],
cliBackends: [],
speechProviders: [],
realtimeTranscriptionProviders: [],
realtimeVoiceProviders: [],

View File

@@ -39,7 +39,6 @@ import {
stripPromptMutationFieldsFromLegacyHookResult,
} from "./types.js";
import type {
CliBackendPlugin,
ImageGenerationProviderPlugin,
RealtimeTranscriptionProviderPlugin,
OpenClawPluginApi,
@@ -130,14 +129,6 @@ export type PluginProviderRegistration = {
rootDir?: string;
};
export type PluginCliBackendRegistration = {
pluginId: string;
pluginName?: string;
backend: CliBackendPlugin;
source: string;
rootDir?: string;
};
type PluginOwnedProviderRegistration<T extends { id: string }> = {
pluginId: string;
pluginName?: string;
@@ -224,7 +215,6 @@ export type PluginRecord = {
toolNames: string[];
hookNames: string[];
channelIds: string[];
cliBackendIds: string[];
providerIds: string[];
speechProviderIds: string[];
realtimeTranscriptionProviderIds: string[];
@@ -256,7 +246,6 @@ export type PluginRegistry = {
channels: PluginChannelRegistration[];
channelSetups: PluginChannelSetupRegistration[];
providers: PluginProviderRegistration[];
cliBackends?: PluginCliBackendRegistration[];
speechProviders: PluginSpeechProviderRegistration[];
realtimeTranscriptionProviders: PluginRealtimeTranscriptionProviderRegistration[];
realtimeVoiceProviders: PluginRealtimeVoiceProviderRegistration[];
@@ -645,40 +634,6 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
});
};
const registerCliBackend = (record: PluginRecord, backend: CliBackendPlugin) => {
const id = backend.id.trim();
if (!id) {
pushDiagnostic({
level: "error",
pluginId: record.id,
source: record.source,
message: "cli backend registration missing id",
});
return;
}
const existing = (registry.cliBackends ?? []).find((entry) => entry.backend.id === id);
if (existing) {
pushDiagnostic({
level: "error",
pluginId: record.id,
source: record.source,
message: `cli backend already registered: ${id} (${existing.pluginId})`,
});
return;
}
(registry.cliBackends ??= []).push({
pluginId: record.id,
pluginName: record.name,
backend: {
...backend,
id,
},
source: record.source,
rootDir: record.rootDir,
});
record.cliBackendIds.push(id);
};
const registerUniqueProviderLike = <
T extends { id: string },
R extends PluginOwnedProviderRegistration<T>,
@@ -1096,7 +1051,6 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
registerGatewayMethod: (method, handler, opts) =>
registerGatewayMethod(record, method, handler, opts),
registerService: (service) => registerService(record, service),
registerCliBackend: (backend) => registerCliBackend(record, backend),
registerInteractiveHandler: (registration) => {
const result = registerPluginInteractiveHandler(record.id, registration, {
pluginName: record.name,
@@ -1284,7 +1238,6 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
registerTool,
registerChannel,
registerProvider,
registerCliBackend,
registerSpeechProvider,
registerRealtimeTranscriptionProvider,
registerRealtimeVoiceProvider,

View File

@@ -15,7 +15,6 @@ import {
shouldPreferNativeJiti,
} from "./sdk-alias.js";
import type {
CliBackendPlugin,
OpenClawPluginModule,
PluginConfigMigration,
PluginLogger,
@@ -34,11 +33,6 @@ type SetupProviderEntry = {
provider: ProviderPlugin;
};
type SetupCliBackendEntry = {
pluginId: string;
backend: CliBackendPlugin;
};
type SetupConfigMigrationEntry = {
pluginId: string;
migrate: PluginConfigMigration;
@@ -51,7 +45,6 @@ type SetupAutoEnableProbeEntry = {
type PluginSetupRegistry = {
providers: SetupProviderEntry[];
cliBackends: SetupCliBackendEntry[];
configMigrations: SetupConfigMigrationEntry[];
autoEnableProbes: SetupAutoEnableProbeEntry[];
};
@@ -158,11 +151,9 @@ export function resolvePluginSetupRegistry(params?: {
}
const providers: SetupProviderEntry[] = [];
const cliBackends: SetupCliBackendEntry[] = [];
const configMigrations: SetupConfigMigrationEntry[] = [];
const autoEnableProbes: SetupAutoEnableProbeEntry[] = [];
const providerKeys = new Set<string>();
const cliBackendKeys = new Set<string>();
const discovery = discoverOpenClawPlugins({
workspaceDir: params?.workspaceDir,
@@ -222,17 +213,6 @@ export function resolvePluginSetupRegistry(params?: {
provider,
});
},
registerCliBackend(backend) {
const key = `${record.id}:${normalizeProviderId(backend.id)}`;
if (cliBackendKeys.has(key)) {
return;
}
cliBackendKeys.add(key);
cliBackends.push({
pluginId: record.id,
backend,
});
},
registerConfigMigration(migrate) {
configMigrations.push({
pluginId: record.id,
@@ -260,7 +240,6 @@ export function resolvePluginSetupRegistry(params?: {
const registry = {
providers,
cliBackends,
configMigrations,
autoEnableProbes,
} satisfies PluginSetupRegistry;
@@ -278,17 +257,6 @@ export function resolvePluginSetupProvider(params: {
)?.provider;
}
export function resolvePluginSetupCliBackend(params: {
backend: string;
workspaceDir?: string;
env?: NodeJS.ProcessEnv;
}): SetupCliBackendEntry | undefined {
const normalized = normalizeProviderId(params.backend);
return resolvePluginSetupRegistry(params).cliBackends.find(
(entry) => normalizeProviderId(entry.backend.id) === normalized,
);
}
export function runPluginSetupConfigMigrations(params: {
config: OpenClawConfig;
workspaceDir?: string;

View File

@@ -232,7 +232,6 @@ export function buildPluginDiagnosticsReport(params?: PluginReportParams): Plugi
function buildCapabilityEntries(plugin: PluginRegistry["plugins"][number]) {
return [
{ kind: "cli-backend" as const, ids: plugin.cliBackendIds ?? [] },
{ kind: "text-inference" as const, ids: plugin.providerIds },
{ kind: "speech" as const, ids: plugin.speechProviderIds },
{ kind: "realtime-transcription" as const, ids: plugin.realtimeTranscriptionProviderIds },

View File

@@ -22,11 +22,7 @@ import type { ThinkLevel } from "../auto-reply/thinking.js";
import type { ReplyPayload } from "../auto-reply/types.js";
import type { ChannelId, ChannelPlugin } from "../channels/plugins/types.js";
import type { OpenClawConfig } from "../config/config.js";
import type {
CliBackendConfig,
ModelProviderAuthMode,
ModelProviderConfig,
} from "../config/types.js";
import type { ModelProviderAuthMode, ModelProviderConfig } from "../config/types.js";
import type { ModelCompatConfig } from "../config/types.models.js";
import type { TtsAutoMode } from "../config/types.tts.js";
import type { OperatorScope } from "../gateway/method-scopes.js";
@@ -1947,28 +1943,6 @@ export type OpenClawPluginService = {
stop?: (ctx: OpenClawPluginServiceContext) => void | Promise<void>;
};
/** Plugin-owned CLI backend defaults used by the text-only CLI runner. */
export type CliBackendPlugin = {
/** Provider id used in model refs, for example `codex-cli/gpt-5`. */
id: string;
/** Default backend config before user overrides from `agents.defaults.cliBackends`. */
config: CliBackendConfig;
/**
* Whether OpenClaw should inject bundle MCP config for this backend.
*
* Keep this opt-in. Only backends that explicitly consume an MCP config file
* should enable it.
*/
bundleMcp?: boolean;
/**
* Optional config normalizer applied after user overrides merge.
*
* Use this for backend-specific compatibility rewrites when old config
* shapes need to stay working.
*/
normalizeConfig?: (config: CliBackendConfig) => CliBackendConfig;
};
export type OpenClawPluginChannelRegistration = {
plugin: ChannelPlugin;
};
@@ -2067,8 +2041,6 @@ export type OpenClawPluginApi = {
},
) => void;
registerService: (service: OpenClawPluginService) => void;
/** Register a text-only CLI backend used by the local CLI runner. */
registerCliBackend: (backend: CliBackendPlugin) => void;
/** Register a lightweight config migration that can run before plugin runtime loads. */
registerConfigMigration: (migrate: PluginConfigMigration) => void;
/** Register a lightweight config probe that can auto-enable this plugin generically. */