rasa-pro 3.10.16__py3-none-any.whl → 3.11.0__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 +31 -15
- rasa/api.py +12 -2
- rasa/cli/arguments/default_arguments.py +24 -4
- rasa/cli/arguments/run.py +15 -0
- rasa/cli/arguments/shell.py +5 -1
- rasa/cli/arguments/train.py +17 -9
- rasa/cli/evaluate.py +7 -7
- rasa/cli/inspect.py +19 -7
- rasa/cli/interactive.py +1 -0
- rasa/cli/llm_fine_tuning.py +11 -14
- rasa/cli/project_templates/calm/config.yml +5 -7
- rasa/cli/project_templates/calm/endpoints.yml +15 -2
- rasa/cli/project_templates/tutorial/config.yml +8 -5
- rasa/cli/project_templates/tutorial/data/flows.yml +1 -1
- rasa/cli/project_templates/tutorial/data/patterns.yml +5 -0
- rasa/cli/project_templates/tutorial/domain.yml +14 -0
- rasa/cli/project_templates/tutorial/endpoints.yml +5 -0
- rasa/cli/run.py +7 -0
- rasa/cli/scaffold.py +4 -2
- rasa/cli/studio/upload.py +0 -15
- rasa/cli/train.py +14 -53
- rasa/cli/utils.py +14 -11
- rasa/cli/x.py +7 -7
- rasa/constants.py +3 -1
- rasa/core/actions/action.py +77 -33
- rasa/core/actions/action_hangup.py +29 -0
- rasa/core/actions/action_repeat_bot_messages.py +89 -0
- rasa/core/actions/e2e_stub_custom_action_executor.py +5 -1
- rasa/core/actions/http_custom_action_executor.py +4 -0
- rasa/core/agent.py +2 -2
- rasa/core/brokers/kafka.py +3 -1
- rasa/core/brokers/pika.py +3 -1
- rasa/core/channels/__init__.py +10 -6
- rasa/core/channels/channel.py +41 -4
- rasa/core/channels/development_inspector.py +150 -46
- rasa/core/channels/inspector/README.md +1 -1
- rasa/core/channels/inspector/dist/assets/{arc-b6e548fe.js → arc-bc141fb2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-d0fbc5ce-fa03ac9e.js → c4Diagram-d0fbc5ce-be2db283.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-936ed81e-ee67392a.js → classDiagram-936ed81e-55366915.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-c3cb15f1-9b283fae.js → classDiagram-v2-c3cb15f1-bb529518.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{createText-62fc7601-8b6fcc2a.js → createText-62fc7601-b0ec81d6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-f2ad444c-22e77f4f.js → edges-f2ad444c-6166330c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-60ffc87f.js → erDiagram-9d236eb7-5ccc6a8e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-1972c806-9dd802e4.js → flowDb-1972c806-fca3bfe4.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-7ea5b25a-5fa1912f.js → flowDiagram-7ea5b25a-4739080f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-736177bf.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-abe16c3d-622a1fd2.js → flowchart-elk-definition-abe16c3d-7c1b0e0f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-9b5ea136-e285a63a.js → ganttDiagram-9b5ea136-772fd050.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-99d0ae7c-f237bdca.js → gitGraphDiagram-99d0ae7c-8eae1dc9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-2c4b9a3b-4b03d70e.js → index-2c4b9a3b-f55afcdf.js} +1 -1
- rasa/core/channels/inspector/dist/assets/index-e7cef9de.js +1317 -0
- rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-72a0fa5f.js → infoDiagram-736b4530-124d4a14.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-82218c41.js → journeyDiagram-df861f2b-7c4fae44.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-78cff630.js → layout-b9885fb6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-5038b469.js → line-7c59abb6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-c4fc4098.js → linear-4776f780.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-beec6740-c33c8ea6.js → mindmap-definition-beec6740-2332c46c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-a8d03059.js → pieDiagram-dbbf0591-8fb39303.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-6a0e56b2.js → quadrantDiagram-4d7f4fd6-3c7180a2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-2dc7c7bd.js → requirementDiagram-6fc4c22a-e910bcb8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-8f13d901-2360fe39.js → sankeyDiagram-8f13d901-ead16c89.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-b655622a-41b9f9ad.js → sequenceDiagram-b655622a-29a02a19.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-59f0c015-0aad326f.js → stateDiagram-59f0c015-042b3137.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-2b26beab-9847d984.js → stateDiagram-v2-2b26beab-2178c0f3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-080da4f6-564d890e.js → styles-080da4f6-23ffa4fc.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-3dcbcfbf-38957613.js → styles-3dcbcfbf-94f59763.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9c745c82-f0fc6921.js → styles-9c745c82-78a6bebc.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-4835440b-ef3c5a77.js → svgDrawCommon-4835440b-eae2a6f6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-bf3e91c1.js → timeline-definition-5b62e21b-5c968d92.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-4d4026c0.js → xychartDiagram-2b33534f-fd3db0d5.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +18 -17
- rasa/core/channels/inspector/index.html +17 -16
- rasa/core/channels/inspector/package.json +5 -1
- rasa/core/channels/inspector/src/App.tsx +118 -68
- rasa/core/channels/inspector/src/components/Chat.tsx +95 -0
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +11 -10
- rasa/core/channels/inspector/src/components/DialogueStack.tsx +10 -25
- rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +6 -3
- rasa/core/channels/inspector/src/helpers/audiostream.ts +165 -0
- rasa/core/channels/inspector/src/helpers/formatters.test.ts +10 -0
- rasa/core/channels/inspector/src/helpers/formatters.ts +107 -41
- rasa/core/channels/inspector/src/helpers/utils.ts +92 -7
- rasa/core/channels/inspector/src/types.ts +21 -1
- rasa/core/channels/inspector/yarn.lock +94 -1
- rasa/core/channels/rest.py +51 -46
- rasa/core/channels/socketio.py +28 -1
- rasa/core/channels/telegram.py +1 -1
- rasa/core/channels/twilio.py +1 -1
- rasa/core/channels/{audiocodes.py → voice_ready/audiocodes.py} +122 -69
- rasa/core/channels/{voice_aware → voice_ready}/jambonz.py +26 -8
- rasa/core/channels/{voice_aware → voice_ready}/jambonz_protocol.py +57 -5
- rasa/core/channels/{twilio_voice.py → voice_ready/twilio_voice.py} +64 -28
- rasa/core/channels/voice_ready/utils.py +37 -0
- rasa/core/channels/voice_stream/asr/__init__.py +0 -0
- rasa/core/channels/voice_stream/asr/asr_engine.py +89 -0
- rasa/core/channels/voice_stream/asr/asr_event.py +18 -0
- rasa/core/channels/voice_stream/asr/azure.py +129 -0
- rasa/core/channels/voice_stream/asr/deepgram.py +90 -0
- rasa/core/channels/voice_stream/audio_bytes.py +8 -0
- rasa/core/channels/voice_stream/browser_audio.py +107 -0
- rasa/core/channels/voice_stream/call_state.py +23 -0
- rasa/core/channels/voice_stream/tts/__init__.py +0 -0
- rasa/core/channels/voice_stream/tts/azure.py +106 -0
- rasa/core/channels/voice_stream/tts/cartesia.py +118 -0
- rasa/core/channels/voice_stream/tts/tts_cache.py +27 -0
- rasa/core/channels/voice_stream/tts/tts_engine.py +58 -0
- rasa/core/channels/voice_stream/twilio_media_streams.py +173 -0
- rasa/core/channels/voice_stream/util.py +57 -0
- rasa/core/channels/voice_stream/voice_channel.py +427 -0
- rasa/core/information_retrieval/qdrant.py +1 -0
- rasa/core/nlg/contextual_response_rephraser.py +45 -17
- rasa/{nlu → core}/persistor.py +203 -68
- rasa/core/policies/enterprise_search_policy.py +119 -63
- rasa/core/policies/flows/flow_executor.py +15 -22
- rasa/core/policies/intentless_policy.py +83 -28
- rasa/core/processor.py +25 -0
- rasa/core/run.py +12 -2
- rasa/core/secrets_manager/constants.py +4 -0
- rasa/core/secrets_manager/factory.py +8 -0
- rasa/core/secrets_manager/vault.py +11 -1
- rasa/core/training/interactive.py +33 -34
- rasa/core/utils.py +47 -21
- rasa/dialogue_understanding/coexistence/llm_based_router.py +41 -14
- rasa/dialogue_understanding/commands/__init__.py +6 -0
- rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +60 -0
- rasa/dialogue_understanding/commands/session_end_command.py +61 -0
- rasa/dialogue_understanding/commands/user_silence_command.py +59 -0
- rasa/dialogue_understanding/commands/utils.py +5 -0
- rasa/dialogue_understanding/generator/constants.py +2 -0
- rasa/dialogue_understanding/generator/flow_retrieval.py +47 -9
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +38 -15
- rasa/dialogue_understanding/generator/llm_command_generator.py +1 -1
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +35 -13
- rasa/dialogue_understanding/generator/single_step/command_prompt_template.jinja2 +3 -0
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +60 -13
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +53 -0
- rasa/dialogue_understanding/patterns/repeat.py +37 -0
- rasa/dialogue_understanding/patterns/user_silence.py +37 -0
- rasa/dialogue_understanding/processor/command_processor.py +21 -1
- rasa/e2e_test/aggregate_test_stats_calculator.py +1 -11
- rasa/e2e_test/assertions.py +136 -61
- rasa/e2e_test/assertions_schema.yml +23 -0
- rasa/e2e_test/e2e_test_case.py +85 -6
- rasa/e2e_test/e2e_test_runner.py +2 -3
- rasa/e2e_test/utils/e2e_yaml_utils.py +1 -1
- rasa/engine/graph.py +3 -10
- rasa/engine/loader.py +12 -0
- rasa/engine/recipes/config_files/default_config.yml +0 -3
- rasa/engine/recipes/default_recipe.py +0 -1
- rasa/engine/recipes/graph_recipe.py +0 -1
- rasa/engine/runner/dask.py +2 -2
- rasa/engine/storage/local_model_storage.py +12 -42
- rasa/engine/storage/storage.py +1 -5
- rasa/engine/validation.py +527 -74
- rasa/model_manager/__init__.py +0 -0
- rasa/model_manager/config.py +40 -0
- rasa/model_manager/model_api.py +559 -0
- rasa/model_manager/runner_service.py +286 -0
- rasa/model_manager/socket_bridge.py +146 -0
- rasa/model_manager/studio_jwt_auth.py +86 -0
- rasa/model_manager/trainer_service.py +325 -0
- rasa/model_manager/utils.py +87 -0
- rasa/model_manager/warm_rasa_process.py +187 -0
- rasa/model_service.py +112 -0
- rasa/model_training.py +42 -23
- rasa/nlu/tokenizers/whitespace_tokenizer.py +3 -14
- rasa/server.py +4 -2
- rasa/shared/constants.py +60 -8
- rasa/shared/core/constants.py +13 -0
- rasa/shared/core/domain.py +107 -50
- rasa/shared/core/events.py +29 -0
- rasa/shared/core/flows/flow.py +5 -0
- rasa/shared/core/flows/flows_list.py +19 -6
- rasa/shared/core/flows/flows_yaml_schema.json +10 -0
- rasa/shared/core/flows/utils.py +39 -0
- rasa/shared/core/flows/validation.py +121 -0
- rasa/shared/core/flows/yaml_flows_io.py +15 -27
- rasa/shared/core/slots.py +5 -0
- rasa/shared/importers/importer.py +59 -41
- rasa/shared/importers/multi_project.py +23 -11
- rasa/shared/importers/rasa.py +12 -3
- rasa/shared/importers/remote_importer.py +196 -0
- rasa/shared/importers/utils.py +3 -1
- rasa/shared/nlu/training_data/formats/rasa_yaml.py +18 -3
- rasa/shared/nlu/training_data/training_data.py +18 -19
- rasa/shared/providers/_configs/litellm_router_client_config.py +220 -0
- rasa/shared/providers/_configs/model_group_config.py +167 -0
- rasa/shared/providers/_configs/openai_client_config.py +1 -1
- rasa/shared/providers/_configs/rasa_llm_client_config.py +73 -0
- rasa/shared/providers/_configs/self_hosted_llm_client_config.py +1 -0
- rasa/shared/providers/_configs/utils.py +16 -0
- rasa/shared/providers/_utils.py +79 -0
- rasa/shared/providers/embedding/_base_litellm_embedding_client.py +13 -29
- rasa/shared/providers/embedding/azure_openai_embedding_client.py +54 -21
- rasa/shared/providers/embedding/default_litellm_embedding_client.py +24 -0
- rasa/shared/providers/embedding/litellm_router_embedding_client.py +135 -0
- rasa/shared/providers/llm/_base_litellm_client.py +34 -22
- rasa/shared/providers/llm/azure_openai_llm_client.py +50 -29
- rasa/shared/providers/llm/default_litellm_llm_client.py +24 -0
- rasa/shared/providers/llm/litellm_router_llm_client.py +182 -0
- rasa/shared/providers/llm/rasa_llm_client.py +112 -0
- rasa/shared/providers/llm/self_hosted_llm_client.py +5 -29
- rasa/shared/providers/mappings.py +19 -0
- rasa/shared/providers/router/__init__.py +0 -0
- rasa/shared/providers/router/_base_litellm_router_client.py +183 -0
- rasa/shared/providers/router/router_client.py +73 -0
- rasa/shared/utils/common.py +40 -24
- rasa/shared/utils/health_check/__init__.py +0 -0
- rasa/shared/utils/health_check/embeddings_health_check_mixin.py +31 -0
- rasa/shared/utils/health_check/health_check.py +258 -0
- rasa/shared/utils/health_check/llm_health_check_mixin.py +31 -0
- rasa/shared/utils/io.py +27 -6
- rasa/shared/utils/llm.py +354 -44
- rasa/shared/utils/schemas/events.py +2 -0
- rasa/shared/utils/schemas/model_config.yml +0 -10
- rasa/shared/utils/yaml.py +181 -38
- rasa/studio/data_handler.py +3 -1
- rasa/studio/upload.py +160 -74
- rasa/telemetry.py +94 -17
- rasa/tracing/config.py +3 -1
- rasa/tracing/instrumentation/attribute_extractors.py +95 -18
- rasa/tracing/instrumentation/instrumentation.py +121 -0
- rasa/utils/common.py +5 -0
- rasa/utils/endpoints.py +27 -1
- rasa/utils/io.py +8 -16
- rasa/utils/log_utils.py +9 -2
- rasa/utils/sanic_error_handler.py +32 -0
- rasa/validator.py +110 -16
- rasa/version.py +1 -1
- {rasa_pro-3.10.16.dist-info → rasa_pro-3.11.0.dist-info}/METADATA +16 -14
- {rasa_pro-3.10.16.dist-info → rasa_pro-3.11.0.dist-info}/RECORD +236 -185
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-1844e5a5.js +0 -1
- rasa/core/channels/inspector/dist/assets/index-a5d3e69d.js +0 -1040
- rasa/core/channels/voice_aware/utils.py +0 -20
- rasa/llm_fine_tuning/notebooks/unsloth_finetuning.ipynb +0 -407
- /rasa/core/channels/{voice_aware → voice_ready}/__init__.py +0 -0
- /rasa/core/channels/{voice_native → voice_stream}/__init__.py +0 -0
- {rasa_pro-3.10.16.dist-info → rasa_pro-3.11.0.dist-info}/NOTICE +0 -0
- {rasa_pro-3.10.16.dist-info → rasa_pro-3.11.0.dist-info}/WHEEL +0 -0
- {rasa_pro-3.10.16.dist-info → rasa_pro-3.11.0.dist-info}/entry_points.txt +0 -0
|
@@ -16,6 +16,7 @@ from rasa.dialogue_understanding.generator.constants import (
|
|
|
16
16
|
LLM_CONFIG_KEY,
|
|
17
17
|
FLOW_RETRIEVAL_KEY,
|
|
18
18
|
FLOW_RETRIEVAL_ACTIVE_KEY,
|
|
19
|
+
FLOW_RETRIEVAL_FLOW_THRESHOLD,
|
|
19
20
|
)
|
|
20
21
|
from rasa.dialogue_understanding.generator.flow_retrieval import FlowRetrieval
|
|
21
22
|
from rasa.engine.graph import GraphComponent, ExecutionContext
|
|
@@ -31,10 +32,11 @@ from rasa.shared.exceptions import ProviderClientAPIException
|
|
|
31
32
|
from rasa.shared.nlu.constants import FLOWS_IN_PROMPT
|
|
32
33
|
from rasa.shared.nlu.training_data.message import Message
|
|
33
34
|
from rasa.shared.nlu.training_data.training_data import TrainingData
|
|
35
|
+
from rasa.shared.utils.health_check.llm_health_check_mixin import LLMHealthCheckMixin
|
|
34
36
|
from rasa.shared.utils.llm import (
|
|
35
37
|
allowed_values_for_slot,
|
|
36
38
|
llm_factory,
|
|
37
|
-
|
|
39
|
+
resolve_model_client_config,
|
|
38
40
|
)
|
|
39
41
|
from rasa.utils.log_utils import log_llm
|
|
40
42
|
|
|
@@ -47,7 +49,9 @@ structlogger = structlog.get_logger()
|
|
|
47
49
|
],
|
|
48
50
|
is_trainable=True,
|
|
49
51
|
)
|
|
50
|
-
class LLMBasedCommandGenerator(
|
|
52
|
+
class LLMBasedCommandGenerator(
|
|
53
|
+
LLMHealthCheckMixin, GraphComponent, CommandGenerator, ABC
|
|
54
|
+
):
|
|
51
55
|
"""An abstract class defining interface and common functionality
|
|
52
56
|
of an LLM-based command generators.
|
|
53
57
|
"""
|
|
@@ -61,6 +65,9 @@ class LLMBasedCommandGenerator(GraphComponent, CommandGenerator, ABC):
|
|
|
61
65
|
) -> None:
|
|
62
66
|
super().__init__(config)
|
|
63
67
|
self.config = {**self.get_default_config(), **config}
|
|
68
|
+
self.config[LLM_CONFIG_KEY] = resolve_model_client_config(
|
|
69
|
+
self.config.get(LLM_CONFIG_KEY), LLMBasedCommandGenerator.__name__
|
|
70
|
+
)
|
|
64
71
|
self._model_storage = model_storage
|
|
65
72
|
self._resource = resource
|
|
66
73
|
self.flow_retrieval: Optional[FlowRetrieval]
|
|
@@ -70,17 +77,9 @@ class LLMBasedCommandGenerator(GraphComponent, CommandGenerator, ABC):
|
|
|
70
77
|
self.config[FLOW_RETRIEVAL_KEY], model_storage, resource
|
|
71
78
|
)
|
|
72
79
|
structlogger.info("llm_based_command_generator.flow_retrieval.enabled")
|
|
80
|
+
self.config[FLOW_RETRIEVAL_KEY] = self.flow_retrieval.config
|
|
73
81
|
else:
|
|
74
82
|
self.flow_retrieval = None
|
|
75
|
-
structlogger.warn(
|
|
76
|
-
"llm_based_command_generator.flow_retrieval.disabled",
|
|
77
|
-
event_info=(
|
|
78
|
-
"Disabling flow retrieval can cause issues when there are a "
|
|
79
|
-
"large number of flows to be included in the prompt. For more"
|
|
80
|
-
"information see:\n"
|
|
81
|
-
"https://rasa.com/docs/rasa-pro/concepts/dialogue-understanding#how-the-llmcommandgenerator-works"
|
|
82
|
-
),
|
|
83
|
-
)
|
|
84
83
|
|
|
85
84
|
### Abstract methods
|
|
86
85
|
@staticmethod
|
|
@@ -168,14 +167,34 @@ class LLMBasedCommandGenerator(GraphComponent, CommandGenerator, ABC):
|
|
|
168
167
|
"""Train the llm based command generator. Stores all flows into a vector
|
|
169
168
|
store.
|
|
170
169
|
"""
|
|
171
|
-
|
|
172
|
-
try_instantiate_llm_client(
|
|
170
|
+
self.perform_llm_health_check(
|
|
173
171
|
self.config.get(LLM_CONFIG_KEY),
|
|
174
172
|
DEFAULT_LLM_CONFIG,
|
|
175
173
|
"llm_based_command_generator.train",
|
|
176
|
-
|
|
174
|
+
LLMBasedCommandGenerator.__name__,
|
|
177
175
|
)
|
|
178
176
|
|
|
177
|
+
if (
|
|
178
|
+
self.flow_retrieval is None
|
|
179
|
+
and len(flows.user_flows) > FLOW_RETRIEVAL_FLOW_THRESHOLD
|
|
180
|
+
):
|
|
181
|
+
structlogger.warn(
|
|
182
|
+
"llm_based_command_generator.flow_retrieval.disabled",
|
|
183
|
+
event_info=(
|
|
184
|
+
f"You have {len(flows.user_flows)} user flows but flow "
|
|
185
|
+
f"retrieval is disabled. "
|
|
186
|
+
f"It is recommended to enable flow retrieval if the "
|
|
187
|
+
f"total number of user flows exceed "
|
|
188
|
+
f"{FLOW_RETRIEVAL_FLOW_THRESHOLD}. "
|
|
189
|
+
f"Keeping it disabled can result in deterioration of "
|
|
190
|
+
f"command generator's functional "
|
|
191
|
+
f"performance and higher costs because of increased "
|
|
192
|
+
f"number of tokens in the prompt. For more"
|
|
193
|
+
"information see:\n"
|
|
194
|
+
"https://rasa.com/docs/rasa-pro/concepts/dialogue-understanding#how-the-llmcommandgenerator-works"
|
|
195
|
+
),
|
|
196
|
+
)
|
|
197
|
+
|
|
179
198
|
# flow retrieval is populated with only user-defined flows
|
|
180
199
|
try:
|
|
181
200
|
if self.flow_retrieval is not None and not flows.is_empty():
|
|
@@ -187,6 +206,7 @@ class LLMBasedCommandGenerator(GraphComponent, CommandGenerator, ABC):
|
|
|
187
206
|
error=e,
|
|
188
207
|
)
|
|
189
208
|
raise
|
|
209
|
+
|
|
190
210
|
self.persist()
|
|
191
211
|
return self._resource
|
|
192
212
|
|
|
@@ -224,7 +244,10 @@ class LLMBasedCommandGenerator(GraphComponent, CommandGenerator, ABC):
|
|
|
224
244
|
|
|
225
245
|
@classmethod
|
|
226
246
|
def load_flow_retrival(
|
|
227
|
-
cls,
|
|
247
|
+
cls,
|
|
248
|
+
config: Dict[str, Any],
|
|
249
|
+
model_storage: ModelStorage,
|
|
250
|
+
resource: Resource,
|
|
228
251
|
) -> Optional[FlowRetrieval]:
|
|
229
252
|
"""Load the FlowRetrieval component if it is enabled in the configuration."""
|
|
230
253
|
enable_flow_retrieval = config.get(FLOW_RETRIEVAL_KEY, {}).get(
|
|
@@ -40,7 +40,10 @@ from rasa.engine.graph import ExecutionContext
|
|
|
40
40
|
from rasa.engine.recipes.default_recipe import DefaultV1Recipe
|
|
41
41
|
from rasa.engine.storage.resource import Resource
|
|
42
42
|
from rasa.engine.storage.storage import ModelStorage
|
|
43
|
-
from rasa.shared.constants import
|
|
43
|
+
from rasa.shared.constants import (
|
|
44
|
+
RASA_PATTERN_CANNOT_HANDLE_NOT_SUPPORTED,
|
|
45
|
+
EMBEDDINGS_CONFIG_KEY,
|
|
46
|
+
)
|
|
44
47
|
from rasa.shared.constants import ROUTE_TO_CALM_SLOT
|
|
45
48
|
from rasa.shared.core.flows import FlowStep, Flow, FlowsList
|
|
46
49
|
from rasa.shared.core.flows.steps.collect import CollectInformationFlowStep
|
|
@@ -54,7 +57,7 @@ from rasa.shared.utils.llm import (
|
|
|
54
57
|
tracker_as_readable_transcript,
|
|
55
58
|
sanitize_message_for_prompt,
|
|
56
59
|
allowed_values_for_slot,
|
|
57
|
-
|
|
60
|
+
resolve_model_client_config,
|
|
58
61
|
)
|
|
59
62
|
|
|
60
63
|
# multistep template keys
|
|
@@ -72,6 +75,7 @@ DEFAULT_HANDLE_FLOWS_TEMPLATE = importlib.resources.read_text(
|
|
|
72
75
|
DEFAULT_FILL_SLOTS_TEMPLATE = importlib.resources.read_text(
|
|
73
76
|
"rasa.dialogue_understanding.generator.multi_step", "fill_slots_prompt.jinja2"
|
|
74
77
|
).strip()
|
|
78
|
+
MULTI_STEP_LLM_COMMAND_GENERATOR_CONFIG_FILE = "config.json"
|
|
75
79
|
|
|
76
80
|
# dictionary of template names and associated file names and default values
|
|
77
81
|
PROMPT_TEMPLATES = {
|
|
@@ -140,27 +144,32 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
140
144
|
**kwargs: Any,
|
|
141
145
|
) -> "MultiStepLLMCommandGenerator":
|
|
142
146
|
"""Loads trained component (see parent class for full docstring)."""
|
|
143
|
-
|
|
144
|
-
#
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
147
|
+
|
|
148
|
+
# Perform health check of the LLM client config
|
|
149
|
+
llm_config = resolve_model_client_config(config.get(LLM_CONFIG_KEY, {}))
|
|
150
|
+
cls.perform_llm_health_check(
|
|
151
|
+
llm_config,
|
|
148
152
|
DEFAULT_LLM_CONFIG,
|
|
149
153
|
"multi_step_llm_command_generator.load",
|
|
150
154
|
MultiStepLLMCommandGenerator.__name__,
|
|
151
155
|
)
|
|
156
|
+
|
|
157
|
+
prompts = cls._load_prompt_templates(model_storage, resource)
|
|
158
|
+
|
|
159
|
+
# init base command generator
|
|
160
|
+
command_generator = cls(config, model_storage, resource, prompts)
|
|
152
161
|
# load flow retrieval if enabled
|
|
153
162
|
if command_generator.enabled_flow_retrieval:
|
|
154
163
|
command_generator.flow_retrieval = cls.load_flow_retrival(
|
|
155
164
|
command_generator.config, model_storage, resource
|
|
156
165
|
)
|
|
166
|
+
|
|
157
167
|
return command_generator
|
|
158
168
|
|
|
159
169
|
def persist(self) -> None:
|
|
160
170
|
"""Persist this component to disk for future loading."""
|
|
161
|
-
# persist prompt template
|
|
162
171
|
self._persist_prompt_templates()
|
|
163
|
-
|
|
172
|
+
self._persist_config()
|
|
164
173
|
if self.flow_retrieval is not None:
|
|
165
174
|
self.flow_retrieval.persist()
|
|
166
175
|
|
|
@@ -393,6 +402,13 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
393
402
|
file_path = path / file_name
|
|
394
403
|
rasa.shared.utils.io.write_text_file(template, file_path)
|
|
395
404
|
|
|
405
|
+
def _persist_config(self) -> None:
|
|
406
|
+
"""Persist config as a source of truth for resolved clients."""
|
|
407
|
+
with self._model_storage.write_to(self._resource) as path:
|
|
408
|
+
rasa.shared.utils.io.dump_obj_as_json_to_file(
|
|
409
|
+
path / MULTI_STEP_LLM_COMMAND_GENERATOR_CONFIG_FILE, self.config
|
|
410
|
+
)
|
|
411
|
+
|
|
396
412
|
async def _predict_commands_with_multi_step(
|
|
397
413
|
self,
|
|
398
414
|
message: Message,
|
|
@@ -786,11 +802,17 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
786
802
|
.get(FILE_PATH_KEY),
|
|
787
803
|
DEFAULT_FILL_SLOTS_TEMPLATE,
|
|
788
804
|
)
|
|
805
|
+
|
|
806
|
+
llm_config = resolve_model_client_config(
|
|
807
|
+
config.get(LLM_CONFIG_KEY), MultiStepLLMCommandGenerator.__name__
|
|
808
|
+
)
|
|
809
|
+
embedding_config = resolve_model_client_config(
|
|
810
|
+
config.get(FLOW_RETRIEVAL_KEY, {}).get(EMBEDDINGS_CONFIG_KEY),
|
|
811
|
+
FlowRetrieval.__name__,
|
|
812
|
+
)
|
|
813
|
+
|
|
789
814
|
return deep_container_fingerprint(
|
|
790
|
-
[
|
|
791
|
-
handle_flows_template,
|
|
792
|
-
fill_slots_template,
|
|
793
|
-
]
|
|
815
|
+
[handle_flows_template, fill_slots_template, llm_config, embedding_config]
|
|
794
816
|
)
|
|
795
817
|
|
|
796
818
|
@staticmethod
|
|
@@ -41,6 +41,9 @@ Based on this information generate a list of actions you want to take. Your job
|
|
|
41
41
|
* Responding to knowledge-oriented user messages, described by "SearchAndReply()"
|
|
42
42
|
* Responding to a casual, non-task-oriented user message, described by "ChitChat()".
|
|
43
43
|
* Handing off to a human, in case the user seems frustrated or explicitly asks to speak to one, described by "HumanHandoff()".
|
|
44
|
+
{% if is_repeat_command_enabled %}
|
|
45
|
+
* Repeat the last bot messages, described by "RepeatLastBotMessages()". This is useful when the user asks to repeat the last bot messages.
|
|
46
|
+
{% endif %}
|
|
44
47
|
|
|
45
48
|
===
|
|
46
49
|
Write out the actions you want to take, one per line, in the order they should take place.
|
|
@@ -16,6 +16,7 @@ from rasa.dialogue_understanding.commands import (
|
|
|
16
16
|
KnowledgeAnswerCommand,
|
|
17
17
|
ClarifyCommand,
|
|
18
18
|
CannotHandleCommand,
|
|
19
|
+
RepeatBotMessagesCommand,
|
|
19
20
|
)
|
|
20
21
|
from rasa.dialogue_understanding.generator.constants import (
|
|
21
22
|
LLM_CONFIG_KEY,
|
|
@@ -38,6 +39,7 @@ from rasa.shared.constants import (
|
|
|
38
39
|
ROUTE_TO_CALM_SLOT,
|
|
39
40
|
PROMPT_CONFIG_KEY,
|
|
40
41
|
PROMPT_TEMPLATE_CONFIG_KEY,
|
|
42
|
+
EMBEDDINGS_CONFIG_KEY,
|
|
41
43
|
)
|
|
42
44
|
from rasa.shared.core.flows import FlowsList
|
|
43
45
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
@@ -49,8 +51,9 @@ from rasa.shared.utils.llm import (
|
|
|
49
51
|
get_prompt_template,
|
|
50
52
|
tracker_as_readable_transcript,
|
|
51
53
|
sanitize_message_for_prompt,
|
|
52
|
-
|
|
54
|
+
resolve_model_client_config,
|
|
53
55
|
)
|
|
56
|
+
from rasa.utils.beta import ensure_beta_feature_is_enabled, BetaNotEnabledException
|
|
54
57
|
from rasa.utils.log_utils import log_llm
|
|
55
58
|
|
|
56
59
|
COMMAND_PROMPT_FILE_NAME = "command_prompt.jinja2"
|
|
@@ -59,6 +62,7 @@ DEFAULT_COMMAND_PROMPT_TEMPLATE = importlib.resources.read_text(
|
|
|
59
62
|
"rasa.dialogue_understanding.generator.single_step",
|
|
60
63
|
"command_prompt_template.jinja2",
|
|
61
64
|
)
|
|
65
|
+
SINGLE_STEP_LLM_COMMAND_GENERATOR_CONFIG_FILE = "config.json"
|
|
62
66
|
|
|
63
67
|
structlogger = structlog.get_logger()
|
|
64
68
|
|
|
@@ -109,6 +113,7 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
109
113
|
)
|
|
110
114
|
|
|
111
115
|
self.trace_prompt_tokens = self.config.get("trace_prompt_tokens", False)
|
|
116
|
+
self.repeat_command_enabled = self.is_repeat_command_enabled()
|
|
112
117
|
|
|
113
118
|
### Implementations of LLMBasedCommandGenerator parent
|
|
114
119
|
@staticmethod
|
|
@@ -132,35 +137,51 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
132
137
|
**kwargs: Any,
|
|
133
138
|
) -> "SingleStepLLMCommandGenerator":
|
|
134
139
|
"""Loads trained component (see parent class for full docstring)."""
|
|
140
|
+
|
|
141
|
+
# Perform health check of the LLM API endpoint
|
|
142
|
+
llm_config = resolve_model_client_config(config.get(LLM_CONFIG_KEY, {}))
|
|
143
|
+
cls.perform_llm_health_check(
|
|
144
|
+
llm_config,
|
|
145
|
+
DEFAULT_LLM_CONFIG,
|
|
146
|
+
"single_step_llm_command_generator.load",
|
|
147
|
+
SingleStepLLMCommandGenerator.__name__,
|
|
148
|
+
)
|
|
149
|
+
|
|
135
150
|
# load prompt template from the model storage.
|
|
136
151
|
prompt_template = cls.load_prompt_template_from_model_storage(
|
|
137
152
|
model_storage, resource, COMMAND_PROMPT_FILE_NAME
|
|
138
153
|
)
|
|
154
|
+
|
|
139
155
|
# init base command generator
|
|
140
156
|
command_generator = cls(config, model_storage, resource, prompt_template)
|
|
141
|
-
try_instantiate_llm_client(
|
|
142
|
-
command_generator.config.get(LLM_CONFIG_KEY),
|
|
143
|
-
DEFAULT_LLM_CONFIG,
|
|
144
|
-
"single_step_llm_command_generator.load",
|
|
145
|
-
SingleStepLLMCommandGenerator.__name__,
|
|
146
|
-
)
|
|
147
157
|
# load flow retrieval if enabled
|
|
148
158
|
if command_generator.enabled_flow_retrieval:
|
|
149
159
|
command_generator.flow_retrieval = cls.load_flow_retrival(
|
|
150
160
|
command_generator.config, model_storage, resource
|
|
151
161
|
)
|
|
162
|
+
|
|
152
163
|
return command_generator
|
|
153
164
|
|
|
154
165
|
def persist(self) -> None:
|
|
155
166
|
"""Persist this component to disk for future loading."""
|
|
156
|
-
|
|
167
|
+
self._persist_prompt_template()
|
|
168
|
+
self._persist_config()
|
|
169
|
+
if self.flow_retrieval is not None:
|
|
170
|
+
self.flow_retrieval.persist()
|
|
171
|
+
|
|
172
|
+
def _persist_prompt_template(self) -> None:
|
|
173
|
+
"""Persist prompt template for future loading."""
|
|
157
174
|
with self._model_storage.write_to(self._resource) as path:
|
|
158
175
|
rasa.shared.utils.io.write_text_file(
|
|
159
176
|
self.prompt_template, path / COMMAND_PROMPT_FILE_NAME
|
|
160
177
|
)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
178
|
+
|
|
179
|
+
def _persist_config(self) -> None:
|
|
180
|
+
"""Persist config as a source of truth for resolved clients."""
|
|
181
|
+
with self._model_storage.write_to(self._resource) as path:
|
|
182
|
+
rasa.shared.utils.io.dump_obj_as_json_to_file(
|
|
183
|
+
path / SINGLE_STEP_LLM_COMMAND_GENERATOR_CONFIG_FILE, self.config
|
|
184
|
+
)
|
|
164
185
|
|
|
165
186
|
async def predict_commands(
|
|
166
187
|
self,
|
|
@@ -309,6 +330,7 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
309
330
|
knowledge_re = re.compile(r"SearchAndReply\(\)")
|
|
310
331
|
humand_handoff_re = re.compile(r"HumanHandoff\(\)")
|
|
311
332
|
clarify_re = re.compile(r"Clarify\(([\"\'a-zA-Z0-9_, ]+)\)")
|
|
333
|
+
repeat_re = re.compile(r"RepeatLastBotMessages\(\)")
|
|
312
334
|
|
|
313
335
|
for action in actions.strip().splitlines():
|
|
314
336
|
if match := slot_set_re.search(action):
|
|
@@ -335,6 +357,8 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
335
357
|
commands.append(KnowledgeAnswerCommand())
|
|
336
358
|
elif humand_handoff_re.search(action):
|
|
337
359
|
commands.append(HumanHandoffCommand())
|
|
360
|
+
elif repeat_re.search(action):
|
|
361
|
+
commands.append(RepeatBotMessagesCommand())
|
|
338
362
|
elif match := clarify_re.search(action):
|
|
339
363
|
options = sorted([opt.strip() for opt in match.group(1).split(",")])
|
|
340
364
|
# Remove surrounding quotes if present
|
|
@@ -366,7 +390,7 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
366
390
|
|
|
367
391
|
@classmethod
|
|
368
392
|
def fingerprint_addon(cls: Any, config: Dict[str, Any]) -> Optional[str]:
|
|
369
|
-
"""Add a fingerprint
|
|
393
|
+
"""Add a fingerprint for the graph."""
|
|
370
394
|
config_prompt = (
|
|
371
395
|
config.get(PROMPT_CONFIG_KEY)
|
|
372
396
|
or config.get(PROMPT_TEMPLATE_CONFIG_KEY)
|
|
@@ -376,7 +400,16 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
376
400
|
config_prompt,
|
|
377
401
|
DEFAULT_COMMAND_PROMPT_TEMPLATE,
|
|
378
402
|
)
|
|
379
|
-
|
|
403
|
+
llm_config = resolve_model_client_config(
|
|
404
|
+
config.get(LLM_CONFIG_KEY), SingleStepLLMCommandGenerator.__name__
|
|
405
|
+
)
|
|
406
|
+
embedding_config = resolve_model_client_config(
|
|
407
|
+
config.get(FLOW_RETRIEVAL_KEY, {}).get(EMBEDDINGS_CONFIG_KEY),
|
|
408
|
+
FlowRetrieval.__name__,
|
|
409
|
+
)
|
|
410
|
+
return deep_container_fingerprint(
|
|
411
|
+
[prompt_template, llm_config, embedding_config]
|
|
412
|
+
)
|
|
380
413
|
|
|
381
414
|
### Helper methods
|
|
382
415
|
def render_template(
|
|
@@ -426,6 +459,20 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
426
459
|
"current_slot": current_slot,
|
|
427
460
|
"current_slot_description": current_slot_description,
|
|
428
461
|
"user_message": latest_user_message,
|
|
462
|
+
"is_repeat_command_enabled": self.repeat_command_enabled,
|
|
429
463
|
}
|
|
430
464
|
|
|
431
465
|
return self.compile_template(self.prompt_template).render(**inputs)
|
|
466
|
+
|
|
467
|
+
def is_repeat_command_enabled(self) -> bool:
|
|
468
|
+
"""Check for feature flag"""
|
|
469
|
+
RASA_PRO_BETA_REPEAT_COMMAND_ENV_VAR_NAME = "RASA_PRO_BETA_REPEAT_COMMAND"
|
|
470
|
+
try:
|
|
471
|
+
ensure_beta_feature_is_enabled(
|
|
472
|
+
"Repeat Command",
|
|
473
|
+
env_flag=RASA_PRO_BETA_REPEAT_COMMAND_ENV_VAR_NAME,
|
|
474
|
+
)
|
|
475
|
+
except BetaNotEnabledException:
|
|
476
|
+
return False
|
|
477
|
+
|
|
478
|
+
return True
|
|
@@ -4,6 +4,11 @@ responses:
|
|
|
4
4
|
utter_ask_rephrase:
|
|
5
5
|
- text: I’m sorry I am unable to understand you, could you please rephrase?
|
|
6
6
|
|
|
7
|
+
utter_ask_still_there:
|
|
8
|
+
- text: "Hello, are you still there?"
|
|
9
|
+
metadata:
|
|
10
|
+
rephrase: True
|
|
11
|
+
|
|
7
12
|
utter_boolean_slot_rejection:
|
|
8
13
|
- text: "Sorry, the value you provided, `{{value}}`, is not valid. Please respond with a valid value."
|
|
9
14
|
metadata:
|
|
@@ -75,6 +80,11 @@ responses:
|
|
|
75
80
|
metadata:
|
|
76
81
|
rephrase: True
|
|
77
82
|
|
|
83
|
+
utter_inform_hangup:
|
|
84
|
+
- text: It seems you are not there anymore. I will hang up shortly.
|
|
85
|
+
metadata:
|
|
86
|
+
rephrase: True
|
|
87
|
+
|
|
78
88
|
utter_internal_error_rasa:
|
|
79
89
|
- text: Sorry, I am having trouble with that. Please try again in a few minutes.
|
|
80
90
|
|
|
@@ -101,6 +111,15 @@ slots:
|
|
|
101
111
|
type: bool
|
|
102
112
|
mappings:
|
|
103
113
|
- type: from_llm
|
|
114
|
+
silence_timeout:
|
|
115
|
+
type: float
|
|
116
|
+
initial_value: 6.0
|
|
117
|
+
max_value: 1000000
|
|
118
|
+
consecutive_silence_timeouts:
|
|
119
|
+
type: float
|
|
120
|
+
initial_value: 0.0
|
|
121
|
+
max_value: 1000000
|
|
122
|
+
|
|
104
123
|
|
|
105
124
|
flows:
|
|
106
125
|
pattern_cancel_flow:
|
|
@@ -217,6 +236,11 @@ flows:
|
|
|
217
236
|
- action: utter_internal_error_rasa
|
|
218
237
|
next: END
|
|
219
238
|
|
|
239
|
+
pattern_repeat_bot_messages:
|
|
240
|
+
description: Voice conversation repair pattern to repeat bot messages
|
|
241
|
+
name: pattern repeat bot messages
|
|
242
|
+
steps:
|
|
243
|
+
- action: action_repeat_bot_messages
|
|
220
244
|
|
|
221
245
|
pattern_restart:
|
|
222
246
|
description: Flow for restarting the conversation
|
|
@@ -246,3 +270,32 @@ flows:
|
|
|
246
270
|
name: pattern skip question
|
|
247
271
|
steps:
|
|
248
272
|
- action: utter_skip_question_answer
|
|
273
|
+
|
|
274
|
+
pattern_user_silence:
|
|
275
|
+
description: Reacting to user silence in voice bots
|
|
276
|
+
name: pattern react to silence
|
|
277
|
+
nlu_trigger:
|
|
278
|
+
- intent: silence_timeout
|
|
279
|
+
persisted_slots:
|
|
280
|
+
- consecutive_silence_timeouts
|
|
281
|
+
steps:
|
|
282
|
+
- noop: true
|
|
283
|
+
next:
|
|
284
|
+
- if: "slots.consecutive_silence_timeouts = 0.0"
|
|
285
|
+
then:
|
|
286
|
+
- set_slots:
|
|
287
|
+
- consecutive_silence_timeouts: 1.0
|
|
288
|
+
- action: action_repeat_bot_messages
|
|
289
|
+
next: END
|
|
290
|
+
- if: "slots.consecutive_silence_timeouts = 1.0"
|
|
291
|
+
then:
|
|
292
|
+
- set_slots:
|
|
293
|
+
- consecutive_silence_timeouts: 2.0
|
|
294
|
+
- action: utter_ask_still_there
|
|
295
|
+
next: END
|
|
296
|
+
- if: "slots.consecutive_silence_timeouts > 1.0"
|
|
297
|
+
then:
|
|
298
|
+
- action: utter_inform_hangup
|
|
299
|
+
- action: action_hangup
|
|
300
|
+
next: END
|
|
301
|
+
- else: END
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any, Dict
|
|
5
|
+
|
|
6
|
+
from rasa.dialogue_understanding.stack.frames import PatternFlowStackFrame
|
|
7
|
+
from rasa.shared.constants import RASA_DEFAULT_FLOW_PATTERN_PREFIX
|
|
8
|
+
|
|
9
|
+
FLOW_PATTERN_REPEAT = RASA_DEFAULT_FLOW_PATTERN_PREFIX + "repeat_bot_messages"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class RepeatBotMessagesPatternFlowStackFrame(PatternFlowStackFrame):
|
|
14
|
+
"""A flow stack frame that can get added when bot messages should be repeated"""
|
|
15
|
+
|
|
16
|
+
flow_id: str = FLOW_PATTERN_REPEAT
|
|
17
|
+
"""The ID of the flow."""
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def type(cls) -> str:
|
|
21
|
+
"""Returns the type of the frame."""
|
|
22
|
+
return FLOW_PATTERN_REPEAT
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def from_dict(data: Dict[str, Any]) -> RepeatBotMessagesPatternFlowStackFrame:
|
|
26
|
+
"""Creates a `DialogueStackFrame` from a dictionary.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
data: The dictionary to create the `DialogueStackFrame` from.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
The created `DialogueStackFrame`.
|
|
33
|
+
"""
|
|
34
|
+
return RepeatBotMessagesPatternFlowStackFrame(
|
|
35
|
+
frame_id=data["frame_id"],
|
|
36
|
+
step_id=data["step_id"],
|
|
37
|
+
)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Any, Dict
|
|
4
|
+
|
|
5
|
+
from rasa.dialogue_understanding.stack.frames import PatternFlowStackFrame
|
|
6
|
+
from rasa.shared.constants import RASA_DEFAULT_FLOW_PATTERN_PREFIX
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
FLOW_PATTERN_USER_SILENCE = RASA_DEFAULT_FLOW_PATTERN_PREFIX + "user_silence"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class UserSilencePatternFlowStackFrame(PatternFlowStackFrame):
|
|
14
|
+
"""A flow stack frame that can get added when the silence timeout trips."""
|
|
15
|
+
|
|
16
|
+
flow_id: str = FLOW_PATTERN_USER_SILENCE
|
|
17
|
+
"""The ID of the flow."""
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def type(cls) -> str:
|
|
21
|
+
"""Returns the type of the frame."""
|
|
22
|
+
return FLOW_PATTERN_USER_SILENCE
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def from_dict(data: Dict[str, Any]) -> UserSilencePatternFlowStackFrame:
|
|
26
|
+
"""Creates a `DialogueStackFrame` from a dictionary.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
data: The dictionary to create the `DialogueStackFrame` from.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
The created `DialogueStackFrame`.
|
|
33
|
+
"""
|
|
34
|
+
return UserSilencePatternFlowStackFrame(
|
|
35
|
+
frame_id=data["frame_id"],
|
|
36
|
+
step_id=data["step_id"],
|
|
37
|
+
)
|
|
@@ -8,6 +8,7 @@ from rasa.dialogue_understanding.commands import (
|
|
|
8
8
|
Command,
|
|
9
9
|
CorrectSlotsCommand,
|
|
10
10
|
CorrectedSlot,
|
|
11
|
+
RepeatBotMessagesCommand,
|
|
11
12
|
SetSlotCommand,
|
|
12
13
|
StartFlowCommand,
|
|
13
14
|
FreeFormAnswerCommand,
|
|
@@ -422,6 +423,9 @@ def clean_up_commands(
|
|
|
422
423
|
elif not tracker.has_coexistence_routing_slot and len(clean_commands) > 1:
|
|
423
424
|
clean_commands = filter_cannot_handle_command_for_skipped_slots(clean_commands)
|
|
424
425
|
|
|
426
|
+
clean_commands = ensure_max_number_of_command_type(
|
|
427
|
+
clean_commands, RepeatBotMessagesCommand, 1
|
|
428
|
+
)
|
|
425
429
|
structlogger.debug(
|
|
426
430
|
"command_processor.clean_up_commands.final_commands",
|
|
427
431
|
command=clean_commands,
|
|
@@ -430,6 +434,22 @@ def clean_up_commands(
|
|
|
430
434
|
return clean_commands
|
|
431
435
|
|
|
432
436
|
|
|
437
|
+
def ensure_max_number_of_command_type(
|
|
438
|
+
commands: List[Command], command_type: Type[Command], n: int
|
|
439
|
+
) -> List[Command]:
|
|
440
|
+
"""Ensures that for a given command type only the first n stay in the list."""
|
|
441
|
+
filtered: List[Command] = []
|
|
442
|
+
count = 0
|
|
443
|
+
for c in commands:
|
|
444
|
+
if isinstance(c, command_type):
|
|
445
|
+
if count >= n:
|
|
446
|
+
continue
|
|
447
|
+
else:
|
|
448
|
+
count += 1
|
|
449
|
+
filtered.append(c)
|
|
450
|
+
return filtered
|
|
451
|
+
|
|
452
|
+
|
|
433
453
|
def clean_up_clarify_command(
|
|
434
454
|
commands_so_far: List[Command],
|
|
435
455
|
all_commands: List[Command],
|
|
@@ -452,7 +472,7 @@ def clean_up_clarify_command(
|
|
|
452
472
|
if not (isinstance(c, SetSlotCommand) and c.name == ROUTE_TO_CALM_SLOT)
|
|
453
473
|
]
|
|
454
474
|
|
|
455
|
-
# if
|
|
475
|
+
# if all commands are clarify commands, add the first one only, otherwise add none
|
|
456
476
|
if all(
|
|
457
477
|
isinstance(c, ClarifyCommand) for c in commands_without_route_to_calm_set_slot
|
|
458
478
|
):
|
|
@@ -35,7 +35,6 @@ class AggregateTestStatsCalculator:
|
|
|
35
35
|
self.test_cases = test_cases
|
|
36
36
|
|
|
37
37
|
self.failed_assertion_set: Set["Assertion"] = set()
|
|
38
|
-
self.failed_test_cases_without_assertion_failure: Set[str] = set()
|
|
39
38
|
self.passed_count_mapping = {
|
|
40
39
|
subclass_type: 0
|
|
41
40
|
for subclass_type in _get_all_assertion_subclasses().keys()
|
|
@@ -90,14 +89,8 @@ class AggregateTestStatsCalculator:
|
|
|
90
89
|
passed_test_case_names = [
|
|
91
90
|
passed.test_case.name for passed in self.passed_results
|
|
92
91
|
]
|
|
93
|
-
# We filter out test cases that failed without an assertion failure
|
|
94
|
-
filtered_test_cases = [
|
|
95
|
-
test_case
|
|
96
|
-
for test_case in self.test_cases
|
|
97
|
-
if test_case.name not in self.failed_test_cases_without_assertion_failure
|
|
98
|
-
]
|
|
99
92
|
|
|
100
|
-
for test_case in
|
|
93
|
+
for test_case in self.test_cases:
|
|
101
94
|
if test_case.name in passed_test_case_names:
|
|
102
95
|
for step in test_case.steps:
|
|
103
96
|
if step.assertions is None:
|
|
@@ -125,9 +118,6 @@ class AggregateTestStatsCalculator:
|
|
|
125
118
|
"no_assertion_failure_in_failed_result",
|
|
126
119
|
test_case=failed.test_case.name,
|
|
127
120
|
)
|
|
128
|
-
self.failed_test_cases_without_assertion_failure.add(
|
|
129
|
-
failed.test_case.name
|
|
130
|
-
)
|
|
131
121
|
continue
|
|
132
122
|
|
|
133
123
|
self.failed_assertion_set.add(failed.assertion_failure.assertion)
|