fastworkflow 2.17.5__tar.gz → 2.17.7__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 (183) hide show
  1. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/PKG-INFO +1 -1
  2. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/chat_session.py +15 -2
  3. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/run_fastapi_mcp/README.md +29 -0
  4. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/run_fastapi_mcp/__main__.py +13 -11
  5. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/run_fastapi_mcp/jwt_manager.py +83 -16
  6. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/run_fastapi_mcp/utils.py +7 -7
  7. fastworkflow-2.17.7/fastworkflow/utils/chat_adapter.py +99 -0
  8. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/utils/react.py +7 -3
  9. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/pyproject.toml +1 -1
  10. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/LICENSE +0 -0
  11. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/README.md +0 -0
  12. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/.DS_Store +0 -0
  13. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/__init__.py +0 -0
  14. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/_commands/.gitkeep +0 -0
  15. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/_workflows/__init__.py +0 -0
  16. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/_workflows/command_metadata_extraction/__init__.py +0 -0
  17. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/_workflows/command_metadata_extraction/_commands/ErrorCorrection/abort.py +0 -0
  18. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/_workflows/command_metadata_extraction/_commands/ErrorCorrection/you_misunderstood.py +0 -0
  19. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/go_up.py +0 -0
  20. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/reset_context.py +0 -0
  21. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/what_can_i_do.py +0 -0
  22. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/what_is_current_context.py +0 -0
  23. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/_workflows/command_metadata_extraction/_commands/__init__.py +0 -0
  24. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/_workflows/command_metadata_extraction/_commands/wildcard.py +0 -0
  25. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/_workflows/command_metadata_extraction/command_context_model.json +0 -0
  26. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/_workflows/command_metadata_extraction/intent_detection.py +0 -0
  27. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/_workflows/command_metadata_extraction/parameter_extraction.py +0 -0
  28. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/__main__.py +0 -0
  29. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/ast_class_extractor.py +0 -0
  30. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/class_analysis_structures.py +0 -0
  31. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/cli_specification.md +0 -0
  32. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/command_dependency_resolver.py +0 -0
  33. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/command_file_generator.py +0 -0
  34. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/command_file_template.py +0 -0
  35. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/command_import_utils.py +0 -0
  36. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/command_stub_generator.py +0 -0
  37. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/context_folder_generator.py +0 -0
  38. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/context_model_generator.py +0 -0
  39. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/dependency_manager.py +0 -0
  40. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/dir_scanner.py +0 -0
  41. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/documentation_generator.py +0 -0
  42. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/genai_postprocessor.py +0 -0
  43. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/inheritance_block_regenerator.py +0 -0
  44. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/libcst_transformers.py +0 -0
  45. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/navigator_stub_generator.py +0 -0
  46. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/pydantic_model_generator.py +0 -0
  47. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/build/utterance_generator.py +0 -0
  48. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/cache_matching.py +0 -0
  49. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/cli.py +0 -0
  50. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/command_context_model.py +0 -0
  51. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/command_directory.py +0 -0
  52. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/command_executor.py +0 -0
  53. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/command_interfaces.py +0 -0
  54. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/command_metadata_api.py +0 -0
  55. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/command_routing.py +0 -0
  56. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/docs/context_modules_prd.txt +0 -0
  57. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/extended_workflow_example/README.md +0 -0
  58. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/extended_workflow_example/_commands/WorkItem/get_status.py +0 -0
  59. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/extended_workflow_example/_commands/generate_report.py +0 -0
  60. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/extended_workflow_example/_commands/startup.py +0 -0
  61. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/extended_workflow_example/simple_workflow_template.json +0 -0
  62. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/extended_workflow_example/workflow_inheritance_model.json +0 -0
  63. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/fastworkflow.env +0 -0
  64. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/fastworkflow.passwords.env +0 -0
  65. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/hello_world/_commands/README.md +0 -0
  66. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/hello_world/_commands/add_two_numbers.py +0 -0
  67. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/hello_world/_commands/context_inheritance_model.json +0 -0
  68. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/hello_world/application/add_two_numbers.py +0 -0
  69. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_1/_commands/context_inheritance_model.json +0 -0
  70. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_1/_commands/send_message.py +0 -0
  71. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_1/application/send_message.py +0 -0
  72. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_2/_commands/User/send_message.py +0 -0
  73. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_2/_commands/context_inheritance_model.json +0 -0
  74. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_2/_commands/startup.py +0 -0
  75. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_2/application/user.py +0 -0
  76. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_3/_commands/PremiumUser/send_priority_message.py +0 -0
  77. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_3/_commands/User/send_message.py +0 -0
  78. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_3/_commands/context_inheritance_model.json +0 -0
  79. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_3/_commands/initialize_user.py +0 -0
  80. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_3/application/user.py +0 -0
  81. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/_ChatRoom.py +0 -0
  82. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/add_user.py +0 -0
  83. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/broadcast_message.py +0 -0
  84. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/get_current_user.py +0 -0
  85. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/list_users.py +0 -0
  86. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/set_current_user.py +0 -0
  87. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_4/_commands/PremiumUser/_PremiumUser.py +0 -0
  88. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_4/_commands/PremiumUser/send_priority_message.py +0 -0
  89. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_4/_commands/User/_User.py +0 -0
  90. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_4/_commands/User/send_message.py +0 -0
  91. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_4/_commands/context_inheritance_model.json +0 -0
  92. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_4/_commands/set_root_context.py +0 -0
  93. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_4/application/chatroom.py +0 -0
  94. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_4/application/user.py +0 -0
  95. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_4/context_hierarchy_model.json +0 -0
  96. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/messaging_app_4/startup_action.json +0 -0
  97. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/_commands/calculate.py +0 -0
  98. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/_commands/cancel_pending_order.py +0 -0
  99. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/_commands/exchange_delivered_order_items.py +0 -0
  100. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/_commands/find_user_id_by_email.py +0 -0
  101. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/_commands/find_user_id_by_name_zip.py +0 -0
  102. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/_commands/get_order_details.py +0 -0
  103. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/_commands/get_product_details.py +0 -0
  104. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/_commands/get_user_details.py +0 -0
  105. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/_commands/list_all_product_types.py +0 -0
  106. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_address.py +0 -0
  107. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_items.py +0 -0
  108. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_payment.py +0 -0
  109. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/_commands/modify_user_address.py +0 -0
  110. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/_commands/return_delivered_order_items.py +0 -0
  111. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/_commands/transfer_to_human_agents.py +0 -0
  112. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/context_inheritance_model.json +0 -0
  113. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/retail_data/__init__.py +0 -0
  114. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/retail_data/orders.json +0 -0
  115. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/retail_data/products.json +0 -0
  116. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/retail_data/users.json +0 -0
  117. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/tools/calculate.py +0 -0
  118. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/tools/cancel_pending_order.py +0 -0
  119. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/tools/exchange_delivered_order_items.py +0 -0
  120. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/tools/find_user_id_by_email.py +0 -0
  121. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/tools/find_user_id_by_name_zip.py +0 -0
  122. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/tools/get_order_details.py +0 -0
  123. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/tools/get_product_details.py +0 -0
  124. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/tools/get_user_details.py +0 -0
  125. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/tools/list_all_product_types.py +0 -0
  126. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_address.py +0 -0
  127. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_items.py +0 -0
  128. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_payment.py +0 -0
  129. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/tools/modify_user_address.py +0 -0
  130. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/tools/return_delivered_order_items.py +0 -0
  131. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/tools/think.py +0 -0
  132. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/tools/tool.py +0 -0
  133. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/tools/transfer_to_human_agents.py +0 -0
  134. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/retail_workflow/workflow_description.txt +0 -0
  135. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/__init__.py +0 -0
  136. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/_WorkItem.py +0 -0
  137. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/add_child_workitem.py +0 -0
  138. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/get_status.py +0 -0
  139. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/go_to_workitem.py +0 -0
  140. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/mark_as_complete.py +0 -0
  141. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_first_child_workitem.py +0 -0
  142. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_last_child_workitem.py +0 -0
  143. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_next_workitem.py +0 -0
  144. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_previous_workitem.py +0 -0
  145. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/remove_all_child_workitems.py +0 -0
  146. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/remove_child_workitem.py +0 -0
  147. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/show_schema.py +0 -0
  148. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/_commands/startup.py +0 -0
  149. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/application/__init__.py +0 -0
  150. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/application/workitem.py +0 -0
  151. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/simple_workflow_template.json +0 -0
  152. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/examples/simple_workflow_template/startup_action.json +0 -0
  153. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/mcp_server.py +0 -0
  154. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/model_pipeline_training.py +0 -0
  155. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/refine/__main__.py +0 -0
  156. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/run/__init__.py +0 -0
  157. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/run/__main__.py +0 -0
  158. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/run_fastapi_mcp/__init__.py +0 -0
  159. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/run_fastapi_mcp/conversation_store.py +0 -0
  160. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/run_fastapi_mcp/mcp_specific.py +0 -0
  161. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/run_fastapi_mcp/redoc_2_standalone_html.py +0 -0
  162. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/train/__init__.py +0 -0
  163. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/train/__main__.py +0 -0
  164. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/train/generate_synthetic.py +0 -0
  165. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/user_message_queues.py +0 -0
  166. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/utils/__init__.py +0 -0
  167. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/utils/command_dependency_graph.py +0 -0
  168. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/utils/context_utils.py +0 -0
  169. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/utils/dspy_cache_utils.py +0 -0
  170. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/utils/dspy_logger.py +0 -0
  171. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/utils/dspy_utils.py +0 -0
  172. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/utils/env.py +0 -0
  173. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/utils/fuzzy_match.py +0 -0
  174. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/utils/generate_param_examples.py +0 -0
  175. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/utils/logging.py +0 -0
  176. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/utils/parameterize_func_decorator.py +0 -0
  177. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/utils/pydantic_model_2_dspy_signature_class.py +0 -0
  178. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/utils/python_utils.py +0 -0
  179. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/utils/signatures.py +0 -0
  180. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/utils/startup_progress.py +0 -0
  181. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/workflow.py +0 -0
  182. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/workflow_agent.py +0 -0
  183. {fastworkflow-2.17.5 → fastworkflow-2.17.7}/fastworkflow/workflow_inheritance_model.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastworkflow
