fastworkflow 2.22.3__tar.gz → 2.24.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/PKG-INFO +21 -4
  2. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/README.md +20 -3
  3. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/ErrorCorrection/you_misunderstood.py +4 -2
  4. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/wildcard.py +10 -10
  5. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/intent_detection.py +46 -4
  6. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/parameter_extraction.py +113 -8
  7. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/chat_session.py +11 -2
  8. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/cli.py +13 -0
  9. fastworkflow-2.24.0/fastworkflow/distillation.py +927 -0
  10. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/model_pipeline_training.py +532 -67
  11. fastworkflow-2.24.0/fastworkflow/nlu_labels.py +96 -0
  12. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run/__main__.py +13 -1
  13. fastworkflow-2.24.0/fastworkflow/train/__main__.py +600 -0
  14. fastworkflow-2.24.0/fastworkflow/train/artifact_versioning.py +1120 -0
  15. fastworkflow-2.24.0/fastworkflow/train/class_balance.py +221 -0
  16. fastworkflow-2.24.0/fastworkflow/train/determinism.py +362 -0
  17. fastworkflow-2.24.0/fastworkflow/train/duplicate_detection.py +753 -0
  18. fastworkflow-2.24.0/fastworkflow/train/generate_synthetic.py +767 -0
  19. fastworkflow-2.24.0/fastworkflow/train/heldout_evaluation.py +963 -0
  20. fastworkflow-2.24.0/fastworkflow/train/param_example_cache.py +504 -0
  21. fastworkflow-2.24.0/fastworkflow/train/personas.py +721 -0
  22. fastworkflow-2.24.0/fastworkflow/train/selective_training.py +1327 -0
  23. fastworkflow-2.24.0/fastworkflow/train/training_report.py +1122 -0
  24. fastworkflow-2.24.0/fastworkflow/train/utterance_cache.py +639 -0
  25. fastworkflow-2.24.0/fastworkflow/utils/generate_param_examples.py +1118 -0
  26. fastworkflow-2.24.0/fastworkflow/utils/insights_loader.py +67 -0
  27. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/react.py +50 -12
  28. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/signatures.py +42 -13
  29. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/workflow_agent.py +90 -30
  30. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/workflow_execution_context.py +104 -36
  31. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/pyproject.toml +1 -1
  32. fastworkflow-2.22.3/fastworkflow/train/__main__.py +0 -299
  33. fastworkflow-2.22.3/fastworkflow/train/generate_synthetic.py +0 -158
  34. fastworkflow-2.22.3/fastworkflow/utils/generate_param_examples.py +0 -638
  35. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/LICENSE +0 -0
  36. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/.DS_Store +0 -0
  37. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/__init__.py +0 -0
  38. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_commands/.gitkeep +0 -0
  39. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/__init__.py +0 -0
  40. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/__init__.py +0 -0
  41. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/ErrorCorrection/abort.py +0 -0
  42. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/go_up.py +0 -0
  43. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/reset_context.py +0 -0
  44. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/what_can_i_do.py +0 -0
  45. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/what_is_current_context.py +0 -0
  46. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/__init__.py +0 -0
  47. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/command_context_model.json +0 -0
  48. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/active_workflow.py +0 -0
  49. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/__main__.py +0 -0
  50. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/ast_class_extractor.py +0 -0
  51. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/class_analysis_structures.py +0 -0
  52. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/cli_specification.md +0 -0
  53. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/command_dependency_resolver.py +0 -0
  54. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/command_file_generator.py +0 -0
  55. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/command_file_template.py +0 -0
  56. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/command_import_utils.py +0 -0
  57. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/command_stub_generator.py +0 -0
  58. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/context_folder_generator.py +0 -0
  59. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/context_model_generator.py +0 -0
  60. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/dependency_manager.py +0 -0
  61. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/dir_scanner.py +0 -0
  62. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/documentation_generator.py +0 -0
  63. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/genai_postprocessor.py +0 -0
  64. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/inheritance_block_regenerator.py +0 -0
  65. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/libcst_transformers.py +0 -0
  66. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/navigator_stub_generator.py +0 -0
  67. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/pydantic_model_generator.py +0 -0
  68. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/utterance_generator.py +0 -0
  69. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/cache_matching.py +0 -0
  70. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/command_context_model.py +0 -0
  71. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/command_directory.py +0 -0
  72. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/command_executor.py +0 -0
  73. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/command_interfaces.py +0 -0
  74. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/command_metadata_api.py +0 -0
  75. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/command_routing.py +0 -0
  76. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/conversation_history_io.py +0 -0
  77. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/docs/context_modules_prd.txt +0 -0
  78. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/docs/integrate-chat-agent/SKILL.md +0 -0
  79. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/docs/integrate-chat-agent/reference.md +0 -0
  80. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/extended_workflow_example/README.md +0 -0
  81. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/extended_workflow_example/_commands/WorkItem/get_status.py +0 -0
  82. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/extended_workflow_example/_commands/generate_report.py +0 -0
  83. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/extended_workflow_example/_commands/startup.py +0 -0
  84. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/extended_workflow_example/simple_workflow_template.json +0 -0
  85. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/extended_workflow_example/workflow_inheritance_model.json +0 -0
  86. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/fastworkflow.env +0 -0
  87. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/fastworkflow.passwords.env +0 -0
  88. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/hello_world/_commands/README.md +0 -0
  89. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/hello_world/_commands/add_two_numbers.py +0 -0
  90. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/hello_world/_commands/context_inheritance_model.json +0 -0
  91. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/hello_world/application/add_two_numbers.py +0 -0
  92. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_1/_commands/context_inheritance_model.json +0 -0
  93. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_1/_commands/send_message.py +0 -0
  94. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_1/application/send_message.py +0 -0
  95. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_2/_commands/User/send_message.py +0 -0
  96. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_2/_commands/context_inheritance_model.json +0 -0
  97. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_2/_commands/startup.py +0 -0
  98. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_2/application/user.py +0 -0
  99. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_3/_commands/PremiumUser/send_priority_message.py +0 -0
  100. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_3/_commands/User/send_message.py +0 -0
  101. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_3/_commands/context_inheritance_model.json +0 -0
  102. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_3/_commands/initialize_user.py +0 -0
  103. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_3/application/user.py +0 -0
  104. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/_ChatRoom.py +0 -0
  105. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/add_user.py +0 -0
  106. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/broadcast_message.py +0 -0
  107. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/get_current_user.py +0 -0
  108. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/list_users.py +0 -0
  109. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/set_current_user.py +0 -0
  110. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/PremiumUser/_PremiumUser.py +0 -0
  111. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/PremiumUser/send_priority_message.py +0 -0
  112. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/User/_User.py +0 -0
  113. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/User/send_message.py +0 -0
  114. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/context_inheritance_model.json +0 -0
  115. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/set_root_context.py +0 -0
  116. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/application/chatroom.py +0 -0
  117. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/application/user.py +0 -0
  118. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/context_hierarchy_model.json +0 -0
  119. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/startup_action.json +0 -0
  120. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/calculate.py +0 -0
  121. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/cancel_pending_order.py +0 -0
  122. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/exchange_delivered_order_items.py +0 -0
  123. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/find_user_id_by_email.py +0 -0
  124. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/find_user_id_by_name_zip.py +0 -0
  125. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/get_order_details.py +0 -0
  126. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/get_product_details.py +0 -0
  127. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/get_user_details.py +0 -0
  128. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/list_all_product_types.py +0 -0
  129. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_address.py +0 -0
  130. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_items.py +0 -0
  131. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_payment.py +0 -0
  132. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/modify_user_address.py +0 -0
  133. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/return_delivered_order_items.py +0 -0
  134. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/transfer_to_human_agents.py +0 -0
  135. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/context_inheritance_model.json +0 -0
  136. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/retail_data/__init__.py +0 -0
  137. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/retail_data/orders.json +0 -0
  138. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/retail_data/products.json +0 -0
  139. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/retail_data/users.json +0 -0
  140. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/calculate.py +0 -0
  141. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/cancel_pending_order.py +0 -0
  142. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/exchange_delivered_order_items.py +0 -0
  143. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/find_user_id_by_email.py +0 -0
  144. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/find_user_id_by_name_zip.py +0 -0
  145. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/get_order_details.py +0 -0
  146. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/get_product_details.py +0 -0
  147. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/get_user_details.py +0 -0
  148. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/list_all_product_types.py +0 -0
  149. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_address.py +0 -0
  150. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_items.py +0 -0
  151. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_payment.py +0 -0
  152. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/modify_user_address.py +0 -0
  153. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/return_delivered_order_items.py +0 -0
  154. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/think.py +0 -0
  155. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/tool.py +0 -0
  156. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/transfer_to_human_agents.py +0 -0
  157. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/workflow_description.txt +0 -0
  158. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/__init__.py +0 -0
  159. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/_WorkItem.py +0 -0
  160. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/add_child_workitem.py +0 -0
  161. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/get_status.py +0 -0
  162. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/go_to_workitem.py +0 -0
  163. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/mark_as_complete.py +0 -0
  164. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_first_child_workitem.py +0 -0
  165. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_last_child_workitem.py +0 -0
  166. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_next_workitem.py +0 -0
  167. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_previous_workitem.py +0 -0
  168. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/remove_all_child_workitems.py +0 -0
  169. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/remove_child_workitem.py +0 -0
  170. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/show_schema.py +0 -0
  171. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/startup.py +0 -0
  172. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/application/__init__.py +0 -0
  173. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/application/workitem.py +0 -0
  174. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/simple_workflow_template.json +0 -0
  175. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/startup_action.json +0 -0
  176. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/intent_clarification_agent.py +0 -0
  177. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/mcp_server.py +0 -0
  178. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/refine/__main__.py +0 -0
  179. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run/__init__.py +0 -0
  180. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/README.md +0 -0
  181. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/__init__.py +0 -0
  182. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/__main__.py +0 -0
  183. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/conversation_store.py +0 -0
  184. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/jwt_manager.py +0 -0
  185. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/mcp_specific.py +0 -0
  186. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/redoc_2_standalone_html.py +0 -0
  187. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/turns.py +0 -0
  188. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/utils.py +0 -0
  189. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/session_state_store.py +0 -0
  190. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/train/__init__.py +0 -0
  191. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/turn.py +0 -0
  192. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/user_message_queues.py +0 -0
  193. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/__init__.py +0 -0
  194. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/chat_adapter.py +0 -0
  195. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/context_utils.py +0 -0
  196. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/dspy_cache_utils.py +0 -0
  197. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/dspy_logger.py +0 -0
  198. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/dspy_utils.py +0 -0
  199. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/env.py +0 -0
  200. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/fuzzy_match.py +0 -0
  201. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/logging.py +0 -0
  202. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/parameterize_func_decorator.py +0 -0
  203. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/pydantic_model_2_dspy_signature_class.py +0 -0
  204. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/python_utils.py +0 -0
  205. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/startup_progress.py +0 -0
  206. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/workflow.py +0 -0
  207. {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/workflow_inheritance_model.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastworkflow
3
- Version: 2.22.3
3
+ Version: 2.24.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
@@ -54,7 +54,7 @@ Description-Content-Type: text/markdown
54
54
  <!-- Logo and Title -->
55
55
  <img src="logo.png" height="64" alt="fastWorkflow Logo and Title">
56
56
 
57
- [![License](https://img.shields.io/badge/license-Apache%202.0-blue)](LICENSE) [![PyPI](https://img.shields.io/pypi/v/fastworkflow)](https://pypi.org/project/fastworkflow/) [![CI](https://img.shields.io/badge/ci-passing-brightgreen)](https://github.com/radiantlogicinc/fastworkflow/actions) [![Discord](https://img.shields.io/badge/Discord-Join-5865F2)](https://discord.gg/k2g58dDjYR)
57
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue)](LICENSE) [![PyPI](https://img.shields.io/pypi/v/fastworkflow)](https://pypi.org/project/fastworkflow/) [![CI](https://img.shields.io/badge/ci-passing-brightgreen)](https://github.com/radiantlogicinc/fastworkflow/actions) [![Discord](https://img.shields.io/badge/Discord-Join-5865F2)](https://discord.gg/k2g58dDjYR) [![Paper](https://img.shields.io/badge/Paper-alphaXiv-red)](https://www.alphaxiv.org/abs/2605.fastworkflow)
58
58
 
59
59
  **Build AI agents your application can actually trust in production — with small models cheaply, or frontier models more reliably.**
60
60
 
@@ -138,11 +138,11 @@ fastWorkflow was benchmarked on [Tau Bench](https://github.com/sierra-research/t
138
138
  <table>
139
139
  <tr>
140
140
  <td align="center" width="50%">
141
- <img src="fastWorkflow - Tau Bench Retail.jpg" alt="fastWorkflow Tau Bench Retail results" style="max-width: 100%; height: auto;"/>
141
+ <img src="tau_bench_retail_performance.png" alt="fastWorkflow Tau Bench Retail results" style="max-width: 100%; height: auto;"/>
142
142
  <br/><em>Retail: orders, returns, account operations</em>
143
143
  </td>
144
144
  <td align="center" width="50%">
145
- <img src="fastWorkflow - TauBench Airline.jpg" alt="fastWorkflow Tau Bench Airline results" style="max-width: 100%; height: auto;"/>
145
+ <img src="tau_bench_airline_performance.png" alt="fastWorkflow Tau Bench Airline results" style="max-width: 100%; height: auto;"/>
146
146
  <br/><em>Airline: rebooking, baggage, loyalty workflows</em>
147
147
  </td>
148
148
  </tr>
@@ -209,6 +209,14 @@ You'll get a `User >` prompt. Try **"what can you do?"** or **"add 49 + 51"**. R
209
209
 
210
210
  > [!note]
211
211
  > **"Train" doesn't mean GPUs or fine-tuning a foundation model.** `fastworkflow train` is closer to *compiling a conversational interface*: it generates synthetic utterances and fits small BERT-class intent classifiers for your commands. You run it once per command set, re-run it only when commands change, ship the resulting artifacts with your app, and need **no GPU at runtime**.
212
+ >
213
+ > Training manages its own safety and incremental work. It checks command seeds for
214
+ > duplicate capabilities before making LLM calls, warns when commands have thin seed
215
+ > coverage, reuses cached utterances, and retrains only affected contexts when that is
216
+ > provably safe. Global changes or an incomplete baseline automatically trigger a full
217
+ > retrain. Models are published atomically; fastWorkflow retains only the current model
218
+ > set and one previous recovery point. Use `--regenerate-utterances` only when you
219
+ > intentionally want to discard the generated-data caches.
212
220
 
213
221
  > [!tip]
214
222
  > Get a free API key from [Mistral AI](https://mistral.ai) (works with `mistral-small-latest`) or [OpenRouter](https://openrouter.ai/openai/gpt-oss-20b:free). You can assign different models to different roles in the same workflow.
@@ -291,6 +299,15 @@ class ResponseGenerator:
291
299
 
292
300
  Then `fastworkflow train` and `fastworkflow run` against your workflow directory. That's the entire integration pattern: a thin command layer over code you already have.
293
301
 
302
+ > [!TIP]
303
+ > `plain_utterances` is the highest-leverage thing you write. Training expands your seeds
304
+ > into the synthetic corpus the intent classifier learns from, so seed count and phrasing
305
+ > variety matter more to routing accuracy than any other dial. The two above are enough to
306
+ > get started; before you ship, grow each command to roughly eight varied phrasings —
307
+ > imperative, question, colloquial, terse — rather than paraphrases of one sentence. (The
308
+ > "roughly eight" figure is where returns flattened on one large internal workflow, not a
309
+ > universal constant.)
310
+
294
311
  > [!tip]
295
312
  > Prefer to learn by building the smallest possible workflow by hand first? `fastworkflow examples fetch messaging_app_1` is a minimal, fully-worked single-command workflow you can read end-to-end.
296
313
 
@@ -1,7 +1,7 @@
1
1
  <!-- Logo and Title -->
2
2
  <img src="logo.png" height="64" alt="fastWorkflow Logo and Title">
3
3
 
4
- [![License](https://img.shields.io/badge/license-Apache%202.0-blue)](LICENSE) [![PyPI](https://img.shields.io/pypi/v/fastworkflow)](https://pypi.org/project/fastworkflow/) [![CI](https://img.shields.io/badge/ci-passing-brightgreen)](https://github.com/radiantlogicinc/fastworkflow/actions) [![Discord](https://img.shields.io/badge/Discord-Join-5865F2)](https://discord.gg/k2g58dDjYR)
4
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue)](LICENSE) [![PyPI](https://img.shields.io/pypi/v/fastworkflow)](https://pypi.org/project/fastworkflow/) [![CI](https://img.shields.io/badge/ci-passing-brightgreen)](https://github.com/radiantlogicinc/fastworkflow/actions) [![Discord](https://img.shields.io/badge/Discord-Join-5865F2)](https://discord.gg/k2g58dDjYR) [![Paper](https://img.shields.io/badge/Paper-alphaXiv-red)](https://www.alphaxiv.org/abs/2605.fastworkflow)
5
5
 
6
6
  **Build AI agents your application can actually trust in production — with small models cheaply, or frontier models more reliably.**
7
7
 
@@ -85,11 +85,11 @@ fastWorkflow was benchmarked on [Tau Bench](https://github.com/sierra-research/t
85
85
  <table>
86
86
  <tr>
87
87
  <td align="center" width="50%">
88
- <img src="fastWorkflow - Tau Bench Retail.jpg" alt="fastWorkflow Tau Bench Retail results" style="max-width: 100%; height: auto;"/>
88
+ <img src="tau_bench_retail_performance.png" alt="fastWorkflow Tau Bench Retail results" style="max-width: 100%; height: auto;"/>
89
89
  <br/><em>Retail: orders, returns, account operations</em>
90
90
  </td>
91
91
  <td align="center" width="50%">
92
- <img src="fastWorkflow - TauBench Airline.jpg" alt="fastWorkflow Tau Bench Airline results" style="max-width: 100%; height: auto;"/>
92
+ <img src="tau_bench_airline_performance.png" alt="fastWorkflow Tau Bench Airline results" style="max-width: 100%; height: auto;"/>
93
93
  <br/><em>Airline: rebooking, baggage, loyalty workflows</em>
94
94
  </td>
95
95
  </tr>
@@ -156,6 +156,14 @@ You'll get a `User >` prompt. Try **"what can you do?"** or **"add 49 + 51"**. R
156
156
 
157
157
  > [!note]
158
158
  > **"Train" doesn't mean GPUs or fine-tuning a foundation model.** `fastworkflow train` is closer to *compiling a conversational interface*: it generates synthetic utterances and fits small BERT-class intent classifiers for your commands. You run it once per command set, re-run it only when commands change, ship the resulting artifacts with your app, and need **no GPU at runtime**.
159
+ >
160
+ > Training manages its own safety and incremental work. It checks command seeds for
161
+ > duplicate capabilities before making LLM calls, warns when commands have thin seed
162
+ > coverage, reuses cached utterances, and retrains only affected contexts when that is
163
+ > provably safe. Global changes or an incomplete baseline automatically trigger a full
164
+ > retrain. Models are published atomically; fastWorkflow retains only the current model
165
+ > set and one previous recovery point. Use `--regenerate-utterances` only when you
166
+ > intentionally want to discard the generated-data caches.
159
167
 
160
168
  > [!tip]
161
169
  > Get a free API key from [Mistral AI](https://mistral.ai) (works with `mistral-small-latest`) or [OpenRouter](https://openrouter.ai/openai/gpt-oss-20b:free). You can assign different models to different roles in the same workflow.
@@ -238,6 +246,15 @@ class ResponseGenerator:
238
246
 
239
247
  Then `fastworkflow train` and `fastworkflow run` against your workflow directory. That's the entire integration pattern: a thin command layer over code you already have.
240
248
 
249
+ > [!TIP]
250
+ > `plain_utterances` is the highest-leverage thing you write. Training expands your seeds
251
+ > into the synthetic corpus the intent classifier learns from, so seed count and phrasing
252
+ > variety matter more to routing accuracy than any other dial. The two above are enough to
253
+ > get started; before you ship, grow each command to roughly eight varied phrasings —
254
+ > imperative, question, colloquial, terse — rather than paraphrases of one sentence. (The
255
+ > "roughly eight" figure is where returns flattened on one large internal workflow, not a
256
+ > universal constant.)
257
+
241
258
  > [!tip]
242
259
  > Prefer to learn by building the smallest possible workflow by hand first? `fastworkflow examples fetch messaging_app_1` is a minimal, fully-worked single-command workflow you can read end-to-end.
243
260
 
@@ -60,8 +60,10 @@ class ResponseGenerator:
60
60
  ])
61
61
  )
62
62
  response = (
63
- "Please select the correct command name from the list below:\n"
64
- f"{response}\n\nor type 'abort' to cancel"
63
+ "I couldn't determine which available command matches your request.\n"
64
+ "If one of these options applies, enter its command name:\n"
65
+ f"{response}\n\n"
66
+ "Otherwise, type 'abort' to cancel, then rephrase your request."
65
67
  )
66
68
 
67
69
  return CommandOutput(
@@ -1,27 +1,27 @@
1
1
  import fastworkflow
2
2
  from fastworkflow import Action, CommandOutput, CommandResponse, NLUPipelineStage
3
3
  from fastworkflow.command_executor import CommandExecutor
4
+ from fastworkflow.nlu_labels import PARAMETER_VALUE_PLACEHOLDERS
4
5
 
5
6
  from ..intent_detection import CommandNamePrediction
6
7
  from ..parameter_extraction import ParameterExtraction
7
8
 
8
9
 
9
10
  class Signature:
10
- plain_utterances = [
11
- "3",
12
- "france",
13
- "16.7,.002",
14
- "John Doe, 56, 281-995-6423",
15
- "/path/to/my/object",
16
- "id=3636",
17
- "25.73 and Howard St",
18
- ]
11
+ # These are the PARAMETER_EXTRACTION stage's bare-value literals. They belong
12
+ # to nlu_labels.PARAMETER_VALUE_LABEL, not to this command's INTENT_DETECTION
13
+ # escalation class; see fastworkflow/nlu_labels.py for the stage split.
14
+ plain_utterances = list(PARAMETER_VALUE_PLACEHOLDERS)
19
15
 
20
16
  @staticmethod
21
17
  def generate_utterances(workflow: fastworkflow.Workflow, command_name: str) -> list[str]:
18
+ # Only the humanised command name. The placeholders above are excluded on
19
+ # purpose: training them into the 'wildcard' label taught the escalation
20
+ # classifier that a bare value like "france" means "escalate to my
21
+ # parent". The trainer labels them under PARAMETER_VALUE_LABEL instead.
22
22
  return [
23
23
  command_name.split('/')[-1].lower().replace('_', ' ')
24
- ] + Signature.plain_utterances
24
+ ]
25
25
 
26
26
 
27
27
  class ResponseGenerator:
@@ -13,10 +13,16 @@ from fastworkflow.cache_matching import cache_match, store_utterance_cache
13
13
  from fastworkflow.model_pipeline_training import (
14
14
  CommandRouter
15
15
  )
16
+ from fastworkflow.nlu_labels import is_escalation, is_non_routable
16
17
 
17
18
  from fastworkflow.utils.fuzzy_match import find_best_matches
18
19
 
19
20
 
21
+ # A low-confidence top-k prediction containing an escalation label remains an
22
+ # ambiguity: prompt with the local command candidates and log that the parent signal
23
+ # was discarded. This is product behaviour, not workflow configuration.
24
+
25
+
20
26
  class CommandNamePrediction:
21
27
  class Output(BaseModel):
22
28
  command_name: Optional[str] = None
@@ -125,6 +131,17 @@ class CommandNamePrediction:
125
131
  command_name = predictions[0].split('/')[-1]
126
132
  else:
127
133
  # If confidence is low, treat as ambiguous command (type 1)
134
+ if escalation_signals := self.escalation_signals_in(predictions):
135
+ logger.warning(
136
+ f"Top-k escalation signal discarded in "
137
+ f"context '{command_context_name}' for utterance "
138
+ f"'{command}'. predictions={predictions}, "
139
+ f"suppressed={escalation_signals}. The classifier ranked "
140
+ "an escalation label alongside local candidates; the user "
141
+ "will be prompted with the local candidates only and the "
142
+ "'this belongs to an ancestor context' signal is dropped."
143
+ )
144
+
128
145
  error_msg = self._formulate_ambiguous_command_error_message(
129
146
  predictions, "run_as_agent" in self.app_workflow.context)
130
147
 
@@ -138,11 +155,11 @@ class CommandNamePrediction:
138
155
  ) and not command_name:
139
156
  command_name = "what can i do?"
140
157
 
141
- if not command_name or command_name == "wildcard":
142
- fully_qualified_command_name=None
158
+ fully_qualified_command_name = self.resolve_fully_qualified_command_name(
159
+ command_name, command_name_dict)
160
+ if fully_qualified_command_name is None:
143
161
  is_cme_command=False
144
162
  else:
145
- fully_qualified_command_name = command_name_dict[command_name]
146
163
  is_cme_command=(
147
164
  fully_qualified_command_name in cme_command_names or
148
165
  fully_qualified_command_name in crd.get_command_names('ErrorCorrection')
@@ -154,6 +171,9 @@ class CommandNamePrediction:
154
171
  NLUPipelineStage.INTENT_AMBIGUITY_CLARIFICATION,
155
172
  NLUPipelineStage.INTENT_MISUNDERSTANDING_CLARIFICATION,
156
173
  )
174
+ # A reserved label resolves to None; the clarification cache keys on a
175
+ # real command name, so there is nothing to store for it.
176
+ and fully_qualified_command_name is not None
157
177
  and not fully_qualified_command_name.endswith('abort')
158
178
  and not fully_qualified_command_name.endswith('what_can_i_do')
159
179
  and not fully_qualified_command_name.endswith('you_misunderstood')
@@ -277,13 +297,35 @@ class CommandNamePrediction:
277
297
  finally:
278
298
  db.close()
279
299
 
300
+ @staticmethod
301
+ def resolve_fully_qualified_command_name(
302
+ command_name: Optional[str], command_name_dict: dict[str, str]) -> Optional[str]:
303
+ """Map a predicted label to a fully qualified command name, or None.
304
+
305
+ Reserved labels (`wildcard`, `parameter_value`) name no command, so they
306
+ must resolve to None rather than be looked up in `command_name_dict` —
307
+ which would raise KeyError. None is what drives the parent-chain walk in
308
+ the CME wildcard command.
309
+ """
310
+ if not command_name or is_non_routable(command_name):
311
+ return None
312
+ return command_name_dict[command_name]
313
+
314
+ @staticmethod
315
+ def escalation_signals_in(route_choice_list: list[str]) -> list[str]:
316
+ """Return the escalation labels present in a prediction list."""
317
+ return [
318
+ route_choice for route_choice in route_choice_list
319
+ if is_escalation(route_choice)
320
+ ]
321
+
280
322
  @staticmethod
281
323
  def _formulate_ambiguous_command_error_message(
282
324
  route_choice_list: list[str], run_as_agent: bool) -> str:
283
325
  command_list = (
284
326
  "\n".join([
285
327
  f"{route_choice.split('/')[-1].lower()}"
286
- for route_choice in route_choice_list if route_choice != 'wildcard'
328
+ for route_choice in route_choice_list if not is_non_routable(route_choice)
287
329
  ])
288
330
  )
289
331
 
@@ -1,7 +1,9 @@
1
1
  import contextlib
2
2
  import sys
3
3
  import re
4
- from typing import Dict, List, Optional
4
+ import json
5
+ import ast
6
+ from typing import Dict, List, Optional, Union, get_origin, get_args
5
7
 
6
8
  from pydantic import BaseModel
7
9
  from pydantic_core import PydanticUndefined
@@ -24,6 +26,24 @@ INVALID = fastworkflow.get_env_var("INVALID")
24
26
  PARAMETER_EXTRACTION_ERROR_MSG = None
25
27
 
26
28
 
29
+ def _unwrap_optional(field_type):
30
+ """
31
+ Unwrap ``Optional[X]`` / ``Union[X, None]`` to its underlying type.
32
+
33
+ Returns ``(inner_type, origin)`` where ``origin`` is ``get_origin`` of the
34
+ unwrapped type (e.g. ``list`` for ``Optional[List[str]]``). Non-optional
35
+ types are returned unchanged.
36
+ """
37
+ origin = get_origin(field_type)
38
+ if origin is Union:
39
+ if non_none_types := [
40
+ t for t in get_args(field_type) if t is not type(None)
41
+ ]:
42
+ field_type = non_none_types[0]
43
+ origin = get_origin(field_type)
44
+ return field_type, origin
45
+
46
+
27
47
  class ParameterExtraction:
28
48
  class Output(BaseModel):
29
49
  parameters_are_valid: bool
@@ -90,14 +110,22 @@ class ParameterExtraction:
90
110
  self.app_workflow, self.command_name, new_params
91
111
  )
92
112
 
93
- # Set all the missing and invalid fields to None before storing
113
+ # Set all the missing and invalid fields to appropriate sentinel values before storing
94
114
  current_values = {
95
115
  field_name: getattr(new_params, field_name, None)
96
116
  for field_name in list(type(new_params).model_fields.keys())
97
117
  }
98
118
  for field_name in missing_invalid_fields:
99
119
  if field_name in current_values:
100
- current_values[field_name] = NOT_FOUND
120
+ # Determine appropriate sentinel value based on field type
121
+ field_info = type(new_params).model_fields[field_name]
122
+ _, origin = _unwrap_optional(field_info.annotation)
123
+
124
+ # Use empty list for list fields, NOT_FOUND for others
125
+ if origin in (list, List):
126
+ current_values[field_name] = []
127
+ else:
128
+ current_values[field_name] = NOT_FOUND
101
129
  # Reconstruct the model instance without validation
102
130
  new_params = new_params.__class__.model_construct(**current_values)
103
131
 
@@ -233,13 +261,17 @@ class ParameterExtraction:
233
261
  value = getattr(params, field_name, None)
234
262
 
235
263
  if value in [
236
- NOT_FOUND,
264
+ NOT_FOUND,
237
265
  None,
238
266
  INVALID_INT_VALUE,
239
267
  INVALID_FLOAT_VALUE
240
268
  ]:
241
269
  continue
242
270
 
271
+ # Skip empty lists (sentinel for missing list fields)
272
+ if isinstance(value, list) and len(value) == 0:
273
+ continue
274
+
243
275
  display_name = " ".join(word.capitalize() for word in field_name.split('_'))
244
276
 
245
277
  # Format fields appropriately based on type
@@ -320,7 +352,22 @@ class ParameterExtraction:
320
352
  for field_name in field_names:
321
353
  # Look for <field_name>value</field_name> pattern
322
354
  pattern = rf'<{re.escape(field_name)}>(.+?)</{re.escape(field_name)}>'
323
- if match := re.search(pattern, command, re.DOTALL):
355
+ # For list-typed fields, an agent may repeat the tag once per item
356
+ # (e.g. <item_ids>a</item_ids> <item_ids>b</item_ids>). re.search
357
+ # would keep only the first, silently dropping the rest, so collect
358
+ # ALL occurrences with findall and hand the list parser every value.
359
+ _, forigin = _unwrap_optional(
360
+ command_parameters_class.model_fields[field_name].annotation
361
+ )
362
+ if forigin in (list, List):
363
+ matches = re.findall(pattern, command, re.DOTALL)
364
+ if len(matches) > 1:
365
+ # Multiple repeated tags -> JSON array so the list parser
366
+ # below collects every value (not just the first).
367
+ extracted_data[field_name] = json.dumps([m.strip() for m in matches])
368
+ elif len(matches) == 1:
369
+ extracted_data[field_name] = matches[0].strip()
370
+ elif match := re.search(pattern, command, re.DOTALL):
324
371
  parameter_value = match[1].strip()
325
372
  extracted_data[field_name] = parameter_value
326
373
 
@@ -348,8 +395,66 @@ class ParameterExtraction:
348
395
  else:
349
396
  params_data[field_name] = None
350
397
 
351
- # Update with extracted values
352
- params_data |= extracted_data
398
+ # Parse and type-correct extracted values
399
+ for field_name, raw_value in extracted_data.items():
400
+ field_info = command_parameters_class.model_fields[field_name]
401
+ field_type, origin = _unwrap_optional(field_info.annotation)
402
+
403
+ # Handle list types with robust parsing
404
+ if origin in (list, List):
405
+ inner_type = get_args(field_type)[0] if get_args(field_type) else str
406
+ parsed_list = None
407
+
408
+ # Try JSON array format
409
+ if raw_value.startswith('[') and raw_value.endswith(']'):
410
+ with contextlib.suppress(Exception):
411
+ parsed = json.loads(raw_value)
412
+ if isinstance(parsed, list):
413
+ parsed_list = parsed
414
+
415
+ # Try Python literal format
416
+ if parsed_list is None:
417
+ with contextlib.suppress(Exception):
418
+ parsed = ast.literal_eval(raw_value)
419
+ if isinstance(parsed, list):
420
+ parsed_list = parsed
421
+
422
+ # Try comma-separated format
423
+ if parsed_list is None and ',' in raw_value:
424
+ parsed_list = [item.strip().strip('"').strip("'") for item in raw_value.split(',')]
425
+
426
+ # Try space-separated format
427
+ if parsed_list is None and ' ' in raw_value and not any(c in raw_value for c in ['[', ']', '{', '}', '"', "'"]):
428
+ parsed_list = [item.strip() for item in raw_value.split() if item.strip()]
429
+
430
+ # Single value treated as single-item list
431
+ if parsed_list is None:
432
+ cleaned = raw_value.strip().strip('"').strip("'")
433
+ parsed_list = [cleaned] if cleaned else []
434
+
435
+ # Type-convert list items to match the inner type
436
+ if parsed_list:
437
+ typed_list = []
438
+ for item in parsed_list:
439
+ if inner_type is str:
440
+ typed_list.append(str(item))
441
+ elif inner_type is int:
442
+ with contextlib.suppress(ValueError, TypeError):
443
+ typed_list.append(int(item))
444
+ elif inner_type is float:
445
+ with contextlib.suppress(ValueError, TypeError):
446
+ typed_list.append(float(item))
447
+ elif isinstance(inner_type, type) and issubclass(inner_type, BaseModel) and isinstance(item, dict):
448
+ with contextlib.suppress(Exception):
449
+ typed_list.append(inner_type(**item))
450
+ else:
451
+ typed_list.append(item)
452
+ params_data[field_name] = typed_list
453
+ else:
454
+ params_data[field_name] = []
455
+ else:
456
+ # Non-list types: use raw value as-is
457
+ params_data[field_name] = raw_value
353
458
 
354
459
  # Construct model without validation
355
460
  return command_parameters_class.model_construct(**params_data)
@@ -380,7 +485,7 @@ class ParameterExtraction:
380
485
  None,
381
486
  INVALID_INT_VALUE,
382
487
  INVALID_FLOAT_VALUE,
383
- ]:
488
+ ] or (isinstance(value, list) and len(value) == 0):
384
489
  fields_to_fill.append(field_name)
385
490
 
386
491
  if not fields_to_fill:
@@ -101,14 +101,17 @@ class ChatSession:
101
101
  def __init__(
102
102
  self,
103
103
  run_as_agent: bool = False,
104
+ generate_insights: bool = False,
104
105
  ):
105
106
  """
106
107
  Initialize a chat session.
107
-
108
+
108
109
  Args:
109
110
  run_as_agent: If True, use agent mode (DSPy-based tool selection).
110
111
  If False (default), use traditional command execution.
111
-
112
+ generate_insights: If True, enable teacher/student insights distillation
113
+ on each agent turn (Topology A / CLI only).
114
+
112
115
  A chat session can run multiple workflows that share the same message queues.
113
116
  Use start_workflow() to start a specific workflow within this session.
114
117
  ChatSession is Topology A: ask_user blocks on the queue until the human answers.
@@ -116,6 +119,7 @@ class ChatSession:
116
119
  self._core = WorkflowExecutionContext(
117
120
  run_as_agent=run_as_agent,
118
121
  mirror_action_log_to_file=True,
122
+ generate_insights=generate_insights,
119
123
  )
120
124
 
121
125
  # Create queues for user messages and command outputs (CLI transport)
@@ -275,6 +279,11 @@ class ChatSession:
275
279
  """Check if running in agent mode."""
276
280
  return self._core.run_as_agent
277
281
 
282
+ @property
283
+ def _distillation_insights_count(self) -> int:
284
+ """Number of insights extracted so far in insights-distillation mode."""
285
+ return self._core._distillation_insights_count
286
+
278
287
  @property
279
288
  def user_message_queue(self) -> Queue:
280
289
  return self._user_message_queue
@@ -244,8 +244,17 @@ def add_train_parser(subparsers):
244
244
  default=None,
245
245
  help="Path to the passwords file (default: passwords.env in current directory, or bundled env file for examples)",
246
246
  )
247
+ parser_train.add_argument(
248
+ "--regenerate-utterances",
249
+ action="store_true",
250
+ help="Ignore the generated-utterance and DSPy parameter-example caches and call "
251
+ "the LLM again. Costs money "
252
+ "and breaks reproducibility against previous runs; use after editing seed "
253
+ "utterances or when you suspect the cache is wrong.",
254
+ )
247
255
  parser_train.set_defaults(func=lambda args: train_with_defaults(args))
248
256
 
257
+
249
258
  def add_run_parser(subparsers):
250
259
  """Add subparser for the 'run' command."""
251
260
  parser_run = subparsers.add_parser("run", help="Run a workflow's interactive assistant.")
@@ -273,6 +282,10 @@ def add_run_parser(subparsers):
273
282
  "--assistant", action="store_true", default=False,
274
283
  help="Run in assistant (non-agentic) mode. Default is agentic mode.",
275
284
  )
285
+ parser_run.add_argument(
286
+ "--generate_insights", action="store_true", default=False,
287
+ help="Enable insights-distillation mode: compare teacher and student agents, extract planning and execution insights on divergence.",
288
+ )
276
289
  parser_run.set_defaults(func=lambda args: run_with_defaults(args))
277
290
 
278
291
  def add_run_fastapi_mcp_parser(subparsers):