chore: Enable "curly" rule to avoid single-statement if confusion/errors.

This commit is contained in:
cpojer
2026-01-31 16:19:20 +09:00
parent 009b16fab8
commit 5ceff756e1
1266 changed files with 27871 additions and 9393 deletions

View File

@@ -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;
},
{},

View File

@@ -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}`);

View File

@@ -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";
}

View File

@@ -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;
});

View File

@@ -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;
});

View File

@@ -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);
}

View File

@@ -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");
}

View File

@@ -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)}`;
};

View File

@@ -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,

View File

@@ -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)}`;
}

View File

@@ -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 {

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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[] }

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)) {