Spaces:
Paused
Paused
File size: 3,856 Bytes
fb4d8fe | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | import { listAgentIds } from "../../agents/agent-scope.js";
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "../../agents/defaults.js";
import {
buildModelAliasIndex,
modelKey,
parseModelRef,
resolveModelRefFromString,
} from "../../agents/model-selection.js";
import { formatCliCommand } from "../../cli/command-format.js";
import {
type OpenClawConfig,
readConfigFileSnapshot,
writeConfigFile,
} from "../../config/config.js";
import { normalizeAgentId } from "../../routing/session-key.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: OpenClawConfig) => OpenClawConfig,
): Promise<OpenClawConfig> {
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: OpenClawConfig }): {
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: OpenClawConfig): Set<string> {
const allowed = new 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;
}
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 function resolveKnownAgentId(params: {
cfg: OpenClawConfig;
rawAgentId?: string | null;
}): string | undefined {
const raw = params.rawAgentId?.trim();
if (!raw) {
return undefined;
}
const agentId = normalizeAgentId(raw);
const knownAgents = listAgentIds(params.cfg);
if (!knownAgents.includes(agentId)) {
throw new Error(
`Unknown agent id "${raw}". Use "${formatCliCommand("openclaw agents list")}" to see configured agents.`,
);
}
return agentId;
}
export { modelKey };
export { DEFAULT_MODEL, DEFAULT_PROVIDER };
/**
* Model key format: "provider/model"
*
* The model key is displayed in `/model status` and used to reference models.
* When using `/model <key>`, use the exact format shown (e.g., "openrouter/moonshotai/kimi-k2").
*
* For providers with hierarchical model IDs (e.g., OpenRouter), the model ID may include
* sub-providers (e.g., "moonshotai/kimi-k2"), resulting in a key like "openrouter/moonshotai/kimi-k2".
*/
|