dv-pipecat-flows 0.0.26.dev145__tar.gz → 0.0.26.dev158__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.dev145 → dv_pipecat_flows-0.0.26.dev158}/.gitignore +5 -0
  2. {dv_pipecat_flows-0.0.26.dev145/src/dv_pipecat_flows.egg-info → dv_pipecat_flows-0.0.26.dev158}/PKG-INFO +1 -1
  3. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158/src/dv_pipecat_flows.egg-info}/PKG-INFO +1 -1
  4. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/dv_pipecat_flows.egg-info/scm_file_list.json +5 -0
  5. dv_pipecat_flows-0.0.26.dev158/src/dv_pipecat_flows.egg-info/scm_version.json +8 -0
  6. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/pipecat_flows/adapters.py +70 -0
  7. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/pipecat_flows/manager.py +56 -0
  8. dv_pipecat_flows-0.0.26.dev145/src/dv_pipecat_flows.egg-info/scm_version.json +0 -8
  9. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/.agents/skills/pipecat-logs/SKILL.md +0 -0
  10. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/.agents/skills/pipecat-logs/query-reference.md +0 -0
  11. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/.claude/skills/pipecat-logs/SKILL.md +0 -0
  12. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/.claude/skills/pipecat-logs/query-reference.md +0 -0
  13. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/.gitattributes +0 -0
  14. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/.pre-commit-config.yaml +0 -0
  15. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/.python-version +0 -0
  16. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/.readthedocs.yaml +0 -0
  17. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/AGENTS.md +0 -0
  18. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/CHANGELOG.md +0 -0
  19. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/CLAUDE.md +0 -0
  20. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/CONTRIBUTING.md +0 -0
  21. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/LICENSE +0 -0
  22. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/MANIFEST.in +0 -0
  23. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/README.md +0 -0
  24. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/.env.example +0 -0
  25. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/.gitignore +0 -0
  26. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/README.md +0 -0
  27. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/docs/ARCHITECTURE.md +0 -0
  28. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/docs/CODE_MAP.md +0 -0
  29. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/docs/CONFIG.md +0 -0
  30. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/docs/CONTRACTS.md +0 -0
  31. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/docs/COPILOT_TODO.md +0 -0
  32. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/docs/DISTRIBUTION.md +0 -0
  33. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/docs/HLD.md +0 -0
  34. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/docs/METHODS.md +0 -0
  35. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/docs/VOICE_E2E.md +0 -0
  36. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/ANALYSIS_stagehand_vs_hybrid.md +0 -0
  37. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/RESULTS.md +0 -0
  38. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/_env.py +0 -0
  39. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/bench.py +0 -0
  40. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/bench_browseruse.py +0 -0
  41. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/bench_stagehand.py +0 -0
  42. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/inspect_browseruse.py +0 -0
  43. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/inspect_browseruse_showcase.py +0 -0
  44. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/inspect_stagehand_prompt.py +0 -0
  45. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/pages/checkout.html +0 -0
  46. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/pages/dashboard.html +0 -0
  47. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/pages/signup.html +0 -0
  48. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/results_browseruse.json +0 -0
  49. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/results_perception.json +0 -0
  50. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/results_stagehand.json +0 -0
  51. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/tasks.py +0 -0
  52. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/try_hybrid.py +0 -0
  53. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/try_hybrid_multistep.py +0 -0
  54. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/eval/try_hybrid_oneshot.py +0 -0
  55. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/pyproject.toml +0 -0
  56. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/scripts/dev-stack.sh +0 -0
  57. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/browser_copilot/uv.lock +0 -0
  58. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/dev-requirements.txt +0 -0
  59. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/docker-compose.dev.yml +0 -0
  60. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/.eslintrc.json +0 -0
  61. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/.prettierrc +0 -0
  62. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/css/tailwind.css +0 -0
  63. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/examples/food_ordering.json +0 -0
  64. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/examples/movie_explorer.json +0 -0
  65. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/examples/patient_intake.json +0 -0
  66. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/examples/restaurant_reservation.json +0 -0
  67. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/examples/travel_planner.json +0 -0
  68. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/favicon.png +0 -0
  69. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/favicon.svg +0 -0
  70. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/index.html +0 -0
  71. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/js/editor/canvas.js +0 -0
  72. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/js/editor/editorState.js +0 -0
  73. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/js/editor/sidePanel.js +0 -0
  74. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/js/editor/toolbar.js +0 -0
  75. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/js/main.js +0 -0
  76. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/js/nodes/baseNode.js +0 -0
  77. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/js/nodes/endNode.js +0 -0
  78. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/js/nodes/flowNode.js +0 -0
  79. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/js/nodes/functionNode.js +0 -0
  80. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/js/nodes/index.js +0 -0
  81. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/js/nodes/mergeNode.js +0 -0
  82. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/js/nodes/startNode.js +0 -0
  83. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/js/types.js +0 -0
  84. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/js/utils/export.js +0 -0
  85. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/js/utils/helpers.js +0 -0
  86. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/js/utils/import.js +0 -0
  87. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/js/utils/validation.js +0 -0
  88. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/jsdoc.json +0 -0
  89. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/package-lock.json +0 -0
  90. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/package.json +0 -0
  91. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/postcss.config.cjs +0 -0
  92. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/public/favicon.png +0 -0
  93. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/public/favicon.svg +0 -0
  94. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/tailwind.config.cjs +0 -0
  95. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/vercel.json +0 -0
  96. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/editor/vite.config.js +0 -0
  97. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/engine_primitives_plan.md +0 -0
  98. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/env.example +0 -0
  99. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/images/food-ordering-flow.png +0 -0
  100. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/pipecat-flows.png +0 -0
  101. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/pipecat_upgrade.md +0 -0
  102. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/pyproject.toml +0 -0
  103. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/remote-asterisk-code/README.md +0 -0
  104. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/remote-asterisk-code/extensions.conf +0 -0
  105. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/remote-asterisk-code/rtp.conf +0 -0
  106. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/requirements.txt +0 -0
  107. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/scripts/build_uae_pipecat_secret_blob.py +0 -0
  108. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/scripts/check-ar-package.py +0 -0
  109. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/scripts/fix-ruff.sh +0 -0
  110. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/scripts/pre-commit.sh +0 -0
  111. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/scripts/test_build_uae_pipecat_secret_blob.py +0 -0
  112. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/setup.cfg +0 -0
  113. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/dv_pipecat_flows.egg-info/SOURCES.txt +0 -0
  114. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/dv_pipecat_flows.egg-info/dependency_links.txt +0 -0
  115. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/dv_pipecat_flows.egg-info/requires.txt +0 -0
  116. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/dv_pipecat_flows.egg-info/top_level.txt +0 -0
  117. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/pipecat_flows/__init__.py +0 -0
  118. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/pipecat_flows/actions.py +0 -0
  119. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/pipecat_flows/condition_evaluator.py +0 -0
  120. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/pipecat_flows/exceptions.py +0 -0
  121. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/pipecat_flows/flow_validator.py +0 -0
  122. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/pipecat_flows/processors/__init__.py +0 -0
  123. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/pipecat_flows/processors/router_mode_guard.py +0 -0
  124. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/pipecat_flows/processors/speak_interruption_guard.py +0 -0
  125. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/pipecat_flows/processors/user_turn_observer.py +0 -0
  126. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/pipecat_flows/router_mode.py +0 -0
  127. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/src/pipecat_flows/types.py +0 -0
  128. {dv_pipecat_flows-0.0.26.dev145 → dv_pipecat_flows-0.0.26.dev158}/uv.lock +0 -0
