mirror of https://github.com/openclaw/openclaw.git
222 lines
7.7 KiB
TypeScript
222 lines
7.7 KiB
TypeScript
import { beforeEach, describe, expect, it } from "vitest";
|
|
import { buildAnthropicCliBackend } from "../../extensions/anthropic/cli-backend.js";
|
|
import { buildGoogleGeminiCliBackend } from "../../extensions/google/cli-backend.js";
|
|
import { buildOpenAICodexCliBackend } from "../../extensions/openai/cli-backend.js";
|
|
import type { OpenClawConfig } from "../config/config.js";
|
|
import { createEmptyPluginRegistry } from "../plugins/registry.js";
|
|
import { setActivePluginRegistry } from "../plugins/runtime.js";
|
|
import { resolveCliBackendConfig } from "./cli-backends.js";
|
|
|
|
beforeEach(() => {
|
|
const registry = createEmptyPluginRegistry();
|
|
registry.cliBackends = [
|
|
{
|
|
pluginId: "anthropic",
|
|
backend: buildAnthropicCliBackend(),
|
|
source: "test",
|
|
},
|
|
{
|
|
pluginId: "openai",
|
|
backend: buildOpenAICodexCliBackend(),
|
|
source: "test",
|
|
},
|
|
{
|
|
pluginId: "google",
|
|
backend: buildGoogleGeminiCliBackend(),
|
|
source: "test",
|
|
},
|
|
];
|
|
setActivePluginRegistry(registry);
|
|
});
|
|
|
|
describe("resolveCliBackendConfig reliability merge", () => {
|
|
it("defaults codex-cli to workspace-write for fresh and resume runs", () => {
|
|
const resolved = resolveCliBackendConfig("codex-cli");
|
|
|
|
expect(resolved).not.toBeNull();
|
|
expect(resolved?.config.args).toEqual([
|
|
"exec",
|
|
"--json",
|
|
"--color",
|
|
"never",
|
|
"--sandbox",
|
|
"workspace-write",
|
|
"--skip-git-repo-check",
|
|
]);
|
|
expect(resolved?.config.resumeArgs).toEqual([
|
|
"exec",
|
|
"resume",
|
|
"{sessionId}",
|
|
"--color",
|
|
"never",
|
|
"--sandbox",
|
|
"workspace-write",
|
|
"--skip-git-repo-check",
|
|
]);
|
|
});
|
|
|
|
it("deep-merges reliability watchdog overrides for codex", () => {
|
|
const cfg = {
|
|
agents: {
|
|
defaults: {
|
|
cliBackends: {
|
|
"codex-cli": {
|
|
command: "codex",
|
|
reliability: {
|
|
watchdog: {
|
|
resume: {
|
|
noOutputTimeoutMs: 42_000,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
} satisfies OpenClawConfig;
|
|
|
|
const resolved = resolveCliBackendConfig("codex-cli", cfg);
|
|
|
|
expect(resolved).not.toBeNull();
|
|
expect(resolved?.config.reliability?.watchdog?.resume?.noOutputTimeoutMs).toBe(42_000);
|
|
// Ensure defaults are retained when only one field is overridden.
|
|
expect(resolved?.config.reliability?.watchdog?.resume?.noOutputTimeoutRatio).toBe(0.3);
|
|
expect(resolved?.config.reliability?.watchdog?.resume?.minMs).toBe(60_000);
|
|
expect(resolved?.config.reliability?.watchdog?.resume?.maxMs).toBe(180_000);
|
|
expect(resolved?.config.reliability?.watchdog?.fresh?.noOutputTimeoutRatio).toBe(0.8);
|
|
});
|
|
});
|
|
|
|
describe("resolveCliBackendConfig claude-cli defaults", () => {
|
|
it("uses non-interactive permission-mode defaults for fresh and resume args", () => {
|
|
const resolved = resolveCliBackendConfig("claude-cli");
|
|
|
|
expect(resolved).not.toBeNull();
|
|
expect(resolved?.config.output).toBe("jsonl");
|
|
expect(resolved?.config.args).toContain("stream-json");
|
|
expect(resolved?.config.args).toContain("--verbose");
|
|
expect(resolved?.config.args).toContain("--permission-mode");
|
|
expect(resolved?.config.args).toContain("bypassPermissions");
|
|
expect(resolved?.config.args).not.toContain("--dangerously-skip-permissions");
|
|
expect(resolved?.config.resumeArgs).toContain("stream-json");
|
|
expect(resolved?.config.resumeArgs).toContain("--verbose");
|
|
expect(resolved?.config.resumeArgs).toContain("--permission-mode");
|
|
expect(resolved?.config.resumeArgs).toContain("bypassPermissions");
|
|
expect(resolved?.config.resumeArgs).not.toContain("--dangerously-skip-permissions");
|
|
});
|
|
|
|
it("retains default claude safety args when only command is overridden", () => {
|
|
const cfg = {
|
|
agents: {
|
|
defaults: {
|
|
cliBackends: {
|
|
"claude-cli": {
|
|
command: "/usr/local/bin/claude",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
} satisfies OpenClawConfig;
|
|
|
|
const resolved = resolveCliBackendConfig("claude-cli", cfg);
|
|
|
|
expect(resolved).not.toBeNull();
|
|
expect(resolved?.config.command).toBe("/usr/local/bin/claude");
|
|
expect(resolved?.config.args).toContain("--permission-mode");
|
|
expect(resolved?.config.args).toContain("bypassPermissions");
|
|
expect(resolved?.config.resumeArgs).toContain("--permission-mode");
|
|
expect(resolved?.config.resumeArgs).toContain("bypassPermissions");
|
|
});
|
|
|
|
it("normalizes legacy skip-permissions overrides to permission-mode bypassPermissions", () => {
|
|
const cfg = {
|
|
agents: {
|
|
defaults: {
|
|
cliBackends: {
|
|
"claude-cli": {
|
|
command: "claude",
|
|
args: ["-p", "--dangerously-skip-permissions", "--output-format", "json"],
|
|
resumeArgs: [
|
|
"-p",
|
|
"--dangerously-skip-permissions",
|
|
"--output-format",
|
|
"json",
|
|
"--resume",
|
|
"{sessionId}",
|
|
],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
} satisfies OpenClawConfig;
|
|
|
|
const resolved = resolveCliBackendConfig("claude-cli", cfg);
|
|
|
|
expect(resolved).not.toBeNull();
|
|
expect(resolved?.config.args).not.toContain("--dangerously-skip-permissions");
|
|
expect(resolved?.config.args).toContain("--permission-mode");
|
|
expect(resolved?.config.args).toContain("bypassPermissions");
|
|
expect(resolved?.config.resumeArgs).not.toContain("--dangerously-skip-permissions");
|
|
expect(resolved?.config.resumeArgs).toContain("--permission-mode");
|
|
expect(resolved?.config.resumeArgs).toContain("bypassPermissions");
|
|
});
|
|
|
|
it("keeps explicit permission-mode overrides while removing legacy skip flag", () => {
|
|
const cfg = {
|
|
agents: {
|
|
defaults: {
|
|
cliBackends: {
|
|
"claude-cli": {
|
|
command: "claude",
|
|
args: ["-p", "--dangerously-skip-permissions", "--permission-mode", "acceptEdits"],
|
|
resumeArgs: [
|
|
"-p",
|
|
"--dangerously-skip-permissions",
|
|
"--permission-mode=acceptEdits",
|
|
"--resume",
|
|
"{sessionId}",
|
|
],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
} satisfies OpenClawConfig;
|
|
|
|
const resolved = resolveCliBackendConfig("claude-cli", cfg);
|
|
|
|
expect(resolved).not.toBeNull();
|
|
expect(resolved?.config.args).not.toContain("--dangerously-skip-permissions");
|
|
expect(resolved?.config.args).toEqual(["-p", "--permission-mode", "acceptEdits"]);
|
|
expect(resolved?.config.resumeArgs).not.toContain("--dangerously-skip-permissions");
|
|
expect(resolved?.config.resumeArgs).toEqual([
|
|
"-p",
|
|
"--permission-mode=acceptEdits",
|
|
"--resume",
|
|
"{sessionId}",
|
|
]);
|
|
expect(resolved?.config.args).not.toContain("bypassPermissions");
|
|
expect(resolved?.config.resumeArgs).not.toContain("bypassPermissions");
|
|
});
|
|
});
|
|
|
|
describe("resolveCliBackendConfig google-gemini-cli defaults", () => {
|
|
it("uses Gemini CLI json args and existing-session resume mode", () => {
|
|
const resolved = resolveCliBackendConfig("google-gemini-cli");
|
|
|
|
expect(resolved).not.toBeNull();
|
|
expect(resolved?.bundleMcp).toBe(false);
|
|
expect(resolved?.config.args).toEqual(["--prompt", "--output-format", "json"]);
|
|
expect(resolved?.config.resumeArgs).toEqual([
|
|
"--resume",
|
|
"{sessionId}",
|
|
"--prompt",
|
|
"--output-format",
|
|
"json",
|
|
]);
|
|
expect(resolved?.config.modelArg).toBe("--model");
|
|
expect(resolved?.config.sessionMode).toBe("existing");
|
|
expect(resolved?.config.sessionIdFields).toEqual(["session_id", "sessionId"]);
|
|
expect(resolved?.config.modelAliases?.pro).toBe("gemini-3.1-pro-preview");
|
|
});
|
|
});
|