3
- Version: 2.17.5
3
+ Version: 2.17.7
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
@@ -467,15 +467,28 @@ class ChatSession:
467
467
  self
468
468
  )
469
469
 
470
+ # Get available commands for current context and pass to agent.
471
+ # The CommandsSystemPreludeAdapter will inject these commands into the system
472
+ # message, keeping them out of the trajectory to avoid token bloat while still
473
+ # providing context-specific command info.
474
+ from fastworkflow.workflow_agent import _what_can_i_do
475
+ available_commands = _what_can_i_do(self)
476
+
470
477
  lm = dspy_utils.get_lm("LLM_AGENT", "LITELLM_API_KEY_AGENT")
471
478
  from dspy.utils.exceptions import AdapterParseError
479
+ from fastworkflow.utils.chat_adapter import CommandsSystemPreludeAdapter
480
+
481
+ # Use CommandsSystemPreludeAdapter specifically for workflow agent calls
482
+ agent_adapter = CommandsSystemPreludeAdapter()
483
+
472
484
  # Retry logic for AdapterParseError
473
485
  max_retries = 2
474
486
  for attempt in range(max_retries):
475
487
  try:
476
- with dspy.context(lm=lm, adapter=dspy.ChatAdapter()):
488
+ with dspy.context(lm=lm, adapter=agent_adapter):
477
489
  agent_result = self._workflow_tool_agent(
478
- user_query=command_info_and_refined_message_with_todolist
490
+ user_query=command_info_and_refined_message_with_todolist,
491
+ available_commands=available_commands
479
492
  )
