quantalogic 0.51.0__tar.gz → 0.52.0__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 (171) hide show
  1. {quantalogic-0.51.0 → quantalogic-0.52.0}/PKG-INFO +89 -2
  2. {quantalogic-0.51.0 → quantalogic-0.52.0}/README.md +88 -1
  3. {quantalogic-0.51.0 → quantalogic-0.52.0}/pyproject.toml +1 -1
  4. quantalogic-0.52.0/quantalogic/flow/__init__.py +40 -0
  5. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/flow/flow_extractor.py +32 -103
  6. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/flow/flow_generator.py +6 -2
  7. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/flow/flow_manager.py +33 -24
  8. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/flow/flow_manager_schema.py +2 -3
  9. quantalogic-0.52.0/quantalogic/flow/flow_mermaid.py +240 -0
  10. quantalogic-0.52.0/quantalogic/flow/flow_validator.py +335 -0
  11. quantalogic-0.52.0/quantalogic/flow/flow_yaml.md +490 -0
  12. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/__init__.py +3 -2
  13. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/tool.py +129 -3
  14. quantalogic-0.51.0/quantalogic/flow/__init__.py +0 -23
  15. quantalogic-0.51.0/quantalogic/flow/flow_yaml.md +0 -506
  16. {quantalogic-0.51.0 → quantalogic-0.52.0}/LICENSE +0 -0
  17. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/__init__.py +0 -0
  18. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/agent.py +0 -0
  19. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/agent_config.py +0 -0
  20. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/agent_factory.py +0 -0
  21. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/coding_agent.py +0 -0
  22. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/config.py +0 -0
  23. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/console_print_events.py +0 -0
  24. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/console_print_token.py +0 -0
  25. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/create_custom_agent.py +0 -0
  26. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/docs_cli.py +0 -0
  27. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/event_emitter.py +0 -0
  28. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/flow/flow.py +0 -0
  29. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/generative_model.py +0 -0
  30. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/get_model_info.py +0 -0
  31. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/interactive_text_editor.py +0 -0
  32. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/main.py +0 -0
  33. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/memory.py +0 -0
  34. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/model_info.py +0 -0
  35. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/model_info_list.py +0 -0
  36. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/model_info_litellm.py +0 -0
  37. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/model_names.py +0 -0
  38. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/prompts/memory_compaction_prompt.j2 +0 -0
  39. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/prompts/observation_response_format.j2 +0 -0
  40. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/prompts/repeated_tool_call_error.j2 +0 -0
  41. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/prompts/system_prompt.j2 +0 -0
  42. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/prompts/task_prompt.j2 +0 -0
  43. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/prompts/task_summary_prompt.j2 +0 -0
  44. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/prompts/tools_prompt.j2 +0 -0
  45. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/prompts/variables_prompt.j2 +0 -0
  46. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/prompts.py +0 -0
  47. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/quantlitellm.py +0 -0
  48. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/search_agent.py +0 -0
  49. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/server/__init__.py +0 -0
  50. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/server/agent_server.py +0 -0
  51. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/server/models.py +0 -0
  52. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/server/routes.py +0 -0
  53. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/server/state.py +0 -0
  54. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/server/static/js/event_visualizer.js +0 -0
  55. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/server/static/js/quantalogic.js +0 -0
  56. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/server/templates/index.html +0 -0
  57. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/task_file_reader.py +0 -0
  58. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/task_runner.py +0 -0
  59. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tool_manager.py +0 -0
  60. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/agent_tool.py +0 -0
  61. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/composio/__init__.py +0 -0
  62. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/composio/composio.py +0 -0
  63. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/database/__init__.py +0 -0
  64. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/database/generate_database_report_tool.py +0 -0
  65. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/database/sql_query_tool_advanced.py +0 -0
  66. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/document_tools/__init__.py +0 -0
  67. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/document_tools/markdown_to_docx_tool.py +0 -0
  68. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/document_tools/markdown_to_epub_tool.py +0 -0
  69. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/document_tools/markdown_to_html_tool.py +0 -0
  70. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/document_tools/markdown_to_ipynb_tool.py +0 -0
  71. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/document_tools/markdown_to_latex_tool.py +0 -0
  72. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/document_tools/markdown_to_pdf_tool.py +0 -0
  73. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/document_tools/markdown_to_pptx_tool.py +0 -0
  74. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/download_http_file_tool.py +0 -0
  75. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/duckduckgo_search_tool.py +0 -0
  76. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/edit_whole_content_tool.py +0 -0
  77. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/elixir_tool.py +0 -0
  78. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/execute_bash_command_tool.py +0 -0
  79. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/finance/__init__.py +0 -0
  80. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/finance/alpha_vantage_tool.py +0 -0
  81. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/finance/ccxt_tool.py +0 -0
  82. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/finance/finance_llm_tool.py +0 -0
  83. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/finance/google_finance.py +0 -0
  84. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/finance/market_intelligence_tool.py +0 -0
  85. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/finance/technical_analysis_tool.py +0 -0
  86. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/finance/tradingview_tool.py +0 -0
  87. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/finance/yahoo_finance.py +0 -0
  88. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/git/__init__.py +0 -0
  89. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/git/bitbucket_clone_repo_tool.py +0 -0
  90. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/git/bitbucket_operations_tool.py +0 -0
  91. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/git/clone_repo_tool.py +0 -0
  92. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/git/git_operations_tool.py +0 -0
  93. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/google_packages/__init__.py +0 -0
  94. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/google_packages/google_news_tool.py +0 -0
  95. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/grep_app_tool.py +0 -0
  96. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/image_generation/__init__.py +0 -0
  97. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/image_generation/dalle_e.py +0 -0
  98. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/input_question_tool.py +0 -0
  99. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/jinja_tool.py +0 -0
  100. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/language_handlers/__init__.py +0 -0
  101. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/language_handlers/c_handler.py +0 -0
  102. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/language_handlers/cpp_handler.py +0 -0
  103. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/language_handlers/go_handler.py +0 -0
  104. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/language_handlers/java_handler.py +0 -0
  105. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/language_handlers/javascript_handler.py +0 -0
  106. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/language_handlers/python_handler.py +0 -0
  107. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/language_handlers/rust_handler.py +0 -0
  108. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/language_handlers/scala_handler.py +0 -0
  109. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/language_handlers/typescript_handler.py +0 -0
  110. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/list_directory_tool.py +0 -0
  111. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/llm_tool.py +0 -0
  112. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/llm_vision_tool.py +0 -0
  113. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/markitdown_tool.py +0 -0
  114. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/nasa_packages/__init__.py +0 -0
  115. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/nasa_packages/models.py +0 -0
  116. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/nasa_packages/nasa_apod_tool.py +0 -0
  117. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/nasa_packages/nasa_neows_tool.py +0 -0
  118. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/nasa_packages/services.py +0 -0
  119. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/nodejs_tool.py +0 -0
  120. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/presentation_tools/__init__.py +0 -0
  121. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/presentation_tools/presentation_llm_tool.py +0 -0
  122. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/product_hunt/__init__.py +0 -0
  123. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/product_hunt/product_hunt_tool.py +0 -0
  124. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/product_hunt/services.py +0 -0
  125. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/python_tool.py +0 -0
  126. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/rag_tool/__init__.py +0 -0
  127. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/rag_tool/document_metadata.py +0 -0
  128. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/rag_tool/query_response.py +0 -0
  129. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/rag_tool/rag_tool.py +0 -0
  130. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/rag_tool/rag_tool_beta.py +0 -0
  131. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/read_file_block_tool.py +0 -0
  132. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/read_file_tool.py +0 -0
  133. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/read_html_tool.py +0 -0
  134. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/replace_in_file_tool.py +0 -0
  135. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/ripgrep_tool.py +0 -0
  136. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/safe_python_interpreter_tool.py +0 -0
  137. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/search_definition_names.py +0 -0
  138. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/sequence_tool.py +0 -0
  139. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/serpapi_search_tool.py +0 -0
  140. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/sql_query_tool.py +0 -0
  141. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/task_complete_tool.py +0 -0
  142. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/unified_diff_tool.py +0 -0
  143. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/utilities/__init__.py +0 -0
  144. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/utilities/csv_processor_tool.py +0 -0
  145. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/utilities/download_file_tool.py +0 -0
  146. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/utilities/mermaid_validator_tool.py +0 -0
  147. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/utils/__init__.py +0 -0
  148. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/utils/create_sample_database.py +0 -0
  149. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/utils/generate_database_report.py +0 -0
  150. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/wikipedia_search_tool.py +0 -0
  151. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/tools/write_file_tool.py +0 -0
  152. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/utils/__init__.py +0 -0
  153. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/utils/ask_user_validation.py +0 -0
  154. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/utils/async_utils.py +0 -0
  155. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/utils/check_version.py +0 -0
  156. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/utils/download_http_file.py +0 -0
  157. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/utils/get_all_models.py +0 -0
  158. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/utils/get_coding_environment.py +0 -0
  159. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/utils/get_environment.py +0 -0
  160. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/utils/get_quantalogic_rules_content.py +0 -0
  161. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/utils/git_ls.py +0 -0
  162. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/utils/lm_studio_model_info.py +0 -0
  163. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/utils/python_interpreter.py +0 -0
  164. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/utils/read_file.py +0 -0
  165. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/utils/read_http_text_content.py +0 -0
  166. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/utils/xml_utility.py +0 -0
  167. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/version.py +0 -0
  168. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/version_check.py +0 -0
  169. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/welcome_message.py +0 -0
  170. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/xml_parser.py +0 -0
  171. {quantalogic-0.51.0 → quantalogic-0.52.0}/quantalogic/xml_tool_parser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: quantalogic
