rasa-pro 3.14.0.dev20250731__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.
- rasa/core/channels/channel.py +4 -3
- rasa/core/channels/constants.py +3 -0
- rasa/core/channels/development_inspector.py +48 -15
- rasa/core/channels/inspector/dist/assets/{arc-0b11fe30.js → arc-1ddec37b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-9eef30a7.js → blockDiagram-38ab4fdb-18af387c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-03e94f28.js → c4Diagram-3d4e48cf-250127a3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-59f6d54b.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-95c09eba.js → classDiagram-70f12bd4-c3388b34.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-38e8446c.js → classDiagram-v2-f2320105-9c893a82.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-26177ddb.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-57dc3038.js → createText-2e5e7dd3-c111213b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-4bac0545.js → edges-e0da2a9e-812a729d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-81795c90.js → erDiagram-9861fffd-fd5051bc.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-89489ae6.js → flowDb-956e92f1-3287ac02.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-cd152627.js → flowDiagram-66a62f08-692fb0b2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-29c03f5a.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-3da369bc.js → flowchart-elk-definition-4a651766-008376f1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-85ec16f8.js → ganttDiagram-c361ad54-df330a69.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-495bc140.js → gitGraphDiagram-72cf32ee-e03676fb.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-1ec4d266.js → graph-46fad2ba.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-0a0e97c9.js → index-3862675e-a484ac55.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-c804b295.js → index-a003633f.js} +164 -164
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-4d54bcde.js → infoDiagram-f8f76790-3f9e6ec2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-dc097114.js → journeyDiagram-49397b02-79f72383.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-1a08981e.js → layout-aad098e5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-95f7f1d3.js → line-219ab7ae.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-97e69543.js → linear-2cddbe62.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-8c71ff03.js → mindmap-definition-fc14e90a-1d41ed99.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-f14c71c7.js → pieDiagram-8a3498a8-cc496ee8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-f1d3c9ff.js → quadrantDiagram-120e2f19-84d32884.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-bfa2412f.js → requirementDiagram-deff3bca-c0deb984.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-53f2c97b.js → sankeyDiagram-04a897e0-b9d7fd62.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-319d7c0e.js → sequenceDiagram-704730f1-7d517565.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-76a09418.js → stateDiagram-587899a1-98ef9b27.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-a67f15d4.js → stateDiagram-v2-d93cdb3a-cee70748.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-0654e7c3.js → styles-6aaf32cf-3f9d1c96.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-1394bb9d.js → styles-9a916d00-67471923.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-e4c5bdae.js → styles-c10674c1-bd093fb7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-50957104.js → svgDrawCommon-08f97a94-675794e8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-b0885a6a.js → timeline-definition-85554ec2-0ac67617.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-79e6541a.js → xychartDiagram-e933f94c-c018dc37.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +2 -2
- rasa/core/channels/inspector/index.html +1 -1
- rasa/core/channels/inspector/src/App.tsx +53 -7
- rasa/core/channels/inspector/src/components/Chat.tsx +3 -2
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +1 -1
- rasa/core/channels/inspector/src/components/LatencyDisplay.tsx +268 -0
- rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +6 -2
- rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +8 -3
- rasa/core/channels/inspector/src/types.ts +8 -0
- rasa/core/channels/socketio.py +212 -51
- rasa/core/channels/studio_chat.py +77 -31
- rasa/core/channels/voice_stream/audiocodes.py +2 -2
- rasa/core/channels/voice_stream/browser_audio.py +20 -3
- rasa/core/channels/voice_stream/call_state.py +13 -2
- rasa/core/channels/voice_stream/genesys.py +2 -2
- rasa/core/channels/voice_stream/jambonz.py +2 -2
- rasa/core/channels/voice_stream/twilio_media_streams.py +2 -2
- rasa/core/channels/voice_stream/voice_channel.py +88 -16
- rasa/core/nlg/contextual_response_rephraser.py +13 -2
- rasa/core/run.py +13 -3
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +1 -1
- rasa/dialogue_understanding/processor/command_processor.py +27 -11
- rasa/model_manager/model_api.py +3 -3
- rasa/model_manager/socket_bridge.py +21 -16
- rasa/shared/providers/_utils.py +60 -44
- rasa/shared/providers/embedding/default_litellm_embedding_client.py +2 -0
- rasa/shared/providers/llm/default_litellm_llm_client.py +2 -0
- rasa/studio/upload.py +7 -4
- rasa/studio/utils.py +33 -22
- rasa/version.py +1 -1
- {rasa_pro-3.14.0.dev20250731.dist-info → rasa_pro-3.14.0.dev20250825.dist-info}/METADATA +6 -6
- {rasa_pro-3.14.0.dev20250731.dist-info → rasa_pro-3.14.0.dev20250825.dist-info}/RECORD +76 -74
- rasa/core/channels/inspector/dist/assets/channel-51d02e9e.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-cc738fa6.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-0c716443.js +0 -1
- {rasa_pro-3.14.0.dev20250731.dist-info → rasa_pro-3.14.0.dev20250825.dist-info}/NOTICE +0 -0
- {rasa_pro-3.14.0.dev20250731.dist-info → rasa_pro-3.14.0.dev20250825.dist-info}/WHEEL +0 -0
- {rasa_pro-3.14.0.dev20250731.dist-info → rasa_pro-3.14.0.dev20250825.dist-info}/entry_points.txt +0 -0
|
@@ -24,6 +24,7 @@ from rasa.shared.constants import (
|
|
|
24
24
|
)
|
|
25
25
|
from rasa.shared.core.domain import KEY_RESPONSES_TEXT, Domain
|
|
26
26
|
from rasa.shared.core.events import BotUttered, UserUttered
|
|
27
|
+
from rasa.shared.core.flows.constants import KEY_TRANSLATION
|
|
27
28
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
28
29
|
from rasa.shared.nlu.constants import (
|
|
29
30
|
KEY_COMPONENT_NAME,
|
|
@@ -307,7 +308,12 @@ class ContextualResponseRephraser(
|
|
|
307
308
|
Returns:
|
|
308
309
|
The response with the rephrased text.
|
|
309
310
|
"""
|
|
310
|
-
|
|
311
|
+
translation_response = response.get(KEY_TRANSLATION) or {}
|
|
312
|
+
lang_code = getattr(tracker.current_language, "code", None)
|
|
313
|
+
response_text = translation_response.get(
|
|
314
|
+
lang_code, response.get(KEY_RESPONSES_TEXT)
|
|
315
|
+
)
|
|
316
|
+
if not response_text:
|
|
311
317
|
return response
|
|
312
318
|
|
|
313
319
|
prompt_template_text = self._template_for_response_rephrasing(response)
|
|
@@ -369,12 +375,17 @@ class ContextualResponseRephraser(
|
|
|
369
375
|
return response
|
|
370
376
|
|
|
371
377
|
updated_text = llm_response.choices[0]
|
|
378
|
+
|
|
379
|
+
if lang_code in translation_response:
|
|
380
|
+
response[KEY_TRANSLATION][lang_code] = updated_text
|
|
381
|
+
else:
|
|
382
|
+
response[KEY_RESPONSES_TEXT] = updated_text
|
|
383
|
+
|
|
372
384
|
structlogger.debug(
|
|
373
385
|
"nlg.rewrite.complete",
|
|
374
386
|
response_text=response_text,
|
|
375
387
|
updated_text=updated_text,
|
|
376
388
|
)
|
|
377
|
-
response[KEY_RESPONSES_TEXT] = updated_text
|
|
378
389
|
return response
|
|
379
390
|
|
|
380
391
|
def does_response_allow_rephrasing(self, template: Dict[Text, Any]) -> bool:
|
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
|
|
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 =
|
|
266
|
+
input_channels = create_input_channels(channel, credentials)
|
|
257
267
|
|
|
258
268
|
if inspect:
|
|
259
269
|
logger.info("Starting development inspector.")
|
|
@@ -398,19 +398,12 @@ def clean_up_commands(
|
|
|
398
398
|
"""
|
|
399
399
|
domain = domain if domain else Domain.empty()
|
|
400
400
|
|
|
401
|
-
# we consider all slots that were set in the tracker for potential corrections
|
|
402
|
-
# in the correct_slot_command we will check if a slot should actually be
|
|
403
|
-
# corrected
|
|
404
|
-
slots_so_far = set(
|
|
405
|
-
[event.key for event in tracker.events if isinstance(event, SlotSet)]
|
|
406
|
-
)
|
|
407
|
-
|
|
408
401
|
clean_commands: List[Command] = []
|
|
409
402
|
|
|
410
403
|
for command in commands:
|
|
411
404
|
if isinstance(command, SetSlotCommand):
|
|
412
405
|
clean_commands = clean_up_slot_command(
|
|
413
|
-
clean_commands, command, tracker, all_flows
|
|
406
|
+
clean_commands, command, tracker, all_flows
|
|
414
407
|
)
|
|
415
408
|
|
|
416
409
|
elif isinstance(command, CancelFlowCommand) and contains_command(
|
|
@@ -501,6 +494,25 @@ def clean_up_commands(
|
|
|
501
494
|
return clean_commands
|
|
502
495
|
|
|
503
496
|
|
|
497
|
+
def _get_slots_eligible_for_correction(tracker: DialogueStateTracker) -> Set[str]:
|
|
498
|
+
"""Get all slots that are eligible for correction.
|
|
499
|
+
|
|
500
|
+
# We consider all slots, which are not None, that were set in the tracker
|
|
501
|
+
# eligible for correction.
|
|
502
|
+
# In the correct_slot_command we will check if a slot should actually be
|
|
503
|
+
# corrected.
|
|
504
|
+
"""
|
|
505
|
+
# get all slots that were set in the tracker
|
|
506
|
+
slots_so_far = set(
|
|
507
|
+
[event.key for event in tracker.events if isinstance(event, SlotSet)]
|
|
508
|
+
)
|
|
509
|
+
|
|
510
|
+
# filter out slots that are set to None (None = empty value)
|
|
511
|
+
slots_so_far = {slot for slot in slots_so_far if tracker.get_slot(slot) is not None}
|
|
512
|
+
|
|
513
|
+
return slots_so_far
|
|
514
|
+
|
|
515
|
+
|
|
504
516
|
def ensure_max_number_of_command_type(
|
|
505
517
|
commands: List[Command], command_type: Type[Command], n: int
|
|
506
518
|
) -> List[Command]:
|
|
@@ -560,7 +572,6 @@ def clean_up_slot_command(
|
|
|
560
572
|
command: SetSlotCommand,
|
|
561
573
|
tracker: DialogueStateTracker,
|
|
562
574
|
all_flows: FlowsList,
|
|
563
|
-
slots_so_far: Set[str],
|
|
564
575
|
) -> List[Command]:
|
|
565
576
|
"""Clean up a slot command.
|
|
566
577
|
|
|
@@ -573,7 +584,6 @@ def clean_up_slot_command(
|
|
|
573
584
|
command: The command to clean up.
|
|
574
585
|
tracker: The dialogue state tracker.
|
|
575
586
|
all_flows: All flows.
|
|
576
|
-
slots_so_far: The slots that have been filled so far.
|
|
577
587
|
|
|
578
588
|
Returns:
|
|
579
589
|
The cleaned up commands.
|
|
@@ -642,7 +652,13 @@ def clean_up_slot_command(
|
|
|
642
652
|
)
|
|
643
653
|
return resulting_commands
|
|
644
654
|
|
|
645
|
-
|
|
655
|
+
# get all slots that were set in the tracker and are eligible for correction
|
|
656
|
+
slots_eligible_for_correction = _get_slots_eligible_for_correction(tracker)
|
|
657
|
+
|
|
658
|
+
if (
|
|
659
|
+
command.name in slots_eligible_for_correction
|
|
660
|
+
and command.name != ROUTE_TO_CALM_SLOT
|
|
661
|
+
):
|
|
646
662
|
current_collect_info = get_current_collect_step(stack, all_flows)
|
|
647
663
|
|
|
648
664
|
if current_collect_info and current_collect_info.collect == command.name:
|
rasa/model_manager/model_api.py
CHANGED
|
@@ -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
|
-
|
|
575
|
-
bp = SocketBlueprint(
|
|
574
|
+
sio_server = AsyncServer(async_mode="sanic", cors_allowed_origins="*")
|
|
575
|
+
bp = SocketBlueprint(sio_server, "", "model_api_external")
|
|
576
576
|
|
|
577
|
-
create_bridge_server(
|
|
577
|
+
create_bridge_server(sio_server, running_bots)
|
|
578
578
|
|
|
579
579
|
@bp.get("/health")
|
|
580
580
|
async def health(request: Request) -> response.HTTPResponse:
|
|
@@ -2,8 +2,7 @@ import json
|
|
|
2
2
|
from typing import Any, Dict, Optional
|
|
3
3
|
|
|
4
4
|
import structlog
|
|
5
|
-
from socketio import AsyncServer
|
|
6
|
-
from socketio.asyncio_client import AsyncClient
|
|
5
|
+
from socketio import AsyncClient, AsyncServer # type: ignore[attr-defined]
|
|
7
6
|
from socketio.exceptions import ConnectionRefusedError
|
|
8
7
|
|
|
9
8
|
from rasa.model_manager.runner_service import BotSession
|
|
@@ -20,7 +19,7 @@ socket_proxy_clients = {}
|
|
|
20
19
|
|
|
21
20
|
|
|
22
21
|
async def socketio_websocket_traffic_wrapper(
|
|
23
|
-
|
|
22
|
+
sio_server: AsyncServer,
|
|
24
23
|
running_bots: Dict[str, BotSession],
|
|
25
24
|
sid: str,
|
|
26
25
|
auth: Optional[Dict],
|
|
@@ -56,7 +55,9 @@ async def socketio_websocket_traffic_wrapper(
|
|
|
56
55
|
structlogger.error("model_runner.bot_not_alive", deployment_id=deployment_id)
|
|
57
56
|
raise ConnectionRefusedError("model_runner.bot_not_alive")
|
|
58
57
|
|
|
59
|
-
client = await create_bridge_client(
|
|
58
|
+
client = await create_bridge_client(
|
|
59
|
+
sio_server, bot.internal_url, sid, deployment_id
|
|
60
|
+
)
|
|
60
61
|
|
|
61
62
|
if client.sid is not None:
|
|
62
63
|
structlogger.debug(
|
|
@@ -71,20 +72,24 @@ async def socketio_websocket_traffic_wrapper(
|
|
|
71
72
|
raise ConnectionRefusedError("model_runner.bot_connection_failed")
|
|
72
73
|
|
|
73
74
|
|
|
74
|
-
def create_bridge_server(
|
|
75
|
+
def create_bridge_server(
|
|
76
|
+
sio_server: AsyncServer, running_bots: Dict[str, BotSession]
|
|
77
|
+
) -> None:
|
|
75
78
|
"""Create handlers for the socket server side.
|
|
76
79
|
|
|
77
80
|
Forwards messages coming from the user to the bot.
|
|
78
81
|
"""
|
|
79
82
|
|
|
80
|
-
@
|
|
83
|
+
@sio_server.on("connect")
|
|
81
84
|
async def socketio_websocket_traffic(
|
|
82
85
|
sid: str, environ: Dict, auth: Optional[Dict]
|
|
83
86
|
) -> bool:
|
|
84
87
|
"""Bridge websockets between user chat socket and bot server."""
|
|
85
|
-
return await socketio_websocket_traffic_wrapper(
|
|
88
|
+
return await socketio_websocket_traffic_wrapper(
|
|
89
|
+
sio_server, running_bots, sid, auth
|
|
90
|
+
)
|
|
86
91
|
|
|
87
|
-
@
|
|
92
|
+
@sio_server.on("disconnect")
|
|
88
93
|
async def disconnect(sid: str) -> None:
|
|
89
94
|
"""Disconnect the bot connection."""
|
|
90
95
|
structlogger.debug("model_runner.bot_disconnect", sid=sid)
|
|
@@ -92,7 +97,7 @@ def create_bridge_server(sio: AsyncServer, running_bots: Dict[str, BotSession])
|
|
|
92
97
|
await socket_proxy_clients[sid].disconnect()
|
|
93
98
|
del socket_proxy_clients[sid]
|
|
94
99
|
|
|
95
|
-
@
|
|
100
|
+
@sio_server.on("*")
|
|
96
101
|
async def handle_message(event: str, sid: str, data: Dict[str, Any]) -> None:
|
|
97
102
|
"""Bridge messages between user and bot.
|
|
98
103
|
|
|
@@ -109,7 +114,7 @@ def create_bridge_server(sio: AsyncServer, running_bots: Dict[str, BotSession])
|
|
|
109
114
|
|
|
110
115
|
|
|
111
116
|
async def create_bridge_client(
|
|
112
|
-
|
|
117
|
+
sio_server: AsyncServer, url: str, sid: str, deployment_id: str
|
|
113
118
|
) -> AsyncClient:
|
|
114
119
|
"""Create a new socket bridge client.
|
|
115
120
|
|
|
@@ -124,36 +129,36 @@ async def create_bridge_client(
|
|
|
124
129
|
structlogger.debug(
|
|
125
130
|
"model_runner.bot_session_confirmed", deployment_id=deployment_id
|
|
126
131
|
)
|
|
127
|
-
await
|
|
132
|
+
await sio_server.emit("session_confirm", room=sid)
|
|
128
133
|
|
|
129
134
|
@client.event # type: ignore[misc]
|
|
130
135
|
async def bot_message(data: Dict[str, Any]) -> None:
|
|
131
136
|
structlogger.debug("model_runner.bot_message", deployment_id=deployment_id)
|
|
132
|
-
await
|
|
137
|
+
await sio_server.emit("bot_message", data, room=sid)
|
|
133
138
|
|
|
134
139
|
@client.event # type: ignore[misc]
|
|
135
140
|
async def error(data: Dict[str, Any]) -> None:
|
|
136
141
|
structlogger.debug(
|
|
137
142
|
"model_runner.bot_error", deployment_id=deployment_id, data=data
|
|
138
143
|
)
|
|
139
|
-
await
|
|
144
|
+
await sio_server.emit("error", data, room=sid)
|
|
140
145
|
|
|
141
146
|
@client.event # type: ignore[misc]
|
|
142
147
|
async def tracker(data: Dict[str, Any]) -> None:
|
|
143
|
-
await
|
|
148
|
+
await sio_server.emit("tracker", json.loads(data), room=sid)
|
|
144
149
|
|
|
145
150
|
@client.event # type: ignore[misc]
|
|
146
151
|
async def disconnect() -> None:
|
|
147
152
|
structlogger.debug(
|
|
148
153
|
"model_runner.bot_connection_closed", deployment_id=deployment_id
|
|
149
154
|
)
|
|
150
|
-
await
|
|
155
|
+
await sio_server.emit("disconnect", room=sid)
|
|
151
156
|
|
|
152
157
|
@client.event # type: ignore[misc]
|
|
153
158
|
async def connect_error() -> None:
|
|
154
159
|
structlogger.error(
|
|
155
160
|
"model_runner.bot_connection_error", deployment_id=deployment_id
|
|
156
161
|
)
|
|
157
|
-
await
|
|
162
|
+
await sio_server.emit("disconnect", room=sid)
|
|
158
163
|
|
|
159
164
|
return client
|
rasa/shared/providers/_utils.py
CHANGED
|
@@ -1,87 +1,103 @@
|
|
|
1
1
|
from typing import Any, Dict, Optional
|
|
2
2
|
|
|
3
|
+
import boto3
|
|
3
4
|
import structlog
|
|
4
|
-
from
|
|
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
|
-
|
|
11
|
+
AWS_BEDROCK_PROVIDER,
|
|
11
12
|
AWS_REGION_NAME_CONFIG_KEY,
|
|
12
|
-
|
|
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.
|
|
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:
|
|
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
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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"
|
|
77
|
-
f"
|
|
78
|
-
f"
|
|
79
|
-
f"
|
|
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}.
|
|
97
|
+
f"{source_log}.validate_aws_credentials_for_litellm_clients",
|
|
83
98
|
event_info=event_info,
|
|
84
|
-
|
|
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/studio/upload.py
CHANGED
|
@@ -115,9 +115,10 @@ def run_validation(args: argparse.Namespace) -> None:
|
|
|
115
115
|
"""
|
|
116
116
|
from rasa.validator import Validator
|
|
117
117
|
|
|
118
|
+
training_data_paths = args.data if isinstance(args.data, list) else [args.data]
|
|
118
119
|
training_data_importer = TrainingDataImporter.load_from_dict(
|
|
119
120
|
domain_path=args.domain,
|
|
120
|
-
training_data_paths=
|
|
121
|
+
training_data_paths=training_data_paths,
|
|
121
122
|
config_path=args.config,
|
|
122
123
|
expand_env_vars=False,
|
|
123
124
|
)
|
|
@@ -263,8 +264,9 @@ def build_calm_import_parts(
|
|
|
263
264
|
domain_from_files = importer.get_user_domain().as_dict()
|
|
264
265
|
domain = extract_values(domain_from_files, DOMAIN_KEYS)
|
|
265
266
|
|
|
267
|
+
training_data_paths = data_path if isinstance(data_path, list) else [str(data_path)]
|
|
266
268
|
flow_importer = FlowSyncImporter.load_from_dict(
|
|
267
|
-
training_data_paths=
|
|
269
|
+
training_data_paths=training_data_paths, expand_env_vars=False
|
|
268
270
|
)
|
|
269
271
|
|
|
270
272
|
flows = list(flow_importer.get_user_flows())
|
|
@@ -272,7 +274,7 @@ def build_calm_import_parts(
|
|
|
272
274
|
flows = read_yaml(flows_yaml, expand_env_vars=False)
|
|
273
275
|
|
|
274
276
|
nlu_importer = TrainingDataImporter.load_from_dict(
|
|
275
|
-
training_data_paths=
|
|
277
|
+
training_data_paths=training_data_paths, expand_env_vars=False
|
|
276
278
|
)
|
|
277
279
|
nlu_data = nlu_importer.get_nlu_data()
|
|
278
280
|
nlu_examples = nlu_data.filter_training_examples(
|
|
@@ -349,9 +351,10 @@ def upload_nlu_assistant(
|
|
|
349
351
|
"rasa.studio.upload.nlu_data_read",
|
|
350
352
|
event_info="Found DM1 assistant data, parsing...",
|
|
351
353
|
)
|
|
354
|
+
training_data_paths = args.data if isinstance(args.data, list) else [args.data]
|
|
352
355
|
importer = TrainingDataImporter.load_from_dict(
|
|
353
356
|
domain_path=args.domain,
|
|
354
|
-
training_data_paths=
|
|
357
|
+
training_data_paths=training_data_paths,
|
|
355
358
|
config_path=args.config,
|
|
356
359
|
expand_env_vars=False,
|
|
357
360
|
)
|
rasa/studio/utils.py
CHANGED
|
@@ -1,33 +1,44 @@
|
|
|
1
1
|
import argparse
|
|
2
2
|
from pathlib import Path
|
|
3
|
+
from typing import List
|
|
3
4
|
|
|
4
5
|
import rasa.shared.utils.cli
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
from rasa.studio.constants import DOMAIN_FILENAME
|
|
6
|
+
|
|
7
|
+
DOMAIN_FILENAME = "domain.yml"
|
|
8
|
+
DEFAULT_CONFIG_PATH = "config.yml"
|
|
9
|
+
DEFAULT_ENDPOINTS_PATH = "endpoints.yml"
|
|
10
|
+
DEFAULT_DATA_PATH = "data"
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def validate_argument_paths(args: argparse.Namespace) -> None:
|
|
14
|
-
"""
|
|
14
|
+
"""Validate every path passed via CLI arguments.
|
|
15
15
|
|
|
16
16
|
Args:
|
|
17
|
-
args:
|
|
17
|
+
args: CLI arguments containing paths to validate.
|
|
18
|
+
|
|
19
|
+
Raises:
|
|
20
|
+
rasa.shared.utils.cli.PrintErrorAndExit: If any path does not exist.
|
|
18
21
|
"""
|
|
22
|
+
invalid_paths: List[str] = []
|
|
23
|
+
|
|
24
|
+
def collect_invalid_paths(arg_name: str, default: str) -> None:
|
|
25
|
+
value = getattr(args, arg_name, None)
|
|
26
|
+
path_values = value if isinstance(value, list) else [value]
|
|
27
|
+
for path_value in path_values:
|
|
28
|
+
if not path_value or path_value == default:
|
|
29
|
+
continue
|
|
30
|
+
|
|
31
|
+
if not Path(path_value).resolve().exists():
|
|
32
|
+
invalid_paths.append(f"{arg_name}: '{path_value}'")
|
|
33
|
+
|
|
34
|
+
collect_invalid_paths("domain", DOMAIN_FILENAME)
|
|
35
|
+
collect_invalid_paths("config", DEFAULT_CONFIG_PATH)
|
|
36
|
+
collect_invalid_paths("endpoints", DEFAULT_ENDPOINTS_PATH)
|
|
37
|
+
collect_invalid_paths("data", DEFAULT_DATA_PATH)
|
|
19
38
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
f"{arg_name.capitalize()} file or directory "
|
|
27
|
-
f"'{path_value}' does not exist."
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
validate_path("domain", DOMAIN_FILENAME)
|
|
31
|
-
validate_path("config", DEFAULT_CONFIG_PATH)
|
|
32
|
-
validate_path("endpoints", DEFAULT_ENDPOINTS_PATH)
|
|
33
|
-
validate_path("data", DEFAULT_DATA_PATH)
|
|
39
|
+
if invalid_paths:
|
|
40
|
+
message = (
|
|
41
|
+
"The following files or directories do not exist:\n - "
|
|
42
|
+
+ "\n - ".join(invalid_paths)
|
|
43
|
+
)
|
|
44
|
+
rasa.shared.utils.cli.print_error_and_exit(message)
|
rasa/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: rasa-pro
|
|
3
|
-
Version: 3.14.0.
|
|
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
|
|
@@ -23,7 +23,7 @@ Provides-Extra: spacy
|
|
|
23
23
|
Provides-Extra: transformers
|
|
24
24
|
Requires-Dist: CacheControl (>=0.14.2,<0.15.0)
|
|
25
25
|
Requires-Dist: PyJWT[crypto] (>=2.8.0,<3.0.0)
|
|
26
|
-
Requires-Dist: SQLAlchemy (>=2.0.
|
|
26
|
+
Requires-Dist: SQLAlchemy (>=2.0.42,<2.1.0)
|
|
27
27
|
Requires-Dist: absl-py (>=2.0,<2.1)
|
|
28
28
|
Requires-Dist: aio-pika (>=8.2.3,<9.4.4)
|
|
29
29
|
Requires-Dist: aiogram (>=3.15,<3.16)
|
|
@@ -38,7 +38,7 @@ Requires-Dist: colorama (>=0.4.6,<0.5.0) ; sys_platform == "win32"
|
|
|
38
38
|
Requires-Dist: colorclass (>=2.2,<2.3)
|
|
39
39
|
Requires-Dist: coloredlogs (>=15,<16)
|
|
40
40
|
Requires-Dist: colorhash (>=2.0,<2.1.0)
|
|
41
|
-
Requires-Dist: confluent-kafka (>=2.
|
|
41
|
+
Requires-Dist: confluent-kafka (>=2.11.0,<3.0.0)
|
|
42
42
|
Requires-Dist: cryptography (>=44.0.1)
|
|
43
43
|
Requires-Dist: cvg-python-sdk (>=0.5.1,<0.6.0)
|
|
44
44
|
Requires-Dist: dask (>=2024.8.0,<2024.9.0)
|
|
@@ -93,9 +93,9 @@ Requires-Dist: python-dateutil (>=2.8.2,<2.9.0)
|
|
|
93
93
|
Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
|
94
94
|
Requires-Dist: python-engineio (>=4.12.2,<4.13.0)
|
|
95
95
|
Requires-Dist: python-keycloak (>=3.12.0,<4.0.0)
|
|
96
|
-
Requires-Dist: python-socketio (>=5.
|
|
96
|
+
Requires-Dist: python-socketio (>=5.13,<6)
|
|
97
97
|
Requires-Dist: pytz (>=2022.7.1,<2023.0)
|
|
98
|
-
Requires-Dist: pyyaml (>=6.0)
|
|
98
|
+
Requires-Dist: pyyaml (>=6.0.2,<6.1.0)
|
|
99
99
|
Requires-Dist: qdrant-client (>=1.9.1,<1.10.0)
|
|
100
100
|
Requires-Dist: questionary (>=1.10.0,<2.1.0)
|
|
101
101
|
Requires-Dist: randomname (>=0.2.1,<0.3.0)
|
|
@@ -120,7 +120,7 @@ Requires-Dist: sklearn-crfsuite (>=0.5.0,<0.6.0)
|
|
|
120
120
|
Requires-Dist: skops (>=0.11.0,<0.12.0)
|
|
121
121
|
Requires-Dist: slack-sdk (>=3.27.1,<3.28.0)
|
|
122
122
|
Requires-Dist: spacy (>=3.5.4,<4.0.0) ; extra == "spacy" or extra == "full"
|
|
123
|
-
Requires-Dist: structlog (>=
|
|
123
|
+
Requires-Dist: structlog (>=25.4.0,<25.5.0)
|
|
124
124
|
Requires-Dist: structlog-sentry (>=2.0.3,<2.1.0)
|
|
125
125
|
Requires-Dist: tarsafe (>=0.0.5,<0.0.6)
|
|
126
126
|
Requires-Dist: tenacity (>=8.4.1,<8.5.0)
|