rasa-pro 3.13.0.dev2__py3-none-any.whl → 3.13.0.dev5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rasa-pro might be problematic. Click here for more details.
- rasa/__main__.py +3 -1
- rasa/cli/inspect.py +8 -4
- 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/run.py +10 -6
- rasa/cli/scaffold.py +3 -4
- rasa/cli/studio/download.py +1 -1
- rasa/cli/studio/upload.py +0 -6
- rasa/cli/utils.py +7 -0
- rasa/core/channels/channel.py +93 -0
- rasa/core/channels/inspector/dist/assets/{arc-c7691751.js → arc-9f75cc3b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-ab99dff7.js → blockDiagram-38ab4fdb-7f34db23.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-08c35a6b.js → c4Diagram-3d4e48cf-948bab2c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-dfa68278.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-9e9c71c9.js → classDiagram-70f12bd4-53b0dd0e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-15e7e2bf.js → classDiagram-v2-f2320105-fdf789e7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-edb7f119.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-9c105cb1.js → createText-2e5e7dd3-87c4ece5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-77e89e48.js → edges-e0da2a9e-5a8b0749.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-7a011646.js → erDiagram-9861fffd-66da90e2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-b6f105ac.js → flowDb-956e92f1-10044f05.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-ce4f18c2.js → flowDiagram-66a62f08-f338f66a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-65e7c670.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-cb5f6da4.js → flowchart-elk-definition-4a651766-b13140aa.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-e4d19e28.js → ganttDiagram-c361ad54-f2b4a55a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-727b1c33.js → gitGraphDiagram-72cf32ee-dedc298d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-6e2ab9a7.js → graph-4ede11ff.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-84ec700f.js → index-3862675e-65549d37.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-098a1a24.js → index-3a23e736.js} +142 -129
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-78dda442.js → infoDiagram-f8f76790-65439671.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-f1cc6dd1.js → journeyDiagram-49397b02-56d03d98.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-d98dcd0c.js → layout-dd48f7f4.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-838e3d82.js → line-1569ad2c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-eae72406.js → linear-48bf4935.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-c96fd84b.js → mindmap-definition-fc14e90a-688504c1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-c936d4e2.js → pieDiagram-8a3498a8-78b6d7e6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-b338eb8f.js → quadrantDiagram-120e2f19-048b84b3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-c6b6c0d5.js → requirementDiagram-deff3bca-dd67f107.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-b9372e19.js → sankeyDiagram-04a897e0-8128436e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-479e0a3f.js → sequenceDiagram-704730f1-1a0d1461.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-fd26eebc.js → stateDiagram-587899a1-46d388ed.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-3233e0ae.js → stateDiagram-v2-d93cdb3a-ea42951a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-1fdd392b.js → styles-6aaf32cf-7427ed0c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-6d7bfa1b.js → styles-9a916d00-ff5e5a16.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-f86aab11.js → styles-c10674c1-7b3680cf.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-e3e49d7a.js → svgDrawCommon-08f97a94-f860f2ad.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-6fe08b4d.js → timeline-definition-85554ec2-2eebf0c8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-c2e06fd6.js → xychartDiagram-e933f94c-5d7f4e96.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/src/App.tsx +3 -2
- rasa/core/channels/inspector/src/components/Chat.tsx +23 -2
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +2 -5
- rasa/core/channels/inspector/src/helpers/conversation.ts +16 -0
- rasa/core/channels/inspector/src/types.ts +1 -1
- rasa/core/channels/voice_ready/audiocodes.py +41 -15
- rasa/core/channels/voice_ready/jambonz.py +25 -5
- rasa/core/channels/voice_ready/jambonz_protocol.py +4 -0
- rasa/core/channels/voice_ready/twilio_voice.py +48 -1
- rasa/core/channels/voice_stream/tts/azure.py +11 -2
- rasa/core/channels/voice_stream/twilio_media_streams.py +101 -26
- rasa/core/channels/voice_stream/voice_channel.py +28 -2
- rasa/core/concurrent_lock_store.py +24 -10
- rasa/core/information_retrieval/faiss.py +7 -68
- rasa/core/information_retrieval/information_retrieval.py +2 -40
- rasa/core/information_retrieval/milvus.py +2 -7
- rasa/core/information_retrieval/qdrant.py +2 -7
- rasa/core/lock_store.py +151 -60
- rasa/core/nlg/contextual_response_rephraser.py +3 -0
- rasa/core/policies/enterprise_search_policy.py +310 -61
- rasa/core/policies/intentless_policy.py +3 -0
- rasa/dialogue_understanding/coexistence/llm_based_router.py +8 -0
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +2 -2
- rasa/dialogue_understanding/generator/command_parser.py +1 -1
- rasa/dialogue_understanding/generator/flow_retrieval.py +1 -4
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +1 -2
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +13 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_template.jinja2 +1 -1
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +1 -1
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +2 -24
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +22 -17
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +27 -12
- rasa/dialogue_understanding_test/du_test_case.py +16 -8
- rasa/dialogue_understanding_test/io.py +8 -13
- rasa/e2e_test/utils/validation.py +3 -3
- rasa/engine/recipes/default_components.py +0 -2
- rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +3 -0
- rasa/plugin.py +0 -3
- rasa/shared/constants.py +1 -0
- rasa/shared/core/domain.py +165 -11
- rasa/shared/core/flows/flow.py +155 -131
- rasa/shared/core/flows/flow_step.py +19 -3
- rasa/shared/core/flows/flow_step_links.py +15 -0
- rasa/shared/core/flows/flow_step_sequence.py +6 -0
- rasa/shared/core/flows/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 +27 -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/yaml_flows_io.py +106 -5
- rasa/shared/importers/importer.py +8 -0
- rasa/shared/providers/_utils.py +83 -0
- rasa/shared/providers/llm/_base_litellm_client.py +6 -3
- rasa/shared/providers/llm/azure_openai_llm_client.py +6 -68
- rasa/shared/providers/router/_base_litellm_router_client.py +53 -1
- rasa/shared/utils/common.py +42 -0
- rasa/shared/utils/constants.py +3 -0
- rasa/shared/utils/llm.py +70 -24
- rasa/studio/download/domains.py +49 -0
- rasa/studio/download/download.py +439 -0
- rasa/studio/download/flows.py +359 -0
- rasa/studio/results_logger.py +6 -1
- rasa/studio/upload.py +69 -5
- rasa/tracing/instrumentation/attribute_extractors.py +7 -10
- rasa/tracing/instrumentation/instrumentation.py +12 -12
- rasa/utils/common.py +36 -0
- rasa/utils/endpoints.py +22 -1
- rasa/utils/licensing.py +1 -1
- rasa/validator.py +1 -2
- rasa/version.py +1 -1
- {rasa_pro-3.13.0.dev2.dist-info → rasa_pro-3.13.0.dev5.dist-info}/METADATA +7 -7
- {rasa_pro-3.13.0.dev2.dist-info → rasa_pro-3.13.0.dev5.dist-info}/RECORD +149 -166
- 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-11268142.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-ff7f2ce7.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-cba7ae20.js +0 -1
- rasa/document_retrieval/__init__.py +0 -0
- rasa/document_retrieval/constants.py +0 -32
- rasa/document_retrieval/document_post_processor.py +0 -351
- rasa/document_retrieval/document_post_processor_prompt_template.jinja2 +0 -0
- rasa/document_retrieval/document_retriever.py +0 -333
- rasa/document_retrieval/knowledge_base_connectors/__init__.py +0 -0
- rasa/document_retrieval/knowledge_base_connectors/api_connector.py +0 -39
- rasa/document_retrieval/knowledge_base_connectors/knowledge_base_connector.py +0 -34
- rasa/document_retrieval/knowledge_base_connectors/vector_store_connector.py +0 -226
- rasa/document_retrieval/query_rewriter.py +0 -234
- rasa/document_retrieval/query_rewriter_prompt_template.jinja2 +0 -8
- rasa/studio/download.py +0 -489
- /rasa/cli/project_templates/{calm → default}/actions/action_template.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/add_contact.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/db.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/list_contacts.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/remove_contact.py +0 -0
- /rasa/cli/project_templates/{calm → default}/data/flows/add_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/data/flows/list_contacts.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/data/flows/remove_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/db/contacts.json +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/add_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/list_contacts.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/remove_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/shared.yml +0 -0
- /rasa/{cli/project_templates/calm/actions → studio/download}/__init__.py +0 -0
- {rasa_pro-3.13.0.dev2.dist-info → rasa_pro-3.13.0.dev5.dist-info}/NOTICE +0 -0
- {rasa_pro-3.13.0.dev2.dist-info → rasa_pro-3.13.0.dev5.dist-info}/WHEEL +0 -0
- {rasa_pro-3.13.0.dev2.dist-info → rasa_pro-3.13.0.dev5.dist-info}/entry_points.txt +0 -0
|
@@ -52,6 +52,10 @@ from rasa.shared.exceptions import ProviderClientAPIException
|
|
|
52
52
|
from rasa.shared.nlu.constants import TEXT
|
|
53
53
|
from rasa.shared.nlu.training_data.message import Message
|
|
54
54
|
from rasa.shared.providers.llm.llm_response import LLMResponse
|
|
55
|
+
from rasa.shared.utils.constants import (
|
|
56
|
+
LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON,
|
|
57
|
+
LOG_COMPONENT_SOURCE_METHOD_INIT,
|
|
58
|
+
)
|
|
55
59
|
from rasa.shared.utils.io import deep_container_fingerprint, raise_deprecation_warning
|
|
56
60
|
from rasa.shared.utils.llm import (
|
|
57
61
|
allowed_values_for_slot,
|
|
@@ -330,6 +334,8 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
330
334
|
return get_prompt_template(
|
|
331
335
|
config.get("prompt_templates", {}).get(key, {}).get(FILE_PATH_KEY),
|
|
332
336
|
default_value,
|
|
337
|
+
log_source_component=MultiStepLLMCommandGenerator.__name__,
|
|
338
|
+
log_source_method=LOG_COMPONENT_SOURCE_METHOD_INIT,
|
|
333
339
|
)
|
|
334
340
|
|
|
335
341
|
@classmethod
|
|
@@ -786,17 +792,24 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
786
792
|
@classmethod
|
|
787
793
|
def fingerprint_addon(cls, config: Dict[str, Any]) -> Optional[str]:
|
|
788
794
|
"""Add a fingerprint for the graph."""
|
|
795
|
+
get_prompt_template_log_params = {
|
|
796
|
+
"log_source_component": MultiStepLLMCommandGenerator.__name__,
|
|
797
|
+
"log_source_method": LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON,
|
|
798
|
+
}
|
|
799
|
+
|
|
789
800
|
handle_flows_template = get_prompt_template(
|
|
790
801
|
config.get("prompt_templates", {})
|
|
791
802
|
.get(HANDLE_FLOWS_KEY, {})
|
|
792
803
|
.get(FILE_PATH_KEY),
|
|
793
804
|
DEFAULT_HANDLE_FLOWS_TEMPLATE,
|
|
805
|
+
**get_prompt_template_log_params,
|
|
794
806
|
)
|
|
795
807
|
fill_slots_template = get_prompt_template(
|
|
796
808
|
config.get("prompt_templates", {})
|
|
797
809
|
.get(FILL_SLOTS_KEY, {})
|
|
798
810
|
.get(FILE_PATH_KEY),
|
|
799
811
|
DEFAULT_FILL_SLOTS_TEMPLATE,
|
|
812
|
+
**get_prompt_template_log_params,
|
|
800
813
|
)
|
|
801
814
|
|
|
802
815
|
llm_config = resolve_model_client_config(
|
|
@@ -8,7 +8,7 @@ Your task is to analyze the current conversation context and generate a list of
|
|
|
8
8
|
* `set slot slot_name slot_value`: Slot setting. For example, `set slot transfer_money_recipient Freddy`. Can be used to correct and change previously set values.
|
|
9
9
|
* `cancel flow`: Cancelling the current flow.
|
|
10
10
|
* `disambiguate flows flow_name1 flow_name2 ... flow_name_n`: Disambiguate which flow should be started when user input is ambiguous by listing the potential flows as options. For example, `disambiguate flows list_contacts add_contact remove_contact ...` if the user just wrote "contacts".
|
|
11
|
-
* `
|
|
11
|
+
* `provide info`: Responding to the user's questions by supplying relevant information, such as answering FAQs or explaining services.
|
|
12
12
|
* `offtopic reply`: Responding to casual or social user messages that are unrelated to any flows, engaging in friendly conversation and addressing off-topic remarks.
|
|
13
13
|
* `hand over`: Handing over to a human, in case the user seems frustrated or explicitly asks to speak to one.
|
|
14
14
|
|
|
@@ -16,9 +16,7 @@ Use the following structured data:
|
|
|
16
16
|
* `set slot slot_name slot_value`: Slot setting. For example, `set slot transfer_money_recipient Freddy`. Can be used to correct and change previously set values.
|
|
17
17
|
* `cancel flow`: Cancelling the current flow.
|
|
18
18
|
* `disambiguate flows flow_name1 flow_name2 ... flow_name_n`: Disambiguate which flow should be started when user input is ambiguous by listing the potential flows as options. For example, `disambiguate flows list_contacts add_contact remove_contact ...` if the user just wrote "contacts".
|
|
19
|
-
|
|
20
|
-
* `search and reply`: Responding to the user's message by using the relevant FAQs (included in this prompt) retrieved from the knowledge base.
|
|
21
|
-
{%- endif %}
|
|
19
|
+
* `provide info`: Responding to the user's questions by supplying relevant information, such as answering FAQs or explaining services.
|
|
22
20
|
* `offtopic reply`: Responding to casual or social user messages that are unrelated to any flows, engaging in friendly conversation and addressing off-topic remarks.
|
|
23
21
|
* `hand over`: Handing over to a human, in case the user seems frustrated or explicitly asks to speak to one.
|
|
24
22
|
|
|
@@ -29,36 +27,16 @@ Use the following structured data:
|
|
|
29
27
|
* For categorical slots try to match the user message with allowed slot values. Use "other" if you cannot match it.
|
|
30
28
|
* Set the boolean slots based on the user response. Map positive responses to `True`, and negative to `False`.
|
|
31
29
|
* Extract text slot values exactly as provided by the user. Avoid assumptions, format changes, or partial extractions.
|
|
32
|
-
* Use clarification in ambiguous cases.
|
|
33
|
-
* Use `disambiguate flows` only when multiple flows could fit the same message (e.g., "card" could mean `block_card` or `replace_card`).
|
|
34
|
-
{%- if relevant_documents.results %}
|
|
35
|
-
* A user asking a question does not automatically imply that they want `search and reply`. The objective is to help them complete a business process if its possible to do so via a flow.
|
|
36
|
-
* **Flow Priority**: If a user message can be addressed by starting a flow (even if it looks like a general question), ALWAYS start the flow first. Example: If the user says "How do I activate my card?", use `start flow activate_card` instead of `search and reply`. Only use `search and reply` if no flow matches the request.
|
|
37
|
-
{%- endif %}
|
|
38
30
|
* Only use information provided by the user.
|
|
31
|
+
* Use clarification in ambiguous cases.
|
|
39
32
|
* Multiple flows can be started. If a user wants to digress into a second flow, you do not need to cancel the current flow.
|
|
40
33
|
* Do not cancel the flow unless the user explicitly requests it.
|
|
41
34
|
* Strictly adhere to the provided action format.
|
|
42
35
|
* Focus on the last message and take it one step at a time.
|
|
43
36
|
* Use the previous conversation steps only to aid understanding.
|
|
44
37
|
|
|
45
|
-
{%- if relevant_documents.results %}
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
## Relevant FAQs from the knowledge base
|
|
50
|
-
```json
|
|
51
|
-
{"documents":[{% for document in relevant_documents.results %}{"Q":"{{ document.text }}","A":"{{ document.metadata.answer }}"},{% endfor %}]}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
---
|
|
55
|
-
|
|
56
|
-
{% else %}
|
|
57
|
-
|
|
58
38
|
---
|
|
59
39
|
|
|
60
|
-
{% endif -%}
|
|
61
|
-
|
|
62
40
|
## Current State
|
|
63
41
|
{% if current_flow != None %}Use the following structured data:
|
|
64
42
|
```json
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import copy
|
|
2
|
-
from typing import Any, Dict, List, Optional, Text
|
|
2
|
+
from typing import Any, Dict, List, Literal, Optional, Text
|
|
3
3
|
|
|
4
4
|
import structlog
|
|
5
5
|
|
|
6
6
|
import rasa.shared.utils.io
|
|
7
|
-
from rasa.core.information_retrieval import SearchResultList
|
|
8
7
|
from rasa.dialogue_understanding.commands import (
|
|
9
8
|
CannotHandleCommand,
|
|
10
9
|
Command,
|
|
@@ -39,7 +38,6 @@ from rasa.dialogue_understanding.utils import (
|
|
|
39
38
|
add_commands_to_message_parse_data,
|
|
40
39
|
add_prompt_to_message_parse_data,
|
|
41
40
|
)
|
|
42
|
-
from rasa.document_retrieval.constants import POST_PROCESSED_DOCUMENTS_KEY
|
|
43
41
|
from rasa.engine.graph import ExecutionContext
|
|
44
42
|
from rasa.engine.recipes.default_recipe import DefaultV1Recipe
|
|
45
43
|
from rasa.engine.storage.resource import Resource
|
|
@@ -60,6 +58,10 @@ from rasa.shared.exceptions import ProviderClientAPIException
|
|
|
60
58
|
from rasa.shared.nlu.constants import LLM_COMMANDS, LLM_PROMPT, TEXT
|
|
61
59
|
from rasa.shared.nlu.training_data.message import Message
|
|
62
60
|
from rasa.shared.providers.llm.llm_response import LLMResponse
|
|
61
|
+
from rasa.shared.utils.constants import (
|
|
62
|
+
LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON,
|
|
63
|
+
LOG_COMPONENT_SOURCE_METHOD_INIT,
|
|
64
|
+
)
|
|
63
65
|
from rasa.shared.utils.io import deep_container_fingerprint
|
|
64
66
|
from rasa.shared.utils.llm import (
|
|
65
67
|
allowed_values_for_slot,
|
|
@@ -189,8 +191,8 @@ class CompactLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
189
191
|
)
|
|
190
192
|
|
|
191
193
|
# Get the prompt template from the config or the default prompt template.
|
|
192
|
-
self.prompt_template = self.
|
|
193
|
-
self.config, prompt_template
|
|
194
|
+
self.prompt_template = self._resolve_component_prompt_template(
|
|
195
|
+
self.config, prompt_template, log_context=LOG_COMPONENT_SOURCE_METHOD_INIT
|
|
194
196
|
)
|
|
195
197
|
|
|
196
198
|
# Set the command syntax version to v2
|
|
@@ -495,10 +497,6 @@ class CompactLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
495
497
|
latest_user_message = sanitize_message_for_prompt(message.get(TEXT))
|
|
496
498
|
current_conversation += f"\nUSER: {latest_user_message}"
|
|
497
499
|
|
|
498
|
-
relevant_documents = SearchResultList.from_dict(
|
|
499
|
-
message.get(POST_PROCESSED_DOCUMENTS_KEY, [])
|
|
500
|
-
)
|
|
501
|
-
|
|
502
500
|
inputs = {
|
|
503
501
|
"available_flows": self.prepare_flows_for_template(
|
|
504
502
|
startable_flows, tracker
|
|
@@ -512,7 +510,6 @@ class CompactLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
512
510
|
"current_slot_allowed_values": current_slot_allowed_values,
|
|
513
511
|
"user_message": latest_user_message,
|
|
514
512
|
"is_repeat_command_enabled": self.repeat_command_enabled,
|
|
515
|
-
"relevant_documents": relevant_documents,
|
|
516
513
|
}
|
|
517
514
|
|
|
518
515
|
return self.compile_template(self.prompt_template).render(**inputs)
|
|
@@ -546,7 +543,9 @@ class CompactLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
546
543
|
# and update the llm config with the resolved llm config.
|
|
547
544
|
_config_copy = copy.deepcopy(config)
|
|
548
545
|
_config_copy[LLM_CONFIG_KEY] = llm_config
|
|
549
|
-
prompt_template = cls.
|
|
546
|
+
prompt_template = cls._resolve_component_prompt_template(
|
|
547
|
+
_config_copy, log_context=LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON
|
|
548
|
+
)
|
|
550
549
|
|
|
551
550
|
return deep_container_fingerprint(
|
|
552
551
|
[prompt_template, llm_config, embedding_config]
|
|
@@ -562,20 +561,26 @@ class CompactLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
562
561
|
return CommandSyntaxVersion.v2
|
|
563
562
|
|
|
564
563
|
@staticmethod
|
|
565
|
-
def
|
|
566
|
-
config: Dict[str, Any],
|
|
564
|
+
def _resolve_component_prompt_template(
|
|
565
|
+
config: Dict[str, Any],
|
|
566
|
+
prompt_template: Optional[str] = None,
|
|
567
|
+
log_context: Optional[Literal["init", "fingerprint_addon"]] = None,
|
|
567
568
|
) -> Optional[str]:
|
|
568
569
|
"""Get the prompt template from the config or the default prompt template."""
|
|
569
570
|
# Get the default prompt template based on the model name.
|
|
570
571
|
default_command_prompt_template = get_default_prompt_template_based_on_model(
|
|
571
|
-
config.get(LLM_CONFIG_KEY, {}) or {},
|
|
572
|
-
MODEL_PROMPT_MAPPER,
|
|
573
|
-
DEFAULT_COMMAND_PROMPT_TEMPLATE_FILE_NAME,
|
|
574
|
-
FALLBACK_COMMAND_PROMPT_TEMPLATE_FILE_NAME,
|
|
572
|
+
llm_config=config.get(LLM_CONFIG_KEY, {}) or {},
|
|
573
|
+
model_prompt_mapping=MODEL_PROMPT_MAPPER,
|
|
574
|
+
default_prompt_path=DEFAULT_COMMAND_PROMPT_TEMPLATE_FILE_NAME,
|
|
575
|
+
fallback_prompt_path=FALLBACK_COMMAND_PROMPT_TEMPLATE_FILE_NAME,
|
|
576
|
+
log_source_component=CompactLLMCommandGenerator.__name__,
|
|
577
|
+
log_source_method=log_context,
|
|
575
578
|
)
|
|
576
579
|
|
|
577
580
|
# Return the prompt template either from the config or the default prompt.
|
|
578
581
|
return prompt_template or get_prompt_template(
|
|
579
582
|
config.get(PROMPT_TEMPLATE_CONFIG_KEY),
|
|
580
583
|
default_command_prompt_template,
|
|
584
|
+
log_source_component=CompactLLMCommandGenerator.__name__,
|
|
585
|
+
log_source_method=log_context,
|
|
581
586
|
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import importlib.resources
|
|
2
|
-
from typing import Any, Dict, Optional, Text
|
|
2
|
+
from typing import Any, Dict, Literal, Optional, Text
|
|
3
3
|
|
|
4
4
|
import structlog
|
|
5
5
|
|
|
@@ -25,8 +25,12 @@ from rasa.shared.constants import (
|
|
|
25
25
|
PROMPT_CONFIG_KEY,
|
|
26
26
|
PROMPT_TEMPLATE_CONFIG_KEY,
|
|
27
27
|
)
|
|
28
|
+
from rasa.shared.utils.constants import LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON
|
|
28
29
|
from rasa.shared.utils.io import deep_container_fingerprint
|
|
29
|
-
from rasa.shared.utils.llm import
|
|
30
|
+
from rasa.shared.utils.llm import (
|
|
31
|
+
get_prompt_template,
|
|
32
|
+
resolve_model_client_config,
|
|
33
|
+
)
|
|
30
34
|
|
|
31
35
|
DEFAULT_COMMAND_PROMPT_TEMPLATE = importlib.resources.read_text(
|
|
32
36
|
"rasa.dialogue_understanding.generator.prompt_templates",
|
|
@@ -72,9 +76,6 @@ class SingleStepLLMCommandGenerator(CompactLLMCommandGenerator):
|
|
|
72
76
|
"Please use the config parameter 'prompt_template' instead. "
|
|
73
77
|
),
|
|
74
78
|
)
|
|
75
|
-
self.prompt_template = self.resolve_component_prompt_template(
|
|
76
|
-
config, prompt_template
|
|
77
|
-
)
|
|
78
79
|
|
|
79
80
|
# Set the command syntax version to v1
|
|
80
81
|
CommandSyntaxManager.set_syntax_version(
|
|
@@ -95,7 +96,9 @@ class SingleStepLLMCommandGenerator(CompactLLMCommandGenerator):
|
|
|
95
96
|
@classmethod
|
|
96
97
|
def fingerprint_addon(cls: Any, config: Dict[str, Any]) -> Optional[str]:
|
|
97
98
|
"""Add a fingerprint for the graph."""
|
|
98
|
-
prompt_template = cls.
|
|
99
|
+
prompt_template = cls._resolve_component_prompt_template(
|
|
100
|
+
config, log_context=LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON
|
|
101
|
+
)
|
|
99
102
|
llm_config = resolve_model_client_config(
|
|
100
103
|
config.get(LLM_CONFIG_KEY), SingleStepLLMCommandGenerator.__name__
|
|
101
104
|
)
|
|
@@ -117,17 +120,29 @@ class SingleStepLLMCommandGenerator(CompactLLMCommandGenerator):
|
|
|
117
120
|
return CommandSyntaxVersion.v1
|
|
118
121
|
|
|
119
122
|
@staticmethod
|
|
120
|
-
def
|
|
121
|
-
config: Dict[str, Any],
|
|
123
|
+
def _resolve_component_prompt_template(
|
|
124
|
+
config: Dict[str, Any],
|
|
125
|
+
prompt_template: Optional[str] = None,
|
|
126
|
+
log_context: Optional[Literal["init", "fingerprint_addon"]] = None,
|
|
122
127
|
) -> Optional[str]:
|
|
123
128
|
"""Get the prompt template from the config or the default prompt template."""
|
|
124
|
-
#
|
|
125
|
-
|
|
129
|
+
# Case when model is being loaded
|
|
130
|
+
if prompt_template is not None:
|
|
131
|
+
return prompt_template
|
|
132
|
+
|
|
133
|
+
# The prompt can be configured in the config via the "prompt" (deprecated) or
|
|
134
|
+
# "prompt_template" properties
|
|
135
|
+
prompt_template_path = (
|
|
126
136
|
config.get(PROMPT_CONFIG_KEY)
|
|
127
137
|
or config.get(PROMPT_TEMPLATE_CONFIG_KEY)
|
|
128
138
|
or None
|
|
129
139
|
)
|
|
130
|
-
|
|
131
|
-
|
|
140
|
+
|
|
141
|
+
# Try to load the template from the given path or fallback to the default for
|
|
142
|
+
# the component
|
|
143
|
+
return get_prompt_template(
|
|
144
|
+
prompt_template_path,
|
|
132
145
|
DEFAULT_COMMAND_PROMPT_TEMPLATE,
|
|
146
|
+
log_source_component=SingleStepLLMCommandGenerator.__name__,
|
|
147
|
+
log_source_method=log_context,
|
|
133
148
|
)
|
|
@@ -261,19 +261,27 @@ class DialogueUnderstandingTestStep(BaseModel):
|
|
|
261
261
|
# Safely extract commands from the step.
|
|
262
262
|
commands = []
|
|
263
263
|
for command in step.get(KEY_COMMANDS, []):
|
|
264
|
+
parsed_commands = None
|
|
264
265
|
try:
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
default_commands_to_remove=remove_default_commands,
|
|
272
|
-
)
|
|
266
|
+
parsed_commands = parse_commands(
|
|
267
|
+
command,
|
|
268
|
+
flows,
|
|
269
|
+
clarify_options_optional=True,
|
|
270
|
+
additional_commands=custom_command_classes,
|
|
271
|
+
default_commands_to_remove=remove_default_commands,
|
|
273
272
|
)
|
|
274
273
|
except (IndexError, ValueError) as e:
|
|
275
274
|
raise ValueError(f"Failed to parse command '{command}': {e}") from e
|
|
276
275
|
|
|
276
|
+
if not parsed_commands:
|
|
277
|
+
raise ValueError(
|
|
278
|
+
f"Failed to parse command '{command}': command parser returned "
|
|
279
|
+
f"None. Please make sure that you are using the correct command "
|
|
280
|
+
f"syntax and the command arguments are valid."
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
commands.extend(parsed_commands)
|
|
284
|
+
|
|
277
285
|
# Construct the DialogueUnderstandingTestStep
|
|
278
286
|
return DialogueUnderstandingTestStep(
|
|
279
287
|
actor=ACTOR_USER if ACTOR_USER in step else ACTOR_BOT,
|
|
@@ -329,19 +329,14 @@ def print_prompt(step: FailedTestStep) -> None:
|
|
|
329
329
|
rich.print(
|
|
330
330
|
f"[bold] prompt name [/bold]: {prompt_data[KEY_PROMPT_NAME]}"
|
|
331
331
|
)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
)
|
|
341
|
-
if KEY_LATENCY in prompt_data:
|
|
342
|
-
rich.print(
|
|
343
|
-
f"[bold] latency [/bold]: {prompt_data[KEY_LATENCY]}"
|
|
344
|
-
)
|
|
332
|
+
rich.print(
|
|
333
|
+
f"[bold] prompt tokens [/bold]: {prompt_data[KEY_PROMPT_TOKENS]}"
|
|
334
|
+
)
|
|
335
|
+
rich.print(
|
|
336
|
+
f"[bold] completion tokens[/bold]: "
|
|
337
|
+
f"{prompt_data[KEY_COMPLETION_TOKENS]}"
|
|
338
|
+
)
|
|
339
|
+
rich.print(f"[bold] latency [/bold]: {prompt_data[KEY_LATENCY]}")
|
|
345
340
|
if KEY_SYSTEM_PROMPT in prompt_data:
|
|
346
341
|
rich.print(
|
|
347
342
|
f"[bold] system prompt [/bold]: "
|
|
@@ -7,6 +7,7 @@ import structlog
|
|
|
7
7
|
import rasa.shared.utils.io
|
|
8
8
|
from rasa.e2e_test.constants import SCHEMA_FILE_PATH
|
|
9
9
|
from rasa.e2e_test.e2e_test_case import Fixture, Metadata
|
|
10
|
+
from rasa.exceptions import ModelNotFound
|
|
10
11
|
from rasa.shared.utils.yaml import read_schema_file
|
|
11
12
|
|
|
12
13
|
if TYPE_CHECKING:
|
|
@@ -152,10 +153,9 @@ def validate_model_path(model_path: Optional[str], parameter: str, default: str)
|
|
|
152
153
|
return model_path
|
|
153
154
|
|
|
154
155
|
if model_path and not Path(model_path).exists():
|
|
155
|
-
|
|
156
|
+
raise ModelNotFound(
|
|
156
157
|
f"The provided model path '{model_path}' could not be found. "
|
|
157
|
-
|
|
158
|
-
UserWarning,
|
|
158
|
+
"Provide an existing model path."
|
|
159
159
|
)
|
|
160
160
|
|
|
161
161
|
elif model_path is None:
|
|
@@ -13,7 +13,6 @@ from rasa.dialogue_understanding.generator import (
|
|
|
13
13
|
LLMCommandGenerator,
|
|
14
14
|
)
|
|
15
15
|
from rasa.dialogue_understanding.generator.nlu_command_adapter import NLUCommandAdapter
|
|
16
|
-
from rasa.document_retrieval.document_retriever import DocumentRetriever
|
|
17
16
|
from rasa.nlu.classifiers.diet_classifier import DIETClassifier
|
|
18
17
|
from rasa.nlu.classifiers.fallback_classifier import FallbackClassifier
|
|
19
18
|
from rasa.nlu.classifiers.keyword_intent_classifier import KeywordIntentClassifier
|
|
@@ -93,5 +92,4 @@ DEFAULT_COMPONENTS = [
|
|
|
93
92
|
FlowPolicy,
|
|
94
93
|
EnterpriseSearchPolicy,
|
|
95
94
|
IntentlessPolicy,
|
|
96
|
-
DocumentRetriever,
|
|
97
95
|
]
|
|
@@ -19,6 +19,7 @@ from rasa.shared.constants import (
|
|
|
19
19
|
)
|
|
20
20
|
from rasa.shared.exceptions import ProviderClientAPIException
|
|
21
21
|
from rasa.shared.providers.mappings import OPENAI_PROVIDER
|
|
22
|
+
from rasa.shared.utils.constants import LOG_COMPONENT_SOURCE_METHOD_INIT
|
|
22
23
|
from rasa.shared.utils.llm import (
|
|
23
24
|
USER,
|
|
24
25
|
get_prompt_template,
|
|
@@ -54,6 +55,8 @@ class ConversationRephraser:
|
|
|
54
55
|
self.prompt_template = get_prompt_template(
|
|
55
56
|
self.config.get(PROMPT_TEMPLATE_CONFIG_KEY),
|
|
56
57
|
DEFAULT_REPHRASING_PROMPT_TEMPLATE,
|
|
58
|
+
log_source_component=ConversationRephraser.__name__,
|
|
59
|
+
log_source_method=LOG_COMPONENT_SOURCE_METHOD_INIT,
|
|
57
60
|
)
|
|
58
61
|
|
|
59
62
|
@staticmethod
|
rasa/plugin.py
CHANGED
|
@@ -32,11 +32,8 @@ def plugin_manager() -> pluggy.PluginManager:
|
|
|
32
32
|
|
|
33
33
|
def init_hooks(manager: pluggy.PluginManager) -> None:
|
|
34
34
|
"""Initialise hooks into rasa."""
|
|
35
|
-
import rasa.utils.licensing
|
|
36
35
|
from rasa import hooks
|
|
37
36
|
|
|
38
|
-
rasa.utils.licensing.validate_license_from_env()
|
|
39
|
-
|
|
40
37
|
manager.register(hooks)
|
|
41
38
|
|
|
42
39
|
|
rasa/shared/constants.py
CHANGED
|
@@ -238,6 +238,7 @@ EXTRA_PARAMETERS_KEY = "extra_parameters"
|
|
|
238
238
|
MODEL_GROUP_ID_KEY = "model_group_id"
|
|
239
239
|
MODEL_LIST_KEY = "model_list"
|
|
240
240
|
LITELLM_PARAMS_KEY = "litellm_params"
|
|
241
|
+
_VALIDATE_ENVIRONMENT_MISSING_KEYS_KEY = "missing_keys"
|
|
241
242
|
|
|
242
243
|
LLM_API_HEALTH_CHECK_ENV_VAR = "LLM_API_HEALTH_CHECK"
|
|
243
244
|
LLM_API_HEALTH_CHECK_DEFAULT_VALUE = "false"
|
rasa/shared/core/domain.py
CHANGED
|
@@ -134,6 +134,22 @@ ALL_DOMAIN_KEYS = [
|
|
|
134
134
|
|
|
135
135
|
PREV_PREFIX = "prev_"
|
|
136
136
|
|
|
137
|
+
MERGE_FUNC_MAPPING: Dict[Text, Callable[..., Any]] = {
|
|
138
|
+
KEY_ACTIONS: rasa.shared.utils.common.merge_lists_of_dicts,
|
|
139
|
+
KEY_RESPONSES: rasa.shared.utils.common.merge_dicts,
|
|
140
|
+
KEY_SLOTS: rasa.shared.utils.common.merge_dicts,
|
|
141
|
+
KEY_INTENTS: rasa.shared.utils.common.merge_lists_of_dicts,
|
|
142
|
+
KEY_ENTITIES: rasa.shared.utils.common.merge_lists_of_dicts,
|
|
143
|
+
KEY_E2E_ACTIONS: rasa.shared.utils.common.merge_lists,
|
|
144
|
+
KEY_FORMS: rasa.shared.utils.common.merge_dicts,
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
DICT_DATA_KEYS = [
|
|
148
|
+
key
|
|
149
|
+
for key, value in MERGE_FUNC_MAPPING.items()
|
|
150
|
+
if value == rasa.shared.utils.common.merge_dicts
|
|
151
|
+
]
|
|
152
|
+
|
|
137
153
|
# State is a dictionary with keys (USER, PREVIOUS_ACTION, SLOTS, ACTIVE_LOOP)
|
|
138
154
|
# representing the origin of a SubState;
|
|
139
155
|
# the values are SubStates, that contain the information needed for featurization
|
|
@@ -466,17 +482,7 @@ class Domain:
|
|
|
466
482
|
|
|
467
483
|
duplicates: Dict[Text, List[Text]] = {}
|
|
468
484
|
|
|
469
|
-
|
|
470
|
-
KEY_INTENTS: rasa.shared.utils.common.merge_lists_of_dicts,
|
|
471
|
-
KEY_ENTITIES: rasa.shared.utils.common.merge_lists_of_dicts,
|
|
472
|
-
KEY_ACTIONS: rasa.shared.utils.common.merge_lists_of_dicts,
|
|
473
|
-
KEY_E2E_ACTIONS: rasa.shared.utils.common.merge_lists,
|
|
474
|
-
KEY_FORMS: rasa.shared.utils.common.merge_dicts,
|
|
475
|
-
KEY_RESPONSES: rasa.shared.utils.common.merge_dicts,
|
|
476
|
-
KEY_SLOTS: rasa.shared.utils.common.merge_dicts,
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
for key, merge_func in merge_func_mappings.items():
|
|
485
|
+
for key, merge_func in MERGE_FUNC_MAPPING.items():
|
|
480
486
|
duplicates[key] = rasa.shared.utils.common.extract_duplicates(
|
|
481
487
|
combined.get(key, []), domain_dict.get(key, [])
|
|
482
488
|
)
|
|
@@ -494,6 +500,74 @@ class Domain:
|
|
|
494
500
|
|
|
495
501
|
return combined
|
|
496
502
|
|
|
503
|
+
def partial_merge(self, other: Domain) -> Domain:
|
|
504
|
+
"""
|
|
505
|
+
Returns a new Domain with intersection-based merging:
|
|
506
|
+
- For each domain section only overwrite items that already exist in self.
|
|
507
|
+
- Brand-new items in `other` are ignored.
|
|
508
|
+
|
|
509
|
+
Args:
|
|
510
|
+
other: The domain to merge with.
|
|
511
|
+
|
|
512
|
+
Returns:
|
|
513
|
+
A new Domain object with the merged content.
|
|
514
|
+
"""
|
|
515
|
+
updated_self = copy.deepcopy(self.as_dict())
|
|
516
|
+
other_dict = other.as_dict()
|
|
517
|
+
|
|
518
|
+
keys_to_merge = MERGE_FUNC_MAPPING.keys()
|
|
519
|
+
for key in keys_to_merge:
|
|
520
|
+
if key in DICT_DATA_KEYS:
|
|
521
|
+
# Merge dictionaries
|
|
522
|
+
self_val = updated_self.get(key, {})
|
|
523
|
+
other_val = other_dict.get(key, {})
|
|
524
|
+
updated_self[key] = rasa.shared.utils.common.partial_merge_dict(
|
|
525
|
+
self_val, other_val
|
|
526
|
+
)
|
|
527
|
+
else:
|
|
528
|
+
# Merge lists
|
|
529
|
+
self_val = updated_self.get(key, [])
|
|
530
|
+
other_val = other_dict.get(key, [])
|
|
531
|
+
is_same_item_fn = SAME_ITEM_FUNCTIONS.get(key, default_is_same_item)
|
|
532
|
+
updated_self[key] = rasa.shared.utils.common.partial_merge_list(
|
|
533
|
+
self_val, other_val, is_same_item_fn
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
return Domain.from_dict(updated_self)
|
|
537
|
+
|
|
538
|
+
def difference(self, other: Domain) -> Domain:
|
|
539
|
+
"""
|
|
540
|
+
Returns a new Domain containing items in `self` that are NOT in `other`,
|
|
541
|
+
using simple equality checks for dict/list items.
|
|
542
|
+
|
|
543
|
+
Args:
|
|
544
|
+
other: The domain to compare with.
|
|
545
|
+
|
|
546
|
+
Returns:
|
|
547
|
+
A new Domain object with the difference content.
|
|
548
|
+
"""
|
|
549
|
+
self_dict = self.as_dict()
|
|
550
|
+
other_dict = other.as_dict()
|
|
551
|
+
|
|
552
|
+
difference_dict = {}
|
|
553
|
+
for key in MERGE_FUNC_MAPPING.keys():
|
|
554
|
+
is_dict = key in DICT_DATA_KEYS
|
|
555
|
+
self_val = self_dict.get(key, {} if is_dict else [])
|
|
556
|
+
other_val = other_dict.get(key, {} if is_dict else [])
|
|
557
|
+
|
|
558
|
+
if is_dict and isinstance(self_val, dict) and isinstance(other_val, dict):
|
|
559
|
+
difference_dict[key] = {
|
|
560
|
+
k: v
|
|
561
|
+
for k, v in self_val.items()
|
|
562
|
+
if k not in other_val or v != other_val[k]
|
|
563
|
+
}
|
|
564
|
+
else:
|
|
565
|
+
difference_dict[key] = [
|
|
566
|
+
item for item in self_val if item not in other_val
|
|
567
|
+
] # type: ignore[assignment]
|
|
568
|
+
|
|
569
|
+
return Domain.from_dict(difference_dict)
|
|
570
|
+
|
|
497
571
|
def _preprocess_domain_dict(
|
|
498
572
|
self,
|
|
499
573
|
data: Dict,
|
|
@@ -2120,6 +2194,11 @@ class Domain:
|
|
|
2120
2194
|
"""Remove all builtin slots from the domain."""
|
|
2121
2195
|
self.slots = [slot for slot in self.slots if not slot.is_builtin]
|
|
2122
2196
|
|
|
2197
|
+
def __eq__(self, other: object) -> bool:
|
|
2198
|
+
if isinstance(other, Domain):
|
|
2199
|
+
return self.as_dict() == other.as_dict()
|
|
2200
|
+
return False
|
|
2201
|
+
|
|
2123
2202
|
|
|
2124
2203
|
def warn_about_duplicates_found_during_domain_merging(
|
|
2125
2204
|
duplicates: Dict[Text, List[Text]],
|
|
@@ -2178,3 +2257,78 @@ def _validate_forms(forms: Union[Dict, List]) -> None:
|
|
|
2178
2257
|
f"the keyword `{REQUIRED_SLOTS_KEY}` is required. "
|
|
2179
2258
|
f"Please see {DOCS_URL_FORMS} for more information."
|
|
2180
2259
|
)
|
|
2260
|
+
|
|
2261
|
+
|
|
2262
|
+
def is_same_entity(e1: Any, e2: Any) -> bool:
|
|
2263
|
+
"""Check if two entities are the 'same' (string or dict).
|
|
2264
|
+
|
|
2265
|
+
Args:
|
|
2266
|
+
e1: First entity to compare.
|
|
2267
|
+
e2: Second entity to compare.
|
|
2268
|
+
|
|
2269
|
+
Returns:
|
|
2270
|
+
True if the entities are the same, False otherwise.
|
|
2271
|
+
"""
|
|
2272
|
+
if isinstance(e1, str) and isinstance(e2, str):
|
|
2273
|
+
return e1 == e2
|
|
2274
|
+
|
|
2275
|
+
if isinstance(e1, dict) and isinstance(e2, dict):
|
|
2276
|
+
return (
|
|
2277
|
+
e1.get(ENTITY_ATTRIBUTE_TYPE) == e2.get(ENTITY_ATTRIBUTE_TYPE)
|
|
2278
|
+
and e1.get(ENTITY_ATTRIBUTE_ROLE) == e2.get(ENTITY_ATTRIBUTE_ROLE)
|
|
2279
|
+
and e1.get(ENTITY_ATTRIBUTE_GROUP) == e2.get(ENTITY_ATTRIBUTE_GROUP)
|
|
2280
|
+
)
|
|
2281
|
+
|
|
2282
|
+
return False
|
|
2283
|
+
|
|
2284
|
+
|
|
2285
|
+
def is_same_intent(i1: Any, i2: Any) -> bool:
|
|
2286
|
+
"""Check if two intents are the 'same' (string or dict).
|
|
2287
|
+
|
|
2288
|
+
Args:
|
|
2289
|
+
i1: First intent to compare.
|
|
2290
|
+
i2: Second intent to compare.
|
|
2291
|
+
|
|
2292
|
+
Returns:
|
|
2293
|
+
True if the intents are the same, False otherwise.
|
|
2294
|
+
"""
|
|
2295
|
+
if isinstance(i1, str) and isinstance(i2, str):
|
|
2296
|
+
return i1 == i2
|
|
2297
|
+
|
|
2298
|
+
if isinstance(i1, dict) and isinstance(i2, dict):
|
|
2299
|
+
key1, key2 = next(iter(i1.keys())), next(iter((i2.keys())))
|
|
2300
|
+
return key1 == key2
|
|
2301
|
+
|
|
2302
|
+
return False
|
|
2303
|
+
|
|
2304
|
+
|
|
2305
|
+
def is_same_action(a1: Any, a2: Any) -> bool:
|
|
2306
|
+
"""Check if two actions are the 'same' (string or dict).
|
|
2307
|
+
|
|
2308
|
+
Args:
|
|
2309
|
+
a1: First action to compare.
|
|
2310
|
+
a2: Second action to compare.
|
|
2311
|
+
|
|
2312
|
+
Returns:
|
|
2313
|
+
True if the actions are the same, False otherwise.
|
|
2314
|
+
"""
|
|
2315
|
+
if isinstance(a1, str) and isinstance(a2, str):
|
|
2316
|
+
return a1 == a2
|
|
2317
|
+
|
|
2318
|
+
if isinstance(a1, dict) and isinstance(a2, dict):
|
|
2319
|
+
key1, key2 = next(iter((a1.keys()))), next(iter((a2.keys())))
|
|
2320
|
+
return key1 == key2
|
|
2321
|
+
|
|
2322
|
+
return False
|
|
2323
|
+
|
|
2324
|
+
|
|
2325
|
+
def default_is_same_item(a: Any, b: Any) -> bool:
|
|
2326
|
+
"""Fallback exact equality check if a key doesn't need special handling."""
|
|
2327
|
+
return a == b
|
|
2328
|
+
|
|
2329
|
+
|
|
2330
|
+
SAME_ITEM_FUNCTIONS: Dict[Text, Callable[[Any, Any], bool]] = {
|
|
2331
|
+
KEY_ENTITIES: is_same_entity,
|
|
2332
|
+
KEY_INTENTS: is_same_intent,
|
|
2333
|
+
KEY_ACTIONS: is_same_action,
|
|
2334
|
+
}
|