dv-pipecat-flows 0.0.26.dev142__tar.gz → 0.0.26.dev145__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. {dv_pipecat_flows-0.0.26.dev142/src/dv_pipecat_flows.egg-info → dv_pipecat_flows-0.0.26.dev145}/PKG-INFO +1 -1
  2. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145/src/dv_pipecat_flows.egg-info}/PKG-INFO +1 -1
  3. dv_pipecat_flows-0.0.26.dev145/src/dv_pipecat_flows.egg-info/scm_version.json +8 -0
  4. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/pipecat_flows/manager.py +72 -0
  5. dv_pipecat_flows-0.0.26.dev142/src/dv_pipecat_flows.egg-info/scm_version.json +0 -8
  6. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/.agents/skills/pipecat-logs/SKILL.md +0 -0
  7. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/.agents/skills/pipecat-logs/query-reference.md +0 -0
  8. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/.claude/skills/pipecat-logs/SKILL.md +0 -0
  9. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/.claude/skills/pipecat-logs/query-reference.md +0 -0
  10. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/.gitattributes +0 -0
  11. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/.gitignore +0 -0
  12. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/.pre-commit-config.yaml +0 -0
  13. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/.python-version +0 -0
  14. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/.readthedocs.yaml +0 -0
  15. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/AGENTS.md +0 -0
  16. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/CHANGELOG.md +0 -0
  17. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/CLAUDE.md +0 -0
  18. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/CONTRIBUTING.md +0 -0
  19. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/LICENSE +0 -0
  20. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/MANIFEST.in +0 -0
  21. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/README.md +0 -0
  22. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/.env.example +0 -0
  23. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/.gitignore +0 -0
  24. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/README.md +0 -0
  25. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/docs/ARCHITECTURE.md +0 -0
  26. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/docs/CODE_MAP.md +0 -0
  27. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/docs/CONFIG.md +0 -0
  28. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/docs/CONTRACTS.md +0 -0
  29. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/docs/COPILOT_TODO.md +0 -0
  30. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/docs/DISTRIBUTION.md +0 -0
  31. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/docs/HLD.md +0 -0
  32. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/docs/METHODS.md +0 -0
  33. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/docs/VOICE_E2E.md +0 -0
  34. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/ANALYSIS_stagehand_vs_hybrid.md +0 -0
  35. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/RESULTS.md +0 -0
  36. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/_env.py +0 -0
  37. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/bench.py +0 -0
  38. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/bench_browseruse.py +0 -0
  39. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/bench_stagehand.py +0 -0
  40. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/inspect_browseruse.py +0 -0
  41. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/inspect_browseruse_showcase.py +0 -0
  42. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/inspect_stagehand_prompt.py +0 -0
  43. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/pages/checkout.html +0 -0
  44. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/pages/dashboard.html +0 -0
  45. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/pages/signup.html +0 -0
  46. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/results_browseruse.json +0 -0
  47. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/results_perception.json +0 -0
  48. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/results_stagehand.json +0 -0
  49. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/tasks.py +0 -0
  50. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/try_hybrid.py +0 -0
  51. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/try_hybrid_multistep.py +0 -0
  52. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/eval/try_hybrid_oneshot.py +0 -0
  53. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/pyproject.toml +0 -0
  54. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/scripts/dev-stack.sh +0 -0
  55. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/browser_copilot/uv.lock +0 -0
  56. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/dev-requirements.txt +0 -0
  57. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/docker-compose.dev.yml +0 -0
  58. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/.eslintrc.json +0 -0
  59. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/.prettierrc +0 -0
  60. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/css/tailwind.css +0 -0
  61. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/examples/food_ordering.json +0 -0
  62. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/examples/movie_explorer.json +0 -0
  63. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/examples/patient_intake.json +0 -0
  64. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/examples/restaurant_reservation.json +0 -0
  65. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/examples/travel_planner.json +0 -0
  66. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/favicon.png +0 -0
  67. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/favicon.svg +0 -0
  68. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/index.html +0 -0
  69. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/js/editor/canvas.js +0 -0
  70. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/js/editor/editorState.js +0 -0
  71. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/js/editor/sidePanel.js +0 -0
  72. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/js/editor/toolbar.js +0 -0
  73. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/js/main.js +0 -0
  74. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/js/nodes/baseNode.js +0 -0
  75. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/js/nodes/endNode.js +0 -0
  76. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/js/nodes/flowNode.js +0 -0
  77. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/js/nodes/functionNode.js +0 -0
  78. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/js/nodes/index.js +0 -0
  79. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/js/nodes/mergeNode.js +0 -0
  80. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/js/nodes/startNode.js +0 -0
  81. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/js/types.js +0 -0
  82. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/js/utils/export.js +0 -0
  83. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/js/utils/helpers.js +0 -0
  84. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/js/utils/import.js +0 -0
  85. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/js/utils/validation.js +0 -0
  86. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/jsdoc.json +0 -0
  87. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/package-lock.json +0 -0
  88. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/package.json +0 -0
  89. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/postcss.config.cjs +0 -0
  90. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/public/favicon.png +0 -0
  91. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/public/favicon.svg +0 -0
  92. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/tailwind.config.cjs +0 -0
  93. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/vercel.json +0 -0
  94. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/editor/vite.config.js +0 -0
  95. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/engine_primitives_plan.md +0 -0
  96. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/env.example +0 -0
  97. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/images/food-ordering-flow.png +0 -0
  98. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/pipecat-flows.png +0 -0
  99. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/pipecat_upgrade.md +0 -0
  100. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/pyproject.toml +0 -0
  101. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/remote-asterisk-code/README.md +0 -0
  102. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/remote-asterisk-code/extensions.conf +0 -0
  103. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/remote-asterisk-code/rtp.conf +0 -0
  104. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/requirements.txt +0 -0
  105. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/scripts/build_uae_pipecat_secret_blob.py +0 -0
  106. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/scripts/check-ar-package.py +0 -0
  107. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/scripts/fix-ruff.sh +0 -0
  108. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/scripts/pre-commit.sh +0 -0
  109. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/scripts/test_build_uae_pipecat_secret_blob.py +0 -0
  110. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/setup.cfg +0 -0
  111. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/dv_pipecat_flows.egg-info/SOURCES.txt +0 -0
  112. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/dv_pipecat_flows.egg-info/dependency_links.txt +0 -0
  113. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/dv_pipecat_flows.egg-info/requires.txt +0 -0
  114. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/dv_pipecat_flows.egg-info/scm_file_list.json +0 -0
  115. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/dv_pipecat_flows.egg-info/top_level.txt +0 -0
  116. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/pipecat_flows/__init__.py +0 -0
  117. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/pipecat_flows/actions.py +0 -0
  118. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/pipecat_flows/adapters.py +0 -0
  119. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/pipecat_flows/condition_evaluator.py +0 -0
  120. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/pipecat_flows/exceptions.py +0 -0
  121. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/pipecat_flows/flow_validator.py +0 -0
  122. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/pipecat_flows/processors/__init__.py +0 -0
  123. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/pipecat_flows/processors/router_mode_guard.py +0 -0
  124. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/pipecat_flows/processors/speak_interruption_guard.py +0 -0
  125. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/pipecat_flows/processors/user_turn_observer.py +0 -0
  126. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/pipecat_flows/router_mode.py +0 -0
  127. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/src/pipecat_flows/types.py +0 -0
  128. {dv_pipecat_flows-0.0.26.dev142 → dv_pipecat_flows-0.0.26.dev145}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dv-pipecat-flows
