From ba2781de8fceefabe18216bd97648920288dbe41 Mon Sep 17 00:00:00 2001 From: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com> Date: Sun, 3 May 2026 00:21:14 +0000 Subject: [PATCH] fix(clawsweeper): address review for automerge-openclaw-openclaw-75840 (1) --- .../isolated-agent.model-formatting.test.ts | 8 +-- src/cron/isolated-agent/model-selection.ts | 10 +--- src/cron/isolated-agent/run-executor.ts | 13 +++-- .../run.payload-fallbacks.test.ts | 52 +++++++++++++++++++ 4 files changed, 67 insertions(+), 16 deletions(-) diff --git a/src/cron/isolated-agent.model-formatting.test.ts b/src/cron/isolated-agent.model-formatting.test.ts index e1f382ba286..86e714e3b30 100644 --- a/src/cron/isolated-agent.model-formatting.test.ts +++ b/src/cron/isolated-agent.model-formatting.test.ts @@ -404,7 +404,7 @@ describe("cron model formatting and precedence edge cases", () => { }); describe("CLI runtime compatibility", () => { - it("uses a configured per-agent Claude CLI runtime for resolved Anthropic models", async () => { + it("keeps the canonical Anthropic provider when a per-agent Claude CLI runtime is configured", async () => { await expectSelectedModel( { cfg: { @@ -422,7 +422,7 @@ describe("cron model formatting and precedence edge cases", () => { }, agentId: "scheduler", }, - { provider: "claude-cli", model: "claude-opus-4-6" }, + { provider: "anthropic", model: "claude-opus-4-6" }, ); }); @@ -453,7 +453,7 @@ describe("cron model formatting and precedence edge cases", () => { ); }); - it("uses a configured default Claude CLI runtime for resolved Anthropic models", async () => { + it("keeps the canonical Anthropic provider when a default Claude CLI runtime is configured", async () => { await expectSelectedModel( { cfg: { @@ -465,7 +465,7 @@ describe("cron model formatting and precedence edge cases", () => { }, }, }, - { provider: "claude-cli", model: "claude-opus-4-6" }, + { provider: "anthropic", model: "claude-opus-4-6" }, ); }); diff --git a/src/cron/isolated-agent/model-selection.ts b/src/cron/isolated-agent/model-selection.ts index 9a41d93ad11..9ae0b2d07df 100644 --- a/src/cron/isolated-agent/model-selection.ts +++ b/src/cron/isolated-agent/model-selection.ts @@ -1,4 +1,3 @@ -import { resolveCliRuntimeExecutionProvider } from "../../agents/model-runtime-aliases.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; import type { CronJob } from "../types.js"; import { @@ -149,12 +148,5 @@ export async function resolveCronModelSelection( } } - const executionProvider = - resolveCliRuntimeExecutionProvider({ - provider, - cfg: params.cfgWithAgentDefaults, - agentId: params.agentId, - }) ?? provider; - - return { ok: true, provider: executionProvider, model }; + return { ok: true, provider, model }; } diff --git a/src/cron/isolated-agent/run-executor.ts b/src/cron/isolated-agent/run-executor.ts index e623996a84d..ceb5a864d1b 100644 --- a/src/cron/isolated-agent/run-executor.ts +++ b/src/cron/isolated-agent/run-executor.ts @@ -1,3 +1,4 @@ +import { resolveCliRuntimeExecutionProvider } from "../../agents/model-runtime-aliases.js"; import type { SkillSnapshot } from "../../agents/skills.js"; import { normalizeToolList } from "../../agents/tool-policy.js"; import type { ThinkLevel, VerboseLevel } from "../../auto-reply/thinking.js"; @@ -135,12 +136,18 @@ export function createCronPromptExecutor(params: { if (params.abortSignal?.aborted) { throw new Error(params.abortReason()); } + const executionProvider = + resolveCliRuntimeExecutionProvider({ + provider: providerOverride, + cfg: params.cfgWithAgentDefaults, + agentId: params.agentId, + }) ?? providerOverride; const bootstrapPromptWarningSignature = bootstrapPromptWarningSignaturesSeen[bootstrapPromptWarningSignaturesSeen.length - 1]; - if (isCliProvider(providerOverride, params.cfgWithAgentDefaults)) { + if (isCliProvider(executionProvider, params.cfgWithAgentDefaults)) { const cliSessionId = params.cronSession.isNewSession ? undefined - : await getCliSessionId(params.cronSession.sessionEntry, providerOverride); + : await getCliSessionId(params.cronSession.sessionEntry, executionProvider); const result = await runCliAgent({ sessionId: params.cronSession.sessionEntry.sessionId, sessionKey: params.runSessionKey, @@ -151,7 +158,7 @@ export function createCronPromptExecutor(params: { workspaceDir: params.workspaceDir, config: params.cfgWithAgentDefaults, prompt: promptText, - provider: providerOverride, + provider: executionProvider, model: modelOverride, thinkLevel: params.thinkLevel, timeoutMs: params.timeoutMs, diff --git a/src/cron/isolated-agent/run.payload-fallbacks.test.ts b/src/cron/isolated-agent/run.payload-fallbacks.test.ts index dd1b672636f..f131718ec17 100644 --- a/src/cron/isolated-agent/run.payload-fallbacks.test.ts +++ b/src/cron/isolated-agent/run.payload-fallbacks.test.ts @@ -5,8 +5,11 @@ import { setupRunCronIsolatedAgentTurnSuite, } from "./run.suite-helpers.js"; import { + isCliProviderMock, loadRunCronIsolatedAgentTurn, + resolveConfiguredModelRefMock, resolveAgentModelFallbacksOverrideMock, + runCliAgentMock, runWithModelFallbackMock, } from "./run.test-harness.js"; @@ -54,4 +57,53 @@ describe("runCronIsolatedAgentTurn — payload.fallbacks", () => { expect(runWithModelFallbackMock).toHaveBeenCalledOnce(); expect(runWithModelFallbackMock.mock.calls[0][0].fallbacksOverride).toEqual(expectedFallbacks); }); + + it("plans Anthropic fallbacks canonically while executing compatible attempts through Claude CLI", async () => { + isCliProviderMock.mockImplementation((provider: string) => provider === "claude-cli"); + resolveConfiguredModelRefMock.mockReturnValue({ + provider: "anthropic", + model: "claude-opus-4-6", + }); + runCliAgentMock.mockResolvedValue({ + payloads: [{ text: "fallback ok" }], + meta: { agentMeta: { usage: { input: 10, output: 20 } } }, + }); + runWithModelFallbackMock.mockImplementation(async ({ provider, model, run }) => { + const firstResult = await run(provider, model); + const secondResult = await run("anthropic", "claude-sonnet-4-6"); + return { + result: secondResult ?? firstResult, + provider: "anthropic", + model: "claude-sonnet-4-6", + attempts: [], + }; + }); + + const result = await runCronIsolatedAgentTurn( + makeIsolatedAgentTurnParams({ + cfg: { + agents: { + defaults: { + agentRuntime: { id: "claude-cli" }, + model: { + primary: "anthropic/claude-opus-4-6", + fallbacks: ["anthropic/claude-sonnet-4-6"], + }, + }, + }, + }, + }), + ); + + expect(result.status).toBe("ok"); + expect(runWithModelFallbackMock).toHaveBeenCalledOnce(); + expect(runWithModelFallbackMock.mock.calls[0][0]).toMatchObject({ + provider: "anthropic", + model: "claude-opus-4-6", + }); + expect(runCliAgentMock.mock.calls.map((call) => [call[0].provider, call[0].model])).toEqual([ + ["claude-cli", "claude-opus-4-6"], + ["claude-cli", "claude-sonnet-4-6"], + ]); + }); });