rasa-pro 3.14.0.dev20250818__py3-none-any.whl → 3.14.0.dev20250825__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.

@@ -102,6 +102,9 @@ class UserMessage:
102
102
  return f"{self.__class__.__name__}({self.text})"
103
103
 
104
104
 
105
+ OnNewMessageType = Callable[[UserMessage], Awaitable[Any]]
106
+
107
+
105
108
  def register(
106
109
  input_channels: List[InputChannel], app: Sanic, route: Optional[Text]
107
110
  ) -> None:
@@ -135,9 +138,7 @@ class InputChannel:
135
138
  def url_prefix(self) -> Text:
136
139
  return self.name()
137
140
 
138
- def blueprint(
139
- self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
140
- ) -> Blueprint:
141
+ def blueprint(self, on_new_message: OnNewMessageType) -> Blueprint:
141
142
  """Defines a Sanic blueprint.
142
143
 
143
144
  The blueprint will be attached to a running sanic server and handle
@@ -0,0 +1,3 @@
1
+ USER_CONVERSATION_SESSION_END = "/session_end"
2
+ USER_CONVERSATION_SESSION_START = "/session_start"
3
+ USER_CONVERSATION_SILENCE_TIMEOUT = "/silence_timeout"
@@ -195,7 +195,7 @@ class DevelopmentInspectProxy(InputChannel):
195
195
  self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
196
196
  ) -> "Blueprint":
197
197
  """Defines a Sanic blueprint."""
198
- self.sio = AsyncServer(async_mode="sanic", cors_allowed_origins=[])
198
+ self.sio_server = AsyncServer(async_mode="sanic", cors_allowed_origins=[])
199
199
  underlying_webhook: Blueprint = self.underlying.blueprint(
200
200
  partial(self.on_message_proxy, on_new_message)
201
201
  )
@@ -1,34 +1,54 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
1
4
  import inspect
2
5
  import json
3
- import logging
4
6
  import uuid
7
+ from asyncio import Task
8
+ from dataclasses import dataclass
5
9
  from typing import Any, Awaitable, Callable, Dict, Iterable, List, Optional, Text
6
10
 
11
+ import structlog
7
12
  from sanic import Blueprint, Sanic, response
8
13
  from sanic.request import Request
9
14
  from sanic.response import HTTPResponse
10
15
  from socketio import AsyncServer
11
16
 
12
- import rasa.core.channels.channel
13
17
  import rasa.shared.utils.io
14
- from rasa.core.channels.channel import InputChannel, OutputChannel, UserMessage
18
+ from rasa.core.channels.channel import (
19
+ InputChannel,
20
+ OnNewMessageType,
21
+ OutputChannel,
22
+ UserMessage,
23
+ )
24
+ from rasa.core.channels.constants import USER_CONVERSATION_SILENCE_TIMEOUT
25
+ from rasa.shared.core.constants import SILENCE_TIMEOUT_SLOT
26
+
27
+ logger = structlog.getLogger(__name__)
28
+
15
29
 
16
- logger = logging.getLogger(__name__)
30
+ @dataclass
31
+ class SilenceTimeout:
32
+ sender_id: str
33
+ timeout: float
34
+
35
+
36
+ UserSilenceHandlerType = Callable[[SilenceTimeout], Awaitable[Any]]
17
37
 
18
38
 
19
39
  class SocketBlueprint(Blueprint):
20
40
  """Blueprint for socketio connections."""
21
41
 
22
42
  def __init__(
23
- self, sio: AsyncServer, socketio_path: Text, *args: Any, **kwargs: Any
43
+ self, sio_server: AsyncServer, socketio_path: Text, *args: Any, **kwargs: Any
24
44
  ) -> None:
25
- """Creates a :class:`sanic.Blueprint` for routing socketio connenctions.
45
+ """Creates a :class:`sanic.Blueprint` for routing socketio connections.
26
46
 
27
- :param sio: Instance of :class:`socketio.AsyncServer` class
47
+ :param sio_server: Instance of :class:`socketio.AsyncServer` class
28
48
  :param socketio_path: string indicating the route to accept requests on.
29
49
  """
30
50
  super().__init__(*args, **kwargs)
31
- self.ctx.sio = sio
51
+ self.ctx.sio_server = sio_server
32
52
  self.ctx.socketio_path = socketio_path
33
53
 
34
54
  def register(self, app: Sanic, options: Dict[Text, Any]) -> None:
@@ -42,7 +62,7 @@ class SocketBlueprint(Blueprint):
42
62
  path = self.ctx.socketio_path
43
63
  else:
44
64
  path = options.get("url_prefix", "/socket.io")
45
- self.ctx.sio.attach(app, path)
65
+ self.ctx.sio_server.attach(app, path)
46
66
  super().register(app, options)
47
67
 
48
68
 
@@ -51,14 +71,45 @@ class SocketIOOutput(OutputChannel):
51
71
  def name(cls) -> Text:
52
72
  return "socketio"
53
73
 
54
- def __init__(self, sio: AsyncServer, bot_message_evt: Text) -> None:
74
+ def __init__(
75
+ self,
76
+ input_channel: SocketIOInput,
77
+ sio_server: AsyncServer,
78
+ bot_message_evt: Text,
79
+ ) -> None:
55
80
  super().__init__()
56
- self.sio = sio
81
+ self._input_channel = input_channel
82
+ self.sio_server = sio_server
57
83
  self.bot_message_evt = bot_message_evt
58
84
 
59
85
  async def _send_message(self, socket_id: Text, response: Any) -> None:
60
86
  """Sends a message to the recipient using the bot event."""
61
- await self.sio.emit(self.bot_message_evt, response, room=socket_id)
87
+ await self.sio_server.emit(self.bot_message_evt, response, room=socket_id)
88
+ if self.tracker_state and self._input_channel.enable_silence_timeout:
89
+ silence_timeout = self.tracker_state["slots"][SILENCE_TIMEOUT_SLOT]
90
+
91
+ logger.debug(
92
+ "socketio_channel.silence_timeout_updated",
93
+ sender_id=socket_id,
94
+ silence_timeout=silence_timeout,
95
+ )
96
+
97
+ silence_timeout_counts = self.tracker_state["slots"][
98
+ "consecutive_silence_timeouts"
99
+ ]
100
+
101
+ logger.debug(
102
+ "socketio_channel.consecutive_silence_timeouts_updated",
103
+ sender_id=socket_id,
104
+ silence_timeout_counts=silence_timeout_counts,
105
+ )
106
+
107
+ self._input_channel.reset_silence_timeout(
108
+ SilenceTimeout(
109
+ sender_id=socket_id,
110
+ timeout=silence_timeout,
111
+ ),
112
+ )
62
113
 
