fastworkflow 2.15.13__tar.gz → 2.17.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.

Potentially problematic release.


This version of fastworkflow might be problematic. Click here for more details.

Files changed (184) hide show
  1. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/PKG-INFO +4 -2
  2. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/README.md +2 -0
  3. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/what_can_i_do.py +16 -2
  4. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/wildcard.py +15 -6
  5. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/_workflows/command_metadata_extraction/intent_detection.py +1 -1
  6. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/chat_session.py +117 -54
  7. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/command_context_model.py +73 -7
  8. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/command_executor.py +1 -1
  9. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/command_metadata_api.py +56 -6
  10. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/fastworkflow.env +1 -0
  11. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/fastworkflow.passwords.env +2 -1
  12. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/mcp_server.py +3 -3
  13. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/run/__main__.py +0 -6
  14. fastworkflow-2.17.0/fastworkflow/run_fastapi_mcp/README.md +300 -0
  15. fastworkflow-2.17.0/fastworkflow/run_fastapi_mcp/conversation_store.py +391 -0
  16. fastworkflow-2.17.0/fastworkflow/run_fastapi_mcp/jwt_manager.py +256 -0
  17. fastworkflow-2.17.0/fastworkflow/run_fastapi_mcp/main.py +1206 -0
  18. fastworkflow-2.17.0/fastworkflow/run_fastapi_mcp/mcp_specific.py +103 -0
  19. fastworkflow-2.17.0/fastworkflow/run_fastapi_mcp/redoc_2_standalone_html.py +40 -0
  20. fastworkflow-2.17.0/fastworkflow/run_fastapi_mcp/utils.py +427 -0
  21. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/workflow_agent.py +3 -2
  22. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/pyproject.toml +9 -3
  23. fastworkflow-2.15.13/fastworkflow/run_agent/__main__.py +0 -294
  24. fastworkflow-2.15.13/fastworkflow/run_agent/agent_module.py +0 -194
  25. fastworkflow-2.15.13/fastworkflow/utils/__init__.py +0 -0
  26. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/LICENSE +0 -0
  27. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/.DS_Store +0 -0
  28. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/__init__.py +0 -0
  29. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/_commands/.gitkeep +0 -0
  30. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/_workflows/__init__.py +0 -0
  31. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/_workflows/command_metadata_extraction/__init__.py +0 -0
  32. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/ErrorCorrection/abort.py +0 -0
  33. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/ErrorCorrection/you_misunderstood.py +0 -0
  34. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/go_up.py +0 -0
  35. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/reset_context.py +0 -0
  36. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/what_is_current_context.py +0 -0
  37. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/__init__.py +0 -0
  38. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/_workflows/command_metadata_extraction/command_context_model.json +0 -0
  39. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/_workflows/command_metadata_extraction/parameter_extraction.py +0 -0
  40. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/__main__.py +0 -0
  41. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/ast_class_extractor.py +0 -0
  42. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/class_analysis_structures.py +0 -0
  43. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/cli_specification.md +0 -0
  44. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/command_dependency_resolver.py +0 -0
  45. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/command_file_generator.py +0 -0
  46. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/command_file_template.py +0 -0
  47. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/command_import_utils.py +0 -0
  48. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/command_stub_generator.py +0 -0
  49. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/context_folder_generator.py +0 -0
  50. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/context_model_generator.py +0 -0
  51. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/dependency_manager.py +0 -0
  52. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/dir_scanner.py +0 -0
  53. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/documentation_generator.py +0 -0
  54. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/genai_postprocessor.py +0 -0
  55. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/inheritance_block_regenerator.py +0 -0
  56. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/libcst_transformers.py +0 -0
  57. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/navigator_stub_generator.py +0 -0
  58. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/pydantic_model_generator.py +0 -0
  59. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/build/utterance_generator.py +0 -0
  60. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/cache_matching.py +0 -0
  61. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/cli.py +0 -0
  62. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/command_directory.py +0 -0
  63. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/command_interfaces.py +0 -0
  64. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/command_routing.py +0 -0
  65. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/docs/context_modules_prd.txt +0 -0
  66. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/extended_workflow_example/README.md +0 -0
  67. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/extended_workflow_example/_commands/WorkItem/get_status.py +0 -0
  68. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/extended_workflow_example/_commands/generate_report.py +0 -0
  69. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/extended_workflow_example/_commands/startup.py +0 -0
  70. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/extended_workflow_example/simple_workflow_template.json +0 -0
  71. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/extended_workflow_example/workflow_inheritance_model.json +0 -0
  72. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/hello_world/_commands/README.md +0 -0
  73. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/hello_world/_commands/add_two_numbers.py +0 -0
  74. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/hello_world/_commands/context_inheritance_model.json +0 -0
  75. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/hello_world/application/add_two_numbers.py +0 -0
  76. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_1/_commands/context_inheritance_model.json +0 -0
  77. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_1/_commands/send_message.py +0 -0
  78. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_1/application/send_message.py +0 -0
  79. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_2/_commands/User/send_message.py +0 -0
  80. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_2/_commands/context_inheritance_model.json +0 -0
  81. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_2/_commands/startup.py +0 -0
  82. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_2/application/user.py +0 -0
  83. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_3/_commands/PremiumUser/send_priority_message.py +0 -0
  84. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_3/_commands/User/send_message.py +0 -0
  85. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_3/_commands/context_inheritance_model.json +0 -0
  86. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_3/_commands/initialize_user.py +0 -0
  87. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_3/application/user.py +0 -0
  88. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/_ChatRoom.py +0 -0
  89. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/add_user.py +0 -0
  90. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/broadcast_message.py +0 -0
  91. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/get_current_user.py +0 -0
  92. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/list_users.py +0 -0
  93. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/set_current_user.py +0 -0
  94. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_4/_commands/PremiumUser/_PremiumUser.py +0 -0
  95. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_4/_commands/PremiumUser/send_priority_message.py +0 -0
  96. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_4/_commands/User/_User.py +0 -0
  97. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_4/_commands/User/send_message.py +0 -0
  98. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_4/_commands/context_inheritance_model.json +0 -0
  99. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_4/_commands/set_root_context.py +0 -0
  100. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_4/application/chatroom.py +0 -0
  101. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_4/application/user.py +0 -0
  102. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_4/context_hierarchy_model.json +0 -0
  103. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/messaging_app_4/startup_action.json +0 -0
  104. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/_commands/calculate.py +0 -0
  105. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/_commands/cancel_pending_order.py +0 -0
  106. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/_commands/exchange_delivered_order_items.py +0 -0
  107. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/_commands/find_user_id_by_email.py +0 -0
  108. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/_commands/find_user_id_by_name_zip.py +0 -0
  109. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/_commands/get_order_details.py +0 -0
  110. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/_commands/get_product_details.py +0 -0
  111. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/_commands/get_user_details.py +0 -0
  112. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/_commands/list_all_product_types.py +0 -0
  113. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_address.py +0 -0
  114. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_items.py +0 -0
  115. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_payment.py +0 -0
  116. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/_commands/modify_user_address.py +0 -0
  117. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/_commands/return_delivered_order_items.py +0 -0
  118. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/_commands/transfer_to_human_agents.py +0 -0
  119. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/context_inheritance_model.json +0 -0
  120. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/retail_data/__init__.py +0 -0
  121. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/retail_data/orders.json +0 -0
  122. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/retail_data/products.json +0 -0
  123. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/retail_data/users.json +0 -0
  124. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/tools/calculate.py +0 -0
  125. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/tools/cancel_pending_order.py +0 -0
  126. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/tools/exchange_delivered_order_items.py +0 -0
  127. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/tools/find_user_id_by_email.py +0 -0
  128. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/tools/find_user_id_by_name_zip.py +0 -0
  129. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/tools/get_order_details.py +0 -0
  130. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/tools/get_product_details.py +0 -0
  131. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/tools/get_user_details.py +0 -0
  132. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/tools/list_all_product_types.py +0 -0
  133. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_address.py +0 -0
  134. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_items.py +0 -0
  135. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_payment.py +0 -0
  136. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/tools/modify_user_address.py +0 -0
  137. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/tools/return_delivered_order_items.py +0 -0
  138. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/tools/think.py +0 -0
  139. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/tools/tool.py +0 -0
  140. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/tools/transfer_to_human_agents.py +0 -0
  141. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/retail_workflow/workflow_description.txt +0 -0
  142. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/__init__.py +0 -0
  143. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/_WorkItem.py +0 -0
  144. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/add_child_workitem.py +0 -0
  145. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/get_status.py +0 -0
  146. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/go_to_workitem.py +0 -0
  147. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/mark_as_complete.py +0 -0
  148. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_first_child_workitem.py +0 -0
  149. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_last_child_workitem.py +0 -0
  150. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_next_workitem.py +0 -0
  151. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_previous_workitem.py +0 -0
  152. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/remove_all_child_workitems.py +0 -0
  153. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/remove_child_workitem.py +0 -0
  154. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/show_schema.py +0 -0
  155. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/_commands/startup.py +0 -0
  156. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/application/__init__.py +0 -0
  157. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/application/workitem.py +0 -0
  158. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/simple_workflow_template.json +0 -0
  159. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/examples/simple_workflow_template/startup_action.json +0 -0
  160. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/model_pipeline_training.py +0 -0
  161. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/refine/__main__.py +0 -0
  162. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/run/__init__.py +0 -0
  163. {fastworkflow-2.15.13/fastworkflow/run_agent → fastworkflow-2.17.0/fastworkflow/train}/__init__.py +0 -0
  164. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/train/__main__.py +0 -0
  165. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/train/generate_synthetic.py +0 -0
  166. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/user_message_queues.py +0 -0
  167. {fastworkflow-2.15.13/fastworkflow/train → fastworkflow-2.17.0/fastworkflow/utils}/__init__.py +0 -0
  168. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/utils/command_dependency_graph.py +0 -0
  169. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/utils/context_utils.py +0 -0
  170. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/utils/dspy_cache_utils.py +0 -0
  171. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/utils/dspy_logger.py +0 -0
  172. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/utils/dspy_utils.py +0 -0
  173. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/utils/env.py +0 -0
  174. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/utils/fuzzy_match.py +0 -0
  175. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/utils/generate_param_examples.py +0 -0
  176. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/utils/logging.py +0 -0
  177. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/utils/parameterize_func_decorator.py +0 -0
  178. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/utils/pydantic_model_2_dspy_signature_class.py +0 -0
  179. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/utils/python_utils.py +0 -0
  180. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/utils/react.py +0 -0
  181. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/utils/signatures.py +0 -0
  182. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/utils/startup_progress.py +0 -0
  183. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/workflow.py +0 -0
  184. {fastworkflow-2.15.13 → fastworkflow-2.17.0}/fastworkflow/workflow_inheritance_model.py +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastworkflow
