Skip to content

Fix RTVIObserver missing upstream-only frames#3774

Merged
filipi87 merged 6 commits intomainfrom
mb/broadcast-frames-rtvi-observer
Feb 19, 2026
Merged

Fix RTVIObserver missing upstream-only frames#3774
filipi87 merged 6 commits intomainfrom
mb/broadcast-frames-rtvi-observer

Conversation

@markbackman
Copy link
Copy Markdown
Contributor

@markbackman markbackman commented Feb 19, 2026

Summary

  • Fixed RTVIObserver silently ignoring upstream-only frames. The observer previously filtered out all upstream frames to prevent duplicate RTVI messages from broadcasted frames (frames pushed in both directions). This meant any frame that only traveled upstream was never converted to an RTVI client message.
  • Added a broadcasted boolean field to the base Frame class, automatically set to True by broadcast_frame() and broadcast_frame_instance().
  • Updated RTVIObserver to only skip the upstream copy of broadcasted frames, allowing upstream-only frames to be observed normally.

Testing

  • All existing tests pass (576 passed, 55 skipped)
  • Verify upstream-only frames are now observed by RTVIObserver
  • Verify broadcasted frames still only produce one RTVI message (downstream copy)

🤖 Generated with Claude Code

RTVIObserver previously filtered out all upstream frames to avoid
duplicate messages from broadcasted frames. This caused upstream-only
frames to be silently ignored. Instead, add a `broadcasted` field to
the Frame base class that is set by broadcast_frame() and
broadcast_frame_instance(), and only skip upstream copies of
broadcasted frames.
@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 19, 2026

Codecov Report

❌ Patch coverage is 54.54545% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/pipecat/transports/base_output.py 0.00% 5 Missing ⚠️
Files with missing lines Coverage Δ
src/pipecat/frames/frames.py 89.40% <100.00%> (+0.08%) ⬆️
src/pipecat/processors/frame_processor.py 87.56% <100.00%> (+0.18%) ⬆️
src/pipecat/processors/frameworks/rtvi.py 54.07% <100.00%> (-0.12%) ⬇️
src/pipecat/transports/base_output.py 19.03% <0.00%> (-0.09%) ⬇️

... and 7 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread src/pipecat/frames/frames.py Outdated
id: int = field(init=False)
name: str = field(init=False)
pts: Optional[int] = field(init=False)
broadcasted: bool = field(init=False)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@markbackman, after discussing this with @kompfner and @aconchillo, we agreed that instead we should store broadcasted_sibling_id, which will reference the frame ID of the other frame that has been broadcast. This will be useful for debugging in the future.

So, I will apply this change so we can include this PR in the next release.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@kwindla
Copy link
Copy Markdown
Contributor

kwindla commented Feb 19, 2026

Related: I had an issue with ParallelPipeline sending multiple RTVI events, because of how observers work. I wonder if it makes sense to fix this behavior in this PR, too.

Claude came up with this very hacky workaround that unsets the "extra" RTVI observers: https://github.com/pipecat-ai/gradient-bang/blob/8d3c573259887eb7a6ea78ea223391b9284f5795/src/gradientbang/pipecat_server/bot.py#L361

@filipi87
Copy link
Copy Markdown
Contributor

Related: I had an issue with ParallelPipeline sending multiple RTVI events, because of how observers work. I wonder if it makes sense to fix this behavior in this PR, too.

Hi @kwindla, in this case it wasn’t that the RTVI events were duplicated, but that you wanted to filter out RTVI events from a specific branch (source). Is that right ?

Comment thread src/pipecat/frames/frames.py Outdated
id: Unique identifier for the frame instance.
name: Human-readable name combining class name and instance count.
pts: Presentation timestamp in nanoseconds.
broadcasted_sibling_id: ID of the paired frame when this frame was
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Searching for the correct past tense, it seems broadcast is more common that broadcasted.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, wondering if this should be a string instead. 🤔 . I'm just thinking mainly for Whisker. The id is hard to track, but not the name. For example, we could have id 1376434 but frame name UserSpeakingFrame#56. So, it would be broadcast_sibling_name, WDYT? I'm not sure though.

Copy link
Copy Markdown
Contributor

@filipi87 filipi87 Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that right now this is mostly for debugging, so if we think that using the name would make things easier to debug, I can do that.

However, the id still feels more natural for referencing something than the name. Maybe Whisker could simply create a link between the frames using the ID and retrieve any other information as needed ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have renamed to broadcast_sibling_id, but let me know in case you think we should use the name instead.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, let's use id for now.

@filipi87 filipi87 requested a review from aconchillo February 19, 2026 19:24
Comment thread src/pipecat/processors/frameworks/rtvi.py Outdated
@aconchillo
Copy link
Copy Markdown
Contributor

LGTM

@filipi87
Copy link
Copy Markdown
Contributor

@kwindla, I will push a follow up PR to filter out RTVI events from a specific branch, so we can include this one in today’s release.

@filipi87 filipi87 merged commit 2963c75 into main Feb 19, 2026
4 of 5 checks passed
@filipi87 filipi87 deleted the mb/broadcast-frames-rtvi-observer branch February 19, 2026 20:32
@filipi87
Copy link
Copy Markdown
Contributor

Follow up PR for filtering RTVI events from a specific source:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants