rasa-pro 3.14.0a20__py3-none-any.whl → 3.14.0a23__py3-none-any.whl
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 rasa-pro might be problematic. Click here for more details.
- rasa/__main__.py +15 -3
- rasa/agents/__init__.py +0 -0
- rasa/agents/agent_factory.py +122 -0
- rasa/agents/agent_manager.py +211 -0
- rasa/agents/constants.py +43 -0
- rasa/agents/core/__init__.py +0 -0
- rasa/agents/core/agent_protocol.py +107 -0
- rasa/agents/core/types.py +81 -0
- rasa/agents/exceptions.py +38 -0
- rasa/agents/protocol/__init__.py +5 -0
- rasa/agents/protocol/a2a/__init__.py +0 -0
- rasa/agents/protocol/a2a/a2a_agent.py +879 -0
- rasa/agents/protocol/mcp/__init__.py +0 -0
- rasa/agents/protocol/mcp/mcp_base_agent.py +726 -0
- rasa/agents/protocol/mcp/mcp_open_agent.py +327 -0
- rasa/agents/protocol/mcp/mcp_task_agent.py +522 -0
- rasa/agents/schemas/__init__.py +13 -0
- rasa/agents/schemas/agent_input.py +38 -0
- rasa/agents/schemas/agent_output.py +26 -0
- rasa/agents/schemas/agent_tool_result.py +65 -0
- rasa/agents/schemas/agent_tool_schema.py +186 -0
- rasa/agents/templates/__init__.py +0 -0
- rasa/agents/templates/mcp_open_agent_prompt_template.jinja2 +20 -0
- rasa/agents/templates/mcp_task_agent_prompt_template.jinja2 +22 -0
- rasa/agents/utils.py +206 -0
- rasa/agents/validation.py +485 -0
- rasa/api.py +24 -9
- rasa/builder/config.py +6 -2
- rasa/builder/guardrails/{lakera.py → clients.py} +55 -5
- rasa/builder/guardrails/constants.py +3 -0
- rasa/builder/guardrails/models.py +45 -10
- rasa/builder/guardrails/policy_checker.py +324 -0
- rasa/builder/guardrails/utils.py +42 -276
- rasa/builder/llm_service.py +32 -5
- rasa/builder/models.py +1 -0
- rasa/builder/project_generator.py +6 -1
- rasa/builder/service.py +16 -13
- rasa/builder/training_service.py +18 -24
- rasa/builder/validation_service.py +1 -1
- rasa/cli/arguments/default_arguments.py +12 -0
- rasa/cli/arguments/run.py +2 -0
- rasa/cli/arguments/train.py +2 -0
- rasa/cli/data.py +10 -8
- rasa/cli/dialogue_understanding_test.py +10 -7
- rasa/cli/e2e_test.py +9 -6
- rasa/cli/evaluate.py +4 -2
- rasa/cli/export.py +5 -2
- rasa/cli/inspect.py +8 -4
- rasa/cli/interactive.py +5 -4
- rasa/cli/llm_fine_tuning.py +11 -6
- rasa/cli/project_templates/finance/actions/general/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/general/action_human_handoff.py +49 -0
- rasa/cli/project_templates/finance/data/general/bot_challenge.yml +6 -0
- rasa/cli/project_templates/finance/data/general/goodbye.yml +1 -1
- rasa/cli/project_templates/finance/data/general/human_handoff.yml +1 -1
- rasa/cli/project_templates/finance/data/system/patterns/pattern_session_start.yml +1 -1
- rasa/cli/project_templates/finance/domain/general/_shared.yml +0 -14
- rasa/cli/project_templates/finance/domain/general/bot_challenge.yml +4 -0
- rasa/cli/project_templates/finance/domain/general/goodbye.yml +7 -0
- rasa/cli/project_templates/finance/domain/general/human_handoff.yml +3 -6
- rasa/cli/project_templates/finance/domain/general/welcome.yml +29 -1
- rasa/cli/project_templates/finance/tests/e2e_test_cases/accounts/check_balance.yml +9 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/accounts/download_statements.yml +43 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/cards/block_card.yml +55 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/bot_challenge.yml +8 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/feedback.yml +46 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/goodbye.yml +9 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/hello.yml +8 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/human_handoff.yml +35 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/patterns.yml +22 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/transfers/transfer_money.yml +56 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/general/feedback.yml +1 -1
- rasa/cli/project_templates/telco/tests/e2e_test_cases/general/hello.yml +1 -1
- rasa/cli/project_templates/telco/tests/e2e_test_cases/general/human_handoff.yml +1 -1
- rasa/cli/project_templates/telco/tests/e2e_test_cases/general/patterns.yml +1 -1
- rasa/cli/project_templates/tutorial/credentials.yml +10 -0
- rasa/cli/run.py +12 -10
- rasa/cli/scaffold.py +4 -4
- rasa/cli/shell.py +9 -5
- rasa/cli/studio/studio.py +1 -1
- rasa/cli/test.py +34 -14
- rasa/cli/train.py +41 -28
- rasa/cli/utils.py +1 -393
- rasa/cli/validation/__init__.py +0 -0
- rasa/cli/validation/bot_config.py +223 -0
- rasa/cli/validation/config_path_validation.py +257 -0
- rasa/cli/x.py +8 -4
- rasa/constants.py +7 -1
- rasa/core/actions/action.py +51 -10
- rasa/core/actions/action_run_slot_rejections.py +1 -1
- rasa/core/actions/direct_custom_actions_executor.py +9 -2
- rasa/core/actions/grpc_custom_action_executor.py +1 -1
- rasa/core/agent.py +19 -2
- rasa/core/available_agents.py +229 -0
- rasa/core/brokers/kafka.py +1 -1
- rasa/core/channels/__init__.py +82 -35
- rasa/core/channels/development_inspector.py +3 -3
- rasa/core/channels/inspector/README.md +25 -13
- rasa/core/channels/inspector/dist/assets/{arc-35222594.js → arc-6177260a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-a0efbfd3.js → blockDiagram-38ab4fdb-b054f038.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-0584c0f2.js → c4Diagram-3d4e48cf-f25427d5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-bf9cbb34.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-39f40dbe.js → classDiagram-70f12bd4-c7a2af53.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-1ad755f3.js → classDiagram-v2-f2320105-58db65c0.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-8f9083bb.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-b0f4f0fe.js → createText-2e5e7dd3-088372e2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-9039bff9.js → edges-e0da2a9e-58676240.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-65c9b127.js → erDiagram-9861fffd-0c14d7c6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-4f08b38e.js → flowDb-956e92f1-ea63f85c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-e95c362a.js → flowDiagram-66a62f08-a2af48cd.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-9ecd5b59.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-703c3015.js → flowchart-elk-definition-4a651766-6937abe7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-699328ea.js → ganttDiagram-c361ad54-7473f357.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-04cf4b05.js → gitGraphDiagram-72cf32ee-d0c9405e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-ee94449e.js → graph-0a6f8466.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-940162b4.js → index-3862675e-7610671a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/index-74e01d94.js +1354 -0
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-c79c2866.js → infoDiagram-f8f76790-be397dc7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-84489d30.js → journeyDiagram-49397b02-4cefbf62.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-a9aa9858.js → layout-e7fbc2bf.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-eb73cf26.js → line-a8aa457c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-b3399f9a.js → linear-3351e0d2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-b095bf1a.js → mindmap-definition-fc14e90a-b8cbf605.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-07644b66.js → pieDiagram-8a3498a8-f327f774.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-573a3f9c.js → quadrantDiagram-120e2f19-2854c591.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-d457e1e1.js → requirementDiagram-deff3bca-964985d5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-9d26e1a2.js → sankeyDiagram-04a897e0-edeb4f33.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-3a9cde10.js → sequenceDiagram-704730f1-fcf70125.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-4f3e8cec.js → stateDiagram-587899a1-0e770395.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-e617e5bf.js → stateDiagram-v2-d93cdb3a-af8dcd22.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-eab30d2f.js → styles-6aaf32cf-36a9e70d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-09994be2.js → styles-9a916d00-884a8b5b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-b7110364.js → styles-c10674c1-dc097813.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-3ebc92ad.js → svgDrawCommon-08f97a94-5a2c7eed.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-7d13d2f2.js → timeline-definition-85554ec2-e89c4f6e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-488385e1.js → xychartDiagram-e933f94c-afb6fe56.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/package.json +18 -18
- rasa/core/channels/inspector/src/App.tsx +29 -4
- rasa/core/channels/inspector/src/components/DialogueAgentStack.tsx +108 -0
- rasa/core/channels/inspector/src/components/{DialogueStack.tsx → DialogueHistoryStack.tsx} +4 -2
- rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +7 -4
- rasa/core/channels/inspector/src/helpers/formatters.test.ts +4 -0
- rasa/core/channels/inspector/src/helpers/formatters.ts +24 -3
- rasa/core/channels/inspector/src/helpers/utils.test.ts +127 -0
- rasa/core/channels/inspector/src/helpers/utils.ts +66 -1
- rasa/core/channels/inspector/src/theme/base/styles.ts +19 -1
- rasa/core/channels/inspector/src/types.ts +21 -0
- rasa/core/channels/inspector/yarn.lock +336 -189
- rasa/core/channels/studio_chat.py +6 -6
- rasa/core/channels/telegram.py +4 -9
- rasa/core/channels/voice_stream/browser_audio.py +2 -0
- rasa/core/channels/voice_stream/genesys.py +1 -1
- rasa/core/channels/voice_stream/tts/deepgram.py +140 -0
- rasa/core/channels/voice_stream/twilio_media_streams.py +5 -1
- rasa/core/channels/voice_stream/voice_channel.py +3 -0
- rasa/core/config/__init__.py +0 -0
- rasa/core/{available_endpoints.py → config/available_endpoints.py} +51 -16
- rasa/core/config/configuration.py +260 -0
- rasa/core/config/credentials.py +19 -0
- rasa/core/config/message_procesing_config.py +34 -0
- rasa/core/constants.py +5 -0
- rasa/core/iam_credentials_providers/aws_iam_credentials_providers.py +88 -3
- rasa/core/iam_credentials_providers/credentials_provider_protocol.py +2 -1
- rasa/core/lock_store.py +6 -4
- rasa/core/nlg/generator.py +1 -1
- rasa/core/policies/enterprise_search_policy.py +5 -3
- rasa/core/policies/flow_policy.py +4 -4
- rasa/core/policies/flows/agent_executor.py +632 -0
- rasa/core/policies/flows/flow_executor.py +137 -76
- rasa/core/policies/flows/mcp_tool_executor.py +298 -0
- rasa/core/policies/intentless_policy.py +1 -1
- rasa/core/policies/ted_policy.py +20 -12
- rasa/core/policies/unexpected_intent_policy.py +6 -0
- rasa/core/processor.py +68 -44
- rasa/core/redis_connection_factory.py +78 -20
- rasa/core/run.py +37 -8
- rasa/core/test.py +4 -0
- rasa/core/tracker_stores/sql_tracker_store.py +1 -1
- rasa/core/tracker_stores/tracker_store.py +3 -7
- rasa/core/train.py +1 -1
- rasa/core/training/interactive.py +20 -18
- rasa/core/training/story_conflict.py +5 -5
- rasa/core/utils.py +22 -23
- rasa/dialogue_understanding/commands/__init__.py +8 -0
- rasa/dialogue_understanding/commands/cancel_flow_command.py +19 -5
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +21 -2
- rasa/dialogue_understanding/commands/clarify_command.py +20 -2
- rasa/dialogue_understanding/commands/continue_agent_command.py +91 -0
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +21 -2
- rasa/dialogue_understanding/commands/restart_agent_command.py +162 -0
- rasa/dialogue_understanding/commands/start_flow_command.py +68 -7
- rasa/dialogue_understanding/commands/utils.py +124 -2
- rasa/dialogue_understanding/generator/command_parser.py +4 -0
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +50 -12
- rasa/dialogue_understanding/generator/llm_command_generator.py +1 -1
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +1 -1
- rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +66 -0
- rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +66 -0
- rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +89 -0
- rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +88 -0
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +42 -7
- rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +40 -3
- rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +20 -3
- rasa/dialogue_understanding/patterns/cancel.py +27 -6
- rasa/dialogue_understanding/patterns/clarify.py +3 -14
- rasa/dialogue_understanding/patterns/continue_interrupted.py +239 -6
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +46 -8
- rasa/dialogue_understanding/processor/command_processor.py +136 -15
- rasa/dialogue_understanding/stack/dialogue_stack.py +98 -2
- rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +57 -0
- rasa/dialogue_understanding/stack/utils.py +57 -3
- rasa/dialogue_understanding/utils.py +24 -4
- rasa/dialogue_understanding_test/du_test_runner.py +8 -3
- rasa/e2e_test/e2e_test_runner.py +13 -3
- rasa/engine/caching.py +2 -2
- rasa/engine/constants.py +1 -1
- rasa/engine/loader.py +12 -0
- rasa/engine/recipes/default_components.py +138 -49
- rasa/engine/recipes/default_recipe.py +108 -11
- rasa/engine/runner/dask.py +8 -5
- rasa/engine/validation.py +19 -6
- rasa/graph_components/validators/default_recipe_validator.py +86 -28
- rasa/hooks.py +5 -5
- rasa/llm_fine_tuning/utils.py +2 -2
- rasa/model_training.py +60 -47
- rasa/nlu/classifiers/diet_classifier.py +198 -98
- rasa/nlu/classifiers/logistic_regression_classifier.py +1 -4
- rasa/nlu/classifiers/mitie_intent_classifier.py +3 -0
- rasa/nlu/classifiers/sklearn_intent_classifier.py +1 -3
- rasa/nlu/extractors/crf_entity_extractor.py +9 -10
- rasa/nlu/extractors/mitie_entity_extractor.py +3 -0
- rasa/nlu/extractors/spacy_entity_extractor.py +3 -0
- rasa/nlu/featurizers/dense_featurizer/convert_featurizer.py +4 -0
- rasa/nlu/featurizers/dense_featurizer/lm_featurizer.py +5 -0
- rasa/nlu/featurizers/dense_featurizer/mitie_featurizer.py +2 -0
- rasa/nlu/featurizers/dense_featurizer/spacy_featurizer.py +3 -0
- rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +4 -2
- rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +4 -0
- rasa/nlu/selectors/response_selector.py +10 -2
- rasa/nlu/tokenizers/jieba_tokenizer.py +3 -4
- rasa/nlu/tokenizers/mitie_tokenizer.py +3 -2
- rasa/nlu/tokenizers/spacy_tokenizer.py +3 -2
- rasa/nlu/utils/mitie_utils.py +3 -0
- rasa/nlu/utils/spacy_utils.py +3 -2
- rasa/plugin.py +8 -8
- rasa/privacy/privacy_manager.py +12 -3
- rasa/server.py +15 -3
- rasa/shared/agents/__init__.py +0 -0
- rasa/shared/agents/auth/__init__.py +0 -0
- rasa/shared/agents/auth/agent_auth_factory.py +105 -0
- rasa/shared/agents/auth/agent_auth_manager.py +92 -0
- rasa/shared/agents/auth/auth_strategy/__init__.py +19 -0
- rasa/shared/agents/auth/auth_strategy/agent_auth_strategy.py +52 -0
- rasa/shared/agents/auth/auth_strategy/api_key_auth_strategy.py +42 -0
- rasa/shared/agents/auth/auth_strategy/bearer_token_auth_strategy.py +28 -0
- rasa/shared/agents/auth/auth_strategy/oauth2_auth_strategy.py +167 -0
- rasa/shared/agents/auth/constants.py +12 -0
- rasa/shared/agents/auth/types.py +12 -0
- rasa/shared/agents/utils.py +35 -0
- rasa/shared/constants.py +8 -0
- rasa/shared/core/constants.py +16 -1
- rasa/shared/core/domain.py +0 -7
- rasa/shared/core/events.py +327 -0
- rasa/shared/core/flows/constants.py +5 -0
- rasa/shared/core/flows/flow.py +1 -1
- rasa/shared/core/flows/flows_list.py +21 -5
- rasa/shared/core/flows/flows_yaml_schema.json +119 -184
- rasa/shared/core/flows/steps/call.py +49 -5
- rasa/shared/core/flows/steps/collect.py +98 -13
- rasa/shared/core/flows/validation.py +372 -8
- rasa/shared/core/flows/yaml_flows_io.py +3 -2
- rasa/shared/core/slots.py +2 -2
- rasa/shared/core/trackers.py +5 -2
- rasa/shared/exceptions.py +16 -0
- rasa/shared/importers/rasa.py +1 -1
- rasa/shared/importers/utils.py +9 -3
- rasa/shared/providers/llm/_base_litellm_client.py +41 -9
- rasa/shared/providers/llm/litellm_router_llm_client.py +8 -4
- rasa/shared/providers/llm/llm_client.py +7 -3
- rasa/shared/providers/llm/llm_response.py +66 -0
- rasa/shared/providers/llm/self_hosted_llm_client.py +8 -4
- rasa/shared/utils/common.py +24 -0
- rasa/shared/utils/health_check/health_check.py +7 -3
- rasa/shared/utils/llm.py +39 -16
- rasa/shared/utils/mcp/__init__.py +0 -0
- rasa/shared/utils/mcp/server_connection.py +247 -0
- rasa/shared/utils/mcp/utils.py +20 -0
- rasa/shared/utils/schemas/events.py +42 -0
- rasa/shared/utils/yaml.py +3 -1
- rasa/studio/pull/pull.py +3 -2
- rasa/studio/train.py +8 -7
- rasa/studio/upload.py +3 -6
- rasa/telemetry.py +69 -5
- rasa/tracing/config.py +45 -12
- rasa/tracing/constants.py +14 -0
- rasa/tracing/instrumentation/attribute_extractors.py +142 -9
- rasa/tracing/instrumentation/instrumentation.py +626 -21
- rasa/tracing/instrumentation/intentless_policy_instrumentation.py +4 -4
- rasa/tracing/instrumentation/metrics.py +32 -0
- rasa/tracing/metric_instrument_provider.py +68 -0
- rasa/utils/common.py +92 -1
- rasa/utils/endpoints.py +11 -2
- rasa/utils/log_utils.py +96 -5
- rasa/utils/ml_utils.py +1 -1
- rasa/utils/pypred.py +38 -0
- rasa/utils/tensorflow/__init__.py +7 -0
- rasa/utils/tensorflow/callback.py +136 -101
- rasa/utils/tensorflow/crf.py +1 -1
- rasa/utils/tensorflow/data_generator.py +21 -8
- rasa/utils/tensorflow/layers.py +21 -11
- rasa/utils/tensorflow/metrics.py +7 -3
- rasa/utils/tensorflow/models.py +56 -8
- rasa/utils/tensorflow/rasa_layers.py +8 -6
- rasa/utils/tensorflow/transformer.py +2 -3
- rasa/utils/train_utils.py +54 -24
- rasa/validator.py +17 -13
- rasa/version.py +1 -1
- {rasa_pro-3.14.0a20.dist-info → rasa_pro-3.14.0a23.dist-info}/METADATA +48 -42
- {rasa_pro-3.14.0a20.dist-info → rasa_pro-3.14.0a23.dist-info}/RECORD +323 -251
- rasa/builder/scrape_rasa_docs.py +0 -97
- rasa/cli/project_templates/finance/data/general/agent_details.yml +0 -6
- rasa/cli/project_templates/finance/domain/_system/patterns/pattern_session_start.yml +0 -11
- rasa/cli/project_templates/finance/domain/general/agent_details.yml +0 -31
- rasa/core/channels/inspector/dist/assets/channel-8e08bed9.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-78c82dea.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-2b08f601.js +0 -1
- rasa/core/channels/inspector/dist/assets/index-c941dcb3.js +0 -1336
- {rasa_pro-3.14.0a20.dist-info → rasa_pro-3.14.0a23.dist-info}/NOTICE +0 -0
- {rasa_pro-3.14.0a20.dist-info → rasa_pro-3.14.0a23.dist-info}/WHEEL +0 -0
- {rasa_pro-3.14.0a20.dist-info → rasa_pro-3.14.0a23.dist-info}/entry_points.txt +0 -0
|
@@ -4,13 +4,11 @@ from typing import Any, Dict, List, Optional, Text
|
|
|
4
4
|
|
|
5
5
|
import structlog
|
|
6
6
|
from jinja2 import Template
|
|
7
|
-
from
|
|
8
|
-
from structlog.contextvars import (
|
|
9
|
-
bound_contextvars,
|
|
10
|
-
)
|
|
7
|
+
from structlog.contextvars import bound_contextvars
|
|
11
8
|
|
|
12
|
-
from rasa.core.
|
|
9
|
+
from rasa.core.config.configuration import Configuration
|
|
13
10
|
from rasa.core.constants import ACTIVE_FLOW_METADATA_KEY, STEP_ID_METADATA_KEY
|
|
11
|
+
from rasa.core.policies.flows.agent_executor import run_agent
|
|
14
12
|
from rasa.core.policies.flows.flow_exceptions import (
|
|
15
13
|
FlowCircuitBreakerTrippedException,
|
|
16
14
|
FlowException,
|
|
@@ -22,7 +20,7 @@ from rasa.core.policies.flows.flow_step_result import (
|
|
|
22
20
|
FlowStepResult,
|
|
23
21
|
PauseFlowReturnPrediction,
|
|
24
22
|
)
|
|
25
|
-
from rasa.
|
|
23
|
+
from rasa.core.policies.flows.mcp_tool_executor import call_mcp_tool
|
|
26
24
|
from rasa.dialogue_understanding.patterns.cancel import CancelPatternFlowStackFrame
|
|
27
25
|
from rasa.dialogue_understanding.patterns.collect_information import (
|
|
28
26
|
FLOW_PATTERN_COLLECT_INFORMATION,
|
|
@@ -49,14 +47,18 @@ from rasa.dialogue_understanding.stack.frames import (
|
|
|
49
47
|
UserFlowStackFrame,
|
|
50
48
|
)
|
|
51
49
|
from rasa.dialogue_understanding.stack.frames.flow_stack_frame import (
|
|
50
|
+
AgentStackFrame,
|
|
52
51
|
FlowStackFrameType,
|
|
53
52
|
)
|
|
54
53
|
from rasa.dialogue_understanding.stack.utils import (
|
|
55
|
-
|
|
54
|
+
user_frames_on_the_stack,
|
|
56
55
|
)
|
|
56
|
+
from rasa.dialogue_understanding.utils import assemble_options_string
|
|
57
57
|
from rasa.shared.constants import RASA_PATTERN_HUMAN_HANDOFF
|
|
58
58
|
from rasa.shared.core.constants import (
|
|
59
59
|
ACTION_LISTEN_NAME,
|
|
60
|
+
GLOBAL_SILENCE_TIMEOUT_DEFAULT_VALUE,
|
|
61
|
+
SILENCE_TIMEOUT_CHANNEL_KEY,
|
|
60
62
|
SILENCE_TIMEOUT_SLOT,
|
|
61
63
|
)
|
|
62
64
|
from rasa.shared.core.events import (
|
|
@@ -67,11 +69,7 @@ from rasa.shared.core.events import (
|
|
|
67
69
|
SlotSet,
|
|
68
70
|
)
|
|
69
71
|
from rasa.shared.core.flows import FlowsList
|
|
70
|
-
from rasa.shared.core.flows.flow import
|
|
71
|
-
END_STEP,
|
|
72
|
-
Flow,
|
|
73
|
-
FlowStep,
|
|
74
|
-
)
|
|
72
|
+
from rasa.shared.core.flows.flow import END_STEP, Flow, FlowStep
|
|
75
73
|
from rasa.shared.core.flows.flow_step_links import (
|
|
76
74
|
ElseFlowStepLink,
|
|
77
75
|
IfFlowStepLink,
|
|
@@ -89,9 +87,8 @@ from rasa.shared.core.flows.steps import (
|
|
|
89
87
|
)
|
|
90
88
|
from rasa.shared.core.flows.steps.constants import START_STEP
|
|
91
89
|
from rasa.shared.core.slots import Slot, SlotRejection
|
|
92
|
-
from rasa.shared.core.trackers import
|
|
93
|
-
|
|
94
|
-
)
|
|
90
|
+
from rasa.shared.core.trackers import DialogueStateTracker
|
|
91
|
+
from rasa.utils.pypred import Predicate
|
|
95
92
|
|
|
96
93
|
structlogger = structlog.get_logger()
|
|
97
94
|
|
|
@@ -148,6 +145,13 @@ def select_next_step_id(
|
|
|
148
145
|
tracker: DialogueStateTracker,
|
|
149
146
|
) -> Optional[Text]:
|
|
150
147
|
"""Selects the next step id based on the current step."""
|
|
148
|
+
# if the current step is a call step to an agent, and we already have an
|
|
149
|
+
# AgentStackFrame on top of the stack, we need to return the current
|
|
150
|
+
# step id again in order to loop back to the agent.
|
|
151
|
+
top_stack_frame = tracker.stack.top()
|
|
152
|
+
if top_stack_frame and isinstance(top_stack_frame, AgentStackFrame):
|
|
153
|
+
return current.id
|
|
154
|
+
|
|
151
155
|
next_step = current.next
|
|
152
156
|
if len(next_step.links) == 1 and isinstance(next_step.links[0], StaticFlowStepLink):
|
|
153
157
|
return next_step.links[0].target
|
|
@@ -234,38 +238,58 @@ def trigger_pattern_continue_interrupted(
|
|
|
234
238
|
stack: DialogueStack,
|
|
235
239
|
flows: FlowsList,
|
|
236
240
|
tracker: DialogueStateTracker,
|
|
237
|
-
) ->
|
|
241
|
+
) -> None:
|
|
238
242
|
"""Trigger the pattern to continue an interrupted flow if needed."""
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
# get previously started user flow that will be continued
|
|
242
|
-
interrupted_user_flow_frame = top_user_flow_frame(stack)
|
|
243
|
-
interrupted_user_flow_step = (
|
|
244
|
-
interrupted_user_flow_frame.step(flows) if interrupted_user_flow_frame else None
|
|
245
|
-
)
|
|
246
|
-
interrupted_user_flow = (
|
|
247
|
-
interrupted_user_flow_frame.flow(flows) if interrupted_user_flow_frame else None
|
|
248
|
-
)
|
|
249
|
-
|
|
243
|
+
# only trigger the pattern if the current frame is a user flow frame
|
|
244
|
+
# with a frame type of interrupt
|
|
250
245
|
if (
|
|
251
|
-
isinstance(current_frame, UserFlowStackFrame)
|
|
252
|
-
|
|
253
|
-
and interrupted_user_flow is not None
|
|
254
|
-
and current_frame.frame_type == FlowStackFrameType.INTERRUPT
|
|
255
|
-
and not is_step_end_of_flow(interrupted_user_flow_step)
|
|
246
|
+
not isinstance(current_frame, UserFlowStackFrame)
|
|
247
|
+
or current_frame.frame_type != FlowStackFrameType.INTERRUPT
|
|
256
248
|
):
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
249
|
+
return None
|
|
250
|
+
|
|
251
|
+
# get all previously interrupted user flows
|
|
252
|
+
interrupted_user_flow_stack_frames = user_frames_on_the_stack(stack)
|
|
253
|
+
|
|
254
|
+
interrupted_user_flows_to_continue: List[UserFlowStackFrame] = []
|
|
255
|
+
# check if interrupted user flows can be continued
|
|
256
|
+
# i.e. the flow is not at the end of the flow
|
|
257
|
+
for frame in interrupted_user_flow_stack_frames:
|
|
258
|
+
interrupted_user_flow_step = frame.step(flows)
|
|
259
|
+
interrupted_user_flow = frame.flow(flows)
|
|
260
|
+
if (
|
|
261
|
+
interrupted_user_flow_step is not None
|
|
262
|
+
and interrupted_user_flow is not None
|
|
263
|
+
and not is_step_end_of_flow(interrupted_user_flow_step)
|
|
264
|
+
):
|
|
265
|
+
interrupted_user_flows_to_continue.append(frame)
|
|
266
|
+
|
|
267
|
+
# if there are no interrupted user flows to continue,
|
|
268
|
+
# we don't need to trigger the pattern
|
|
269
|
+
if len(interrupted_user_flows_to_continue) == 0:
|
|
270
|
+
return None
|
|
271
|
+
|
|
272
|
+
# get the flow names and ids of the interrupted flows
|
|
273
|
+
# and assemble the options string
|
|
274
|
+
flow_names: List[str] = []
|
|
275
|
+
flow_ids: List[str] = []
|
|
276
|
+
for frame in interrupted_user_flows_to_continue:
|
|
277
|
+
flow_names.append(
|
|
278
|
+
frame.flow(flows).readable_name(language=tracker.current_language)
|
|
263
279
|
)
|
|
264
|
-
|
|
265
|
-
|
|
280
|
+
flow_ids.append(frame.flow_id)
|
|
281
|
+
options_string = assemble_options_string(flow_names)
|
|
282
|
+
|
|
283
|
+
# trigger the pattern to continue the interrupted flows
|
|
284
|
+
stack.push(
|
|
285
|
+
ContinueInterruptedPatternFlowStackFrame(
|
|
286
|
+
interrupted_flow_names=flow_names,
|
|
287
|
+
interrupted_flow_ids=flow_ids,
|
|
288
|
+
interrupted_flow_options=options_string,
|
|
266
289
|
)
|
|
290
|
+
)
|
|
267
291
|
|
|
268
|
-
return
|
|
292
|
+
return None
|
|
269
293
|
|
|
270
294
|
|
|
271
295
|
def trigger_pattern_completed(
|
|
@@ -359,8 +383,11 @@ def reset_scoped_slots(
|
|
|
359
383
|
return events
|
|
360
384
|
|
|
361
385
|
|
|
362
|
-
def advance_flows(
|
|
363
|
-
tracker: DialogueStateTracker,
|
|
386
|
+
async def advance_flows(
|
|
387
|
+
tracker: DialogueStateTracker,
|
|
388
|
+
available_actions: List[str],
|
|
389
|
+
flows: FlowsList,
|
|
390
|
+
slots: List[Slot],
|
|
364
391
|
) -> FlowActionPrediction:
|
|
365
392
|
"""Advance the current flows until the next action.
|
|
366
393
|
|
|
@@ -368,6 +395,7 @@ def advance_flows(
|
|
|
368
395
|
tracker: The tracker to get the next action for.
|
|
369
396
|
available_actions: The actions that are available in the domain.
|
|
370
397
|
flows: All flows.
|
|
398
|
+
slots: The slots that are available in the domain.
|
|
371
399
|
|
|
372
400
|
Returns:
|
|
373
401
|
The predicted action and the events to run.
|
|
@@ -377,13 +405,16 @@ def advance_flows(
|
|
|
377
405
|
# if there are no flows, there is nothing to do
|
|
378
406
|
return FlowActionPrediction(None, 0.0)
|
|
379
407
|
|
|
380
|
-
return advance_flows_until_next_action(
|
|
408
|
+
return await advance_flows_until_next_action(
|
|
409
|
+
tracker, available_actions, flows, slots
|
|
410
|
+
)
|
|
381
411
|
|
|
382
412
|
|
|
383
|
-
def advance_flows_until_next_action(
|
|
413
|
+
async def advance_flows_until_next_action(
|
|
384
414
|
tracker: DialogueStateTracker,
|
|
385
415
|
available_actions: List[str],
|
|
386
416
|
flows: FlowsList,
|
|
417
|
+
slots: List[Slot],
|
|
387
418
|
) -> FlowActionPrediction:
|
|
388
419
|
"""Advance the flow and select the next action to execute.
|
|
389
420
|
|
|
@@ -441,7 +472,7 @@ def advance_flows_until_next_action(
|
|
|
441
472
|
|
|
442
473
|
with bound_contextvars(step_id=next_step.id):
|
|
443
474
|
step_stack = tracker.stack
|
|
444
|
-
step_result = run_step(
|
|
475
|
+
step_result = await run_step(
|
|
445
476
|
next_step,
|
|
446
477
|
current_flow,
|
|
447
478
|
step_stack,
|
|
@@ -449,6 +480,7 @@ def advance_flows_until_next_action(
|
|
|
449
480
|
available_actions,
|
|
450
481
|
flows,
|
|
451
482
|
previous_step_id,
|
|
483
|
+
slots,
|
|
452
484
|
)
|
|
453
485
|
new_events = step_result.events
|
|
454
486
|
if (
|
|
@@ -477,10 +509,9 @@ def advance_flows_until_next_action(
|
|
|
477
509
|
# make sure we really return all events that got created during the
|
|
478
510
|
# step execution of all steps (not only the last one)
|
|
479
511
|
prediction.events = gathered_events
|
|
480
|
-
prediction.metadata = {
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
}
|
|
512
|
+
prediction.metadata = prediction.metadata or {}
|
|
513
|
+
prediction.metadata[ACTIVE_FLOW_METADATA_KEY] = tracker.active_flow
|
|
514
|
+
prediction.metadata[STEP_ID_METADATA_KEY] = tracker.current_step_id
|
|
484
515
|
return prediction
|
|
485
516
|
else:
|
|
486
517
|
structlogger.warning("flow.step.execution.no_action")
|
|
@@ -522,6 +553,8 @@ def validate_collect_step(
|
|
|
522
553
|
|
|
523
554
|
def cancel_flow_and_push_internal_error(stack: DialogueStack, flow_name: str) -> None:
|
|
524
555
|
"""Cancel the top user flow and push the internal error pattern."""
|
|
556
|
+
from rasa.dialogue_understanding.commands import CancelFlowCommand
|
|
557
|
+
|
|
525
558
|
top_frame = stack.top()
|
|
526
559
|
|
|
527
560
|
if isinstance(top_frame, BaseFlowStackFrame):
|
|
@@ -550,7 +583,7 @@ def attach_stack_metadata_to_events(
|
|
|
550
583
|
event.metadata[ACTIVE_FLOW_METADATA_KEY] = flow_id
|
|
551
584
|
|
|
552
585
|
|
|
553
|
-
def run_step(
|
|
586
|
+
async def run_step(
|
|
554
587
|
step: FlowStep,
|
|
555
588
|
flow: Flow,
|
|
556
589
|
stack: DialogueStack,
|
|
@@ -558,6 +591,7 @@ def run_step(
|
|
|
558
591
|
available_actions: List[str],
|
|
559
592
|
flows: FlowsList,
|
|
560
593
|
previous_step_id: str,
|
|
594
|
+
slots: List[Slot],
|
|
561
595
|
) -> FlowStepResult:
|
|
562
596
|
"""Run a single step of a flow.
|
|
563
597
|
|
|
@@ -576,6 +610,7 @@ def run_step(
|
|
|
576
610
|
available_actions: The actions that are available in the domain.
|
|
577
611
|
flows: All flows.
|
|
578
612
|
previous_step_id: The ID of the previous step.
|
|
613
|
+
slots: The slots that are available in the domain.
|
|
579
614
|
|
|
580
615
|
Returns:
|
|
581
616
|
A result of running the step describing where to transition to.
|
|
@@ -615,7 +650,7 @@ def run_step(
|
|
|
615
650
|
return _run_link_step(initial_events, stack, step)
|
|
616
651
|
|
|
617
652
|
elif isinstance(step, CallFlowStep):
|
|
618
|
-
return _run_call_step(initial_events, stack, step)
|
|
653
|
+
return await _run_call_step(initial_events, stack, step, tracker, slots)
|
|
619
654
|
|
|
620
655
|
elif isinstance(step, SetSlotsFlowStep):
|
|
621
656
|
return _run_set_slot_step(initial_events, step)
|
|
@@ -667,12 +702,10 @@ def _run_end_step(
|
|
|
667
702
|
structlogger.debug("flow.step.run.flow_end")
|
|
668
703
|
current_frame = stack.pop()
|
|
669
704
|
trigger_pattern_completed(current_frame, stack, flows)
|
|
670
|
-
|
|
671
|
-
current_frame, stack, flows, tracker
|
|
672
|
-
)
|
|
705
|
+
trigger_pattern_continue_interrupted(current_frame, stack, flows, tracker)
|
|
673
706
|
reset_events: List[Event] = reset_scoped_slots(current_frame, flow, tracker)
|
|
674
707
|
return ContinueFlowWithNextStep(
|
|
675
|
-
events=initial_events + reset_events
|
|
708
|
+
events=initial_events + reset_events, has_flow_ended=True
|
|
676
709
|
)
|
|
677
710
|
|
|
678
711
|
|
|
@@ -684,17 +717,26 @@ def _run_set_slot_step(
|
|
|
684
717
|
return ContinueFlowWithNextStep(events=initial_events + slot_events)
|
|
685
718
|
|
|
686
719
|
|
|
687
|
-
def _run_call_step(
|
|
688
|
-
initial_events: List[Event],
|
|
720
|
+
async def _run_call_step(
|
|
721
|
+
initial_events: List[Event],
|
|
722
|
+
stack: DialogueStack,
|
|
723
|
+
step: CallFlowStep,
|
|
724
|
+
tracker: DialogueStateTracker,
|
|
725
|
+
slots: List[Slot],
|
|
689
726
|
) -> FlowStepResult:
|
|
690
727
|
structlogger.debug("flow.step.run.call")
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
728
|
+
if step.is_calling_mcp_tool():
|
|
729
|
+
return await call_mcp_tool(initial_events, stack, step, tracker)
|
|
730
|
+
elif step.is_calling_agent():
|
|
731
|
+
return await run_agent(initial_events, stack, step, tracker, slots)
|
|
732
|
+
else:
|
|
733
|
+
stack.push(
|
|
734
|
+
UserFlowStackFrame(
|
|
735
|
+
flow_id=step.call,
|
|
736
|
+
frame_type=FlowStackFrameType.CALL,
|
|
737
|
+
),
|
|
738
|
+
)
|
|
739
|
+
return ContinueFlowWithNextStep(events=initial_events)
|
|
698
740
|
|
|
699
741
|
|
|
700
742
|
def _run_link_step(
|
|
@@ -797,21 +839,41 @@ def _silence_timeout_events_for_collect_step(
|
|
|
797
839
|
) -> List[Event]:
|
|
798
840
|
events: List[Event] = []
|
|
799
841
|
|
|
800
|
-
silence_timeout = (
|
|
801
|
-
AvailableEndpoints.get_instance().interaction_handling.global_silence_timeout
|
|
802
|
-
)
|
|
803
|
-
|
|
804
842
|
if step.silence_timeout:
|
|
843
|
+
input_channel_name = tracker.get_latest_input_channel()
|
|
844
|
+
|
|
805
845
|
structlogger.debug(
|
|
806
|
-
"flow.step.run.
|
|
846
|
+
"flow.step.run.using_step_silence_timeout",
|
|
807
847
|
duration=step.silence_timeout,
|
|
808
848
|
collect=step.collect,
|
|
809
849
|
)
|
|
810
850
|
|
|
811
|
-
silence_timeout = step.silence_timeout
|
|
851
|
+
silence_timeout = step.silence_timeout.get_silence_for_channel(
|
|
852
|
+
input_channel_name
|
|
853
|
+
)
|
|
812
854
|
else:
|
|
855
|
+
input_channel_name = tracker.get_latest_input_channel()
|
|
856
|
+
credentials_config = Configuration.get_instance().credentials
|
|
857
|
+
|
|
858
|
+
if credentials_config:
|
|
859
|
+
channel_config = (
|
|
860
|
+
credentials_config.channels.get(input_channel_name)
|
|
861
|
+
if input_channel_name
|
|
862
|
+
else None
|
|
863
|
+
)
|
|
864
|
+
|
|
865
|
+
silence_timeout = (
|
|
866
|
+
channel_config.get(
|
|
867
|
+
SILENCE_TIMEOUT_CHANNEL_KEY, GLOBAL_SILENCE_TIMEOUT_DEFAULT_VALUE
|
|
868
|
+
)
|
|
869
|
+
if channel_config
|
|
870
|
+
else GLOBAL_SILENCE_TIMEOUT_DEFAULT_VALUE
|
|
871
|
+
)
|
|
872
|
+
else:
|
|
873
|
+
silence_timeout = GLOBAL_SILENCE_TIMEOUT_DEFAULT_VALUE
|
|
874
|
+
|
|
813
875
|
structlogger.debug(
|
|
814
|
-
"flow.step.run.
|
|
876
|
+
"flow.step.run.use_channel_silence_timeout",
|
|
815
877
|
duration=silence_timeout,
|
|
816
878
|
collect=step.collect,
|
|
817
879
|
)
|
|
@@ -828,14 +890,13 @@ def _append_global_silence_timeout_event(
|
|
|
828
890
|
events: List[Event], tracker: DialogueStateTracker
|
|
829
891
|
) -> None:
|
|
830
892
|
current_silence_timeout = tracker.get_slot(SILENCE_TIMEOUT_SLOT)
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
)
|
|
893
|
+
endpoints = Configuration.get_instance().endpoints
|
|
894
|
+
global_silence_timeout = endpoints.interaction_handling.global_silence_timeout
|
|
834
895
|
|
|
835
896
|
if current_silence_timeout != global_silence_timeout:
|
|
836
897
|
events.append(
|
|
837
898
|
SlotSet(
|
|
838
899
|
SILENCE_TIMEOUT_SLOT,
|
|
839
|
-
|
|
900
|
+
global_silence_timeout,
|
|
840
901
|
)
|
|
841
902
|
)
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import Any, Dict, List, Optional
|
|
3
|
+
|
|
4
|
+
import structlog
|
|
5
|
+
from jinja2.sandbox import SandboxedEnvironment
|
|
6
|
+
from mcp.types import CallToolResult
|
|
7
|
+
|
|
8
|
+
from rasa.core.config.configuration import Configuration
|
|
9
|
+
from rasa.core.policies.flows.flow_step_result import (
|
|
10
|
+
ContinueFlowWithNextStep,
|
|
11
|
+
FlowStepResult,
|
|
12
|
+
)
|
|
13
|
+
from rasa.dialogue_understanding.patterns.internal_error import (
|
|
14
|
+
InternalErrorPatternFlowStackFrame,
|
|
15
|
+
)
|
|
16
|
+
from rasa.dialogue_understanding.stack.dialogue_stack import DialogueStack
|
|
17
|
+
from rasa.shared.core.events import Event, SlotSet
|
|
18
|
+
from rasa.shared.core.flows.steps import CallFlowStep
|
|
19
|
+
from rasa.shared.core.trackers import DialogueStateTracker
|
|
20
|
+
from rasa.shared.utils.mcp.server_connection import MCPServerConnection
|
|
21
|
+
from rasa.utils.common import ensure_jsonified_iterable
|
|
22
|
+
|
|
23
|
+
structlogger = structlog.get_logger()
|
|
24
|
+
|
|
25
|
+
CONFIG_VALUE = "value"
|
|
26
|
+
CONFIG_SLOT = "slot"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
async def call_mcp_tool(
|
|
30
|
+
initial_events: List[Event],
|
|
31
|
+
stack: DialogueStack,
|
|
32
|
+
step: CallFlowStep,
|
|
33
|
+
tracker: DialogueStateTracker,
|
|
34
|
+
) -> FlowStepResult:
|
|
35
|
+
"""Run an MCP tool call step."""
|
|
36
|
+
structlogger.debug(
|
|
37
|
+
"flow.step.call_mcp_tool",
|
|
38
|
+
tool_id=step.call,
|
|
39
|
+
mcp_server=step.mcp_server,
|
|
40
|
+
mapping=step.mapping,
|
|
41
|
+
step_id=step.id,
|
|
42
|
+
flow_id=step.flow_id,
|
|
43
|
+
json_formatting=["mapping"],
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
return await _execute_mcp_tool_call(initial_events, stack, step, tracker)
|
|
48
|
+
except Exception as e:
|
|
49
|
+
return _handle_mcp_tool_error(
|
|
50
|
+
stack,
|
|
51
|
+
initial_events,
|
|
52
|
+
error_message=f"Failed to execute MCP tool call: {e}.",
|
|
53
|
+
tool_name=step.call,
|
|
54
|
+
mcp_server=step.mcp_server,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
async def _execute_mcp_tool_call(
|
|
59
|
+
initial_events: List[Event],
|
|
60
|
+
stack: DialogueStack,
|
|
61
|
+
step: CallFlowStep,
|
|
62
|
+
tracker: DialogueStateTracker,
|
|
63
|
+
) -> FlowStepResult:
|
|
64
|
+
"""Execute the MCP tool call with proper error handling."""
|
|
65
|
+
mcp_server_connection = None
|
|
66
|
+
try:
|
|
67
|
+
# Connect to the MCP server
|
|
68
|
+
mcp_server_connection = await _connect_to_mcp_server(step.mcp_server)
|
|
69
|
+
|
|
70
|
+
if not mcp_server_connection:
|
|
71
|
+
return _handle_mcp_tool_error(
|
|
72
|
+
stack,
|
|
73
|
+
initial_events,
|
|
74
|
+
f"Cannot connect to MCP server '{step.mcp_server}'.",
|
|
75
|
+
tool_name=step.call,
|
|
76
|
+
mcp_server=step.mcp_server,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Validate tool availability
|
|
80
|
+
if not await _is_tool_available(mcp_server_connection, step.call):
|
|
81
|
+
return _handle_mcp_tool_error(
|
|
82
|
+
stack,
|
|
83
|
+
initial_events,
|
|
84
|
+
f"Tool '{step.call}' is not available on MCP server "
|
|
85
|
+
f"'{step.mcp_server}'.",
|
|
86
|
+
tool_name=step.call,
|
|
87
|
+
mcp_server=step.mcp_server,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# This should not happen, but we need to check for type checking to pass
|
|
91
|
+
if not step.mapping:
|
|
92
|
+
return _handle_mcp_tool_error(
|
|
93
|
+
stack,
|
|
94
|
+
initial_events,
|
|
95
|
+
f"No mapping found for tool '{step.call}'.",
|
|
96
|
+
tool_name=step.call,
|
|
97
|
+
mcp_server=step.mcp_server,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Prepare arguments for the tool call
|
|
101
|
+
arguments = _prepare_tool_arguments(step.mapping["input"], tracker)
|
|
102
|
+
|
|
103
|
+
# Call the tool with parameters
|
|
104
|
+
mcp_server = await mcp_server_connection.ensure_active_session()
|
|
105
|
+
result = await mcp_server.call_tool(step.call, arguments)
|
|
106
|
+
|
|
107
|
+
# Handle tool execution result
|
|
108
|
+
if result is None or result.isError:
|
|
109
|
+
return _handle_mcp_tool_error(
|
|
110
|
+
stack,
|
|
111
|
+
initial_events,
|
|
112
|
+
f"Tool '{step.call}' execution failed: {result.content}.",
|
|
113
|
+
tool_name=step.call,
|
|
114
|
+
mcp_server=step.mcp_server,
|
|
115
|
+
)
|
|
116
|
+
elif not result.content:
|
|
117
|
+
structlogger.warning(
|
|
118
|
+
"call_mcp_tool.empty_tool_result",
|
|
119
|
+
tool_name=step.call,
|
|
120
|
+
mcp_server=step.mcp_server,
|
|
121
|
+
)
|
|
122
|
+
else:
|
|
123
|
+
structlogger.debug(
|
|
124
|
+
"call_mcp_tool.tool_execution_success",
|
|
125
|
+
tool_name=step.call,
|
|
126
|
+
mcp_server=step.mcp_server,
|
|
127
|
+
result_content=result.content,
|
|
128
|
+
result_structured_content=result.structuredContent,
|
|
129
|
+
json_formatting=["result_content", "result_structured_content"],
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Process successful result
|
|
133
|
+
if set_slot_event := _process_tool_result(result, step.mapping["output"]):
|
|
134
|
+
initial_events.extend(set_slot_event)
|
|
135
|
+
else:
|
|
136
|
+
return _handle_mcp_tool_error(
|
|
137
|
+
stack,
|
|
138
|
+
initial_events,
|
|
139
|
+
f"Failed to process tool result for '{step.call}'.",
|
|
140
|
+
tool_name=step.call,
|
|
141
|
+
mcp_server=step.mcp_server,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
return ContinueFlowWithNextStep(events=initial_events)
|
|
145
|
+
|
|
146
|
+
finally:
|
|
147
|
+
# Always clean up the connection to prevent resource leaks
|
|
148
|
+
if mcp_server_connection:
|
|
149
|
+
try:
|
|
150
|
+
await mcp_server_connection.close()
|
|
151
|
+
except Exception as e:
|
|
152
|
+
structlogger.warning(
|
|
153
|
+
"call_mcp_tool.connection_cleanup_failed",
|
|
154
|
+
tool_name=step.call,
|
|
155
|
+
mcp_server=step.mcp_server,
|
|
156
|
+
error=str(e),
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
async def _is_tool_available(
|
|
161
|
+
mcp_server_connection: MCPServerConnection, tool_name: str
|
|
162
|
+
) -> bool:
|
|
163
|
+
"""Check if the specified tool is available on the MCP server."""
|
|
164
|
+
try:
|
|
165
|
+
# Get the active session from the connection
|
|
166
|
+
mcp_server = await mcp_server_connection.ensure_active_session()
|
|
167
|
+
available_tools = await mcp_server.list_tools()
|
|
168
|
+
tool_names = [tool.name for tool in available_tools.tools]
|
|
169
|
+
return tool_name in tool_names
|
|
170
|
+
except Exception as e:
|
|
171
|
+
structlogger.warning(
|
|
172
|
+
"call_mcp_tool.tool_availability_check_failed",
|
|
173
|
+
tool_name=tool_name,
|
|
174
|
+
error=str(e),
|
|
175
|
+
)
|
|
176
|
+
return False
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
async def _connect_to_mcp_server(
|
|
180
|
+
mcp_server_name: Optional[str],
|
|
181
|
+
) -> Optional[MCPServerConnection]:
|
|
182
|
+
"""Connect to the MCP server."""
|
|
183
|
+
if not mcp_server_name:
|
|
184
|
+
return None
|
|
185
|
+
|
|
186
|
+
# get the MCP server config from the available endpoints
|
|
187
|
+
endpoints = Configuration.get_instance().endpoints
|
|
188
|
+
mcp_servers = endpoints.mcp_servers
|
|
189
|
+
if not mcp_servers:
|
|
190
|
+
return None
|
|
191
|
+
|
|
192
|
+
mcp_server_configs = [
|
|
193
|
+
mcp_server for mcp_server in mcp_servers if mcp_server.name == mcp_server_name
|
|
194
|
+
]
|
|
195
|
+
if not mcp_server_configs or len(mcp_server_configs) != 1:
|
|
196
|
+
return None
|
|
197
|
+
|
|
198
|
+
mcp_server_config = mcp_server_configs[0]
|
|
199
|
+
|
|
200
|
+
mcp_server_connection = MCPServerConnection.from_config(
|
|
201
|
+
mcp_server_config.model_dump()
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
# Ensure the connection is established and return the connection object
|
|
205
|
+
await mcp_server_connection.ensure_active_session()
|
|
206
|
+
return mcp_server_connection
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _prepare_tool_arguments(
|
|
210
|
+
input_mapping: List[Dict[str, str]], tracker: DialogueStateTracker
|
|
211
|
+
) -> Dict[str, Any]:
|
|
212
|
+
"""Prepare arguments for the tool call from slot values."""
|
|
213
|
+
arguments = {}
|
|
214
|
+
for argument in input_mapping:
|
|
215
|
+
slot_value = tracker.get_slot(argument["slot"])
|
|
216
|
+
arguments[argument["param"]] = slot_value
|
|
217
|
+
return arguments
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _jsonify_slot_value(value: Any) -> str | int | float | bool | None:
|
|
221
|
+
"""Prepare value for SlotSet: iterables -> JSON string, primitives -> as-is"""
|
|
222
|
+
if isinstance(value, (list, dict)) and len(value):
|
|
223
|
+
return json.dumps(ensure_jsonified_iterable(value))
|
|
224
|
+
return value
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _get_slot_value_from_jinja2_expression(
|
|
228
|
+
result_expression: str,
|
|
229
|
+
result_as_dict: Dict[str, Any],
|
|
230
|
+
) -> Any:
|
|
231
|
+
"""Get the slot value from the Jinja2 expression"""
|
|
232
|
+
# Create a sandboxed environment to evaluate the expression
|
|
233
|
+
_env = SandboxedEnvironment()
|
|
234
|
+
|
|
235
|
+
# Compile the expression
|
|
236
|
+
compiled_expr = _env.compile_expression(result_expression)
|
|
237
|
+
|
|
238
|
+
# Evaluate the expression
|
|
239
|
+
return compiled_expr(result_as_dict)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def _process_tool_result(
|
|
243
|
+
result: CallToolResult,
|
|
244
|
+
output_mapping: List[Dict[str, str]],
|
|
245
|
+
) -> Optional[List[SlotSet]]:
|
|
246
|
+
"""Create a SetSlot event for the tool result using Jinja2 expressions"""
|
|
247
|
+
try:
|
|
248
|
+
_result_as_dict = {"result": result.model_dump()}
|
|
249
|
+
slots = []
|
|
250
|
+
for mapping in output_mapping:
|
|
251
|
+
try:
|
|
252
|
+
result_expression = mapping[CONFIG_VALUE]
|
|
253
|
+
|
|
254
|
+
# Get the slot value from the Jinja2 expression
|
|
255
|
+
slot_value = _get_slot_value_from_jinja2_expression(
|
|
256
|
+
result_expression, _result_as_dict
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
slots.append(
|
|
260
|
+
SlotSet(mapping[CONFIG_SLOT], _jsonify_slot_value(slot_value))
|
|
261
|
+
)
|
|
262
|
+
except Exception as e:
|
|
263
|
+
structlogger.error(
|
|
264
|
+
"call_mcp_tool.value_not_found_in_tool_result",
|
|
265
|
+
slot=mapping[CONFIG_SLOT],
|
|
266
|
+
value=mapping[CONFIG_VALUE],
|
|
267
|
+
result=_result_as_dict,
|
|
268
|
+
error=str(e),
|
|
269
|
+
json_formatting=["result"],
|
|
270
|
+
)
|
|
271
|
+
return None
|
|
272
|
+
return slots
|
|
273
|
+
except Exception as e:
|
|
274
|
+
structlogger.error(
|
|
275
|
+
"call_mcp_tool.result_processing_failed",
|
|
276
|
+
error=str(e),
|
|
277
|
+
result=result,
|
|
278
|
+
json_formatting=["result"],
|
|
279
|
+
)
|
|
280
|
+
return None
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def _handle_mcp_tool_error(
|
|
284
|
+
stack: DialogueStack,
|
|
285
|
+
events: List[Event],
|
|
286
|
+
error_message: str,
|
|
287
|
+
tool_name: str,
|
|
288
|
+
mcp_server: Optional[str],
|
|
289
|
+
) -> FlowStepResult:
|
|
290
|
+
"""Handle MCP tool errors consistently."""
|
|
291
|
+
structlogger.error(
|
|
292
|
+
"call_mcp_tool.error",
|
|
293
|
+
error_message=error_message,
|
|
294
|
+
tool_name=tool_name,
|
|
295
|
+
mcp_server=mcp_server,
|
|
296
|
+
)
|
|
297
|
+
stack.push(InternalErrorPatternFlowStackFrame())
|
|
298
|
+
return ContinueFlowWithNextStep(events=events)
|