rasa-pro 3.13.1a18__py3-none-any.whl → 3.13.1a20__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rasa-pro might be problematic. Click here for more details.
- rasa/__main__.py +8 -0
- rasa/builder/auth.py +71 -0
- rasa/builder/config.py +16 -0
- rasa/builder/copilot/constants.py +15 -0
- rasa/builder/copilot/copilot.py +342 -0
- rasa/builder/copilot/copilot_response_handler.py +471 -0
- rasa/builder/copilot/exceptions.py +20 -0
- rasa/builder/copilot/models.py +344 -0
- rasa/builder/copilot/prompts/copilot_system_prompt.jinja2 +495 -0
- rasa/builder/copilot/telemetry.py +195 -0
- rasa/builder/document_retrieval/__init__.py +0 -0
- rasa/builder/document_retrieval/constants.py +16 -0
- rasa/builder/{inkeep_document_retrieval.py → document_retrieval/inkeep_document_retrieval.py} +53 -44
- rasa/builder/document_retrieval/models.py +62 -0
- rasa/builder/download.py +140 -0
- rasa/builder/guardrails/__init__.py +1 -0
- rasa/builder/guardrails/constants.py +4 -0
- rasa/builder/guardrails/exceptions.py +4 -0
- rasa/builder/guardrails/lakera.py +188 -0
- rasa/builder/guardrails/models.py +199 -0
- rasa/builder/guardrails/utils.py +305 -0
- rasa/builder/job_manager.py +87 -0
- rasa/builder/jobs.py +232 -0
- rasa/builder/llm_service.py +89 -173
- rasa/builder/logging_utils.py +162 -4
- rasa/builder/main.py +29 -16
- rasa/builder/models.py +93 -121
- rasa/builder/project_generator.py +91 -7
- rasa/builder/scrape_rasa_docs.py +1 -1
- rasa/builder/service.py +650 -452
- rasa/builder/shared/tracker_context.py +212 -0
- rasa/builder/validation_service.py +4 -4
- rasa/cli/data.py +8 -3
- rasa/cli/project_templates/basic/actions/action_api.py +15 -0
- rasa/cli/project_templates/basic/actions/action_human_handoff.py +44 -0
- rasa/cli/project_templates/basic/config.yml +23 -0
- rasa/cli/project_templates/{plain → basic}/credentials.yml +8 -7
- rasa/cli/project_templates/basic/data/general/feedback.yml +20 -0
- rasa/cli/project_templates/basic/data/general/goodbye.yml +6 -0
- rasa/cli/project_templates/basic/data/general/hello.yml +7 -0
- rasa/cli/project_templates/basic/data/general/help.yml +6 -0
- rasa/cli/project_templates/basic/data/general/human_handoff.yml +16 -0
- rasa/cli/project_templates/basic/data/general/welcome.yml +9 -0
- rasa/cli/project_templates/{finance/data/patterns → basic/data/system}/pattern_completed.yml +2 -1
- rasa/cli/project_templates/basic/data/system/pattern_correction.yml +7 -0
- rasa/cli/project_templates/basic/data/system/pattern_search.yml +8 -0
- rasa/cli/project_templates/basic/data/system/pattern_session_start.yml +8 -0
- rasa/cli/project_templates/basic/docs/rasa_assistant_qa.txt +65 -0
- rasa/cli/project_templates/basic/docs/template.txt +7 -0
- rasa/cli/project_templates/basic/domain/general/assistant_details.yml +12 -0
- rasa/cli/project_templates/basic/domain/general/bot_identity.yml +5 -0
- rasa/cli/project_templates/basic/domain/general/cannot_handle.yml +5 -0
- rasa/cli/project_templates/basic/domain/general/feedback.yml +28 -0
- rasa/cli/project_templates/basic/domain/general/goodbye.yml +7 -0
- rasa/cli/project_templates/basic/domain/general/help.yml +5 -0
- rasa/cli/project_templates/basic/domain/general/human_handoff_domain.yml +35 -0
- rasa/cli/project_templates/{finance/domain/default_actions.yml → basic/domain/general/utils.yml} +0 -3
- rasa/cli/project_templates/basic/domain/general/welcome.yml +7 -0
- rasa/cli/project_templates/{plain → basic}/endpoints.yml +42 -27
- rasa/cli/project_templates/basic/prompts/rephraser_demo_personality_prompt.jinja2 +19 -0
- rasa/cli/project_templates/defaults.py +25 -3
- rasa/cli/project_templates/finance/actions/__init__.py +46 -0
- rasa/cli/project_templates/finance/actions/accounts/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/{action_ask_account.py → accounts/action_ask_account.py} +6 -9
- rasa/cli/project_templates/finance/actions/{action_check_balance.py → accounts/action_check_balance.py} +4 -4
- rasa/cli/project_templates/finance/actions/action_session_start.py +11 -6
- rasa/cli/project_templates/finance/actions/cards/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/{action_ask_card.py → cards/action_ask_card.py} +4 -3
- rasa/cli/project_templates/finance/actions/{action_check_card_existence.py → cards/action_check_card_existence.py} +4 -3
- rasa/cli/project_templates/finance/actions/{action_update_card_status.py → cards/action_update_card_status.py} +18 -9
- rasa/cli/project_templates/finance/actions/database.py +1 -0
- rasa/cli/project_templates/finance/actions/transfers/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/{action_add_payee.py → transfers/action_add_payee.py} +8 -3
- rasa/cli/project_templates/finance/actions/{action_ask_account_from.py → transfers/action_ask_account_from.py} +5 -4
- rasa/cli/project_templates/finance/actions/{action_check_payee_existence.py → transfers/action_check_payee_existence.py} +3 -3
- rasa/cli/project_templates/finance/actions/{action_check_sufficient_funds.py → transfers/action_check_sufficient_funds.py} +3 -4
- rasa/cli/project_templates/finance/actions/{action_list_payees.py → transfers/action_list_payees.py} +4 -3
- rasa/cli/project_templates/finance/actions/{action_remove_payee.py → transfers/action_remove_payee.py} +4 -4
- rasa/cli/project_templates/finance/config.yml +8 -19
- rasa/cli/project_templates/finance/credentials.yml +6 -7
- rasa/cli/project_templates/finance/csvs/cards.csv +10 -10
- rasa/cli/project_templates/finance/csvs/payees.csv +10 -9
- rasa/cli/project_templates/finance/data/{flows → accounts}/check_balance.yml +2 -1
- rasa/cli/project_templates/finance/data/general/bot_identity.yml +6 -0
- rasa/cli/project_templates/finance/data/general/feedback.yml +20 -0
- rasa/cli/project_templates/finance/data/general/goodbye.yml +6 -0
- rasa/cli/project_templates/finance/data/general/hello.yml +7 -0
- rasa/cli/project_templates/finance/data/{flows/welcome.yml → general/help.yml} +2 -7
- rasa/cli/project_templates/finance/data/general/human_handoff.yml +16 -0
- rasa/cli/project_templates/finance/data/general/welcome.yml +9 -0
- rasa/cli/project_templates/finance/data/{patterns → system/patterns}/pattern_chitchat.yml +0 -2
- rasa/cli/project_templates/finance/data/system/patterns/pattern_completed.yml +7 -0
- rasa/cli/project_templates/finance/data/system/patterns/pattern_correction.yml +7 -0
- rasa/cli/project_templates/finance/data/system/patterns/pattern_search.yml +8 -0
- rasa/cli/project_templates/finance/data/{patterns → system/patterns}/pattern_session_start.yml +0 -1
- rasa/cli/project_templates/finance/domain/{check_balance.yml → accounts/check_balance.yml} +2 -0
- rasa/cli/project_templates/finance/domain/general/assistant_details.yml +12 -0
- rasa/cli/project_templates/finance/domain/general/bot_identity.yml +5 -0
- rasa/cli/project_templates/finance/domain/general/cannot_handle.yml +5 -0
- rasa/cli/project_templates/finance/domain/general/defaults.yml +24 -0
- rasa/cli/project_templates/finance/domain/general/feedback.yml +28 -0
- rasa/cli/project_templates/finance/domain/general/goodbye.yml +7 -0
- rasa/cli/project_templates/finance/domain/general/help.yml +5 -0
- rasa/cli/project_templates/finance/domain/general/human_handoff.yml +30 -0
- rasa/cli/project_templates/finance/domain/general/utils.yml +13 -0
- rasa/cli/project_templates/finance/domain/general/welcome.yml +8 -0
- rasa/cli/project_templates/finance/endpoints.yml +1 -0
- rasa/cli/project_templates/finance/prompts/rephraser_demo_personality_prompt.jinja2 +3 -3
- rasa/cli/project_templates/telco/actions/actions_billing.py +24 -17
- rasa/cli/project_templates/telco/actions/actions_get_data_from_db.py +6 -1
- rasa/cli/project_templates/telco/actions/actions_run_diagnostics.py +6 -1
- rasa/cli/project_templates/telco/actions/actions_session_start.py +6 -1
- rasa/cli/project_templates/tutorial/config.yml +2 -1
- rasa/cli/scaffold.py +27 -2
- rasa/cli/train.py +8 -0
- rasa/cli/utils.py +31 -15
- rasa/core/actions/action.py +28 -41
- rasa/core/actions/action_run_slot_rejections.py +1 -1
- rasa/core/channels/development_inspector.py +47 -14
- rasa/core/channels/inspector/dist/assets/{arc-371401b1.js → arc-1ddec37b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-3f126156.js → blockDiagram-38ab4fdb-18af387c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-12f22eb7.js → c4Diagram-3d4e48cf-250127a3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-59f6d54b.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-03b1d386.js → classDiagram-70f12bd4-c3388b34.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-84f69d63.js → classDiagram-v2-f2320105-9c893a82.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-26177ddb.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-ca47fd38.js → createText-2e5e7dd3-c111213b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-f837ca8a.js → edges-e0da2a9e-812a729d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-8717ac54.js → erDiagram-9861fffd-fd5051bc.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-94f38b83.js → flowDb-956e92f1-3287ac02.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-b616f9fb.js → flowDiagram-66a62f08-692fb0b2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-29c03f5a.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-f5d24bb8.js → flowchart-elk-definition-4a651766-008376f1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-b43ba8d9.js → ganttDiagram-c361ad54-df330a69.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-c3aafaa5.js → gitGraphDiagram-72cf32ee-e03676fb.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-0d0a2c10.js → graph-46fad2ba.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-58ea0305.js → index-3862675e-a484ac55.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-cce6f8a1.js → index-a003633f.js} +179 -179
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-b8f60461.js → infoDiagram-f8f76790-3f9e6ec2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-95be5545.js → journeyDiagram-49397b02-79f72383.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-da885b9b.js → layout-aad098e5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-f1c817d3.js → line-219ab7ae.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-d42801e6.js → linear-2cddbe62.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-a38923a6.js → mindmap-definition-fc14e90a-1d41ed99.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-ca6e71e9.js → pieDiagram-8a3498a8-cc496ee8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-b290dae9.js → quadrantDiagram-120e2f19-84d32884.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-03f02ceb.js → requirementDiagram-deff3bca-c0deb984.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-c49eee40.js → sankeyDiagram-04a897e0-b9d7fd62.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-b2cd6a3d.js → sequenceDiagram-704730f1-7d517565.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-e53a2028.js → stateDiagram-587899a1-98ef9b27.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-e1982a03.js → stateDiagram-v2-d93cdb3a-cee70748.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-d0226ca5.js → styles-6aaf32cf-3f9d1c96.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-0e21dc00.js → styles-9a916d00-67471923.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-9588494e.js → styles-c10674c1-bd093fb7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-be478d4f.js → svgDrawCommon-08f97a94-675794e8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-74631749.js → timeline-definition-85554ec2-0ac67617.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-a043552f.js → xychartDiagram-e933f94c-c018dc37.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +2 -2
- rasa/core/channels/inspector/index.html +1 -1
- rasa/core/channels/inspector/package.json +4 -3
- rasa/core/channels/inspector/src/App.tsx +53 -7
- rasa/core/channels/inspector/src/components/Chat.tsx +3 -2
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +1 -1
- rasa/core/channels/inspector/src/components/LatencyDisplay.tsx +268 -0
- rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +6 -2
- rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +8 -3
- rasa/core/channels/inspector/src/types.ts +8 -0
- rasa/core/channels/inspector/yarn.lock +12 -12
- rasa/core/channels/studio_chat.py +119 -34
- rasa/core/channels/voice_ready/twilio_voice.py +1 -1
- rasa/core/channels/voice_stream/asr/asr_engine.py +5 -1
- rasa/core/channels/voice_stream/asr/deepgram.py +5 -0
- rasa/core/channels/voice_stream/audiocodes.py +16 -8
- rasa/core/channels/voice_stream/browser_audio.py +39 -4
- rasa/core/channels/voice_stream/call_state.py +13 -2
- rasa/core/channels/voice_stream/genesys.py +16 -13
- rasa/core/channels/voice_stream/jambonz.py +14 -12
- rasa/core/channels/voice_stream/twilio_media_streams.py +14 -13
- rasa/core/channels/voice_stream/util.py +11 -1
- rasa/core/channels/voice_stream/voice_channel.py +108 -29
- rasa/core/nlg/callback.py +1 -1
- rasa/core/nlg/contextual_response_rephraser.py +19 -9
- rasa/core/nlg/generator.py +21 -5
- rasa/core/nlg/response.py +43 -6
- rasa/core/nlg/translate.py +8 -0
- rasa/core/policies/enterprise_search_policy.py +16 -21
- rasa/dialogue_understanding/commands/correct_slots_command.py +38 -10
- rasa/dialogue_understanding/generator/command_generator.py +5 -5
- rasa/dialogue_understanding/generator/command_parser.py +9 -13
- rasa/dialogue_understanding/processor/command_processor.py +149 -55
- rasa/dialogue_understanding/stack/utils.py +13 -3
- rasa/dialogue_understanding_test/du_test_schema.yml +3 -3
- rasa/dialogue_understanding_test/validation.py +9 -10
- rasa/e2e_test/e2e_config.py +18 -11
- rasa/e2e_test/e2e_test_schema.yml +3 -3
- rasa/e2e_test/utils/validation.py +17 -19
- rasa/engine/validation.py +86 -91
- rasa/exceptions.py +26 -1
- rasa/model_manager/model_api.py +2 -2
- rasa/model_manager/socket_bridge.py +8 -2
- rasa/shared/providers/_configs/default_litellm_client_config.py +3 -7
- rasa/shared/utils/cli.py +2 -0
- rasa/shared/utils/common.py +2 -1
- rasa/shared/utils/health_check/health_check.py +10 -14
- rasa/studio/upload.py +6 -2
- rasa/studio/utils.py +33 -22
- rasa/telemetry.py +95 -22
- rasa/utils/licensing.py +21 -10
- rasa/utils/log_utils.py +1 -1
- rasa/utils/tensorflow/transformer.py +3 -3
- rasa/validator.py +7 -5
- rasa/version.py +1 -1
- {rasa_pro-3.13.1a18.dist-info → rasa_pro-3.13.1a20.dist-info}/METADATA +7 -7
- {rasa_pro-3.13.1a18.dist-info → rasa_pro-3.13.1a20.dist-info}/RECORD +242 -203
- rasa/builder/create_openai_vector_store.py +0 -228
- rasa/builder/llm-helper-schema.json +0 -69
- rasa/builder/llm_context.py +0 -81
- rasa/builder/llm_helper_prompt.jinja2 +0 -245
- rasa/cli/project_templates/finance/data/nlu.yml +0 -29
- rasa/cli/project_templates/finance/data/patterns/pattern_search.yml +0 -5
- rasa/cli/project_templates/finance/domain/default_flows.yml +0 -33
- rasa/cli/project_templates/finance/prompts/command-generator.jinja2 +0 -57
- rasa/cli/project_templates/finance/tests/conversation_repair/cancellations.yml +0 -12
- rasa/cli/project_templates/finance/tests/conversation_repair/cannot_handle.yml +0 -7
- rasa/cli/project_templates/finance/tests/conversation_repair/chitchat.yml +0 -7
- rasa/cli/project_templates/finance/tests/conversation_repair/clarification.yml +0 -9
- rasa/cli/project_templates/finance/tests/conversation_repair/completion.yml +0 -18
- rasa/cli/project_templates/finance/tests/conversation_repair/corrections.yml +0 -17
- rasa/cli/project_templates/finance/tests/conversation_repair/digressions.yml +0 -32
- rasa/cli/project_templates/finance/tests/conversation_repair/human_handoff.yml +0 -21
- rasa/cli/project_templates/finance/tests/conversation_repair/skipping_collect_steps.yml +0 -16
- rasa/cli/project_templates/finance/tests/demo_scripts/main.yml +0 -16
- rasa/cli/project_templates/finance/tests/happy_paths/balance_verification.yml +0 -15
- rasa/cli/project_templates/finance/tests/happy_paths/banking_questions.yml +0 -12
- rasa/cli/project_templates/finance/tests/happy_paths/card_blocking.yml +0 -52
- rasa/cli/project_templates/finance/tests/happy_paths/money_transfer.yml +0 -136
- rasa/cli/project_templates/finance/tests/happy_paths/payee_management.yml +0 -27
- rasa/cli/project_templates/finance/tests/happy_paths/user_greeted.yml +0 -5
- rasa/cli/project_templates/plain/config.yml +0 -17
- rasa/cli/project_templates/plain/data/patterns/pattern_session_start.yml +0 -7
- rasa/cli/project_templates/plain/domain.yml +0 -5
- rasa/core/channels/inspector/dist/assets/channel-f1efda17.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-fdf164e2.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-7d7a1629.js +0 -1
- rasa/shared/importers/static.py +0 -63
- /rasa/{cli/project_templates/plain/actions → builder/copilot}/__init__.py +0 -0
- /rasa/builder/{inkeep-rag-response-schema.json → document_retrieval/inkeep-rag-response-schema.json} +0 -0
- /rasa/cli/project_templates/finance/actions/{action_process_immediate_payment.py → transfers/action_process_immediate_payment.py} +0 -0
- /rasa/cli/project_templates/finance/actions/{action_schedule_payment.py → transfers/action_schedule_payment.py} +0 -0
- /rasa/cli/project_templates/finance/actions/{action_validate_payment_date.py → transfers/action_validate_payment_date.py} +0 -0
- /rasa/cli/project_templates/finance/data/{flows → cards}/block_card.yml +0 -0
- /rasa/cli/project_templates/finance/data/{flows → cards}/select_card.yml +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/accounts.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/advisors.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/appointments.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/branches.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/cards.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/payees.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/transactions.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/users.json +0 -0
- /rasa/cli/project_templates/finance/data/{flows → transfers}/add_payee.yml +0 -0
- /rasa/cli/project_templates/finance/data/{flows → transfers}/list_payees.yml +0 -0
- /rasa/cli/project_templates/finance/data/{flows → transfers}/remove_payee.yml +0 -0
- /rasa/cli/project_templates/finance/data/{flows → transfers}/transfer_money.yml +0 -0
- /rasa/cli/project_templates/finance/domain/{block_card.yml → cards/block_card.yml} +0 -0
- /rasa/cli/project_templates/finance/domain/{select_card.yml → cards/select_card.yml} +0 -0
- /rasa/cli/project_templates/finance/domain/{add_payee.yml → transfers/add_payee.yml} +0 -0
- /rasa/cli/project_templates/finance/domain/{list_payees.yml → transfers/list_payees.yml} +0 -0
- /rasa/cli/project_templates/finance/domain/{remove_payee.yml → transfers/remove_payee.yml} +0 -0
- /rasa/cli/project_templates/finance/domain/{transfer_money.yml → transfers/transfer_money.yml} +0 -0
- {rasa_pro-3.13.1a18.dist-info → rasa_pro-3.13.1a20.dist-info}/NOTICE +0 -0
- {rasa_pro-3.13.1a18.dist-info → rasa_pro-3.13.1a20.dist-info}/WHEEL +0 -0
- {rasa_pro-3.13.1a18.dist-info → rasa_pro-3.13.1a20.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import importlib_resources
|
|
2
|
+
|
|
3
|
+
from rasa.constants import PACKAGE_NAME
|
|
4
|
+
|
|
5
|
+
INKEEP_API_KEY_ENV_VAR = "INKEEP_API_KEY"
|
|
6
|
+
|
|
7
|
+
INKEEP_RAG_RESPONSE_SCHEMA_PATH = str(
|
|
8
|
+
importlib_resources.files(PACKAGE_NAME)
|
|
9
|
+
.joinpath("builder")
|
|
10
|
+
.joinpath("document_retrieval")
|
|
11
|
+
.joinpath("inkeep-rag-response-schema.json")
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
INKEEP_DOCUMENT_RETRIEVAL_MODEL = "inkeep-rag"
|
|
16
|
+
INKEEP_BASE_URL = "https://api.inkeep.com/v1/"
|
rasa/builder/{inkeep_document_retrieval.py → document_retrieval/inkeep_document_retrieval.py}
RENAMED
|
@@ -2,28 +2,23 @@ import asyncio
|
|
|
2
2
|
import json
|
|
3
3
|
import os
|
|
4
4
|
from contextlib import asynccontextmanager
|
|
5
|
-
from typing import List, Optional
|
|
5
|
+
from typing import AsyncGenerator, List, Optional
|
|
6
6
|
|
|
7
|
-
import importlib_resources
|
|
8
7
|
import openai
|
|
9
8
|
import structlog
|
|
10
9
|
from openai.types.chat import ChatCompletion
|
|
11
10
|
|
|
11
|
+
from rasa.builder.copilot.constants import ROLE_USER
|
|
12
|
+
from rasa.builder.document_retrieval.constants import (
|
|
13
|
+
INKEEP_API_KEY_ENV_VAR,
|
|
14
|
+
INKEEP_BASE_URL,
|
|
15
|
+
INKEEP_DOCUMENT_RETRIEVAL_MODEL,
|
|
16
|
+
INKEEP_RAG_RESPONSE_SCHEMA_PATH,
|
|
17
|
+
)
|
|
18
|
+
from rasa.builder.document_retrieval.models import Document
|
|
12
19
|
from rasa.builder.exceptions import DocumentRetrievalError
|
|
13
|
-
from rasa.builder.models import Document
|
|
14
|
-
from rasa.constants import PACKAGE_NAME
|
|
15
20
|
from rasa.shared.utils.io import read_json_file
|
|
16
21
|
|
|
17
|
-
INKEEP_API_KEY_ENV_VAR = "INKEEP_API_KEY"
|
|
18
|
-
INKEEP_RAG_RESPONSE_SCHEMA_PATH = str(
|
|
19
|
-
importlib_resources.files(PACKAGE_NAME).joinpath(
|
|
20
|
-
"builder/inkeep-rag-response-schema.json"
|
|
21
|
-
)
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
INKEEP_DOCUMENT_RETRIEVAL_MODEL = "inkeep-rag"
|
|
25
|
-
INKEEP_BASE_URL = "https://api.inkeep.com/v1/"
|
|
26
|
-
|
|
27
22
|
structlogger = structlog.get_logger()
|
|
28
23
|
|
|
29
24
|
|
|
@@ -52,15 +47,28 @@ class InKeepDocumentRetrieval:
|
|
|
52
47
|
List of Document objects containing retrieved content
|
|
53
48
|
|
|
54
49
|
Raises:
|
|
55
|
-
|
|
50
|
+
DocumentRetrievalError: When document retrieval fails due to:
|
|
51
|
+
- Empty response from InKeep AI API
|
|
52
|
+
- OpenAI API errors (authentication, rate limiting, etc.)
|
|
53
|
+
- Request timeout
|
|
54
|
+
- Unexpected errors during API communication
|
|
56
55
|
"""
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
56
|
+
try:
|
|
57
|
+
response = await self._call_inkeep_rag_api(
|
|
58
|
+
query=query,
|
|
59
|
+
temperature=temperature,
|
|
60
|
+
timeout=timeout,
|
|
61
|
+
)
|
|
62
|
+
documents = self._parse_documents_from_response(response)
|
|
63
|
+
return documents
|
|
64
|
+
except DocumentRetrievalError as e:
|
|
65
|
+
structlogger.error(
|
|
66
|
+
"inkeep_document_retrieval.retrieve_documents.error",
|
|
67
|
+
event_info="InKeep Document Retrieval: Error",
|
|
68
|
+
query=query,
|
|
69
|
+
error=str(e),
|
|
70
|
+
)
|
|
71
|
+
raise e
|
|
64
72
|
|
|
65
73
|
async def _call_inkeep_rag_api(
|
|
66
74
|
self, query: str, temperature: float, timeout: float
|
|
@@ -79,25 +87,24 @@ class InKeepDocumentRetrieval:
|
|
|
79
87
|
Raises:
|
|
80
88
|
LLMGenerationError: If the API call fails or returns invalid response
|
|
81
89
|
"""
|
|
82
|
-
request_params = {
|
|
83
|
-
"model": INKEEP_DOCUMENT_RETRIEVAL_MODEL,
|
|
84
|
-
"messages": [{"role": "user", "content": query}],
|
|
85
|
-
"temperature": temperature,
|
|
86
|
-
"timeout": timeout,
|
|
87
|
-
"response_format": {
|
|
88
|
-
"type": "json_schema",
|
|
89
|
-
"json_schema": self._rag_schema,
|
|
90
|
-
},
|
|
91
|
-
}
|
|
92
90
|
try:
|
|
93
91
|
async with self._get_client() as client:
|
|
94
|
-
response = await client.chat.completions.create(
|
|
92
|
+
response = await client.chat.completions.create(
|
|
93
|
+
model=INKEEP_DOCUMENT_RETRIEVAL_MODEL,
|
|
94
|
+
messages=[{"role": ROLE_USER, "content": query}],
|
|
95
|
+
temperature=temperature,
|
|
96
|
+
timeout=timeout,
|
|
97
|
+
response_format={
|
|
98
|
+
"type": "json_schema",
|
|
99
|
+
"json_schema": self._rag_schema,
|
|
100
|
+
},
|
|
101
|
+
)
|
|
95
102
|
|
|
96
103
|
if not response.choices[0].message.content:
|
|
97
104
|
structlogger.warning(
|
|
98
105
|
"inkeep_document_retrieval.empty_response",
|
|
99
106
|
event_info="InKeep AI returned an empty response. ",
|
|
100
|
-
|
|
107
|
+
query=query,
|
|
101
108
|
response_content=response.choices[0].message.content,
|
|
102
109
|
)
|
|
103
110
|
raise DocumentRetrievalError(
|
|
@@ -108,25 +115,25 @@ class InKeepDocumentRetrieval:
|
|
|
108
115
|
|
|
109
116
|
except openai.OpenAIError as e:
|
|
110
117
|
structlogger.error(
|
|
111
|
-
"inkeep_document_retrieval.api_error",
|
|
118
|
+
"inkeep_document_retrieval.call_inkeep_rag_api.api_error",
|
|
112
119
|
event_info="InKeep Document Retrieval: API error",
|
|
113
|
-
|
|
120
|
+
query=query,
|
|
114
121
|
error=e,
|
|
115
122
|
)
|
|
116
123
|
raise DocumentRetrievalError(f"InKeep Document Retrieval: API error: {e}")
|
|
117
124
|
except asyncio.TimeoutError as e:
|
|
118
125
|
structlogger.error(
|
|
119
|
-
"inkeep_document_retrieval.timeout_error",
|
|
126
|
+
"inkeep_document_retrieval.call_inkeep_rag_api.timeout_error",
|
|
120
127
|
event_info="InKeep Document Retrieval: Timeout error",
|
|
121
|
-
|
|
128
|
+
query=query,
|
|
122
129
|
error=e,
|
|
123
130
|
)
|
|
124
131
|
raise DocumentRetrievalError(f"InKeep AI request timed out: {e}")
|
|
125
132
|
except Exception as e:
|
|
126
133
|
structlogger.error(
|
|
127
|
-
"inkeep_document_retrieval.error",
|
|
134
|
+
"inkeep_document_retrieval.call_inkeep_rag_api.error",
|
|
128
135
|
event_info="InKeep Document Retrieval: Error",
|
|
129
|
-
|
|
136
|
+
query=query,
|
|
130
137
|
error=e,
|
|
131
138
|
)
|
|
132
139
|
raise DocumentRetrievalError(
|
|
@@ -134,7 +141,7 @@ class InKeepDocumentRetrieval:
|
|
|
134
141
|
)
|
|
135
142
|
|
|
136
143
|
@asynccontextmanager
|
|
137
|
-
async def _get_client(self):
|
|
144
|
+
async def _get_client(self) -> AsyncGenerator[openai.AsyncOpenAI, None]:
|
|
138
145
|
"""Get or create client that handles the API calls to InKeep AI."""
|
|
139
146
|
if self._client is None:
|
|
140
147
|
self._client = openai.AsyncOpenAI(
|
|
@@ -161,7 +168,8 @@ class InKeepDocumentRetrieval:
|
|
|
161
168
|
response: ChatCompletion response from InKeep AI's RAG model.
|
|
162
169
|
|
|
163
170
|
Returns:
|
|
164
|
-
List of Document objects
|
|
171
|
+
List of Document objects. Empty list is returned if the response is empty
|
|
172
|
+
or if the response is invalid.
|
|
165
173
|
"""
|
|
166
174
|
try:
|
|
167
175
|
content = response.choices[0].message.content
|
|
@@ -192,7 +200,8 @@ class InKeepDocumentRetrieval:
|
|
|
192
200
|
|
|
193
201
|
except json.JSONDecodeError as e:
|
|
194
202
|
structlogger.warning(
|
|
195
|
-
"inkeep_document_retrieval.
|
|
203
|
+
"inkeep_document_retrieval.parse_documents_from_response"
|
|
204
|
+
".parse_response_failed",
|
|
196
205
|
event_info=(
|
|
197
206
|
"InKeep Document Retrieval: Parse response failed. "
|
|
198
207
|
"Returning empty list.",
|
|
@@ -202,7 +211,7 @@ class InKeepDocumentRetrieval:
|
|
|
202
211
|
return []
|
|
203
212
|
except Exception as e:
|
|
204
213
|
structlogger.error(
|
|
205
|
-
"inkeep_document_retrieval.
|
|
214
|
+
"inkeep_document_retrieval.parse_documents_from_response.error",
|
|
206
215
|
event_info=(
|
|
207
216
|
"InKeep Document Retrieval: Parse response error. "
|
|
208
217
|
"Returning empty list.",
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from typing import Any, Dict, Optional
|
|
2
|
+
|
|
3
|
+
import structlog
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
structlogger = structlog.get_logger()
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Document(BaseModel):
|
|
10
|
+
"""Model for document retrieval results."""
|
|
11
|
+
|
|
12
|
+
content: str = Field(...)
|
|
13
|
+
url: Optional[str] = Field(None)
|
|
14
|
+
title: Optional[str] = Field(None)
|
|
15
|
+
metadata: Optional[Dict[str, Any]] = Field(None)
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def from_inkeep_rag_response(cls, rag_item: Dict[str, Any]) -> "Document":
|
|
19
|
+
"""Create a Document object from a single InKeep RAG response item.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
rag_item: Single item from InKeep RAG response
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
Document object with extracted content and metadata
|
|
26
|
+
"""
|
|
27
|
+
source = rag_item.get("source", {})
|
|
28
|
+
text_content = cls._extract_text_from_source(source)
|
|
29
|
+
|
|
30
|
+
return cls(
|
|
31
|
+
content=text_content.strip() if text_content else "",
|
|
32
|
+
url=rag_item.get("url"),
|
|
33
|
+
title=rag_item.get("title"),
|
|
34
|
+
metadata={
|
|
35
|
+
"type": rag_item.get("type"),
|
|
36
|
+
"record_type": rag_item.get("record_type"),
|
|
37
|
+
"context": rag_item.get("context"),
|
|
38
|
+
"media_type": source.get("media_type"),
|
|
39
|
+
},
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def _extract_text_from_source(source: Dict[str, Any]) -> str:
|
|
44
|
+
"""Extract text content from InKeep source object.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
source: Source object from InKeep RAG response
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Extracted text content
|
|
51
|
+
"""
|
|
52
|
+
# Try to extract from content array first
|
|
53
|
+
if "content" in source:
|
|
54
|
+
text_parts = []
|
|
55
|
+
for content_item in source["content"]:
|
|
56
|
+
if content_item.get("type") == "text" and content_item.get("text"):
|
|
57
|
+
text_parts.append(content_item["text"])
|
|
58
|
+
if text_parts:
|
|
59
|
+
return "\n".join(text_parts)
|
|
60
|
+
|
|
61
|
+
# Fallback to source data
|
|
62
|
+
return source.get("data", "")
|
rasa/builder/download.py
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""Download utilities for bot projects."""
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
import tarfile
|
|
7
|
+
from textwrap import dedent
|
|
8
|
+
from typing import Dict, Optional
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _get_env_content() -> str:
|
|
12
|
+
"""Generate .env file content."""
|
|
13
|
+
return f"RASA_PRO_LICENSE={os.getenv('RASA_PRO_LICENSE')}\n"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _get_python_version_content() -> str:
|
|
17
|
+
"""Generate .python-version file content with current Python version."""
|
|
18
|
+
return f"{sys.version_info.major}.{sys.version_info.minor}\n"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _get_pyproject_toml_content(project_id: str) -> str:
|
|
22
|
+
"""Generate pyproject.toml file content."""
|
|
23
|
+
return dedent(
|
|
24
|
+
f"""
|
|
25
|
+
[project]
|
|
26
|
+
name = "{project_id}"
|
|
27
|
+
version = "0.1.0"
|
|
28
|
+
description = "Add your description for your Rasa bot here"
|
|
29
|
+
readme = "README.md"
|
|
30
|
+
dependencies = []
|
|
31
|
+
requires-python = ">={sys.version_info.major}.{sys.version_info.minor}"
|
|
32
|
+
"""
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _get_readme_content() -> str:
|
|
37
|
+
"""Generate README.md file content with basic instructions."""
|
|
38
|
+
return dedent(
|
|
39
|
+
"""
|
|
40
|
+
# Rasa Assistant
|
|
41
|
+
|
|
42
|
+
This is your Rasa assistant project. Below are the basic commands to
|
|
43
|
+
get started.
|
|
44
|
+
|
|
45
|
+
## Prerequisites
|
|
46
|
+
Make sure you have [uv](https://docs.astral.sh/uv/) installed.
|
|
47
|
+
|
|
48
|
+
## Training the Assistant
|
|
49
|
+
|
|
50
|
+
To train your assistant with the current configuration and training data:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv run rasa train
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
This will create a model in the `models/` directory.
|
|
57
|
+
|
|
58
|
+
## Testing the Assistant
|
|
59
|
+
|
|
60
|
+
To test your assistant interactively in the command line:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
uv run rasa inspect
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Running the Assistant
|
|
67
|
+
|
|
68
|
+
To start the Rasa server:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
uv run rasa run
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The server will be available at `http://localhost:5005`.
|
|
75
|
+
|
|
76
|
+
## Project Structure
|
|
77
|
+
|
|
78
|
+
- `config.yml` - Configuration for your NLU pipeline and policies
|
|
79
|
+
- `domain.yml` - Defines intents, entities, slots, responses, and actions
|
|
80
|
+
- `data/` - Flows of your bot
|
|
81
|
+
- `actions/` - Custom action code (if any)
|
|
82
|
+
|
|
83
|
+
## Next Steps
|
|
84
|
+
|
|
85
|
+
1. Customize your domain and flows
|
|
86
|
+
2. Train your model with `rasa train`
|
|
87
|
+
3. Test your assistant with `rasa inspect`
|
|
88
|
+
4. Deploy your assistant with `rasa run`
|
|
89
|
+
|
|
90
|
+
For more information, visit the [Rasa documentation](https://rasa.com/docs/).
|
|
91
|
+
"""
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _add_file_to_tar(tar: tarfile.TarFile, filename: str, content: str) -> None:
|
|
96
|
+
"""Add a file with the given content to the tar archive.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
tar: The tar file object to add to
|
|
100
|
+
filename: Name of the file in the archive
|
|
101
|
+
content: Content of the file as a string
|
|
102
|
+
"""
|
|
103
|
+
file_data = content.encode("utf-8")
|
|
104
|
+
tarinfo = tarfile.TarInfo(name=filename)
|
|
105
|
+
tarinfo.size = len(file_data)
|
|
106
|
+
tar.addfile(tarinfo, io.BytesIO(file_data))
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def create_bot_project_archive(
|
|
110
|
+
bot_files: Dict[str, Optional[str]], project_id: str
|
|
111
|
+
) -> bytes:
|
|
112
|
+
"""Create a tar.gz archive containing bot files and additional project files.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
bot_files: Dictionary mapping file names to their content
|
|
116
|
+
project_id: Name of the project for the archive filename and pyproject.toml
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
bytes: The tar.gz archive data
|
|
120
|
+
"""
|
|
121
|
+
tar_buffer = io.BytesIO()
|
|
122
|
+
|
|
123
|
+
with tarfile.open(fileobj=tar_buffer, mode="w:gz") as tar:
|
|
124
|
+
# Add bot files to archive
|
|
125
|
+
for filename, content in bot_files.items():
|
|
126
|
+
if content is not None:
|
|
127
|
+
_add_file_to_tar(tar, filename, content)
|
|
128
|
+
|
|
129
|
+
# Add additional project files
|
|
130
|
+
_add_file_to_tar(tar, ".env", _get_env_content())
|
|
131
|
+
_add_file_to_tar(tar, ".python-version", _get_python_version_content())
|
|
132
|
+
_add_file_to_tar(
|
|
133
|
+
tar,
|
|
134
|
+
"pyproject.toml",
|
|
135
|
+
_get_pyproject_toml_content(project_id),
|
|
136
|
+
)
|
|
137
|
+
_add_file_to_tar(tar, "README.md", _get_readme_content())
|
|
138
|
+
|
|
139
|
+
tar_buffer.seek(0)
|
|
140
|
+
return tar_buffer.getvalue()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"""Lakera AI guardrails provider implementation."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import os
|
|
5
|
+
import time
|
|
6
|
+
from contextlib import asynccontextmanager
|
|
7
|
+
from typing import Any, AsyncGenerator, Dict, Optional
|
|
8
|
+
|
|
9
|
+
import aiohttp
|
|
10
|
+
import structlog
|
|
11
|
+
|
|
12
|
+
from rasa.builder.guardrails.constants import (
|
|
13
|
+
LAKERA_API_KEY_ENV_VAR,
|
|
14
|
+
LAKERA_BASE_URL,
|
|
15
|
+
LAKERA_GUARD_ENDPOINT,
|
|
16
|
+
LAKERA_GUARD_RESULTS_ENDPOINT,
|
|
17
|
+
)
|
|
18
|
+
from rasa.builder.guardrails.exceptions import GuardrailsError
|
|
19
|
+
from rasa.builder.guardrails.models import (
|
|
20
|
+
GuardrailResponse,
|
|
21
|
+
LakeraGuardrailRequest,
|
|
22
|
+
LakeraGuardrailResponse,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
structlogger = structlog.get_logger()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class LakeraAIGuardrails:
|
|
29
|
+
"""Guardrails provider using Lakera AI."""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
api_key: Optional[str] = None,
|
|
34
|
+
base_url: Optional[str] = None,
|
|
35
|
+
):
|
|
36
|
+
"""Initialize Lakera guardrails provider.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
severity_threshold: The minimum severity level for the guardrail to flag
|
|
40
|
+
the user request as unsafe.
|
|
41
|
+
api_key: Lakera AI API key.
|
|
42
|
+
base_url: Optional base URL for the API. If not provided, the default
|
|
43
|
+
Lakera API URL (https://api.lakera.ai/v2) will be used.
|
|
44
|
+
"""
|
|
45
|
+
self.base_url: str = base_url or LAKERA_BASE_URL
|
|
46
|
+
self._api_key: Optional[str] = api_key or os.getenv(LAKERA_API_KEY_ENV_VAR)
|
|
47
|
+
self._session: Optional[aiohttp.ClientSession] = None
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def guard_endpoint(self) -> str:
|
|
51
|
+
"""Get the guard endpoint for the Lakera API."""
|
|
52
|
+
return f"{self.base_url}/{LAKERA_GUARD_ENDPOINT}"
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def guard_results_endpoint(self) -> str:
|
|
56
|
+
"""Get the guard results endpoint for the Lakera API."""
|
|
57
|
+
return f"{self.base_url}/{LAKERA_GUARD_RESULTS_ENDPOINT}"
|
|
58
|
+
|
|
59
|
+
@asynccontextmanager
|
|
60
|
+
async def _get_session(self) -> AsyncGenerator[aiohttp.ClientSession, None]:
|
|
61
|
+
"""Create a fresh ClientSession, yield it, and always close it."""
|
|
62
|
+
session = aiohttp.ClientSession(headers=self._get_headers())
|
|
63
|
+
try:
|
|
64
|
+
yield session
|
|
65
|
+
except Exception as e:
|
|
66
|
+
structlogger.error("lakera_guardrails.session_error", error=str(e))
|
|
67
|
+
raise
|
|
68
|
+
finally:
|
|
69
|
+
try:
|
|
70
|
+
await session.close()
|
|
71
|
+
except Exception as exc:
|
|
72
|
+
structlogger.warning(
|
|
73
|
+
"lakera_guardrails.session_close_error",
|
|
74
|
+
event_info="Failed to close aiohttp client session cleanly.",
|
|
75
|
+
error=str(exc),
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def _get_headers(self) -> Dict[str, Any]:
|
|
79
|
+
"""Get the headers for the Lakera API request."""
|
|
80
|
+
headers: Dict[str, Any] = {}
|
|
81
|
+
if self._api_key is not None:
|
|
82
|
+
headers["Authorization"] = f"Bearer {self._api_key}"
|
|
83
|
+
return headers
|
|
84
|
+
|
|
85
|
+
async def send_request(self, request: LakeraGuardrailRequest) -> GuardrailResponse:
|
|
86
|
+
"""Send a request to the Lakera API.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
request: The guardrail request to send to the Lakera API.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
GuardrailResponse with the results of the check.
|
|
93
|
+
|
|
94
|
+
Raises:
|
|
95
|
+
GuardrailsError: If the request times out or returns a non-200 status code.
|
|
96
|
+
Exception: If the request fails for any other reason.
|
|
97
|
+
"""
|
|
98
|
+
start_time = time.time()
|
|
99
|
+
try:
|
|
100
|
+
async with self._get_session() as session:
|
|
101
|
+
raw_response = await self._send_http_request(session, request)
|
|
102
|
+
response = LakeraGuardrailResponse.from_raw_response(
|
|
103
|
+
raw_response,
|
|
104
|
+
hello_rasa_user_id=request.hello_rasa_user_id,
|
|
105
|
+
hello_rasa_project_id=request.hello_rasa_project_id,
|
|
106
|
+
)
|
|
107
|
+
processing_time_ms = (time.time() - start_time) * 1000
|
|
108
|
+
response.processing_time_ms = processing_time_ms
|
|
109
|
+
return response
|
|
110
|
+
|
|
111
|
+
# Propagate the GuardrailsError if it occurs.
|
|
112
|
+
except GuardrailsError as e:
|
|
113
|
+
raise e
|
|
114
|
+
|
|
115
|
+
except asyncio.TimeoutError:
|
|
116
|
+
message = "Lakera API request timed out."
|
|
117
|
+
structlogger.error(
|
|
118
|
+
"lakera_guardrails.send_request.timeout_error",
|
|
119
|
+
event_info=message,
|
|
120
|
+
processing_time_ms=(time.time() - start_time) * 1000,
|
|
121
|
+
)
|
|
122
|
+
raise GuardrailsError(message)
|
|
123
|
+
|
|
124
|
+
# Propagate the unexpected exceptions.
|
|
125
|
+
except Exception as e:
|
|
126
|
+
message = "Lakera API request failed."
|
|
127
|
+
structlogger.error(
|
|
128
|
+
"lakera_guardrails.send_request.unexpected_error",
|
|
129
|
+
event_info="Lakera API request failed.",
|
|
130
|
+
request=request,
|
|
131
|
+
error=e,
|
|
132
|
+
processing_time_ms=(time.time() - start_time) * 1000,
|
|
133
|
+
)
|
|
134
|
+
raise e
|
|
135
|
+
|
|
136
|
+
async def _send_http_request(
|
|
137
|
+
self, session: aiohttp.ClientSession, request: LakeraGuardrailRequest
|
|
138
|
+
) -> Dict[str, Any]:
|
|
139
|
+
"""Make an HTTP request to the Lakera API.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
session: The aiohttp session to use for the request.
|
|
143
|
+
request: The guardrail request to send.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
The raw JSON response from the API.
|
|
147
|
+
|
|
148
|
+
Raises:
|
|
149
|
+
GuardrailsError: If the request fails or response parsing fails.
|
|
150
|
+
"""
|
|
151
|
+
# Log the request details for debugging
|
|
152
|
+
json_payload = request.to_json_payload()
|
|
153
|
+
structlogger.debug(
|
|
154
|
+
"lakera_guardrails.send_request.request",
|
|
155
|
+
url=self.guard_endpoint,
|
|
156
|
+
method="POST",
|
|
157
|
+
request_body=json_payload,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
async with session.post(
|
|
161
|
+
self.guard_endpoint,
|
|
162
|
+
json=json_payload,
|
|
163
|
+
) as client_response:
|
|
164
|
+
# Check if the response is successful. If not, raise an error.
|
|
165
|
+
if client_response.status >= 400:
|
|
166
|
+
error_text = await client_response.text()
|
|
167
|
+
message = (
|
|
168
|
+
f"Lakera API request failed with status "
|
|
169
|
+
f"`{client_response.status}`. Error: "
|
|
170
|
+
f"`{error_text}`."
|
|
171
|
+
)
|
|
172
|
+
structlogger.error(
|
|
173
|
+
"lakera_guardrails.send_request.http_error",
|
|
174
|
+
event_info=message,
|
|
175
|
+
url=self.guard_endpoint,
|
|
176
|
+
status=client_response.status,
|
|
177
|
+
error=error_text,
|
|
178
|
+
request_body=json_payload,
|
|
179
|
+
)
|
|
180
|
+
raise GuardrailsError(message)
|
|
181
|
+
|
|
182
|
+
# Parse the response as a dictionary.
|
|
183
|
+
raw_response = await client_response.json()
|
|
184
|
+
structlogger.debug(
|
|
185
|
+
"lakera_guardrails.send_request.response",
|
|
186
|
+
response_body=raw_response,
|
|
187
|
+
)
|
|
188
|
+
return raw_response
|