mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 04:41:25 +00:00
chore: Enable "curly" rule to avoid single-statement if confusion/errors.
This commit is contained in:
@@ -18,7 +18,9 @@ export async function modelsAliasesListCommand(
|
||||
const aliases = Object.entries(models).reduce<Record<string, string>>(
|
||||
(acc, [modelKey, entry]) => {
|
||||
const alias = entry?.alias?.trim();
|
||||
if (alias) acc[alias] = modelKey;
|
||||
if (alias) {
|
||||
acc[alias] = modelKey;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{},
|
||||
|
||||
@@ -33,7 +33,9 @@ export async function modelsAuthOrderGetCommand(
|
||||
runtime: RuntimeEnv,
|
||||
) {
|
||||
const rawProvider = opts.provider?.trim();
|
||||
if (!rawProvider) throw new Error("Missing --provider.");
|
||||
if (!rawProvider) {
|
||||
throw new Error("Missing --provider.");
|
||||
}
|
||||
const provider = normalizeProviderId(rawProvider);
|
||||
|
||||
const cfg = loadConfig();
|
||||
@@ -71,7 +73,9 @@ export async function modelsAuthOrderClearCommand(
|
||||
runtime: RuntimeEnv,
|
||||
) {
|
||||
const rawProvider = opts.provider?.trim();
|
||||
if (!rawProvider) throw new Error("Missing --provider.");
|
||||
if (!rawProvider) {
|
||||
throw new Error("Missing --provider.");
|
||||
}
|
||||
const provider = normalizeProviderId(rawProvider);
|
||||
|
||||
const cfg = loadConfig();
|
||||
@@ -81,7 +85,9 @@ export async function modelsAuthOrderClearCommand(
|
||||
provider,
|
||||
order: null,
|
||||
});
|
||||
if (!updated) throw new Error("Failed to update auth-profiles.json (lock busy?).");
|
||||
if (!updated) {
|
||||
throw new Error("Failed to update auth-profiles.json (lock busy?).");
|
||||
}
|
||||
|
||||
runtime.log(`Agent: ${agentId}`);
|
||||
runtime.log(`Provider: ${provider}`);
|
||||
@@ -93,7 +99,9 @@ export async function modelsAuthOrderSetCommand(
|
||||
runtime: RuntimeEnv,
|
||||
) {
|
||||
const rawProvider = opts.provider?.trim();
|
||||
if (!rawProvider) throw new Error("Missing --provider.");
|
||||
if (!rawProvider) {
|
||||
throw new Error("Missing --provider.");
|
||||
}
|
||||
const provider = normalizeProviderId(rawProvider);
|
||||
|
||||
const cfg = loadConfig();
|
||||
@@ -123,7 +131,9 @@ export async function modelsAuthOrderSetCommand(
|
||||
provider,
|
||||
order: requested,
|
||||
});
|
||||
if (!updated) throw new Error("Failed to update auth-profiles.json (lock busy?).");
|
||||
if (!updated) {
|
||||
throw new Error("Failed to update auth-profiles.json (lock busy?).");
|
||||
}
|
||||
|
||||
runtime.log(`Agent: ${agentId}`);
|
||||
runtime.log(`Provider: ${provider}`);
|
||||
|
||||
@@ -52,9 +52,13 @@ type TokenProvider = "anthropic";
|
||||
|
||||
function resolveTokenProvider(raw?: string): TokenProvider | "custom" | null {
|
||||
const trimmed = raw?.trim();
|
||||
if (!trimmed) return null;
|
||||
if (!trimmed) {
|
||||
return null;
|
||||
}
|
||||
const normalized = normalizeProviderId(trimmed);
|
||||
if (normalized === "anthropic") return "anthropic";
|
||||
if (normalized === "anthropic") {
|
||||
return "anthropic";
|
||||
}
|
||||
return "custom";
|
||||
}
|
||||
|
||||
@@ -80,7 +84,9 @@ export async function modelsAuthSetupTokenCommand(
|
||||
message: "Have you run `claude setup-token` and copied the token?",
|
||||
initialValue: true,
|
||||
});
|
||||
if (!proceed) return;
|
||||
if (!proceed) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const tokenInput = await text({
|
||||
@@ -239,7 +245,9 @@ function resolveProviderMatch(
|
||||
rawProvider?: string,
|
||||
): ProviderPlugin | null {
|
||||
const raw = rawProvider?.trim();
|
||||
if (!raw) return null;
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
const normalized = normalizeProviderId(raw);
|
||||
return (
|
||||
providers.find((provider) => normalizeProviderId(provider.id) === normalized) ??
|
||||
@@ -253,7 +261,9 @@ function resolveProviderMatch(
|
||||
|
||||
function pickAuthMethod(provider: ProviderPlugin, rawMethod?: string): ProviderAuthMethod | null {
|
||||
const raw = rawMethod?.trim();
|
||||
if (!raw) return null;
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
const normalized = raw.toLowerCase();
|
||||
return (
|
||||
provider.auth.find((method) => method.id.toLowerCase() === normalized) ??
|
||||
@@ -307,8 +317,12 @@ function applyDefaultModel(cfg: OpenClawConfig, model: string): OpenClawConfig {
|
||||
}
|
||||
|
||||
function credentialMode(credential: AuthProfileCredential): "api_key" | "oauth" | "token" {
|
||||
if (credential.type === "api_key") return "api_key";
|
||||
if (credential.type === "token") return "token";
|
||||
if (credential.type === "api_key") {
|
||||
return "api_key";
|
||||
}
|
||||
if (credential.type === "token") {
|
||||
return "token";
|
||||
}
|
||||
return "oauth";
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ export async function modelsFallbacksListCommand(
|
||||
return;
|
||||
}
|
||||
if (opts.plain) {
|
||||
for (const entry of fallbacks) runtime.log(entry);
|
||||
for (const entry of fallbacks) {
|
||||
runtime.log(entry);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -32,7 +34,9 @@ export async function modelsFallbacksListCommand(
|
||||
runtime.log("- none");
|
||||
return;
|
||||
}
|
||||
for (const entry of fallbacks) runtime.log(`- ${entry}`);
|
||||
for (const entry of fallbacks) {
|
||||
runtime.log(`- ${entry}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function modelsFallbacksAddCommand(modelRaw: string, runtime: RuntimeEnv) {
|
||||
@@ -40,7 +44,9 @@ export async function modelsFallbacksAddCommand(modelRaw: string, runtime: Runti
|
||||
const resolved = resolveModelTarget({ raw: modelRaw, cfg });
|
||||
const targetKey = modelKey(resolved.provider, resolved.model);
|
||||
const nextModels = { ...cfg.agents?.defaults?.models };
|
||||
if (!nextModels[targetKey]) nextModels[targetKey] = {};
|
||||
if (!nextModels[targetKey]) {
|
||||
nextModels[targetKey] = {};
|
||||
}
|
||||
const aliasIndex = buildModelAliasIndex({
|
||||
cfg,
|
||||
defaultProvider: DEFAULT_PROVIDER,
|
||||
@@ -57,7 +63,9 @@ export async function modelsFallbacksAddCommand(modelRaw: string, runtime: Runti
|
||||
.filter((entry): entry is NonNullable<typeof entry> => Boolean(entry))
|
||||
.map((entry) => modelKey(entry.ref.provider, entry.ref.model));
|
||||
|
||||
if (existingKeys.includes(targetKey)) return cfg;
|
||||
if (existingKeys.includes(targetKey)) {
|
||||
return cfg;
|
||||
}
|
||||
|
||||
const existingModel = cfg.agents?.defaults?.model as
|
||||
| { primary?: string; fallbacks?: string[] }
|
||||
@@ -98,7 +106,9 @@ export async function modelsFallbacksRemoveCommand(modelRaw: string, runtime: Ru
|
||||
defaultProvider: DEFAULT_PROVIDER,
|
||||
aliasIndex,
|
||||
});
|
||||
if (!resolvedEntry) return true;
|
||||
if (!resolvedEntry) {
|
||||
return true;
|
||||
}
|
||||
return modelKey(resolvedEntry.ref.provider, resolvedEntry.ref.model) !== targetKey;
|
||||
});
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ export async function modelsImageFallbacksListCommand(
|
||||
return;
|
||||
}
|
||||
if (opts.plain) {
|
||||
for (const entry of fallbacks) runtime.log(entry);
|
||||
for (const entry of fallbacks) {
|
||||
runtime.log(entry);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -32,7 +34,9 @@ export async function modelsImageFallbacksListCommand(
|
||||
runtime.log("- none");
|
||||
return;
|
||||
}
|
||||
for (const entry of fallbacks) runtime.log(`- ${entry}`);
|
||||
for (const entry of fallbacks) {
|
||||
runtime.log(`- ${entry}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function modelsImageFallbacksAddCommand(modelRaw: string, runtime: RuntimeEnv) {
|
||||
@@ -40,7 +44,9 @@ export async function modelsImageFallbacksAddCommand(modelRaw: string, runtime:
|
||||
const resolved = resolveModelTarget({ raw: modelRaw, cfg });
|
||||
const targetKey = modelKey(resolved.provider, resolved.model);
|
||||
const nextModels = { ...cfg.agents?.defaults?.models };
|
||||
if (!nextModels[targetKey]) nextModels[targetKey] = {};
|
||||
if (!nextModels[targetKey]) {
|
||||
nextModels[targetKey] = {};
|
||||
}
|
||||
const aliasIndex = buildModelAliasIndex({
|
||||
cfg,
|
||||
defaultProvider: DEFAULT_PROVIDER,
|
||||
@@ -57,7 +63,9 @@ export async function modelsImageFallbacksAddCommand(modelRaw: string, runtime:
|
||||
.filter((entry): entry is NonNullable<typeof entry> => Boolean(entry))
|
||||
.map((entry) => modelKey(entry.ref.provider, entry.ref.model));
|
||||
|
||||
if (existingKeys.includes(targetKey)) return cfg;
|
||||
if (existingKeys.includes(targetKey)) {
|
||||
return cfg;
|
||||
}
|
||||
|
||||
const existingModel = cfg.agents?.defaults?.imageModel as
|
||||
| { primary?: string; fallbacks?: string[] }
|
||||
@@ -100,7 +108,9 @@ export async function modelsImageFallbacksRemoveCommand(modelRaw: string, runtim
|
||||
defaultProvider: DEFAULT_PROVIDER,
|
||||
aliasIndex,
|
||||
});
|
||||
if (!resolvedEntry) return true;
|
||||
if (!resolvedEntry) {
|
||||
return true;
|
||||
}
|
||||
return modelKey(resolvedEntry.ref.provider, resolvedEntry.ref.model) !== targetKey;
|
||||
});
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ export function resolveProviderAuthOverview(params: {
|
||||
const profiles = listProfilesForProvider(store, provider);
|
||||
const withUnusableSuffix = (base: string, profileId: string) => {
|
||||
const unusableUntil = resolveProfileUnusableUntilForDisplay(store, profileId);
|
||||
if (!unusableUntil || now >= unusableUntil) return base;
|
||||
if (!unusableUntil || now >= unusableUntil) {
|
||||
return base;
|
||||
}
|
||||
const stats = store.usageStats?.[profileId];
|
||||
const kind =
|
||||
typeof stats?.disabledUntil === "number" && now < stats.disabledUntil
|
||||
@@ -34,7 +36,9 @@ export function resolveProviderAuthOverview(params: {
|
||||
};
|
||||
const labels = profiles.map((profileId) => {
|
||||
const profile = store.profiles[profileId];
|
||||
if (!profile) return `${profileId}=missing`;
|
||||
if (!profile) {
|
||||
return `${profileId}=missing`;
|
||||
}
|
||||
if (profile.type === "api_key") {
|
||||
return withUnusableSuffix(`${profileId}=${maskApiKey(profile.key)}`, profileId);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,9 @@ export function resolveConfiguredEntries(cfg: OpenClawConfig) {
|
||||
defaultProvider: DEFAULT_PROVIDER,
|
||||
aliasIndex,
|
||||
});
|
||||
if (!resolved) return;
|
||||
if (!resolved) {
|
||||
return;
|
||||
}
|
||||
addEntry(resolved.ref, `fallback#${idx + 1}`);
|
||||
});
|
||||
|
||||
@@ -64,7 +66,9 @@ export function resolveConfiguredEntries(cfg: OpenClawConfig) {
|
||||
defaultProvider: DEFAULT_PROVIDER,
|
||||
aliasIndex,
|
||||
});
|
||||
if (resolved) addEntry(resolved.ref, "image");
|
||||
if (resolved) {
|
||||
addEntry(resolved.ref, "image");
|
||||
}
|
||||
}
|
||||
|
||||
imageFallbacks.forEach((raw, idx) => {
|
||||
@@ -73,13 +77,17 @@ export function resolveConfiguredEntries(cfg: OpenClawConfig) {
|
||||
defaultProvider: DEFAULT_PROVIDER,
|
||||
aliasIndex,
|
||||
});
|
||||
if (!resolved) return;
|
||||
if (!resolved) {
|
||||
return;
|
||||
}
|
||||
addEntry(resolved.ref, `img-fallback#${idx + 1}`);
|
||||
});
|
||||
|
||||
for (const key of Object.keys(cfg.agents?.defaults?.models ?? {})) {
|
||||
const parsed = parseModelRef(String(key ?? ""), DEFAULT_PROVIDER);
|
||||
if (!parsed) continue;
|
||||
if (!parsed) {
|
||||
continue;
|
||||
}
|
||||
addEntry(parsed, "configured");
|
||||
}
|
||||
|
||||
|
||||
@@ -19,26 +19,50 @@ export const formatKeyValue = (
|
||||
export const formatSeparator = (rich: boolean) => colorize(rich, theme.muted, " | ");
|
||||
|
||||
export const formatTag = (tag: string, rich: boolean) => {
|
||||
if (!rich) return tag;
|
||||
if (tag === "default") return theme.success(tag);
|
||||
if (tag === "image") return theme.accentBright(tag);
|
||||
if (tag === "configured") return theme.accent(tag);
|
||||
if (tag === "missing") return theme.error(tag);
|
||||
if (tag.startsWith("fallback#")) return theme.warn(tag);
|
||||
if (tag.startsWith("img-fallback#")) return theme.warn(tag);
|
||||
if (tag.startsWith("alias:")) return theme.accentDim(tag);
|
||||
if (!rich) {
|
||||
return tag;
|
||||
}
|
||||
if (tag === "default") {
|
||||
return theme.success(tag);
|
||||
}
|
||||
if (tag === "image") {
|
||||
return theme.accentBright(tag);
|
||||
}
|
||||
if (tag === "configured") {
|
||||
return theme.accent(tag);
|
||||
}
|
||||
if (tag === "missing") {
|
||||
return theme.error(tag);
|
||||
}
|
||||
if (tag.startsWith("fallback#")) {
|
||||
return theme.warn(tag);
|
||||
}
|
||||
if (tag.startsWith("img-fallback#")) {
|
||||
return theme.warn(tag);
|
||||
}
|
||||
if (tag.startsWith("alias:")) {
|
||||
return theme.accentDim(tag);
|
||||
}
|
||||
return theme.muted(tag);
|
||||
};
|
||||
|
||||
export const truncate = (value: string, max: number) => {
|
||||
if (value.length <= max) return value;
|
||||
if (max <= 3) return value.slice(0, max);
|
||||
if (value.length <= max) {
|
||||
return value;
|
||||
}
|
||||
if (max <= 3) {
|
||||
return value.slice(0, max);
|
||||
}
|
||||
return `${value.slice(0, max - 3)}...`;
|
||||
};
|
||||
|
||||
export const maskApiKey = (value: string): string => {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) return "missing";
|
||||
if (trimmed.length <= 16) return trimmed;
|
||||
if (!trimmed) {
|
||||
return "missing";
|
||||
}
|
||||
if (trimmed.length <= 16) {
|
||||
return trimmed;
|
||||
}
|
||||
return `${trimmed.slice(0, 8)}...${trimmed.slice(-8)}`;
|
||||
};
|
||||
|
||||
@@ -25,7 +25,9 @@ export async function modelsListCommand(
|
||||
const authStore = ensureAuthProfileStore();
|
||||
const providerFilter = (() => {
|
||||
const raw = opts.provider?.trim();
|
||||
if (!raw) return undefined;
|
||||
if (!raw) {
|
||||
return undefined;
|
||||
}
|
||||
const parsed = parseModelRef(`${raw}/_`, DEFAULT_PROVIDER);
|
||||
return parsed?.provider ?? raw.toLowerCase();
|
||||
})();
|
||||
@@ -66,7 +68,9 @@ export async function modelsListCommand(
|
||||
if (opts.all) {
|
||||
const sorted = [...models].toSorted((a, b) => {
|
||||
const p = a.provider.localeCompare(b.provider);
|
||||
if (p !== 0) return p;
|
||||
if (p !== 0) {
|
||||
return p;
|
||||
}
|
||||
return a.id.localeCompare(b.id);
|
||||
});
|
||||
|
||||
@@ -74,7 +78,9 @@ export async function modelsListCommand(
|
||||
if (providerFilter && model.provider.toLowerCase() !== providerFilter) {
|
||||
continue;
|
||||
}
|
||||
if (opts.local && !isLocalBaseUrl(model.baseUrl)) continue;
|
||||
if (opts.local && !isLocalBaseUrl(model.baseUrl)) {
|
||||
continue;
|
||||
}
|
||||
const key = modelKey(model.provider, model.id);
|
||||
const configured = configuredByKey.get(key);
|
||||
rows.push(
|
||||
@@ -95,8 +101,12 @@ export async function modelsListCommand(
|
||||
continue;
|
||||
}
|
||||
const model = modelByKey.get(entry.key);
|
||||
if (opts.local && model && !isLocalBaseUrl(model.baseUrl)) continue;
|
||||
if (opts.local && !model) continue;
|
||||
if (opts.local && model && !isLocalBaseUrl(model.baseUrl)) {
|
||||
continue;
|
||||
}
|
||||
if (opts.local && !model) {
|
||||
continue;
|
||||
}
|
||||
rows.push(
|
||||
toModelRow({
|
||||
model,
|
||||
|
||||
@@ -80,12 +80,24 @@ export type AuthProbeOptions = {
|
||||
};
|
||||
|
||||
const toStatus = (reason?: string | null): AuthProbeStatus => {
|
||||
if (!reason) return "unknown";
|
||||
if (reason === "auth") return "auth";
|
||||
if (reason === "rate_limit") return "rate_limit";
|
||||
if (reason === "billing") return "billing";
|
||||
if (reason === "timeout") return "timeout";
|
||||
if (reason === "format") return "format";
|
||||
if (!reason) {
|
||||
return "unknown";
|
||||
}
|
||||
if (reason === "auth") {
|
||||
return "auth";
|
||||
}
|
||||
if (reason === "rate_limit") {
|
||||
return "rate_limit";
|
||||
}
|
||||
if (reason === "billing") {
|
||||
return "billing";
|
||||
}
|
||||
if (reason === "timeout") {
|
||||
return "timeout";
|
||||
}
|
||||
if (reason === "format") {
|
||||
return "format";
|
||||
}
|
||||
return "unknown";
|
||||
};
|
||||
|
||||
@@ -93,9 +105,13 @@ function buildCandidateMap(modelCandidates: string[]): Map<string, string[]> {
|
||||
const map = new Map<string, string[]>();
|
||||
for (const raw of modelCandidates) {
|
||||
const parsed = parseModelRef(String(raw ?? ""), DEFAULT_PROVIDER);
|
||||
if (!parsed) continue;
|
||||
if (!parsed) {
|
||||
continue;
|
||||
}
|
||||
const list = map.get(parsed.provider) ?? [];
|
||||
if (!list.includes(parsed.model)) list.push(parsed.model);
|
||||
if (!list.includes(parsed.model)) {
|
||||
list.push(parsed.model);
|
||||
}
|
||||
map.set(parsed.provider, list);
|
||||
}
|
||||
return map;
|
||||
@@ -112,7 +128,9 @@ function selectProbeModel(params: {
|
||||
return { provider, model: direct[0] };
|
||||
}
|
||||
const fromCatalog = catalog.find((entry) => entry.provider === provider);
|
||||
if (fromCatalog) return { provider: fromCatalog.provider, model: fromCatalog.id };
|
||||
if (fromCatalog) {
|
||||
return { provider: fromCatalog.provider, model: fromCatalog.id };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -135,7 +153,9 @@ function buildProbeTargets(params: {
|
||||
|
||||
for (const provider of providers) {
|
||||
const providerKey = normalizeProviderId(provider);
|
||||
if (providerFilterKey && providerKey !== providerFilterKey) continue;
|
||||
if (providerFilterKey && providerKey !== providerFilterKey) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const model = selectProbeModel({
|
||||
provider: providerKey,
|
||||
@@ -148,13 +168,17 @@ function buildProbeTargets(params: {
|
||||
const order = store.order;
|
||||
if (order) {
|
||||
for (const [key, value] of Object.entries(order)) {
|
||||
if (normalizeProviderId(key) === providerKey) return value;
|
||||
if (normalizeProviderId(key) === providerKey) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
const cfgOrder = cfg?.auth?.order;
|
||||
if (cfgOrder) {
|
||||
for (const [key, value] of Object.entries(cfgOrder)) {
|
||||
if (normalizeProviderId(key) === providerKey) return value;
|
||||
if (normalizeProviderId(key) === providerKey) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
@@ -223,11 +247,15 @@ function buildProbeTargets(params: {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (profileFilter.size > 0) continue;
|
||||
if (profileFilter.size > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const envKey = resolveEnvApiKey(providerKey);
|
||||
const customKey = getCustomProviderApiKey(cfg, providerKey);
|
||||
if (!envKey && !customKey) continue;
|
||||
if (!envKey && !customKey) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const label = envKey ? "env" : "models.json";
|
||||
const source = envKey ? "env" : "models.json";
|
||||
@@ -360,7 +388,9 @@ async function runTargetsWithConcurrency(params: {
|
||||
while (true) {
|
||||
const index = cursor;
|
||||
cursor += 1;
|
||||
if (index >= targets.length) return;
|
||||
if (index >= targets.length) {
|
||||
return;
|
||||
}
|
||||
const target = targets[index];
|
||||
onProgress?.({
|
||||
completed,
|
||||
@@ -430,7 +460,9 @@ export async function runAuthProbes(params: {
|
||||
}
|
||||
|
||||
export function formatProbeLatency(latencyMs?: number | null) {
|
||||
if (!latencyMs && latencyMs !== 0) return "-";
|
||||
if (!latencyMs && latencyMs !== 0) {
|
||||
return "-";
|
||||
}
|
||||
return formatMs(latencyMs);
|
||||
}
|
||||
|
||||
@@ -447,7 +479,9 @@ export function groupProbeResults(results: AuthProbeResult[]): Map<string, AuthP
|
||||
export function sortProbeResults(results: AuthProbeResult[]): AuthProbeResult[] {
|
||||
return results.slice().toSorted((a, b) => {
|
||||
const provider = a.provider.localeCompare(b.provider);
|
||||
if (provider !== 0) return provider;
|
||||
if (provider !== 0) {
|
||||
return provider;
|
||||
}
|
||||
const aLabel = a.label || a.profileId || "";
|
||||
const bLabel = b.label || b.profileId || "";
|
||||
return aLabel.localeCompare(bLabel);
|
||||
@@ -455,6 +489,8 @@ export function sortProbeResults(results: AuthProbeResult[]): AuthProbeResult[]
|
||||
}
|
||||
|
||||
export function describeProbeSummary(summary: AuthProbeSummary): string {
|
||||
if (summary.totalTargets === 0) return "No probe targets.";
|
||||
if (summary.totalTargets === 0) {
|
||||
return "No probe targets.";
|
||||
}
|
||||
return `Probed ${summary.totalTargets} target${summary.totalTargets === 1 ? "" : "s"} in ${formatMs(summary.durationMs)}`;
|
||||
}
|
||||
|
||||
@@ -31,10 +31,18 @@ const isLocalBaseUrl = (baseUrl: string) => {
|
||||
};
|
||||
|
||||
const hasAuthForProvider = (provider: string, cfg: OpenClawConfig, authStore: AuthProfileStore) => {
|
||||
if (listProfilesForProvider(authStore, provider).length > 0) return true;
|
||||
if (provider === "amazon-bedrock" && resolveAwsSdkEnvVarName()) return true;
|
||||
if (resolveEnvApiKey(provider)) return true;
|
||||
if (getCustomProviderApiKey(cfg, provider)) return true;
|
||||
if (listProfilesForProvider(authStore, provider).length > 0) {
|
||||
return true;
|
||||
}
|
||||
if (provider === "amazon-bedrock" && resolveAwsSdkEnvVarName()) {
|
||||
return true;
|
||||
}
|
||||
if (resolveEnvApiKey(provider)) {
|
||||
return true;
|
||||
}
|
||||
if (getCustomProviderApiKey(cfg, provider)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -82,9 +90,13 @@ export function toModelRow(params: {
|
||||
const mergedTags = new Set(tags);
|
||||
if (aliasTags.length > 0) {
|
||||
for (const tag of mergedTags) {
|
||||
if (tag === "alias" || tag.startsWith("alias:")) mergedTags.delete(tag);
|
||||
if (tag === "alias" || tag.startsWith("alias:")) {
|
||||
mergedTags.delete(tag);
|
||||
}
|
||||
}
|
||||
for (const tag of aliasTags) {
|
||||
mergedTags.add(tag);
|
||||
}
|
||||
for (const tag of aliasTags) mergedTags.add(tag);
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -108,7 +108,9 @@ export async function modelsStatusCommand(
|
||||
const aliases = Object.entries(cfg.agents?.defaults?.models ?? {}).reduce<Record<string, string>>(
|
||||
(acc, [key, entry]) => {
|
||||
const alias = entry?.alias?.trim();
|
||||
if (alias) acc[alias] = key;
|
||||
if (alias) {
|
||||
acc[alias] = key;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{},
|
||||
@@ -132,11 +134,15 @@ export async function modelsStatusCommand(
|
||||
const providersInUse = new Set<string>();
|
||||
for (const raw of [defaultLabel, ...fallbacks, imageModel, ...imageFallbacks, ...allowed]) {
|
||||
const parsed = parseModelRef(String(raw ?? ""), DEFAULT_PROVIDER);
|
||||
if (parsed?.provider) providersFromModels.add(parsed.provider);
|
||||
if (parsed?.provider) {
|
||||
providersFromModels.add(parsed.provider);
|
||||
}
|
||||
}
|
||||
for (const raw of [defaultLabel, ...fallbacks, imageModel, ...imageFallbacks]) {
|
||||
const parsed = parseModelRef(String(raw ?? ""), DEFAULT_PROVIDER);
|
||||
if (parsed?.provider) providersInUse.add(parsed.provider);
|
||||
if (parsed?.provider) {
|
||||
providersInUse.add(parsed.provider);
|
||||
}
|
||||
}
|
||||
|
||||
const providersFromEnv = new Set<string>();
|
||||
@@ -157,7 +163,9 @@ export async function modelsStatusCommand(
|
||||
"synthetic",
|
||||
];
|
||||
for (const provider of envProbeProviders) {
|
||||
if (resolveEnvApiKey(provider)) providersFromEnv.add(provider);
|
||||
if (resolveEnvApiKey(provider)) {
|
||||
providersFromEnv.add(provider);
|
||||
}
|
||||
}
|
||||
|
||||
const providers = Array.from(
|
||||
@@ -188,7 +196,9 @@ export async function modelsStatusCommand(
|
||||
.toSorted((a, b) => a.localeCompare(b));
|
||||
|
||||
const probeProfileIds = (() => {
|
||||
if (!opts.probeProfile) return [];
|
||||
if (!opts.probeProfile) {
|
||||
return [];
|
||||
}
|
||||
const raw = Array.isArray(opts.probeProfile) ? opts.probeProfile : [opts.probeProfile];
|
||||
return raw
|
||||
.flatMap((value) => String(value ?? "").split(","))
|
||||
@@ -283,7 +293,9 @@ export async function modelsStatusCommand(
|
||||
}> = [];
|
||||
for (const profileId of Object.keys(store.usageStats ?? {})) {
|
||||
const unusableUntil = resolveProfileUnusableUntilForDisplay(store, profileId);
|
||||
if (!unusableUntil || now >= unusableUntil) continue;
|
||||
if (!unusableUntil || now >= unusableUntil) {
|
||||
continue;
|
||||
}
|
||||
const stats = store.usageStats?.[profileId];
|
||||
const kind =
|
||||
typeof stats?.disabledUntil === "number" && now < stats.disabledUntil
|
||||
@@ -306,8 +318,12 @@ export async function modelsStatusCommand(
|
||||
oauthProfiles.some((profile) => ["expired", "missing"].includes(profile.status)) ||
|
||||
missingProvidersInUse.length > 0;
|
||||
const hasExpiring = oauthProfiles.some((profile) => profile.status === "expiring");
|
||||
if (hasExpiredOrMissing) return 1;
|
||||
if (hasExpiring) return 2;
|
||||
if (hasExpiredOrMissing) {
|
||||
return 1;
|
||||
}
|
||||
if (hasExpiring) {
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
})();
|
||||
|
||||
@@ -355,13 +371,17 @@ export async function modelsStatusCommand(
|
||||
2,
|
||||
),
|
||||
);
|
||||
if (opts.check) runtime.exit(checkStatus);
|
||||
if (opts.check) {
|
||||
runtime.exit(checkStatus);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (opts.plain) {
|
||||
runtime.log(resolvedLabel);
|
||||
if (opts.check) runtime.exit(checkStatus);
|
||||
if (opts.check) {
|
||||
runtime.exit(checkStatus);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -564,18 +584,29 @@ export async function modelsStatusCommand(
|
||||
}
|
||||
|
||||
const formatStatus = (status: string) => {
|
||||
if (status === "ok") return colorize(rich, theme.success, "ok");
|
||||
if (status === "static") return colorize(rich, theme.muted, "static");
|
||||
if (status === "expiring") return colorize(rich, theme.warn, "expiring");
|
||||
if (status === "missing") return colorize(rich, theme.warn, "unknown");
|
||||
if (status === "ok") {
|
||||
return colorize(rich, theme.success, "ok");
|
||||
}
|
||||
if (status === "static") {
|
||||
return colorize(rich, theme.muted, "static");
|
||||
}
|
||||
if (status === "expiring") {
|
||||
return colorize(rich, theme.warn, "expiring");
|
||||
}
|
||||
if (status === "missing") {
|
||||
return colorize(rich, theme.warn, "unknown");
|
||||
}
|
||||
return colorize(rich, theme.error, "expired");
|
||||
};
|
||||
|
||||
const profilesByProvider = new Map<string, typeof oauthProfiles>();
|
||||
for (const profile of oauthProfiles) {
|
||||
const current = profilesByProvider.get(profile.provider);
|
||||
if (current) current.push(profile);
|
||||
else profilesByProvider.set(profile.provider, [profile]);
|
||||
if (current) {
|
||||
current.push(profile);
|
||||
} else {
|
||||
profilesByProvider.set(profile.provider, [profile]);
|
||||
}
|
||||
}
|
||||
|
||||
for (const [provider, profiles] of profilesByProvider) {
|
||||
@@ -607,11 +638,21 @@ export async function modelsStatusCommand(
|
||||
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
|
||||
const sorted = sortProbeResults(probeSummary.results);
|
||||
const statusColor = (status: string) => {
|
||||
if (status === "ok") return theme.success;
|
||||
if (status === "rate_limit") return theme.warn;
|
||||
if (status === "timeout" || status === "billing") return theme.warn;
|
||||
if (status === "auth" || status === "format") return theme.error;
|
||||
if (status === "no_model") return theme.muted;
|
||||
if (status === "ok") {
|
||||
return theme.success;
|
||||
}
|
||||
if (status === "rate_limit") {
|
||||
return theme.warn;
|
||||
}
|
||||
if (status === "timeout" || status === "billing") {
|
||||
return theme.warn;
|
||||
}
|
||||
if (status === "auth" || status === "format") {
|
||||
return theme.error;
|
||||
}
|
||||
if (status === "no_model") {
|
||||
return theme.muted;
|
||||
}
|
||||
return theme.muted;
|
||||
};
|
||||
const rows = sorted.map((result) => {
|
||||
@@ -644,5 +685,7 @@ export async function modelsStatusCommand(
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.check) runtime.exit(checkStatus);
|
||||
if (opts.check) {
|
||||
runtime.exit(checkStatus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,9 @@ export function printModelTable(
|
||||
}
|
||||
|
||||
if (opts.plain) {
|
||||
for (const row of rows) runtime.log(row.key);
|
||||
for (const row of rows) {
|
||||
runtime.log(row.key);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,12 @@ const multiselect = <T>(params: Parameters<typeof clackMultiselect<T>>[0]) =>
|
||||
const pad = (value: string, size: number) => value.padEnd(size);
|
||||
|
||||
const truncate = (value: string, max: number) => {
|
||||
if (value.length <= max) return value;
|
||||
if (max <= 3) return value.slice(0, max);
|
||||
if (value.length <= max) {
|
||||
return value;
|
||||
}
|
||||
if (max <= 3) {
|
||||
return value.slice(0, max);
|
||||
}
|
||||
return `${value.slice(0, max - 3)}...`;
|
||||
};
|
||||
|
||||
@@ -36,19 +40,27 @@ function sortScanResults(results: ModelScanResult[]): ModelScanResult[] {
|
||||
return results.slice().toSorted((a, b) => {
|
||||
const aImage = a.image.ok ? 1 : 0;
|
||||
const bImage = b.image.ok ? 1 : 0;
|
||||
if (aImage !== bImage) return bImage - aImage;
|
||||
if (aImage !== bImage) {
|
||||
return bImage - aImage;
|
||||
}
|
||||
|
||||
const aToolLatency = a.tool.latencyMs ?? Number.POSITIVE_INFINITY;
|
||||
const bToolLatency = b.tool.latencyMs ?? Number.POSITIVE_INFINITY;
|
||||
if (aToolLatency !== bToolLatency) return aToolLatency - bToolLatency;
|
||||
if (aToolLatency !== bToolLatency) {
|
||||
return aToolLatency - bToolLatency;
|
||||
}
|
||||
|
||||
const aCtx = a.contextLength ?? 0;
|
||||
const bCtx = b.contextLength ?? 0;
|
||||
if (aCtx !== bCtx) return bCtx - aCtx;
|
||||
if (aCtx !== bCtx) {
|
||||
return bCtx - aCtx;
|
||||
}
|
||||
|
||||
const aParams = a.inferredParamB ?? 0;
|
||||
const bParams = b.inferredParamB ?? 0;
|
||||
if (aParams !== bParams) return bParams - aParams;
|
||||
if (aParams !== bParams) {
|
||||
return bParams - aParams;
|
||||
}
|
||||
|
||||
return a.modelRef.localeCompare(b.modelRef);
|
||||
});
|
||||
@@ -58,15 +70,21 @@ function sortImageResults(results: ModelScanResult[]): ModelScanResult[] {
|
||||
return results.slice().toSorted((a, b) => {
|
||||
const aLatency = a.image.latencyMs ?? Number.POSITIVE_INFINITY;
|
||||
const bLatency = b.image.latencyMs ?? Number.POSITIVE_INFINITY;
|
||||
if (aLatency !== bLatency) return aLatency - bLatency;
|
||||
if (aLatency !== bLatency) {
|
||||
return aLatency - bLatency;
|
||||
}
|
||||
|
||||
const aCtx = a.contextLength ?? 0;
|
||||
const bCtx = b.contextLength ?? 0;
|
||||
if (aCtx !== bCtx) return bCtx - aCtx;
|
||||
if (aCtx !== bCtx) {
|
||||
return bCtx - aCtx;
|
||||
}
|
||||
|
||||
const aParams = a.inferredParamB ?? 0;
|
||||
const bParams = b.inferredParamB ?? 0;
|
||||
if (aParams !== bParams) return bParams - aParams;
|
||||
if (aParams !== bParams) {
|
||||
return bParams - aParams;
|
||||
}
|
||||
|
||||
return a.modelRef.localeCompare(b.modelRef);
|
||||
});
|
||||
@@ -188,7 +206,9 @@ export async function modelsScanCommand(
|
||||
concurrency,
|
||||
probe,
|
||||
onProgress: ({ phase, completed, total }) => {
|
||||
if (phase !== "probe") return;
|
||||
if (phase !== "probe") {
|
||||
return;
|
||||
}
|
||||
const labelBase = probe ? "Probing models" : "Scanning models";
|
||||
update({
|
||||
completed,
|
||||
@@ -288,10 +308,14 @@ export async function modelsScanCommand(
|
||||
const _updated = await updateConfig((cfg) => {
|
||||
const nextModels = { ...cfg.agents?.defaults?.models };
|
||||
for (const entry of selected) {
|
||||
if (!nextModels[entry]) nextModels[entry] = {};
|
||||
if (!nextModels[entry]) {
|
||||
nextModels[entry] = {};
|
||||
}
|
||||
}
|
||||
for (const entry of selectedImages) {
|
||||
if (!nextModels[entry]) nextModels[entry] = {};
|
||||
if (!nextModels[entry]) {
|
||||
nextModels[entry] = {};
|
||||
}
|
||||
}
|
||||
const existingImageModel = cfg.agents?.defaults?.imageModel as
|
||||
| { primary?: string; fallbacks?: string[] }
|
||||
|
||||
@@ -7,7 +7,9 @@ export async function modelsSetImageCommand(modelRaw: string, runtime: RuntimeEn
|
||||
const resolved = resolveModelTarget({ raw: modelRaw, cfg });
|
||||
const key = `${resolved.provider}/${resolved.model}`;
|
||||
const nextModels = { ...cfg.agents?.defaults?.models };
|
||||
if (!nextModels[key]) nextModels[key] = {};
|
||||
if (!nextModels[key]) {
|
||||
nextModels[key] = {};
|
||||
}
|
||||
const existingModel = cfg.agents?.defaults?.imageModel as
|
||||
| { primary?: string; fallbacks?: string[] }
|
||||
| undefined;
|
||||
|
||||
@@ -7,7 +7,9 @@ export async function modelsSetCommand(modelRaw: string, runtime: RuntimeEnv) {
|
||||
const resolved = resolveModelTarget({ raw: modelRaw, cfg });
|
||||
const key = `${resolved.provider}/${resolved.model}`;
|
||||
const nextModels = { ...cfg.agents?.defaults?.models };
|
||||
if (!nextModels[key]) nextModels[key] = {};
|
||||
if (!nextModels[key]) {
|
||||
nextModels[key] = {};
|
||||
}
|
||||
const existingModel = cfg.agents?.defaults?.model as
|
||||
| { primary?: string; fallbacks?: string[] }
|
||||
| undefined;
|
||||
|
||||
@@ -21,15 +21,25 @@ export const ensureFlagCompatibility = (opts: { json?: boolean; plain?: boolean
|
||||
};
|
||||
|
||||
export const formatTokenK = (value?: number | null) => {
|
||||
if (!value || !Number.isFinite(value)) return "-";
|
||||
if (value < 1024) return `${Math.round(value)}`;
|
||||
if (!value || !Number.isFinite(value)) {
|
||||
return "-";
|
||||
}
|
||||
if (value < 1024) {
|
||||
return `${Math.round(value)}`;
|
||||
}
|
||||
return `${Math.round(value / 1024)}k`;
|
||||
};
|
||||
|
||||
export const formatMs = (value?: number | null) => {
|
||||
if (value === null || value === undefined) return "-";
|
||||
if (!Number.isFinite(value)) return "-";
|
||||
if (value < 1000) return `${Math.round(value)}ms`;
|
||||
if (value === null || value === undefined) {
|
||||
return "-";
|
||||
}
|
||||
if (!Number.isFinite(value)) {
|
||||
return "-";
|
||||
}
|
||||
if (value < 1000) {
|
||||
return `${Math.round(value)}ms`;
|
||||
}
|
||||
return `${Math.round(value / 100) / 10}s`;
|
||||
};
|
||||
|
||||
@@ -70,7 +80,9 @@ export function buildAllowlistSet(cfg: OpenClawConfig): Set<string> {
|
||||
const models = cfg.agents?.defaults?.models ?? {};
|
||||
for (const raw of Object.keys(models)) {
|
||||
const parsed = parseModelRef(String(raw ?? ""), DEFAULT_PROVIDER);
|
||||
if (!parsed) continue;
|
||||
if (!parsed) {
|
||||
continue;
|
||||
}
|
||||
allowed.add(modelKey(parsed.provider, parsed.model));
|
||||
}
|
||||
return allowed;
|
||||
@@ -78,7 +90,9 @@ export function buildAllowlistSet(cfg: OpenClawConfig): Set<string> {
|
||||
|
||||
export function normalizeAlias(alias: string): string {
|
||||
const trimmed = alias.trim();
|
||||
if (!trimmed) throw new Error("Alias cannot be empty.");
|
||||
if (!trimmed) {
|
||||
throw new Error("Alias cannot be empty.");
|
||||
}
|
||||
if (!/^[A-Za-z0-9_.:-]+$/.test(trimmed)) {
|
||||
throw new Error("Alias must use letters, numbers, dots, underscores, colons, or dashes.");
|
||||
}
|
||||
@@ -90,7 +104,9 @@ export function resolveKnownAgentId(params: {
|
||||
rawAgentId?: string | null;
|
||||
}): string | undefined {
|
||||
const raw = params.rawAgentId?.trim();
|
||||
if (!raw) return undefined;
|
||||
if (!raw) {
|
||||
return undefined;
|
||||
}
|
||||
const agentId = normalizeAgentId(raw);
|
||||
const knownAgents = listAgentIds(params.cfg);
|
||||
if (!knownAgents.includes(agentId)) {
|
||||
|
||||
Reference in New Issue
Block a user