3
- Version: 0.51.0
3
+ Version: 0.52.0
4
4
  Summary: QuantaLogic ReAct Agents
5
5
  Author: Raphaël MANSUY
6
6
  Author-email: raphael.mansuy@gmail.com
@@ -88,6 +88,8 @@ At [QuantaLogic](https://www.quantalogic.app), we spotted a black hole: amazing
88
88
  - [Quick Start](#quick-start)
89
89
  - [ReAct Framework: Dynamic Agents](#react-framework-dynamic-agents)
90
90
  - [Flow Module: Structured Workflows](#flow-module-structured-workflows)
91
+ - 📘 **[Workflow YAML DSL Specification](./quantalogic/flow/flow_yaml.md)**: Comprehensive guide to defining powerful, structured workflows using our Domain-Specific Language
92
+ - 📚 **[Flow YAML Documentation](https://quantalogic.github.io/quantalogic/flow/flow_yaml)**: Dive into the official documentation for a deeper understanding of Flow YAML and its applications
91
93
  - [ReAct vs. Flow: Pick Your Power](#react-vs-flow-pick-your-power)
92
94
  - [Using the CLI](#using-the-cli)
93
95
  - [Examples That Spark Joy](#examples-that-spark-joy)
@@ -357,7 +359,15 @@ Perfect for coding, debugging, or answering wild questions on the fly.
357
359
 
358
360
  ## Flow Module: Structured Workflows
359
361
 
360
- The **Flow module** is your architect—building workflows that hum with precision. Its all about nodes, transitions, and a steady rhythm, ideal for repeatable missions.
362
+ The **Flow module** is your architect—building workflows that hum with precision. It's all about nodes, transitions, and a steady rhythm, ideal for repeatable missions.
363
+
364
+ 🔍 **Want to dive deeper?** Check out our comprehensive [Workflow YAML DSL Specification](./quantalogic/flow/flow_yaml.md), a detailed guide that walks you through defining powerful, structured workflows. From basic node configurations to complex transition logic, this documentation is your roadmap to mastering workflow design with QuantaLogic.
365
+
366
+ 📚 **For a deeper understanding of Flow YAML and its applications, please refer to the official [Flow YAML Documentation](https://quantalogic.github.io/quantalogic/flow/flow_yaml).**
367
+
368
+ The Flow YAML documentation provides a comprehensive overview of the Flow YAML language, including its syntax, features, and best practices. It's a valuable resource for anyone looking to create complex workflows with QuantaLogic.
369
+
370
+ Additionally, the Flow YAML documentation includes a number of examples and tutorials to help you get started with creating your own workflows. These examples cover a range of topics, from simple workflows to more complex scenarios, and are designed to help you understand how to use Flow YAML to create powerful and flexible workflows.
361
371
 
362
372
  ### The Building Blocks
363
373
  - **Nodes**: Tasks like functions or LLM calls.
@@ -629,6 +639,83 @@ mypy quantalogic # Check types
629
639
  ruff check quantalogic # Lint it
630
640
  ```
631
641
 
642
+ ### Create Custom Tools
643
+ The `create_tool()` function transforms any Python function into a reusable Tool:
644
+
645
+ ```python
646
+ from quantalogic.tools import create_tool
647
+
648
+ def weather_lookup(city: str, country: str = "US") -> dict:
649
+ """Retrieve current weather for a given location.
650
+
651
+ Args:
652
+ city: Name of the city to look up
653
+ country: Two-letter country code (default: US)
654
+
655
+ Returns:
656
+ Dictionary with weather information
657
+ """
658
+ # Implement weather lookup logic here
659
+ return {"temperature": 22, "condition": "Sunny"}
660
+
661
+ # Convert the function to a Tool
662
+ weather_tool = create_tool(weather_lookup)
663
+
664
+ # Now you can use it as a Tool
665
+ print(weather_tool.to_markdown()) # Generate tool documentation
666
+ result = weather_tool.execute(city="New York") # Execute as a tool
667
+ ```
668
+
669
+ #### Using Custom Tools with ReAct Agent
670
+
671
+ Here's how to integrate custom tools with a ReAct Agent:
672
+
673
+ ```python
674
+ from quantalogic import Agent
675
+ from quantalogic.tools import create_tool, PythonTool
676
+
677
+ # Create a custom stock price lookup tool
678
+ def get_stock_price(symbol: str) -> str:
679
+ """Get the current price of a stock by its ticker symbol.
680
+
681
+ Args:
682
+ symbol: Stock ticker symbol (e.g., AAPL, MSFT)
683
+
684
+ Returns:
685
+ Current stock price information
686
+ """
687
+ # In a real implementation, you would fetch from an API
688
+ prices = {"AAPL": 185.92, "MSFT": 425.27, "GOOGL": 175.43}
689
+ if symbol in prices:
690
+ return f"{symbol} is currently trading at ${prices[symbol]}"
691
+ return f"Could not find price for {symbol}"
692
+
693
+ # Create an agent with standard and custom tools
694
+ agent = Agent(
695
+ model_name="gpt-4o",
696
+ tools=[
697
+ PythonTool(), # Standard Python execution tool
698
+ create_tool(get_stock_price) # Custom stock price tool
699
+ ]
700
+ )
701
+
702
+ # The agent can now use both tools to solve tasks
703
+ result = agent.solve_task(
704
+ "Write a Python function to calculate investment growth, "
705
+ "then analyze Apple stock's current price"
706
+ )
707
+
708
+ print(result)
709
+ ```
710
+
711
+ In this example, the agent can seamlessly use both the standard `PythonTool` and your custom stock price lookup tool to complete the task.
712
+
713
+ Key features of `create_tool()`:
714
+ - 🔧 Automatically converts functions to Tools
715
+ - 📝 Extracts metadata from function signature and docstring
716
+ - 🔍 Supports both synchronous and asynchronous functions
717
+ - 🛠️ Generates tool documentation and validation
718
+
632
719
  ---
633
720
 
634
721
  ## Contributing
@@ -42,6 +42,8 @@ At [QuantaLogic](https://www.quantalogic.app), we spotted a black hole: amazing
42
42
  - [Quick Start](#quick-start)
43
43
  - [ReAct Framework: Dynamic Agents](#react-framework-dynamic-agents)
44
44
  - [Flow Module: Structured Workflows](#flow-module-structured-workflows)
45
+ - 📘 **[Workflow YAML DSL Specification](./quantalogic/flow/flow_yaml.md)**: Comprehensive guide to defining powerful, structured workflows using our Domain-Specific Language
46
+ - 📚 **[Flow YAML Documentation](https://quantalogic.github.io/quantalogic/flow/flow_yaml)**: Dive into the official documentation for a deeper understanding of Flow YAML and its applications
45
47
  - [ReAct vs. Flow: Pick Your Power](#react-vs-flow-pick-your-power)
46
48
  - [Using the CLI](#using-the-cli)
47
49
  - [Examples That Spark Joy](#examples-that-spark-joy)
@@ -311,7 +313,15 @@ Perfect for coding, debugging, or answering wild questions on the fly.
311
313
 
312
314
  ## Flow Module: Structured Workflows
313
315
 
314
- The **Flow module** is your architect—building workflows that hum with precision. Its all about nodes, transitions, and a steady rhythm, ideal for repeatable missions.
316
+ The **Flow module** is your architect—building workflows that hum with precision. It's all about nodes, transitions, and a steady rhythm, ideal for repeatable missions.
317
+
318
+ 🔍 **Want to dive deeper?** Check out our comprehensive [Workflow YAML DSL Specification](./quantalogic/flow/flow_yaml.md), a detailed guide that walks you through defining powerful, structured workflows. From basic node configurations to complex transition logic, this documentation is your roadmap to mastering workflow design with QuantaLogic.
319
+
320
+ 📚 **For a deeper understanding of Flow YAML and its applications, please refer to the official [Flow YAML Documentation](https://quantalogic.github.io/quantalogic/flow/flow_yaml).**
321
+
322
+ The Flow YAML documentation provides a comprehensive overview of the Flow YAML language, including its syntax, features, and best practices. It's a valuable resource for anyone looking to create complex workflows with QuantaLogic.
323
+
324
+ Additionally, the Flow YAML documentation includes a number of examples and tutorials to help you get started with creating your own workflows. These examples cover a range of topics, from simple workflows to more complex scenarios, and are designed to help you understand how to use Flow YAML to create powerful and flexible workflows.
315
325
 
316
326
  ### The Building Blocks
317
327
  - **Nodes**: Tasks like functions or LLM calls.
@@ -583,6 +593,83 @@ mypy quantalogic # Check types
583
593
  ruff check quantalogic # Lint it
584
594
  ```
585
595
 
596
+ ### Create Custom Tools
597
+ The `create_tool()` function transforms any Python function into a reusable Tool:
598
+
599
+ ```python
600
+ from quantalogic.tools import create_tool
601
+
602
+ def weather_lookup(city: str, country: str = "US") -> dict:
603
+ """Retrieve current weather for a given location.
604
+
605
+ Args:
606
+ city: Name of the city to look up
607
+ country: Two-letter country code (default: US)
608
+
609
+ Returns:
610
+ Dictionary with weather information
611
+ """
612
+ # Implement weather lookup logic here
613
+ return {"temperature": 22, "condition": "Sunny"}
614
+
615
+ # Convert the function to a Tool
616
+ weather_tool = create_tool(weather_lookup)
617
+
618
+ # Now you can use it as a Tool
619
+ print(weather_tool.to_markdown()) # Generate tool documentation
620
+ result = weather_tool.execute(city="New York") # Execute as a tool
621
+ ```
622
+
623
+ #### Using Custom Tools with ReAct Agent
624
+
625
+ Here's how to integrate custom tools with a ReAct Agent:
626
+
627
+ ```python
628
+ from quantalogic import Agent
629
+ from quantalogic.tools import create_tool, PythonTool
630
+
631
+ # Create a custom stock price lookup tool
632
+ def get_stock_price(symbol: str) -> str:
633
+ """Get the current price of a stock by its ticker symbol.
634
+
635
+ Args:
636
+ symbol: Stock ticker symbol (e.g., AAPL, MSFT)
637
+
638
+ Returns:
639
+ Current stock price information
640
+ """
641
+ # In a real implementation, you would fetch from an API
642
+ prices = {"AAPL": 185.92, "MSFT": 425.27, "GOOGL": 175.43}
643
+ if symbol in prices:
644
+ return f"{symbol} is currently trading at ${prices[symbol]}"
645
+ return f"Could not find price for {symbol}"
646
+
647
+ # Create an agent with standard and custom tools
648
+ agent = Agent(
649
+ model_name="gpt-4o",
650
+ tools=[
651
+ PythonTool(), # Standard Python execution tool
652
+ create_tool(get_stock_price) # Custom stock price tool
653
+ ]
654
+ )
655
+
656
+ # The agent can now use both tools to solve tasks
657
+ result = agent.solve_task(
658
+ "Write a Python function to calculate investment growth, "
659
+ "then analyze Apple stock's current price"
660
+ )
661
+
662
+ print(result)
663
+ ```
664
+
665
+ In this example, the agent can seamlessly use both the standard `PythonTool` and your custom stock price lookup tool to complete the task.
666
+
667
+ Key features of `create_tool()`:
668
+ - 🔧 Automatically converts functions to Tools
669
+ - 📝 Extracts metadata from function signature and docstring
670
+ - 🔍 Supports both synchronous and asynchronous functions
671
+ - 🛠️ Generates tool documentation and validation
672
+
586
673
  ---
587
674
 
588
675
  ## Contributing
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "quantalogic"
3
- version = "0.51.0"
3
+ version = "0.52.0"
4
4
  description = "QuantaLogic ReAct Agents"
5
5
  authors = ["Raphaël MANSUY <raphael.mansuy@gmail.com>"]
6
6
  readme = "README.md"
@@ -0,0 +1,40 @@
1
+ """
2
+ Flow Package Initialization
3
+
4
+ This module initializes the flow package and provides package-level imports.
5
+ Now supports nested workflows for hierarchical flow definitions.
6
+
7
+ Key Visualization Utilities:
8
+ - generate_mermaid_diagram(): Convert workflow definitions to visual Mermaid flowcharts
9
+ - Supports pastel-colored node styling
10
+ - Generates interactive, readable workflow diagrams
11
+ - Handles complex workflows with multiple node types
12
+
13
+ - Generates descriptive labels
14
+ - Supports conditional node detection
15
+ """
16
+
17
+ from loguru import logger
18
+
19
+ # Expose key components for easy importing
20
+ from .flow import Nodes, Workflow, WorkflowEngine
21
+ from .flow_extractor import extract_workflow_from_file
22
+ from .flow_generator import generate_executable_script
23
+ from .flow_manager import WorkflowManager
24
+ from .flow_mermaid import generate_mermaid_diagram
25
+ from .flow_validator import validate_workflow_definition
26
+
27
+ # Define which symbols are exported when using `from flow import *`
28
+ __all__ = [
29
+ "WorkflowManager",
30
+ "Nodes",
31
+ "Workflow",
32
+ "WorkflowEngine",
33
+ "generate_mermaid_diagram",
34
+ "extract_workflow_from_file",
35
+ "generate_executable_script",
36
+ "validate_workflow_definition"
37
+ ]
38
+
39
+ # Package-level logger configuration
40
+ logger.info("Initializing Quantalogic Flow Package")
@@ -3,6 +3,7 @@ import os
3
3
 
4
4
  from loguru import logger
5
5
 
6
+ from quantalogic.flow.flow_generator import generate_executable_script # Import from flow_generator
6
7
  from quantalogic.flow.flow_manager import WorkflowManager # Added for YAML saving
7
8
  from quantalogic.flow.flow_manager_schema import (
8
9
  FunctionDefinition,
@@ -396,7 +397,7 @@ class WorkflowExtractor(ast.NodeVisitor):
396
397
  "sub_workflow": WorkflowStructure(
397
398
  start=sub_extractor.start_node,
398
399
  transitions=[
399
- TransitionDefinition(from_=t[0], to=t[1], condition=t[2]) for t in sub_extractor.transitions
400
+ TransitionDefinition(from_node=t[0], to_node=t[1], condition=t[2]) for t in sub_extractor.transitions
400
401
  ],
401
402
  ),
402
403
  "inputs": list(inputs.keys()),
@@ -494,7 +495,7 @@ def extract_workflow_from_file(file_path):
494
495
 
495
496
  # Construct TransitionDefinition objects
496
497
  transitions = [
497
- TransitionDefinition(**{"from": from_node, "to": to_node, "condition": cond})
498
+ TransitionDefinition(from_node=from_node, to_node=to_node, condition=cond)
498
499
  for from_node, to_node, cond in extractor.transitions
499
500
  ]
500
501
 
@@ -509,95 +510,7 @@ def extract_workflow_from_file(file_path):
509
510
  return workflow_def, extractor.global_vars
510
511
 
511
512
 
512
- def generate_executable_script(workflow_def: WorkflowDefinition, global_vars: dict, output_file: str) -> None:
513
- """
514
- Generate an executable Python script from a WorkflowDefinition with global variables.
515
-
516
- Args:
517
- workflow_def: The WorkflowDefinition object containing the workflow details.
518
- global_vars: Dictionary of global variables extracted from the source file.
519
- output_file: The path where the executable script will be written.
520
-
521
- The generated script includes:
522
- - A shebang using `uv run` for environment management.
523
- - Metadata specifying the required Python version and dependencies.
524
- - Global variables from the original script.
525
- - Embedded functions included directly in the script.
526
- - Workflow instantiation using direct chaining syntax.
527
- - A default initial_context matching the example.
528
- """
529
- with open(output_file, "w") as f:
530
- # Write the shebang and metadata
531
- f.write("#!/usr/bin/env -S uv run\n")
532
- f.write("# /// script\n")
533
- f.write('# requires-python = ">=3.12"\n')
534
- f.write("# dependencies = [\n")
535
- f.write('# "loguru",\n')
536
- f.write('# "litellm",\n')
537
- f.write('# "pydantic>=2.0",\n')
538
- f.write('# "anyio",\n')
539
- f.write('# "quantalogic>=0.35",\n')
540
- f.write('# "jinja2",\n')
541
- f.write('# "instructor[litellm]",\n') # Kept for potential structured LLM support
542
- f.write("# ]\n")
543
- f.write("# ///\n\n")
544
-
545
- # Write necessary imports
546
- f.write("import anyio\n")
547
- f.write("from typing import List\n")
548
- f.write("from loguru import logger\n")
549
- f.write("from quantalogic.flow import Nodes, Workflow\n\n")
550
-
551
- # Write global variables
552
- for var_name, value in global_vars.items():
553
- f.write(f"{var_name} = {repr(value)}\n")
554
- f.write("\n")
555
-
556
- # Embed functions from workflow_def
557
- for func_name, func_def in workflow_def.functions.items():
558
- if func_def.type == "embedded":
559
- if func_def.code is not None:
560
- f.write(func_def.code + "\n\n")
561
- else:
562
- f.write("\n\n")
563
-
564
- # Define workflow using chaining syntax
565
- f.write("# Define the workflow using simplified syntax with automatic node registration\n")
566
- f.write("workflow = (\n")
567
- f.write(f' Workflow("{workflow_def.workflow.start}")\n')
568
- for trans in workflow_def.workflow.transitions:
569
- _from_node = trans.from_
570
- to_node = trans.to
571
- condition = trans.condition or "None"
572
- if condition != "None":
573
- # Ensure condition is formatted as a lambda if not already
574
- if not condition.startswith("lambda ctx:"):
575
- condition = f"lambda ctx: {condition}"
576
- f.write(f' .then("{to_node}", condition={condition})\n')
577
- for observer in workflow_def.observers:
578
- f.write(f" .add_observer({observer})\n")
579
- f.write(")\n\n")
580
-
581
- # Main asynchronous function to run the workflow
582
- f.write("async def main():\n")
583
- f.write(' """Main function to run the story generation workflow."""\n')
584
- f.write(" initial_context = {\n")
585
- f.write(' "genre": "science fiction",\n')
586
- f.write(' "num_chapters": 3,\n')
587
- f.write(' "chapters": [],\n')
588
- f.write(' "completed_chapters": 0,\n')
589
- f.write(' "style": "descriptive"\n')
590
- f.write(" } # Customize initial_context as needed\n")
591
- f.write(" engine = workflow.build()\n")
592
- f.write(" result = await engine.run(initial_context)\n")
593
- f.write(' logger.info(f"Workflow result: {result}")\n\n')
594
-
595
- # Entry point to execute the main function
596
- f.write('if __name__ == "__main__":\n')
597
- f.write(" anyio.run(main)\n")
598
-
599
- # Set executable permissions (rwxr-xr-x)
600
- os.chmod(output_file, 0o755)
513
+ # The generate_executable_script function has been moved to flow_generator.py
601
514
 
602
515
 
603
516
  def print_workflow_definition(workflow_def):
@@ -638,11 +551,11 @@ def print_workflow_definition(workflow_def):
638
551
  print("Transitions:")
639
552
  for trans in workflow_def.workflow.transitions:
640
553
  condition_str = f" [Condition: {trans.condition}]" if trans.condition else ""
641
- if isinstance(trans.to, list):
642
- for to_node in trans.to:
643
- print(f"- {trans.from_} -> {to_node}{condition_str}")
554
+ if isinstance(trans.to_node, list):
555
+ for to_node in trans.to_node:
556
+ print(f"- {trans.from_node} -> {to_node}{condition_str}")
644
557
  else:
645
- print(f"- {trans.from_} -> {trans.to}{condition_str}")
558
+ print(f"- {trans.from_node} -> {trans.to_node}{condition_str}")
646
559
 
647
560
  print("\n#### Observers:")
648
561
  for observer in workflow_def.observers:
@@ -650,23 +563,39 @@ def print_workflow_definition(workflow_def):
650
563
 
651
564
 
652
565
  def main():
653
- """Demonstrate parsing the story_generator_agent.py workflow and saving it to YAML."""
654
- from quantalogic.flow.flow_generator import generate_executable_script # Ensure correct import
655
-
656
- output_file_python = "./story_generator.py"
657
- file_path = "examples/qflow/story_generator_agent.py"
658
- yaml_output_path = "story_generator_workflow.yaml" # Output YAML file path
566
+ """Demonstrate extracting a workflow from a Python file and saving it to YAML."""
567
+ import argparse
568
+ import sys
569
+
570
+ parser = argparse.ArgumentParser(description='Extract workflow from a Python file')
571
+ parser.add_argument('file_path', nargs='?', default="examples/qflow/story_generator_agent.py",
572
+ help='Path to the Python file containing the workflow')
573
+ parser.add_argument('--output', '-o', default="./generated_workflow.py",
574
+ help='Output path for the executable Python script')
575
+ parser.add_argument('--yaml', '-y', default="workflow_definition.yaml",
576
+ help='Output path for the YAML workflow definition')
577
+
578
+ args = parser.parse_args()
579
+ file_path = args.file_path
580
+ output_file_python = args.output
581
+ yaml_output_path = args.yaml
582
+
583
+ if not os.path.exists(file_path):
584
+ logger.error(f"File '{file_path}' not found. Please provide a valid file path.")
585
+ logger.info("Example usage: python -m quantalogic.flow.flow_extractor path/to/your/workflow_file.py")
586
+ sys.exit(1)
587
+
659
588
  try:
660
589
  workflow_def, global_vars = extract_workflow_from_file(file_path)
661
590
  logger.info(f"Successfully extracted workflow from '{file_path}'")
662
591
  print_workflow_definition(workflow_def)
663
592
  generate_executable_script(workflow_def, global_vars, output_file_python)
593
+ logger.info(f"Executable script generated at '{output_file_python}'")
594
+
664
595
  # Save the workflow to a YAML file
665
596
  manager = WorkflowManager(workflow_def)
666
597
  manager.save_to_yaml(yaml_output_path)
667
598
  logger.info(f"Workflow saved to YAML file '{yaml_output_path}'")
668
- except FileNotFoundError:
669
- logger.error(f"File '{file_path}' not found. Please ensure it exists in the specified directory.")
670
599
  except Exception as e:
671
600
  logger.error(f"Failed to parse or save workflow from '{file_path}': {e}")
672
601
 
@@ -60,14 +60,18 @@ def generate_executable_script(workflow_def: WorkflowDefinition, global_vars: di
60
60
  f.write("workflow = (\n")
61
61
  f.write(f' Workflow("{workflow_def.workflow.start}")\n')
62
62
  for trans in workflow_def.workflow.transitions:
63
- _from_node = trans.from_
64
- to_node = trans.to
63
+ _from_node = trans.from_node
64
+ to_node = trans.to_node
65
65
  condition = trans.condition or "None"
66
66
  if condition != "None":
67
67
  # Ensure condition is formatted as a lambda if not already
68
68
  if not condition.startswith("lambda ctx:"):
69
69
  condition = f"lambda ctx: {condition}"
70
70
  f.write(f' .then("{to_node}", condition={condition})\n')
71
+ # Add observers if any exist in the workflow definition
72
+ if hasattr(workflow_def, 'observers'):
73
+ for observer in workflow_def.observers:
74
+ f.write(f" .add_observer({observer})\n")
71
75
  f.write(")\n\n")
72
76
 
73
77
  # Main asynchronous function to run the workflow
@@ -65,7 +65,7 @@ class WorkflowManager:
65
65
  self.workflow.workflow.transitions = [
66
66
  t
67
67
  for t in self.workflow.workflow.transitions
68
- if t.from_ != name and (isinstance(t.to, str) or name not in t.to)
68
+ if t.from_node != name and (isinstance(t.to_node, str) or name not in t.to_node)
69
69
  ]
70
70
  if self.workflow.workflow.start == name:
71
71
  self.workflow.workflow.start = None
@@ -99,27 +99,36 @@ class WorkflowManager:
99
99
 
100
100
  def add_transition(
101
101
  self,
102
- from_: str,
103
- to: Union[str, List[str]],
102
+ from_node: str,
103
+ to_node: Union[str, List[str]],
104
104
  condition: Optional[str] = None,
105
+ strict: bool = True,
105
106
  ) -> None:
106
- """Add a transition between nodes, ensuring all nodes exist."""
107
- if from_ not in self.workflow.nodes:
108
- raise ValueError(f"Source node '{from_}' does not exist")
109
- if isinstance(to, str):
110
- if to not in self.workflow.nodes:
111
- raise ValueError(f"Target node '{to}' does not exist")
112
- else:
113
- for t in to:
114
- if t not in self.workflow.nodes:
115
- raise ValueError(f"Target node '{t}' does not exist")
107
+ """Add a transition between nodes.
108
+
109
+ Args:
110
+ from_node: Source node name
111
+ to_node: Target node name or list of target node names
112
+ condition: Optional condition for the transition
113
+ strict: If True, validates that all nodes exist before adding the transition.
114
+ If False, allows adding transitions to non-existent nodes.
115
+ """
116
+ if strict:
117
+ if from_node not in self.workflow.nodes:
118
+ raise ValueError(f"Source node '{from_node}' does not exist")
119
+ if isinstance(to_node, str):
120
+ if to_node not in self.workflow.nodes:
121
+ raise ValueError(f"Target node '{to_node}' does not exist")
122
+ else:
123
+ for t in to_node:
124
+ if t not in self.workflow.nodes:
125
+ raise ValueError(f"Target node '{t}' does not exist")
116
126
  # Create TransitionDefinition with named parameters
117
- # Create a TransitionDefinition with the correct field names
118
- # The field is defined with alias="from" in the schema
119
- transition_dict = {"from": from_, "to": to}
120
- if condition is not None:
121
- transition_dict["condition"] = condition
122
- transition = TransitionDefinition.model_validate(transition_dict)
127
+ transition = TransitionDefinition(
128
+ from_node=from_node,
129
+ to_node=to_node,
130
+ condition=condition
131
+ )
123
132
  self.workflow.workflow.transitions.append(transition)
124
133
 
125
134
  def set_start_node(self, name: str) -> None:
@@ -281,8 +290,8 @@ class WorkflowManager:
281
290
  sub_workflows[node_name] = sub_wf
282
291
  added_sub_nodes = set()
283
292
  for trans in node_def.sub_workflow.transitions:
284
- from_node = trans.from_
285
- to_nodes = [trans.to] if isinstance(trans.to, str) else trans.to
293
+ from_node = trans.from_node
294
+ to_nodes = [trans.to_node] if isinstance(trans.to_node, str) else trans.to_node
286
295
  if from_node not in added_sub_nodes:
287
296
  sub_wf.node(from_node)
288
297
  added_sub_nodes.add(from_node)
@@ -362,8 +371,8 @@ class WorkflowManager:
362
371
 
363
372
  added_nodes = set()
364
373
  for trans in self.workflow.workflow.transitions:
365
- from_node = trans.from_
366
- to_nodes = [trans.to] if isinstance(trans.to, str) else trans.to
374
+ from_node = trans.from_node
375
+ to_nodes = [trans.to_node] if isinstance(trans.to_node, str) else trans.to_node
367
376
  if from_node not in added_nodes and from_node not in sub_workflows:
368
377
  wf.node(from_node)
369
378
  added_nodes.add(from_node)
@@ -441,7 +450,7 @@ def main():
441
450
  manager.add_node(name="start", function="greet")
442
451
  manager.add_node(name="end", function="farewell")
443
452
  manager.set_start_node("start")
444
- manager.add_transition(from_="start", to="end")
453
+ manager.add_transition(from_node="start", to_node="end")
445
454
  manager.add_observer("monitor") # Add the observer
446
455
  manager.save_to_yaml("workflow.yaml")
447
456
  new_manager = WorkflowManager()
@@ -128,12 +128,11 @@ class NodeDefinition(BaseModel):
128
128
  class TransitionDefinition(BaseModel):
129
129
  """Definition of a transition between nodes."""
130
130
 
131
- from_: str = Field(
131
+ from_node: str = Field(
132
132
  ...,
133
133
  description="Source node name for the transition.",
134
- alias="from", # Supports YAML aliasing
135
134
  )
136
- to: Union[str, List[str]] = Field(
135
+ to_node: Union[str, List[str]] = Field(
137
136
  ..., description="Target node(s). A string for sequential, a list for parallel execution."
138
137
  )
139
138
  condition: Optional[str] = Field(