rasa-pro 3.11.4__py3-none-any.whl → 3.12.0__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.
- README.md +10 -13
- rasa/__main__.py +7 -7
- rasa/anonymization/anonymisation_rule_yaml_reader.py +1 -1
- rasa/anonymization/anonymization_pipeline.py +3 -3
- rasa/anonymization/anonymization_rule_executor.py +17 -11
- rasa/anonymization/anonymization_rule_orchestrator.py +2 -3
- rasa/cli/arguments/data.py +2 -2
- rasa/cli/arguments/default_arguments.py +1 -1
- rasa/cli/arguments/evaluate.py +2 -1
- rasa/cli/arguments/interactive.py +1 -1
- rasa/cli/arguments/run.py +1 -1
- rasa/cli/arguments/test.py +7 -5
- rasa/cli/arguments/train.py +3 -3
- rasa/cli/arguments/visualize.py +2 -2
- rasa/cli/arguments/x.py +1 -0
- rasa/cli/data.py +20 -3
- rasa/cli/dialogue_understanding_test.py +386 -0
- rasa/cli/evaluate.py +1 -1
- rasa/cli/export.py +6 -6
- rasa/cli/inspect.py +20 -1
- rasa/cli/interactive.py +4 -5
- rasa/cli/llm_fine_tuning.py +51 -16
- rasa/cli/markers.py +1 -2
- rasa/cli/project_templates/calm/actions/add_contact.py +1 -1
- rasa/cli/project_templates/calm/config.yml +2 -2
- rasa/cli/project_templates/calm/domain/list_contacts.yml +1 -2
- rasa/cli/project_templates/calm/domain/remove_contact.yml +1 -2
- rasa/cli/project_templates/calm/domain/shared.yml +1 -4
- rasa/cli/project_templates/calm/endpoints.yml +2 -2
- rasa/cli/project_templates/tutorial/actions/actions.py +3 -2
- rasa/cli/shell.py +5 -6
- rasa/cli/studio/download.py +1 -2
- rasa/cli/studio/studio.py +2 -3
- rasa/cli/studio/train.py +0 -1
- rasa/cli/telemetry.py +2 -2
- rasa/cli/test.py +11 -11
- rasa/cli/train.py +3 -0
- rasa/cli/utils.py +25 -5
- rasa/constants.py +0 -1
- rasa/core/__init__.py +0 -1
- rasa/core/actions/action.py +137 -208
- rasa/core/actions/action_handle_digressions.py +164 -0
- rasa/core/actions/action_hangup.py +1 -1
- rasa/core/actions/action_repeat_bot_messages.py +2 -2
- rasa/core/actions/action_run_slot_rejections.py +18 -6
- rasa/core/actions/action_trigger_chitchat.py +1 -1
- rasa/core/actions/action_trigger_flow.py +5 -5
- rasa/core/actions/action_trigger_search.py +1 -1
- rasa/core/actions/custom_action_executor.py +1 -1
- rasa/core/actions/direct_custom_actions_executor.py +1 -0
- rasa/core/actions/forms.py +22 -15
- rasa/core/actions/http_custom_action_executor.py +8 -1
- rasa/core/actions/loops.py +3 -3
- rasa/core/actions/two_stage_fallback.py +13 -13
- rasa/core/auth_retry_tracker_store.py +1 -2
- rasa/core/brokers/broker.py +2 -1
- rasa/core/brokers/file.py +1 -1
- rasa/core/brokers/kafka.py +8 -8
- rasa/core/brokers/pika.py +8 -9
- rasa/core/brokers/sql.py +4 -3
- rasa/core/channels/__init__.py +7 -0
- rasa/core/channels/botframework.py +2 -2
- rasa/core/channels/callback.py +4 -4
- rasa/core/channels/channel.py +11 -11
- rasa/core/channels/console.py +0 -1
- rasa/core/channels/development_inspector.py +80 -24
- rasa/core/channels/facebook.py +5 -5
- rasa/core/channels/hangouts.py +7 -8
- rasa/core/channels/inspector/dist/assets/Tableau10-1b767f5e.js +1 -0
- rasa/core/channels/inspector/dist/assets/arc-9f1365dc.js +1 -0
- rasa/core/channels/inspector/dist/assets/blockDiagram-38ab4fdb-e0f81b12.js +118 -0
- rasa/core/channels/inspector/dist/assets/c4Diagram-3d4e48cf-9deaee1c.js +10 -0
- rasa/core/channels/inspector/dist/assets/channel-44956714.js +1 -0
- rasa/core/channels/inspector/dist/assets/classDiagram-70f12bd4-20450a96.js +2 -0
- rasa/core/channels/inspector/dist/assets/classDiagram-v2-f2320105-749d2abf.js +2 -0
- rasa/core/channels/inspector/dist/assets/clone-a9475142.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-62fc7601-89c73b31.js → createText-2e5e7dd3-bef0b38c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/edges-e0da2a9e-943801a7.js +4 -0
- rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-907e0440.js → erDiagram-9861fffd-d523a948.js} +4 -4
- rasa/core/channels/inspector/dist/assets/flowDb-956e92f1-54e4cf19.js +10 -0
- rasa/core/channels/inspector/dist/assets/flowDiagram-66a62f08-48bfbbe8.js +4 -0
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-43fa749a.js +1 -0
- rasa/core/channels/inspector/dist/assets/flowchart-elk-definition-4a651766-17c30827.js +139 -0
- rasa/core/channels/inspector/dist/assets/ganttDiagram-c361ad54-43086f2d.js +257 -0
- rasa/core/channels/inspector/dist/assets/gitGraphDiagram-72cf32ee-5c8b693e.js +70 -0
- rasa/core/channels/inspector/dist/assets/graph-41a90d26.js +1 -0
- rasa/core/channels/inspector/dist/assets/index-3862675e-b43eeae9.js +1 -0
- rasa/core/channels/inspector/dist/assets/{index-e793d777.js → index-e8affe45.js} +201 -196
- rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-8ceba4db.js → infoDiagram-f8f76790-0b20676b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-960d3809.js → journeyDiagram-49397b02-39bce7b5.js} +4 -4
- rasa/core/channels/inspector/dist/assets/katex-498eb57e.js +261 -0
- rasa/core/channels/inspector/dist/assets/layout-dc8eeea4.js +1 -0
- rasa/core/channels/inspector/dist/assets/{line-eeccc4e2.js → line-c4d2e756.js} +1 -1
- rasa/core/channels/inspector/dist/assets/linear-86f6f2d9.js +1 -0
- rasa/core/channels/inspector/dist/assets/mindmap-definition-fc14e90a-4216f771.js +312 -0
- rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-dc9b5e1b.js → pieDiagram-8a3498a8-1a0cfa96.js} +7 -7
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-a08cba6d.js → quadrantDiagram-120e2f19-f91e67cf.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-87242b9e.js → requirementDiagram-deff3bca-d4046bed.js} +2 -2
- rasa/core/channels/inspector/dist/assets/sankeyDiagram-04a897e0-2cf6d1d7.js +8 -0
- rasa/core/channels/inspector/dist/assets/sequenceDiagram-704730f1-751ac4f5.js +122 -0
- rasa/core/channels/inspector/dist/assets/stateDiagram-587899a1-f734f4d4.js +1 -0
- rasa/core/channels/inspector/dist/assets/stateDiagram-v2-d93cdb3a-91c65710.js +1 -0
- rasa/core/channels/inspector/dist/assets/{styles-9c745c82-cef936a6.js → styles-6aaf32cf-e0cff7be.js} +1 -1
- rasa/core/channels/inspector/dist/assets/styles-9a916d00-c8029e5d.js +160 -0
- rasa/core/channels/inspector/dist/assets/styles-c10674c1-114f312a.js +116 -0
- rasa/core/channels/inspector/dist/assets/svgDrawCommon-08f97a94-b7b9dc00.js +1 -0
- rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-0d39bdb2.js → timeline-definition-85554ec2-9536d189.js} +3 -3
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-a03fa445.js → xychartDiagram-e933f94c-bf3b0f36.js} +3 -3
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/package.json +11 -3
- rasa/core/channels/inspector/src/App.tsx +15 -2
- rasa/core/channels/inspector/src/components/RasaLogo.tsx +31 -0
- rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +68 -0
- rasa/core/channels/inspector/src/components/Welcome.tsx +19 -13
- rasa/core/channels/inspector/yarn.lock +94 -99
- rasa/core/channels/mattermost.py +4 -4
- rasa/core/channels/rasa_chat.py +4 -4
- rasa/core/channels/rest.py +11 -12
- rasa/core/channels/rocketchat.py +4 -3
- rasa/core/channels/slack.py +6 -5
- rasa/core/channels/socketio.py +8 -28
- rasa/core/channels/studio_chat.py +212 -0
- rasa/core/channels/telegram.py +105 -55
- rasa/core/channels/twilio.py +3 -3
- rasa/core/channels/vier_cvg.py +2 -2
- rasa/core/channels/voice_ready/audiocodes.py +51 -32
- rasa/core/channels/voice_ready/jambonz.py +5 -5
- rasa/core/channels/voice_ready/jambonz_protocol.py +3 -4
- rasa/core/channels/voice_ready/twilio_voice.py +9 -8
- rasa/core/channels/voice_ready/utils.py +2 -2
- rasa/core/channels/voice_stream/asr/asr_engine.py +12 -6
- rasa/core/channels/voice_stream/asr/asr_event.py +5 -0
- rasa/core/channels/voice_stream/asr/azure.py +16 -3
- rasa/core/channels/voice_stream/asr/deepgram.py +76 -19
- rasa/core/channels/voice_stream/audiocodes.py +292 -0
- rasa/core/channels/voice_stream/browser_audio.py +14 -7
- rasa/core/channels/voice_stream/call_state.py +6 -2
- rasa/core/channels/voice_stream/genesys.py +320 -0
- rasa/core/channels/voice_stream/tts/azure.py +13 -5
- rasa/core/channels/voice_stream/tts/cartesia.py +34 -14
- rasa/core/channels/voice_stream/tts/tts_cache.py +3 -2
- rasa/core/channels/voice_stream/tts/tts_engine.py +1 -1
- rasa/core/channels/voice_stream/twilio_media_streams.py +12 -8
- rasa/core/channels/voice_stream/util.py +1 -1
- rasa/core/channels/voice_stream/voice_channel.py +100 -56
- rasa/core/channels/webexteams.py +3 -4
- rasa/core/constants.py +2 -0
- rasa/core/evaluation/marker.py +7 -6
- rasa/core/evaluation/marker_base.py +15 -16
- rasa/core/evaluation/marker_stats.py +3 -4
- rasa/core/evaluation/marker_tracker_loader.py +5 -4
- rasa/core/exporter.py +4 -4
- rasa/core/featurizers/precomputation.py +8 -8
- rasa/core/featurizers/single_state_featurizer.py +7 -7
- rasa/core/featurizers/tracker_featurizers.py +13 -13
- rasa/core/http_interpreter.py +3 -4
- rasa/core/information_retrieval/__init__.py +1 -1
- rasa/core/information_retrieval/faiss.py +4 -4
- rasa/core/information_retrieval/information_retrieval.py +2 -2
- rasa/core/information_retrieval/milvus.py +3 -3
- rasa/core/information_retrieval/qdrant.py +3 -3
- rasa/core/jobs.py +1 -0
- rasa/core/lock.py +2 -3
- rasa/core/lock_store.py +3 -3
- rasa/core/migrate.py +12 -9
- rasa/core/nlg/__init__.py +1 -1
- rasa/core/nlg/callback.py +2 -3
- rasa/core/nlg/contextual_response_rephraser.py +82 -14
- rasa/core/nlg/generator.py +85 -17
- rasa/core/nlg/interpolator.py +4 -3
- rasa/core/nlg/response.py +9 -7
- rasa/core/nlg/summarize.py +1 -0
- rasa/core/nlg/translate.py +55 -0
- rasa/core/persistor.py +3 -3
- rasa/core/policies/ensemble.py +10 -9
- rasa/core/policies/enterprise_search_policy.py +87 -21
- rasa/core/policies/enterprise_search_prompt_with_citation_template.jinja2 +1 -1
- rasa/core/policies/flow_policy.py +13 -14
- rasa/core/policies/flows/flow_executor.py +85 -55
- rasa/core/policies/intentless_policy.py +6 -7
- rasa/core/policies/memoization.py +22 -20
- rasa/core/policies/policy.py +24 -22
- rasa/core/policies/rule_policy.py +37 -36
- rasa/core/policies/ted_policy.py +87 -85
- rasa/core/policies/unexpected_intent_policy.py +77 -75
- rasa/core/processor.py +167 -74
- rasa/core/run.py +5 -4
- rasa/core/secrets_manager/endpoints.py +2 -3
- rasa/core/secrets_manager/factory.py +2 -3
- rasa/core/secrets_manager/secret_manager.py +2 -3
- rasa/core/secrets_manager/vault.py +2 -2
- rasa/core/test.py +30 -30
- rasa/core/tracker_store.py +138 -49
- rasa/core/train.py +1 -1
- rasa/core/training/__init__.py +2 -2
- rasa/core/training/converters/responses_prefix_converter.py +1 -2
- rasa/core/training/interactive.py +13 -13
- rasa/core/training/story_conflict.py +4 -5
- rasa/core/training/training.py +3 -5
- rasa/core/utils.py +5 -5
- rasa/core/visualize.py +1 -1
- rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -2
- rasa/dialogue_understanding/coexistence/llm_based_router.py +5 -5
- rasa/dialogue_understanding/commands/__init__.py +22 -22
- rasa/dialogue_understanding/commands/can_not_handle_command.py +38 -1
- rasa/dialogue_understanding/commands/cancel_flow_command.py +96 -9
- rasa/dialogue_understanding/commands/change_flow_command.py +36 -2
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +36 -4
- rasa/dialogue_understanding/commands/clarify_command.py +46 -4
- rasa/dialogue_understanding/commands/command.py +3 -2
- rasa/dialogue_understanding/commands/command_syntax_manager.py +55 -0
- rasa/dialogue_understanding/commands/correct_slots_command.py +14 -5
- rasa/dialogue_understanding/commands/error_command.py +1 -1
- rasa/dialogue_understanding/commands/free_form_answer_command.py +2 -1
- rasa/dialogue_understanding/commands/handle_code_change_command.py +2 -2
- rasa/dialogue_understanding/commands/handle_digressions_command.py +144 -0
- rasa/dialogue_understanding/commands/human_handoff_command.py +34 -4
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +36 -4
- rasa/dialogue_understanding/commands/noop_command.py +2 -1
- rasa/dialogue_understanding/commands/prompt_command.py +94 -0
- rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +34 -4
- rasa/dialogue_understanding/commands/restart_command.py +2 -5
- rasa/dialogue_understanding/commands/session_end_command.py +3 -5
- rasa/dialogue_understanding/commands/session_start_command.py +3 -5
- rasa/dialogue_understanding/commands/set_slot_command.py +55 -16
- rasa/dialogue_understanding/commands/skip_question_command.py +34 -4
- rasa/dialogue_understanding/commands/start_flow_command.py +78 -2
- rasa/dialogue_understanding/commands/user_silence_command.py +3 -5
- rasa/dialogue_understanding/commands/utils.py +126 -43
- rasa/dialogue_understanding/constants.py +2 -0
- rasa/dialogue_understanding/generator/__init__.py +2 -0
- rasa/dialogue_understanding/generator/command_generator.py +120 -79
- rasa/dialogue_understanding/generator/command_parser.py +245 -0
- rasa/dialogue_understanding/generator/constants.py +12 -4
- rasa/dialogue_understanding/generator/flow_retrieval.py +7 -7
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +187 -59
- rasa/dialogue_understanding/generator/llm_command_generator.py +6 -3
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +106 -110
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +53 -11
- rasa/dialogue_understanding/generator/prompt_templates/__init__.py +0 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +58 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +57 -0
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +574 -0
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +41 -386
- rasa/dialogue_understanding/generator/utils.py +76 -0
- rasa/dialogue_understanding/patterns/cancel.py +2 -1
- rasa/dialogue_understanding/patterns/cannot_handle.py +1 -0
- rasa/dialogue_understanding/patterns/chitchat.py +1 -1
- rasa/dialogue_understanding/patterns/clarify.py +2 -1
- rasa/dialogue_understanding/patterns/code_change.py +2 -0
- rasa/dialogue_understanding/patterns/collect_information.py +7 -4
- rasa/dialogue_understanding/patterns/completed.py +1 -1
- rasa/dialogue_understanding/patterns/continue_interrupted.py +1 -1
- rasa/dialogue_understanding/patterns/correction.py +17 -3
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +78 -2
- rasa/dialogue_understanding/patterns/handle_digressions.py +81 -0
- rasa/dialogue_understanding/patterns/human_handoff.py +1 -1
- rasa/dialogue_understanding/patterns/internal_error.py +1 -0
- rasa/dialogue_understanding/patterns/search.py +1 -1
- rasa/dialogue_understanding/patterns/session_start.py +1 -1
- rasa/dialogue_understanding/patterns/skip_question.py +1 -0
- rasa/dialogue_understanding/patterns/user_silence.py +1 -1
- rasa/dialogue_understanding/patterns/validate_slot.py +65 -0
- rasa/dialogue_understanding/processor/command_processor.py +193 -43
- rasa/dialogue_understanding/processor/command_processor_component.py +1 -1
- rasa/dialogue_understanding/stack/dialogue_stack.py +4 -3
- rasa/dialogue_understanding/stack/frames/__init__.py +2 -2
- rasa/dialogue_understanding/stack/frames/chit_chat_frame.py +4 -1
- rasa/dialogue_understanding/stack/frames/dialogue_stack_frame.py +2 -3
- rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +5 -2
- rasa/dialogue_understanding/stack/frames/search_frame.py +4 -1
- rasa/dialogue_understanding/stack/utils.py +56 -10
- rasa/dialogue_understanding/utils.py +164 -0
- rasa/dialogue_understanding_test/README.md +429 -0
- rasa/dialogue_understanding_test/__init__.py +0 -0
- rasa/dialogue_understanding_test/command_comparison.py +60 -0
- rasa/dialogue_understanding_test/command_metric_calculation.py +122 -0
- rasa/dialogue_understanding_test/constants.py +22 -0
- rasa/dialogue_understanding_test/du_test_case.py +448 -0
- rasa/dialogue_understanding_test/du_test_result.py +390 -0
- rasa/dialogue_understanding_test/du_test_runner.py +322 -0
- rasa/dialogue_understanding_test/du_test_schema.yml +161 -0
- rasa/dialogue_understanding_test/io.py +443 -0
- rasa/dialogue_understanding_test/test_case_simulation/__init__.py +0 -0
- rasa/dialogue_understanding_test/test_case_simulation/exception.py +28 -0
- rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +336 -0
- rasa/dialogue_understanding_test/utils.py +70 -0
- rasa/dialogue_understanding_test/validation.py +77 -0
- rasa/e2e_test/aggregate_test_stats_calculator.py +1 -1
- rasa/e2e_test/assertions.py +202 -175
- rasa/e2e_test/assertions_schema.yml +6 -0
- rasa/e2e_test/constants.py +16 -1
- rasa/e2e_test/e2e_config.py +102 -41
- rasa/e2e_test/e2e_config_schema.yml +28 -10
- rasa/e2e_test/e2e_test_case.py +5 -5
- rasa/e2e_test/e2e_test_converter.py +2 -3
- rasa/e2e_test/e2e_test_coverage_report.py +6 -6
- rasa/e2e_test/e2e_test_result.py +1 -1
- rasa/e2e_test/e2e_test_runner.py +143 -38
- rasa/e2e_test/llm_judge_prompts/answer_relevance_prompt_template.jinja2 +93 -0
- rasa/e2e_test/llm_judge_prompts/groundedness_prompt_template.jinja2 +169 -0
- rasa/e2e_test/stub_custom_action.py +1 -1
- rasa/e2e_test/utils/generative_assertions.py +243 -0
- rasa/e2e_test/utils/io.py +123 -93
- rasa/e2e_test/utils/validation.py +101 -3
- rasa/engine/caching.py +5 -7
- rasa/engine/constants.py +1 -1
- rasa/engine/graph.py +3 -2
- rasa/engine/language.py +182 -0
- rasa/engine/recipes/config_files/default_config.yml +4 -0
- rasa/engine/recipes/default_components.py +13 -15
- rasa/engine/recipes/default_recipe.py +65 -49
- rasa/engine/recipes/graph_recipe.py +10 -7
- rasa/engine/recipes/recipe.py +2 -2
- rasa/engine/runner/dask.py +2 -2
- rasa/engine/runner/interface.py +1 -0
- rasa/engine/storage/local_model_storage.py +6 -4
- rasa/engine/storage/resource.py +2 -1
- rasa/engine/storage/storage.py +8 -3
- rasa/engine/training/components.py +2 -1
- rasa/engine/training/fingerprinting.py +4 -2
- rasa/engine/training/graph_trainer.py +4 -4
- rasa/engine/training/hooks.py +2 -2
- rasa/engine/validation.py +36 -33
- rasa/exceptions.py +3 -2
- rasa/graph_components/converters/nlu_message_converter.py +3 -3
- rasa/graph_components/providers/domain_for_core_training_provider.py +3 -3
- rasa/graph_components/providers/domain_provider.py +3 -2
- rasa/graph_components/providers/flows_provider.py +2 -3
- rasa/graph_components/providers/forms_provider.py +4 -4
- rasa/graph_components/providers/nlu_training_data_provider.py +5 -3
- rasa/graph_components/providers/responses_provider.py +4 -4
- rasa/graph_components/providers/rule_only_provider.py +3 -2
- rasa/graph_components/providers/story_graph_provider.py +8 -8
- rasa/graph_components/providers/training_tracker_provider.py +3 -2
- rasa/graph_components/validators/default_recipe_validator.py +16 -16
- rasa/graph_components/validators/finetuning_validator.py +10 -8
- rasa/hooks.py +19 -14
- rasa/jupyter.py +2 -2
- rasa/llm_fine_tuning/annotation_module.py +4 -4
- rasa/llm_fine_tuning/conversations.py +5 -33
- rasa/llm_fine_tuning/llm_data_preparation_module.py +6 -4
- rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +4 -4
- rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +18 -13
- rasa/llm_fine_tuning/paraphrasing_module.py +6 -2
- rasa/llm_fine_tuning/storage.py +3 -3
- rasa/llm_fine_tuning/train_test_split_module.py +27 -27
- rasa/llm_fine_tuning/utils.py +7 -0
- rasa/markers/marker.py +2 -3
- rasa/markers/marker_base.py +1 -2
- rasa/markers/upload.py +2 -2
- rasa/markers/validate.py +2 -3
- rasa/model.py +3 -5
- rasa/model_manager/config.py +1 -1
- rasa/model_manager/model_api.py +5 -4
- rasa/model_manager/runner_service.py +13 -10
- rasa/model_manager/socket_bridge.py +15 -9
- rasa/model_manager/studio_jwt_auth.py +1 -0
- rasa/model_manager/trainer_service.py +9 -7
- rasa/model_manager/utils.py +1 -1
- rasa/model_manager/warm_rasa_process.py +14 -9
- rasa/model_service.py +5 -6
- rasa/model_testing.py +13 -15
- rasa/model_training.py +29 -29
- rasa/nlu/classifiers/diet_classifier.py +72 -73
- rasa/nlu/classifiers/fallback_classifier.py +9 -8
- rasa/nlu/classifiers/keyword_intent_classifier.py +7 -6
- rasa/nlu/classifiers/logistic_regression_classifier.py +3 -3
- rasa/nlu/classifiers/mitie_intent_classifier.py +5 -4
- rasa/nlu/classifiers/regex_message_handler.py +3 -2
- rasa/nlu/classifiers/sklearn_intent_classifier.py +2 -2
- rasa/nlu/convert.py +2 -2
- rasa/nlu/emulators/dialogflow.py +3 -3
- rasa/nlu/emulators/luis.py +5 -5
- rasa/nlu/emulators/no_emulator.py +1 -0
- rasa/nlu/emulators/wit.py +4 -4
- rasa/nlu/extractors/crf_entity_extractor.py +11 -11
- rasa/nlu/extractors/duckling_entity_extractor.py +7 -6
- rasa/nlu/extractors/entity_synonyms.py +10 -9
- rasa/nlu/extractors/extractor.py +16 -16
- rasa/nlu/extractors/mitie_entity_extractor.py +10 -9
- rasa/nlu/extractors/regex_entity_extractor.py +11 -10
- rasa/nlu/extractors/spacy_entity_extractor.py +2 -2
- rasa/nlu/featurizers/dense_featurizer/convert_featurizer.py +15 -14
- rasa/nlu/featurizers/dense_featurizer/dense_featurizer.py +2 -1
- rasa/nlu/featurizers/dense_featurizer/lm_featurizer.py +10 -9
- rasa/nlu/featurizers/dense_featurizer/mitie_featurizer.py +9 -7
- rasa/nlu/featurizers/dense_featurizer/spacy_featurizer.py +13 -12
- rasa/nlu/featurizers/featurizer.py +5 -4
- rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +6 -6
- rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +4 -4
- rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +4 -4
- rasa/nlu/featurizers/sparse_featurizer/sparse_featurizer.py +2 -0
- rasa/nlu/model.py +0 -1
- rasa/nlu/selectors/response_selector.py +67 -68
- rasa/nlu/test.py +38 -38
- rasa/nlu/tokenizers/jieba_tokenizer.py +1 -2
- rasa/nlu/tokenizers/mitie_tokenizer.py +2 -2
- rasa/nlu/tokenizers/spacy_tokenizer.py +3 -3
- rasa/nlu/tokenizers/tokenizer.py +6 -7
- rasa/nlu/tokenizers/whitespace_tokenizer.py +1 -1
- rasa/nlu/utils/bilou_utils.py +7 -7
- rasa/nlu/utils/hugging_face/registry.py +22 -22
- rasa/nlu/utils/hugging_face/transformers_pre_post_processors.py +2 -1
- rasa/nlu/utils/mitie_utils.py +2 -1
- rasa/nlu/utils/pattern_utils.py +1 -1
- rasa/nlu/utils/spacy_utils.py +3 -3
- rasa/plugin.py +12 -1
- rasa/server.py +6 -3
- rasa/shared/constants.py +45 -18
- rasa/shared/core/command_payload_reader.py +15 -7
- rasa/shared/core/constants.py +34 -4
- rasa/shared/core/conversation.py +1 -2
- rasa/shared/core/domain.py +19 -20
- rasa/shared/core/events.py +60 -39
- rasa/shared/core/flows/__init__.py +0 -1
- rasa/shared/core/flows/constants.py +11 -0
- rasa/shared/core/flows/flow.py +107 -26
- rasa/shared/core/flows/flow_step.py +4 -3
- rasa/shared/core/flows/flow_step_links.py +1 -2
- rasa/shared/core/flows/flow_step_sequence.py +1 -1
- rasa/shared/core/flows/flows_list.py +3 -3
- rasa/shared/core/flows/flows_yaml_schema.json +69 -3
- rasa/shared/core/flows/nlu_trigger.py +1 -1
- rasa/shared/core/flows/steps/__init__.py +2 -2
- rasa/shared/core/flows/steps/action.py +1 -1
- rasa/shared/core/flows/steps/call.py +1 -1
- rasa/shared/core/flows/steps/collect.py +22 -40
- rasa/shared/core/flows/steps/internal.py +1 -1
- rasa/shared/core/flows/steps/link.py +1 -1
- rasa/shared/core/flows/steps/no_operation.py +2 -2
- rasa/shared/core/flows/steps/set_slots.py +1 -1
- rasa/shared/core/flows/utils.py +44 -4
- rasa/shared/core/flows/validation.py +4 -6
- rasa/shared/core/generator.py +20 -21
- rasa/shared/core/slot_mappings.py +360 -121
- rasa/shared/core/slots.py +163 -6
- rasa/shared/core/trackers.py +108 -33
- rasa/shared/core/training_data/loading.py +1 -1
- rasa/shared/core/training_data/story_reader/story_reader.py +3 -3
- rasa/shared/core/training_data/story_reader/story_step_builder.py +4 -4
- rasa/shared/core/training_data/story_reader/yaml_story_reader.py +29 -31
- rasa/shared/core/training_data/story_writer/yaml_story_writer.py +22 -24
- rasa/shared/core/training_data/structures.py +11 -12
- rasa/shared/core/training_data/visualization.py +10 -10
- rasa/shared/data.py +6 -6
- rasa/shared/engine/caching.py +0 -1
- rasa/shared/exceptions.py +2 -2
- rasa/shared/importers/importer.py +58 -2
- rasa/shared/importers/rasa.py +5 -6
- rasa/shared/importers/utils.py +1 -1
- rasa/shared/nlu/constants.py +9 -0
- rasa/shared/nlu/training_data/entities_parser.py +6 -6
- rasa/shared/nlu/training_data/features.py +3 -3
- rasa/shared/nlu/training_data/formats/__init__.py +1 -1
- rasa/shared/nlu/training_data/formats/dialogflow.py +4 -5
- rasa/shared/nlu/training_data/formats/luis.py +7 -8
- rasa/shared/nlu/training_data/formats/rasa.py +4 -5
- rasa/shared/nlu/training_data/formats/rasa_yaml.py +17 -16
- rasa/shared/nlu/training_data/formats/readerwriter.py +8 -11
- rasa/shared/nlu/training_data/formats/wit.py +3 -4
- rasa/shared/nlu/training_data/loading.py +4 -4
- rasa/shared/nlu/training_data/lookup_tables_parser.py +1 -1
- rasa/shared/nlu/training_data/message.py +13 -14
- rasa/shared/nlu/training_data/schemas/data_schema.py +1 -1
- rasa/shared/nlu/training_data/schemas/responses.yml +19 -11
- rasa/shared/nlu/training_data/synonyms_parser.py +3 -3
- rasa/shared/nlu/training_data/training_data.py +12 -13
- rasa/shared/nlu/training_data/util.py +11 -10
- rasa/shared/providers/_configs/azure_entra_id_config.py +541 -0
- rasa/shared/providers/_configs/azure_openai_client_config.py +150 -15
- rasa/shared/providers/_configs/client_config.py +3 -1
- rasa/shared/providers/_configs/default_litellm_client_config.py +9 -7
- rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +13 -11
- rasa/shared/providers/_configs/litellm_router_client_config.py +12 -10
- rasa/shared/providers/_configs/model_group_config.py +8 -5
- rasa/shared/providers/_configs/oauth_config.py +33 -0
- rasa/shared/providers/_configs/openai_client_config.py +14 -12
- rasa/shared/providers/_configs/rasa_llm_client_config.py +5 -3
- rasa/shared/providers/_configs/self_hosted_llm_client_config.py +12 -11
- rasa/shared/providers/_configs/utils.py +1 -0
- rasa/shared/providers/_ssl_verification_utils.py +5 -6
- rasa/shared/providers/_utils.py +5 -5
- rasa/shared/providers/constants.py +6 -0
- rasa/shared/providers/embedding/_base_litellm_embedding_client.py +1 -1
- rasa/shared/providers/embedding/azure_openai_embedding_client.py +32 -7
- rasa/shared/providers/embedding/embedding_client.py +1 -1
- rasa/shared/providers/embedding/litellm_router_embedding_client.py +5 -2
- rasa/shared/providers/llm/_base_litellm_client.py +43 -18
- rasa/shared/providers/llm/azure_openai_llm_client.py +90 -34
- rasa/shared/providers/llm/default_litellm_llm_client.py +4 -2
- rasa/shared/providers/llm/litellm_router_llm_client.py +32 -9
- rasa/shared/providers/llm/llm_client.py +24 -8
- rasa/shared/providers/llm/llm_response.py +61 -2
- rasa/shared/providers/llm/openai_llm_client.py +11 -5
- rasa/shared/providers/llm/rasa_llm_client.py +17 -14
- rasa/shared/providers/llm/self_hosted_llm_client.py +35 -15
- rasa/shared/providers/mappings.py +18 -19
- rasa/shared/providers/router/_base_litellm_router_client.py +48 -15
- rasa/shared/providers/router/router_client.py +3 -1
- rasa/shared/utils/cli.py +1 -1
- rasa/shared/utils/common.py +15 -1
- rasa/shared/utils/constants.py +3 -0
- rasa/shared/utils/health_check/embeddings_health_check_mixin.py +1 -1
- rasa/shared/utils/health_check/health_check.py +3 -3
- rasa/shared/utils/health_check/llm_health_check_mixin.py +1 -1
- rasa/shared/utils/io.py +1 -1
- rasa/shared/utils/llm.py +100 -18
- rasa/shared/utils/pykwalify_extensions.py +25 -1
- rasa/shared/utils/schemas/domain.yml +26 -1
- rasa/shared/utils/schemas/events.py +1 -1
- rasa/shared/utils/yaml.py +24 -20
- rasa/studio/auth.py +3 -3
- rasa/studio/config.py +1 -2
- rasa/studio/data_handler.py +3 -3
- rasa/studio/download.py +1 -1
- rasa/studio/results_logger.py +3 -3
- rasa/studio/upload.py +21 -5
- rasa/telemetry.py +127 -48
- rasa/tracing/config.py +5 -3
- rasa/tracing/constants.py +12 -0
- rasa/tracing/instrumentation/attribute_extractors.py +92 -14
- rasa/tracing/instrumentation/instrumentation.py +61 -5
- rasa/tracing/instrumentation/intentless_policy_instrumentation.py +1 -1
- rasa/tracing/instrumentation/metrics.py +52 -11
- rasa/tracing/metric_instrument_provider.py +54 -14
- rasa/utils/common.py +12 -24
- rasa/utils/endpoints.py +1 -1
- rasa/utils/io.py +7 -7
- rasa/utils/licensing.py +3 -4
- rasa/utils/log_utils.py +7 -6
- rasa/utils/ml_utils.py +1 -0
- rasa/utils/plotting.py +3 -3
- rasa/utils/sanic_error_handler.py +1 -1
- rasa/utils/tensorflow/callback.py +2 -2
- rasa/utils/tensorflow/crf.py +2 -2
- rasa/utils/tensorflow/data_generator.py +5 -5
- rasa/utils/tensorflow/environment.py +3 -3
- rasa/utils/tensorflow/feature_array.py +2 -3
- rasa/utils/tensorflow/layers.py +18 -12
- rasa/utils/tensorflow/layers_utils.py +2 -1
- rasa/utils/tensorflow/metrics.py +2 -2
- rasa/utils/tensorflow/model_data.py +7 -7
- rasa/utils/tensorflow/model_data_utils.py +10 -9
- rasa/utils/tensorflow/models.py +31 -32
- rasa/utils/tensorflow/rasa_layers.py +20 -19
- rasa/utils/tensorflow/types.py +2 -1
- rasa/utils/train_utils.py +23 -21
- rasa/utils/url_tools.py +1 -1
- rasa/validator.py +594 -115
- rasa/version.py +1 -1
- {rasa_pro-3.11.4.dist-info → rasa_pro-3.12.0.dist-info}/METADATA +23 -26
- rasa_pro-3.12.0.dist-info/RECORD +829 -0
- rasa/core/channels/inspector/dist/assets/arc-632a63ec.js +0 -1
- rasa/core/channels/inspector/dist/assets/c4Diagram-d0fbc5ce-081e0df4.js +0 -10
- rasa/core/channels/inspector/dist/assets/classDiagram-936ed81e-3df0afc2.js +0 -2
- rasa/core/channels/inspector/dist/assets/classDiagram-v2-c3cb15f1-8c5ed31e.js +0 -2
- rasa/core/channels/inspector/dist/assets/edges-f2ad444c-4fc48c3e.js +0 -4
- rasa/core/channels/inspector/dist/assets/flowDb-1972c806-9ec53a3c.js +0 -6
- rasa/core/channels/inspector/dist/assets/flowDiagram-7ea5b25a-41da787a.js +0 -4
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-8bea338b.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowchart-elk-definition-abe16c3d-ce370633.js +0 -139
- rasa/core/channels/inspector/dist/assets/ganttDiagram-9b5ea136-90a36523.js +0 -266
- rasa/core/channels/inspector/dist/assets/gitGraphDiagram-99d0ae7c-41e1aa3f.js +0 -70
- rasa/core/channels/inspector/dist/assets/index-2c4b9a3b-e6f2af62.js +0 -1
- rasa/core/channels/inspector/dist/assets/layout-498807d8.js +0 -1
- rasa/core/channels/inspector/dist/assets/linear-8a078617.js +0 -1
- rasa/core/channels/inspector/dist/assets/mindmap-definition-beec6740-396d17dd.js +0 -109
- rasa/core/channels/inspector/dist/assets/sankeyDiagram-8f13d901-53f6f391.js +0 -8
- rasa/core/channels/inspector/dist/assets/sequenceDiagram-b655622a-715c9c20.js +0 -122
- rasa/core/channels/inspector/dist/assets/stateDiagram-59f0c015-2e8fb31f.js +0 -1
- rasa/core/channels/inspector/dist/assets/stateDiagram-v2-2b26beab-7e2d2aa0.js +0 -1
- rasa/core/channels/inspector/dist/assets/styles-080da4f6-4420cea6.js +0 -110
- rasa/core/channels/inspector/dist/assets/styles-3dcbcfbf-28676cf4.js +0 -159
- rasa/core/channels/inspector/dist/assets/svgDrawCommon-4835440b-151251e9.js +0 -1
- rasa_pro-3.11.4.dist-info/RECORD +0 -779
- /rasa/dialogue_understanding/generator/{single_step → prompt_templates}/command_prompt_template.jinja2 +0 -0
- {rasa_pro-3.11.4.dist-info → rasa_pro-3.12.0.dist-info}/NOTICE +0 -0
- {rasa_pro-3.11.4.dist-info → rasa_pro-3.12.0.dist-info}/WHEEL +0 -0
- {rasa_pro-3.11.4.dist-info → rasa_pro-3.12.0.dist-info}/entry_points.txt +0 -0
rasa/validator.py
CHANGED
|
@@ -3,70 +3,84 @@ import re
|
|
|
3
3
|
import string
|
|
4
4
|
import sys
|
|
5
5
|
from collections import defaultdict
|
|
6
|
-
from typing import
|
|
6
|
+
from typing import Any, Dict, List, Optional, Set, Text, Tuple
|
|
7
7
|
|
|
8
8
|
import structlog
|
|
9
9
|
from jinja2 import Template
|
|
10
10
|
from pypred import Predicate
|
|
11
|
-
from pypred.ast import
|
|
11
|
+
from pypred.ast import CompareOperator, Literal, NegateOperator
|
|
12
12
|
|
|
13
13
|
import rasa.core.training.story_conflict
|
|
14
|
+
import rasa.shared.nlu.constants
|
|
15
|
+
import rasa.shared.utils.cli
|
|
16
|
+
import rasa.shared.utils.io
|
|
14
17
|
from rasa.core.channels import UserMessage
|
|
15
18
|
from rasa.dialogue_understanding.stack.frames import PatternFlowStackFrame
|
|
16
|
-
from rasa.
|
|
17
|
-
CommandPayloadReader,
|
|
18
|
-
MAX_NUMBER_OF_SLOTS,
|
|
19
|
-
)
|
|
20
|
-
from rasa.shared.core.flows.flow_step_links import IfFlowStepLink
|
|
21
|
-
from rasa.shared.core.flows.steps.set_slots import SetSlotsFlowStep
|
|
22
|
-
from rasa.shared.core.flows.steps.collect import CollectInformationFlowStep
|
|
23
|
-
from rasa.shared.core.flows.steps.action import ActionFlowStep
|
|
24
|
-
from rasa.shared.core.flows.steps.link import LinkFlowStep
|
|
25
|
-
from rasa.shared.core.flows import FlowsList
|
|
26
|
-
from rasa.shared.core.flows.utils import (
|
|
27
|
-
warn_deprecated_collect_step_config,
|
|
28
|
-
get_duplicate_slot_persistence_config_error_message,
|
|
29
|
-
get_invalid_slot_persistence_config_error_message,
|
|
30
|
-
)
|
|
31
|
-
import rasa.shared.nlu.constants
|
|
19
|
+
from rasa.engine.language import Language
|
|
32
20
|
from rasa.shared.constants import (
|
|
33
21
|
ASSISTANT_ID_DEFAULT_VALUE,
|
|
34
22
|
ASSISTANT_ID_KEY,
|
|
23
|
+
CONFIG_ADDITIONAL_LANGUAGES_KEY,
|
|
24
|
+
CONFIG_LANGUAGE_KEY,
|
|
35
25
|
CONFIG_MANDATORY_KEYS,
|
|
26
|
+
CONFIG_PIPELINE_KEY,
|
|
27
|
+
DOCS_URL_ACTIONS,
|
|
36
28
|
DOCS_URL_DOMAIN,
|
|
37
29
|
DOCS_URL_DOMAINS,
|
|
38
30
|
DOCS_URL_FORMS,
|
|
39
31
|
DOCS_URL_RESPONSES,
|
|
40
|
-
UTTER_PREFIX,
|
|
41
|
-
DOCS_URL_ACTIONS,
|
|
42
32
|
REQUIRED_SLOTS_KEY,
|
|
33
|
+
RESPONSE_CONDITION,
|
|
34
|
+
UTTER_PREFIX,
|
|
43
35
|
)
|
|
44
36
|
from rasa.shared.core import constants
|
|
45
|
-
from rasa.shared.core.
|
|
46
|
-
|
|
47
|
-
|
|
37
|
+
from rasa.shared.core.command_payload_reader import (
|
|
38
|
+
MAX_NUMBER_OF_SLOTS,
|
|
39
|
+
CommandPayloadReader,
|
|
40
|
+
)
|
|
41
|
+
from rasa.shared.core.constants import (
|
|
42
|
+
KEY_ALLOW_NLU_CORRECTION,
|
|
43
|
+
SLOTS,
|
|
44
|
+
SlotMappingType,
|
|
45
|
+
)
|
|
48
46
|
from rasa.shared.core.domain import (
|
|
49
|
-
Domain,
|
|
50
47
|
RESPONSE_KEYS_TO_INTERPOLATE,
|
|
48
|
+
Domain,
|
|
49
|
+
)
|
|
50
|
+
from rasa.shared.core.events import ActionExecuted, ActiveLoop, UserUttered
|
|
51
|
+
from rasa.shared.core.flows import Flow, FlowsList
|
|
52
|
+
from rasa.shared.core.flows.constants import KEY_NAME, KEY_TRANSLATION
|
|
53
|
+
from rasa.shared.core.flows.flow_step_links import IfFlowStepLink
|
|
54
|
+
from rasa.shared.core.flows.steps.action import ActionFlowStep
|
|
55
|
+
from rasa.shared.core.flows.steps.collect import CollectInformationFlowStep
|
|
56
|
+
from rasa.shared.core.flows.steps.link import LinkFlowStep
|
|
57
|
+
from rasa.shared.core.flows.steps.set_slots import SetSlotsFlowStep
|
|
58
|
+
from rasa.shared.core.flows.utils import (
|
|
59
|
+
ALL_LABEL,
|
|
60
|
+
get_duplicate_slot_persistence_config_error_message,
|
|
61
|
+
get_invalid_slot_persistence_config_error_message,
|
|
62
|
+
warn_deprecated_collect_step_config,
|
|
51
63
|
)
|
|
52
64
|
from rasa.shared.core.generator import TrainingDataGenerator
|
|
53
|
-
from rasa.shared.core.
|
|
65
|
+
from rasa.shared.core.slot_mappings import CoexistenceSystemType
|
|
54
66
|
from rasa.shared.core.slots import BooleanSlot, CategoricalSlot, ListSlot, Slot
|
|
55
67
|
from rasa.shared.core.training_data.story_reader.yaml_story_reader import (
|
|
56
68
|
YAMLStoryReader,
|
|
57
69
|
)
|
|
58
70
|
from rasa.shared.core.training_data.structures import StoryGraph
|
|
59
71
|
from rasa.shared.data import create_regex_pattern_reader
|
|
72
|
+
from rasa.shared.exceptions import RasaException
|
|
60
73
|
from rasa.shared.importers.importer import TrainingDataImporter
|
|
61
74
|
from rasa.shared.nlu.constants import COMMANDS
|
|
62
75
|
from rasa.shared.nlu.training_data.message import Message
|
|
63
76
|
from rasa.shared.nlu.training_data.training_data import TrainingData
|
|
64
|
-
|
|
65
|
-
import rasa.shared.utils.cli
|
|
66
|
-
import rasa.shared.utils.io
|
|
77
|
+
from rasa.telemetry import track_validation_error_log
|
|
67
78
|
|
|
68
79
|
logger = logging.getLogger(__name__)
|
|
69
|
-
|
|
80
|
+
|
|
81
|
+
structlog_processors = structlog.get_config()["processors"]
|
|
82
|
+
updated_processors = [track_validation_error_log] + structlog_processors
|
|
83
|
+
structlogger = structlog.get_logger(processors=updated_processors)
|
|
70
84
|
|
|
71
85
|
|
|
72
86
|
class Validator:
|
|
@@ -511,9 +525,9 @@ class Validator:
|
|
|
511
525
|
|
|
512
526
|
for slot in self.domain.slots:
|
|
513
527
|
for mapping in slot.mappings:
|
|
514
|
-
for condition in mapping.
|
|
515
|
-
condition_active_loop = condition.
|
|
516
|
-
mapping_type =
|
|
528
|
+
for condition in mapping.conditions:
|
|
529
|
+
condition_active_loop = condition.active_loop
|
|
530
|
+
mapping_type = mapping.type
|
|
517
531
|
if (
|
|
518
532
|
condition_active_loop
|
|
519
533
|
and condition_active_loop not in self.domain.form_names
|
|
@@ -901,6 +915,16 @@ class Validator:
|
|
|
901
915
|
f"'{object_id}': {exception}"
|
|
902
916
|
),
|
|
903
917
|
)
|
|
918
|
+
elif object_id.startswith("utter_"):
|
|
919
|
+
structlogger.error(
|
|
920
|
+
"validator.validate_conditional_response_variation_predicates.error",
|
|
921
|
+
utter=object_id,
|
|
922
|
+
exception=exception,
|
|
923
|
+
event_info=(
|
|
924
|
+
f"Could not initialize the predicate found under response "
|
|
925
|
+
f"variation '{object_id}': {exception}"
|
|
926
|
+
),
|
|
927
|
+
)
|
|
904
928
|
else:
|
|
905
929
|
structlogger.error(
|
|
906
930
|
"validator.verify_predicates.flow_guard_predicate.error",
|
|
@@ -932,7 +956,7 @@ class Validator:
|
|
|
932
956
|
def _extract_slot_name_and_slot_value(
|
|
933
957
|
self,
|
|
934
958
|
predicate_syntax_tree: Any,
|
|
935
|
-
) ->
|
|
959
|
+
) -> Tuple[Optional[List[str]], Optional[Any]]:
|
|
936
960
|
"""Extract the slot name and slot value from the predicate syntax tree.
|
|
937
961
|
|
|
938
962
|
Args:
|
|
@@ -1037,15 +1061,15 @@ class Validator:
|
|
|
1037
1061
|
False, if validation failed, previous value of all_good, otherwise
|
|
1038
1062
|
"""
|
|
1039
1063
|
predicate_syntax_tree = self._extract_predicate_syntax_tree(predicate)
|
|
1040
|
-
|
|
1064
|
+
slot_namespace, slot_value = self._extract_slot_name_and_slot_value(
|
|
1041
1065
|
predicate_syntax_tree
|
|
1042
1066
|
)
|
|
1043
1067
|
|
|
1044
|
-
if
|
|
1068
|
+
if slot_namespace is None:
|
|
1045
1069
|
return all_good
|
|
1046
1070
|
|
|
1047
|
-
if
|
|
1048
|
-
slot_name =
|
|
1071
|
+
if slot_namespace[0] == "slots":
|
|
1072
|
+
slot_name = slot_namespace[1]
|
|
1049
1073
|
# slots.{{context.variable}} gets evaluated to `slots.None`,
|
|
1050
1074
|
# these predicates can only be validated during runtime
|
|
1051
1075
|
if slot_name == "None":
|
|
@@ -1257,6 +1281,7 @@ class Validator:
|
|
|
1257
1281
|
self.verify_unique_flows(),
|
|
1258
1282
|
self.verify_predicates(),
|
|
1259
1283
|
self.verify_slot_persistence_configuration(),
|
|
1284
|
+
self.verify_digression_configuration(),
|
|
1260
1285
|
]
|
|
1261
1286
|
|
|
1262
1287
|
all_good = all(flow_validation_conditions)
|
|
@@ -1265,6 +1290,165 @@ class Validator:
|
|
|
1265
1290
|
|
|
1266
1291
|
return all_good
|
|
1267
1292
|
|
|
1293
|
+
def _get_response_translation_warnings(self) -> list:
|
|
1294
|
+
"""Collect warnings for responses missing translations.
|
|
1295
|
+
|
|
1296
|
+
Returns:
|
|
1297
|
+
List of warnings for responses missing translations.
|
|
1298
|
+
"""
|
|
1299
|
+
additional_languages = self.config.get(CONFIG_ADDITIONAL_LANGUAGES_KEY) or []
|
|
1300
|
+
response_warnings = []
|
|
1301
|
+
|
|
1302
|
+
for response_name, responses in self.domain.responses.items():
|
|
1303
|
+
provided_languages = set()
|
|
1304
|
+
# For each response variation, we check if the additional
|
|
1305
|
+
# languages are available in at least on variation
|
|
1306
|
+
for response in responses:
|
|
1307
|
+
translation = response.get(KEY_TRANSLATION) or {}
|
|
1308
|
+
for language_code in additional_languages:
|
|
1309
|
+
if translation.get(language_code):
|
|
1310
|
+
provided_languages.add(language_code)
|
|
1311
|
+
|
|
1312
|
+
missing_languages = [
|
|
1313
|
+
lang for lang in additional_languages if lang not in provided_languages
|
|
1314
|
+
]
|
|
1315
|
+
if missing_languages:
|
|
1316
|
+
language_code_str = ", ".join(missing_languages)
|
|
1317
|
+
response_warnings.append(
|
|
1318
|
+
{
|
|
1319
|
+
"event": (
|
|
1320
|
+
"validator.verify_translations.missing_response_translation"
|
|
1321
|
+
),
|
|
1322
|
+
"response": response_name,
|
|
1323
|
+
"missing_languages": missing_languages,
|
|
1324
|
+
"event_info": (
|
|
1325
|
+
f"The response '{response_name}' is "
|
|
1326
|
+
f"missing a translation for the following "
|
|
1327
|
+
f"languages: {language_code_str}."
|
|
1328
|
+
),
|
|
1329
|
+
}
|
|
1330
|
+
)
|
|
1331
|
+
return response_warnings
|
|
1332
|
+
|
|
1333
|
+
def _get_flow_translation_warnings(self) -> list:
|
|
1334
|
+
"""Collect warnings for flows missing translations.
|
|
1335
|
+
|
|
1336
|
+
Returns:
|
|
1337
|
+
List of warnings for flows missing translations.
|
|
1338
|
+
"""
|
|
1339
|
+
additional_languages = self.config.get(CONFIG_ADDITIONAL_LANGUAGES_KEY) or []
|
|
1340
|
+
|
|
1341
|
+
flow_warnings = []
|
|
1342
|
+
for flow in self.flows.underlying_flows:
|
|
1343
|
+
required_field_translation = [KEY_NAME]
|
|
1344
|
+
missing_languages = []
|
|
1345
|
+
for language_code in additional_languages:
|
|
1346
|
+
translation = flow.translation.get(language_code)
|
|
1347
|
+
# If translation for the language code doesn't exist,
|
|
1348
|
+
# or the required fields are not set properly,
|
|
1349
|
+
# we add the language code to the list.
|
|
1350
|
+
if not translation or not all(
|
|
1351
|
+
getattr(translation, field, None)
|
|
1352
|
+
for field in required_field_translation
|
|
1353
|
+
):
|
|
1354
|
+
missing_languages.append(language_code)
|
|
1355
|
+
|
|
1356
|
+
if missing_languages:
|
|
1357
|
+
language_code_str = ", ".join(missing_languages)
|
|
1358
|
+
flow_warnings.append(
|
|
1359
|
+
{
|
|
1360
|
+
"event": (
|
|
1361
|
+
"validator.verify_translations.missing_flow_translation"
|
|
1362
|
+
),
|
|
1363
|
+
"flow": flow.id,
|
|
1364
|
+
"missing_languages": missing_languages,
|
|
1365
|
+
"event_info": (
|
|
1366
|
+
f"The flow '{flow.id}' is missing the translation for "
|
|
1367
|
+
f"the following languages: {language_code_str}."
|
|
1368
|
+
),
|
|
1369
|
+
}
|
|
1370
|
+
)
|
|
1371
|
+
return flow_warnings
|
|
1372
|
+
|
|
1373
|
+
def verify_config_language(self) -> bool:
|
|
1374
|
+
"""Verify that config languages are properly set up.
|
|
1375
|
+
|
|
1376
|
+
Returns:
|
|
1377
|
+
`True` if all languages are properly set up, `False` otherwise.
|
|
1378
|
+
|
|
1379
|
+
Raises:
|
|
1380
|
+
RasaException: If the default language is listed as an
|
|
1381
|
+
additional language or if the language code is invalid.
|
|
1382
|
+
"""
|
|
1383
|
+
language = self.config.get(CONFIG_LANGUAGE_KEY)
|
|
1384
|
+
additional_languages = self.config.get(CONFIG_ADDITIONAL_LANGUAGES_KEY, [])
|
|
1385
|
+
|
|
1386
|
+
# Check if the default language is in the additional languages.
|
|
1387
|
+
if language in additional_languages:
|
|
1388
|
+
raise RasaException(
|
|
1389
|
+
f"The default language '{language}' is listed as an additional "
|
|
1390
|
+
f"language in the configuration file. Please remove it from "
|
|
1391
|
+
f"the list of additional languages."
|
|
1392
|
+
)
|
|
1393
|
+
|
|
1394
|
+
# Verify the language codes by initializing the Language class.
|
|
1395
|
+
for language_code in [language] + additional_languages:
|
|
1396
|
+
Language.from_language_code(language_code=language_code)
|
|
1397
|
+
|
|
1398
|
+
return True
|
|
1399
|
+
|
|
1400
|
+
def verify_translations(self, summary_mode: bool = False) -> bool:
|
|
1401
|
+
"""Checks for inconsistencies in translations.
|
|
1402
|
+
|
|
1403
|
+
Args:
|
|
1404
|
+
summary_mode: If True, logs a single aggregated warning per category;
|
|
1405
|
+
otherwise, logs each warning individually.
|
|
1406
|
+
|
|
1407
|
+
Returns:
|
|
1408
|
+
`True` if no inconsistencies were found, `False` otherwise.
|
|
1409
|
+
|
|
1410
|
+
Raises:
|
|
1411
|
+
Warning: Single warning per response or flow missing translations
|
|
1412
|
+
if `summary_mode` is `True`, otherwise one warning per missing translation.
|
|
1413
|
+
"""
|
|
1414
|
+
all_good = self.verify_config_language()
|
|
1415
|
+
|
|
1416
|
+
additional_languages = self.config.get(CONFIG_ADDITIONAL_LANGUAGES_KEY, [])
|
|
1417
|
+
if not additional_languages:
|
|
1418
|
+
return all_good
|
|
1419
|
+
|
|
1420
|
+
response_warnings = self._get_response_translation_warnings()
|
|
1421
|
+
flow_warnings = self._get_flow_translation_warnings()
|
|
1422
|
+
|
|
1423
|
+
if summary_mode:
|
|
1424
|
+
if response_warnings:
|
|
1425
|
+
count = len(response_warnings)
|
|
1426
|
+
structlogger.warn(
|
|
1427
|
+
"validator.verify_translations.missing_response_translation_summary",
|
|
1428
|
+
count=count,
|
|
1429
|
+
event_info=(
|
|
1430
|
+
f"{count} response{' is' if count == 1 else 's are'} "
|
|
1431
|
+
f"missing translations for some languages. "
|
|
1432
|
+
"Run 'rasa data validate translations' for details."
|
|
1433
|
+
),
|
|
1434
|
+
)
|
|
1435
|
+
if flow_warnings:
|
|
1436
|
+
count = len(flow_warnings)
|
|
1437
|
+
structlogger.warn(
|
|
1438
|
+
"validator.verify_translations.missing_flow_translation_summary",
|
|
1439
|
+
count=count,
|
|
1440
|
+
event_info=(
|
|
1441
|
+
f"{count} flow{' is' if count == 1 else 's are'} "
|
|
1442
|
+
f"missing translations for some languages. "
|
|
1443
|
+
"Run 'rasa data validate translations' for details."
|
|
1444
|
+
),
|
|
1445
|
+
)
|
|
1446
|
+
else:
|
|
1447
|
+
for warning in response_warnings + flow_warnings:
|
|
1448
|
+
structlogger.warn(**warning)
|
|
1449
|
+
|
|
1450
|
+
return all_good
|
|
1451
|
+
|
|
1268
1452
|
def validate_button_payloads(self) -> bool:
|
|
1269
1453
|
"""Check if the response button payloads are valid."""
|
|
1270
1454
|
all_good = True
|
|
@@ -1385,36 +1569,26 @@ class Validator:
|
|
|
1385
1569
|
|
|
1386
1570
|
for slot in self.domain._user_slots:
|
|
1387
1571
|
nlu_mappings = any(
|
|
1388
|
-
[
|
|
1389
|
-
SlotMappingType(
|
|
1390
|
-
mapping.get("type", SlotMappingType.FROM_LLM.value)
|
|
1391
|
-
).is_predefined_type()
|
|
1392
|
-
for mapping in slot.mappings
|
|
1393
|
-
]
|
|
1572
|
+
[mapping.type.is_predefined_type() for mapping in slot.mappings]
|
|
1394
1573
|
)
|
|
1395
1574
|
llm_mappings = any(
|
|
1396
|
-
[
|
|
1397
|
-
SlotMappingType(mapping.get("type", SlotMappingType.FROM_LLM.value))
|
|
1398
|
-
== SlotMappingType.FROM_LLM
|
|
1399
|
-
for mapping in slot.mappings
|
|
1400
|
-
]
|
|
1575
|
+
[mapping.type == SlotMappingType.FROM_LLM for mapping in slot.mappings]
|
|
1401
1576
|
)
|
|
1402
|
-
|
|
1577
|
+
controlled_mappings = any(
|
|
1403
1578
|
[
|
|
1404
|
-
|
|
1405
|
-
== SlotMappingType.CUSTOM
|
|
1579
|
+
mapping.type == SlotMappingType.CONTROLLED
|
|
1406
1580
|
for mapping in slot.mappings
|
|
1407
1581
|
]
|
|
1408
1582
|
)
|
|
1409
1583
|
|
|
1410
|
-
all_good = self.
|
|
1411
|
-
llm_mappings, nlu_mappings, custom_mappings, slot.name, all_good
|
|
1412
|
-
)
|
|
1584
|
+
all_good = self._allow_nlu_correction_is_valid(slot, nlu_mappings, all_good)
|
|
1413
1585
|
|
|
1414
1586
|
all_good = self._custom_action_name_is_defined_in_the_domain(
|
|
1415
|
-
|
|
1587
|
+
controlled_mappings, slot, all_good
|
|
1416
1588
|
)
|
|
1417
1589
|
|
|
1590
|
+
all_good = self._validate_controlled_mappings(slot, all_good)
|
|
1591
|
+
|
|
1418
1592
|
all_good = self._config_contains_nlu_command_adapter(
|
|
1419
1593
|
nlu_mappings, slot.name, all_good
|
|
1420
1594
|
)
|
|
@@ -1426,23 +1600,45 @@ class Validator:
|
|
|
1426
1600
|
return all_good
|
|
1427
1601
|
|
|
1428
1602
|
@staticmethod
|
|
1429
|
-
def
|
|
1430
|
-
|
|
1431
|
-
nlu_mappings: bool,
|
|
1432
|
-
custom_mappings: bool,
|
|
1433
|
-
slot_name: str,
|
|
1434
|
-
all_good: bool,
|
|
1603
|
+
def _allow_nlu_correction_is_valid(
|
|
1604
|
+
slot: Slot, nlu_mappings: bool, all_good: bool
|
|
1435
1605
|
) -> bool:
|
|
1436
|
-
|
|
1606
|
+
"""Verify that `allow_nlu_correction` property is used correctly in a `from_llm` mappings only.""" # noqa: E501
|
|
1607
|
+
if not slot.mappings:
|
|
1608
|
+
return all_good
|
|
1609
|
+
|
|
1610
|
+
invalid_usage = False
|
|
1611
|
+
|
|
1612
|
+
for mapping in slot.mappings:
|
|
1613
|
+
allow_nlu_correction = mapping.allow_nlu_correction
|
|
1614
|
+
if allow_nlu_correction and mapping.type != SlotMappingType.FROM_LLM:
|
|
1615
|
+
invalid_usage = True
|
|
1616
|
+
|
|
1617
|
+
if allow_nlu_correction and not nlu_mappings:
|
|
1618
|
+
structlogger.error(
|
|
1619
|
+
"validator.validate_slot_mappings_in_CALM.nlu_mappings_not_present",
|
|
1620
|
+
slot_name=slot.name,
|
|
1621
|
+
event_info=(
|
|
1622
|
+
f"The slot '{slot.name}' does not have any "
|
|
1623
|
+
f"NLU-based slot mappings. "
|
|
1624
|
+
f"The property `allow_nlu_correction` is only "
|
|
1625
|
+
f"applicable when the slot "
|
|
1626
|
+
f"contains both NLU-based and LLM-based slot mappings."
|
|
1627
|
+
),
|
|
1628
|
+
)
|
|
1629
|
+
all_good = False
|
|
1630
|
+
|
|
1631
|
+
if invalid_usage:
|
|
1437
1632
|
structlogger.error(
|
|
1438
|
-
"validator.validate_slot_mappings_in_CALM.
|
|
1439
|
-
slot_name=
|
|
1633
|
+
"validator.validate_slot_mappings_in_CALM.allow_nlu_correction",
|
|
1634
|
+
slot_name=slot.name,
|
|
1440
1635
|
event_info=(
|
|
1441
|
-
f"The slot '{
|
|
1442
|
-
f"
|
|
1443
|
-
f"
|
|
1636
|
+
f"The slot '{slot.name}' has at least 1 slot mapping with "
|
|
1637
|
+
f"'{KEY_ALLOW_NLU_CORRECTION}' set to 'true', but "
|
|
1638
|
+
f"the slot mapping type is not 'from_llm'. "
|
|
1639
|
+
f"Please set the slot mapping type to 'from_llm' "
|
|
1640
|
+
f"to allow the LLM to correct this slot."
|
|
1444
1641
|
),
|
|
1445
|
-
docs_link=DOCS_URL_DOMAIN + "#calm-slot-mappings",
|
|
1446
1642
|
)
|
|
1447
1643
|
all_good = False
|
|
1448
1644
|
|
|
@@ -1450,55 +1646,32 @@ class Validator:
|
|
|
1450
1646
|
|
|
1451
1647
|
def _custom_action_name_is_defined_in_the_domain(
|
|
1452
1648
|
self,
|
|
1453
|
-
|
|
1649
|
+
controlled_mappings: bool,
|
|
1454
1650
|
slot: Slot,
|
|
1455
1651
|
all_good: bool,
|
|
1456
1652
|
) -> bool:
|
|
1457
|
-
if not
|
|
1653
|
+
if not controlled_mappings:
|
|
1458
1654
|
return all_good
|
|
1459
1655
|
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
if isinstance(step, CollectInformationFlowStep)
|
|
1480
|
-
]
|
|
1481
|
-
)
|
|
1482
|
-
|
|
1483
|
-
if not slot_collected_by_flows:
|
|
1484
|
-
# if the slot is not collected by any flow,
|
|
1485
|
-
# it could be a DM1 custom slot
|
|
1486
|
-
return all_good
|
|
1487
|
-
|
|
1488
|
-
custom_action_ask_name = f"action_ask_{slot.name}"
|
|
1489
|
-
if custom_action_ask_name not in self.domain.action_names_or_texts:
|
|
1490
|
-
structlogger.error(
|
|
1491
|
-
"validator.validate_slot_mappings_in_CALM.custom_action_not_in_domain",
|
|
1492
|
-
slot_name=slot.name,
|
|
1493
|
-
event_info=(
|
|
1494
|
-
f"The slot '{slot.name}' has a custom slot mapping, but "
|
|
1495
|
-
f"neither the action '{custom_action_ask_name}' nor "
|
|
1496
|
-
f"another custom action are defined in the domain file. "
|
|
1497
|
-
f"Please add one of the actions to your domain file."
|
|
1498
|
-
),
|
|
1499
|
-
docs_link=DOCS_URL_DOMAIN + "#custom-slot-mappings",
|
|
1500
|
-
)
|
|
1501
|
-
all_good = False
|
|
1656
|
+
for mapping in slot.mappings:
|
|
1657
|
+
if (
|
|
1658
|
+
mapping.run_action_every_turn is not None
|
|
1659
|
+
and mapping.run_action_every_turn
|
|
1660
|
+
not in self.domain.action_names_or_texts
|
|
1661
|
+
):
|
|
1662
|
+
structlogger.error(
|
|
1663
|
+
"validator.validate_slot_mappings_in_CALM.custom_action_not_in_domain",
|
|
1664
|
+
slot_name=slot.name,
|
|
1665
|
+
action_name=mapping.run_action_every_turn,
|
|
1666
|
+
event_info=(
|
|
1667
|
+
f"The slot '{slot.name}' has a custom action "
|
|
1668
|
+
f"'{mapping.run_action_every_turn}' "
|
|
1669
|
+
f"defined in its slot mappings, "
|
|
1670
|
+
f"but the action is not listed in the domain actions. "
|
|
1671
|
+
f"Please add the action to your domain file."
|
|
1672
|
+
),
|
|
1673
|
+
)
|
|
1674
|
+
all_good = False
|
|
1502
1675
|
|
|
1503
1676
|
return all_good
|
|
1504
1677
|
|
|
@@ -1514,7 +1687,7 @@ class Validator:
|
|
|
1514
1687
|
contains_nlu_command_adapter = any(
|
|
1515
1688
|
[
|
|
1516
1689
|
component.get("name") == "NLUCommandAdapter"
|
|
1517
|
-
for component in self.config.get(
|
|
1690
|
+
for component in self.config.get(CONFIG_PIPELINE_KEY, [])
|
|
1518
1691
|
]
|
|
1519
1692
|
)
|
|
1520
1693
|
|
|
@@ -1583,7 +1756,7 @@ class Validator:
|
|
|
1583
1756
|
collect_step = step.collect
|
|
1584
1757
|
flow_slots.add(collect_step)
|
|
1585
1758
|
if not step.reset_after_flow_ends:
|
|
1586
|
-
warn_deprecated_collect_step_config(
|
|
1759
|
+
warn_deprecated_collect_step_config()
|
|
1587
1760
|
|
|
1588
1761
|
if has_flow_level_persistence:
|
|
1589
1762
|
structlogger.error(
|
|
@@ -1644,10 +1817,316 @@ class Validator:
|
|
|
1644
1817
|
self.verify_predicates(),
|
|
1645
1818
|
]
|
|
1646
1819
|
)
|
|
1820
|
+
valid_translations = self.verify_translations(summary_mode=True)
|
|
1647
1821
|
valid_calm_slot_mappings = self.validate_CALM_slot_mappings()
|
|
1648
1822
|
|
|
1649
1823
|
all_good = (
|
|
1650
|
-
valid_responses
|
|
1824
|
+
valid_responses
|
|
1825
|
+
and valid_nlu
|
|
1826
|
+
and valid_flows
|
|
1827
|
+
and valid_translations
|
|
1828
|
+
and valid_calm_slot_mappings
|
|
1651
1829
|
)
|
|
1652
1830
|
|
|
1653
1831
|
return all_good
|
|
1832
|
+
|
|
1833
|
+
def verify_digression_configuration(self) -> bool:
|
|
1834
|
+
"""Validates the digression configuration in flows."""
|
|
1835
|
+
all_good = True
|
|
1836
|
+
|
|
1837
|
+
for flow in self.flows.underlying_flows:
|
|
1838
|
+
all_good = self._validate_ask_confirm_digressions(flow, all_good)
|
|
1839
|
+
all_good = self._validate_block_digressions(flow, all_good)
|
|
1840
|
+
|
|
1841
|
+
return all_good
|
|
1842
|
+
|
|
1843
|
+
def _validate_ask_confirm_digressions(self, flow: Flow, all_good: bool) -> bool:
|
|
1844
|
+
"""Validates the ask_confirm_digressions configuration in a flow."""
|
|
1845
|
+
for flow_id in flow.ask_confirm_digressions:
|
|
1846
|
+
if flow_id == ALL_LABEL:
|
|
1847
|
+
continue
|
|
1848
|
+
if flow_id not in self.flows.flow_ids:
|
|
1849
|
+
structlogger.error(
|
|
1850
|
+
"validator.verify_digression_configuration.ask_confirm_digressions",
|
|
1851
|
+
flow=flow.id,
|
|
1852
|
+
event_info=(
|
|
1853
|
+
f"The flow '{flow_id}' is listed in the "
|
|
1854
|
+
f"`ask_confirm_digressions` configuration of flow "
|
|
1855
|
+
f"'{flow.id}', but it is not found in the "
|
|
1856
|
+
f"flows file. Please make sure that the flow id is correct."
|
|
1857
|
+
),
|
|
1858
|
+
)
|
|
1859
|
+
all_good = False
|
|
1860
|
+
|
|
1861
|
+
if flow_id in flow.block_digressions:
|
|
1862
|
+
structlogger.error(
|
|
1863
|
+
"validator.verify_digression_configuration.overlap_digressions",
|
|
1864
|
+
flow=flow.id,
|
|
1865
|
+
event_info=(
|
|
1866
|
+
f"The flow '{flow_id}' is listed in both the "
|
|
1867
|
+
f"`ask_confirm_digressions` and `block_digressions` "
|
|
1868
|
+
f"configuration of flow '{flow.id}'. "
|
|
1869
|
+
f"Please make sure that the flow id is not listed in both "
|
|
1870
|
+
f"configurations."
|
|
1871
|
+
),
|
|
1872
|
+
)
|
|
1873
|
+
all_good = False
|
|
1874
|
+
|
|
1875
|
+
for step in flow.get_collect_steps():
|
|
1876
|
+
for flow_id in step.ask_confirm_digressions:
|
|
1877
|
+
if flow_id == ALL_LABEL:
|
|
1878
|
+
continue
|
|
1879
|
+
|
|
1880
|
+
if flow_id not in self.flows.flow_ids:
|
|
1881
|
+
structlogger.error(
|
|
1882
|
+
"validator.verify_digression_configuration.ask_confirm_digressions",
|
|
1883
|
+
flow=flow.id,
|
|
1884
|
+
step_id=step.id,
|
|
1885
|
+
event_info=(
|
|
1886
|
+
f"The flow '{flow_id}' is listed in the "
|
|
1887
|
+
f"`ask_confirm_digressions` configuration of step "
|
|
1888
|
+
f"'{step.id}' in flow '{flow.id}', but it is "
|
|
1889
|
+
f"not found in the flows file. "
|
|
1890
|
+
f"Please make sure that the flow id is correct."
|
|
1891
|
+
),
|
|
1892
|
+
)
|
|
1893
|
+
all_good = False
|
|
1894
|
+
|
|
1895
|
+
if flow_id in step.block_digressions:
|
|
1896
|
+
structlogger.error(
|
|
1897
|
+
"validator.verify_digression_configuration.overlap_digressions",
|
|
1898
|
+
flow=flow.id,
|
|
1899
|
+
step_id=step.id,
|
|
1900
|
+
event_info=(
|
|
1901
|
+
f"The flow '{flow_id}' is listed in both the "
|
|
1902
|
+
f"`ask_confirm_digressions` and `block_digressions` "
|
|
1903
|
+
f"configuration of step '{step.id}' in flow '{flow.id}'. "
|
|
1904
|
+
f"Please make sure that the flow id is not listed in both "
|
|
1905
|
+
f"configurations."
|
|
1906
|
+
),
|
|
1907
|
+
)
|
|
1908
|
+
all_good = False
|
|
1909
|
+
|
|
1910
|
+
return all_good
|
|
1911
|
+
|
|
1912
|
+
def _validate_block_digressions(self, flow: Flow, all_good: bool) -> bool:
|
|
1913
|
+
"""Validates the block_digressions configuration in a flow."""
|
|
1914
|
+
for flow_id in flow.block_digressions:
|
|
1915
|
+
if flow_id == ALL_LABEL:
|
|
1916
|
+
continue
|
|
1917
|
+
|
|
1918
|
+
if flow_id not in self.flows.flow_ids:
|
|
1919
|
+
structlogger.error(
|
|
1920
|
+
"validator.verify_digression_configuration.block_digressions",
|
|
1921
|
+
flow=flow.id,
|
|
1922
|
+
event_info=(
|
|
1923
|
+
f"The flow '{flow_id}' is listed in the `block_digressions` "
|
|
1924
|
+
f"configuration of flow '{flow.id}', but it is not found "
|
|
1925
|
+
f"in the flows file. Please make sure that the flow id "
|
|
1926
|
+
f"is correct."
|
|
1927
|
+
),
|
|
1928
|
+
)
|
|
1929
|
+
all_good = False
|
|
1930
|
+
|
|
1931
|
+
for step in flow.get_collect_steps():
|
|
1932
|
+
for flow_id in step.block_digressions:
|
|
1933
|
+
if flow_id == ALL_LABEL:
|
|
1934
|
+
continue
|
|
1935
|
+
|
|
1936
|
+
if flow_id not in self.flows.flow_ids:
|
|
1937
|
+
structlogger.error(
|
|
1938
|
+
"validator.verify_digression_configuration.block_digressions",
|
|
1939
|
+
flow=flow.id,
|
|
1940
|
+
step_id=step.id,
|
|
1941
|
+
event_info=(
|
|
1942
|
+
f"The flow '{flow_id}' is listed in the "
|
|
1943
|
+
f"`block_digressions` configuration of step "
|
|
1944
|
+
f"'{step.id}' in flow '{flow.id}', but it is "
|
|
1945
|
+
f"not found in the flows file. "
|
|
1946
|
+
f"Please make sure that the flow id is correct."
|
|
1947
|
+
),
|
|
1948
|
+
)
|
|
1949
|
+
all_good = False
|
|
1950
|
+
|
|
1951
|
+
return all_good
|
|
1952
|
+
|
|
1953
|
+
def verify_slot_validation(self) -> bool:
|
|
1954
|
+
"""Validates the slot validation configuration in the domain file."""
|
|
1955
|
+
all_good = True
|
|
1956
|
+
|
|
1957
|
+
for slot in self.domain._user_slots:
|
|
1958
|
+
if slot.requires_validation():
|
|
1959
|
+
refill_utter = slot.validation.refill_utter # type: ignore[union-attr]
|
|
1960
|
+
if refill_utter and refill_utter not in self.domain.responses:
|
|
1961
|
+
self._log_slot_validation_error(
|
|
1962
|
+
slot.name, "refill utterance", refill_utter
|
|
1963
|
+
)
|
|
1964
|
+
all_good = False
|
|
1965
|
+
rejections = slot.validation.rejections # type: ignore[union-attr]
|
|
1966
|
+
for rejection in rejections:
|
|
1967
|
+
if rejection.utter not in self.domain.responses:
|
|
1968
|
+
self._log_slot_validation_error(
|
|
1969
|
+
slot.name, "rejection utterance", rejection.utter
|
|
1970
|
+
)
|
|
1971
|
+
all_good = False
|
|
1972
|
+
|
|
1973
|
+
return all_good
|
|
1974
|
+
|
|
1975
|
+
def _log_slot_validation_error(self, slot_name: str, key: str, value: str) -> None:
|
|
1976
|
+
structlogger.error(
|
|
1977
|
+
"validator.verify_slot_validation.response_not_in_domain",
|
|
1978
|
+
slot=slot_name,
|
|
1979
|
+
event_info=(
|
|
1980
|
+
f"The slot '{slot_name}' requires validation, "
|
|
1981
|
+
f"but the {key} '{value}' "
|
|
1982
|
+
f"is not listed in the domain responses. "
|
|
1983
|
+
f"Please add it to your domain file."
|
|
1984
|
+
),
|
|
1985
|
+
)
|
|
1986
|
+
|
|
1987
|
+
@staticmethod
|
|
1988
|
+
def _validate_controlled_mappings(slot: Slot, all_good: bool) -> bool:
|
|
1989
|
+
for mapping in slot.mappings:
|
|
1990
|
+
if (
|
|
1991
|
+
mapping.run_action_every_turn is not None
|
|
1992
|
+
and mapping.type != SlotMappingType.CONTROLLED
|
|
1993
|
+
):
|
|
1994
|
+
structlogger.error(
|
|
1995
|
+
"validator.validate_slot_mappings_in_CALM.run_action_every_turn_invalid",
|
|
1996
|
+
slot_name=slot.name,
|
|
1997
|
+
event_info=(
|
|
1998
|
+
f"The slot '{slot.name}' has a custom action "
|
|
1999
|
+
f"'{mapping.run_action_every_turn}' "
|
|
2000
|
+
f"defined in its slot mapping, "
|
|
2001
|
+
f"but the slot mapping type is not 'controlled'. "
|
|
2002
|
+
),
|
|
2003
|
+
)
|
|
2004
|
+
all_good = False
|
|
2005
|
+
|
|
2006
|
+
if (
|
|
2007
|
+
mapping.coexistence_system is not None
|
|
2008
|
+
and mapping.type != SlotMappingType.CONTROLLED
|
|
2009
|
+
):
|
|
2010
|
+
structlogger.error(
|
|
2011
|
+
"validator.validate_slot_mappings_in_CALM.coexistence_system_invalid",
|
|
2012
|
+
slot_name=slot.name,
|
|
2013
|
+
event_info=(
|
|
2014
|
+
f"The slot '{slot.name}' has a coexistence system "
|
|
2015
|
+
f"'{mapping.coexistence_system.value}' "
|
|
2016
|
+
f"defined in its slot mapping, "
|
|
2017
|
+
f"but the slot mapping type is not 'controlled'. "
|
|
2018
|
+
),
|
|
2019
|
+
)
|
|
2020
|
+
all_good = False
|
|
2021
|
+
|
|
2022
|
+
if (
|
|
2023
|
+
mapping.coexistence_system is not None
|
|
2024
|
+
and mapping.coexistence_system != CoexistenceSystemType.SHARED
|
|
2025
|
+
and slot.shared_for_coexistence
|
|
2026
|
+
):
|
|
2027
|
+
structlogger.error(
|
|
2028
|
+
"validator.validate_slot_mappings_in_CALM.shared_for_coexistence_invalid",
|
|
2029
|
+
slot_name=slot.name,
|
|
2030
|
+
event_info=(
|
|
2031
|
+
f"The slot '{slot.name}' has the `shared_for_coexistence` "
|
|
2032
|
+
f"property set to `True`, but the slot mapping `controlled` "
|
|
2033
|
+
f"type defines the `coexistence_system` property with a "
|
|
2034
|
+
f"value different to the expected `SHARED` value. "
|
|
2035
|
+
),
|
|
2036
|
+
)
|
|
2037
|
+
all_good = False
|
|
2038
|
+
|
|
2039
|
+
multiple_controlled_mappings = {
|
|
2040
|
+
mapping.coexistence_system.value
|
|
2041
|
+
for mapping in slot.mappings
|
|
2042
|
+
if mapping.type == SlotMappingType.CONTROLLED
|
|
2043
|
+
and mapping.coexistence_system is not None
|
|
2044
|
+
}
|
|
2045
|
+
contains_inconsistent_coexistence_system = len(multiple_controlled_mappings) > 1
|
|
2046
|
+
|
|
2047
|
+
if contains_inconsistent_coexistence_system:
|
|
2048
|
+
structlogger.error(
|
|
2049
|
+
"validator.validate_slot_mappings_in_CALM.inconsistent_multiple_mappings",
|
|
2050
|
+
slot_name=slot.name,
|
|
2051
|
+
event_info=(
|
|
2052
|
+
f"The slot '{slot.name}' has multiple `controlled` mappings "
|
|
2053
|
+
f"with different coexistence systems defined: "
|
|
2054
|
+
f"'{sorted(list(multiple_controlled_mappings))}'. "
|
|
2055
|
+
f"Please only define one coexistence system for the slot. "
|
|
2056
|
+
),
|
|
2057
|
+
)
|
|
2058
|
+
all_good = False
|
|
2059
|
+
|
|
2060
|
+
return all_good
|
|
2061
|
+
|
|
2062
|
+
def validate_conditional_response_variation_predicates(self) -> bool:
|
|
2063
|
+
"""Validate the conditional response variation predicates."""
|
|
2064
|
+
context = {SLOTS: {slot.name: None for slot in self.domain.slots}}
|
|
2065
|
+
all_good = True
|
|
2066
|
+
|
|
2067
|
+
for utter_name, variations in self.domain.responses.items():
|
|
2068
|
+
for variation in variations:
|
|
2069
|
+
condition = variation.get(RESPONSE_CONDITION)
|
|
2070
|
+
if not isinstance(condition, str):
|
|
2071
|
+
continue
|
|
2072
|
+
|
|
2073
|
+
predicate, all_good = self._construct_predicate(
|
|
2074
|
+
condition,
|
|
2075
|
+
utter_name,
|
|
2076
|
+
context,
|
|
2077
|
+
is_step=False,
|
|
2078
|
+
all_good=all_good,
|
|
2079
|
+
)
|
|
2080
|
+
if not predicate:
|
|
2081
|
+
continue
|
|
2082
|
+
|
|
2083
|
+
if not predicate.is_valid():
|
|
2084
|
+
structlogger.error(
|
|
2085
|
+
"validator.validate_conditional_response_variation_predicates.invalid_condition",
|
|
2086
|
+
utter=utter_name,
|
|
2087
|
+
event_info=(
|
|
2088
|
+
f"Detected invalid condition '{condition}' "
|
|
2089
|
+
f"for response variation '{utter_name}'. "
|
|
2090
|
+
f"Please make sure that all conditions are valid."
|
|
2091
|
+
),
|
|
2092
|
+
)
|
|
2093
|
+
all_good = False
|
|
2094
|
+
continue
|
|
2095
|
+
|
|
2096
|
+
predicate_syntax_tree = self._extract_predicate_syntax_tree(predicate)
|
|
2097
|
+
slot_namespace, _ = self._extract_slot_name_and_slot_value(
|
|
2098
|
+
predicate_syntax_tree
|
|
2099
|
+
)
|
|
2100
|
+
|
|
2101
|
+
if slot_namespace is not None and slot_namespace[0] != SLOTS:
|
|
2102
|
+
structlogger.error(
|
|
2103
|
+
"validator.validate_conditional_response_variation_predicates.invalid_namespace",
|
|
2104
|
+
utter=utter_name,
|
|
2105
|
+
event_info=(
|
|
2106
|
+
f"Detected invalid namespace '{slot_namespace[0]}' in "
|
|
2107
|
+
f"condition '{condition}' for response variation "
|
|
2108
|
+
f"'{utter_name}'. Please make sure that you're "
|
|
2109
|
+
f"using a valid namespace. "
|
|
2110
|
+
f"The current supported option is: 'slots'."
|
|
2111
|
+
),
|
|
2112
|
+
)
|
|
2113
|
+
all_good = False
|
|
2114
|
+
continue
|
|
2115
|
+
|
|
2116
|
+
if (
|
|
2117
|
+
slot_namespace is not None
|
|
2118
|
+
and slot_namespace[1] not in context[SLOTS]
|
|
2119
|
+
):
|
|
2120
|
+
structlogger.error(
|
|
2121
|
+
"validator.validate_conditional_response_variation_predicates.invalid_slot",
|
|
2122
|
+
utter=utter_name,
|
|
2123
|
+
event_info=(
|
|
2124
|
+
f"Detected invalid slot '{slot_namespace[1]}' in "
|
|
2125
|
+
f"condition '{condition}' for response variation "
|
|
2126
|
+
f"'{utter_name}'. Please make sure that all slots "
|
|
2127
|
+
f"are specified in the domain file."
|
|
2128
|
+
),
|
|
2129
|
+
)
|
|
2130
|
+
all_good = False
|
|
2131
|
+
|
|
2132
|
+
return all_good
|