diff --git a/src/agents/cli-backends.test.ts b/src/agents/cli-backends.test.ts index d7384d9e3f7..46c3bb56cf2 100644 --- a/src/agents/cli-backends.test.ts +++ b/src/agents/cli-backends.test.ts @@ -1,13 +1,22 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeEach, describe, expect, it } from "vitest"; import type { OpenClawConfig } from "../config/config.js"; import type { CliBackendConfig } from "../config/types.js"; import type { CliBundleMcpMode } from "../plugins/types.js"; +import { + __testing as cliBackendsTesting, + resolveCliBackendConfig, + resolveCliBackendLiveTest, +} from "./cli-backends.js"; -let createEmptyPluginRegistry: typeof import("../plugins/registry.js").createEmptyPluginRegistry; -let resetPluginRuntimeStateForTest: typeof import("../plugins/runtime.js").resetPluginRuntimeStateForTest; -let setActivePluginRegistry: typeof import("../plugins/runtime.js").setActivePluginRegistry; -let resolveCliBackendConfig: typeof import("./cli-backends.js").resolveCliBackendConfig; -let resolveCliBackendLiveTest: typeof import("./cli-backends.js").resolveCliBackendLiveTest; +type RuntimeBackendEntry = ReturnType< + (typeof import("../plugins/cli-backends.runtime.js"))["resolveRuntimeCliBackends"] +>[number]; +type SetupBackendEntry = NonNullable< + ReturnType<(typeof import("../plugins/setup-registry.js"))["resolvePluginSetupCliBackend"]> +>; + +let runtimeBackendEntries: RuntimeBackendEntry[] = []; +let setupBackendEntries: SetupBackendEntry[] = []; function createBackendEntry(params: { pluginId: string; @@ -60,6 +69,14 @@ function createBackendEntry(params: { }; } +function createRuntimeBackendEntry(params: Parameters[0]) { + const entry = createBackendEntry(params); + return { + ...entry.backend, + pluginId: entry.pluginId, + } satisfies RuntimeBackendEntry; +} + function createClaudeCliOverrideConfig(config: CliBackendConfig): OpenClawConfig { return { agents: { @@ -149,24 +166,13 @@ function normalizeTestClaudeBackendConfig(config: CliBackendConfig): CliBackendC }; } -beforeAll(async () => { - vi.doUnmock("../plugins/setup-registry.js"); - vi.doUnmock("../plugins/cli-backends.runtime.js"); - vi.resetModules(); - ({ createEmptyPluginRegistry } = await import("../plugins/registry.js")); - ({ resetPluginRuntimeStateForTest, setActivePluginRegistry } = - await import("../plugins/runtime.js")); - ({ resolveCliBackendConfig, resolveCliBackendLiveTest } = await import("./cli-backends.js")); -}); - afterEach(() => { - resetPluginRuntimeStateForTest(); + cliBackendsTesting.resetDepsForTest(); }); beforeEach(() => { - const registry = createEmptyPluginRegistry(); - registry.cliBackends = [ - createBackendEntry({ + runtimeBackendEntries = [ + createRuntimeBackendEntry({ pluginId: "anthropic", id: "claude-cli", bundleMcp: true, @@ -222,7 +228,7 @@ beforeEach(() => { }, normalizeConfig: normalizeTestClaudeBackendConfig, }), - createBackendEntry({ + createRuntimeBackendEntry({ pluginId: "openai", id: "codex-cli", bundleMcp: true, @@ -258,7 +264,7 @@ beforeEach(() => { }, }, }), - createBackendEntry({ + createRuntimeBackendEntry({ pluginId: "google", id: "google-gemini-cli", bundleMcp: true, @@ -276,7 +282,30 @@ beforeEach(() => { }, }), ]; - setActivePluginRegistry(registry); + const claudeBackend = runtimeBackendEntries.find((entry) => entry.id === "claude-cli"); + setupBackendEntries = claudeBackend + ? [ + { + pluginId: claudeBackend.pluginId, + backend: { + ...claudeBackend, + config: { + ...claudeBackend.config, + sessionArg: "--session-id", + sessionMode: "always", + systemPromptArg: "--append-system-prompt", + systemPromptWhen: "first", + }, + }, + }, + ] + : []; + cliBackendsTesting.setDepsForTest({ + resolveRuntimeCliBackends: () => runtimeBackendEntries, + resolvePluginSetupCliBackend: ({ backend }) => { + return setupBackendEntries.find((entry) => entry.backend.id === backend); + }, + }); }); describe("resolveCliBackendConfig reliability merge", () => { @@ -648,8 +677,7 @@ describe("resolveCliBackendConfig claude-cli defaults", () => { }); it("normalizes override-only claude-cli config when the plugin registry is absent", () => { - const registry = createEmptyPluginRegistry(); - setActivePluginRegistry(registry); + runtimeBackendEntries = []; const cfg = { agents: { @@ -735,9 +763,8 @@ describe("resolveCliBackendConfig google-gemini-cli defaults", () => { describe("resolveCliBackendConfig alias precedence", () => { it("prefers the canonical backend key over legacy aliases when both are configured", () => { - const registry = createEmptyPluginRegistry(); - registry.cliBackends = [ - createBackendEntry({ + runtimeBackendEntries = [ + createRuntimeBackendEntry({ pluginId: "moonshot", id: "kimi", config: { @@ -746,7 +773,6 @@ describe("resolveCliBackendConfig alias precedence", () => { }, }), ]; - setActivePluginRegistry(registry); const cfg = { agents: { diff --git a/src/agents/cli-backends.ts b/src/agents/cli-backends.ts index f6a28b1d421..8b526afde6d 100644 --- a/src/agents/cli-backends.ts +++ b/src/agents/cli-backends.ts @@ -6,6 +6,18 @@ import type { CliBundleMcpMode } from "../plugins/types.js"; import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js"; import { normalizeProviderId } from "./model-selection.js"; +type CliBackendsDeps = { + resolvePluginSetupCliBackend: typeof resolvePluginSetupCliBackend; + resolveRuntimeCliBackends: typeof resolveRuntimeCliBackends; +}; + +const defaultCliBackendsDeps: CliBackendsDeps = { + resolvePluginSetupCliBackend, + resolveRuntimeCliBackends, +}; + +let cliBackendsDeps: CliBackendsDeps = defaultCliBackendsDeps; + export type ResolvedCliBackend = { id: string; config: CliBackendConfig; @@ -47,7 +59,7 @@ function normalizeBundleMcpMode( } function resolveSetupCliBackendPolicy(provider: string): FallbackCliBackendPolicy | undefined { - const entry = resolvePluginSetupCliBackend({ + const entry = cliBackendsDeps.resolvePluginSetupCliBackend({ backend: provider, }); if (!entry) { @@ -94,7 +106,9 @@ function pickBackendConfig( function resolveRegisteredBackend(provider: string) { const normalized = normalizeBackendKey(provider); - return resolveRuntimeCliBackends().find((entry) => normalizeBackendKey(entry.id) === normalized); + return cliBackendsDeps + .resolveRuntimeCliBackends() + .find((entry) => normalizeBackendKey(entry.id) === normalized); } function mergeBackendConfig(base: CliBackendConfig, override?: CliBackendConfig): CliBackendConfig { @@ -136,7 +150,7 @@ function mergeBackendConfig(base: CliBackendConfig, override?: CliBackendConfig) export function resolveCliBackendIds(cfg?: OpenClawConfig): Set { const ids = new Set(); - for (const backend of resolveRuntimeCliBackends()) { + for (const backend of cliBackendsDeps.resolveRuntimeCliBackends()) { ids.add(normalizeBackendKey(backend.id)); } const configured = cfg?.agents?.defaults?.cliBackends ?? {}; @@ -149,8 +163,10 @@ export function resolveCliBackendIds(cfg?: OpenClawConfig): Set { export function resolveCliBackendLiveTest(provider: string): ResolvedCliBackendLiveTest | null { const normalized = normalizeBackendKey(provider); const entry = - resolvePluginSetupCliBackend({ backend: normalized }) ?? - resolveRuntimeCliBackends().find((backend) => normalizeBackendKey(backend.id) === normalized); + cliBackendsDeps.resolvePluginSetupCliBackend({ backend: normalized }) ?? + cliBackendsDeps + .resolveRuntimeCliBackends() + .find((backend) => normalizeBackendKey(backend.id) === normalized); if (!entry) { return null; } @@ -227,3 +243,15 @@ export function resolveCliBackendConfig( bundleMcpMode: fallbackPolicy?.bundleMcpMode, }; } + +export const __testing = { + resetDepsForTest(): void { + cliBackendsDeps = defaultCliBackendsDeps; + }, + setDepsForTest(deps: Partial): void { + cliBackendsDeps = { + ...defaultCliBackendsDeps, + ...deps, + }; + }, +} as const;