2026-07-05 21:10:14 +02:00
import test from 'node:test' ;
import assert from 'node:assert/strict' ;
import { TerminalAgent , TerminalToolRegistry } from '../lib/agent/terminal-agent.mjs' ;
function providerWith ( decisions ) {
let index = 0 ;
return {
isConfigured : true ,
async complete ( ) {
const decision = decisions [ Math . min ( index ++ , decisions . length - 1 ) ] ;
return { text : JSON . stringify ( decision ) } ;
} ,
} ;
}
test ( 'terminal agent performs bounded multi-step tool reasoning' , async ( ) => {
const registry = new TerminalToolRegistry ( [
{ name : 'get_status' , description : 'status' , handler : async ( ) => ( { status : 'degraded' } ) } ,
{ name : 'search_memory' , description : 'memory' , handler : async args => ( { query : args . query , hits : 2 } ) } ,
] ) ;
const agent = new TerminalAgent ( {
registry ,
provider : providerWith ( [
{ type : 'tool_call' , tool : 'get_status' , arguments : { } , rationale : 'Check freshness' } ,
{ type : 'tool_call' , tool : 'search_memory' , arguments : { query : 'Iran' } , rationale : 'Compare history' } ,
{ type : 'final' , answer : 'Two historical events support the current signal.' , confidence : 'medium' , evidence : [ 'evt-1' ] , notify : false , priority : 'routine' } ,
] ) ,
maxSteps : 4 ,
} ) ;
const result = await agent . run ( 'What changed?' , { chatId : 42 } ) ;
assert . equal ( result . answer , 'Two historical events support the current signal.' ) ;
assert . equal ( result . confidence , 'medium' ) ;
assert . deepEqual ( result . trace . map ( item => item . tool ) , [ 'get_status' , 'search_memory' ] ) ;
assert . ok ( result . trace . every ( item => item . status === 'ok' ) ) ;
} ) ;
test ( 'mutating tools require chat-bound confirmation' , async ( ) => {
let executions = 0 ;
const registry = new TerminalToolRegistry ( [ {
name : 'trigger_sweep' ,
description : 'sweep' ,
mutating : true ,
handler : async ( _args , runtime ) => {
assert . equal ( runtime . confirmed , true ) ;
executions ++ ;
return { accepted : true } ;
} ,
} ] ) ;
const agent = new TerminalAgent ( {
registry ,
provider : providerWith ( [ { type : 'tool_call' , tool : 'trigger_sweep' , arguments : { } , rationale : 'Fresh data needed' } ] ) ,
} ) ;
const proposal = await agent . run ( 'Run a sweep' , { chatId : 42 } ) ;
assert . equal ( executions , 0 ) ;
assert . equal ( proposal . pendingAction . tool , 'trigger_sweep' ) ;
assert . equal ( ( await agent . confirm ( proposal . pendingAction . id , 99 ) ) . ok , false ) ;
assert . equal ( executions , 0 ) ;
assert . equal ( ( await agent . confirm ( proposal . pendingAction . id , 42 ) ) . ok , true ) ;
assert . equal ( executions , 1 ) ;
assert . equal ( ( await agent . confirm ( proposal . pendingAction . id , 42 ) ) . ok , false ) ;
} ) ;
test ( 'unknown tools fail closed and remain in audit trace' , async ( ) => {
const agent = new TerminalAgent ( {
registry : new TerminalToolRegistry ( [ ] ) ,
provider : providerWith ( [
{ type : 'tool_call' , tool : 'run_shell' , arguments : { command : 'whoami' } , rationale : 'Not allowed' } ,
{ type : 'final' , answer : 'That operation is not available.' , confidence : 'high' , evidence : [ ] , notify : false , priority : 'routine' } ,
] ) ,
} ) ;
const result = await agent . run ( 'Run shell' , { chatId : 42 } ) ;
assert . equal ( result . answer , 'That operation is not available.' ) ;
assert . deepEqual ( result . trace [ 0 ] , { tool : 'run_shell' , status : 'rejected' , durationMs : 0 , rationale : 'Not allowed' } ) ;
} ) ;
test ( 'proactive notifications observe cooldown' , async ( ) => {
const agent = new TerminalAgent ( {
registry : new TerminalToolRegistry ( [ ] ) ,
provider : providerWith ( [ { type : 'final' , answer : 'Material escalation detected.' , confidence : 'high' , evidence : [ 'https://example.test' ] , notify : true , priority : 'flash' } ] ) ,
proactiveCooldownMs : 60000 ,
} ) ;
const first = await agent . analyzeProactively ( 'Evaluate' ) ;
const second = await agent . analyzeProactively ( 'Evaluate again' ) ;
assert . equal ( first . notify , true ) ;
assert . equal ( first . priority , 'flash' ) ;
assert . equal ( second . notify , false ) ;
assert . equal ( second . suppressed , 'cooldown' ) ;
} ) ;
2026-07-05 22:11:15 +02:00
test ( 'step exhaustion uses a final-only prompt and returns synthesized evidence' , async ( ) => {
const prompts = [ ] ;
let call = 0 ;
const provider = {
isConfigured : true ,
async complete ( system ) {
prompts . push ( system ) ;
call ++ ;
return call === 1
? { text : JSON . stringify ( { type : 'tool_call' , tool : 'get_evidence' , arguments : { } , rationale : 'Verify claim' } ) }
: { text : JSON . stringify ( { type : 'final' , answer : 'The available evidence does not confirm the claim.' , confidence : 'medium' , evidence : [ 'evt-1' ] , notify : false , priority : 'routine' } ) } ;
} ,
} ;
const agent = new TerminalAgent ( {
provider ,
registry : new TerminalToolRegistry ( [ { name : 'get_evidence' , handler : async ( ) => [ { id : 'evt-1' } ] } ] ) ,
maxSteps : 1 ,
} ) ;
const result = await agent . run ( 'Is the claim confirmed?' ) ;
assert . equal ( result . answer , 'The available evidence does not confirm the claim.' ) ;
assert . match ( prompts [ 1 ] , /Tool use is finished and unavailable/ ) ;
assert . doesNotMatch ( prompts [ 1 ] , /ALLOWLISTED TOOLS/ ) ;
2026-07-05 22:28:40 +02:00
assert . match ( prompts [ 0 ] , /Your name is DAVE/ ) ;
assert . match ( prompts [ 0 ] , /ADAPTIVE WRITING STYLE/ ) ;
assert . match ( prompts [ 1 ] , /Your name is DAVE/ ) ;
2026-07-05 22:11:15 +02:00
} ) ;
test ( 'repeated tool calls during finalization fail closed without leaking protocol JSON' , async ( ) => {
const provider = providerWith ( [ { type : 'tool_call' , tool : 'get_evidence' , arguments : { } , rationale : 'Keep searching' } ] ) ;
const agent = new TerminalAgent ( {
provider ,
registry : new TerminalToolRegistry ( [ { name : 'get_evidence' , handler : async ( ) => [ ] } ] ) ,
maxSteps : 1 ,
} ) ;
const result = await agent . run ( 'Wie sieht es mit dem Angriff aus?' ) ;
assert . match ( result . answer , /nicht zuverlässig/ ) ;
assert . doesNotMatch ( result . answer , /tool_call|get_evidence|rationale/i ) ;
assert . equal ( result . notify , false ) ;
} ) ;
2026-07-05 22:47:08 +02:00
2026-07-06 09:14:55 +02:00
test ( 'agent propagates preferred German language through tool and finalization prompts' , async ( ) => {
const prompts = [ ] ;
let call = 0 ;
const agent = new TerminalAgent ( {
provider : {
isConfigured : true ,
async complete ( systemPrompt ) {
prompts . push ( systemPrompt ) ;
call ++ ;
return call === 1
? { text : JSON . stringify ( { type : 'tool_call' , tool : 'get_status' , arguments : { } , rationale : 'Status prüfen' } ) }
: { text : JSON . stringify ( { type : 'final' , answer : 'Die Systemlage ist stabil.' , confidence : 'high' , evidence : [ ] , notify : false , priority : 'routine' } ) } ;
} ,
} ,
registry : new TerminalToolRegistry ( [ { name : 'get_status' , handler : async ( ) => ( { status : 'healthy' } ) } ] ) ,
maxSteps : 1 ,
} ) ;
const result = await agent . run ( 'Lage?' , { preferredLanguage : 'de' } ) ;
assert . equal ( result . answer , 'Die Systemlage ist stabil.' ) ;
assert . match ( prompts [ 0 ] , /REQUIRED RESPONSE LANGUAGE: German \(de\)/ ) ;
assert . match ( prompts [ 1 ] , /REQUIRED RESPONSE LANGUAGE: German \(de\)/ ) ;
} ) ;
2026-07-05 22:47:08 +02:00
test ( 'scheduled presence cannot create pending mutating actions' , async ( ) => {
let executions = 0 ;
const agent = new TerminalAgent ( {
provider : providerWith ( [
{ type : 'tool_call' , tool : 'trigger_sweep' , arguments : { } , rationale : 'Refresh data' } ,
{ type : 'final' , answer : 'No autonomous action was taken.' , confidence : 'high' , evidence : [ ] , notify : false , priority : 'routine' } ,
] ) ,
registry : new TerminalToolRegistry ( [ {
name : 'trigger_sweep' ,
mutating : true ,
handler : async ( ) => { executions ++ ; } ,
} ] ) ,
} ) ;
const result = await agent . run ( 'Evaluate presence' , { mode : 'presence' } ) ;
assert . equal ( result . pendingAction , undefined ) ;
assert . equal ( result . trace [ 0 ] . status , 'rejected' ) ;
assert . equal ( executions , 0 ) ;
} ) ;
2026-07-05 23:14:29 +02:00
test ( 'ChatML-style tagged tool calls are executed without leaking protocol text' , async ( ) => {
const calls = [ ] ;
let responseIndex = 0 ;
const responses = [
'<|tool_call>call:get_evidence{query:"Russia planned attack military escalation",limit:5}<tool_call|>' ,
JSON . stringify ( { type : 'final' , answer : 'The retrieved evidence does not confirm a specific planned attack.' , confidence : 'medium' , evidence : [ 'evt-russia' ] , notify : false , priority : 'routine' } ) ,
] ;
const agent = new TerminalAgent ( {
provider : {
isConfigured : true ,
async complete ( ) { return { text : responses [ responseIndex ++ ] } ; } ,
} ,
registry : new TerminalToolRegistry ( [ {
name : 'get_evidence' ,
handler : async args => { calls . push ( args ) ; return [ { id : 'evt-russia' } ] ; } ,
} ] ) ,
} ) ;
const result = await agent . run ( 'Wie sieht es mit dem angeblich geplanten Angriff von Russland aus?' ) ;
assert . deepEqual ( calls , [ { query : 'Russia planned attack military escalation' , limit : 5 } ] ) ;
assert . equal ( result . trace [ 0 ] . tool , 'get_evidence' ) ;
assert . doesNotMatch ( result . answer , /tool_call|call:get_evidence/i ) ;
} ) ;
test ( 'malformed tagged protocol is repaired instead of returned to the user' , async ( ) => {
let responseIndex = 0 ;
const responses = [
'<|tool_call>call:get_evidence{broken arguments}<tool_call|>' ,
JSON . stringify ( { type : 'final' , answer : 'I could not run the malformed tool request.' , confidence : 'low' , evidence : [ ] , notify : false , priority : 'routine' } ) ,
] ;
const agent = new TerminalAgent ( {
provider : { isConfigured : true , async complete ( ) { return { text : responses [ responseIndex ++ ] } ; } } ,
registry : new TerminalToolRegistry ( [ ] ) ,
} ) ;
const result = await agent . run ( 'Check the claim' ) ;
assert . equal ( result . answer , 'I could not run the malformed tool request.' ) ;
assert . doesNotMatch ( result . answer , /tool_call|call:get_evidence/i ) ;
} ) ;