rasa-pro 3.12.8__py3-none-any.whl → 3.12.10__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/actions/action.py +1 -1
- rasa/core/channels/studio_chat.py +25 -9
- rasa/core/channels/voice_ready/audiocodes.py +71 -31
- rasa/shared/core/flows/flow.py +121 -125
- rasa/version.py +1 -1
- {rasa_pro-3.12.8.dist-info → rasa_pro-3.12.10.dist-info}/METADATA +3 -3
- {rasa_pro-3.12.8.dist-info → rasa_pro-3.12.10.dist-info}/RECORD +10 -10
- {rasa_pro-3.12.8.dist-info → rasa_pro-3.12.10.dist-info}/NOTICE +0 -0
- {rasa_pro-3.12.8.dist-info → rasa_pro-3.12.10.dist-info}/WHEEL +0 -0
- {rasa_pro-3.12.8.dist-info → rasa_pro-3.12.10.dist-info}/entry_points.txt +0 -0
rasa/core/actions/action.py
CHANGED
|
@@ -898,7 +898,7 @@ class RemoteAction(Action):
|
|
|
898
898
|
draft["buttons"].extend(buttons)
|
|
899
899
|
|
|
900
900
|
# Avoid overwriting `draft` values with empty values
|
|
901
|
-
response = {k: v for k, v in response.items() if v}
|
|
901
|
+
response = {k: v for k, v in response.items() if v is not None}
|
|
902
902
|
draft.update(response)
|
|
903
903
|
bot_messages.append(create_bot_utterance(draft))
|
|
904
904
|
|
|
@@ -16,6 +16,7 @@ import structlog
|
|
|
16
16
|
from sanic import Sanic
|
|
17
17
|
|
|
18
18
|
from rasa.core.channels.socketio import SocketBlueprint, SocketIOInput
|
|
19
|
+
from rasa.core.exceptions import AgentNotReady
|
|
19
20
|
from rasa.hooks import hookimpl
|
|
20
21
|
from rasa.plugin import plugin_manager
|
|
21
22
|
from rasa.shared.core.constants import ACTION_LISTEN_NAME
|
|
@@ -149,8 +150,15 @@ class StudioChatInput(SocketIOInput):
|
|
|
149
150
|
"""
|
|
150
151
|
await on_new_message(message)
|
|
151
152
|
|
|
152
|
-
if not self.agent:
|
|
153
|
+
if not self.agent or not self.agent.is_ready():
|
|
153
154
|
structlogger.error("studio_chat.on_message_proxy.agent_not_initialized")
|
|
155
|
+
await self.emit_error(
|
|
156
|
+
"The Rasa Pro model could not be loaded. "
|
|
157
|
+
"Please check the training and deployment logs "
|
|
158
|
+
"for more information.",
|
|
159
|
+
message.sender_id,
|
|
160
|
+
AgentNotReady("The Rasa Pro model could not be loaded."),
|
|
161
|
+
)
|
|
154
162
|
return
|
|
155
163
|
|
|
156
164
|
tracker = await self.agent.tracker_store.retrieve(message.sender_id)
|
|
@@ -160,6 +168,17 @@ class StudioChatInput(SocketIOInput):
|
|
|
160
168
|
|
|
161
169
|
await self.on_tracker_updated(tracker)
|
|
162
170
|
|
|
171
|
+
async def emit_error(self, message: str, room: str, e: Exception) -> None:
|
|
172
|
+
await self.emit(
|
|
173
|
+
"error",
|
|
174
|
+
{
|
|
175
|
+
"message": message,
|
|
176
|
+
"error": str(e),
|
|
177
|
+
"exception": str(type(e).__name__),
|
|
178
|
+
},
|
|
179
|
+
room=room,
|
|
180
|
+
)
|
|
181
|
+
|
|
163
182
|
async def handle_tracker_update(self, sid: str, data: Dict) -> None:
|
|
164
183
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
165
184
|
|
|
@@ -200,15 +219,12 @@ class StudioChatInput(SocketIOInput):
|
|
|
200
219
|
error=e,
|
|
201
220
|
sender_id=data["sender_id"],
|
|
202
221
|
)
|
|
203
|
-
await self.
|
|
204
|
-
"error",
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
"error": str(e),
|
|
208
|
-
"exception": str(type(e).__name__),
|
|
209
|
-
},
|
|
210
|
-
room=sid,
|
|
222
|
+
await self.emit_error(
|
|
223
|
+
"An error occurred while updating the conversation.",
|
|
224
|
+
data["sender_id"],
|
|
225
|
+
e,
|
|
211
226
|
)
|
|
227
|
+
|
|
212
228
|
if not tracker:
|
|
213
229
|
# in case the tracker couldn't be updated, we retrieve the prior
|
|
214
230
|
# version and use that to populate the update
|
|
@@ -6,7 +6,18 @@ import uuid
|
|
|
6
6
|
from collections import defaultdict
|
|
7
7
|
from dataclasses import asdict
|
|
8
8
|
from datetime import datetime, timedelta, timezone
|
|
9
|
-
from typing import
|
|
9
|
+
from typing import (
|
|
10
|
+
Any,
|
|
11
|
+
Awaitable,
|
|
12
|
+
Callable,
|
|
13
|
+
Dict,
|
|
14
|
+
List,
|
|
15
|
+
Optional,
|
|
16
|
+
Set,
|
|
17
|
+
Text,
|
|
18
|
+
Tuple,
|
|
19
|
+
Union,
|
|
20
|
+
)
|
|
10
21
|
|
|
11
22
|
import structlog
|
|
12
23
|
from jsonschema import ValidationError, validate
|
|
@@ -76,35 +87,45 @@ class Conversation:
|
|
|
76
87
|
|
|
77
88
|
@staticmethod
|
|
78
89
|
def get_metadata(activity: Dict[Text, Any]) -> Optional[Dict[Text, Any]]:
|
|
79
|
-
"""Get metadata from the activity.
|
|
80
|
-
|
|
90
|
+
"""Get metadata from the activity.
|
|
91
|
+
|
|
92
|
+
ONLY used for activities NOT for events (see _handle_event)."""
|
|
93
|
+
return activity.get("parameters")
|
|
81
94
|
|
|
82
95
|
@staticmethod
|
|
83
|
-
def _handle_event(event: Dict[Text, Any]) -> Text:
|
|
84
|
-
"""Handle
|
|
96
|
+
def _handle_event(event: Dict[Text, Any]) -> Tuple[Text, Dict[Text, Any]]:
|
|
97
|
+
"""Handle events and return a tuple of text and metadata.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
event: The event to handle.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Tuple of text and metadata.
|
|
104
|
+
text is either /session_start or /vaig_event_<event_name>
|
|
105
|
+
metadata is a dictionary with the event parameters.
|
|
106
|
+
"""
|
|
85
107
|
structlogger.debug("audiocodes.handle.event", event_payload=event)
|
|
86
108
|
if "name" not in event:
|
|
87
109
|
structlogger.warning(
|
|
88
110
|
"audiocodes.handle.event.no_name_key", event_payload=event
|
|
89
111
|
)
|
|
90
|
-
return ""
|
|
112
|
+
return "", {}
|
|
91
113
|
|
|
92
114
|
if event["name"] == EVENT_START:
|
|
93
115
|
text = f"{INTENT_MESSAGE_PREFIX}{USER_INTENT_SESSION_START}"
|
|
116
|
+
metadata = asdict(map_call_params(event.get("parameters", {})))
|
|
94
117
|
elif event["name"] == EVENT_DTMF:
|
|
95
118
|
text = f"{INTENT_MESSAGE_PREFIX}vaig_event_DTMF"
|
|
96
|
-
|
|
97
|
-
text += json.dumps(event_params)
|
|
119
|
+
metadata = {"value": event["value"]}
|
|
98
120
|
else:
|
|
99
121
|
# handle other events described by Audiocodes
|
|
100
122
|
# https://techdocs.audiocodes.com/voice-ai-connect/#VAIG_Combined/inactivity-detection.htm?TocPath=Bot%2520integration%257CReceiving%2520notifications%257C_____3
|
|
101
123
|
text = f"{INTENT_MESSAGE_PREFIX}vaig_event_{event['name']}"
|
|
102
|
-
|
|
124
|
+
metadata = {**event.get("parameters", {})}
|
|
103
125
|
if "value" in event:
|
|
104
|
-
|
|
105
|
-
text += json.dumps(event_params)
|
|
126
|
+
metadata["value"] = event["value"]
|
|
106
127
|
|
|
107
|
-
return text
|
|
128
|
+
return text, metadata
|
|
108
129
|
|
|
109
130
|
def is_active_conversation(self, now: datetime, delta: timedelta) -> bool:
|
|
110
131
|
"""Check if the conversation is active."""
|
|
@@ -139,21 +160,29 @@ class Conversation:
|
|
|
139
160
|
structlogger.warning(
|
|
140
161
|
"audiocodes.handle.activities.duplicate_activity",
|
|
141
162
|
activity_id=activity[ACTIVITY_ID_KEY],
|
|
163
|
+
event_info=(
|
|
164
|
+
"Audiocodes might send duplicate activities if the bot has not "
|
|
165
|
+
"responded to the previous one or responded too late. Please "
|
|
166
|
+
"consider enabling the `use_websocket` option to use"
|
|
167
|
+
" Audiocodes Asynchronous API."
|
|
168
|
+
),
|
|
142
169
|
)
|
|
143
170
|
continue
|
|
144
171
|
self.activity_ids.append(activity[ACTIVITY_ID_KEY])
|
|
145
172
|
if activity["type"] == ACTIVITY_MESSAGE:
|
|
146
173
|
text = activity["text"]
|
|
174
|
+
metadata = self.get_metadata(activity)
|
|
147
175
|
elif activity["type"] == ACTIVITY_EVENT:
|
|
148
|
-
text = self._handle_event(activity)
|
|
176
|
+
text, metadata = self._handle_event(activity)
|
|
149
177
|
else:
|
|
150
178
|
structlogger.warning(
|
|
151
179
|
"audiocodes.handle.activities.unknown_activity_type",
|
|
152
180
|
activity=activity,
|
|
153
181
|
)
|
|
182
|
+
continue
|
|
183
|
+
|
|
154
184
|
if not text:
|
|
155
185
|
continue
|
|
156
|
-
metadata = self.get_metadata(activity)
|
|
157
186
|
user_msg = UserMessage(
|
|
158
187
|
text=text,
|
|
159
188
|
input_channel=input_channel_name,
|
|
@@ -392,30 +421,41 @@ class AudiocodesInput(InputChannel):
|
|
|
392
421
|
"audiocodes.on_activities.no_conversation", request=request.json
|
|
393
422
|
)
|
|
394
423
|
return response.json({})
|
|
395
|
-
|
|
424
|
+
|
|
425
|
+
if self.use_websocket:
|
|
426
|
+
# send an empty response for this request
|
|
427
|
+
# activities are processed in the background
|
|
428
|
+
# chat response is sent via the websocket
|
|
396
429
|
ac_output: Union[WebsocketOutput, AudiocodesOutput] = WebsocketOutput(
|
|
397
430
|
conversation.ws, conversation_id
|
|
398
431
|
)
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
432
|
+
self._create_task(
|
|
433
|
+
conversation_id,
|
|
434
|
+
conversation.handle_activities(
|
|
435
|
+
request.json,
|
|
436
|
+
input_channel_name=self.name(),
|
|
437
|
+
output_channel=ac_output,
|
|
438
|
+
on_new_message=on_new_message,
|
|
439
|
+
),
|
|
440
|
+
)
|
|
441
|
+
return response.json({})
|
|
442
|
+
|
|
443
|
+
# without websockets, this becomes a blocking call
|
|
444
|
+
# and the response is sent back to the Audiocodes server
|
|
445
|
+
# after the activities are processed
|
|
446
|
+
ac_output = AudiocodesOutput()
|
|
447
|
+
await conversation.handle_activities(
|
|
448
|
+
request.json,
|
|
449
|
+
input_channel_name=self.name(),
|
|
450
|
+
output_channel=ac_output,
|
|
451
|
+
on_new_message=on_new_message,
|
|
452
|
+
)
|
|
453
|
+
return response.json(
|
|
454
|
+
{
|
|
404
455
|
"conversation": conversation_id,
|
|
405
456
|
"activities": ac_output.messages,
|
|
406
457
|
}
|
|
407
|
-
|
|
408
|
-
# start a background task to handle activities
|
|
409
|
-
self._create_task(
|
|
410
|
-
conversation_id,
|
|
411
|
-
conversation.handle_activities(
|
|
412
|
-
request.json,
|
|
413
|
-
input_channel_name=self.name(),
|
|
414
|
-
output_channel=ac_output,
|
|
415
|
-
on_new_message=on_new_message,
|
|
416
|
-
),
|
|
417
458
|
)
|
|
418
|
-
return response.json(response_json)
|
|
419
459
|
|
|
420
460
|
@ac_webhook.route(
|
|
421
461
|
"/conversation/<conversation_id>/disconnect", methods=["POST"]
|
rasa/shared/core/flows/flow.py
CHANGED
|
@@ -38,6 +38,7 @@ from rasa.shared.core.flows.flow_step_sequence import FlowStepSequence
|
|
|
38
38
|
from rasa.shared.core.flows.nlu_trigger import NLUTriggers
|
|
39
39
|
from rasa.shared.core.flows.steps import (
|
|
40
40
|
ActionFlowStep,
|
|
41
|
+
CallFlowStep,
|
|
41
42
|
CollectInformationFlowStep,
|
|
42
43
|
EndFlowStep,
|
|
43
44
|
StartFlowStep,
|
|
@@ -466,161 +467,156 @@ class Flow:
|
|
|
466
467
|
and a set of visited step IDs to prevent revisiting steps.
|
|
467
468
|
It calls `go_over_steps` to recursively explore and fill the paths list.
|
|
468
469
|
"""
|
|
469
|
-
|
|
470
|
-
|
|
470
|
+
all_paths = FlowPathsList(self.id, paths=[])
|
|
471
|
+
start_step: FlowStep = self.first_step_in_flow()
|
|
471
472
|
current_path: FlowPath = FlowPath(flow=self.id, nodes=[])
|
|
472
|
-
|
|
473
|
+
visited_step_ids: Set[str] = set()
|
|
473
474
|
|
|
474
|
-
self._go_over_steps(
|
|
475
|
-
|
|
476
|
-
if not flow_paths_list.is_path_part_of_list(current_path):
|
|
477
|
-
flow_paths_list.paths.append(copy.deepcopy(current_path))
|
|
475
|
+
self._go_over_steps(start_step, current_path, all_paths, visited_step_ids)
|
|
478
476
|
|
|
479
477
|
structlogger.debug(
|
|
480
478
|
"shared.core.flows.flow.extract_all_paths",
|
|
481
479
|
comment="Extraction complete",
|
|
482
|
-
number_of_paths=len(
|
|
480
|
+
number_of_paths=len(all_paths.paths),
|
|
483
481
|
flow_name=self.name,
|
|
484
482
|
)
|
|
485
|
-
return
|
|
483
|
+
return all_paths
|
|
486
484
|
|
|
487
485
|
def _go_over_steps(
|
|
488
486
|
self,
|
|
489
|
-
|
|
487
|
+
current_step: FlowStep,
|
|
490
488
|
current_path: FlowPath,
|
|
491
|
-
|
|
492
|
-
|
|
489
|
+
all_paths: FlowPathsList,
|
|
490
|
+
visited_step_ids: Set[str],
|
|
493
491
|
) -> None:
|
|
494
492
|
"""Processes the flow steps recursively.
|
|
495
493
|
|
|
496
|
-
Either following direct step IDs or handling conditions, and adds complete
|
|
497
|
-
paths to the collected_paths.
|
|
498
|
-
|
|
499
494
|
Args:
|
|
500
|
-
|
|
495
|
+
current_step: The current step being processed.
|
|
501
496
|
current_path: The current path being constructed.
|
|
502
|
-
|
|
503
|
-
|
|
497
|
+
all_paths: The list where completed paths are added.
|
|
498
|
+
visited_step_ids: A set of steps that have been visited to avoid cycles.
|
|
504
499
|
|
|
505
500
|
Returns:
|
|
506
|
-
None: This function modifies
|
|
501
|
+
None: This function modifies all_paths in place by appending new paths
|
|
507
502
|
as they are found.
|
|
508
503
|
"""
|
|
509
|
-
#
|
|
510
|
-
#
|
|
511
|
-
#
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
# We only create new path nodes for ActionFlowStep and
|
|
526
|
-
# CollectInformationFlowStep because these are externally visible
|
|
527
|
-
# changes in the assistant's behaviour (trackable in the e2e tests).
|
|
528
|
-
# For other flow steps, we only follow their links.
|
|
529
|
-
# We decided to ignore calls to other flows in our coverage analysis.
|
|
530
|
-
if not isinstance(step, (CollectInformationFlowStep, ActionFlowStep)):
|
|
531
|
-
self._handle_links(
|
|
532
|
-
step.next.links,
|
|
533
|
-
current_path,
|
|
534
|
-
completed_paths,
|
|
535
|
-
step_ids_visited,
|
|
536
|
-
)
|
|
537
|
-
continue
|
|
538
|
-
|
|
539
|
-
# 2. Check if already visited this custom step id
|
|
540
|
-
# in order to keep track of loops
|
|
541
|
-
if step.custom_id is not None and step.custom_id in step_ids_visited:
|
|
542
|
-
if not completed_paths.is_path_part_of_list(current_path):
|
|
543
|
-
completed_paths.paths.append(copy.deepcopy(current_path))
|
|
544
|
-
return # Stop traversing this path if we've revisited a step
|
|
545
|
-
elif step.custom_id is not None:
|
|
546
|
-
step_ids_visited.add(step.custom_id)
|
|
547
|
-
|
|
548
|
-
# 3. Append step info to the path
|
|
549
|
-
current_path.nodes.append(
|
|
550
|
-
PathNode(
|
|
551
|
-
flow=current_path.flow,
|
|
552
|
-
step_id=step.id,
|
|
553
|
-
lines=step.metadata["line_numbers"],
|
|
554
|
-
)
|
|
504
|
+
# Check if the step is relevant for testable_paths extraction.
|
|
505
|
+
# We only create new path nodes for ActionFlowStep, CallFlowStep and
|
|
506
|
+
# CollectInformationFlowStep because these are externally visible
|
|
507
|
+
# changes in the assistant's behaviour (trackable in the e2e tests).
|
|
508
|
+
# For other flow steps, we only follow their links.
|
|
509
|
+
# We decided to ignore calls to other flows in our coverage analysis.
|
|
510
|
+
should_add_node = isinstance(
|
|
511
|
+
current_step, (CollectInformationFlowStep, ActionFlowStep, CallFlowStep)
|
|
512
|
+
)
|
|
513
|
+
if should_add_node:
|
|
514
|
+
# Add current step to the current path that is being constructed.
|
|
515
|
+
current_path.nodes.append(
|
|
516
|
+
PathNode(
|
|
517
|
+
flow=current_path.flow,
|
|
518
|
+
step_id=current_step.id,
|
|
519
|
+
lines=current_step.metadata["line_numbers"],
|
|
555
520
|
)
|
|
521
|
+
)
|
|
556
522
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
)
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
523
|
+
if current_step.id in visited_step_ids or self.is_end_of_path(current_step):
|
|
524
|
+
# Found a cycle, or reached an end step, do not proceed further.
|
|
525
|
+
all_paths.paths.append(copy.deepcopy(current_path))
|
|
526
|
+
# Remove the last node from the path if it was added.
|
|
527
|
+
if should_add_node:
|
|
528
|
+
current_path.nodes.pop()
|
|
529
|
+
return
|
|
530
|
+
|
|
531
|
+
# Mark current step as visited in this path.
|
|
532
|
+
visited_step_ids.add(current_step.id)
|
|
533
|
+
|
|
534
|
+
# Iterate over all links of the current step.
|
|
535
|
+
for link in current_step.next.links:
|
|
536
|
+
self._handle_link(
|
|
537
|
+
current_path,
|
|
538
|
+
all_paths,
|
|
539
|
+
visited_step_ids,
|
|
540
|
+
link,
|
|
541
|
+
)
|
|
542
|
+
|
|
543
|
+
# Backtrack the current step and remove it from the path.
|
|
544
|
+
visited_step_ids.remove(current_step.id)
|
|
573
545
|
|
|
574
|
-
|
|
546
|
+
# Remove the last node from the path if it was added.
|
|
547
|
+
if should_add_node:
|
|
548
|
+
current_path.nodes.pop()
|
|
549
|
+
|
|
550
|
+
def _handle_link(
|
|
575
551
|
self,
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
552
|
+
current_path: FlowPath,
|
|
553
|
+
all_paths: FlowPathsList,
|
|
554
|
+
visited_step_ids: Set[str],
|
|
555
|
+
link: FlowStepLink,
|
|
580
556
|
) -> None:
|
|
581
|
-
"""
|
|
582
|
-
|
|
583
|
-
Potentially recursively calling itself to handle conditional paths and
|
|
584
|
-
branching.
|
|
557
|
+
"""Handles the next step in a flow.
|
|
585
558
|
|
|
586
559
|
Args:
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
to avoid loops.
|
|
560
|
+
current_path: The current path being constructed.
|
|
561
|
+
all_paths: The list where completed paths are added.
|
|
562
|
+
visited_step_ids: A set of steps that have been visited to avoid cycles.
|
|
563
|
+
link: The link to be followed.
|
|
592
564
|
|
|
593
565
|
Returns:
|
|
594
|
-
None:
|
|
595
|
-
as they are
|
|
566
|
+
None: This function modifies all_paths in place by appending new paths
|
|
567
|
+
as they are found.
|
|
596
568
|
"""
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
if isinstance(link, StaticFlowStepLink):
|
|
602
|
-
# Find this id in the flow steps and restart from there
|
|
603
|
-
for i, step in enumerate(steps):
|
|
604
|
-
if step.id == link.target_step_id:
|
|
605
|
-
self._go_over_steps(
|
|
606
|
-
steps[i:],
|
|
607
|
-
copy.deepcopy(path),
|
|
608
|
-
collected_paths,
|
|
609
|
-
copy.deepcopy(step_ids_visited),
|
|
610
|
-
)
|
|
611
|
-
|
|
612
|
-
# If conditions
|
|
613
|
-
elif isinstance(link, (IfFlowStepLink, ElseFlowStepLink)):
|
|
614
|
-
# Handling conditional paths
|
|
615
|
-
target_steps: Union[str, List[FlowStep]]
|
|
616
|
-
if isinstance(link.target_reference, FlowStepSequence):
|
|
617
|
-
target_steps = link.target_reference.child_steps
|
|
618
|
-
else:
|
|
619
|
-
target_steps = link.target_reference
|
|
620
|
-
|
|
569
|
+
# StaticFlowStepLink is a direct link to the next step.
|
|
570
|
+
if isinstance(link, StaticFlowStepLink):
|
|
571
|
+
# Find the step by its id and continue the path.
|
|
572
|
+
if step := self._get_step_by_step_id(link.target_step_id):
|
|
621
573
|
self._go_over_steps(
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
574
|
+
step,
|
|
575
|
+
current_path,
|
|
576
|
+
all_paths,
|
|
577
|
+
visited_step_ids,
|
|
626
578
|
)
|
|
579
|
+
return
|
|
580
|
+
# IfFlowStepLink and ElseFlowStepLink are conditional links.
|
|
581
|
+
elif isinstance(link, (IfFlowStepLink, ElseFlowStepLink)):
|
|
582
|
+
if isinstance(link.target_reference, FlowStepSequence):
|
|
583
|
+
# If the target is a FlowStepSequence, we need to go over all
|
|
584
|
+
# child steps of the sequence.
|
|
585
|
+
for child_step in link.target_reference.child_steps:
|
|
586
|
+
self._go_over_steps(
|
|
587
|
+
child_step,
|
|
588
|
+
current_path,
|
|
589
|
+
all_paths,
|
|
590
|
+
visited_step_ids,
|
|
591
|
+
)
|
|
592
|
+
return
|
|
593
|
+
else:
|
|
594
|
+
# Find the step by its id and continue the path.
|
|
595
|
+
if step := self._get_step_by_step_id(link.target_reference):
|
|
596
|
+
self._go_over_steps(
|
|
597
|
+
step,
|
|
598
|
+
current_path,
|
|
599
|
+
all_paths,
|
|
600
|
+
visited_step_ids,
|
|
601
|
+
)
|
|
602
|
+
return
|
|
603
|
+
|
|
604
|
+
def is_end_of_path(self, step: FlowStep) -> bool:
|
|
605
|
+
"""Check if there is no path available from the current step."""
|
|
606
|
+
if (
|
|
607
|
+
len(step.next.links) == 1
|
|
608
|
+
and isinstance(step.next.links[0], StaticFlowStepLink)
|
|
609
|
+
and step.next.links[0].target == END_STEP
|
|
610
|
+
):
|
|
611
|
+
return True
|
|
612
|
+
return False
|
|
613
|
+
|
|
614
|
+
def _get_step_by_step_id(
|
|
615
|
+
self,
|
|
616
|
+
step_id: Optional[str],
|
|
617
|
+
) -> Optional[FlowStep]:
|
|
618
|
+
"""Get a step by its id from a list of steps."""
|
|
619
|
+
for step in self.steps:
|
|
620
|
+
if step.id == step_id:
|
|
621
|
+
return step
|
|
622
|
+
return None
|
rasa/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: rasa-pro
|
|
3
|
-
Version: 3.12.
|
|
3
|
+
Version: 3.12.10
|
|
4
4
|
Summary: State-of-the-art open-core Conversational AI framework for Enterprises that natively leverages generative AI for effortless assistant development.
|
|
5
5
|
Keywords: nlp,machine-learning,machine-learning-library,bot,bots,botkit,rasa conversational-agents,conversational-ai,chatbot,chatbot-framework,bot-framework
|
|
6
6
|
Author: Rasa Technologies GmbH
|
|
@@ -63,12 +63,12 @@ Requires-Dist: keras (==2.14.0)
|
|
|
63
63
|
Requires-Dist: langchain (>=0.2.17,<0.3.0)
|
|
64
64
|
Requires-Dist: langchain-community (>=0.2.19,<0.3.0)
|
|
65
65
|
Requires-Dist: langcodes (>=3.5.0,<4.0.0)
|
|
66
|
-
Requires-Dist: litellm (
|
|
66
|
+
Requires-Dist: litellm (>=1.68.0,<1.69.0)
|
|
67
67
|
Requires-Dist: matplotlib (>=3.7,<3.8)
|
|
68
68
|
Requires-Dist: mattermostwrapper (>=2.2,<2.3)
|
|
69
69
|
Requires-Dist: networkx (>=3.1,<3.2)
|
|
70
70
|
Requires-Dist: numpy (>=1.26.4,<1.27.0)
|
|
71
|
-
Requires-Dist: openai (>=1.
|
|
71
|
+
Requires-Dist: openai (>=1.68.2,<1.69.0)
|
|
72
72
|
Requires-Dist: openpyxl (>=3.1.5,<4.0.0)
|
|
73
73
|
Requires-Dist: opentelemetry-api (>=1.16.0,<1.17.0)
|
|
74
74
|
Requires-Dist: opentelemetry-exporter-jaeger (>=1.16.0,<1.17.0)
|
|
@@ -92,7 +92,7 @@ rasa/cli/x.py,sha256=C7dLtYXAkD-uj7hNj7Pz5YbOupp2yRcMjQbsEVqXUJ8,6825
|
|
|
92
92
|
rasa/constants.py,sha256=m6If7alC5obaHU-JQWXEBo4mooVwIMzNRTjyTzzZSVg,1306
|
|
93
93
|
rasa/core/__init__.py,sha256=wTSmsFlgK0Ylvuyq20q9APwpT5xyVJYZfzhs4rrkciM,456
|
|
94
94
|
rasa/core/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
95
|
-
rasa/core/actions/action.py,sha256=
|
|
95
|
+
rasa/core/actions/action.py,sha256=_QfY3ngSF2sf2Y3QDPJo7Nd6F_FA6_zDWgw1OQSLkEk,42676
|
|
96
96
|
rasa/core/actions/action_clean_stack.py,sha256=xUP-2ipPsPAnAiwP17c-ezmHPSrV4JSUZr-eSgPQwIs,2279
|
|
97
97
|
rasa/core/actions/action_exceptions.py,sha256=hghzXYN6VeHC-O_O7WiPesCNV86ZTkHgG90ZnQcbai8,724
|
|
98
98
|
rasa/core/actions/action_hangup.py,sha256=o5iklHG-F9IcRgWis5C6AumVXznxzAV3o9zdduhozEM,994
|
|
@@ -263,12 +263,12 @@ rasa/core/channels/rest.py,sha256=ShKGmooXphhcDnHyV8TiQhDhj2r7hxTKNQ57FwFfyUA,72
|
|
|
263
263
|
rasa/core/channels/rocketchat.py,sha256=hajaH6549CjEYFM5jSapw1DQKBPKTXbn7cVSuZzknmI,5999
|
|
264
264
|
rasa/core/channels/slack.py,sha256=jVsTTUu9wUjukPoIsAhbee9o0QFUMCNlQHbR8LTcMBc,24406
|
|
265
265
|
rasa/core/channels/socketio.py,sha256=Q7Gts30Ulwj90pQQxaUk4NykzagXErXgbHYwOjTmDig,10842
|
|
266
|
-
rasa/core/channels/studio_chat.py,sha256=
|
|
266
|
+
rasa/core/channels/studio_chat.py,sha256=KUhR0Irst8pJ7zGMoeZuKquAUOYVB45i75wlVsbDqPU,9218
|
|
267
267
|
rasa/core/channels/telegram.py,sha256=TKVknsk3U9tYeY1a8bzlhqkltWmZfGSOvrcmwa9qozc,12499
|
|
268
268
|
rasa/core/channels/twilio.py,sha256=2BTQpyx0b0yPpc0A2BHYfxLPgodrLGLs8nq6i3lVGAM,5906
|
|
269
269
|
rasa/core/channels/vier_cvg.py,sha256=GkrWKu7NRMFtLMyYp-kQ2taWAc_keAwhYrkVPW56iaU,13544
|
|
270
270
|
rasa/core/channels/voice_ready/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
271
|
-
rasa/core/channels/voice_ready/audiocodes.py,sha256=
|
|
271
|
+
rasa/core/channels/voice_ready/audiocodes.py,sha256=eUUL9awt4P49LA5WC2hbsMZsi_qYHd-S3HL1Kpyj2ew,22353
|
|
272
272
|
rasa/core/channels/voice_ready/jambonz.py,sha256=bU2yrO6Gw_JcmFXeFVc8f1DK3ZDDYLQVjBB8SM2JjWc,4783
|
|
273
273
|
rasa/core/channels/voice_ready/jambonz_protocol.py,sha256=E9iwvitSDpVkL7BxbckczF4b0a8lWZt-3zR4Innflow,13116
|
|
274
274
|
rasa/core/channels/voice_ready/twilio_voice.py,sha256=z2pdausxQnXQP9htGh8AL2q9AvcMIx70Y5tErWpssV4,16224
|
|
@@ -633,7 +633,7 @@ rasa/shared/core/domain.py,sha256=piJu4Kr2exC9ehC3e2oNaxPxXkeIhOYoQJQQOuzMw18,81
|
|
|
633
633
|
rasa/shared/core/events.py,sha256=kTUWSpDepj3kpjjXveYXz3h2XcIQV3Sq8h7MTbx5fMw,86489
|
|
634
634
|
rasa/shared/core/flows/__init__.py,sha256=Z4pBY0qcEbHeOwgmKsyg2Nz4dX9CF67fFCwj2KXSMpg,180
|
|
635
635
|
rasa/shared/core/flows/constants.py,sha256=0HN3k-apOb_fi8E2AJtUxMxro8jwFVyXQpil-tHEzbM,340
|
|
636
|
-
rasa/shared/core/flows/flow.py,sha256=
|
|
636
|
+
rasa/shared/core/flows/flow.py,sha256=nW7EvfWBS9eK24GIodDUwwKY8nTaJtY6bp5Xz_IHZAc,23107
|
|
637
637
|
rasa/shared/core/flows/flow_path.py,sha256=xstwahZBU5cfMY46mREA4NoOGlKLBRAqeP_mJ3UZqOI,2283
|
|
638
638
|
rasa/shared/core/flows/flow_step.py,sha256=ZvjXz1Fs5FR1_BlGBitOEYRnLhzk-bBYv1CC2Oi6iWQ,4537
|
|
639
639
|
rasa/shared/core/flows/flow_step_links.py,sha256=U9c4MFASieJGp_-XMhR0hrxFQISCJAF4TQ0wEy4IjB0,10530
|
|
@@ -821,9 +821,9 @@ rasa/utils/train_utils.py,sha256=ClJx-6x3-h3Vt6mskacgkcCUJTMXjFPe3zAcy_DfmaU,212
|
|
|
821
821
|
rasa/utils/url_tools.py,sha256=dZ1HGkVdWTJB7zYEdwoDIrEuyX9HE5WsxKKFVsXBLE0,1218
|
|
822
822
|
rasa/utils/yaml.py,sha256=KjbZq5C94ZP7Jdsw8bYYF7HASI6K4-C_kdHfrnPLpSI,2000
|
|
823
823
|
rasa/validator.py,sha256=524VlFTYK0B3iXYveVD6BDC3K0j1QfpzJ9O-TAWczmc,83166
|
|
824
|
-
rasa/version.py,sha256=
|
|
825
|
-
rasa_pro-3.12.
|
|
826
|
-
rasa_pro-3.12.
|
|
827
|
-
rasa_pro-3.12.
|
|
828
|
-
rasa_pro-3.12.
|
|
829
|
-
rasa_pro-3.12.
|
|
824
|
+
rasa/version.py,sha256=F6TWQP94ECROLtXqlCrwu9xSrvxZDs3JVTp6gPLbxfE,118
|
|
825
|
+
rasa_pro-3.12.10.dist-info/METADATA,sha256=3wU4IxYsMJruxuysovjfW1wt7IOsh0YELYX4uvwhDhY,10616
|
|
826
|
+
rasa_pro-3.12.10.dist-info/NOTICE,sha256=7HlBoMHJY9CL2GlYSfTQ-PZsVmLmVkYmMiPlTjhuCqA,218
|
|
827
|
+
rasa_pro-3.12.10.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
|
828
|
+
rasa_pro-3.12.10.dist-info/entry_points.txt,sha256=ckJ2SfEyTPgBqj_I6vm_tqY9dZF_LAPJZA335Xp0Q9U,43
|
|
829
|
+
rasa_pro-3.12.10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|