480
493
  break # Success, exit retry loop
481
494
  except AdapterParseError as _:
@@ -47,12 +47,41 @@ Configure in your environment (loaded at process startup via CLI args or env loa
47
47
  | Variable | Description | Required | Default |
48
48
  |----------|-------------|----------|---------|
49
49
  | `SPEEDDICT_FOLDERNAME` | Base folder for workflow contexts and conversation storage | Yes | - |
50
+ | `--expect_encrypted_jwt` | Enable full JWT signature verification (pass flag to require signed tokens) | No | False (no verification by default) |
50
51
 
51
52
  Notes:
52
53
  - Conversation DBs are stored under `SPEEDDICT_FOLDERNAME/user_conversations` (directory is auto-created).
53
54
  - `/conversations` now accepts a `limit` query parameter (default `20`).
54
55
  - Shutdown waits up to 30 seconds for active turns (hard-coded).
55
56
 
57
+ ## JWT Verification Modes
58
+
59
+ ### Default Behavior: No Signature Verification
60
+ By default, the service does NOT verify JWT signatures, accepting unsigned tokens for trusted internal networks where JWT is used purely for data transport:
61
+
62
+ ```bash
63
+ uvicorn services.run_fastapi.main:app --workflow_path /path/to/workflow
64
+ ```
65
+
66
+ **Use cases** (no verification):
67
+ - Controlled internal networks with network-level security
68
+ - Systems where JWT carries non-sensitive routing information
69
+ - Trusted environments where data transport is the primary concern
70
+
71
+ The service logs a warning on startup when running in this mode.
72
+
73
+ ### Secure Mode: Enable Signature Verification
74
+ For production deployments requiring full RSA signature verification:
75
+
76
+ ```bash
77
+ uvicorn services.run_fastapi.main:app --workflow_path /path/to/workflow --expect_encrypted_jwt
78
+ ```
79
+
80
+ **Secure mode** (with `--expect_encrypted_jwt` flag):
81
+ - JWT tokens are cryptographically verified using RSA signatures
82
+ - Tokens without valid signatures are rejected
83
+ - Recommended for production deployments in untrusted environments
84
+
56
85
  ## API Endpoints (REST)
57
86
 
58
87
  ### `POST /initialize`
@@ -61,6 +61,7 @@ from .jwt_manager import (
61
61
  create_access_token,
62
62
  create_refresh_token,
63
63
  verify_token,
64
+ set_jwt_verification_mode,
64
65
  JWT_ACCESS_TOKEN_EXPIRE_MINUTES
65
66
  )
66
67
 
@@ -148,6 +149,9 @@ async def lifespan(_app: FastAPI):
148
149
  if ARGS.passwords_file_path:
149
150
  env_vars.update(dotenv_values(ARGS.passwords_file_path))
150
151
  fastworkflow.init(env_vars=env_vars)
152
+
153
+ # Configure JWT verification mode based on CLI parameter
154
+ set_jwt_verification_mode(ARGS.expect_encrypted_jwt)
151
155
 
152
156
  async def _active_turn_user_ids() -> list[str]:
153
157
  active: list[str] = []
@@ -219,6 +223,8 @@ def load_args():
219
223
  parser.add_argument("--project_folderpath", required=False)
220
224
  parser.add_argument("--port", type=int, default=8000, help="Port to run the server on (default: 8000)")
221
225
  parser.add_argument("--host", default="0.0.0.0", help="Host to bind the server to (default: 0.0.0.0)")
226
+ parser.add_argument("--expect_encrypted_jwt", action="store_true", default=False,
227
+ help="Enable JWT signature verification (default: unsigned tokens accepted for trusted networks)")
222
228
  return parser.parse_args()
223
229
 
224
230
  ARGS = load_args()
@@ -251,13 +257,11 @@ def custom_openapi():
251
257
 
252
258
  # Enhance the auto-generated Bearer token security scheme with better documentation
253
259
  # The HTTPBearer dependency in utils.py creates the base scheme, we just improve it
254
- if "components" in openapi_schema and "securitySchemes" in openapi_schema["components"]:
255
- if "BearerAuth" in openapi_schema["components"]["securitySchemes"]:
256
- # Update the description to be more helpful
257
- openapi_schema["components"]["securitySchemes"]["BearerAuth"]["description"] = (
258
- "JWT access token from /initialize or /refresh_token endpoint. "
259
- "Enter ONLY the token (Swagger UI automatically adds 'Bearer ' prefix)"
260
- )
260
+ if "components" in openapi_schema and "securitySchemes" in openapi_schema["components"] and "BearerAuth" in openapi_schema["components"]["securitySchemes"]:
261
+ openapi_schema["components"]["securitySchemes"]["BearerAuth"]["description"] = (
262
+ "JWT access token from /initialize or /refresh_token endpoint. "
263
+ "Enter ONLY the token (Swagger UI automatically adds 'Bearer ' prefix)"
264
+ )
261
265
 
262
266
  # Apply security globally to all endpoints except public ones
263
267
  for path, path_item in openapi_schema["paths"].items():
@@ -265,10 +269,8 @@ def custom_openapi():
265
269
  if path in ["/initialize", "/refresh_token", "/", "/admin/dump_all_conversations", "/admin/generate_mcp_token"]:
266
270
  continue
267
271
  for method in path_item:
268
- if method in ["get", "post", "put", "delete", "patch"]:
269
- # Ensure security is applied (should already be set by HTTPBearer dependency)
270
- if "security" not in path_item[method]:
271
- path_item[method]["security"] = [{"BearerAuth": []}]
272
+ if method in ["get", "post", "put", "delete", "patch"] and "security" not in path_item[method]:
273
+ path_item[method]["security"] = [{"BearerAuth": []}]
272
274
 
273
275
  app.openapi_schema = openapi_schema
274
276
  return app.openapi_schema
@@ -34,6 +34,9 @@ PUBLIC_KEY_PATH = os.path.join(KEYS_DIR, "public_key.pem")
34
34
  _private_key: Optional[str] = None
35
35
  _public_key: Optional[str] = None
36
36
 
37
+ # Flag to control JWT verification behavior (set from CLI)
38
+ EXPECT_ENCRYPTED_JWT = True # Default to secure mode
39
+
37
40
 
38
41
  def ensure_keys_directory() -> None:
39
42
  """Create jwt_keys directory if it doesn't exist."""
@@ -129,19 +132,42 @@ def load_or_generate_keys() -> tuple[str, str]:
129
132
  return _private_key, _public_key
130
133
 
131
134
 
135
+ def set_jwt_verification_mode(expect_encrypted: bool) -> None:
136
+ """
137
+ Configure JWT verification mode for trusted network scenarios.
138
+
139
+ When expect_encrypted=False, JWT tokens are decoded without signature verification.
140
+ This mode is ONLY suitable for trusted internal networks where JWT is used for
141
+ data transport rather than security.
142
+
143
+ WARNING: Disabling signature verification allows any client to forge tokens.
144
+ Only use in controlled environments.
145
+ """
146
+ global EXPECT_ENCRYPTED_JWT
147
+ EXPECT_ENCRYPTED_JWT = expect_encrypted
148
+ if not expect_encrypted:
149
+ logger.warning(
150
+ "JWT signature verification DISABLED. "
151
+ "Tokens will be accepted without cryptographic validation. "
152
+ "Only use in trusted internal networks."
153
+ )
154
+
155
+
132
156
  def create_access_token(user_id: str, expires_days: int | None = None) -> str:
133
157
  """
134
158
  Create a JWT access token for a user.
135
159
 
160
+ Behavior depends on EXPECT_ENCRYPTED_JWT flag:
161
+ - If True: Creates a signed token using RSA algorithm
162
+ - If False: Creates an unsigned token for trusted network use
163
+
136
164
  Args:
137
165
  user_id: User identifier
138
166
  expires_days: Optional custom expiration in days. If None, uses JWT_ACCESS_TOKEN_EXPIRE_MINUTES (default 60 minutes).
139
167
 
140
168
  Returns:
141
- str: Encoded JWT access token
169
+ str: Encoded JWT access token (signed or unsigned based on EXPECT_ENCRYPTED_JWT)
142
170
  """
143
- private_key, _ = load_or_generate_keys()
144
-
145
171
  now = datetime.now(timezone.utc)
146
172
  if expires_days is not None:
147
173
  expire = now + timedelta(days=expires_days)
@@ -159,8 +185,17 @@ def create_access_token(user_id: str, expires_days: int | None = None) -> str:
159
185
  "aud": JWT_AUDIENCE # Audience
160
186
  }
