rasa-pro 3.11.0__py3-none-any.whl → 3.11.0a2__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 +396 -17
- rasa/__main__.py +15 -31
- rasa/api.py +1 -5
- rasa/cli/arguments/default_arguments.py +2 -1
- rasa/cli/arguments/shell.py +1 -5
- rasa/cli/arguments/train.py +0 -14
- rasa/cli/e2e_test.py +1 -1
- rasa/cli/evaluate.py +8 -8
- rasa/cli/inspect.py +5 -7
- rasa/cli/interactive.py +0 -1
- rasa/cli/llm_fine_tuning.py +1 -1
- rasa/cli/project_templates/calm/config.yml +7 -5
- rasa/cli/project_templates/calm/endpoints.yml +2 -15
- rasa/cli/project_templates/tutorial/config.yml +5 -8
- rasa/cli/project_templates/tutorial/data/flows.yml +1 -1
- rasa/cli/project_templates/tutorial/data/patterns.yml +0 -5
- rasa/cli/project_templates/tutorial/domain.yml +0 -14
- rasa/cli/project_templates/tutorial/endpoints.yml +0 -5
- rasa/cli/run.py +1 -1
- rasa/cli/scaffold.py +2 -4
- rasa/cli/studio/studio.py +8 -18
- rasa/cli/studio/upload.py +15 -0
- rasa/cli/train.py +0 -3
- rasa/cli/utils.py +1 -6
- rasa/cli/x.py +8 -8
- rasa/constants.py +1 -3
- rasa/core/actions/action.py +33 -75
- rasa/core/actions/e2e_stub_custom_action_executor.py +1 -5
- rasa/core/actions/http_custom_action_executor.py +0 -4
- rasa/core/channels/channel.py +0 -20
- rasa/core/channels/development_inspector.py +2 -8
- rasa/core/channels/inspector/dist/assets/{arc-bc141fb2.js → arc-6852c607.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-d0fbc5ce-be2db283.js → c4Diagram-d0fbc5ce-acc952b2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-936ed81e-55366915.js → classDiagram-936ed81e-848a7597.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-c3cb15f1-bb529518.js → classDiagram-v2-c3cb15f1-a73d3e68.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{createText-62fc7601-b0ec81d6.js → createText-62fc7601-e5ee049d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-f2ad444c-6166330c.js → edges-f2ad444c-771e517e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-5ccc6a8e.js → erDiagram-9d236eb7-aa347178.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-1972c806-fca3bfe4.js → flowDb-1972c806-651fc57d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-7ea5b25a-4739080f.js → flowDiagram-7ea5b25a-ca67804f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-587d82d8.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-abe16c3d-7c1b0e0f.js → flowchart-elk-definition-abe16c3d-2dbc568d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-9b5ea136-772fd050.js → ganttDiagram-9b5ea136-25a65bd8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-99d0ae7c-8eae1dc9.js → gitGraphDiagram-99d0ae7c-fdc7378d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-2c4b9a3b-f55afcdf.js → index-2c4b9a3b-6f1fd606.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-e7cef9de.js → index-efdd30c1.js} +68 -68
- rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-124d4a14.js → infoDiagram-736b4530-cb1a041a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-7c4fae44.js → journeyDiagram-df861f2b-14609879.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-b9885fb6.js → layout-2490f52b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-7c59abb6.js → line-40186f1f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-4776f780.js → linear-08814e93.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-beec6740-2332c46c.js → mindmap-definition-beec6740-1a534584.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-8fb39303.js → pieDiagram-dbbf0591-72397b61.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-3c7180a2.js → quadrantDiagram-4d7f4fd6-3bb0b6a3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-e910bcb8.js → requirementDiagram-6fc4c22a-57334f61.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-8f13d901-ead16c89.js → sankeyDiagram-8f13d901-111e1297.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-b655622a-29a02a19.js → sequenceDiagram-b655622a-10bcfe62.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-59f0c015-042b3137.js → stateDiagram-59f0c015-acaf7513.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-2b26beab-2178c0f3.js → stateDiagram-v2-2b26beab-3ec2a235.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-080da4f6-23ffa4fc.js → styles-080da4f6-62730289.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-3dcbcfbf-94f59763.js → styles-3dcbcfbf-5284ee76.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9c745c82-78a6bebc.js → styles-9c745c82-642435e3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-4835440b-eae2a6f6.js → svgDrawCommon-4835440b-b250a350.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-5c968d92.js → timeline-definition-5b62e21b-c2b147ed.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-fd3db0d5.js → xychartDiagram-2b33534f-f92cfea9.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 +16 -77
- rasa/core/channels/socketio.py +2 -7
- rasa/core/channels/telegram.py +1 -1
- rasa/core/channels/twilio.py +1 -1
- rasa/core/channels/voice_ready/audiocodes.py +4 -15
- rasa/core/channels/voice_ready/jambonz.py +4 -15
- rasa/core/channels/voice_ready/twilio_voice.py +21 -6
- rasa/core/channels/voice_ready/utils.py +5 -6
- rasa/core/channels/voice_stream/asr/asr_engine.py +1 -19
- rasa/core/channels/voice_stream/asr/asr_event.py +0 -5
- rasa/core/channels/voice_stream/asr/deepgram.py +15 -28
- rasa/core/channels/voice_stream/audio_bytes.py +0 -1
- rasa/core/channels/voice_stream/browser_audio.py +9 -32
- rasa/core/channels/voice_stream/tts/azure.py +3 -9
- rasa/core/channels/voice_stream/tts/cartesia.py +8 -12
- rasa/core/channels/voice_stream/tts/tts_engine.py +1 -11
- rasa/core/channels/voice_stream/twilio_media_streams.py +19 -28
- rasa/core/channels/voice_stream/util.py +4 -4
- rasa/core/channels/voice_stream/voice_channel.py +42 -222
- rasa/core/featurizers/single_state_featurizer.py +1 -22
- rasa/core/featurizers/tracker_featurizers.py +18 -115
- rasa/core/information_retrieval/qdrant.py +0 -1
- rasa/core/nlg/contextual_response_rephraser.py +25 -44
- rasa/core/persistor.py +34 -191
- rasa/core/policies/enterprise_search_policy.py +60 -119
- rasa/core/policies/flows/flow_executor.py +4 -7
- rasa/core/policies/intentless_policy.py +22 -82
- rasa/core/policies/ted_policy.py +33 -58
- rasa/core/policies/unexpected_intent_policy.py +7 -15
- rasa/core/processor.py +5 -32
- rasa/core/training/interactive.py +35 -34
- rasa/core/utils.py +22 -58
- rasa/dialogue_understanding/coexistence/llm_based_router.py +12 -39
- rasa/dialogue_understanding/commands/__init__.py +0 -4
- rasa/dialogue_understanding/commands/change_flow_command.py +0 -6
- rasa/dialogue_understanding/commands/utils.py +0 -5
- rasa/dialogue_understanding/generator/constants.py +0 -2
- rasa/dialogue_understanding/generator/flow_retrieval.py +4 -49
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +23 -37
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +10 -57
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +1 -19
- rasa/dialogue_understanding/generator/single_step/command_prompt_template.jinja2 +0 -3
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +10 -90
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +0 -53
- rasa/dialogue_understanding/processor/command_processor.py +1 -21
- rasa/e2e_test/assertions.py +16 -133
- rasa/e2e_test/assertions_schema.yml +0 -23
- rasa/e2e_test/e2e_test_case.py +6 -85
- rasa/e2e_test/e2e_test_runner.py +4 -6
- rasa/e2e_test/utils/io.py +1 -3
- rasa/engine/loader.py +0 -12
- rasa/engine/validation.py +11 -541
- rasa/keys +1 -0
- rasa/llm_fine_tuning/notebooks/unsloth_finetuning.ipynb +407 -0
- rasa/model_training.py +7 -29
- rasa/nlu/classifiers/diet_classifier.py +25 -38
- 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 +50 -93
- rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +16 -45
- rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +17 -52
- rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +3 -5
- rasa/nlu/tokenizers/whitespace_tokenizer.py +14 -3
- rasa/server.py +1 -3
- rasa/shared/constants.py +0 -61
- rasa/shared/core/constants.py +0 -9
- rasa/shared/core/domain.py +5 -8
- rasa/shared/core/flows/flow.py +0 -5
- rasa/shared/core/flows/flows_list.py +1 -5
- rasa/shared/core/flows/flows_yaml_schema.json +0 -10
- rasa/shared/core/flows/validation.py +0 -96
- rasa/shared/core/flows/yaml_flows_io.py +4 -13
- rasa/shared/core/slots.py +0 -5
- rasa/shared/importers/importer.py +2 -19
- rasa/shared/importers/rasa.py +1 -5
- rasa/shared/nlu/training_data/features.py +2 -120
- rasa/shared/nlu/training_data/formats/rasa_yaml.py +3 -18
- rasa/shared/providers/_configs/azure_openai_client_config.py +3 -5
- rasa/shared/providers/_configs/openai_client_config.py +1 -1
- rasa/shared/providers/_configs/self_hosted_llm_client_config.py +0 -1
- rasa/shared/providers/_configs/utils.py +0 -16
- rasa/shared/providers/embedding/_base_litellm_embedding_client.py +29 -18
- rasa/shared/providers/embedding/azure_openai_embedding_client.py +21 -54
- rasa/shared/providers/embedding/default_litellm_embedding_client.py +0 -24
- rasa/shared/providers/llm/_base_litellm_client.py +31 -63
- rasa/shared/providers/llm/azure_openai_llm_client.py +29 -50
- rasa/shared/providers/llm/default_litellm_llm_client.py +0 -24
- rasa/shared/providers/llm/self_hosted_llm_client.py +29 -17
- rasa/shared/providers/mappings.py +0 -19
- rasa/shared/utils/common.py +2 -37
- rasa/shared/utils/io.py +6 -28
- rasa/shared/utils/llm.py +46 -353
- rasa/shared/utils/yaml.py +82 -181
- rasa/studio/auth.py +5 -3
- rasa/studio/config.py +4 -13
- rasa/studio/constants.py +0 -1
- rasa/studio/data_handler.py +4 -13
- rasa/studio/upload.py +80 -175
- rasa/telemetry.py +17 -94
- rasa/tracing/config.py +1 -3
- rasa/tracing/instrumentation/attribute_extractors.py +17 -94
- rasa/tracing/instrumentation/instrumentation.py +0 -121
- rasa/utils/common.py +0 -5
- rasa/utils/endpoints.py +1 -27
- rasa/utils/io.py +81 -7
- rasa/utils/log_utils.py +2 -9
- rasa/utils/tensorflow/model_data.py +193 -2
- rasa/validator.py +4 -110
- rasa/version.py +1 -1
- rasa_pro-3.11.0a2.dist-info/METADATA +576 -0
- {rasa_pro-3.11.0.dist-info → rasa_pro-3.11.0a2.dist-info}/RECORD +181 -213
- rasa/core/actions/action_repeat_bot_messages.py +0 -89
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-736177bf.js +0 -1
- rasa/core/channels/voice_stream/asr/azure.py +0 -129
- rasa/core/channels/voice_stream/call_state.py +0 -23
- rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +0 -60
- rasa/dialogue_understanding/commands/user_silence_command.py +0 -59
- rasa/dialogue_understanding/patterns/repeat.py +0 -37
- rasa/dialogue_understanding/patterns/user_silence.py +0 -37
- rasa/model_manager/__init__.py +0 -0
- rasa/model_manager/config.py +0 -40
- rasa/model_manager/model_api.py +0 -559
- rasa/model_manager/runner_service.py +0 -286
- rasa/model_manager/socket_bridge.py +0 -146
- rasa/model_manager/studio_jwt_auth.py +0 -86
- rasa/model_manager/trainer_service.py +0 -325
- rasa/model_manager/utils.py +0 -87
- rasa/model_manager/warm_rasa_process.py +0 -187
- rasa/model_service.py +0 -112
- rasa/shared/core/flows/utils.py +0 -39
- rasa/shared/providers/_configs/litellm_router_client_config.py +0 -220
- rasa/shared/providers/_configs/model_group_config.py +0 -167
- rasa/shared/providers/_configs/rasa_llm_client_config.py +0 -73
- rasa/shared/providers/_utils.py +0 -79
- rasa/shared/providers/embedding/litellm_router_embedding_client.py +0 -135
- rasa/shared/providers/llm/litellm_router_llm_client.py +0 -182
- rasa/shared/providers/llm/rasa_llm_client.py +0 -112
- rasa/shared/providers/router/__init__.py +0 -0
- rasa/shared/providers/router/_base_litellm_router_client.py +0 -183
- rasa/shared/providers/router/router_client.py +0 -73
- rasa/shared/utils/health_check/__init__.py +0 -0
- rasa/shared/utils/health_check/embeddings_health_check_mixin.py +0 -31
- rasa/shared/utils/health_check/health_check.py +0 -258
- rasa/shared/utils/health_check/llm_health_check_mixin.py +0 -31
- rasa/utils/sanic_error_handler.py +0 -32
- rasa/utils/tensorflow/feature_array.py +0 -366
- rasa_pro-3.11.0.dist-info/METADATA +0 -198
- {rasa_pro-3.11.0.dist-info → rasa_pro-3.11.0a2.dist-info}/NOTICE +0 -0
- {rasa_pro-3.11.0.dist-info → rasa_pro-3.11.0a2.dist-info}/WHEEL +0 -0
- {rasa_pro-3.11.0.dist-info → rasa_pro-3.11.0a2.dist-info}/entry_points.txt +0 -0
|
@@ -16,13 +16,11 @@ from rasa.dialogue_understanding.commands import (
|
|
|
16
16
|
KnowledgeAnswerCommand,
|
|
17
17
|
ClarifyCommand,
|
|
18
18
|
CannotHandleCommand,
|
|
19
|
-
RepeatBotMessagesCommand,
|
|
20
19
|
)
|
|
21
20
|
from rasa.dialogue_understanding.generator.constants import (
|
|
22
21
|
LLM_CONFIG_KEY,
|
|
23
22
|
USER_INPUT_CONFIG_KEY,
|
|
24
23
|
FLOW_RETRIEVAL_KEY,
|
|
25
|
-
DEFAULT_LLM_CONFIG,
|
|
26
24
|
)
|
|
27
25
|
from rasa.dialogue_understanding.generator.flow_retrieval import (
|
|
28
26
|
FlowRetrieval,
|
|
@@ -39,7 +37,6 @@ from rasa.shared.constants import (
|
|
|
39
37
|
ROUTE_TO_CALM_SLOT,
|
|
40
38
|
PROMPT_CONFIG_KEY,
|
|
41
39
|
PROMPT_TEMPLATE_CONFIG_KEY,
|
|
42
|
-
EMBEDDINGS_CONFIG_KEY,
|
|
43
40
|
)
|
|
44
41
|
from rasa.shared.core.flows import FlowsList
|
|
45
42
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
@@ -51,9 +48,7 @@ from rasa.shared.utils.llm import (
|
|
|
51
48
|
get_prompt_template,
|
|
52
49
|
tracker_as_readable_transcript,
|
|
53
50
|
sanitize_message_for_prompt,
|
|
54
|
-
resolve_model_client_config,
|
|
55
51
|
)
|
|
56
|
-
from rasa.utils.beta import ensure_beta_feature_is_enabled, BetaNotEnabledException
|
|
57
52
|
from rasa.utils.log_utils import log_llm
|
|
58
53
|
|
|
59
54
|
COMMAND_PROMPT_FILE_NAME = "command_prompt.jinja2"
|
|
@@ -62,7 +57,6 @@ DEFAULT_COMMAND_PROMPT_TEMPLATE = importlib.resources.read_text(
|
|
|
62
57
|
"rasa.dialogue_understanding.generator.single_step",
|
|
63
58
|
"command_prompt_template.jinja2",
|
|
64
59
|
)
|
|
65
|
-
SINGLE_STEP_LLM_COMMAND_GENERATOR_CONFIG_FILE = "config.json"
|
|
66
60
|
|
|
67
61
|
structlogger = structlog.get_logger()
|
|
68
62
|
|
|
@@ -113,7 +107,6 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
113
107
|
)
|
|
114
108
|
|
|
115
109
|
self.trace_prompt_tokens = self.config.get("trace_prompt_tokens", False)
|
|
116
|
-
self.repeat_command_enabled = self.is_repeat_command_enabled()
|
|
117
110
|
|
|
118
111
|
### Implementations of LLMBasedCommandGenerator parent
|
|
119
112
|
@staticmethod
|
|
@@ -137,21 +130,10 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
137
130
|
**kwargs: Any,
|
|
138
131
|
) -> "SingleStepLLMCommandGenerator":
|
|
139
132
|
"""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
|
-
|
|
150
133
|
# load prompt template from the model storage.
|
|
151
134
|
prompt_template = cls.load_prompt_template_from_model_storage(
|
|
152
135
|
model_storage, resource, COMMAND_PROMPT_FILE_NAME
|
|
153
136
|
)
|
|
154
|
-
|
|
155
137
|
# init base command generator
|
|
156
138
|
command_generator = cls(config, model_storage, resource, prompt_template)
|
|
157
139
|
# load flow retrieval if enabled
|
|
@@ -159,29 +141,18 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
159
141
|
command_generator.flow_retrieval = cls.load_flow_retrival(
|
|
160
142
|
command_generator.config, model_storage, resource
|
|
161
143
|
)
|
|
162
|
-
|
|
163
144
|
return command_generator
|
|
164
145
|
|
|
165
146
|
def persist(self) -> None:
|
|
166
147
|
"""Persist this component to disk for future loading."""
|
|
167
|
-
|
|
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."""
|
|
148
|
+
# persist prompt template
|
|
174
149
|
with self._model_storage.write_to(self._resource) as path:
|
|
175
150
|
rasa.shared.utils.io.write_text_file(
|
|
176
151
|
self.prompt_template, path / COMMAND_PROMPT_FILE_NAME
|
|
177
152
|
)
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
)
|
|
153
|
+
# persist flow retrieval
|
|
154
|
+
if self.flow_retrieval is not None:
|
|
155
|
+
self.flow_retrieval.persist()
|
|
185
156
|
|
|
186
157
|
async def predict_commands(
|
|
187
158
|
self,
|
|
@@ -214,12 +185,6 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
214
185
|
|
|
215
186
|
if not commands:
|
|
216
187
|
# no commands are parsed or there's an invalid command
|
|
217
|
-
structlogger.warning(
|
|
218
|
-
"single_step_llm_command_generator.predict_commands",
|
|
219
|
-
message="No commands were predicted as the LLM response could "
|
|
220
|
-
"not be parsed or the LLM responded with an invalid command."
|
|
221
|
-
"Returning a CannotHandleCommand instead.",
|
|
222
|
-
)
|
|
223
188
|
commands = [CannotHandleCommand()]
|
|
224
189
|
|
|
225
190
|
if tracker.has_coexistence_routing_slot:
|
|
@@ -320,17 +285,14 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
320
285
|
|
|
321
286
|
commands: List[Command] = []
|
|
322
287
|
|
|
323
|
-
slot_set_re = re.compile(
|
|
324
|
-
|
|
325
|
-
)
|
|
326
|
-
start_flow_re = re.compile(r"StartFlow\(['\"]?([a-zA-Z0-9_-]+)['\"]?\)")
|
|
288
|
+
slot_set_re = re.compile(r"""SetSlot\(([a-zA-Z_][a-zA-Z0-9_-]*?), ?(.*)\)""")
|
|
289
|
+
start_flow_re = re.compile(r"StartFlow\(([a-zA-Z0-9_-]+?)\)")
|
|
327
290
|
cancel_flow_re = re.compile(r"CancelFlow\(\)")
|
|
328
291
|
chitchat_re = re.compile(r"ChitChat\(\)")
|
|
329
292
|
skip_question_re = re.compile(r"SkipQuestion\(\)")
|
|
330
293
|
knowledge_re = re.compile(r"SearchAndReply\(\)")
|
|
331
294
|
humand_handoff_re = re.compile(r"HumanHandoff\(\)")
|
|
332
|
-
clarify_re = re.compile(r"Clarify\(([
|
|
333
|
-
repeat_re = re.compile(r"RepeatLastBotMessages\(\)")
|
|
295
|
+
clarify_re = re.compile(r"Clarify\(([a-zA-Z0-9_, ]+)\)")
|
|
334
296
|
|
|
335
297
|
for action in actions.strip().splitlines():
|
|
336
298
|
if match := slot_set_re.search(action):
|
|
@@ -357,40 +319,21 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
357
319
|
commands.append(KnowledgeAnswerCommand())
|
|
358
320
|
elif humand_handoff_re.search(action):
|
|
359
321
|
commands.append(HumanHandoffCommand())
|
|
360
|
-
elif repeat_re.search(action):
|
|
361
|
-
commands.append(RepeatBotMessagesCommand())
|
|
362
322
|
elif match := clarify_re.search(action):
|
|
363
323
|
options = sorted([opt.strip() for opt in match.group(1).split(",")])
|
|
364
|
-
# Remove surrounding quotes if present
|
|
365
|
-
cleaned_options = []
|
|
366
|
-
for flow in options:
|
|
367
|
-
if (flow.startswith('"') and flow.endswith('"')) or (
|
|
368
|
-
flow.startswith("'") and flow.endswith("'")
|
|
369
|
-
):
|
|
370
|
-
cleaned_options.append(flow[1:-1])
|
|
371
|
-
else:
|
|
372
|
-
cleaned_options.append(flow)
|
|
373
|
-
# check if flow is valid
|
|
374
324
|
valid_options = [
|
|
375
|
-
flow for flow in
|
|
325
|
+
flow for flow in options if flow in flows.user_flow_ids
|
|
376
326
|
]
|
|
377
327
|
if len(set(valid_options)) == 1:
|
|
378
328
|
commands.extend(cls.start_flow_by_name(valid_options[0], flows))
|
|
379
329
|
elif len(valid_options) > 1:
|
|
380
330
|
commands.append(ClarifyCommand(valid_options))
|
|
381
331
|
|
|
382
|
-
if not commands:
|
|
383
|
-
structlogger.debug(
|
|
384
|
-
"single_step_llm_command_generator.parse_commands",
|
|
385
|
-
message="No commands were parsed from the LLM actions.",
|
|
386
|
-
actions=actions,
|
|
387
|
-
)
|
|
388
|
-
|
|
389
332
|
return commands
|
|
390
333
|
|
|
391
334
|
@classmethod
|
|
392
335
|
def fingerprint_addon(cls: Any, config: Dict[str, Any]) -> Optional[str]:
|
|
393
|
-
"""Add a fingerprint for the graph."""
|
|
336
|
+
"""Add a fingerprint of the knowledge base for the graph."""
|
|
394
337
|
config_prompt = (
|
|
395
338
|
config.get(PROMPT_CONFIG_KEY)
|
|
396
339
|
or config.get(PROMPT_TEMPLATE_CONFIG_KEY)
|
|
@@ -400,16 +343,7 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
400
343
|
config_prompt,
|
|
401
344
|
DEFAULT_COMMAND_PROMPT_TEMPLATE,
|
|
402
345
|
)
|
|
403
|
-
|
|
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
|
-
)
|
|
346
|
+
return deep_container_fingerprint(prompt_template)
|
|
413
347
|
|
|
414
348
|
### Helper methods
|
|
415
349
|
def render_template(
|
|
@@ -459,20 +393,6 @@ class SingleStepLLMCommandGenerator(LLMBasedCommandGenerator):
|
|
|
459
393
|
"current_slot": current_slot,
|
|
460
394
|
"current_slot_description": current_slot_description,
|
|
461
395
|
"user_message": latest_user_message,
|
|
462
|
-
"is_repeat_command_enabled": self.repeat_command_enabled,
|
|
463
396
|
}
|
|
464
397
|
|
|
465
398
|
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,11 +4,6 @@ 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
|
-
|
|
12
7
|
utter_boolean_slot_rejection:
|
|
13
8
|
- text: "Sorry, the value you provided, `{{value}}`, is not valid. Please respond with a valid value."
|
|
14
9
|
metadata:
|
|
@@ -80,11 +75,6 @@ responses:
|
|
|
80
75
|
metadata:
|
|
81
76
|
rephrase: True
|
|
82
77
|
|
|
83
|
-
utter_inform_hangup:
|
|
84
|
-
- text: It seems you are not there anymore. I will hang up shortly.
|
|
85
|
-
metadata:
|
|
86
|
-
rephrase: True
|
|
87
|
-
|
|
88
78
|
utter_internal_error_rasa:
|
|
89
79
|
- text: Sorry, I am having trouble with that. Please try again in a few minutes.
|
|
90
80
|
|
|
@@ -111,15 +101,6 @@ slots:
|
|
|
111
101
|
type: bool
|
|
112
102
|
mappings:
|
|
113
103
|
- 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
|
-
|
|
123
104
|
|
|
124
105
|
flows:
|
|
125
106
|
pattern_cancel_flow:
|
|
@@ -236,11 +217,6 @@ flows:
|
|
|
236
217
|
- action: utter_internal_error_rasa
|
|
237
218
|
next: END
|
|
238
219
|
|
|
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
|
|
244
220
|
|
|
245
221
|
pattern_restart:
|
|
246
222
|
description: Flow for restarting the conversation
|
|
@@ -270,32 +246,3 @@ flows:
|
|
|
270
246
|
name: pattern skip question
|
|
271
247
|
steps:
|
|
272
248
|
- 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
|
|
@@ -8,7 +8,6 @@ from rasa.dialogue_understanding.commands import (
|
|
|
8
8
|
Command,
|
|
9
9
|
CorrectSlotsCommand,
|
|
10
10
|
CorrectedSlot,
|
|
11
|
-
RepeatBotMessagesCommand,
|
|
12
11
|
SetSlotCommand,
|
|
13
12
|
StartFlowCommand,
|
|
14
13
|
FreeFormAnswerCommand,
|
|
@@ -423,9 +422,6 @@ def clean_up_commands(
|
|
|
423
422
|
elif not tracker.has_coexistence_routing_slot and len(clean_commands) > 1:
|
|
424
423
|
clean_commands = filter_cannot_handle_command_for_skipped_slots(clean_commands)
|
|
425
424
|
|
|
426
|
-
clean_commands = ensure_max_number_of_command_type(
|
|
427
|
-
clean_commands, RepeatBotMessagesCommand, 1
|
|
428
|
-
)
|
|
429
425
|
structlogger.debug(
|
|
430
426
|
"command_processor.clean_up_commands.final_commands",
|
|
431
427
|
command=clean_commands,
|
|
@@ -434,22 +430,6 @@ def clean_up_commands(
|
|
|
434
430
|
return clean_commands
|
|
435
431
|
|
|
436
432
|
|
|
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
|
-
|
|
453
433
|
def clean_up_clarify_command(
|
|
454
434
|
commands_so_far: List[Command],
|
|
455
435
|
all_commands: List[Command],
|
|
@@ -472,7 +452,7 @@ def clean_up_clarify_command(
|
|
|
472
452
|
if not (isinstance(c, SetSlotCommand) and c.name == ROUTE_TO_CALM_SLOT)
|
|
473
453
|
]
|
|
474
454
|
|
|
475
|
-
# if
|
|
455
|
+
# if there are multiple clarify commands, do add the first one
|
|
476
456
|
if all(
|
|
477
457
|
isinstance(c, ClarifyCommand) for c in commands_without_route_to_calm_set_slot
|
|
478
458
|
):
|
rasa/e2e_test/assertions.py
CHANGED
|
@@ -71,7 +71,6 @@ class AssertionType(Enum):
|
|
|
71
71
|
SLOT_WAS_SET = "slot_was_set"
|
|
72
72
|
SLOT_WAS_NOT_SET = "slot_was_not_set"
|
|
73
73
|
BOT_UTTERED = "bot_uttered"
|
|
74
|
-
BOT_DID_NOT_UTTER = "bot_did_not_utter"
|
|
75
74
|
GENERATIVE_RESPONSE_IS_RELEVANT = "generative_response_is_relevant"
|
|
76
75
|
GENERATIVE_RESPONSE_IS_GROUNDED = "generative_response_is_grounded"
|
|
77
76
|
|
|
@@ -723,7 +722,6 @@ class BotUtteredAssertion(Assertion):
|
|
|
723
722
|
) -> Tuple[Optional[AssertionFailure], Optional[Event]]:
|
|
724
723
|
"""Run the bot_uttered assertion on the given events for that user turn."""
|
|
725
724
|
matching_event = None
|
|
726
|
-
error_messages = []
|
|
727
725
|
|
|
728
726
|
if self.utter_name is not None:
|
|
729
727
|
try:
|
|
@@ -734,8 +732,11 @@ class BotUtteredAssertion(Assertion):
|
|
|
734
732
|
and event.metadata.get("utter_action") == self.utter_name
|
|
735
733
|
)
|
|
736
734
|
except StopIteration:
|
|
737
|
-
|
|
738
|
-
|
|
735
|
+
error_message = f"Bot did not utter '{self.utter_name}' response."
|
|
736
|
+
error_message += assertion_order_error_message
|
|
737
|
+
|
|
738
|
+
return self._generate_assertion_failure(
|
|
739
|
+
error_message, prior_events, turn_events, self.line
|
|
739
740
|
)
|
|
740
741
|
|
|
741
742
|
if self.text_matches is not None:
|
|
@@ -747,11 +748,16 @@ class BotUtteredAssertion(Assertion):
|
|
|
747
748
|
if isinstance(event, BotUttered) and pattern.search(event.text)
|
|
748
749
|
)
|
|
749
750
|
except StopIteration:
|
|
750
|
-
|
|
751
|
+
error_message = (
|
|
751
752
|
f"Bot did not utter any response which "
|
|
752
753
|
f"matches the provided text pattern "
|
|
753
754
|
f"'{self.text_matches}'."
|
|
754
755
|
)
|
|
756
|
+
error_message += assertion_order_error_message
|
|
757
|
+
|
|
758
|
+
return self._generate_assertion_failure(
|
|
759
|
+
error_message, prior_events, turn_events, self.line
|
|
760
|
+
)
|
|
755
761
|
|
|
756
762
|
if self.buttons:
|
|
757
763
|
try:
|
|
@@ -761,16 +767,13 @@ class BotUtteredAssertion(Assertion):
|
|
|
761
767
|
if isinstance(event, BotUttered) and self._buttons_match(event)
|
|
762
768
|
)
|
|
763
769
|
except StopIteration:
|
|
764
|
-
|
|
770
|
+
error_message = (
|
|
765
771
|
"Bot did not utter any response with the expected buttons."
|
|
766
772
|
)
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
return self._generate_assertion_failure(
|
|
772
|
-
error_message, prior_events, turn_events, self.line
|
|
773
|
-
)
|
|
773
|
+
error_message += assertion_order_error_message
|
|
774
|
+
return self._generate_assertion_failure(
|
|
775
|
+
error_message, prior_events, turn_events, self.line
|
|
776
|
+
)
|
|
774
777
|
|
|
775
778
|
return None, matching_event
|
|
776
779
|
|
|
@@ -800,126 +803,6 @@ class BotUtteredAssertion(Assertion):
|
|
|
800
803
|
return hash(json.dumps(self.as_dict()))
|
|
801
804
|
|
|
802
805
|
|
|
803
|
-
@dataclass
|
|
804
|
-
class BotDidNotUtterAssertion(Assertion):
|
|
805
|
-
"""Class for the 'bot_did_not_utter' assertion."""
|
|
806
|
-
|
|
807
|
-
utter_name: Optional[str] = None
|
|
808
|
-
text_matches: Optional[str] = None
|
|
809
|
-
buttons: Optional[List[AssertedButton]] = None
|
|
810
|
-
line: Optional[int] = None
|
|
811
|
-
|
|
812
|
-
@classmethod
|
|
813
|
-
def type(cls) -> str:
|
|
814
|
-
return AssertionType.BOT_DID_NOT_UTTER.value
|
|
815
|
-
|
|
816
|
-
@staticmethod
|
|
817
|
-
def from_dict(assertion_dict: Dict[Text, Any]) -> BotDidNotUtterAssertion:
|
|
818
|
-
"""Creates a BotDidNotUtterAssertion from a dictionary."""
|
|
819
|
-
assertion_dict = assertion_dict.get(AssertionType.BOT_DID_NOT_UTTER.value, {})
|
|
820
|
-
utter_name = assertion_dict.get("utter_name")
|
|
821
|
-
text_matches = assertion_dict.get("text_matches")
|
|
822
|
-
buttons = [
|
|
823
|
-
AssertedButton.from_dict(button)
|
|
824
|
-
for button in assertion_dict.get("buttons", [])
|
|
825
|
-
]
|
|
826
|
-
|
|
827
|
-
if not utter_name and not text_matches and not buttons:
|
|
828
|
-
raise RasaException(
|
|
829
|
-
"A 'bot_did_not_utter' assertion is empty. "
|
|
830
|
-
"It should contain at least one of the allowed properties: "
|
|
831
|
-
"'utter_name', 'text_matches', or 'buttons'."
|
|
832
|
-
)
|
|
833
|
-
|
|
834
|
-
return BotDidNotUtterAssertion(
|
|
835
|
-
utter_name=utter_name,
|
|
836
|
-
text_matches=text_matches,
|
|
837
|
-
buttons=buttons,
|
|
838
|
-
line=assertion_dict.lc.line + 1 if hasattr(assertion_dict, "lc") else None,
|
|
839
|
-
)
|
|
840
|
-
|
|
841
|
-
def run(
|
|
842
|
-
self,
|
|
843
|
-
turn_events: List[Event],
|
|
844
|
-
prior_events: List[Event],
|
|
845
|
-
assertion_order_error_message: str = "",
|
|
846
|
-
**kwargs: Any,
|
|
847
|
-
) -> Tuple[Optional[AssertionFailure], Optional[Event]]:
|
|
848
|
-
"""Checks that the bot did not utter the specified messages or buttons."""
|
|
849
|
-
for event in turn_events:
|
|
850
|
-
if isinstance(event, BotUttered):
|
|
851
|
-
error_messages = []
|
|
852
|
-
if self._utter_name_matches(event):
|
|
853
|
-
error_messages.append(
|
|
854
|
-
f"Bot uttered a forbidden utterance '{self.utter_name}'."
|
|
855
|
-
)
|
|
856
|
-
if self._text_matches(event):
|
|
857
|
-
error_messages.append(
|
|
858
|
-
f"Bot uttered a forbidden message matching "
|
|
859
|
-
f"the pattern '{self.text_matches}'."
|
|
860
|
-
)
|
|
861
|
-
if self._buttons_match(event):
|
|
862
|
-
error_messages.append(
|
|
863
|
-
"Bot uttered a forbidden response with specified buttons."
|
|
864
|
-
)
|
|
865
|
-
|
|
866
|
-
if error_messages:
|
|
867
|
-
error_message = " ".join(error_messages)
|
|
868
|
-
error_message += assertion_order_error_message
|
|
869
|
-
return self._generate_assertion_failure(
|
|
870
|
-
error_message, prior_events, turn_events, self.line
|
|
871
|
-
)
|
|
872
|
-
return None, None
|
|
873
|
-
|
|
874
|
-
def _utter_name_matches(self, event: BotUttered) -> bool:
|
|
875
|
-
if self.utter_name is not None:
|
|
876
|
-
if event.metadata.get("utter_action") == self.utter_name:
|
|
877
|
-
return True
|
|
878
|
-
return False
|
|
879
|
-
|
|
880
|
-
def _text_matches(self, event: BotUttered) -> bool:
|
|
881
|
-
if self.text_matches is not None:
|
|
882
|
-
pattern = re.compile(self.text_matches)
|
|
883
|
-
if pattern.search(event.text):
|
|
884
|
-
return True
|
|
885
|
-
return False
|
|
886
|
-
|
|
887
|
-
def _buttons_match(self, event: BotUttered) -> bool:
|
|
888
|
-
"""Check if the bot response contains any of the forbidden buttons."""
|
|
889
|
-
if self.buttons is None:
|
|
890
|
-
return False
|
|
891
|
-
|
|
892
|
-
actual_buttons = event.data.get("buttons", [])
|
|
893
|
-
if not actual_buttons:
|
|
894
|
-
return False
|
|
895
|
-
|
|
896
|
-
for actual_button in actual_buttons:
|
|
897
|
-
if any(
|
|
898
|
-
self._is_forbidden_button(actual_button, forbidden_button)
|
|
899
|
-
for forbidden_button in self.buttons
|
|
900
|
-
):
|
|
901
|
-
return True
|
|
902
|
-
return False
|
|
903
|
-
|
|
904
|
-
@staticmethod
|
|
905
|
-
def _is_forbidden_button(
|
|
906
|
-
actual_button: Dict[str, Any], forbidden_button: AssertedButton
|
|
907
|
-
) -> bool:
|
|
908
|
-
"""Check if the button matches any of the forbidden buttons."""
|
|
909
|
-
actual_title = actual_button.get("title")
|
|
910
|
-
actual_payload = actual_button.get("payload")
|
|
911
|
-
|
|
912
|
-
title_matches = forbidden_button.title == actual_title
|
|
913
|
-
payload_matches = forbidden_button.payload == actual_payload
|
|
914
|
-
if title_matches and payload_matches:
|
|
915
|
-
return True
|
|
916
|
-
return False
|
|
917
|
-
|
|
918
|
-
def __hash__(self) -> int:
|
|
919
|
-
"""Hash method to ensure the assertion is hashable."""
|
|
920
|
-
return hash(json.dumps(self.as_dict()))
|
|
921
|
-
|
|
922
|
-
|
|
923
806
|
@dataclass
|
|
924
807
|
class GenerativeResponseMixin(Assertion):
|
|
925
808
|
"""Mixin class for storing generative response assertions."""
|
|
@@ -83,29 +83,6 @@ schema;assertions:
|
|
|
83
83
|
text_matches:
|
|
84
84
|
type: str
|
|
85
85
|
nullable: false
|
|
86
|
-
bot_did_not_utter:
|
|
87
|
-
type: map
|
|
88
|
-
nullable: false
|
|
89
|
-
mapping:
|
|
90
|
-
utter_name:
|
|
91
|
-
type: str
|
|
92
|
-
nullable: false
|
|
93
|
-
buttons:
|
|
94
|
-
type: seq
|
|
95
|
-
nullable: false
|
|
96
|
-
matching: "all"
|
|
97
|
-
sequence:
|
|
98
|
-
- type: map
|
|
99
|
-
mapping:
|
|
100
|
-
title:
|
|
101
|
-
type: str
|
|
102
|
-
nullable: false
|
|
103
|
-
payload:
|
|
104
|
-
type: str
|
|
105
|
-
nullable: false
|
|
106
|
-
text_matches:
|
|
107
|
-
type: str
|
|
108
|
-
nullable: false
|
|
109
86
|
generative_response_is_relevant:
|
|
110
87
|
type: map
|
|
111
88
|
mapping:
|