rasa-pro 3.8.18__py3-none-any.whl → 3.9.14__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.
- README.md +6 -42
- rasa/__main__.py +14 -9
- rasa/anonymization/anonymization_pipeline.py +0 -1
- rasa/anonymization/anonymization_rule_executor.py +3 -3
- rasa/anonymization/utils.py +4 -3
- rasa/api.py +2 -2
- rasa/cli/arguments/default_arguments.py +1 -1
- rasa/cli/arguments/run.py +2 -2
- rasa/cli/arguments/test.py +1 -1
- rasa/cli/arguments/train.py +10 -10
- rasa/cli/e2e_test.py +27 -7
- rasa/cli/export.py +0 -1
- rasa/cli/license.py +3 -3
- rasa/cli/project_templates/calm/actions/action_template.py +1 -1
- rasa/cli/project_templates/calm/config.yml +1 -1
- rasa/cli/project_templates/calm/credentials.yml +1 -1
- rasa/cli/project_templates/calm/data/flows/add_contact.yml +1 -1
- rasa/cli/project_templates/calm/data/flows/remove_contact.yml +1 -1
- rasa/cli/project_templates/calm/domain/add_contact.yml +8 -2
- rasa/cli/project_templates/calm/domain/list_contacts.yml +3 -0
- rasa/cli/project_templates/calm/domain/remove_contact.yml +9 -2
- rasa/cli/project_templates/calm/domain/shared.yml +5 -0
- rasa/cli/project_templates/calm/endpoints.yml +4 -4
- rasa/cli/project_templates/default/actions/actions.py +1 -1
- rasa/cli/project_templates/default/config.yml +5 -5
- rasa/cli/project_templates/default/credentials.yml +1 -1
- rasa/cli/project_templates/default/endpoints.yml +4 -4
- rasa/cli/project_templates/default/tests/test_stories.yml +1 -1
- rasa/cli/project_templates/tutorial/config.yml +1 -1
- rasa/cli/project_templates/tutorial/credentials.yml +1 -1
- rasa/cli/project_templates/tutorial/data/patterns.yml +6 -0
- rasa/cli/project_templates/tutorial/domain.yml +4 -0
- rasa/cli/project_templates/tutorial/endpoints.yml +6 -6
- rasa/cli/run.py +0 -1
- rasa/cli/scaffold.py +3 -2
- rasa/cli/studio/download.py +11 -0
- rasa/cli/studio/studio.py +180 -24
- rasa/cli/studio/upload.py +0 -8
- rasa/cli/telemetry.py +18 -6
- rasa/cli/utils.py +21 -10
- rasa/cli/x.py +3 -2
- rasa/constants.py +1 -1
- rasa/core/actions/action.py +90 -315
- rasa/core/actions/action_exceptions.py +24 -0
- rasa/core/actions/constants.py +3 -0
- rasa/core/actions/custom_action_executor.py +188 -0
- rasa/core/actions/forms.py +11 -7
- rasa/core/actions/grpc_custom_action_executor.py +251 -0
- rasa/core/actions/http_custom_action_executor.py +140 -0
- rasa/core/actions/loops.py +3 -0
- rasa/core/actions/two_stage_fallback.py +1 -1
- rasa/core/agent.py +2 -4
- rasa/core/brokers/pika.py +1 -2
- rasa/core/channels/audiocodes.py +1 -1
- rasa/core/channels/botframework.py +0 -1
- rasa/core/channels/callback.py +0 -1
- rasa/core/channels/console.py +6 -8
- rasa/core/channels/development_inspector.py +1 -1
- rasa/core/channels/facebook.py +0 -3
- rasa/core/channels/hangouts.py +0 -6
- rasa/core/channels/inspector/dist/assets/{arc-5623b6dc.js → arc-b6e548fe.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-d0fbc5ce-685c106a.js → c4Diagram-d0fbc5ce-fa03ac9e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-936ed81e-8cbed007.js → classDiagram-936ed81e-ee67392a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-c3cb15f1-5889cf12.js → classDiagram-v2-c3cb15f1-9b283fae.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{createText-62fc7601-24c249d7.js → createText-62fc7601-8b6fcc2a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-f2ad444c-7dd06a75.js → edges-f2ad444c-22e77f4f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-62c1e54c.js → erDiagram-9d236eb7-60ffc87f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-1972c806-ce49b86f.js → flowDb-1972c806-9dd802e4.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-7ea5b25a-4067e48f.js → flowDiagram-7ea5b25a-5fa1912f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-1844e5a5.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-abe16c3d-59fe4051.js → flowchart-elk-definition-abe16c3d-622a1fd2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-9b5ea136-47e3a43b.js → ganttDiagram-9b5ea136-e285a63a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-99d0ae7c-5a2ac0d9.js → gitGraphDiagram-99d0ae7c-f237bdca.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-2c4b9a3b-dfb8efc4.js → index-2c4b9a3b-4b03d70e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-268a75c0.js → index-a5d3e69d.js} +4 -4
- rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-b0c470f2.js → infoDiagram-736b4530-72a0fa5f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-2edb829a.js → journeyDiagram-df861f2b-82218c41.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-b6873d69.js → layout-78cff630.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-1efc5781.js → line-5038b469.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-661e9b94.js → linear-c4fc4098.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-beec6740-2d2e727f.js → mindmap-definition-beec6740-c33c8ea6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-9d3ea93d.js → pieDiagram-dbbf0591-a8d03059.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-06a178a2.js → quadrantDiagram-4d7f4fd6-6a0e56b2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-0bfedffc.js → requirementDiagram-6fc4c22a-2dc7c7bd.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-8f13d901-d76d0a04.js → sankeyDiagram-8f13d901-2360fe39.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-b655622a-37bb4341.js → sequenceDiagram-b655622a-41b9f9ad.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-59f0c015-f52f7f57.js → stateDiagram-59f0c015-0aad326f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-2b26beab-4a986a20.js → stateDiagram-v2-2b26beab-9847d984.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-080da4f6-7dd9ae12.js → styles-080da4f6-564d890e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-3dcbcfbf-46e1ca14.js → styles-3dcbcfbf-38957613.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9c745c82-4a97439a.js → styles-9c745c82-f0fc6921.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-4835440b-823917a3.js → svgDrawCommon-4835440b-ef3c5a77.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-9ea72896.js → timeline-definition-5b62e21b-bf3e91c1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-b631a8b6.js → xychartDiagram-2b33534f-4d4026c0.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +10 -0
- rasa/core/channels/inspector/src/helpers/formatters.test.ts +4 -7
- rasa/core/channels/inspector/src/helpers/formatters.ts +3 -2
- rasa/core/channels/rest.py +36 -21
- rasa/core/channels/rocketchat.py +0 -1
- rasa/core/channels/socketio.py +1 -1
- rasa/core/channels/telegram.py +3 -3
- rasa/core/channels/webexteams.py +0 -1
- rasa/core/concurrent_lock_store.py +1 -1
- rasa/core/evaluation/marker_base.py +1 -3
- rasa/core/evaluation/marker_stats.py +1 -2
- rasa/core/featurizers/single_state_featurizer.py +3 -26
- rasa/core/featurizers/tracker_featurizers.py +18 -122
- rasa/core/information_retrieval/__init__.py +7 -0
- rasa/core/information_retrieval/faiss.py +9 -4
- rasa/core/information_retrieval/information_retrieval.py +64 -7
- rasa/core/information_retrieval/milvus.py +7 -14
- rasa/core/information_retrieval/qdrant.py +8 -15
- rasa/core/lock_store.py +0 -1
- rasa/core/migrate.py +1 -2
- rasa/core/nlg/callback.py +3 -4
- rasa/core/policies/enterprise_search_policy.py +86 -22
- rasa/core/policies/enterprise_search_prompt_template.jinja2 +4 -41
- rasa/core/policies/enterprise_search_prompt_with_citation_template.jinja2 +60 -0
- rasa/core/policies/flows/flow_executor.py +104 -2
- rasa/core/policies/intentless_policy.py +7 -9
- rasa/core/policies/memoization.py +3 -3
- rasa/core/policies/policy.py +18 -9
- rasa/core/policies/rule_policy.py +8 -11
- rasa/core/policies/ted_policy.py +61 -88
- rasa/core/policies/unexpected_intent_policy.py +8 -17
- rasa/core/processor.py +136 -47
- rasa/core/run.py +41 -25
- rasa/core/secrets_manager/endpoints.py +2 -2
- rasa/core/secrets_manager/vault.py +6 -8
- rasa/core/test.py +3 -5
- rasa/core/tracker_store.py +49 -14
- rasa/core/train.py +1 -3
- rasa/core/training/interactive.py +9 -6
- rasa/core/utils.py +5 -10
- rasa/dialogue_understanding/coexistence/intent_based_router.py +11 -4
- rasa/dialogue_understanding/coexistence/llm_based_router.py +2 -3
- rasa/dialogue_understanding/commands/__init__.py +4 -0
- rasa/dialogue_understanding/commands/can_not_handle_command.py +9 -0
- rasa/dialogue_understanding/commands/cancel_flow_command.py +9 -0
- rasa/dialogue_understanding/commands/change_flow_command.py +38 -0
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +9 -0
- rasa/dialogue_understanding/commands/clarify_command.py +9 -0
- rasa/dialogue_understanding/commands/correct_slots_command.py +9 -0
- rasa/dialogue_understanding/commands/error_command.py +12 -0
- rasa/dialogue_understanding/commands/handle_code_change_command.py +9 -0
- rasa/dialogue_understanding/commands/human_handoff_command.py +9 -0
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +9 -0
- rasa/dialogue_understanding/commands/noop_command.py +9 -0
- rasa/dialogue_understanding/commands/set_slot_command.py +34 -3
- rasa/dialogue_understanding/commands/skip_question_command.py +9 -0
- rasa/dialogue_understanding/commands/start_flow_command.py +9 -0
- rasa/dialogue_understanding/generator/__init__.py +16 -1
- rasa/dialogue_understanding/generator/command_generator.py +92 -6
- rasa/dialogue_understanding/generator/constants.py +18 -0
- rasa/dialogue_understanding/generator/flow_retrieval.py +7 -5
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +467 -0
- rasa/dialogue_understanding/generator/llm_command_generator.py +39 -609
- rasa/dialogue_understanding/generator/multi_step/__init__.py +0 -0
- rasa/dialogue_understanding/generator/multi_step/fill_slots_prompt.jinja2 +62 -0
- rasa/dialogue_understanding/generator/multi_step/handle_flows_prompt.jinja2 +38 -0
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +827 -0
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +69 -8
- rasa/dialogue_understanding/generator/single_step/__init__.py +0 -0
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +345 -0
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +44 -39
- rasa/dialogue_understanding/processor/command_processor.py +111 -3
- rasa/e2e_test/constants.py +1 -0
- rasa/e2e_test/e2e_test_case.py +44 -0
- rasa/e2e_test/e2e_test_runner.py +114 -11
- rasa/e2e_test/e2e_test_schema.yml +18 -0
- rasa/engine/caching.py +0 -1
- rasa/engine/graph.py +18 -6
- rasa/engine/recipes/config_files/default_config.yml +3 -3
- rasa/engine/recipes/default_components.py +1 -1
- rasa/engine/recipes/default_recipe.py +4 -5
- rasa/engine/recipes/recipe.py +1 -1
- rasa/engine/runner/dask.py +3 -9
- rasa/engine/storage/local_model_storage.py +0 -2
- rasa/engine/validation.py +179 -145
- rasa/exceptions.py +2 -2
- rasa/graph_components/validators/default_recipe_validator.py +3 -5
- rasa/hooks.py +0 -1
- rasa/model.py +1 -1
- rasa/model_training.py +1 -0
- rasa/nlu/classifiers/diet_classifier.py +33 -52
- rasa/nlu/classifiers/logistic_regression_classifier.py +9 -22
- rasa/nlu/classifiers/sklearn_intent_classifier.py +16 -37
- rasa/nlu/extractors/crf_entity_extractor.py +54 -97
- rasa/nlu/extractors/duckling_entity_extractor.py +1 -1
- rasa/nlu/featurizers/dense_featurizer/convert_featurizer.py +1 -5
- rasa/nlu/featurizers/dense_featurizer/lm_featurizer.py +0 -4
- rasa/nlu/featurizers/featurizer.py +1 -1
- rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +18 -49
- rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +26 -64
- rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +3 -5
- rasa/nlu/persistor.py +68 -26
- rasa/nlu/selectors/response_selector.py +7 -10
- rasa/nlu/test.py +0 -3
- rasa/nlu/utils/hugging_face/registry.py +1 -1
- rasa/nlu/utils/spacy_utils.py +1 -3
- rasa/server.py +22 -7
- rasa/shared/constants.py +12 -1
- rasa/shared/core/command_payload_reader.py +109 -0
- rasa/shared/core/constants.py +4 -5
- rasa/shared/core/domain.py +57 -56
- rasa/shared/core/events.py +4 -7
- rasa/shared/core/flows/flow.py +9 -0
- rasa/shared/core/flows/flows_list.py +12 -0
- rasa/shared/core/flows/steps/action.py +7 -2
- rasa/shared/core/generator.py +12 -11
- rasa/shared/core/slot_mappings.py +315 -24
- rasa/shared/core/slots.py +4 -2
- rasa/shared/core/trackers.py +32 -14
- rasa/shared/core/training_data/loading.py +0 -1
- rasa/shared/core/training_data/story_reader/story_reader.py +3 -3
- rasa/shared/core/training_data/story_reader/yaml_story_reader.py +11 -11
- rasa/shared/core/training_data/story_writer/yaml_story_writer.py +5 -3
- rasa/shared/core/training_data/structures.py +1 -1
- rasa/shared/core/training_data/visualization.py +1 -1
- rasa/shared/data.py +58 -1
- rasa/shared/exceptions.py +36 -2
- rasa/shared/importers/importer.py +1 -2
- rasa/shared/importers/rasa.py +0 -1
- rasa/shared/nlu/constants.py +2 -0
- rasa/shared/nlu/training_data/entities_parser.py +1 -2
- rasa/shared/nlu/training_data/features.py +2 -120
- rasa/shared/nlu/training_data/formats/dialogflow.py +3 -2
- rasa/shared/nlu/training_data/formats/rasa_yaml.py +3 -5
- rasa/shared/nlu/training_data/formats/readerwriter.py +0 -1
- rasa/shared/nlu/training_data/message.py +13 -0
- rasa/shared/nlu/training_data/training_data.py +0 -2
- rasa/shared/providers/openai/session_handler.py +2 -2
- rasa/shared/utils/constants.py +3 -0
- rasa/shared/utils/io.py +11 -1
- rasa/shared/utils/llm.py +1 -2
- rasa/shared/utils/pykwalify_extensions.py +1 -0
- rasa/shared/utils/schemas/domain.yml +3 -0
- rasa/shared/utils/yaml.py +44 -35
- rasa/studio/auth.py +26 -10
- rasa/studio/constants.py +2 -0
- rasa/studio/data_handler.py +114 -107
- rasa/studio/download.py +160 -27
- rasa/studio/results_logger.py +137 -0
- rasa/studio/train.py +6 -7
- rasa/studio/upload.py +159 -134
- rasa/telemetry.py +188 -34
- rasa/tracing/config.py +18 -3
- rasa/tracing/constants.py +26 -2
- rasa/tracing/instrumentation/attribute_extractors.py +50 -41
- rasa/tracing/instrumentation/instrumentation.py +290 -44
- rasa/tracing/instrumentation/intentless_policy_instrumentation.py +7 -5
- rasa/tracing/instrumentation/metrics.py +109 -21
- rasa/tracing/metric_instrument_provider.py +83 -3
- rasa/utils/cli.py +2 -1
- rasa/utils/common.py +1 -1
- rasa/utils/endpoints.py +1 -2
- rasa/utils/io.py +72 -6
- rasa/utils/licensing.py +246 -31
- rasa/utils/ml_utils.py +1 -1
- rasa/utils/tensorflow/data_generator.py +1 -1
- rasa/utils/tensorflow/environment.py +1 -1
- rasa/utils/tensorflow/model_data.py +201 -12
- rasa/utils/tensorflow/model_data_utils.py +499 -500
- rasa/utils/tensorflow/models.py +5 -6
- rasa/utils/tensorflow/rasa_layers.py +15 -15
- rasa/utils/train_utils.py +1 -1
- rasa/utils/url_tools.py +53 -0
- rasa/validator.py +305 -3
- rasa/version.py +1 -1
- {rasa_pro-3.8.18.dist-info → rasa_pro-3.9.14.dist-info}/METADATA +25 -61
- {rasa_pro-3.8.18.dist-info → rasa_pro-3.9.14.dist-info}/RECORD +276 -259
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-85583a23.js +0 -1
- rasa/utils/tensorflow/feature_array.py +0 -370
- /rasa/dialogue_understanding/generator/{command_prompt_template.jinja2 → single_step/command_prompt_template.jinja2} +0 -0
- {rasa_pro-3.8.18.dist-info → rasa_pro-3.9.14.dist-info}/NOTICE +0 -0
- {rasa_pro-3.8.18.dist-info → rasa_pro-3.9.14.dist-info}/WHEEL +0 -0
- {rasa_pro-3.8.18.dist-info → rasa_pro-3.9.14.dist-info}/entry_points.txt +0 -0
|
@@ -2,20 +2,27 @@ from typing import Dict, Text, Any, Optional, List
|
|
|
2
2
|
|
|
3
3
|
import structlog
|
|
4
4
|
|
|
5
|
+
|
|
5
6
|
from rasa.dialogue_understanding.commands import (
|
|
6
7
|
Command,
|
|
7
8
|
StartFlowCommand,
|
|
8
9
|
SetSlotCommand,
|
|
9
10
|
)
|
|
11
|
+
from rasa.dialogue_understanding.commands.set_slot_command import SetSlotExtractor
|
|
10
12
|
from rasa.dialogue_understanding.generator import CommandGenerator
|
|
11
13
|
from rasa.engine.graph import GraphComponent, ExecutionContext
|
|
12
14
|
from rasa.engine.recipes.default_recipe import DefaultV1Recipe
|
|
13
15
|
from rasa.engine.storage.resource import Resource
|
|
14
16
|
from rasa.engine.storage.storage import ModelStorage
|
|
15
17
|
from rasa.shared.constants import ROUTE_TO_CALM_SLOT
|
|
18
|
+
from rasa.shared.core.domain import Domain
|
|
16
19
|
from rasa.shared.core.flows.flows_list import FlowsList
|
|
20
|
+
from rasa.shared.core.slot_mappings import (
|
|
21
|
+
SlotFillingManager,
|
|
22
|
+
extract_slot_value,
|
|
23
|
+
)
|
|
17
24
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
18
|
-
from rasa.shared.nlu.constants import INTENT
|
|
25
|
+
from rasa.shared.nlu.constants import ENTITIES, INTENT
|
|
19
26
|
from rasa.shared.nlu.training_data.message import Message
|
|
20
27
|
from rasa.shared.nlu.training_data.training_data import TrainingData
|
|
21
28
|
|
|
@@ -76,6 +83,7 @@ class NLUCommandAdapter(GraphComponent, CommandGenerator):
|
|
|
76
83
|
message: Message,
|
|
77
84
|
flows: FlowsList,
|
|
78
85
|
tracker: Optional[DialogueStateTracker] = None,
|
|
86
|
+
**kwargs: Any,
|
|
79
87
|
) -> List[Command]:
|
|
80
88
|
"""Creates commands using the predicted intents.
|
|
81
89
|
|
|
@@ -83,6 +91,7 @@ class NLUCommandAdapter(GraphComponent, CommandGenerator):
|
|
|
83
91
|
message: The message from the user.
|
|
84
92
|
flows: The flows available to the user.
|
|
85
93
|
tracker: The tracker containing the current state of the conversation.
|
|
94
|
+
**kwargs: Keyword arguments for forward compatibility.
|
|
86
95
|
|
|
87
96
|
Returns:
|
|
88
97
|
The commands triggered by NLU.
|
|
@@ -91,9 +100,18 @@ class NLUCommandAdapter(GraphComponent, CommandGenerator):
|
|
|
91
100
|
# cannot do anything if there are no flows or no tracker
|
|
92
101
|
return []
|
|
93
102
|
|
|
94
|
-
|
|
103
|
+
domain = kwargs.get("domain", None)
|
|
104
|
+
commands = self.convert_nlu_to_commands(message, tracker, flows, domain)
|
|
105
|
+
|
|
106
|
+
commands_contain_start_flow = any(
|
|
107
|
+
isinstance(command, StartFlowCommand) for command in commands
|
|
108
|
+
)
|
|
95
109
|
|
|
96
|
-
if
|
|
110
|
+
if (
|
|
111
|
+
commands
|
|
112
|
+
and commands_contain_start_flow
|
|
113
|
+
and tracker.has_coexistence_routing_slot
|
|
114
|
+
):
|
|
97
115
|
# if the nlu command adapter will start a flow and the coexistence feature
|
|
98
116
|
# is used, make sure to set the routing slot
|
|
99
117
|
commands += [SetSlotCommand(ROUTE_TO_CALM_SLOT, True)]
|
|
@@ -121,15 +139,22 @@ class NLUCommandAdapter(GraphComponent, CommandGenerator):
|
|
|
121
139
|
|
|
122
140
|
@staticmethod
|
|
123
141
|
def convert_nlu_to_commands(
|
|
124
|
-
message: Message,
|
|
142
|
+
message: Message,
|
|
143
|
+
tracker: DialogueStateTracker,
|
|
144
|
+
flows: FlowsList,
|
|
145
|
+
domain: Optional[Domain] = None,
|
|
125
146
|
) -> List[Command]:
|
|
126
147
|
"""Converts the predicted intent to a command."""
|
|
127
148
|
if tracker is None or flows.is_empty():
|
|
128
149
|
# cannot do anything if there are no flows or no tracker
|
|
129
150
|
return []
|
|
130
151
|
|
|
131
|
-
if not
|
|
132
|
-
|
|
152
|
+
if not (
|
|
153
|
+
message.get(INTENT)
|
|
154
|
+
or message.get(INTENT, {}).get("name")
|
|
155
|
+
or message.get(ENTITIES)
|
|
156
|
+
):
|
|
157
|
+
# if the message does not have an intent or entities set
|
|
133
158
|
# no commands can be predicted
|
|
134
159
|
return []
|
|
135
160
|
|
|
@@ -139,8 +164,6 @@ class NLUCommandAdapter(GraphComponent, CommandGenerator):
|
|
|
139
164
|
if flow.nlu_triggers and flow.nlu_triggers.is_triggered(message):
|
|
140
165
|
commands.append(StartFlowCommand(flow.id))
|
|
141
166
|
|
|
142
|
-
structlogger.info("nlu_command_adapter.predict_commands", commands=commands)
|
|
143
|
-
|
|
144
167
|
# there should be just one flow that can be triggered by the predicted intent
|
|
145
168
|
# this is checked when loading the flows
|
|
146
169
|
# however we just doublecheck here and return the first command if there are
|
|
@@ -154,4 +177,42 @@ class NLUCommandAdapter(GraphComponent, CommandGenerator):
|
|
|
154
177
|
)
|
|
155
178
|
commands = [commands[0]]
|
|
156
179
|
|
|
180
|
+
set_slot_commands = _issue_set_slot_commands(message, tracker, flows, domain)
|
|
181
|
+
commands.extend(set_slot_commands)
|
|
182
|
+
|
|
183
|
+
structlogger.info("nlu_command_adapter.predict_commands", commands=commands)
|
|
184
|
+
|
|
157
185
|
return commands
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _issue_set_slot_commands(
|
|
189
|
+
message: Message,
|
|
190
|
+
tracker: DialogueStateTracker,
|
|
191
|
+
flows: FlowsList,
|
|
192
|
+
domain: Optional[Domain] = None,
|
|
193
|
+
) -> List[Command]:
|
|
194
|
+
"""Issue SetSlotCommand for each slot that can be filled with NLU properties."""
|
|
195
|
+
commands: List[Command] = []
|
|
196
|
+
domain = domain if domain else Domain.empty()
|
|
197
|
+
slot_filling_manager = SlotFillingManager(domain, tracker, message)
|
|
198
|
+
available_slot_names = flows.available_slot_names()
|
|
199
|
+
|
|
200
|
+
for _, slot in tracker.slots.items():
|
|
201
|
+
# if a slot is not collected in available flows,
|
|
202
|
+
# it means that it is not a slot that can be filled by CALM,
|
|
203
|
+
# so we skip it
|
|
204
|
+
if slot.name not in available_slot_names:
|
|
205
|
+
structlogger.debug("nlu_command_adapter.skip_slot", slot=slot.name)
|
|
206
|
+
continue
|
|
207
|
+
|
|
208
|
+
slot_value, is_extracted = extract_slot_value(slot, slot_filling_manager)
|
|
209
|
+
if is_extracted:
|
|
210
|
+
commands.append(
|
|
211
|
+
SetSlotCommand(
|
|
212
|
+
name=slot.name,
|
|
213
|
+
value=slot_value,
|
|
214
|
+
extractor=SetSlotExtractor.NLU.value,
|
|
215
|
+
)
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
return commands
|
|
File without changes
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import importlib.resources
|
|
2
|
+
import re
|
|
3
|
+
import structlog
|
|
4
|
+
from typing import Dict, Any, List, Optional, Text
|
|
5
|
+
|
|
6
|
+
import rasa.shared.utils.io
|
|
7
|
+
from rasa.dialogue_understanding.commands import (
|
|
8
|
+
Command,
|
|
9
|
+
ErrorCommand,
|
|
10
|
+
SetSlotCommand,
|
|
11
|
+
CancelFlowCommand,
|
|
12
|
+
HumanHandoffCommand,
|
|
13
|
+
ChitChatAnswerCommand,
|
|
14
|
+
SkipQuestionCommand,
|
|
15
|
+
KnowledgeAnswerCommand,
|
|
16
|
+
ClarifyCommand,
|
|
17
|
+
CannotHandleCommand,
|
|
18
|
+
)
|
|
19
|
+
from rasa.dialogue_understanding.generator.llm_based_command_generator import (
|
|
20
|
+
LLMBasedCommandGenerator,
|
|
21
|
+
)
|
|
22
|
+
from rasa.dialogue_understanding.generator.constants import (
|
|
23
|
+
LLM_CONFIG_KEY,
|
|
24
|
+
USER_INPUT_CONFIG_KEY,
|
|
25
|
+
FLOW_RETRIEVAL_KEY,
|
|
26
|
+
)
|
|
27
|
+
from rasa.dialogue_understanding.generator.flow_retrieval import (
|
|
28
|
+
FlowRetrieval,
|
|
29
|
+
)
|
|
30
|
+
from rasa.dialogue_understanding.stack.utils import top_flow_frame
|
|
31
|
+
from rasa.engine.graph import ExecutionContext
|
|
32
|
+
from rasa.engine.recipes.default_recipe import DefaultV1Recipe
|
|
33
|
+
from rasa.engine.storage.resource import Resource
|
|
34
|
+
from rasa.engine.storage.storage import ModelStorage
|
|
35
|
+
from rasa.shared.constants import ROUTE_TO_CALM_SLOT
|
|
36
|
+
from rasa.shared.core.flows import FlowsList
|
|
37
|
+
from rasa.shared.core.trackers import DialogueStateTracker
|
|
38
|
+
from rasa.shared.nlu.constants import TEXT
|
|
39
|
+
from rasa.shared.nlu.training_data.message import Message
|
|
40
|
+
from rasa.shared.exceptions import ProviderClientAPIException
|
|
41
|
+
from rasa.shared.utils.io import deep_container_fingerprint
|
|
42
|
+
from rasa.shared.utils.llm import (
|
|
43
|
+
get_prompt_template,
|
|
44
|
+
tracker_as_readable_transcript,
|
|
45
|
+
sanitize_message_for_prompt,
|
|
46
|
+
)
|
|
47
|
+
from rasa.utils.log_utils import log_llm
|
|
48
|
+
|
|
49
|
+
COMMAND_PROMPT_FILE_NAME = "command_prompt.jinja2"
|
|
50
|
+
|
|
51
|
+
DEFAULT_COMMAND_PROMPT_TEMPLATE = importlib.resources.read_text(
|
|
52
|
+
"rasa.dialogue_understanding.generator.single_step",
|
|
53
|
+
"command_prompt_template.jinja2",
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
structlogger = structlog.get_logger()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@DefaultV1Recipe.register(
|
|
60
|
+
[
|
|
61
|
+
DefaultV1Recipe.ComponentType.COMMAND_GENERATOR,
|
|
62
|
+
],
|
|
63
|
+
is_trainable=True,
|
|
64
|
+
)
|
|
65
|
+
class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
66
|
+
"""A single step LLM-based command generator."""
|
|
67
|
+
|
|
68
|
+
def __init__(
|
|
69
|
+
self,
|
|
70
|
+
config: Dict[str, Any],
|
|
71
|
+
model_storage: ModelStorage,
|
|
72
|
+
resource: Resource,
|
|
73
|
+
prompt_template: Optional[Text] = None,
|
|
74
|
+
**kwargs: Any,
|
|
75
|
+
) -> None:
|
|
76
|
+
super().__init__(
|
|
77
|
+
config,
|
|
78
|
+
model_storage,
|
|
79
|
+
resource,
|
|
80
|
+
prompt_template=prompt_template,
|
|
81
|
+
**kwargs,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# Set the prompt template
|
|
85
|
+
if config.get("prompt"):
|
|
86
|
+
structlogger.warning(
|
|
87
|
+
"single_step_llm_command_generator.init",
|
|
88
|
+
event_info=(
|
|
89
|
+
"The config parameter 'prompt' is deprecated "
|
|
90
|
+
"and will be removed in Rasa 4.0.0. "
|
|
91
|
+
"Please use the config parameter 'prompt_template' instead. "
|
|
92
|
+
),
|
|
93
|
+
)
|
|
94
|
+
config_prompt = config.get("prompt") or config.get("prompt_template") or None
|
|
95
|
+
self.prompt_template = prompt_template or get_prompt_template(
|
|
96
|
+
config_prompt,
|
|
97
|
+
DEFAULT_COMMAND_PROMPT_TEMPLATE,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
self.trace_prompt_tokens = self.config.get("trace_prompt_tokens", False)
|
|
101
|
+
|
|
102
|
+
### Implementations of LLMBasedCommandGenerator parent
|
|
103
|
+
@staticmethod
|
|
104
|
+
def get_default_config() -> Dict[str, Any]:
|
|
105
|
+
"""The component's default config (see parent class for full docstring)."""
|
|
106
|
+
return {
|
|
107
|
+
"prompt": None, # Legacy
|
|
108
|
+
"prompt_template": None,
|
|
109
|
+
USER_INPUT_CONFIG_KEY: None,
|
|
110
|
+
LLM_CONFIG_KEY: None,
|
|
111
|
+
FLOW_RETRIEVAL_KEY: FlowRetrieval.get_default_config(),
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@classmethod
|
|
115
|
+
def load(
|
|
116
|
+
cls: Any,
|
|
117
|
+
config: Dict[str, Any],
|
|
118
|
+
model_storage: ModelStorage,
|
|
119
|
+
resource: Resource,
|
|
120
|
+
execution_context: ExecutionContext,
|
|
121
|
+
**kwargs: Any,
|
|
122
|
+
) -> "SingleStepLLMCommandGenerator":
|
|
123
|
+
"""Loads trained component (see parent class for full docstring)."""
|
|
124
|
+
# load prompt template from the model storage.
|
|
125
|
+
prompt_template = cls.load_prompt_template_from_model_storage(
|
|
126
|
+
model_storage, resource, COMMAND_PROMPT_FILE_NAME
|
|
127
|
+
)
|
|
128
|
+
# init base command generator
|
|
129
|
+
command_generator = cls(config, model_storage, resource, prompt_template)
|
|
130
|
+
# load flow retrieval if enabled
|
|
131
|
+
if command_generator.enabled_flow_retrieval:
|
|
132
|
+
command_generator.flow_retrieval = cls.load_flow_retrival(
|
|
133
|
+
command_generator.config, model_storage, resource
|
|
134
|
+
)
|
|
135
|
+
return command_generator
|
|
136
|
+
|
|
137
|
+
def persist(self) -> None:
|
|
138
|
+
"""Persist this component to disk for future loading."""
|
|
139
|
+
# persist prompt template
|
|
140
|
+
with self._model_storage.write_to(self._resource) as path:
|
|
141
|
+
rasa.shared.utils.io.write_text_file(
|
|
142
|
+
self.prompt_template, path / COMMAND_PROMPT_FILE_NAME
|
|
143
|
+
)
|
|
144
|
+
# persist flow retrieval
|
|
145
|
+
if self.flow_retrieval is not None:
|
|
146
|
+
self.flow_retrieval.persist()
|
|
147
|
+
|
|
148
|
+
async def predict_commands(
|
|
149
|
+
self,
|
|
150
|
+
message: Message,
|
|
151
|
+
flows: FlowsList,
|
|
152
|
+
tracker: Optional[DialogueStateTracker] = None,
|
|
153
|
+
**kwargs: Any,
|
|
154
|
+
) -> List[Command]:
|
|
155
|
+
"""Predict commands using the LLM.
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
message: The message from the user.
|
|
159
|
+
flows: The flows available to the user.
|
|
160
|
+
tracker: The tracker containing the current state of the conversation.
|
|
161
|
+
**kwargs: Keyword arguments for forward compatibility.
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
The commands generated by the llm.
|
|
165
|
+
"""
|
|
166
|
+
if tracker is None or flows.is_empty():
|
|
167
|
+
# cannot do anything if there are no flows or no tracker
|
|
168
|
+
return []
|
|
169
|
+
|
|
170
|
+
# retrieve flows
|
|
171
|
+
try:
|
|
172
|
+
filtered_flows = await self.filter_flows(message, flows, tracker)
|
|
173
|
+
except ProviderClientAPIException:
|
|
174
|
+
return [ErrorCommand()]
|
|
175
|
+
|
|
176
|
+
flow_prompt = self.render_template(message, tracker, filtered_flows, flows)
|
|
177
|
+
log_llm(
|
|
178
|
+
logger=structlogger,
|
|
179
|
+
log_module="SingleStepLLMCommandGenerator",
|
|
180
|
+
log_event="llm_command_generator.predict_commands.prompt_rendered",
|
|
181
|
+
prompt=flow_prompt,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
try:
|
|
185
|
+
action_list = await self.invoke_llm(flow_prompt)
|
|
186
|
+
# The check for 'None' maintains compatibility with older versions
|
|
187
|
+
# of LLMCommandGenerator. In previous implementations, 'invoke_llm'
|
|
188
|
+
# might return 'None' to indicate a failure to generate actions.
|
|
189
|
+
if action_list is None:
|
|
190
|
+
return [ErrorCommand()]
|
|
191
|
+
except ProviderClientAPIException:
|
|
192
|
+
return [ErrorCommand()]
|
|
193
|
+
|
|
194
|
+
log_llm(
|
|
195
|
+
logger=structlogger,
|
|
196
|
+
log_module="SingleStepLLMCommandGenerator",
|
|
197
|
+
log_event="llm_command_generator.predict_commands.actions_generated",
|
|
198
|
+
action_list=action_list,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
commands = self.parse_commands(action_list, tracker, flows)
|
|
202
|
+
|
|
203
|
+
if not commands:
|
|
204
|
+
# no commands are parsed or there's an invalid command
|
|
205
|
+
commands = [CannotHandleCommand()]
|
|
206
|
+
else:
|
|
207
|
+
# if the LLM command generator predicted valid commands and the
|
|
208
|
+
# coexistence feature is used, set the routing slot
|
|
209
|
+
if tracker.has_coexistence_routing_slot:
|
|
210
|
+
commands += [SetSlotCommand(ROUTE_TO_CALM_SLOT, True)]
|
|
211
|
+
|
|
212
|
+
log_llm(
|
|
213
|
+
logger=structlogger,
|
|
214
|
+
log_module="SingleStepLLMCommandGenerator",
|
|
215
|
+
log_event="llm_command_generator.predict_commands.finished",
|
|
216
|
+
commands=commands,
|
|
217
|
+
)
|
|
218
|
+
return commands
|
|
219
|
+
|
|
220
|
+
@classmethod
|
|
221
|
+
def parse_commands(
|
|
222
|
+
cls, actions: Optional[str], tracker: DialogueStateTracker, flows: FlowsList
|
|
223
|
+
) -> List[Command]:
|
|
224
|
+
"""Parse the actions returned by the llm into intent and entities.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
actions: The actions returned by the llm.
|
|
228
|
+
tracker: The tracker containing the current state of the conversation.
|
|
229
|
+
flows: the list of flows
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
The parsed commands.
|
|
233
|
+
"""
|
|
234
|
+
if actions is None:
|
|
235
|
+
return []
|
|
236
|
+
|
|
237
|
+
commands: List[Command] = []
|
|
238
|
+
|
|
239
|
+
slot_set_re = re.compile(r"""SetSlot\(([a-zA-Z_][a-zA-Z0-9_-]*?), ?(.*)\)""")
|
|
240
|
+
start_flow_re = re.compile(r"StartFlow\(([a-zA-Z0-9_-]+?)\)")
|
|
241
|
+
cancel_flow_re = re.compile(r"CancelFlow\(\)")
|
|
242
|
+
chitchat_re = re.compile(r"ChitChat\(\)")
|
|
243
|
+
skip_question_re = re.compile(r"SkipQuestion\(\)")
|
|
244
|
+
knowledge_re = re.compile(r"SearchAndReply\(\)")
|
|
245
|
+
humand_handoff_re = re.compile(r"HumanHandoff\(\)")
|
|
246
|
+
clarify_re = re.compile(r"Clarify\(([a-zA-Z0-9_, ]+)\)")
|
|
247
|
+
|
|
248
|
+
for action in actions.strip().splitlines():
|
|
249
|
+
if match := slot_set_re.search(action):
|
|
250
|
+
slot_name = match.group(1).strip()
|
|
251
|
+
slot_value = cls.clean_extracted_value(match.group(2))
|
|
252
|
+
# error case where the llm tries to start a flow using a slot set
|
|
253
|
+
if slot_name == "flow_name":
|
|
254
|
+
commands.extend(cls.start_flow_by_name(slot_value, flows))
|
|
255
|
+
else:
|
|
256
|
+
typed_slot_value = cls.get_nullable_slot_value(slot_value)
|
|
257
|
+
commands.append(
|
|
258
|
+
SetSlotCommand(name=slot_name, value=typed_slot_value)
|
|
259
|
+
)
|
|
260
|
+
elif match := start_flow_re.search(action):
|
|
261
|
+
flow_name = match.group(1).strip()
|
|
262
|
+
commands.extend(cls.start_flow_by_name(flow_name, flows))
|
|
263
|
+
elif cancel_flow_re.search(action):
|
|
264
|
+
commands.append(CancelFlowCommand())
|
|
265
|
+
elif chitchat_re.search(action):
|
|
266
|
+
commands.append(ChitChatAnswerCommand())
|
|
267
|
+
elif skip_question_re.search(action):
|
|
268
|
+
commands.append(SkipQuestionCommand())
|
|
269
|
+
elif knowledge_re.search(action):
|
|
270
|
+
commands.append(KnowledgeAnswerCommand())
|
|
271
|
+
elif humand_handoff_re.search(action):
|
|
272
|
+
commands.append(HumanHandoffCommand())
|
|
273
|
+
elif match := clarify_re.search(action):
|
|
274
|
+
options = sorted([opt.strip() for opt in match.group(1).split(",")])
|
|
275
|
+
valid_options = [
|
|
276
|
+
flow for flow in options if flow in flows.user_flow_ids
|
|
277
|
+
]
|
|
278
|
+
if len(set(valid_options)) == 1:
|
|
279
|
+
commands.extend(cls.start_flow_by_name(valid_options[0], flows))
|
|
280
|
+
elif len(valid_options) > 1:
|
|
281
|
+
commands.append(ClarifyCommand(valid_options))
|
|
282
|
+
|
|
283
|
+
return commands
|
|
284
|
+
|
|
285
|
+
@classmethod
|
|
286
|
+
def fingerprint_addon(cls: Any, config: Dict[str, Any]) -> Optional[str]:
|
|
287
|
+
"""Add a fingerprint of the knowledge base for the graph."""
|
|
288
|
+
config_prompt = config.get("prompt") or config.get("prompt_template") or None
|
|
289
|
+
prompt_template = get_prompt_template(
|
|
290
|
+
config_prompt,
|
|
291
|
+
DEFAULT_COMMAND_PROMPT_TEMPLATE,
|
|
292
|
+
)
|
|
293
|
+
return deep_container_fingerprint(prompt_template)
|
|
294
|
+
|
|
295
|
+
### Helper methods
|
|
296
|
+
def render_template(
|
|
297
|
+
self,
|
|
298
|
+
message: Message,
|
|
299
|
+
tracker: DialogueStateTracker,
|
|
300
|
+
startable_flows: FlowsList,
|
|
301
|
+
all_flows: FlowsList,
|
|
302
|
+
) -> str:
|
|
303
|
+
"""Render the jinja template to create the prompt for the LLM.
|
|
304
|
+
|
|
305
|
+
Args:
|
|
306
|
+
message: The current message from the user.
|
|
307
|
+
tracker: The tracker containing the current state of the conversation.
|
|
308
|
+
startable_flows: The flows startable at this point in time by the user.
|
|
309
|
+
all_flows: all flows present in the assistant
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
The rendered prompt template.
|
|
313
|
+
"""
|
|
314
|
+
# need to make this distinction here because current step of the
|
|
315
|
+
# top_calling_frame would be the call step, but we need the collect step from
|
|
316
|
+
# the called frame. If no call is active calling and called frame are the same.
|
|
317
|
+
top_calling_frame = top_flow_frame(tracker.stack)
|
|
318
|
+
top_called_frame = top_flow_frame(tracker.stack, ignore_call_frames=False)
|
|
319
|
+
|
|
320
|
+
top_flow = top_calling_frame.flow(all_flows) if top_calling_frame else None
|
|
321
|
+
current_step = top_called_frame.step(all_flows) if top_called_frame else None
|
|
322
|
+
|
|
323
|
+
flow_slots = self.prepare_current_flow_slots_for_template(
|
|
324
|
+
top_flow, current_step, tracker
|
|
325
|
+
)
|
|
326
|
+
current_slot, current_slot_description = self.prepare_current_slot_for_template(
|
|
327
|
+
current_step
|
|
328
|
+
)
|
|
329
|
+
current_conversation = tracker_as_readable_transcript(tracker)
|
|
330
|
+
latest_user_message = sanitize_message_for_prompt(message.get(TEXT))
|
|
331
|
+
current_conversation += f"\nUSER: {latest_user_message}"
|
|
332
|
+
|
|
333
|
+
inputs = {
|
|
334
|
+
"available_flows": self.prepare_flows_for_template(
|
|
335
|
+
startable_flows, tracker
|
|
336
|
+
),
|
|
337
|
+
"current_conversation": current_conversation,
|
|
338
|
+
"flow_slots": flow_slots,
|
|
339
|
+
"current_flow": top_flow.id if top_flow is not None else None,
|
|
340
|
+
"current_slot": current_slot,
|
|
341
|
+
"current_slot_description": current_slot_description,
|
|
342
|
+
"user_message": latest_user_message,
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return self.compile_template(self.prompt_template).render(**inputs)
|