dv-pipecat-flows 0.0.22.dev1487__tar.gz → 0.0.22.dev1489__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 (89) hide show
  1. {dv_pipecat_flows-0.0.22.dev1487/src/dv_pipecat_flows.egg-info → dv_pipecat_flows-0.0.22.dev1489}/PKG-INFO +1 -1
  2. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489/src/dv_pipecat_flows.egg-info}/PKG-INFO +1 -1
  3. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/src/pipecat_flows/manager.py +43 -28
  4. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/.agents/skills/loki-logs/SKILL.md +0 -0
  5. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/.agents/skills/loki-logs/query-reference.md +0 -0
  6. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/.claude/skills/loki-logs/SKILL.md +0 -0
  7. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/.claude/skills/loki-logs/query-reference.md +0 -0
  8. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/.gitattributes +0 -0
  9. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/.gitignore +0 -0
  10. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/.pre-commit-config.yaml +0 -0
  11. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/.python-version +0 -0
  12. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/.readthedocs.yaml +0 -0
  13. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/AGENTS.md +0 -0
  14. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/CHANGELOG.md +0 -0
  15. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/CLAUDE.md +0 -0
  16. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/CONTRIBUTING.md +0 -0
  17. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/LICENSE +0 -0
  18. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/MANIFEST.in +0 -0
  19. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/README.md +0 -0
  20. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/dev-requirements.txt +0 -0
  21. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/docker-compose.dev.yml +0 -0
  22. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/.eslintrc.json +0 -0
  23. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/.prettierrc +0 -0
  24. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/css/tailwind.css +0 -0
  25. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/examples/food_ordering.json +0 -0
  26. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/examples/movie_explorer.json +0 -0
  27. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/examples/patient_intake.json +0 -0
  28. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/examples/restaurant_reservation.json +0 -0
  29. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/examples/travel_planner.json +0 -0
  30. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/favicon.png +0 -0
  31. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/favicon.svg +0 -0
  32. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/index.html +0 -0
  33. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/js/editor/canvas.js +0 -0
  34. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/js/editor/editorState.js +0 -0
  35. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/js/editor/sidePanel.js +0 -0
  36. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/js/editor/toolbar.js +0 -0
  37. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/js/main.js +0 -0
  38. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/js/nodes/baseNode.js +0 -0
  39. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/js/nodes/endNode.js +0 -0
  40. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/js/nodes/flowNode.js +0 -0
  41. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/js/nodes/functionNode.js +0 -0
  42. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/js/nodes/index.js +0 -0
  43. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/js/nodes/mergeNode.js +0 -0
  44. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/js/nodes/startNode.js +0 -0
  45. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/js/types.js +0 -0
  46. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/js/utils/export.js +0 -0
  47. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/js/utils/helpers.js +0 -0
  48. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/js/utils/import.js +0 -0
  49. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/js/utils/validation.js +0 -0
  50. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/jsdoc.json +0 -0
  51. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/package-lock.json +0 -0
  52. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/package.json +0 -0
  53. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/postcss.config.cjs +0 -0
  54. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/public/favicon.png +0 -0
  55. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/public/favicon.svg +0 -0
  56. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/tailwind.config.cjs +0 -0
  57. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/vercel.json +0 -0
  58. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/editor/vite.config.js +0 -0
  59. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/engine_primitives_plan.md +0 -0
  60. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/env.example +0 -0
  61. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/images/food-ordering-flow.png +0 -0
  62. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/pipecat-flows.png +0 -0
  63. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/pipecat_upgrade.md +0 -0
  64. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/pyproject.toml +0 -0
  65. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/remote-asterisk-code/README.md +0 -0
  66. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/remote-asterisk-code/extensions.conf +0 -0
  67. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/remote-asterisk-code/rtp.conf +0 -0
  68. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/requirements.txt +0 -0
  69. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/scripts/check-pypi-package.py +0 -0
  70. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/scripts/fix-ruff.sh +0 -0
  71. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/scripts/pre-commit.sh +0 -0
  72. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/setup.cfg +0 -0
  73. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/src/dv_pipecat_flows.egg-info/SOURCES.txt +0 -0
  74. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/src/dv_pipecat_flows.egg-info/dependency_links.txt +0 -0
  75. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/src/dv_pipecat_flows.egg-info/requires.txt +0 -0
  76. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/src/dv_pipecat_flows.egg-info/top_level.txt +0 -0
  77. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/src/pipecat_flows/__init__.py +0 -0
  78. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/src/pipecat_flows/actions.py +0 -0
  79. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/src/pipecat_flows/adapters.py +0 -0
  80. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/src/pipecat_flows/condition_evaluator.py +0 -0
  81. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/src/pipecat_flows/exceptions.py +0 -0
  82. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/src/pipecat_flows/flow_validator.py +0 -0
  83. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/src/pipecat_flows/processors/__init__.py +0 -0
  84. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/src/pipecat_flows/processors/router_mode_guard.py +0 -0
  85. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/src/pipecat_flows/processors/speak_interruption_guard.py +0 -0
  86. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/src/pipecat_flows/processors/user_turn_observer.py +0 -0
  87. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/src/pipecat_flows/router_mode.py +0 -0
  88. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/src/pipecat_flows/types.py +0 -0
  89. {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1489}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dv-pipecat-flows
