CLI: add --agent flag to models status

This commit is contained in:
Jeremiah Lowin
2026-01-30 12:22:19 -05:00
committed by Gustavo Madeira Santana
parent 192a6ee870
commit dd4715a2c4
3 changed files with 44 additions and 8 deletions

View File

@@ -41,6 +41,7 @@ export function registerModelsCli(program: Command) {
.description("Model discovery, scanning, and configuration")
.option("--status-json", "Output JSON (alias for `models status --json`)", false)
.option("--status-plain", "Plain output (alias for `models status --plain`)", false)
.option("--agent <id>", "Agent id (default: configured default agent)")
.addHelpText(
"after",
() =>
@@ -85,6 +86,7 @@ export function registerModelsCli(program: Command) {
.option("--probe-timeout <ms>", "Per-probe timeout in ms")
.option("--probe-concurrency <n>", "Concurrent probes")
.option("--probe-max-tokens <n>", "Probe max tokens (best-effort)")
.option("--agent <id>", "Agent id (default: configured default agent)")
.action(async (opts) => {
await runModelsCommand(async () => {
await modelsStatusCommand(
@@ -98,6 +100,7 @@ export function registerModelsCli(program: Command) {
probeTimeout: opts.probeTimeout as string | undefined,
probeConcurrency: opts.probeConcurrency as string | undefined,
probeMaxTokens: opts.probeMaxTokens as string | undefined,
agent: opts.agent as string | undefined,
},
defaultRuntime,
);
@@ -271,6 +274,7 @@ export function registerModelsCli(program: Command) {
{
json: Boolean(opts?.statusJson),
plain: Boolean(opts?.statusPlain),
agent: opts?.agent as string | undefined,
},
defaultRuntime,
);

View File

@@ -1,5 +1,5 @@
import path from "node:path";
import { resolveOpenClawAgentDir } from "../../agents/agent-paths.js";
import { resolveAgentDir, resolveDefaultAgentId } from "../../agents/agent-scope.js";
import {
buildAuthHealthSummary,
DEFAULT_OAUTH_WARN_MS,
@@ -40,6 +40,7 @@ import {
sortProbeResults,
type AuthProbeSummary,
} from "./list.probe.js";
import { normalizeAgentId } from "../../routing/session-key.js";
import { DEFAULT_MODEL, DEFAULT_PROVIDER, ensureFlagCompatibility } from "./shared.js";
export async function modelsStatusCommand(
@@ -53,6 +54,7 @@ export async function modelsStatusCommand(
probeTimeout?: string;
probeConcurrency?: string;
probeMaxTokens?: string;
agent?: string;
},
runtime: RuntimeEnv,
) {
@@ -93,8 +95,11 @@ export async function modelsStatusCommand(
);
const allowed = Object.keys(cfg.agents?.defaults?.models ?? {});
const agentDir = resolveOpenClawAgentDir();
const store = ensureAuthProfileStore();
const agentId = opts.agent?.trim()
? normalizeAgentId(opts.agent.trim())
: resolveDefaultAgentId(cfg);
const agentDir = resolveAgentDir(cfg, agentId);
const store = ensureAuthProfileStore(agentDir);
const modelsPath = path.join(agentDir, "models.json");
const providersFromStore = new Set(
@@ -304,7 +309,7 @@ export async function modelsStatusCommand(
aliases,
allowed,
auth: {
storePath: resolveAuthStorePathForDisplay(),
storePath: resolveAuthStorePathForDisplay(agentDir),
shellEnvFallback: {
enabled: shellFallbackEnabled,
appliedKeys: applied,
@@ -411,7 +416,7 @@ export async function modelsStatusCommand(
`${label("Auth store")}${colorize(rich, theme.muted, ":")} ${colorize(
rich,
theme.info,
shortenHomePath(resolveAuthStorePathForDisplay()),
shortenHomePath(resolveAuthStorePathForDisplay(agentDir)),
)}`,
);
runtime.log(

View File

@@ -29,7 +29,8 @@ const mocks = vi.hoisted(() => {
return {
store,
resolveOpenClawAgentDir: vi.fn().mockReturnValue("/tmp/openclaw-agent"),
resolveAgentDir: vi.fn().mockReturnValue("/tmp/openclaw-agent"),
resolveDefaultAgentId: vi.fn().mockReturnValue("main"),
ensureAuthProfileStore: vi.fn().mockReturnValue(store),
listProfilesForProvider: vi.fn((s: typeof store, provider: string) => {
return Object.entries(s.profiles)
@@ -71,10 +72,19 @@ const mocks = vi.hoisted(() => {
};
});
vi.mock("../../agents/agent-paths.js", () => ({
resolveOpenClawAgentDir: mocks.resolveOpenClawAgentDir,
vi.mock("../../agents/agent-scope.js", () => ({
resolveAgentDir: mocks.resolveAgentDir,
resolveDefaultAgentId: mocks.resolveDefaultAgentId,
}));
vi.mock("../../routing/session-key.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../routing/session-key.js")>();
return {
...actual,
normalizeAgentId: (id: string) => id.toLowerCase().replace(/\s+/g, "-"),
};
});
vi.mock("../../agents/auth-profiles.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/auth-profiles.js")>();
return {
@@ -147,6 +157,23 @@ describe("modelsStatusCommand auth overview", () => {
).toBe(true);
});
it("resolves agent dir from --agent flag", async () => {
mocks.resolveAgentDir.mockReturnValue("/tmp/openclaw-agent-custom");
const localRuntime = {
log: vi.fn(),
error: vi.fn(),
exit: vi.fn(),
};
try {
await modelsStatusCommand({ json: true, agent: "jeremiah" }, localRuntime as never);
expect(mocks.resolveAgentDir).toHaveBeenCalledWith(expect.anything(), "jeremiah");
const payload = JSON.parse(String((localRuntime.log as vi.Mock).mock.calls[0][0]));
expect(payload.agentDir).toBe("/tmp/openclaw-agent-custom");
} finally {
mocks.resolveAgentDir.mockReturnValue("/tmp/openclaw-agent");
}
});
it("exits non-zero when auth is missing", async () => {
const originalProfiles = { ...mocks.store.profiles };
mocks.store.profiles = {};