161
187
 
162
- token = jwt.encode(payload, private_key, algorithm=JWT_ALGORITHM)
163
- logger.debug(f"Created access token for user_id: {user_id}, expires: {expire.isoformat()}")
188
+ if EXPECT_ENCRYPTED_JWT:
189
+ # Secure mode: create signed token
190
+ private_key, _ = load_or_generate_keys()
191
+ token = jwt.encode(payload, private_key, algorithm=JWT_ALGORITHM)
192
+ logger.debug(f"Created signed access token for user_id: {user_id}, expires: {expire.isoformat()}")
193
+ else:
194
+ # Trusted network mode: create unsigned token using HS256 with empty key
195
+ # This creates a JWT that can be decoded without verification
196
+ token = jwt.encode(payload, "", algorithm="HS256")
197
+ logger.debug(f"Created unsigned access token for user_id: {user_id}, expires: {expire.isoformat()}")
198
+
164
199
  return token
165
200
 
166
201
 
@@ -168,14 +203,16 @@ def create_refresh_token(user_id: str) -> str:
168
203
  """
169
204
  Create a JWT refresh token for a user.
170
205
 
206
+ Behavior depends on EXPECT_ENCRYPTED_JWT flag:
207
+ - If True: Creates a signed token using RSA algorithm
208
+ - If False: Creates an unsigned token for trusted network use
209
+
171
210
  Args:
172
211
  user_id: User identifier
173
212
 
174
213
  Returns:
175
- str: Encoded JWT refresh token
214
+ str: Encoded JWT refresh token (signed or unsigned based on EXPECT_ENCRYPTED_JWT)
176
215
  """