63
114
  async def send_text_message(
64
115
  self, recipient_id: Text, text: Text, **kwargs: Any
@@ -123,9 +174,11 @@ class SocketIOOutput(OutputChannel):
123
174
  """Sends custom json to the output."""
124
175
  if "data" in json_message:
125
176
  json_message.setdefault("room", recipient_id)
126
- await self.sio.emit(self.bot_message_evt, **json_message)
177
+ await self.sio_server.emit(self.bot_message_evt, **json_message)
127
178
  else:
128
- await self.sio.emit(self.bot_message_evt, json_message, room=recipient_id)
179
+ await self.sio_server.emit(
180
+ self.bot_message_evt, json_message, room=recipient_id
181
+ )
129
182
 
130
183
  async def send_attachment( # type: ignore[override]
131
184
  self, recipient_id: Text, attachment: Dict[Text, Any], **kwargs: Any
@@ -133,26 +186,38 @@ class SocketIOOutput(OutputChannel):
133
186
  """Sends an attachment to the user."""
134
187
  await self._send_message(recipient_id, {"attachment": attachment})
135
188
 
189
+ async def hangup(self, recipient_id: Text, **kwargs: Any) -> None:
190
+ """Hangs up the call for the given sender."""
191
+ # This method is not applicable for socket.io, but we implement it
192
+ # to satisfy the OutputChannel interface.
193
+ logger.debug(
194
+ "socketio_channel.output.hangup",
195
+ message=f"Hanging up call for user {recipient_id}.",
196
+ )
197
+
198
+ self._input_channel.disconnect(recipient_id)
199
+
136
200
 
137
201
  class SocketIOInput(InputChannel):
138
202
  """A socket.io input channel."""
139
203
 
140
204
  @classmethod
141
- def name(cls) -> Text:
205
+ def name(cls) -> str:
142
206
  return "socketio"
143
207
 
144
208
  @classmethod
145
209
  def from_credentials(cls, credentials: Optional[Dict[Text, Any]]) -> InputChannel:
146
210
  credentials = credentials or {}
147
211
  return cls(
148
- credentials.get("user_message_evt", "user_uttered"),
149
- credentials.get("bot_message_evt", "bot_uttered"),
150
- credentials.get("namespace"),
151
- credentials.get("session_persistence", False),
152
- credentials.get("socketio_path", "/socket.io"),
153
- credentials.get("jwt_key"),
154
- credentials.get("jwt_method", "HS256"),
155
- credentials.get("metadata_key", "metadata"),
212
+ user_message_evt=credentials.get("user_message_evt", "user_uttered"),
213
+ bot_message_evt=credentials.get("bot_message_evt", "bot_uttered"),
214
+ namespace=credentials.get("namespace"),
215
+ session_persistence=credentials.get("session_persistence", False),
216
+ socketio_path=credentials.get("socketio_path", "/socket.io"),
217
+ jwt_key=credentials.get("jwt_key"),
218
+ jwt_method=credentials.get("jwt_method", "HS256"),
219
+ metadata_key=credentials.get("metadata_key", "metadata"),
220
+ enable_silence_timeout=credentials.get("enable_silence_timeout", False),
156
221
  )
157
222
 
158
223
  def __init__(
@@ -165,6 +230,7 @@ class SocketIOInput(InputChannel):
165
230
  jwt_key: Optional[Text] = None,
166
231
  jwt_method: Optional[Text] = "HS256",
167
232
  metadata_key: Optional[Text] = "metadata",
233
+ enable_silence_timeout: bool = False,
168
234
  ):
169
235
  """Creates a ``SocketIOInput`` object."""
170
236
  self.bot_message_evt = bot_message_evt
@@ -172,15 +238,18 @@ class SocketIOInput(InputChannel):
172
238
  self.user_message_evt = user_message_evt
173
239
  self.namespace = namespace
174
240
  self.socketio_path = socketio_path
175
- self.sio: Optional[AsyncServer] = None
241
+ self.sio_server: Optional[AsyncServer] = None
176
242
  self.metadata_key = metadata_key
243
+ self.enable_silence_timeout = enable_silence_timeout
177
244
 
178
245
  self.jwt_key = jwt_key
179
246
  self.jwt_algorithm = jwt_method
247
+ self.on_new_message: Optional[OnNewMessageType] = None
248
+ self.sender_silence_map: Dict[str, Task] = {}
180
249
 
181
- def get_output_channel(self) -> Optional["OutputChannel"]:
250
+ def get_output_channel(self) -> Optional[OutputChannel]:
182
251
  """Creates socket.io output channel object."""
183
- if self.sio is None:
252
+ if self.sio_server is None:
184
253
  rasa.shared.utils.io.raise_warning(
185
254
  "SocketIO output channel cannot be recreated. "
186
255
  "This is expected behavior when using multiple Sanic "
@@ -189,7 +258,7 @@ class SocketIOInput(InputChannel):
189
258
  "scenarios."
190
259
  )
191
260
  return None
192
- return SocketIOOutput(self.sio, self.bot_message_evt)
261
+ return SocketIOOutput(self, self.sio_server, self.bot_message_evt)
193
262
 
194
263
  async def handle_session_request(
195
264
  self, sid: Text, data: Optional[Dict] = None
@@ -200,23 +269,26 @@ class SocketIOInput(InputChannel):
200
269
  if "session_id" not in data or data["session_id"] is None:
201
270
  data["session_id"] = uuid.uuid4().hex
202
271
  if self.session_persistence:
203
- if inspect.iscoroutinefunction(self.sio.enter_room): # type: ignore[union-attr]
204
- await self.sio.enter_room(sid, data["session_id"]) # type: ignore[union-attr]
272
+ if inspect.iscoroutinefunction(self.sio_server.enter_room): # type: ignore[union-attr]
273
+ await self.sio_server.enter_room(sid, data["session_id"]) # type: ignore[union-attr]
205
274
  else:
206
275
  # for backwards compatibility with python-socketio < 5.10.
207
276
  # previously, this function was NOT async.
208
- self.sio.enter_room(sid, data["session_id"]) # type: ignore[union-attr]
209
- await self.sio.emit("session_confirm", data["session_id"], room=sid) # type: ignore[union-attr]
210
- logger.debug(f"User {sid} connected to socketIO endpoint.")
277
+ self.sio_server.enter_room(sid, data["session_id"]) # type: ignore[union-attr]
278
+ await self.sio_server.emit("session_confirm", data["session_id"], room=sid) # type: ignore[union-attr]
279
+ logger.debug(
280
+ "socketio_channel.input.handle_session_request",
281
+ message=f"User {sid} connected to socketIO endpoint.",
282
+ )
211
283
 
212
284
  async def handle_user_message(
213
285
  self,
214
286
  sid: Text,
215
287
  data: Dict,
216
- on_new_message: Callable[[UserMessage], Awaitable[Any]],
288
+ on_new_message: OnNewMessageType,
217
289
  ) -> None:
218
290
  """Handles user messages received from the client."""
219
- output_channel = SocketIOOutput(self.sio, self.bot_message_evt)
291
+ output_channel = self.get_output_channel()
220
292
 
221
293
  if self.session_persistence:
222
294
  if not data.get("session_id"):
@@ -232,38 +304,44 @@ class SocketIOInput(InputChannel):
232
304
  else:
233
305
  sender_id = sid
234
306
 
307
+ # We cancel silence timeout when a new message is received
308
+ # to prevent sending a silence timeout message
309
+ # if the user sends a message after the silence timeout
310
+ self._cancel_silence_timeout(sender_id)
311
+
235
312
  metadata = data.get(self.metadata_key, {})
236
313
  if isinstance(metadata, Text):
237
314
  metadata = json.loads(metadata)
238
315
 
239
316
  message = UserMessage(
240
- data.get("message", ""),
241
- output_channel,
242
- sender_id,
317
+ text=data.get("message", ""),
318
+ output_channel=output_channel,
319
+ sender_id=sender_id,
243
320
  input_channel=self.name(),
244
321
  metadata=metadata,
245
322
  )
246
323
  await on_new_message(message)
247
324
 
248
- def blueprint(
249
- self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
250
- ) -> SocketBlueprint:
325
+ def blueprint(self, on_new_message: OnNewMessageType) -> SocketBlueprint:
251
326
  """Defines a Sanic blueprint."""
252
327
  # Workaround so that socketio works with requests from other origins.
253
328
  # https://github.com/miguelgrinberg/python-socketio/issues/205#issuecomment-493769183
254
- sio = AsyncServer(async_mode="sanic", cors_allowed_origins=[])
329
+ sio_server = AsyncServer(async_mode="sanic", cors_allowed_origins=[])
255
330
  socketio_webhook = SocketBlueprint(
256
- sio, self.socketio_path, "socketio_webhook", __name__
331
+ sio_server, self.socketio_path, "socketio_webhook", __name__
257
332
  )
258
333
 
259
- # make sio object static to use in get_output_channel
260
- self.sio = sio
334
+ # make sio_server object static to use in get_output_channel
335
+ self.sio_server = sio_server
336
+ # We need to store the on_new_message callback
337
+ # so that we can call it when a silence timeout occurs
338
+ self.on_new_message = on_new_message
261
339
 
262
340
  @socketio_webhook.route("/", methods=["GET"])
263
341
  async def health(_: Request) -> HTTPResponse:
264
342
  return response.json({"status": "ok"})
265
343
 
266
- @sio.on("connect", namespace=self.namespace)
344
+ @sio_server.on("connect", namespace=self.namespace)
267
345
  async def connect(sid: Text, environ: Dict, auth: Optional[Dict]) -> bool:
268
346
  if self.jwt_key:
269
347
  jwt_payload = None
@@ -273,24 +351,107 @@ class SocketIOInput(InputChannel):
273
351
  )
274
352
 
275
353
  if jwt_payload:
276
- logger.debug(f"User {sid} connected to socketIO endpoint.")
354
+ logger.debug(
355
+ "socketio_channel.input.connect.jwt",
356
+ message=f"User {sid} connected to socketIO endpoint.",
357
+ )
358
+ # Store the chat state for this user
277
359
  return True
278
360
  else:
279
361
  return False
280
362
  else:
281
- logger.debug(f"User {sid} connected to socketIO endpoint.")
363
+ logger.debug(
364
+ "socketio_channel.input.connect",
365
+ message=f"User {sid} connected to socketIO endpoint.",
366
+ )
367
+ # Store the chat state for this user
282
368
  return True
283
369
 
284
- @sio.on("disconnect", namespace=self.namespace)
370
+ @sio_server.on("disconnect", namespace=self.namespace)
285
371
  async def disconnect(sid: Text) -> None:
286
- logger.debug(f"User {sid} disconnected from socketIO endpoint.")
372
+ logger.debug(
373
+ "socketio_channel.input.disconnect",
374
+ message=f"User {sid} disconnected from socketIO endpoint.",
375
+ )
287
376
 
288
- @sio.on("session_request", namespace=self.namespace)
377
+ @sio_server.on("session_request", namespace=self.namespace)
289
378
  async def session_request(sid: Text, data: Optional[Dict]) -> None:
379
+ logger.debug(
380
+ "socketio_channel.input.session_request",
381
+ message=f"User {sid} requested a session.",
382
+ )
290
383
  await self.handle_session_request(sid, data)
291
384
 
292
- @sio.on(self.user_message_evt, namespace=self.namespace)
385
+ @sio_server.on(self.user_message_evt, namespace=self.namespace)
293
386
  async def handle_message(sid: Text, data: Dict) -> None:
387
+ logger.debug(
388
+ "socketio_channel.input.handle_message",
389
+ message=f"User {sid} sent a message.",
390
+ data=data,
391
+ )
294
392
  await self.handle_user_message(sid, data, on_new_message)
295
393
 
296
394
  return socketio_webhook
395
+
396
+ def reset_silence_timeout(self, silence_timeout: SilenceTimeout) -> None:
397
+ self._cancel_silence_timeout(silence_timeout.sender_id)
398
+
399
+ self.sender_silence_map[silence_timeout.sender_id] = (
400
+ asyncio.get_event_loop().create_task(
401
+ self._monitor_silence_timeout(
402
+ silence_timeout,
403
+ )
404
+ )
405
+ )
406
+
407
+ def disconnect(self, sender_id: str) -> None:
408
+ """Disconnects the user with the given sender ID."""
409
+ self._cancel_silence_timeout(sender_id)
410
+ if self.sio_server:
411
+ asyncio.get_event_loop().create_task(self.sio_server.disconnect(sender_id))
412
+ logger.debug(
413
+ "socketio_channel.input.disconnect",
414
+ message=f"User {sender_id} disconnected from socketIO endpoint.",
415
+ )
416
+
417
+ async def _monitor_silence_timeout(self, silence_timeout: SilenceTimeout) -> None:
418
+ logger.debug(
419
+ "socketio_channel.input.silence_timeout_watch_started",
420
+ sender_id=silence_timeout.sender_id,
421
+ timeout=silence_timeout.timeout,
422
+ )
423
+ await asyncio.sleep(silence_timeout.timeout)
424
+
425
+ # once the timer is up, we call the handler
426
+ # to notify the user about the silence timeout
427
+ # this is important if monitoring trask is cancelled while handler is executed
428
+ asyncio.get_event_loop().create_task(
429
+ self._handle_silence_timeout(silence_timeout)
430
+ )
431
+
432
+ logger.debug(
433
+ "socketio_channel.input.silence_timeout_tripped",
434
+ sender_id=silence_timeout.sender_id,
435
+ silence_timeout=silence_timeout.timeout,
436
+ )
437
+
438
+ async def _handle_silence_timeout(self, event: SilenceTimeout) -> None:
439
+ if self.on_new_message:
440
+ output_channel = self.get_output_channel()
441
+ message = UserMessage(
442
+ text=USER_CONVERSATION_SILENCE_TIMEOUT,
443
+ output_channel=output_channel,
444
+ sender_id=event.sender_id,
445
+ input_channel=self.name(),
446
+ )
447
+ await self.on_new_message(message)
448
+
449
+ def _cancel_silence_timeout(self, sender_id: str) -> None:
450
+ """Cancels the silence timeout task for the given sender."""
451
+ task = self.sender_silence_map.pop(sender_id, None)
452
+ if task and not task.done():
453
+ logger.debug(
454
+ "socketio_channel.input.silence_timeout_cancelled",
455
+ sender_id=sender_id,
456
+ )
457
+ task.cancel()
@@ -47,7 +47,6 @@ if TYPE_CHECKING:
47
47
  from sanic import Sanic, Websocket # type: ignore[attr-defined]
48
48
  from socketio import AsyncServer
49
49
 
50
- from rasa.core.channels.channel import UserMessage
51
50
  from rasa.shared.core.trackers import DialogueStateTracker
52
51
 
53
52
 
@@ -153,6 +152,7 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
153
152
  jwt_key: Optional[Text] = None,
154
153
  jwt_method: Optional[Text] = "HS256",
155
154
  metadata_key: Optional[Text] = "metadata",
155
+ enable_silence_timeout: bool = False,
156
156
  ) -> None:
157
157
  """Creates a `StudioChatInput` object."""
158
158
  from rasa.core.agent import Agent
@@ -170,6 +170,7 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
170
170
  jwt_key=jwt_key,
171
171
  jwt_method=jwt_method,
172
172
  metadata_key=metadata_key,
173
+ enable_silence_timeout=enable_silence_timeout,
173
174
  )
