@@ -382,6 +382,97 @@ describe.sequential("workflow streaming", () => {
382382 expect ( result ) . toEqual ( { result : 10 } ) ;
383383 } ) ;
384384
385+ it ( "should expose watch/watchAsync and streamLegacy on workflow stream results" , async ( ) => {
386+ const memory = new Memory ( { storage : new InMemoryStorageAdapter ( ) } ) ;
387+ const workflow = createWorkflow (
388+ {
389+ id : "stream-observer-surface" ,
390+ name : "Stream Observer Surface" ,
391+ input : z . object ( { value : z . number ( ) } ) ,
392+ result : z . object ( { result : z . number ( ) } ) ,
393+ memory,
394+ } ,
395+ andThen ( {
396+ id : "multiply" ,
397+ execute : async ( { data } ) => ( { result : data . value * 3 } ) ,
398+ } ) ,
399+ ) ;
400+
401+ const registry = WorkflowRegistry . getInstance ( ) ;
402+ registry . registerWorkflow ( workflow ) ;
403+
404+ const stream = workflow . stream ( { value : 7 } ) ;
405+ const watchedEvents : string [ ] = [ ] ;
406+ const watchedAsyncEvents : string [ ] = [ ] ;
407+
408+ const unsubscribe = stream . watch ( ( event ) => {
409+ watchedEvents . push ( event . type ) ;
410+ } ) ;
411+ const unsubscribeAsync = await stream . watchAsync ( ( event ) => {
412+ watchedAsyncEvents . push ( event . type ) ;
413+ } ) ;
414+
415+ for await ( const _event of stream ) {
416+ // Drain the iterator to completion.
417+ }
418+
419+ unsubscribe ( ) ;
420+ unsubscribeAsync ( ) ;
421+
422+ expect ( watchedEvents . length ) . toBeGreaterThan ( 0 ) ;
423+ expect ( watchedAsyncEvents . length ) . toBeGreaterThan ( 0 ) ;
424+ expect ( watchedEvents ) . toContain ( "workflow-start" ) ;
425+ expect ( watchedEvents ) . toContain ( "workflow-complete" ) ;
426+ expect ( watchedAsyncEvents ) . toContain ( "workflow-start" ) ;
427+ expect ( watchedAsyncEvents ) . toContain ( "workflow-complete" ) ;
428+
429+ const legacyState = await stream . streamLegacy ( ) . getWorkflowState ( ) ;
430+ expect ( legacyState ) . toEqual (
431+ expect . objectContaining ( {
432+ id : stream . executionId ,
433+ status : "completed" ,
434+ } ) ,
435+ ) ;
436+ } ) ;
437+
438+ it ( "should expose observeStream as readable stream on workflow stream results" , async ( ) => {
439+ const memory = new Memory ( { storage : new InMemoryStorageAdapter ( ) } ) ;
440+ const workflow = createWorkflow (
441+ {
442+ id : "stream-observe-readable" ,
443+ name : "Stream Observe Readable" ,
444+ input : z . object ( { value : z . number ( ) } ) ,
445+ result : z . object ( { result : z . number ( ) } ) ,
446+ memory,
447+ } ,
448+ andThen ( {
449+ id : "multiply" ,
450+ execute : async ( { data } ) => ( { result : data . value * 2 } ) ,
451+ } ) ,
452+ ) ;
453+
454+ const registry = WorkflowRegistry . getInstance ( ) ;
455+ registry . registerWorkflow ( workflow ) ;
456+
457+ const stream = workflow . stream ( { value : 4 } ) ;
458+ const reader = stream . observeStream ( ) . getReader ( ) ;
459+ const observedTypes : string [ ] = [ ] ;
460+
461+ while ( true ) {
462+ const { done, value } = await reader . read ( ) ;
463+ if ( done ) {
464+ break ;
465+ }
466+ if ( value ) {
467+ observedTypes . push ( value . type ) ;
468+ }
469+ }
470+
471+ expect ( observedTypes ) . toContain ( "workflow-start" ) ;
472+ expect ( observedTypes ) . toContain ( "workflow-complete" ) ;
473+ expect ( await stream . result ) . toEqual ( { result : 8 } ) ;
474+ } ) ;
475+
385476 it ( "should have usage with default values" , async ( ) => {
386477 const memory = new Memory ( { storage : new InMemoryStorageAdapter ( ) } ) ;
387478 const workflow = createWorkflow (
0 commit comments