fix(ci): align cron and session tests with runtime

This commit is contained in:
Vincent Koc
2026-04-13 22:20:53 +01:00
parent 36a58e714c
commit a16331c36e
7 changed files with 43 additions and 33 deletions

View File

@@ -18,9 +18,11 @@ export function resolveThinkingDefault(params: {
}): ThinkLevel {
const normalizedProvider = normalizeProviderId(params.provider);
const normalizedModel = normalizeLowercaseStringOrEmpty(params.model).replace(/\./g, "-");
const catalogCandidate = params.catalog?.find(
(entry) => entry.provider === params.provider && entry.id === params.model,
);
const catalogCandidate = Array.isArray(params.catalog)
? params.catalog.find(
(entry) => entry.provider === params.provider && entry.id === params.model,
)
: undefined;
const configuredModels = params.cfg.agents?.defaults?.models;
const canonicalKey = modelKey(params.provider, params.model);
const legacyKey = legacyModelKey(params.provider, params.model);

View File

@@ -8,17 +8,24 @@ const mocks = vi.hoisted(() => ({
listAgentIds: vi.fn(),
}));
vi.mock("../../config/sessions.js", async () => {
const actual = await vi.importActual<typeof import("../../config/sessions.js")>(
"../../config/sessions.js",
vi.mock("../../config/sessions/main-session.js", async () => {
const actual = await vi.importActual<typeof import("../../config/sessions/main-session.js")>(
"../../config/sessions/main-session.js",
);
return {
...actual,
loadSessionStore: mocks.loadSessionStore,
resolveStorePath: mocks.resolveStorePath,
resolveExplicitAgentSessionKey: () => undefined,
};
});
vi.mock("../../config/sessions/paths.js", () => ({
resolveStorePath: mocks.resolveStorePath,
}));
vi.mock("../../config/sessions/store-load.js", () => ({
loadSessionStore: mocks.loadSessionStore,
}));
vi.mock("../../agents/agent-scope.js", () => ({
listAgentIds: mocks.listAgentIds,
}));

View File

@@ -1,7 +1,6 @@
import "./isolated-agent.mocks.js";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { loadModelCatalog } from "../agents/model-catalog.js";
import * as modelSelection from "../agents/model-selection.js";
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
import {
DEFAULT_MESSAGE,
@@ -10,10 +9,11 @@ import {
runCronTurn,
withTempHome,
} from "./isolated-agent.turn-test-helpers.js";
import * as isolatedAgentRunRuntime from "./isolated-agent/run.runtime.js";
describe("runCronIsolatedAgentTurn hook content wrapping", () => {
beforeEach(() => {
vi.spyOn(modelSelection, "resolveThinkingDefault").mockReturnValue("off");
vi.spyOn(isolatedAgentRunRuntime, "resolveThinkingDefault").mockReturnValue("off");
vi.mocked(runEmbeddedPiAgent).mockClear();
vi.mocked(loadModelCatalog).mockResolvedValue([]);
});

View File

@@ -1,4 +1,5 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "../agents/defaults.js";
const {
loadModelCatalogMock,
@@ -49,8 +50,6 @@ vi.mock("../agents/model-selection.js", () => ({
import { resolveCronModelSelection } from "./isolated-agent/model-selection.js";
const DEFAULT_MESSAGE = "do it";
const DEFAULT_PROVIDER = "anthropic";
const DEFAULT_MODEL = "claude-opus-4-6";
type AgentTurnPayload = {
kind: "agentTurn";
@@ -88,7 +87,7 @@ function parseModelRef(raw: string): { provider: string; model: string } | { err
}
const provider = providerRaw === "bedrock" ? "amazon-bedrock" : providerRaw;
const model = provider === "anthropic" && modelRaw === "opus-4.5" ? "claude-opus-4-6" : modelRaw;
const model = provider === "anthropic" && modelRaw === "opus-4.5" ? "claude-opus-4-5" : modelRaw;
return { provider, model };
}
@@ -204,7 +203,7 @@ describe("cron model formatting and precedence edge cases", () => {
selectModel({
payload: { kind: "agentTurn", message: DEFAULT_MESSAGE, model: "openai/" },
}),
).resolves.toEqual({ ok: false, error: "invalid model" });
).resolves.toEqual({ ok: false, error: "invalid model: openai/" });
});
it("rejects model with leading slash (empty provider)", async () => {
@@ -212,7 +211,7 @@ describe("cron model formatting and precedence edge cases", () => {
selectModel({
payload: { kind: "agentTurn", message: DEFAULT_MESSAGE, model: "/gpt-4.1-mini" },
}),
).resolves.toEqual({ ok: false, error: "invalid model" });
).resolves.toEqual({ ok: false, error: "invalid model: /gpt-4.1-mini" });
});
it("normalizes provider casing", async () => {
@@ -237,7 +236,7 @@ describe("cron model formatting and precedence edge cases", () => {
model: "anthropic/opus-4.5",
},
},
{ provider: "anthropic", model: "claude-opus-4-6" },
{ provider: "anthropic", model: "claude-opus-4-5" },
);
});

View File

@@ -1,7 +1,6 @@
import "./isolated-agent.mocks.js";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { loadModelCatalog } from "../agents/model-catalog.js";
import * as modelSelection from "../agents/model-selection.js";
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
import {
DEFAULT_AGENT_TURN_PAYLOAD,
@@ -13,10 +12,11 @@ import {
runTurnWithStoredModelOverride,
withTempHome,
} from "./isolated-agent.turn-test-helpers.js";
import * as isolatedAgentRunRuntime from "./isolated-agent/run.runtime.js";
describe("runCronIsolatedAgentTurn model overrides", () => {
beforeEach(() => {
vi.spyOn(modelSelection, "resolveThinkingDefault").mockReturnValue("off");
vi.spyOn(isolatedAgentRunRuntime, "resolveThinkingDefault").mockReturnValue("off");
vi.mocked(runEmbeddedPiAgent).mockClear();
vi.mocked(loadModelCatalog).mockResolvedValue([]);
});
@@ -176,7 +176,7 @@ describe("runCronIsolatedAgentTurn model overrides", () => {
it("passes through the resolved default thinking level", async () => {
await withTempHome(async (home) => {
vi.mocked(modelSelection.resolveThinkingDefault).mockReturnValueOnce("low");
vi.mocked(isolatedAgentRunRuntime.resolveThinkingDefault).mockReturnValueOnce("low");
await runCronTurn(home, {
jobPayload: DEFAULT_AGENT_TURN_PAYLOAD,

View File

@@ -1,9 +1,7 @@
import "./isolated-agent.mocks.js";
import fs from "node:fs/promises";
import path from "node:path";
import { beforeEach, describe, expect, it, vi } from "vitest";
import * as modelSelection from "../agents/model-selection.js";
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
import { beforeEach, describe, expect, it } from "vitest";
import { runCronIsolatedAgentTurn } from "./isolated-agent.js";
import { makeCfg, makeJob, writeSessionStore } from "./isolated-agent.test-harness.js";
import {
@@ -16,13 +14,17 @@ import {
withTempHome,
} from "./isolated-agent.turn-test-helpers.js";
import { setupRunCronIsolatedAgentTurnSuite } from "./isolated-agent/run.suite-helpers.js";
import {
mockRunCronFallbackPassthrough,
runEmbeddedPiAgentMock,
} from "./isolated-agent/run.test-harness.js";
setupRunCronIsolatedAgentTurnSuite();
describe("runCronIsolatedAgentTurn session identity", () => {
beforeEach(() => {
vi.spyOn(modelSelection, "resolveThinkingDefault").mockReturnValue("off");
vi.mocked(runEmbeddedPiAgent).mockClear();
mockRunCronFallbackPassthrough();
runEmbeddedPiAgentMock.mockClear();
});
it("passes resolved agentDir to runEmbeddedPiAgent", async () => {
@@ -32,7 +34,7 @@ describe("runCronIsolatedAgentTurn session identity", () => {
});
expect(res.status).toBe("ok");
const call = vi.mocked(runEmbeddedPiAgent).mock.calls.at(-1)?.[0] as {
const call = runEmbeddedPiAgentMock.mock.calls.at(-1)?.[0] as {
agentDir?: string;
};
expect(call?.agentDir).toBe(path.join(home, ".openclaw", "agents", "main", "agent"));
@@ -45,7 +47,7 @@ describe("runCronIsolatedAgentTurn session identity", () => {
jobPayload: DEFAULT_AGENT_TURN_PAYLOAD,
});
const call = vi.mocked(runEmbeddedPiAgent).mock.calls.at(-1)?.[0] as {
const call = runEmbeddedPiAgentMock.mock.calls.at(-1)?.[0] as {
prompt?: string;
};
const lines = call?.prompt?.split("\n") ?? [];
@@ -93,7 +95,7 @@ describe("runCronIsolatedAgentTurn session identity", () => {
});
expect(res.status).toBe("ok");
const call = vi.mocked(runEmbeddedPiAgent).mock.calls.at(-1)?.[0] as {
const call = runEmbeddedPiAgentMock.mock.calls.at(-1)?.[0] as {
sessionKey?: string;
workspaceDir?: string;
sessionFile?: string;
@@ -109,7 +111,7 @@ describe("runCronIsolatedAgentTurn session identity", () => {
await runCronTurn(home, {
jobPayload: DEFAULT_AGENT_TURN_PAYLOAD,
});
const call = vi.mocked(runEmbeddedPiAgent).mock.calls.at(-1)?.[0] as {
const call = runEmbeddedPiAgentMock.mock.calls.at(-1)?.[0] as {
sessionFile?: string;
};

View File

@@ -143,7 +143,7 @@ vi.mock("./skills-snapshot.runtime.js", () => ({
}));
vi.mock("./run-model-selection.runtime.js", () => ({
DEFAULT_MODEL: "gpt-4",
DEFAULT_MODEL: "gpt-5.4",
DEFAULT_PROVIDER: "openai",
loadModelCatalog: loadModelCatalogMock,
getModelRefStatus: getModelRefStatusMock,
@@ -252,7 +252,7 @@ function makeDefaultModelFallbackResult() {
meta: { agentMeta: { usage: { input: 10, output: 20 } } },
},
provider: "openai",
model: "gpt-4",
model: "gpt-5.4",
};
}
@@ -292,8 +292,8 @@ function resetRunConfigMocks(): void {
);
resolveAgentModelFallbacksOverrideMock.mockReturnValue(undefined);
resolveAgentSkillsFilterMock.mockReturnValue(undefined);
resolveConfiguredModelRefMock.mockReturnValue({ provider: "openai", model: "gpt-4" });
resolveAllowedModelRefMock.mockReturnValue({ ref: { provider: "openai", model: "gpt-4" } });
resolveConfiguredModelRefMock.mockReturnValue({ provider: "openai", model: "gpt-5.4" });
resolveAllowedModelRefMock.mockReturnValue({ ref: { provider: "openai", model: "gpt-5.4" } });
resolveHooksGmailModelMock.mockReturnValue(null);
resolveThinkingDefaultMock.mockReturnValue("off");
getModelRefStatusMock.mockReturnValue({ allowed: false });
@@ -315,7 +315,7 @@ function resetRunConfigMocks(): void {
isExternalHookSessionMock.mockReturnValue(false);
resolveHookExternalContentSourceMock.mockReturnValue(undefined);
getSkillsSnapshotVersionMock.mockReturnValue(42);
loadModelCatalogMock.mockResolvedValue({ models: [] });
loadModelCatalogMock.mockResolvedValue([]);
getRemoteSkillEligibilityMock.mockResolvedValue({ remoteSkillsEnabled: false });
}