Skip to content

Fix #5972: Allow multi-source OR listeners to re-fire in cyclic flows#5974

Open
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1780047127-fix-or-listener-cyclic-retrigger
Open

Fix #5972: Allow multi-source OR listeners to re-fire in cyclic flows#5974
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1780047127-fix-or-listener-cyclic-retrigger

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

Summary

Fixes #5972@listen(or_(A, B, C)) multi-source OR listeners only fire once, blocking cyclic flow re-triggering.

Root cause: When a multi-source OR listener fires, it's added to _fired_or_listeners and permanently blocked by _find_triggered_methods. Although there's clearing logic in _execute_single_listener (for cyclic re-execution of already-completed methods), it can never be reached because _find_triggered_methods blocks the listener from being found in the first place — a catch-22.

Fix: Added _reset_or_listeners_for_router_results() which is called in _execute_listeners before processing router results as triggers. It clears _fired_or_listeners entries for any OR listeners whose conditions match the router output signals. This:

  • Preserves concurrent start-method protection (the original trigger_method is still guarded)
  • Unblocks cyclic re-triggering through routers (router results are sequential, not concurrent)

Review & Testing Checklist for Human

  • Verify the fix handles the exact pattern from issue [BUG] @listen(or_(A, B, C)) multi-source OR listener only fires once, blocking cyclic flow re-triggering #5972: @listen(or_("SignalA", "SignalB")) where different router signals cycle back to re-trigger the OR listener
  • Confirm no regressions in existing cyclic flow tests (test_cyclic_flow_or_listeners_fire_every_iteration, test_cyclic_flow_multiple_or_listeners_fire_every_iteration, test_cyclic_flow_works_with_persist_and_id_input)
  • Verify test_or_condition_self_listen_fires_once still passes (self-listen guard preserved)
  • Test with the exact repro from the issue if possible (classify router → handler OR listener → handler router → re-trigger)

Recommended test plan: Run uv run pytest lib/crewai/tests/test_flow.py -x to verify all 69 flow tests pass (they do locally).

Notes

The fix is minimal and targeted — a single new helper method (_reset_or_listeners_for_router_results) and one call site in _execute_listeners. The two new tests cover both variants of the bug: different router signals triggering the OR listener across iterations, and the same signal repeated.

Link to Devin session: https://app.devin.ai/sessions/633bab68f1d84198aabc677145227839

When a router emits a signal that should re-trigger an or_() listener
that has already fired, the listener was permanently blocked by
_fired_or_listeners. This created a catch-22: the clearing logic in
_execute_single_listener (for cyclic re-execution) could never be
reached because _find_triggered_methods blocked the listener first.

Fix: Before processing router results as triggers, reset
_fired_or_listeners entries for any OR listeners whose conditions
match the router output signals. This preserves concurrent start-method
protection (original trigger_method) while unblocking cyclic
re-triggering through routers.

Co-Authored-By: João <joao@crewai.com>
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] @listen(or_(A, B, C)) multi-source OR listener only fires once, blocking cyclic flow re-triggering

0 participants