openclaw / src /cli /capability-cli /shared.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
f778c12 verified
Raw
History Blame Contribute Delete
7.96 kB
import {
parseStrictFiniteNumber,
parseStrictPositiveInteger,
} from "@openclaw/normalization-core/number-coercion";
import type { Command } from "commander";
import {
resolveAgentOperationAgentId,
resolveConfiguredAgentId,
} from "../../agents/agent-scope-config.js";
import { resolveAgentDir } from "../../agents/agent-scope.js";
import {
listProfilesForProvider,
loadAuthProfileStoreForRuntime,
} from "../../agents/auth-profiles.js";
import {
getRuntimeConfig,
getRuntimeConfigSourceSnapshot,
setRuntimeConfigSnapshot,
} from "../../config/config.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { defaultRuntime } from "../../runtime.js";
import { getProviderEnvVars } from "../../secrets/provider-env-vars.js";
import { runCommandWithRuntime } from "../cli-utils.js";
import { resolveCommandConfigWithSecrets } from "../command-config-resolution.js";
import { inheritOptionFromParent } from "../command-options.js";
import { parseTimeoutMsWithFallback } from "../parse-timeout.js";
import type { CapabilityTransport } from "./metadata.js";
import { emitJsonOrText } from "./output.js";
export function registerLocalProvidersCommand<T>(
parent: Command,
description: string,
collect: (cfg: OpenClawConfig, agentId: string) => T | Promise<T>,
format: (value: T) => string,
): void {
parent
.command("providers")
.description(description)
.option("--agent <id>", "Agent whose provider state should be inspected")
.option("--json", "Output JSON", false)
.action(async (opts, command) => {
await runCommandWithRuntime(defaultRuntime, async () => {
const cfg = getRuntimeConfig();
const agentId = resolveCapabilityProviderAgentId(
cfg,
resolveCapabilityAgentOption(command, opts.agent),
);
const result = await collect(cfg, agentId);
emitJsonOrText(defaultRuntime, Boolean(opts.json), result, format);
});
});
}
export function resolveTransport(opts: {
local?: boolean;
gateway?: boolean;
supported: Array<CapabilityTransport>;
defaultTransport: CapabilityTransport;
}): CapabilityTransport {
if (opts.local && opts.gateway) {
throw new Error("Pass only one of --local or --gateway.");
}
if (opts.local) {
if (!opts.supported.includes("local")) {
throw new Error("This command does not support --local.");
}
return "local";
}
if (opts.gateway) {
if (!opts.supported.includes("gateway")) {
throw new Error("This command does not support --gateway.");
}
return "gateway";
}
return opts.defaultTransport;
}
function hasOwnKeys(value: unknown): boolean {
return Boolean(
value && typeof value === "object" && Object.keys(value as Record<string, unknown>).length > 0,
);
}
export function resolveSelectedProviderFromModelRef(
modelRef: string | undefined,
): string | undefined {
return resolveModelRefOverride(modelRef).provider;
}
export function resolveCapabilityProviderAgentId(
cfg: OpenClawConfig,
rawAgentId: string | undefined,
surface = "inference provider inspection",
): string {
const requestedAgentId = rawAgentId?.trim();
if (rawAgentId !== undefined && !requestedAgentId) {
throw new Error("--agent must not be blank");
}
const agentId = resolveAgentOperationAgentId(cfg, requestedAgentId, {
surface,
hint: "Pass --agent <id> or set agents.defaults.systemAgent.agentId.",
});
return resolveConfiguredAgentId(cfg, agentId);
}
export function resolveCapabilityAgentOption(
command: Command | undefined,
rawAgentId: unknown,
): string | undefined {
return typeof rawAgentId === "string"
? rawAgentId
: inheritOptionFromParent<string>(command, "agent");
}
function getAuthProfileIdsForProvider(
cfg: OpenClawConfig,
providerId: string,
agentId: string,
): string[] {
const agentDir = resolveAgentDir(cfg, agentId);
const store = loadAuthProfileStoreForRuntime(agentDir);
return listProfilesForProvider(store, providerId);
}
export function providerHasGenericConfig(params: {
cfg: OpenClawConfig;
providerId: string;
/** Omit only for aggregate/global callers that intentionally exclude agent auth stores. */
agentId?: string;
envVars?: string[];
}): boolean {
const modelsProviders = (params.cfg.models?.providers ?? {}) as Record<string, unknown>;
const pluginEntries = (params.cfg.plugins?.entries ?? {}) as Record<string, { config?: unknown }>;
const ttsProviders = (params.cfg.tts?.providers ?? {}) as Record<string, unknown>;
const envVars =
params.envVars ??
getProviderEnvVars(params.providerId, {
config: params.cfg,
includeUntrustedWorkspacePlugins: false,
});
const envConfigured = envVars.some((envVar) => Boolean(process.env[envVar]?.trim()));
return (
(params.agentId
? getAuthProfileIdsForProvider(params.cfg, params.providerId, params.agentId).length > 0
: false) ||
hasOwnKeys(modelsProviders[params.providerId]) ||
hasOwnKeys(pluginEntries[params.providerId]?.config) ||
hasOwnKeys(ttsProviders[params.providerId]) ||
envConfigured
);
}
export function resolveModelRefOverride(raw: string | undefined): {
provider?: string;
model?: string;
} {
const trimmed = raw?.trim();
if (!trimmed) {
return {};
}
const slash = trimmed.indexOf("/");
if (slash <= 0 || slash === trimmed.length - 1) {
return { model: trimmed };
}
return {
provider: trimmed.slice(0, slash),
model: trimmed.slice(slash + 1),
};
}
export function requireProviderModelOverride(
raw: string | undefined,
): { provider: string; model: string } | undefined {
const resolved = resolveModelRefOverride(raw);
if (!raw?.trim()) {
return undefined;
}
if (!resolved.provider || !resolved.model) {
throw new Error("Model overrides must use the form <provider/model>.");
}
return {
provider: resolved.provider,
model: resolved.model,
};
}
export function parseOptionalFiniteNumber(
raw: string | number | undefined,
label: string,
): number | undefined {
if (raw === undefined) {
return undefined;
}
const value = parseStrictFiniteNumber(raw);
if (value === undefined) {
throw new Error(`${label} must be a finite number`);
}
return value;
}
export function parseOptionalPositiveInteger(raw: unknown, label: string): number | undefined {
if (raw === undefined) {
return undefined;
}
const value = parseStrictPositiveInteger(raw);
if (value === undefined) {
throw new Error(`${label} must be a positive integer`);
}
return value;
}
export function parseOptionalTimeoutMs(raw: string | number | undefined): number | undefined {
if (raw === undefined) {
return undefined;
}
return parseTimeoutMsWithFallback(raw, 0, { invalidType: "error" });
}
export async function resolveLocalCapabilityRuntimeConfig(params: {
commandName: string;
targetIds: Set<string>;
allowedPaths?: Set<string>;
forcedActivePaths?: Set<string>;
optionalActivePaths?: Set<string>;
config?: OpenClawConfig;
}): Promise<OpenClawConfig> {
const cfg = params.config ?? getRuntimeConfig();
const { effectiveConfig } = await resolveCommandConfigWithSecrets({
config: cfg,
commandName: params.commandName,
targetIds: params.targetIds,
...(params.allowedPaths ? { allowedPaths: params.allowedPaths } : {}),
...(params.forcedActivePaths ? { forcedActivePaths: params.forcedActivePaths } : {}),
...(params.optionalActivePaths ? { optionalActivePaths: params.optionalActivePaths } : {}),
runtime: defaultRuntime,
autoEnable: true,
});
pinRuntimeConfigSnapshot(effectiveConfig);
return effectiveConfig;
}
export function pinRuntimeConfigSnapshot(config: OpenClawConfig): void {
const sourceConfig = getRuntimeConfigSourceSnapshot();
if (sourceConfig) {
setRuntimeConfigSnapshot(config, sourceConfig);
} else {
setRuntimeConfigSnapshot(config);
}
}