rasa-pro 3.12.4__py3-none-any.whl → 3.12.6.dev1__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/core/channels/voice_ready/audiocodes.py +6 -0
- rasa/core/channels/voice_stream/audiocodes.py +53 -9
- rasa/core/channels/voice_stream/genesys.py +146 -16
- rasa/core/policies/intentless_policy.py +6 -59
- rasa/dialogue_understanding/generator/_jinja_filters.py +9 -0
- rasa/dialogue_understanding/generator/constants.py +4 -0
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +20 -4
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +1 -1
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +2 -2
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +2 -2
- rasa/dialogue_understanding/processor/command_processor.py +20 -5
- rasa/dialogue_understanding/processor/command_processor_component.py +5 -2
- rasa/e2e_test/llm_judge_prompts/answer_relevance_prompt_template.jinja2 +1 -1
- rasa/engine/validation.py +36 -1
- rasa/model_training.py +2 -1
- rasa/shared/constants.py +2 -0
- rasa/shared/core/domain.py +12 -3
- rasa/shared/core/policies/__init__.py +0 -0
- rasa/shared/core/policies/utils.py +87 -0
- rasa/shared/core/slot_mappings.py +12 -0
- rasa/tracing/instrumentation/attribute_extractors.py +2 -0
- rasa/version.py +2 -1
- {rasa_pro-3.12.4.dist-info → rasa_pro-3.12.6.dev1.dist-info}/METADATA +4 -7
- {rasa_pro-3.12.4.dist-info → rasa_pro-3.12.6.dev1.dist-info}/RECORD +27 -26
- {rasa_pro-3.12.4.dist-info → rasa_pro-3.12.6.dev1.dist-info}/WHEEL +1 -1
- README.md +0 -38
- rasa/keys +0 -1
- {rasa_pro-3.12.4.dist-info → rasa_pro-3.12.6.dev1.dist-info}/NOTICE +0 -0
- {rasa_pro-3.12.4.dist-info → rasa_pro-3.12.6.dev1.dist-info}/entry_points.txt +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import copy
|
|
3
|
+
import hmac
|
|
3
4
|
import json
|
|
4
5
|
import uuid
|
|
5
6
|
from collections import defaultdict
|
|
@@ -245,8 +246,13 @@ class AudiocodesInput(InputChannel):
|
|
|
245
246
|
|
|
246
247
|
def _check_token(self, token: Optional[Text]) -> None:
|
|
247
248
|
if not token:
|
|
249
|
+
structlogger.error("audiocodes.token_not_provided")
|
|
248
250
|
raise HttpUnauthorized("Authentication token required.")
|
|
249
251
|
|
|
252
|
+
if not hmac.compare_digest(str(token), str(self.token)):
|
|
253
|
+
structlogger.error("audiocodes.invalid_token", invalid_token=token)
|
|
254
|
+
raise HttpUnauthorized("Invalid authentication token.")
|
|
255
|
+
|
|
250
256
|
def _get_conversation(
|
|
251
257
|
self, token: Optional[Text], conversation_id: Text
|
|
252
258
|
) -> Conversation:
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import base64
|
|
3
|
+
import hmac
|
|
3
4
|
import json
|
|
4
5
|
from typing import Any, Awaitable, Callable, Dict, Optional, Text
|
|
5
6
|
|
|
@@ -103,6 +104,7 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
|
|
|
103
104
|
|
|
104
105
|
def __init__(
|
|
105
106
|
self,
|
|
107
|
+
token: Optional[Text],
|
|
106
108
|
server_url: str,
|
|
107
109
|
asr_config: Dict,
|
|
108
110
|
tts_config: Dict,
|
|
@@ -110,6 +112,22 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
|
|
|
110
112
|
):
|
|
111
113
|
mark_as_beta_feature("Audiocodes (audiocodes_stream) Channel")
|
|
112
114
|
super().__init__(server_url, asr_config, tts_config, monitor_silence)
|
|
115
|
+
self.token = token
|
|
116
|
+
|
|
117
|
+
@classmethod
|
|
118
|
+
def from_credentials(
|
|
119
|
+
cls, credentials: Optional[Dict[str, Any]]
|
|
120
|
+
) -> VoiceInputChannel:
|
|
121
|
+
if not credentials:
|
|
122
|
+
raise ValueError("No credentials given for Audiocodes voice channel.")
|
|
123
|
+
|
|
124
|
+
return cls(
|
|
125
|
+
token=credentials.get("token"),
|
|
126
|
+
server_url=credentials["server_url"],
|
|
127
|
+
asr_config=credentials["asr"],
|
|
128
|
+
tts_config=credentials["tts"],
|
|
129
|
+
monitor_silence=credentials.get("monitor_silence", False),
|
|
130
|
+
)
|
|
113
131
|
|
|
114
132
|
def channel_bytes_to_rasa_audio_bytes(self, input_bytes: bytes) -> RasaAudioBytes:
|
|
115
133
|
return RasaAudioBytes(base64.b64decode(input_bytes))
|
|
@@ -135,6 +153,13 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
|
|
|
135
153
|
)
|
|
136
154
|
if activity["name"] == "start":
|
|
137
155
|
return map_call_params(activity["parameters"])
|
|
156
|
+
elif data["type"] == "connection.validate":
|
|
157
|
+
# not part of call flow; only sent when integration is created
|
|
158
|
+
logger.info(
|
|
159
|
+
"audiocodes_stream.collect_call_parameters.connection.validate",
|
|
160
|
+
event_info="received request to validate integration",
|
|
161
|
+
)
|
|
162
|
+
self._send_validated(channel_websocket, data)
|
|
138
163
|
else:
|
|
139
164
|
logger.warning("audiocodes_stream.unknown_message", data=data)
|
|
140
165
|
return None
|
|
@@ -158,7 +183,7 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
|
|
|
158
183
|
elif activity["name"] == "playFinished":
|
|
159
184
|
logger.debug("audiocodes_stream.playFinished", data=activity)
|
|
160
185
|
if call_state.should_hangup:
|
|
161
|
-
logger.info("
|
|
186
|
+
logger.info("audiocodes_stream.hangup")
|
|
162
187
|
self._send_hangup(ws, data)
|
|
163
188
|
# the conversation should continue until
|
|
164
189
|
# we receive a end message from audiocodes
|
|
@@ -180,11 +205,10 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
|
|
|
180
205
|
elif data["type"] == "session.end":
|
|
181
206
|
logger.debug("audiocodes_stream.end", data=data)
|
|
182
207
|
return EndConversationAction()
|
|
183
|
-
elif data["type"] == "connection.validate":
|
|
184
|
-
# not part of call flow; only sent when integration is created
|
|
185
|
-
self._send_validated(ws, data)
|
|
186
208
|
else:
|
|
187
|
-
logger.warning(
|
|
209
|
+
logger.warning(
|
|
210
|
+
"audiocodes_stream.map_input_message.unknown_message", data=data
|
|
211
|
+
)
|
|
188
212
|
|
|
189
213
|
return ContinueConversationAction()
|
|
190
214
|
|
|
@@ -254,6 +278,17 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
|
|
|
254
278
|
self.tts_cache,
|
|
255
279
|
)
|
|
256
280
|
|
|
281
|
+
def _is_token_valid(self, token: Optional[Text]) -> bool:
|
|
282
|
+
# If no token is set, always return True
|
|
283
|
+
if not self.token:
|
|
284
|
+
return True
|
|
285
|
+
|
|
286
|
+
# Token is required, but not provided
|
|
287
|
+
if not token:
|
|
288
|
+
return False
|
|
289
|
+
|
|
290
|
+
return hmac.compare_digest(str(self.token), str(token))
|
|
291
|
+
|
|
257
292
|
def blueprint(
|
|
258
293
|
self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
|
|
259
294
|
) -> Blueprint:
|
|
@@ -266,17 +301,26 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
|
|
|
266
301
|
|
|
267
302
|
@blueprint.websocket("/websocket") # type: ignore
|
|
268
303
|
async def receive(request: Request, ws: Websocket) -> None:
|
|
269
|
-
|
|
270
|
-
|
|
304
|
+
if not self._is_token_valid(request.token):
|
|
305
|
+
logger.error(
|
|
306
|
+
"audiocodes_stream.invalid_token",
|
|
307
|
+
invalid_token=request.token,
|
|
308
|
+
)
|
|
309
|
+
await ws.close(code=1008, reason="Invalid token")
|
|
310
|
+
return
|
|
311
|
+
|
|
312
|
+
logger.info(
|
|
313
|
+
"audiocodes_stream.receive", event_info="Started websocket connection"
|
|
314
|
+
)
|
|
271
315
|
try:
|
|
272
316
|
await self.run_audio_streaming(on_new_message, ws)
|
|
273
317
|
except Exception as e:
|
|
274
318
|
logger.exception(
|
|
275
|
-
"
|
|
319
|
+
"audiocodes_stream.receive",
|
|
276
320
|
message="Error during audio streaming",
|
|
277
321
|
error=e,
|
|
278
322
|
)
|
|
279
|
-
|
|
323
|
+
await ws.close(code=1011, reason="Error during audio streaming")
|
|
280
324
|
raise
|
|
281
325
|
|
|
282
326
|
return blueprint
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
import base64
|
|
3
|
+
import hashlib
|
|
4
|
+
import hmac
|
|
2
5
|
import json
|
|
3
6
|
from typing import Any, Awaitable, Callable, Dict, Optional, Text
|
|
4
7
|
|
|
@@ -45,6 +48,7 @@ in the documentation but observed in their example app
|
|
|
45
48
|
https://github.com/GenesysCloudBlueprints/audioconnector-server-reference-implementation
|
|
46
49
|
"""
|
|
47
50
|
MAXIMUM_BINARY_MESSAGE_SIZE = 64000 # 64KB
|
|
51
|
+
HEADER_API_KEY = "X-Api-Key"
|
|
48
52
|
logger = structlog.get_logger(__name__)
|
|
49
53
|
|
|
50
54
|
|
|
@@ -86,8 +90,31 @@ class GenesysInputChannel(VoiceInputChannel):
|
|
|
86
90
|
def name(cls) -> str:
|
|
87
91
|
return "genesys"
|
|
88
92
|
|
|
89
|
-
def __init__(
|
|
93
|
+
def __init__(
|
|
94
|
+
self, api_key: Text, client_secret: Optional[Text], *args: Any, **kwargs: Any
|
|
95
|
+
) -> None:
|
|
90
96
|
super().__init__(*args, **kwargs)
|
|
97
|
+
self.api_key = api_key
|
|
98
|
+
self.client_secret = client_secret
|
|
99
|
+
|
|
100
|
+
@classmethod
|
|
101
|
+
def from_credentials(
|
|
102
|
+
cls, credentials: Optional[Dict[str, Any]]
|
|
103
|
+
) -> VoiceInputChannel:
|
|
104
|
+
if not credentials:
|
|
105
|
+
raise ValueError("No credentials given for Genesys voice channel.")
|
|
106
|
+
|
|
107
|
+
if not credentials.get("api_key"):
|
|
108
|
+
raise ValueError("No API key given for Genesys voice channel (api_key).")
|
|
109
|
+
|
|
110
|
+
return cls(
|
|
111
|
+
api_key=credentials["api_key"],
|
|
112
|
+
client_secret=credentials.get("client_secret"),
|
|
113
|
+
server_url=credentials["server_url"],
|
|
114
|
+
asr_config=credentials["asr"],
|
|
115
|
+
tts_config=credentials["tts"],
|
|
116
|
+
monitor_silence=credentials.get("monitor_silence", False),
|
|
117
|
+
)
|
|
91
118
|
|
|
92
119
|
def _ensure_channel_data_initialized(self) -> None:
|
|
93
120
|
"""Initialize Genesys-specific channel data if not already present.
|
|
@@ -273,6 +300,93 @@ class GenesysInputChannel(VoiceInputChannel):
|
|
|
273
300
|
logger.debug("genesys.disconnect", message=message)
|
|
274
301
|
_schedule_ws_task(ws.send(json.dumps(message)))
|
|
275
302
|
|
|
303
|
+
def _calculate_signature(self, request: Request) -> str:
|
|
304
|
+
"""Calculate the signature using request data."""
|
|
305
|
+
org_id = request.headers.get("Audiohook-Organization-Id")
|
|
306
|
+
session_id = request.headers.get("Audiohook-Session-Id")
|
|
307
|
+
correlation_id = request.headers.get("Audiohook-Correlation-Id")
|
|
308
|
+
api_key = request.headers.get(HEADER_API_KEY)
|
|
309
|
+
|
|
310
|
+
# order of components is important!
|
|
311
|
+
components = [
|
|
312
|
+
("@request-target", "/webhooks/genesys/websocket"),
|
|
313
|
+
("audiohook-session-id", session_id),
|
|
314
|
+
("audiohook-organization-id", org_id),
|
|
315
|
+
("audiohook-correlation-id", correlation_id),
|
|
316
|
+
(HEADER_API_KEY.lower(), api_key),
|
|
317
|
+
("@authority", self.server_url),
|
|
318
|
+
]
|
|
319
|
+
|
|
320
|
+
# Create signature base string
|
|
321
|
+
signing_string = ""
|
|
322
|
+
for name, value in components:
|
|
323
|
+
signing_string += f'"{name}": {value}\n'
|
|
324
|
+
|
|
325
|
+
# Add @signature-params
|
|
326
|
+
signature_input = request.headers["Signature-Input"]
|
|
327
|
+
_, params_str = signature_input.split("=", 1)
|
|
328
|
+
signing_string += f'"@signature-params": {params_str}'
|
|
329
|
+
|
|
330
|
+
# Calculate the HMAC signature
|
|
331
|
+
key_bytes = base64.b64decode(self.client_secret)
|
|
332
|
+
signature = hmac.new(
|
|
333
|
+
key_bytes, signing_string.encode("utf-8"), hashlib.sha256
|
|
334
|
+
).digest()
|
|
335
|
+
return base64.b64encode(signature).decode("utf-8")
|
|
336
|
+
|
|
337
|
+
async def _verify_signature(self, request: Request) -> bool:
|
|
338
|
+
"""Verify the HTTP message signature from Genesys."""
|
|
339
|
+
if not self.client_secret:
|
|
340
|
+
logger.info(
|
|
341
|
+
"genesys.verify_signature.no_client_secret",
|
|
342
|
+
event_info="Signature verification skipped",
|
|
343
|
+
)
|
|
344
|
+
return True # Skip verification if no client secret
|
|
345
|
+
|
|
346
|
+
signature = request.headers.get("Signature")
|
|
347
|
+
signature_input = request.headers.get("Signature-Input")
|
|
348
|
+
if not signature or not signature_input:
|
|
349
|
+
logger.error("genesys.signature.missing_signature_header")
|
|
350
|
+
return False
|
|
351
|
+
|
|
352
|
+
try:
|
|
353
|
+
actual_signature = signature.split("=", 1)[1].strip(':"')
|
|
354
|
+
expected_signature = self._calculate_signature(request)
|
|
355
|
+
return hmac.compare_digest(
|
|
356
|
+
expected_signature.encode("utf-8"), actual_signature.encode("utf-8")
|
|
357
|
+
)
|
|
358
|
+
except Exception as e:
|
|
359
|
+
logger.exception("genesys.signature.verification_error", error=e)
|
|
360
|
+
return False
|
|
361
|
+
|
|
362
|
+
def _ensure_required_headers(self, request: Request) -> bool:
|
|
363
|
+
"""Ensure required headers are present in the request."""
|
|
364
|
+
required_headers = [
|
|
365
|
+
"Audiohook-Organization-Id",
|
|
366
|
+
"Audiohook-Correlation-Id",
|
|
367
|
+
"Audiohook-Session-Id",
|
|
368
|
+
HEADER_API_KEY,
|
|
369
|
+
]
|
|
370
|
+
|
|
371
|
+
missing_headers = [
|
|
372
|
+
header for header in required_headers if header not in request.headers
|
|
373
|
+
]
|
|
374
|
+
|
|
375
|
+
if missing_headers:
|
|
376
|
+
logger.error(
|
|
377
|
+
"genesys.missing_required_headers",
|
|
378
|
+
missing_headers=missing_headers,
|
|
379
|
+
)
|
|
380
|
+
return False
|
|
381
|
+
return True
|
|
382
|
+
|
|
383
|
+
def _ensure_api_key(self, request: Request) -> bool:
|
|
384
|
+
"""Ensure the API key is present in the request."""
|
|
385
|
+
api_key = request.headers.get(HEADER_API_KEY)
|
|
386
|
+
if not hmac.compare_digest(str(self.api_key), str(api_key)):
|
|
387
|
+
return False
|
|
388
|
+
return True
|
|
389
|
+
|
|
276
390
|
def blueprint(
|
|
277
391
|
self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
|
|
278
392
|
) -> Blueprint:
|
|
@@ -289,23 +403,39 @@ class GenesysInputChannel(VoiceInputChannel):
|
|
|
289
403
|
"genesys.receive",
|
|
290
404
|
audiohook_session_id=request.headers.get("audiohook-session-id"),
|
|
291
405
|
)
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
"
|
|
296
|
-
"
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
406
|
+
|
|
407
|
+
# verify signature
|
|
408
|
+
if not await self._verify_signature(request):
|
|
409
|
+
logger.error("genesys.receive.invalid_signature")
|
|
410
|
+
await ws.close(code=1008, reason="Invalid signature")
|
|
411
|
+
return
|
|
412
|
+
|
|
413
|
+
# ensure required headers are present
|
|
414
|
+
if not self._ensure_required_headers(request):
|
|
415
|
+
await ws.close(code=1002, reason="Missing required headers")
|
|
416
|
+
return
|
|
417
|
+
|
|
418
|
+
# ensure API key is correct
|
|
419
|
+
if not self._ensure_api_key(request):
|
|
420
|
+
logger.error(
|
|
421
|
+
"genesys.receive.invalid_api_key",
|
|
422
|
+
invalid_api_key=request.headers.get(HEADER_API_KEY),
|
|
423
|
+
)
|
|
424
|
+
await ws.close(code=1008, reason="Invalid API key")
|
|
425
|
+
return
|
|
426
|
+
|
|
306
427
|
# process audio streaming
|
|
307
428
|
logger.info("genesys.receive", message="Starting audio streaming")
|
|
308
|
-
|
|
429
|
+
try:
|
|
430
|
+
await self.run_audio_streaming(on_new_message, ws)
|
|
431
|
+
except Exception as e:
|
|
432
|
+
logger.exception(
|
|
433
|
+
"genesys.receive",
|
|
434
|
+
message="Error during audio streaming",
|
|
435
|
+
error=e,
|
|
436
|
+
)
|
|
437
|
+
await ws.close(code=1011, reason="Error during audio streaming")
|
|
438
|
+
raise
|
|
309
439
|
|
|
310
440
|
return blueprint
|
|
311
441
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import importlib.resources
|
|
2
2
|
import math
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
|
-
from typing import TYPE_CHECKING, Any, Dict, List, Optional,
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Text, Tuple
|
|
5
5
|
|
|
6
6
|
import structlog
|
|
7
7
|
import tiktoken
|
|
@@ -18,7 +18,6 @@ from rasa.core.constants import (
|
|
|
18
18
|
UTTER_SOURCE_METADATA_KEY,
|
|
19
19
|
)
|
|
20
20
|
from rasa.core.policies.policy import Policy, PolicyPrediction, SupportedData
|
|
21
|
-
from rasa.dialogue_understanding.patterns.chitchat import FLOW_PATTERN_CHITCHAT
|
|
22
21
|
from rasa.dialogue_understanding.stack.frames import (
|
|
23
22
|
ChitChatStackFrame,
|
|
24
23
|
DialogueStackFrame,
|
|
@@ -38,10 +37,9 @@ from rasa.shared.constants import (
|
|
|
38
37
|
OPENAI_PROVIDER,
|
|
39
38
|
PROMPT_CONFIG_KEY,
|
|
40
39
|
PROVIDER_CONFIG_KEY,
|
|
41
|
-
REQUIRED_SLOTS_KEY,
|
|
42
40
|
TIMEOUT_CONFIG_KEY,
|
|
43
41
|
)
|
|
44
|
-
from rasa.shared.core.constants import ACTION_LISTEN_NAME
|
|
42
|
+
from rasa.shared.core.constants import ACTION_LISTEN_NAME
|
|
45
43
|
from rasa.shared.core.domain import KEY_RESPONSES_TEXT, Domain
|
|
46
44
|
from rasa.shared.core.events import (
|
|
47
45
|
ActionExecuted,
|
|
@@ -51,6 +49,7 @@ from rasa.shared.core.events import (
|
|
|
51
49
|
)
|
|
52
50
|
from rasa.shared.core.flows import FlowsList
|
|
53
51
|
from rasa.shared.core.generator import TrackerWithCachedStates
|
|
52
|
+
from rasa.shared.core.policies.utils import filter_responses_for_intentless_policy
|
|
54
53
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
55
54
|
from rasa.shared.exceptions import FileIOException, RasaCoreException
|
|
56
55
|
from rasa.shared.nlu.constants import PREDICTED_CONFIDENCE_KEY
|
|
@@ -146,59 +145,6 @@ class Conversation:
|
|
|
146
145
|
interactions: List[Interaction] = field(default_factory=list)
|
|
147
146
|
|
|
148
147
|
|
|
149
|
-
def collect_form_responses(forms: Forms) -> Set[Text]:
|
|
150
|
-
"""Collect responses that belong the requested slots in forms.
|
|
151
|
-
|
|
152
|
-
Args:
|
|
153
|
-
forms: the forms from the domain
|
|
154
|
-
Returns:
|
|
155
|
-
all utterances used in forms
|
|
156
|
-
"""
|
|
157
|
-
form_responses = set()
|
|
158
|
-
for _, form_info in forms.data.items():
|
|
159
|
-
for required_slot in form_info.get(REQUIRED_SLOTS_KEY, []):
|
|
160
|
-
form_responses.add(f"utter_ask_{required_slot}")
|
|
161
|
-
return form_responses
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
def filter_responses(responses: Responses, forms: Forms, flows: FlowsList) -> Responses:
|
|
165
|
-
"""Filters out responses that are unwanted for the intentless policy.
|
|
166
|
-
|
|
167
|
-
This includes utterances used in flows and forms.
|
|
168
|
-
|
|
169
|
-
Args:
|
|
170
|
-
responses: the responses from the domain
|
|
171
|
-
forms: the forms from the domain
|
|
172
|
-
flows: all flows
|
|
173
|
-
Returns:
|
|
174
|
-
The remaining, relevant responses for the intentless policy.
|
|
175
|
-
"""
|
|
176
|
-
form_responses = collect_form_responses(forms)
|
|
177
|
-
flow_responses = flows.utterances
|
|
178
|
-
combined_responses = form_responses | flow_responses
|
|
179
|
-
filtered_responses = {
|
|
180
|
-
name: variants
|
|
181
|
-
for name, variants in responses.data.items()
|
|
182
|
-
if name not in combined_responses
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
pattern_chitchat = flows.flow_by_id(FLOW_PATTERN_CHITCHAT)
|
|
186
|
-
|
|
187
|
-
# The following condition is highly unlikely, but mypy requires the case
|
|
188
|
-
# of pattern_chitchat == None to be addressed
|
|
189
|
-
if not pattern_chitchat:
|
|
190
|
-
return Responses(data=filtered_responses)
|
|
191
|
-
|
|
192
|
-
# if action_trigger_chitchat, filter out "utter_free_chitchat_response"
|
|
193
|
-
has_action_trigger_chitchat = pattern_chitchat.has_action_step(
|
|
194
|
-
ACTION_TRIGGER_CHITCHAT
|
|
195
|
-
)
|
|
196
|
-
if has_action_trigger_chitchat:
|
|
197
|
-
filtered_responses.pop("utter_free_chitchat_response", None)
|
|
198
|
-
|
|
199
|
-
return Responses(data=filtered_responses)
|
|
200
|
-
|
|
201
|
-
|
|
202
148
|
def action_from_response(
|
|
203
149
|
text: Optional[str], responses: Dict[Text, List[Dict[Text, Any]]]
|
|
204
150
|
) -> Optional[str]:
|
|
@@ -512,7 +458,9 @@ class IntentlessPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Policy):
|
|
|
512
458
|
# Perform health checks of both LLM and embeddings client configs
|
|
513
459
|
self._perform_health_checks(self.config, "intentless_policy.train")
|
|
514
460
|
|
|
515
|
-
responses =
|
|
461
|
+
responses = filter_responses_for_intentless_policy(
|
|
462
|
+
responses, forms, flows or FlowsList([])
|
|
463
|
+
)
|
|
516
464
|
telemetry.track_intentless_policy_train()
|
|
517
465
|
response_texts = [r for r in extract_ai_response_examples(responses.data)]
|
|
518
466
|
|
|
@@ -947,7 +895,6 @@ class IntentlessPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Policy):
|
|
|
947
895
|
**kwargs: Any,
|
|
948
896
|
) -> "IntentlessPolicy":
|
|
949
897
|
"""Loads a trained policy (see parent class for full docstring)."""
|
|
950
|
-
|
|
951
898
|
# Perform health checks of both LLM and embeddings client configs
|
|
952
899
|
cls._perform_health_checks(config, "intentless_policy.load")
|
|
953
900
|
|
|
@@ -33,3 +33,7 @@ LLM_BASED_COMMAND_GENERATOR_CONFIG_FILE = "config.json"
|
|
|
33
33
|
|
|
34
34
|
MODEL_NAME_GPT_4O_2024_11_20 = "gpt-4o-2024-11-20"
|
|
35
35
|
MODEL_NAME_CLAUDE_3_5_SONNET_20240620 = "claude-3-5-sonnet-20240620"
|
|
36
|
+
|
|
37
|
+
# JINJA template filters
|
|
38
|
+
|
|
39
|
+
TO_JSON_ESCAPED_STRING_JINJA_FILTER = "to_json_escaped_string"
|
|
@@ -3,7 +3,7 @@ from functools import lru_cache
|
|
|
3
3
|
from typing import Any, Dict, List, Optional, Set, Text, Tuple, Union
|
|
4
4
|
|
|
5
5
|
import structlog
|
|
6
|
-
from jinja2 import Template
|
|
6
|
+
from jinja2 import Environment, Template, select_autoescape
|
|
7
7
|
|
|
8
8
|
import rasa.dialogue_understanding.generator.utils
|
|
9
9
|
import rasa.shared.utils.io
|
|
@@ -17,12 +17,14 @@ from rasa.dialogue_understanding.commands.handle_digressions_command import (
|
|
|
17
17
|
)
|
|
18
18
|
from rasa.dialogue_understanding.constants import KEY_MINIMIZE_NUM_CALLS
|
|
19
19
|
from rasa.dialogue_understanding.generator import CommandGenerator
|
|
20
|
+
from rasa.dialogue_understanding.generator._jinja_filters import to_json_escaped_string
|
|
20
21
|
from rasa.dialogue_understanding.generator.constants import (
|
|
21
22
|
DEFAULT_LLM_CONFIG,
|
|
22
23
|
FLOW_RETRIEVAL_ACTIVE_KEY,
|
|
23
24
|
FLOW_RETRIEVAL_FLOW_THRESHOLD,
|
|
24
25
|
FLOW_RETRIEVAL_KEY,
|
|
25
26
|
LLM_CONFIG_KEY,
|
|
27
|
+
TO_JSON_ESCAPED_STRING_JINJA_FILTER,
|
|
26
28
|
)
|
|
27
29
|
from rasa.dialogue_understanding.generator.flow_retrieval import FlowRetrieval
|
|
28
30
|
from rasa.dialogue_understanding.stack.utils import top_flow_frame
|
|
@@ -226,12 +228,26 @@ class LLMBasedCommandGenerator(
|
|
|
226
228
|
|
|
227
229
|
@lru_cache
|
|
228
230
|
def compile_template(self, template: str) -> Template:
|
|
229
|
-
"""
|
|
230
|
-
|
|
231
|
+
"""
|
|
232
|
+
Compile the prompt template and register custom filters.
|
|
231
233
|
Compiling the template is an expensive operation,
|
|
232
234
|
so we cache the result.
|
|
233
235
|
"""
|
|
234
|
-
|
|
236
|
+
# Create an environment
|
|
237
|
+
# Autoescaping disabled explicitly for LLM prompt templates rendered from
|
|
238
|
+
|
|
239
|
+
# strings (safe, not HTML)
|
|
240
|
+
env = Environment(
|
|
241
|
+
autoescape=select_autoescape(
|
|
242
|
+
disabled_extensions=["jinja2"], default_for_string=False, default=True
|
|
243
|
+
)
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
# Register filters
|
|
247
|
+
env.filters[TO_JSON_ESCAPED_STRING_JINJA_FILTER] = to_json_escaped_string
|
|
248
|
+
|
|
249
|
+
# Return the template which can leverage registered filters
|
|
250
|
+
return env.from_string(template)
|
|
235
251
|
|
|
236
252
|
@classmethod
|
|
237
253
|
def load_prompt_template_from_model_storage(
|
|
@@ -140,7 +140,7 @@ class NLUCommandAdapter(GraphComponent, CommandGenerator):
|
|
|
140
140
|
|
|
141
141
|
if commands:
|
|
142
142
|
commands = clean_up_commands(
|
|
143
|
-
commands, tracker, flows, self._execution_context
|
|
143
|
+
commands, tracker, flows, self._execution_context, domain
|
|
144
144
|
)
|
|
145
145
|
log_llm(
|
|
146
146
|
logger=structlogger,
|
|
@@ -33,7 +33,7 @@ Your task is to analyze the current conversation context and generate a list of
|
|
|
33
33
|
## Available Flows and Slots
|
|
34
34
|
Use the following structured data:
|
|
35
35
|
```json
|
|
36
|
-
{"flows":[{% for flow in available_flows %}{"name":"{{ flow.name }}","description":
|
|
36
|
+
{"flows":[{% for flow in available_flows %}{"name":"{{ flow.name }}","description":{{ flow.description | to_json_escaped_string }}{% if flow.slots %},"slots":[{% for slot in flow.slots %}{"name":"{{ slot.name }}"{% if slot.description %},"description":{{ slot.description | to_json_escaped_string }}{% endif %}{% if slot.allowed_values %},"allowed_values":{{ slot.allowed_values }}{% endif %}}{% if not loop.last %},{% endif %}{% endfor %}]{% endif %}}{% if not loop.last %},{% endif %}{% endfor %}]}
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
--
|
|
@@ -41,7 +41,7 @@ Use the following structured data:
|
|
|
41
41
|
## Current State
|
|
42
42
|
{% if current_flow != None %}Use the following structured data:
|
|
43
43
|
```json
|
|
44
|
-
{"active_flow":"{{ current_flow }}","current_step":{"requested_slot":"{{ current_slot }}","requested_slot_description":
|
|
44
|
+
{"active_flow":"{{ current_flow }}","current_step":{"requested_slot":"{{ current_slot }}","requested_slot_description":{{ current_slot_description | to_json_escaped_string }}},"slots":[{% for slot in flow_slots %}{"name":"{{ slot.name }}","value":"{{ slot.value }}","type":"{{ slot.type }}"{% if slot.description %},"description":{{ slot.description | to_json_escaped_string }}{% endif %}{% if slot.allowed_values %},"allowed_values":"{{ slot.allowed_values }}"{% endif %}}{% if not loop.last %},{% endif %}{% endfor %}]}
|
|
45
45
|
```{% else %}
|
|
46
46
|
You are currently not inside any flow.{% endif %}
|
|
47
47
|
|
|
@@ -6,7 +6,7 @@ Your task is to analyze the current conversation context and generate a list of
|
|
|
6
6
|
## Available Flows and Slots
|
|
7
7
|
Use the following structured data:
|
|
8
8
|
```json
|
|
9
|
-
{"flows":[{% for flow in available_flows %}{"name":"{{ flow.name }}","description":
|
|
9
|
+
{"flows":[{% for flow in available_flows %}{"name":"{{ flow.name }}","description":{{ flow.description | to_json_escaped_string }}{% if flow.slots %},"slots":[{% for slot in flow.slots %}{"name":"{{ slot.name }}"{% if slot.description %},"description":{{ slot.description | to_json_escaped_string }}{% endif %}{% if slot.allowed_values %},"allowed_values":{{ slot.allowed_values }}{% endif %}}{% if not loop.last %},{% endif %}{% endfor %}]{% endif %}}{% if not loop.last %},{% endif %}{% endfor %}]}
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
---
|
|
@@ -40,7 +40,7 @@ Use the following structured data:
|
|
|
40
40
|
## Current State
|
|
41
41
|
{% if current_flow != None %}Use the following structured data:
|
|
42
42
|
```json
|
|
43
|
-
{"active_flow":"{{ current_flow }}","current_step":{"requested_slot":"{{ current_slot }}","requested_slot_description":
|
|
43
|
+
{"active_flow":"{{ current_flow }}","current_step":{"requested_slot":"{{ current_slot }}","requested_slot_description":{{ current_slot_description | to_json_escaped_string }}},"slots":[{% for slot in flow_slots %}{"name":"{{ slot.name }}","value":"{{ slot.value }}","type":"{{ slot.type }}"{% if slot.description %},"description":{{ slot.description | to_json_escaped_string }}{% endif %}{% if slot.allowed_values %},"allowed_values":"{{ slot.allowed_values }}"{% endif %}}{% if not loop.last %},{% endif %}{% endfor %}]}
|
|
44
44
|
```{% else %}
|
|
45
45
|
You are currently not inside any flow.{% endif %}
|
|
46
46
|
|
|
@@ -54,9 +54,11 @@ from rasa.shared.core.constants import (
|
|
|
54
54
|
FLOW_HASHES_SLOT,
|
|
55
55
|
SlotMappingType,
|
|
56
56
|
)
|
|
57
|
+
from rasa.shared.core.domain import Domain
|
|
57
58
|
from rasa.shared.core.events import Event, SlotSet
|
|
58
59
|
from rasa.shared.core.flows import FlowsList
|
|
59
60
|
from rasa.shared.core.flows.steps.collect import CollectInformationFlowStep
|
|
61
|
+
from rasa.shared.core.policies.utils import contains_intentless_policy_responses
|
|
60
62
|
from rasa.shared.core.slot_mappings import SlotMapping
|
|
61
63
|
from rasa.shared.core.slots import Slot
|
|
62
64
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
@@ -197,6 +199,7 @@ def execute_commands(
|
|
|
197
199
|
all_flows: FlowsList,
|
|
198
200
|
execution_context: ExecutionContext,
|
|
199
201
|
story_graph: Optional[StoryGraph] = None,
|
|
202
|
+
domain: Optional[Domain] = None,
|
|
200
203
|
) -> List[Event]:
|
|
201
204
|
"""Executes a list of commands.
|
|
202
205
|
|
|
@@ -206,6 +209,7 @@ def execute_commands(
|
|
|
206
209
|
all_flows: All flows.
|
|
207
210
|
execution_context: Information about the single graph run.
|
|
208
211
|
story_graph: StoryGraph object with stories available for training.
|
|
212
|
+
domain: The domain of the bot.
|
|
209
213
|
|
|
210
214
|
Returns:
|
|
211
215
|
A list of the events that were created.
|
|
@@ -214,7 +218,7 @@ def execute_commands(
|
|
|
214
218
|
original_tracker = tracker.copy()
|
|
215
219
|
|
|
216
220
|
commands = clean_up_commands(
|
|
217
|
-
commands, tracker, all_flows, execution_context, story_graph
|
|
221
|
+
commands, tracker, all_flows, execution_context, story_graph, domain
|
|
218
222
|
)
|
|
219
223
|
|
|
220
224
|
updated_flows = find_updated_flows(tracker, all_flows)
|
|
@@ -381,6 +385,7 @@ def clean_up_commands(
|
|
|
381
385
|
all_flows: FlowsList,
|
|
382
386
|
execution_context: ExecutionContext,
|
|
383
387
|
story_graph: Optional[StoryGraph] = None,
|
|
388
|
+
domain: Optional[Domain] = None,
|
|
384
389
|
) -> List[Command]:
|
|
385
390
|
"""Clean up a list of commands.
|
|
386
391
|
|
|
@@ -396,10 +401,13 @@ def clean_up_commands(
|
|
|
396
401
|
all_flows: All flows.
|
|
397
402
|
execution_context: Information about a single graph run.
|
|
398
403
|
story_graph: StoryGraph object with stories available for training.
|
|
404
|
+
domain: The domain of the bot.
|
|
399
405
|
|
|
400
406
|
Returns:
|
|
401
407
|
The cleaned up commands.
|
|
402
408
|
"""
|
|
409
|
+
domain = domain if domain else Domain.empty()
|
|
410
|
+
|
|
403
411
|
slots_so_far, active_flow = filled_slots_for_active_flow(tracker, all_flows)
|
|
404
412
|
|
|
405
413
|
clean_commands: List[Command] = []
|
|
@@ -465,7 +473,12 @@ def clean_up_commands(
|
|
|
465
473
|
# handle chitchat command differently from other free-form answer commands
|
|
466
474
|
elif isinstance(command, ChitChatAnswerCommand):
|
|
467
475
|
clean_commands = clean_up_chitchat_command(
|
|
468
|
-
clean_commands,
|
|
476
|
+
clean_commands,
|
|
477
|
+
command,
|
|
478
|
+
all_flows,
|
|
479
|
+
execution_context,
|
|
480
|
+
domain,
|
|
481
|
+
story_graph,
|
|
469
482
|
)
|
|
470
483
|
|
|
471
484
|
elif isinstance(command, FreeFormAnswerCommand):
|
|
@@ -708,6 +721,7 @@ def clean_up_chitchat_command(
|
|
|
708
721
|
command: ChitChatAnswerCommand,
|
|
709
722
|
flows: FlowsList,
|
|
710
723
|
execution_context: ExecutionContext,
|
|
724
|
+
domain: Domain,
|
|
711
725
|
story_graph: Optional[StoryGraph] = None,
|
|
712
726
|
) -> List[Command]:
|
|
713
727
|
"""Clean up a chitchat answer command.
|
|
@@ -721,6 +735,8 @@ def clean_up_chitchat_command(
|
|
|
721
735
|
flows: All flows.
|
|
722
736
|
execution_context: Information about a single graph run.
|
|
723
737
|
story_graph: StoryGraph object with stories available for training.
|
|
738
|
+
domain: The domain of the bot.
|
|
739
|
+
|
|
724
740
|
Returns:
|
|
725
741
|
The cleaned up commands.
|
|
726
742
|
"""
|
|
@@ -746,10 +762,9 @@ def clean_up_chitchat_command(
|
|
|
746
762
|
)
|
|
747
763
|
defines_intentless_policy = execution_context.has_node(IntentlessPolicy)
|
|
748
764
|
|
|
749
|
-
has_e2e_stories = True if (story_graph and story_graph.has_e2e_stories()) else False
|
|
750
|
-
|
|
751
765
|
if (has_action_trigger_chitchat and not defines_intentless_policy) or (
|
|
752
|
-
defines_intentless_policy
|
|
766
|
+
defines_intentless_policy
|
|
767
|
+
and not contains_intentless_policy_responses(flows, domain, story_graph)
|
|
753
768
|
):
|
|
754
769
|
resulting_commands.insert(
|
|
755
770
|
0, CannotHandleCommand(RASA_PATTERN_CANNOT_HANDLE_CHITCHAT)
|
|
@@ -6,6 +6,7 @@ import rasa.dialogue_understanding.processor.command_processor
|
|
|
6
6
|
from rasa.engine.graph import ExecutionContext, GraphComponent
|
|
7
7
|
from rasa.engine.storage.resource import Resource
|
|
8
8
|
from rasa.engine.storage.storage import ModelStorage
|
|
9
|
+
from rasa.shared.core.domain import Domain
|
|
9
10
|
from rasa.shared.core.events import Event
|
|
10
11
|
from rasa.shared.core.flows import FlowsList
|
|
11
12
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
@@ -15,7 +16,8 @@ from rasa.shared.core.training_data.structures import StoryGraph
|
|
|
15
16
|
class CommandProcessorComponent(GraphComponent):
|
|
16
17
|
"""Processes commands by issuing events to modify a tracker.
|
|
17
18
|
|
|
18
|
-
Minimal component that applies commands to a tracker.
|
|
19
|
+
Minimal component that applies commands to a tracker.
|
|
20
|
+
"""
|
|
19
21
|
|
|
20
22
|
def __init__(self, execution_context: ExecutionContext):
|
|
21
23
|
self._execution_context = execution_context
|
|
@@ -36,8 +38,9 @@ class CommandProcessorComponent(GraphComponent):
|
|
|
36
38
|
tracker: DialogueStateTracker,
|
|
37
39
|
flows: FlowsList,
|
|
38
40
|
story_graph: StoryGraph,
|
|
41
|
+
domain: Domain,
|
|
39
42
|
) -> List[Event]:
|
|
40
43
|
"""Execute commands to update tracker state."""
|
|
41
44
|
return rasa.dialogue_understanding.processor.command_processor.execute_commands(
|
|
42
|
-
tracker, flows, self._execution_context, story_graph
|
|
45
|
+
tracker, flows, self._execution_context, story_graph, domain
|
|
43
46
|
)
|
|
@@ -6,7 +6,7 @@ Each question variation should be a question that the input answer is attempting
|
|
|
6
6
|
Follow these steps to complete the task:
|
|
7
7
|
|
|
8
8
|
1. Generate {{ num_variations }} question variations that the input answer is attempting to answer.
|
|
9
|
-
|
|
9
|
+
2. Compile all the question variations into a JSON object.
|
|
10
10
|
|
|
11
11
|
### JSON Output
|
|
12
12
|
|
rasa/engine/validation.py
CHANGED
|
@@ -86,7 +86,9 @@ from rasa.shared.constants import (
|
|
|
86
86
|
from rasa.shared.core.constants import ACTION_RESET_ROUTING, ACTION_TRIGGER_CHITCHAT
|
|
87
87
|
from rasa.shared.core.domain import Domain
|
|
88
88
|
from rasa.shared.core.flows import Flow, FlowsList
|
|
89
|
+
from rasa.shared.core.policies.utils import contains_intentless_policy_responses
|
|
89
90
|
from rasa.shared.core.slots import Slot
|
|
91
|
+
from rasa.shared.core.training_data.structures import StoryGraph
|
|
90
92
|
from rasa.shared.exceptions import RasaException
|
|
91
93
|
from rasa.shared.nlu.training_data.message import Message
|
|
92
94
|
from rasa.shared.utils.common import display_research_study_prompt
|
|
@@ -642,11 +644,18 @@ def _recursively_check_required_components(
|
|
|
642
644
|
|
|
643
645
|
|
|
644
646
|
def validate_flow_component_dependencies(
|
|
645
|
-
flows: FlowsList,
|
|
647
|
+
flows: FlowsList,
|
|
648
|
+
domain: Domain,
|
|
649
|
+
story_graph: StoryGraph,
|
|
650
|
+
model_configuration: GraphModelConfiguration,
|
|
646
651
|
) -> None:
|
|
647
652
|
if (pattern_chitchat := flows.flow_by_id(FLOW_PATTERN_CHITCHAT)) is not None:
|
|
648
653
|
_validate_chitchat_dependencies(pattern_chitchat, model_configuration)
|
|
649
654
|
|
|
655
|
+
_validate_intentless_policy_responses(
|
|
656
|
+
flows, domain, story_graph, model_configuration
|
|
657
|
+
)
|
|
658
|
+
|
|
650
659
|
|
|
651
660
|
def _validate_chitchat_dependencies(
|
|
652
661
|
pattern_chitchat: Flow, model_configuration: GraphModelConfiguration
|
|
@@ -674,6 +683,32 @@ def _validate_chitchat_dependencies(
|
|
|
674
683
|
)
|
|
675
684
|
|
|
676
685
|
|
|
686
|
+
def _validate_intentless_policy_responses(
|
|
687
|
+
flows: FlowsList,
|
|
688
|
+
domain: Domain,
|
|
689
|
+
story_graph: StoryGraph,
|
|
690
|
+
model_configuration: GraphModelConfiguration,
|
|
691
|
+
) -> None:
|
|
692
|
+
"""If IntentlessPolicy is configured, validate that it has responses to use:
|
|
693
|
+
either responses from the domain that are not part of any flow, or from
|
|
694
|
+
end-to-end stories.
|
|
695
|
+
"""
|
|
696
|
+
if not model_configuration.predict_schema.has_node(IntentlessPolicy):
|
|
697
|
+
return
|
|
698
|
+
|
|
699
|
+
if not contains_intentless_policy_responses(flows, domain, story_graph):
|
|
700
|
+
structlogger.error(
|
|
701
|
+
"validation.intentless_policy.no_applicable_responses_found",
|
|
702
|
+
event_info=(
|
|
703
|
+
"IntentlessPolicy is configured, but no applicable responses are "
|
|
704
|
+
"found. Please make sure that there are responses defined in the "
|
|
705
|
+
"domain that are not part of any flow, or that there are "
|
|
706
|
+
"end-to-end stories in the training data."
|
|
707
|
+
),
|
|
708
|
+
)
|
|
709
|
+
sys.exit(1)
|
|
710
|
+
|
|
711
|
+
|
|
677
712
|
def get_component_index(schema: GraphSchema, component_class: Type) -> Optional[int]:
|
|
678
713
|
"""Extracts the index of a component of the given class in the schema.
|
|
679
714
|
This function assumes that each component's node name is stored in a way
|
rasa/model_training.py
CHANGED
|
@@ -315,6 +315,7 @@ async def _train_graph(
|
|
|
315
315
|
)
|
|
316
316
|
flows = file_importer.get_flows()
|
|
317
317
|
domain = file_importer.get_domain()
|
|
318
|
+
story_graph = file_importer.get_stories()
|
|
318
319
|
model_configuration = recipe.graph_config_for_recipe(
|
|
319
320
|
config,
|
|
320
321
|
kwargs,
|
|
@@ -330,7 +331,7 @@ async def _train_graph(
|
|
|
330
331
|
config
|
|
331
332
|
)
|
|
332
333
|
rasa.engine.validation.validate_flow_component_dependencies(
|
|
333
|
-
flows, model_configuration
|
|
334
|
+
flows, domain, story_graph, model_configuration
|
|
334
335
|
)
|
|
335
336
|
rasa.engine.validation.validate_command_generator_setup(model_configuration)
|
|
336
337
|
|
rasa/shared/constants.py
CHANGED
|
@@ -99,6 +99,8 @@ UTTER_ASK_PREFIX = "utter_ask_"
|
|
|
99
99
|
ACTION_ASK_PREFIX = "action_ask_"
|
|
100
100
|
FLOW_PREFIX = "flow_"
|
|
101
101
|
|
|
102
|
+
UTTER_FREE_CHITCHAT_RESPONSE = "utter_free_chitchat_response"
|
|
103
|
+
|
|
102
104
|
ASSISTANT_ID_KEY = "assistant_id"
|
|
103
105
|
ASSISTANT_ID_DEFAULT_VALUE = "placeholder_default"
|
|
104
106
|
|
rasa/shared/core/domain.py
CHANGED
|
@@ -1678,6 +1678,14 @@ class Domain:
|
|
|
1678
1678
|
"""Write domain to a file."""
|
|
1679
1679
|
as_yaml = self.as_yaml()
|
|
1680
1680
|
rasa.shared.utils.io.write_text_file(as_yaml, filename)
|
|
1681
|
+
# run the check again on the written domain to catch any errors
|
|
1682
|
+
# that may have been missed in the user defined domain files
|
|
1683
|
+
structlogger.info(
|
|
1684
|
+
"domain.persist.domain_written_to_file",
|
|
1685
|
+
event_info="The entire domain content has been written to file.",
|
|
1686
|
+
filename=filename,
|
|
1687
|
+
)
|
|
1688
|
+
Domain.is_domain_file(filename)
|
|
1681
1689
|
|
|
1682
1690
|
def as_yaml(self) -> Text:
|
|
1683
1691
|
"""Dump the `Domain` object as a YAML string.
|
|
@@ -1972,17 +1980,18 @@ class Domain:
|
|
|
1972
1980
|
|
|
1973
1981
|
try:
|
|
1974
1982
|
content = read_yaml_file(filename, expand_env_vars=cls.expand_env_vars)
|
|
1975
|
-
except (RasaException, YamlSyntaxException):
|
|
1976
|
-
structlogger.
|
|
1983
|
+
except (RasaException, YamlSyntaxException) as error:
|
|
1984
|
+
structlogger.error(
|
|
1977
1985
|
"domain.cannot_load_domain_file",
|
|
1978
1986
|
file=filename,
|
|
1987
|
+
error=error,
|
|
1979
1988
|
event_info=(
|
|
1980
1989
|
f"The file {filename} could not be loaded as domain file. "
|
|
1981
1990
|
f"You can use https://yamlchecker.com/ to validate "
|
|
1982
1991
|
f"the YAML syntax of your file."
|
|
1983
1992
|
),
|
|
1984
1993
|
)
|
|
1985
|
-
|
|
1994
|
+
raise RasaException(f"Domain could not be loaded: {error}")
|
|
1986
1995
|
|
|
1987
1996
|
return any(key in content for key in ALL_DOMAIN_KEYS)
|
|
1988
1997
|
|
|
File without changes
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from typing import Set, Text
|
|
2
|
+
|
|
3
|
+
from rasa.dialogue_understanding.patterns.chitchat import FLOW_PATTERN_CHITCHAT
|
|
4
|
+
from rasa.graph_components.providers.forms_provider import Forms
|
|
5
|
+
from rasa.graph_components.providers.responses_provider import Responses
|
|
6
|
+
from rasa.shared.constants import (
|
|
7
|
+
REQUIRED_SLOTS_KEY,
|
|
8
|
+
UTTER_ASK_PREFIX,
|
|
9
|
+
UTTER_FREE_CHITCHAT_RESPONSE,
|
|
10
|
+
)
|
|
11
|
+
from rasa.shared.core.constants import ACTION_TRIGGER_CHITCHAT
|
|
12
|
+
from rasa.shared.core.domain import Domain
|
|
13
|
+
from rasa.shared.core.flows import FlowsList
|
|
14
|
+
from rasa.shared.core.training_data.structures import StoryGraph
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def collect_form_responses(forms: Forms) -> Set[Text]:
|
|
18
|
+
"""Collect responses that belong the requested slots in forms.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
forms: the forms from the domain
|
|
22
|
+
Returns:
|
|
23
|
+
all utterances used in forms
|
|
24
|
+
"""
|
|
25
|
+
form_responses = set()
|
|
26
|
+
for _, form_info in forms.data.items():
|
|
27
|
+
for required_slot in form_info.get(REQUIRED_SLOTS_KEY, []):
|
|
28
|
+
form_responses.add(f"{UTTER_ASK_PREFIX}{required_slot}")
|
|
29
|
+
return form_responses
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def filter_responses_for_intentless_policy(
|
|
33
|
+
responses: Responses, forms: Forms, flows: FlowsList
|
|
34
|
+
) -> Responses:
|
|
35
|
+
"""Filters out responses that are unwanted for the intentless policy.
|
|
36
|
+
|
|
37
|
+
This includes utterances used in flows and forms.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
responses: the responses from the domain
|
|
41
|
+
forms: the forms from the domain
|
|
42
|
+
flows: all flows
|
|
43
|
+
Returns:
|
|
44
|
+
The remaining, relevant responses for the intentless policy.
|
|
45
|
+
"""
|
|
46
|
+
form_responses = collect_form_responses(forms)
|
|
47
|
+
flow_responses = flows.utterances
|
|
48
|
+
combined_responses = form_responses | flow_responses
|
|
49
|
+
filtered_responses = {
|
|
50
|
+
name: variants
|
|
51
|
+
for name, variants in responses.data.items()
|
|
52
|
+
if name not in combined_responses
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
pattern_chitchat = flows.flow_by_id(FLOW_PATTERN_CHITCHAT)
|
|
56
|
+
|
|
57
|
+
# The following condition is highly unlikely, but mypy requires the case
|
|
58
|
+
# of pattern_chitchat == None to be addressed
|
|
59
|
+
if not pattern_chitchat:
|
|
60
|
+
return Responses(data=filtered_responses)
|
|
61
|
+
|
|
62
|
+
# if action_trigger_chitchat, filter out "utter_free_chitchat_response"
|
|
63
|
+
has_action_trigger_chitchat = pattern_chitchat.has_action_step(
|
|
64
|
+
ACTION_TRIGGER_CHITCHAT
|
|
65
|
+
)
|
|
66
|
+
if has_action_trigger_chitchat:
|
|
67
|
+
filtered_responses.pop(UTTER_FREE_CHITCHAT_RESPONSE, None)
|
|
68
|
+
|
|
69
|
+
return Responses(data=filtered_responses)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def contains_intentless_policy_responses(
|
|
73
|
+
flows: FlowsList, domain: Domain, story_graph: StoryGraph
|
|
74
|
+
) -> bool:
|
|
75
|
+
"""Checks if IntentlessPolicy has applicable responses: either responses in the
|
|
76
|
+
domain that are not part of any flow, or if there are e2e stories.
|
|
77
|
+
"""
|
|
78
|
+
responses = filter_responses_for_intentless_policy(
|
|
79
|
+
Responses(data=domain.responses), Forms(data=domain.forms), flows
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
has_applicable_responses = bool(
|
|
83
|
+
responses and responses.data and len(responses.data) > 0
|
|
84
|
+
)
|
|
85
|
+
has_e2e_stories = bool(story_graph and story_graph.has_e2e_stories())
|
|
86
|
+
|
|
87
|
+
return has_applicable_responses or has_e2e_stories
|
|
@@ -115,6 +115,18 @@ class SlotMapping(BaseModel):
|
|
|
115
115
|
)
|
|
116
116
|
data_copy[KEY_RUN_ACTION_EVERY_TURN] = deprecated_action
|
|
117
117
|
|
|
118
|
+
structlogger.warning(
|
|
119
|
+
"slot_mapping.deprecated_action_key_replaced_with_run_action_every_turn",
|
|
120
|
+
slot_name=slot_name,
|
|
121
|
+
event_info=f"The `{KEY_ACTION}` key in slot mappings "
|
|
122
|
+
f"has been replaced with "
|
|
123
|
+
f"the `{KEY_RUN_ACTION_EVERY_TURN}` key. "
|
|
124
|
+
f"This will result in the custom action "
|
|
125
|
+
f"being executed at every conversation turn "
|
|
126
|
+
f"automatically. Remove the key "
|
|
127
|
+
f"to avoid this behavior.",
|
|
128
|
+
)
|
|
129
|
+
|
|
118
130
|
run_action_every_turn = data_copy.pop(KEY_RUN_ACTION_EVERY_TURN, None)
|
|
119
131
|
|
|
120
132
|
coexistence_system = data_copy.pop(KEY_COEXISTENCE_SYSTEM, None)
|
|
@@ -454,6 +454,7 @@ def extract_attrs_for_execute_commands(
|
|
|
454
454
|
all_flows: FlowsList,
|
|
455
455
|
execution_context: ExecutionContext,
|
|
456
456
|
story_graph: Optional[StoryGraph] = None,
|
|
457
|
+
domain: Optional[Domain] = None,
|
|
457
458
|
) -> Dict[str, Any]:
|
|
458
459
|
return {
|
|
459
460
|
"number_of_events": len(tracker.events),
|
|
@@ -497,6 +498,7 @@ def extract_attrs_for_clean_up_commands(
|
|
|
497
498
|
all_flows: FlowsList,
|
|
498
499
|
execution_context: ExecutionContext,
|
|
499
500
|
story_graph: Optional[StoryGraph] = None,
|
|
501
|
+
domain: Optional[Domain] = None,
|
|
500
502
|
) -> Dict[str, Any]:
|
|
501
503
|
commands_list = []
|
|
502
504
|
|
rasa/version.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: rasa-pro
|
|
3
|
-
Version: 3.12.
|
|
3
|
+
Version: 3.12.6.dev1
|
|
4
4
|
Summary: State-of-the-art open-core Conversational AI framework for Enterprises that natively leverages generative AI for effortless assistant development.
|
|
5
|
-
Home-page: https://rasa.com
|
|
6
5
|
Keywords: nlp,machine-learning,machine-learning-library,bot,bots,botkit,rasa conversational-agents,conversational-ai,chatbot,chatbot-framework,bot-framework
|
|
7
6
|
Author: Rasa Technologies GmbH
|
|
8
7
|
Author-email: hi@rasa.com
|
|
@@ -86,7 +85,6 @@ Requires-Dist: protobuf (>=4.23.3,<4.25.4)
|
|
|
86
85
|
Requires-Dist: psutil (>=5.9.5,<6.0.0)
|
|
87
86
|
Requires-Dist: psycopg2-binary (>=2.9.9,<2.10.0)
|
|
88
87
|
Requires-Dist: pycountry (>=22.3.5,<23.0.0)
|
|
89
|
-
Requires-Dist: pydantic (>=2.0,<3.0)
|
|
90
88
|
Requires-Dist: pydot (>=1.4,<1.5)
|
|
91
89
|
Requires-Dist: pykwalify (>=1.8,<1.9)
|
|
92
90
|
Requires-Dist: pymilvus (>=2.4.1,<2.4.2)
|
|
@@ -118,7 +116,6 @@ Requires-Dist: scikit-learn (>=1.5.1,<1.6.0)
|
|
|
118
116
|
Requires-Dist: scipy (>=1.13.1,<1.14.0)
|
|
119
117
|
Requires-Dist: sentencepiece[sentencepiece] (>=0.1.99,<0.2.0) ; extra == "transformers" or extra == "full"
|
|
120
118
|
Requires-Dist: sentry-sdk (>=1.14.0,<1.15.0)
|
|
121
|
-
Requires-Dist: setuptools (>=70.0.0,<70.1.0)
|
|
122
119
|
Requires-Dist: sklearn-crfsuite (>=0.3.6,<0.4.0)
|
|
123
120
|
Requires-Dist: skops (>=0.10.0,<0.11.0)
|
|
124
121
|
Requires-Dist: slack-sdk (>=3.27.1,<3.28.0)
|
|
@@ -135,7 +132,7 @@ Requires-Dist: tensorflow-io-gcs-filesystem (==0.34) ; sys_platform == "darwin"
|
|
|
135
132
|
Requires-Dist: tensorflow-io-gcs-filesystem (==0.34) ; sys_platform == "linux"
|
|
136
133
|
Requires-Dist: tensorflow-macos (==2.14.1) ; sys_platform == "darwin" and platform_machine == "arm64"
|
|
137
134
|
Requires-Dist: tensorflow-metal (==1.1.0) ; (sys_platform == "darwin" and platform_machine == "arm64") and (extra == "metal")
|
|
138
|
-
Requires-Dist: tensorflow-text (==2.14.0) ; sys_platform != "win32" and
|
|
135
|
+
Requires-Dist: tensorflow-text (==2.14.0) ; sys_platform != "win32" and platform_machine != "arm64" and platform_machine != "aarch64"
|
|
139
136
|
Requires-Dist: tensorflow_hub (>=0.13.0,<0.14.0)
|
|
140
137
|
Requires-Dist: terminaltables (>=3.1.10,<3.2.0)
|
|
141
138
|
Requires-Dist: tiktoken (>=0.7.0,<0.8.0)
|
|
@@ -148,8 +145,8 @@ Requires-Dist: typing-utils (>=0.1.0,<0.2.0)
|
|
|
148
145
|
Requires-Dist: ujson (>=5.8,<6.0)
|
|
149
146
|
Requires-Dist: webexteamssdk (>=1.6.1,<1.7.0)
|
|
150
147
|
Requires-Dist: websockets (>=10.4,<11.0)
|
|
151
|
-
Requires-Dist: wheel (>=0.40.0)
|
|
152
148
|
Project-URL: Documentation, https://rasa.com/docs
|
|
149
|
+
Project-URL: Homepage, https://rasa.com
|
|
153
150
|
Project-URL: Repository, https://github.com/rasahq/rasa
|
|
154
151
|
Description-Content-Type: text/markdown
|
|
155
152
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
README.md,sha256=rn81McEFcq6MM6i5ZVs-MV7HQd4ffBVtBeVV2DvF7Bo,3175
|
|
2
1
|
rasa/__init__.py,sha256=YXG8RzVxiSJ__v-AewtV453YoCbmzWlHsU_4S0O2XpE,206
|
|
3
2
|
rasa/__main__.py,sha256=OmUXcaA9l7KR_eSYCwaCSetuczxjrcN2taNnZ2ZUTbA,6472
|
|
4
3
|
rasa/anonymization/__init__.py,sha256=Z-ZUW2ofZGfI6ysjYIS7U0JL4JSzDNOkHiiXK488Zik,86
|
|
@@ -269,7 +268,7 @@ rasa/core/channels/telegram.py,sha256=TKVknsk3U9tYeY1a8bzlhqkltWmZfGSOvrcmwa9qoz
|
|
|
269
268
|
rasa/core/channels/twilio.py,sha256=2BTQpyx0b0yPpc0A2BHYfxLPgodrLGLs8nq6i3lVGAM,5906
|
|
270
269
|
rasa/core/channels/vier_cvg.py,sha256=GkrWKu7NRMFtLMyYp-kQ2taWAc_keAwhYrkVPW56iaU,13544
|
|
271
270
|
rasa/core/channels/voice_ready/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
272
|
-
rasa/core/channels/voice_ready/audiocodes.py,sha256=
|
|
271
|
+
rasa/core/channels/voice_ready/audiocodes.py,sha256=s9tA6Tv2Ywro0YP_XhoKO7Q92g5MbPPzw6GdFij4cwk,19833
|
|
273
272
|
rasa/core/channels/voice_ready/jambonz.py,sha256=r7O8k_X934lQe0fzY7R0z_hMeX5qMN663bTugQ1-8eQ,4154
|
|
274
273
|
rasa/core/channels/voice_ready/jambonz_protocol.py,sha256=idWArI4SRr4fjyZx3VIUoua_cbLwpvw4e5VeHyQjE8E,12975
|
|
275
274
|
rasa/core/channels/voice_ready/twilio_voice.py,sha256=5N5dQ2l_u8CC9J16USgufl6MB1bJziCky7VT58MPt68,14520
|
|
@@ -281,10 +280,10 @@ rasa/core/channels/voice_stream/asr/asr_event.py,sha256=skPwrkRrcsptmeWXu9q68i4B
|
|
|
281
280
|
rasa/core/channels/voice_stream/asr/azure.py,sha256=uqg2xAmGfP8N9pts_AT6KxobiuQIqRy1lkyU7vqC564,5845
|
|
282
281
|
rasa/core/channels/voice_stream/asr/deepgram.py,sha256=9cIqRuv9gWzOfEKxeDbhijGoT8EPUV7Oo493WXaHlBo,5682
|
|
283
282
|
rasa/core/channels/voice_stream/audio_bytes.py,sha256=3V0QQplPD-kVfebaaeVcKgV7pwIJyjnTenujVD3y3sY,340
|
|
284
|
-
rasa/core/channels/voice_stream/audiocodes.py,sha256=
|
|
283
|
+
rasa/core/channels/voice_stream/audiocodes.py,sha256=WVAd5ksO97y7a6Wvv6PqQKQVgS1_IdRXeDIjnl6IAkY,12498
|
|
285
284
|
rasa/core/channels/voice_stream/browser_audio.py,sha256=fDwp-yaalik8R92EOJHsgHMuNAg9yoeGWVRGMCH2lJQ,3939
|
|
286
285
|
rasa/core/channels/voice_stream/call_state.py,sha256=fbwVbT0ddE7AjTYjx-Mq5jBMEGXanbug5wlBwstaews,899
|
|
287
|
-
rasa/core/channels/voice_stream/genesys.py,sha256
|
|
286
|
+
rasa/core/channels/voice_stream/genesys.py,sha256=EyZ4G3gfiQ5HXP6jslTjXRBYVEhpyO8nK5r6znQtHtE,16965
|
|
288
287
|
rasa/core/channels/voice_stream/tts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
289
288
|
rasa/core/channels/voice_stream/tts/azure.py,sha256=Fj9vLg-8d6aCoDcycDMG0oIPl5gw7Nhb8MXb-wBvLhE,4221
|
|
290
289
|
rasa/core/channels/voice_stream/tts/cartesia.py,sha256=cH2eHicZ_NCWtDH-cn9Chq8SSm-1agJRy-ieDJCVlD4,5407
|
|
@@ -336,7 +335,7 @@ rasa/core/policies/flows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
336
335
|
rasa/core/policies/flows/flow_exceptions.py,sha256=_FQuN-cerQDM1pivce9bz4zylh5UYkljvYS1gjDukHI,1527
|
|
337
336
|
rasa/core/policies/flows/flow_executor.py,sha256=1KJhBovD9INHVF7PQD4N7CH46JFfPrsy7QXnnGAPlNU,26938
|
|
338
337
|
rasa/core/policies/flows/flow_step_result.py,sha256=agjPrD6lahGSe2ViO5peBeoMdI9ngVGRSgtytgxmJmg,1360
|
|
339
|
-
rasa/core/policies/intentless_policy.py,sha256=
|
|
338
|
+
rasa/core/policies/intentless_policy.py,sha256=rSETeSDC3jodKvVeNeBc5OBptpSCsEYJdeJEB0b2p3U,36091
|
|
340
339
|
rasa/core/policies/intentless_prompt_template.jinja2,sha256=KhIL3cruMmkxhrs5oVbqgSvK6ZiN_6TQ_jXrgtEB-ZY,677
|
|
341
340
|
rasa/core/policies/memoization.py,sha256=CX2d3yP7FehSMW92Wi9NYLZei7tBzoT3T6yybu-Nb5s,19377
|
|
342
341
|
rasa/core/policies/policy.py,sha256=5SUnPajSTSf8PzB1-jFbQPtsvR-zLN-xkjeotWOxuJc,27432
|
|
@@ -396,22 +395,23 @@ rasa/dialogue_understanding/commands/user_silence_command.py,sha256=DQjRfZk09sV1
|
|
|
396
395
|
rasa/dialogue_understanding/commands/utils.py,sha256=lyl8FSdR2kQogqdjX2NSpQVQ9D2FZpwYUG6z4yFIMlU,4057
|
|
397
396
|
rasa/dialogue_understanding/constants.py,sha256=_kB0edGV23uvhujlF193N2jk6YG0R6LC599YDX5B5vo,129
|
|
398
397
|
rasa/dialogue_understanding/generator/__init__.py,sha256=pBm0o6pnJA_0W0UOrGuVsiG4hsTNH_n5GLrz8BYQHM8,830
|
|
398
|
+
rasa/dialogue_understanding/generator/_jinja_filters.py,sha256=KuK7nGKvKzKJz6Wg3AmrLFvzneGgIyeK825MCE379wc,248
|
|
399
399
|
rasa/dialogue_understanding/generator/command_generator.py,sha256=QvYHF3w_WgyItMySUtf0B2Qmb_7SEOLONmQXdLseIt8,13184
|
|
400
400
|
rasa/dialogue_understanding/generator/command_parser.py,sha256=wf6FSgqBw5F0legg06SqKlzajIN6sc_Cov2lFY_O9MI,8109
|
|
401
|
-
rasa/dialogue_understanding/generator/constants.py,sha256=
|
|
401
|
+
rasa/dialogue_understanding/generator/constants.py,sha256=PuUckBGUZ-Tu31B0cs8yxN99BDW3PGoExZa-BlIL5v8,1108
|
|
402
402
|
rasa/dialogue_understanding/generator/flow_document_template.jinja2,sha256=f4H6vVd-_nX_RtutMh1xD3ZQE_J2OyuPHAtiltfiAPY,253
|
|
403
403
|
rasa/dialogue_understanding/generator/flow_retrieval.py,sha256=wlGnMj17-X1-siQmdSvOd7K61sRzBf82MQEL2pqDQMI,17891
|
|
404
|
-
rasa/dialogue_understanding/generator/llm_based_command_generator.py,sha256=
|
|
404
|
+
rasa/dialogue_understanding/generator/llm_based_command_generator.py,sha256=7fjjA6aPKmHd3Qml0AqEhuqIySXzVjhpYsfFcN7sPws,23950
|
|
405
405
|
rasa/dialogue_understanding/generator/llm_command_generator.py,sha256=z7jhIJ3W_5GFH-p15kVoWbigMIoY8fIJjc_j_uX7yxw,2581
|
|
406
406
|
rasa/dialogue_understanding/generator/multi_step/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
407
407
|
rasa/dialogue_understanding/generator/multi_step/fill_slots_prompt.jinja2,sha256=Y0m673tAML3cFPaLM-urMXDsBYUUcXIw9YUpkAhGUuA,2933
|
|
408
408
|
rasa/dialogue_understanding/generator/multi_step/handle_flows_prompt.jinja2,sha256=8l93_QBKBYnqLICVdiTu5ejZDE8F36BU8-qwba0px44,1927
|
|
409
409
|
rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py,sha256=kvVbUibV-OgiaLhgnmbA7UWKXKsN7TN_OjmLJfI49M8,31969
|
|
410
|
-
rasa/dialogue_understanding/generator/nlu_command_adapter.py,sha256=
|
|
410
|
+
rasa/dialogue_understanding/generator/nlu_command_adapter.py,sha256=cisxLlPVQXgbWMAz9xSxBvrOz4HO-f0G3CFVjJ2wt-g,10876
|
|
411
411
|
rasa/dialogue_understanding/generator/prompt_templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
412
412
|
rasa/dialogue_understanding/generator/prompt_templates/command_prompt_template.jinja2,sha256=nMayu-heJYH1QmcL1cFmXb8SeiJzfdDR_9Oy5IRUXsM,3937
|
|
413
|
-
rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2,sha256=
|
|
414
|
-
rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2,sha256=
|
|
413
|
+
rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2,sha256=z-cnFVfIE_kEnY1o52YE2CdCWwgYTv7R3xVxsjXWlnw,3808
|
|
414
|
+
rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2,sha256=4076ARsy0E0iADBX6li19IoM3F4F-2wK3bL6UEOvCdo,3620
|
|
415
415
|
rasa/dialogue_understanding/generator/single_step/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
416
416
|
rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py,sha256=jRnc_vp95kR5qkEHyGnq3VGuMxdho88a0KZis96NbWU,21735
|
|
417
417
|
rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py,sha256=cvWsl-hYUgZ_tIQmWjMM1RQwsgRTlZ_osfLaUQiBk-U,4543
|
|
@@ -438,8 +438,8 @@ rasa/dialogue_understanding/patterns/skip_question.py,sha256=fJ1MC0WEEtS-BpnGJEf
|
|
|
438
438
|
rasa/dialogue_understanding/patterns/user_silence.py,sha256=xP-QMnd-MsybH5z4g01hBv4OLOHcw6m3rc26LQfe2zo,1140
|
|
439
439
|
rasa/dialogue_understanding/patterns/validate_slot.py,sha256=hqd5AEGT3M3HLNhMwuI9W9kZNCvgU6GyI-2xc2b4kz8,2085
|
|
440
440
|
rasa/dialogue_understanding/processor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
441
|
-
rasa/dialogue_understanding/processor/command_processor.py,sha256=-
|
|
442
|
-
rasa/dialogue_understanding/processor/command_processor_component.py,sha256=
|
|
441
|
+
rasa/dialogue_understanding/processor/command_processor.py,sha256=-x0sS1btKChMRMResArpdZiskbLJABu9JowL6vIBlas,32335
|
|
442
|
+
rasa/dialogue_understanding/processor/command_processor_component.py,sha256=nvp_q-vM2ZEa7sbNMjRhEeuvmCwVWQl1ckTf0UAXuH4,1606
|
|
443
443
|
rasa/dialogue_understanding/stack/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
444
444
|
rasa/dialogue_understanding/stack/dialogue_stack.py,sha256=cYV6aQeh0EuOJHODDqK3biqXozYTX8baPgLwHhPxFqs,5244
|
|
445
445
|
rasa/dialogue_understanding/stack/frames/__init__.py,sha256=wczg4PXtwGlCcRWT4gdtwgO-ZHVDcEYG11qDMe5hRNw,656
|
|
@@ -479,7 +479,7 @@ rasa/e2e_test/e2e_test_coverage_report.py,sha256=zO_3hQIuCf4r9YIbQ2_DHM7HCWHe9pZ
|
|
|
479
479
|
rasa/e2e_test/e2e_test_result.py,sha256=qVurjFC4cAWIY7rOsc-A-4nIdcnnw98TaK86-bDwI7Y,1649
|
|
480
480
|
rasa/e2e_test/e2e_test_runner.py,sha256=eXV5DJ0rAVY7FAXYI9aKvYqZXdfsE92y6deEUqUvrTY,47965
|
|
481
481
|
rasa/e2e_test/e2e_test_schema.yml,sha256=0deWjuKRHNo6e_LSCnUoiw9NLIYf6dj1-zFPl_AqLYA,5632
|
|
482
|
-
rasa/e2e_test/llm_judge_prompts/answer_relevance_prompt_template.jinja2,sha256=
|
|
482
|
+
rasa/e2e_test/llm_judge_prompts/answer_relevance_prompt_template.jinja2,sha256=6Ddszg4Y6sIvhH7C1jjEAArpzke48mfCOa2KUQYbNVA,2725
|
|
483
483
|
rasa/e2e_test/llm_judge_prompts/groundedness_prompt_template.jinja2,sha256=jCgDbZvWn5fncr4zvB5UQSK1VJu9xDQtpY4B8GKtlmA,8226
|
|
484
484
|
rasa/e2e_test/pykwalify_extensions.py,sha256=OGYKIKYJXd2S0NrWknoQuijyBQaE-oMLkfV_eMRkGSM,1331
|
|
485
485
|
rasa/e2e_test/stub_custom_action.py,sha256=aGOdZEQVZJpfY5zaHUcG447_tdJCncgD3G85eDUlVj0,2369
|
|
@@ -513,7 +513,7 @@ rasa/engine/training/components.py,sha256=Ymz8-JcKm5A9dqPblay11Lxo_AFShkakXlsHQ9
|
|
|
513
513
|
rasa/engine/training/fingerprinting.py,sha256=RrJzkhTefKsj2A1S4yAJ4IIUZGganGTcKKdor-FfLjA,2008
|
|
514
514
|
rasa/engine/training/graph_trainer.py,sha256=jLfJZVn-mDwIOEADnx56Ly67EPf5XMpf_gH5PwRe-7o,10636
|
|
515
515
|
rasa/engine/training/hooks.py,sha256=dec5yMRNbVIJwtijhESJNlt8lbZb1KJffcBRBajuZes,5469
|
|
516
|
-
rasa/engine/validation.py,sha256=
|
|
516
|
+
rasa/engine/validation.py,sha256=bL9jDZ7VdZgi3eujqUvXHY7WdyOTVJOKYxxs-F-xGzo,60816
|
|
517
517
|
rasa/env.py,sha256=zLzQMkATVIZj6s4C7RsLLOLT8g6-Q96m5iBaHW_mEA8,480
|
|
518
518
|
rasa/exceptions.py,sha256=sUcLgF-iGK1CEQkCVar28nzap8hUhaxSJvtKu2jPLFY,2117
|
|
519
519
|
rasa/graph_components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -534,7 +534,6 @@ rasa/graph_components/validators/default_recipe_validator.py,sha256=iOVoB7zVTKes
|
|
|
534
534
|
rasa/graph_components/validators/finetuning_validator.py,sha256=VfCGytnweijKBG8bAqYp7zKZB2aRgi2ZI8R0eou5Ev4,12865
|
|
535
535
|
rasa/hooks.py,sha256=5ZMrqNz323w56MMY6E8jeZ_YXgRqq8p-yi18S2XOmbo,4061
|
|
536
536
|
rasa/jupyter.py,sha256=TCYVD4QPQIMmfA6ZwDUBOBTAECwCwbU2XOkosodLO9k,1782
|
|
537
|
-
rasa/keys,sha256=2Stg1fstgJ203cOoW1B2gGMY29fhEnjIfTVxKv_fqPo,101
|
|
538
537
|
rasa/llm_fine_tuning/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
539
538
|
rasa/llm_fine_tuning/annotation_module.py,sha256=6wBBjGwONVlikp79xAHp5g3rydEhPM6kP1bw1g-maYk,8578
|
|
540
539
|
rasa/llm_fine_tuning/conversations.py,sha256=QZVaUsfXe5iIE830Bv-_3oo8luhGfHpirvubxzOoEvA,4116
|
|
@@ -565,7 +564,7 @@ rasa/model_manager/utils.py,sha256=rS0ST-rJMuZOna90r_Ioz7gOkZ8r8vm4XAhzI0iUZOA,2
|
|
|
565
564
|
rasa/model_manager/warm_rasa_process.py,sha256=2vg8gBEUvPrr6C5W-fxtWWSajksrOaT83CTk6S4KCkg,5843
|
|
566
565
|
rasa/model_service.py,sha256=XXCaiLj2xq58n05W3R1jmTIv-V8f_7PG30kVpRxf71Y,3727
|
|
567
566
|
rasa/model_testing.py,sha256=eZw7l8Zz3HkH_ZPBurY93HzzudHdoQn8HBnDdZSysAY,14929
|
|
568
|
-
rasa/model_training.py,sha256=
|
|
567
|
+
rasa/model_training.py,sha256=1opig8_npw7dLHd8k06ZYUQCrJ61sFIbNHBgvF63yH8,21733
|
|
569
568
|
rasa/nlu/__init__.py,sha256=D0IYuTK_ZQ_F_9xsy0bXxVCAtU62Fzvp8S7J9tmfI_c,123
|
|
570
569
|
rasa/nlu/classifiers/__init__.py,sha256=Qvrf7_rfiMxm2Vt2fClb56R3QFExf7WPdFdL-AOvgsk,118
|
|
571
570
|
rasa/nlu/classifiers/classifier.py,sha256=9fm1mORuFf1vowYIXmqE9yLRKdSC4nGQW7UqNZQipKY,133
|
|
@@ -627,12 +626,12 @@ rasa/nlu/utils/spacy_utils.py,sha256=5EnHR-MVAZhGbg2rq8VpOu7I0tagV3ThRTlM0-WO2Cg
|
|
|
627
626
|
rasa/plugin.py,sha256=cSmFhSWr5WQyYXdJOWwgH4ra_2kbhoNLZAtnqcsGny4,3071
|
|
628
627
|
rasa/server.py,sha256=eomGM_3SpBxaF_-VfZbkSO_bMk_vI1XLUZjt32f4gcI,59390
|
|
629
628
|
rasa/shared/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
630
|
-
rasa/shared/constants.py,sha256=
|
|
629
|
+
rasa/shared/constants.py,sha256=lGZKYydyfIKz98ZYyXKM0quCatB4R3mPXZZZ0AIHlfY,12073
|
|
631
630
|
rasa/shared/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
632
631
|
rasa/shared/core/command_payload_reader.py,sha256=puHYsp9xbX0YQm2L1NDBItOFmdzI7AzmfGefgcHiCc0,3871
|
|
633
632
|
rasa/shared/core/constants.py,sha256=kbaZlfjhJWrRhWhYRBjGCj6TeHF03-wuXcD9FXX1plY,6632
|
|
634
633
|
rasa/shared/core/conversation.py,sha256=0nUhcbQkPDnO3_Rig7oiinrWmPy5fsVQs_U6Fx1hG5c,1384
|
|
635
|
-
rasa/shared/core/domain.py,sha256=
|
|
634
|
+
rasa/shared/core/domain.py,sha256=piJu4Kr2exC9ehC3e2oNaxPxXkeIhOYoQJQQOuzMw18,81638
|
|
636
635
|
rasa/shared/core/events.py,sha256=kTUWSpDepj3kpjjXveYXz3h2XcIQV3Sq8h7MTbx5fMw,86489
|
|
637
636
|
rasa/shared/core/flows/__init__.py,sha256=Z4pBY0qcEbHeOwgmKsyg2Nz4dX9CF67fFCwj2KXSMpg,180
|
|
638
637
|
rasa/shared/core/flows/constants.py,sha256=0HN3k-apOb_fi8E2AJtUxMxro8jwFVyXQpil-tHEzbM,340
|
|
@@ -660,7 +659,9 @@ rasa/shared/core/flows/utils.py,sha256=jOp063Lkt5ZZ832K6gLnlGU6HjHe5iLDzMLiGvugS
|
|
|
660
659
|
rasa/shared/core/flows/validation.py,sha256=4IfTR8LoaJcqP8I7NQXjl0Ysmwc7VO7YzCshpiDEDP0,27410
|
|
661
660
|
rasa/shared/core/flows/yaml_flows_io.py,sha256=85ln95jpkh7ZqDl1cheFa8Q21gnadLjWrW8ADmQlrUQ,14385
|
|
662
661
|
rasa/shared/core/generator.py,sha256=UAuBPu5UjUhL9djVK-PvrWZcNhRACOEgnRsTleV7eeY,35686
|
|
663
|
-
rasa/shared/core/
|
|
662
|
+
rasa/shared/core/policies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
663
|
+
rasa/shared/core/policies/utils.py,sha256=rWE_-48Ovc__V7wOKCJ-2lTerVRtN3iRHV4ZvuU2b2g,3070
|
|
664
|
+
rasa/shared/core/slot_mappings.py,sha256=t-YAYmZpKTkEfrkZuOkJ1ZPcct29lIZJYmp1SsUgoJA,26410
|
|
664
665
|
rasa/shared/core/slots.py,sha256=KOGC5dqW7yLIZZrNqoMBrqqEmaJMNbKB_0yW7d__1yM,29211
|
|
665
666
|
rasa/shared/core/trackers.py,sha256=fgSBpaoVm98dQjFhfJGxaDiQN7Gg94AnT_Rk4z_UEms,45271
|
|
666
667
|
rasa/shared/core/training_data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -781,7 +782,7 @@ rasa/tracing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
781
782
|
rasa/tracing/config.py,sha256=32X2rqAiHe0e-Iijb5AivjqDs2j03n8xx5mo07NBMI4,12964
|
|
782
783
|
rasa/tracing/constants.py,sha256=-3vlfI9v_D8f-KB5tuiqBHhszu2WofFQOyjKBn28gyg,2889
|
|
783
784
|
rasa/tracing/instrumentation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
784
|
-
rasa/tracing/instrumentation/attribute_extractors.py,sha256=
|
|
785
|
+
rasa/tracing/instrumentation/attribute_extractors.py,sha256=hkdnqIn8PkD1ykxGbPMv-TPHbhtLgOoMQGmwcvfhi2c,29471
|
|
785
786
|
rasa/tracing/instrumentation/instrumentation.py,sha256=BPI5OoZFbl90kVJzlKEz-eD8cf-CaX_x1t4V9XBhDKo,53625
|
|
786
787
|
rasa/tracing/instrumentation/intentless_policy_instrumentation.py,sha256=RgixI0FVIzBz19E3onidUpSEwjkAh8paA5_w07PMzFo,4821
|
|
787
788
|
rasa/tracing/instrumentation/metrics.py,sha256=DI_qIS6sz5KYU4QDcPKfnHxKLL_Ma3wV6diH4_vg85c,12051
|
|
@@ -822,9 +823,9 @@ rasa/utils/train_utils.py,sha256=ClJx-6x3-h3Vt6mskacgkcCUJTMXjFPe3zAcy_DfmaU,212
|
|
|
822
823
|
rasa/utils/url_tools.py,sha256=dZ1HGkVdWTJB7zYEdwoDIrEuyX9HE5WsxKKFVsXBLE0,1218
|
|
823
824
|
rasa/utils/yaml.py,sha256=KjbZq5C94ZP7Jdsw8bYYF7HASI6K4-C_kdHfrnPLpSI,2000
|
|
824
825
|
rasa/validator.py,sha256=tAFzUKVbCPRPx0LjCUKY0zSCaX2hgINuaMfK123FCyc,88716
|
|
825
|
-
rasa/version.py,sha256=
|
|
826
|
-
rasa_pro-3.12.
|
|
827
|
-
rasa_pro-3.12.
|
|
828
|
-
rasa_pro-3.12.
|
|
829
|
-
rasa_pro-3.12.
|
|
830
|
-
rasa_pro-3.12.
|
|
826
|
+
rasa/version.py,sha256=dCdw26gY8ytDoDFG56GDqpByHMafnjQY_VsX_BOyF6c,123
|
|
827
|
+
rasa_pro-3.12.6.dev1.dist-info/METADATA,sha256=NWxqRDfzBbgnaybvxSrmtRY-IHxYt_vr_Q2cUCbshFU,10543
|
|
828
|
+
rasa_pro-3.12.6.dev1.dist-info/NOTICE,sha256=7HlBoMHJY9CL2GlYSfTQ-PZsVmLmVkYmMiPlTjhuCqA,218
|
|
829
|
+
rasa_pro-3.12.6.dev1.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
|
830
|
+
rasa_pro-3.12.6.dev1.dist-info/entry_points.txt,sha256=ckJ2SfEyTPgBqj_I6vm_tqY9dZF_LAPJZA335Xp0Q9U,43
|
|
831
|
+
rasa_pro-3.12.6.dev1.dist-info/RECORD,,
|
README.md
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
<h1 align="center">Rasa Pro</h1>
|
|
2
|
-
|
|
3
|
-
<div align="center">
|
|
4
|
-
|
|
5
|
-
[](https://sonarcloud.io/summary/new_code?id=RasaHQ_rasa)
|
|
6
|
-
[](https://rasa.com/docs/docs/pro/intro)
|
|
7
|
-

|
|
8
|
-
|
|
9
|
-
</div>
|
|
10
|
-
|
|
11
|
-
<hr />
|
|
12
|
-
|
|
13
|
-
Rasa Pro is a framework for building scalable, dynamic conversational AI assistants that integrate large language models (LLMs) to enable more contextually aware and agentic interactions. Whether you’re new to conversational AI or an experienced developer, Rasa Pro offers enhanced flexibility, control, and performance for mission-critical applications.
|
|
14
|
-
|
|
15
|
-
Building on the foundation of Rasa Open Source, Rasa Pro adds advanced features like CALM (Conversational AI with Language Models) and Dialogue Understanding (DU), which enable developers to shift from traditional intent-driven systems to LLM-based agents. This allows for more robust, responsive interactions that adhere strictly to business logic, while reducing risks like prompt injection and minimizing hallucinations.
|
|
16
|
-
|
|
17
|
-
**Key Features:**
|
|
18
|
-
|
|
19
|
-
- **Flows for Business Logic:** Easily define business logic through Flows, a simplified way to describe how your AI assistant should handle conversations. Flows help streamline the development process, focusing on key tasks and reducing the complexity involved in managing conversations.
|
|
20
|
-
- **Automatic Conversation Repair:** Ensure seamless interactions by automatically handling interruptions or unexpected inputs. Developers have full control to customize these repairs based on specific use cases.
|
|
21
|
-
- **Customizable and Open:** Fully customizable code that allows developers to modify Rasa Pro to meet specific requirements, ensuring flexibility and adaptability to various conversational AI needs.
|
|
22
|
-
- **Robustness and Control:** Maintain strict adherence to business logic, preventing unwanted behaviors like prompt injection and hallucinations, leading to more reliable responses and secure interactions.
|
|
23
|
-
- **Built-in Security:** Safeguard sensitive data, control access, and ensure secure deployment, essential for production environments that demand high levels of security and compliance.
|
|
24
|
-
|
|
25
|
-
A [free developer license](https://rasa.com/docs/pro/intro/#who-rasa-pro-is-for) is available so you can explore and get to know Rasa Pro. It allows you to take your assistant live in production a limited capacity. A paid license is required for larger-scale production use, but all code is visible and can be customized as needed.
|
|
26
|
-
|
|
27
|
-
To get started right now, you can
|
|
28
|
-
|
|
29
|
-
`pip install rasa-pro`
|
|
30
|
-
|
|
31
|
-
Check out our
|
|
32
|
-
|
|
33
|
-
- [Rasa-pro Quickstart](https://rasa.com/docs/learn/quickstart/pro),
|
|
34
|
-
- [Conversational AI with Language Models (CALM) conceptual rundown](https://rasa.com/docs/learn/concepts/calm),
|
|
35
|
-
- [Rasa Pro / CALM tutorial](https://rasa.com/docs/pro/tutorial), and
|
|
36
|
-
- [Rasa pro changelog](https://rasa.com/docs/reference/changelogs/rasa-pro-changelog)
|
|
37
|
-
|
|
38
|
-
for more. Also feel free to reach out to us on the [Rasa forum](https://forum.rasa.com/).
|
rasa/keys
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"segment": "CcvVD1I68Nkkxrv93cIqv1twIwrwG8nz", "sentry": "a283f1fde04347b099c8d729109dd450@o251570"}
|
|
File without changes
|
|
File without changes
|