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.
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/PKG-INFO +21 -4
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/README.md +20 -3
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/ErrorCorrection/you_misunderstood.py +4 -2
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/wildcard.py +10 -10
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/intent_detection.py +46 -4
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/parameter_extraction.py +113 -8
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/chat_session.py +11 -2
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/cli.py +13 -0
- fastworkflow-2.24.0/fastworkflow/distillation.py +927 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/model_pipeline_training.py +532 -67
- fastworkflow-2.24.0/fastworkflow/nlu_labels.py +96 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run/__main__.py +13 -1
- fastworkflow-2.24.0/fastworkflow/train/__main__.py +600 -0
- fastworkflow-2.24.0/fastworkflow/train/artifact_versioning.py +1120 -0
- fastworkflow-2.24.0/fastworkflow/train/class_balance.py +221 -0
- fastworkflow-2.24.0/fastworkflow/train/determinism.py +362 -0
- fastworkflow-2.24.0/fastworkflow/train/duplicate_detection.py +753 -0
- fastworkflow-2.24.0/fastworkflow/train/generate_synthetic.py +767 -0
- fastworkflow-2.24.0/fastworkflow/train/heldout_evaluation.py +963 -0
- fastworkflow-2.24.0/fastworkflow/train/param_example_cache.py +504 -0
- fastworkflow-2.24.0/fastworkflow/train/personas.py +721 -0
- fastworkflow-2.24.0/fastworkflow/train/selective_training.py +1327 -0
- fastworkflow-2.24.0/fastworkflow/train/training_report.py +1122 -0
- fastworkflow-2.24.0/fastworkflow/train/utterance_cache.py +639 -0
- fastworkflow-2.24.0/fastworkflow/utils/generate_param_examples.py +1118 -0
- fastworkflow-2.24.0/fastworkflow/utils/insights_loader.py +67 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/react.py +50 -12
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/signatures.py +42 -13
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/workflow_agent.py +90 -30
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/workflow_execution_context.py +104 -36
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/pyproject.toml +1 -1
- fastworkflow-2.22.3/fastworkflow/train/__main__.py +0 -299
- fastworkflow-2.22.3/fastworkflow/train/generate_synthetic.py +0 -158
- fastworkflow-2.22.3/fastworkflow/utils/generate_param_examples.py +0 -638
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/LICENSE +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/.DS_Store +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/__init__.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_commands/.gitkeep +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/__init__.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/__init__.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/ErrorCorrection/abort.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/go_up.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/reset_context.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/what_can_i_do.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/what_is_current_context.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/_commands/__init__.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/_workflows/command_metadata_extraction/command_context_model.json +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/active_workflow.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/__main__.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/ast_class_extractor.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/class_analysis_structures.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/cli_specification.md +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/command_dependency_resolver.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/command_file_generator.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/command_file_template.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/command_import_utils.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/command_stub_generator.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/context_folder_generator.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/context_model_generator.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/dependency_manager.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/dir_scanner.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/documentation_generator.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/genai_postprocessor.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/inheritance_block_regenerator.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/libcst_transformers.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/navigator_stub_generator.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/pydantic_model_generator.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/build/utterance_generator.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/cache_matching.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/command_context_model.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/command_directory.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/command_executor.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/command_interfaces.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/command_metadata_api.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/command_routing.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/conversation_history_io.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/docs/context_modules_prd.txt +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/docs/integrate-chat-agent/SKILL.md +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/docs/integrate-chat-agent/reference.md +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/extended_workflow_example/README.md +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/extended_workflow_example/_commands/WorkItem/get_status.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/extended_workflow_example/_commands/generate_report.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/extended_workflow_example/_commands/startup.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/extended_workflow_example/simple_workflow_template.json +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/extended_workflow_example/workflow_inheritance_model.json +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/fastworkflow.env +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/fastworkflow.passwords.env +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/hello_world/_commands/README.md +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/hello_world/_commands/add_two_numbers.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/hello_world/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/hello_world/application/add_two_numbers.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_1/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_1/_commands/send_message.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_1/application/send_message.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_2/_commands/User/send_message.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_2/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_2/_commands/startup.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_2/application/user.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_3/_commands/PremiumUser/send_priority_message.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_3/_commands/User/send_message.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_3/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_3/_commands/initialize_user.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_3/application/user.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/_ChatRoom.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/add_user.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/broadcast_message.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/get_current_user.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/list_users.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/set_current_user.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/PremiumUser/_PremiumUser.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/PremiumUser/send_priority_message.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/User/_User.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/User/send_message.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/_commands/set_root_context.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/application/chatroom.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/application/user.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/context_hierarchy_model.json +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/messaging_app_4/startup_action.json +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/calculate.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/cancel_pending_order.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/exchange_delivered_order_items.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/find_user_id_by_email.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/find_user_id_by_name_zip.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/get_order_details.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/get_product_details.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/get_user_details.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/list_all_product_types.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_address.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_items.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_payment.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/modify_user_address.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/return_delivered_order_items.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/_commands/transfer_to_human_agents.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/context_inheritance_model.json +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/retail_data/__init__.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/retail_data/orders.json +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/retail_data/products.json +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/retail_data/users.json +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/calculate.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/cancel_pending_order.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/exchange_delivered_order_items.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/find_user_id_by_email.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/find_user_id_by_name_zip.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/get_order_details.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/get_product_details.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/get_user_details.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/list_all_product_types.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_address.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_items.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_payment.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/modify_user_address.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/return_delivered_order_items.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/think.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/tool.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/tools/transfer_to_human_agents.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/retail_workflow/workflow_description.txt +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/__init__.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/_WorkItem.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/add_child_workitem.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/get_status.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/go_to_workitem.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/mark_as_complete.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_first_child_workitem.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_last_child_workitem.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_next_workitem.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_previous_workitem.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/remove_all_child_workitems.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/remove_child_workitem.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/show_schema.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/_commands/startup.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/application/__init__.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/application/workitem.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/simple_workflow_template.json +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/examples/simple_workflow_template/startup_action.json +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/intent_clarification_agent.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/mcp_server.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/refine/__main__.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run/__init__.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/README.md +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/__init__.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/__main__.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/conversation_store.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/jwt_manager.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/mcp_specific.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/redoc_2_standalone_html.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/turns.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/run_fastapi_mcp/utils.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/session_state_store.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/train/__init__.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/turn.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/user_message_queues.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/__init__.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/chat_adapter.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/context_utils.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/dspy_cache_utils.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/dspy_logger.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/dspy_utils.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/env.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/fuzzy_match.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/logging.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/parameterize_func_decorator.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/pydantic_model_2_dspy_signature_class.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/python_utils.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/utils/startup_progress.py +0 -0
- {fastworkflow-2.22.3 → fastworkflow-2.24.0}/fastworkflow/workflow.py +0 -0
- {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.
|
|
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://pypi.org/project/fastworkflow/) [](https://github.com/radiantlogicinc/fastworkflow/actions) [](https://discord.gg/k2g58dDjYR)
|
|
57
|
+
[](LICENSE) [](https://pypi.org/project/fastworkflow/) [](https://github.com/radiantlogicinc/fastworkflow/actions) [](https://discord.gg/k2g58dDjYR) [](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="
|
|
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="
|
|
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://pypi.org/project/fastworkflow/) [](https://github.com/radiantlogicinc/fastworkflow/actions) [](https://discord.gg/k2g58dDjYR)
|
|
4
|
+
[](LICENSE) [](https://pypi.org/project/fastworkflow/) [](https://github.com/radiantlogicinc/fastworkflow/actions) [](https://discord.gg/k2g58dDjYR) [](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="
|
|
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="
|
|
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
|
-
"
|
|
64
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
]
|
|
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
|
-
|
|
142
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
352
|
-
|
|
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):
|