@@ -187,3 +187,8 @@ MANIFEST
187
187
 
188
188
  # Asterisk configs
189
189
  remote-asterisk-code/pjsip.conf
190
+
191
+
192
+ # local files
193
+ scratch/
194
+ tmp/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dv-pipecat-flows
3
- Version: 0.0.26.dev145
3
+ Version: 0.0.26.dev158
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.dev145
3
+ Version: 0.0.26.dev158
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
@@ -385,6 +385,7 @@
385
385
  "ringg-bot/tests/conftest.py",
386
386
  "ringg-bot/tests/test_abandoned_call_report.py",
387
387
  "ringg-bot/tests/test_action_call_variables.py",
388
+ "ringg-bot/tests/test_anthropic_llm.py",
388
389
  "ringg-bot/tests/test_app_metrics.py",
389
390
  "ringg-bot/tests/test_arabic_amount.py",
390
391
  "ringg-bot/tests/test_artifact_store.py",
@@ -506,6 +507,7 @@
506
507
  "ringg-bot/tests/test_regional_vendor_endpoints.py",
507
508
  "ringg-bot/tests/test_regression_monitor_sync.py",
508
509
  "ringg-bot/tests/test_replay_kb_flag.py",
510
+ "ringg-bot/tests/test_replay_mock_websocket.py",
509
511
  "ringg-bot/tests/test_ringg_stt_mapping.py",
510
512
  "ringg-bot/tests/test_router_model_client.py",
511
513
  "ringg-bot/tests/test_router_shadow.py",
@@ -529,6 +531,7 @@
529
531
  "ringg-bot/tests/test_simulate_agent_config.py",
530
532
  "ringg-bot/tests/test_simulate_batch.py",
