feat: add models scan and fallbacks
This commit is contained in:
95
src/commands/models/shared.ts
Normal file
95
src/commands/models/shared.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import {
|
||||
DEFAULT_MODEL,
|
||||
DEFAULT_PROVIDER,
|
||||
} from "../../agents/defaults.js";
|
||||
import {
|
||||
buildModelAliasIndex,
|
||||
modelKey,
|
||||
parseModelRef,
|
||||
resolveModelRefFromString,
|
||||
} from "../../agents/model-selection.js";
|
||||
import {
|
||||
readConfigFileSnapshot,
|
||||
writeConfigFile,
|
||||
type ClawdbotConfig,
|
||||
} from "../../config/config.js";
|
||||
|
||||
export const ensureFlagCompatibility = (opts: {
|
||||
json?: boolean;
|
||||
plain?: boolean;
|
||||
}) => {
|
||||
if (opts.json && opts.plain) {
|
||||
throw new Error("Choose either --json or --plain, not both.");
|
||||
}
|
||||
};
|
||||
|
||||
export const formatTokenK = (value?: number | null) => {
|
||||
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`;
|
||||
return `${Math.round(value / 100) / 10}s`;
|
||||
};
|
||||
|
||||
export async function updateConfig(
|
||||
mutator: (cfg: ClawdbotConfig) => ClawdbotConfig,
|
||||
): Promise<ClawdbotConfig> {
|
||||
const snapshot = await readConfigFileSnapshot();
|
||||
if (!snapshot.valid) {
|
||||
const issues = snapshot.issues
|
||||
.map((issue) => `- ${issue.path}: ${issue.message}`)
|
||||
.join("\n");
|
||||
throw new Error(`Invalid config at ${snapshot.path}\n${issues}`);
|
||||
}
|
||||
const next = mutator(snapshot.config);
|
||||
await writeConfigFile(next);
|
||||
return next;
|
||||
}
|
||||
|
||||
export function resolveModelTarget(params: {
|
||||
raw: string;
|
||||
cfg: ClawdbotConfig;
|
||||
}): { provider: string; model: string } {
|
||||
const aliasIndex = buildModelAliasIndex({
|
||||
cfg: params.cfg,
|
||||
defaultProvider: DEFAULT_PROVIDER,
|
||||
});
|
||||
const resolved = resolveModelRefFromString({
|
||||
raw: params.raw,
|
||||
defaultProvider: DEFAULT_PROVIDER,
|
||||
aliasIndex,
|
||||
});
|
||||
if (!resolved) {
|
||||
throw new Error(`Invalid model reference: ${params.raw}`);
|
||||
}
|
||||
return resolved.ref;
|
||||
}
|
||||
|
||||
export function buildAllowlistSet(cfg: ClawdbotConfig): Set<string> {
|
||||
const allowed = new Set<string>();
|
||||
for (const raw of cfg.agent?.allowedModels ?? []) {
|
||||
const parsed = parseModelRef(String(raw ?? ""), DEFAULT_PROVIDER);
|
||||
if (!parsed) continue;
|
||||
allowed.add(modelKey(parsed.provider, parsed.model));
|
||||
}
|
||||
return allowed;
|
||||
}
|
||||
|
||||
export function normalizeAlias(alias: string): string {
|
||||
const trimmed = alias.trim();
|
||||
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.",
|
||||
);
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
export { modelKey };
|
||||
export { DEFAULT_MODEL, DEFAULT_PROVIDER };
|
||||
Reference in New Issue
Block a user