177
- private_key, _ = load_or_generate_keys()
178
-
179
216
  now = datetime.now(timezone.utc)
180
217
  expire = now + timedelta(days=JWT_REFRESH_TOKEN_EXPIRE_DAYS)
181
218
 
@@ -190,15 +227,29 @@ def create_refresh_token(user_id: str) -> str:
190
227
  "aud": JWT_AUDIENCE # Audience
191
228
  }
192
229
 
193
- token = jwt.encode(payload, private_key, algorithm=JWT_ALGORITHM)
194
- logger.debug(f"Created refresh token for user_id: {user_id}, expires: {expire.isoformat()}")
230
+ if EXPECT_ENCRYPTED_JWT:
231
+ # Secure mode: create signed token
232
+ private_key, _ = load_or_generate_keys()
233
+ token = jwt.encode(payload, private_key, algorithm=JWT_ALGORITHM)
234
+ logger.debug(f"Created signed refresh token for user_id: {user_id}, expires: {expire.isoformat()}")
235
+ else:
236
+ # Trusted network mode: create unsigned token using HS256 with empty key
237
+ # This creates a JWT that can be decoded without verification
238
+ token = jwt.encode(payload, "", algorithm="HS256")
239
+ logger.debug(f"Created unsigned refresh token for user_id: {user_id}, expires: {expire.isoformat()}")
240
+
195
241
  return token