531
533
  "ringg-bot/tests/test_simulate_progress.py",
534
+ "ringg-bot/tests/test_simulation_action_widget_guard.py",
532
535
  "ringg-bot/tests/test_single_node_kb_id_resolution.py",
533
536
  "ringg-bot/tests/test_stall_watchdog.py",
534
537
  "ringg-bot/tests/test_status_router.py",
@@ -571,6 +574,7 @@
571
574
  "ringg-bot/transports/factory.py",
572
575
  "ringg-bot/utils/action_call_handler.py",
573
576
  "ringg-bot/utils/analyzer_pool.py",
577
+ "ringg-bot/utils/anthropic_llm.py",
574
578
  "ringg-bot/utils/api_calls.py",
575
579
  "ringg-bot/utils/app_metrics.py",
576
580
  "ringg-bot/utils/arabic_amount.py",
@@ -771,6 +775,7 @@
771
775
  "tests/__init__.py",
772
776
  "tests/test_actions.py",
773
777
  "tests/test_adapters.py",
778
+ "tests/test_anthropic_router_completion.py",
774
779
  "tests/test_capture_code_conversation_mimic.py",
775
780
  "tests/test_capture_code_handler.py",
776
781
  "tests/test_capture_code_processor.py",
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "0.0.25",
3
+ "distance": 158,
4
+ "node": "g36e5d45c",
5
+ "dirty": false,
6
+ "branch": "dv-stage",
7
+ "node_date": "2026-10-09"
8
+ }
@@ -18,6 +18,7 @@ The adapter system allows the flow manager to work with different LLM
18
18
  providers while maintaining a consistent internal format.
19
19
  """
20
20
 
21
+ import json
21
22
  import sys
22
23
  from typing import Any, Callable, Dict, List, Optional, Union
23
24
 
@@ -297,6 +298,69 @@ class LLMAdapter:
297
298
  raise NotImplementedError("Subclasses must implement this method")
298
299
 
299
300
 
301
+ def _text_of(content: Any) -> str:
302
+ if isinstance(content, list):
303
+ return "".join(p.get("text", "") if isinstance(p, dict) else str(p) for p in content)
304
+ return content if isinstance(content, str) else ""
305
+
306
+
307
+ async def anthropic_router_completion(
308
+ client: Any,
309
+ model_name: Optional[str],
310
+ system_prompt: str,
311
+ response_schema: Dict[str, Any],
312
+ context_messages: List[Dict[str, Any]],
313
+ schema_name: str = "router_decision",
314
+ ) -> Optional[str]:
315
+ """Claude router decision: one forced tool call whose input is the routing JSON.
316
+
317
+ The recent turns are sent as alternating user / assistant text (tool traffic and
318
+ system messages dropped), starting and ending on a user turn as the Messages API
319
+ requires. Thinking is turned off explicitly: Anthropic rejects a forced tool choice
320
+ while thinking is on, and Claude 5.x models think unless told not to.
321
+
322
+ Returns the tool input as a JSON string, or None on failure.
323
+ """
324
+ turns: List[Dict[str, str]] = []
325
+ for msg in context_messages or []:
326
+ role = msg.get("role")
327
+ text = _text_of(msg.get("content")).strip()
328
+ if role not in ("user", "assistant") or not text:
329
+ continue
330
+ if turns and turns[-1]["role"] == role:
331
+ turns[-1]["content"] += "\n\n" + text
332
+ else:
333
+ turns.append({"role": role, "content": text})
334
+ if not turns or turns[0]["role"] != "user":
335
+ turns.insert(0, {"role": "user", "content": "(start of conversation)"})
336
+ if turns[-1]["role"] != "user":
337
+ turns.append({"role": "user", "content": "Pick the branch for the conversation above."})
338
+ try:
339
+ response = await client.messages.create(
340
+ model=model_name,
341
+ max_tokens=1024,
342
+ system=system_prompt,
343
+ messages=turns,
344
+ tools=[
345
+ {
346
+ "name": schema_name,
347
+ "description": "Record the routing decision.",
348
+ "input_schema": response_schema,
349
+ }
350
+ ],
351
+ tool_choice={"type": "tool", "name": schema_name},
352
+ extra_body={"thinking": {"type": "disabled"}},
353
+ )
354
+ except Exception as exc: # noqa: BLE001
355
+ logger.error(f"Anthropic router completion failed: {exc!r}")
356
+ return None
357
+ for block in response.content:
358
+ if getattr(block, "type", "") == "tool_use":
359
+ return json.dumps(block.input)
360
+ logger.warning("Anthropic router completion returned no tool call")
361
+ return None
362
+
363
+
300
364
  class UniversalLLMAdapter(LLMAdapter):
301
365
  """Format adapter when universal LLMContext is in use.
