fastworkflow 3.1.0__tar.gz → 3.1.2__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-3.1.0 → fastworkflow-3.1.2}/PKG-INFO +2 -2
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/_workflows/command_metadata_extraction/intent_detection.py +18 -1
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/docs/integrate-chat-agent/reference.md +5 -1
- fastworkflow-3.1.2/fastworkflow/utils/fuzzy_match.py +170 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/utils/signatures.py +43 -6
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/pyproject.toml +2 -2
- fastworkflow-3.1.0/fastworkflow/utils/fuzzy_match.py +0 -70
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/LICENSE +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/README.md +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/.DS_Store +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/__init__.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/_commands/.gitkeep +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/_workflows/__init__.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/_workflows/command_metadata_extraction/__init__.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/_workflows/command_metadata_extraction/_commands/ErrorCorrection/abort.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/_workflows/command_metadata_extraction/_commands/ErrorCorrection/you_misunderstood.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/go_up.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/reset_context.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/what_can_i_do.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/what_is_current_context.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/_workflows/command_metadata_extraction/_commands/__init__.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/_workflows/command_metadata_extraction/_commands/wildcard.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/_workflows/command_metadata_extraction/command_context_model.json +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/_workflows/command_metadata_extraction/parameter_extraction.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/active_workflow.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/__main__.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/ast_class_extractor.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/class_analysis_structures.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/cli_specification.md +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/command_dependency_resolver.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/command_file_generator.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/command_file_template.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/command_import_utils.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/command_stub_generator.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/context_folder_generator.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/context_model_generator.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/dependency_manager.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/dir_scanner.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/documentation_generator.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/genai_postprocessor.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/inheritance_block_regenerator.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/libcst_transformers.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/navigator_stub_generator.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/pydantic_model_generator.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/utterance_generator.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/cache_matching.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/chat_session.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/checkpoint_store.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/cli.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/command_context_model.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/command_directory.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/command_executor.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/command_interfaces.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/command_metadata_api.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/command_routing.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/conversation_history_io.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/distillation.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/docs/context_modules_prd.txt +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/docs/integrate-chat-agent/SKILL.md +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/extended_workflow_example/README.md +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/extended_workflow_example/_commands/WorkItem/get_status.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/extended_workflow_example/_commands/generate_report.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/extended_workflow_example/_commands/startup.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/extended_workflow_example/simple_workflow_template.json +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/extended_workflow_example/workflow_inheritance_model.json +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/fastworkflow.env +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/fastworkflow.passwords.env +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/hello_world/_commands/README.md +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/hello_world/_commands/add_two_numbers.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/hello_world/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/hello_world/application/add_two_numbers.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_1/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_1/_commands/send_message.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_1/application/send_message.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_2/_commands/User/_User.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_2/_commands/User/send_message.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_2/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_2/_commands/startup.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_2/application/user.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_3/_commands/PremiumUser/_PremiumUser.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_3/_commands/PremiumUser/send_priority_message.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_3/_commands/User/_User.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_3/_commands/User/send_message.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_3/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_3/_commands/initialize_user.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_3/application/user.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/_ChatRoom.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/add_user.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/broadcast_message.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/get_current_user.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/list_users.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/set_current_user.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_4/_commands/PremiumUser/_PremiumUser.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_4/_commands/PremiumUser/send_priority_message.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_4/_commands/User/_User.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_4/_commands/User/send_message.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_4/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_4/_commands/set_root_context.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_4/application/chatroom.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_4/application/user.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_4/context_hierarchy_model.json +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_4/startup_action.json +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/_commands/calculate.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/_commands/cancel_pending_order.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/_commands/exchange_delivered_order_items.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/_commands/find_user_id_by_email.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/_commands/find_user_id_by_name_zip.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/_commands/get_order_details.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/_commands/get_product_details.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/_commands/get_user_details.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/_commands/list_all_product_types.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_address.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_items.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_payment.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/_commands/modify_user_address.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/_commands/return_delivered_order_items.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/_commands/transfer_to_human_agents.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/context_inheritance_model.json +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/retail_data/__init__.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/retail_data/orders.json +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/retail_data/products.json +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/retail_data/users.json +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/tools/calculate.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/tools/cancel_pending_order.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/tools/exchange_delivered_order_items.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/tools/find_user_id_by_email.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/tools/find_user_id_by_name_zip.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/tools/get_order_details.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/tools/get_product_details.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/tools/get_user_details.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/tools/list_all_product_types.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_address.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_items.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_payment.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/tools/modify_user_address.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/tools/return_delivered_order_items.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/tools/think.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/tools/tool.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/tools/transfer_to_human_agents.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/retail_workflow/workflow_description.txt +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/__init__.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/_WorkItem.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/add_child_workitem.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/get_status.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/go_to_workitem.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/mark_as_complete.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_first_child_workitem.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_last_child_workitem.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_next_workitem.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_previous_workitem.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/remove_all_child_workitems.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/remove_child_workitem.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/show_schema.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/_commands/startup.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/application/__init__.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/application/workitem.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/simple_workflow_template.json +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/simple_workflow_template/startup_action.json +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/intent_clarification_agent.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/kvstore.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/mcp_server.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/model_pipeline_training.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/nlu_labels.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/refine/__main__.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/run/__init__.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/run/__main__.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/run_fastapi_mcp/README.md +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/run_fastapi_mcp/__init__.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/run_fastapi_mcp/__main__.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/run_fastapi_mcp/checkpoint.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/run_fastapi_mcp/conversation_store.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/run_fastapi_mcp/jwt_manager.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/run_fastapi_mcp/mcp_specific.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/run_fastapi_mcp/redoc_2_standalone_html.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/run_fastapi_mcp/server_memory.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/run_fastapi_mcp/turns.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/run_fastapi_mcp/utils.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/serialization_hooks.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/session_state_store.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/state_paths.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/state_serialization.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/storage_keys.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/train/__init__.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/train/__main__.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/train/artifact_versioning.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/train/class_balance.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/train/determinism.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/train/duplicate_detection.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/train/generate_synthetic.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/train/heldout_evaluation.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/train/param_example_cache.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/train/personas.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/train/selective_training.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/train/training_report.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/train/utterance_cache.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/turn.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/user_message_queues.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/utils/__init__.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/utils/chat_adapter.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/utils/context_utils.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/utils/dspy_cache_utils.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/utils/dspy_logger.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/utils/dspy_utils.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/utils/env.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/utils/generate_param_examples.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/utils/insights_loader.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/utils/logging.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/utils/parameterize_func_decorator.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/utils/pydantic_model_2_dspy_signature_class.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/utils/python_utils.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/utils/react.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/utils/startup_progress.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/workflow.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/workflow_agent.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/workflow_execution_context.py +0 -0
- {fastworkflow-3.1.0 → fastworkflow-3.1.2}/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.
|
|
3
|
+
Version: 3.1.2
|
|
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
|
|
@@ -15,7 +15,7 @@ Provides-Extra: training
|
|
|
15
15
|
Requires-Dist: aiohttp (>=3.14.3)
|
|
16
16
|
Requires-Dist: colorama (>=0.4.6,<0.5.0)
|
|
17
17
|
Requires-Dist: cryptography (>=50.0.0)
|
|
18
|
-
Requires-Dist: datasets (>=
|
|
18
|
+
Requires-Dist: datasets (>=5.0.1,<6.0.0) ; extra == "training"
|
|
19
19
|
Requires-Dist: dspy (>=3.0.1,<4.0.0)
|
|
20
20
|
Requires-Dist: fastapi (>=0.120.1) ; extra == "server" or extra == "fastapi"
|
|
21
21
|
Requires-Dist: fastapi-mcp (>=0.4.0,<0.5.0) ; extra == "server" or extra == "fastapi"
|
|
@@ -111,12 +111,29 @@ class CommandNamePrediction:
|
|
|
111
111
|
command = command.replace(f"{tentative_command_name}", "").strip().replace(" ", " ")
|
|
112
112
|
else:
|
|
113
113
|
# Use Levenshtein distance for fuzzy matching with the full command part after @
|
|
114
|
+
# No match is ([], None), never (None, None) — len() here is safe.
|
|
114
115
|
best_matched_commands, _ = find_best_matches(
|
|
115
116
|
command.replace(" ", "_"),
|
|
116
117
|
command_name_dict.keys(),
|
|
117
118
|
threshold=0.3 # Adjust threshold as needed
|
|
118
119
|
)
|
|
119
|
-
if
|
|
120
|
+
if (
|
|
121
|
+
len(best_matched_commands) > 1
|
|
122
|
+
and nlu_pipeline_stage == NLUPipelineStage.INTENT_DETECTION
|
|
123
|
+
):
|
|
124
|
+
# Commands sharing a prefix tie at distance 0, because scoring
|
|
125
|
+
# compares only the leading len(input) characters, and
|
|
126
|
+
# command_name_dict iterates a set — so picking [0] would choose
|
|
127
|
+
# nondeterministically between them across processes. Leave the
|
|
128
|
+
# name unset so the classifier and its ambiguity prompt decide.
|
|
129
|
+
# The clarification stages are deliberately excluded: they have
|
|
130
|
+
# no classifier to fall back to.
|
|
131
|
+
logger.warning(
|
|
132
|
+
f"Fuzzy pre-match tied across {best_matched_commands} for "
|
|
133
|
+
f"utterance '{command}' in context '{command_context_name}'. "
|
|
134
|
+
"Deferring to the classifier instead of picking one."
|
|
135
|
+
)
|
|
136
|
+
elif best_matched_commands:
|
|
120
137
|
command_name = best_matched_commands[0]
|
|
121
138
|
|
|
122
139
|
if nlu_pipeline_stage == NLUPipelineStage.INTENT_DETECTION:
|
{fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/docs/integrate-chat-agent/reference.md
RENAMED
|
@@ -168,7 +168,11 @@ class ResponseGenerator:
|
|
|
168
168
|
```
|
|
169
169
|
- Use `default="NOT_FOUND"` for parameters so missing values are detected, not hallucinated.
|
|
170
170
|
- Use `Field` `description` + `examples` (and `pattern`/`min_length` where helpful) to drive accurate parameter extraction.
|
|
171
|
-
- Optional hooks: `db_lookup(
|
|
171
|
+
- Optional hooks: `db_lookup(workflow, field_name, field_value) -> tuple[bool, str | None, list[str]]`,
|
|
172
|
+
`process_extracted_parameters(...)`. `db_lookup` runs for fields marked
|
|
173
|
+
`json_schema_extra={'db_lookup': True}` and has three return states: `(True, value, [])`
|
|
174
|
+
overwrites the field, `(False, None, [suggestions])` fails validation, and
|
|
175
|
+
`(False, None, [])` does neither — use that last one for a value your hook does not own.
|
|
172
176
|
- For LLM-generated responses, use `fastworkflow.utils.dspy_utils.dspySignature(Signature.Input, Signature.Output)` with `dspy.Predict`.
|
|
173
177
|
|
|
174
178
|
### Context model — `_commands/context_inheritance_model.json`
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import sys
|
|
3
|
+
from typing import Optional
|
|
4
|
+
import Levenshtein
|
|
5
|
+
|
|
6
|
+
# Windows are the (normalized) input length. db_lookup scores catalogue
|
|
7
|
+
# fields — names, emails, ids — tens to a few hundred characters, not
|
|
8
|
+
# megabytes. Rounding error on max_normalized * max_length is about
|
|
9
|
+
# sys.float_info.epsilon * max_length; at one million characters that is
|
|
10
|
+
# still ~2e-10. The nudge must exceed that scaled error so a product one
|
|
11
|
+
# ulp below an integer (e.g. (1/49)*49) is not floored, and stay << 1 so
|
|
12
|
+
# a fractional edit count such as 0.8 (bound 0.2 on a 4-char window) is
|
|
13
|
+
# not promoted to the next integer.
|
|
14
|
+
_MAX_SCORED_WINDOW = 1_000_000
|
|
15
|
+
_SCORE_CUTOFF_NUDGE = 8 * sys.float_info.epsilon * _MAX_SCORED_WINDOW
|
|
16
|
+
|
|
17
|
+
def normalize_text(text):
|
|
18
|
+
"""
|
|
19
|
+
Normalize text by removing spaces, @ symbol, underscores, and converting to lowercase
|
|
20
|
+
"""
|
|
21
|
+
return re.sub(r'[@\s_]', '', str(text).lower())
|
|
22
|
+
|
|
23
|
+
def normalized_levenshtein_distance(
|
|
24
|
+
s1, s2, max_normalized: Optional[float] = None):
|
|
25
|
+
"""Calculate normalized Levenshtein distance.
|
|
26
|
+
|
|
27
|
+
``max_normalized`` is an optional upper bound. Distances that cannot
|
|
28
|
+
beat it are not fully computed; a value strictly greater than
|
|
29
|
+
``max_normalized`` is returned instead. Callers must treat that
|
|
30
|
+
sentinel as "worse", never as a tie at the bound.
|
|
31
|
+
"""
|
|
32
|
+
max_length = max(len(s1), len(s2))
|
|
33
|
+
if max_length == 0:
|
|
34
|
+
return 0.0
|
|
35
|
+
if max_normalized is None:
|
|
36
|
+
return Levenshtein.distance(s1, s2) / max_length
|
|
37
|
+
cutoff = int(max_normalized * max_length + _SCORE_CUTOFF_NUDGE)
|
|
38
|
+
distance = Levenshtein.distance(s1, s2, score_cutoff=cutoff)
|
|
39
|
+
if distance > cutoff:
|
|
40
|
+
return max_normalized + 1.0
|
|
41
|
+
return distance / max_length
|
|
42
|
+
|
|
43
|
+
def best_window_distance(
|
|
44
|
+
normalized_input: str,
|
|
45
|
+
normalized_candidate: str,
|
|
46
|
+
max_normalized: float = 1.0,
|
|
47
|
+
) -> float:
|
|
48
|
+
"""Smallest normalized distance between the input and any equal-length window
|
|
49
|
+
of the candidate.
|
|
50
|
+
|
|
51
|
+
Exact containment is distance 0.0 and returns immediately. Remaining
|
|
52
|
+
windows use Levenshtein's ``score_cutoff`` so a window that cannot beat
|
|
53
|
+
``max_normalized`` (or the best window seen so far) is abandoned early.
|
|
54
|
+
If no window beats ``max_normalized``, a value strictly greater than it
|
|
55
|
+
is returned so the caller does not invent a tie at the bound.
|
|
56
|
+
"""
|
|
57
|
+
if normalized_input in normalized_candidate:
|
|
58
|
+
return 0.0
|
|
59
|
+
|
|
60
|
+
len_input = len(normalized_input)
|
|
61
|
+
n_windows = max(len(normalized_candidate) - len_input, 0) + 1
|
|
62
|
+
best: Optional[float] = None
|
|
63
|
+
bound = max_normalized
|
|
64
|
+
for i in range(n_windows):
|
|
65
|
+
dist = normalized_levenshtein_distance(
|
|
66
|
+
normalized_input,
|
|
67
|
+
normalized_candidate[i:i + len_input],
|
|
68
|
+
max_normalized=bound,
|
|
69
|
+
)
|
|
70
|
+
if dist > bound:
|
|
71
|
+
continue
|
|
72
|
+
if best is None or dist < best:
|
|
73
|
+
best = dist
|
|
74
|
+
bound = dist
|
|
75
|
+
if best == 0.0:
|
|
76
|
+
return 0.0
|
|
77
|
+
return best if best is not None else max_normalized + 1.0
|
|
78
|
+
|
|
79
|
+
def find_best_matches(input_text: str,
|
|
80
|
+
text_list: list[str],
|
|
81
|
+
threshold: float=0.4,
|
|
82
|
+
best_window: bool=False
|
|
83
|
+
) -> tuple[list[str], Optional[float]]:
|
|
84
|
+
"""Find best match(es) using normalized Levenshtein distance.
|
|
85
|
+
|
|
86
|
+
The function now returns *all* entries whose normalized Levenshtein
|
|
87
|
+
distance equals the minimum distance computed for the provided
|
|
88
|
+
``input_text``. This is useful when multiple candidates tie for the
|
|
89
|
+
smallest distance.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
best_window
|
|
94
|
+
By default each candidate is scored on its *leading* ``len(input_text)``
|
|
95
|
+
characters, so a candidate that contains the input anywhere else is
|
|
96
|
+
scored as though it did not contain it at all: searching for
|
|
97
|
+
``Garrison`` scores ``Barry Jones`` (0.375) ahead of ``Aaron Garrison``
|
|
98
|
+
(0.750). When true, every window of that length is scored and the best
|
|
99
|
+
one wins, so a containing candidate always reaches distance 0.0.
|
|
100
|
+
|
|
101
|
+
This is opt-in rather than the default because it can only *lower*
|
|
102
|
+
distances, and therefore admits strictly more matches at any fixed
|
|
103
|
+
threshold. Callers that route on the first match instead of treating
|
|
104
|
+
ties as ambiguity depend on the narrower leading-window behaviour.
|
|
105
|
+
|
|
106
|
+
Returns
|
|
107
|
+
-------
|
|
108
|
+
tuple[list[str], Optional[float]]
|
|
109
|
+
A tuple containing the list of best-matching original strings
|
|
110
|
+
and the corresponding distance. If the best distance exceeds
|
|
111
|
+
the ``threshold`` value, or if ``text_list`` is empty,
|
|
112
|
+
``([], None)`` is returned — never ``(None, None)``. Callers
|
|
113
|
+
must treat an empty list as "no match" (truthiness or ``len``);
|
|
114
|
+
``best_matches is None`` is always false.
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
# Ensure we have a concrete list (e.g., when a generator is passed)
|
|
118
|
+
text_list = list(text_list)
|
|
119
|
+
|
|
120
|
+
normalized_input = normalize_text(input_text)
|
|
121
|
+
normalized_list = [normalize_text(text) for text in text_list]
|
|
122
|
+
|
|
123
|
+
if not normalized_list:
|
|
124
|
+
return ([], None)
|
|
125
|
+
|
|
126
|
+
if best_window:
|
|
127
|
+
# Containment is distance 0.0. Once any candidate contains the
|
|
128
|
+
# input, later candidates can only tie by also containing it —
|
|
129
|
+
# there is no need to slide windows over the rest of the list.
|
|
130
|
+
contained = [
|
|
131
|
+
text for text, normalized in zip(text_list, normalized_list)
|
|
132
|
+
if normalized_input in normalized
|
|
133
|
+
]
|
|
134
|
+
if contained:
|
|
135
|
+
return (contained, 0.0)
|
|
136
|
+
|
|
137
|
+
normalized_distances = []
|
|
138
|
+
best_so_far = 1.0
|
|
139
|
+
for normalized in normalized_list:
|
|
140
|
+
dist = best_window_distance(
|
|
141
|
+
normalized_input, normalized, max_normalized=best_so_far)
|
|
142
|
+
if dist < best_so_far:
|
|
143
|
+
best_so_far = dist
|
|
144
|
+
normalized_distances.append(dist)
|
|
145
|
+
else:
|
|
146
|
+
len_input = len(normalized_input)
|
|
147
|
+
# Compute distances between the input and every candidate truncated to len of input
|
|
148
|
+
normalized_distances = [
|
|
149
|
+
normalized_levenshtein_distance(normalized_input, normalized[:len_input])
|
|
150
|
+
for normalized in normalized_list
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
# Determine the minimal distance observed
|
|
154
|
+
best_distance = min(normalized_distances)
|
|
155
|
+
|
|
156
|
+
# Gather *all* indices whose distance equals the minimal distance
|
|
157
|
+
# Use a small tolerance to account for floating-point precision issues
|
|
158
|
+
tolerance = 1e-12
|
|
159
|
+
best_match_indices = [
|
|
160
|
+
i for i, dist in enumerate(normalized_distances)
|
|
161
|
+
if abs(dist - best_distance) <= tolerance
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
# Map indices back to the original (non-normalized) texts
|
|
165
|
+
best_matches = [text_list[i] for i in best_match_indices]
|
|
166
|
+
|
|
167
|
+
if best_distance <= threshold:
|
|
168
|
+
return (best_matches, best_distance)
|
|
169
|
+
|
|
170
|
+
return ([], None)
|
|
@@ -68,8 +68,38 @@ class DatabaseValidator:
|
|
|
68
68
|
"""Generic validator for database lookups with fuzzy matching"""
|
|
69
69
|
|
|
70
70
|
@staticmethod
|
|
71
|
-
def fuzzy_match(value: str, key_values: list[str], threshold: float = 0.
|
|
72
|
-
|
|
71
|
+
def fuzzy_match(value: str, key_values: list[str], threshold: float = 0.6,
|
|
72
|
+
suggest_threshold: float = 0.7,
|
|
73
|
+
auto_apply_threshold: float = 0.2) -> Tuple[bool, Optional[str], List[str]]:
|
|
74
|
+
"""Find the closest matching value in the specified database.
|
|
75
|
+
|
|
76
|
+
Three stages run in order, and each one short-circuits: a
|
|
77
|
+
case-insensitive exact match, then Levenshtein, then ``difflib``.
|
|
78
|
+
|
|
79
|
+
Parameters
|
|
80
|
+
----------
|
|
81
|
+
threshold
|
|
82
|
+
``difflib`` cutoff for the final suggestion-only stage. Only values
|
|
83
|
+
that no candidate came within ``suggest_threshold`` of reach it, so
|
|
84
|
+
a loose cutoff here yields unrelated suggestions rather than useful
|
|
85
|
+
ones — and because any non-empty suggestion list fails validation,
|
|
86
|
+
those unrelated suggestions reject values that are merely absent
|
|
87
|
+
from this particular candidate list.
|
|
88
|
+
suggest_threshold
|
|
89
|
+
Maximum Levenshtein distance at which a candidate is considered at
|
|
90
|
+
all. Beyond this the value falls through to ``difflib``.
|
|
91
|
+
auto_apply_threshold
|
|
92
|
+
Maximum Levenshtein distance at which a *unique* match is reported
|
|
93
|
+
as matched, which makes the framework overwrite the user's value.
|
|
94
|
+
Kept strict deliberately: the distance at which a real typo lands
|
|
95
|
+
and the distance at which an unrelated value lands are separable,
|
|
96
|
+
and being generous here silently substitutes non-members (``Batman``
|
|
97
|
+
scores 0.333 against a customer list). Note the metric is
|
|
98
|
+
edits/length, so a one-edit typo on a value shorter than about five
|
|
99
|
+
characters exceeds this and is offered as a suggestion instead.
|
|
100
|
+
Raise it per command if an extra clarification turn costs more than
|
|
101
|
+
a wrong substitution.
|
|
102
|
+
"""
|
|
73
103
|
global NOT_FOUND
|
|
74
104
|
if not NOT_FOUND:
|
|
75
105
|
NOT_FOUND = fastworkflow.get_env_var("NOT_FOUND")
|
|
@@ -84,10 +114,12 @@ class DatabaseValidator:
|
|
|
84
114
|
if match is not None:
|
|
85
115
|
return True, match, []
|
|
86
116
|
|
|
87
|
-
best_matches,
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
117
|
+
best_matches, best_distance = find_best_matches(
|
|
118
|
+
value, key_values, threshold = suggest_threshold, best_window = True)
|
|
119
|
+
if best_matches:
|
|
120
|
+
if len(best_matches) == 1 and best_distance <= auto_apply_threshold:
|
|
121
|
+
return True, best_matches[0], []
|
|
122
|
+
# Ambiguous, or close enough to offer but too far to apply unannounced.
|
|
91
123
|
return False, None, best_matches
|
|
92
124
|
|
|
93
125
|
lowercase_matches = get_close_matches(
|
|
@@ -634,6 +666,11 @@ Today's date is {today}.
|
|
|
634
666
|
# matched, corrected_value, field_suggestions = DatabaseValidator.fuzzy_match(field_value, key_values)
|
|
635
667
|
|
|
636
668
|
if matched:
|
|
669
|
+
if corrected_value != field_value:
|
|
670
|
+
logger.debug(
|
|
671
|
+
f"db_lookup substituted {subject_command_name}.{field_name}: "
|
|
672
|
+
f"'{field_value}' -> '{corrected_value}'"
|
|
673
|
+
)
|
|
637
674
|
setattr(cmd_parameters, field_name, corrected_value)
|
|
638
675
|
elif field_suggestions:
|
|
639
676
|
invalid_fields.append(f"{field_name} '{field_value}'")
|
|
@@ -9,7 +9,7 @@ repository = "https://github.com/radiantlogicinc/fastworkflow"
|
|
|
9
9
|
|
|
10
10
|
[tool.poetry]
|
|
11
11
|
name = "fastworkflow"
|
|
12
|
-
version = "3.1.
|
|
12
|
+
version = "3.1.2"
|
|
13
13
|
description = "A framework for rapidly building large-scale, deterministic, interactive workflows with a fault-tolerant, conversational UX"
|
|
14
14
|
authors = ["Dhar Rawal <drawal@radiantlogic.com>"]
|
|
15
15
|
license = "Apache-2.0"
|
|
@@ -76,7 +76,7 @@ starlette = {version = ">=1.3.1", optional = true} # CVE-2025-62727, CVE-2025-5
|
|
|
76
76
|
# and future starlette releases will require httpx2. Floor matches starlette's `full` extra (httpx2>=2.0.0).
|
|
77
77
|
httpx2 = {version = ">=2.0.0", optional = true}
|
|
78
78
|
pydantic-settings = {version = ">=2.14.2", optional = true} # GHSA-4xgf-cpjx-pc3j (NestedSecretsSettingsSource follows symlinks outside secrets_dir -> local file read + secrets_dir_max_size bypass, fixed 2.14.2). Pulled transitively by mcp/fastapi-mcp in the `server` extra.
|
|
79
|
-
datasets = {version = "^
|
|
79
|
+
datasets = {version = "^5.0.1", optional = true} # CVE-2026-66007 / PYSEC-2026-3716 (path traversal via unsanitized file_name; fixed 5.0.1)
|
|
80
80
|
|
|
81
81
|
# Security floor constraints for transitive dependencies of the CORE (client) install.
|
|
82
82
|
# These ensure users get patched versions even though these are not direct deps.
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
from typing import Optional
|
|
3
|
-
import Levenshtein
|
|
4
|
-
|
|
5
|
-
def normalize_text(text):
|
|
6
|
-
"""
|
|
7
|
-
Normalize text by removing spaces, @ symbol, underscores, and converting to lowercase
|
|
8
|
-
"""
|
|
9
|
-
return re.sub(r'[@\s_]', '', str(text).lower())
|
|
10
|
-
|
|
11
|
-
def normalized_levenshtein_distance(s1, s2):
|
|
12
|
-
"""Calculate normalized Levenshtein distance"""
|
|
13
|
-
distance = Levenshtein.distance(s1, s2)
|
|
14
|
-
max_length = max(len(s1), len(s2))
|
|
15
|
-
return 0.0 if max_length == 0 else distance / max_length
|
|
16
|
-
|
|
17
|
-
def find_best_matches(input_text: str,
|
|
18
|
-
text_list: list[str],
|
|
19
|
-
threshold: float=0.4
|
|
20
|
-
) -> tuple[list[str], float] | tuple[None, None]:
|
|
21
|
-
"""Find best match(es) using normalized Levenshtein distance.
|
|
22
|
-
|
|
23
|
-
The function now returns *all* entries whose normalized Levenshtein
|
|
24
|
-
distance equals the minimum distance computed for the provided
|
|
25
|
-
``input_text``. This is useful when multiple candidates tie for the
|
|
26
|
-
smallest distance.
|
|
27
|
-
|
|
28
|
-
Returns
|
|
29
|
-
-------
|
|
30
|
-
tuple[list[str], float] | tuple[None, None]
|
|
31
|
-
A tuple containing the list of best-matching original strings
|
|
32
|
-
and the corresponding distance. If the best distance exceeds
|
|
33
|
-
the ``threshold`` value, ``(None, None)`` is returned.
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
# Ensure we have a concrete list (e.g., when a generator is passed)
|
|
37
|
-
text_list = list(text_list)
|
|
38
|
-
|
|
39
|
-
normalized_input = normalize_text(input_text)
|
|
40
|
-
normalized_list = [normalize_text(text) for text in text_list]
|
|
41
|
-
|
|
42
|
-
# If empty list, return None
|
|
43
|
-
if not normalized_list:
|
|
44
|
-
return ([], None)
|
|
45
|
-
|
|
46
|
-
len_input = len(normalized_input)
|
|
47
|
-
# Compute distances between the input and every candidate truncated to len of input
|
|
48
|
-
normalized_distances = [
|
|
49
|
-
normalized_levenshtein_distance(normalized_input, normalized[:len_input])
|
|
50
|
-
for normalized in normalized_list
|
|
51
|
-
]
|
|
52
|
-
|
|
53
|
-
# Determine the minimal distance observed
|
|
54
|
-
best_distance = min(normalized_distances)
|
|
55
|
-
|
|
56
|
-
# Gather *all* indices whose distance equals the minimal distance
|
|
57
|
-
# Use a small tolerance to account for floating-point precision issues
|
|
58
|
-
tolerance = 1e-12
|
|
59
|
-
best_match_indices = [
|
|
60
|
-
i for i, dist in enumerate(normalized_distances)
|
|
61
|
-
if abs(dist - best_distance) <= tolerance
|
|
62
|
-
]
|
|
63
|
-
|
|
64
|
-
# Map indices back to the original (non-normalized) texts
|
|
65
|
-
best_matches = [text_list[i] for i in best_match_indices]
|
|
66
|
-
|
|
67
|
-
if best_distance <= threshold:
|
|
68
|
-
return (best_matches, best_distance)
|
|
69
|
-
|
|
70
|
-
return ([], None)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/build/inheritance_block_regenerator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/extended_workflow_example/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/hello_world/_commands/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_2/_commands/startup.py
RENAMED
|
File without changes
|
{fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_2/application/user.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastworkflow-3.1.0 → fastworkflow-3.1.2}/fastworkflow/examples/messaging_app_3/application/user.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|