From 6bc3458222aa9d096519b4b36776be4a50146252 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 1 May 2026 03:12:51 +0100 Subject: [PATCH] perf(test): keep commitment runtime tests focused --- scripts/test-projects.test-support.mjs | 4 ++++ src/agents/model-selection.test.ts | 28 ++++++++++++++++++++++ src/commitments/model-selection.runtime.ts | 9 +++++++ src/commitments/runtime.test.ts | 11 +++++++++ src/commitments/runtime.ts | 16 +++++++++++-- test/scripts/test-projects.test.ts | 14 +++++++++++ 6 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 src/commitments/model-selection.runtime.ts diff --git a/scripts/test-projects.test-support.mjs b/scripts/test-projects.test-support.mjs index ab73decf15c..eaefe57b3e1 100644 --- a/scripts/test-projects.test-support.mjs +++ b/scripts/test-projects.test-support.mjs @@ -346,6 +346,10 @@ const SOURCE_TEST_TARGETS = new Map([ ["extensions/google-meet/src/create.ts", ["extensions/google-meet/index.test.ts"]], ["extensions/google-meet/src/oauth.ts", ["extensions/google-meet/src/oauth.test.ts"]], ["src/commands/doctor-memory-search.ts", ["src/commands/doctor-memory-search.test.ts"]], + [ + "src/commitments/model-selection.runtime.ts", + ["src/commitments/runtime.test.ts", "src/agents/model-selection.test.ts"], + ], ["src/agents/live-model-turn-probes.ts", ["src/agents/live-model-turn-probes.test.ts"]], [ "src/plugins/provider-auth-choice.ts", diff --git a/src/agents/model-selection.test.ts b/src/agents/model-selection.test.ts index 669606de74f..ba172294d10 100644 --- a/src/agents/model-selection.test.ts +++ b/src/agents/model-selection.test.ts @@ -18,6 +18,7 @@ import { resolvePersistedSelectedModelRef, resolveAllowedModelRef, resolveConfiguredModelRef, + resolveDefaultModelForAgent, resolveSubagentConfiguredModelSelection, resolveSubagentSpawnModelSelection, resolveThinkingDefault, @@ -1624,6 +1625,33 @@ describe("model-selection", () => { }); }); +describe("resolveDefaultModelForAgent", () => { + it("uses an agent primary model override before the global default", () => { + const cfg = { + agents: { + defaults: { + model: { + primary: "openai/gpt-5.4", + }, + }, + list: [ + { + id: "main", + model: { + primary: "openai-codex/gpt-5.5", + }, + }, + ], + }, + } as OpenClawConfig; + + expect(resolveDefaultModelForAgent({ cfg, agentId: "main" })).toEqual({ + provider: "openai-codex", + model: "gpt-5.5", + }); + }); +}); + describe("normalizeModelSelection", () => { it("returns trimmed string for string input", () => { expect(normalizeModelSelection("ollama/llama3.2:3b")).toBe("ollama/llama3.2:3b"); diff --git a/src/commitments/model-selection.runtime.ts b/src/commitments/model-selection.runtime.ts new file mode 100644 index 00000000000..665a6631d59 --- /dev/null +++ b/src/commitments/model-selection.runtime.ts @@ -0,0 +1,9 @@ +import { resolveDefaultModelForAgent } from "../agents/model-selection.js"; +import type { OpenClawConfig } from "../config/config.js"; + +export function resolveCommitmentDefaultModelRef(params: { + cfg: OpenClawConfig; + agentId?: string; +}): { provider: string; model: string } { + return resolveDefaultModelForAgent(params); +} diff --git a/src/commitments/runtime.test.ts b/src/commitments/runtime.test.ts index 4d01d4000fb..d82f178f27b 100644 --- a/src/commitments/runtime.test.ts +++ b/src/commitments/runtime.test.ts @@ -14,11 +14,16 @@ import { loadCommitmentStore } from "./store.js"; import type { CommitmentExtractionBatchResult, CommitmentExtractionItem } from "./types.js"; const runEmbeddedPiAgentMock = vi.hoisted(() => vi.fn()); +const resolveDefaultModelMock = vi.hoisted(() => vi.fn()); vi.mock("../agents/pi-embedded.js", () => ({ runEmbeddedPiAgent: runEmbeddedPiAgentMock, })); +vi.mock("./model-selection.runtime.js", () => ({ + resolveCommitmentDefaultModelRef: resolveDefaultModelMock, +})); + describe("commitment extraction runtime", () => { const tmpDirs: string[] = []; const nowMs = Date.parse("2026-04-29T16:00:00.000Z"); @@ -26,6 +31,7 @@ describe("commitment extraction runtime", () => { afterEach(async () => { resetCommitmentExtractionRuntimeForTests(); runEmbeddedPiAgentMock.mockReset(); + resolveDefaultModelMock.mockReset(); vi.useRealTimers(); vi.unstubAllEnvs(); await Promise.all(tmpDirs.map((dir) => fs.rm(dir, { recursive: true, force: true }))); @@ -165,6 +171,10 @@ describe("commitment extraction runtime", () => { runEmbeddedPiAgentMock.mockResolvedValue({ payloads: [{ text: '{"candidates":[]}' }], }); + resolveDefaultModelMock.mockReturnValue({ + provider: "openai-codex", + model: "gpt-5.5", + }); configureCommitmentExtractionRuntime({ forceInTests: true, setTimer: () => ({ unref() {} }) as ReturnType, @@ -184,6 +194,7 @@ describe("commitment extraction runtime", () => { ).toBe(true); await expect(drainCommitmentExtractionQueue()).resolves.toBe(1); + expect(resolveDefaultModelMock).toHaveBeenCalledWith({ cfg, agentId: "main" }); expect(runEmbeddedPiAgentMock).toHaveBeenCalledWith( expect.objectContaining({ provider: "openai-codex", diff --git a/src/commitments/runtime.ts b/src/commitments/runtime.ts index 2349c32b224..bf473df92dd 100644 --- a/src/commitments/runtime.ts +++ b/src/commitments/runtime.ts @@ -1,7 +1,6 @@ import { randomUUID } from "node:crypto"; import path from "node:path"; import { resolveAgentWorkspaceDir } from "../agents/agent-scope.js"; -import { resolveDefaultModelForAgent } from "../agents/model-selection.js"; import { runEmbeddedPiAgent, type EmbeddedPiRunResult } from "../agents/pi-embedded.js"; import type { OpenClawConfig } from "../config/config.js"; import { resolveStateDir } from "../config/paths.js"; @@ -21,6 +20,7 @@ import type { } from "./types.js"; type TimerHandle = ReturnType; +type ModelRef = { provider: string; model: string }; export type CommitmentExtractionEnqueueInput = CommitmentScope & { cfg?: OpenClawConfig; @@ -36,6 +36,7 @@ export type CommitmentExtractionRuntime = { cfg?: OpenClawConfig; items: CommitmentExtractionItem[]; }) => Promise; + resolveDefaultModel?: (params: { cfg: OpenClawConfig; agentId?: string }) => ModelRef; setTimer?: (callback: () => void, delayMs: number) => TimerHandle; clearTimer?: (timer: TimerHandle) => void; forceInTests?: boolean; @@ -200,6 +201,17 @@ function joinPayloadText(result: EmbeddedPiRunResult): string { ); } +async function resolveDefaultModel(params: { + cfg: OpenClawConfig; + agentId?: string; +}): Promise { + if (runtime.resolveDefaultModel) { + return runtime.resolveDefaultModel(params); + } + const { resolveCommitmentDefaultModelRef } = await import("./model-selection.runtime.js"); + return resolveCommitmentDefaultModelRef(params); +} + async function defaultExtractBatch(params: { cfg?: OpenClawConfig; items: CommitmentExtractionItem[]; @@ -211,7 +223,7 @@ async function defaultExtractBatch(params: { } const resolved = resolveCommitmentsConfig(cfg); const runId = `commitments-${randomUUID()}`; - const modelRef = resolveDefaultModelForAgent({ cfg, agentId: first.agentId }); + const modelRef = await resolveDefaultModel({ cfg, agentId: first.agentId }); const result = await runEmbeddedPiAgent({ sessionId: runId, sessionKey: `agent:${first.agentId}:commitments:${runId}`, diff --git a/test/scripts/test-projects.test.ts b/test/scripts/test-projects.test.ts index 50d539c0dad..85afb70fce1 100644 --- a/test/scripts/test-projects.test.ts +++ b/test/scripts/test-projects.test.ts @@ -602,6 +602,20 @@ describe("scripts/test-projects changed-target routing", () => { }); }); + it("routes commitment model-selection runtime edits away from broad gateway dependents", () => { + expect( + resolveChangedTestTargetPlan([ + "src/agents/model-selection.test.ts", + "src/commitments/model-selection.runtime.ts", + "src/commitments/runtime.test.ts", + "src/commitments/runtime.ts", + ]), + ).toEqual({ + mode: "targets", + targets: ["src/agents/model-selection.test.ts", "src/commitments/runtime.test.ts"], + }); + }); + it("routes provider auth choice edits to focused auth-choice tests", () => { expect(resolveChangedTestTargetPlan(["src/plugins/provider-auth-choice.ts"])).toEqual({ mode: "targets",