feat: enable/disable providers from settings
Adds a per-provider toggle in Settings → Providers, persisted via daemon config, so users can turn off providers they don't have installed (or don't want to use) without removing them from the registry. Disabled providers stay visible everywhere — settings, `paseo provider ls`, MCP `list_providers`, model/mode lists — marked as disabled rather than silently filtered. Availability probes are skipped for them, and attempts to launch an agent or fetch models/modes from a disabled provider return a clear "Provider '<id>' is disabled" error. Schema additions (`enabled` on `ProviderSnapshotEntry`, MCP provider summary) are backward-compatible: optional with a default of true so older clients continue to parse new daemon messages. CLI: `paseo provider ls` gains an ENABLED column; JSON output includes the new field.
This commit is contained in:
@@ -169,6 +169,43 @@ function resolveRegisteredProviderIds(
|
||||
: agentManager.getRegisteredProviderIds();
|
||||
}
|
||||
|
||||
interface ProviderSummary {
|
||||
id: AgentProvider;
|
||||
label: string;
|
||||
description: string;
|
||||
enabled: boolean;
|
||||
modes: ProviderDefinition["modes"];
|
||||
status: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
async function resolveProviderSummary(
|
||||
provider: ProviderDefinition,
|
||||
logger: Logger,
|
||||
): Promise<ProviderSummary> {
|
||||
const base = {
|
||||
id: provider.id,
|
||||
label: provider.label,
|
||||
description: provider.description,
|
||||
modes: provider.modes,
|
||||
};
|
||||
if (!provider.enabled) {
|
||||
return { ...base, enabled: false, status: "unavailable" };
|
||||
}
|
||||
try {
|
||||
const available = await provider.createClient(logger).isAvailable();
|
||||
return { ...base, enabled: true, status: available ? "available" : "unavailable" };
|
||||
} catch (availabilityError) {
|
||||
return {
|
||||
...base,
|
||||
enabled: true,
|
||||
status: "unavailable",
|
||||
error:
|
||||
availabilityError instanceof Error ? availabilityError.message : String(availabilityError),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function compareAgentListItems(a: AgentListItemPayload, b: AgentListItemPayload): number {
|
||||
const attentionDelta =
|
||||
Number(b.requiresAttention ?? false) - Number(a.requiresAttention ?? false);
|
||||
@@ -1650,35 +1687,9 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
|
||||
},
|
||||
async () => {
|
||||
const providers = await Promise.all(
|
||||
Object.values(providerRegistry ?? {}).map(async (provider) => {
|
||||
let status = "unknown";
|
||||
let error: string | undefined;
|
||||
try {
|
||||
status = (await provider.createClient(childLogger).isAvailable())
|
||||
? "available"
|
||||
: "unavailable";
|
||||
} catch (availabilityError) {
|
||||
status = "unavailable";
|
||||
error =
|
||||
availabilityError instanceof Error
|
||||
? availabilityError.message
|
||||
: String(availabilityError);
|
||||
}
|
||||
const summary = {
|
||||
id: provider.id,
|
||||
label: provider.label,
|
||||
status,
|
||||
modes: provider.modes.map((mode) => ({
|
||||
id: mode.id,
|
||||
label: mode.label,
|
||||
...(mode.description ? { description: mode.description } : {}),
|
||||
})),
|
||||
};
|
||||
if (error) {
|
||||
return Object.assign(summary, { error });
|
||||
}
|
||||
return summary;
|
||||
}),
|
||||
Object.values(providerRegistry ?? {}).map((provider) =>
|
||||
resolveProviderSummary(provider, childLogger),
|
||||
),
|
||||
);
|
||||
return {
|
||||
content: [],
|
||||
@@ -1709,6 +1720,9 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
|
||||
if (!definition) {
|
||||
throw new Error(`Provider ${provider} is not configured`);
|
||||
}
|
||||
if (!definition.enabled) {
|
||||
throw new Error(`Provider '${provider}' is disabled`);
|
||||
}
|
||||
|
||||
const models = await definition.fetchModels({ cwd: resolveSnapshotCwd(), force: false });
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user