3
- Version: 0.0.22.dev1487
3
+ Version: 0.0.22.dev1489
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.22.dev1487
3
+ Version: 0.0.22.dev1489
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
@@ -2580,20 +2580,16 @@ In all of these cases, you can provide a `name` in your new node's config for de
2580
2580
  # ignore the rejected attempt's turns.
2581
2581
  start_ts = time.monotonic()
2582
2582
  buffer = ""
2583
+ echoed = "" # bare digits already spoken back, so we echo only the NEW ones
2583
2584
  misses = 0
2584
2585
  corrections = 0 # confirm "no" rounds, bounded so a correction can't loop
2585
2586
  deadline = time.monotonic() + self._MAX_CAPTURE_SECONDS
2586
2587
 
2587
2588
  async def _nudge(language: str) -> None:
2588
- """Re-ask: echo a partial and ask for the rest, else the author reask."""
2589
- if buffer:
2590
- remaining = max(0, target - len(buffer))
2591
- unit = collect_prompt(language, "unit_one" if remaining == 1 else "unit_many")
2592
- await self._task.queue_frame(TTSSpeakFrame(text=collect_prompt(
2593
- language, "continue_partial", readback=" ".join(buffer),
2594
- remaining=remaining, unit=unit,
2595
- )))
2596
- elif reask:
2589
+ """Re-prompt ONLY when we have nothing yet (the author's reask). Holding a
2590
+ partial → stay silent: the progress echo already spoke the digits, so
2591
+ re-speaking them just sounds like a repeat (and talks over the caller)."""
2592
+ if not buffer and reask:
2597
2593
  await self._task.queue_frame(TTSSpeakFrame(text=reask))
2598
2594
 
2599
2595
  while misses < max_attempts:
@@ -2601,7 +2597,7 @@ In all of these cases, you can provide a `name` in your new node's config for de
2601
2597
  # Longer window to START dictating; 7s once we hold a partial. Patient
2602
2598
  # while the caller is mid-utterance, so a timeout can't clip them.
2603
2599
  got_turn = await self._wait_for_caller_input(
2604
- 5.0 if buffer else 15.0, deadline, allow_keypad, keypad_dtmf
2600
+ 7.0 if buffer else 15.0, deadline, allow_keypad, keypad_dtmf
2605
2601
  )
2606
2602
  if not got_turn:
2607
2603
  if time.monotonic() >= deadline:
@@ -2661,6 +2657,7 @@ In all of these cases, you can provide a `name` in your new node's config for de
2661
2657
  # Enough digits but not a valid number → reset and re-ask.
2662
2658
  start_ts = time.monotonic()
2663
2659
  buffer = ""
2660
+ echoed = ""
2664
2661
  misses += 1
2665
2662
  if misses < max_attempts:
2666
2663
  await self._task.queue_frame(
@@ -2668,17 +2665,28 @@ In all of these cases, you can provide a `name` in your new node's config for de
2668
2665
  )
2669
2666
  continue
2670
2667
 
2671
- if len(buffer) == len(previous):
2672
- # A turn arrived but added no new digits (filler / mis-hear) →
2673
- # re-ask and count a miss so garbage can't loop forever.
2668
+ if buffer == previous:
2669
+ # A turn arrived but the number is UNCHANGED (filler / mis-hear) →
2670
+ # re-ask and count a miss so garbage can't loop forever. Compare by
2671
+ # VALUE, not length: a same-length correction during the echo phase
2672
+ # ("no, the 3rd is 5": 7765 → 7755) changes the value but not the
2673
+ # length, so a length check would mis-read the fix as "no progress"
2674
+ # and burn a miss instead of echoing the correction below.
2674
2675
  misses += 1
2675
2676
  if misses < max_attempts:
2676
2677
  await _nudge(language)
2677
2678
  continue
2678
2679
 
