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,645 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import importlib
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
import sys
|
|
6
|
+
import tempfile
|
|
7
|
+
import traceback
|
|
8
|
+
from copy import deepcopy
|
|
9
|
+
from textwrap import dedent
|
|
10
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
11
|
+
|
|
12
|
+
import importlib_resources
|
|
13
|
+
import openai
|
|
14
|
+
import structlog
|
|
15
|
+
from jinja2 import Template
|
|
16
|
+
from pydantic import BaseModel
|
|
17
|
+
from sanic import Sanic, response
|
|
18
|
+
from structlog.testing import capture_logs
|
|
19
|
+
|
|
20
|
+
import rasa.core.utils
|
|
21
|
+
from rasa.cli.utils import validate_files
|
|
22
|
+
from rasa.constants import PACKAGE_NAME
|
|
23
|
+
from rasa.core import agent, channels
|
|
24
|
+
from rasa.core.channels.channel import InputChannel
|
|
25
|
+
from rasa.core.channels.studio_chat import StudioChatInput
|
|
26
|
+
from rasa.core.utils import AvailableEndpoints, read_endpoints_from_path
|
|
27
|
+
from rasa.model_training import train
|
|
28
|
+
from rasa.server import configure_cors
|
|
29
|
+
from rasa.shared.constants import DOMAIN_SCHEMA_FILE, RESPONSES_SCHEMA_FILE
|
|
30
|
+
from rasa.shared.core.domain import Domain
|
|
31
|
+
from rasa.shared.core.flows.yaml_flows_io import FLOWS_SCHEMA_FILE, YAMLFlowsReader
|
|
32
|
+
from rasa.shared.core.trackers import DialogueStateTracker
|
|
33
|
+
from rasa.shared.importers.importer import TrainingDataImporter
|
|
34
|
+
from rasa.shared.importers.static import StaticTrainingDataImporter
|
|
35
|
+
from rasa.shared.utils.io import read_json_file
|
|
36
|
+
from rasa.shared.utils.yaml import (
|
|
37
|
+
dump_obj_as_yaml_to_string,
|
|
38
|
+
read_schema_file,
|
|
39
|
+
read_yaml,
|
|
40
|
+
read_yaml_file,
|
|
41
|
+
)
|
|
42
|
+
from rasa.utils.common import configure_logging_and_warnings
|
|
43
|
+
from rasa.utils.log_utils import configure_structlog
|
|
44
|
+
from rasa.utils.sanic_error_handler import register_custom_sanic_error_handler
|
|
45
|
+
|
|
46
|
+
structlogger = structlog.get_logger()
|
|
47
|
+
|
|
48
|
+
DEFAULT_SKILL_GENERATION_SYSTEM_PROMPT = importlib.resources.read_text(
|
|
49
|
+
"rasa.builder",
|
|
50
|
+
"skill_to_bot_prompt.jinja",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
VECTOR_STORE_ID = "vs_685123376e288191a005b6b144d3026f"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class PromptRequest(BaseModel):
|
|
57
|
+
prompt: str
|
|
58
|
+
client_id: Optional[str] = None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
default_credentials_yaml = """
|
|
62
|
+
studio_chat:
|
|
63
|
+
user_message_evt: "user_message"
|
|
64
|
+
bot_message_evt: "bot_message"
|
|
65
|
+
session_persistence: true
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def default_credentials() -> Dict[str, Any]:
|
|
70
|
+
return read_yaml(default_credentials_yaml)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def default_endpoints() -> Dict[str, Any]:
|
|
74
|
+
return read_yaml_file(
|
|
75
|
+
str(
|
|
76
|
+
importlib_resources.files(PACKAGE_NAME).joinpath(
|
|
77
|
+
"cli/project_templates/calm/endpoints.yml"
|
|
78
|
+
)
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def default_config(assistant_id: str) -> Dict[str, Any]:
|
|
84
|
+
base_config = read_yaml_file(
|
|
85
|
+
str(
|
|
86
|
+
importlib_resources.files(PACKAGE_NAME).joinpath(
|
|
87
|
+
"cli/project_templates/calm/config.yml"
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
base_config["assistant_id"] = assistant_id
|
|
93
|
+
|
|
94
|
+
return base_config
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
async def continuously_run_task(task: Callable, name: str) -> None:
|
|
98
|
+
"""Regularly run a task."""
|
|
99
|
+
structlogger.debug("prompt_to_bot.continuously_run_task.started", name=name)
|
|
100
|
+
|
|
101
|
+
while True:
|
|
102
|
+
try:
|
|
103
|
+
if asyncio.iscoroutinefunction(task):
|
|
104
|
+
await task()
|
|
105
|
+
else:
|
|
106
|
+
task()
|
|
107
|
+
except asyncio.exceptions.CancelledError:
|
|
108
|
+
structlogger.debug(
|
|
109
|
+
"prompt_to_bot.continuously_run_task.cancelled", name=name
|
|
110
|
+
)
|
|
111
|
+
break
|
|
112
|
+
except Exception as e:
|
|
113
|
+
structlogger.error(
|
|
114
|
+
"prompt_to_bot.continuously_run_task.error", name=name, error=str(e)
|
|
115
|
+
)
|
|
116
|
+
finally:
|
|
117
|
+
await asyncio.sleep(0.1)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class PromptToBotService:
|
|
121
|
+
def __init__(self):
|
|
122
|
+
self.app = Sanic("PromptToBotService")
|
|
123
|
+
self.app.ctx.agent = None
|
|
124
|
+
self.input_channel = self.setup_input_channel()
|
|
125
|
+
self.setup_routes(self.input_channel)
|
|
126
|
+
self.max_retries = 5
|
|
127
|
+
self.bot_files = {}
|
|
128
|
+
|
|
129
|
+
configure_cors(self.app, cors_origins=["*"])
|
|
130
|
+
|
|
131
|
+
def setup_input_channel(self) -> StudioChatInput:
|
|
132
|
+
studio_chat_credentials = default_credentials().get(StudioChatInput.name())
|
|
133
|
+
return StudioChatInput.from_credentials(credentials=studio_chat_credentials)
|
|
134
|
+
|
|
135
|
+
def setup_routes(self, input_channel: InputChannel):
|
|
136
|
+
self.app.add_route(
|
|
137
|
+
self.handle_prompt_to_bot, "/api/prompt-to-bot", methods=["POST"]
|
|
138
|
+
)
|
|
139
|
+
self.app.add_route(self.get_bot_data, "/api/bot-data", methods=["GET"])
|
|
140
|
+
|
|
141
|
+
self.app.add_route(self.update_bot_data, "/api/bot-data", methods=["PUT"])
|
|
142
|
+
|
|
143
|
+
self.app.add_route(self.llm_builder, "/api/llm-builder", methods=["POST"])
|
|
144
|
+
|
|
145
|
+
input_channels = [input_channel]
|
|
146
|
+
channels.channel.register(input_channels, self.app, route="/webhooks/")
|
|
147
|
+
|
|
148
|
+
def importer_for_data(self) -> TrainingDataImporter:
|
|
149
|
+
return TrainingDataImporter.wrap_in_builtins(
|
|
150
|
+
[
|
|
151
|
+
StaticTrainingDataImporter(
|
|
152
|
+
domain=Domain.from_dict(
|
|
153
|
+
read_yaml(self.bot_files.get("domain.yml", ""))
|
|
154
|
+
),
|
|
155
|
+
flows=YAMLFlowsReader.read_from_string(
|
|
156
|
+
self.bot_files.get("flows.yml", "")
|
|
157
|
+
),
|
|
158
|
+
config=self.config_from_bot_data(),
|
|
159
|
+
)
|
|
160
|
+
]
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
async def validate_rasa_project(self) -> Optional[str]:
|
|
164
|
+
"""Validate the Rasa project data."""
|
|
165
|
+
was_sys_exit_called = {"value": False}
|
|
166
|
+
|
|
167
|
+
def sys_exit_mock(code: int = 0):
|
|
168
|
+
was_sys_exit_called["value"] = True
|
|
169
|
+
|
|
170
|
+
# prevent sys.exit from being called
|
|
171
|
+
original_exit = sys.exit
|
|
172
|
+
# TODO: avoid sys exit in the validation functions in the first place
|
|
173
|
+
sys.exit = sys_exit_mock
|
|
174
|
+
try:
|
|
175
|
+
training_data_importer = self.importer_for_data()
|
|
176
|
+
|
|
177
|
+
with capture_logs() as cap_logs:
|
|
178
|
+
validate_files(
|
|
179
|
+
fail_on_warnings=False,
|
|
180
|
+
max_history=None,
|
|
181
|
+
importer=training_data_importer,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
if was_sys_exit_called["value"]:
|
|
185
|
+
structlogger.error(
|
|
186
|
+
"prompt_to_bot.validate_rasa_project.failed.sys_exit",
|
|
187
|
+
error_logs=cap_logs,
|
|
188
|
+
)
|
|
189
|
+
return json.dumps(
|
|
190
|
+
[x for x in cap_logs if x.get("log_level") != "debug"]
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
return None
|
|
194
|
+
except Exception as e:
|
|
195
|
+
structlogger.error(
|
|
196
|
+
"prompt_to_bot.validate_rasa_project.failed.exception",
|
|
197
|
+
error=str(e),
|
|
198
|
+
traceback=traceback.format_exc(),
|
|
199
|
+
)
|
|
200
|
+
return str(e)
|
|
201
|
+
finally:
|
|
202
|
+
sys.exit = original_exit
|
|
203
|
+
|
|
204
|
+
async def handle_prompt_to_bot(self, request):
|
|
205
|
+
try:
|
|
206
|
+
prompt_data = PromptRequest(**request.json)
|
|
207
|
+
config = default_config(prompt_data.client_id)
|
|
208
|
+
# Generate Rasa project data with retries
|
|
209
|
+
await self.generate_rasa_project_with_retries(
|
|
210
|
+
prompt_data.prompt,
|
|
211
|
+
config,
|
|
212
|
+
self.max_retries,
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
self.app.ctx.agent = await self.train_and_load_agent()
|
|
216
|
+
|
|
217
|
+
return response.json(
|
|
218
|
+
{
|
|
219
|
+
"bot_data": self.bot_files,
|
|
220
|
+
"status": "success",
|
|
221
|
+
}
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
except Exception as e:
|
|
225
|
+
structlogger.error("prompt_to_bot.error", error=str(e))
|
|
226
|
+
return response.json({"error": str(e)}, status=500)
|
|
227
|
+
|
|
228
|
+
async def get_bot_data(self, request):
|
|
229
|
+
return response.json(self.bot_files)
|
|
230
|
+
|
|
231
|
+
async def update_bot_data(self, request):
|
|
232
|
+
response = await request.respond(content_type="text/event-stream")
|
|
233
|
+
|
|
234
|
+
def sse_event(event, data):
|
|
235
|
+
return f"event: {event}\ndata: {json.dumps(data)}\n\n"
|
|
236
|
+
|
|
237
|
+
# 1. Received
|
|
238
|
+
await response.send(sse_event("received", {"status": "received"}))
|
|
239
|
+
|
|
240
|
+
bot_data = request.json
|
|
241
|
+
for file_name, file_content in bot_data.items():
|
|
242
|
+
self.bot_files[file_name] = file_content
|
|
243
|
+
|
|
244
|
+
# 2. Validating
|
|
245
|
+
await response.send(sse_event("validating", {"status": "validating"}))
|
|
246
|
+
try:
|
|
247
|
+
await self.validate_rasa_project()
|
|
248
|
+
await response.send(
|
|
249
|
+
sse_event("validation_success", {"status": "validation_success"})
|
|
250
|
+
)
|
|
251
|
+
except Exception as e:
|
|
252
|
+
structlogger.error(
|
|
253
|
+
"prompt_to_bot.update_bot_data.validation_error", error=str(e)
|
|
254
|
+
)
|
|
255
|
+
await response.send(
|
|
256
|
+
sse_event(
|
|
257
|
+
"validation_error",
|
|
258
|
+
{"status": "validation_error", "error": str(e)},
|
|
259
|
+
)
|
|
260
|
+
)
|
|
261
|
+
await response.eof()
|
|
262
|
+
return
|
|
263
|
+
|
|
264
|
+
# 3. Training
|
|
265
|
+
await response.send(sse_event("training", {"status": "training"}))
|
|
266
|
+
try:
|
|
267
|
+
self.app.ctx.agent = await self.train_and_load_agent()
|
|
268
|
+
await response.send(sse_event("train_success", {"status": "train_success"}))
|
|
269
|
+
except Exception as e:
|
|
270
|
+
structlogger.error(
|
|
271
|
+
"prompt_to_bot.update_bot_data.train_error", error=str(e)
|
|
272
|
+
)
|
|
273
|
+
await response.send(
|
|
274
|
+
sse_event("train_error", {"status": "train_error", "error": str(e)})
|
|
275
|
+
)
|
|
276
|
+
await response.eof()
|
|
277
|
+
return
|
|
278
|
+
|
|
279
|
+
# 4. Done
|
|
280
|
+
await response.send(
|
|
281
|
+
sse_event("done", {"status": "done", "bot_data": self.bot_files})
|
|
282
|
+
)
|
|
283
|
+
await response.eof()
|
|
284
|
+
|
|
285
|
+
def config_from_bot_data(self) -> Dict[str, Any]:
|
|
286
|
+
return read_yaml(self.bot_files.get("config.yml", ""))
|
|
287
|
+
|
|
288
|
+
def update_stored_bot_data(self, bot_data: Dict[str, Any], config: Dict[str, Any]):
|
|
289
|
+
self.bot_files = {
|
|
290
|
+
"domain.yml": dump_obj_as_yaml_to_string(bot_data["domain"]),
|
|
291
|
+
"flows.yml": dump_obj_as_yaml_to_string(bot_data["flows"]),
|
|
292
|
+
"config.yml": dump_obj_as_yaml_to_string(config),
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
async def generate_rasa_project_with_retries(
|
|
296
|
+
self, base_prompt: str, config: Dict[str, Any], max_retry_count: int = 5
|
|
297
|
+
) -> Dict[str, Any]:
|
|
298
|
+
"""Generate Rasa project data with retry logic."""
|
|
299
|
+
initial_messages = self.prompt_messages(base_prompt)
|
|
300
|
+
|
|
301
|
+
async def _generate(messages: List[Dict[str, Any]], tries_left: int):
|
|
302
|
+
rasa_project_data = await self.generate_rasa_project(messages)
|
|
303
|
+
self.update_stored_bot_data(rasa_project_data, config)
|
|
304
|
+
|
|
305
|
+
# write the data to a file
|
|
306
|
+
with open(f"rasa_project_{tries_left}.json", "w") as f:
|
|
307
|
+
json.dump(rasa_project_data, f)
|
|
308
|
+
|
|
309
|
+
structlogger.info(
|
|
310
|
+
"prompt_to_bot.generate_rasa_project_with_retries.generated_project",
|
|
311
|
+
tries_left=tries_left,
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
try:
|
|
315
|
+
validation_error = await self.validate_rasa_project()
|
|
316
|
+
|
|
317
|
+
if validation_error:
|
|
318
|
+
structlogger.error(
|
|
319
|
+
"prompt_to_bot.generate_rasa_project_with_retries.validation_error",
|
|
320
|
+
validation_error=validation_error,
|
|
321
|
+
)
|
|
322
|
+
raise Exception(validation_error)
|
|
323
|
+
|
|
324
|
+
structlogger.info(
|
|
325
|
+
"prompt_to_bot.generate_rasa_project_with_retries.validation_success",
|
|
326
|
+
tries_left=tries_left,
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
return rasa_project_data
|
|
330
|
+
except Exception as e:
|
|
331
|
+
structlogger.error(
|
|
332
|
+
"prompt_to_bot.generate_rasa_project_with_retries.error",
|
|
333
|
+
error=str(e),
|
|
334
|
+
tries_left=tries_left,
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
if tries_left <= 0:
|
|
338
|
+
raise Exception(
|
|
339
|
+
f"Failed to generate valid Rasa project after "
|
|
340
|
+
f"{max_retry_count} attempts"
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
# Use error to improve the prompt
|
|
344
|
+
messages = messages + [
|
|
345
|
+
{
|
|
346
|
+
"role": "assistant",
|
|
347
|
+
"content": json.dumps(rasa_project_data),
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
"role": "user",
|
|
351
|
+
"content": dedent(f"""
|
|
352
|
+
Previous attempt failed with error: {e!s}
|
|
353
|
+
|
|
354
|
+
Please fix the issues and generate a valid Rasa project.
|
|
355
|
+
"""),
|
|
356
|
+
},
|
|
357
|
+
]
|
|
358
|
+
|
|
359
|
+
return await _generate(messages, tries_left - 1)
|
|
360
|
+
|
|
361
|
+
return await _generate(initial_messages, max_retry_count)
|
|
362
|
+
|
|
363
|
+
def prompt_messages(self, prompt: str) -> List[Dict[str, Any]]:
|
|
364
|
+
system_prompt = Template(DEFAULT_SKILL_GENERATION_SYSTEM_PROMPT).render(
|
|
365
|
+
prompt=prompt
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
return [
|
|
369
|
+
{"role": "system", "content": system_prompt},
|
|
370
|
+
]
|
|
371
|
+
|
|
372
|
+
async def generate_rasa_project(
|
|
373
|
+
self, messages: List[Dict[str, Any]]
|
|
374
|
+
) -> Dict[str, Any]:
|
|
375
|
+
"""Generate Rasa project data using LLM."""
|
|
376
|
+
schema_file = str(
|
|
377
|
+
importlib_resources.files(PACKAGE_NAME).joinpath(FLOWS_SCHEMA_FILE)
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
# TODO: clean up the schema
|
|
381
|
+
flows_schema = deepcopy(read_json_file(schema_file))
|
|
382
|
+
|
|
383
|
+
del flows_schema["$defs"]["flow"]["properties"]["nlu_trigger"]
|
|
384
|
+
|
|
385
|
+
# TODO: restrict the domain schema to only the properties that are
|
|
386
|
+
# needed for the CALM bot
|
|
387
|
+
domain_schema = deepcopy(
|
|
388
|
+
read_schema_file(DOMAIN_SCHEMA_FILE, PACKAGE_NAME, False)
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
# not needed in calm
|
|
392
|
+
del domain_schema["mapping"]["intents"]
|
|
393
|
+
del domain_schema["mapping"]["entities"]
|
|
394
|
+
del domain_schema["mapping"]["forms"]
|
|
395
|
+
|
|
396
|
+
# don't think the llm needs to configure these
|
|
397
|
+
del domain_schema["mapping"]["config"]
|
|
398
|
+
del domain_schema["mapping"]["session_config"]
|
|
399
|
+
|
|
400
|
+
# don't work, llm tends to pick from_intent or something like that
|
|
401
|
+
del domain_schema["mapping"]["slots"]["mapping"]["regex;([A-Za-z]+)"][
|
|
402
|
+
"mapping"
|
|
403
|
+
]["mappings"]
|
|
404
|
+
# also creates issues...
|
|
405
|
+
del domain_schema["mapping"]["slots"]["mapping"]["regex;([A-Za-z]+)"][
|
|
406
|
+
"mapping"
|
|
407
|
+
]["validation"]
|
|
408
|
+
|
|
409
|
+
# pull in the responses schema
|
|
410
|
+
domain_schema["mapping"]["responses"] = read_schema_file(
|
|
411
|
+
RESPONSES_SCHEMA_FILE, PACKAGE_NAME, False
|
|
412
|
+
)["schema;responses"]
|
|
413
|
+
|
|
414
|
+
client = openai.AsyncOpenAI()
|
|
415
|
+
response = await client.chat.completions.create(
|
|
416
|
+
model="gpt-4.1-2025-04-14",
|
|
417
|
+
messages=messages,
|
|
418
|
+
temperature=0.7,
|
|
419
|
+
response_format={
|
|
420
|
+
"type": "json_schema",
|
|
421
|
+
"json_schema": {
|
|
422
|
+
"name": "rasa_project",
|
|
423
|
+
"schema": {
|
|
424
|
+
"type": "object",
|
|
425
|
+
"properties": {
|
|
426
|
+
"domain": domain_schema,
|
|
427
|
+
"flows": flows_schema,
|
|
428
|
+
},
|
|
429
|
+
"required": ["domain", "flows"],
|
|
430
|
+
},
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
try:
|
|
436
|
+
return json.loads(response.choices[0].message.content)
|
|
437
|
+
except json.JSONDecodeError:
|
|
438
|
+
raise Exception("LLM response was not valid JSON")
|
|
439
|
+
|
|
440
|
+
async def generate_chat_bot_context(self) -> str:
|
|
441
|
+
"""Generate a chat bot context."""
|
|
442
|
+
if self.app.ctx.agent and self.input_channel.latest_tracker_session_id:
|
|
443
|
+
tracker: Optional[
|
|
444
|
+
DialogueStateTracker
|
|
445
|
+
] = await self.app.ctx.agent.tracker_store.retrieve(
|
|
446
|
+
self.input_channel.latest_tracker_session_id
|
|
447
|
+
)
|
|
448
|
+
if tracker is None:
|
|
449
|
+
test_conversation = []
|
|
450
|
+
else:
|
|
451
|
+
test_conversation = tracker.current_state()
|
|
452
|
+
else:
|
|
453
|
+
test_conversation = []
|
|
454
|
+
|
|
455
|
+
chat_bot_files = self.bot_files
|
|
456
|
+
|
|
457
|
+
return {
|
|
458
|
+
"test_conversation": test_conversation,
|
|
459
|
+
"chat_bot_files": chat_bot_files,
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
async def llm_builder(self, request):
|
|
463
|
+
chat_bot_context = await self.generate_chat_bot_context()
|
|
464
|
+
user_chat_history = request.json.get("messages", [])
|
|
465
|
+
last_user_message = (
|
|
466
|
+
user_chat_history[-1].get("content") if user_chat_history else ""
|
|
467
|
+
)
|
|
468
|
+
|
|
469
|
+
prompt = dedent(f"""
|
|
470
|
+
You are a helpful assistant that helps users building chatbots using Rasa.
|
|
471
|
+
You are given the user question as well as context about the user's project.
|
|
472
|
+
You need to generate a response using content blocks.
|
|
473
|
+
|
|
474
|
+
The content blocks should be in the following format:
|
|
475
|
+
{{
|
|
476
|
+
"type": "text",
|
|
477
|
+
"text": "Great question, you can take a look at the following resource:"
|
|
478
|
+
}}
|
|
479
|
+
The type can be one of the following: text, link, file, code.
|
|
480
|
+
When using a block of type `text`, the `text` attribute can contain markdown.
|
|
481
|
+
Use markdown to format the text when needed.
|
|
482
|
+
The text is the text of the content block.
|
|
483
|
+
|
|
484
|
+
Code blocks:
|
|
485
|
+
{{
|
|
486
|
+
"type": "code",
|
|
487
|
+
"text": "```yaml\n- action: utter_greet\n next: END\n```"
|
|
488
|
+
}}
|
|
489
|
+
|
|
490
|
+
Link blocks:
|
|
491
|
+
{{
|
|
492
|
+
"type": "link",
|
|
493
|
+
"text": "http://rasa.com/docs/rasa/core/flows"
|
|
494
|
+
}}
|
|
495
|
+
|
|
496
|
+
File blocks:
|
|
497
|
+
{{
|
|
498
|
+
"type": "file",
|
|
499
|
+
"file": "flows.yml",
|
|
500
|
+
"content": "```yaml\n- action: utter_greet\n next: END\n```"
|
|
501
|
+
}}
|
|
502
|
+
|
|
503
|
+
You can use multiple content blocks to answer the user's question. Return
|
|
504
|
+
as many content blocks as needed.
|
|
505
|
+
|
|
506
|
+
Create links to https://rasa.com/docs for the user to take a look at.
|
|
507
|
+
|
|
508
|
+
Chat bot context:
|
|
509
|
+
{json.dumps(chat_bot_context)}
|
|
510
|
+
""")
|
|
511
|
+
|
|
512
|
+
past_messages = []
|
|
513
|
+
for message in user_chat_history:
|
|
514
|
+
past_messages.append(
|
|
515
|
+
{
|
|
516
|
+
"role": "user" if message.get("type") == "user" else "assistant",
|
|
517
|
+
"content": json.dumps(message.get("content")),
|
|
518
|
+
}
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
client = openai.AsyncOpenAI()
|
|
522
|
+
|
|
523
|
+
results = await client.vector_stores.search(
|
|
524
|
+
vector_store_id=VECTOR_STORE_ID,
|
|
525
|
+
query=last_user_message,
|
|
526
|
+
)
|
|
527
|
+
|
|
528
|
+
formatted_results = self.format_results(results.data)
|
|
529
|
+
|
|
530
|
+
messages = [
|
|
531
|
+
{"role": "system", "content": prompt},
|
|
532
|
+
*past_messages,
|
|
533
|
+
{
|
|
534
|
+
"role": "user",
|
|
535
|
+
"content": (
|
|
536
|
+
f"Documentation Context: {formatted_results}\n\n"
|
|
537
|
+
"Respond with a json array of content blocks. Keep the "
|
|
538
|
+
"response short and concise."
|
|
539
|
+
),
|
|
540
|
+
},
|
|
541
|
+
]
|
|
542
|
+
|
|
543
|
+
llm_helper_schema = read_json_file(
|
|
544
|
+
importlib_resources.files(PACKAGE_NAME).joinpath(
|
|
545
|
+
"builder/llm-helper-schema.json"
|
|
546
|
+
)
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
openai_response = await client.chat.completions.create(
|
|
550
|
+
model="gpt-4.1-2025-04-14",
|
|
551
|
+
messages=messages,
|
|
552
|
+
response_format={
|
|
553
|
+
"type": "json_schema",
|
|
554
|
+
"json_schema": {
|
|
555
|
+
"name": "llm_helper",
|
|
556
|
+
"schema": llm_helper_schema,
|
|
557
|
+
},
|
|
558
|
+
},
|
|
559
|
+
)
|
|
560
|
+
|
|
561
|
+
return response.json(json.loads(openai_response.choices[0].message.content))
|
|
562
|
+
|
|
563
|
+
@staticmethod
|
|
564
|
+
def format_results(results):
|
|
565
|
+
formatted_results = ""
|
|
566
|
+
for result in results:
|
|
567
|
+
formatted_result = f"<result url='{result.attributes.get('url')}'>"
|
|
568
|
+
for part in result.content:
|
|
569
|
+
formatted_result += f"<content>{part.text}</content>"
|
|
570
|
+
formatted_results += formatted_result + "</result>"
|
|
571
|
+
return f"<sources>{formatted_results}</sources>"
|
|
572
|
+
|
|
573
|
+
async def train_and_load_agent(self):
|
|
574
|
+
file_importer = self.importer_for_data()
|
|
575
|
+
# this is used inside the training validation. validation assumes
|
|
576
|
+
# that the endpoints are either stored in the default location or
|
|
577
|
+
# that they have been loaded before - so that is what we do here.
|
|
578
|
+
with tempfile.NamedTemporaryFile() as temp_file:
|
|
579
|
+
temp_file.write(
|
|
580
|
+
dump_obj_as_yaml_to_string(default_endpoints()).encode("utf-8")
|
|
581
|
+
)
|
|
582
|
+
temp_file.flush()
|
|
583
|
+
AvailableEndpoints.reset_instance()
|
|
584
|
+
read_endpoints_from_path(temp_file.name)
|
|
585
|
+
|
|
586
|
+
available_endpoints = AvailableEndpoints.get_instance()
|
|
587
|
+
assert available_endpoints is not None
|
|
588
|
+
|
|
589
|
+
training_result = await train(
|
|
590
|
+
domain="",
|
|
591
|
+
config="",
|
|
592
|
+
training_files=None,
|
|
593
|
+
file_importer=file_importer,
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
structlogger.info(
|
|
597
|
+
"prompt_to_bot.train_and_load_agent.training_result",
|
|
598
|
+
training_result=training_result,
|
|
599
|
+
)
|
|
600
|
+
|
|
601
|
+
agent_instance = await agent.load_agent(
|
|
602
|
+
model_path=training_result.model,
|
|
603
|
+
remote_storage=None,
|
|
604
|
+
endpoints=available_endpoints,
|
|
605
|
+
loop=self.app.loop,
|
|
606
|
+
)
|
|
607
|
+
|
|
608
|
+
structlogger.info(
|
|
609
|
+
"prompt_to_bot.train_and_load_agent.agent_instance",
|
|
610
|
+
agent_instance=agent_instance,
|
|
611
|
+
)
|
|
612
|
+
|
|
613
|
+
if not agent_instance.is_ready():
|
|
614
|
+
raise Exception("Failed to load model.")
|
|
615
|
+
|
|
616
|
+
structlogger.info(
|
|
617
|
+
"prompt_to_bot.train_and_load_agent.agent_ready",
|
|
618
|
+
agent_instance=agent_instance,
|
|
619
|
+
)
|
|
620
|
+
|
|
621
|
+
self.input_channel.agent = agent_instance
|
|
622
|
+
return agent_instance
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
def main():
|
|
626
|
+
"""Start the Prompt to Bot service."""
|
|
627
|
+
log_level = logging.DEBUG
|
|
628
|
+
configure_logging_and_warnings(
|
|
629
|
+
log_level=log_level,
|
|
630
|
+
logging_config_file=None,
|
|
631
|
+
warn_only_once=True,
|
|
632
|
+
filter_repeated_logs=True,
|
|
633
|
+
)
|
|
634
|
+
configure_structlog(log_level, include_time=True)
|
|
635
|
+
|
|
636
|
+
service = PromptToBotService()
|
|
637
|
+
register_custom_sanic_error_handler(service.app)
|
|
638
|
+
|
|
639
|
+
rasa.core.utils.list_routes(service.app)
|
|
640
|
+
|
|
641
|
+
service.app.run(host="0.0.0.0", port=5005, legacy=True, motd=False)
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
if __name__ == "__main__":
|
|
645
|
+
main()
|