rasa-pro 3.14.1__py3-none-any.whl → 3.15.0.dev20251027__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/builder/config.py +4 -0
- rasa/builder/copilot/copilot.py +28 -9
- rasa/builder/copilot/models.py +251 -32
- rasa/builder/document_retrieval/inkeep_document_retrieval.py +2 -0
- rasa/builder/download.py +1 -1
- rasa/builder/evaluator/__init__.py +0 -0
- rasa/builder/evaluator/constants.py +15 -0
- rasa/builder/evaluator/copilot_executor.py +89 -0
- rasa/builder/evaluator/dataset/models.py +173 -0
- rasa/builder/evaluator/exceptions.py +4 -0
- rasa/builder/evaluator/response_classification/__init__.py +0 -0
- rasa/builder/evaluator/response_classification/constants.py +66 -0
- rasa/builder/evaluator/response_classification/evaluator.py +346 -0
- rasa/builder/evaluator/response_classification/langfuse_runner.py +463 -0
- rasa/builder/evaluator/response_classification/models.py +61 -0
- rasa/builder/evaluator/scripts/__init__.py +0 -0
- rasa/builder/evaluator/scripts/run_response_classification_evaluator.py +152 -0
- rasa/builder/service.py +101 -24
- rasa/builder/telemetry/__init__.py +0 -0
- rasa/builder/telemetry/copilot_langfuse_telemetry.py +384 -0
- rasa/builder/{copilot/telemetry.py → telemetry/copilot_segment_telemetry.py} +21 -3
- rasa/constants.py +1 -0
- rasa/core/policies/flows/flow_executor.py +20 -6
- rasa/core/run.py +15 -4
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +15 -7
- rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +15 -8
- rasa/e2e_test/e2e_config.py +4 -3
- rasa/engine/recipes/default_components.py +16 -6
- rasa/graph_components/validators/default_recipe_validator.py +10 -4
- rasa/nlu/classifiers/diet_classifier.py +2 -0
- rasa/shared/core/slots.py +55 -24
- rasa/shared/utils/common.py +9 -1
- rasa/utils/common.py +9 -0
- rasa/utils/endpoints.py +2 -0
- rasa/utils/installation_utils.py +111 -0
- rasa/utils/tensorflow/callback.py +2 -0
- rasa/utils/train_utils.py +2 -0
- rasa/version.py +1 -1
- {rasa_pro-3.14.1.dist-info → rasa_pro-3.15.0.dev20251027.dist-info}/METADATA +4 -2
- {rasa_pro-3.14.1.dist-info → rasa_pro-3.15.0.dev20251027.dist-info}/RECORD +43 -28
- {rasa_pro-3.14.1.dist-info → rasa_pro-3.15.0.dev20251027.dist-info}/NOTICE +0 -0
- {rasa_pro-3.14.1.dist-info → rasa_pro-3.15.0.dev20251027.dist-info}/WHEEL +0 -0
- {rasa_pro-3.14.1.dist-info → rasa_pro-3.15.0.dev20251027.dist-info}/entry_points.txt +0 -0
|
@@ -357,6 +357,10 @@ def reset_scoped_slots(
|
|
|
357
357
|
flow_persistable_slots = current_flow.persisted_slots
|
|
358
358
|
|
|
359
359
|
for step in current_flow.steps_with_calls_resolved:
|
|
360
|
+
# take persisted slots from called flows into consideration
|
|
361
|
+
# before resetting slots
|
|
362
|
+
if isinstance(step, CallFlowStep) and step.called_flow_reference:
|
|
363
|
+
flow_persistable_slots.extend(step.called_flow_reference.persisted_slots)
|
|
360
364
|
if isinstance(step, CollectInformationFlowStep):
|
|
361
365
|
# reset all slots scoped to the flow
|
|
362
366
|
slot_name = step.collect
|
|
@@ -368,7 +372,22 @@ def reset_scoped_slots(
|
|
|
368
372
|
# slots set by the set slots step should be reset after the flow ends
|
|
369
373
|
# unless they are also used in a collect step where `reset_after_flow_ends`
|
|
370
374
|
# is set to `False` or set in the `persisted_slots` list.
|
|
371
|
-
resettable_set_slots =
|
|
375
|
+
resettable_set_slots = _get_resettable_set_slots(
|
|
376
|
+
current_flow, not_resettable_slot_names, flow_persistable_slots
|
|
377
|
+
)
|
|
378
|
+
for name in resettable_set_slots:
|
|
379
|
+
_reset_slot(name, tracker)
|
|
380
|
+
|
|
381
|
+
return events
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def _get_resettable_set_slots(
|
|
385
|
+
current_flow: Flow,
|
|
386
|
+
not_resettable_slot_names: set[Text],
|
|
387
|
+
flow_persistable_slots: List[Text],
|
|
388
|
+
) -> List[Text]:
|
|
389
|
+
"""Get list of slot names from SetSlotsFlowStep that should be reset."""
|
|
390
|
+
return [
|
|
372
391
|
slot["key"]
|
|
373
392
|
for step in current_flow.steps_with_calls_resolved
|
|
374
393
|
if isinstance(step, SetSlotsFlowStep)
|
|
@@ -377,11 +396,6 @@ def reset_scoped_slots(
|
|
|
377
396
|
and slot["key"] not in flow_persistable_slots
|
|
378
397
|
]
|
|
379
398
|
|
|
380
|
-
for name in resettable_set_slots:
|
|
381
|
-
_reset_slot(name, tracker)
|
|
382
|
-
|
|
383
|
-
return events
|
|
384
|
-
|
|
385
399
|
|
|
386
400
|
async def advance_flows(
|
|
387
401
|
tracker: DialogueStateTracker,
|
rasa/core/run.py
CHANGED
|
@@ -328,10 +328,21 @@ def serve_application(
|
|
|
328
328
|
|
|
329
329
|
logger.info(f"Starting Rasa server on {protocol}://{interface}:{port}")
|
|
330
330
|
|
|
331
|
-
app
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
331
|
+
async def load_agent_and_check_failure(app: Sanic, loop: AbstractEventLoop) -> None:
|
|
332
|
+
"""Load agent and exit if it fails in non-debug mode."""
|
|
333
|
+
try:
|
|
334
|
+
await load_agent_on_start(
|
|
335
|
+
model_path, endpoints, remote_storage, sub_agents, app, loop
|
|
336
|
+
)
|
|
337
|
+
except Exception as e:
|
|
338
|
+
is_debug = logger.isEnabledFor(logging.DEBUG)
|
|
339
|
+
if is_debug:
|
|
340
|
+
raise e # show traceback in debug
|
|
341
|
+
# non-debug: log and exit without starting server
|
|
342
|
+
logger.error(f"Failed to load agent: {e}")
|
|
343
|
+
os._exit(1) # Any other exit method would show a traceback.
|
|
344
|
+
|
|
345
|
+
app.register_listener(load_agent_and_check_failure, "before_server_start")
|
|
335
346
|
|
|
336
347
|
app.register_listener(
|
|
337
348
|
licensing.validate_limited_server_license, "after_server_start"
|
|
@@ -168,6 +168,20 @@ class CompactLLMCommandGenerator(SingleStepBasedLLMCommandGenerator):
|
|
|
168
168
|
if prompt_template is not None:
|
|
169
169
|
return prompt_template
|
|
170
170
|
|
|
171
|
+
# Try to load the template from the given path or fallback to the default for
|
|
172
|
+
# the component.
|
|
173
|
+
custom_prompt_template_path = config.get(PROMPT_TEMPLATE_CONFIG_KEY)
|
|
174
|
+
if custom_prompt_template_path is not None:
|
|
175
|
+
custom_prompt_template = get_prompt_template(
|
|
176
|
+
custom_prompt_template_path,
|
|
177
|
+
None, # Default will be based on the model
|
|
178
|
+
log_source_component=log_source_component,
|
|
179
|
+
log_source_method=log_context,
|
|
180
|
+
)
|
|
181
|
+
if custom_prompt_template is not None:
|
|
182
|
+
return custom_prompt_template
|
|
183
|
+
|
|
184
|
+
# Fallback to the default prompt template based on the model.
|
|
171
185
|
default_command_prompt_template = get_default_prompt_template_based_on_model(
|
|
172
186
|
llm_config=config.get(LLM_CONFIG_KEY, {}) or {},
|
|
173
187
|
model_prompt_mapping=cls.get_model_prompt_mapper(),
|
|
@@ -177,10 +191,4 @@ class CompactLLMCommandGenerator(SingleStepBasedLLMCommandGenerator):
|
|
|
177
191
|
log_source_method=log_context,
|
|
178
192
|
)
|
|
179
193
|
|
|
180
|
-
|
|
181
|
-
return get_prompt_template(
|
|
182
|
-
config.get(PROMPT_TEMPLATE_CONFIG_KEY),
|
|
183
|
-
default_command_prompt_template,
|
|
184
|
-
log_source_component=log_source_component,
|
|
185
|
-
log_source_method=log_context,
|
|
186
|
-
)
|
|
194
|
+
return default_command_prompt_template
|
|
@@ -165,7 +165,20 @@ class SearchReadyLLMCommandGenerator(SingleStepBasedLLMCommandGenerator):
|
|
|
165
165
|
if prompt_template is not None:
|
|
166
166
|
return prompt_template
|
|
167
167
|
|
|
168
|
-
#
|
|
168
|
+
# Try to load the template from the given path or fallback to the default for
|
|
169
|
+
# the component.
|
|
170
|
+
custom_prompt_template_path = config.get(PROMPT_TEMPLATE_CONFIG_KEY)
|
|
171
|
+
if custom_prompt_template_path is not None:
|
|
172
|
+
custom_prompt_template = get_prompt_template(
|
|
173
|
+
custom_prompt_template_path,
|
|
174
|
+
None, # Default will be based on the model
|
|
175
|
+
log_source_component=log_source_component,
|
|
176
|
+
log_source_method=log_context,
|
|
177
|
+
)
|
|
178
|
+
if custom_prompt_template is not None:
|
|
179
|
+
return custom_prompt_template
|
|
180
|
+
|
|
181
|
+
# Fallback to the default prompt template based on the model.
|
|
169
182
|
default_command_prompt_template = get_default_prompt_template_based_on_model(
|
|
170
183
|
llm_config=config.get(LLM_CONFIG_KEY, {}) or {},
|
|
171
184
|
model_prompt_mapping=cls.get_model_prompt_mapper(),
|
|
@@ -175,10 +188,4 @@ class SearchReadyLLMCommandGenerator(SingleStepBasedLLMCommandGenerator):
|
|
|
175
188
|
log_source_method=log_context,
|
|
176
189
|
)
|
|
177
190
|
|
|
178
|
-
|
|
179
|
-
return get_prompt_template(
|
|
180
|
-
config.get(PROMPT_TEMPLATE_CONFIG_KEY),
|
|
181
|
-
default_command_prompt_template,
|
|
182
|
-
log_source_component=log_source_component,
|
|
183
|
-
log_source_method=log_context,
|
|
184
|
-
)
|
|
191
|
+
return default_command_prompt_template
|
rasa/e2e_test/e2e_config.py
CHANGED
|
@@ -72,9 +72,10 @@ class LLMJudgeConfig(BaseModel):
|
|
|
72
72
|
|
|
73
73
|
llm_config = resolve_model_client_config(llm_config)
|
|
74
74
|
llm_config, llm_extra_parameters = cls.extract_attributes(llm_config)
|
|
75
|
-
|
|
76
|
-
llm_config
|
|
77
|
-
|
|
75
|
+
if not llm_config:
|
|
76
|
+
llm_config = combine_custom_and_default_config(
|
|
77
|
+
llm_config, cls.get_default_llm_config()
|
|
78
|
+
)
|
|
78
79
|
embeddings_config = resolve_model_client_config(embeddings)
|
|
79
80
|
embeddings_config, embeddings_extra_parameters = cls.extract_attributes(
|
|
80
81
|
embeddings_config
|
|
@@ -27,22 +27,32 @@ from rasa.shared.utils.common import conditional_import
|
|
|
27
27
|
|
|
28
28
|
# components dependent on tensorflow
|
|
29
29
|
TEDPolicy, TED_POLICY_AVAILABLE = conditional_import(
|
|
30
|
-
"rasa.core.policies.ted_policy", "TEDPolicy"
|
|
30
|
+
"rasa.core.policies.ted_policy", "TEDPolicy", check_installation_setup=True
|
|
31
31
|
)
|
|
32
32
|
UnexpecTEDIntentPolicy, UNEXPECTED_INTENT_POLICY_AVAILABLE = conditional_import(
|
|
33
|
-
"rasa.core.policies.unexpected_intent_policy",
|
|
33
|
+
"rasa.core.policies.unexpected_intent_policy",
|
|
34
|
+
"UnexpecTEDIntentPolicy",
|
|
35
|
+
check_installation_setup=True,
|
|
34
36
|
)
|
|
35
37
|
DIETClassifier, DIET_CLASSIFIER_AVAILABLE = conditional_import(
|
|
36
|
-
"rasa.nlu.classifiers.diet_classifier",
|
|
38
|
+
"rasa.nlu.classifiers.diet_classifier",
|
|
39
|
+
"DIETClassifier",
|
|
40
|
+
check_installation_setup=True,
|
|
37
41
|
)
|
|
38
42
|
ConveRTFeaturizer, CONVERT_FEATURIZER_AVAILABLE = conditional_import(
|
|
39
|
-
"rasa.nlu.featurizers.dense_featurizer.convert_featurizer",
|
|
43
|
+
"rasa.nlu.featurizers.dense_featurizer.convert_featurizer",
|
|
44
|
+
"ConveRTFeaturizer",
|
|
45
|
+
check_installation_setup=True,
|
|
40
46
|
)
|
|
41
47
|
LanguageModelFeaturizer, LANGUAGE_MODEL_FEATURIZER_AVAILABLE = conditional_import(
|
|
42
|
-
"rasa.nlu.featurizers.dense_featurizer.lm_featurizer",
|
|
48
|
+
"rasa.nlu.featurizers.dense_featurizer.lm_featurizer",
|
|
49
|
+
"LanguageModelFeaturizer",
|
|
50
|
+
check_installation_setup=True,
|
|
43
51
|
)
|
|
44
52
|
ResponseSelector, RESPONSE_SELECTOR_AVAILABLE = conditional_import(
|
|
45
|
-
"rasa.nlu.selectors.response_selector",
|
|
53
|
+
"rasa.nlu.selectors.response_selector",
|
|
54
|
+
"ResponseSelector",
|
|
55
|
+
check_installation_setup=True,
|
|
46
56
|
)
|
|
47
57
|
|
|
48
58
|
# components dependent on skops
|
|
@@ -40,16 +40,22 @@ from rasa.shared.utils.common import conditional_import
|
|
|
40
40
|
|
|
41
41
|
# Conditional imports for TensorFlow-dependent components
|
|
42
42
|
TEDPolicy, TED_POLICY_AVAILABLE = conditional_import(
|
|
43
|
-
"rasa.core.policies.ted_policy", "TEDPolicy"
|
|
43
|
+
"rasa.core.policies.ted_policy", "TEDPolicy", check_installation_setup=True
|
|
44
44
|
)
|
|
45
45
|
UnexpecTEDIntentPolicy, UNEXPECTED_INTENT_POLICY_AVAILABLE = conditional_import(
|
|
46
|
-
"rasa.core.policies.unexpected_intent_policy",
|
|
46
|
+
"rasa.core.policies.unexpected_intent_policy",
|
|
47
|
+
"UnexpecTEDIntentPolicy",
|
|
48
|
+
check_installation_setup=True,
|
|
47
49
|
)
|
|
48
50
|
DIETClassifier, DIET_CLASSIFIER_AVAILABLE = conditional_import(
|
|
49
|
-
"rasa.nlu.classifiers.diet_classifier",
|
|
51
|
+
"rasa.nlu.classifiers.diet_classifier",
|
|
52
|
+
"DIETClassifier",
|
|
53
|
+
check_installation_setup=True,
|
|
50
54
|
)
|
|
51
55
|
ResponseSelector, RESPONSE_SELECTOR_AVAILABLE = conditional_import(
|
|
52
|
-
"rasa.nlu.selectors.response_selector",
|
|
56
|
+
"rasa.nlu.selectors.response_selector",
|
|
57
|
+
"ResponseSelector",
|
|
58
|
+
check_installation_setup=True,
|
|
53
59
|
)
|
|
54
60
|
|
|
55
61
|
# Conditional imports for nlu components requiring other dependencies than tensorflow
|
|
@@ -9,9 +9,11 @@ from typing import Any, Dict, List, Optional, Text, Tuple, Type, TypeVar, Union
|
|
|
9
9
|
import numpy as np
|
|
10
10
|
import scipy.sparse
|
|
11
11
|
|
|
12
|
+
from rasa.utils.installation_utils import check_for_installation_issues
|
|
12
13
|
from rasa.utils.tensorflow import TENSORFLOW_AVAILABLE
|
|
13
14
|
|
|
14
15
|
if TENSORFLOW_AVAILABLE:
|
|
16
|
+
check_for_installation_issues()
|
|
15
17
|
import tensorflow as tf
|
|
16
18
|
else:
|
|
17
19
|
tf = None
|
rasa/shared/core/slots.py
CHANGED
|
@@ -355,8 +355,8 @@ class FloatSlot(Slot):
|
|
|
355
355
|
mappings: List[Dict[Text, Any]],
|
|
356
356
|
initial_value: Optional[float] = None,
|
|
357
357
|
value_reset_delay: Optional[int] = None,
|
|
358
|
-
max_value: float =
|
|
359
|
-
min_value: float =
|
|
358
|
+
max_value: Optional[float] = None,
|
|
359
|
+
min_value: Optional[float] = None,
|
|
360
360
|
influence_conversation: bool = True,
|
|
361
361
|
is_builtin: bool = False,
|
|
362
362
|
shared_for_coexistence: bool = False,
|
|
@@ -380,32 +380,24 @@ class FloatSlot(Slot):
|
|
|
380
380
|
filled_by=filled_by,
|
|
381
381
|
validation=validation,
|
|
382
382
|
)
|
|
383
|
+
self.validate_min_max_range(min_value, max_value)
|
|
384
|
+
|
|
383
385
|
self.max_value = max_value
|
|
384
386
|
self.min_value = min_value
|
|
385
387
|
|
|
386
|
-
if min_value >= max_value:
|
|
387
|
-
raise InvalidSlotConfigError(
|
|
388
|
-
"Float slot ('{}') created with an invalid range "
|
|
389
|
-
"using min ({}) and max ({}) values. Make sure "
|
|
390
|
-
"min is smaller than max."
|
|
391
|
-
"".format(self.name, self.min_value, self.max_value)
|
|
392
|
-
)
|
|
393
|
-
|
|
394
|
-
if initial_value is not None and not (min_value <= initial_value <= max_value):
|
|
395
|
-
rasa.shared.utils.io.raise_warning(
|
|
396
|
-
f"Float slot ('{self.name}') created with an initial value "
|
|
397
|
-
f"{self.value}. This value is outside of the configured min "
|
|
398
|
-
f"({self.min_value}) and max ({self.max_value}) values."
|
|
399
|
-
)
|
|
400
|
-
|
|
401
388
|
def _as_feature(self) -> List[float]:
|
|
389
|
+
# set default min and max values used in prior releases
|
|
390
|
+
# to prevent regressions for existing models
|
|
391
|
+
min_value = self.min_value or 0.0
|
|
392
|
+
max_value = self.max_value or 1.0
|
|
393
|
+
|
|
402
394
|
try:
|
|
403
|
-
capped_value = max(
|
|
404
|
-
if abs(
|
|
405
|
-
covered_range = abs(
|
|
395
|
+
capped_value = max(min_value, min(max_value, float(self.value)))
|
|
396
|
+
if abs(max_value - min_value) > 0:
|
|
397
|
+
covered_range = abs(max_value - min_value)
|
|
406
398
|
else:
|
|
407
399
|
covered_range = 1
|
|
408
|
-
return [1.0, (capped_value -
|
|
400
|
+
return [1.0, (capped_value - min_value) / covered_range]
|
|
409
401
|
except (TypeError, ValueError):
|
|
410
402
|
return [0.0, 0.0]
|
|
411
403
|
|
|
@@ -424,13 +416,52 @@ class FloatSlot(Slot):
|
|
|
424
416
|
return value
|
|
425
417
|
|
|
426
418
|
def is_valid_value(self, value: Any) -> bool:
|
|
427
|
-
"""Checks if the slot
|
|
428
|
-
|
|
429
|
-
|
|
419
|
+
"""Checks if the slot value is valid."""
|
|
420
|
+
if value is None:
|
|
421
|
+
return True
|
|
422
|
+
|
|
423
|
+
if not isinstance(self.coerce_value(value), float):
|
|
424
|
+
return False
|
|
425
|
+
|
|
426
|
+
if (
|
|
427
|
+
self.min_value is not None
|
|
428
|
+
and self.max_value is not None
|
|
429
|
+
and not (self.min_value <= value <= self.max_value)
|
|
430
|
+
):
|
|
431
|
+
return False
|
|
432
|
+
|
|
433
|
+
return True
|
|
430
434
|
|
|
431
435
|
def _feature_dimensionality(self) -> int:
|
|
432
436
|
return len(self.as_feature())
|
|
433
437
|
|
|
438
|
+
def validate_min_max_range(
|
|
439
|
+
self, min_value: Optional[float], max_value: Optional[float]
|
|
440
|
+
) -> None:
|
|
441
|
+
"""Validates the min-max range for the slot.
|
|
442
|
+
|
|
443
|
+
Raises:
|
|
444
|
+
InvalidSlotConfigError, if the min-max range is invalid.
|
|
445
|
+
"""
|
|
446
|
+
if min_value is not None and max_value is not None and min_value >= max_value:
|
|
447
|
+
raise InvalidSlotConfigError(
|
|
448
|
+
f"Float slot ('{self.name}') created with an invalid range "
|
|
449
|
+
f"using min ({min_value}) and max ({max_value}) values. Make sure "
|
|
450
|
+
f"min is smaller than max."
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
if (
|
|
454
|
+
self.initial_value is not None
|
|
455
|
+
and min_value is not None
|
|
456
|
+
and max_value is not None
|
|
457
|
+
and not (min_value <= self.initial_value <= max_value)
|
|
458
|
+
):
|
|
459
|
+
raise InvalidSlotConfigError(
|
|
460
|
+
f"Float slot ('{self.name}') created with an initial value "
|
|
461
|
+
f"{self.initial_value}. This value is outside of the configured min "
|
|
462
|
+
f"({min_value}) and max ({max_value}) values."
|
|
463
|
+
)
|
|
464
|
+
|
|
434
465
|
|
|
435
466
|
class BooleanSlot(Slot):
|
|
436
467
|
"""A slot storing a truth value."""
|
rasa/shared/utils/common.py
CHANGED
|
@@ -26,6 +26,7 @@ from rasa.exceptions import MissingDependencyException
|
|
|
26
26
|
from rasa.shared.constants import DOCS_URL_MIGRATION_GUIDE
|
|
27
27
|
from rasa.shared.exceptions import ProviderClientValidationError, RasaException
|
|
28
28
|
from rasa.shared.utils.cli import print_success
|
|
29
|
+
from rasa.utils.installation_utils import check_for_installation_issues
|
|
29
30
|
|
|
30
31
|
logger = logging.getLogger(__name__)
|
|
31
32
|
|
|
@@ -396,7 +397,11 @@ Sign up at: https://feedback.rasa.com
|
|
|
396
397
|
print_success(message)
|
|
397
398
|
|
|
398
399
|
|
|
399
|
-
def conditional_import(
|
|
400
|
+
def conditional_import(
|
|
401
|
+
module_name: str,
|
|
402
|
+
class_name: str,
|
|
403
|
+
check_installation_setup: bool = False,
|
|
404
|
+
) -> Tuple[Any, bool]:
|
|
400
405
|
"""Conditionally import a class, returning (class, is_available) tuple.
|
|
401
406
|
|
|
402
407
|
Args:
|
|
@@ -408,6 +413,9 @@ def conditional_import(module_name: str, class_name: str) -> Tuple[Any, bool]:
|
|
|
408
413
|
or None if import failed, and is_available is a boolean indicating
|
|
409
414
|
whether the import was successful.
|
|
410
415
|
"""
|
|
416
|
+
if check_installation_setup:
|
|
417
|
+
check_for_installation_issues()
|
|
418
|
+
|
|
411
419
|
try:
|
|
412
420
|
module = __import__(module_name, fromlist=[class_name])
|
|
413
421
|
return getattr(module, class_name), True
|
rasa/utils/common.py
CHANGED
|
@@ -36,6 +36,7 @@ from rasa.constants import (
|
|
|
36
36
|
ENV_LOG_LEVEL_LIBRARIES,
|
|
37
37
|
ENV_LOG_LEVEL_MATPLOTLIB,
|
|
38
38
|
ENV_LOG_LEVEL_MCP,
|
|
39
|
+
ENV_LOG_LEVEL_PYMONGO,
|
|
39
40
|
ENV_LOG_LEVEL_RABBITMQ,
|
|
40
41
|
ENV_MCP_LOGGING_ENABLED,
|
|
41
42
|
)
|
|
@@ -297,6 +298,7 @@ def configure_library_logging() -> None:
|
|
|
297
298
|
update_rabbitmq_log_level(library_log_level)
|
|
298
299
|
update_websockets_log_level(library_log_level)
|
|
299
300
|
update_mcp_log_level()
|
|
301
|
+
update_pymongo_log_level(library_log_level)
|
|
300
302
|
|
|
301
303
|
|
|
302
304
|
def update_apscheduler_log_level() -> None:
|
|
@@ -481,6 +483,13 @@ def update_mcp_log_level() -> None:
|
|
|
481
483
|
logging.getLogger(logger_name).propagate = False
|
|
482
484
|
|
|
483
485
|
|
|
486
|
+
def update_pymongo_log_level(library_log_level: str) -> None:
|
|
487
|
+
"""Set the log level of pymongo."""
|
|
488
|
+
log_level = os.environ.get(ENV_LOG_LEVEL_PYMONGO, library_log_level)
|
|
489
|
+
logging.getLogger("pymongo").setLevel(log_level)
|
|
490
|
+
logging.getLogger("pymongo").propagate = False
|
|
491
|
+
|
|
492
|
+
|
|
484
493
|
def sort_list_of_dicts_by_first_key(dicts: List[Dict]) -> List[Dict]:
|
|
485
494
|
"""Sorts a list of dictionaries by their first key."""
|
|
486
495
|
return sorted(dicts, key=lambda d: next(iter(d.keys())))
|
rasa/utils/endpoints.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import ssl
|
|
3
|
+
from functools import lru_cache
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
from types import ModuleType
|
|
5
6
|
from typing import Any, Dict, List, Optional, Text, Union
|
|
@@ -16,6 +17,7 @@ from rasa.shared.utils.yaml import read_config_file
|
|
|
16
17
|
structlogger = structlog.get_logger()
|
|
17
18
|
|
|
18
19
|
|
|
20
|
+
@lru_cache(maxsize=10)
|
|
19
21
|
def read_endpoint_config(
|
|
20
22
|
filename: Union[str, Path], endpoint_type: Text
|
|
21
23
|
) -> Optional["EndpointConfig"]:
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import importlib.util
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
import structlog
|
|
5
|
+
|
|
6
|
+
structlogger = structlog.get_logger()
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def check_tensorflow_installation() -> None:
|
|
10
|
+
"""Check if TensorFlow is installed without proper Rasa extras."""
|
|
11
|
+
# Check if tensorflow is available in the environment
|
|
12
|
+
tensorflow_available = importlib.util.find_spec("tensorflow") is not None
|
|
13
|
+
|
|
14
|
+
if not tensorflow_available:
|
|
15
|
+
return
|
|
16
|
+
|
|
17
|
+
# Check if any TensorFlow-related extras were installed
|
|
18
|
+
# We do this by checking for packages that are only installed with nlu/full extras
|
|
19
|
+
tensorflow_extras_indicators = [
|
|
20
|
+
"tensorflow_text", # Only in nlu/full extras
|
|
21
|
+
"tensorflow_hub", # Only in nlu/full extras
|
|
22
|
+
"tf_keras", # Only in nlu/full extras
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
extras_installed = any(
|
|
26
|
+
importlib.util.find_spec(pkg) is not None
|
|
27
|
+
for pkg in tensorflow_extras_indicators
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
if tensorflow_available and not extras_installed:
|
|
31
|
+
structlogger.warning(
|
|
32
|
+
"installation_utils.tensorflow_installation",
|
|
33
|
+
warning=(
|
|
34
|
+
"TensorFlow is installed but Rasa was not installed with TensorFlow "
|
|
35
|
+
"support, i.e. additional packages required to use NLU components "
|
|
36
|
+
"have not been installed. For the most reliable setup, delete your "
|
|
37
|
+
"current virtual environment, create a new one, and install Rasa "
|
|
38
|
+
"again. Please follow the instructions at "
|
|
39
|
+
"https://rasa.com/docs/pro/installation/python"
|
|
40
|
+
),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def check_tensorflow_integrity() -> None:
|
|
45
|
+
"""Check if TensorFlow installation is corrupted or incomplete."""
|
|
46
|
+
# Only check if tensorflow is available
|
|
47
|
+
if importlib.util.find_spec("tensorflow") is None:
|
|
48
|
+
return
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
# Try to import tensorflow - this will fail if installation is corrupted
|
|
52
|
+
import tensorflow as tf
|
|
53
|
+
|
|
54
|
+
# Try to access a basic TensorFlow function
|
|
55
|
+
_ = tf.constant([1, 2, 3])
|
|
56
|
+
except Exception:
|
|
57
|
+
# Simplified error message for all TensorFlow corruption issues
|
|
58
|
+
structlogger.error(
|
|
59
|
+
"installation_utils.tensorflow_integrity",
|
|
60
|
+
issue=(
|
|
61
|
+
"TensorFlow is installed but appears to be corrupted or incomplete. "
|
|
62
|
+
"For the most reliable setup, delete your current virtual "
|
|
63
|
+
"environment, create a new one, and install Rasa again. "
|
|
64
|
+
"Please follow the instructions at "
|
|
65
|
+
"https://rasa.com/docs/pro/installation/python"
|
|
66
|
+
),
|
|
67
|
+
)
|
|
68
|
+
sys.exit(1)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def check_rasa_availability() -> None:
|
|
72
|
+
"""Check if Rasa is installed and importable."""
|
|
73
|
+
if importlib.util.find_spec("rasa") is None:
|
|
74
|
+
structlogger.error(
|
|
75
|
+
"installation_utils.rasa_availability",
|
|
76
|
+
issue=(
|
|
77
|
+
"Rasa is not installed in this environment. "
|
|
78
|
+
"Please follow the instructions at "
|
|
79
|
+
"https://rasa.com/docs/pro/installation/python"
|
|
80
|
+
),
|
|
81
|
+
)
|
|
82
|
+
sys.exit(1)
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
_ = importlib.import_module("rasa")
|
|
86
|
+
except Exception as e:
|
|
87
|
+
structlogger.error(
|
|
88
|
+
"installation_utils.rasa_availability",
|
|
89
|
+
issue=(
|
|
90
|
+
f"Rasa is installed but cannot be imported: {e!s}."
|
|
91
|
+
f"Please follow the instructions at "
|
|
92
|
+
f"https://rasa.com/docs/pro/installation/python"
|
|
93
|
+
),
|
|
94
|
+
)
|
|
95
|
+
sys.exit(1)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def check_for_installation_issues() -> None:
|
|
99
|
+
"""Check for all potential installation issues.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
List of warning messages for detected issues.
|
|
103
|
+
"""
|
|
104
|
+
# Check if Rasa is available first
|
|
105
|
+
check_rasa_availability()
|
|
106
|
+
|
|
107
|
+
# Check TensorFlow integrity first (more critical)
|
|
108
|
+
check_tensorflow_integrity()
|
|
109
|
+
|
|
110
|
+
# Check for orphaned TensorFlow
|
|
111
|
+
check_tensorflow_installation()
|
|
@@ -2,9 +2,11 @@ import logging
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from typing import Any, Dict, Optional, Text
|
|
4
4
|
|
|
5
|
+
from rasa.utils.installation_utils import check_for_installation_issues
|
|
5
6
|
from rasa.utils.tensorflow import TENSORFLOW_AVAILABLE
|
|
6
7
|
|
|
7
8
|
if TENSORFLOW_AVAILABLE:
|
|
9
|
+
check_for_installation_issues()
|
|
8
10
|
import tensorflow as tf
|
|
9
11
|
from tqdm import tqdm
|
|
10
12
|
else:
|
rasa/utils/train_utils.py
CHANGED
|
@@ -11,10 +11,12 @@ from rasa.nlu.constants import NUMBER_OF_SUB_TOKENS
|
|
|
11
11
|
from rasa.shared.constants import NEXT_MAJOR_VERSION_FOR_DEPRECATIONS
|
|
12
12
|
from rasa.shared.exceptions import InvalidConfigException
|
|
13
13
|
from rasa.shared.nlu.constants import SPLIT_ENTITIES_BY_COMMA
|
|
14
|
+
from rasa.utils.installation_utils import check_for_installation_issues
|
|
14
15
|
from rasa.utils.tensorflow import TENSORFLOW_AVAILABLE
|
|
15
16
|
|
|
16
17
|
# Conditional imports for TensorFlow-dependent modules
|
|
17
18
|
if TENSORFLOW_AVAILABLE:
|
|
19
|
+
check_for_installation_issues()
|
|
18
20
|
from rasa.utils.tensorflow.callback import RasaModelCheckpoint, RasaTrainingLogger
|
|
19
21
|
from rasa.utils.tensorflow.constants import (
|
|
20
22
|
AUTO,
|
rasa/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: rasa-pro
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.15.0.dev20251027
|
|
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
|
|
@@ -21,6 +21,7 @@ Provides-Extra: full
|
|
|
21
21
|
Provides-Extra: gh-release-notes
|
|
22
22
|
Provides-Extra: jieba
|
|
23
23
|
Provides-Extra: metal
|
|
24
|
+
Provides-Extra: monitoring
|
|
24
25
|
Provides-Extra: nlu
|
|
25
26
|
Provides-Extra: pii
|
|
26
27
|
Provides-Extra: spacy
|
|
@@ -72,6 +73,7 @@ Requires-Dist: keras (>=3.11.0)
|
|
|
72
73
|
Requires-Dist: langchain (>=0.3.27,<0.4.0)
|
|
73
74
|
Requires-Dist: langchain-community (>=0.3.29,<0.4.0)
|
|
74
75
|
Requires-Dist: langcodes (>=3.5.0,<4.0.0)
|
|
76
|
+
Requires-Dist: langfuse (>=3.6.0,<3.7.0) ; extra == "full" or extra == "monitoring"
|
|
75
77
|
Requires-Dist: litellm (>=1.69.0,<1.70.0)
|
|
76
78
|
Requires-Dist: matplotlib (>=3.9.4,<3.10.0)
|
|
77
79
|
Requires-Dist: mattermostwrapper (>=2.2,<2.3) ; extra == "full" or extra == "channels"
|
|
@@ -108,7 +110,7 @@ Requires-Dist: pyyaml (>=6.0.2,<6.1.0)
|
|
|
108
110
|
Requires-Dist: qdrant-client (>=1.9.1,<1.10.0)
|
|
109
111
|
Requires-Dist: questionary (>=2.1.1,<2.2.0)
|
|
110
112
|
Requires-Dist: randomname (>=0.2.1,<0.3.0)
|
|
111
|
-
Requires-Dist: rasa-sdk (==3.
|
|
113
|
+
Requires-Dist: rasa-sdk (==3.15.0.dev1)
|
|
112
114
|
Requires-Dist: redis (>=4.6.0,<6.0)
|
|
113
115
|
Requires-Dist: regex (>=2024.7.24,<2024.8.0)
|
|
114
116
|
Requires-Dist: requests (>=2.32.5,<2.33.0)
|