fix(flow): stop replaying previous turn's intent when route_turn() returns falsy#6505
Open
joaomdmoura wants to merge 1 commit into
Open
Conversation
…turns falsy In conversational flows, a falsy return from an overridden route_turn() fell back to the sticky state.last_intent from a previous turn, silently re-running the prior turn's handler for an unhandled input. The fallback exists for the legacy default_intents path, where receive_user_message() classifies the intent fresh each turn. Track that per-turn classification in _turn_classified_intent (cleared on every turn reset) and route on it instead, so a falsy route_turn() now falls through to the built-in answer_from_history/converse defaults and never reuses stale routing state. Fixes EPD-176. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughConversational routing now tracks intent classification per turn, clears it between turns, and uses it instead of persisted intent for route selection. Regression tests cover falsy route results, fallback behavior, route events, and changing legacy intent classifications. ChangesConversational routing
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes EPD-176: in the experimental Conversational Flow, an overridden
route_turn()returning a falsy value (e.g.Nonefor an unhandled input) silently fell back to the stickystate.last_intentfrom the previous turn, re-running the prior turn's handler with no error, warning, or event — invisible misrouting, hit by an enterprise customer in production migration.Root cause
The
last_intentfallback inroute_conversation()exists to serve the legacydefault_intentspath, wherereceive_user_message()classifies an intent fresh at the start of every turn and stashes it instate.last_intent. The field couldn't distinguish "classified this turn" from "left over from a previous turn", so customroute_turn()overrides returning falsy picked up stale routing state. A side effect: thecan_answer_from_historycheck was dead after the first turn, since the sticky intent always won.Fix
_turn_classified_intent), set byreceive_user_message()and cleared on every turn reset.route_conversation()now routes on that per-turn value; a falsyroute_turn()with no fresh classification falls through to the built-inanswer_from_history/conversedefaults and never replays a previous turn's intent. A debug log notes when a stale intent is ignored.route_turn()'s docstring.Testing
converseinstead of re-running the previous turn's handler.TestFalsyRouteTurnFallback: the repro scenario,ConversationRouteSelectedEventemission on fallback (withprevious_intentstill reported), and the legacydefault_intentsmulti-turn path routing on fresh per-turn classification, including intent changes between turns.test_flow_conversation.py(45 passed) plus the broader flow suite (357 passed), ruff, and mypy are green.🤖 Generated with Claude Code
Note
Medium Risk
Changes conversational turn routing in experimental flows—a behavior bugfix with targeted tests, but incorrect routing logic could still affect production chat flows using custom
route_turn()overrides.Overview
Fixes silent misrouting in experimental conversational flows when a custom
route_turn()returns a falsy value (e.g.Nonefor unhandled input). Previouslyroute_conversation()fell back to stickystate.last_intentfrom the prior turn, re-running the wrong@listenhandler with no warning.Routing now uses a per-turn
_turn_classified_intent(set whenreceive_user_message()classifies via legacydefault_intents, cleared on each turn reset). After a truthyroute_turn()decision, only that turn’s classified intent is reused; otherwise the flow falls through toanswer_from_history/converseand logs when a stalelast_intentis ignored. The falsyroute_turn()contract is documented onroute_turn().Adds
TestFalsyRouteTurnFallbackregression tests (EPD-176 repro, route events on fallback, legacy multi-turn classification).Reviewed by Cursor Bugbot for commit 0094863. Bugbot is set up for automated code reviews on this repo. Configure here.