fastworkflow 2.15.10__tar.gz → 2.17.11__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.15.10 → fastworkflow-2.17.11}/PKG-INFO +10 -3
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/README.md +3 -1
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/what_can_i_do.py +16 -2
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/_workflows/command_metadata_extraction/_commands/wildcard.py +15 -6
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/_workflows/command_metadata_extraction/intent_detection.py +3 -3
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/_workflows/command_metadata_extraction/parameter_extraction.py +89 -5
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/chat_session.py +235 -67
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/cli.py +84 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/command_context_model.py +73 -7
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/command_executor.py +1 -1
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/command_metadata_api.py +106 -6
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/fastworkflow.env +1 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/fastworkflow.passwords.env +2 -1
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/_commands/find_user_id_by_email.py +6 -5
- fastworkflow-2.17.11/fastworkflow/intent_clarification_agent.py +132 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/mcp_server.py +3 -3
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/run/__main__.py +0 -6
- fastworkflow-2.17.11/fastworkflow/run_fastapi_mcp/README.md +373 -0
- fastworkflow-2.17.11/fastworkflow/run_fastapi_mcp/__main__.py +1300 -0
- fastworkflow-2.17.11/fastworkflow/run_fastapi_mcp/conversation_store.py +391 -0
- fastworkflow-2.17.11/fastworkflow/run_fastapi_mcp/jwt_manager.py +341 -0
- fastworkflow-2.17.11/fastworkflow/run_fastapi_mcp/mcp_specific.py +103 -0
- fastworkflow-2.17.11/fastworkflow/run_fastapi_mcp/redoc_2_standalone_html.py +40 -0
- fastworkflow-2.17.11/fastworkflow/run_fastapi_mcp/utils.py +517 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/train/__main__.py +1 -1
- fastworkflow-2.17.11/fastworkflow/utils/chat_adapter.py +99 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/utils/python_utils.py +4 -4
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/utils/react.py +20 -4
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/utils/signatures.py +137 -132
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/workflow_agent.py +94 -11
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/pyproject.toml +9 -3
- fastworkflow-2.15.10/fastworkflow/run_agent/__main__.py +0 -294
- fastworkflow-2.15.10/fastworkflow/run_agent/agent_module.py +0 -194
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/LICENSE +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/.DS_Store +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/__init__.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/_commands/.gitkeep +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/_workflows/__init__.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/_workflows/command_metadata_extraction/__init__.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/_workflows/command_metadata_extraction/_commands/ErrorCorrection/abort.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/_workflows/command_metadata_extraction/_commands/ErrorCorrection/you_misunderstood.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/go_up.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/reset_context.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/what_is_current_context.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/_workflows/command_metadata_extraction/_commands/__init__.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/_workflows/command_metadata_extraction/command_context_model.json +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/__main__.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/ast_class_extractor.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/class_analysis_structures.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/cli_specification.md +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/command_dependency_resolver.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/command_file_generator.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/command_file_template.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/command_import_utils.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/command_stub_generator.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/context_folder_generator.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/context_model_generator.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/dependency_manager.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/dir_scanner.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/documentation_generator.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/genai_postprocessor.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/inheritance_block_regenerator.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/libcst_transformers.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/navigator_stub_generator.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/pydantic_model_generator.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/build/utterance_generator.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/cache_matching.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/command_directory.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/command_interfaces.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/command_routing.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/docs/context_modules_prd.txt +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/extended_workflow_example/README.md +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/extended_workflow_example/_commands/WorkItem/get_status.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/extended_workflow_example/_commands/generate_report.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/extended_workflow_example/_commands/startup.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/extended_workflow_example/simple_workflow_template.json +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/extended_workflow_example/workflow_inheritance_model.json +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/hello_world/_commands/README.md +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/hello_world/_commands/add_two_numbers.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/hello_world/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/hello_world/application/add_two_numbers.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_1/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_1/_commands/send_message.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_1/application/send_message.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_2/_commands/User/send_message.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_2/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_2/_commands/startup.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_2/application/user.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_3/_commands/PremiumUser/send_priority_message.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_3/_commands/User/send_message.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_3/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_3/_commands/initialize_user.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_3/application/user.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/_ChatRoom.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/add_user.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/broadcast_message.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/get_current_user.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/list_users.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/set_current_user.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_4/_commands/PremiumUser/_PremiumUser.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_4/_commands/PremiumUser/send_priority_message.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_4/_commands/User/_User.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_4/_commands/User/send_message.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_4/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_4/_commands/set_root_context.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_4/application/chatroom.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_4/application/user.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_4/context_hierarchy_model.json +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/messaging_app_4/startup_action.json +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/_commands/calculate.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/_commands/cancel_pending_order.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/_commands/exchange_delivered_order_items.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/_commands/find_user_id_by_name_zip.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/_commands/get_order_details.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/_commands/get_product_details.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/_commands/get_user_details.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/_commands/list_all_product_types.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_address.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_items.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_payment.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/_commands/modify_user_address.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/_commands/return_delivered_order_items.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/_commands/transfer_to_human_agents.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/context_inheritance_model.json +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/retail_data/__init__.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/retail_data/orders.json +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/retail_data/products.json +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/retail_data/users.json +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/tools/calculate.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/tools/cancel_pending_order.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/tools/exchange_delivered_order_items.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/tools/find_user_id_by_email.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/tools/find_user_id_by_name_zip.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/tools/get_order_details.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/tools/get_product_details.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/tools/get_user_details.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/tools/list_all_product_types.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_address.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_items.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_payment.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/tools/modify_user_address.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/tools/return_delivered_order_items.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/tools/think.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/tools/tool.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/tools/transfer_to_human_agents.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/retail_workflow/workflow_description.txt +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/__init__.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/_WorkItem.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/add_child_workitem.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/get_status.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/go_to_workitem.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/mark_as_complete.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_first_child_workitem.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_last_child_workitem.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_next_workitem.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_previous_workitem.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/remove_all_child_workitems.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/remove_child_workitem.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/show_schema.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/_commands/startup.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/application/__init__.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/application/workitem.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/simple_workflow_template.json +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/examples/simple_workflow_template/startup_action.json +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/model_pipeline_training.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/refine/__main__.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/run/__init__.py +0 -0
- {fastworkflow-2.15.10/fastworkflow/run_agent → fastworkflow-2.17.11/fastworkflow/run_fastapi_mcp}/__init__.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/train/__init__.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/train/generate_synthetic.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/user_message_queues.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/utils/__init__.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/utils/command_dependency_graph.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/utils/context_utils.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/utils/dspy_cache_utils.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/utils/dspy_logger.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/utils/dspy_utils.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/utils/env.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/utils/fuzzy_match.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/utils/generate_param_examples.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/utils/logging.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/utils/parameterize_func_decorator.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/utils/pydantic_model_2_dspy_signature_class.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/utils/startup_progress.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/workflow.py +0 -0
- {fastworkflow-2.15.10 → fastworkflow-2.17.11}/fastworkflow/workflow_inheritance_model.py +0 -0
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fastworkflow
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.17.11
|
|
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
|
|
7
7
|
Author: Dhar Rawal
|
|
8
8
|
Author-email: drawal@radiantlogic.com
|
|
9
|
-
Requires-Python: >=3.11
|
|
9
|
+
Requires-Python: >=3.11,<3.14
|
|
10
10
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
11
|
Classifier: Programming Language :: Python :: 3
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Provides-Extra: fastapi
|
|
14
15
|
Requires-Dist: colorama (>=0.4.6,<0.5.0)
|
|
15
16
|
Requires-Dist: datasets (>=4.0.0,<5.0.0)
|
|
16
17
|
Requires-Dist: dspy (>=3.0.1,<4.0.0)
|
|
18
|
+
Requires-Dist: fastapi (>=0.115.5,<0.116.0) ; extra == "fastapi"
|
|
19
|
+
Requires-Dist: fastapi-mcp (>=0.4.0,<0.5.0) ; extra == "fastapi"
|
|
17
20
|
Requires-Dist: libcst (>=1.8.2,<2.0.0)
|
|
18
21
|
Requires-Dist: litellm[proxy] (>=1.75.8,<2.0.0)
|
|
19
22
|
Requires-Dist: mmh3 (>=5.1.0,<6.0.0)
|
|
@@ -21,12 +24,14 @@ Requires-Dist: openai (>=1.99.5,<1.100.0)
|
|
|
21
24
|
Requires-Dist: prompt_toolkit (>=3.0.43,<4.0.0)
|
|
22
25
|
Requires-Dist: pydantic (>=2.9.2,<3.0.0)
|
|
23
26
|
Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
|
27
|
+
Requires-Dist: python-jose[cryptography] (>=3.3.0,<4.0.0) ; extra == "fastapi"
|
|
24
28
|
Requires-Dist: python-levenshtein (>=0.27.1,<0.28.0)
|
|
25
29
|
Requires-Dist: scikit-learn (>=1.6.1,<2.0.0)
|
|
26
30
|
Requires-Dist: sentence-transformers (>=3.4.1,<4.0.0)
|
|
27
31
|
Requires-Dist: speedict (>=0.3.12,<0.4.0)
|
|
28
32
|
Requires-Dist: torch (>=2.7.1,<3.0.0)
|
|
29
33
|
Requires-Dist: transformers (>=4.48.2,<5.0.0)
|
|
34
|
+
Requires-Dist: uvicorn (>=0.29.0,<0.30.0) ; extra == "fastapi"
|
|
30
35
|
Project-URL: homepage, https://github.com/radiantlogicinc/fastworkflow
|
|
31
36
|
Project-URL: repository, https://github.com/radiantlogicinc/fastworkflow
|
|
32
37
|
Description-Content-Type: text/markdown
|
|
@@ -581,6 +586,7 @@ This single command will generate the `greet.py` command, `get_properties` and `
|
|
|
581
586
|
| `LLM_RESPONSE_GEN` | LiteLLM model string for response generation | `run` | `mistral/mistral-small-latest` |
|
|
582
587
|
| `LLM_PLANNER` | LiteLLM model string for the agent's task planner | `run` (agent mode) | `mistral/mistral-small-latest` |
|
|
583
588
|
| `LLM_AGENT` | LiteLLM model string for the DSPy agent | `run` (agent mode) | `mistral/mistral-small-latest` |
|
|
589
|
+
| `LLM_CONVERSATION_STORE` | LiteLLM model string for conversation topic/summary generation | FastAPI service | `mistral/mistral-small-latest` |
|
|
584
590
|
| `NOT_FOUND` | Placeholder value for missing parameters during extraction | Always | `"NOT_FOUND"` |
|
|
585
591
|
| `MISSING_INFORMATION_ERRMSG` | Error message prefix for missing parameters | Always | `"Missing required..."` |
|
|
586
592
|
| `INVALID_INFORMATION_ERRMSG` | Error message prefix for invalid parameters | Always | `"Invalid information..."` |
|
|
@@ -594,6 +600,7 @@ This single command will generate the `greet.py` command, `get_properties` and `
|
|
|
594
600
|
| `LITELLM_API_KEY_RESPONSE_GEN`| API key for the `LLM_RESPONSE_GEN` model | `run` | *required* |
|
|
595
601
|
| `LITELLM_API_KEY_PLANNER`| API key for the `LLM_PLANNER` model | `run` (agent mode) | *required* |
|
|
596
602
|
| `LITELLM_API_KEY_AGENT`| API key for the `LLM_AGENT` model | `run` (agent mode) | *required* |
|
|
603
|
+
| `LITELLM_API_KEY_CONVERSATION_STORE`| API key for the `LLM_CONVERSATION_STORE` model | FastAPI service | *required* |
|
|
597
604
|
|
|
598
605
|
> [!tip]
|
|
599
606
|
> The example workflows are configured to use Mistral's models by default. You can get a free API key from [Mistral AI](https://mistral.ai) that works with the `mistral-small-latest` model.
|
|
@@ -629,7 +636,7 @@ Interested in contributing to `fastWorkflow` itself? Great!
|
|
|
629
636
|
1. **Clone the repository:** `git clone https://github.com/your-repo/fastworkflow.git`
|
|
630
637
|
2. **Set up the environment:** Create a virtual environment using your preferred tool (venv, uv, conda, poetry, etc.) with Python 3.11+
|
|
631
638
|
3. **Install in editable mode with dev dependencies:** `pip install -e .` or `uv pip install -e ".[dev]"`
|
|
632
|
-
4. **[Join our Discord](https://discord.gg/
|
|
639
|
+
4. **[Join our Discord](https://discord.gg/k2g58dDjYR):** Ask questions, discuss functionality, showcase your fastWorkflows
|
|
633
640
|
|
|
634
641
|
---
|
|
635
642
|
|
|
@@ -548,6 +548,7 @@ This single command will generate the `greet.py` command, `get_properties` and `
|
|
|
548
548
|
| `LLM_RESPONSE_GEN` | LiteLLM model string for response generation | `run` | `mistral/mistral-small-latest` |
|
|
549
549
|
| `LLM_PLANNER` | LiteLLM model string for the agent's task planner | `run` (agent mode) | `mistral/mistral-small-latest` |
|
|
550
550
|
| `LLM_AGENT` | LiteLLM model string for the DSPy agent | `run` (agent mode) | `mistral/mistral-small-latest` |
|
|
551
|
+
| `LLM_CONVERSATION_STORE` | LiteLLM model string for conversation topic/summary generation | FastAPI service | `mistral/mistral-small-latest` |
|
|
551
552
|
| `NOT_FOUND` | Placeholder value for missing parameters during extraction | Always | `"NOT_FOUND"` |
|
|
552
553
|
| `MISSING_INFORMATION_ERRMSG` | Error message prefix for missing parameters | Always | `"Missing required..."` |
|
|
553
554
|
| `INVALID_INFORMATION_ERRMSG` | Error message prefix for invalid parameters | Always | `"Invalid information..."` |
|
|
@@ -561,6 +562,7 @@ This single command will generate the `greet.py` command, `get_properties` and `
|
|
|
561
562
|
| `LITELLM_API_KEY_RESPONSE_GEN`| API key for the `LLM_RESPONSE_GEN` model | `run` | *required* |
|
|
562
563
|
| `LITELLM_API_KEY_PLANNER`| API key for the `LLM_PLANNER` model | `run` (agent mode) | *required* |
|
|
563
564
|
| `LITELLM_API_KEY_AGENT`| API key for the `LLM_AGENT` model | `run` (agent mode) | *required* |
|
|
565
|
+
| `LITELLM_API_KEY_CONVERSATION_STORE`| API key for the `LLM_CONVERSATION_STORE` model | FastAPI service | *required* |
|
|
564
566
|
|
|
565
567
|
> [!tip]
|
|
566
568
|
> The example workflows are configured to use Mistral's models by default. You can get a free API key from [Mistral AI](https://mistral.ai) that works with the `mistral-small-latest` model.
|
|
@@ -596,7 +598,7 @@ Interested in contributing to `fastWorkflow` itself? Great!
|
|
|
596
598
|
1. **Clone the repository:** `git clone https://github.com/your-repo/fastworkflow.git`
|
|
597
599
|
2. **Set up the environment:** Create a virtual environment using your preferred tool (venv, uv, conda, poetry, etc.) with Python 3.11+
|
|
598
600
|
3. **Install in editable mode with dev dependencies:** `pip install -e .` or `uv pip install -e ".[dev]"`
|
|
599
|
-
4. **[Join our Discord](https://discord.gg/
|
|
601
|
+
4. **[Join our Discord](https://discord.gg/k2g58dDjYR):** Ask questions, discuss functionality, showcase your fastWorkflows
|
|
600
602
|
|
|
601
603
|
---
|
|
602
604
|
|
|
@@ -8,6 +8,7 @@ import json
|
|
|
8
8
|
|
|
9
9
|
import fastworkflow
|
|
10
10
|
from fastworkflow.train.generate_synthetic import generate_diverse_utterances
|
|
11
|
+
from fastworkflow.command_context_model import get_workflow_info
|
|
11
12
|
from fastworkflow.command_metadata_api import CommandMetadataAPI
|
|
12
13
|
|
|
13
14
|
class Signature:
|
|
@@ -139,20 +140,33 @@ class ResponseGenerator:
|
|
|
139
140
|
with contextlib.suppress(Exception):
|
|
140
141
|
if fastworkflow.chat_session:
|
|
141
142
|
is_agent_mode = fastworkflow.chat_session.run_as_agent
|
|
142
|
-
|
|
143
|
+
|
|
143
144
|
app_workflow = workflow.context["app_workflow"]
|
|
144
|
-
|
|
145
|
+
|
|
146
|
+
# Get workflow definition
|
|
147
|
+
workflow_info = get_workflow_info(app_workflow.folderpath)
|
|
148
|
+
workflow_def_text = CommandMetadataAPI.get_workflow_definition_display_text(workflow_info)
|
|
149
|
+
|
|
150
|
+
# Get available commands in current context
|
|
151
|
+
commands_text = CommandMetadataAPI.get_command_display_text(
|
|
145
152
|
subject_workflow_path=app_workflow.folderpath,
|
|
146
153
|
cme_workflow_path=workflow.folderpath,
|
|
147
154
|
active_context_name=app_workflow.current_command_context_name,
|
|
148
155
|
for_agents=is_agent_mode,
|
|
149
156
|
)
|
|
157
|
+
|
|
158
|
+
response = f"{workflow_def_text}\n\n{commands_text}"
|
|
150
159
|
|
|
160
|
+
nlu_pipeline_stage = workflow.context.get(
|
|
161
|
+
"NLU_Pipeline_Stage",
|
|
162
|
+
fastworkflow.NLUPipelineStage.INTENT_DETECTION)
|
|
163
|
+
success = nlu_pipeline_stage == fastworkflow.NLUPipelineStage.INTENT_DETECTION
|
|
151
164
|
return fastworkflow.CommandOutput(
|
|
152
165
|
workflow_id=workflow.id,
|
|
153
166
|
command_responses=[
|
|
154
167
|
fastworkflow.CommandResponse(
|
|
155
168
|
response=response,
|
|
169
|
+
success=success
|
|
156
170
|
)
|
|
157
171
|
]
|
|
158
172
|
)
|
|
@@ -67,7 +67,10 @@ class ResponseGenerator:
|
|
|
67
67
|
if cnp_output.command_name == 'ErrorCorrection/you_misunderstood':
|
|
68
68
|
workflow_context["NLU_Pipeline_Stage"] = NLUPipelineStage.INTENT_MISUNDERSTANDING_CLARIFICATION
|
|
69
69
|
workflow_context["command"] = command
|
|
70
|
-
|
|
70
|
+
elif (
|
|
71
|
+
nlu_pipeline_stage == fastworkflow.NLUPipelineStage.INTENT_DETECTION or
|
|
72
|
+
cnp_output.command_name == 'ErrorCorrection/abort'
|
|
73
|
+
):
|
|
71
74
|
workflow.end_command_processing()
|
|
72
75
|
workflow.context = workflow_context
|
|
73
76
|
|
|
@@ -76,9 +79,13 @@ class ResponseGenerator:
|
|
|
76
79
|
command=command,
|
|
77
80
|
)
|
|
78
81
|
command_output = CommandExecutor.perform_action(workflow, startup_action)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
if (
|
|
83
|
+
nlu_pipeline_stage == fastworkflow.NLUPipelineStage.INTENT_DETECTION or
|
|
84
|
+
cnp_output.command_name == 'ErrorCorrection/abort'
|
|
85
|
+
):
|
|
86
|
+
command_output.command_responses[0].artifacts["command_handled"] = True
|
|
87
|
+
# Set the additional attributes
|
|
88
|
+
command_output.command_name = cnp_output.command_name
|
|
82
89
|
return command_output
|
|
83
90
|
|
|
84
91
|
if nlu_pipeline_stage in {
|
|
@@ -138,7 +145,9 @@ class ResponseGenerator:
|
|
|
138
145
|
workflow.context = workflow_context
|
|
139
146
|
|
|
140
147
|
command_name = cnp_output.command_name
|
|
141
|
-
|
|
148
|
+
# Use the preserved original command (with parameters) if available
|
|
149
|
+
preserved_command = f'{command_name}: {workflow.context.get("command", command)}'
|
|
150
|
+
extractor = ParameterExtraction(workflow, app_workflow, command_name, preserved_command)
|
|
142
151
|
pe_output = extractor.extract()
|
|
143
152
|
if not pe_output.parameters_are_valid:
|
|
144
153
|
return CommandOutput(
|
|
@@ -161,7 +170,7 @@ class ResponseGenerator:
|
|
|
161
170
|
CommandResponse(
|
|
162
171
|
response="",
|
|
163
172
|
artifacts={
|
|
164
|
-
"command":
|
|
173
|
+
"command": preserved_command,
|
|
165
174
|
"command_name": command_name,
|
|
166
175
|
"cmd_parameters": pe_output.cmd_parameters,
|
|
167
176
|
},
|
|
@@ -96,8 +96,8 @@ class CommandNamePrediction:
|
|
|
96
96
|
].plain_utterances
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
# See if the command starts with a command name followed by a space
|
|
100
|
-
tentative_command_name = command.split(" ", 1)[0]
|
|
99
|
+
# See if the command starts with a command name followed by a space or a '('
|
|
100
|
+
tentative_command_name = command.split(" ", 1)[0].split("(", 1)[0]
|
|
101
101
|
normalized_command_name = tentative_command_name.lower()
|
|
102
102
|
command_name = None
|
|
103
103
|
if normalized_command_name in command_name_dict:
|
|
@@ -136,7 +136,7 @@ class CommandNamePrediction:
|
|
|
136
136
|
NLUPipelineStage.INTENT_AMBIGUITY_CLARIFICATION,
|
|
137
137
|
NLUPipelineStage.INTENT_MISUNDERSTANDING_CLARIFICATION
|
|
138
138
|
) and not command_name:
|
|
139
|
-
command_name = "
|
|
139
|
+
command_name = "what can i do?"
|
|
140
140
|
|
|
141
141
|
if not command_name or command_name == "wildcard":
|
|
142
142
|
fully_qualified_command_name=None
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import contextlib
|
|
2
2
|
import sys
|
|
3
|
+
import re
|
|
3
4
|
from typing import Dict, List, Optional
|
|
4
5
|
|
|
5
6
|
from pydantic import BaseModel
|
|
7
|
+
from pydantic_core import PydanticUndefined
|
|
6
8
|
|
|
7
9
|
import fastworkflow
|
|
8
10
|
from fastworkflow.utils.logging import logger
|
|
@@ -59,11 +61,29 @@ class ParameterExtraction:
|
|
|
59
61
|
if stored_params:
|
|
60
62
|
new_params = self._extract_and_merge_missing_parameters(stored_params, self.command)
|
|
61
63
|
else:
|
|
62
|
-
#
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
self.
|
|
66
|
-
|
|
64
|
+
# Check if we're in agentic mode (not assistant mode command)
|
|
65
|
+
is_agentic_mode = (
|
|
66
|
+
"is_assistant_mode_command" not in self.cme_workflow.context
|
|
67
|
+
and "run_as_agent" in self.app_workflow.context
|
|
68
|
+
and self.app_workflow.context["run_as_agent"]
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
if is_agentic_mode:
|
|
72
|
+
# Try regex-based extraction first in agentic mode
|
|
73
|
+
new_params = self._extract_parameters_from_xml(self.command, command_parameters_class)
|
|
74
|
+
|
|
75
|
+
# If regex extraction fails, fall back to LLM-based extraction
|
|
76
|
+
if new_params is None:
|
|
77
|
+
new_params = input_for_param_extraction.extract_parameters(
|
|
78
|
+
command_parameters_class,
|
|
79
|
+
self.command_name,
|
|
80
|
+
app_workflow_folderpath)
|
|
81
|
+
else:
|
|
82
|
+
# Use LLM-based extraction for assistant mode
|
|
83
|
+
new_params = input_for_param_extraction.extract_parameters(
|
|
84
|
+
command_parameters_class,
|
|
85
|
+
self.command_name,
|
|
86
|
+
app_workflow_folderpath)
|
|
67
87
|
|
|
68
88
|
is_valid, error_msg, suggestions, missing_invalid_fields = \
|
|
69
89
|
input_for_param_extraction.validate_parameters(
|
|
@@ -272,6 +292,70 @@ class ParameterExtraction:
|
|
|
272
292
|
# Construct model without validation
|
|
273
293
|
return default_params.__class__.model_construct(**params_data)
|
|
274
294
|
|
|
295
|
+
@staticmethod
|
|
296
|
+
def _extract_parameters_from_xml(command: str, command_parameters_class: type[BaseModel]) -> Optional[BaseModel]:
|
|
297
|
+
"""
|
|
298
|
+
Extract parameters from XML-formatted command using regex.
|
|
299
|
+
|
|
300
|
+
Returns:
|
|
301
|
+
BaseModel instance with extracted parameters, or None if parsing fails
|
|
302
|
+
"""
|
|
303
|
+
field_names = list(command_parameters_class.model_fields.keys())
|
|
304
|
+
|
|
305
|
+
# If no parameters are defined, return empty model immediately
|
|
306
|
+
if not field_names:
|
|
307
|
+
return command_parameters_class.model_construct()
|
|
308
|
+
|
|
309
|
+
extracted_data = {}
|
|
310
|
+
|
|
311
|
+
# Try to extract each parameter using XML tags
|
|
312
|
+
if len(field_names) == 1:
|
|
313
|
+
# If there's only one field, extract content from first XML tag
|
|
314
|
+
pattern = r'<[^>]+>(.+?)</[^>]+>'
|
|
315
|
+
if match := re.search(pattern, command, re.DOTALL):
|
|
316
|
+
parameter_value = match[1].strip()
|
|
317
|
+
extracted_data[field_names[0]] = parameter_value
|
|
318
|
+
else:
|
|
319
|
+
# Try to extract each parameter using XML tags
|
|
320
|
+
for field_name in field_names:
|
|
321
|
+
# Look for <field_name>value</field_name> pattern
|
|
322
|
+
pattern = rf'<{re.escape(field_name)}>(.+?)</{re.escape(field_name)}>'
|
|
323
|
+
if match := re.search(pattern, command, re.DOTALL):
|
|
324
|
+
parameter_value = match[1].strip()
|
|
325
|
+
extracted_data[field_name] = parameter_value
|
|
326
|
+
|
|
327
|
+
# Check if we extracted values for ALL fields (safest criteria for LLM fallback)
|
|
328
|
+
all_fields_extracted = len(extracted_data) == len(field_names)
|
|
329
|
+
|
|
330
|
+
# Check if agent used example values
|
|
331
|
+
if all_fields_extracted:
|
|
332
|
+
for field_name, extracted_value in extracted_data.items():
|
|
333
|
+
field_info = command_parameters_class.model_fields[field_name]
|
|
334
|
+
examples = getattr(field_info, "examples", None)
|
|
335
|
+
if examples and extracted_value in examples:
|
|
336
|
+
all_fields_extracted = False
|
|
337
|
+
break
|
|
338
|
+
|
|
339
|
+
if all_fields_extracted:
|
|
340
|
+
# Initialize all fields with their default values (if they exist) or None
|
|
341
|
+
params_data = {}
|
|
342
|
+
for field_name in field_names:
|
|
343
|
+
field_info = command_parameters_class.model_fields[field_name]
|
|
344
|
+
if field_info.default is not PydanticUndefined:
|
|
345
|
+
params_data[field_name] = field_info.default
|
|
346
|
+
elif field_info.default_factory is not None:
|
|
347
|
+
params_data[field_name] = field_info.default_factory()
|
|
348
|
+
else:
|
|
349
|
+
params_data[field_name] = None
|
|
350
|
+
|
|
351
|
+
# Update with extracted values
|
|
352
|
+
params_data |= extracted_data
|
|
353
|
+
|
|
354
|
+
# Construct model without validation
|
|
355
|
+
return command_parameters_class.model_construct(**params_data)
|
|
356
|
+
|
|
357
|
+
return None
|
|
358
|
+
|
|
275
359
|
@staticmethod
|
|
276
360
|
def _extract_and_merge_missing_parameters(stored_params: BaseModel, command: str):
|
|
277
361
|
"""
|