rasa-pro 3.12.21__py3-none-any.whl → 3.13.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.
- rasa/__main__.py +3 -4
- rasa/api.py +1 -1
- rasa/cli/dialogue_understanding_test.py +1 -1
- rasa/cli/e2e_test.py +1 -8
- rasa/cli/evaluate.py +2 -2
- rasa/cli/export.py +5 -3
- rasa/cli/inspect.py +7 -0
- rasa/cli/llm_fine_tuning.py +1 -1
- rasa/cli/project_templates/default/config.yml +5 -32
- rasa/cli/project_templates/{calm → default}/e2e_tests/cancelations/user_cancels_during_a_correction.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/cancelations/user_changes_mind_on_a_whim.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/corrections/user_corrects_contact_handle.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/corrections/user_corrects_contact_name.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_adds_contact_to_their_list.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_lists_contacts.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_removes_contact.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_removes_contact_from_list.yml +1 -1
- rasa/cli/project_templates/default/endpoints.yml +18 -2
- rasa/cli/project_templates/defaults.py +133 -0
- rasa/cli/project_templates/tutorial/config.yml +1 -1
- rasa/cli/project_templates/tutorial/endpoints.yml +1 -1
- rasa/cli/run.py +1 -1
- rasa/cli/scaffold.py +2 -3
- rasa/cli/shell.py +6 -1
- rasa/cli/studio/download.py +0 -22
- rasa/cli/studio/link.py +36 -0
- rasa/cli/studio/pull.py +79 -0
- rasa/cli/studio/push.py +78 -0
- rasa/cli/studio/studio.py +12 -0
- rasa/cli/studio/train.py +1 -5
- rasa/cli/studio/upload.py +6 -4
- rasa/cli/train.py +5 -1
- rasa/cli/utils.py +1 -1
- rasa/cli/x.py +1 -1
- rasa/constants.py +2 -0
- rasa/core/__init__.py +0 -16
- rasa/core/actions/action.py +43 -29
- rasa/core/actions/action_repeat_bot_messages.py +18 -22
- rasa/core/actions/action_run_slot_rejections.py +1 -2
- rasa/core/agent.py +24 -3
- rasa/core/available_endpoints.py +146 -0
- rasa/core/brokers/kafka.py +4 -0
- rasa/core/brokers/pika.py +5 -2
- rasa/core/brokers/sql.py +1 -1
- rasa/core/channels/__init__.py +3 -0
- rasa/core/channels/botframework.py +2 -2
- rasa/core/channels/channel.py +2 -2
- rasa/core/channels/development_inspector.py +1 -1
- rasa/core/channels/facebook.py +1 -4
- rasa/core/channels/hangouts.py +8 -5
- rasa/core/channels/inspector/.eslintrc.cjs +12 -6
- rasa/core/channels/inspector/.prettierrc +5 -0
- rasa/core/channels/inspector/README.md +11 -5
- rasa/core/channels/inspector/dist/assets/{arc-9f75cc3b.js → arc-371401b1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-7f34db23.js → blockDiagram-38ab4fdb-3f126156.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-948bab2c.js → c4Diagram-3d4e48cf-12f22eb7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-f1efda17.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-53b0dd0e.js → classDiagram-70f12bd4-03b1d386.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-fdf789e7.js → classDiagram-v2-f2320105-84f69d63.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-fdf164e2.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-87c4ece5.js → createText-2e5e7dd3-ca47fd38.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-5a8b0749.js → edges-e0da2a9e-f837ca8a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-66da90e2.js → erDiagram-9861fffd-8717ac54.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-10044f05.js → flowDb-956e92f1-94f38b83.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-f338f66a.js → flowDiagram-66a62f08-b616f9fb.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-7d7a1629.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-b13140aa.js → flowchart-elk-definition-4a651766-f5d24bb8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-f2b4a55a.js → ganttDiagram-c361ad54-b43ba8d9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-dedc298d.js → gitGraphDiagram-72cf32ee-c3aafaa5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-4ede11ff.js → graph-0d0a2c10.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-65549d37.js → index-3862675e-58ea0305.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3a23e736.js → index-cce6f8a1.js} +123 -123
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-65439671.js → infoDiagram-f8f76790-b8f60461.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-56d03d98.js → journeyDiagram-49397b02-95be5545.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-dd48f7f4.js → layout-da885b9b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-1569ad2c.js → line-f1c817d3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-48bf4935.js → linear-d42801e6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-688504c1.js → mindmap-definition-fc14e90a-a38923a6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-78b6d7e6.js → pieDiagram-8a3498a8-ca6e71e9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-048b84b3.js → quadrantDiagram-120e2f19-b290dae9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-dd67f107.js → requirementDiagram-deff3bca-03f02ceb.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-8128436e.js → sankeyDiagram-04a897e0-c49eee40.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-1a0d1461.js → sequenceDiagram-704730f1-b2cd6a3d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-46d388ed.js → stateDiagram-587899a1-e53a2028.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-ea42951a.js → stateDiagram-v2-d93cdb3a-e1982a03.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-7427ed0c.js → styles-6aaf32cf-d0226ca5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-ff5e5a16.js → styles-9a916d00-0e21dc00.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-7b3680cf.js → styles-c10674c1-9588494e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-f860f2ad.js → svgDrawCommon-08f97a94-be478d4f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-2eebf0c8.js → timeline-definition-85554ec2-74631749.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-5d7f4e96.js → xychartDiagram-e933f94c-a043552f.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/package.json +3 -1
- rasa/core/channels/inspector/src/App.tsx +91 -90
- rasa/core/channels/inspector/src/components/Chat.tsx +45 -41
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +40 -40
- rasa/core/channels/inspector/src/components/DialogueInformation.tsx +57 -57
- rasa/core/channels/inspector/src/components/DialogueStack.tsx +36 -27
- rasa/core/channels/inspector/src/components/ExpandIcon.tsx +4 -4
- rasa/core/channels/inspector/src/components/FullscreenButton.tsx +7 -7
- rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +28 -12
- rasa/core/channels/inspector/src/components/NoActiveFlow.tsx +9 -9
- rasa/core/channels/inspector/src/components/RasaLogo.tsx +5 -5
- rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +55 -60
- rasa/core/channels/inspector/src/components/SaraDiagrams.tsx +5 -5
- rasa/core/channels/inspector/src/components/Slots.tsx +22 -22
- rasa/core/channels/inspector/src/components/Welcome.tsx +28 -31
- rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +245 -0
- rasa/core/channels/inspector/src/helpers/audio/microphone-processor.js +12 -0
- rasa/core/channels/inspector/src/helpers/audio/playback-processor.js +36 -0
- rasa/core/channels/inspector/src/helpers/conversation.ts +7 -7
- rasa/core/channels/inspector/src/helpers/formatters.test.ts +181 -181
- rasa/core/channels/inspector/src/helpers/formatters.ts +111 -111
- rasa/core/channels/inspector/src/helpers/utils.ts +78 -61
- rasa/core/channels/inspector/src/main.tsx +8 -8
- rasa/core/channels/inspector/src/theme/Button/Button.ts +8 -8
- rasa/core/channels/inspector/src/theme/Heading/Heading.ts +7 -7
- rasa/core/channels/inspector/src/theme/Input/Input.ts +9 -9
- rasa/core/channels/inspector/src/theme/Link/Link.ts +6 -6
- rasa/core/channels/inspector/src/theme/Modal/Modal.ts +13 -13
- rasa/core/channels/inspector/src/theme/Table/Table.tsx +10 -10
- rasa/core/channels/inspector/src/theme/Tooltip/Tooltip.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/breakpoints.ts +7 -7
- rasa/core/channels/inspector/src/theme/base/colors.ts +64 -64
- rasa/core/channels/inspector/src/theme/base/fonts/fontFaces.css +21 -18
- rasa/core/channels/inspector/src/theme/base/radii.ts +8 -8
- rasa/core/channels/inspector/src/theme/base/shadows.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/sizes.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/space.ts +12 -12
- rasa/core/channels/inspector/src/theme/base/styles.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/typography.ts +12 -12
- rasa/core/channels/inspector/src/theme/base/zIndices.ts +3 -3
- rasa/core/channels/inspector/src/theme/index.ts +38 -38
- rasa/core/channels/inspector/src/types.ts +56 -50
- rasa/core/channels/inspector/yarn.lock +5 -0
- rasa/core/channels/mattermost.py +1 -1
- rasa/core/channels/rasa_chat.py +2 -4
- rasa/core/channels/rest.py +5 -4
- rasa/core/channels/socketio.py +56 -41
- rasa/core/channels/studio_chat.py +329 -68
- rasa/core/channels/vier_cvg.py +1 -2
- rasa/core/channels/voice_ready/audiocodes.py +4 -11
- rasa/core/channels/voice_ready/jambonz.py +5 -6
- rasa/core/channels/voice_ready/twilio_voice.py +13 -12
- rasa/core/channels/voice_ready/utils.py +22 -0
- rasa/core/channels/voice_stream/audiocodes.py +13 -16
- rasa/core/channels/voice_stream/browser_audio.py +1 -1
- rasa/core/channels/voice_stream/genesys.py +37 -18
- rasa/core/channels/voice_stream/jambonz.py +232 -0
- rasa/core/channels/voice_stream/tts/__init__.py +8 -0
- rasa/core/channels/voice_stream/twilio_media_streams.py +15 -12
- rasa/core/channels/voice_stream/voice_channel.py +71 -27
- rasa/core/concurrent_lock_store.py +24 -10
- rasa/core/evaluation/marker_tracker_loader.py +1 -1
- rasa/core/exporter.py +37 -1
- rasa/core/http_interpreter.py +3 -7
- rasa/core/information_retrieval/faiss.py +18 -11
- rasa/core/information_retrieval/ingestion/faq_parser.py +158 -0
- rasa/core/jobs.py +2 -1
- rasa/core/lock_store.py +151 -60
- rasa/core/nlg/contextual_response_rephraser.py +17 -7
- rasa/core/nlg/generator.py +5 -22
- rasa/core/nlg/interpolator.py +2 -3
- rasa/core/nlg/response.py +6 -43
- rasa/core/nlg/summarize.py +1 -1
- rasa/core/nlg/translate.py +0 -8
- rasa/core/policies/enterprise_search_policy.py +305 -189
- rasa/core/policies/enterprise_search_policy_config.py +241 -0
- rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2 +67 -0
- rasa/core/policies/flow_policy.py +1 -1
- rasa/core/policies/flows/flow_executor.py +102 -17
- rasa/core/policies/intentless_policy.py +56 -17
- rasa/core/processor.py +70 -49
- rasa/core/run.py +33 -11
- rasa/core/tracker_stores/__init__.py +0 -0
- rasa/core/{auth_retry_tracker_store.py → tracker_stores/auth_retry_tracker_store.py} +66 -1
- rasa/core/tracker_stores/dynamo_tracker_store.py +256 -0
- rasa/core/tracker_stores/mongo_tracker_store.py +223 -0
- rasa/core/tracker_stores/redis_tracker_store.py +252 -0
- rasa/core/tracker_stores/sql_tracker_store.py +582 -0
- rasa/core/tracker_stores/tracker_store.py +839 -0
- rasa/core/training/interactive.py +1 -1
- rasa/core/utils.py +24 -95
- rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -1
- rasa/dialogue_understanding/coexistence/llm_based_router.py +13 -11
- rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -0
- rasa/dialogue_understanding/commands/cancel_flow_command.py +3 -1
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +2 -0
- rasa/dialogue_understanding/commands/clarify_command.py +6 -2
- rasa/dialogue_understanding/commands/command_syntax_manager.py +1 -0
- rasa/dialogue_understanding/commands/correct_slots_command.py +5 -6
- rasa/dialogue_understanding/commands/error_command.py +1 -1
- rasa/dialogue_understanding/commands/human_handoff_command.py +3 -3
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +2 -0
- rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +2 -0
- rasa/dialogue_understanding/commands/set_slot_command.py +8 -4
- rasa/dialogue_understanding/commands/skip_question_command.py +3 -3
- rasa/dialogue_understanding/commands/start_flow_command.py +7 -3
- rasa/dialogue_understanding/generator/__init__.py +7 -1
- rasa/dialogue_understanding/generator/command_generator.py +4 -2
- rasa/dialogue_understanding/generator/command_parser.py +2 -2
- rasa/dialogue_understanding/generator/command_parser_validator.py +63 -0
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +1 -2
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +3 -2
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +2 -2
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_template.jinja2 +0 -2
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +1 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +1 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +79 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +79 -0
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +26 -461
- rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +147 -0
- rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +461 -0
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +20 -64
- rasa/dialogue_understanding/patterns/cancel.py +1 -2
- rasa/dialogue_understanding/patterns/clarify.py +1 -1
- rasa/dialogue_understanding/patterns/correction.py +2 -2
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +42 -27
- rasa/dialogue_understanding/patterns/domain_for_patterns.py +190 -0
- rasa/dialogue_understanding/processor/command_processor.py +6 -7
- rasa/dialogue_understanding_test/command_metric_calculation.py +7 -40
- rasa/dialogue_understanding_test/command_metrics.py +38 -0
- rasa/dialogue_understanding_test/du_test_case.py +58 -25
- rasa/dialogue_understanding_test/du_test_result.py +228 -132
- rasa/dialogue_understanding_test/du_test_runner.py +11 -2
- rasa/dialogue_understanding_test/du_test_schema.yml +3 -3
- rasa/dialogue_understanding_test/io.py +35 -8
- rasa/e2e_test/constants.py +1 -1
- rasa/e2e_test/e2e_test_runner.py +1 -1
- rasa/e2e_test/e2e_test_schema.yml +3 -3
- rasa/engine/constants.py +1 -1
- rasa/engine/graph.py +2 -2
- rasa/engine/recipes/default_recipe.py +1 -1
- rasa/engine/validation.py +3 -2
- rasa/hooks.py +2 -30
- rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +2 -6
- rasa/model_manager/model_api.py +89 -1
- rasa/model_manager/runner_service.py +20 -4
- rasa/model_manager/socket_bridge.py +0 -7
- rasa/model_manager/trainer_service.py +10 -4
- rasa/plugin.py +2 -15
- rasa/privacy/__init__.py +0 -0
- rasa/privacy/constants.py +83 -0
- rasa/privacy/event_broker_utils.py +77 -0
- rasa/privacy/privacy_config.py +281 -0
- rasa/privacy/privacy_config_schema.json +86 -0
- rasa/privacy/privacy_filter.py +393 -0
- rasa/privacy/privacy_manager.py +594 -0
- rasa/server.py +23 -2
- rasa/shared/constants.py +17 -0
- rasa/shared/core/command_payload_reader.py +1 -5
- rasa/shared/core/constants.py +4 -3
- rasa/shared/core/domain.py +172 -11
- rasa/shared/core/events.py +100 -6
- rasa/shared/core/flows/flow.py +30 -5
- rasa/shared/core/flows/flow_step.py +19 -3
- rasa/shared/core/flows/flow_step_links.py +15 -0
- rasa/shared/core/flows/flow_step_sequence.py +6 -0
- rasa/shared/core/flows/flows_yaml_schema.json +3 -0
- rasa/shared/core/flows/nlu_trigger.py +13 -0
- rasa/shared/core/flows/steps/action.py +7 -4
- rasa/shared/core/flows/steps/call.py +11 -4
- rasa/shared/core/flows/steps/collect.py +71 -6
- rasa/shared/core/flows/steps/internal.py +6 -1
- rasa/shared/core/flows/steps/link.py +7 -4
- rasa/shared/core/flows/steps/no_operation.py +7 -4
- rasa/shared/core/flows/steps/set_slots.py +8 -4
- rasa/shared/core/flows/validation.py +25 -5
- rasa/shared/core/flows/yaml_flows_io.py +106 -5
- rasa/shared/core/slots.py +29 -1
- rasa/shared/core/trackers.py +21 -10
- rasa/shared/core/training_data/story_reader/yaml_story_reader.py +1 -4
- rasa/shared/importers/importer.py +8 -0
- rasa/shared/providers/_configs/azure_openai_client_config.py +2 -2
- rasa/shared/providers/_configs/default_litellm_client_config.py +1 -1
- rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +1 -1
- rasa/shared/providers/_configs/openai_client_config.py +1 -1
- rasa/shared/providers/_configs/rasa_llm_client_config.py +1 -1
- rasa/shared/providers/_configs/self_hosted_llm_client_config.py +1 -1
- rasa/shared/providers/_configs/utils.py +0 -99
- rasa/shared/providers/llm/default_litellm_llm_client.py +2 -2
- rasa/shared/utils/common.py +43 -1
- rasa/shared/utils/configs.py +110 -0
- rasa/shared/utils/constants.py +0 -3
- rasa/shared/utils/llm.py +245 -8
- rasa/shared/utils/pykwalify_extensions.py +0 -9
- rasa/shared/utils/yaml.py +32 -0
- rasa/studio/constants.py +1 -0
- rasa/studio/data_handler.py +33 -12
- rasa/studio/download.py +117 -435
- rasa/studio/link.py +211 -0
- rasa/studio/prompts.py +221 -0
- rasa/studio/pull/__init__.py +0 -0
- rasa/studio/pull/data.py +222 -0
- rasa/studio/pull/domains.py +60 -0
- rasa/studio/pull/pull.py +239 -0
- rasa/studio/push.py +138 -0
- rasa/studio/results_logger.py +6 -1
- rasa/studio/train.py +1 -1
- rasa/studio/upload.py +243 -72
- rasa/studio/utils.py +33 -0
- rasa/telemetry.py +83 -26
- rasa/tracing/config.py +4 -5
- rasa/tracing/constants.py +19 -1
- rasa/tracing/instrumentation/attribute_extractors.py +68 -16
- rasa/tracing/instrumentation/instrumentation.py +54 -3
- rasa/tracing/instrumentation/metrics.py +98 -15
- rasa/tracing/metric_instrument_provider.py +75 -3
- rasa/utils/common.py +43 -22
- rasa/utils/endpoints.py +22 -1
- rasa/utils/licensing.py +2 -3
- rasa/utils/log_utils.py +1 -45
- rasa/validator.py +2 -8
- rasa/version.py +1 -1
- {rasa_pro-3.12.21.dist-info → rasa_pro-3.13.0.dist-info}/METADATA +13 -14
- {rasa_pro-3.12.21.dist-info → rasa_pro-3.13.0.dist-info}/RECORD +333 -309
- rasa/anonymization/__init__.py +0 -2
- rasa/anonymization/anonymisation_rule_yaml_reader.py +0 -91
- rasa/anonymization/anonymization_pipeline.py +0 -286
- rasa/anonymization/anonymization_rule_executor.py +0 -266
- rasa/anonymization/anonymization_rule_orchestrator.py +0 -119
- rasa/anonymization/schemas/config.yml +0 -47
- rasa/anonymization/utils.py +0 -118
- rasa/cli/project_templates/calm/config.yml +0 -10
- rasa/cli/project_templates/calm/credentials.yml +0 -33
- rasa/cli/project_templates/calm/endpoints.yml +0 -58
- rasa/cli/project_templates/default/actions/actions.py +0 -27
- rasa/cli/project_templates/default/data/nlu.yml +0 -91
- rasa/cli/project_templates/default/data/rules.yml +0 -13
- rasa/cli/project_templates/default/data/stories.yml +0 -30
- rasa/cli/project_templates/default/domain.yml +0 -34
- rasa/cli/project_templates/default/tests/test_stories.yml +0 -91
- rasa/core/channels/inspector/dist/assets/channel-dfa68278.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-edb7f119.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-65e7c670.js +0 -1
- rasa/core/channels/inspector/src/helpers/audiostream.ts +0 -191
- rasa/core/tracker_store.py +0 -1792
- /rasa/cli/project_templates/{calm → default}/actions/action_template.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/add_contact.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/db.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/list_contacts.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/remove_contact.py +0 -0
- /rasa/cli/project_templates/{calm → default}/data/flows/add_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/data/flows/list_contacts.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/data/flows/remove_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/db/contacts.json +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/add_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/list_contacts.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/remove_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/shared.yml +0 -0
- /rasa/{cli/project_templates/calm/actions → core/information_retrieval/ingestion}/__init__.py +0 -0
- {rasa_pro-3.12.21.dist-info → rasa_pro-3.13.0.dist-info}/NOTICE +0 -0
- {rasa_pro-3.12.21.dist-info → rasa_pro-3.13.0.dist-info}/WHEEL +0 -0
- {rasa_pro-3.12.21.dist-info → rasa_pro-3.13.0.dist-info}/entry_points.txt +0 -0
rasa/studio/link.py
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import datetime
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any, Dict, List, Optional, Text, Union
|
|
8
|
+
|
|
9
|
+
import questionary
|
|
10
|
+
import structlog
|
|
11
|
+
from pydantic import BaseModel, Field
|
|
12
|
+
|
|
13
|
+
import rasa.shared.utils.cli
|
|
14
|
+
from rasa.constants import RASA_DIR_NAME
|
|
15
|
+
from rasa.shared.utils.yaml import read_yaml_file, write_yaml
|
|
16
|
+
from rasa.studio.config import StudioConfig
|
|
17
|
+
from rasa.studio.upload import (
|
|
18
|
+
check_if_assistant_already_exists,
|
|
19
|
+
handle_upload,
|
|
20
|
+
is_auth_working,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
structlogger = structlog.get_logger(__name__)
|
|
24
|
+
|
|
25
|
+
_LINK_FILE_NAME: Text = "studio.yml"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class AssistantLinkPayload(BaseModel):
|
|
29
|
+
assistant_name: Text
|
|
30
|
+
studio_url: Text
|
|
31
|
+
linked_at: Text = Field(
|
|
32
|
+
default_factory=lambda: datetime.datetime.utcnow().isoformat() + "Z"
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _link_file(project_root: Path) -> Path:
|
|
37
|
+
"""Return `<project-root>/.rasa/studio.yml`.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
project_root: The path to the project root.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
The path to the link file.
|
|
44
|
+
"""
|
|
45
|
+
return project_root / RASA_DIR_NAME / _LINK_FILE_NAME
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _write_link_file(
|
|
49
|
+
project_root: Path, assistant_name: Text, studio_url: Text
|
|
50
|
+
) -> None:
|
|
51
|
+
"""Persist assistant information inside the project.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
project_root: The path to the project root.
|
|
55
|
+
assistant_name: The name of the assistant.
|
|
56
|
+
studio_url: The URL of the Rasa Studio instance.
|
|
57
|
+
"""
|
|
58
|
+
file_path = _link_file(project_root)
|
|
59
|
+
file_path.parent.mkdir(exist_ok=True, parents=True)
|
|
60
|
+
|
|
61
|
+
payload = AssistantLinkPayload(
|
|
62
|
+
assistant_name=assistant_name,
|
|
63
|
+
studio_url=studio_url,
|
|
64
|
+
)
|
|
65
|
+
write_yaml(payload.model_dump(), file_path)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _read_link_file(
|
|
69
|
+
project_root: Path = Path.cwd(),
|
|
70
|
+
) -> Optional[Union[List[Any], Dict[Text, Any]]]:
|
|
71
|
+
"""Reads the link configuration file.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
project_root: The path to the project root.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
The assistant information if the file exists, otherwise None.
|
|
78
|
+
"""
|
|
79
|
+
file_path = _link_file(project_root)
|
|
80
|
+
if not file_path.is_file():
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
return read_yaml_file(file_path)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def read_assistant_name(project_root: Path = Path.cwd()) -> Optional[Text]:
|
|
87
|
+
"""Reads the assistant_name from the linked configuration file.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
project_root: The path to the project root.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
The assistant name if the file exists, otherwise None.
|
|
94
|
+
"""
|
|
95
|
+
linked = _read_link_file(project_root)
|
|
96
|
+
assistant_name = (
|
|
97
|
+
linked.get("assistant_name") if linked and isinstance(linked, dict) else None
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
if not assistant_name:
|
|
101
|
+
rasa.shared.utils.cli.print_error_and_exit(
|
|
102
|
+
"This project is not linked to any Rasa Studio assistant.\n"
|
|
103
|
+
"Run `rasa studio link <assistant-name>` first."
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
return assistant_name
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def get_studio_config() -> StudioConfig:
|
|
110
|
+
"""Get the StudioConfig object or exit with an error message.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
A valid StudioConfig object.
|
|
114
|
+
"""
|
|
115
|
+
config = StudioConfig.read_config()
|
|
116
|
+
if not config.is_valid():
|
|
117
|
+
rasa.shared.utils.cli.print_error_and_exit(
|
|
118
|
+
"Rasa Studio is not configured correctly. Run `rasa studio config` first."
|
|
119
|
+
)
|
|
120
|
+
if not is_auth_working(config.studio_url, not config.disable_verify):
|
|
121
|
+
rasa.shared.utils.cli.print_error_and_exit(
|
|
122
|
+
"Authentication invalid or expired. Please run `rasa studio login`."
|
|
123
|
+
)
|
|
124
|
+
return config
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _ensure_assistant_exists(
|
|
128
|
+
assistant_name: Text,
|
|
129
|
+
studio_cfg: StudioConfig,
|
|
130
|
+
args: argparse.Namespace,
|
|
131
|
+
) -> bool:
|
|
132
|
+
"""Create the assistant on Studio if it does not yet exist.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
assistant_name: The name the user provided on the CLI.
|
|
136
|
+
studio_cfg: The validated Studio configuration.
|
|
137
|
+
args: The original CLI args (needed for `handle_upload`).
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
True if the assistant already exists or was created, False otherwise.
|
|
141
|
+
"""
|
|
142
|
+
verify_ssl = not studio_cfg.disable_verify
|
|
143
|
+
assistant_already_exists = check_if_assistant_already_exists(
|
|
144
|
+
assistant_name, studio_cfg.studio_url, verify_ssl
|
|
145
|
+
)
|
|
146
|
+
if not assistant_already_exists:
|
|
147
|
+
should_create_assistant = questionary.confirm(
|
|
148
|
+
f"Assistant '{assistant_name}' was not found on Rasa Studio. "
|
|
149
|
+
f"Do you want to create it?"
|
|
150
|
+
).ask()
|
|
151
|
+
if should_create_assistant:
|
|
152
|
+
# `handle_upload` expects the name to live in `args.assistant_name`
|
|
153
|
+
args.assistant_name = assistant_name
|
|
154
|
+
handle_upload(args)
|
|
155
|
+
|
|
156
|
+
rasa.shared.utils.cli.print_info(
|
|
157
|
+
f"Assistant {assistant_name} successfully created."
|
|
158
|
+
)
|
|
159
|
+
return should_create_assistant
|
|
160
|
+
|
|
161
|
+
return assistant_already_exists
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def handle_link(args: argparse.Namespace) -> None:
|
|
165
|
+
"""Implementation of `rasa studio link <assistant-name>` CLI command.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
args: The command line arguments.
|
|
169
|
+
"""
|
|
170
|
+
assistant_name: Text = args.assistant_name
|
|
171
|
+
studio_cfg = get_studio_config()
|
|
172
|
+
assistant_exists = _ensure_assistant_exists(assistant_name, studio_cfg, args)
|
|
173
|
+
if not assistant_exists:
|
|
174
|
+
rasa.shared.utils.cli.print_error_and_exit(
|
|
175
|
+
"Project has not been linked with Studio assistant."
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
project_root = Path.cwd()
|
|
179
|
+
link_file = _link_file(project_root)
|
|
180
|
+
|
|
181
|
+
if link_file.exists():
|
|
182
|
+
linked_assistant_name = read_assistant_name(project_root)
|
|
183
|
+
if linked_assistant_name == assistant_name:
|
|
184
|
+
rasa.shared.utils.cli.print_info(
|
|
185
|
+
f"Project is already linked to assistant '{assistant_name}'."
|
|
186
|
+
)
|
|
187
|
+
sys.exit(0)
|
|
188
|
+
|
|
189
|
+
overwrite = questionary.confirm(
|
|
190
|
+
f"Project is currently linked to the following Rasa Studio assistant:\n\n"
|
|
191
|
+
f" Assistant name: {linked_assistant_name}\n"
|
|
192
|
+
f" Studio URL: {studio_cfg.studio_url}\n"
|
|
193
|
+
f" Keycloak Auth URL: {studio_cfg.authentication_server_url}\n\n"
|
|
194
|
+
f"Do you want to overwrite it with the new assistant '{assistant_name}'?"
|
|
195
|
+
).ask()
|
|
196
|
+
if not overwrite:
|
|
197
|
+
rasa.shared.utils.cli.print_info(
|
|
198
|
+
"Existing link kept – nothing was changed."
|
|
199
|
+
)
|
|
200
|
+
sys.exit(0)
|
|
201
|
+
|
|
202
|
+
_write_link_file(project_root, assistant_name, studio_cfg.studio_url)
|
|
203
|
+
|
|
204
|
+
structlogger.info(
|
|
205
|
+
"studio.link.success",
|
|
206
|
+
event_info=f"Project linked to Studio assistant '{assistant_name}'.",
|
|
207
|
+
assistant_name=assistant_name,
|
|
208
|
+
)
|
|
209
|
+
rasa.shared.utils.cli.print_success(
|
|
210
|
+
f"Project successfully linked to assistant '{assistant_name}'."
|
|
211
|
+
)
|
rasa/studio/prompts.py
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Dict, List, Optional, Text
|
|
3
|
+
|
|
4
|
+
import structlog
|
|
5
|
+
|
|
6
|
+
from rasa.core.policies.enterprise_search_policy import EnterpriseSearchPolicy
|
|
7
|
+
from rasa.dialogue_understanding.generator.llm_based_command_generator import (
|
|
8
|
+
LLMBasedCommandGenerator,
|
|
9
|
+
)
|
|
10
|
+
from rasa.shared.constants import (
|
|
11
|
+
CONFIG_NAME_KEY,
|
|
12
|
+
CONFIG_PIPELINE_KEY,
|
|
13
|
+
CONFIG_POLICIES_KEY,
|
|
14
|
+
DEFAULT_CONFIG_PATH,
|
|
15
|
+
DEFAULT_ENDPOINTS_PATH,
|
|
16
|
+
DEFAULT_PROMPTS_PATH,
|
|
17
|
+
PROMPT_CONFIG_KEY,
|
|
18
|
+
PROMPT_TEMPLATE_CONFIG_KEY,
|
|
19
|
+
)
|
|
20
|
+
from rasa.shared.utils.common import all_subclasses
|
|
21
|
+
from rasa.shared.utils.llm import get_system_default_prompts
|
|
22
|
+
from rasa.shared.utils.yaml import read_yaml, write_yaml
|
|
23
|
+
|
|
24
|
+
structlogger = structlog.get_logger()
|
|
25
|
+
|
|
26
|
+
CONTEXTUAL_RESPONSE_REPHRASER_NAME = "contextual_response_rephraser"
|
|
27
|
+
COMMAND_GENERATOR_NAME = "command_generator"
|
|
28
|
+
ENTERPRISE_SEARCH_NAME = "enterprise_search"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def handle_prompts(prompts: Dict[Text, Text], root: Path) -> None:
|
|
32
|
+
"""Handle prompts for the assistant.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
prompts: A dict containing prompt names as keys and their content as values.
|
|
36
|
+
root: The root directory where the prompts should be saved.
|
|
37
|
+
"""
|
|
38
|
+
if not prompts:
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
config_path = root / DEFAULT_CONFIG_PATH
|
|
42
|
+
endpoints_path = root / DEFAULT_ENDPOINTS_PATH
|
|
43
|
+
config: Dict = read_yaml(config_path)
|
|
44
|
+
endpoints: Dict = read_yaml(endpoints_path)
|
|
45
|
+
|
|
46
|
+
system_prompts = get_system_default_prompts(config, endpoints)
|
|
47
|
+
|
|
48
|
+
_handle_contextual_response_rephraser(
|
|
49
|
+
root,
|
|
50
|
+
prompts.get(CONTEXTUAL_RESPONSE_REPHRASER_NAME),
|
|
51
|
+
system_prompts.contextual_response_rephraser,
|
|
52
|
+
endpoints,
|
|
53
|
+
)
|
|
54
|
+
_handle_command_generator(
|
|
55
|
+
root,
|
|
56
|
+
prompts.get(COMMAND_GENERATOR_NAME),
|
|
57
|
+
system_prompts.command_generator,
|
|
58
|
+
config,
|
|
59
|
+
)
|
|
60
|
+
_handle_enterprise_search(
|
|
61
|
+
root,
|
|
62
|
+
prompts.get(ENTERPRISE_SEARCH_NAME),
|
|
63
|
+
system_prompts.enterprise_search,
|
|
64
|
+
config,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _handle_contextual_response_rephraser(
|
|
69
|
+
root: Path,
|
|
70
|
+
prompt_content: Optional[Text],
|
|
71
|
+
system_prompt: Optional[Text],
|
|
72
|
+
endpoints: Dict,
|
|
73
|
+
) -> None:
|
|
74
|
+
"""Handles the contextual response rephraser prompt.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
root: The root directory where the prompt file will be saved.
|
|
78
|
+
prompt_content: The content of the contextual response rephraser prompt.
|
|
79
|
+
system_prompt: The system prompt for comparison.
|
|
80
|
+
endpoints: The endpoints configuration to update with the prompt path.
|
|
81
|
+
"""
|
|
82
|
+
if not _is_custom_prompt(prompt_content, system_prompt):
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
prompt_path = _save_prompt_file(
|
|
86
|
+
root, f"{CONTEXTUAL_RESPONSE_REPHRASER_NAME}.jinja2", prompt_content
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
endpoints["nlg"] = endpoints.get("nlg") or {}
|
|
90
|
+
endpoints["nlg"]["prompt"] = str(prompt_path)
|
|
91
|
+
|
|
92
|
+
endpoints_path = root / DEFAULT_ENDPOINTS_PATH
|
|
93
|
+
write_yaml(data=endpoints, target=endpoints_path, should_preserve_key_order=True)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _handle_command_generator(
|
|
97
|
+
root: Path,
|
|
98
|
+
prompt_content: Optional[Text],
|
|
99
|
+
system_prompt: Optional[Text],
|
|
100
|
+
config: Dict,
|
|
101
|
+
) -> None:
|
|
102
|
+
"""Handles the command generator prompt.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
root: The root directory where the prompt file will be saved.
|
|
106
|
+
prompt_content: The content of the command generator prompt.
|
|
107
|
+
system_prompt: The system prompt for comparison.
|
|
108
|
+
config: The configuration dictionary to update with the prompt path.
|
|
109
|
+
"""
|
|
110
|
+
if not _is_custom_prompt(prompt_content, system_prompt):
|
|
111
|
+
return
|
|
112
|
+
|
|
113
|
+
prompt_path = _save_prompt_file(
|
|
114
|
+
root, f"{COMMAND_GENERATOR_NAME}.jinja2", prompt_content
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
command_generator_names: List[str] = [
|
|
118
|
+
cls.__name__ for cls in all_subclasses(LLMBasedCommandGenerator)
|
|
119
|
+
]
|
|
120
|
+
_add_prompt_to_config(
|
|
121
|
+
config=config,
|
|
122
|
+
section_key=CONFIG_PIPELINE_KEY,
|
|
123
|
+
component_names=command_generator_names,
|
|
124
|
+
prompt_key=PROMPT_TEMPLATE_CONFIG_KEY,
|
|
125
|
+
prompt_path=str(prompt_path),
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
config_path = root / DEFAULT_CONFIG_PATH
|
|
129
|
+
write_yaml(data=config, target=config_path, should_preserve_key_order=True)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _handle_enterprise_search(
|
|
133
|
+
root: Path,
|
|
134
|
+
prompt_content: Optional[Text],
|
|
135
|
+
system_prompt: Optional[Text],
|
|
136
|
+
config: Dict,
|
|
137
|
+
) -> None:
|
|
138
|
+
"""Handles the enterprise search prompt.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
root: The root directory where the prompt file will be saved.
|
|
142
|
+
prompt_content: The content of the enterprise search prompt.
|
|
143
|
+
system_prompt: The system prompt for comparison.
|
|
144
|
+
config: The configuration dictionary to update with the prompt path.
|
|
145
|
+
"""
|
|
146
|
+
if not _is_custom_prompt(prompt_content, system_prompt):
|
|
147
|
+
return
|
|
148
|
+
|
|
149
|
+
prompt_path = _save_prompt_file(
|
|
150
|
+
root, f"{ENTERPRISE_SEARCH_NAME}.jinja2", prompt_content
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
_add_prompt_to_config(
|
|
154
|
+
config=config,
|
|
155
|
+
section_key=CONFIG_POLICIES_KEY,
|
|
156
|
+
component_names=[EnterpriseSearchPolicy.__name__],
|
|
157
|
+
prompt_key=PROMPT_CONFIG_KEY,
|
|
158
|
+
prompt_path=str(prompt_path),
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
config_path = root / DEFAULT_CONFIG_PATH
|
|
162
|
+
write_yaml(data=config, target=config_path, should_preserve_key_order=True)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _is_custom_prompt(
|
|
166
|
+
studio_prompt: Optional[Text], system_prompt: Optional[Text]
|
|
167
|
+
) -> bool:
|
|
168
|
+
"""Check if the prompt has been customized in Studio.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
studio_prompt: The prompt content from the Studio.
|
|
172
|
+
system_prompt: The default system prompt content.
|
|
173
|
+
"""
|
|
174
|
+
return bool(studio_prompt and studio_prompt != system_prompt)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _save_prompt_file(root: Path, filename: str, content: str) -> Path:
|
|
178
|
+
"""Save a prompt file to the specified root directory.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
root: The root directory where the prompt file will be saved.
|
|
182
|
+
filename: The name of the prompt file.
|
|
183
|
+
content: The content of the prompt.
|
|
184
|
+
"""
|
|
185
|
+
prompts_dir = root / DEFAULT_PROMPTS_PATH
|
|
186
|
+
prompts_dir.mkdir(parents=True, exist_ok=True)
|
|
187
|
+
|
|
188
|
+
file_path = prompts_dir / filename
|
|
189
|
+
file_path.write_text(content, encoding="utf-8")
|
|
190
|
+
|
|
191
|
+
return file_path.relative_to(root)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def _add_prompt_to_config(
|
|
195
|
+
*,
|
|
196
|
+
config: Dict,
|
|
197
|
+
section_key: str,
|
|
198
|
+
component_names: List[str],
|
|
199
|
+
prompt_key: str,
|
|
200
|
+
prompt_path: str,
|
|
201
|
+
) -> None:
|
|
202
|
+
"""Add a prompt path to the specified section of the configuration."""
|
|
203
|
+
matches = [
|
|
204
|
+
component
|
|
205
|
+
for component in config.get(section_key, [])
|
|
206
|
+
if component.get(CONFIG_NAME_KEY) in component_names
|
|
207
|
+
]
|
|
208
|
+
|
|
209
|
+
if not matches:
|
|
210
|
+
return
|
|
211
|
+
|
|
212
|
+
# Update the first occurrence of the component.
|
|
213
|
+
matches[0][prompt_key] = prompt_path
|
|
214
|
+
|
|
215
|
+
if len(matches) > 1:
|
|
216
|
+
structlogger.warning(
|
|
217
|
+
"rasa.studio.prompts.add_prompt_to_config.multiple_components",
|
|
218
|
+
event_info=(
|
|
219
|
+
"Multiple components found in the configuration for the same prompt."
|
|
220
|
+
),
|
|
221
|
+
)
|
|
File without changes
|
rasa/studio/pull/data.py
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any, Dict, List, Set, Text
|
|
4
|
+
|
|
5
|
+
from rasa.shared.core.flows import Flow
|
|
6
|
+
from rasa.shared.core.flows.flows_list import FlowsList
|
|
7
|
+
from rasa.shared.core.flows.yaml_flows_io import YAMLFlowsReader, YamlFlowsWriter
|
|
8
|
+
from rasa.shared.importers.importer import TrainingDataImporter
|
|
9
|
+
from rasa.shared.utils.yaml import read_yaml
|
|
10
|
+
from rasa.studio.constants import STUDIO_NLU_FILENAME
|
|
11
|
+
from rasa.utils.mapper import RasaPrimitiveStorageMapper
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
STUDIO_FLOWS_DIR_NAME = "flows"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def merge_nlu_in_directory(
|
|
19
|
+
data_from_studio: TrainingDataImporter,
|
|
20
|
+
data_local: TrainingDataImporter,
|
|
21
|
+
data_path: Path,
|
|
22
|
+
mapper: RasaPrimitiveStorageMapper,
|
|
23
|
+
) -> None:
|
|
24
|
+
"""
|
|
25
|
+
Merges NLU data by checking for an existing NLU file in the directory.
|
|
26
|
+
If it exists, the new Studio data is merged with the local data.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
data_from_studio: The TrainingDataImporter instance for Studio data.
|
|
30
|
+
data_local: The TrainingDataImporter instance for local data.
|
|
31
|
+
data_path: The path to the training data directory.
|
|
32
|
+
mapper: The RasaPrimitiveStorageMapper instance for mapping.
|
|
33
|
+
"""
|
|
34
|
+
from rasa.studio.download import pretty_write_nlu_yaml
|
|
35
|
+
|
|
36
|
+
nlu_data = data_from_studio.get_nlu_data()
|
|
37
|
+
nlu_file_path = get_nlu_path(data_path, data_local, mapper)
|
|
38
|
+
|
|
39
|
+
if nlu_file_path.exists():
|
|
40
|
+
local_nlu = TrainingDataImporter.load_from_dict(
|
|
41
|
+
training_data_paths=[str(nlu_file_path)]
|
|
42
|
+
)
|
|
43
|
+
nlu_data = nlu_data.merge(local_nlu.get_nlu_data())
|
|
44
|
+
|
|
45
|
+
if nlu_yaml := nlu_data.nlu_as_yaml():
|
|
46
|
+
pretty_write_nlu_yaml(read_yaml(nlu_yaml), nlu_file_path)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_nlu_path(
|
|
50
|
+
base_path: Path,
|
|
51
|
+
data_local: TrainingDataImporter,
|
|
52
|
+
mapper: RasaPrimitiveStorageMapper,
|
|
53
|
+
) -> Path:
|
|
54
|
+
"""Determines where NLU data should be stored.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
base_path: The base path for the training data.
|
|
58
|
+
data_local: The TrainingDataImporter instance for local data.
|
|
59
|
+
mapper: The RasaPrimitiveStorageMapper instance for mapping.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
The path where NLU data should be stored.
|
|
63
|
+
"""
|
|
64
|
+
nlu_paths = set()
|
|
65
|
+
for intent in data_local.get_nlu_data().intents:
|
|
66
|
+
for p in mapper.get_file(intent, "intents").get("training", []):
|
|
67
|
+
nlu_paths.add(p)
|
|
68
|
+
|
|
69
|
+
return _select_path(nlu_paths, "nlu", base_path, STUDIO_NLU_FILENAME)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def merge_flows_in_directory(
|
|
73
|
+
data_from_studio: TrainingDataImporter,
|
|
74
|
+
data_path: Path,
|
|
75
|
+
mapper: RasaPrimitiveStorageMapper,
|
|
76
|
+
) -> None:
|
|
77
|
+
"""
|
|
78
|
+
Merges flows data by updating local flow files in a directory with any changes
|
|
79
|
+
from Studio, and then dumping any new flows that do not exist in any local file.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
data_from_studio: Training data importer containing the flows from Studio.
|
|
83
|
+
data_path: The path to the directory where local flows reside.
|
|
84
|
+
mapper: Utility for mapping flow IDs to their respective file paths.
|
|
85
|
+
"""
|
|
86
|
+
# Extract flows from Studio data and map flow IDs to their instances.
|
|
87
|
+
studio_flows = data_from_studio.get_user_flows()
|
|
88
|
+
studio_flow_map: Dict[Text, Flow] = {
|
|
89
|
+
flow.id: flow for flow in studio_flows.underlying_flows
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
# Load existing local flows from the specified directory.
|
|
93
|
+
local_flows_file = TrainingDataImporter.load_from_dict(
|
|
94
|
+
training_data_paths=[str(data_path)]
|
|
95
|
+
)
|
|
96
|
+
local_flows = local_flows_file.get_user_flows().underlying_flows
|
|
97
|
+
|
|
98
|
+
# Gather the unique file paths where each local flow is stored.
|
|
99
|
+
local_flow_paths: Set[Path] = _get_local_flow_paths(local_flows, mapper)
|
|
100
|
+
|
|
101
|
+
# Track updated flows and update local files with Studio flow data.
|
|
102
|
+
all_updated_flows_ids: List[Text] = []
|
|
103
|
+
for flow_file_path in local_flow_paths:
|
|
104
|
+
updated_flows_ids = _update_flow_file(flow_file_path, studio_flow_map)
|
|
105
|
+
all_updated_flows_ids.extend(updated_flows_ids)
|
|
106
|
+
|
|
107
|
+
# Identify new Studio flows and save them as separate files in the directory.
|
|
108
|
+
new_flows = [
|
|
109
|
+
flow
|
|
110
|
+
for flow_id, flow in studio_flow_map.items()
|
|
111
|
+
if flow_id not in all_updated_flows_ids
|
|
112
|
+
]
|
|
113
|
+
_dump_flows_as_separate_files(new_flows, data_path)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _get_local_flow_paths(
|
|
117
|
+
local_flows: List[Any],
|
|
118
|
+
mapper: RasaPrimitiveStorageMapper,
|
|
119
|
+
) -> Set[Path]:
|
|
120
|
+
"""
|
|
121
|
+
Args:
|
|
122
|
+
local_flows: List of local flows.
|
|
123
|
+
mapper: The RasaPrimitiveStorageMapper instance for mapping.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
A set of paths for the local flow files.
|
|
127
|
+
"""
|
|
128
|
+
paths: Set[Path] = set()
|
|
129
|
+
for flow in local_flows:
|
|
130
|
+
paths.update(mapper.get_file(flow.id, "flows").get("training", []))
|
|
131
|
+
return paths
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _update_flow_file(
|
|
135
|
+
flow_file_path: Path, studio_flows_map: Dict[Text, Any]
|
|
136
|
+
) -> List[Text]:
|
|
137
|
+
"""
|
|
138
|
+
Reads a flow file, updates outdated flows, and replaces them with studio versions.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
flow_file_path: The path to the flow file.
|
|
142
|
+
studio_flows_map: A dictionary mapping flow IDs to their updated versions.
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
A list of Flows IDs from the updated flow file.
|
|
146
|
+
"""
|
|
147
|
+
file_flows = YAMLFlowsReader.read_from_file(flow_file_path, False)
|
|
148
|
+
|
|
149
|
+
# Build a list of flows, replacing any outdated flow with its studio version
|
|
150
|
+
updated_flows = [
|
|
151
|
+
studio_flows_map.get(flow.id, flow) or flow
|
|
152
|
+
for flow in file_flows.underlying_flows
|
|
153
|
+
]
|
|
154
|
+
|
|
155
|
+
# If the updated flows differ from the original file flows, write them back
|
|
156
|
+
if updated_flows != file_flows.underlying_flows:
|
|
157
|
+
YamlFlowsWriter.dump(
|
|
158
|
+
flows=updated_flows,
|
|
159
|
+
filename=flow_file_path,
|
|
160
|
+
should_clean_json=True,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
return [flow.id for flow in updated_flows]
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _dump_flows_as_separate_files(flows: List[Any], data_path: Path) -> None:
|
|
167
|
+
"""Dump flow into separate files within a directory.
|
|
168
|
+
|
|
169
|
+
Creates a new directory under the given data_path and writes each flow
|
|
170
|
+
into a separate YAML file. Each file is named after the flow's id.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
flows: List of new flows to be dumped.
|
|
174
|
+
data_path: The path to the directory where the files will be created.
|
|
175
|
+
"""
|
|
176
|
+
# If there are no flows, don't create a directory.
|
|
177
|
+
if not flows:
|
|
178
|
+
return
|
|
179
|
+
|
|
180
|
+
new_flows_dir = data_path / STUDIO_FLOWS_DIR_NAME
|
|
181
|
+
new_flows_dir.mkdir(parents=True, exist_ok=True)
|
|
182
|
+
for flow in flows:
|
|
183
|
+
file_name = f"{flow.id}.yml"
|
|
184
|
+
file_path = new_flows_dir / file_name
|
|
185
|
+
single_flow_list = FlowsList(underlying_flows=[flow])
|
|
186
|
+
YamlFlowsWriter.dump(
|
|
187
|
+
flows=single_flow_list.underlying_flows,
|
|
188
|
+
filename=file_path,
|
|
189
|
+
should_clean_json=True,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def _select_path(
|
|
194
|
+
paths: Set[Path], primitive_type: str, default_path: Path, default: str
|
|
195
|
+
) -> Path:
|
|
196
|
+
"""Selects a path from a set of paths.
|
|
197
|
+
|
|
198
|
+
If exactly one path exists, returns it.
|
|
199
|
+
If multiple exist, returns one with a warning.
|
|
200
|
+
If none exist, returns a default path.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
paths: A set of paths.
|
|
204
|
+
primitive_type: The type of the primitive (e.g., "domain", "nlu").
|
|
205
|
+
default_path: The default path to use if no paths exist.
|
|
206
|
+
default: The default file name.
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
The selected path.
|
|
210
|
+
"""
|
|
211
|
+
if len(paths) == 1:
|
|
212
|
+
path = paths.pop()
|
|
213
|
+
elif len(paths) > 1:
|
|
214
|
+
path = paths.pop()
|
|
215
|
+
logger.warning(
|
|
216
|
+
f"Saving {primitive_type} to {path}. "
|
|
217
|
+
f"Please keep Studio-related {primitive_type} in a single file."
|
|
218
|
+
)
|
|
219
|
+
else:
|
|
220
|
+
path = default_path / Path(default)
|
|
221
|
+
logger.info(f"Saving {primitive_type} to {path}.")
|
|
222
|
+
return path
|