2026-10-14 12:20:11 -07:00
import assert from "node:assert/strict" ;
import test from "node:test" ;
import {
2026-10-14 22:03:21 -07:00
AgentRoomClient , AgentReadSourceChangedError , advanceAgentCursor , agentAuthFrame , agentDisplayMessages , agentUnreadCount ,
applyAgentEvent , applyAgentPage , applyAgentReadState , createAgentReadSession , createAgentReadWriter ,
2026-10-14 12:20:11 -07:00
createAgentRoomState , mergeAgentMessages , normalizeAgentCursor , parseAgentRoomEvent , syncAgentHistory ,
2026-10-16 21:18:15 -07:00
applyAgentHistoryPage , agentUnreadCountIsPartial ,
2026-10-14 12:20:11 -07:00
} from "../src/lib/agent-room.ts" ;
import { createAgentOptimisticOutbox } from "../src/lib/agent-optimistic-outbox.ts" ;
const message = ( id , role = "assistant" , extra = {}) => ({
id : `entry: ${ id } ` , createdAt : `2026-10-14T10:00: ${ String ( id % 60 ). padStart ( 2 , "0" ) } .000Z` ,
2026-10-14 12:37:03 -07:00
role , content : `message ${ id } ` , name : role === "assistant" ? "Sybil Agent" : "buzzert" ,
2026-10-14 12:20:11 -07:00
metadata : { kind : "message" , entryId : id , status : "complete" }, ... extra ,
});
const page = ( cursor , messages = [], hasMore = false ) => ({
conversationId : "1" , messages , cursor , beforeCursor : messages . length ? String ( messages [ 0 ]. metadata . entryId ) : cursor , hasMore ,
});
const activity = ( queuedMessages = []) => ({ state : "idle" , isThinking : false , queued : queuedMessages . length , backgroundWorkers : 0 , tools : [], queuedMessages });
2026-10-14 22:03:21 -07:00
const sourceA = "4599d348-e053-4937-987d-1392746fb2ce" , sourceB = "22222222-2222-4222-8222-222222222222" ;
const deferred = () => { let resolve ; const promise = new Promise ( yes => { resolve = yes ; }); return { promise , resolve }; };
const sourceRoom = () => applyAgentPage ( applyAgentReadState ( createAgentRoomState (), { sourceId : sourceA , cursor : "90" , updatedAt : null }), page ( "100" , [ message ( 100 )]));
2026-10-14 12:20:11 -07:00
test ( "tool starts and results merge across replay without downgrading completed cards" , () => {
const start = message ( 2 , "tool" , { id : "tool:1:call1" , metadata : { kind : "tool_call" , entryId : 2 , status : "initiated" , args : { query : "cookie" }, startedAt : "2026-10-14T10:00:00Z" } });
const done = message ( 3 , "tool" , { id : start . id , metadata : { kind : "tool_call" , entryId : 3 , status : "completed" , resultPreview : "found" } });
const messages = mergeAgentMessages ( mergeAgentMessages ([], [ start ]), [ done , start ]);
assert . equal ( messages . length , 1 );
assert . equal ( messages [ 0 ]. metadata . status , "completed" );
assert . equal ( messages [ 0 ]. metadata . resultPreview , "found" );
assert . deepEqual ( messages [ 0 ]. metadata . args , { query : "cookie" });
assert . equal ( messages [ 0 ]. metadata . entryId , 3 );
assert . equal ( messages [ 0 ]. createdAt , start . createdAt );
});
2026-10-16 21:18:15 -07:00
test ( "forward recovery reads every missing page including invisible entries and counts only unread assistant messages" , async () => {
2026-10-14 12:20:11 -07:00
const requests = [];
const responses = [ page ( "2" , [ message ( 1 ), message ( 2 , "user" )], true ), page ( "4" , [], true ), page ( "7" , [ message ( 5 ), message ( 6 , "tool" ), message ( 7 )], false )];
let state = createAgentRoomState ();
await syncAgentHistory ({ messages : async after => { requests . push ( after ); return responses . shift (); } }, "0" , update => { state = applyAgentPage ( state , update ); });
assert . deepEqual ( requests , [ "0" , "2" , "4" ]);
assert . equal ( state . cursor , "7" );
assert . equal ( agentUnreadCount ( state ), 3 );
state = applyAgentReadState ( state , { cursor : "5" , updatedAt : null });
assert . equal ( agentUnreadCount ( state ), 1 );
state = applyAgentReadState ( state , { cursor : "1" , updatedAt : null });
assert . equal ( state . readCursor , "5" , "a stale tab response cannot regress read state" );
assert . equal ( agentUnreadCount ( state ), 1 );
});
2026-10-16 21:18:15 -07:00
test ( "recent history is one cursorless window and older history uses the returned source boundary" , async () => {
const requests = [];
const client = new AgentRoomClient ({ fetch : async ( url , options ) => {
requests . push ({ url , signal : options . signal });
return new Response ( JSON . stringify ({ ... page ( "1200" , [ message ( 1200 )], true ), beforeCursor : "1101" }));
} });
const controller = new AbortController ();
let state = applyAgentHistoryPage ( createAgentRoomState (), await client . history ( undefined , controller . signal ));
assert . equal ( requests . length , 1 , "hasMore must not drain old history" );
assert . equal ( requests [ 0 ]. url , "/api/v1/agent/messages?limit=100" );
assert . equal ( requests [ 0 ]. signal , controller . signal );
assert . equal ( state . historyLoaded , true );
assert . equal ( state . cursor , "1200" );
assert . equal ( state . beforeCursor , "1101" , "boundary is not derived from visible message 1200" );
assert . equal ( state . hasOlder , true );
await client . history ( state . beforeCursor , controller . signal );
assert . equal ( requests [ 1 ]. url , "/api/v1/agent/messages?before=1101&limit=100" );
});
test ( "delayed older pages preserve newer edits, live cursor, source and read state" , () => {
let state = applyAgentHistoryPage ( sourceRoom (), { ... page ( "100" , [ message ( 100 )], true ), beforeCursor : "90" });
state = applyAgentPage ( state , page ( "110" , [ message ( 100 , "assistant" , { content : "New streamed text" }), message ( 110 )]));
const next = applyAgentHistoryPage ( state , { ... page ( "89" , [ message ( 80 ), message ( 100 , "assistant" , { content : "Old snapshot" })], true ), beforeCursor : "70" }, "90" );
assert . equal ( next . messages . find ( m => m . id === "entry:100" ). content , "New streamed text" );
assert . equal ( next . cursor , "110" );
assert . equal ( next . readCursor , "90" );
assert . equal ( next . sourceId , sourceA );
assert . equal ( next . beforeCursor , "70" );
assert . equal ( next . hasOlder , true );
assert . equal ( applyAgentHistoryPage ( next , page ( "89" , [ message ( 80 )], false ), "90" ), next , "retired boundary cannot replace the next window" );
});
test ( "empty internal pages advance older boundaries without chasing another page or moving read state" , () => {
const initial = applyAgentHistoryPage ( createAgentRoomState (), { ... page ( "1200" , [], true ), beforeCursor : "1101" });
assert . equal ( initial . historyLoaded , true );
assert . equal ( initial . messages . length , 0 );
const next = applyAgentHistoryPage ( initial , { ... page ( "1100" , [], true ), beforeCursor : "1001" }, "1101" );
assert . equal ( next . beforeCursor , "1001" );
assert . equal ( next . cursor , "1200" );
assert . equal ( next . readCursor , "0" );
assert . equal ( next . hasOlder , true );
const end = applyAgentHistoryPage ( next , { ... page ( "0" ), beforeCursor : "1001" }, "1001" );
assert . equal ( end . hasOlder , false );
assert . equal ( end . cursor , "1200" );
});
test ( "malformed or stalled older pages cannot change history or delivery boundaries" , () => {
const state = applyAgentHistoryPage ( createAgentRoomState (), { ... page ( "100" , [ message ( 100 )], true ), beforeCursor : "90" });
for ( const bad of [
{ ... page ( "89" , [], true ), beforeCursor : "90" },
{ ... page ( "89" , [], true ), beforeCursor : null },
{ ... page ( "91" , [], false ), beforeCursor : "80" },
{ ... page ( "89" , [], false ), beforeCursor : "91" },
{ ... page ( "bad" , [], false ), beforeCursor : "80" },
]) assert . throws (() => applyAgentHistoryPage ( state , bad , "90" ), /cursor|boundary/ );
assert . throws (() => applyAgentHistoryPage ( state , { ... page ( "89" ), conversationId : "different" }, "90" ), /conversation changed/ );
assert . equal ( state . beforeCursor , "90" );
assert . equal ( state . cursor , "100" );
});
test ( "unread counts disclose unknown older replies until reading the latest rendered window" , () => {
let state = applyAgentHistoryPage ( createAgentRoomState (), { ... page ( "1200" , [ message ( 1199 ), message ( 1200 , "user" )], true ), beforeCursor : "1101" });
assert . equal ( agentUnreadCount ( state ), 1 );
assert . equal ( agentUnreadCountIsPartial ( state ), true );
state = applyAgentReadState ( state , { cursor : "1100" , updatedAt : null });
assert . equal ( agentUnreadCountIsPartial ( state ), false );
assert . equal ( agentUnreadCount ( state ), 1 );
state = applyAgentReadState ( state , { cursor : "1200" , updatedAt : null });
assert . equal ( agentUnreadCount ( state ), 0 );
assert . equal ( state . hasOlder , true , "reading latest does not fetch or discard older pages" );
});
2026-10-14 12:20:11 -07:00
test ( "queued user messages keep stable IDs and disappear if withdrawn or promoted" , () => {
const pending = message ( 1 , "user" , { id : "inbound:sybil:request1" , metadata : { kind : "message" , status : "queued" } });
let state = applyAgentEvent ( createAgentRoomState (), { type : "activity" , conversationId : "1" , activity : activity ([ pending ]) });
assert . equal ( agentDisplayMessages ( state ). length , 1 );
assert . equal ( state . cursor , "0" , "pending rows never advance replay or read cursors" );
assert . equal ( agentUnreadCount ( state ), 0 );
state = applyAgentPage ( state , page ( "4" , [ message ( 4 , "user" , { id : pending . id })]));
assert . equal ( agentDisplayMessages ( state ). length , 1 );
assert . equal ( agentDisplayMessages ( state )[ 0 ]. metadata . status , "complete" );
state = applyAgentEvent ( state , { type : "activity" , conversationId : "1" , activity : activity () });
assert . equal ( agentDisplayMessages ( state ). length , 1 , "committed rows survive queue removal" );
const onlyPending = applyAgentEvent ( createAgentRoomState (), { type : "activity" , conversationId : "1" , activity : activity ([ pending ]) });
assert . deepEqual ( agentDisplayMessages ( applyAgentEvent ( onlyPending , { type : "activity" , conversationId : "1" , activity : activity () })), []);
});
test ( "failed or stalled page delivery preserves the last applied cursor for replay" , async () => {
let state = createAgentRoomState ();
let calls = 0 ;
await assert . rejects ( syncAgentHistory ({ messages : async () => {
if ( ++ calls === 1 ) return page ( "10" , [ message ( 10 )], true );
throw new Error ( "network unavailable" );
} }, "0" , next => { state = applyAgentPage ( state , next ); }), /network unavailable/ );
assert . equal ( state . cursor , "10" );
await assert . rejects ( syncAgentHistory ({ messages : async () => page ( "10" , [], true ) }, state . cursor , next => { state = applyAgentPage ( state , next ); }), /did not advance/ );
assert . equal ( state . cursor , "10" );
assert . throws (() => applyAgentPage ( state , page ( "bad" , [ message ( 11 )])), /cursor/ );
assert . equal ( state . messages . length , 1 );
assert . throws (() => applyAgentPage ( state , { ... page ( "11" ), conversationId : "different" }), /conversation changed/ );
assert . equal ( advanceAgentCursor ( "9007199254740993" , "9007199254740992" ), "9007199254740993" );
assert . throws (() => normalizeAgentCursor ( "-1" ), /cursor/ );
});
test ( "read acknowledgments use only the rendered cursor and failed persistence retains unread replies" , async () => {
let state = applyAgentPage ( createAgentRoomState (), page ( "5" , [ message ( 5 )]));
const renderedCursor = state . cursor ;
state = applyAgentPage ( state , page ( "6" , [ message ( 6 )]));
const saved = [];
let fail = true ;
const writer = createAgentReadWriter ({
current : () => state . readCursor ,
save : async cursor => { saved . push ( cursor ); if ( fail ) throw new Error ( "database offline" ); return { cursor , updatedAt : null }; },
apply : read => { state = applyAgentReadState ( state , read ); },
});
await assert . rejects ( writer . request ( renderedCursor ), /database offline/ );
assert . equal ( state . readCursor , "0" );
assert . equal ( agentUnreadCount ( state ), 2 );
fail = false ;
await writer . flush ();
assert . deepEqual ( saved , [ "5" , "5" ]);
assert . equal ( state . readCursor , "5" );
assert . equal ( agentUnreadCount ( state ), 1 , "message6 arrived after render and must remain unread" );
});
test ( "read acknowledgments coalesce concurrent seen snapshots and reject unacknowledged cursors" , async () => {
let cursor = "0" ;
let release ;
const gate = new Promise ( resolve => { release = resolve ; });
const saves = [];
const writer = createAgentReadWriter ({ current : () => cursor , save : async value => {
saves . push ( value ); if ( value === "3" ) await gate ; return { cursor : value , updatedAt : null };
}, apply : read => { cursor = read . cursor ; } });
const first = writer . request ( "3" ), second = writer . request ( "7" );
release (); await Promise . all ([ first , second ]);
assert . deepEqual ( saves , [ "3" , "7" ]);
assert . equal ( cursor , "7" );
const broken = createAgentReadWriter ({ current : () => "0" , save : async () => ({ cursor : "0" , updatedAt : null }), apply : () => assert . fail ( "must not apply a failed acknowledgment" ) });
await assert . rejects ( broken . request ( "2" ), /did not acknowledge/ );
});
2026-10-14 22:03:21 -07:00
test ( "source replacement through GET or WS quiesces queued old-history reads without relabeling their cursor" , async () => {
for ( const via of [ "GET" , "WS" ]) {
let room = sourceRoom (); const saved = [], invalidated = [];
const session = createAgentReadSession ({ initial : room ,
save : async ( cursor , sourceId ) => { saved . push ({ cursor , sourceId }); throw new Error ( "temporarily offline" ); },
apply : read => { room = applyAgentReadState ( room , read ); }, invalidated : error => invalidated . push ( error ),
});
await assert . rejects ( session . request ( "100" , sourceA ), /temporarily offline/ );
const replacement = { cursor : "0" , sourceId : sourceB , updatedAt : null };
const incoming = via === "WS" ? parseAgentRoomEvent ( JSON . stringify ({ type : "read_state" , ... replacement })) : replacement ;
assert . throws (() => session . receive ( incoming ), AgentReadSourceChangedError );
for ( let i = 0 ; i < 3 ; i ++ ) await session . flush ();
await assert . rejects ( session . request ( "100" , sourceA ), AgentReadSourceChangedError );
await assert . rejects ( session . request ( "5" , sourceB ), AgentReadSourceChangedError );
assert . deepEqual ( saved , [{ cursor : "100" , sourceId : sourceA }], ` ${ via } : no write to B and no retry loop` );
assert . equal ( room . sourceId , sourceA ); assert . equal ( room . readCursor , "90" ); assert . equal ( room . cursor , "100" );
assert . equal ( session . sourceId (), sourceA ); assert . equal ( invalidated . length , 1 );
}
});
test ( "source replacement cancels an in-flight old read and prevents a coalesced larger write" , async () => {
let room = sourceRoom (); const gate = deferred (), saved = [];
const session = createAgentReadSession ({ initial : room ,
save : async ( cursor , sourceId ) => { saved . push ({ cursor , sourceId }); return gate . promise ; },
apply : read => { room = applyAgentReadState ( room , read ); },
});
const first = session . request ( "100" , sourceA ), second = session . request ( "110" , sourceA );
assert . throws (() => session . receive ({ cursor : "0" , sourceId : sourceB , updatedAt : null }), AgentReadSourceChangedError );
gate . resolve ({ cursor : "100" , sourceId : sourceA , updatedAt : null });
await Promise . all ([ first , second ]); await session . flush ();
assert . deepEqual ( saved , [{ cursor : "100" , sourceId : sourceA }]);
assert . equal ( room . sourceId , sourceA ); assert . equal ( room . readCursor , "90" );
});
test ( "mismatched acknowledgment and server409 stop retries without applying a read to new history" , async () => {
for ( const mode of [ "ack" , "409" ]) {
let room = sourceRoom (), saves = 0 , invalidated = 0 ;
const session = createAgentReadSession ({ initial : room ,
save : async () => { saves ++ ; if ( mode === "409" ) throw Object . assign ( new Error ( "cursor not valid for this source" ), { status : 409 });
return { cursor : "100" , sourceId : sourceB , updatedAt : null }; },
apply : read => { room = applyAgentReadState ( room , read ); }, invalidated : () => invalidated ++ ,
});
await assert . rejects ( session . request ( "100" , sourceA ), AgentReadSourceChangedError );
await session . flush (); await session . flush ();
await assert . rejects ( session . request ( "101" , sourceA ), AgentReadSourceChangedError );
assert . equal ( saves , 1 ); assert . equal ( invalidated , 1 ); assert . equal ( room . readCursor , "90" ); assert . equal ( room . sourceId , sourceA );
}
});
test ( "read writer stops after an ignored acknowledgment instead of repeating the same PUT forever" , async () => {
let saves = 0 ;
const writer = createAgentReadWriter ({ current : () => "0" , save : async cursor => { saves ++ ; return { cursor , updatedAt : null }; }, apply : () => {} });
await assert . rejects ( writer . request ( "2" ), /did not acknowledge/ );
await writer . flush (); await writer . request ( "3" ); assert . equal ( saves , 1 );
});
test ( "legacy source-absent sessions stay compatible but cannot adopt a source after rendering old history" , async () => {
let room = applyAgentPage ( createAgentRoomState (), page ( "5" , [ message ( 5 )])); const saved = [];
const session = createAgentReadSession ({ initial : room ,
save : async ( cursor , sourceId ) => { saved . push ({ cursor , sourceId }); return { cursor , updatedAt : null }; },
apply : read => { room = applyAgentReadState ( room , read ); },
});
session . receive ({ cursor : "0" , updatedAt : null });
assert . equal ( room . sourceId , null );
await session . request ( "5" , room . sourceId );
assert . deepEqual ( saved , [{ cursor : "5" , sourceId : null }]); assert . equal ( room . readCursor , "5" );
assert . throws (() => session . receive ({ cursor : "0" , sourceId : sourceB , updatedAt : null }), AgentReadSourceChangedError );
await session . flush (); assert . equal ( saved . length , 1 );
assert . throws (() => applyAgentReadState ( applyAgentPage ( createAgentRoomState (), page ( "5" , [ message ( 5 )])), { cursor : "0" , sourceId : sourceA , updatedAt : null }), AgentReadSourceChangedError );
assert . throws (() => applyAgentReadState ( sourceRoom (), { cursor : "0" , updatedAt : null }), AgentReadSourceChangedError );
});
test ( "rendered snapshot source must match the pinned session and new sessions cannot read before binding" , async () => {
for ( const initial of [ createAgentRoomState (), sourceRoom ()]) {
const session = createAgentReadSession ({ initial , save : async () => assert . fail ( "must not send unbound or relabeled reads" ), apply : () => {} });
await assert . rejects ( session . request ( "100" , sourceB ), AgentReadSourceChangedError ); await session . flush ();
}
let room = createAgentRoomState (); const saved = [];
const session = createAgentReadSession ({ initial : room ,
save : async ( cursor , sourceId ) => { saved . push ({ cursor , sourceId }); return { cursor , sourceId , updatedAt : null }; },
apply : read => { room = applyAgentReadState ( room , read ); },
});
session . receive ({ cursor : "0" , sourceId : sourceA , updatedAt : null });
room = applyAgentPage ( room , page ( "5" , [ message ( 5 )])); await session . request ( room . cursor , room . sourceId );
assert . deepEqual ( saved , [{ cursor : "5" , sourceId : sourceA }]); assert . equal ( room . readCursor , "5" );
});
2026-10-14 12:20:11 -07:00
test ( "failed persistence after acknowledgment retains the original receipt key across reload" , async () => {
let stored = [], writes = 0 ;
const storage = { read : () => structuredClone ( stored ), write : rows => {
if ( ++ writes === 3 ) throw new Error ( "storage unavailable after acknowledgment" );
stored = structuredClone ( rows );
} };
const requests = [];
const open = () => createAgentOptimisticOutbox ({
storage , changed : () => {}, newId : () => "stable-request" ,
submit : async ( _content , requestId ) => {
requests . push ( requestId );
return { status : "placed" , messageId : `inbound:sybil: ${ requestId } ` };
},
});
const original = open ();
await original . send ( "retry me" );
const accepted = original . display ([])[ 0 ];
assert . equal ( accepted . metadata . status , "complete" , "a storage error cannot undo server acceptance" );
assert . equal ( stored [ 0 ]. status , "sending" , "the pre-admission receipt remains durable if its update fails" );
const restored = open ();
assert . deepEqual ( requests , [ "stable-request" ], "reload never retries automatically" );
const uncertain = restored . display ([])[ 0 ];
assert . equal ( uncertain . metadata . status , "unconfirmed" );
assert . equal ( uncertain . id , accepted . id );
assert . equal ( uncertain . createdAt , accepted . createdAt );
await restored . retry ( uncertain . id );
assert . deepEqual ( requests , [ "stable-request" , "stable-request" ], "manual retry cannot create a second admission" );
restored . reconcile ({ messages : [ message ( 1 , "user" , { id : accepted . id , content : "retry me" })] });
assert . deepEqual ( stored , [], "canonical echo finishes local cleanup" );
});
test ( "client uses Sybil auth and routes while websocket credentials remain in the first frame" , async () => {
const calls = [];
let token = "first-session-token" ;
const client = new AgentRoomClient ({ baseUrl : "https://sybil.example/api/" , token : () => token , fetch : async ( url , init ) => {
calls . push ({ url , init }); return new Response ( JSON . stringify ( init . method === "POST"
? { id : 1 , status : "queued" , messageId : "inbound:sybil:request-1" } : { cursor : "0" , updatedAt : null }), { status : 200 });
} });
await client . messages ( "0" );
token = "second-session-token" ;
await client . markRead ( "42" );
await client . submit ( "hi" , "request-1" );
assert . equal ( calls [ 0 ]. url , "https://sybil.example/api/v1/agent/messages?after=0&limit=200" );
assert . equal ( calls [ 0 ]. init . headers . get ( "Authorization" ), "Bearer first-session-token" );
assert . equal ( calls [ 1 ]. init . headers . get ( "Authorization" ), "Bearer second-session-token" );
assert . equal ( calls [ 1 ]. init . method , "PUT" );
assert . deepEqual ( JSON . parse ( calls [ 1 ]. init . body ), { cursor : "42" });
assert . deepEqual ( JSON . parse ( calls [ 2 ]. init . body ), { content : "hi" , requestId : "request-1" });
const url = client . websocketUrl ( "https://sybil.example/" );
assert . equal ( url , "wss://sybil.example/api/v1/agent/ws" );
assert . equal ( new URL ( url ). search , "" );
2026-10-14 23:06:34 -07:00
assert . deepEqual ( JSON . parse ( agentAuthFrame ( null , "42" )), { type : "auth" , token : null , after : "42" , clientKind : "web" });
assert . deepEqual ( JSON . parse ( agentAuthFrame ( token , "42" )), { type : "auth" , token , after : "42" , clientKind : "web" });
2026-10-14 12:20:11 -07:00
});
2026-10-14 22:03:21 -07:00
test ( "client sends the pinned source and exposes409 without requiring a JSON response body" , async () => {
for ( const json of [ true , false ]) {
let body ;
const client = new AgentRoomClient ({ fetch : async ( _url , init ) => {
body = JSON . parse ( init . body );
return json ? Response . json ({ message : "Read source changed" }, { status : 409 }) : new Response ( null , { status : 409 });
} });
await assert . rejects ( client . markRead ( "100" , undefined , sourceA ), error => error . status === 409 );
assert . deepEqual ( body , { cursor : "100" , sourceId : sourceA });
}
});
2026-10-14 12:20:11 -07:00
test ( "malformed successful receipts keep optimistic messages retryable under the original request ID" , async () => {
const requests = [];
let response = {};
const client = new AgentRoomClient ({ fetch : async ( _url , init ) => {
requests . push ( JSON . parse ( init . body ));
return new Response ( JSON . stringify ( response ), { status : 202 });
} });
const box = createAgentOptimisticOutbox ({ submit : ( content , requestId ) => client . submit ( content , requestId ),
storage : { read : () => [], write : () => {} }, changed : () => {}, newId : () => "retry-id" ,
});
await assert . rejects ( box . send ( "Keep this request" ), /invalid message receipt/ );
const row = box . display ([])[ 0 ];
assert . equal ( row . metadata . status , "failed" );
assert . equal ( box . snapshot ()[ 0 ]. seenOnServer , false );
const valid = { id : 1 , status : "queued" , messageId : row . id };
2026-10-14 12:37:03 -07:00
for ( const malformed of [ null , { error : "Invalid Sybil Agent response" }, { ... valid , id : 0 }, { ... valid , id : 1.5 },
2026-10-14 12:20:11 -07:00
{ ... valid , id : Number . MAX_SAFE_INTEGER + 1 }, { ... valid , status : "unknown" }, { ... valid , status : [ "queued" ] },
{ ... valid , messageId : "inbound:sybil:other" }]) {
response = malformed ;
await assert . rejects ( box . retry ( row . id ), /invalid message receipt/ );
assert . equal ( box . display ([])[ 0 ]. metadata . status , "failed" );
}
response = valid ;
await box . retry ( row . id );
assert . equal ( box . display ([])[ 0 ]. metadata . status , "queued" );
assert . ok ( requests . every ( request => request . requestId === "retry-id" ), "uncertain responses cannot mint a duplicate admission" );
for ( const status of [ "placed" , "done" , "unanswered" ]) {
response = { ... valid , status };
assert . equal (( await client . submit ( "Keep this request" , "retry-id" )). status , status );
}
});
test ( "protocol ignores unknown frames and rejects malformed message cursors" , () => {
assert . equal ( parseAgentRoomEvent ( '{"type":"future-frame"}' ), null );
assert . deepEqual ( parseAgentRoomEvent ( '{"type":"pong"}' ), { type : "pong" });
assert . throws (() => parseAgentRoomEvent ( JSON . stringify ({ type : "messages" , ... page ( "oops" ) })), /cursor/ );
const state = applyAgentEvent ( createAgentRoomState (), { type : "activity" , conversationId : "1" , activity : { ... activity (), state : "thinking" , isThinking : true } });
assert . equal ( state . activity . isThinking , true );
assert . deepEqual ( state . messages , [], "a thinking indicator never becomes a chat message" );
});