rasa-pro 3.12.18.dev1__py3-none-any.whl → 3.13.0a1.dev1__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/__init__.py +0 -6
- rasa/__main__.py +3 -4
- rasa/api.py +1 -1
- rasa/builder/create_openai_vector_store.py +69 -0
- rasa/builder/llm-helper-schema.json +69 -0
- rasa/builder/prompt_to_bot.py +645 -0
- rasa/builder/scrape_rasa_docs.py +97 -0
- rasa/builder/skill_to_bot_prompt.jinja +158 -0
- rasa/cli/dialogue_understanding_test.py +1 -1
- rasa/cli/e2e_test.py +1 -1
- rasa/cli/evaluate.py +2 -2
- rasa/cli/export.py +3 -3
- 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/run.py +1 -1
- rasa/cli/scaffold.py +2 -3
- rasa/cli/studio/download.py +1 -1
- rasa/cli/studio/link.py +53 -0
- rasa/cli/studio/pull.py +78 -0
- rasa/cli/studio/push.py +78 -0
- rasa/cli/studio/studio.py +12 -0
- rasa/cli/studio/upload.py +5 -3
- rasa/cli/train.py +1 -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 +42 -31
- rasa/core/actions/action_repeat_bot_messages.py +18 -22
- rasa/core/actions/action_run_slot_rejections.py +1 -2
- rasa/core/agent.py +18 -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/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-02053cc1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-7f34db23.js → blockDiagram-38ab4fdb-008b6289.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-948bab2c.js → c4Diagram-3d4e48cf-fb2597be.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-078dada8.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-53b0dd0e.js → classDiagram-70f12bd4-7f847e00.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-fdf789e7.js → classDiagram-v2-f2320105-ba1d689b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-5b4516de.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-87c4ece5.js → createText-2e5e7dd3-dd8e67c4.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-5a8b0749.js → edges-e0da2a9e-10784939.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-66da90e2.js → erDiagram-9861fffd-24947ae6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-10044f05.js → flowDb-956e92f1-a9ced505.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-f338f66a.js → flowDiagram-66a62f08-afda9c7c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-f9613071.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-b13140aa.js → flowchart-elk-definition-4a651766-6ef530b8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-f2b4a55a.js → ganttDiagram-c361ad54-0c7dd39a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-dedc298d.js → gitGraphDiagram-72cf32ee-b57239d6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-4ede11ff.js → graph-9ed57cec.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-65549d37.js → index-3862675e-233090de.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3a23e736.js → index-72184470.js} +123 -123
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-65439671.js → infoDiagram-f8f76790-aa116649.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-56d03d98.js → journeyDiagram-49397b02-e51877cc.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-dd48f7f4.js → layout-3ca3798c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-1569ad2c.js → line-26ee10d3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-48bf4935.js → linear-aedded32.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-688504c1.js → mindmap-definition-fc14e90a-d8957261.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-78b6d7e6.js → pieDiagram-8a3498a8-d771f885.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-048b84b3.js → quadrantDiagram-120e2f19-09fdf50c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-dd67f107.js → requirementDiagram-deff3bca-9f0af02e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-8128436e.js → sankeyDiagram-04a897e0-84415b37.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-1a0d1461.js → sequenceDiagram-704730f1-8dec4055.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-46d388ed.js → stateDiagram-587899a1-c5431d07.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-ea42951a.js → stateDiagram-v2-d93cdb3a-274e77d9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-7427ed0c.js → styles-6aaf32cf-e364a1d7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-ff5e5a16.js → styles-9a916d00-0dae36f6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-7b3680cf.js → styles-c10674c1-c4641675.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-f860f2ad.js → svgDrawCommon-08f97a94-831fe9a1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-2eebf0c8.js → timeline-definition-85554ec2-c3304b3a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-5d7f4e96.js → xychartDiagram-e933f94c-da799369.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 +337 -71
- rasa/core/channels/vier_cvg.py +1 -2
- rasa/core/channels/voice_ready/audiocodes.py +4 -11
- rasa/core/channels/voice_stream/audiocodes.py +8 -5
- rasa/core/channels/voice_stream/browser_audio.py +1 -1
- rasa/core/channels/voice_stream/genesys.py +2 -2
- rasa/core/channels/voice_stream/tts/__init__.py +8 -0
- rasa/core/channels/voice_stream/twilio_media_streams.py +10 -5
- rasa/core/channels/voice_stream/voice_channel.py +65 -23
- rasa/core/concurrent_lock_store.py +24 -10
- rasa/core/evaluation/marker_tracker_loader.py +1 -1
- rasa/core/exporter.py +1 -1
- rasa/core/http_interpreter.py +3 -7
- rasa/core/information_retrieval/faiss.py +18 -11
- rasa/core/information_retrieval/ingestion/__init__.py +0 -0
- 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 +262 -62
- rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2 +63 -0
- rasa/core/policies/flow_policy.py +1 -1
- rasa/core/policies/flows/flow_executor.py +96 -17
- rasa/core/policies/intentless_policy.py +57 -20
- rasa/core/processor.py +114 -54
- 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} +5 -1
- rasa/core/tracker_stores/dynamo_tracker_store.py +218 -0
- rasa/core/tracker_stores/mongo_tracker_store.py +206 -0
- rasa/core/tracker_stores/redis_tracker_store.py +219 -0
- rasa/core/tracker_stores/sql_tracker_store.py +555 -0
- rasa/core/tracker_stores/tracker_store.py +805 -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 +10 -6
- rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -0
- rasa/dialogue_understanding/commands/cancel_flow_command.py +5 -1
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +2 -0
- rasa/dialogue_understanding/commands/clarify_command.py +4 -0
- rasa/dialogue_understanding/commands/command_syntax_manager.py +1 -0
- rasa/dialogue_understanding/commands/correct_slots_command.py +1 -3
- rasa/dialogue_understanding/commands/human_handoff_command.py +2 -0
- 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 +10 -0
- rasa/dialogue_understanding/commands/skip_question_command.py +2 -0
- rasa/dialogue_understanding/commands/start_flow_command.py +4 -0
- rasa/dialogue_understanding/commands/utils.py +26 -2
- 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 +5 -17
- rasa/dialogue_understanding/generator/llm_command_generator.py +1 -3
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +4 -44
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +2 -2
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +78 -0
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +26 -474
- 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 +477 -0
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +11 -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 +37 -25
- rasa/dialogue_understanding/patterns/domain_for_patterns.py +190 -0
- rasa/dialogue_understanding/processor/command_processor.py +6 -7
- rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +17 -4
- rasa/dialogue_understanding/stack/utils.py +3 -1
- rasa/dialogue_understanding/utils.py +68 -12
- 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/io.py +35 -8
- rasa/e2e_test/e2e_test_runner.py +1 -1
- 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 -85
- rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +1 -5
- rasa/llm_fine_tuning/utils.py +2 -4
- rasa/model_manager/model_api.py +90 -2
- rasa/model_manager/socket_bridge.py +0 -7
- rasa/model_manager/trainer_service.py +15 -12
- 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 +340 -0
- rasa/privacy/privacy_manager.py +576 -0
- rasa/server.py +23 -2
- rasa/shared/constants.py +13 -4
- 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 +35 -8
- rasa/shared/core/flows/flow_step.py +26 -4
- 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 +16 -3
- rasa/shared/core/flows/yaml_flows_io.py +106 -5
- rasa/shared/core/slots.py +33 -1
- rasa/shared/core/trackers.py +4 -10
- rasa/shared/core/training_data/story_reader/yaml_story_reader.py +1 -4
- rasa/shared/importers/importer.py +14 -0
- rasa/shared/importers/static.py +63 -0
- rasa/shared/providers/constants.py +0 -9
- rasa/shared/providers/llm/_base_litellm_client.py +4 -14
- rasa/shared/providers/llm/default_litellm_llm_client.py +2 -2
- rasa/shared/providers/llm/litellm_router_llm_client.py +7 -17
- rasa/shared/providers/llm/llm_client.py +15 -24
- rasa/shared/providers/llm/self_hosted_llm_client.py +2 -10
- rasa/shared/utils/common.py +43 -1
- rasa/shared/utils/llm.py +155 -3
- rasa/shared/utils/yaml.py +32 -0
- rasa/studio/data_handler.py +3 -3
- rasa/studio/download/__init__.py +0 -0
- rasa/studio/download/domains.py +49 -0
- rasa/studio/download/download.py +416 -0
- rasa/studio/download/flows.py +351 -0
- rasa/studio/link.py +200 -0
- rasa/studio/pull.py +94 -0
- rasa/studio/push.py +131 -0
- rasa/studio/results_logger.py +6 -1
- rasa/studio/upload.py +185 -71
- rasa/telemetry.py +83 -26
- rasa/tracing/config.py +4 -5
- rasa/tracing/constants.py +19 -1
- rasa/tracing/instrumentation/attribute_extractors.py +49 -11
- 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 +37 -27
- rasa/utils/endpoints.py +22 -1
- rasa/utils/licensing.py +2 -3
- rasa/utils/log_utils.py +1 -45
- rasa/validator.py +9 -11
- rasa/version.py +1 -1
- {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/METADATA +12 -14
- {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/RECORD +318 -294
- 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/monkey_patches.py +0 -91
- rasa/studio/download.py +0 -489
- /rasa/{cli/project_templates/calm/actions → builder}/__init__.py +0 -0
- /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_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/NOTICE +0 -0
- {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/WHEEL +0 -0
- {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,351 @@
|
|
|
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.flow_step_links import StaticFlowStepLink
|
|
7
|
+
from rasa.shared.core.flows.flows_list import FlowsList
|
|
8
|
+
from rasa.shared.core.flows.yaml_flows_io import YAMLFlowsReader, YamlFlowsWriter
|
|
9
|
+
from rasa.shared.importers.importer import TrainingDataImporter
|
|
10
|
+
from rasa.shared.utils.yaml import read_yaml
|
|
11
|
+
from rasa.studio.constants import STUDIO_NLU_FILENAME
|
|
12
|
+
from rasa.studio.data_handler import StudioDataHandler
|
|
13
|
+
from rasa.utils.mapper import RasaPrimitiveStorageMapper
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
STUDIO_FLOWS_DIR_NAME = "studio_flows"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def merge_flows_with_overwrite(
|
|
21
|
+
data_path: Path,
|
|
22
|
+
handler: Any,
|
|
23
|
+
data_from_studio: TrainingDataImporter,
|
|
24
|
+
data_local: TrainingDataImporter,
|
|
25
|
+
mapper: RasaPrimitiveStorageMapper,
|
|
26
|
+
) -> None:
|
|
27
|
+
"""
|
|
28
|
+
Merges flows data from a file or directory when overwrite is enabled.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
data_path: List of paths to the training data.
|
|
32
|
+
handler: The StudioDataHandler instance.
|
|
33
|
+
data_from_studio: The TrainingDataImporter instance for Studio data.
|
|
34
|
+
data_local: The TrainingDataImporter instance for local data.
|
|
35
|
+
mapper: The RasaPrimitiveStorageMapper instance for mapping.
|
|
36
|
+
"""
|
|
37
|
+
if data_path.is_file():
|
|
38
|
+
merge_training_data_file(handler, data_from_studio, data_local, data_path)
|
|
39
|
+
elif data_path.is_dir():
|
|
40
|
+
merge_training_data_dir(
|
|
41
|
+
handler, data_from_studio, data_local, data_path, mapper
|
|
42
|
+
)
|
|
43
|
+
else:
|
|
44
|
+
raise ValueError("Provided data path is neither a file nor a directory.")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def merge_training_data_file(
|
|
48
|
+
handler: StudioDataHandler,
|
|
49
|
+
data_from_studio: TrainingDataImporter,
|
|
50
|
+
data_local: TrainingDataImporter,
|
|
51
|
+
file_path: Path,
|
|
52
|
+
) -> None:
|
|
53
|
+
"""
|
|
54
|
+
Merges NLU and flows data when training data is stored in a single file.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
handler: The StudioDataHandler instance.
|
|
58
|
+
data_from_studio: The TrainingDataImporter instance for Studio data.
|
|
59
|
+
data_local: The TrainingDataImporter instance for local data.
|
|
60
|
+
file_path: The path to the training data file.
|
|
61
|
+
"""
|
|
62
|
+
if handler.has_nlu():
|
|
63
|
+
nlu_data_merged = data_from_studio.get_nlu_data().merge(
|
|
64
|
+
data_local.get_nlu_data()
|
|
65
|
+
)
|
|
66
|
+
nlu_data_merged.persist_nlu(file_path)
|
|
67
|
+
|
|
68
|
+
if handler.has_flows():
|
|
69
|
+
flows_data_merged = data_from_studio.get_user_flows().merge(
|
|
70
|
+
data_local.get_user_flows()
|
|
71
|
+
)
|
|
72
|
+
YamlFlowsWriter.dump(
|
|
73
|
+
flows=flows_data_merged.underlying_flows,
|
|
74
|
+
filename=file_path,
|
|
75
|
+
should_clean_json=True,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def merge_training_data_dir(
|
|
80
|
+
handler: StudioDataHandler,
|
|
81
|
+
data_from_studio: TrainingDataImporter,
|
|
82
|
+
data_local: TrainingDataImporter,
|
|
83
|
+
data_path: Path,
|
|
84
|
+
mapper: RasaPrimitiveStorageMapper,
|
|
85
|
+
) -> None:
|
|
86
|
+
"""
|
|
87
|
+
Merges NLU and flows data when training data is stored in a directory.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
handler: The StudioDataHandler instance.
|
|
91
|
+
data_from_studio: The TrainingDataImporter instance for Studio data.
|
|
92
|
+
data_local: The TrainingDataImporter instance for local data.
|
|
93
|
+
data_path: The path to the training data directory.
|
|
94
|
+
mapper: The RasaPrimitiveStorageMapper instance for mapping.
|
|
95
|
+
"""
|
|
96
|
+
if handler.has_nlu():
|
|
97
|
+
merge_nlu_in_directory(data_from_studio, data_local, data_path, mapper)
|
|
98
|
+
|
|
99
|
+
if handler.has_flows():
|
|
100
|
+
merge_flows_in_directory(data_from_studio, data_path, mapper)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def merge_nlu_in_directory(
|
|
104
|
+
data_from_studio: TrainingDataImporter,
|
|
105
|
+
data_local: TrainingDataImporter,
|
|
106
|
+
data_path: Path,
|
|
107
|
+
mapper: RasaPrimitiveStorageMapper,
|
|
108
|
+
) -> None:
|
|
109
|
+
"""
|
|
110
|
+
Merges NLU data by checking for an existing NLU file in the directory.
|
|
111
|
+
If it exists, the new Studio data is merged with the local data.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
data_from_studio: The TrainingDataImporter instance for Studio data.
|
|
115
|
+
data_local: The TrainingDataImporter instance for local data.
|
|
116
|
+
data_path: The path to the training data directory.
|
|
117
|
+
mapper: The RasaPrimitiveStorageMapper instance for mapping.
|
|
118
|
+
"""
|
|
119
|
+
from rasa.studio.download.download import pretty_write_nlu_yaml
|
|
120
|
+
|
|
121
|
+
nlu_data = data_from_studio.get_nlu_data()
|
|
122
|
+
nlu_file_path = get_nlu_path(data_path, data_local, mapper)
|
|
123
|
+
|
|
124
|
+
if nlu_file_path.exists():
|
|
125
|
+
local_nlu = TrainingDataImporter.load_from_dict(
|
|
126
|
+
training_data_paths=[str(nlu_file_path)]
|
|
127
|
+
)
|
|
128
|
+
nlu_data = nlu_data.merge(local_nlu.get_nlu_data())
|
|
129
|
+
|
|
130
|
+
if nlu_yaml := nlu_data.nlu_as_yaml():
|
|
131
|
+
pretty_write_nlu_yaml(read_yaml(nlu_yaml), nlu_file_path)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def get_nlu_path(
|
|
135
|
+
base_path: Path,
|
|
136
|
+
data_local: TrainingDataImporter,
|
|
137
|
+
mapper: RasaPrimitiveStorageMapper,
|
|
138
|
+
) -> Path:
|
|
139
|
+
"""Determines where NLU data should be stored.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
base_path: The base path for the training data.
|
|
143
|
+
data_local: The TrainingDataImporter instance for local data.
|
|
144
|
+
mapper: The RasaPrimitiveStorageMapper instance for mapping.
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
The path where NLU data should be stored.
|
|
148
|
+
"""
|
|
149
|
+
nlu_paths = set()
|
|
150
|
+
for intent in data_local.get_nlu_data().intents:
|
|
151
|
+
for p in mapper.get_file(intent, "intents").get("training", []):
|
|
152
|
+
nlu_paths.add(p)
|
|
153
|
+
|
|
154
|
+
return _select_path(nlu_paths, "nlu", base_path, STUDIO_NLU_FILENAME)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def get_flows_path(
|
|
158
|
+
base_path: Path,
|
|
159
|
+
data_local: TrainingDataImporter,
|
|
160
|
+
mapper: RasaPrimitiveStorageMapper,
|
|
161
|
+
) -> Path:
|
|
162
|
+
"""Determines where flows data should be stored.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
base_path: The base path for the training data.
|
|
166
|
+
data_local: The TrainingDataImporter instance for local data.
|
|
167
|
+
mapper: The RasaPrimitiveStorageMapper instance for mapping.
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
The path where flows data should be stored.
|
|
171
|
+
"""
|
|
172
|
+
flow_paths = set()
|
|
173
|
+
for flow in data_local.get_user_flows().underlying_flows:
|
|
174
|
+
for p in mapper.get_file(flow.id, "flows").get("training", []):
|
|
175
|
+
flow_paths.add(p)
|
|
176
|
+
|
|
177
|
+
return _select_path(flow_paths, "flows", base_path, "flows.yml")
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def merge_flows_in_directory(
|
|
181
|
+
data_from_studio: TrainingDataImporter,
|
|
182
|
+
data_path: Path,
|
|
183
|
+
mapper: RasaPrimitiveStorageMapper,
|
|
184
|
+
) -> None:
|
|
185
|
+
"""
|
|
186
|
+
Merges flows data by updating local flow files in a directory with any changes
|
|
187
|
+
from Studio, and then dumping any new flows that do not exist in any local file.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
data_from_studio: Training data importer containing the flows from Studio.
|
|
191
|
+
data_path: The path to the directory where local flows reside.
|
|
192
|
+
mapper: Utility for mapping flow IDs to their respective file paths.
|
|
193
|
+
"""
|
|
194
|
+
# Extract flows from Studio data and map flow IDs to their instances.
|
|
195
|
+
studio_flows = data_from_studio.get_user_flows()
|
|
196
|
+
studio_flow_map: Dict[Text, Flow] = {
|
|
197
|
+
flow.id: flow for flow in studio_flows.underlying_flows
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
# Load existing local flows from the specified directory.
|
|
201
|
+
local_flows_file = TrainingDataImporter.load_from_dict(
|
|
202
|
+
training_data_paths=[str(data_path)]
|
|
203
|
+
)
|
|
204
|
+
local_flows = local_flows_file.get_user_flows().underlying_flows
|
|
205
|
+
|
|
206
|
+
# Gather the unique file paths where each local flow is stored.
|
|
207
|
+
local_flow_paths: Set[Path] = _get_local_flow_paths(local_flows, mapper)
|
|
208
|
+
|
|
209
|
+
# Track updated flows and update local files with Studio flow data.
|
|
210
|
+
all_updated_flows_ids: List[Text] = []
|
|
211
|
+
for flow_file_path in local_flow_paths:
|
|
212
|
+
updated_flows_ids = _update_flow_file(flow_file_path, studio_flow_map)
|
|
213
|
+
all_updated_flows_ids.extend(updated_flows_ids)
|
|
214
|
+
|
|
215
|
+
# Identify new Studio flows and save them as separate files in the directory.
|
|
216
|
+
new_flows = [
|
|
217
|
+
flow
|
|
218
|
+
for flow_id, flow in studio_flow_map.items()
|
|
219
|
+
if flow_id not in all_updated_flows_ids
|
|
220
|
+
]
|
|
221
|
+
_dump_flows_as_separate_files(new_flows, data_path)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _get_local_flow_paths(
|
|
225
|
+
local_flows: List[Any],
|
|
226
|
+
mapper: RasaPrimitiveStorageMapper,
|
|
227
|
+
) -> Set[Path]:
|
|
228
|
+
"""
|
|
229
|
+
Args:
|
|
230
|
+
local_flows: List of local flows.
|
|
231
|
+
mapper: The RasaPrimitiveStorageMapper instance for mapping.
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
A set of paths for the local flow files.
|
|
235
|
+
"""
|
|
236
|
+
paths: Set[Path] = set()
|
|
237
|
+
for flow in local_flows:
|
|
238
|
+
paths.update(mapper.get_file(flow.id, "flows").get("training", []))
|
|
239
|
+
return paths
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def _update_flow_file(
|
|
243
|
+
flow_file_path: Path, studio_flows_map: Dict[Text, Any]
|
|
244
|
+
) -> List[Text]:
|
|
245
|
+
"""
|
|
246
|
+
Reads a flow file, updates outdated flows, and replaces them with studio versions.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
flow_file_path: The path to the flow file.
|
|
250
|
+
studio_flows_map: A dictionary mapping flow IDs to their updated versions.
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
A list of Flows IDs from the updated flow file.
|
|
254
|
+
"""
|
|
255
|
+
file_flows = YAMLFlowsReader.read_from_file(flow_file_path, False)
|
|
256
|
+
|
|
257
|
+
# Build a list of flows, replacing any outdated flow with its studio version
|
|
258
|
+
updated_flows = [
|
|
259
|
+
studio_flows_map.get(flow.id, flow) or flow
|
|
260
|
+
for flow in file_flows.underlying_flows
|
|
261
|
+
]
|
|
262
|
+
|
|
263
|
+
# If the updated flows differ from the original file flows, write them back
|
|
264
|
+
if updated_flows != file_flows.underlying_flows:
|
|
265
|
+
YamlFlowsWriter.dump(
|
|
266
|
+
flows=updated_flows,
|
|
267
|
+
filename=flow_file_path,
|
|
268
|
+
should_clean_json=True,
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
return [flow.id for flow in updated_flows]
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def _dump_flows_as_separate_files(flows: List[Any], data_path: Path) -> None:
|
|
275
|
+
"""Dump flow into separate files within a directory.
|
|
276
|
+
|
|
277
|
+
Creates a new directory under the given data_path and writes each flow
|
|
278
|
+
into a separate YAML file. Each file is named after the flow's id.
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
flows: List of new flows to be dumped.
|
|
282
|
+
data_path: The path to the directory where the files will be created.
|
|
283
|
+
"""
|
|
284
|
+
# If there are no flows, don't create a directory.
|
|
285
|
+
if not flows:
|
|
286
|
+
return
|
|
287
|
+
|
|
288
|
+
new_flows_dir = data_path / STUDIO_FLOWS_DIR_NAME
|
|
289
|
+
new_flows_dir.mkdir(parents=True, exist_ok=True)
|
|
290
|
+
for flow in flows:
|
|
291
|
+
file_name = f"{flow.id}.yml"
|
|
292
|
+
file_path = new_flows_dir / file_name
|
|
293
|
+
single_flow_list = FlowsList(underlying_flows=[flow])
|
|
294
|
+
YamlFlowsWriter.dump(
|
|
295
|
+
flows=single_flow_list.underlying_flows,
|
|
296
|
+
filename=file_path,
|
|
297
|
+
should_clean_json=True,
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def strip_default_next_references(flows: FlowsList) -> FlowsList:
|
|
302
|
+
"""Strips default next references from flows.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
flows: The FlowsList instance containing the flows.
|
|
306
|
+
|
|
307
|
+
Returns:
|
|
308
|
+
An updated FlowsList instance with default next references removed.
|
|
309
|
+
"""
|
|
310
|
+
default_step_ids = [step.default_id for flow in flows for step in flow.steps]
|
|
311
|
+
for flow in flows:
|
|
312
|
+
for step in flow.steps:
|
|
313
|
+
if (
|
|
314
|
+
step.next.links
|
|
315
|
+
and isinstance(step.next.links[0], StaticFlowStepLink)
|
|
316
|
+
and step.next.links[0].target in default_step_ids
|
|
317
|
+
):
|
|
318
|
+
step.next.links = []
|
|
319
|
+
return flows
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def _select_path(
|
|
323
|
+
paths: Set[Path], primitive_type: str, default_path: Path, default: str
|
|
324
|
+
) -> Path:
|
|
325
|
+
"""Selects a path from a set of paths.
|
|
326
|
+
|
|
327
|
+
If exactly one path exists, returns it.
|
|
328
|
+
If multiple exist, returns one with a warning.
|
|
329
|
+
If none exist, returns a default path.
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
paths: A set of paths.
|
|
333
|
+
primitive_type: The type of the primitive (e.g., "domain", "nlu").
|
|
334
|
+
default_path: The default path to use if no paths exist.
|
|
335
|
+
default: The default file name.
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
The selected path.
|
|
339
|
+
"""
|
|
340
|
+
if len(paths) == 1:
|
|
341
|
+
path = paths.pop()
|
|
342
|
+
elif len(paths) > 1:
|
|
343
|
+
path = paths.pop()
|
|
344
|
+
logger.warning(
|
|
345
|
+
f"Saving {primitive_type} to {path}. "
|
|
346
|
+
f"Please keep Studio-related {primitive_type} in a single file."
|
|
347
|
+
)
|
|
348
|
+
else:
|
|
349
|
+
path = default_path / Path(default)
|
|
350
|
+
logger.info(f"Saving {primitive_type} to {path}.")
|
|
351
|
+
return path
|
rasa/studio/link.py
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
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[0]
|
|
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
|
+
overwrite = questionary.confirm(
|
|
183
|
+
f"This project is already linked " f"(link file '{link_file}').\nOverwrite?"
|
|
184
|
+
).ask()
|
|
185
|
+
if not overwrite:
|
|
186
|
+
rasa.shared.utils.cli.print_info(
|
|
187
|
+
"Existing link kept – nothing was changed."
|
|
188
|
+
)
|
|
189
|
+
sys.exit(0)
|
|
190
|
+
|
|
191
|
+
_write_link_file(project_root, assistant_name, studio_cfg.studio_url)
|
|
192
|
+
|
|
193
|
+
structlogger.info(
|
|
194
|
+
"studio.link.success",
|
|
195
|
+
event_info=f"Project linked to Studio assistant '{assistant_name}'.",
|
|
196
|
+
assistant_name=assistant_name,
|
|
197
|
+
)
|
|
198
|
+
rasa.shared.utils.cli.print_success(
|
|
199
|
+
f"Project successfully linked to assistant '{assistant_name}'."
|
|
200
|
+
)
|
rasa/studio/pull.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Text, Union
|
|
6
|
+
|
|
7
|
+
import structlog
|
|
8
|
+
|
|
9
|
+
import rasa.cli.utils
|
|
10
|
+
import rasa.shared.utils.cli
|
|
11
|
+
from rasa.shared.constants import DEFAULT_CONFIG_PATH, DEFAULT_ENDPOINTS_PATH
|
|
12
|
+
from rasa.shared.utils.io import write_text_file
|
|
13
|
+
from rasa.studio.data_handler import StudioDataHandler
|
|
14
|
+
from rasa.studio.download.download import handle_download
|
|
15
|
+
from rasa.studio.link import get_studio_config, read_assistant_name
|
|
16
|
+
|
|
17
|
+
structlogger = structlog.get_logger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _write_to_file(
|
|
21
|
+
content: Text, file_type: Text, file_path: Text, default_path: Text
|
|
22
|
+
) -> None:
|
|
23
|
+
"""Write the content to a file.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
content: The content to write.
|
|
27
|
+
file_type: The type of file (e.g., "config" or "endpoints".).
|
|
28
|
+
file_path: The path to the file.
|
|
29
|
+
default_path: The default path to use file_path is not valid.
|
|
30
|
+
"""
|
|
31
|
+
path: Union[Path, str, None] = rasa.cli.utils.get_validated_path(
|
|
32
|
+
file_path, file_type, default_path, none_is_valid=True
|
|
33
|
+
)
|
|
34
|
+
write_text_file(content, path, encoding="utf-8")
|
|
35
|
+
rasa.shared.utils.cli.print_success(f"Pulled {file_type} data from assistant.")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def handle_pull(args: argparse.Namespace) -> None:
|
|
39
|
+
"""Pull all data and overwrite the local assistant.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
args: The parsed arguments.
|
|
43
|
+
"""
|
|
44
|
+
assistant_name = read_assistant_name()
|
|
45
|
+
|
|
46
|
+
# Use the CLI command logic to download with overwrite
|
|
47
|
+
download_args = argparse.Namespace(**vars(args))
|
|
48
|
+
download_args.assistant_name = [assistant_name]
|
|
49
|
+
download_args.overwrite = True
|
|
50
|
+
|
|
51
|
+
handle_download(download_args)
|
|
52
|
+
rasa.shared.utils.cli.print_success("Pulled the data from assistant.")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def handle_pull_config(args: argparse.Namespace) -> None:
|
|
56
|
+
"""Pull just the assistant's `config.yml`.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
args: The parsed arguments.
|
|
60
|
+
"""
|
|
61
|
+
studio_cfg = get_studio_config()
|
|
62
|
+
assistant_name = read_assistant_name()
|
|
63
|
+
|
|
64
|
+
handler = StudioDataHandler(studio_cfg, assistant_name)
|
|
65
|
+
handler.request_all_data()
|
|
66
|
+
|
|
67
|
+
config_yaml = handler.get_config()
|
|
68
|
+
if not config_yaml:
|
|
69
|
+
rasa.shared.utils.cli.print_error_and_exit(
|
|
70
|
+
"No configuration data was found in the Studio assistant."
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
_write_to_file(config_yaml, "config", args.config, DEFAULT_CONFIG_PATH)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def handle_pull_endpoints(args: argparse.Namespace) -> None:
|
|
77
|
+
"""Pull just the assistant's `endpoints.yml`.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
args: The parsed arguments.
|
|
81
|
+
"""
|
|
82
|
+
studio_cfg = get_studio_config()
|
|
83
|
+
assistant_name = read_assistant_name()
|
|
84
|
+
|
|
85
|
+
handler = StudioDataHandler(studio_cfg, assistant_name)
|
|
86
|
+
handler.request_all_data()
|
|
87
|
+
|
|
88
|
+
endpoints_yaml = handler.get_endpoints()
|
|
89
|
+
if not endpoints_yaml:
|
|
90
|
+
rasa.shared.utils.cli.print_error_and_exit(
|
|
91
|
+
"No endpoints data was found in the Studio assistant."
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
_write_to_file(endpoints_yaml, "endpoints", args.endpoints, DEFAULT_ENDPOINTS_PATH)
|