2026-01-10 17:32:19 +01:00
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 { getReplyFromConfig } from "./reply.js" ;
vi . mock ( "../agents/pi-embedded.js" , ( ) = > ( {
abortEmbeddedPiRun : vi.fn ( ) . mockReturnValue ( false ) ,
runEmbeddedPiAgent : vi.fn ( ) ,
queueEmbeddedPiMessage : vi.fn ( ) . mockReturnValue ( false ) ,
2026-01-14 14:31:43 +00:00
resolveEmbeddedSessionLane : ( key : string ) = > ` session: ${ key . trim ( ) || "main" } ` ,
2026-01-10 17:32:19 +01:00
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 : {
CLAWDBOT_AGENT_DIR : ( home ) = > path . join ( home , ".clawdbot" , "agent" ) ,
PI_CODING_AGENT_DIR : ( home ) = > path . join ( home , ".clawdbot" , "agent" ) ,
} ,
prefix : "clawdbot-rawbody-" ,
} ,
) ;
}
describe ( "RawBody directive parsing" , ( ) = > {
beforeEach ( ( ) = > {
vi . mocked ( runEmbeddedPiAgent ) . mockReset ( ) ;
vi . mocked ( loadModelCatalog ) . mockResolvedValue ( [
{ id : "claude-opus-4-5" , name : "Opus 4.5" , provider : "anthropic" } ,
] ) ;
} ) ;
afterEach ( ( ) = > {
vi . restoreAllMocks ( ) ;
} ) ;
it ( "/model, /think, /verbose directives detected from RawBody even when Body has structural wrapper" , async ( ) = > {
await withTempHome ( async ( home ) = > {
vi . mocked ( runEmbeddedPiAgent ) . mockReset ( ) ;
const groupMessageCtx = {
Body : ` [Chat messages since your last reply - for context] \\ n[WhatsApp ...] Someone: hello \\ n \\ n[Current message - respond to this] \\ n[WhatsApp ...] Jake: /think:high \\ n[from: Jake McInteer (+6421807830)] ` ,
RawBody : "/think:high" ,
From : "+1222" ,
To : "+1222" ,
ChatType : "group" ,
} ;
const res = await getReplyFromConfig (
groupMessageCtx ,
{ } ,
{
agents : {
defaults : {
model : "anthropic/claude-opus-4-5" ,
workspace : path.join ( home , "clawd" ) ,
} ,
} ,
2026-01-13 06:16:43 +00:00
channels : { whatsapp : { allowFrom : [ "*" ] } } ,
2026-01-10 17:32:19 +01:00
session : { store : path.join ( home , "sessions.json" ) } ,
} ,
) ;
const text = Array . isArray ( res ) ? res [ 0 ] ? . text : res?.text ;
expect ( text ) . toContain ( "Thinking level set to high." ) ;
expect ( runEmbeddedPiAgent ) . not . toHaveBeenCalled ( ) ;
} ) ;
} ) ;
it ( "/model status detected from RawBody" , async ( ) = > {
await withTempHome ( async ( home ) = > {
vi . mocked ( runEmbeddedPiAgent ) . mockReset ( ) ;
const groupMessageCtx = {
Body : ` [Context] \ nJake: /model status \ n[from: Jake] ` ,
RawBody : "/model status" ,
From : "+1222" ,
To : "+1222" ,
ChatType : "group" ,
} ;
const res = await getReplyFromConfig (
groupMessageCtx ,
{ } ,
{
agents : {
defaults : {
model : "anthropic/claude-opus-4-5" ,
workspace : path.join ( home , "clawd" ) ,
models : {
"anthropic/claude-opus-4-5" : { } ,
} ,
} ,
} ,
2026-01-13 06:16:43 +00:00
channels : { whatsapp : { allowFrom : [ "*" ] } } ,
2026-01-10 17:32:19 +01:00
session : { store : path.join ( home , "sessions.json" ) } ,
} ,
) ;
const text = Array . isArray ( res ) ? res [ 0 ] ? . text : res?.text ;
expect ( text ) . toContain ( "anthropic/claude-opus-4-5" ) ;
expect ( runEmbeddedPiAgent ) . not . toHaveBeenCalled ( ) ;
} ) ;
} ) ;
2026-01-10 18:53:33 +01:00
it ( "CommandBody is honored when RawBody is missing" , async ( ) = > {
await withTempHome ( async ( home ) = > {
vi . mocked ( runEmbeddedPiAgent ) . mockReset ( ) ;
const groupMessageCtx = {
Body : ` [Context] \ nJake: /verbose on \ n[from: Jake] ` ,
CommandBody : "/verbose on" ,
From : "+1222" ,
To : "+1222" ,
ChatType : "group" ,
} ;
const res = await getReplyFromConfig (
groupMessageCtx ,
{ } ,
{
agents : {
defaults : {
model : "anthropic/claude-opus-4-5" ,
workspace : path.join ( home , "clawd" ) ,
} ,
} ,
2026-01-13 06:16:43 +00:00
channels : { whatsapp : { allowFrom : [ "*" ] } } ,
2026-01-10 18:53:33 +01:00
session : { store : path.join ( home , "sessions.json" ) } ,
} ,
) ;
const text = Array . isArray ( res ) ? res [ 0 ] ? . text : res?.text ;
expect ( text ) . toContain ( "Verbose logging enabled." ) ;
expect ( runEmbeddedPiAgent ) . not . toHaveBeenCalled ( ) ;
} ) ;
} ) ;
2026-01-10 17:32:19 +01:00
it ( "Integration: WhatsApp group message with structural wrapper and RawBody command" , async ( ) = > {
await withTempHome ( async ( home ) = > {
vi . mocked ( runEmbeddedPiAgent ) . mockReset ( ) ;
const groupMessageCtx = {
Body : ` [Chat messages since your last reply - for context] \\ n[WhatsApp ...] Someone: hello \\ n \\ n[Current message - respond to this] \\ n[WhatsApp ...] Jake: /status \\ n[from: Jake McInteer (+6421807830)] ` ,
RawBody : "/status" ,
ChatType : "group" ,
From : "+1222" ,
To : "+1222" ,
SessionKey : "agent:main:whatsapp:group:G1" ,
Provider : "whatsapp" ,
Surface : "whatsapp" ,
SenderE164 : "+1222" ,
} ;
const res = await getReplyFromConfig (
groupMessageCtx ,
{ } ,
{
agents : {
defaults : {
model : "anthropic/claude-opus-4-5" ,
workspace : path.join ( home , "clawd" ) ,
} ,
} ,
2026-01-13 06:16:43 +00:00
channels : { whatsapp : { allowFrom : [ "+1222" ] } } ,
2026-01-10 17:32:19 +01:00
session : { store : path.join ( home , "sessions.json" ) } ,
} ,
) ;
const text = Array . isArray ( res ) ? res [ 0 ] ? . text : res?.text ;
expect ( text ) . toContain ( "Session: agent:main:whatsapp:group:G1" ) ;
expect ( text ) . toContain ( "anthropic/claude-opus-4-5" ) ;
expect ( runEmbeddedPiAgent ) . not . toHaveBeenCalled ( ) ;
} ) ;
} ) ;
2026-01-10 18:53:33 +01:00
it ( "preserves history when RawBody is provided for command parsing" , async ( ) = > {
await withTempHome ( async ( home ) = > {
vi . mocked ( runEmbeddedPiAgent ) . mockResolvedValue ( {
payloads : [ { text : "ok" } ] ,
meta : {
durationMs : 1 ,
agentMeta : { sessionId : "s" , provider : "p" , model : "m" } ,
} ,
} ) ;
const groupMessageCtx = {
Body : [
"[Chat messages since your last reply - for context]" ,
"[WhatsApp ...] Peter: hello" ,
"" ,
"[Current message - respond to this]" ,
"[WhatsApp ...] Jake: /think:high status please" ,
"[from: Jake McInteer (+6421807830)]" ,
] . join ( "\n" ) ,
RawBody : "/think:high status please" ,
From : "+1222" ,
To : "+1222" ,
ChatType : "group" ,
} ;
const res = await getReplyFromConfig (
groupMessageCtx ,
{ } ,
{
agents : {
defaults : {
model : "anthropic/claude-opus-4-5" ,
workspace : path.join ( home , "clawd" ) ,
} ,
} ,
2026-01-13 06:16:43 +00:00
channels : { whatsapp : { allowFrom : [ "*" ] } } ,
2026-01-10 18:53:33 +01:00
session : { store : path.join ( home , "sessions.json" ) } ,
} ,
) ;
const text = Array . isArray ( res ) ? res [ 0 ] ? . text : res?.text ;
expect ( text ) . toBe ( "ok" ) ;
expect ( runEmbeddedPiAgent ) . toHaveBeenCalledOnce ( ) ;
2026-01-14 14:31:43 +00:00
const prompt = vi . mocked ( runEmbeddedPiAgent ) . mock . calls [ 0 ] ? . [ 0 ] ? . prompt ? ? "" ;
expect ( prompt ) . toContain ( "[Chat messages since your last reply - for context]" ) ;
2026-01-10 18:53:33 +01:00
expect ( prompt ) . toContain ( "Peter: hello" ) ;
expect ( prompt ) . toContain ( "status please" ) ;
expect ( prompt ) . not . toContain ( "/think:high" ) ;
} ) ;
} ) ;
2026-01-10 17:32:19 +01:00
} ) ;