302
366
 
@@ -429,6 +493,12 @@ class UniversalLLMAdapter(LLMAdapter):
429
493
  )
430
494
  return None
431
495
 
496
+ if hasattr(client, "messages") and hasattr(client.messages, "create"):
497
+ # Anthropic client (Claude on the Anthropic API or Bedrock).
498
+ return await anthropic_router_completion(
499
+ client, model_name, system_prompt, response_schema, context_messages, schema_name
500
+ )
501
+
432
502
  logger.warning(
433
503
  f"Universal router completion: llm_service "
434
504
  f"{type(llm_service).__name__} exposes neither responses nor "
@@ -180,6 +180,50 @@ def _paired_transition_call_ids(
180
180
  return call_ids & result_ids
181
181
 
182
182
 
183
+ # Appended after the carried conversation when the node prompt is folded into the
184
+ # system prompt, so the context still ends on a customer-side turn. Without it Claude
185
+ # sees the bot's own last message as the end of the conversation and replies with
186
+ # nothing after a node change (measured on the PB chatbot replay, 9 Oct 2026).
187
+ CONTINUE_NUDGE = (
188
+ "Continue the conversation: act on the customer's latest message using the "
189
+ "instructions in the system prompt above. Do not reply to this note or mention it."
190
+ )
191
+
192
+
193
+ def _system_text(content: Any) -> str:
194
+ if isinstance(content, str):
195
+ return content
196
+ if isinstance(content, list):
197
+ return "\n".join(
198
+ part.get("text", "") for part in content if isinstance(part, dict) and part.get("text")
199
+ )
200
+ return ""
201
+
202
+
203
+ def fold_system_messages(messages: List[dict]) -> List[dict]:
204
+ """Put every system message into one leading system message for Claude.
205
+
206
+ The conversation keeps its order after it, and a system-role nudge closes the
207
+ context: the adapters turn that into a user message (merged into the customer's
208
+ turn when it is last), so the request ends on the customer's side. The nudge is
209
+ a system message so that the next RESET_WITH_CONVERSATION drops it instead of
210
+ carrying it as something the customer said. A context with no conversation is
211
+ left as one system message, as before.
212
+ """
213
+ system_parts = [
214
+ text
215
+ for m in messages
216
+ if m.get("role") == "system" and (text := _system_text(m.get("content")))
217
+ ]
218
+ if not system_parts:
219
+ return messages
220
+ rest = [m for m in messages if m.get("role") != "system"]
221
+ folded = [{"role": "system", "content": "\n\n".join(system_parts)}, *rest]
222
+ if rest:
223
+ folded.append({"role": "system", "content": CONTINUE_NUDGE})
224
+ return folded
225
+
226
+
183
227
  def extract_conversation_messages(
184
228
  messages: List[dict], transition_names: Optional[Set[str]] = None
185
229
  ) -> List[dict]:
@@ -467,6 +511,15 @@ class FlowManager:
467
511
  # `_wait_for_reply_saved`). Off by default: in a voice call the reply is saved
468
512
  # only once it has been spoken, so waiting would hold the hop for the speech.
469
513
  self.carry_waits_for_reply: bool = False
514
+ # Claude (Anthropic API / Bedrock): both take one system prompt at the top, and
515
+ # their adapters turn every later system message into a user message merged
516
+ # with the customer's last turn. A node's task prompt placed after the carried
517
+ # conversation then reads to Claude as something the customer said, and Claude
518
+ # answers the instructions instead of the customer. When set, a context replace
519
+ # folds every system message into one leading system message and ends on a
520
+ # short nudge (see `fold_system_messages`). Off by default: GPT reads a trailing
521
+ # system message as an instruction, which is why the task prompt sits there.
522
+ self.fold_task_into_system: bool = False
470
523
  # Replies the assistant aggregator has started but not yet saved, counted from
471
524
  # its own frame events (`_track_assistant_reply`); `_reply_saved` is set while
472
525
  # there are none.
@@ -5263,6 +5316,9 @@ In all of these cases, you can provide a `name` in your new node's config for de
5263
5316
  except Exception as exc: # never let a provider break a transition
5264
5317
  logger.warning(f"sticky_context_provider failed: {exc}")
5265
5318
 
5319
+ if is_replace and self.fold_task_into_system:
5320
+ messages = fold_system_messages(messages)
5321
+
5266
5322
  frame_type = LLMMessagesUpdateFrame if is_replace else LLMMessagesAppendFrame
5267
5323
 
5268
5324
  await self._task.queue_frames(
@@ -1,8 +0,0 @@
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
- }