3
- Version: 2.15.13
3
+ Version: 2.17.0
4
4
  Summary: A framework for rapidly building large-scale, deterministic, interactive workflows with a fault-tolerant, conversational UX
5
5
  License: Apache-2.0
6
6
  Keywords: fastworkflow,ai,workflow,llm,openai
7
7
  Author: Dhar Rawal
8
8
  Author-email: drawal@radiantlogic.com
9
- Requires-Python: >=3.11
9
+ Requires-Python: >=3.11,<3.14
10
10
  Classifier: License :: OSI Approved :: Apache Software License
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.11
@@ -581,6 +581,7 @@ This single command will generate the `greet.py` command, `get_properties` and `
581
581
  | `LLM_RESPONSE_GEN` | LiteLLM model string for response generation | `run` | `mistral/mistral-small-latest` |
582
582
  | `LLM_PLANNER` | LiteLLM model string for the agent's task planner | `run` (agent mode) | `mistral/mistral-small-latest` |
583
583
  | `LLM_AGENT` | LiteLLM model string for the DSPy agent | `run` (agent mode) | `mistral/mistral-small-latest` |
584
+ | `LLM_CONVERSATION_STORE` | LiteLLM model string for conversation topic/summary generation | FastAPI service | `mistral/mistral-small-latest` |
584
585
  | `NOT_FOUND` | Placeholder value for missing parameters during extraction | Always | `"NOT_FOUND"` |
585
586
  | `MISSING_INFORMATION_ERRMSG` | Error message prefix for missing parameters | Always | `"Missing required..."` |
586
587
  | `INVALID_INFORMATION_ERRMSG` | Error message prefix for invalid parameters | Always | `"Invalid information..."` |
@@ -594,6 +595,7 @@ This single command will generate the `greet.py` command, `get_properties` and `
594
595
  | `LITELLM_API_KEY_RESPONSE_GEN`| API key for the `LLM_RESPONSE_GEN` model | `run` | *required* |
