Fix COMPOSITE node chaining in process_interaction#595
Conversation
The two while loops in process_interaction that chain through non-interactive nodes (ACTION, CONDITION, MESSAGE) did not handle COMPOSITE nodes, causing the session to stall when a MESSAGE node chained to a COMPOSITE node (e.g., stale_collection_msg → profile_composite). Add NodeType.COMPOSITE to both while loops and handle dict question results that composite sub-flows return when entering a sub-flow with a question node.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 54f0cb8686
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
app/services/chat_runtime.py
Outdated
| chained_next_node = None | ||
| break |
There was a problem hiding this comment.
Persist session position before exiting question branch
When a chained COMPOSITE/ACTION/CONDITION returns {"type": "question"} directly, this branch sets awaiting_input and then breaks before the loop’s update_session_state call runs, so the DB session can remain positioned on the processed composite node instead of the returned question node. In sub-flow cases (sub_flow_id set), that leaves current_flow_id and current_node_id out of sync, and the next user reply can be resolved against the wrong node/flow (often restarting or stalling the conversation). The same pattern appears in the mirrored loop in the MESSAGE path.
Useful? React with 👍 / 👎.
Add update_session_state call before break in both while loops when a composite returns a question directly, ensuring session position is persisted to DB before exiting. Without this, the next user reply could resolve against the wrong node/flow. Update E2E test script to walk through composite sub-flows (recommendation, jokes, spelling) and add Test 5 for the stale collection → composite chaining path.
Implement a generic emit_event action in ActionNodeProcessor that
creates events directly from flow configurations, matching the 12
event types produced by the production Landbot chatbot.
- Fire-and-forget: errors logged but never break the chat flow
- Template substitution: {{var}} resolution in title, description, info
- iterate_over: create per-item events (e.g. one per book reviewed)
- School/ServiceAccount resolution cached per action execution
- Seed huey-events service account in admin seed script
- Add emit_event nodes to all 4 Huey flow fixtures
- 6 new unit tests, E2E event verification
…ing loops Both QUESTION and MESSAGE response branches in process_interaction contained nearly identical ~140-line chaining loops. Extract shared logic into a single _process_chained_node method that handles QUESTION, ACTION/CONDITION/COMPOSITE, and MESSAGE node types uniformly. Also document the emit_event action type across chatflow-node-types, node-schemas-reference, and architecture docs.
Summary
stale_collection_msg→profile_compositein the Huey Bookbot flow)process_interactionthat auto-process non-interactive nodes only handled ACTION, CONDITION, and MESSAGE — COMPOSITE nodes fell through toelse: break, causing the session to stall with noinput_requestNodeType.COMPOSITEto both while loops and handle dict question results from composite sub-flow entryRoot Cause
In the production Huey Bookbot flow, when a school's collection is stale (>3 years), the flow shows a warning message (
stale_collection_msg) then chains toprofile_composite. Theprocess_interactionwhile loop didn't handle COMPOSITE nodes, so the session broke — the user saw the warning messages but got no next question to answer.Test plan