@@ -389,12 +389,12 @@ async def on_client_ready(rtvi: RTVIProcessor):
389389 # source allows us to receive and react to upstream frames, and the sink
390390 # allows us to receive and react to downstream frames.
391391 source = PipelineSource (self ._source_push_frame , name = f"{ self } ::Source" )
392- sink = PipelineSink (self ._sink_push_frame , name = f"{ self } ::Sink" )
392+ self . _sink = PipelineSink (self ._sink_push_frame , name = f"{ self } ::Sink" )
393393 # Only prepend the RTVIProcessor if we created it ourselves. When the
394394 # user already placed it inside their pipeline we must not insert it
395395 # again or it will appear twice in the frame chain.
396396 processors = [self ._rtvi , pipeline ] if prepend_rtvi else [pipeline ]
397- self ._pipeline = Pipeline (processors , source = source , sink = sink )
397+ self ._pipeline = Pipeline (processors , source = source , sink = self . _sink )
398398
399399 # The task observer acts as a proxy to the provided observers. This way,
400400 # we only need to pass a single observer (using the StartFrame) which
@@ -625,26 +625,43 @@ async def run(self, params: PipelineTaskParams):
625625 self ._finished = True
626626 logger .debug (f"Pipeline task { self } has finished" )
627627
628- async def queue_frame (self , frame : Frame ):
629- """Queue a single frame to be pushed down the pipeline.
628+ async def queue_frame (
629+ self , frame : Frame , direction : FrameDirection = FrameDirection .DOWNSTREAM
630+ ):
631+ """Queue a single frame to be pushed through the pipeline.
632+
633+ Downstream frames are pushed from the beginning of the pipeline.
634+ Upstream frames are pushed from the end of the pipeline.
630635
631636 Args:
632637 frame: The frame to be processed.
638+ direction: The direction to push the frame. Defaults to downstream.
633639 """
634- await self ._push_queue .put (frame )
640+ if direction == FrameDirection .DOWNSTREAM :
641+ await self ._push_queue .put (frame )
642+ else :
643+ await self ._sink .queue_frame (frame , direction )
644+
645+ async def queue_frames (
646+ self ,
647+ frames : Iterable [Frame ] | AsyncIterable [Frame ],
648+ direction : FrameDirection = FrameDirection .DOWNSTREAM ,
649+ ):
650+ """Queue multiple frames to be pushed through the pipeline.
635651
636- async def queue_frames ( self , frames : Iterable [ Frame ] | AsyncIterable [ Frame ]):
637- """Queues multiple frames to be pushed down the pipeline.
652+ Downstream frames are pushed from the beginning of the pipeline.
653+ Upstream frames are pushed from the end of the pipeline.
638654
639655 Args:
640656 frames: An iterable or async iterable of frames to be processed.
657+ direction: The direction to push the frames. Defaults to downstream.
641658 """
642659 if isinstance (frames , AsyncIterable ):
643660 async for frame in frames :
644- await self .queue_frame (frame )
661+ await self .queue_frame (frame , direction )
645662 elif isinstance (frames , Iterable ):
646663 for frame in frames :
647- await self .queue_frame (frame )
664+ await self .queue_frame (frame , direction )
648665
649666 async def _cancel (self , * , reason : Optional [str ] = None ):
650667 """Internal cancellation logic for the pipeline task.
0 commit comments