595
596
  | `LITELLM_API_KEY_PLANNER`| API key for the `LLM_PLANNER` model | `run` (agent mode) | *required* |
596
597
  | `LITELLM_API_KEY_AGENT`| API key for the `LLM_AGENT` model | `run` (agent mode) | *required* |
598
+ | `LITELLM_API_KEY_CONVERSATION_STORE`| API key for the `LLM_CONVERSATION_STORE` model | FastAPI service | *required* |
597
599
 
598
600
  > [!tip]
599
601
  > The example workflows are configured to use Mistral's models by default. You can get a free API key from [Mistral AI](https://mistral.ai) that works with the `mistral-small-latest` model.
@@ -548,6 +548,7 @@ This single command will generate the `greet.py` command, `get_properties` and `
548
548
  | `LLM_RESPONSE_GEN` | LiteLLM model string for response generation | `run` | `mistral/mistral-small-latest` |
549
549
  | `LLM_PLANNER` | LiteLLM model string for the agent's task planner | `run` (agent mode) | `mistral/mistral-small-latest` |
550
550
  | `LLM_AGENT` | LiteLLM model string for the DSPy agent | `run` (agent mode) | `mistral/mistral-small-latest` |
551
+ | `LLM_CONVERSATION_STORE` | LiteLLM model string for conversation topic/summary generation | FastAPI service | `mistral/mistral-small-latest` |
551
552
  | `NOT_FOUND` | Placeholder value for missing parameters during extraction | Always | `"NOT_FOUND"` |
552
553
  | `MISSING_INFORMATION_ERRMSG` | Error message prefix for missing parameters | Always | `"Missing required..."` |
553
554
  | `INVALID_INFORMATION_ERRMSG` | Error message prefix for invalid parameters | Always | `"Invalid information..."` |
@@ -561,6 +562,7 @@ This single command will generate the `greet.py` command, `get_properties` and `
561
562
  | `LITELLM_API_KEY_RESPONSE_GEN`| API key for the `LLM_RESPONSE_GEN` model | `run` | *required* |
562
563
  | `LITELLM_API_KEY_PLANNER`| API key for the `LLM_PLANNER` model | `run` (agent mode) | *required* |
563
564
  | `LITELLM_API_KEY_AGENT`| API key for the `LLM_AGENT` model | `run` (agent mode) | *required* |
565
+ | `LITELLM_API_KEY_CONVERSATION_STORE`| API key for the `LLM_CONVERSATION_STORE` model | FastAPI service | *required* |
564
566
 
565
567
  > [!tip]
566
568
  > The example workflows are configured to use Mistral's models by default. You can get a free API key from [Mistral AI](https://mistral.ai) that works with the `mistral-small-latest` model.