174
175
 
175
176
  # Initialize the Voice Input Channel
@@ -210,14 +211,15 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
210
211
  jwt_key=credentials.get("jwt_key"),
211
212
  jwt_method=credentials.get("jwt_method", "HS256"),
212
213
  metadata_key=credentials.get("metadata_key", "metadata"),
214
+ enable_silence_timeout=credentials.get("enable_silence_timeout", False),
213
215
  )
214
216
 
215
217
  async def emit(self, event: str, data: str, room: str) -> None:
216
218
  """Emits an event to the websocket."""
217
- if not self.sio:
219
+ if not self.sio_server:
218
220
  structlogger.error("studio_chat.emit.sio_not_initialized")
219
221
  return
220
- await self.sio.emit(event, data, room=room)
222
+ await self.sio_server.emit(event, data, room=room)
221
223
 
222
224
  def _register_tracker_update_hook(self) -> None:
223
225
  plugin_manager().register(StudioTrackerUpdatePlugin(self))
@@ -250,8 +252,8 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
250
252
 
251
253
  async def on_message_proxy(
252
254
  self,
253
- on_new_message: Callable[["UserMessage"], Awaitable[Any]],
254
- message: "UserMessage",
255
+ on_new_message: Callable[[UserMessage], Awaitable[Any]],
256
+ message: UserMessage,
255
257
  ) -> None:
