mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-29 16:54:30 +00:00
refactor(test): dedupe directive behavior e2e setup
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
import "./reply.directive.directive-behavior.e2e-mocks.js";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js";
|
||||
import { loadModelCatalog } from "../agents/model-catalog.js";
|
||||
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
|
||||
import { loadSessionStore } from "../config/sessions.js";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
installDirectiveBehaviorE2EHooks,
|
||||
runEmbeddedPiAgent,
|
||||
withTempHome,
|
||||
} from "./reply.directive.directive-behavior.e2e-harness.js";
|
||||
import { getReplyFromConfig } from "./reply.js";
|
||||
|
||||
const MAIN_SESSION_KEY = "agent:main:main";
|
||||
|
||||
async function writeSkill(params: { workspaceDir: string; name: string; description: string }) {
|
||||
const { workspaceDir, name, description } = params;
|
||||
const skillDir = path.join(workspaceDir, "skills", name);
|
||||
@@ -20,57 +20,8 @@ async function writeSkill(params: { workspaceDir: string; name: string; descript
|
||||
);
|
||||
}
|
||||
|
||||
vi.mock("../agents/pi-embedded.js", () => ({
|
||||
abortEmbeddedPiRun: vi.fn().mockReturnValue(false),
|
||||
runEmbeddedPiAgent: vi.fn(),
|
||||
queueEmbeddedPiMessage: vi.fn().mockReturnValue(false),
|
||||
resolveEmbeddedSessionLane: (key: string) => `session:${key.trim() || "main"}`,
|
||||
isEmbeddedPiRunActive: vi.fn().mockReturnValue(false),
|
||||
isEmbeddedPiRunStreaming: vi.fn().mockReturnValue(false),
|
||||
}));
|
||||
vi.mock("../agents/model-catalog.js", () => ({
|
||||
loadModelCatalog: vi.fn(),
|
||||
}));
|
||||
|
||||
async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
|
||||
return withTempHomeBase(
|
||||
async (home) => {
|
||||
return await fn(home);
|
||||
},
|
||||
{
|
||||
env: {
|
||||
OPENCLAW_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
PI_CODING_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
},
|
||||
prefix: "openclaw-reply-",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function _assertModelSelection(
|
||||
storePath: string,
|
||||
selection: { model?: string; provider?: string } = {},
|
||||
) {
|
||||
const store = loadSessionStore(storePath);
|
||||
const entry = store[MAIN_SESSION_KEY];
|
||||
expect(entry).toBeDefined();
|
||||
expect(entry?.modelOverride).toBe(selection.model);
|
||||
expect(entry?.providerOverride).toBe(selection.provider);
|
||||
}
|
||||
|
||||
describe("directive behavior", () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
vi.mocked(loadModelCatalog).mockResolvedValue([
|
||||
{ id: "claude-opus-4-5", name: "Opus 4.5", provider: "anthropic" },
|
||||
{ id: "claude-sonnet-4-1", name: "Sonnet 4.1", provider: "anthropic" },
|
||||
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", provider: "openai" },
|
||||
]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
installDirectiveBehaviorE2EHooks();
|
||||
|
||||
it("accepts /thinking xhigh for codex models", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
@@ -160,8 +111,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("keeps reserved command aliases from matching after trimming", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{
|
||||
Body: "/help",
|
||||
@@ -192,7 +141,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("treats skill commands as reserved for model aliases", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const workspace = path.join(home, "openclaw");
|
||||
await writeSkill({
|
||||
workspaceDir: workspace,
|
||||
@@ -230,8 +178,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("errors on invalid queue options", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{
|
||||
Body: "/queue collect debounce:bogus cap:zero drop:maybe",
|
||||
@@ -261,8 +207,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("shows current queue settings when /queue has no arguments", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{
|
||||
Body: "/queue",
|
||||
@@ -304,8 +248,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("shows current think level when /think has no argument", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{ Body: "/think", From: "+1222", To: "+1222", CommandAuthorized: true },
|
||||
{},
|
||||
|
||||
@@ -1,64 +1,16 @@
|
||||
import "./reply.directive.directive-behavior.e2e-mocks.js";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js";
|
||||
import { loadModelCatalog } from "../agents/model-catalog.js";
|
||||
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { loadSessionStore } from "../config/sessions.js";
|
||||
import {
|
||||
installDirectiveBehaviorE2EHooks,
|
||||
runEmbeddedPiAgent,
|
||||
withTempHome,
|
||||
} from "./reply.directive.directive-behavior.e2e-harness.js";
|
||||
import { getReplyFromConfig } from "./reply.js";
|
||||
|
||||
const MAIN_SESSION_KEY = "agent:main:main";
|
||||
|
||||
vi.mock("../agents/pi-embedded.js", () => ({
|
||||
abortEmbeddedPiRun: vi.fn().mockReturnValue(false),
|
||||
runEmbeddedPiAgent: vi.fn(),
|
||||
queueEmbeddedPiMessage: vi.fn().mockReturnValue(false),
|
||||
resolveEmbeddedSessionLane: (key: string) => `session:${key.trim() || "main"}`,
|
||||
isEmbeddedPiRunActive: vi.fn().mockReturnValue(false),
|
||||
isEmbeddedPiRunStreaming: vi.fn().mockReturnValue(false),
|
||||
}));
|
||||
vi.mock("../agents/model-catalog.js", () => ({
|
||||
loadModelCatalog: vi.fn(),
|
||||
}));
|
||||
|
||||
async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
|
||||
return withTempHomeBase(
|
||||
async (home) => {
|
||||
return await fn(home);
|
||||
},
|
||||
{
|
||||
env: {
|
||||
OPENCLAW_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
PI_CODING_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
},
|
||||
prefix: "openclaw-reply-",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function _assertModelSelection(
|
||||
storePath: string,
|
||||
selection: { model?: string; provider?: string } = {},
|
||||
) {
|
||||
const store = loadSessionStore(storePath);
|
||||
const entry = store[MAIN_SESSION_KEY];
|
||||
expect(entry).toBeDefined();
|
||||
expect(entry?.modelOverride).toBe(selection.model);
|
||||
expect(entry?.providerOverride).toBe(selection.provider);
|
||||
}
|
||||
|
||||
describe("directive behavior", () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
vi.mocked(loadModelCatalog).mockResolvedValue([
|
||||
{ id: "claude-opus-4-5", name: "Opus 4.5", provider: "anthropic" },
|
||||
{ id: "claude-sonnet-4-1", name: "Sonnet 4.1", provider: "anthropic" },
|
||||
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", provider: "openai" },
|
||||
]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
installDirectiveBehaviorE2EHooks();
|
||||
|
||||
it("applies inline reasoning in mixed messages and acks immediately", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
@@ -176,8 +128,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("acks verbose directive immediately with system marker", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{ Body: "/verbose on", From: "+1222", To: "+1222", CommandAuthorized: true },
|
||||
{},
|
||||
@@ -199,7 +149,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("persists verbose off when directive is standalone", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
@@ -226,8 +175,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("shows current think level when /think has no argument", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{ Body: "/think", From: "+1222", To: "+1222", CommandAuthorized: true },
|
||||
{},
|
||||
@@ -251,8 +198,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("shows off when /think has no argument and no default set", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{ Body: "/think", From: "+1222", To: "+1222", CommandAuthorized: true },
|
||||
{},
|
||||
|
||||
@@ -1,68 +1,19 @@
|
||||
import "./reply.directive.directive-behavior.e2e-mocks.js";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js";
|
||||
import { loadModelCatalog } from "../agents/model-catalog.js";
|
||||
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
|
||||
import { loadSessionStore } from "../config/sessions.js";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
installDirectiveBehaviorE2EHooks,
|
||||
loadModelCatalog,
|
||||
runEmbeddedPiAgent,
|
||||
withTempHome,
|
||||
} from "./reply.directive.directive-behavior.e2e-harness.js";
|
||||
import { getReplyFromConfig } from "./reply.js";
|
||||
|
||||
const MAIN_SESSION_KEY = "agent:main:main";
|
||||
|
||||
vi.mock("../agents/pi-embedded.js", () => ({
|
||||
abortEmbeddedPiRun: vi.fn().mockReturnValue(false),
|
||||
runEmbeddedPiAgent: vi.fn(),
|
||||
queueEmbeddedPiMessage: vi.fn().mockReturnValue(false),
|
||||
resolveEmbeddedSessionLane: (key: string) => `session:${key.trim() || "main"}`,
|
||||
isEmbeddedPiRunActive: vi.fn().mockReturnValue(false),
|
||||
isEmbeddedPiRunStreaming: vi.fn().mockReturnValue(false),
|
||||
}));
|
||||
vi.mock("../agents/model-catalog.js", () => ({
|
||||
loadModelCatalog: vi.fn(),
|
||||
}));
|
||||
|
||||
async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
|
||||
return withTempHomeBase(
|
||||
async (home) => {
|
||||
return await fn(home);
|
||||
},
|
||||
{
|
||||
env: {
|
||||
OPENCLAW_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
PI_CODING_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
},
|
||||
prefix: "openclaw-reply-",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function _assertModelSelection(
|
||||
storePath: string,
|
||||
selection: { model?: string; provider?: string } = {},
|
||||
) {
|
||||
const store = loadSessionStore(storePath);
|
||||
const entry = store[MAIN_SESSION_KEY];
|
||||
expect(entry).toBeDefined();
|
||||
expect(entry?.modelOverride).toBe(selection.model);
|
||||
expect(entry?.providerOverride).toBe(selection.provider);
|
||||
}
|
||||
|
||||
describe("directive behavior", () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
vi.mocked(loadModelCatalog).mockResolvedValue([
|
||||
{ id: "claude-opus-4-5", name: "Opus 4.5", provider: "anthropic" },
|
||||
{ id: "claude-sonnet-4-1", name: "Sonnet 4.1", provider: "anthropic" },
|
||||
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", provider: "openai" },
|
||||
]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
installDirectiveBehaviorE2EHooks();
|
||||
|
||||
it("defaults /think to low for reasoning-capable models when no default set", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
vi.mocked(loadModelCatalog).mockResolvedValueOnce([
|
||||
{
|
||||
id: "claude-opus-4-5",
|
||||
@@ -94,7 +45,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("shows off when /think has no argument and model lacks reasoning", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
vi.mocked(loadModelCatalog).mockResolvedValueOnce([
|
||||
{
|
||||
id: "claude-opus-4-5",
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, expect, vi } from "vitest";
|
||||
import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js";
|
||||
import { loadModelCatalog } from "../agents/model-catalog.js";
|
||||
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
|
||||
import { loadSessionStore } from "../config/sessions.js";
|
||||
|
||||
export { loadModelCatalog } from "../agents/model-catalog.js";
|
||||
export { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
|
||||
|
||||
export const MAIN_SESSION_KEY = "agent:main:main";
|
||||
|
||||
export const DEFAULT_TEST_MODEL_CATALOG: Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
provider: string;
|
||||
}> = [
|
||||
{ id: "claude-opus-4-5", name: "Opus 4.5", provider: "anthropic" },
|
||||
{ id: "claude-sonnet-4-1", name: "Sonnet 4.1", provider: "anthropic" },
|
||||
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", provider: "openai" },
|
||||
];
|
||||
|
||||
export async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
|
||||
return withTempHomeBase(
|
||||
async (home) => {
|
||||
return await fn(home);
|
||||
},
|
||||
{
|
||||
env: {
|
||||
OPENCLAW_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
PI_CODING_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
},
|
||||
prefix: "openclaw-reply-",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export function assertModelSelection(
|
||||
storePath: string,
|
||||
selection: { model?: string; provider?: string } = {},
|
||||
) {
|
||||
const store = loadSessionStore(storePath);
|
||||
const entry = store[MAIN_SESSION_KEY];
|
||||
expect(entry).toBeDefined();
|
||||
expect(entry?.modelOverride).toBe(selection.model);
|
||||
expect(entry?.providerOverride).toBe(selection.provider);
|
||||
}
|
||||
|
||||
export function installDirectiveBehaviorE2EHooks() {
|
||||
beforeEach(() => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
vi.mocked(loadModelCatalog).mockResolvedValue(DEFAULT_TEST_MODEL_CATALOG);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { vi } from "vitest";
|
||||
|
||||
vi.mock("../agents/pi-embedded.js", () => ({
|
||||
abortEmbeddedPiRun: vi.fn().mockReturnValue(false),
|
||||
runEmbeddedPiAgent: vi.fn(),
|
||||
queueEmbeddedPiMessage: vi.fn().mockReturnValue(false),
|
||||
resolveEmbeddedSessionLane: (key: string) => `session:${key.trim() || "main"}`,
|
||||
isEmbeddedPiRunActive: vi.fn().mockReturnValue(false),
|
||||
isEmbeddedPiRunStreaming: vi.fn().mockReturnValue(false),
|
||||
}));
|
||||
|
||||
vi.mock("../agents/model-catalog.js", () => ({
|
||||
loadModelCatalog: vi.fn(),
|
||||
}));
|
||||
@@ -1,64 +1,16 @@
|
||||
import "./reply.directive.directive-behavior.e2e-mocks.js";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js";
|
||||
import { loadModelCatalog } from "../agents/model-catalog.js";
|
||||
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
|
||||
import { loadSessionStore } from "../config/sessions.js";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
installDirectiveBehaviorE2EHooks,
|
||||
loadModelCatalog,
|
||||
runEmbeddedPiAgent,
|
||||
withTempHome,
|
||||
} from "./reply.directive.directive-behavior.e2e-harness.js";
|
||||
import { getReplyFromConfig } from "./reply.js";
|
||||
|
||||
const MAIN_SESSION_KEY = "agent:main:main";
|
||||
|
||||
vi.mock("../agents/pi-embedded.js", () => ({
|
||||
abortEmbeddedPiRun: vi.fn().mockReturnValue(false),
|
||||
runEmbeddedPiAgent: vi.fn(),
|
||||
queueEmbeddedPiMessage: vi.fn().mockReturnValue(false),
|
||||
resolveEmbeddedSessionLane: (key: string) => `session:${key.trim() || "main"}`,
|
||||
isEmbeddedPiRunActive: vi.fn().mockReturnValue(false),
|
||||
isEmbeddedPiRunStreaming: vi.fn().mockReturnValue(false),
|
||||
}));
|
||||
vi.mock("../agents/model-catalog.js", () => ({
|
||||
loadModelCatalog: vi.fn(),
|
||||
}));
|
||||
|
||||
async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
|
||||
return withTempHomeBase(
|
||||
async (home) => {
|
||||
return await fn(home);
|
||||
},
|
||||
{
|
||||
env: {
|
||||
OPENCLAW_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
PI_CODING_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
},
|
||||
prefix: "openclaw-reply-",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function _assertModelSelection(
|
||||
storePath: string,
|
||||
selection: { model?: string; provider?: string } = {},
|
||||
) {
|
||||
const store = loadSessionStore(storePath);
|
||||
const entry = store[MAIN_SESSION_KEY];
|
||||
expect(entry).toBeDefined();
|
||||
expect(entry?.modelOverride).toBe(selection.model);
|
||||
expect(entry?.providerOverride).toBe(selection.provider);
|
||||
}
|
||||
|
||||
describe("directive behavior", () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
vi.mocked(loadModelCatalog).mockResolvedValue([
|
||||
{ id: "claude-opus-4-5", name: "Opus 4.5", provider: "anthropic" },
|
||||
{ id: "claude-sonnet-4-1", name: "Sonnet 4.1", provider: "anthropic" },
|
||||
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", provider: "openai" },
|
||||
]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
installDirectiveBehaviorE2EHooks();
|
||||
|
||||
it("ignores inline /model and uses the default model", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
|
||||
@@ -1,68 +1,20 @@
|
||||
import "./reply.directive.directive-behavior.e2e-mocks.js";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js";
|
||||
import { loadModelCatalog } from "../agents/model-catalog.js";
|
||||
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
|
||||
import { loadSessionStore } from "../config/sessions.js";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
assertModelSelection,
|
||||
installDirectiveBehaviorE2EHooks,
|
||||
loadModelCatalog,
|
||||
runEmbeddedPiAgent,
|
||||
withTempHome,
|
||||
} from "./reply.directive.directive-behavior.e2e-harness.js";
|
||||
import { getReplyFromConfig } from "./reply.js";
|
||||
|
||||
const MAIN_SESSION_KEY = "agent:main:main";
|
||||
|
||||
vi.mock("../agents/pi-embedded.js", () => ({
|
||||
abortEmbeddedPiRun: vi.fn().mockReturnValue(false),
|
||||
runEmbeddedPiAgent: vi.fn(),
|
||||
queueEmbeddedPiMessage: vi.fn().mockReturnValue(false),
|
||||
resolveEmbeddedSessionLane: (key: string) => `session:${key.trim() || "main"}`,
|
||||
isEmbeddedPiRunActive: vi.fn().mockReturnValue(false),
|
||||
isEmbeddedPiRunStreaming: vi.fn().mockReturnValue(false),
|
||||
}));
|
||||
vi.mock("../agents/model-catalog.js", () => ({
|
||||
loadModelCatalog: vi.fn(),
|
||||
}));
|
||||
|
||||
async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
|
||||
return withTempHomeBase(
|
||||
async (home) => {
|
||||
return await fn(home);
|
||||
},
|
||||
{
|
||||
env: {
|
||||
OPENCLAW_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
PI_CODING_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
},
|
||||
prefix: "openclaw-reply-",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function assertModelSelection(
|
||||
storePath: string,
|
||||
selection: { model?: string; provider?: string } = {},
|
||||
) {
|
||||
const store = loadSessionStore(storePath);
|
||||
const entry = store[MAIN_SESSION_KEY];
|
||||
expect(entry).toBeDefined();
|
||||
expect(entry?.modelOverride).toBe(selection.model);
|
||||
expect(entry?.providerOverride).toBe(selection.provider);
|
||||
}
|
||||
|
||||
describe("directive behavior", () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
vi.mocked(loadModelCatalog).mockResolvedValue([
|
||||
{ id: "claude-opus-4-5", name: "Opus 4.5", provider: "anthropic" },
|
||||
{ id: "claude-sonnet-4-1", name: "Sonnet 4.1", provider: "anthropic" },
|
||||
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", provider: "openai" },
|
||||
]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
installDirectiveBehaviorE2EHooks();
|
||||
|
||||
it("aliases /model list to /models", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
@@ -94,7 +46,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("shows current model when catalog is unavailable", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
vi.mocked(loadModelCatalog).mockResolvedValueOnce([]);
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
@@ -126,7 +77,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("includes catalog providers when no allowlist is set", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
vi.mocked(loadModelCatalog).mockResolvedValue([
|
||||
{ id: "claude-opus-4-5", name: "Opus 4.5", provider: "anthropic" },
|
||||
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", provider: "openai" },
|
||||
@@ -163,7 +113,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("lists config-only providers when catalog is present", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
// Catalog present but missing custom providers: /model should still include
|
||||
// allowlisted provider/model keys from config.
|
||||
vi.mocked(loadModelCatalog).mockResolvedValueOnce([
|
||||
@@ -213,7 +162,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("does not repeat missing auth labels on /model list", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
@@ -241,7 +189,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("sets model override on /model directive", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
await getReplyFromConfig(
|
||||
@@ -271,7 +218,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("supports model aliases on /model directive", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
await getReplyFromConfig(
|
||||
|
||||
@@ -1,70 +1,23 @@
|
||||
import "./reply.directive.directive-behavior.e2e-mocks.js";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js";
|
||||
import { loadModelCatalog } from "../agents/model-catalog.js";
|
||||
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { loadSessionStore } from "../config/sessions.js";
|
||||
import { drainSystemEvents } from "../infra/system-events.js";
|
||||
import {
|
||||
assertModelSelection,
|
||||
installDirectiveBehaviorE2EHooks,
|
||||
MAIN_SESSION_KEY,
|
||||
runEmbeddedPiAgent,
|
||||
withTempHome,
|
||||
} from "./reply.directive.directive-behavior.e2e-harness.js";
|
||||
import { getReplyFromConfig } from "./reply.js";
|
||||
|
||||
const MAIN_SESSION_KEY = "agent:main:main";
|
||||
|
||||
vi.mock("../agents/pi-embedded.js", () => ({
|
||||
abortEmbeddedPiRun: vi.fn().mockReturnValue(false),
|
||||
runEmbeddedPiAgent: vi.fn(),
|
||||
queueEmbeddedPiMessage: vi.fn().mockReturnValue(false),
|
||||
resolveEmbeddedSessionLane: (key: string) => `session:${key.trim() || "main"}`,
|
||||
isEmbeddedPiRunActive: vi.fn().mockReturnValue(false),
|
||||
isEmbeddedPiRunStreaming: vi.fn().mockReturnValue(false),
|
||||
}));
|
||||
vi.mock("../agents/model-catalog.js", () => ({
|
||||
loadModelCatalog: vi.fn(),
|
||||
}));
|
||||
|
||||
async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
|
||||
return withTempHomeBase(
|
||||
async (home) => {
|
||||
return await fn(home);
|
||||
},
|
||||
{
|
||||
env: {
|
||||
OPENCLAW_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
PI_CODING_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
},
|
||||
prefix: "openclaw-reply-",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function assertModelSelection(
|
||||
storePath: string,
|
||||
selection: { model?: string; provider?: string } = {},
|
||||
) {
|
||||
const store = loadSessionStore(storePath);
|
||||
const entry = store[MAIN_SESSION_KEY];
|
||||
expect(entry).toBeDefined();
|
||||
expect(entry?.modelOverride).toBe(selection.model);
|
||||
expect(entry?.providerOverride).toBe(selection.provider);
|
||||
}
|
||||
|
||||
describe("directive behavior", () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
vi.mocked(loadModelCatalog).mockResolvedValue([
|
||||
{ id: "claude-opus-4-5", name: "Opus 4.5", provider: "anthropic" },
|
||||
{ id: "claude-sonnet-4-1", name: "Sonnet 4.1", provider: "anthropic" },
|
||||
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", provider: "openai" },
|
||||
]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
installDirectiveBehaviorE2EHooks();
|
||||
|
||||
it("prefers alias matches when fuzzy selection is ambiguous", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
@@ -114,7 +67,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("stores auth profile overrides on /model directive", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
const authDir = path.join(home, ".openclaw", "agents", "main", "agent");
|
||||
await fs.mkdir(authDir, { recursive: true, mode: 0o700 });
|
||||
@@ -165,7 +117,6 @@ describe("directive behavior", () => {
|
||||
it("queues a system event when switching models", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
drainSystemEvents(MAIN_SESSION_KEY);
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
await getReplyFromConfig(
|
||||
|
||||
@@ -1,69 +1,18 @@
|
||||
import "./reply.directive.directive-behavior.e2e-mocks.js";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js";
|
||||
import { loadModelCatalog } from "../agents/model-catalog.js";
|
||||
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
|
||||
import { loadSessionStore } from "../config/sessions.js";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
installDirectiveBehaviorE2EHooks,
|
||||
runEmbeddedPiAgent,
|
||||
withTempHome,
|
||||
} from "./reply.directive.directive-behavior.e2e-harness.js";
|
||||
import { getReplyFromConfig } from "./reply.js";
|
||||
|
||||
const MAIN_SESSION_KEY = "agent:main:main";
|
||||
|
||||
vi.mock("../agents/pi-embedded.js", () => ({
|
||||
abortEmbeddedPiRun: vi.fn().mockReturnValue(false),
|
||||
runEmbeddedPiAgent: vi.fn(),
|
||||
queueEmbeddedPiMessage: vi.fn().mockReturnValue(false),
|
||||
resolveEmbeddedSessionLane: (key: string) => `session:${key.trim() || "main"}`,
|
||||
isEmbeddedPiRunActive: vi.fn().mockReturnValue(false),
|
||||
isEmbeddedPiRunStreaming: vi.fn().mockReturnValue(false),
|
||||
}));
|
||||
vi.mock("../agents/model-catalog.js", () => ({
|
||||
loadModelCatalog: vi.fn(),
|
||||
}));
|
||||
|
||||
async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
|
||||
return withTempHomeBase(
|
||||
async (home) => {
|
||||
return await fn(home);
|
||||
},
|
||||
{
|
||||
env: {
|
||||
OPENCLAW_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
PI_CODING_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
},
|
||||
prefix: "openclaw-reply-",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function _assertModelSelection(
|
||||
storePath: string,
|
||||
selection: { model?: string; provider?: string } = {},
|
||||
) {
|
||||
const store = loadSessionStore(storePath);
|
||||
const entry = store[MAIN_SESSION_KEY];
|
||||
expect(entry).toBeDefined();
|
||||
expect(entry?.modelOverride).toBe(selection.model);
|
||||
expect(entry?.providerOverride).toBe(selection.provider);
|
||||
}
|
||||
|
||||
describe("directive behavior", () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
vi.mocked(loadModelCatalog).mockResolvedValue([
|
||||
{ id: "claude-opus-4-5", name: "Opus 4.5", provider: "anthropic" },
|
||||
{ id: "claude-sonnet-4-1", name: "Sonnet 4.1", provider: "anthropic" },
|
||||
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", provider: "openai" },
|
||||
]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
installDirectiveBehaviorE2EHooks();
|
||||
|
||||
it("requires per-agent allowlist in addition to global", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{
|
||||
Body: "/elevated on",
|
||||
@@ -109,8 +58,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("allows elevated when both global and per-agent allowlists match", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{
|
||||
Body: "/elevated on",
|
||||
@@ -156,8 +103,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("warns when elevated is used in direct runtime", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{
|
||||
Body: "/elevated off",
|
||||
@@ -194,8 +139,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("rejects invalid elevated level", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{
|
||||
Body: "/elevated maybe",
|
||||
@@ -230,8 +173,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("handles multiple directives in a single message", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{
|
||||
Body: "/elevated off\n/verbose on",
|
||||
|
||||
@@ -1,68 +1,19 @@
|
||||
import "./reply.directive.directive-behavior.e2e-mocks.js";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js";
|
||||
import { loadModelCatalog } from "../agents/model-catalog.js";
|
||||
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { loadSessionStore } from "../config/sessions.js";
|
||||
import {
|
||||
installDirectiveBehaviorE2EHooks,
|
||||
runEmbeddedPiAgent,
|
||||
withTempHome,
|
||||
} from "./reply.directive.directive-behavior.e2e-harness.js";
|
||||
import { getReplyFromConfig } from "./reply.js";
|
||||
|
||||
const MAIN_SESSION_KEY = "agent:main:main";
|
||||
|
||||
vi.mock("../agents/pi-embedded.js", () => ({
|
||||
abortEmbeddedPiRun: vi.fn().mockReturnValue(false),
|
||||
runEmbeddedPiAgent: vi.fn(),
|
||||
queueEmbeddedPiMessage: vi.fn().mockReturnValue(false),
|
||||
resolveEmbeddedSessionLane: (key: string) => `session:${key.trim() || "main"}`,
|
||||
isEmbeddedPiRunActive: vi.fn().mockReturnValue(false),
|
||||
isEmbeddedPiRunStreaming: vi.fn().mockReturnValue(false),
|
||||
}));
|
||||
vi.mock("../agents/model-catalog.js", () => ({
|
||||
loadModelCatalog: vi.fn(),
|
||||
}));
|
||||
|
||||
async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
|
||||
return withTempHomeBase(
|
||||
async (home) => {
|
||||
return await fn(home);
|
||||
},
|
||||
{
|
||||
env: {
|
||||
OPENCLAW_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
PI_CODING_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
},
|
||||
prefix: "openclaw-reply-",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function _assertModelSelection(
|
||||
storePath: string,
|
||||
selection: { model?: string; provider?: string } = {},
|
||||
) {
|
||||
const store = loadSessionStore(storePath);
|
||||
const entry = store[MAIN_SESSION_KEY];
|
||||
expect(entry).toBeDefined();
|
||||
expect(entry?.modelOverride).toBe(selection.model);
|
||||
expect(entry?.providerOverride).toBe(selection.provider);
|
||||
}
|
||||
|
||||
describe("directive behavior", () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
vi.mocked(loadModelCatalog).mockResolvedValue([
|
||||
{ id: "claude-opus-4-5", name: "Opus 4.5", provider: "anthropic" },
|
||||
{ id: "claude-sonnet-4-1", name: "Sonnet 4.1", provider: "anthropic" },
|
||||
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", provider: "openai" },
|
||||
]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
installDirectiveBehaviorE2EHooks();
|
||||
|
||||
it("returns status alongside directive-only acks", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
@@ -106,8 +57,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("shows elevated off in status when per-agent elevated is disabled", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{
|
||||
Body: "/status",
|
||||
@@ -151,7 +100,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("acks queue directive and persists override", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
@@ -179,7 +127,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("persists queue options when directive is standalone", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
@@ -218,7 +165,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("resets queue mode to default", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
await getReplyFromConfig(
|
||||
|
||||
@@ -1,68 +1,19 @@
|
||||
import "./reply.directive.directive-behavior.e2e-mocks.js";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js";
|
||||
import { loadModelCatalog } from "../agents/model-catalog.js";
|
||||
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { loadSessionStore } from "../config/sessions.js";
|
||||
import {
|
||||
installDirectiveBehaviorE2EHooks,
|
||||
runEmbeddedPiAgent,
|
||||
withTempHome,
|
||||
} from "./reply.directive.directive-behavior.e2e-harness.js";
|
||||
import { getReplyFromConfig } from "./reply.js";
|
||||
|
||||
const MAIN_SESSION_KEY = "agent:main:main";
|
||||
|
||||
vi.mock("../agents/pi-embedded.js", () => ({
|
||||
abortEmbeddedPiRun: vi.fn().mockReturnValue(false),
|
||||
runEmbeddedPiAgent: vi.fn(),
|
||||
queueEmbeddedPiMessage: vi.fn().mockReturnValue(false),
|
||||
resolveEmbeddedSessionLane: (key: string) => `session:${key.trim() || "main"}`,
|
||||
isEmbeddedPiRunActive: vi.fn().mockReturnValue(false),
|
||||
isEmbeddedPiRunStreaming: vi.fn().mockReturnValue(false),
|
||||
}));
|
||||
vi.mock("../agents/model-catalog.js", () => ({
|
||||
loadModelCatalog: vi.fn(),
|
||||
}));
|
||||
|
||||
async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
|
||||
return withTempHomeBase(
|
||||
async (home) => {
|
||||
return await fn(home);
|
||||
},
|
||||
{
|
||||
env: {
|
||||
OPENCLAW_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
PI_CODING_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
},
|
||||
prefix: "openclaw-reply-",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function _assertModelSelection(
|
||||
storePath: string,
|
||||
selection: { model?: string; provider?: string } = {},
|
||||
) {
|
||||
const store = loadSessionStore(storePath);
|
||||
const entry = store[MAIN_SESSION_KEY];
|
||||
expect(entry).toBeDefined();
|
||||
expect(entry?.modelOverride).toBe(selection.model);
|
||||
expect(entry?.providerOverride).toBe(selection.provider);
|
||||
}
|
||||
|
||||
describe("directive behavior", () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
vi.mocked(loadModelCatalog).mockResolvedValue([
|
||||
{ id: "claude-opus-4-5", name: "Opus 4.5", provider: "anthropic" },
|
||||
{ id: "claude-sonnet-4-1", name: "Sonnet 4.1", provider: "anthropic" },
|
||||
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", provider: "openai" },
|
||||
]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
installDirectiveBehaviorE2EHooks();
|
||||
|
||||
it("shows current elevated level as off after toggling it off", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
await getReplyFromConfig(
|
||||
@@ -128,7 +79,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("can toggle elevated off then back on (status reflects on)", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
const cfg = {
|
||||
@@ -198,8 +148,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("rejects per-agent elevated when disabled", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{
|
||||
Body: "/elevated on",
|
||||
|
||||
@@ -1,69 +1,19 @@
|
||||
import "./reply.directive.directive-behavior.e2e-mocks.js";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js";
|
||||
import { loadModelCatalog } from "../agents/model-catalog.js";
|
||||
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { loadSessionStore } from "../config/sessions.js";
|
||||
import {
|
||||
installDirectiveBehaviorE2EHooks,
|
||||
runEmbeddedPiAgent,
|
||||
withTempHome,
|
||||
} from "./reply.directive.directive-behavior.e2e-harness.js";
|
||||
import { getReplyFromConfig } from "./reply.js";
|
||||
|
||||
const MAIN_SESSION_KEY = "agent:main:main";
|
||||
|
||||
vi.mock("../agents/pi-embedded.js", () => ({
|
||||
abortEmbeddedPiRun: vi.fn().mockReturnValue(false),
|
||||
runEmbeddedPiAgent: vi.fn(),
|
||||
queueEmbeddedPiMessage: vi.fn().mockReturnValue(false),
|
||||
resolveEmbeddedSessionLane: (key: string) => `session:${key.trim() || "main"}`,
|
||||
isEmbeddedPiRunActive: vi.fn().mockReturnValue(false),
|
||||
isEmbeddedPiRunStreaming: vi.fn().mockReturnValue(false),
|
||||
}));
|
||||
vi.mock("../agents/model-catalog.js", () => ({
|
||||
loadModelCatalog: vi.fn(),
|
||||
}));
|
||||
|
||||
async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
|
||||
return withTempHomeBase(
|
||||
async (home) => {
|
||||
return await fn(home);
|
||||
},
|
||||
{
|
||||
env: {
|
||||
OPENCLAW_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
PI_CODING_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
},
|
||||
prefix: "openclaw-reply-",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function _assertModelSelection(
|
||||
storePath: string,
|
||||
selection: { model?: string; provider?: string } = {},
|
||||
) {
|
||||
const store = loadSessionStore(storePath);
|
||||
const entry = store[MAIN_SESSION_KEY];
|
||||
expect(entry).toBeDefined();
|
||||
expect(entry?.modelOverride).toBe(selection.model);
|
||||
expect(entry?.providerOverride).toBe(selection.provider);
|
||||
}
|
||||
|
||||
describe("directive behavior", () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
vi.mocked(loadModelCatalog).mockResolvedValue([
|
||||
{ id: "claude-opus-4-5", name: "Opus 4.5", provider: "anthropic" },
|
||||
{ id: "claude-sonnet-4-1", name: "Sonnet 4.1", provider: "anthropic" },
|
||||
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", provider: "openai" },
|
||||
]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
installDirectiveBehaviorE2EHooks();
|
||||
|
||||
it("shows current verbose level when /verbose has no argument", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{ Body: "/verbose", From: "+1222", To: "+1222", CommandAuthorized: true },
|
||||
{},
|
||||
@@ -87,8 +37,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("shows current reasoning level when /reasoning has no argument", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{ Body: "/reasoning", From: "+1222", To: "+1222", CommandAuthorized: true },
|
||||
{},
|
||||
@@ -111,8 +59,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("shows current elevated level when /elevated has no argument", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{
|
||||
Body: "/elevated",
|
||||
@@ -149,8 +95,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("shows current exec defaults when /exec has no argument", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{
|
||||
Body: "/exec",
|
||||
@@ -190,7 +134,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("persists elevated off and reflects it in /status (even when default is on)", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
|
||||
@@ -1,68 +1,19 @@
|
||||
import "./reply.directive.directive-behavior.e2e-mocks.js";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js";
|
||||
import { loadModelCatalog } from "../agents/model-catalog.js";
|
||||
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
|
||||
import { loadSessionStore } from "../config/sessions.js";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
assertModelSelection,
|
||||
installDirectiveBehaviorE2EHooks,
|
||||
runEmbeddedPiAgent,
|
||||
withTempHome,
|
||||
} from "./reply.directive.directive-behavior.e2e-harness.js";
|
||||
import { getReplyFromConfig } from "./reply.js";
|
||||
|
||||
const MAIN_SESSION_KEY = "agent:main:main";
|
||||
|
||||
vi.mock("../agents/pi-embedded.js", () => ({
|
||||
abortEmbeddedPiRun: vi.fn().mockReturnValue(false),
|
||||
runEmbeddedPiAgent: vi.fn(),
|
||||
queueEmbeddedPiMessage: vi.fn().mockReturnValue(false),
|
||||
resolveEmbeddedSessionLane: (key: string) => `session:${key.trim() || "main"}`,
|
||||
isEmbeddedPiRunActive: vi.fn().mockReturnValue(false),
|
||||
isEmbeddedPiRunStreaming: vi.fn().mockReturnValue(false),
|
||||
}));
|
||||
vi.mock("../agents/model-catalog.js", () => ({
|
||||
loadModelCatalog: vi.fn(),
|
||||
}));
|
||||
|
||||
async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
|
||||
return withTempHomeBase(
|
||||
async (home) => {
|
||||
return await fn(home);
|
||||
},
|
||||
{
|
||||
env: {
|
||||
OPENCLAW_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
PI_CODING_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
},
|
||||
prefix: "openclaw-reply-",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function assertModelSelection(
|
||||
storePath: string,
|
||||
selection: { model?: string; provider?: string } = {},
|
||||
) {
|
||||
const store = loadSessionStore(storePath);
|
||||
const entry = store[MAIN_SESSION_KEY];
|
||||
expect(entry).toBeDefined();
|
||||
expect(entry?.modelOverride).toBe(selection.model);
|
||||
expect(entry?.providerOverride).toBe(selection.provider);
|
||||
}
|
||||
|
||||
describe("directive behavior", () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
vi.mocked(loadModelCatalog).mockResolvedValue([
|
||||
{ id: "claude-opus-4-5", name: "Opus 4.5", provider: "anthropic" },
|
||||
{ id: "claude-sonnet-4-1", name: "Sonnet 4.1", provider: "anthropic" },
|
||||
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", provider: "openai" },
|
||||
]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
installDirectiveBehaviorE2EHooks();
|
||||
|
||||
it("supports fuzzy model matches on /model directive", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
@@ -105,7 +56,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("resolves provider-less exact model ids via fuzzy matching when unambiguous", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
@@ -153,7 +103,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("supports fuzzy matches within a provider on /model provider/model", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
@@ -196,7 +145,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("picks the best fuzzy match when multiple models match", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
await getReplyFromConfig(
|
||||
@@ -241,7 +189,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("picks the best fuzzy match within a provider", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
await getReplyFromConfig(
|
||||
|
||||
@@ -1,64 +1,16 @@
|
||||
import "./reply.directive.directive-behavior.e2e-mocks.js";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js";
|
||||
import { loadModelCatalog } from "../agents/model-catalog.js";
|
||||
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { loadSessionStore, resolveSessionKey, saveSessionStore } from "../config/sessions.js";
|
||||
import {
|
||||
installDirectiveBehaviorE2EHooks,
|
||||
runEmbeddedPiAgent,
|
||||
withTempHome,
|
||||
} from "./reply.directive.directive-behavior.e2e-harness.js";
|
||||
import { getReplyFromConfig } from "./reply.js";
|
||||
|
||||
const MAIN_SESSION_KEY = "agent:main:main";
|
||||
|
||||
vi.mock("../agents/pi-embedded.js", () => ({
|
||||
abortEmbeddedPiRun: vi.fn().mockReturnValue(false),
|
||||
runEmbeddedPiAgent: vi.fn(),
|
||||
queueEmbeddedPiMessage: vi.fn().mockReturnValue(false),
|
||||
resolveEmbeddedSessionLane: (key: string) => `session:${key.trim() || "main"}`,
|
||||
isEmbeddedPiRunActive: vi.fn().mockReturnValue(false),
|
||||
isEmbeddedPiRunStreaming: vi.fn().mockReturnValue(false),
|
||||
}));
|
||||
vi.mock("../agents/model-catalog.js", () => ({
|
||||
loadModelCatalog: vi.fn(),
|
||||
}));
|
||||
|
||||
async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
|
||||
return withTempHomeBase(
|
||||
async (home) => {
|
||||
return await fn(home);
|
||||
},
|
||||
{
|
||||
env: {
|
||||
OPENCLAW_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
PI_CODING_AGENT_DIR: (home) => path.join(home, ".openclaw", "agent"),
|
||||
},
|
||||
prefix: "openclaw-reply-",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function _assertModelSelection(
|
||||
storePath: string,
|
||||
selection: { model?: string; provider?: string } = {},
|
||||
) {
|
||||
const store = loadSessionStore(storePath);
|
||||
const entry = store[MAIN_SESSION_KEY];
|
||||
expect(entry).toBeDefined();
|
||||
expect(entry?.modelOverride).toBe(selection.model);
|
||||
expect(entry?.providerOverride).toBe(selection.provider);
|
||||
}
|
||||
|
||||
describe("directive behavior", () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
vi.mocked(loadModelCatalog).mockResolvedValue([
|
||||
{ id: "claude-opus-4-5", name: "Opus 4.5", provider: "anthropic" },
|
||||
{ id: "claude-sonnet-4-1", name: "Sonnet 4.1", provider: "anthropic" },
|
||||
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", provider: "openai" },
|
||||
]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
installDirectiveBehaviorE2EHooks();
|
||||
|
||||
it("updates tool verbose during an in-flight run (toggle on)", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
@@ -189,7 +141,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("shows summary on /model", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
@@ -221,7 +172,6 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("lists allowlisted models on /model status", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
const storePath = path.join(home, "sessions.json");
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
|
||||
Reference in New Issue
Block a user