196
242
 
197
243
 
198
244
  def verify_token(token: str, expected_type: str = "access") -> dict:
245
+ # sourcery skip: extract-duplicate-method
199
246
  """
200
247
  Verify and decode a JWT token.
201
248
 
249
+ Behavior depends on EXPECT_ENCRYPTED_JWT flag:
250
+ - If True (default): Full cryptographic verification with signature check
251
+ - If False: Extract payload without verification (trusted network mode)
252
+
202
253
  Args:
203
254
  token: JWT token string
204
255
  expected_type: Expected token type ("access" or "refresh")
@@ -209,8 +260,25 @@ def verify_token(token: str, expected_type: str = "access") -> dict:
209
260
  Raises:
210
261
  JWTError: If token is invalid, expired, or type mismatch
211
262
  """
263
+ if not EXPECT_ENCRYPTED_JWT:
264
+ # Trusted network mode: decode without verification (accepts both unsigned and signed tokens)
265
+ try:
266
+ # Use unverified decoding - works for any JWT regardless of algorithm or signing
267
+ payload = jwt.get_unverified_claims(token)
268
+ except Exception as e:
269
+ logger.warning(f"Token decoding failed: {e}")
270
+ raise JWTError(f"Failed to decode token: {e}") from e
271
+
272
+ # Validate token type for consistency (outside try-except to allow JWTError to propagate)
273
+ if payload.get("type") != expected_type:
274
+ raise JWTError(f"Invalid token type: expected {expected_type}, got {payload.get('type')}")
275
+
276
+ logger.debug(f"Token decoded (unverified mode): user_id={payload.get('sub')}, type={expected_type}")
277
+ return payload
278
+
279
+ # Standard mode: full verification (existing code)
212
280
  _, public_key = load_or_generate_keys()
213
-
281
+
214
282
  try:
215
283
  # Decode and verify token
216
284
  payload = jwt.decode(
@@ -220,14 +288,14 @@ def verify_token(token: str, expected_type: str = "access") -> dict:
220
288
  issuer=JWT_ISSUER,
221
289
  audience=JWT_AUDIENCE
222
290
  )
223
-
291
+
224
292
  # Verify token type
225
293
  if payload.get("type") != expected_type:
226
294
  raise JWTError(f"Invalid token type: expected {expected_type}, got {payload.get('type')}")
227
-
295
+
228
296
  logger.debug(f"Token verified successfully: user_id={payload.get('sub')}, type={expected_type}")
229
297
  return payload
