dv-pipecat-flows 0.0.22.dev2200__tar.gz → 0.0.22.dev2400__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.dev2200/src/dv_pipecat_flows.egg-info → dv_pipecat_flows-0.0.22.dev2400}/PKG-INFO +1 -1
  2. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400/src/dv_pipecat_flows.egg-info}/PKG-INFO +1 -1
  3. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/src/pipecat_flows/actions.py +53 -0
  4. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/src/pipecat_flows/manager.py +52 -0
  5. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/src/pipecat_flows/types.py +10 -0
  6. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/.agents/skills/loki-logs/SKILL.md +0 -0
  7. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/.agents/skills/loki-logs/query-reference.md +0 -0
  8. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/.claude/skills/loki-logs/SKILL.md +0 -0
  9. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/.claude/skills/loki-logs/query-reference.md +0 -0
  10. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/.gitattributes +0 -0
  11. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/.gitignore +0 -0
  12. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/.pre-commit-config.yaml +0 -0
  13. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/.python-version +0 -0
  14. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/.readthedocs.yaml +0 -0
  15. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/AGENTS.md +0 -0
  16. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/CHANGELOG.md +0 -0
  17. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/CLAUDE.md +0 -0
  18. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/CONTRIBUTING.md +0 -0
  19. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/LICENSE +0 -0
  20. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/MANIFEST.in +0 -0
  21. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/README.md +0 -0
  22. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/dev-requirements.txt +0 -0
  23. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/docker-compose.dev.yml +0 -0
  24. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/.eslintrc.json +0 -0
  25. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/.prettierrc +0 -0
  26. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/css/tailwind.css +0 -0
  27. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/examples/food_ordering.json +0 -0
  28. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/examples/movie_explorer.json +0 -0
  29. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/examples/patient_intake.json +0 -0
  30. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/examples/restaurant_reservation.json +0 -0
  31. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/examples/travel_planner.json +0 -0
  32. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/favicon.png +0 -0
  33. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/favicon.svg +0 -0
  34. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/index.html +0 -0
  35. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/js/editor/canvas.js +0 -0
  36. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/js/editor/editorState.js +0 -0
  37. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/js/editor/sidePanel.js +0 -0
  38. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/js/editor/toolbar.js +0 -0
  39. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/js/main.js +0 -0
  40. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/js/nodes/baseNode.js +0 -0
  41. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/js/nodes/endNode.js +0 -0
  42. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/js/nodes/flowNode.js +0 -0
  43. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/js/nodes/functionNode.js +0 -0
  44. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/js/nodes/index.js +0 -0
  45. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/js/nodes/mergeNode.js +0 -0
  46. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/js/nodes/startNode.js +0 -0
  47. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/js/types.js +0 -0
  48. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/js/utils/export.js +0 -0
  49. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/js/utils/helpers.js +0 -0
  50. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/js/utils/import.js +0 -0
  51. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/js/utils/validation.js +0 -0
  52. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/jsdoc.json +0 -0
  53. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/package-lock.json +0 -0
  54. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/package.json +0 -0
  55. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/postcss.config.cjs +0 -0
  56. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/public/favicon.png +0 -0
  57. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/public/favicon.svg +0 -0
  58. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/tailwind.config.cjs +0 -0
  59. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/vercel.json +0 -0
  60. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/editor/vite.config.js +0 -0
  61. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/engine_primitives_plan.md +0 -0
  62. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/env.example +0 -0
  63. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/images/food-ordering-flow.png +0 -0
  64. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/pipecat-flows.png +0 -0
  65. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/pipecat_upgrade.md +0 -0
  66. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/pyproject.toml +0 -0
  67. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/remote-asterisk-code/README.md +0 -0
  68. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/remote-asterisk-code/extensions.conf +0 -0
  69. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/remote-asterisk-code/rtp.conf +0 -0
  70. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/requirements.txt +0 -0
  71. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/scripts/check-pypi-package.py +0 -0
  72. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/scripts/fix-ruff.sh +0 -0
  73. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/scripts/pre-commit.sh +0 -0
  74. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/setup.cfg +0 -0
  75. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/src/dv_pipecat_flows.egg-info/SOURCES.txt +0 -0
  76. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/src/dv_pipecat_flows.egg-info/dependency_links.txt +0 -0
  77. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/src/dv_pipecat_flows.egg-info/requires.txt +0 -0
  78. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/src/dv_pipecat_flows.egg-info/top_level.txt +0 -0
  79. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/src/pipecat_flows/__init__.py +0 -0
  80. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/src/pipecat_flows/adapters.py +0 -0
  81. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/src/pipecat_flows/condition_evaluator.py +0 -0
  82. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/src/pipecat_flows/exceptions.py +0 -0
  83. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/src/pipecat_flows/flow_validator.py +0 -0
  84. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/src/pipecat_flows/processors/__init__.py +0 -0
  85. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/src/pipecat_flows/processors/router_mode_guard.py +0 -0
  86. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/src/pipecat_flows/processors/speak_interruption_guard.py +0 -0
  87. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/src/pipecat_flows/processors/user_turn_observer.py +0 -0
  88. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/src/pipecat_flows/router_mode.py +0 -0
  89. {dv_pipecat_flows-0.0.22.dev2200 → dv_pipecat_flows-0.0.22.dev2400}/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.dev2200
