mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 03:11:25 +00:00
test: move more local agents helper suites out of e2e
This commit is contained in:
283
src/agents/agent-scope.test.ts
Normal file
283
src/agents/agent-scope.test.ts
Normal file
@@ -0,0 +1,283 @@
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import {
|
||||
resolveAgentConfig,
|
||||
resolveAgentDir,
|
||||
resolveEffectiveModelFallbacks,
|
||||
resolveAgentModelFallbacksOverride,
|
||||
resolveAgentModelPrimary,
|
||||
resolveAgentWorkspaceDir,
|
||||
} from "./agent-scope.js";
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
describe("resolveAgentConfig", () => {
|
||||
it("should return undefined when no agents config exists", () => {
|
||||
const cfg: OpenClawConfig = {};
|
||||
const result = resolveAgentConfig(cfg, "main");
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should return undefined when agent id does not exist", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
agents: {
|
||||
list: [{ id: "main", workspace: "~/openclaw" }],
|
||||
},
|
||||
};
|
||||
const result = resolveAgentConfig(cfg, "nonexistent");
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should return basic agent config", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
agents: {
|
||||
list: [
|
||||
{
|
||||
id: "main",
|
||||
name: "Main Agent",
|
||||
workspace: "~/openclaw",
|
||||
agentDir: "~/.openclaw/agents/main",
|
||||
model: "anthropic/claude-opus-4",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
const result = resolveAgentConfig(cfg, "main");
|
||||
expect(result).toEqual({
|
||||
name: "Main Agent",
|
||||
workspace: "~/openclaw",
|
||||
agentDir: "~/.openclaw/agents/main",
|
||||
model: "anthropic/claude-opus-4",
|
||||
identity: undefined,
|
||||
groupChat: undefined,
|
||||
subagents: undefined,
|
||||
sandbox: undefined,
|
||||
tools: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("supports per-agent model primary+fallbacks", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
model: {
|
||||
primary: "anthropic/claude-sonnet-4",
|
||||
fallbacks: ["openai/gpt-4.1"],
|
||||
},
|
||||
},
|
||||
list: [
|
||||
{
|
||||
id: "linus",
|
||||
model: {
|
||||
primary: "anthropic/claude-opus-4",
|
||||
fallbacks: ["openai/gpt-5.2"],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
expect(resolveAgentModelPrimary(cfg, "linus")).toBe("anthropic/claude-opus-4");
|
||||
expect(resolveAgentModelFallbacksOverride(cfg, "linus")).toEqual(["openai/gpt-5.2"]);
|
||||
|
||||
// If fallbacks isn't present, we don't override the global fallbacks.
|
||||
const cfgNoOverride: OpenClawConfig = {
|
||||
agents: {
|
||||
list: [
|
||||
{
|
||||
id: "linus",
|
||||
model: {
|
||||
primary: "anthropic/claude-opus-4",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
expect(resolveAgentModelFallbacksOverride(cfgNoOverride, "linus")).toBe(undefined);
|
||||
|
||||
// Explicit empty list disables global fallbacks for that agent.
|
||||
const cfgDisable: OpenClawConfig = {
|
||||
agents: {
|
||||
list: [
|
||||
{
|
||||
id: "linus",
|
||||
model: {
|
||||
primary: "anthropic/claude-opus-4",
|
||||
fallbacks: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
expect(resolveAgentModelFallbacksOverride(cfgDisable, "linus")).toEqual([]);
|
||||
|
||||
expect(
|
||||
resolveEffectiveModelFallbacks({
|
||||
cfg,
|
||||
agentId: "linus",
|
||||
hasSessionModelOverride: false,
|
||||
}),
|
||||
).toEqual(["openai/gpt-5.2"]);
|
||||
expect(
|
||||
resolveEffectiveModelFallbacks({
|
||||
cfg,
|
||||
agentId: "linus",
|
||||
hasSessionModelOverride: true,
|
||||
}),
|
||||
).toEqual(["openai/gpt-5.2"]);
|
||||
expect(
|
||||
resolveEffectiveModelFallbacks({
|
||||
cfg: cfgNoOverride,
|
||||
agentId: "linus",
|
||||
hasSessionModelOverride: true,
|
||||
}),
|
||||
).toEqual([]);
|
||||
|
||||
const cfgInheritDefaults: OpenClawConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
model: {
|
||||
fallbacks: ["openai/gpt-4.1"],
|
||||
},
|
||||
},
|
||||
list: [
|
||||
{
|
||||
id: "linus",
|
||||
model: {
|
||||
primary: "anthropic/claude-opus-4",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
expect(
|
||||
resolveEffectiveModelFallbacks({
|
||||
cfg: cfgInheritDefaults,
|
||||
agentId: "linus",
|
||||
hasSessionModelOverride: true,
|
||||
}),
|
||||
).toEqual(["openai/gpt-4.1"]);
|
||||
expect(
|
||||
resolveEffectiveModelFallbacks({
|
||||
cfg: cfgDisable,
|
||||
agentId: "linus",
|
||||
hasSessionModelOverride: true,
|
||||
}),
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it("should return agent-specific sandbox config", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
agents: {
|
||||
list: [
|
||||
{
|
||||
id: "work",
|
||||
workspace: "~/openclaw-work",
|
||||
sandbox: {
|
||||
mode: "all",
|
||||
scope: "agent",
|
||||
perSession: false,
|
||||
workspaceAccess: "ro",
|
||||
workspaceRoot: "~/sandboxes",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
const result = resolveAgentConfig(cfg, "work");
|
||||
expect(result?.sandbox).toEqual({
|
||||
mode: "all",
|
||||
scope: "agent",
|
||||
perSession: false,
|
||||
workspaceAccess: "ro",
|
||||
workspaceRoot: "~/sandboxes",
|
||||
});
|
||||
});
|
||||
|
||||
it("should return agent-specific tools config", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
agents: {
|
||||
list: [
|
||||
{
|
||||
id: "restricted",
|
||||
workspace: "~/openclaw-restricted",
|
||||
tools: {
|
||||
allow: ["read"],
|
||||
deny: ["exec", "write", "edit"],
|
||||
elevated: {
|
||||
enabled: false,
|
||||
allowFrom: { whatsapp: ["+15555550123"] },
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
const result = resolveAgentConfig(cfg, "restricted");
|
||||
expect(result?.tools).toEqual({
|
||||
allow: ["read"],
|
||||
deny: ["exec", "write", "edit"],
|
||||
elevated: {
|
||||
enabled: false,
|
||||
allowFrom: { whatsapp: ["+15555550123"] },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("should return both sandbox and tools config", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
agents: {
|
||||
list: [
|
||||
{
|
||||
id: "family",
|
||||
workspace: "~/openclaw-family",
|
||||
sandbox: {
|
||||
mode: "all",
|
||||
scope: "agent",
|
||||
},
|
||||
tools: {
|
||||
allow: ["read"],
|
||||
deny: ["exec"],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
const result = resolveAgentConfig(cfg, "family");
|
||||
expect(result?.sandbox?.mode).toBe("all");
|
||||
expect(result?.tools?.allow).toEqual(["read"]);
|
||||
});
|
||||
|
||||
it("should normalize agent id", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
agents: {
|
||||
list: [{ id: "main", workspace: "~/openclaw" }],
|
||||
},
|
||||
};
|
||||
// Should normalize to "main" (default)
|
||||
const result = resolveAgentConfig(cfg, "");
|
||||
expect(result).toBeDefined();
|
||||
expect(result?.workspace).toBe("~/openclaw");
|
||||
});
|
||||
|
||||
it("uses OPENCLAW_HOME for default agent workspace", () => {
|
||||
const home = path.join(path.sep, "srv", "openclaw-home");
|
||||
vi.stubEnv("OPENCLAW_HOME", home);
|
||||
|
||||
const workspace = resolveAgentWorkspaceDir({} as OpenClawConfig, "main");
|
||||
expect(workspace).toBe(path.join(path.resolve(home), ".openclaw", "workspace"));
|
||||
});
|
||||
|
||||
it("uses OPENCLAW_HOME for default agentDir", () => {
|
||||
const home = path.join(path.sep, "srv", "openclaw-home");
|
||||
vi.stubEnv("OPENCLAW_HOME", home);
|
||||
// Clear state dir so it falls back to OPENCLAW_HOME
|
||||
vi.stubEnv("OPENCLAW_STATE_DIR", "");
|
||||
|
||||
const agentDir = resolveAgentDir({} as OpenClawConfig, "main");
|
||||
expect(agentDir).toBe(path.join(path.resolve(home), ".openclaw", "agents", "main", "agent"));
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user