fastworkflow 3.1.2__tar.gz → 3.2.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 (239) hide show
  1. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/PKG-INFO +99 -4
  2. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/README.md +98 -3
  3. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/__init__.py +17 -0
  4. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/_workflows/command_metadata_extraction/intent_detection.py +70 -2
  5. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/_workflows/command_metadata_extraction/parameter_extraction.py +45 -2
  6. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/chat_session.py +12 -1
  7. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/cli.py +63 -3
  8. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/command_executor.py +69 -0
  9. fastworkflow-3.2.0/fastworkflow/conversation_labeling.py +131 -0
  10. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/distillation.py +24 -30
  11. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/fastworkflow.env +14 -0
  12. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/kvstore.py +1 -1
  13. fastworkflow-3.2.0/fastworkflow/metrics.py +65 -0
  14. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/model_pipeline_training.py +27 -9
  15. fastworkflow-3.2.0/fastworkflow/observability_store.py +1862 -0
  16. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/run/__main__.py +40 -1
  17. fastworkflow-3.2.0/fastworkflow/run_chatbot/__init__.py +10 -0
  18. fastworkflow-3.2.0/fastworkflow/run_chatbot/launcher.py +504 -0
  19. fastworkflow-3.2.0/fastworkflow/run_chatbot/server.py +1297 -0
  20. fastworkflow-3.2.0/fastworkflow/run_chatbot/static/index.html +2820 -0
  21. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/run_fastapi_mcp/README.md +7 -0
  22. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/run_fastapi_mcp/__main__.py +478 -140
  23. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/run_fastapi_mcp/mcp_specific.py +7 -1
  24. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/run_fastapi_mcp/server_memory.py +97 -12
  25. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/run_fastapi_mcp/turns.py +166 -32
  26. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/run_fastapi_mcp/utils.py +263 -127
  27. fastworkflow-3.2.0/fastworkflow/skills_for_coding_fastworkflows/build-task-benchmarks/SKILL.md +260 -0
  28. fastworkflow-3.2.0/fastworkflow/skills_for_coding_fastworkflows/build-task-benchmarks/reference.md +340 -0
  29. fastworkflow-3.2.0/fastworkflow/skills_for_coding_fastworkflows/debug-workflow-conversations/SKILL.md +188 -0
  30. fastworkflow-3.2.0/fastworkflow/skills_for_coding_fastworkflows/debug-workflow-conversations/reference.md +272 -0
  31. fastworkflow-3.2.0/fastworkflow/skills_for_coding_fastworkflows/declare-parameter-producers/SKILL.md +137 -0
  32. fastworkflow-3.2.0/fastworkflow/skills_for_coding_fastworkflows/design-context-models/SKILL.md +215 -0
  33. fastworkflow-3.2.0/fastworkflow/skills_for_coding_fastworkflows/design-context-models/reference.md +174 -0
  34. fastworkflow-3.2.0/fastworkflow/skills_for_coding_fastworkflows/detect-duplicate-capabilities/SKILL.md +199 -0
  35. fastworkflow-3.2.0/fastworkflow/skills_for_coding_fastworkflows/evaluate-intent-routing/SKILL.md +183 -0
  36. {fastworkflow-3.1.2/fastworkflow/docs → fastworkflow-3.2.0/fastworkflow/skills_for_coding_fastworkflows}/integrate-chat-agent/SKILL.md +16 -0
  37. {fastworkflow-3.1.2/fastworkflow/docs → fastworkflow-3.2.0/fastworkflow/skills_for_coding_fastworkflows}/integrate-chat-agent/reference.md +3 -1
  38. fastworkflow-3.2.0/fastworkflow/skills_for_coding_fastworkflows/resolve-parameter-values/SKILL.md +156 -0
  39. fastworkflow-3.2.0/fastworkflow/skills_for_coding_fastworkflows/supply-training-personas/SKILL.md +188 -0
  40. fastworkflow-3.2.0/fastworkflow/skills_for_coding_fastworkflows/train-and-publish-models/SKILL.md +226 -0
  41. fastworkflow-3.2.0/fastworkflow/skills_for_coding_fastworkflows/train-and-publish-models/reference.md +177 -0
  42. fastworkflow-3.2.0/fastworkflow/skills_for_coding_fastworkflows/validate-command-parameters/SKILL.md +165 -0
  43. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/state_paths.py +22 -1
  44. fastworkflow-3.2.0/fastworkflow/tracing.py +417 -0
  45. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/train/__main__.py +20 -0
  46. fastworkflow-3.2.0/fastworkflow/train/metrics_persistence.py +242 -0
  47. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/turn.py +9 -0
  48. fastworkflow-3.2.0/fastworkflow/utils/dspy_logger.py +582 -0
  49. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/utils/dspy_utils.py +12 -2
  50. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/utils/react.py +87 -0
  51. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/utils/signatures.py +55 -5
  52. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/workflow.py +5 -4
  53. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/workflow_agent.py +109 -46
  54. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/workflow_execution_context.py +634 -24
  55. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/pyproject.toml +5 -2
  56. fastworkflow-3.1.2/fastworkflow/docs/context_modules_prd.txt +0 -41
  57. fastworkflow-3.1.2/fastworkflow/run_fastapi_mcp/conversation_store.py +0 -697
  58. fastworkflow-3.1.2/fastworkflow/utils/dspy_logger.py +0 -188
  59. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/LICENSE +0 -0
  60. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/.DS_Store +0 -0
  61. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/_commands/.gitkeep +0 -0
  62. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/_workflows/__init__.py +0 -0
  63. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/_workflows/command_metadata_extraction/__init__.py +0 -0
  64. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/ErrorCorrection/abort.py +0 -0
  65. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/ErrorCorrection/you_misunderstood.py +0 -0
  66. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/go_up.py +0 -0
  67. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/reset_context.py +0 -0
  68. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/what_can_i_do.py +0 -0
  69. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/what_is_current_context.py +0 -0
  70. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/__init__.py +0 -0
  71. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/wildcard.py +0 -0
  72. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/_workflows/command_metadata_extraction/command_context_model.json +0 -0
  73. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/active_workflow.py +0 -0
  74. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/__main__.py +0 -0
  75. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/ast_class_extractor.py +0 -0
  76. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/class_analysis_structures.py +0 -0
  77. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/cli_specification.md +0 -0
  78. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/command_dependency_resolver.py +0 -0
  79. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/command_file_generator.py +0 -0
  80. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/command_file_template.py +0 -0
  81. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/command_import_utils.py +0 -0
  82. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/command_stub_generator.py +0 -0
  83. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/context_folder_generator.py +0 -0
  84. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/context_model_generator.py +0 -0
  85. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/dependency_manager.py +0 -0
  86. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/dir_scanner.py +0 -0
  87. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/documentation_generator.py +0 -0
  88. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/genai_postprocessor.py +0 -0
  89. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/inheritance_block_regenerator.py +0 -0
  90. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/libcst_transformers.py +0 -0
  91. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/navigator_stub_generator.py +0 -0
  92. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/pydantic_model_generator.py +0 -0
  93. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/build/utterance_generator.py +0 -0
  94. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/cache_matching.py +0 -0
  95. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/checkpoint_store.py +0 -0
  96. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/command_context_model.py +0 -0
  97. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/command_directory.py +0 -0
  98. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/command_interfaces.py +0 -0
  99. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/command_metadata_api.py +0 -0
  100. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/command_routing.py +0 -0
  101. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/conversation_history_io.py +0 -0
  102. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/extended_workflow_example/README.md +0 -0
  103. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/extended_workflow_example/_commands/WorkItem/get_status.py +0 -0
  104. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/extended_workflow_example/_commands/generate_report.py +0 -0
  105. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/extended_workflow_example/_commands/startup.py +0 -0
  106. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/extended_workflow_example/simple_workflow_template.json +0 -0
  107. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/extended_workflow_example/workflow_inheritance_model.json +0 -0
  108. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/fastworkflow.passwords.env +0 -0
  109. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/hello_world/_commands/README.md +0 -0
  110. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/hello_world/_commands/add_two_numbers.py +0 -0
  111. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/hello_world/_commands/context_inheritance_model.json +0 -0
  112. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/hello_world/application/add_two_numbers.py +0 -0
  113. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_1/_commands/context_inheritance_model.json +0 -0
  114. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_1/_commands/send_message.py +0 -0
  115. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_1/application/send_message.py +0 -0
  116. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_2/_commands/User/_User.py +0 -0
  117. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_2/_commands/User/send_message.py +0 -0
  118. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_2/_commands/context_inheritance_model.json +0 -0
  119. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_2/_commands/startup.py +0 -0
  120. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_2/application/user.py +0 -0
  121. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_3/_commands/PremiumUser/_PremiumUser.py +0 -0
  122. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_3/_commands/PremiumUser/send_priority_message.py +0 -0
  123. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_3/_commands/User/_User.py +0 -0
  124. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_3/_commands/User/send_message.py +0 -0
  125. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_3/_commands/context_inheritance_model.json +0 -0
  126. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_3/_commands/initialize_user.py +0 -0
  127. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_3/application/user.py +0 -0
  128. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/_ChatRoom.py +0 -0
  129. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/add_user.py +0 -0
  130. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/broadcast_message.py +0 -0
  131. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/get_current_user.py +0 -0
  132. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/list_users.py +0 -0
  133. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/set_current_user.py +0 -0
  134. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_4/_commands/PremiumUser/_PremiumUser.py +0 -0
  135. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_4/_commands/PremiumUser/send_priority_message.py +0 -0
  136. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_4/_commands/User/_User.py +0 -0
  137. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_4/_commands/User/send_message.py +0 -0
  138. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_4/_commands/context_inheritance_model.json +0 -0
  139. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_4/_commands/set_root_context.py +0 -0
  140. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_4/application/chatroom.py +0 -0
  141. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_4/application/user.py +0 -0
  142. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_4/context_hierarchy_model.json +0 -0
  143. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/messaging_app_4/startup_action.json +0 -0
  144. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/_commands/calculate.py +0 -0
  145. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/_commands/cancel_pending_order.py +0 -0
  146. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/_commands/exchange_delivered_order_items.py +0 -0
  147. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/_commands/find_user_id_by_email.py +0 -0
  148. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/_commands/find_user_id_by_name_zip.py +0 -0
  149. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/_commands/get_order_details.py +0 -0
  150. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/_commands/get_product_details.py +0 -0
  151. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/_commands/get_user_details.py +0 -0
  152. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/_commands/list_all_product_types.py +0 -0
  153. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_address.py +0 -0
  154. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_items.py +0 -0
  155. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_payment.py +0 -0
  156. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/_commands/modify_user_address.py +0 -0
  157. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/_commands/return_delivered_order_items.py +0 -0
  158. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/_commands/transfer_to_human_agents.py +0 -0
  159. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/context_inheritance_model.json +0 -0
  160. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/retail_data/__init__.py +0 -0
  161. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/retail_data/orders.json +0 -0
  162. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/retail_data/products.json +0 -0
  163. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/retail_data/users.json +0 -0
  164. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/tools/calculate.py +0 -0
  165. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/tools/cancel_pending_order.py +0 -0
  166. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/tools/exchange_delivered_order_items.py +0 -0
  167. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/tools/find_user_id_by_email.py +0 -0
  168. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/tools/find_user_id_by_name_zip.py +0 -0
  169. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/tools/get_order_details.py +0 -0
  170. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/tools/get_product_details.py +0 -0
  171. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/tools/get_user_details.py +0 -0
  172. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/tools/list_all_product_types.py +0 -0
  173. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_address.py +0 -0
  174. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_items.py +0 -0
  175. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_payment.py +0 -0
  176. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/tools/modify_user_address.py +0 -0
  177. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/tools/return_delivered_order_items.py +0 -0
  178. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/tools/think.py +0 -0
  179. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/tools/tool.py +0 -0
  180. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/tools/transfer_to_human_agents.py +0 -0
  181. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/retail_workflow/workflow_description.txt +0 -0
  182. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/__init__.py +0 -0
  183. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/_WorkItem.py +0 -0
  184. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/add_child_workitem.py +0 -0
  185. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/get_status.py +0 -0
  186. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/go_to_workitem.py +0 -0
  187. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/mark_as_complete.py +0 -0
  188. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_first_child_workitem.py +0 -0
  189. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_last_child_workitem.py +0 -0
  190. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_next_workitem.py +0 -0
  191. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_previous_workitem.py +0 -0
  192. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/remove_all_child_workitems.py +0 -0
  193. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/remove_child_workitem.py +0 -0
  194. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/show_schema.py +0 -0
  195. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/_commands/startup.py +0 -0
  196. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/application/__init__.py +0 -0
  197. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/application/workitem.py +0 -0
  198. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/simple_workflow_template.json +0 -0
  199. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/examples/simple_workflow_template/startup_action.json +0 -0
  200. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/intent_clarification_agent.py +0 -0
  201. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/mcp_server.py +0 -0
  202. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/nlu_labels.py +0 -0
  203. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/refine/__main__.py +0 -0
  204. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/run/__init__.py +0 -0
  205. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/run_fastapi_mcp/__init__.py +0 -0
  206. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/run_fastapi_mcp/checkpoint.py +0 -0
  207. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/run_fastapi_mcp/jwt_manager.py +0 -0
  208. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/run_fastapi_mcp/redoc_2_standalone_html.py +0 -0
  209. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/serialization_hooks.py +0 -0
  210. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/session_state_store.py +0 -0
  211. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/state_serialization.py +0 -0
  212. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/storage_keys.py +0 -0
  213. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/train/__init__.py +0 -0
  214. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/train/artifact_versioning.py +0 -0
  215. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/train/class_balance.py +0 -0
  216. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/train/determinism.py +0 -0
  217. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/train/duplicate_detection.py +0 -0
  218. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/train/generate_synthetic.py +0 -0
  219. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/train/heldout_evaluation.py +0 -0
  220. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/train/param_example_cache.py +0 -0
  221. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/train/personas.py +0 -0
  222. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/train/selective_training.py +0 -0
  223. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/train/training_report.py +0 -0
  224. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/train/utterance_cache.py +0 -0
  225. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/user_message_queues.py +0 -0
  226. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/utils/__init__.py +0 -0
  227. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/utils/chat_adapter.py +0 -0
  228. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/utils/context_utils.py +0 -0
  229. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/utils/dspy_cache_utils.py +0 -0
  230. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/utils/env.py +0 -0
  231. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/utils/fuzzy_match.py +0 -0
  232. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/utils/generate_param_examples.py +0 -0
  233. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/utils/insights_loader.py +0 -0
  234. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/utils/logging.py +0 -0
  235. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/utils/parameterize_func_decorator.py +0 -0
  236. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/utils/pydantic_model_2_dspy_signature_class.py +0 -0
  237. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/utils/python_utils.py +0 -0
  238. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/utils/startup_progress.py +0 -0
  239. {fastworkflow-3.1.2 → fastworkflow-3.2.0}/fastworkflow/workflow_inheritance_model.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastworkflow
3
- Version: 3.1.2
3
+ Version: 3.2.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
@@ -167,6 +167,7 @@ fastWorkflow was benchmarked on [Tau Bench](https://github.com/sierra-research/t
167
167
  - [Quick Start: run an example in 5 minutes](#quick-start-run-an-example-in-5-minutes)
168
168
  - [AI-enable your own app (without restructuring it)](#ai-enable-your-own-app-without-restructuring-it)
169
169
  - [How complex workflows scale: context hierarchies](#how-complex-workflows-scale-context-hierarchies)
170
+ - [Chat with it and debug it: `run_chatbot`](#chat-with-it-and-debug-it-run_chatbot)
170
171
  - [Production deployment](#production-deployment)
171
172
  - [Developer FAQ](#developer-faq)
172
173
  - [Key concepts (going deeper)](#key-concepts-going-deeper)
@@ -238,10 +239,10 @@ class OrderService:
238
239
 
239
240
  ### Recommended: let a coding agent wrap it for you
240
241
 
241
- The fastest path for a non-trivial app is the **[integrate-chat-agent](./fastworkflow/docs/integrate-chat-agent) skill** with Cursor or Claude Code:
242
+ The fastest path for a non-trivial app is the **[integrate-chat-agent](./fastworkflow/skills_for_coding_fastworkflows/integrate-chat-agent) skill** with Cursor or Claude Code:
242
243
 
243
244
  ```text
244
- Open fastworkflow/docs/integrate-chat-agent/SKILL.md
245
+ Open fastworkflow/skills_for_coding_fastworkflows/integrate-chat-agent/SKILL.md
245
246
  Prompt: "Integrate a fastWorkflow chat agent for OrderService in orders.py"
246
247
  ```
247
248
 
@@ -352,6 +353,88 @@ This is what lets small models stay accurate as your app grows — and what keep
352
353
 
353
354
  ---
354
355
 
356
+ ## Chat with it and debug it: `run_chatbot`
357
+
358
+ When a turn does the wrong thing, the question is almost always *which stage* got it wrong: did intent detection pick the wrong command, did parameter extraction mis-fill an argument, or did the command itself fail? `run_chatbot` answers that without a debugger.
359
+
360
+ Every run records what it did to a per-workflow SQLite database, `observability.sqlite3`, under `FASTWORKFLOW_STATE_ROOT/workflows/<workflow-id>/`. `run_chatbot` is a local browser UI over the workflow: a chat client for driving new turns, and a trace viewer for everything that already happened.
361
+
362
+ ```sh
363
+ fastworkflow run_chatbot
364
+ ```
365
+
366
+ One command opens the workflow picker, then starts the selected workflow's FastAPI server for you (loopback-only, stopped when the chatbot exits), picks a free port, and connects the chat — no server URL, token, channel, workflow path, or env-file CLI arguments to fill in. Env files are auto-detected in the workflow directory and, for bundled workflows, the shared `examples/` directory. If either is missing, choose existing files in the browser or create owner-only workflow-local copies from the bundled templates.
367
+
368
+ ```
369
+ fastWorkflow Chatbot
370
+ pick a workflow in the browser (bundled examples
371
+ and local folders are listed; you can browse anywhere).
372
+
373
+ Open in your browser:
374
+
375
+ http://127.0.0.1:8901/?token=Bg4-uLpLdETJAsYbGzXbfRQdAEhitS6p8podPXmK25g
376
+ ```
377
+
378
+ Use that printed URL. It carries a one-off token, and requests without it are refused — so one you leave running is not readable by anything else on the machine. Pass `--server-port` to skip spawning and use a FastAPI server already running on that port. The page opens with a workflow picker: bundled examples plus a directory browser, with a **Switch workflow** button to change later.
379
+
380
+ ### Debug mode: what a turn actually did
381
+
382
+ Debug mode nests turns directly beneath their conversations (with a separate conversation-less group when needed), and opens any turn into a span tree — the nested record of the stages that ran, each with its duration, status, and attributes:
383
+
384
+ ```
385
+ fw.turn the whole logical turn (stable across ask_user suspensions)
386
+ ├── fw.planner.plan the agent's plan for the turn (fw.planner.replan on a re-plan)
387
+ │ └── fw.llm.call the planner's LLM request/response
388
+ └── fw.agent.execute the ReAct loop as a whole (attempts, final answer)
389
+ └── fw.agent.step one reasoning step: thought, chosen tool, observation
390
+ ├── fw.llm.call the step's reasoning LLM call (+ provider-native reasoning)
391
+ └── fw.agent.tool_call the agent invoking a command
392
+ └── fw.command.execute resolution + your business logic running
393
+ ├── fw.nlu.intent which matching layer decided, classifier
394
+ │ confidence vs threshold, candidates on ambiguity
395
+ └── fw.nlu.param_extraction extraction method, missing/invalid fields,
396
+ │ db_lookup outcomes, validation-hook verdict
397
+ └── fw.llm.call the LLM extraction call, when one ran
398
+ fw.ask_user a clarifying question, and how long the user took
399
+
400
+ (Deterministic "/"-mode turns skip the planner/agent layers: fw.command.execute
401
+ sits directly under fw.turn.)
402
+ ```
403
+
404
+ The diagnosis lives in the attributes of `fw.command.execute`. It records `raw_command` (the natural-language command the agent sent), `command_name` (what intent detection *resolved* it to), the extracted `parameters`, the `response_text`, and `success`. Comparing the first two is the whole trick:
405
+
406
+ - **`raw_command` was reasonable but `command_name` is the wrong command** → an intent-detection miss. Add seed utterances for that command and retrain.
407
+ - **`command_name` is right but `parameters` are wrong** → a parameter-extraction miss. Strengthen the `Field(description=…, examples=[…])` in that command's Signature.
408
+ - **Both right, span status is `error`** → the bug is in your own code, and `response_text` usually says how.
409
+
410
+ Two turn-level fields are worth knowing because they are deliberately independent. `status` is the turn's lifecycle (`completed`, `failed`, …) and `success` means every command in it succeeded. A turn that is `completed` but not `success` is the case worth hunting: a command failed and the agent wrote a confident answer over it.
411
+
412
+ Coding agents can run this diagnosis directly against the database: the wheel-shipped [`debug-workflow-conversations`](fastworkflow/skills_for_coding_fastworkflows/debug-workflow-conversations/SKILL.md) skill carries the failure-triage decision tree, the full schema and span-attribute contract, and the routing table from each diagnosis to the fastWorkflow feature (and companion skill) that fixes it.
413
+
414
+ The **Health** view reports the background writer's state and the database size, which is how you tell "no spans recorded" apart from "spans dropped under load."
415
+
416
+ ### Chat: drive the workflow from the browser
417
+
418
+ The Chat tab is connected the moment the workflow's server is ready (the first start loads models, so give it a moment — the page tells you what it is waiting on). Every turn is recorded like any other, so you can send a message and immediately open its span tree via its **view trace** link or the Debug tab.
419
+
420
+ Messages go to `/invoke_agent`; prefix one with `/` to force deterministic execution via `/invoke_assistant`, the same convention as the CLI prompt. **New conversation** in the header archives the current thread and starts a fresh one, like the CLI's `//new`. Sessions are single-developer by design: the chatbot manages one fixed private channel (`chatbot`), so there is nothing multi-user to configure and your history is in one place across launches.
421
+
422
+ There is deliberately no box for a startup command or a per-session context: the session is driven by what you type, so pre-seeding it from a chat form makes no sense. Those stay launch-time decisions — `run_fastapi_mcp --startup_command`, or the `/initialize` request fields if you are calling the API yourself.
423
+
424
+ A spawned server always binds `127.0.0.1`, has CORS pinned to loopback origins, and is stopped when the chatbot exits (SIGTERM included). It runs with unsigned dev JWTs — fine for a loopback-only dev server whose tokens the chatbot mints itself; pass `--expect-encrypted-jwt` to require signed tokens instead (then paste one in the chat's Advanced panel). Already have a server running? Launch with `--server-port <port>` and connect via the Advanced panel.
425
+
426
+ Insights distillation (`fastworkflow run --generate_insights`) stays CLI-only by design, as do bind address and env-file choices for externally managed servers. The full capability comparison is in [`docs/run_chatbot_cli_parity.md`](docs/run_chatbot_cli_parity.md).
427
+
428
+ ### Retention and erasure
429
+
430
+ Trace data grows. Spans and artifacts are pruned beyond a retention horizon; **turn records and conversations are never deleted by a default prune**, so history survives.
431
+
432
+ Use **Clear conversations** in Debug mode for an explicit, confirmed reset. It removes conversation labels, turns, spans, artifacts, feedback, and legacy per-channel conversation files. Training runs, writer diagnostics, and monotonic conversation counters survive, so identities are never reused after a clear.
433
+
434
+ To turn recording off entirely, set `FW_OBSERVABILITY=0`.
435
+
436
+ ---
437
+
355
438
  ## Production deployment
356
439
 
357
440
  ### Pattern 1 — host it as a FastAPI service (recommended)
@@ -488,7 +571,7 @@ Deep-dive articles:
488
571
 
489
572
  ## Architecture overview
490
573
 
491
- fastWorkflow separates **build-time**, **train-time**, and **run-time**. At build-time you create a command interface from your code (recommended via the [integrate-chat-agent](./fastworkflow/docs/integrate-chat-agent) skill). `train` builds the NLP models; `run` executes the workflow. Your existing code is never modified — fastWorkflow sits as a layer on top.
574
+ fastWorkflow separates **build-time**, **train-time**, and **run-time**. At build-time you create a command interface from your code (recommended via the [integrate-chat-agent](./fastworkflow/skills_for_coding_fastworkflows/integrate-chat-agent) skill). `train` builds the NLP models; `run` executes the workflow. Your existing code is never modified — fastWorkflow sits as a layer on top.
492
575
 
493
576
  ```mermaid
494
577
  graph LR
@@ -601,6 +684,12 @@ fastworkflow run <workflow_dir> <env_file> <passwords_file> --assistant # dete
601
684
  fastworkflow run <workflow_dir> <env_file> <passwords_file> \
602
685
  --startup_command "your command" --keep_alive False
603
686
 
687
+ # Browser chatbot + observability viewer (`run` is also spelled `run_cli`);
688
+ # workflow, env files, and trace maintenance are chosen in the browser
689
+ fastworkflow run_chatbot
690
+ fastworkflow run_chatbot --server-port 8000 # pin the spawned server's port
691
+ fastworkflow run_chatbot --expect-encrypted-jwt # require signed tokens
692
+
604
693
  # Host as a FastAPI/MCP service
605
694
  python -m fastworkflow.run_fastapi_mcp --workflow_path ./wf --port 8000
606
695
  ```
@@ -630,6 +719,10 @@ Two files per workflow (templates ship with `fastworkflow examples fetch`).
630
719
  | `LITELLM_PROXY_API_BASE` | LiteLLM Proxy URL | with `litellm_proxy/` models | *not set* |
631
720
  | `INTENT_DETECTION_TINY_MODEL` | HF id for the small intent model | `train` (optional) | `google/bert_uncased_L-4_H-128_A-2` |
632
721
  | `INTENT_DETECTION_LARGE_MODEL` | HF id for the large intent model | `train` (optional) | `distilbert-base-uncased` |
722
+ | `FW_OBSERVABILITY` | Master switch for trace recording. `0` disables it. On by default for `run`/`run_fastapi_mcp`; off by default when embedding the core as a library | Optional | `1` (fastWorkflow entry points) |
723
+ | `FW_OBS_RETENTION_DAYS` | Age beyond which the automatic prune (run at recorder startup) drops spans/artifacts (turn records are exempt) | Optional | `30` |
724
+ | `FW_OBS_DB_MAX_BYTES` | Size cap; the automatic prune evicts oldest spans first while over it | Optional | `1073741824` (1 GiB) |
725
+ | `FW_OBS_CAPTURE_TRACEBACKS` | Persist exception tracebacks as artifacts. Off by default because tracebacks can carry sensitive values | Optional | `0` |
633
726
 
634
727
  ### `fastworkflow.passwords.env`
635
728
 
@@ -668,6 +761,8 @@ When a model uses the `litellm_proxy/` prefix, the per-role keys are ignored and
668
761
 
669
762
  > **Commands not recognized** — a command module with an import/syntax error won't load and won't appear as an intent. Check your `_commands/*.py` files.
670
763
 
764
+ > **The agent did something unexpected** — open the chatbot (`fastworkflow run_chatbot`, then pick the workflow) and read the turn's span tree. It shows which command intent detection chose, what parameters were extracted, and whether your command failed — usually enough to identify the stage at fault before reaching for a debugger.
765
+
671
766
  > [!tip]
672
767
  > To debug command files, set up a VSCode `launch.json` with `justMyCode: false`, add breakpoints, and run in debug mode.
673
768
 
@@ -113,6 +113,7 @@ fastWorkflow was benchmarked on [Tau Bench](https://github.com/sierra-research/t
113
113
  - [Quick Start: run an example in 5 minutes](#quick-start-run-an-example-in-5-minutes)
114
114
  - [AI-enable your own app (without restructuring it)](#ai-enable-your-own-app-without-restructuring-it)
115
115
  - [How complex workflows scale: context hierarchies](#how-complex-workflows-scale-context-hierarchies)
116
+ - [Chat with it and debug it: `run_chatbot`](#chat-with-it-and-debug-it-run_chatbot)
116
117
  - [Production deployment](#production-deployment)
117
118
  - [Developer FAQ](#developer-faq)
118
119
  - [Key concepts (going deeper)](#key-concepts-going-deeper)
@@ -184,10 +185,10 @@ class OrderService:
184
185
 
185
186
  ### Recommended: let a coding agent wrap it for you
186
187
 
187
- The fastest path for a non-trivial app is the **[integrate-chat-agent](./fastworkflow/docs/integrate-chat-agent) skill** with Cursor or Claude Code:
188
+ The fastest path for a non-trivial app is the **[integrate-chat-agent](./fastworkflow/skills_for_coding_fastworkflows/integrate-chat-agent) skill** with Cursor or Claude Code:
188
189
 
189
190
  ```text
190
- Open fastworkflow/docs/integrate-chat-agent/SKILL.md
191
+ Open fastworkflow/skills_for_coding_fastworkflows/integrate-chat-agent/SKILL.md
191
192
  Prompt: "Integrate a fastWorkflow chat agent for OrderService in orders.py"
192
193
  ```
193
194
 
@@ -298,6 +299,88 @@ This is what lets small models stay accurate as your app grows — and what keep
298
299
 
299
300
  ---
300
301
 
302
+ ## Chat with it and debug it: `run_chatbot`
303
+
304
+ When a turn does the wrong thing, the question is almost always *which stage* got it wrong: did intent detection pick the wrong command, did parameter extraction mis-fill an argument, or did the command itself fail? `run_chatbot` answers that without a debugger.
305
+
306
+ Every run records what it did to a per-workflow SQLite database, `observability.sqlite3`, under `FASTWORKFLOW_STATE_ROOT/workflows/<workflow-id>/`. `run_chatbot` is a local browser UI over the workflow: a chat client for driving new turns, and a trace viewer for everything that already happened.
307
+
308
+ ```sh
309
+ fastworkflow run_chatbot
310
+ ```
311
+
312
+ One command opens the workflow picker, then starts the selected workflow's FastAPI server for you (loopback-only, stopped when the chatbot exits), picks a free port, and connects the chat — no server URL, token, channel, workflow path, or env-file CLI arguments to fill in. Env files are auto-detected in the workflow directory and, for bundled workflows, the shared `examples/` directory. If either is missing, choose existing files in the browser or create owner-only workflow-local copies from the bundled templates.
313
+
314
+ ```
315
+ fastWorkflow Chatbot
316
+ pick a workflow in the browser (bundled examples
317
+ and local folders are listed; you can browse anywhere).
318
+
319
+ Open in your browser:
320
+
321
+ http://127.0.0.1:8901/?token=Bg4-uLpLdETJAsYbGzXbfRQdAEhitS6p8podPXmK25g
322
+ ```
323
+
324
+ Use that printed URL. It carries a one-off token, and requests without it are refused — so one you leave running is not readable by anything else on the machine. Pass `--server-port` to skip spawning and use a FastAPI server already running on that port. The page opens with a workflow picker: bundled examples plus a directory browser, with a **Switch workflow** button to change later.
325
+
326
+ ### Debug mode: what a turn actually did
327
+
328
+ Debug mode nests turns directly beneath their conversations (with a separate conversation-less group when needed), and opens any turn into a span tree — the nested record of the stages that ran, each with its duration, status, and attributes:
329
+
330
+ ```
331
+ fw.turn the whole logical turn (stable across ask_user suspensions)
332
+ ├── fw.planner.plan the agent's plan for the turn (fw.planner.replan on a re-plan)
333
+ │ └── fw.llm.call the planner's LLM request/response
334
+ └── fw.agent.execute the ReAct loop as a whole (attempts, final answer)
335
+ └── fw.agent.step one reasoning step: thought, chosen tool, observation
336
+ ├── fw.llm.call the step's reasoning LLM call (+ provider-native reasoning)
337
+ └── fw.agent.tool_call the agent invoking a command
338
+ └── fw.command.execute resolution + your business logic running
339
+ ├── fw.nlu.intent which matching layer decided, classifier
340
+ │ confidence vs threshold, candidates on ambiguity
341
+ └── fw.nlu.param_extraction extraction method, missing/invalid fields,
342
+ │ db_lookup outcomes, validation-hook verdict
343
+ └── fw.llm.call the LLM extraction call, when one ran
344
+ fw.ask_user a clarifying question, and how long the user took
345
+
346
+ (Deterministic "/"-mode turns skip the planner/agent layers: fw.command.execute
347
+ sits directly under fw.turn.)
348
+ ```
349
+
350
+ The diagnosis lives in the attributes of `fw.command.execute`. It records `raw_command` (the natural-language command the agent sent), `command_name` (what intent detection *resolved* it to), the extracted `parameters`, the `response_text`, and `success`. Comparing the first two is the whole trick:
351
+
352
+ - **`raw_command` was reasonable but `command_name` is the wrong command** → an intent-detection miss. Add seed utterances for that command and retrain.
353
+ - **`command_name` is right but `parameters` are wrong** → a parameter-extraction miss. Strengthen the `Field(description=…, examples=[…])` in that command's Signature.
354
+ - **Both right, span status is `error`** → the bug is in your own code, and `response_text` usually says how.
355
+
356
+ Two turn-level fields are worth knowing because they are deliberately independent. `status` is the turn's lifecycle (`completed`, `failed`, …) and `success` means every command in it succeeded. A turn that is `completed` but not `success` is the case worth hunting: a command failed and the agent wrote a confident answer over it.
357
+
358
+ Coding agents can run this diagnosis directly against the database: the wheel-shipped [`debug-workflow-conversations`](fastworkflow/skills_for_coding_fastworkflows/debug-workflow-conversations/SKILL.md) skill carries the failure-triage decision tree, the full schema and span-attribute contract, and the routing table from each diagnosis to the fastWorkflow feature (and companion skill) that fixes it.
359
+
360
+ The **Health** view reports the background writer's state and the database size, which is how you tell "no spans recorded" apart from "spans dropped under load."
361
+
362
+ ### Chat: drive the workflow from the browser
363
+
364
+ The Chat tab is connected the moment the workflow's server is ready (the first start loads models, so give it a moment — the page tells you what it is waiting on). Every turn is recorded like any other, so you can send a message and immediately open its span tree via its **view trace** link or the Debug tab.
365
+
366
+ Messages go to `/invoke_agent`; prefix one with `/` to force deterministic execution via `/invoke_assistant`, the same convention as the CLI prompt. **New conversation** in the header archives the current thread and starts a fresh one, like the CLI's `//new`. Sessions are single-developer by design: the chatbot manages one fixed private channel (`chatbot`), so there is nothing multi-user to configure and your history is in one place across launches.
367
+
368
+ There is deliberately no box for a startup command or a per-session context: the session is driven by what you type, so pre-seeding it from a chat form makes no sense. Those stay launch-time decisions — `run_fastapi_mcp --startup_command`, or the `/initialize` request fields if you are calling the API yourself.
369
+
370
+ A spawned server always binds `127.0.0.1`, has CORS pinned to loopback origins, and is stopped when the chatbot exits (SIGTERM included). It runs with unsigned dev JWTs — fine for a loopback-only dev server whose tokens the chatbot mints itself; pass `--expect-encrypted-jwt` to require signed tokens instead (then paste one in the chat's Advanced panel). Already have a server running? Launch with `--server-port <port>` and connect via the Advanced panel.
371
+
372
+ Insights distillation (`fastworkflow run --generate_insights`) stays CLI-only by design, as do bind address and env-file choices for externally managed servers. The full capability comparison is in [`docs/run_chatbot_cli_parity.md`](docs/run_chatbot_cli_parity.md).
373
+
374
+ ### Retention and erasure
375
+
376
+ Trace data grows. Spans and artifacts are pruned beyond a retention horizon; **turn records and conversations are never deleted by a default prune**, so history survives.
377
+
378
+ Use **Clear conversations** in Debug mode for an explicit, confirmed reset. It removes conversation labels, turns, spans, artifacts, feedback, and legacy per-channel conversation files. Training runs, writer diagnostics, and monotonic conversation counters survive, so identities are never reused after a clear.
379
+
380
+ To turn recording off entirely, set `FW_OBSERVABILITY=0`.
381
+
382
+ ---
383
+
301
384
  ## Production deployment
302
385
 
303
386
  ### Pattern 1 — host it as a FastAPI service (recommended)
@@ -434,7 +517,7 @@ Deep-dive articles:
434
517
 
435
518
  ## Architecture overview
436
519
 
437
- fastWorkflow separates **build-time**, **train-time**, and **run-time**. At build-time you create a command interface from your code (recommended via the [integrate-chat-agent](./fastworkflow/docs/integrate-chat-agent) skill). `train` builds the NLP models; `run` executes the workflow. Your existing code is never modified — fastWorkflow sits as a layer on top.
520
+ fastWorkflow separates **build-time**, **train-time**, and **run-time**. At build-time you create a command interface from your code (recommended via the [integrate-chat-agent](./fastworkflow/skills_for_coding_fastworkflows/integrate-chat-agent) skill). `train` builds the NLP models; `run` executes the workflow. Your existing code is never modified — fastWorkflow sits as a layer on top.
438
521
 
439
522
  ```mermaid
440
523
  graph LR
@@ -547,6 +630,12 @@ fastworkflow run <workflow_dir> <env_file> <passwords_file> --assistant # dete
547
630
  fastworkflow run <workflow_dir> <env_file> <passwords_file> \
548
631
  --startup_command "your command" --keep_alive False
549
632
 
633
+ # Browser chatbot + observability viewer (`run` is also spelled `run_cli`);
634
+ # workflow, env files, and trace maintenance are chosen in the browser
635
+ fastworkflow run_chatbot
636
+ fastworkflow run_chatbot --server-port 8000 # pin the spawned server's port
637
+ fastworkflow run_chatbot --expect-encrypted-jwt # require signed tokens
638
+
550
639
  # Host as a FastAPI/MCP service
551
640
  python -m fastworkflow.run_fastapi_mcp --workflow_path ./wf --port 8000
552
641
  ```
@@ -576,6 +665,10 @@ Two files per workflow (templates ship with `fastworkflow examples fetch`).
576
665
  | `LITELLM_PROXY_API_BASE` | LiteLLM Proxy URL | with `litellm_proxy/` models | *not set* |
577
666
  | `INTENT_DETECTION_TINY_MODEL` | HF id for the small intent model | `train` (optional) | `google/bert_uncased_L-4_H-128_A-2` |
578
667
  | `INTENT_DETECTION_LARGE_MODEL` | HF id for the large intent model | `train` (optional) | `distilbert-base-uncased` |
668
+ | `FW_OBSERVABILITY` | Master switch for trace recording. `0` disables it. On by default for `run`/`run_fastapi_mcp`; off by default when embedding the core as a library | Optional | `1` (fastWorkflow entry points) |
669
+ | `FW_OBS_RETENTION_DAYS` | Age beyond which the automatic prune (run at recorder startup) drops spans/artifacts (turn records are exempt) | Optional | `30` |
670
+ | `FW_OBS_DB_MAX_BYTES` | Size cap; the automatic prune evicts oldest spans first while over it | Optional | `1073741824` (1 GiB) |
671
+ | `FW_OBS_CAPTURE_TRACEBACKS` | Persist exception tracebacks as artifacts. Off by default because tracebacks can carry sensitive values | Optional | `0` |
579
672
 
580
673
  ### `fastworkflow.passwords.env`
581
674
 
@@ -614,6 +707,8 @@ When a model uses the `litellm_proxy/` prefix, the per-role keys are ignored and
614
707
 
615
708
  > **Commands not recognized** — a command module with an import/syntax error won't load and won't appear as an intent. Check your `_commands/*.py` files.
616
709
 
710
+ > **The agent did something unexpected** — open the chatbot (`fastworkflow run_chatbot`, then pick the workflow) and read the turn's span tree. It shows which command intent detection chose, what parameters were extracted, and whether your command failed — usually enough to identify the stage at fault before reaching for a debugger.
711
+
617
712
  > [!tip]
618
713
  > To debug command files, set up a VSCode `launch.json` with `justMyCode: false`, add breakpoints, and run in debug mode.
619
714
 
@@ -63,6 +63,9 @@ class CommandTraceEvent:
63
63
  response_text: str | None
64
64
  success: bool | None
65
65
  timestamp_ms: int
66
+ # Logical-turn correlation key (additive, observability design §3.1 [X7]).
67
+ # None only for events emitted outside any logical turn.
68
+ turn_key: str | None = None
66
69
 
67
70
  class CommandOutput(BaseModel):
68
71
  """The result of one command execution.
@@ -343,3 +346,17 @@ _turn_types_namespace = {
343
346
  }
344
347
  TurnOutput.model_rebuild(_types_namespace=_turn_types_namespace)
345
348
  TurnResult.model_rebuild(_types_namespace=_turn_types_namespace)
349
+
350
+ # Observability sinks (fastworkflow.tracing / fastworkflow.metrics, both
351
+ # stdlib-only). Embedders implement TraceSink/MetricsSink and wire them via
352
+ # WorkflowExecutionContext (observability design §3.1).
353
+ from fastworkflow.tracing import (
354
+ Span as Span,
355
+ TraceSink as TraceSink,
356
+ NoOpTraceSink as NoOpTraceSink,
357
+ )
358
+ from fastworkflow.metrics import (
359
+ MetricsSink as MetricsSink,
360
+ NoOpMetricsSink as NoOpMetricsSink,
361
+ LoggingMetricsSink as LoggingMetricsSink,
362
+ )
@@ -7,7 +7,7 @@ from pydantic import BaseModel
7
7
 
8
8
  import fastworkflow
9
9
  from fastworkflow.utils.logging import logger
10
- from fastworkflow import NLUPipelineStage
10
+ from fastworkflow import NLUPipelineStage, tracing
11
11
  from fastworkflow.cache_matching import cache_match, store_utterance_cache
12
12
  from fastworkflow.kvstore import KVStore
13
13
  from fastworkflow.model_pipeline_training import (
@@ -40,6 +40,60 @@ class CommandNamePrediction:
40
40
  self.path = self._get_cache_path_cache(self.convo_path)
41
41
 
42
42
  def predict(self, command_context_name: str, command: str, nlu_pipeline_stage: NLUPipelineStage) -> "CommandNamePrediction.Output":
43
+ """Predict, wrapped in a ``fw.nlu.intent`` span (D3 as amended).
44
+
45
+ One span per prediction attempt — the wildcard command's parent-chain
46
+ walk calls this once per context, and each attempt is recorded with
47
+ the context it ran against. The span carries which matching layer
48
+ decided (exact prefix / fuzzy pre-match / embedding cache /
49
+ classifier), the classifier's confidence and threshold when it ran,
50
+ and the candidate set on an ambiguity. Emission never affects the
51
+ prediction: the helpers no-op without a bound host/sink.
52
+ """
53
+ host = tracing.current_host()
54
+ span = tracing.start_span(
55
+ host,
56
+ tracing.SPAN_NLU_INTENT,
57
+ attributes={
58
+ "context": command_context_name,
59
+ "stage": nlu_pipeline_stage.name,
60
+ "utterance": command,
61
+ },
62
+ )
63
+ nlu_trace: dict = {}
64
+ try:
65
+ output = self._predict_impl(
66
+ command_context_name, command, nlu_pipeline_stage, nlu_trace
67
+ )
68
+ except BaseException:
69
+ tracing.end_span(
70
+ host, span, status=tracing.STATUS_ERROR, attributes=nlu_trace
71
+ )
72
+ raise
73
+ tracing.end_span(
74
+ host,
75
+ span,
76
+ status=tracing.STATUS_OK,
77
+ attributes={
78
+ **nlu_trace,
79
+ "command_name": output.command_name,
80
+ "is_cme_command": output.is_cme_command,
81
+ "ambiguous": output.error_msg is not None,
82
+ # None = no local prediction; the caller walks up the context
83
+ # chain (or files a misunderstanding) — exactly the routing
84
+ # signal a debugging agent needs.
85
+ "resolved": output.command_name is not None,
86
+ },
87
+ )
88
+ return output
89
+
90
+ def _predict_impl(
91
+ self,
92
+ command_context_name: str,
93
+ command: str,
94
+ nlu_pipeline_stage: NLUPipelineStage,
95
+ nlu_trace: dict,
96
+ ) -> "CommandNamePrediction.Output":
43
97
  # sourcery skip: extract-duplicate-method
44
98
 
45
99
  model_artifact_path = f"{self.app_workflow_folderpath}/___command_info/{command_context_name}"
@@ -109,6 +163,7 @@ class CommandNamePrediction:
109
163
  if normalized_command_name in command_name_dict:
110
164
  command_name = normalized_command_name
111
165
  command = command.replace(f"{tentative_command_name}", "").strip().replace(" ", " ")
166
+ nlu_trace["matcher_layer"] = "exact_prefix"
112
167
  else:
113
168
  # Use Levenshtein distance for fuzzy matching with the full command part after @
114
169
  # No match is ([], None), never (None, None) — len() here is safe.
@@ -133,16 +188,24 @@ class CommandNamePrediction:
133
188
  f"utterance '{command}' in context '{command_context_name}'. "
134
189
  "Deferring to the classifier instead of picking one."
135
190
  )
191
+ nlu_trace["fuzzy_prematch_tie"] = [str(c) for c in best_matched_commands]
136
192
  elif best_matched_commands:
137
193
  command_name = best_matched_commands[0]
194
+ nlu_trace["matcher_layer"] = "fuzzy_prematch"
138
195
 
139
196
  if nlu_pipeline_stage == NLUPipelineStage.INTENT_DETECTION:
140
197
  if not command_name:
141
198
  if cache_result := cache_match(self.path, command, modelpipeline, 0.85):
142
199
  command_name = cache_result
200
+ nlu_trace["matcher_layer"] = "embedding_cache"
201
+ nlu_trace["cache_similarity_threshold"] = 0.85
143
202
  else:
144
- predictions=command_router.predict(command)
203
+ predictions, classifier_details = (
204
+ command_router.predict_with_details(command)
205
+ )
145
206
  # predictions = majority_vote_predictions(command_router, command)
207
+ nlu_trace["matcher_layer"] = "classifier"
208
+ nlu_trace["classifier"] = classifier_details
146
209
 
147
210
  if len(predictions)==1:
148
211
  command_name = predictions[0].split('/')[-1]
@@ -158,11 +221,15 @@ class CommandNamePrediction:
158
221
  "will be prompted with the local candidates only and the "
159
222
  "'this belongs to an ancestor context' signal is dropped."
160
223
  )
224
+ nlu_trace["escalation_labels_discarded"] = [
225
+ str(label) for label in escalation_signals
226
+ ]
161
227
 
162
228
  error_msg = self._formulate_ambiguous_command_error_message(
163
229
  predictions, "run_as_agent" in self.app_workflow.context)
164
230
 
165
231
  # Store suggested commands
232
+ nlu_trace["candidates"] = [str(p) for p in predictions]
166
233
  self._store_suggested_commands(self.path, predictions, 1)
167
234
  return CommandNamePrediction.Output(error_msg=error_msg)
168
235
 
@@ -171,6 +238,7 @@ class CommandNamePrediction:
171
238
  NLUPipelineStage.INTENT_MISUNDERSTANDING_CLARIFICATION
172
239
  ) and not command_name:
173
240
  command_name = "what can i do?"
241
+ nlu_trace["matcher_layer"] = "clarification_default"
174
242
 
175
243
  fully_qualified_command_name = self.resolve_fully_qualified_command_name(
176
244
  command_name, command_name_dict)
@@ -10,7 +10,7 @@ from pydantic_core import PydanticUndefined
10
10
 
11
11
  import fastworkflow
12
12
  from fastworkflow.utils.logging import logger
13
- from fastworkflow import ModuleType
13
+ from fastworkflow import ModuleType, tracing
14
14
 
15
15
  from fastworkflow.utils.signatures import InputForParamExtraction
16
16
 
@@ -58,6 +58,43 @@ class ParameterExtraction:
58
58
  self.command = command
59
59
 
60
60
  def extract(self) -> "ParameterExtraction.Output":
61
+ """Extract, wrapped in a ``fw.nlu.param_extraction`` span (D3 as
62
+ amended). The span records the extraction method (stored-merge /
63
+ xml-regex / llm), whether this is a NOT_FOUND retry round, and the
64
+ STRUCTURED validation outcome from ``validate_parameters`` —
65
+ missing/invalid fields, per-field db_lookup events, and the
66
+ validate_extracted_parameters verdict. A failed extraction is a
67
+ conversational state, not a span error: status stays ok and
68
+ ``parameters_valid`` carries the signal; only an exception marks the
69
+ span error. Emission never affects extraction (no-op without a host).
70
+ """
71
+ host = tracing.current_host()
72
+ span = tracing.start_span(
73
+ host,
74
+ tracing.SPAN_NLU_PARAM_EXTRACTION,
75
+ command_name=self.command_name,
76
+ attributes={"command_name": self.command_name},
77
+ )
78
+ diagnostics: dict = {}
79
+ try:
80
+ output = self._extract_impl(diagnostics)
81
+ except BaseException:
82
+ tracing.end_span(
83
+ host, span, status=tracing.STATUS_ERROR, attributes=diagnostics
84
+ )
85
+ raise
86
+ tracing.end_span(
87
+ host,
88
+ span,
89
+ status=tracing.STATUS_OK,
90
+ attributes={
91
+ **diagnostics,
92
+ "parameters_valid": output.parameters_are_valid,
93
+ },
94
+ )
95
+ return output
96
+
97
+ def _extract_impl(self, diagnostics: dict) -> "ParameterExtraction.Output":
61
98
  app_workflow_folderpath = self.app_workflow.folderpath
62
99
  app_command_routing_definition = fastworkflow.RoutingRegistry.get_definition(app_workflow_folderpath)
63
100
 
@@ -78,8 +115,10 @@ class ParameterExtraction:
78
115
  self.command)
79
116
 
80
117
  # If we have missing fields (in parameter extraction error state), try to apply the command directly
118
+ diagnostics["retry_round"] = bool(stored_params)
81
119
  if stored_params:
82
120
  new_params = self._extract_and_merge_missing_parameters(stored_params, self.command)
121
+ diagnostics["extraction_method"] = "stored_merge"
83
122
  else:
84
123
  # Check if we're in agentic mode (not assistant mode command)
85
124
  is_agentic_mode = (
@@ -91,6 +130,7 @@ class ParameterExtraction:
91
130
  if is_agentic_mode:
92
131
  # Try regex-based extraction first in agentic mode
93
132
  new_params = self._extract_parameters_from_xml(self.command, command_parameters_class)
133
+ diagnostics["extraction_method"] = "xml_regex"
94
134
 
95
135
  # If regex extraction fails, fall back to LLM-based extraction
96
136
  if new_params is None:
@@ -98,16 +138,19 @@ class ParameterExtraction:
98
138
  command_parameters_class,
99
139
  self.command_name,
100
140
  app_workflow_folderpath)
141
+ diagnostics["extraction_method"] = "llm"
101
142
  else:
102
143
  # Use LLM-based extraction for assistant mode
103
144
  new_params = input_for_param_extraction.extract_parameters(
104
145
  command_parameters_class,
105
146
  self.command_name,
106
147
  app_workflow_folderpath)
148
+ diagnostics["extraction_method"] = "llm"
107
149
 
108
150
  is_valid, error_msg, suggestions, missing_invalid_fields = \
109
151
  input_for_param_extraction.validate_parameters(
110
- self.app_workflow, self.command_name, new_params
152
+ self.app_workflow, self.command_name, new_params,
153
+ diagnostics=diagnostics
111
154
  )
112
155
 
113
156
  # Set all the missing and invalid fields to appropriate sentinel values before storing
@@ -117,9 +117,15 @@ class ChatSession:
117
117
  """
118
118
  self._core = WorkflowExecutionContext(
119
119
  run_as_agent=run_as_agent,
120
- mirror_action_log_to_file=True,
121
120
  generate_insights=generate_insights,
122
121
  )
122
+ # CLI identity [R17]: a synthetic per-session channel so CLI turns are
123
+ # attributable in the observability store (conversation ids are minted
124
+ # by the store from Phase 2).
125
+ from datetime import datetime, timezone
126
+ self._core.bind_observability_identity(
127
+ channel_id=f"cli:{datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%S.%f')}Z"
128
+ )
123
129
 
124
130
  # Create queues for user messages and command outputs (CLI transport)
125
131
  self._user_message_queue = Queue()
@@ -371,8 +377,10 @@ class ChatSession:
371
377
  # Handle startup command/action
372
378
  if self._startup_command:
373
379
  last_output = self._core._execute_message(self._startup_command)
380
+ self._core.finalize_turn_for_observability(last_output)
374
381
  elif self._startup_action:
375
382
  last_output = self._core.process_action(self._startup_action)
383
+ self._core.finalize_turn_for_observability(last_output)
376
384
 
377
385
  while (
378
386
  not self.workflow_is_complete or self._keep_alive
@@ -384,6 +392,9 @@ class ChatSession:
384
392
  last_output = self._core.process_action(message)
385
393
  else:
386
394
  last_output = self._core._execute_message(message)
395
+ # Emit the turn record/root-span close for observability;
396
+ # the CLI transport itself still rides the queues.
397
+ self._core.finalize_turn_for_observability(last_output)
387
398
 
388
399
  except Empty:
389
400
  continue