refactor: share models command helpers

This commit is contained in:
Peter Steinberger 2026-03-13 23:38:48 +00:00
parent a9194f7a67
commit 0a50eb0343
3 changed files with 53 additions and 82 deletions

View File

@ -39,6 +39,17 @@ export function resolveConfiguredEntries(cfg: OpenClawConfig) {
tagsByKey.get(key)?.add(tag);
};
const addResolvedModelRef = (raw: string, tag: string) => {
const resolved = resolveModelRefFromString({
raw,
defaultProvider: DEFAULT_PROVIDER,
aliasIndex,
});
if (resolved) {
addEntry(resolved.ref, tag);
}
};
addEntry(resolvedDefault, "default");
const modelFallbacks = resolveAgentModelFallbackValues(cfg.agents?.defaults?.model);
@ -46,38 +57,15 @@ export function resolveConfiguredEntries(cfg: OpenClawConfig) {
const imagePrimary = resolveAgentModelPrimaryValue(cfg.agents?.defaults?.imageModel) ?? "";
modelFallbacks.forEach((raw, idx) => {
const resolved = resolveModelRefFromString({
raw: String(raw ?? ""),
defaultProvider: DEFAULT_PROVIDER,
aliasIndex,
});
if (!resolved) {
return;
}
addEntry(resolved.ref, `fallback#${idx + 1}`);
addResolvedModelRef(String(raw ?? ""), `fallback#${idx + 1}`);
});
if (imagePrimary) {
const resolved = resolveModelRefFromString({
raw: imagePrimary,
defaultProvider: DEFAULT_PROVIDER,
aliasIndex,
});
if (resolved) {
addEntry(resolved.ref, "image");
}
addResolvedModelRef(imagePrimary, "image");
}
imageFallbacks.forEach((raw, idx) => {
const resolved = resolveModelRefFromString({
raw: String(raw ?? ""),
defaultProvider: DEFAULT_PROVIDER,
aliasIndex,
});
if (!resolved) {
return;
}
addEntry(resolved.ref, `img-fallback#${idx + 1}`);
addResolvedModelRef(String(raw ?? ""), `img-fallback#${idx + 1}`);
});
for (const key of Object.keys(cfg.agents?.defaults?.models ?? {})) {

View File

@ -437,6 +437,17 @@ async function probeTarget(params: {
await fs.mkdir(sessionDir, { recursive: true });
const start = Date.now();
const buildResult = (status: AuthProbeResult["status"], error?: string): AuthProbeResult => ({
provider: target.provider,
model: `${target.model.provider}/${target.model.model}`,
profileId: target.profileId,
label: target.label,
source: target.source,
mode: target.mode,
status,
...(error ? { error } : {}),
latencyMs: Date.now() - start,
});
try {
await runEmbeddedPiAgent({
sessionId,
@ -458,29 +469,13 @@ async function probeTarget(params: {
verboseLevel: "off",
streamParams: { maxTokens },
});
return {
provider: target.provider,
model: `${target.model.provider}/${target.model.model}`,
profileId: target.profileId,
label: target.label,
source: target.source,
mode: target.mode,
status: "ok",
latencyMs: Date.now() - start,
};
return buildResult("ok");
} catch (err) {
const described = describeFailoverError(err);
return {
provider: target.provider,
model: `${target.model.provider}/${target.model.model}`,
profileId: target.profileId,
label: target.label,
source: target.source,
mode: target.mode,
status: mapFailoverReasonToProbeStatus(described.reason),
error: redactSecrets(described.message),
latencyMs: Date.now() - start,
};
return buildResult(
mapFailoverReasonToProbeStatus(described.reason),
redactSecrets(described.message),
);
}
}

View File

@ -25,6 +25,27 @@ vi.mock("../../cli/command-secret-targets.js", () => ({
import { loadModelsConfig, loadModelsConfigWithSource } from "./load-config.js";
describe("models load-config", () => {
const runtimeConfig = {
models: { providers: { openai: { apiKey: "sk-runtime" } } }, // pragma: allowlist secret
};
const resolvedConfig = {
models: { providers: { openai: { apiKey: "sk-resolved" } } }, // pragma: allowlist secret
};
const targetIds = new Set(["models.providers.*.apiKey"]);
function mockResolvedConfigFlow(params: { sourceConfig: unknown; diagnostics: string[] }) {
mocks.loadConfig.mockReturnValue(runtimeConfig);
mocks.readConfigFileSnapshotForWrite.mockResolvedValue({
snapshot: { valid: true, resolved: params.sourceConfig },
writeOptions: {},
});
mocks.getModelsCommandSecretTargetIds.mockReturnValue(targetIds);
mocks.resolveCommandSecretRefsViaGateway.mockResolvedValue({
resolvedConfig,
diagnostics: params.diagnostics,
});
}
beforeEach(() => {
vi.clearAllMocks();
});
@ -39,25 +60,9 @@ describe("models load-config", () => {
},
},
};
const runtimeConfig = {
models: { providers: { openai: { apiKey: "sk-runtime" } } }, // pragma: allowlist secret
};
const resolvedConfig = {
models: { providers: { openai: { apiKey: "sk-resolved" } } }, // pragma: allowlist secret
};
const targetIds = new Set(["models.providers.*.apiKey"]);
const runtime = { log: vi.fn(), error: vi.fn(), exit: vi.fn() };
mocks.loadConfig.mockReturnValue(runtimeConfig);
mocks.readConfigFileSnapshotForWrite.mockResolvedValue({
snapshot: { valid: true, resolved: sourceConfig },
writeOptions: {},
});
mocks.getModelsCommandSecretTargetIds.mockReturnValue(targetIds);
mocks.resolveCommandSecretRefsViaGateway.mockResolvedValue({
resolvedConfig,
diagnostics: ["diag-one", "diag-two"],
});
mockResolvedConfigFlow({ sourceConfig, diagnostics: ["diag-one", "diag-two"] });
const result = await loadModelsConfigWithSource({ commandName: "models list", runtime });
@ -78,24 +83,7 @@ describe("models load-config", () => {
it("loadModelsConfig returns resolved config while preserving runtime snapshot behavior", async () => {
const sourceConfig = { models: { providers: {} } };
const runtimeConfig = {
models: { providers: { openai: { apiKey: "sk-runtime" } } }, // pragma: allowlist secret
};
const resolvedConfig = {
models: { providers: { openai: { apiKey: "sk-resolved" } } }, // pragma: allowlist secret
};
const targetIds = new Set(["models.providers.*.apiKey"]);
mocks.loadConfig.mockReturnValue(runtimeConfig);
mocks.readConfigFileSnapshotForWrite.mockResolvedValue({
snapshot: { valid: true, resolved: sourceConfig },
writeOptions: {},
});
mocks.getModelsCommandSecretTargetIds.mockReturnValue(targetIds);
mocks.resolveCommandSecretRefsViaGateway.mockResolvedValue({
resolvedConfig,
diagnostics: [],
});
mockResolvedConfigFlow({ sourceConfig, diagnostics: [] });
await expect(loadModelsConfig({ commandName: "models list" })).resolves.toBe(resolvedConfig);
expect(mocks.setRuntimeConfigSnapshot).toHaveBeenCalledWith(resolvedConfig, sourceConfig);