rasa-pro 3.11.0a4.dev2__py3-none-any.whl → 3.11.0rc1__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 +22 -12
- rasa/api.py +1 -1
- rasa/cli/arguments/default_arguments.py +1 -2
- rasa/cli/arguments/shell.py +5 -1
- rasa/cli/e2e_test.py +1 -1
- rasa/cli/evaluate.py +8 -8
- rasa/cli/inspect.py +4 -4
- rasa/cli/llm_fine_tuning.py +1 -1
- rasa/cli/project_templates/calm/config.yml +5 -7
- rasa/cli/project_templates/calm/endpoints.yml +8 -0
- 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 +7 -7
- rasa/cli/run.py +1 -1
- rasa/cli/scaffold.py +4 -2
- rasa/cli/utils.py +5 -0
- rasa/cli/x.py +8 -8
- rasa/constants.py +1 -1
- rasa/core/channels/channel.py +3 -0
- rasa/core/channels/inspector/dist/assets/{arc-6852c607.js → arc-bc141fb2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-d0fbc5ce-acc952b2.js → c4Diagram-d0fbc5ce-be2db283.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-936ed81e-848a7597.js → classDiagram-936ed81e-55366915.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-c3cb15f1-a73d3e68.js → classDiagram-v2-c3cb15f1-bb529518.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{createText-62fc7601-e5ee049d.js → createText-62fc7601-b0ec81d6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-f2ad444c-771e517e.js → edges-f2ad444c-6166330c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-aa347178.js → erDiagram-9d236eb7-5ccc6a8e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-1972c806-651fc57d.js → flowDb-1972c806-fca3bfe4.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-7ea5b25a-ca67804f.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-2dbc568d.js → flowchart-elk-definition-abe16c3d-7c1b0e0f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-9b5ea136-25a65bd8.js → ganttDiagram-9b5ea136-772fd050.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-99d0ae7c-fdc7378d.js → gitGraphDiagram-99d0ae7c-8eae1dc9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-2c4b9a3b-6f1fd606.js → index-2c4b9a3b-f55afcdf.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-efdd30c1.js → index-e7cef9de.js} +68 -68
- rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-cb1a041a.js → infoDiagram-736b4530-124d4a14.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-14609879.js → journeyDiagram-df861f2b-7c4fae44.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-2490f52b.js → layout-b9885fb6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-40186f1f.js → line-7c59abb6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-08814e93.js → linear-4776f780.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-beec6740-1a534584.js → mindmap-definition-beec6740-2332c46c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-72397b61.js → pieDiagram-dbbf0591-8fb39303.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-3bb0b6a3.js → quadrantDiagram-4d7f4fd6-3c7180a2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-57334f61.js → requirementDiagram-6fc4c22a-e910bcb8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-8f13d901-111e1297.js → sankeyDiagram-8f13d901-ead16c89.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-b655622a-10bcfe62.js → sequenceDiagram-b655622a-29a02a19.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-59f0c015-acaf7513.js → stateDiagram-59f0c015-042b3137.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-2b26beab-3ec2a235.js → stateDiagram-v2-2b26beab-2178c0f3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-080da4f6-62730289.js → styles-080da4f6-23ffa4fc.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-3dcbcfbf-5284ee76.js → styles-3dcbcfbf-94f59763.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9c745c82-642435e3.js → styles-9c745c82-78a6bebc.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-4835440b-b250a350.js → svgDrawCommon-4835440b-eae2a6f6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-c2b147ed.js → timeline-definition-5b62e21b-5c968d92.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-f92cfea9.js → xychartDiagram-2b33534f-fd3db0d5.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/src/App.tsx +1 -1
- rasa/core/channels/inspector/src/helpers/audiostream.ts +77 -16
- rasa/core/channels/socketio.py +2 -1
- rasa/core/channels/telegram.py +1 -1
- rasa/core/channels/twilio.py +1 -1
- rasa/core/channels/voice_ready/jambonz.py +2 -2
- rasa/core/channels/voice_stream/asr/asr_event.py +5 -0
- rasa/core/channels/voice_stream/asr/azure.py +122 -0
- rasa/core/channels/voice_stream/asr/deepgram.py +16 -6
- rasa/core/channels/voice_stream/audio_bytes.py +1 -0
- rasa/core/channels/voice_stream/browser_audio.py +31 -8
- rasa/core/channels/voice_stream/call_state.py +23 -0
- rasa/core/channels/voice_stream/tts/azure.py +6 -2
- rasa/core/channels/voice_stream/tts/cartesia.py +10 -6
- rasa/core/channels/voice_stream/tts/tts_engine.py +1 -0
- rasa/core/channels/voice_stream/twilio_media_streams.py +27 -18
- rasa/core/channels/voice_stream/util.py +4 -4
- rasa/core/channels/voice_stream/voice_channel.py +177 -39
- rasa/core/featurizers/single_state_featurizer.py +22 -1
- rasa/core/featurizers/tracker_featurizers.py +115 -18
- rasa/core/nlg/contextual_response_rephraser.py +16 -22
- rasa/core/persistor.py +86 -39
- rasa/core/policies/enterprise_search_policy.py +159 -60
- rasa/core/policies/flows/flow_executor.py +7 -4
- rasa/core/policies/intentless_policy.py +120 -22
- rasa/core/policies/ted_policy.py +58 -33
- rasa/core/policies/unexpected_intent_policy.py +15 -7
- rasa/core/processor.py +25 -0
- rasa/core/training/interactive.py +34 -35
- rasa/core/utils.py +8 -3
- rasa/dialogue_understanding/coexistence/llm_based_router.py +58 -16
- rasa/dialogue_understanding/commands/change_flow_command.py +6 -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 +4 -0
- rasa/dialogue_understanding/generator/flow_retrieval.py +65 -3
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +68 -26
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +57 -8
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +64 -7
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +39 -0
- rasa/dialogue_understanding/patterns/user_silence.py +37 -0
- rasa/e2e_test/e2e_test_runner.py +4 -2
- rasa/e2e_test/utils/io.py +1 -1
- rasa/engine/validation.py +297 -7
- rasa/model_manager/config.py +17 -3
- rasa/model_manager/model_api.py +16 -8
- rasa/model_manager/runner_service.py +8 -6
- rasa/model_manager/socket_bridge.py +6 -3
- rasa/model_manager/trainer_service.py +7 -5
- rasa/model_manager/utils.py +28 -7
- rasa/model_service.py +7 -5
- rasa/model_training.py +2 -0
- rasa/nlu/classifiers/diet_classifier.py +38 -25
- rasa/nlu/classifiers/logistic_regression_classifier.py +22 -9
- rasa/nlu/classifiers/sklearn_intent_classifier.py +37 -16
- rasa/nlu/extractors/crf_entity_extractor.py +93 -50
- rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +45 -16
- rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +52 -17
- rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +5 -3
- rasa/shared/constants.py +36 -3
- rasa/shared/core/constants.py +7 -0
- rasa/shared/core/domain.py +26 -0
- rasa/shared/core/flows/flow.py +5 -0
- rasa/shared/core/flows/flows_yaml_schema.json +10 -0
- rasa/shared/core/flows/utils.py +39 -0
- rasa/shared/core/flows/validation.py +96 -0
- rasa/shared/core/slots.py +5 -0
- rasa/shared/nlu/training_data/features.py +120 -2
- rasa/shared/providers/_configs/azure_openai_client_config.py +5 -3
- rasa/shared/providers/_configs/litellm_router_client_config.py +200 -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/embedding/_base_litellm_embedding_client.py +12 -15
- rasa/shared/providers/embedding/azure_openai_embedding_client.py +54 -21
- rasa/shared/providers/embedding/litellm_router_embedding_client.py +135 -0
- rasa/shared/providers/llm/_base_litellm_client.py +31 -30
- rasa/shared/providers/llm/azure_openai_llm_client.py +50 -29
- rasa/shared/providers/llm/litellm_router_llm_client.py +127 -0
- rasa/shared/providers/llm/rasa_llm_client.py +112 -0
- rasa/shared/providers/llm/self_hosted_llm_client.py +1 -1
- rasa/shared/providers/mappings.py +19 -0
- rasa/shared/providers/router/__init__.py +0 -0
- rasa/shared/providers/router/_base_litellm_router_client.py +149 -0
- rasa/shared/providers/router/router_client.py +73 -0
- rasa/shared/utils/common.py +8 -0
- rasa/shared/utils/health_check.py +533 -0
- rasa/shared/utils/io.py +28 -6
- rasa/shared/utils/llm.py +350 -46
- rasa/shared/utils/yaml.py +11 -13
- rasa/studio/upload.py +64 -20
- rasa/telemetry.py +80 -17
- rasa/tracing/instrumentation/attribute_extractors.py +74 -17
- rasa/utils/io.py +0 -66
- rasa/utils/log_utils.py +9 -2
- rasa/utils/tensorflow/feature_array.py +366 -0
- rasa/utils/tensorflow/model_data.py +2 -193
- rasa/validator.py +70 -0
- rasa/version.py +1 -1
- {rasa_pro-3.11.0a4.dev2.dist-info → rasa_pro-3.11.0rc1.dist-info}/METADATA +10 -10
- {rasa_pro-3.11.0a4.dev2.dist-info → rasa_pro-3.11.0rc1.dist-info}/RECORD +162 -146
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-587d82d8.js +0 -1
- {rasa_pro-3.11.0a4.dev2.dist-info → rasa_pro-3.11.0rc1.dist-info}/NOTICE +0 -0
- {rasa_pro-3.11.0a4.dev2.dist-info → rasa_pro-3.11.0rc1.dist-info}/WHEEL +0 -0
- {rasa_pro-3.11.0a4.dev2.dist-info → rasa_pro-3.11.0rc1.dist-info}/entry_points.txt +0 -0
|
@@ -24,6 +24,8 @@ from rasa.dialogue_understanding.generator.constants import (
|
|
|
24
24
|
LLM_CONFIG_KEY,
|
|
25
25
|
USER_INPUT_CONFIG_KEY,
|
|
26
26
|
FLOW_RETRIEVAL_KEY,
|
|
27
|
+
TRAINED_MODEL_NAME_CONFIG_KEY,
|
|
28
|
+
DEFAULT_LLM_CONFIG,
|
|
27
29
|
)
|
|
28
30
|
from rasa.dialogue_understanding.generator.flow_retrieval import FlowRetrieval
|
|
29
31
|
from rasa.dialogue_understanding.generator.llm_based_command_generator import (
|
|
@@ -39,7 +41,10 @@ from rasa.engine.graph import ExecutionContext
|
|
|
39
41
|
from rasa.engine.recipes.default_recipe import DefaultV1Recipe
|
|
40
42
|
from rasa.engine.storage.resource import Resource
|
|
41
43
|
from rasa.engine.storage.storage import ModelStorage
|
|
42
|
-
from rasa.shared.constants import
|
|
44
|
+
from rasa.shared.constants import (
|
|
45
|
+
RASA_PATTERN_CANNOT_HANDLE_NOT_SUPPORTED,
|
|
46
|
+
EMBEDDINGS_CONFIG_KEY,
|
|
47
|
+
)
|
|
43
48
|
from rasa.shared.constants import ROUTE_TO_CALM_SLOT
|
|
44
49
|
from rasa.shared.core.flows import FlowStep, Flow, FlowsList
|
|
45
50
|
from rasa.shared.core.flows.steps.collect import CollectInformationFlowStep
|
|
@@ -53,7 +58,9 @@ from rasa.shared.utils.llm import (
|
|
|
53
58
|
tracker_as_readable_transcript,
|
|
54
59
|
sanitize_message_for_prompt,
|
|
55
60
|
allowed_values_for_slot,
|
|
61
|
+
resolve_model_client_config,
|
|
56
62
|
)
|
|
63
|
+
from rasa.shared.utils.health_check import perform_inference_time_llm_health_check
|
|
57
64
|
|
|
58
65
|
# multistep template keys
|
|
59
66
|
HANDLE_FLOWS_KEY = "handle_flows"
|
|
@@ -139,6 +146,14 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
139
146
|
) -> "MultiStepLLMCommandGenerator":
|
|
140
147
|
"""Loads trained component (see parent class for full docstring)."""
|
|
141
148
|
prompts = cls._load_prompt_templates(model_storage, resource)
|
|
149
|
+
|
|
150
|
+
persisted_config = cls.load_config_from_model_storage(model_storage, resource)
|
|
151
|
+
train_model_name = (
|
|
152
|
+
persisted_config.get(TRAINED_MODEL_NAME_CONFIG_KEY, None)
|
|
153
|
+
if persisted_config
|
|
154
|
+
else None
|
|
155
|
+
)
|
|
156
|
+
|
|
142
157
|
# init base command generator
|
|
143
158
|
command_generator = cls(config, model_storage, resource, prompts)
|
|
144
159
|
# load flow retrieval if enabled
|
|
@@ -146,10 +161,21 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
146
161
|
command_generator.flow_retrieval = cls.load_flow_retrival(
|
|
147
162
|
command_generator.config, model_storage, resource
|
|
148
163
|
)
|
|
164
|
+
|
|
165
|
+
perform_inference_time_llm_health_check(
|
|
166
|
+
command_generator.config.get(LLM_CONFIG_KEY),
|
|
167
|
+
DEFAULT_LLM_CONFIG,
|
|
168
|
+
train_model_name,
|
|
169
|
+
"multi_step_llm_command_generator.load",
|
|
170
|
+
MultiStepLLMCommandGenerator.__name__,
|
|
171
|
+
)
|
|
172
|
+
|
|
149
173
|
return command_generator
|
|
150
174
|
|
|
151
175
|
def persist(self) -> None:
|
|
152
176
|
"""Persist this component to disk for future loading."""
|
|
177
|
+
super().persist()
|
|
178
|
+
|
|
153
179
|
# persist prompt template
|
|
154
180
|
self._persist_prompt_templates()
|
|
155
181
|
# persist flow retrieval
|
|
@@ -229,9 +255,9 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
229
255
|
commands: List[Command] = []
|
|
230
256
|
|
|
231
257
|
slot_set_re = re.compile(
|
|
232
|
-
r"""SetSlot\(
|
|
258
|
+
r"""SetSlot\(['"]?([a-zA-Z_][a-zA-Z0-9_-]*)['"]?, ?['"]?(.*)['"]?\)"""
|
|
233
259
|
)
|
|
234
|
-
start_flow_re = re.compile(r"StartFlow\(([a-zA-Z0-9_-]
|
|
260
|
+
start_flow_re = re.compile(r"StartFlow\(['\"]?([a-zA-Z0-9_-]+)['\"]?\)")
|
|
235
261
|
change_flow_re = re.compile(r"ChangeFlow\(\)")
|
|
236
262
|
cancel_flow_re = re.compile(r"CancelFlow\(\)")
|
|
237
263
|
chitchat_re = re.compile(r"ChitChat\(\)")
|
|
@@ -280,9 +306,19 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
280
306
|
commands.append(HumanHandoffCommand())
|
|
281
307
|
elif match := clarify_re.search(action):
|
|
282
308
|
options = sorted([opt.strip() for opt in match.group(1).split(",")])
|
|
309
|
+
# Remove surrounding quotes if present
|
|
310
|
+
cleaned_options = []
|
|
311
|
+
for flow in options:
|
|
312
|
+
if (flow.startswith('"') and flow.endswith('"')) or (
|
|
313
|
+
flow.startswith("'") and flow.endswith("'")
|
|
314
|
+
):
|
|
315
|
+
cleaned_options.append(flow[1:-1])
|
|
316
|
+
else:
|
|
317
|
+
cleaned_options.append(flow)
|
|
318
|
+
# check if flow is valid
|
|
283
319
|
valid_options = [
|
|
284
320
|
flow
|
|
285
|
-
for flow in
|
|
321
|
+
for flow in cleaned_options
|
|
286
322
|
if flow in flows.user_flow_ids
|
|
287
323
|
and flow not in user_flows_on_the_stack(tracker.stack)
|
|
288
324
|
]
|
|
@@ -293,6 +329,13 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
293
329
|
elif change_flow_re.search(action):
|
|
294
330
|
commands.append(ChangeFlowCommand())
|
|
295
331
|
|
|
332
|
+
if not commands:
|
|
333
|
+
structlogger.debug(
|
|
334
|
+
"multi_step_llm_command_generator.parse_commands",
|
|
335
|
+
message="No commands were parsed from the LLM actions.",
|
|
336
|
+
actions=actions,
|
|
337
|
+
)
|
|
338
|
+
|
|
296
339
|
return commands
|
|
297
340
|
|
|
298
341
|
### Helper methods
|
|
@@ -761,11 +804,17 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
761
804
|
.get(FILE_PATH_KEY),
|
|
762
805
|
DEFAULT_FILL_SLOTS_TEMPLATE,
|
|
763
806
|
)
|
|
807
|
+
|
|
808
|
+
llm_config = resolve_model_client_config(
|
|
809
|
+
config.get(LLM_CONFIG_KEY), MultiStepLLMCommandGenerator.__name__
|
|
810
|
+
)
|
|
811
|
+
embedding_config = resolve_model_client_config(
|
|
812
|
+
config.get(FLOW_RETRIEVAL_KEY, {}).get(EMBEDDINGS_CONFIG_KEY),
|
|
813
|
+
FlowRetrieval.__name__,
|
|
814
|
+
)
|
|
815
|
+
|
|
764
816
|
return deep_container_fingerprint(
|
|
765
|
-
[
|
|
766
|
-
handle_flows_template,
|
|
767
|
-
fill_slots_template,
|
|
768
|
-
]
|
|
817
|
+
[handle_flows_template, fill_slots_template, llm_config, embedding_config]
|
|
769
818
|
)
|
|
770
819
|
|
|
771
820
|
@staticmethod
|
|
@@ -22,6 +22,8 @@ from rasa.dialogue_understanding.generator.constants import (
|
|
|
22
22
|
LLM_CONFIG_KEY,
|
|
23
23
|
USER_INPUT_CONFIG_KEY,
|
|
24
24
|
FLOW_RETRIEVAL_KEY,
|
|
25
|
+
DEFAULT_LLM_CONFIG,
|
|
26
|
+
TRAINED_MODEL_NAME_CONFIG_KEY,
|
|
25
27
|
)
|
|
26
28
|
from rasa.dialogue_understanding.generator.flow_retrieval import (
|
|
27
29
|
FlowRetrieval,
|
|
@@ -38,6 +40,7 @@ from rasa.shared.constants import (
|
|
|
38
40
|
ROUTE_TO_CALM_SLOT,
|
|
39
41
|
PROMPT_CONFIG_KEY,
|
|
40
42
|
PROMPT_TEMPLATE_CONFIG_KEY,
|
|
43
|
+
EMBEDDINGS_CONFIG_KEY,
|
|
41
44
|
)
|
|
42
45
|
from rasa.shared.core.flows import FlowsList
|
|
43
46
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
@@ -49,9 +52,11 @@ from rasa.shared.utils.llm import (
|
|
|
49
52
|
get_prompt_template,
|
|
50
53
|
tracker_as_readable_transcript,
|
|
51
54
|
sanitize_message_for_prompt,
|
|
55
|
+
resolve_model_client_config,
|
|
52
56
|
)
|
|
53
|
-
from rasa.utils.
|
|
57
|
+
from rasa.shared.utils.health_check import perform_inference_time_llm_health_check
|
|
54
58
|
from rasa.utils.beta import ensure_beta_feature_is_enabled, BetaNotEnabledException
|
|
59
|
+
from rasa.utils.log_utils import log_llm
|
|
55
60
|
|
|
56
61
|
COMMAND_PROMPT_FILE_NAME = "command_prompt.jinja2"
|
|
57
62
|
|
|
@@ -136,6 +141,7 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
136
141
|
prompt_template = cls.load_prompt_template_from_model_storage(
|
|
137
142
|
model_storage, resource, COMMAND_PROMPT_FILE_NAME
|
|
138
143
|
)
|
|
144
|
+
|
|
139
145
|
# init base command generator
|
|
140
146
|
command_generator = cls(config, model_storage, resource, prompt_template)
|
|
141
147
|
# load flow retrieval if enabled
|
|
@@ -143,11 +149,28 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
143
149
|
command_generator.flow_retrieval = cls.load_flow_retrival(
|
|
144
150
|
command_generator.config, model_storage, resource
|
|
145
151
|
)
|
|
152
|
+
|
|
153
|
+
persisted_config = cls.load_config_from_model_storage(model_storage, resource)
|
|
154
|
+
train_model_name = (
|
|
155
|
+
persisted_config.get(TRAINED_MODEL_NAME_CONFIG_KEY, None)
|
|
156
|
+
if persisted_config
|
|
157
|
+
else None
|
|
158
|
+
)
|
|
159
|
+
perform_inference_time_llm_health_check(
|
|
160
|
+
command_generator.config.get(LLM_CONFIG_KEY),
|
|
161
|
+
DEFAULT_LLM_CONFIG,
|
|
162
|
+
train_model_name,
|
|
163
|
+
"single_step_llm_command_generator.load",
|
|
164
|
+
SingleStepLLMCommandGenerator.__name__,
|
|
165
|
+
)
|
|
166
|
+
|
|
146
167
|
return command_generator
|
|
147
168
|
|
|
148
169
|
def persist(self) -> None:
|
|
149
170
|
"""Persist this component to disk for future loading."""
|
|
150
171
|
# persist prompt template
|
|
172
|
+
super().persist()
|
|
173
|
+
|
|
151
174
|
with self._model_storage.write_to(self._resource) as path:
|
|
152
175
|
rasa.shared.utils.io.write_text_file(
|
|
153
176
|
self.prompt_template, path / COMMAND_PROMPT_FILE_NAME
|
|
@@ -187,6 +210,12 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
187
210
|
|
|
188
211
|
if not commands:
|
|
189
212
|
# no commands are parsed or there's an invalid command
|
|
213
|
+
structlogger.warning(
|
|
214
|
+
"single_step_llm_command_generator.predict_commands",
|
|
215
|
+
message="No commands were predicted as the LLM response could "
|
|
216
|
+
"not be parsed or the LLM responded with an invalid command."
|
|
217
|
+
"Returning a CannotHandleCommand instead.",
|
|
218
|
+
)
|
|
190
219
|
commands = [CannotHandleCommand()]
|
|
191
220
|
|
|
192
221
|
if tracker.has_coexistence_routing_slot:
|
|
@@ -287,14 +316,16 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
287
316
|
|
|
288
317
|
commands: List[Command] = []
|
|
289
318
|
|
|
290
|
-
slot_set_re = re.compile(
|
|
291
|
-
|
|
319
|
+
slot_set_re = re.compile(
|
|
320
|
+
r"""SetSlot\(['"]?([a-zA-Z_][a-zA-Z0-9_-]*)['"]?, ?['"]?(.*)['"]?\)"""
|
|
321
|
+
)
|
|
322
|
+
start_flow_re = re.compile(r"StartFlow\(['\"]?([a-zA-Z0-9_-]+)['\"]?\)")
|
|
292
323
|
cancel_flow_re = re.compile(r"CancelFlow\(\)")
|
|
293
324
|
chitchat_re = re.compile(r"ChitChat\(\)")
|
|
294
325
|
skip_question_re = re.compile(r"SkipQuestion\(\)")
|
|
295
326
|
knowledge_re = re.compile(r"SearchAndReply\(\)")
|
|
296
327
|
humand_handoff_re = re.compile(r"HumanHandoff\(\)")
|
|
297
|
-
clarify_re = re.compile(r"Clarify\(([a-zA-Z0-9_, ]+)\)")
|
|
328
|
+
clarify_re = re.compile(r"Clarify\(([\"\'a-zA-Z0-9_, ]+)\)")
|
|
298
329
|
repeat_re = re.compile(r"RepeatLastBotMessages\(\)")
|
|
299
330
|
|
|
300
331
|
for action in actions.strip().splitlines():
|
|
@@ -326,19 +357,36 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
326
357
|
commands.append(RepeatBotMessagesCommand())
|
|
327
358
|
elif match := clarify_re.search(action):
|
|
328
359
|
options = sorted([opt.strip() for opt in match.group(1).split(",")])
|
|
360
|
+
# Remove surrounding quotes if present
|
|
361
|
+
cleaned_options = []
|
|
362
|
+
for flow in options:
|
|
363
|
+
if (flow.startswith('"') and flow.endswith('"')) or (
|
|
364
|
+
flow.startswith("'") and flow.endswith("'")
|
|
365
|
+
):
|
|
366
|
+
cleaned_options.append(flow[1:-1])
|
|
367
|
+
else:
|
|
368
|
+
cleaned_options.append(flow)
|
|
369
|
+
# check if flow is valid
|
|
329
370
|
valid_options = [
|
|
330
|
-
flow for flow in
|
|
371
|
+
flow for flow in cleaned_options if flow in flows.user_flow_ids
|
|
331
372
|
]
|
|
332
373
|
if len(set(valid_options)) == 1:
|
|
333
374
|
commands.extend(cls.start_flow_by_name(valid_options[0], flows))
|
|
334
375
|
elif len(valid_options) > 1:
|
|
335
376
|
commands.append(ClarifyCommand(valid_options))
|
|
336
377
|
|
|
378
|
+
if not commands:
|
|
379
|
+
structlogger.debug(
|
|
380
|
+
"single_step_llm_command_generator.parse_commands",
|
|
381
|
+
message="No commands were parsed from the LLM actions.",
|
|
382
|
+
actions=actions,
|
|
383
|
+
)
|
|
384
|
+
|
|
337
385
|
return commands
|
|
338
386
|
|
|
339
387
|
@classmethod
|
|
340
388
|
def fingerprint_addon(cls: Any, config: Dict[str, Any]) -> Optional[str]:
|
|
341
|
-
"""Add a fingerprint
|
|
389
|
+
"""Add a fingerprint for the graph."""
|
|
342
390
|
config_prompt = (
|
|
343
391
|
config.get(PROMPT_CONFIG_KEY)
|
|
344
392
|
or config.get(PROMPT_TEMPLATE_CONFIG_KEY)
|
|
@@ -348,7 +396,16 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
348
396
|
config_prompt,
|
|
349
397
|
DEFAULT_COMMAND_PROMPT_TEMPLATE,
|
|
350
398
|
)
|
|
351
|
-
|
|
399
|
+
llm_config = resolve_model_client_config(
|
|
400
|
+
config.get(LLM_CONFIG_KEY), SingleStepLLMCommandGenerator.__name__
|
|
401
|
+
)
|
|
402
|
+
embedding_config = resolve_model_client_config(
|
|
403
|
+
config.get(FLOW_RETRIEVAL_KEY, {}).get(EMBEDDINGS_CONFIG_KEY),
|
|
404
|
+
FlowRetrieval.__name__,
|
|
405
|
+
)
|
|
406
|
+
return deep_container_fingerprint(
|
|
407
|
+
[prompt_template, llm_config, embedding_config]
|
|
408
|
+
)
|
|
352
409
|
|
|
353
410
|
### Helper methods
|
|
354
411
|
def render_template(
|
|
@@ -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
|
|
|
@@ -251,3 +261,32 @@ flows:
|
|
|
251
261
|
name: pattern skip question
|
|
252
262
|
steps:
|
|
253
263
|
- action: utter_skip_question_answer
|
|
264
|
+
|
|
265
|
+
pattern_user_silence:
|
|
266
|
+
description: Reacting to user silence in voice bots
|
|
267
|
+
name: pattern react to silence
|
|
268
|
+
nlu_trigger:
|
|
269
|
+
- intent: silence_timeout
|
|
270
|
+
persisted_slots:
|
|
271
|
+
- consecutive_silence_timeouts
|
|
272
|
+
steps:
|
|
273
|
+
- noop: true
|
|
274
|
+
next:
|
|
275
|
+
- if: "slots.consecutive_silence_timeouts = 0.0"
|
|
276
|
+
then:
|
|
277
|
+
- set_slots:
|
|
278
|
+
- consecutive_silence_timeouts: 1.0
|
|
279
|
+
- action: action_repeat_bot_messages
|
|
280
|
+
next: END
|
|
281
|
+
- if: "slots.consecutive_silence_timeouts = 1.0"
|
|
282
|
+
then:
|
|
283
|
+
- set_slots:
|
|
284
|
+
- consecutive_silence_timeouts: 2.0
|
|
285
|
+
- action: utter_ask_still_there
|
|
286
|
+
next: END
|
|
287
|
+
- if: "slots.consecutive_silence_timeouts > 1.0"
|
|
288
|
+
then:
|
|
289
|
+
- action: utter_inform_hangup
|
|
290
|
+
- action: action_hangup
|
|
291
|
+
next: END
|
|
292
|
+
- else: END
|
|
@@ -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
|
+
)
|
rasa/e2e_test/e2e_test_runner.py
CHANGED
|
@@ -190,11 +190,11 @@ class E2ETestRunner:
|
|
|
190
190
|
error=f"Message handling timed out for user message '{step.text}'.",
|
|
191
191
|
exc_info=True,
|
|
192
192
|
)
|
|
193
|
-
except Exception:
|
|
193
|
+
except Exception as exc:
|
|
194
194
|
structlogger.error(
|
|
195
195
|
"e2e_test_runner.run_prediction_loop",
|
|
196
196
|
error=f"An exception occurred while handling "
|
|
197
|
-
f"user message '{step.text}'.",
|
|
197
|
+
f"user message '{step.text}'. Error: {exc}",
|
|
198
198
|
)
|
|
199
199
|
tracker = await self.agent.tracker_store.retrieve(sender_id) # type: ignore[assignment]
|
|
200
200
|
turns[position], event_cursor = self.get_actual_step_output(
|
|
@@ -1155,6 +1155,8 @@ class E2ETestRunner:
|
|
|
1155
1155
|
flow_paths_stack
|
|
1156
1156
|
and self.agent.domain
|
|
1157
1157
|
and self.agent.domain.is_custom_action(event.action_name)
|
|
1158
|
+
and STEP_ID_METADATA_KEY in event.metadata
|
|
1159
|
+
and ACTIVE_FLOW_METADATA_KEY in event.metadata
|
|
1158
1160
|
):
|
|
1159
1161
|
flow_paths_stack[-1].nodes.append(self._create_path_node(event))
|
|
1160
1162
|
|
rasa/e2e_test/utils/io.py
CHANGED
|
@@ -346,7 +346,7 @@ def read_test_cases(path: str) -> TestSuite:
|
|
|
346
346
|
beta_flag_verified = False
|
|
347
347
|
|
|
348
348
|
for test_file in test_files:
|
|
349
|
-
test_file_content = parse_raw_yaml(Path(test_file).read_text())
|
|
349
|
+
test_file_content = parse_raw_yaml(Path(test_file).read_text(encoding="utf-8"))
|
|
350
350
|
|
|
351
351
|
validate_yaml_data_using_schema_with_assertions(
|
|
352
352
|
yaml_data=test_file_content, schema_content=e2e_test_schema
|