2679
- # Buffer GREW (progress) reset the give-up counter so a caller who
2680
- # keeps adding digits (even slowly, pausing to think) is never cut
2681
- # off; only a genuine stall trips the bound. Keep listening silently.
2680
+ # Buffer CHANGED (progress new digits OR a correction) echo it back
2681
+ # (bare, in the caller's language) so they hear we caught the change, and
2682
+ # reset the give-up counter. A clean append echoes only the NEW digits; a
2683
+ # correction (not a prefix of what we echoed) re-echoes the full number.
2684
+ delta = buffer[len(echoed):] if buffer.startswith(echoed) else buffer
2685
+ if delta:
2686
+ await self._task.queue_frame(TTSSpeakFrame(
2687
+ text=collect_prompt(language, "echo", digits=" ".join(delta))
2688
+ ))
2689
+ echoed = buffer
2682
2690
  misses = 0
2683
2691
 
2684
2692
  logger.info(f"Collect '{node_id}': gave up after {misses} misses (buffer='{buffer}')")
@@ -2707,6 +2715,7 @@ In all of these cases, you can provide a `name` in your new node's config for de
2707
2715
  target = int(num_digits) if num_digits else 6
2708
2716
  start_ts = time.monotonic()
2709
2717
  buffer = ""
2718
+ echoed = "" # bare digits already spoken back, so we echo only the NEW ones
2710
2719
  misses = 0
2711
2720
  corrections = 0 # confirm "no" rounds, bounded so a correction can't loop
2712
2721
  deadline = time.monotonic() + self._MAX_CAPTURE_SECONDS
@@ -2714,20 +2723,15 @@ In all of these cases, you can provide a `name` in your new node's config for de
2714
2723
  code_dtmf = {**(keypad_dtmf or {}), "digits": target}
2715
2724
 
2716
2725
  async def _nudge(language: str) -> None:
2717
- if buffer:
2718
- remaining = max(0, target - len(buffer))
2719
- unit = collect_prompt(language, "unit_one" if remaining == 1 else "unit_many")
2720
- await self._task.queue_frame(TTSSpeakFrame(text=collect_prompt(
2721
- language, "continue_partial", readback=" ".join(buffer),
2722
- remaining=remaining, unit=unit,
2723
- )))
2724
- elif reask:
2726
+ """Re-prompt ONLY when we have nothing yet (the author's reask); holding a
2727
+ partial stay silent (the progress echo already spoke the digits)."""
2728
+ if not buffer and reask:
2725
2729
  await self._task.queue_frame(TTSSpeakFrame(text=reask))
2726
2730
 
2727
2731
  while misses < max_attempts:
2728
2732
  language = self._active_language()
2729
2733
  got_turn = await self._wait_for_caller_input(
2730
- 5.0 if buffer else 15.0, deadline, allow_keypad, code_dtmf
2734
+ 7.0 if buffer else 15.0, deadline, allow_keypad, code_dtmf
2731
2735
  )
2732
2736
  if not got_turn:
2733
2737
  if time.monotonic() >= deadline:
@@ -2780,6 +2784,7 @@ In all of these cases, you can provide a `name` in your new node's config for de
2780
2784
  # Too many digits for this code → reset and re-ask.
2781
2785
  start_ts = time.monotonic()
2782
2786
  buffer = ""
2787
+ echoed = ""
2783
2788
  misses += 1
2784
2789
  if misses < max_attempts:
2785
2790
  await self._task.queue_frame(
@@ -2787,14 +2792,24 @@ In all of these cases, you can provide a `name` in your new node's config for de
2787
2792
  )
2788
2793
  continue
2789
2794
 
2790
- if len(buffer) == len(previous):
2791
- # A turn arrived but added no new digits → re-ask, count a miss.
2795
+ if buffer == previous:
2796
+ # Unchanged (filler / mis-hear) → re-ask, count a miss. Compare by
2797
+ # VALUE not length so a same-length correction during the echo phase
2798
+ # counts as progress (echoed below) instead of burning a miss.
2792
2799
  misses += 1
2793
2800
  if misses < max_attempts:
2794
2801
  await _nudge(language)
2795
2802
  continue
2796
2803
 
2797
- # Buffer GREW (progress) → reset the give-up counter; keep listening.
2804
+ # Buffer CHANGED (new digits OR a correction) → echo it back, bare, and
2805
+ # reset the give-up counter. Append → only the new digits; a correction →
2806
+ # the full code re-echoed.
2807
+ delta = buffer[len(echoed):] if buffer.startswith(echoed) else buffer
2808
+ if delta:
2809
+ await self._task.queue_frame(TTSSpeakFrame(
2810
+ text=collect_prompt(language, "echo", digits=" ".join(delta))
2811
+ ))
2812
+ echoed = buffer
2798
2813
  misses = 0
2799
2814
 
2800
2815
  logger.info(f"Collect '{node_id}': code give-up after {misses} misses (buffer='{buffer}')")