@@ -8,6 +8,7 @@ import json
8
8
 
9
9
  import fastworkflow
10
10
  from fastworkflow.train.generate_synthetic import generate_diverse_utterances
11
+ from fastworkflow.command_context_model import get_workflow_info
11
12
  from fastworkflow.command_metadata_api import CommandMetadataAPI
12
13
 
13
14
  class Signature:
@@ -139,20 +140,33 @@ class ResponseGenerator:
139
140
  with contextlib.suppress(Exception):
140
141
  if fastworkflow.chat_session:
141
142
  is_agent_mode = fastworkflow.chat_session.run_as_agent
142
-
143
+
143
144
  app_workflow = workflow.context["app_workflow"]
144
- response = CommandMetadataAPI.get_command_display_text(
145
+
146
+ # Get workflow definition
147
+ workflow_info = get_workflow_info(app_workflow.folderpath)
148
+ workflow_def_text = CommandMetadataAPI.get_workflow_definition_display_text(workflow_info)
149
+
150
+ # Get available commands in current context
151
+ commands_text = CommandMetadataAPI.get_command_display_text(
145
152
  subject_workflow_path=app_workflow.folderpath,
146
153
  cme_workflow_path=workflow.folderpath,
147
154
  active_context_name=app_workflow.current_command_context_name,
148
155
  for_agents=is_agent_mode,
149
156
  )
157
+
158
+ response = f"{workflow_def_text}\n\n{commands_text}"
150
159
 
160
+ nlu_pipeline_stage = workflow.context.get(
161
+ "NLU_Pipeline_Stage",
162
+ fastworkflow.NLUPipelineStage.INTENT_DETECTION)
163
+ success = nlu_pipeline_stage == fastworkflow.NLUPipelineStage.INTENT_DETECTION
151
164
  return fastworkflow.CommandOutput(
152
165
  workflow_id=workflow.id,
153
166
  command_responses=[
154
167
  fastworkflow.CommandResponse(
155
168
  response=response,
169
+ success=success
156
170
  )
157
171
  ]
158
172
  )
@@ -67,7 +67,10 @@ class ResponseGenerator:
67
67
  if cnp_output.command_name == 'ErrorCorrection/you_misunderstood':
68
68
  workflow_context["NLU_Pipeline_Stage"] = NLUPipelineStage.INTENT_MISUNDERSTANDING_CLARIFICATION
69
69
  workflow_context["command"] = command
70
- else:
70
+ elif (
71
+ nlu_pipeline_stage == fastworkflow.NLUPipelineStage.INTENT_DETECTION or
72
+ cnp_output.command_name == 'ErrorCorrection/abort'
73
+ ):
71
74
  workflow.end_command_processing()
72
75
  workflow.context = workflow_context
73
76
 
@@ -76,9 +79,13 @@ class ResponseGenerator:
76
79
  command=command,
77
80
  )
78
81
  command_output = CommandExecutor.perform_action(workflow, startup_action)
79
- command_output.command_responses[0].artifacts["command_handled"] = True
80
- # Set the additional attributes
81
- command_output.command_name = cnp_output.command_name
82
+ if (
83
+ nlu_pipeline_stage == fastworkflow.NLUPipelineStage.INTENT_DETECTION or
84
+ cnp_output.command_name == 'ErrorCorrection/abort'
85
+ ):
86
+ command_output.command_responses[0].artifacts["command_handled"] = True
87
+ # Set the additional attributes
88
+ command_output.command_name = cnp_output.command_name
82
89
  return command_output
83
90
 
