Skip to content

Conversation

@aconchillo
Copy link
Contributor

Please describe the changes in your PR. If it is addressing an issue, please reference that as well.

We the following report:

  • idle_timeout_frames set to LLMFullResponseEndFrame
  • Frame LLMFullResponseEndFrame was being generated
  • Pipeline was considered idle.

The reason is because the LLM assistant aggregator swallows LLMFullResponseEndFrame.

Since we don't know when frames can be swallowed we now use an observer and an asyncio event that gets set when the expected frames are generated. This also simplifies the timeout logic since we just rely on asyncio.wait_for().

@codecov
Copy link

codecov bot commented Oct 31, 2025

Codecov Report

❌ Patch coverage is 95.45455% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/pipecat/pipeline/task.py 95.23% 1 Missing ⚠️
Files with missing lines Coverage Δ
src/pipecat/pipeline/task_observer.py 89.74% <100.00%> (ø)
src/pipecat/pipeline/task.py 88.69% <95.23%> (-0.13%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@aconchillo aconchillo force-pushed the aleix/idle-timeout-observer branch from fe3220b to 9fbab86 Compare October 31, 2025 02:14

self._idle_queue.task_done()

await asyncio.wait_for(self._idle_event.wait(), timeout=self._idle_timeout_secs)
Copy link
Contributor

Choose a reason for hiding this comment

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

much tidier!

# If we are cancelling, just exit the task.
if self._cancelled:
return True
return False
Copy link
Contributor

Choose a reason for hiding this comment

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

What effect does flipping this value have?

Copy link
Contributor

Choose a reason for hiding this comment

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

It seems like the return value of _idle_timeout_detected determines whether to stop the pipeline (based on the assumption that the _idle_monitor_task is the only thing keeping the pipeline alive still...right? what if that's not true?).

If we're already mid-cancelling the pipeline when we detect that the pipeline is idle...then now we're saying we keep the _idle_monitor_task alive and keep monitoring for future idle detections?

I'm probably misunderstanding this mechanism.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, this mechanism is just for detecting a pipeline that's not being used, not one that's stuck/blocked for some reason. Got it.

But wait, shouldn't we actually return True here, to tell the _idle_monitor_task to stop? We don't need it anymore if we're already canceling the pipeline, right?

Side note: the comments in this method state that the return value indicates whether the pipeline task should continue running, which doesn't seem accurate—it indicates whether the idle timeout monitor should continue, right?

Copy link
Contributor

Choose a reason for hiding this comment

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

We don't need it anymore if we're already canceling the pipeline, right?

Hmm...is the thinking that if cancelling takes a long time and _cancel_on_idle_timeout is False the user might still want to get an "on_idle_timeout" event mid-cancellation? 🤔

Copy link
Contributor

Choose a reason for hiding this comment

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

I suppose I can see this value going either way...unclear to me what the right behavior is in this edge case.

One piece of feedback, though, is to fix the comments in this method to better describe the return value.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If it's True we keep running the task. If it's False then running becomes False so we exit.

Copy link
Contributor Author

@aconchillo aconchillo Oct 31, 2025

Choose a reason for hiding this comment

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

We don't need it anymore if we're already canceling the pipeline, right?

Hmm...is the thinking that if cancelling takes a long time and _cancel_on_idle_timeout is False the user might still want to get an "on_idle_timeout" event mid-cancellation? 🤔

If we cancel we will likely not get the frames we are expecting, but I don't think we want to trigger an idle timeout in that case, we just don't want to keep checking for the idle timeout frames.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah right False means stop. OK I got turned around. This makes sense. No need to keep running the timeout checker. 👍

Copy link
Contributor

@kompfner kompfner left a comment

Choose a reason for hiding this comment

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

One nit, buried in a stream-of-consciousness series of comments (pardon me)

@aconchillo aconchillo force-pushed the aleix/idle-timeout-observer branch from 9fbab86 to 0f5030b Compare October 31, 2025 15:46
@aconchillo aconchillo merged commit 67ab377 into main Oct 31, 2025
6 checks passed
@aconchillo aconchillo deleted the aleix/idle-timeout-observer branch October 31, 2025 15:51
sivakumarai2828 pushed a commit to sivakumarai2828/pipecat-speech2speech that referenced this pull request Nov 18, 2025
…-observer

PipelineTask: add IdleFrameObserver to detect idle pipelines
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.

3 participants