3
+ Version: 0.0.22.dev2400
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.dev2200
3
+ Version: 0.0.22.dev2400
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
@@ -25,6 +25,7 @@ Actions are used to perform side effects during conversations, such as:
25
25
 
26
26
  import asyncio
27
27
  import inspect
28
+ import re
28
29
  from dataclasses import dataclass
29
30
  from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Tuple
30
31
 
@@ -56,6 +57,48 @@ if TYPE_CHECKING:
56
57
  ONGOING_ACTIONS_WAIT_TIMEOUT_S = 60.0
57
58
 
58
59
 
60
+ # Router/Agent-extracted variable token: ``[{name}]`` (distinct from custom
61
+ # ``{{name}}`` on the FE — see VariableSelect.tsx). Resolved at TTS time from
62
+ # ``flow_manager.state``, where ``_run_router_node`` (and the flattened
63
+ # agent_node→llm_router path) writes the LLM's extracted args. Backend
64
+ # lowering only substitutes compile-time vars (custom_args, api_responses);
65
+ # anything a router extracts at runtime needs this pass to reach TTS.
66
+ #
67
+ # Pattern matches BOTH the FE's dominant mention form ``@[{var}]`` (the
68
+ # ``@``-prefixed visible text inside a Tiptap mention span) AND the raw
69
+ # ``[{var}]`` form — mirrors how ``replace_custom_variables`` handles both
70
+ # ``@{{var}}`` and ``{{var}}`` for custom_args.
71
+ _EXTRACT_VAR_RE = re.compile(
72
+ r"@?\[\{\s*([A-Za-z_][A-Za-z0-9_.]*)\s*\}\]"
73
+ )
74
+
75
+
76
+ def _substitute_extract_vars(text: str, state: dict) -> str:
77
+ """Replace ``[{var}]`` / ``@[{var}]`` occurrences with ``state[var]``.
78
+
79
+ Supports dotted paths (``[{user.name}]``). Unknown variables (key not
80
+ in state, or any path segment missing) are LEFT LITERAL — the marker
81
+ survives so downstream debugging can spot the misconfigured extract.
82
+ """
83
+ if not text or "[{" not in text or not isinstance(state, dict):
84
+ return text
85
+
86
+ def _resolve(key: str):
87
+ cur = state
88
+ for seg in key.split("."):
89
+ if isinstance(cur, dict) and seg in cur:
90
+ cur = cur[seg]
91
+ else:
92
+ return None
93
+ return cur
94
+
95
+ def _repl(match: "re.Match[str]") -> str:
96
+ value = _resolve(match.group(1))
97
+ return str(value) if value is not None else match.group(0)
98
+
99
+ return _EXTRACT_VAR_RE.sub(_repl, text)
100
+
101
+
59
102
  @dataclass
60
103
  class FunctionActionFrame(ControlFrame):
61
104
  """Frame containing a function action to be executed.
@@ -432,6 +475,16 @@ class ActionManager:
432
475
  logger.error("TTS action missing 'text' / 'text_variants' field")
433
476
  return
434
477
 
478
+ # Runtime resolution of [{var}] / @[{var}] tokens against
479
+ # flow_manager.state. Backend lowering substitutes {{var}} (custom
480
+ # args) and ((tool.field)) (pre-call outputs) at compile time, but
481
+ # router/agent-extracted vars only exist at runtime — without this
482
+ # pass, the bot speaks literals like "@[{user_name}]" verbatim.
483
+ # text_raw stays unrendered so the split-cache's prefix derivation
484
+ # remains stable across calls.
485
+ state = self._flow_manager.state if isinstance(self._flow_manager.state, dict) else {}
486
+ text = _substitute_extract_vars(text, state)
487
+
435
488
  await self._maybe_switch_tts_service_for_action(action)
436
489
 
437
490
  use_cache = action.get("use_cache", False)
@@ -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).
@@ -2611,6 +2662,7 @@ In all of these cases, you can provide a `name` in your new node's config for de
2611
2662
  transition_to=schema.transition_to,
2612
2663
  transition_callback=schema.transition_callback,
2613
2664
  state_update_keys=schema.state_update_keys,
2665
+ router_node_meta=schema.router_node_meta,
2614
2666
  )
2615
2667
 
2616
2668
  async def register_direct_function(func):
@@ -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.