256
258
  """Proxies the on_new_message call to the underlying channel.
257
259
 
@@ -377,7 +379,7 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
377
379
  call_state.is_bot_speaking = True
378
380
  return ContinueConversationAction()
379
381
 
380
- def create_output_channel(
382
+ def _create_output_channel(
381
383
  self, voice_websocket: "Websocket", tts_engine: TTSEngine
382
384
  ) -> VoiceOutputChannel:
383
385
  """Create a voice output channel."""
@@ -407,7 +409,7 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
407
409
 
408
410
  # Create a websocket adapter for this connection
409
411
  ws_adapter = SocketIOVoiceWebsocketAdapter(
410
- sio=self.sio,
412
+ sio_server=self.sio_server,
411
413
  session_id=session_id,
412
414
  sid=sid,
413
415
  bot_message_evt=self.bot_message_evt,
@@ -455,12 +457,12 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
455
457
  task.cancel()
456
458
 
457
459
  def blueprint(
458
- self, on_new_message: Callable[["UserMessage"], Awaitable[Any]]
460
+ self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
459
461
  ) -> SocketBlueprint:
460
462
  proxied_on_message = partial(self.on_message_proxy, on_new_message)
461
463
  socket_blueprint = super().blueprint(proxied_on_message)
462
464
 
463
- if not self.sio:
465
+ if not self.sio_server:
464
466
  structlogger.error("studio_chat.blueprint.sio_not_initialized")
465
467
  return socket_blueprint
466
468
 
@@ -470,12 +472,12 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
470
472
  ) -> None:
471
473
  self.agent = app.ctx.agent
472
474
 
473
- @self.sio.on("disconnect", namespace=self.namespace)
475
+ @self.sio_server.on("disconnect", namespace=self.namespace)
474
476
  async def disconnect(sid: Text) -> None:
475
477
  structlogger.debug("studio_chat.sio.disconnect", sid=sid)
476
478
  self._cleanup_tasks_for_sid(sid)
477
479
 
478
- @self.sio.on("session_request", namespace=self.namespace)
480
+ @self.sio_server.on("session_request", namespace=self.namespace)
479
481
  async def session_request(sid: Text, data: Optional[Dict]) -> None:
480
482
  """Overrides the base SocketIOInput session_request handler.
481
483
 
@@ -495,7 +497,7 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
495
497
  if data and data.get("is_voice", False):
496
498
  self._start_voice_session(data["session_id"], sid, proxied_on_message)
497
499
 
498
- @self.sio.on(self.user_message_evt, namespace=self.namespace)
500
+ @self.sio_server.on(self.user_message_evt, namespace=self.namespace)
499
501
  async def handle_message(sid: Text, data: Dict) -> None:
500
502
  """Overrides the base SocketIOInput handle_message handler."""
501
503
  # Handle voice messages
@@ -509,7 +511,7 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
509
511
  # Handle text messages
510
512
  await self.handle_user_message(sid, data, proxied_on_message)
511
513
 
512
- @self.sio.on("update_tracker", namespace=self.namespace)
514
+ @self.sio_server.on("update_tracker", namespace=self.namespace)
513
515
  async def on_update_tracker(sid: Text, data: Dict) -> None:
514
516
  await self.handle_tracker_update(sid, data)
515
517
 
@@ -555,9 +557,9 @@ class SocketIOVoiceWebsocketAdapter:
555
557
  """Adapter to make Socket.IO work like a Sanic WebSocket for voice channels."""
556
558
 
557
559
  def __init__(
558
- self, sio: "AsyncServer", session_id: str, sid: str, bot_message_evt: str
560
+ self, sio_server: "AsyncServer", session_id: str, sid: str, bot_message_evt: str
559
561
  ) -> None:
560
- self.sio = sio
562
+ self.sio_server = sio_server
561
563
  self.bot_message_evt = bot_message_evt
562
564
  self._closed = False
563
565
  self._receive_queue: asyncio.Queue[Any] = asyncio.Queue()
@@ -576,7 +578,7 @@ class SocketIOVoiceWebsocketAdapter:
576
578
  async def send(self, data: Any) -> None:
577
579
  """Send data to the client."""
578
580
  if not self.closed:
579
- await self.sio.emit(self.bot_message_evt, data, room=self.sid)
581
+ await self.sio_server.emit(self.bot_message_evt, data, room=self.sid)
580
582
 
581
583
  async def recv(self) -> Any:
582
584
  """Receive data from the client."""
@@ -11,6 +11,11 @@ from sanic import Websocket # type: ignore
11
11
  from sanic.exceptions import ServerError, WebsocketClosed
12
12
 
13
13
  from rasa.core.channels import InputChannel, OutputChannel, UserMessage
