diff --git a/src/auto-reply/reply.directive.directive-behavior.defaults-think-low-reasoning-capable-models-no.e2e.test.ts b/src/auto-reply/reply.directive.directive-behavior.defaults-think-low-reasoning-capable-models-no.e2e.test.ts index 9d0321bfbe..ab86435c79 100644 --- a/src/auto-reply/reply.directive.directive-behavior.defaults-think-low-reasoning-capable-models-no.e2e.test.ts +++ b/src/auto-reply/reply.directive.directive-behavior.defaults-think-low-reasoning-capable-models-no.e2e.test.ts @@ -1,48 +1,20 @@ import "./reply.directive.directive-behavior.e2e-mocks.js"; -import path from "node:path"; import { describe, expect, it, vi } from "vitest"; -import type { OpenClawConfig } from "../config/config.js"; import { installDirectiveBehaviorE2EHooks, loadModelCatalog, + makeEmbeddedTextResult, + makeWhatsAppDirectiveConfig, + mockEmbeddedTextResult, + replyText, + replyTexts, runEmbeddedPiAgent, withTempHome, } from "./reply.directive.directive-behavior.e2e-harness.js"; import { getReplyFromConfig } from "./reply.js"; -function makeThinkConfig(home: string) { - return { - agents: { - defaults: { - model: "anthropic/claude-opus-4-5", - workspace: path.join(home, "openclaw"), - }, - }, - session: { store: path.join(home, "sessions.json") }, - } as unknown as OpenClawConfig; -} - -function makeWhatsAppConfig(home: string) { - return { - agents: { - defaults: { - model: "anthropic/claude-opus-4-5", - workspace: path.join(home, "openclaw"), - }, - }, - channels: { whatsapp: { allowFrom: ["*"] } }, - session: { store: path.join(home, "sessions.json") }, - } as unknown as OpenClawConfig; -} - async function runReplyToCurrentCase(home: string, text: string) { - vi.mocked(runEmbeddedPiAgent).mockResolvedValue({ - payloads: [{ text }], - meta: { - durationMs: 5, - agentMeta: { sessionId: "s", provider: "p", model: "m" }, - }, - }); + vi.mocked(runEmbeddedPiAgent).mockResolvedValue(makeEmbeddedTextResult(text)); const res = await getReplyFromConfig( { @@ -52,7 +24,7 @@ async function runReplyToCurrentCase(home: string, text: string) { MessageSid: "msg-123", }, {}, - makeWhatsAppConfig(home), + makeWhatsAppDirectiveConfig(home, { model: "anthropic/claude-opus-4-5" }), ); return Array.isArray(res) ? res[0] : res; @@ -75,10 +47,10 @@ describe("directive behavior", () => { const res = await getReplyFromConfig( { Body: "/think", From: "+1222", To: "+1222", CommandAuthorized: true }, {}, - makeThinkConfig(home), + makeWhatsAppDirectiveConfig(home, { model: "anthropic/claude-opus-4-5" }), ); - const text = Array.isArray(res) ? res[0]?.text : res?.text; + const text = replyText(res); expect(text).toContain("Current thinking level: low"); expect(text).toContain("Options: off, minimal, low, medium, high."); expect(runEmbeddedPiAgent).not.toHaveBeenCalled(); @@ -98,42 +70,29 @@ describe("directive behavior", () => { const res = await getReplyFromConfig( { Body: "/think", From: "+1222", To: "+1222", CommandAuthorized: true }, {}, - makeThinkConfig(home), + makeWhatsAppDirectiveConfig(home, { model: "anthropic/claude-opus-4-5" }), ); - const text = Array.isArray(res) ? res[0]?.text : res?.text; + const text = replyText(res); expect(text).toContain("Current thinking level: off"); expect(text).toContain("Options: off, minimal, low, medium, high."); expect(runEmbeddedPiAgent).not.toHaveBeenCalled(); }); }); - it("strips reply tags and maps reply_to_current to MessageSid", async () => { - await withTempHome(async (home) => { - const payload = await runReplyToCurrentCase(home, "hello [[reply_to_current]]"); - expect(payload?.text).toBe("hello"); - expect(payload?.replyToId).toBe("msg-123"); + for (const replyTag of ["[[reply_to_current]]", "[[ reply_to_current ]]"]) { + it(`strips ${replyTag} and maps reply_to_current to MessageSid`, async () => { + await withTempHome(async (home) => { + const payload = await runReplyToCurrentCase(home, `hello ${replyTag}`); + expect(payload?.text).toBe("hello"); + expect(payload?.replyToId).toBe("msg-123"); + }); }); - }); - it("strips reply tags with whitespace and maps reply_to_current to MessageSid", async () => { - await withTempHome(async (home) => { - const payload = await runReplyToCurrentCase(home, "hello [[ reply_to_current ]]"); - expect(payload?.text).toBe("hello"); - expect(payload?.replyToId).toBe("msg-123"); - }); - }); + } it("prefers explicit reply_to id over reply_to_current", async () => { await withTempHome(async (home) => { - vi.mocked(runEmbeddedPiAgent).mockResolvedValue({ - payloads: [ - { - text: "hi [[reply_to_current]] [[reply_to:abc-456]]", - }, - ], - meta: { - durationMs: 5, - agentMeta: { sessionId: "s", provider: "p", model: "m" }, - }, - }); + vi.mocked(runEmbeddedPiAgent).mockResolvedValue( + makeEmbeddedTextResult("hi [[reply_to_current]] [[reply_to:abc-456]]"), + ); const res = await getReplyFromConfig( { @@ -143,16 +102,7 @@ describe("directive behavior", () => { MessageSid: "msg-123", }, {}, - { - agents: { - defaults: { - model: { primary: "anthropic/claude-opus-4-5" }, - workspace: path.join(home, "openclaw"), - }, - }, - channels: { whatsapp: { allowFrom: ["*"] } }, - session: { store: path.join(home, "sessions.json") }, - }, + makeWhatsAppDirectiveConfig(home, { model: { primary: "anthropic/claude-opus-4-5" } }), ); const payload = Array.isArray(res) ? res[0] : res; @@ -162,13 +112,7 @@ describe("directive behavior", () => { }); it("applies inline think and still runs agent content", async () => { await withTempHome(async (home) => { - vi.mocked(runEmbeddedPiAgent).mockResolvedValue({ - payloads: [{ text: "done" }], - meta: { - durationMs: 5, - agentMeta: { sessionId: "s", provider: "p", model: "m" }, - }, - }); + mockEmbeddedTextResult("done"); const res = await getReplyFromConfig( { @@ -177,19 +121,10 @@ describe("directive behavior", () => { To: "+2000", }, {}, - { - agents: { - defaults: { - model: { primary: "anthropic/claude-opus-4-5" }, - workspace: path.join(home, "openclaw"), - }, - }, - channels: { whatsapp: { allowFrom: ["*"] } }, - session: { store: path.join(home, "sessions.json") }, - }, + makeWhatsAppDirectiveConfig(home, { model: { primary: "anthropic/claude-opus-4-5" } }), ); - const texts = (Array.isArray(res) ? res : [res]).map((entry) => entry?.text).filter(Boolean); + const texts = replyTexts(res); expect(texts).toContain("done"); expect(runEmbeddedPiAgent).toHaveBeenCalledOnce(); }); diff --git a/src/auto-reply/reply.directive.directive-behavior.e2e-harness.ts b/src/auto-reply/reply.directive.directive-behavior.e2e-harness.ts index 98c20e0de7..03f2466108 100644 --- a/src/auto-reply/reply.directive.directive-behavior.e2e-harness.ts +++ b/src/auto-reply/reply.directive.directive-behavior.e2e-harness.ts @@ -36,6 +36,20 @@ export function replyTexts(res: ReplyPayloadText | ReplyPayloadText[]): string[] .filter((value): value is string => Boolean(value)); } +export function makeEmbeddedTextResult(text = "done") { + return { + payloads: [{ text }], + meta: { + durationMs: 5, + agentMeta: { sessionId: "s", provider: "p", model: "m" }, + }, + }; +} + +export function mockEmbeddedTextResult(text = "done") { + vi.mocked(runEmbeddedPiAgent).mockResolvedValue(makeEmbeddedTextResult(text)); +} + export async function withTempHome(fn: (home: string) => Promise): Promise { return withTempHomeBase( async (home) => { diff --git a/src/auto-reply/reply.directive.directive-behavior.ignores-inline-model-uses-default-model.e2e.test.ts b/src/auto-reply/reply.directive.directive-behavior.ignores-inline-model-uses-default-model.e2e.test.ts index 276dc239ca..410a5b62fd 100644 --- a/src/auto-reply/reply.directive.directive-behavior.ignores-inline-model-uses-default-model.e2e.test.ts +++ b/src/auto-reply/reply.directive.directive-behavior.ignores-inline-model-uses-default-model.e2e.test.ts @@ -1,27 +1,32 @@ import "./reply.directive.directive-behavior.e2e-mocks.js"; -import path from "node:path"; import { describe, expect, it, vi } from "vitest"; import { installDirectiveBehaviorE2EHooks, loadModelCatalog, + makeWhatsAppDirectiveConfig, + mockEmbeddedTextResult, + replyTexts, runEmbeddedPiAgent, withTempHome, } from "./reply.directive.directive-behavior.e2e-harness.js"; import { getReplyFromConfig } from "./reply.js"; +function makeDefaultModelConfig(home: string) { + return makeWhatsAppDirectiveConfig(home, { + model: { primary: "anthropic/claude-opus-4-5" }, + models: { + "anthropic/claude-opus-4-5": {}, + "openai/gpt-4.1-mini": {}, + }, + }); +} + describe("directive behavior", () => { installDirectiveBehaviorE2EHooks(); it("ignores inline /model and uses the default model", async () => { await withTempHome(async (home) => { - const storePath = path.join(home, "sessions.json"); - vi.mocked(runEmbeddedPiAgent).mockResolvedValue({ - payloads: [{ text: "done" }], - meta: { - durationMs: 5, - agentMeta: { sessionId: "s", provider: "p", model: "m" }, - }, - }); + mockEmbeddedTextResult("done"); const res = await getReplyFromConfig( { @@ -30,23 +35,10 @@ describe("directive behavior", () => { To: "+2000", }, {}, - { - agents: { - defaults: { - model: { primary: "anthropic/claude-opus-4-5" }, - workspace: path.join(home, "openclaw"), - models: { - "anthropic/claude-opus-4-5": {}, - "openai/gpt-4.1-mini": {}, - }, - }, - }, - channels: { whatsapp: { allowFrom: ["*"] } }, - session: { store: storePath }, - }, + makeDefaultModelConfig(home), ); - const texts = (Array.isArray(res) ? res : [res]).map((entry) => entry?.text).filter(Boolean); + const texts = replyTexts(res); expect(texts).toContain("done"); expect(runEmbeddedPiAgent).toHaveBeenCalledOnce(); const call = vi.mocked(runEmbeddedPiAgent).mock.calls[0]?.[0]; @@ -56,14 +48,7 @@ describe("directive behavior", () => { }); it("defaults thinking to low for reasoning-capable models", async () => { await withTempHome(async (home) => { - const storePath = path.join(home, "sessions.json"); - vi.mocked(runEmbeddedPiAgent).mockResolvedValue({ - payloads: [{ text: "done" }], - meta: { - durationMs: 5, - agentMeta: { sessionId: "s", provider: "p", model: "m" }, - }, - }); + mockEmbeddedTextResult("done"); vi.mocked(loadModelCatalog).mockResolvedValueOnce([ { id: "claude-opus-4-5", @@ -80,16 +65,7 @@ describe("directive behavior", () => { To: "+2000", }, {}, - { - agents: { - defaults: { - model: { primary: "anthropic/claude-opus-4-5" }, - workspace: path.join(home, "openclaw"), - }, - }, - channels: { whatsapp: { allowFrom: ["*"] } }, - session: { store: storePath }, - }, + makeWhatsAppDirectiveConfig(home, { model: { primary: "anthropic/claude-opus-4-5" } }), ); expect(runEmbeddedPiAgent).toHaveBeenCalledOnce(); @@ -99,14 +75,7 @@ describe("directive behavior", () => { }); it("passes elevated defaults when sender is approved", async () => { await withTempHome(async (home) => { - const storePath = path.join(home, "sessions.json"); - vi.mocked(runEmbeddedPiAgent).mockResolvedValue({ - payloads: [{ text: "done" }], - meta: { - durationMs: 5, - agentMeta: { sessionId: "s", provider: "p", model: "m" }, - }, - }); + mockEmbeddedTextResult("done"); await getReplyFromConfig( { @@ -117,21 +86,17 @@ describe("directive behavior", () => { SenderE164: "+1004", }, {}, - { - agents: { - defaults: { - model: { primary: "anthropic/claude-opus-4-5" }, - workspace: path.join(home, "openclaw"), + makeWhatsAppDirectiveConfig( + home, + { model: { primary: "anthropic/claude-opus-4-5" } }, + { + tools: { + elevated: { + allowFrom: { whatsapp: ["+1004"] }, + }, }, }, - tools: { - elevated: { - allowFrom: { whatsapp: ["+1004"] }, - }, - }, - channels: { whatsapp: { allowFrom: ["*"] } }, - session: { store: storePath }, - }, + ), ); expect(runEmbeddedPiAgent).toHaveBeenCalledOnce(); diff --git a/src/auto-reply/reply.directive.directive-behavior.prefers-alias-matches-fuzzy-selection-is-ambiguous.e2e.test.ts b/src/auto-reply/reply.directive.directive-behavior.prefers-alias-matches-fuzzy-selection-is-ambiguous.e2e.test.ts index 1658c4a8f6..098728deb4 100644 --- a/src/auto-reply/reply.directive.directive-behavior.prefers-alias-matches-fuzzy-selection-is-ambiguous.e2e.test.ts +++ b/src/auto-reply/reply.directive.directive-behavior.prefers-alias-matches-fuzzy-selection-is-ambiguous.e2e.test.ts @@ -9,7 +9,10 @@ import { assertModelSelection, installDirectiveBehaviorE2EHooks, MAIN_SESSION_KEY, + makeWhatsAppDirectiveConfig, + replyText, runEmbeddedPiAgent, + sessionStorePath, withTempHome, } from "./reply.directive.directive-behavior.e2e-harness.js"; import { getReplyFromConfig } from "./reply.js"; @@ -26,12 +29,22 @@ function makeModelDefinition(id: string, name: string): ModelDefinitionConfig { }; } +function makeModelSwitchConfig(home: string) { + return makeWhatsAppDirectiveConfig(home, { + model: { primary: "openai/gpt-4.1-mini" }, + models: { + "openai/gpt-4.1-mini": {}, + "anthropic/claude-opus-4-5": { alias: "Opus" }, + }, + }); +} + describe("directive behavior", () => { installDirectiveBehaviorE2EHooks(); it("prefers alias matches when fuzzy selection is ambiguous", async () => { await withTempHome(async (home) => { - const storePath = path.join(home, "sessions.json"); + const storePath = sessionStorePath(home); const res = await getReplyFromConfig( { Body: "/model ki", From: "+1222", To: "+1222", CommandAuthorized: true }, @@ -69,7 +82,7 @@ describe("directive behavior", () => { }, ); - const text = Array.isArray(res) ? res[0]?.text : res?.text; + const text = replyText(res); expect(text).toContain("Model set to Kimi (moonshot/kimi-k2-0905-preview)."); assertModelSelection(storePath, { provider: "moonshot", @@ -80,7 +93,7 @@ describe("directive behavior", () => { }); it("stores auth profile overrides on /model directive", async () => { await withTempHome(async (home) => { - const storePath = path.join(home, "sessions.json"); + const storePath = sessionStorePath(home); const authDir = path.join(home, ".openclaw", "agents", "main", "agent"); await fs.mkdir(authDir, { recursive: true, mode: 0o700 }); await fs.writeFile( @@ -104,22 +117,10 @@ describe("directive behavior", () => { const res = await getReplyFromConfig( { Body: "/model Opus@anthropic:work", From: "+1222", To: "+1222", CommandAuthorized: true }, {}, - { - agents: { - defaults: { - model: { primary: "openai/gpt-4.1-mini" }, - workspace: path.join(home, "openclaw"), - models: { - "openai/gpt-4.1-mini": {}, - "anthropic/claude-opus-4-5": { alias: "Opus" }, - }, - }, - }, - session: { store: storePath }, - }, + makeModelSwitchConfig(home), ); - const text = Array.isArray(res) ? res[0]?.text : res?.text; + const text = replyText(res); expect(text).toContain("Auth profile set to anthropic:work"); const store = loadSessionStore(storePath); const entry = store["agent:main:main"]; @@ -130,24 +131,10 @@ describe("directive behavior", () => { it("queues a system event when switching models", async () => { await withTempHome(async (home) => { drainSystemEvents(MAIN_SESSION_KEY); - const storePath = path.join(home, "sessions.json"); - await getReplyFromConfig( { Body: "/model Opus", From: "+1222", To: "+1222", CommandAuthorized: true }, {}, - { - agents: { - defaults: { - model: { primary: "openai/gpt-4.1-mini" }, - workspace: path.join(home, "openclaw"), - models: { - "openai/gpt-4.1-mini": {}, - "anthropic/claude-opus-4-5": { alias: "Opus" }, - }, - }, - }, - session: { store: storePath }, - }, + makeModelSwitchConfig(home), ); const events = drainSystemEvents(MAIN_SESSION_KEY); @@ -158,7 +145,6 @@ describe("directive behavior", () => { it("queues a system event when toggling elevated", async () => { await withTempHome(async (home) => { drainSystemEvents(MAIN_SESSION_KEY); - const storePath = path.join(home, "sessions.json"); await getReplyFromConfig( { @@ -169,17 +155,11 @@ describe("directive behavior", () => { CommandAuthorized: true, }, {}, - { - agents: { - defaults: { - model: { primary: "openai/gpt-4.1-mini" }, - workspace: path.join(home, "openclaw"), - }, - }, - tools: { elevated: { allowFrom: { whatsapp: ["*"] } } }, - channels: { whatsapp: { allowFrom: ["*"] } }, - session: { store: storePath }, - }, + makeWhatsAppDirectiveConfig( + home, + { model: { primary: "openai/gpt-4.1-mini" } }, + { tools: { elevated: { allowFrom: { whatsapp: ["*"] } } } }, + ), ); const events = drainSystemEvents(MAIN_SESSION_KEY); @@ -189,7 +169,6 @@ describe("directive behavior", () => { it("queues a system event when toggling reasoning", async () => { await withTempHome(async (home) => { drainSystemEvents(MAIN_SESSION_KEY); - const storePath = path.join(home, "sessions.json"); await getReplyFromConfig( { @@ -200,16 +179,7 @@ describe("directive behavior", () => { CommandAuthorized: true, }, {}, - { - agents: { - defaults: { - model: { primary: "openai/gpt-4.1-mini" }, - workspace: path.join(home, "openclaw"), - }, - }, - channels: { whatsapp: { allowFrom: ["*"] } }, - session: { store: storePath }, - }, + makeWhatsAppDirectiveConfig(home, { model: { primary: "openai/gpt-4.1-mini" } }), ); const events = drainSystemEvents(MAIN_SESSION_KEY); diff --git a/src/auto-reply/reply.directive.directive-behavior.requires-per-agent-allowlist-addition-global.e2e.test.ts b/src/auto-reply/reply.directive.directive-behavior.requires-per-agent-allowlist-addition-global.e2e.test.ts index 2f6117829c..767cbf476a 100644 --- a/src/auto-reply/reply.directive.directive-behavior.requires-per-agent-allowlist-addition-global.e2e.test.ts +++ b/src/auto-reply/reply.directive.directive-behavior.requires-per-agent-allowlist-addition-global.e2e.test.ts @@ -42,6 +42,29 @@ function makeWorkElevatedAllowlistConfig(home: string) { }; } +function makeElevatedDirectiveConfig( + home: string, + defaults: Record = {}, + extra: Record = {}, +) { + return makeWhatsAppDirectiveConfig( + home, + { + model: "anthropic/claude-opus-4-5", + ...defaults, + }, + { + tools: { + elevated: { + allowFrom: { whatsapp: ["+1222"] }, + }, + }, + channels: { whatsapp: { allowFrom: ["+1222"] } }, + ...extra, + }, + ); +} + function makeCommandMessage(body: string, from = "+1222") { return { Body: body, @@ -98,21 +121,7 @@ describe("directive behavior", () => { const res = await getReplyFromConfig( makeCommandMessage("/elevated off"), {}, - makeWhatsAppDirectiveConfig( - home, - { - model: "anthropic/claude-opus-4-5", - sandbox: { mode: "off" }, - }, - { - tools: { - elevated: { - allowFrom: { whatsapp: ["+1222"] }, - }, - }, - channels: { whatsapp: { allowFrom: ["+1222"] } }, - }, - ), + makeElevatedDirectiveConfig(home, { sandbox: { mode: "off" } }), ); const text = replyText(res); @@ -126,18 +135,7 @@ describe("directive behavior", () => { const res = await getReplyFromConfig( makeCommandMessage("/elevated maybe"), {}, - makeWhatsAppDirectiveConfig( - home, - { model: "anthropic/claude-opus-4-5" }, - { - tools: { - elevated: { - allowFrom: { whatsapp: ["+1222"] }, - }, - }, - channels: { whatsapp: { allowFrom: ["+1222"] } }, - }, - ), + makeElevatedDirectiveConfig(home), ); const text = replyText(res); @@ -150,18 +148,7 @@ describe("directive behavior", () => { const res = await getReplyFromConfig( makeCommandMessage("/elevated off\n/verbose on"), {}, - makeWhatsAppDirectiveConfig( - home, - { model: "anthropic/claude-opus-4-5" }, - { - tools: { - elevated: { - allowFrom: { whatsapp: ["+1222"] }, - }, - }, - channels: { whatsapp: { allowFrom: ["+1222"] } }, - }, - ), + makeElevatedDirectiveConfig(home), ); const text = replyText(res); diff --git a/src/auto-reply/reply.directive.directive-behavior.updates-tool-verbose-during-flight-run-toggle.e2e.test.ts b/src/auto-reply/reply.directive.directive-behavior.updates-tool-verbose-during-flight-run-toggle.e2e.test.ts index 0e1c34e6ed..b150ff8b8f 100644 --- a/src/auto-reply/reply.directive.directive-behavior.updates-tool-verbose-during-flight-run-toggle.e2e.test.ts +++ b/src/auto-reply/reply.directive.directive-behavior.updates-tool-verbose-during-flight-run-toggle.e2e.test.ts @@ -3,6 +3,7 @@ import { describe, expect, it, vi } from "vitest"; import { loadSessionStore, resolveSessionKey, saveSessionStore } from "../config/sessions.js"; import { installDirectiveBehaviorE2EHooks, + makeEmbeddedTextResult, makeWhatsAppDirectiveConfig, replyText, replyTexts, @@ -12,6 +13,62 @@ import { } from "./reply.directive.directive-behavior.e2e-harness.js"; import { getReplyFromConfig } from "./reply.js"; +function makeRunConfig(home: string, storePath: string) { + return makeWhatsAppDirectiveConfig( + home, + { model: "anthropic/claude-opus-4-5" }, + { session: { store: storePath } }, + ); +} + +async function runInFlightVerboseToggleCase(params: { + home: string; + shouldEmitBefore: boolean; + toggledVerboseLevel: "on" | "off"; + seedVerboseOn?: boolean; +}) { + const storePath = sessionStorePath(params.home); + const ctx = { + Body: "please do the thing", + From: "+1004", + To: "+2000", + }; + const sessionKey = resolveSessionKey( + "per-sender", + { From: ctx.From, To: ctx.To, Body: ctx.Body }, + "main", + ); + + vi.mocked(runEmbeddedPiAgent).mockImplementation(async (agentParams) => { + const shouldEmit = agentParams.shouldEmitToolResult; + expect(shouldEmit?.()).toBe(params.shouldEmitBefore); + const store = loadSessionStore(storePath); + const entry = store[sessionKey] ?? { + sessionId: "s", + updatedAt: Date.now(), + }; + store[sessionKey] = { + ...entry, + verboseLevel: params.toggledVerboseLevel, + updatedAt: Date.now(), + }; + await saveSessionStore(storePath, store); + expect(shouldEmit?.()).toBe(!params.shouldEmitBefore); + return makeEmbeddedTextResult("done"); + }); + + if (params.seedVerboseOn) { + await getReplyFromConfig( + { Body: "/verbose on", From: ctx.From, To: ctx.To, CommandAuthorized: true }, + {}, + makeRunConfig(params.home, storePath), + ); + } + + const res = await getReplyFromConfig(ctx, {}, makeRunConfig(params.home, storePath)); + return { res }; +} + async function runModelDirectiveAndGetText( home: string, body: string, @@ -35,50 +92,12 @@ describe("directive behavior", () => { it("updates tool verbose during an in-flight run (toggle on)", async () => { await withTempHome(async (home) => { - const storePath = sessionStorePath(home); - const ctx = { Body: "please do the thing", From: "+1004", To: "+2000" }; - const sessionKey = resolveSessionKey( - "per-sender", - { From: ctx.From, To: ctx.To, Body: ctx.Body }, - "main", - ); - - vi.mocked(runEmbeddedPiAgent).mockImplementation(async (params) => { - const shouldEmit = params.shouldEmitToolResult; - expect(shouldEmit?.()).toBe(false); - const store = loadSessionStore(storePath); - const entry = store[sessionKey] ?? { - sessionId: "s", - updatedAt: Date.now(), - }; - store[sessionKey] = { - ...entry, - verboseLevel: "on", - updatedAt: Date.now(), - }; - await saveSessionStore(storePath, store); - expect(shouldEmit?.()).toBe(true); - return { - payloads: [{ text: "done" }], - meta: { - durationMs: 5, - agentMeta: { sessionId: "s", provider: "p", model: "m" }, - }, - }; + const { res } = await runInFlightVerboseToggleCase({ + home, + shouldEmitBefore: false, + toggledVerboseLevel: "on", }); - const res = await getReplyFromConfig( - ctx, - {}, - makeWhatsAppDirectiveConfig( - home, - { model: "anthropic/claude-opus-4-5" }, - { - session: { store: storePath }, - }, - ), - ); - const texts = replyTexts(res); expect(texts).toContain("done"); expect(runEmbeddedPiAgent).toHaveBeenCalledOnce(); @@ -86,66 +105,13 @@ describe("directive behavior", () => { }); it("updates tool verbose during an in-flight run (toggle off)", async () => { await withTempHome(async (home) => { - const storePath = sessionStorePath(home); - const ctx = { - Body: "please do the thing", - From: "+1004", - To: "+2000", - }; - const sessionKey = resolveSessionKey( - "per-sender", - { From: ctx.From, To: ctx.To, Body: ctx.Body }, - "main", - ); - - vi.mocked(runEmbeddedPiAgent).mockImplementation(async (params) => { - const shouldEmit = params.shouldEmitToolResult; - expect(shouldEmit?.()).toBe(true); - const store = loadSessionStore(storePath); - const entry = store[sessionKey] ?? { - sessionId: "s", - updatedAt: Date.now(), - }; - store[sessionKey] = { - ...entry, - verboseLevel: "off", - updatedAt: Date.now(), - }; - await saveSessionStore(storePath, store); - expect(shouldEmit?.()).toBe(false); - return { - payloads: [{ text: "done" }], - meta: { - durationMs: 5, - agentMeta: { sessionId: "s", provider: "p", model: "m" }, - }, - }; + const { res } = await runInFlightVerboseToggleCase({ + home, + shouldEmitBefore: true, + toggledVerboseLevel: "off", + seedVerboseOn: true, }); - await getReplyFromConfig( - { Body: "/verbose on", From: ctx.From, To: ctx.To, CommandAuthorized: true }, - {}, - makeWhatsAppDirectiveConfig( - home, - { model: "anthropic/claude-opus-4-5" }, - { - session: { store: storePath }, - }, - ), - ); - - const res = await getReplyFromConfig( - ctx, - {}, - makeWhatsAppDirectiveConfig( - home, - { model: "anthropic/claude-opus-4-5" }, - { - session: { store: storePath }, - }, - ), - ); - const texts = replyTexts(res); expect(texts).toContain("done"); expect(runEmbeddedPiAgent).toHaveBeenCalledOnce();