84
91
  if nlu_pipeline_stage in {
@@ -138,7 +145,9 @@ class ResponseGenerator:
138
145
  workflow.context = workflow_context
139
146
 
140
147
  command_name = cnp_output.command_name
141
- extractor = ParameterExtraction(workflow, app_workflow, command_name, command)
148
+ # Use the preserved original command (with parameters) if available
149
+ preserved_command = f'{command_name}: {workflow.context.get("command", command)}'
150
+ extractor = ParameterExtraction(workflow, app_workflow, command_name, preserved_command)
142
151
  pe_output = extractor.extract()
143
152
  if not pe_output.parameters_are_valid:
144
153
  return CommandOutput(
@@ -161,7 +170,7 @@ class ResponseGenerator:
161
170
  CommandResponse(
162
171
  response="",
163
172
  artifacts={
164
- "command": command,
173
+ "command": preserved_command,
165
174
  "command_name": command_name,
166
175
  "cmd_parameters": pe_output.cmd_parameters,
167
176
  },
@@ -136,7 +136,7 @@ class CommandNamePrediction:
136
136
  NLUPipelineStage.INTENT_AMBIGUITY_CLARIFICATION,
137
137
  NLUPipelineStage.INTENT_MISUNDERSTANDING_CLARIFICATION
138
138
  ) and not command_name:
139
- command_name = "what_can_i_do"
139
+ command_name = "what can i do?"
140
140
 
141
141
  if not command_name or command_name == "wildcard":
142
142
  fully_qualified_command_name=None
@@ -35,7 +35,7 @@ class ChatWorker(Thread):
35
35
  """Process messages for the root workflow"""
36
36
  try:
37
37
  self.chat_session._status = SessionStatus.RUNNING
38
- workflow = ChatSession.get_active_workflow()
38
+ workflow = self.chat_session.get_active_workflow()
39
39
  logger.debug(f"Started root workflow {workflow.id}")
40
40
 
41
41
  # Run the workflow loop
@@ -44,39 +44,34 @@ class ChatWorker(Thread):
44
44
  finally:
45
45
  self.chat_session._status = SessionStatus.STOPPED
46
46
  # Ensure workflow is popped if thread terminates unexpectedly
47
- if ChatSession.get_active_workflow() is not None:
48
- ChatSession.pop_active_workflow()
47
+ if self.chat_session.get_active_workflow() is not None:
48
+ self.chat_session.pop_active_workflow()
49
49
 
50
50
  class ChatSession:
51
- _workflow_stack_lock = Lock()
52
- _workflow_stack: ClassVar[deque[fastworkflow.Workflow]] = deque() # Stack of workflow objects
53
-
54
- @classmethod
55
- def get_active_workflow(cls) -> Optional[fastworkflow.Workflow]:
51
+ def get_active_workflow(self) -> Optional[fastworkflow.Workflow]:
56
52
  """Get the currently active workflow (top of stack)"""
57
- with cls._workflow_stack_lock:
58
- return cls._workflow_stack[-1] if cls._workflow_stack else None
53
+ with self._workflow_stack_lock:
54
+ return self._workflow_stack[-1] if self._workflow_stack else None
59
55
 
60
- @classmethod
61
- def push_active_workflow(cls, workflow: fastworkflow.Workflow) -> None:
62
- with cls._workflow_stack_lock:
63
- cls._workflow_stack.append(workflow)
64
- logger.debug(f"Workflow stack: {[w.id for w in cls._workflow_stack]}")
56
+ def push_active_workflow(self, workflow: fastworkflow.Workflow) -> None:
57
+ """Push a workflow onto this session's stack"""
58
+ with self._workflow_stack_lock:
59
+ self._workflow_stack.append(workflow)
60
+ logger.debug(f"Workflow stack: {[w.id for w in self._workflow_stack]}")
65
61
 
66
- @classmethod
67
- def pop_active_workflow(cls) -> Optional[fastworkflow.Workflow]:
68
- with cls._workflow_stack_lock:
69
- if not cls._workflow_stack:
62
+ def pop_active_workflow(self) -> Optional[fastworkflow.Workflow]:
63
+ """Pop a workflow from this session's stack"""
64
+ with self._workflow_stack_lock:
65
+ if not self._workflow_stack:
70
66
  return None
71
- workflow = cls._workflow_stack.pop()
72
- logger.debug(f"Workflow stack after pop: {[w.id for w in cls._workflow_stack]}")
67
+ workflow = self._workflow_stack.pop()
68
+ logger.debug(f"Workflow stack after pop: {[w.id for w in self._workflow_stack]}")
73
69
  return workflow
74
70
 
75
- @classmethod
76
- def clear_workflow_stack(cls) -> None:
77
- """Clear the entire workflow stack"""
78
- with cls._workflow_stack_lock:
79
- cls._workflow_stack.clear()
71
+ def clear_workflow_stack(self) -> None:
72
+ """Clear the entire workflow stack for this session"""
73
+ with self._workflow_stack_lock:
74
+ self._workflow_stack.clear()
80
75
  logger.debug("Workflow stack cleared")
81
76
 
82
77
  def stop_workflow(self) -> None:
@@ -95,7 +90,7 @@ class ChatSession:
95
90
  logger.warning("Chat worker thread did not terminate within timeout")
96
91
 
97
92
  # Clear the workflow stack
98
- ChatSession.clear_workflow_stack()
93
+ self.clear_workflow_stack()
99
94
 
100
95
  # Reset status to stopped
101
96
  self._status = SessionStatus.STOPPED
@@ -116,6 +111,10 @@ class ChatSession:
116
111
  A chat session can run multiple workflows that share the same message queues.
117
112
  Use start_workflow() to start a specific workflow within this session.
118
113
  """
114
+ # Create instance-level workflow stack (supports nested workflows within this session)
115
+ self._workflow_stack: deque[fastworkflow.Workflow] = deque()
116
+ self._workflow_stack_lock = Lock()
117
+
119
118
  # Create queues for user messages and command outputs
120
119
  self._user_message_queue = Queue()
121
120
  self._command_output_queue = Queue()
@@ -197,7 +196,7 @@ class ChatSession:
197
196
 
198
197
  # Check if we need to stop the current workflow
199
198
  # Stop if this is a new root workflow (no parent, keep_alive=True)
200
- current_workflow = ChatSession.get_active_workflow()
199
+ current_workflow = self.get_active_workflow()
201
200
  if (current_workflow and
202
201
  parent_workflow_id is None and
203
202
  self._keep_alive):
@@ -244,7 +243,7 @@ class ChatSession:
244
243
  self._status = SessionStatus.STARTING
245
244
 
246
245
  # Push this workflow as active
247
- ChatSession.push_active_workflow(workflow)
246
+ self.push_active_workflow(workflow)
248
247
 
249
248
  # Initialize workflow tool agent if in agent mode
250
249
  # This must happen after pushing the workflow to the stack
@@ -304,12 +303,12 @@ class ChatSession:
304
303
 
305
304
  @property
306
305
  def workflow_is_complete(self) -> bool:
307
- workflow = ChatSession.get_active_workflow()
306
+ workflow = self.get_active_workflow()
308
307
  return workflow.is_complete if workflow else True
309
308
 
310
309
  @workflow_is_complete.setter
311
310
  def workflow_is_complete(self, value: bool) -> None:
312
- if workflow := ChatSession.get_active_workflow():
311
+ if workflow := self.get_active_workflow():
313
312
  workflow.is_complete = value
314
313
 
315
314
  @property
@@ -317,21 +316,22 @@ class ChatSession:
317
316
  """Return the conversation history."""
318
317
  return self._conversation_history
319
318
 
320
- def clear_conversation_history(self, trace_filename_suffix: Optional[str] = None) -> None:
319
+ # def clear_conversation_history(self, trace_filename_suffix: Optional[str] = None) -> None:
320
+ def clear_conversation_history(self) -> None:
321
321
  """
322
322
  Clear the conversation history.
323
323
  This resets the conversation history to an empty state.
324
324
  """
325
325
  self._conversation_history = dspy.History(messages=[])
326
326
  # Filename for conversation traces
327
- if trace_filename_suffix:
328
- self._conversation_traces_file_name: str = (
329
- f"conversation_traces_{trace_filename_suffix}"
330
- )
331
- else:
332
- self._conversation_traces_file_name: str = (
333
- f"conversation_traces_{datetime.now().strftime('%m_%d_%Y:%H_%M_%S')}.jsonl"
334
- )
327
+ # if trace_filename_suffix:
328
+ # self._conversation_traces_file_name: str = (
329
+ # f"conversation_traces_{trace_filename_suffix}"
330
+ # )
331
+ # else:
332
+ # self._conversation_traces_file_name: str = (
333
+ # f"conversation_traces_{datetime.now().strftime('%m_%d_%Y:%H_%M_%S')}.jsonl"
334
+ # )
335
335
 
336
336
  def _run_workflow_loop(self) -> Optional[fastworkflow.CommandOutput]:
337
337
  """
@@ -341,7 +341,7 @@ class ChatSession:
341
341
  - All outputs (success or failure) are sent to queue during processing
342
342
  """
343
343
  last_output = None
344
- workflow = ChatSession.get_active_workflow()
344
+ workflow = self.get_active_workflow()
345
345
 
346
346
  try:
347
347
  # Handle startup command/action
@@ -385,7 +385,7 @@ class ChatSession:
385
385
 
386
386
  finally:
387
387
  self._status = SessionStatus.STOPPED
388
- ChatSession.pop_active_workflow()
388
+ self.pop_active_workflow()
389
389
  logger.debug(f"Workflow {workflow.id if workflow else 'unknown'} completed")
390
390
 
391
391
  return None
@@ -401,7 +401,7 @@ class ChatSession:
401
401
  # def _process_mcp_tool_call(self, message: str) -> fastworkflow.CommandOutput:
402
402
  # # sourcery skip: class-extract-method, extract-method
403
403
  # """Process an MCP tool call message"""
404
- # workflow = ChatSession.get_active_workflow()
404
+ # workflow = self.get_active_workflow()
405
405
 
406
406
  # try:
407
407
  # # Parse JSON message
@@ -429,7 +429,7 @@ class ChatSession:
429
429
  # self.command_output_queue.put(command_output)
430
430
 
431
431
  # # Flush on successful or failed tool call – state may have changed.
432
- # if workflow := ChatSession.get_active_workflow():
432
+ # if workflow := self.get_active_workflow():
433
433
  # workflow.flush()
434
434
 
435
435
  # return command_output
@@ -495,16 +495,21 @@ class ChatSession:
495
495
  # Create CommandOutput with the agent's response
496
496
  command_response = fastworkflow.CommandResponse(response=result_text)
497
497
 
498
+ conversation_traces = None
498
499
  conversation_summary = message
499
500
  # Attach actions captured during agent execution as artifacts if available
500
501
  if os.path.exists("action.jsonl"):
501
502
  with open("action.jsonl", "r", encoding="utf-8") as f:
502
503
  actions = [json.loads(line) for line in f if line.strip()]
503
- conversation_summary = self._extract_conversation_summary(message, actions, result_text)
504
+ conversation_summary, conversation_traces = self._extract_conversation_summary(message, actions, result_text)
504
505
  command_response.artifacts["conversation_summary"] = conversation_summary
505
506
 
506
507
  self.conversation_history.messages.append(
507
- {f"conversation {len(self.conversation_history.messages) + 1}": conversation_summary}
508
+ {
509
+ "conversation summary": conversation_summary,
510
+ "conversation_traces": conversation_traces,
511
+ "feedback": None # Initialize feedback slot for this turn
512
+ }
508
513
  )
509
514
 
510
515
  command_output = fastworkflow.CommandOutput(
@@ -514,11 +519,11 @@ class ChatSession:
514
519
 
515
520
  # Put output in queue (following same pattern as _process_message)
516
521
  if (not command_output.success or self._keep_alive) and \
517
- self.command_output_queue:
522
+ self.command_output_queue:
518
523
  self.command_output_queue.put(command_output)
519
524
 
520
525
  # Persist workflow state changes
521
- if workflow := ChatSession.get_active_workflow():
526
+ if workflow := self.get_active_workflow():
522
527
  workflow.flush()
523
528
 
524
529
  return command_output
@@ -529,20 +534,77 @@ class ChatSession:
529
534
  # command_output = self.profile_invoke_command(message)
530
535
 
531
536
  command_output = self._CommandExecutor.invoke_command(self, message)
537
+
538
+ # Record assistant mode trace to action.jsonl (similar to agent mode in workflow_agent.py)
539
+ # This ensures assistant commands are captured even when interspersed with agent commands
540
+ response_text = ""
541
+ if command_output.command_responses:
542
+ response_text = command_output.command_responses[0].response or ""
543
+
544
+ # Convert parameters to dict if it's a Pydantic model or other complex object
545
+ params = command_output.command_parameters or {}
546
+ if hasattr(params, 'model_dump'):
547
+ params = params.model_dump()
548
+ elif hasattr(params, 'dict'):
549
+ params = params.dict()
550
+
551
+ record = {
552
+ "command": message,
553
+ "command_name": command_output.command_name or "",
554
+ "parameters": params,
555
+ "response": response_text
556
+ }
557
+
558
+ self.conversation_history.messages.append(
559
+ {
560
+ "conversation summary": "assistant_mode_command",
561
+ "conversation_traces": json.dumps(record),
562
+ "feedback": None # Initialize feedback slot for this turn
563
+ }
564
+ )
565
+
532
566
  if (not command_output.success or self._keep_alive) and \
533
567
  self.command_output_queue:
534
568
  self.command_output_queue.put(command_output)
535
569
 
536
570
  # Persist workflow state changes lazily accumulated during message processing.
537
- if workflow := ChatSession.get_active_workflow():
571
+ if workflow := self.get_active_workflow():
538
572
  workflow.flush()
539
573
 
540
574
  return command_output
541
575
 
542
576
  def _process_action(self, action: fastworkflow.Action) -> fastworkflow.CommandOutput:
543
577
  """Process a startup action"""
544
- workflow = ChatSession.get_active_workflow()
578
+ workflow = self.get_active_workflow()
545
579
  command_output = self._CommandExecutor.perform_action(workflow, action)
580
+
581
+ # Record action trace to action.jsonl
582
+ response_text = ""
583
+ if command_output.command_responses:
584
+ response_text = command_output.command_responses[0].response or ""
585
+
586
+ # Convert parameters to dict if it's a Pydantic model or other complex object
587
+ params = action.parameters or {}
588
+ if hasattr(params, 'model_dump'):
589
+ params = params.model_dump()
590
+ elif hasattr(params, 'dict'):
591
+ params = params.dict()
592
+
593
+ record = {
594
+ "command": "process_action",
595
+ "command_name": action.command_name,
596
+ "parameters": params,
597
+ "response": response_text
598
+ }
599
+
600
+ self.conversation_history.messages.append(
601
+ {
602
+ "conversation summary": "process_action command",
603
+ "conversation_traces": json.dumps(record),
604
+ "feedback": None # Initialize feedback slot for this turn
605
+ }
606
+ )
607
+
546
608
  if (not command_output.success or self._keep_alive) and \
547
609
  self.command_output_queue:
548
610
  self.command_output_queue.put(command_output)
@@ -573,15 +635,16 @@ class ChatSession:
573
635
  user_query: str, workflow_actions: list[dict[str, str]], final_agent_response: str) -> str:
574
636
  """
575
637
  Summarizes conversation based on original user query, workflow actions and agentt response.
638
+ Returns the conversation summary and the log entry
576
639
  """
577
640
  # Lets log everything to a file called action_log.jsonl, if it exists
578
- log_entry = {
641
+ conversation_traces = {
579
642
  "user_query": user_query,
580
643
  "agent_workflow_interactions": workflow_actions,
581
644
  "final_agent_response": final_agent_response
582
645
  }
583
- with open(self._conversation_traces_file_name, "a", encoding="utf-8") as f:
584
- f.write(json.dumps(log_entry) + "\n")
646
+ # with open(self._conversation_traces_file_name, "a", encoding="utf-8") as f:
647
+ # f.write(json.dumps(log_entry) + "\n")
585
648
 
586
649
  class ConversationSummarySignature(dspy.Signature):
587
650
  """
@@ -601,7 +664,7 @@ class ChatSession:
601
664
  user_query=user_query,
602
665
  workflow_actions=workflow_actions,
603
666
  final_agent_response=final_agent_response)
604
- return prediction.conversation_summary
667
+ return prediction.conversation_summary, json.dumps(conversation_traces)
605
668
 
606
669
 
607
670
  def profile_invoke_command(self, message: str):
@@ -2,11 +2,12 @@ from __future__ import annotations
2
2
 
3
3
  import json
4
4
  from dataclasses import dataclass, field
5
+ from typing import Any
6
+ import os
5
7
  from pathlib import Path
6
- from typing import Any, Optional, Type
7
8
 
8
9
  import fastworkflow
9
- from fastworkflow.command_directory import CommandDirectory, get_cached_command_directory
10
+ from fastworkflow.command_directory import get_cached_command_directory
10
11
  from fastworkflow.utils import python_utils
11
12
 
12
13
  """Utility for loading and traversing the single-file workflow command context model.
@@ -152,10 +153,10 @@ class CommandContextModel:
152
153
  hierarchy_model_path = Path(self._workflow_path) / "context_hierarchy_model.json"
153
154
  if not hierarchy_model_path.is_file():
154
155
  return {}
155
-
156
+
156
157
  with hierarchy_model_path.open("r") as f:
157
158
  hierarchy_data = json.load(f)
158
-
159
+
159
160
  return hierarchy_data
160
161
 
161
162
  def _resolve_ancestry(self, hierarchy: dict[str, dict[str, list[str]]]) -> None:
@@ -205,10 +206,10 @@ class CommandContextModel:
205
206
  all_ancestors.add(parent)
206
207
  grandparents = self.get_ancestor_contexts(parent, visiting.copy(), _hierarchy)
207
208
  all_ancestors.update(grandparents)
208
-
209
+
209
210
  final_ancestors = sorted(list(all_ancestors))
210
211
  self._resolved_ancestors[context_name] = final_ancestors
211
-
212
+
212
213
  visiting.remove(context_name)
213
214
 
214
215
  return final_ancestors
@@ -228,7 +229,7 @@ class CommandContextModel:
228
229
  # or by being part of a command inheritance structure. If it's not
229
230
  # in _command_contexts, it's an unknown/invalid context.
230
231
  raise CommandContextModelValidationError(f"Context '{context_name}' not found in model.")
231
-
232
+
232
233
  if visiting is None:
233
234
  visiting = set()
234
235
 
@@ -294,3 +295,68 @@ class CommandContextModel:
294
295
  return getattr(module, context_metadata.context_class, None)
295
296
  else:
296
297
  return None
298
+
299
+
300
+ # ---------------------------------------------------------------------
301
+ # Workflow info helper (module-level)
302
+ # ---------------------------------------------------------------------
303
+
304
+ def get_workflow_info(chat_session_or_path: fastworkflow.ChatSession | str) -> dict[str, Any]:
305
+ """
306
+ Return workflow-level metadata for the active workflow in the given chat session or workflow path.
307
+
308
+ Shape:
309
+ {
310
+ "workflow_name": str,
311
+ "available_contexts": list[str],
312
+ "context_inheritance_model": dict,
313
+ "context_hierarchy_model": dict
314
+ }
315
+
316
+ Notes:
317
+ - available_contexts are derived from CommandContextModel.load(workflow_path)
318
+ so they reflect filesystem + inheritance.
319
+ - current context and purpose/description are intentionally omitted.
320
+ - Raw JSON for inheritance (from _commands/context_inheritance_model.json)
321
+ and hierarchy (from context_hierarchy_model.json) is returned verbatim when present.
322
+ """
323
+ if isinstance(chat_session_or_path, str):
324
+ workflow_path_str = chat_session_or_path
325
+ else:
326
+ workflow_path_str = chat_session_or_path.get_active_workflow().folderpath
327
+ workflow_name = os.path.basename(os.path.abspath(workflow_path_str))
328
+
329
+ available_contexts: list[str]
330
+ inheritance_json: dict[str, Any] = {}
331
+ hierarchy_json: dict[str, Any] = {}
332
+
333
+ try:
334
+ # Derive contexts via consolidated model
335
+ context_model = CommandContextModel.load(workflow_path_str)
336
+ # Do not normalize names beyond keeping what the model exposes
337
+ available_contexts = sorted([key for key in context_model._command_contexts.keys() if key != 'IntentDetection'])
338
+ except Exception:
339
+ available_contexts = ["/"]
340
+
341
+ # Load raw context inheritance model (if present)
342
+ try:
343
+ inheritance_path = Path(workflow_path_str) / "_commands" / "context_inheritance_model.json"
344
+ if inheritance_path.is_file():
345
+ inheritance_json = json.loads(inheritance_path.read_text())
346
+ except Exception:
347
+ inheritance_json = {}
348
+
349
+ # Load raw context hierarchy model (if present)
350
+ try:
351
+ hierarchy_path = Path(workflow_path_str) / "context_hierarchy_model.json"
352
+ if hierarchy_path.is_file():
353
+ hierarchy_json = json.loads(hierarchy_path.read_text())
354
+ except Exception:
355
+ hierarchy_json = {}
356
+
357
+ return {
358
+ "workflow_name": workflow_name,
359
+ "available_contexts": available_contexts,
360
+ "context_inheritance_model": inheritance_json,
361
+ "context_hierarchy_model": hierarchy_json,
362
+ }
@@ -56,7 +56,7 @@ class CommandExecutor(CommandExecutorInterface):
56
56
  command_name = command_output.command_responses[0].artifacts["command_name"]
57
57
  input_obj = command_output.command_responses[0].artifacts["cmd_parameters"]
58
58
 
59
- workflow = ChatSession.get_active_workflow()
59
+ workflow = chat_session.get_active_workflow()
60
60
  workflow_name = workflow.folderpath.split('/')[-1]
61
61
  context = workflow.current_command_context_displayname
62
62