44 toolUpdateFromToolResult ,
55 toolUpdateFromEditToolResponse ,
66 forwardSessionUpdates ,
7+ nextSdkMessageOrAbort ,
78} from '../bridge.js'
89import { promptToQueryInput } from '../promptConversion.js'
910import { markdownEscape , toDisplayPath } from '../utils.js'
@@ -30,6 +31,10 @@ async function* makeStream(
3031 for ( const m of msgs ) yield m
3132}
3233
34+ async function * makeWaitingStream ( ) : AsyncGenerator < SDKMessage , void , unknown > {
35+ await new Promise < never > ( ( ) => { } )
36+ }
37+
3338// ── toolInfoFromToolUse ────────────────────────────────────────────
3439
3540describe ( 'toolInfoFromToolUse' , ( ) => {
@@ -692,6 +697,47 @@ describe('toDisplayPath', () => {
692697
693698// ── forwardSessionUpdates ─────────────────────────────────────────
694699
700+ describe ( 'nextSdkMessageOrAbort' , ( ) => {
701+ test ( 'returns undefined when aborted while waiting for next message' , async ( ) => {
702+ const ac = new AbortController ( )
703+ const pending = nextSdkMessageOrAbort ( makeWaitingStream ( ) , ac . signal )
704+ ac . abort ( )
705+
706+ const result = await Promise . race ( [
707+ pending ,
708+ new Promise < 'timeout' > ( resolve => setTimeout ( resolve , 100 , 'timeout' ) ) ,
709+ ] )
710+
711+ expect ( result ) . toBeUndefined ( )
712+ } )
713+
714+ test ( 'returns undefined when stream is done' , async ( ) => {
715+ const result = await nextSdkMessageOrAbort (
716+ makeStream ( [ ] ) ,
717+ new AbortController ( ) . signal ,
718+ )
719+
720+ expect ( result ) . toBeUndefined ( )
721+ } )
722+
723+ test ( 'returns a valid SDKMessage' , async ( ) => {
724+ const msg = {
725+ type : 'assistant' ,
726+ message : {
727+ role : 'assistant' ,
728+ content : [ { type : 'text' , text : 'hello' } ] ,
729+ } ,
730+ } as unknown as SDKMessage
731+
732+ const result = await nextSdkMessageOrAbort (
733+ makeStream ( [ msg ] ) ,
734+ new AbortController ( ) . signal ,
735+ )
736+
737+ expect ( result ) . toBe ( msg )
738+ } )
739+ } )
740+
695741describe ( 'forwardSessionUpdates' , ( ) => {
696742 test ( 'returns end_turn when stream is empty' , async ( ) => {
697743 const conn = makeConn ( )
@@ -1077,6 +1123,28 @@ describe('forwardSessionUpdates', () => {
10771123 ) . toBe ( 0 )
10781124 } )
10791125
1126+ test ( 'ignores unknown message types without crashing' , async ( ) => {
1127+ const conn = makeConn ( )
1128+ const debug = console . debug
1129+ const debugMock = mock ( ( ) => { } )
1130+ console . debug = debugMock as typeof console . debug
1131+
1132+ try {
1133+ const result = await forwardSessionUpdates (
1134+ 's1' ,
1135+ makeStream ( [ { type : 'future_message' } as unknown as SDKMessage ] ) ,
1136+ conn ,
1137+ new AbortController ( ) . signal ,
1138+ { } ,
1139+ )
1140+
1141+ expect ( result . stopReason ) . toBe ( 'end_turn' )
1142+ expect ( debugMock ) . toHaveBeenCalled ( )
1143+ } finally {
1144+ console . debug = debug
1145+ }
1146+ } )
1147+
10801148 test ( 're-throws unexpected errors from stream' , async ( ) => {
10811149 const conn = makeConn ( )
10821150 async function * errorStream ( ) : AsyncGenerator <
0 commit comments