14
+ from rasa.core.channels.constants import (
15
+ USER_CONVERSATION_SESSION_END,
16
+ USER_CONVERSATION_SESSION_START,
17
+ USER_CONVERSATION_SILENCE_TIMEOUT,
18
+ )
14
19
  from rasa.core.channels.voice_ready.utils import (
15
20
  CallParameters,
16
21
  validate_voice_license_scope,
@@ -48,9 +53,6 @@ from rasa.utils.io import remove_emojis
48
53
  logger = structlog.get_logger(__name__)
49
54
 
50
55
  # define constants for the voice channel
51
- USER_CONVERSATION_SESSION_END = "/session_end"
52
- USER_CONVERSATION_SESSION_START = "/session_start"
53
- USER_CONVERSATION_SILENCE_TIMEOUT = "/silence_timeout"
54
56
 
55
57
 
56
58
  @dataclass
rasa/core/run.py CHANGED
@@ -42,10 +42,20 @@ from rasa.utils import licensing
42
42
  logger = logging.getLogger() # get the root logger
43
43
 
44
44
 
45
- def create_http_input_channels(
45
+ def create_input_channels(
46
46
  channel: Optional[Text], credentials_file: Optional[Text]
47
47
  ) -> List[InputChannel]:
48
- """Instantiate the chosen input channel."""
48
+ """Instantiate the chosen input channel.
49
+
50
+ Args:
51
+ channel (optional): The name of the specific input channel to create.
52
+ credentials_file: Path to the credentials file containing channel credentials.
53
+
54
+ Returns:
55
+ A list of instantiated input channels. If a specific channel is provided,
56
+ it returns a list with that single channel. If no channel is specified,
57
+ it returns a list of all channels defined in the credentials file.
58
+ """
49
59
  if credentials_file:
50
60
  all_credentials = read_config_file(credentials_file)
51
61
  else:
@@ -253,7 +263,7 @@ def serve_application(
253
263
  if not channel and not credentials:
254
264
  channel = "cmdline"
255
265
 
256
- input_channels = create_http_input_channels(channel, credentials)
266
+ input_channels = create_input_channels(channel, credentials)
257
267
 
258
268
  if inspect:
259
269
  logger.info("Starting development inspector.")
@@ -81,7 +81,7 @@ responses:
81
81
  rephrase: True
82
82
 
83
83
  utter_inform_hangup:
84
- - text: It seems you are not there anymore. I will hang up shortly.
84
+ - text: I haven’t heard from you, so I’ll end our conversation shortly.
85
85
  metadata:
86
86
  rephrase: True
87
87
 
@@ -571,10 +571,10 @@ def external_blueprint() -> Blueprint:
571
571
  """Create a blueprint for the model manager API."""
572
572
  from rasa.core.channels.socketio import SocketBlueprint
573
573
 
574
- sio = AsyncServer(async_mode="sanic", cors_allowed_origins="*")
575
- bp = SocketBlueprint(sio, "", "model_api_external")
574
+ sio_server = AsyncServer(async_mode="sanic", cors_allowed_origins="*")
575
+ bp = SocketBlueprint(sio_server, "", "model_api_external")
576
576
 
577
- create_bridge_server(sio, running_bots)
577
+ create_bridge_server(sio_server, running_bots)
578
578
 
579
579
  @bp.get("/health")
580
580
  async def health(request: Request) -> response.HTTPResponse:
@@ -19,7 +19,7 @@ socket_proxy_clients = {}
19
19
 
20
20
 
21
21
  async def socketio_websocket_traffic_wrapper(
22
- sio: AsyncServer,
22
+ sio_server: AsyncServer,
23
23
  running_bots: Dict[str, BotSession],
24
24
  sid: str,
25
25
  auth: Optional[Dict],
@@ -55,7 +55,9 @@ async def socketio_websocket_traffic_wrapper(
55
55
  structlogger.error("model_runner.bot_not_alive", deployment_id=deployment_id)
56
56
  raise ConnectionRefusedError("model_runner.bot_not_alive")
57
57
 
58
- client = await create_bridge_client(sio, bot.internal_url, sid, deployment_id)
58
+ client = await create_bridge_client(
59
+ sio_server, bot.internal_url, sid, deployment_id
60
+ )
59
61
 
60
62
  if client.sid is not None:
61
63
  structlogger.debug(
@@ -70,20 +72,24 @@ async def socketio_websocket_traffic_wrapper(
70
72
  raise ConnectionRefusedError("model_runner.bot_connection_failed")
71
73
 
72
74
 
73
- def create_bridge_server(sio: AsyncServer, running_bots: Dict[str, BotSession]) -> None:
75
+ def create_bridge_server(
76
+ sio_server: AsyncServer, running_bots: Dict[str, BotSession]
77
+ ) -> None:
74
78
  """Create handlers for the socket server side.
75
79
 
76
80
  Forwards messages coming from the user to the bot.
77
81
  """
78
82
 
79
- @sio.on("connect")
83
+ @sio_server.on("connect")
80
84
  async def socketio_websocket_traffic(
81
85
  sid: str, environ: Dict, auth: Optional[Dict]
82
86
  ) -> bool:
83
87
  """Bridge websockets between user chat socket and bot server."""
84
- return await socketio_websocket_traffic_wrapper(sio, running_bots, sid, auth)
88
+ return await socketio_websocket_traffic_wrapper(
89
+ sio_server, running_bots, sid, auth
90
+ )
85
91
 
86
- @sio.on("disconnect")
92
+ @sio_server.on("disconnect")
87
93
  async def disconnect(sid: str) -> None:
88
94
  """Disconnect the bot connection."""
89
95
  structlogger.debug("model_runner.bot_disconnect", sid=sid)
@@ -91,7 +97,7 @@ def create_bridge_server(sio: AsyncServer, running_bots: Dict[str, BotSession])
91
97
  await socket_proxy_clients[sid].disconnect()
92
98
  del socket_proxy_clients[sid]
93
99
 
94
- @sio.on("*")
100
+ @sio_server.on("*")
95
101
  async def handle_message(event: str, sid: str, data: Dict[str, Any]) -> None:
96
102
  """Bridge messages between user and bot.
97
103
 
@@ -108,7 +114,7 @@ def create_bridge_server(sio: AsyncServer, running_bots: Dict[str, BotSession])
108
114
 
109
115
 
110
116
  async def create_bridge_client(
111
- sio: AsyncServer, url: str, sid: str, deployment_id: str
117
+ sio_server: AsyncServer, url: str, sid: str, deployment_id: str
112
118
  ) -> AsyncClient:
113
119
  """Create a new socket bridge client.
114
120
 
@@ -123,36 +129,36 @@ async def create_bridge_client(
123
129
  structlogger.debug(
124
130
  "model_runner.bot_session_confirmed", deployment_id=deployment_id
125
131
  )
126
- await sio.emit("session_confirm", room=sid)
132
+ await sio_server.emit("session_confirm", room=sid)
127
133
 
128
134
  @client.event # type: ignore[misc]
129
135
  async def bot_message(data: Dict[str, Any]) -> None:
130
136
  structlogger.debug("model_runner.bot_message", deployment_id=deployment_id)
131
- await sio.emit("bot_message", data, room=sid)
137
+ await sio_server.emit("bot_message", data, room=sid)
132
138
 
133
139
  @client.event # type: ignore[misc]
134
140
  async def error(data: Dict[str, Any]) -> None:
135
141
  structlogger.debug(
136
142
  "model_runner.bot_error", deployment_id=deployment_id, data=data
137
143
  )
138
- await sio.emit("error", data, room=sid)
144
+ await sio_server.emit("error", data, room=sid)
139
145
 
140
146
  @client.event # type: ignore[misc]
141
147
  async def tracker(data: Dict[str, Any]) -> None:
142
- await sio.emit("tracker", json.loads(data), room=sid)
148
+ await sio_server.emit("tracker", json.loads(data), room=sid)
143
149
 
144
150
  @client.event # type: ignore[misc]
145
151
  async def disconnect() -> None:
146
152
  structlogger.debug(
147
153
  "model_runner.bot_connection_closed", deployment_id=deployment_id
148
154
  )
149
- await sio.emit("disconnect", room=sid)
155
+ await sio_server.emit("disconnect", room=sid)
150
156
 
151
157
  @client.event # type: ignore[misc]
152
158
  async def connect_error() -> None:
153
159
  structlogger.error(
154
160
  "model_runner.bot_connection_error", deployment_id=deployment_id
155
161
  )
156
- await sio.emit("disconnect", room=sid)
162
+ await sio_server.emit("disconnect", room=sid)
157
163
 
158
164
  return client
@@ -1,87 +1,103 @@
1
1
  from typing import Any, Dict, Optional
2
2
 
3
+ import boto3
3
4
  import structlog
4
- from litellm import validate_environment
5
+ from botocore.exceptions import BotoCoreError, ClientError
5
6
 
6
7
  from rasa.shared.constants import (
7
8
  API_BASE_CONFIG_KEY,
8
9
  API_VERSION_CONFIG_KEY,
9
10
  AWS_ACCESS_KEY_ID_CONFIG_KEY,
10
- AWS_ACCESS_KEY_ID_ENV_VAR,
11
+ AWS_BEDROCK_PROVIDER,
11
12
  AWS_REGION_NAME_CONFIG_KEY,
12
- AWS_REGION_NAME_ENV_VAR,
13
+ AWS_SAGEMAKER_CHAT_PROVIDER,
14
+ AWS_SAGEMAKER_PROVIDER,
13
15
  AWS_SECRET_ACCESS_KEY_CONFIG_KEY,
14
- AWS_SECRET_ACCESS_KEY_ENV_VAR,
15
16
  AWS_SESSION_TOKEN_CONFIG_KEY,
16
- AWS_SESSION_TOKEN_ENV_VAR,
17
17
  AZURE_API_BASE_ENV_VAR,
18
18
  AZURE_API_VERSION_ENV_VAR,
19
19
  DEPLOYMENT_CONFIG_KEY,
20
20
  )
21
21
  from rasa.shared.exceptions import ProviderClientValidationError
22
- from rasa.shared.providers.embedding._base_litellm_embedding_client import (
23
- _VALIDATE_ENVIRONMENT_MISSING_KEYS_KEY,
24
- )
22
+ from rasa.shared.utils.io import resolve_environment_variables
25
23
 
26
24
  structlogger = structlog.get_logger()
27
25
 
28
26
 
29
27
  def validate_aws_setup_for_litellm_clients(
30
- litellm_model_name: str, litellm_call_kwargs: dict, source_log: str
28
+ litellm_model_name: str, litellm_call_kwargs: Dict, source_log: str, provider: str
31
29
  ) -> None:
32
- """Validates the AWS setup for LiteLLM clients to ensure all required
33
- environment variables or corresponding call kwargs are set.
30
+ """Validates the AWS setup for LiteLLM clients to ensure credentials are set.
34
31
 
35
32
  Args:
36
33
  litellm_model_name (str): The name of the LiteLLM model being validated.
37
34
  litellm_call_kwargs (dict): Additional keyword arguments passed to the client,
38
35
  which may include configuration values for AWS credentials.
39
36
  source_log (str): The source log identifier for structured logging.
37
+ provider (str): The provider for which the validation is being performed.
40
38
 
41
39
  Raises:
42
40
  ProviderClientValidationError: If any required AWS environment variable
43
41
  or corresponding configuration key is missing.
44
42
  """
45
-
46
- # Mapping of environment variable names to their corresponding config keys
47
- envs_to_args = {
48
- AWS_ACCESS_KEY_ID_ENV_VAR: AWS_ACCESS_KEY_ID_CONFIG_KEY,
49
- AWS_SECRET_ACCESS_KEY_ENV_VAR: AWS_SECRET_ACCESS_KEY_CONFIG_KEY,
50
- AWS_REGION_NAME_ENV_VAR: AWS_REGION_NAME_CONFIG_KEY,
51
- AWS_SESSION_TOKEN_ENV_VAR: AWS_SESSION_TOKEN_CONFIG_KEY,
52
- }
53
-
54
- # Validate the environment setup for the model
55
- validation_info = validate_environment(litellm_model_name)
56
- missing_environment_variables = validation_info.get(
57
- _VALIDATE_ENVIRONMENT_MISSING_KEYS_KEY, []
43
+ # expand environment variables if referenced in the config
44
+ resolved_litellm_call_kwargs: Dict = resolve_environment_variables(
45
+ litellm_call_kwargs
46
+ ) # type: ignore[assignment]
47
+
48
+ # boto3 only accepts bedrock and sagemaker as valid clients
49
+ # therefore we need to convert the provider name if it is defined
50
+ # as sagemaker_chat
51
+ provider = (
52
+ AWS_SAGEMAKER_PROVIDER if provider == AWS_SAGEMAKER_CHAT_PROVIDER else provider
58
53
  )
59
- # Filter out missing environment variables that have been set trough arguments
60
- # in extra parameters
61
- missing_environment_variables = [
62
- missing_env_var
63
- for missing_env_var in missing_environment_variables
64
- if litellm_call_kwargs.get(envs_to_args.get(missing_env_var)) is None
65
- ]
66
54
 
67
- if missing_environment_variables:
68
- missing_environment_details = [
69
- (
70
- f"'{missing_env_var}' environment variable or "
71
- f"'{envs_to_args.get(missing_env_var)}' config key"
72
- )
73
- for missing_env_var in missing_environment_variables
55
+ # if the AWS credentials are defined in the endpoints yaml model config,
56
+ # either as referenced secret env vars or direct values, we need to pass them
57
+ # to the boto3 client to ensure that the client can connect to the AWS service.
58
+ additional_kwargs: Dict[str, Any] = {}
59
+ if AWS_ACCESS_KEY_ID_CONFIG_KEY in resolved_litellm_call_kwargs:
60
+ additional_kwargs[AWS_ACCESS_KEY_ID_CONFIG_KEY] = resolved_litellm_call_kwargs[
61
+ AWS_ACCESS_KEY_ID_CONFIG_KEY
74
62
  ]
63
+ if AWS_SECRET_ACCESS_KEY_CONFIG_KEY in resolved_litellm_call_kwargs:
64
+ additional_kwargs[AWS_SECRET_ACCESS_KEY_CONFIG_KEY] = (
65
+ resolved_litellm_call_kwargs[AWS_SECRET_ACCESS_KEY_CONFIG_KEY]
66
+ )
67
+ if AWS_SESSION_TOKEN_CONFIG_KEY in resolved_litellm_call_kwargs:
68
+ additional_kwargs[AWS_SESSION_TOKEN_CONFIG_KEY] = resolved_litellm_call_kwargs[
69
+ AWS_SESSION_TOKEN_CONFIG_KEY
70
+ ]
71
+ if AWS_REGION_NAME_CONFIG_KEY in resolved_litellm_call_kwargs:
72
+ additional_kwargs["region_name"] = resolved_litellm_call_kwargs[
73
+ AWS_REGION_NAME_CONFIG_KEY
74
+ ]
75
+
76
+ try:
77
+ # We are using the boto3 client because it can discover the AWS credentials
78
+ # from the environment variables, credentials file, or IAM roles.
79
+ # This is necessary to ensure that the client can connect to the AWS service.
80
+ aws_client = boto3.client(provider, **additional_kwargs)
81
+
82
+ # Using different method calls available to different AWS clients
83
+ # to test the connection
84
+ if provider == AWS_SAGEMAKER_PROVIDER:
85
+ aws_client.list_models()
86
+ elif provider == AWS_BEDROCK_PROVIDER:
87
+ aws_client.get_model_invocation_logging_configuration()
88
+
89
+ except (ClientError, BotoCoreError) as exc:
75
90
  event_info = (
76
- f"The following environment variables or configuration keys are "
77
- f"missing: "
78
- f"{', '.join(missing_environment_details)}. "
79
- f"These settings are required for API calls."
91
+ f"Failed to validate AWS setup for LiteLLM clients: {exc}. "
92
+ f"Ensure that you are using one of the available authentication methods:"
93
+ f"credentials file, environment variables, or IAM roles. "
94
+ f"Also, ensure that the AWS region is set correctly. "
80
95
  )
81
96
  structlogger.error(
82
- f"{source_log}.validate_aws_environment_variables",
97
+ f"{source_log}.validate_aws_credentials_for_litellm_clients",
83
98
  event_info=event_info,
84
- missing_environment_variables=missing_environment_variables,
99
+ exception=str(exc),
100
+ model_name=litellm_model_name,
85
101
  )
86
102
  raise ProviderClientValidationError(event_info)
87
103
 
@@ -37,6 +37,7 @@ class DefaultLiteLLMEmbeddingClient(_BaseLiteLLMEmbeddingClient):
37
37
 
38
38
  @classmethod
39
39
  def from_config(cls, config: Dict[str, Any]) -> "DefaultLiteLLMEmbeddingClient":
40
+ """Creates a DefaultLiteLLMEmbeddingClient instance from a config dict."""
40
41
  default_config = DefaultLiteLLMClientConfig.from_dict(config)
41
42
  return cls(
42
43
  model=default_config.model,
@@ -121,6 +122,7 @@ class DefaultLiteLLMEmbeddingClient(_BaseLiteLLMEmbeddingClient):
121
122
  self._litellm_model_name,
122
123
  self._litellm_extra_parameters,
123
124
  "default_litellm_embedding_client",
125
+ provider=self.provider,
124
126
  )
125
127
  else:
126
128
  super().validate_client_setup()
@@ -39,6 +39,7 @@ class DefaultLiteLLMClient(_BaseLiteLLMClient):
39
39
 
40
40
  @classmethod
41
41
  def from_config(cls, config: Dict[str, Any]) -> DefaultLiteLLMClient:
42
+ """Creates a DefaultLiteLLMClient instance from a configuration dictionary."""
42
43
  default_config = DefaultLiteLLMClientConfig.from_dict(config)
43
44
  return cls(
44
45
  model=default_config.model,
@@ -110,6 +111,7 @@ class DefaultLiteLLMClient(_BaseLiteLLMClient):
110
111
  self._litellm_model_name,
111
112
  self._litellm_extra_parameters,
112
113
  "default_litellm_llm_client",
114
+ provider=self.provider,
113
115
  )
114
116
  else:
115
117
  super().validate_client_setup()
rasa/version.py CHANGED
@@ -1,3 +1,3 @@
1
1
  # this file will automatically be changed,
2
2
  # do not add anything but the version number here!
3
- __version__ = "3.14.0.dev20250818"
3
+ __version__ = "3.14.0.dev20250825"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: rasa-pro
3
- Version: 3.14.0.dev20250818
3
+ Version: 3.14.0.dev20250825
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
@@ -108,9 +108,10 @@ rasa/core/brokers/sql.py,sha256=SZ-ZFVaPnkCPNNKnISf3KQ-HnG4mQhZ4AoLJrkrIfUE,2748
108
108
  rasa/core/channels/__init__.py,sha256=cK3Yk6BChYPd01LIt-XPftaN5obucxTQTEpNuzkdKSs,2624
109
109
  rasa/core/channels/botframework.py,sha256=yMtg-xIsH8t_26dCOpR7V4eCrRPYumM5KhGvdNhHYl4,11668
110
110
  rasa/core/channels/callback.py,sha256=Llt5TGimf_5P29s2KxEPOZUX6_df7u8uBCsNSFy7CQA,2750
111
- rasa/core/channels/channel.py,sha256=m51H4YD-CS2e1jYCDBvyWC4l1bu70_19TGP7EF4VLUY,18706
111
+ rasa/core/channels/channel.py,sha256=q8zq9n86kb9iccXoGv_Vj4vcwB75AlXnoK5vg_3evhE,18730
112
112
  rasa/core/channels/console.py,sha256=13bjhsmnuKoShYVdtt2VHzzt9xylER-hDTONC1MiQG0,8075
113
- rasa/core/channels/development_inspector.py,sha256=vOE-2h3bvkn3Xy3sIJCqFSMYLY5JXKRCJdbf7DcaADo,10787
113
+ rasa/core/channels/constants.py,sha256=HWLmyE1kuq9veQFVfAJuGLm3I3Y_IvzEHAJ7PoSxbLQ,153
114
+ rasa/core/channels/development_inspector.py,sha256=J4Ip9B7TuUjbqutoS7fBRH0cFfIpqoBjlpdFn7xvKAM,10794
114
115
  rasa/core/channels/facebook.py,sha256=7DTNz2hKLG7sm0U6UjqPgedZthZXrWFnLEW40c8OrCg,15742
115
116
  rasa/core/channels/hangouts.py,sha256=MlHX-KKhF0D-f4EtPAN56e7N1ZuvupTxLl4MXMsCbQg,11732
116
117
  rasa/core/channels/inspector/.eslintrc.cjs,sha256=FAnPE1mm-eiGeQb9JLMVxDtxX4YOQG4wEFM6OFHB74Y,721
@@ -253,8 +254,8 @@ rasa/core/channels/rasa_chat.py,sha256=pRXn4NLHUCW0_D1FH2B87p7Lnf-xMfPxkjrpbnFXn
253
254
  rasa/core/channels/rest.py,sha256=LWBYBdVzOz5Vv5tZCkB1QA7LxXJFTeC87CQLAi_ZGeI,7310
254
255
  rasa/core/channels/rocketchat.py,sha256=hajaH6549CjEYFM5jSapw1DQKBPKTXbn7cVSuZzknmI,5999
255
256
  rasa/core/channels/slack.py,sha256=jVsTTUu9wUjukPoIsAhbee9o0QFUMCNlQHbR8LTcMBc,24406
256
- rasa/core/channels/socketio.py,sha256=ZEavmx2on9AH73cuIFSGMKn1LHJhzcQVaqrFz7SH-CE,11348
257
- rasa/core/channels/studio_chat.py,sha256=oHNUPxND3zJN2SO3HLhZM-aOjpPdddNNCyBW1or79oc,22686
257
+ rasa/core/channels/socketio.py,sha256=N3aldDMzXotO85lX5pkmVtVq7g6gh9YpUpQpbAH3ogs,17560
258
+ rasa/core/channels/studio_chat.py,sha256=g_whnLDmPdGxR63dX2AmJWnPhRnrMxaJsnGz--cDen0,22907
258
259
  rasa/core/channels/telegram.py,sha256=TKVknsk3U9tYeY1a8bzlhqkltWmZfGSOvrcmwa9qozc,12499
259
260
  rasa/core/channels/twilio.py,sha256=2BTQpyx0b0yPpc0A2BHYfxLPgodrLGLs8nq6i3lVGAM,5906
260
261
  rasa/core/channels/vier_cvg.py,sha256=5O4yx0TDQIMppvlCxTOzmPB60CA-vqQXqWQ7upfrTO0,13496
@@ -283,7 +284,7 @@ rasa/core/channels/voice_stream/tts/tts_cache.py,sha256=K4S2d8zWX2h2ylYALp7IdqFS
283
284
  rasa/core/channels/voice_stream/tts/tts_engine.py,sha256=JMCWGHxT8QiqKoBeI6F4RX_-Q9EEqG3vUtkgOUnlt-w,1812
284
285
  rasa/core/channels/voice_stream/twilio_media_streams.py,sha256=UbaSTaB0tUTf7ryToK6epxb5p31SpFk3tMNnFFo4q_E,9074
285
286
  rasa/core/channels/voice_stream/util.py,sha256=nbr0yUl0NIn4-94VUYjPEg_NB2kadcFCq-i9rRJMv4U,2323
286
- rasa/core/channels/voice_stream/voice_channel.py,sha256=PqULi5aul0TA4zfjFKAa9rInA04i03ylHO7mLam_ld4,23996
287
+ rasa/core/channels/voice_stream/voice_channel.py,sha256=loflCjR9nCZEtlpnR49jofOWsx7buhRyOsgc27rss-Q,23999
287
288
  rasa/core/channels/webexteams.py,sha256=z_o_jnc6B7hsHpd6XorImFkF43wB4yx_kiTPKAjPSuo,4805
288
289
  rasa/core/concurrent_lock_store.py,sha256=aAZDAYUVffCx2J8wbJ05vTE3Xd9bQ4Dx13RZmCy3ohw,8285
289
290
  rasa/core/constants.py,sha256=dEokmEf6XkOFA_xpuwjqwNtlZv-a5Tz5dLMRc7Vu4CU,4070
@@ -339,7 +340,7 @@ rasa/core/policies/rule_policy.py,sha256=EItfUn07JIBLRIbriPKDprsvWq_-xzZTGrlTS2e
339
340
  rasa/core/policies/ted_policy.py,sha256=0RzIuyrtt4PxLcqQ-bfaExkZvU-TnsMbgmDcwh2SakY,87710
340
341
  rasa/core/policies/unexpected_intent_policy.py,sha256=ZXvbswf2NDy00kHmBQcyXa1OVYFyc79HQKrFkQ4gCfM,39609
341
342
  rasa/core/processor.py,sha256=9bFLV7Thgde1XXsvkKbXqwsSz8QxaC2E88qAYmpEBuI,62314
342
- rasa/core/run.py,sha256=Md-Pl9xjfRA_7VgFcqpT9wpmY-ZceDB0nieMSMadpYA,12124
343
+ rasa/core/run.py,sha256=zwRHM0iXguU1HR___SnOUIwTsCVvSj3FEeiijEiO4Hw,12546
343
344
  rasa/core/secrets_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
344
345
  rasa/core/secrets_manager/constants.py,sha256=dTDHenvG1JBVi34QIR6FpdO5RDOXQwAjAxLlgJ2ZNEI,1193
345
346
  rasa/core/secrets_manager/endpoints.py,sha256=4b7KXB9amdF23eYGsx8215bOjE5-TQ73qD2hdI8Sm9c,12662
@@ -432,7 +433,7 @@ rasa/dialogue_understanding/patterns/collect_information.py,sha256=8YWvhFTt8CJML
432
433
  rasa/dialogue_understanding/patterns/completed.py,sha256=7qkyUj2d__2R3mpwWVmQpfwCCbJruBrjRZbmbDr3Zbo,1278
433
434
  rasa/dialogue_understanding/patterns/continue_interrupted.py,sha256=OSTbe5l0B0ECNIYWpYB0pdzIeaqM3m3UZskNNjL5vrw,1682
434
435
  rasa/dialogue_understanding/patterns/correction.py,sha256=7fQ02-JU1CGZiTjTi9YqmD1F4o-9Tv5WCAXnFgZlvtY,11380
435
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml,sha256=NwNXqrodwOTgDPYtu6L5n6epBLzXjnnRCzH_oBPLMnc,11030
436
+ rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml,sha256=2rAErw1D6i_m7cxd2kbxf24xg5Y1duE3Kpx6O7j_Xdc,11038
436
437
  rasa/dialogue_understanding/patterns/domain_for_patterns.py,sha256=Zv_lCJn4nbkxeNYOPGsR0V8tmYAUsM_Ho_9to8hku-o,6493
437
438
  rasa/dialogue_understanding/patterns/human_handoff.py,sha256=1hkSdL6kui42rZc7zERZ9R7nLyvRHi_tHgNU7FyrhAQ,1132
438
439
  rasa/dialogue_understanding/patterns/internal_error.py,sha256=APCKVv16M6mSQ4upu4UwG0yIaaKTyr7uB2yV8ZtpMzo,1609
@@ -563,9 +564,9 @@ rasa/markers/validate.py,sha256=dZvMTcDK_sji9OP8JY4kUcjeIScLF93C3CKTWK8DplI,708
563
564
  rasa/model.py,sha256=cAbQXvfZXBKHAj79Z0-mCy29hSSWp2KaroScgDeTfJw,3489
564
565
  rasa/model_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
565
566
  rasa/model_manager/config.py,sha256=8upZP4CokMBy0imiiPvINJuLW4JOQ326dPiJ041jJUI,1231
566
- rasa/model_manager/model_api.py,sha256=uY8gC4xSwb7OxnMU0hcT5fx6bGgoTURA3r6bhpxNJdk,23855
567
+ rasa/model_manager/model_api.py,sha256=RZqQLFqlbcao0gnqpjN8EG6E29Ls2pxZiDnCPKoIhKw,23876
567
568
  rasa/model_manager/runner_service.py,sha256=CfvkmCqk-syCqTxb4u3N44WvzXuWFlpomR9SvgzIFKs,9514
568
- rasa/model_manager/socket_bridge.py,sha256=g_cxeFDrvl0u6a7g-Ap55hx4-G3dfxtUpxtSH4Ah9ec,5549
569
+ rasa/model_manager/socket_bridge.py,sha256=S_7aijsXuqHSlSscJfNw2Kt_iWXGfhwn6WhKA3FBLr0,5689
569
570
  rasa/model_manager/studio_jwt_auth.py,sha256=uls2QiHUlUrR3fOzZssW4UaAMJMfnPMZeV1aDmZIT0E,2645
570
571
  rasa/model_manager/trainer_service.py,sha256=aw3tp2736fILT5bYunkERPcWR5TjjyhThBXIktJfhqU,10628
571
572
  rasa/model_manager/utils.py,sha256=rS0ST-rJMuZOna90r_Ioz7gOkZ8r8vm4XAhzI0iUZOA,2643
@@ -739,13 +740,13 @@ rasa/shared/providers/_configs/rasa_llm_client_config.py,sha256=UiEVmjkoS3a0AHLQ
739
740
  rasa/shared/providers/_configs/self_hosted_llm_client_config.py,sha256=rxUFj8s4HAukjhILlOs7vrgXL9WNlfvGEcfMVEa-LrA,5952
740
741
  rasa/shared/providers/_configs/utils.py,sha256=AUnvh4qF9VfLoXpTPoZfwYQ9YsVW8HPMbWa-vG6wOHw,453
741
742
  rasa/shared/providers/_ssl_verification_utils.py,sha256=vUnP0vocf0GQ0wG8IQpPcCet4c1C9-wQWQNckNWbDBk,4165
742
- rasa/shared/providers/_utils.py,sha256=EZIrz3ugcI-9PWgC7v0VMUNYondAAOeeRLIE8ZmResw,5886
743
+ rasa/shared/providers/_utils.py,sha256=LVPsZbl6zzF4hZE6bNVwgY4BkbeIWnRD0dhEqA-kWkk,6975
743
744
  rasa/shared/providers/constants.py,sha256=hgV8yNGxIbID_2h65OoSfSjIE4UkazrsqRg4SdkPAmI,234
744
745
  rasa/shared/providers/embedding/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
745
746
  rasa/shared/providers/embedding/_base_litellm_embedding_client.py,sha256=1CUYxps_TrLVyPsPfOw7iDS502fDePseBIKnqc3ncwQ,9005
746
747
  rasa/shared/providers/embedding/_langchain_embedding_client_adapter.py,sha256=IR2Rb3ReJ9C9sxOoOGRXgtz8STWdMREs_4AeSMKFjl4,2135
747
748
  rasa/shared/providers/embedding/azure_openai_embedding_client.py,sha256=HKHMx6m669CC19u6GPnpSLzA0PwvHlquhaK3QhqHI78,12469
748
- rasa/shared/providers/embedding/default_litellm_embedding_client.py,sha256=da17WeHjZp95Uv9jmTKxklNRcNpn-qRsRPcwDQusElg,4397
749
+ rasa/shared/providers/embedding/default_litellm_embedding_client.py,sha256=FQUFglXN9Ty-FnUaA80itdyutDxLk7HRZwzULG02k8s,4520
749
750
  rasa/shared/providers/embedding/embedding_client.py,sha256=LGFlnsf5B0XDn8GRn_mLfCJ5erhf2p3zXiKTdG9jNXY,2839
750
751
  rasa/shared/providers/embedding/embedding_response.py,sha256=H55mSAL3LfVvDlBklaCCQ4AnNwCsQSQ1f2D0oPrx3FY,1204
751
752
  rasa/shared/providers/embedding/huggingface_local_embedding_client.py,sha256=Zo3gyj49h4LxXV7bx39TXpIPKlernG-5xzqXczTCbig,6913
@@ -754,7 +755,7 @@ rasa/shared/providers/embedding/openai_embedding_client.py,sha256=XNRGE7apo2v3kW
754
755
  rasa/shared/providers/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
755
756
  rasa/shared/providers/llm/_base_litellm_client.py,sha256=Ua5Kt6VGe5vRzSzWWWx2Q3LH2PCDd8V7V4zfYD464yU,11634
756
757
  rasa/shared/providers/llm/azure_openai_llm_client.py,sha256=ui85vothxR2P_-eLc4nLgbpjnpEKY2BXnIjLxBZoYz8,12504
757
- rasa/shared/providers/llm/default_litellm_llm_client.py,sha256=mPDehyLxt3Q9fPSyaMArkVAMkMTf5lfSzhgv--pMTt4,4083
758
+ rasa/shared/providers/llm/default_litellm_llm_client.py,sha256=q6QoyPPq0K7V9aeD0zr08ZK69xlH4GseGFdhUxpWcG8,4210
758
759
  rasa/shared/providers/llm/litellm_router_llm_client.py,sha256=_6vAdPLAVSI_sBJLaXLnE87M-0ip_klfQ78fQ_pyoyI,7947
759
760
  rasa/shared/providers/llm/llm_client.py,sha256=-hTCRsL-A3GCMRHtcyCgcCyra-9OJ8GUC-mURoRXH0k,3242
760
761
  rasa/shared/providers/llm/llm_response.py,sha256=8mOpZdmh4-3yM7aOmNO0yEYUmRDErfoP7ZDMUuHr2Cc,3504
@@ -847,9 +848,9 @@ rasa/utils/train_utils.py,sha256=ClJx-6x3-h3Vt6mskacgkcCUJTMXjFPe3zAcy_DfmaU,212
847
848
  rasa/utils/url_tools.py,sha256=dZ1HGkVdWTJB7zYEdwoDIrEuyX9HE5WsxKKFVsXBLE0,1218
848
849
  rasa/utils/yaml.py,sha256=KjbZq5C94ZP7Jdsw8bYYF7HASI6K4-C_kdHfrnPLpSI,2000
849
850
  rasa/validator.py,sha256=fhRlHQvuBkiup0FnNYmwRmqQwC3QpdCJt0TuvW4jMaI,83125
850
- rasa/version.py,sha256=ahOxjS-ZcfByCTpKZeJQpy8Nz8tWQSofg4M4o09jjXc,129
851
- rasa_pro-3.14.0.dev20250818.dist-info/METADATA,sha256=yh-5sm-77YpUXPMLIH0myQPyO4Df4mSRMkUNWcqJifI,10585
852
- rasa_pro-3.14.0.dev20250818.dist-info/NOTICE,sha256=7HlBoMHJY9CL2GlYSfTQ-PZsVmLmVkYmMiPlTjhuCqA,218
853
- rasa_pro-3.14.0.dev20250818.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
854
- rasa_pro-3.14.0.dev20250818.dist-info/entry_points.txt,sha256=ckJ2SfEyTPgBqj_I6vm_tqY9dZF_LAPJZA335Xp0Q9U,43
855
- rasa_pro-3.14.0.dev20250818.dist-info/RECORD,,
851
+ rasa/version.py,sha256=Ky7QZgOki_d2qRC7Z1GAZctbe6IxA52vhVkvPpQ_8pc,129
852
+ rasa_pro-3.14.0.dev20250825.dist-info/METADATA,sha256=V3KjozHtsQb15IjlJK2CYfppD_oVL17uPhmIx7pXJ18,10585
853
+ rasa_pro-3.14.0.dev20250825.dist-info/NOTICE,sha256=7HlBoMHJY9CL2GlYSfTQ-PZsVmLmVkYmMiPlTjhuCqA,218
854
+ rasa_pro-3.14.0.dev20250825.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
855
+ rasa_pro-3.14.0.dev20250825.dist-info/entry_points.txt,sha256=ckJ2SfEyTPgBqj_I6vm_tqY9dZF_LAPJZA335Xp0Q9U,43
856
+ rasa_pro-3.14.0.dev20250825.dist-info/RECORD,,