3
- Version: 0.0.26.dev142
3
+ Version: 0.0.26.dev145
4
4
  Summary: Conversation Flow management for Pipecat AI applications
5
5
  License: BSD 2-Clause License
6
6
  Project-URL: Source, https://github.com/pipecat-ai/pipecat-flows
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dv-pipecat-flows
3
- Version: 0.0.26.dev142
3
+ Version: 0.0.26.dev145
4
4
  Summary: Conversation Flow management for Pipecat AI applications
5
5
  License: BSD 2-Clause License
6
6
  Project-URL: Source, https://github.com/pipecat-ai/pipecat-flows
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "0.0.25",
3
+ "distance": 145,
4
+ "node": "g056447d2",
5
+ "dirty": false,
6
+ "branch": "dv-stage",
7
+ "node_date": "2026-10-08"
8
+ }
@@ -53,6 +53,9 @@ from utils.collect_prompts import collect_prompt
53
53
  from pipecat.frames.frames import (
54
54
  DTMFUpdateSettingsFrame,
55
55
  FunctionCallResultProperties,
56
+ InterruptionFrame,
57
+ LLMFullResponseEndFrame,
58
+ LLMFullResponseStartFrame,
56
59
  LLMMessagesAppendFrame,
57
60
  LLMMessagesUpdateFrame,
58
61
  LLMRunFrame,
@@ -265,6 +268,11 @@ def extract_conversation_messages(
265
268
  # drained the terminal frame. Coarse on purpose — nothing waits on it.
266
269
  _CALL_END_POLL_INTERVAL_S = 5.0
267
270
 
271
+ # How long a RESET_WITH_CONVERSATION carry waits for the reply in flight to be
272
+ # saved (see FlowManager._wait_for_reply_saved). In a chat session the end frame
273
+ # lands within milliseconds of the transition.
274
+ _REPLY_SAVE_TIMEOUT_S = 1.5
275
+
268
276
  # How long to let an utterance that straddled the wait ceiling finish
269
277
  # committing. The caller started speaking just before the ceiling fired, so STT
270
278
  # has a final in flight; deciding anything before it lands means classifying
@@ -453,6 +461,20 @@ class FlowManager:
453
461
  # Signature: is_injected(message) -> bool
454
462
  self.injected_message_filter: Optional[Callable[[Any], bool]] = None
455
463
 
464
+ # Chat sessions: before RESET_WITH_CONVERSATION carries the conversation into
465
+ # the next node, wait for the assistant aggregator to save the reply in flight,
466
+ # so text the LLM wrote alongside the transition is carried too (see
467
+ # `_wait_for_reply_saved`). Off by default: in a voice call the reply is saved
468
+ # only once it has been spoken, so waiting would hold the hop for the speech.
469
+ self.carry_waits_for_reply: bool = False
470
+ # Replies the assistant aggregator has started but not yet saved, counted from
471
+ # its own frame events (`_track_assistant_reply`); `_reply_saved` is set while
472
+ # there are none.
473
+ self._replies_in_flight = 0
474
+ self._reply_saved = asyncio.Event()
475
+ self._reply_saved.set()
476
+ self._watch_assistant_replies()
477
+
456
478
  # Wired in `initialize()` once the pipeline is up. Tracks the timestamp
457
479
  # of the latest UserStoppedSpeakingFrame so router-mode nodes can gate
458
480
  # their LLM classification on "user has actually replied" instead of
@@ -5078,6 +5100,54 @@ In all of these cases, you can provide a `name` in your new node's config for de
5078
5100
  resolved.append(message)
5079
5101
  return resolved
5080
5102
 
5103
+ def _watch_assistant_replies(self) -> None:
5104
+ """Follow the assistant aggregator's replies through its on_after_process_frame event."""
5105
+ assistant = self._context_aggregator.assistant() if self._context_aggregator else None
5106
+ add_event_handler = getattr(assistant, "add_event_handler", None)
5107
+ if add_event_handler is None:
5108
+ return
5109
+ try:
5110
+ add_event_handler("on_after_process_frame", self._track_assistant_reply)
5111
+ except Exception as exc: # never let reply tracking break flow setup
5112
+ logger.debug(f"Not tracking assistant replies: {exc}")
5113
+
5114
+ async def _track_assistant_reply(self, _aggregator: Any, frame: Any) -> None:
5115
+ """Count replies in flight. The aggregator saves a reply's text to the context
5116
+ while processing its LLMFullResponseEndFrame, so after that frame it is saved."""
5117
+ if isinstance(frame, LLMFullResponseStartFrame):
5118
+ self._replies_in_flight += 1
5119
+ self._reply_saved.clear()
5120
+ elif isinstance(frame, (LLMFullResponseEndFrame, InterruptionFrame)):
5121
+ if isinstance(frame, InterruptionFrame):
5122
+ self._replies_in_flight = 0
5123
+ else:
5124
+ self._replies_in_flight = max(0, self._replies_in_flight - 1)
5125
+ if not self._replies_in_flight:
5126
+ self._reply_saved.set()
5127
+
5128
+ async def _wait_for_reply_saved(self) -> None:
5129
+ """Wait, briefly, until the assistant aggregator has saved the reply in flight.
5130
+
5131
+ A transition fires on its function-call result, a SystemFrame that overtakes
5132
+ the reply's queued text and its LLMFullResponseEndFrame. The aggregator adds
5133
+ that text to the context only at the end frame, so a carry taken before it
5134
+ leaves out what the LLM wrote alongside the transition ("Plans that work well
5135
+ for NRIs -") and the LLMMessagesUpdateFrame then erases it from the live
5136
+ context: the customer saw it, the LLM never does, and the next node re-routes
5137
+ on a turn that was already answered (Policybazaar chat, Oct 2026).
5138
+
5139
+ Capped, so a lost end frame only delays the hop.
5140
+ """
5141
+ if self._reply_saved.is_set():
5142
+ return
5143
+ try:
5144
+ await asyncio.wait_for(self._reply_saved.wait(), timeout=_REPLY_SAVE_TIMEOUT_S)
5145
+ except asyncio.TimeoutError:
5146
+ logger.warning(
5147
+ f"Reply still in flight after {_REPLY_SAVE_TIMEOUT_S}s; carrying the "
5148
+ "conversation without it"
5149
+ )
5150
+
5081
5151
  async def _update_llm_context(
5082
5152
  self,
5083
5153
  role_messages: Optional[List[dict]],
@@ -5156,6 +5226,8 @@ In all of these cases, you can provide a `name` in your new node's config for de
5156
5226
  # prompt and tool-call/tool-result logs are dropped. Placed after
5157
5227
  # role_messages (the new system instruction) and before task
5158
5228
  # messages, mirroring the RESET_WITH_SUMMARY layout.
5229
+ if self.carry_waits_for_reply:
5230
+ await self._wait_for_reply_saved()
5159
5231
  carried = extract_conversation_messages(
5160
5232
  self._without_injected(
5161
5233
  self._context_aggregator.user()._context.get_messages()
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "0.0.25",
3
- "distance": 142,
4
- "node": "g5494275d",
5
- "dirty": false,
6
- "branch": "dv-stage",
7
- "node_date": "2026-10-07"
8
- }