230
-
298
+
231
299
  except JWTError as e:
232
300
  logger.warning(f"Token verification failed: {e}")
233
301
  raise
@@ -247,8 +315,7 @@ def get_token_expiry(token: str) -> Optional[datetime]:
247
315
  try:
248
316
  # Decode without verification (just to inspect claims)
249
317
  payload = jwt.get_unverified_claims(token)
250
- exp_timestamp = payload.get("exp")
251
- if exp_timestamp:
318
+ if exp_timestamp := payload.get("exp"):
252
319
  return datetime.fromtimestamp(exp_timestamp, tz=timezone.utc)
253
320
  except Exception as e:
254
321
  logger.debug(f"Failed to get token expiry: {e}")
@@ -169,11 +169,11 @@ def get_session_from_jwt(
169
169
  """
170
170
  # Extract token from credentials (already validated by HTTPBearer)
171
171
  token = credentials.credentials
172
-
172
+
173
173
  # Verify and decode token
174
174
  try:
175
175
  payload = verify_token(token, expected_type="access")
176
-
176
+
177
177
  # Extract session data from payload
178
178
  return SessionData(
179
179
  user_id=payload["sub"],
@@ -182,19 +182,19 @@ def get_session_from_jwt(
182
182
  expires_at=payload["exp"],
183
183
  jti=payload["jti"]
184
184
  )
185
-
185
+
186
186
  except JWTError as e:
187
187
  raise HTTPException(
188
188
  status_code=status.HTTP_401_UNAUTHORIZED,
189
189
  detail=f"Invalid or expired token: {str(e)}",
190
- headers={"WWW-Authenticate": "Bearer"}
191
- )
190
+ headers={"WWW-Authenticate": "Bearer"},
191
+ ) from e
192
192
  except KeyError as e:
193
193
  raise HTTPException(
194
194
  status_code=status.HTTP_401_UNAUTHORIZED,
195
195
  detail=f"Token missing required claim: {str(e)}",
196
- headers={"WWW-Authenticate": "Bearer"}
197
- )
196
+ headers={"WWW-Authenticate": "Bearer"},
197
+ ) from e
198
198
 
199
199
 
200
200
  async def ensure_user_runtime_exists(
@@ -0,0 +1,99 @@
1
+ """
2
+ ChatAdapter wrapper for injecting context-specific available commands into system messages.
3
+
4
+ Design Overview:
5
+ ---------------
6
+ This module implements a ChatAdapter wrapper that dynamically injects workflow command information
7
+ into the system message at runtime, avoiding the need to rebuild ReAct agent modules per context.
8
+
9
+ Key Benefits:
10
+ - Single shared agent: No per-context module caching required
11
+ - Dynamic updates: Commands refresh per call based on current workflow context
12
+ - Token efficiency: Commands appear in system (not repeated in trajectory/history)
13
+ - Zero rebuild cost: Signature and modules remain stable across context changes
14
+
15
+ Usage:
16
+ ------
17
+ The adapter is used specifically for workflow agent calls via dspy.context():
18
+
19
+ from fastworkflow.utils.chat_adapter import CommandsSystemPreludeAdapter
20
+
21
+ agent_adapter = CommandsSystemPreludeAdapter()
22
+ available_commands = _what_can_i_do(chat_session)
23
+
24
+ with dspy.context(lm=lm, adapter=agent_adapter):
25
+ agent_result = agent(
26
+ user_query="...",
27
+ available_commands=available_commands
28
+ )
29
+
30
+ The adapter intercepts the format call and prepends commands to the system message,
31
+ keeping them out of the trajectory to prevent token bloat across iterations.
32
+ This scoped approach ensures the adapter only affects workflow agent calls, not other
33
+ DSPy operations in the system.
34
+ """
35
+ import dspy
36
+
37
+
38
+ class CommandsSystemPreludeAdapter(dspy.ChatAdapter):
39
+ """
40
+ Wraps a base DSPy ChatAdapter to inject available commands into the system message.
41
+
42
+ This adapter intercepts the render process and prepends a "Available commands" section
43
+ to the system message when `available_commands` is present in inputs. This ensures
44
+ commands are visible to the model at each step without being added to the trajectory
45
+ or conversation history.
46
+
47
+ Args:
48
+ base: The underlying ChatAdapter to wrap. Defaults to dspy.ChatAdapter() if None.
49
+ title: The header text for the commands section. Defaults to "Available commands".
50
+
51
+ Example:
52
+ >>> import dspy
53
+ >>> from fastworkflow.utils.chat_adapter import CommandsSystemPreludeAdapter
54
+ >>> dspy.settings.adapter = CommandsSystemPreludeAdapter()
55
+ """
56
+
57
+ def __init__(self, base: dspy.ChatAdapter | None = None, title: str = "Available commands"):
58
+ super().__init__()
59
+ self.base = base or dspy.ChatAdapter()
60
+ self.title = title
61
+
62
+ def format(self, signature, demos, inputs):
63
+ """
64
+ Format the inputs for the model, injecting available_commands into system message.
65
+
66
+ This method wraps the base adapter's format method and modifies the result
67
+ to include available commands in the system message if present in inputs.
68
+
69
+ Args:
70
+ signature: The DSPy signature defining the task
71
+ demos: List of demonstration examples
72
+ inputs: Dictionary of input values, may include 'available_commands'
73
+
74
+ Returns:
75
+ Formatted messages with commands injected into system message
76
+ """
77
+ # Call the base adapter's format method
78
+ formatted = self.base.format(signature, demos, inputs)
79
+
80
+ # Check if available_commands is in inputs
81
+ cmds = inputs.get("available_commands")
82
+ if not cmds:
83
+ return formatted
84
+
85
+ # Inject commands into the system message
86
+ prelude = f"{self.title}:\n{cmds}".strip()
87
+
88
+ # Formatted output is a list of messages, first may be system
89
+ # Find and modify the system message, or prepend one
90
+ if formatted and formatted[0].get("role") == "system":
91
+ # Prepend to existing system message
92
+ existing_content = formatted[0].get("content", "")
93
+ formatted[0]["content"] = f"{prelude}\n\n{existing_content}".strip()
94
+ else:
95
+ # No system message exists, prepend one
96
+ formatted.insert(0, {"role": "system", "content": prelude})
97
+
98
+ return formatted
99
+
@@ -67,13 +67,17 @@ class fastWorkflowReAct(Module):
67
67
  args={},
68
68
  )
69
69
 
70
- for idx, tool in enumerate(tools.values()):
71
- instr.append(f"({idx + 1}) {tool}")
70
+ instr.extend(f"({idx + 1}) {tool}" for idx, tool in enumerate(tools.values()))
72
71
  instr.append("When providing `next_tool_args`, the value inside the field must be in JSON format")
73
72
 
73
+ # Build the ReAct signature with trajectory and available_commands inputs.
74
+ # available_commands is injected into system message by CommandsSystemPreludeAdapter
75
+ # (see fastworkflow/utils/chat_adapter.py) and is NOT included in the trajectory
76
+ # formatting to avoid token bloat across iterations.
74
77
  react_signature = (
75
78
  dspy.Signature({**signature.input_fields}, "\n".join(instr))
76
79
  .append("trajectory", dspy.InputField(), type_=str)
80
+ .append("available_commands", dspy.InputField(), type_=str)
77
81
  .append("next_thought", dspy.OutputField(), type_=str)
78
82
  .append("next_tool_name", dspy.OutputField(), type_=Literal[tuple(tools.keys())])
79
83
  .append("next_tool_args", dspy.OutputField(), type_=dict[str, Any])
@@ -82,7 +86,7 @@ class fastWorkflowReAct(Module):
82
86
  fallback_signature = dspy.Signature(
83
87
  {**signature.input_fields, **signature.output_fields},
84
88
  signature.instructions,
85
- ).append("trajectory", dspy.InputField(), type_=str)
89
+ ).append("trajectory", dspy.InputField(), type_=str).append("available_commands", dspy.InputField(), type_=str)
86
90
 
87
91
  self.tools = tools
88
92
  self.react = dspy.Predict(react_signature)
@@ -9,7 +9,7 @@ repository = "https://github.com/radiantlogicinc/fastworkflow"
9
9
 
10
10
  [tool.poetry]
11
11
  name = "fastworkflow"
12
- version = "2.17.5"
12
+ version = "2.17.7"
13
13
  description = "A framework for rapidly building large-scale, deterministic, interactive workflows with a fault-tolerant, conversational UX"
14
14
  authors = ["Dhar Rawal <drawal@radiantlogic.com>"]
15
15
  license = "Apache-2.0"
File without changes
File without changes