refactor(agent): dedupe harness and command workflows

This commit is contained in:
Peter Steinberger
2026-02-16 14:52:09 +00:00
parent 04892ee230
commit f717a13039
204 changed files with 7366 additions and 11540 deletions

View File

@@ -123,6 +123,16 @@ describe("models list/status", () => {
baseUrl: "https://api.openai.com/v1",
contextWindow: 128000,
};
const GOOGLE_ANTIGRAVITY_TEMPLATE_BASE = {
provider: "google-antigravity",
api: "google-gemini-cli",
input: ["text", "image"],
baseUrl: "https://daily-cloudcode-pa.sandbox.googleapis.com",
contextWindow: 200000,
maxTokens: 64000,
reasoning: true,
cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
};
function setDefaultModel(model: string) {
loadConfig.mockReturnValue({
@@ -130,11 +140,68 @@ describe("models list/status", () => {
});
}
function configureModelAsConfigured(model: string) {
loadConfig.mockReturnValue({
agents: {
defaults: {
model,
models: {
[model]: {},
},
},
},
});
}
function configureGoogleAntigravityModel(modelId: string) {
configureModelAsConfigured(`google-antigravity/${modelId}`);
}
function makeGoogleAntigravityTemplate(id: string, name: string) {
return {
...GOOGLE_ANTIGRAVITY_TEMPLATE_BASE,
id,
name,
};
}
function enableGoogleAntigravityAuthProfile() {
listProfilesForProvider.mockImplementation((_: unknown, provider: string) =>
provider === "google-antigravity"
? ([{ id: "profile-1" }] as Array<Record<string, unknown>>)
: [],
);
}
function parseJsonLog(runtime: ReturnType<typeof makeRuntime>) {
expect(runtime.log).toHaveBeenCalledTimes(1);
return JSON.parse(String(runtime.log.mock.calls[0]?.[0]));
}
async function runAvailabilityFallbackCase(params: {
setup?: () => void;
expectedErrorDetail: string;
}) {
configureGoogleAntigravityModel("claude-opus-4-6-thinking");
enableGoogleAntigravityAuthProfile();
const runtime = makeRuntime();
modelRegistryState.models = [
makeGoogleAntigravityTemplate("claude-opus-4-5-thinking", "Claude Opus 4.5 Thinking"),
];
modelRegistryState.available = [];
params.setup?.();
await modelsListCommand({ json: true }, runtime);
expect(runtime.error).toHaveBeenCalledTimes(1);
expect(runtime.error.mock.calls[0]?.[0]).toContain("falling back to auth heuristics");
expect(runtime.error.mock.calls[0]?.[0]).toContain(params.expectedErrorDetail);
const payload = parseJsonLog(runtime);
expect(payload.models[0]?.key).toBe("google-antigravity/claude-opus-4-6-thinking");
expect(payload.models[0]?.missing).toBe(false);
expect(payload.models[0]?.available).toBe(true);
}
async function expectZaiProviderFilter(provider: string) {
setDefaultModel("z.ai/glm-4.7");
const runtime = makeRuntime();
@@ -153,49 +220,54 @@ describe("models list/status", () => {
({ modelsListCommand } = await import("./models/list.list-command.js"));
});
it("models list outputs canonical zai key for configured z.ai model", async () => {
loadConfig.mockReturnValue({
agents: { defaults: { model: "z.ai/glm-4.7" } },
});
const runtime = makeRuntime();
modelRegistryState.models = [ZAI_MODEL];
modelRegistryState.available = [ZAI_MODEL];
await modelsListCommand({ json: true }, runtime);
expect(runtime.log).toHaveBeenCalledTimes(1);
const payload = JSON.parse(String(runtime.log.mock.calls[0]?.[0]));
expect(payload.models[0]?.key).toBe("zai/glm-4.7");
});
it("models list plain outputs canonical zai key", async () => {
loadConfig.mockReturnValue({
agents: { defaults: { model: "z.ai/glm-4.7" } },
});
const runtime = makeRuntime();
const model = {
provider: "zai",
id: "glm-4.7",
name: "GLM-4.7",
input: ["text"],
baseUrl: "https://api.z.ai/v1",
contextWindow: 128000,
};
modelRegistryState.models = [model];
modelRegistryState.available = [model];
modelRegistryState.models = [ZAI_MODEL];
modelRegistryState.available = [ZAI_MODEL];
await modelsListCommand({ plain: true }, runtime);
expect(runtime.log).toHaveBeenCalledTimes(1);
expect(runtime.log.mock.calls[0]?.[0]).toBe("zai/glm-4.7");
});
it("models list provider filter normalizes z.ai alias", async () => {
await expectZaiProviderFilter("z.ai");
});
it("models list provider filter normalizes Z.AI alias casing", async () => {
await expectZaiProviderFilter("Z.AI");
});
it("models list provider filter normalizes z-ai alias", async () => {
await expectZaiProviderFilter("z-ai");
});
it("models list marks auth as unavailable when ZAI key is missing", async () => {
loadConfig.mockReturnValue({
agents: { defaults: { model: "z.ai/glm-4.7" } },
});
const runtime = makeRuntime();
const model = {
provider: "zai",
id: "glm-4.7",
name: "GLM-4.7",
input: ["text"],
baseUrl: "https://api.z.ai/v1",
contextWindow: 128000,
};
modelRegistryState.models = [model];
modelRegistryState.models = [ZAI_MODEL];
modelRegistryState.available = [];
await modelsListCommand({ all: true, json: true }, runtime);
@@ -205,31 +277,11 @@ describe("models list/status", () => {
});
it("models list resolves antigravity opus 4.6 thinking from 4.5 template", async () => {
loadConfig.mockReturnValue({
agents: {
defaults: {
model: "google-antigravity/claude-opus-4-6-thinking",
models: {
"google-antigravity/claude-opus-4-6-thinking": {},
},
},
},
});
configureGoogleAntigravityModel("claude-opus-4-6-thinking");
const runtime = makeRuntime();
modelRegistryState.models = [
{
provider: "google-antigravity",
id: "claude-opus-4-5-thinking",
name: "Claude Opus 4.5 Thinking",
api: "google-gemini-cli",
input: ["text", "image"],
baseUrl: "https://daily-cloudcode-pa.sandbox.googleapis.com",
contextWindow: 200000,
maxTokens: 64000,
reasoning: true,
cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
},
makeGoogleAntigravityTemplate("claude-opus-4-5-thinking", "Claude Opus 4.5 Thinking"),
];
modelRegistryState.available = [];
await modelsListCommand({ json: true }, runtime);
@@ -243,31 +295,11 @@ describe("models list/status", () => {
});
it("models list resolves antigravity opus 4.6 (non-thinking) from 4.5 template", async () => {
loadConfig.mockReturnValue({
agents: {
defaults: {
model: "google-antigravity/claude-opus-4-6",
models: {
"google-antigravity/claude-opus-4-6": {},
},
},
},
});
configureGoogleAntigravityModel("claude-opus-4-6");
const runtime = makeRuntime();
modelRegistryState.models = [
{
provider: "google-antigravity",
id: "claude-opus-4-5",
name: "Claude Opus 4.5",
api: "google-gemini-cli",
input: ["text", "image"],
baseUrl: "https://daily-cloudcode-pa.sandbox.googleapis.com",
contextWindow: 200000,
maxTokens: 64000,
reasoning: true,
cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
},
makeGoogleAntigravityTemplate("claude-opus-4-5", "Claude Opus 4.5"),
];
modelRegistryState.available = [];
await modelsListCommand({ json: true }, runtime);
@@ -281,30 +313,13 @@ describe("models list/status", () => {
});
it("models list marks synthesized antigravity opus 4.6 thinking as available when template is available", async () => {
loadConfig.mockReturnValue({
agents: {
defaults: {
model: "google-antigravity/claude-opus-4-6-thinking",
models: {
"google-antigravity/claude-opus-4-6-thinking": {},
},
},
},
});
configureGoogleAntigravityModel("claude-opus-4-6-thinking");
const runtime = makeRuntime();
const template = {
provider: "google-antigravity",
id: "claude-opus-4-5-thinking",
name: "Claude Opus 4.5 Thinking",
api: "google-gemini-cli",
input: ["text", "image"],
baseUrl: "https://daily-cloudcode-pa.sandbox.googleapis.com",
contextWindow: 200000,
maxTokens: 64000,
reasoning: true,
cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
};
const template = makeGoogleAntigravityTemplate(
"claude-opus-4-5-thinking",
"Claude Opus 4.5 Thinking",
);
modelRegistryState.models = [template];
modelRegistryState.available = [template];
await modelsListCommand({ json: true }, runtime);
@@ -316,36 +331,31 @@ describe("models list/status", () => {
expect(payload.models[0]?.available).toBe(true);
});
it("models list prefers registry availability over provider auth heuristics", async () => {
loadConfig.mockReturnValue({
agents: {
defaults: {
model: "google-antigravity/claude-opus-4-6-thinking",
models: {
"google-antigravity/claude-opus-4-6-thinking": {},
},
},
},
});
listProfilesForProvider.mockImplementation((_: unknown, provider: string) =>
provider === "google-antigravity"
? ([{ id: "profile-1" }] as Array<Record<string, unknown>>)
: [],
);
it("models list marks synthesized antigravity opus 4.6 (non-thinking) as available when template is available", async () => {
configureGoogleAntigravityModel("claude-opus-4-6");
const runtime = makeRuntime();
const template = {
provider: "google-antigravity",
id: "claude-opus-4-5-thinking",
name: "Claude Opus 4.5 Thinking",
api: "google-gemini-cli",
input: ["text", "image"],
baseUrl: "https://daily-cloudcode-pa.sandbox.googleapis.com",
contextWindow: 200000,
maxTokens: 64000,
reasoning: true,
cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
};
const template = makeGoogleAntigravityTemplate("claude-opus-4-5", "Claude Opus 4.5");
modelRegistryState.models = [template];
modelRegistryState.available = [template];
await modelsListCommand({ json: true }, runtime);
expect(runtime.log).toHaveBeenCalledTimes(1);
const payload = JSON.parse(String(runtime.log.mock.calls[0]?.[0]));
expect(payload.models[0]?.key).toBe("google-antigravity/claude-opus-4-6");
expect(payload.models[0]?.missing).toBe(false);
expect(payload.models[0]?.available).toBe(true);
});
it("models list prefers registry availability over provider auth heuristics", async () => {
configureGoogleAntigravityModel("claude-opus-4-6-thinking");
enableGoogleAntigravityAuthProfile();
const runtime = makeRuntime();
const template = makeGoogleAntigravityTemplate(
"claude-opus-4-5-thinking",
"Claude Opus 4.5 Thinking",
);
modelRegistryState.models = [template];
modelRegistryState.available = [];
await modelsListCommand({ json: true }, runtime);
@@ -358,112 +368,40 @@ describe("models list/status", () => {
listProfilesForProvider.mockReturnValue([]);
});
it("models list falls back to auth heuristics when getAvailable returns invalid shape", async () => {
loadConfig.mockReturnValue({
agents: {
defaults: {
model: "google-antigravity/claude-opus-4-6-thinking",
models: {
"google-antigravity/claude-opus-4-6-thinking": {},
},
},
it("models list falls back to auth heuristics when registry availability is unavailable", async () => {
await runAvailabilityFallbackCase({
setup: () => {
modelRegistryState.getAvailableError = Object.assign(
new Error("availability unsupported: getAvailable failed"),
{ code: "MODEL_AVAILABILITY_UNAVAILABLE" },
);
},
expectedErrorDetail: "getAvailable failed",
});
listProfilesForProvider.mockImplementation((_: unknown, provider: string) =>
provider === "google-antigravity"
? ([{ id: "profile-1" }] as Array<Record<string, unknown>>)
: [],
);
modelRegistryState.available = { bad: true } as unknown as Array<Record<string, unknown>>;
const runtime = makeRuntime();
});
modelRegistryState.models = [
{
provider: "google-antigravity",
id: "claude-opus-4-5-thinking",
name: "Claude Opus 4.5 Thinking",
api: "google-gemini-cli",
input: ["text", "image"],
baseUrl: "https://daily-cloudcode-pa.sandbox.googleapis.com",
contextWindow: 200000,
maxTokens: 64000,
reasoning: true,
cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
it("models list falls back to auth heuristics when getAvailable returns invalid shape", async () => {
await runAvailabilityFallbackCase({
setup: () => {
modelRegistryState.available = { bad: true } as unknown as Array<Record<string, unknown>>;
},
];
await modelsListCommand({ json: true }, runtime);
expect(runtime.error).toHaveBeenCalledTimes(1);
expect(runtime.error.mock.calls[0]?.[0]).toContain("falling back to auth heuristics");
expect(runtime.error.mock.calls[0]?.[0]).toContain("non-array value");
expect(runtime.log).toHaveBeenCalledTimes(1);
const payload = JSON.parse(String(runtime.log.mock.calls[0]?.[0]));
expect(payload.models[0]?.key).toBe("google-antigravity/claude-opus-4-6-thinking");
expect(payload.models[0]?.missing).toBe(false);
expect(payload.models[0]?.available).toBe(true);
expectedErrorDetail: "non-array value",
});
});
it("models list falls back to auth heuristics when getAvailable throws", async () => {
loadConfig.mockReturnValue({
agents: {
defaults: {
model: "google-antigravity/claude-opus-4-6-thinking",
models: {
"google-antigravity/claude-opus-4-6-thinking": {},
},
},
await runAvailabilityFallbackCase({
setup: () => {
modelRegistryState.getAvailableError = new Error(
"availability unsupported: getAvailable failed",
);
},
expectedErrorDetail: "availability unsupported: getAvailable failed",
});
listProfilesForProvider.mockImplementation((_: unknown, provider: string) =>
provider === "google-antigravity"
? ([{ id: "profile-1" }] as Array<Record<string, unknown>>)
: [],
);
modelRegistryState.getAvailableError = new Error(
"availability unsupported: getAvailable failed",
);
const runtime = makeRuntime();
modelRegistryState.models = [
{
provider: "google-antigravity",
id: "claude-opus-4-5-thinking",
name: "Claude Opus 4.5 Thinking",
api: "google-gemini-cli",
input: ["text", "image"],
baseUrl: "https://daily-cloudcode-pa.sandbox.googleapis.com",
contextWindow: 200000,
maxTokens: 64000,
reasoning: true,
cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
},
];
modelRegistryState.available = [];
await modelsListCommand({ json: true }, runtime);
expect(runtime.error).toHaveBeenCalledTimes(1);
expect(runtime.error.mock.calls[0]?.[0]).toContain("falling back to auth heuristics");
expect(runtime.error.mock.calls[0]?.[0]).toContain(
"availability unsupported: getAvailable failed",
);
expect(runtime.log).toHaveBeenCalledTimes(1);
const payload = JSON.parse(String(runtime.log.mock.calls[0]?.[0]));
expect(payload.models[0]?.key).toBe("google-antigravity/claude-opus-4-6-thinking");
expect(payload.models[0]?.missing).toBe(false);
expect(payload.models[0]?.available).toBe(true);
});
it("models list does not treat availability-unavailable code as discovery fallback", async () => {
loadConfig.mockReturnValue({
agents: {
defaults: {
model: "google-antigravity/claude-opus-4-6-thinking",
models: {
"google-antigravity/claude-opus-4-6-thinking": {},
},
},
},
});
configureGoogleAntigravityModel("claude-opus-4-6-thinking");
modelRegistryState.getAllError = Object.assign(new Error("model discovery failed"), {
code: "MODEL_AVAILABILITY_UNAVAILABLE",
});
@@ -479,21 +417,8 @@ describe("models list/status", () => {
});
it("models list fails fast when registry model discovery is unavailable", async () => {
loadConfig.mockReturnValue({
agents: {
defaults: {
model: "google-antigravity/claude-opus-4-6-thinking",
models: {
"google-antigravity/claude-opus-4-6-thinking": {},
},
},
},
});
listProfilesForProvider.mockImplementation((_: unknown, provider: string) =>
provider === "google-antigravity"
? ([{ id: "profile-1" }] as Array<Record<string, unknown>>)
: [],
);
configureGoogleAntigravityModel("claude-opus-4-6-thinking");
enableGoogleAntigravityAuthProfile();
modelRegistryState.getAllError = Object.assign(new Error("model discovery unavailable"), {
code: "MODEL_DISCOVERY_UNAVAILABLE",
});
@@ -510,6 +435,18 @@ describe("models list/status", () => {
expect(process.exitCode).toBe(1);
});
it("loadModelRegistry throws when model discovery is unavailable", async () => {
modelRegistryState.getAllError = Object.assign(new Error("model discovery unavailable"), {
code: "MODEL_DISCOVERY_UNAVAILABLE",
});
modelRegistryState.available = [
makeGoogleAntigravityTemplate("claude-opus-4-5-thinking", "Claude Opus 4.5 Thinking"),
];
const { loadModelRegistry } = await import("./models/list.registry.js");
await expect(loadModelRegistry({})).rejects.toThrow("model discovery unavailable");
});
it("toModelRow does not crash without cfg/authStore when availability is undefined", async () => {
const { toModelRow } = await import("./models/list.registry.js");