dv-pipecat-flows 0.0.22.dev2300__tar.gz → 0.0.22.dev2500__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.
- {dv_pipecat_flows-0.0.22.dev2300/src/dv_pipecat_flows.egg-info → dv_pipecat_flows-0.0.22.dev2500}/PKG-INFO +1 -1
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500/src/dv_pipecat_flows.egg-info}/PKG-INFO +1 -1
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/pipecat_flows/manager.py +85 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/pipecat_flows/types.py +10 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/uv.lock +1185 -109
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/.agents/skills/loki-logs/SKILL.md +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/.agents/skills/loki-logs/query-reference.md +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/.claude/skills/loki-logs/SKILL.md +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/.claude/skills/loki-logs/query-reference.md +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/.gitattributes +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/.gitignore +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/.pre-commit-config.yaml +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/.python-version +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/.readthedocs.yaml +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/AGENTS.md +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/CHANGELOG.md +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/CLAUDE.md +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/CONTRIBUTING.md +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/LICENSE +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/MANIFEST.in +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/README.md +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/dev-requirements.txt +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/docker-compose.dev.yml +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/.eslintrc.json +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/.prettierrc +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/css/tailwind.css +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/examples/food_ordering.json +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/examples/movie_explorer.json +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/examples/patient_intake.json +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/examples/restaurant_reservation.json +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/examples/travel_planner.json +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/favicon.png +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/favicon.svg +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/index.html +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/js/editor/canvas.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/js/editor/editorState.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/js/editor/sidePanel.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/js/editor/toolbar.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/js/main.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/js/nodes/baseNode.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/js/nodes/endNode.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/js/nodes/flowNode.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/js/nodes/functionNode.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/js/nodes/index.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/js/nodes/mergeNode.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/js/nodes/startNode.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/js/types.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/js/utils/export.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/js/utils/helpers.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/js/utils/import.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/js/utils/validation.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/jsdoc.json +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/package-lock.json +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/package.json +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/postcss.config.cjs +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/public/favicon.png +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/public/favicon.svg +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/tailwind.config.cjs +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/vercel.json +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/editor/vite.config.js +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/engine_primitives_plan.md +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/env.example +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/images/food-ordering-flow.png +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/pipecat-flows.png +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/pipecat_upgrade.md +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/pyproject.toml +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/remote-asterisk-code/README.md +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/remote-asterisk-code/extensions.conf +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/remote-asterisk-code/rtp.conf +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/requirements.txt +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/scripts/check-pypi-package.py +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/scripts/fix-ruff.sh +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/scripts/pre-commit.sh +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/setup.cfg +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/dv_pipecat_flows.egg-info/SOURCES.txt +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/dv_pipecat_flows.egg-info/dependency_links.txt +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/dv_pipecat_flows.egg-info/requires.txt +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/dv_pipecat_flows.egg-info/top_level.txt +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/pipecat_flows/__init__.py +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/pipecat_flows/actions.py +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/pipecat_flows/adapters.py +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/pipecat_flows/condition_evaluator.py +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/pipecat_flows/exceptions.py +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/pipecat_flows/flow_validator.py +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/pipecat_flows/processors/__init__.py +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/pipecat_flows/processors/router_mode_guard.py +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/pipecat_flows/processors/speak_interruption_guard.py +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/pipecat_flows/processors/user_turn_observer.py +0 -0
- {dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/pipecat_flows/router_mode.py +0 -0
{dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/pipecat_flows/manager.py
RENAMED
|
@@ -623,6 +623,7 @@ class FlowManager:
|
|
|
623
623
|
transition_to: Optional[str],
|
|
624
624
|
transition_callback: Optional[Callable] = None,
|
|
625
625
|
state_update_keys: Optional[List[str]] = None,
|
|
626
|
+
router_node_meta: Optional[Dict[str, Any]] = None,
|
|
626
627
|
) -> Callable:
|
|
627
628
|
"""Create a transition function for the given name and handler.
|
|
628
629
|
|
|
@@ -668,6 +669,7 @@ class FlowManager:
|
|
|
668
669
|
# ``_set_node`` after the transition. Mirrors the
|
|
669
670
|
# ``state.update(extracted)`` that ``_run_router_node`` does
|
|
670
671
|
# on the non-flattened path.
|
|
672
|
+
extract_update: Dict[str, Any] = {}
|
|
671
673
|
if state_update_keys and params.arguments:
|
|
672
674
|
extract_update = {
|
|
673
675
|
key: params.arguments[key]
|
|
@@ -681,6 +683,53 @@ class FlowManager:
|
|
|
681
683
|
f"{list(extract_update.keys())} function={name}"
|
|
682
684
|
)
|
|
683
685
|
|
|
686
|
+
# Flattened-router observability: when this function bypasses
|
|
687
|
+
# an llm_router (router_node_meta set by backend wiring), the
|
|
688
|
+
# router was never ``_set_node``'d, so its on_node_entered +
|
|
689
|
+
# on_variables_extracted events never fired naturally. Emit
|
|
690
|
+
# them synthetically here so the FE canvas highlights the
|
|
691
|
+
# bypassed router and displays the extracted variables (e.g.
|
|
692
|
+
# ``state["language"]``) — same visual continuity as the
|
|
693
|
+
# non-flattened classifier path. Gated by the same
|
|
694
|
+
# ``state["observable"]`` flag as the natural fires, so prod
|
|
695
|
+
# calls (no SSE subscriber) skip the publish overhead.
|
|
696
|
+
if router_node_meta and self.state.get("observable"):
|
|
697
|
+
_router_id = router_node_meta.get("id") or router_node_meta.get("name")
|
|
698
|
+
_router_label = router_node_meta.get("name") or _router_id
|
|
699
|
+
_router_kind = router_node_meta.get("kind") or "router_node"
|
|
700
|
+
if self.on_node_entered and _router_id:
|
|
701
|
+
_prev_node_id = self._current_node
|
|
702
|
+
_prev_cfg = (
|
|
703
|
+
self._nodes.get(_prev_node_id) if _prev_node_id else None
|
|
704
|
+
)
|
|
705
|
+
_from_label = (_prev_cfg or {}).get("name") if _prev_cfg else None
|
|
706
|
+
self._fire_and_forget_observe(
|
|
707
|
+
self.on_node_entered(
|
|
708
|
+
{
|
|
709
|
+
"from_node_id": _prev_node_id,
|
|
710
|
+
"from_label": _from_label,
|
|
711
|
+
"node_id": _router_id,
|
|
712
|
+
"label": _router_label,
|
|
713
|
+
"kind": _router_kind,
|
|
714
|
+
"synthetic": "flattened_router",
|
|
715
|
+
"ts": time.time(),
|
|
716
|
+
}
|
|
717
|
+
),
|
|
718
|
+
label=f"flattened_router_entered:{_router_id}",
|
|
719
|
+
)
|
|
720
|
+
if self.on_variables_extracted and extract_update and _router_id:
|
|
721
|
+
self._fire_and_forget_observe(
|
|
722
|
+
self.on_variables_extracted(
|
|
723
|
+
{
|
|
724
|
+
"node_id": _router_id,
|
|
725
|
+
"variables": dict(extract_update),
|
|
726
|
+
"source": "flattened_router",
|
|
727
|
+
"ts": time.time(),
|
|
728
|
+
}
|
|
729
|
+
),
|
|
730
|
+
label=f"flattened_router_variables_extracted:{_router_id}",
|
|
731
|
+
)
|
|
732
|
+
|
|
684
733
|
function_call_id = await start_tracking(
|
|
685
734
|
transcript_handler=self._transcript_handler,
|
|
686
735
|
tool_name=name,
|
|
@@ -931,6 +980,7 @@ class FlowManager:
|
|
|
931
980
|
transition_to: Optional[str] = None,
|
|
932
981
|
transition_callback: Optional[Callable] = None,
|
|
933
982
|
state_update_keys: Optional[List[str]] = None,
|
|
983
|
+
router_node_meta: Optional[Dict[str, Any]] = None,
|
|
934
984
|
) -> None:
|
|
935
985
|
"""Register a function with the LLM if not already registered.
|
|
936
986
|
|
|
@@ -959,6 +1009,7 @@ class FlowManager:
|
|
|
959
1009
|
transition_to,
|
|
960
1010
|
transition_callback,
|
|
961
1011
|
state_update_keys=state_update_keys,
|
|
1012
|
+
router_node_meta=router_node_meta,
|
|
962
1013
|
)
|
|
963
1014
|
|
|
964
1015
|
# Register function with LLM (or LLMSwitcher).
|
|
@@ -2535,6 +2586,39 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2535
2586
|
await self._short_circuit_to(pure_code_target)
|
|
2536
2587
|
return
|
|
2537
2588
|
|
|
2589
|
+
# ``pure_code_target is None`` for a node that SHOULD be
|
|
2590
|
+
# pure-code-dispatched is an author-config failure: condition
|
|
2591
|
+
# router with no matching rule + no ``router_default_next``
|
|
2592
|
+
# (or default points at a deleted node and the backend's
|
|
2593
|
+
# ``_resolve_node_ref`` returned None), or an action node
|
|
2594
|
+
# with success/failure both pointing at deleted targets.
|
|
2595
|
+
# Falling through to LLM dispatch below makes no sense — these
|
|
2596
|
+
# nodes have ``task_messages: []`` (no LLM context), so the
|
|
2597
|
+
# bot just sits silent until ``user_idle_processor`` fires
|
|
2598
|
+
# the generic "Sorry, could you please repeat that?" prompt.
|
|
2599
|
+
# End the call gracefully with a logged error so the misconfig
|
|
2600
|
+
# is visible instead of silently degrading.
|
|
2601
|
+
auto_transition = node_config.get("auto_transition")
|
|
2602
|
+
if auto_transition == "__condition__" or isinstance(auto_transition, dict):
|
|
2603
|
+
self._current_node = node_id
|
|
2604
|
+
logger.error(
|
|
2605
|
+
f"Pure-code dispatch on '{node_id}' resolved no target "
|
|
2606
|
+
f"(auto_transition={auto_transition!r}). Ending the call "
|
|
2607
|
+
f"gracefully — this is an author-config error: a condition "
|
|
2608
|
+
f"router with no matching rule + no valid router_default_next, "
|
|
2609
|
+
f"OR an action node whose success/failure targets were deleted."
|
|
2610
|
+
)
|
|
2611
|
+
try:
|
|
2612
|
+
await self._action_manager.execute_actions(
|
|
2613
|
+
[{"type": "end_conversation"}]
|
|
2614
|
+
)
|
|
2615
|
+
except Exception as end_exc:
|
|
2616
|
+
logger.warning(
|
|
2617
|
+
f"end_conversation action failed during graceful-end on "
|
|
2618
|
+
f"'{node_id}': {end_exc!r}"
|
|
2619
|
+
)
|
|
2620
|
+
return
|
|
2621
|
+
|
|
2538
2622
|
# Router-mode LLM short-circuit: if this node uses constrained
|
|
2539
2623
|
# JSON output (llm_mode="router"), run the small classification
|
|
2540
2624
|
# call, parse the response, recurse into the chosen branch.
|
|
@@ -2611,6 +2695,7 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2611
2695
|
transition_to=schema.transition_to,
|
|
2612
2696
|
transition_callback=schema.transition_callback,
|
|
2613
2697
|
state_update_keys=schema.state_update_keys,
|
|
2698
|
+
router_node_meta=schema.router_node_meta,
|
|
2614
2699
|
)
|
|
2615
2700
|
|
|
2616
2701
|
async def register_direct_function(func):
|
{dv_pipecat_flows-0.0.22.dev2300 → dv_pipecat_flows-0.0.22.dev2500}/src/pipecat_flows/types.py
RENAMED
|
@@ -279,6 +279,16 @@ class FlowsFunctionSchema:
|
|
|
279
279
|
# transitions and still propagate the router's ``router_extract``
|
|
280
280
|
# variables (e.g. ``language``) into state. Empty/None = no-op.
|
|
281
281
|
state_update_keys: Optional[List[str]] = None
|
|
282
|
+
# Identity of the LLM-router this function bypassed in the flatten path
|
|
283
|
+
# (``agent_node → llm_router``). When set, the engine emits a synthetic
|
|
284
|
+
# ``on_node_entered`` for the router and an ``on_variables_extracted``
|
|
285
|
+
# for the LLM's args at function-call time — so the FE canvas still
|
|
286
|
+
# highlights the bypassed router AND displays the extracted variables
|
|
287
|
+
# (e.g. "language") even though the router's classifier turn never ran.
|
|
288
|
+
# Shape: ``{"id": <node_uuid>, "name": <node_name>, "kind": "router_node"}``
|
|
289
|
+
# None means this function is a direct agent→non-router transition;
|
|
290
|
+
# no synthetic events fire.
|
|
291
|
+
router_node_meta: Optional[Dict[str, Any]] = None
|
|
282
292
|
|
|
283
293
|
def __post_init__(self):
|
|
284
294
|
"""Validate the schema configuration.
|