fastworkflow 2.17.6__tar.gz → 2.17.8__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.
Potentially problematic release.
This version of fastworkflow might be problematic. Click here for more details.
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/PKG-INFO +1 -1
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/run_fastapi_mcp/README.md +55 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/run_fastapi_mcp/__main__.py +15 -12
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/run_fastapi_mcp/jwt_manager.py +91 -16
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/run_fastapi_mcp/utils.py +36 -10
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/pyproject.toml +1 -1
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/LICENSE +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/README.md +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/.DS_Store +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/__init__.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/_commands/.gitkeep +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/_workflows/__init__.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/_workflows/command_metadata_extraction/__init__.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/_workflows/command_metadata_extraction/_commands/ErrorCorrection/abort.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/_workflows/command_metadata_extraction/_commands/ErrorCorrection/you_misunderstood.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/go_up.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/reset_context.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/what_can_i_do.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/_workflows/command_metadata_extraction/_commands/IntentDetection/what_is_current_context.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/_workflows/command_metadata_extraction/_commands/__init__.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/_workflows/command_metadata_extraction/_commands/wildcard.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/_workflows/command_metadata_extraction/command_context_model.json +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/_workflows/command_metadata_extraction/intent_detection.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/_workflows/command_metadata_extraction/parameter_extraction.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/__main__.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/ast_class_extractor.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/class_analysis_structures.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/cli_specification.md +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/command_dependency_resolver.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/command_file_generator.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/command_file_template.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/command_import_utils.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/command_stub_generator.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/context_folder_generator.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/context_model_generator.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/dependency_manager.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/dir_scanner.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/documentation_generator.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/genai_postprocessor.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/inheritance_block_regenerator.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/libcst_transformers.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/navigator_stub_generator.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/pydantic_model_generator.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/utterance_generator.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/cache_matching.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/chat_session.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/cli.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/command_context_model.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/command_directory.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/command_executor.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/command_interfaces.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/command_metadata_api.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/command_routing.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/docs/context_modules_prd.txt +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/extended_workflow_example/README.md +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/extended_workflow_example/_commands/WorkItem/get_status.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/extended_workflow_example/_commands/generate_report.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/extended_workflow_example/_commands/startup.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/extended_workflow_example/simple_workflow_template.json +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/extended_workflow_example/workflow_inheritance_model.json +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/fastworkflow.env +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/fastworkflow.passwords.env +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/hello_world/_commands/README.md +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/hello_world/_commands/add_two_numbers.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/hello_world/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/hello_world/application/add_two_numbers.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_1/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_1/_commands/send_message.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_1/application/send_message.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_2/_commands/User/send_message.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_2/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_2/_commands/startup.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_2/application/user.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_3/_commands/PremiumUser/send_priority_message.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_3/_commands/User/send_message.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_3/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_3/_commands/initialize_user.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_3/application/user.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/_ChatRoom.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/add_user.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/broadcast_message.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/get_current_user.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/list_users.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_4/_commands/ChatRoom/set_current_user.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_4/_commands/PremiumUser/_PremiumUser.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_4/_commands/PremiumUser/send_priority_message.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_4/_commands/User/_User.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_4/_commands/User/send_message.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_4/_commands/context_inheritance_model.json +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_4/_commands/set_root_context.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_4/application/chatroom.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_4/application/user.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_4/context_hierarchy_model.json +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/messaging_app_4/startup_action.json +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/_commands/calculate.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/_commands/cancel_pending_order.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/_commands/exchange_delivered_order_items.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/_commands/find_user_id_by_email.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/_commands/find_user_id_by_name_zip.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/_commands/get_order_details.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/_commands/get_product_details.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/_commands/get_user_details.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/_commands/list_all_product_types.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_address.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_items.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/_commands/modify_pending_order_payment.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/_commands/modify_user_address.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/_commands/return_delivered_order_items.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/_commands/transfer_to_human_agents.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/context_inheritance_model.json +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/retail_data/__init__.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/retail_data/orders.json +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/retail_data/products.json +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/retail_data/users.json +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/calculate.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/cancel_pending_order.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/exchange_delivered_order_items.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/find_user_id_by_email.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/find_user_id_by_name_zip.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/get_order_details.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/get_product_details.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/get_user_details.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/list_all_product_types.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_address.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_items.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/modify_pending_order_payment.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/modify_user_address.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/return_delivered_order_items.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/think.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/tool.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/transfer_to_human_agents.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/workflow_description.txt +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/__init__.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/_WorkItem.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/add_child_workitem.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/get_status.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/go_to_workitem.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/mark_as_complete.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_first_child_workitem.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_last_child_workitem.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_next_workitem.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/move_to_previous_workitem.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/remove_all_child_workitems.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/remove_child_workitem.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/_commands/WorkItem/show_schema.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/_commands/startup.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/application/__init__.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/application/workitem.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/simple_workflow_template.json +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/simple_workflow_template/startup_action.json +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/mcp_server.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/model_pipeline_training.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/refine/__main__.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/run/__init__.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/run/__main__.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/run_fastapi_mcp/__init__.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/run_fastapi_mcp/conversation_store.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/run_fastapi_mcp/mcp_specific.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/run_fastapi_mcp/redoc_2_standalone_html.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/train/__init__.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/train/__main__.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/train/generate_synthetic.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/user_message_queues.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/__init__.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/chat_adapter.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/command_dependency_graph.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/context_utils.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/dspy_cache_utils.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/dspy_logger.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/dspy_utils.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/env.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/fuzzy_match.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/generate_param_examples.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/logging.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/parameterize_func_decorator.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/pydantic_model_2_dspy_signature_class.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/python_utils.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/react.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/signatures.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/startup_progress.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/workflow.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/workflow_agent.py +0 -0
- {fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/workflow_inheritance_model.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fastworkflow
|
|
3
|
-
Version: 2.17.
|
|
3
|
+
Version: 2.17.8
|
|
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
|
|
@@ -47,12 +47,67 @@ Configure in your environment (loaded at process startup via CLI args or env loa
|
|
|
47
47
|
| Variable | Description | Required | Default |
|
|
48
48
|
|----------|-------------|----------|---------|
|
|
49
49
|
| `SPEEDDICT_FOLDERNAME` | Base folder for workflow contexts and conversation storage | Yes | - |
|
|
50
|
+
| `--expect_encrypted_jwt` | Enable full JWT signature verification (pass flag to require signed tokens) | No | False (no verification by default) |
|
|
50
51
|
|
|
51
52
|
Notes:
|
|
52
53
|
- Conversation DBs are stored under `SPEEDDICT_FOLDERNAME/user_conversations` (directory is auto-created).
|
|
53
54
|
- `/conversations` now accepts a `limit` query parameter (default `20`).
|
|
54
55
|
- Shutdown waits up to 30 seconds for active turns (hard-coded).
|
|
55
56
|
|
|
57
|
+
## JWT Verification Modes
|
|
58
|
+
|
|
59
|
+
### Default Behavior: No Signature Verification
|
|
60
|
+
By default, the service does NOT verify JWT signatures, accepting unsigned tokens for trusted internal networks where JWT is used purely for data transport:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
uvicorn services.run_fastapi.main:app --workflow_path /path/to/workflow
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Use cases** (no verification):
|
|
67
|
+
- Controlled internal networks with network-level security
|
|
68
|
+
- Systems where JWT carries non-sensitive routing information
|
|
69
|
+
- Trusted environments where data transport is the primary concern
|
|
70
|
+
|
|
71
|
+
The service logs a warning on startup when running in this mode.
|
|
72
|
+
|
|
73
|
+
### Secure Mode: Enable Signature Verification
|
|
74
|
+
For production deployments requiring full RSA signature verification:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
uvicorn services.run_fastapi.main:app --workflow_path /path/to/workflow --expect_encrypted_jwt
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Secure mode** (with `--expect_encrypted_jwt` flag):
|
|
81
|
+
- JWT tokens are cryptographically verified using RSA signatures
|
|
82
|
+
- Tokens without valid signatures are rejected
|
|
83
|
+
- Recommended for production deployments in untrusted environments
|
|
84
|
+
|
|
85
|
+
### Token Access in Workflow Context
|
|
86
|
+
|
|
87
|
+
JWT tokens are automatically passed to workflows via the `workflow_context` parameter as `http_bearer_token`. This allows workflows to access the bearer token for making authenticated API calls or forwarding authentication.
|
|
88
|
+
|
|
89
|
+
**Important notes:**
|
|
90
|
+
- The token is **only available to authenticated endpoints** (those using `get_session_and_ensure_runtime` dependency)
|
|
91
|
+
- The token is stored in the workflow context dictionary under the key `http_bearer_token`
|
|
92
|
+
- Token is **automatically updated** on every authenticated request, ensuring workflows always have the current valid token
|
|
93
|
+
- Token expiration is **automatically verified** by `verify_token()` in both secure mode (`--expect_encrypted_jwt` flag) and trusted network mode
|
|
94
|
+
- In secure mode: Full cryptographic signature verification + expiration checking
|
|
95
|
+
- In trusted network mode: Expiration checking is performed (signature verification disabled)
|
|
96
|
+
- Tokens should be treated as sensitive data and handled securely in workflows
|
|
97
|
+
- The `/initialize` endpoint is unauthenticated and does NOT provide a token to the workflow context; tokens are only available after calling `/initialize` and using the returned token in subsequent requests
|
|
98
|
+
|
|
99
|
+
**Example usage in workflow:**
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
# In workflow code
|
|
103
|
+
workflow_context = self._context # Gets the workflow_context
|
|
104
|
+
bearer_token = workflow_context.get('http_bearer_token')
|
|
105
|
+
|
|
106
|
+
# Use token for API calls
|
|
107
|
+
headers = {"Authorization": f"Bearer {bearer_token}"}
|
|
108
|
+
response = requests.get("https://api.example.com/data", headers=headers)
|
|
109
|
+
```
|
|
110
|
+
|
|
56
111
|
## API Endpoints (REST)
|
|
57
112
|
|
|
58
113
|
### `POST /initialize`
|
|
@@ -61,6 +61,7 @@ from .jwt_manager import (
|
|
|
61
61
|
create_access_token,
|
|
62
62
|
create_refresh_token,
|
|
63
63
|
verify_token,
|
|
64
|
+
set_jwt_verification_mode,
|
|
64
65
|
JWT_ACCESS_TOKEN_EXPIRE_MINUTES
|
|
65
66
|
)
|
|
66
67
|
|
|
@@ -125,7 +126,8 @@ async def get_session_and_ensure_runtime(
|
|
|
125
126
|
workflow_path=ARGS.workflow_path,
|
|
126
127
|
context=json.loads(ARGS.context) if ARGS.context else None,
|
|
127
128
|
startup_command=ARGS.startup_command,
|
|
128
|
-
startup_action=fastworkflow.Action(**json.loads(ARGS.startup_action)) if ARGS.startup_action else None
|
|
129
|
+
startup_action=fastworkflow.Action(**json.loads(ARGS.startup_action)) if ARGS.startup_action else None,
|
|
130
|
+
http_bearer_token=session.http_bearer_token
|
|
129
131
|
)
|
|
130
132
|
|
|
131
133
|
return session
|
|
@@ -148,6 +150,9 @@ async def lifespan(_app: FastAPI):
|
|
|
148
150
|
if ARGS.passwords_file_path:
|
|
149
151
|
env_vars.update(dotenv_values(ARGS.passwords_file_path))
|
|
150
152
|
fastworkflow.init(env_vars=env_vars)
|
|
153
|
+
|
|
154
|
+
# Configure JWT verification mode based on CLI parameter
|
|
155
|
+
set_jwt_verification_mode(ARGS.expect_encrypted_jwt)
|
|
151
156
|
|
|
152
157
|
async def _active_turn_user_ids() -> list[str]:
|
|
153
158
|
active: list[str] = []
|
|
@@ -219,6 +224,8 @@ def load_args():
|
|
|
219
224
|
parser.add_argument("--project_folderpath", required=False)
|
|
220
225
|
parser.add_argument("--port", type=int, default=8000, help="Port to run the server on (default: 8000)")
|
|
221
226
|
parser.add_argument("--host", default="0.0.0.0", help="Host to bind the server to (default: 0.0.0.0)")
|
|
227
|
+
parser.add_argument("--expect_encrypted_jwt", action="store_true", default=False,
|
|
228
|
+
help="Enable JWT signature verification (default: unsigned tokens accepted for trusted networks)")
|
|
222
229
|
return parser.parse_args()
|
|
223
230
|
|
|
224
231
|
ARGS = load_args()
|
|
@@ -251,13 +258,11 @@ def custom_openapi():
|
|
|
251
258
|
|
|
252
259
|
# Enhance the auto-generated Bearer token security scheme with better documentation
|
|
253
260
|
# The HTTPBearer dependency in utils.py creates the base scheme, we just improve it
|
|
254
|
-
if "components" in openapi_schema and "securitySchemes" in openapi_schema["components"]:
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
"Enter ONLY the token (Swagger UI automatically adds 'Bearer ' prefix)"
|
|
260
|
-
)
|
|
261
|
+
if "components" in openapi_schema and "securitySchemes" in openapi_schema["components"] and "BearerAuth" in openapi_schema["components"]["securitySchemes"]:
|
|
262
|
+
openapi_schema["components"]["securitySchemes"]["BearerAuth"]["description"] = (
|
|
263
|
+
"JWT access token from /initialize or /refresh_token endpoint. "
|
|
264
|
+
"Enter ONLY the token (Swagger UI automatically adds 'Bearer ' prefix)"
|
|
265
|
+
)
|
|
261
266
|
|
|
262
267
|
# Apply security globally to all endpoints except public ones
|
|
263
268
|
for path, path_item in openapi_schema["paths"].items():
|
|
@@ -265,10 +270,8 @@ def custom_openapi():
|
|
|
265
270
|
if path in ["/initialize", "/refresh_token", "/", "/admin/dump_all_conversations", "/admin/generate_mcp_token"]:
|
|
266
271
|
continue
|
|
267
272
|
for method in path_item:
|
|
268
|
-
if method in ["get", "post", "put", "delete", "patch"]:
|
|
269
|
-
|
|
270
|
-
if "security" not in path_item[method]:
|
|
271
|
-
path_item[method]["security"] = [{"BearerAuth": []}]
|
|
273
|
+
if method in ["get", "post", "put", "delete", "patch"] and "security" not in path_item[method]:
|
|
274
|
+
path_item[method]["security"] = [{"BearerAuth": []}]
|
|
272
275
|
|
|
273
276
|
app.openapi_schema = openapi_schema
|
|
274
277
|
return app.openapi_schema
|
|
@@ -34,6 +34,9 @@ PUBLIC_KEY_PATH = os.path.join(KEYS_DIR, "public_key.pem")
|
|
|
34
34
|
_private_key: Optional[str] = None
|
|
35
35
|
_public_key: Optional[str] = None
|
|
36
36
|
|
|
37
|
+
# Flag to control JWT verification behavior (set from CLI)
|
|
38
|
+
EXPECT_ENCRYPTED_JWT = True # Default to secure mode
|
|
39
|
+
|
|
37
40
|
|
|
38
41
|
def ensure_keys_directory() -> None:
|
|
39
42
|
"""Create jwt_keys directory if it doesn't exist."""
|
|
@@ -129,19 +132,42 @@ def load_or_generate_keys() -> tuple[str, str]:
|
|
|
129
132
|
return _private_key, _public_key
|
|
130
133
|
|
|
131
134
|
|
|
135
|
+
def set_jwt_verification_mode(expect_encrypted: bool) -> None:
|
|
136
|
+
"""
|
|
137
|
+
Configure JWT verification mode for trusted network scenarios.
|
|
138
|
+
|
|
139
|
+
When expect_encrypted=False, JWT tokens are decoded without signature verification.
|
|
140
|
+
This mode is ONLY suitable for trusted internal networks where JWT is used for
|
|
141
|
+
data transport rather than security.
|
|
142
|
+
|
|
143
|
+
WARNING: Disabling signature verification allows any client to forge tokens.
|
|
144
|
+
Only use in controlled environments.
|
|
145
|
+
"""
|
|
146
|
+
global EXPECT_ENCRYPTED_JWT
|
|
147
|
+
EXPECT_ENCRYPTED_JWT = expect_encrypted
|
|
148
|
+
if not expect_encrypted:
|
|
149
|
+
logger.warning(
|
|
150
|
+
"JWT signature verification DISABLED. "
|
|
151
|
+
"Tokens will be accepted without cryptographic validation. "
|
|
152
|
+
"Only use in trusted internal networks."
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
|
|
132
156
|
def create_access_token(user_id: str, expires_days: int | None = None) -> str:
|
|
133
157
|
"""
|
|
134
158
|
Create a JWT access token for a user.
|
|
135
159
|
|
|
160
|
+
Behavior depends on EXPECT_ENCRYPTED_JWT flag:
|
|
161
|
+
- If True: Creates a signed token using RSA algorithm
|
|
162
|
+
- If False: Creates an unsigned token for trusted network use
|
|
163
|
+
|
|
136
164
|
Args:
|
|
137
165
|
user_id: User identifier
|
|
138
166
|
expires_days: Optional custom expiration in days. If None, uses JWT_ACCESS_TOKEN_EXPIRE_MINUTES (default 60 minutes).
|
|
139
167
|
|
|
140
168
|
Returns:
|
|
141
|
-
str: Encoded JWT access token
|
|
169
|
+
str: Encoded JWT access token (signed or unsigned based on EXPECT_ENCRYPTED_JWT)
|
|
142
170
|
"""
|
|
143
|
-
private_key, _ = load_or_generate_keys()
|
|
144
|
-
|
|
145
171
|
now = datetime.now(timezone.utc)
|
|
146
172
|
if expires_days is not None:
|
|
147
173
|
expire = now + timedelta(days=expires_days)
|
|
@@ -159,8 +185,17 @@ def create_access_token(user_id: str, expires_days: int | None = None) -> str:
|
|
|
159
185
|
"aud": JWT_AUDIENCE # Audience
|
|
160
186
|
}
|
|
161
187
|
|
|
162
|
-
|
|
163
|
-
|
|
188
|
+
if EXPECT_ENCRYPTED_JWT:
|
|
189
|
+
# Secure mode: create signed token
|
|
190
|
+
private_key, _ = load_or_generate_keys()
|
|
191
|
+
token = jwt.encode(payload, private_key, algorithm=JWT_ALGORITHM)
|
|
192
|
+
logger.debug(f"Created signed access token for user_id: {user_id}, expires: {expire.isoformat()}")
|
|
193
|
+
else:
|
|
194
|
+
# Trusted network mode: create unsigned token using HS256 with empty key
|
|
195
|
+
# This creates a JWT that can be decoded without verification
|
|
196
|
+
token = jwt.encode(payload, "", algorithm="HS256")
|
|
197
|
+
logger.debug(f"Created unsigned access token for user_id: {user_id}, expires: {expire.isoformat()}")
|
|
198
|
+
|
|
164
199
|
return token
|
|
165
200
|
|
|
166
201
|
|
|
@@ -168,14 +203,16 @@ def create_refresh_token(user_id: str) -> str:
|
|
|
168
203
|
"""
|
|
169
204
|
Create a JWT refresh token for a user.
|
|
170
205
|
|
|
206
|
+
Behavior depends on EXPECT_ENCRYPTED_JWT flag:
|
|
207
|
+
- If True: Creates a signed token using RSA algorithm
|
|
208
|
+
- If False: Creates an unsigned token for trusted network use
|
|
209
|
+
|
|
171
210
|
Args:
|
|
172
211
|
user_id: User identifier
|
|
173
212
|
|
|
174
213
|
Returns:
|
|
175
|
-
str: Encoded JWT refresh token
|
|
214
|
+
str: Encoded JWT refresh token (signed or unsigned based on EXPECT_ENCRYPTED_JWT)
|
|
176
215
|
"""
|
|
177
|
-
private_key, _ = load_or_generate_keys()
|
|
178
|
-
|
|
179
216
|
now = datetime.now(timezone.utc)
|
|
180
217
|
expire = now + timedelta(days=JWT_REFRESH_TOKEN_EXPIRE_DAYS)
|
|
181
218
|
|
|
@@ -190,15 +227,29 @@ def create_refresh_token(user_id: str) -> str:
|
|
|
190
227
|
"aud": JWT_AUDIENCE # Audience
|
|
191
228
|
}
|
|
192
229
|
|
|
193
|
-
|
|
194
|
-
|
|
230
|
+
if EXPECT_ENCRYPTED_JWT:
|
|
231
|
+
# Secure mode: create signed token
|
|
232
|
+
private_key, _ = load_or_generate_keys()
|
|
233
|
+
token = jwt.encode(payload, private_key, algorithm=JWT_ALGORITHM)
|
|
234
|
+
logger.debug(f"Created signed refresh token for user_id: {user_id}, expires: {expire.isoformat()}")
|
|
235
|
+
else:
|
|
236
|
+
# Trusted network mode: create unsigned token using HS256 with empty key
|
|
237
|
+
# This creates a JWT that can be decoded without verification
|
|
238
|
+
token = jwt.encode(payload, "", algorithm="HS256")
|
|
239
|
+
logger.debug(f"Created unsigned refresh token for user_id: {user_id}, expires: {expire.isoformat()}")
|
|
240
|
+
|
|
195
241
|
return token
|
|
196
242
|
|
|
197
243
|
|
|
198
244
|
def verify_token(token: str, expected_type: str = "access") -> dict:
|
|
245
|
+
# sourcery skip: extract-duplicate-method
|
|
199
246
|
"""
|
|
200
247
|
Verify and decode a JWT token.
|
|
201
248
|
|
|
249
|
+
Behavior depends on EXPECT_ENCRYPTED_JWT flag:
|
|
250
|
+
- If True (default): Full cryptographic verification with signature check
|
|
251
|
+
- If False: Extract payload without verification (trusted network mode)
|
|
252
|
+
|
|
202
253
|
Args:
|
|
203
254
|
token: JWT token string
|
|
204
255
|
expected_type: Expected token type ("access" or "refresh")
|
|
@@ -209,8 +260,33 @@ def verify_token(token: str, expected_type: str = "access") -> dict:
|
|
|
209
260
|
Raises:
|
|
210
261
|
JWTError: If token is invalid, expired, or type mismatch
|
|
211
262
|
"""
|
|
263
|
+
if not EXPECT_ENCRYPTED_JWT:
|
|
264
|
+
# Trusted network mode: decode without verification (accepts both unsigned and signed tokens)
|
|
265
|
+
try:
|
|
266
|
+
# Use unverified decoding - works for any JWT regardless of algorithm or signing
|
|
267
|
+
payload = jwt.get_unverified_claims(token)
|
|
268
|
+
except Exception as e:
|
|
269
|
+
logger.warning(f"Token decoding failed: {e}")
|
|
270
|
+
raise JWTError(f"Failed to decode token: {e}") from e
|
|
271
|
+
|
|
272
|
+
# Manually check expiration even in unverified mode
|
|
273
|
+
if exp_timestamp := payload.get("exp"):
|
|
274
|
+
import time
|
|
275
|
+
current_time = int(time.time())
|
|
276
|
+
if exp_timestamp < current_time:
|
|
277
|
+
logger.warning(f"Token expired: exp={exp_timestamp}, now={current_time}")
|
|
278
|
+
raise JWTError("Token has expired")
|
|
279
|
+
|
|
280
|
+
# Validate token type for consistency (outside try-except to allow JWTError to propagate)
|
|
281
|
+
if payload.get("type") != expected_type:
|
|
282
|
+
raise JWTError(f"Invalid token type: expected {expected_type}, got {payload.get('type')}")
|
|
283
|
+
|
|
284
|
+
logger.debug(f"Token decoded (unverified mode): user_id={payload.get('sub')}, type={expected_type}")
|
|
285
|
+
return payload
|
|
286
|
+
|
|
287
|
+
# Standard mode: full verification (existing code)
|
|
212
288
|
_, public_key = load_or_generate_keys()
|
|
213
|
-
|
|
289
|
+
|
|
214
290
|
try:
|
|
215
291
|
# Decode and verify token
|
|
216
292
|
payload = jwt.decode(
|
|
@@ -220,14 +296,14 @@ def verify_token(token: str, expected_type: str = "access") -> dict:
|
|
|
220
296
|
issuer=JWT_ISSUER,
|
|
221
297
|
audience=JWT_AUDIENCE
|
|
222
298
|
)
|
|
223
|
-
|
|
299
|
+
|
|
224
300
|
# Verify token type
|
|
225
301
|
if payload.get("type") != expected_type:
|
|
226
302
|
raise JWTError(f"Invalid token type: expected {expected_type}, got {payload.get('type')}")
|
|
227
|
-
|
|
303
|
+
|
|
228
304
|
logger.debug(f"Token verified successfully: user_id={payload.get('sub')}, type={expected_type}")
|
|
229
305
|
return payload
|
|
230
|
-
|
|
306
|
+
|
|
231
307
|
except JWTError as e:
|
|
232
308
|
logger.warning(f"Token verification failed: {e}")
|
|
233
309
|
raise
|
|
@@ -247,8 +323,7 @@ def get_token_expiry(token: str) -> Optional[datetime]:
|
|
|
247
323
|
try:
|
|
248
324
|
# Decode without verification (just to inspect claims)
|
|
249
325
|
payload = jwt.get_unverified_claims(token)
|
|
250
|
-
exp_timestamp
|
|
251
|
-
if exp_timestamp:
|
|
326
|
+
if exp_timestamp := payload.get("exp"):
|
|
252
327
|
return datetime.fromtimestamp(exp_timestamp, tz=timezone.utc)
|
|
253
328
|
except Exception as e:
|
|
254
329
|
logger.debug(f"Failed to get token expiry: {e}")
|
|
@@ -42,6 +42,7 @@ class SessionData(BaseModel):
|
|
|
42
42
|
issued_at: int # Unix timestamp
|
|
43
43
|
expires_at: int # Unix timestamp
|
|
44
44
|
jti: str # JWT ID (unique token identifier)
|
|
45
|
+
http_bearer_token: Optional[str] = None # The actual JWT token string for workflow context access
|
|
45
46
|
|
|
46
47
|
|
|
47
48
|
class InvokeRequest(BaseModel):
|
|
@@ -169,32 +170,33 @@ def get_session_from_jwt(
|
|
|
169
170
|
"""
|
|
170
171
|
# Extract token from credentials (already validated by HTTPBearer)
|
|
171
172
|
token = credentials.credentials
|
|
172
|
-
|
|
173
|
+
|
|
173
174
|
# Verify and decode token
|
|
174
175
|
try:
|
|
175
176
|
payload = verify_token(token, expected_type="access")
|
|
176
|
-
|
|
177
|
-
# Extract session data from payload
|
|
177
|
+
|
|
178
|
+
# Extract session data from payload, including the token for workflow context
|
|
178
179
|
return SessionData(
|
|
179
180
|
user_id=payload["sub"],
|
|
180
181
|
token_type=payload["type"],
|
|
181
182
|
issued_at=payload["iat"],
|
|
182
183
|
expires_at=payload["exp"],
|
|
183
|
-
jti=payload["jti"]
|
|
184
|
+
jti=payload["jti"],
|
|
185
|
+
http_bearer_token=token # Store the actual token for workflow access
|
|
184
186
|
)
|
|
185
|
-
|
|
187
|
+
|
|
186
188
|
except JWTError as e:
|
|
187
189
|
raise HTTPException(
|
|
188
190
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
189
191
|
detail=f"Invalid or expired token: {str(e)}",
|
|
190
|
-
headers={"WWW-Authenticate": "Bearer"}
|
|
191
|
-
)
|
|
192
|
+
headers={"WWW-Authenticate": "Bearer"},
|
|
193
|
+
) from e
|
|
192
194
|
except KeyError as e:
|
|
193
195
|
raise HTTPException(
|
|
194
196
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
195
197
|
detail=f"Token missing required claim: {str(e)}",
|
|
196
|
-
headers={"WWW-Authenticate": "Bearer"}
|
|
197
|
-
)
|
|
198
|
+
headers={"WWW-Authenticate": "Bearer"},
|
|
199
|
+
) from e
|
|
198
200
|
|
|
199
201
|
|
|
200
202
|
async def ensure_user_runtime_exists(
|
|
@@ -204,7 +206,8 @@ async def ensure_user_runtime_exists(
|
|
|
204
206
|
context: Optional[dict] = None,
|
|
205
207
|
startup_command: Optional[str] = None,
|
|
206
208
|
startup_action: Optional['fastworkflow.Action'] = None,
|
|
207
|
-
stream_format: str = "ndjson"
|
|
209
|
+
stream_format: str = "ndjson",
|
|
210
|
+
http_bearer_token: Optional[str] = None
|
|
208
211
|
) -> None:
|
|
209
212
|
"""
|
|
210
213
|
Ensure a user runtime exists in the session manager. If not, create it.
|
|
@@ -220,6 +223,7 @@ async def ensure_user_runtime_exists(
|
|
|
220
223
|
startup_command: Optional startup command
|
|
221
224
|
startup_action: Optional startup action
|
|
222
225
|
stream_format: Stream format preference ("ndjson" or "sse", default "ndjson")
|
|
226
|
+
http_bearer_token: Optional JWT token to update in workflow context
|
|
223
227
|
|
|
224
228
|
Raises:
|
|
225
229
|
HTTPException: If session creation fails
|
|
@@ -228,8 +232,30 @@ async def ensure_user_runtime_exists(
|
|
|
228
232
|
existing_runtime = await session_manager.get_session(user_id)
|
|
229
233
|
if existing_runtime:
|
|
230
234
|
logger.debug(f"Session for user_id {user_id} already exists, skipping creation")
|
|
235
|
+
|
|
236
|
+
# Update the workflow's context with the current token if provided
|
|
237
|
+
if http_bearer_token and existing_runtime.chat_session:
|
|
238
|
+
active_workflow = existing_runtime.chat_session.get_active_workflow()
|
|
239
|
+
if active_workflow and active_workflow.context:
|
|
240
|
+
# Update the workflow's context with the current token
|
|
241
|
+
# Note: We mutate the dictionary in-place (no setter call), which means:
|
|
242
|
+
# 1. The change is immediate and visible to workflow code
|
|
243
|
+
# 2. The workflow is NOT marked dirty (won't persist to disk)
|
|
244
|
+
# 3. This is intentional for JWT tokens - we don't want to persist sensitive tokens
|
|
245
|
+
active_workflow.context['http_bearer_token'] = http_bearer_token
|
|
246
|
+
logger.debug(f"Updated http_bearer_token in workflow context for user_id {user_id}")
|
|
247
|
+
|
|
231
248
|
return
|
|
232
249
|
|
|
250
|
+
# Prepare workflow context, ensuring http_bearer_token is available
|
|
251
|
+
if http_bearer_token:
|
|
252
|
+
if context:
|
|
253
|
+
# Add or replace http_bearer_token in the context
|
|
254
|
+
context['http_bearer_token'] = http_bearer_token
|
|
255
|
+
else:
|
|
256
|
+
# Initialize context with http_bearer_token
|
|
257
|
+
context = {'http_bearer_token': http_bearer_token}
|
|
258
|
+
|
|
233
259
|
logger.info(f"Creating new session for user_id: {user_id}")
|
|
234
260
|
|
|
235
261
|
# Resolve conversation store base folder from SPEEDDICT_FOLDERNAME/user_conversations
|
|
@@ -9,7 +9,7 @@ repository = "https://github.com/radiantlogicinc/fastworkflow"
|
|
|
9
9
|
|
|
10
10
|
[tool.poetry]
|
|
11
11
|
name = "fastworkflow"
|
|
12
|
-
version = "2.17.
|
|
12
|
+
version = "2.17.8"
|
|
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"
|
|
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-2.17.6 → fastworkflow-2.17.8}/fastworkflow/build/command_dependency_resolver.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
|
{fastworkflow-2.17.6 → fastworkflow-2.17.8}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/fastworkflow.passwords.env
RENAMED
|
File without changes
|
{fastworkflow-2.17.6 → fastworkflow-2.17.8}/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
|
|
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
|
|
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-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/calculate.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
|
{fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/think.py
RENAMED
|
File without changes
|
{fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/examples/retail_workflow/tools/tool.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
|
|
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-2.17.6 → fastworkflow-2.17.8}/fastworkflow/run_fastapi_mcp/conversation_store.py
RENAMED
|
File without changes
|
|
File without changes
|
{fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/run_fastapi_mcp/redoc_2_standalone_html.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
|
{fastworkflow-2.17.6 → fastworkflow-2.17.8}/fastworkflow/utils/parameterize_func_decorator.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
|