rasa-pro 3.10.7.dev5__py3-none-any.whl → 3.10.9__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.

Files changed (79) hide show
  1. README.md +37 -1
  2. rasa/api.py +2 -8
  3. rasa/cli/arguments/default_arguments.py +2 -23
  4. rasa/cli/arguments/run.py +0 -2
  5. rasa/cli/e2e_test.py +8 -10
  6. rasa/cli/inspect.py +2 -5
  7. rasa/cli/run.py +0 -7
  8. rasa/cli/studio/studio.py +21 -1
  9. rasa/cli/train.py +4 -9
  10. rasa/cli/utils.py +3 -3
  11. rasa/core/agent.py +2 -2
  12. rasa/core/brokers/kafka.py +1 -3
  13. rasa/core/brokers/pika.py +1 -3
  14. rasa/core/channels/socketio.py +1 -5
  15. rasa/core/channels/voice_aware/utils.py +5 -6
  16. rasa/core/nlg/contextual_response_rephraser.py +2 -11
  17. rasa/core/policies/enterprise_search_policy.py +2 -11
  18. rasa/core/policies/intentless_policy.py +2 -9
  19. rasa/core/processor.py +57 -8
  20. rasa/core/run.py +1 -2
  21. rasa/core/secrets_manager/constants.py +0 -4
  22. rasa/core/secrets_manager/factory.py +0 -8
  23. rasa/core/secrets_manager/vault.py +1 -11
  24. rasa/core/utils.py +19 -30
  25. rasa/dialogue_understanding/coexistence/llm_based_router.py +2 -9
  26. rasa/dialogue_understanding/commands/__init__.py +2 -0
  27. rasa/dialogue_understanding/commands/restart_command.py +58 -0
  28. rasa/dialogue_understanding/commands/set_slot_command.py +5 -1
  29. rasa/dialogue_understanding/commands/utils.py +3 -1
  30. rasa/dialogue_understanding/generator/llm_based_command_generator.py +2 -11
  31. rasa/dialogue_understanding/generator/llm_command_generator.py +1 -1
  32. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +15 -15
  33. rasa/dialogue_understanding/patterns/restart.py +37 -0
  34. rasa/e2e_test/e2e_test_runner.py +1 -1
  35. rasa/e2e_test/utils/io.py +3 -1
  36. rasa/engine/graph.py +1 -0
  37. rasa/engine/recipes/config_files/default_config.yml +3 -0
  38. rasa/engine/recipes/default_recipe.py +1 -0
  39. rasa/engine/recipes/graph_recipe.py +1 -0
  40. rasa/engine/storage/local_model_storage.py +1 -0
  41. rasa/engine/storage/storage.py +5 -1
  42. rasa/model_training.py +6 -11
  43. rasa/{core → nlu}/persistor.py +1 -1
  44. rasa/server.py +1 -1
  45. rasa/shared/constants.py +3 -2
  46. rasa/shared/core/domain.py +47 -101
  47. rasa/shared/core/flows/flows_list.py +6 -19
  48. rasa/shared/core/flows/validation.py +0 -25
  49. rasa/shared/core/flows/yaml_flows_io.py +24 -3
  50. rasa/shared/importers/importer.py +32 -32
  51. rasa/shared/importers/multi_project.py +11 -23
  52. rasa/shared/importers/rasa.py +2 -7
  53. rasa/shared/importers/remote_importer.py +2 -2
  54. rasa/shared/importers/utils.py +1 -3
  55. rasa/shared/nlu/training_data/training_data.py +19 -18
  56. rasa/shared/providers/_configs/azure_openai_client_config.py +5 -3
  57. rasa/shared/providers/llm/_base_litellm_client.py +26 -10
  58. rasa/shared/providers/llm/self_hosted_llm_client.py +15 -3
  59. rasa/shared/utils/common.py +22 -3
  60. rasa/shared/utils/llm.py +5 -29
  61. rasa/shared/utils/schemas/model_config.yml +10 -0
  62. rasa/studio/auth.py +4 -0
  63. rasa/tracing/instrumentation/attribute_extractors.py +1 -1
  64. rasa/validator.py +5 -2
  65. rasa/version.py +1 -1
  66. {rasa_pro-3.10.7.dev5.dist-info → rasa_pro-3.10.9.dist-info}/METADATA +43 -7
  67. {rasa_pro-3.10.7.dev5.dist-info → rasa_pro-3.10.9.dist-info}/RECORD +70 -77
  68. rasa/keys +0 -1
  69. rasa/model_manager/__init__.py +0 -0
  70. rasa/model_manager/config.py +0 -12
  71. rasa/model_manager/model_api.py +0 -467
  72. rasa/model_manager/runner_service.py +0 -185
  73. rasa/model_manager/socket_bridge.py +0 -44
  74. rasa/model_manager/trainer_service.py +0 -240
  75. rasa/model_manager/utils.py +0 -27
  76. rasa/model_service.py +0 -66
  77. {rasa_pro-3.10.7.dev5.dist-info → rasa_pro-3.10.9.dist-info}/NOTICE +0 -0
  78. {rasa_pro-3.10.7.dev5.dist-info → rasa_pro-3.10.9.dist-info}/WHEEL +0 -0
  79. {rasa_pro-3.10.7.dev5.dist-info → rasa_pro-3.10.9.dist-info}/entry_points.txt +0 -0
README.md CHANGED
@@ -236,6 +236,39 @@ To check the types execute
236
236
  make types
237
237
  ```
238
238
 
239
+ ### Backporting
240
+
241
+ In order to port changes to `main` and across release branches, we use the `backport` workflow located at
242
+ the `.github/workflows/backport.yml` path.
243
+ This workflow is triggered by the `backport-to-<release-branch>` label applied to a PR, for example `backport-to-3.8.x`.
244
+ Current available target branches are `main` and maintained release branches.
245
+
246
+ When a PR gets labelled `backport-to-<release-branch>`, a PR is opened by the `backport-github-action` as soon as the
247
+ source PR gets closed (by merging). If you want to close the PR without merging changes, make sure to remove the `backport-to-<release-branch>` label.
248
+
249
+ The PR author which the action assigns to the backporting PR has to resolve any conflicts before approving and merging.
250
+ Release PRs should also be labelled with `backport-to-main` to backport the `CHANGELOG.md` updates to `main`.
251
+ Backporting version updates should be accepted to the `main` branch from the latest release branch only.
252
+
253
+ Here are some guidelines to follow when backporting changes and resolving conflicts:
254
+
255
+ a) for conflicts in `version.py`: accept only the version from the latest release branch. Do not merge version changes
256
+ from earlier release branches into `main` because this could cause issues when trying to make the next minor release.
257
+
258
+ b) for conflicts in `pyproject.toml`: if related to the `rasa-pro` version, accept only the latest release branch;
259
+ if related to other dependencies, accept `main` or whichever is the higher upgrade (main usually has the updated
260
+ dependencies because we only do housekeeping on `main`, apart from vulnerability updates). Be mindful of dependencies that
261
+ are removed from `main` but still exist in former release branches (for example `langchain`).
262
+
263
+ c) for conflicts in `poetry.lock`: accept changes which were already present on the target branch, then run
264
+ `poetry lock --no-update` so that the lock file contains your changes from `pyproject.toml` too.
265
+
266
+ d) for conflicts in `CHANGELOG.md`: Manually place the changelog in their allocated section (e.g. 3.8.10 will go under the
267
+ 3.8 section with the other releases, rather than go at the top of the file)
268
+
269
+ If the backporting workflow fails, you are encouraged to cherry-pick the commits manually and create a PR to
270
+ the target branch. Alternatively, you can install the backporting CLI tool as described [here](https://github.com/sorenlouv/backport?tab=readme-ov-file#install).
271
+
239
272
  ## Releases
240
273
  Rasa has implemented robust policies governing version naming, as well as release pace for major, minor, and patch releases.
241
274
 
@@ -318,9 +351,12 @@ Releasing a new version is quite simple, as the packages are build and distribut
318
351
  9. If however an error occurs in the build, then we should see a failure message automatically posted in the company's Slack (`dev-tribe` channel) like this [one](https://rasa-hq.slack.com/archives/C01M5TAHDHA/p1701444735622919)
319
352
  (In this case do the following checks):
320
353
  - Check the workflows in [Github Actions](https://github.com/RasaHQ/rasa-private/actions) and make sure that the merged PR of the current release is completed successfully. To easily find your PR you can use the filters `event: push` and `branch: <version number>` (example on release 2.4 you can see [here](https://github.com/RasaHQ/rasa/actions/runs/643344876))
321
- - If the workflow is not completed, then try to re run the workflow in case that solves the problem
354
+ - If the workflow is not completed, then try to re-run the workflow in case that solves the problem
322
355
  - If the problem persists, check also the log files and try to find the root cause of the issue
323
356
  - If you still cannot resolve the error, contact the infrastructure team by providing any helpful information from your investigation
357
+ 10. If the release is successful, add the newly created release branch to the backporting configuration in the `.backportrc.json` file to
358
+ the `targetBranchesChoices` list. This is necessary for the backporting workflow to work correctly with new release branches.
359
+
324
360
 
325
361
  ### Cutting a Patch release
326
362
 
rasa/api.py CHANGED
@@ -2,7 +2,7 @@ import asyncio
2
2
  from typing import TYPE_CHECKING, Any, Dict, List, Optional, Text, Union
3
3
 
4
4
  import rasa.shared.constants
5
- from rasa.core.persistor import StorageType
5
+ from rasa.nlu.persistor import StorageType
6
6
 
7
7
  # WARNING: Be careful about adding any top level imports at this place!
8
8
  # These functions are imported in `rasa.__init__` and any top level import
@@ -14,7 +14,6 @@ from rasa.core.persistor import StorageType
14
14
 
15
15
  if TYPE_CHECKING:
16
16
  from rasa.model_training import TrainingResult
17
- from rasa.shared.importers.importer import TrainingDataImporter
18
17
 
19
18
 
20
19
  def run(
@@ -79,7 +78,6 @@ def train(
79
78
  model_to_finetune: Optional[Text] = None,
80
79
  finetuning_epoch_fraction: float = 1.0,
81
80
  remote_storage: Optional[StorageType] = None,
82
- file_importer: Optional["TrainingDataImporter"] = None,
83
81
  ) -> "TrainingResult":
84
82
  """Runs Rasa Core and NLU training in `async` loop.
85
83
 
@@ -101,10 +99,7 @@ def train(
101
99
  a directory in case the latest trained model should be used.
102
100
  finetuning_epoch_fraction: The fraction currently specified training epochs
103
101
  in the model configuration which should be used for finetuning.
104
- remote_storage: Optional name of the remote storage to
105
- use for storing the model.
106
- file_importer: Instance of `TrainingDataImporter` to use for training.
107
- If it is not provided, a new instance will be created.
102
+ remote_storage: Remote storage to use for model storage.
108
103
 
109
104
  Returns:
110
105
  An instance of `TrainingResult`.
@@ -126,7 +121,6 @@ def train(
126
121
  model_to_finetune=model_to_finetune,
127
122
  finetuning_epoch_fraction=finetuning_epoch_fraction,
128
123
  remote_storage=remote_storage,
129
- file_importer=file_importer,
130
124
  )
131
125
  )
132
126
 
@@ -1,9 +1,8 @@
1
1
  import argparse
2
2
  import logging
3
- from enum import Enum
4
- from typing import List, Optional, Text, Union
3
+ from typing import Optional, Text, Union
5
4
 
6
- from rasa.core.persistor import RemoteStorageType, StorageType, parse_remote_storage
5
+ from rasa.nlu.persistor import RemoteStorageType, StorageType, parse_remote_storage
7
6
  from rasa.shared.constants import (
8
7
  DEFAULT_CONFIG_PATH,
9
8
  DEFAULT_DATA_PATH,
@@ -186,23 +185,3 @@ def parse_remote_storage_arg(value: str) -> StorageType:
186
185
  return parse_remote_storage(value)
187
186
  except ValueError as e:
188
187
  raise argparse.ArgumentTypeError(str(e))
189
-
190
-
191
- class SkipYamlValidation(Enum):
192
- DOMAIN = "domain"
193
-
194
- @classmethod
195
- def list(cls) -> List[str]:
196
- return [e.value for e in SkipYamlValidation]
197
-
198
-
199
- def add_skip_validation_flag(
200
- parser: Union[argparse.ArgumentParser, argparse._ActionsContainer],
201
- ) -> None:
202
- parser.add_argument(
203
- "--skip-yaml-validation",
204
- default=[],
205
- choices=SkipYamlValidation.list(),
206
- action="append",
207
- help="Skip YAML validation for selected parts of the training data.",
208
- )
rasa/cli/arguments/run.py CHANGED
@@ -5,7 +5,6 @@ from typing import Union
5
5
  from rasa.cli.arguments.default_arguments import (
6
6
  add_endpoint_param,
7
7
  add_model_param,
8
- add_skip_validation_flag,
9
8
  add_remote_storage_param,
10
9
  )
11
10
  from rasa.core import constants
@@ -22,7 +21,6 @@ def set_run_arguments(parser: argparse.ArgumentParser) -> None:
22
21
  """Arguments for running Rasa directly using `rasa run`."""
23
22
  add_model_param(parser)
24
23
  add_server_arguments(parser)
25
- add_skip_validation_flag(parser)
26
24
 
27
25
 
28
26
  def set_run_action_arguments(parser: argparse.ArgumentParser) -> None:
rasa/cli/e2e_test.py CHANGED
@@ -221,17 +221,15 @@ def execute_e2e_tests(args: argparse.Namespace) -> None:
221
221
  if args.e2e_results is not None:
222
222
  results_path = Path(args.e2e_results)
223
223
 
224
- if passed:
225
- passed_file = rasa.cli.utils.get_e2e_results_file_name(
226
- results_path, STATUS_PASSED
227
- )
228
- write_test_results_to_file(passed, passed_file)
224
+ passed_file = rasa.cli.utils.get_e2e_results_file_name(
225
+ results_path, STATUS_PASSED
226
+ )
227
+ write_test_results_to_file(passed, passed_file)
229
228
 
230
- if failed:
231
- failed_file = rasa.cli.utils.get_e2e_results_file_name(
232
- results_path, STATUS_FAILED
233
- )
234
- write_test_results_to_file(failed, failed_file)
229
+ failed_file = rasa.cli.utils.get_e2e_results_file_name(
230
+ results_path, STATUS_FAILED
231
+ )
232
+ write_test_results_to_file(failed, failed_file)
235
233
 
236
234
  aggregate_stats_calculator = AggregateTestStatsCalculator(
237
235
  passed_results=passed, failed_results=failed, test_cases=test_suite.test_cases
rasa/cli/inspect.py CHANGED
@@ -3,12 +3,11 @@ import webbrowser
3
3
  from asyncio import AbstractEventLoop
4
4
  from typing import List, Text
5
5
 
6
- from sanic import Sanic
7
-
8
6
  from rasa.cli import SubParsersAction
9
7
  from rasa.cli.arguments import shell as arguments
10
- from rasa.cli.arguments.default_arguments import add_skip_validation_flag
11
8
  from rasa.core import constants
9
+ from sanic import Sanic
10
+
12
11
  from rasa.utils.cli import remove_argument_from_parser
13
12
 
14
13
 
@@ -34,8 +33,6 @@ def add_subparser(
34
33
  inspect_parser.set_defaults(func=inspect)
35
34
 
36
35
  arguments.set_shell_arguments(inspect_parser)
37
- add_skip_validation_flag(inspect_parser)
38
-
39
36
  # it'd be confusing to expose those arguments to the user,
40
37
  # so we remove them
41
38
  remove_argument_from_parser(inspect_parser, "--credentials")
rasa/cli/run.py CHANGED
@@ -6,7 +6,6 @@ from typing import List, Text
6
6
  from rasa.api import run as rasa_run
7
7
  from rasa.cli import SubParsersAction
8
8
  from rasa.cli.arguments import run as arguments
9
- from rasa.cli.arguments.default_arguments import SkipYamlValidation
10
9
  from rasa.cli.utils import get_validated_path
11
10
  from rasa.exceptions import ModelNotFound
12
11
  from rasa.shared.constants import (
@@ -16,7 +15,6 @@ from rasa.shared.constants import (
16
15
  DEFAULT_MODELS_PATH,
17
16
  DOCS_BASE_URL,
18
17
  )
19
- from rasa.shared.core.domain import Domain
20
18
  from rasa.shared.utils.cli import print_error
21
19
 
22
20
  logger = logging.getLogger(__name__)
@@ -89,11 +87,6 @@ def run(args: argparse.Namespace) -> None:
89
87
  args.credentials, "credentials", DEFAULT_CREDENTIALS_PATH, True
90
88
  )
91
89
 
92
- if SkipYamlValidation.DOMAIN.value in args.skip_yaml_validation:
93
- Domain.validate_yaml = False
94
- else:
95
- Domain.validate_yaml = True
96
-
97
90
  if args.enable_api:
98
91
  if not args.remote_storage:
99
92
  args.model = _validate_model_path(args.model, "model", DEFAULT_MODELS_PATH)
rasa/cli/studio/studio.py CHANGED
@@ -5,6 +5,7 @@ from urllib.parse import ParseResult, urlparse
5
5
  import questionary
6
6
  from rasa.cli import SubParsersAction
7
7
 
8
+ import rasa.shared.utils.cli
8
9
  import rasa.cli.studio.download
9
10
  import rasa.cli.studio.train
10
11
  import rasa.cli.studio.upload
@@ -50,6 +51,15 @@ def _add_config_subparser(
50
51
 
51
52
  studio_config_parser.set_defaults(func=create_and_store_studio_config)
52
53
 
54
+ studio_config_parser.add_argument(
55
+ "--disable-verify",
56
+ "-x",
57
+ action="store_true",
58
+ default=False,
59
+ help="Disable strict SSL verification for the "
60
+ "Rasa Studio authentication server.",
61
+ )
62
+
53
63
  # add advanced configuration flag to trigger
54
64
  # advanced configuration setup for authentication settings
55
65
  studio_config_parser.add_argument(
@@ -219,7 +229,17 @@ def _configure_studio_config(args: argparse.Namespace) -> StudioConfig:
219
229
  studio_config = _create_studio_config(
220
230
  studio_url, keycloak_url, realm_name, client_id
221
231
  )
222
- studio_auth = StudioAuth(studio_config)
232
+
233
+ if args.disable_verify:
234
+ rasa.shared.utils.cli.print_info(
235
+ "Disabling SSL verification for the Rasa Studio authentication server."
236
+ )
237
+ studio_auth = StudioAuth(studio_config, verify=False)
238
+ else:
239
+ rasa.shared.utils.cli.print_info(
240
+ "Enabling SSL verification for the Rasa Studio authentication server."
241
+ )
242
+ studio_auth = StudioAuth(studio_config, verify=True)
223
243
 
224
244
  if _check_studio_auth(studio_auth):
225
245
  return studio_config
rasa/cli/train.py CHANGED
@@ -110,20 +110,16 @@ def run_training(args: argparse.Namespace, can_exit: bool = False) -> Optional[T
110
110
  for f in args.data
111
111
  ]
112
112
 
113
- training_data_importer = TrainingDataImporter.load_from_config(
114
- domain_path=domain, training_data_paths=args.data, config_path=config
115
- )
116
-
117
113
  if not args.skip_validation:
118
114
  structlogger.info(
119
115
  "cli.train.run_training",
120
116
  event_info="Started validating domain and training data...",
121
117
  )
122
-
118
+ importer = TrainingDataImporter.load_from_config(
119
+ domain_path=domain, training_data_paths=args.data, config_path=config
120
+ )
123
121
  rasa.cli.utils.validate_files(
124
- args.fail_on_validation_warnings,
125
- args.validation_max_history,
126
- training_data_importer,
122
+ args.fail_on_validation_warnings, args.validation_max_history, importer
127
123
  )
128
124
 
129
125
  training_result = train_all(
@@ -142,7 +138,6 @@ def run_training(args: argparse.Namespace, can_exit: bool = False) -> Optional[T
142
138
  model_to_finetune=_model_for_finetuning(args),
143
139
  finetuning_epoch_fraction=args.epoch_fraction,
144
140
  remote_storage=args.remote_storage,
145
- file_importer=training_data_importer,
146
141
  )
147
142
  if training_result.code != 0 and can_exit:
148
143
  sys.exit(training_result.code)
rasa/cli/utils.py CHANGED
@@ -470,10 +470,10 @@ def get_e2e_results_file_name(
470
470
  ) -> str:
471
471
  """Returns the name of the e2e results file."""
472
472
  if results_output_path.is_dir():
473
- file_name = results_output_path / f"e2e_results_{result_type}.yml"
473
+ file_name = str(results_output_path) + f"/e2e_results_{result_type}.yml"
474
474
  else:
475
475
  parent = results_output_path.parent
476
476
  stem = results_output_path.stem
477
- file_name = parent / f"{stem}_{result_type}.yml"
477
+ file_name = str(parent) + f"/{stem}_{result_type}.yml"
478
478
 
479
- return str(file_name)
479
+ return file_name
rasa/core/agent.py CHANGED
@@ -19,7 +19,6 @@ from rasa.core.exceptions import AgentNotReady
19
19
  from rasa.core.http_interpreter import RasaNLUHttpInterpreter
20
20
  from rasa.core.lock_store import InMemoryLockStore, LockStore
21
21
  from rasa.core.nlg import NaturalLanguageGenerator, TemplatedNaturalLanguageGenerator
22
- from rasa.core.persistor import StorageType
23
22
  from rasa.core.policies.policy import PolicyPrediction
24
23
  from rasa.core.processor import MessageProcessor
25
24
  from rasa.core.tracker_store import (
@@ -29,6 +28,7 @@ from rasa.core.tracker_store import (
29
28
  )
30
29
  from rasa.core.utils import AvailableEndpoints
31
30
  from rasa.exceptions import ModelNotFound
31
+ from rasa.nlu.persistor import StorageType
32
32
  from rasa.nlu.utils import is_url
33
33
  from rasa.shared.constants import DEFAULT_SENDER_ID
34
34
  from rasa.shared.core.domain import Domain
@@ -544,7 +544,7 @@ class Agent:
544
544
 
545
545
  def load_model_from_remote_storage(self, model_name: Text) -> None:
546
546
  """Loads an Agent from remote storage."""
547
- from rasa.core.persistor import get_persistor
547
+ from rasa.nlu.persistor import get_persistor
548
548
 
549
549
  persistor = get_persistor(self.remote_storage)
550
550
 
@@ -2,8 +2,6 @@ import asyncio
2
2
  import os
3
3
  import json
4
4
  import logging
5
- from functools import cached_property
6
-
7
5
  import structlog
8
6
  import threading
9
7
  from asyncio import AbstractEventLoop
@@ -272,7 +270,7 @@ class KafkaEventBroker(EventBroker):
272
270
  if self.producer:
273
271
  self.producer.flush()
274
272
 
275
- @cached_property
273
+ @rasa.shared.utils.common.lazy_property
276
274
  def rasa_environment(self) -> Optional[Text]:
277
275
  """Get value of the `RASA_ENVIRONMENT` environment variable."""
278
276
  return os.environ.get("RASA_ENVIRONMENT", "RASA_ENVIRONMENT_NOT_SET")
rasa/core/brokers/pika.py CHANGED
@@ -1,8 +1,6 @@
1
1
  import asyncio
2
2
  import json
3
3
  import logging
4
- from functools import cached_property
5
-
6
4
  import structlog
7
5
  import os
8
6
  import ssl
@@ -335,7 +333,7 @@ class PikaEventBroker(EventBroker):
335
333
  delivery_mode=aio_pika.DeliveryMode.PERSISTENT,
336
334
  )
337
335
 
338
- @cached_property
336
+ @rasa.shared.utils.common.lazy_property
339
337
  def rasa_environment(self) -> Optional[Text]:
340
338
  """Get value of the `RASA_ENVIRONMENT` environment variable."""
341
339
  return os.environ.get("RASA_ENVIRONMENT")
@@ -37,11 +37,7 @@ class SocketBlueprint(Blueprint):
37
37
  :param options: Options to be used while registering the
38
38
  blueprint into the app.
39
39
  """
40
- if self.ctx.socketio_path:
41
- path = self.ctx.socketio_path
42
- else:
43
- path = options.get("url_prefix", "/socket.io")
44
- self.ctx.sio.attach(app, path)
40
+ self.ctx.sio.attach(app, self.ctx.socketio_path)
45
41
  super().register(app, options)
46
42
 
47
43
 
@@ -1,16 +1,15 @@
1
1
  import structlog
2
2
 
3
+ from rasa.utils.licensing import (
4
+ PRODUCT_AREA,
5
+ VOICE_SCOPE,
6
+ validate_license_from_env,
7
+ )
3
8
 
4
9
  structlogger = structlog.get_logger()
5
10
 
6
11
 
7
12
  def validate_voice_license_scope() -> None:
8
- from rasa.utils.licensing import (
9
- PRODUCT_AREA,
10
- VOICE_SCOPE,
11
- validate_license_from_env,
12
- )
13
-
14
13
  """Validate that the correct license scope is present."""
15
14
  structlogger.info(
16
15
  f"Validating current Rasa Pro license scope which must include "
@@ -1,13 +1,11 @@
1
1
  from typing import Any, Dict, Optional, Text
2
2
 
3
- import os
4
3
  import structlog
5
4
  from jinja2 import Template
6
5
 
7
6
  from rasa import telemetry
8
7
  from rasa.core.nlg.response import TemplatedNaturalLanguageGenerator
9
8
  from rasa.shared.constants import (
10
- LLM_API_HEALTH_CHECK_ENV_VAR,
11
9
  LLM_CONFIG_KEY,
12
10
  MODEL_CONFIG_KEY,
13
11
  MODEL_NAME_CONFIG_KEY,
@@ -25,7 +23,6 @@ from rasa.shared.utils.llm import (
25
23
  USER,
26
24
  combine_custom_and_default_config,
27
25
  get_prompt_template,
28
- llm_api_health_check,
29
26
  llm_factory,
30
27
  try_instantiate_llm_client,
31
28
  )
@@ -100,18 +97,12 @@ class ContextualResponseRephraser(TemplatedNaturalLanguageGenerator):
100
97
  self.trace_prompt_tokens = self.nlg_endpoint.kwargs.get(
101
98
  "trace_prompt_tokens", False
102
99
  )
103
- llm_client = try_instantiate_llm_client(
100
+ try_instantiate_llm_client(
104
101
  self.nlg_endpoint.kwargs.get(LLM_CONFIG_KEY),
105
102
  DEFAULT_LLM_CONFIG,
106
103
  "contextual_response_rephraser.init",
107
- ContextualResponseRephraser.__name__,
104
+ "ContextualResponseRephraser",
108
105
  )
109
- if os.getenv(LLM_API_HEALTH_CHECK_ENV_VAR, "true").lower() == "true":
110
- llm_api_health_check(
111
- llm_client,
112
- "contextual_response_rephraser.init",
113
- ContextualResponseRephraser.__name__,
114
- )
115
106
 
116
107
  def _last_message_if_human(self, tracker: DialogueStateTracker) -> Optional[str]:
117
108
  """Returns the latest message from the tracker.
@@ -1,6 +1,5 @@
1
1
  import importlib.resources
2
2
  import json
3
- import os
4
3
  import re
5
4
  from typing import TYPE_CHECKING, Any, Dict, List, Optional, Text
6
5
 
@@ -48,7 +47,6 @@ from rasa.graph_components.providers.forms_provider import Forms
48
47
  from rasa.graph_components.providers.responses_provider import Responses
49
48
  from rasa.shared.constants import (
50
49
  EMBEDDINGS_CONFIG_KEY,
51
- LLM_API_HEALTH_CHECK_ENV_VAR,
52
50
  LLM_CONFIG_KEY,
53
51
  MODEL_CONFIG_KEY,
54
52
  MODEL_NAME_CONFIG_KEY,
@@ -74,7 +72,6 @@ from rasa.shared.utils.llm import (
74
72
  DEFAULT_OPENAI_EMBEDDING_MODEL_NAME,
75
73
  embedder_factory,
76
74
  get_prompt_template,
77
- llm_api_health_check,
78
75
  llm_factory,
79
76
  sanitize_message_for_prompt,
80
77
  tracker_as_readable_transcript,
@@ -295,18 +292,12 @@ class EnterpriseSearchPolicy(Policy):
295
292
  )
296
293
 
297
294
  # validate llm configuration
298
- llm_client = try_instantiate_llm_client(
295
+ try_instantiate_llm_client(
299
296
  self.config.get(LLM_CONFIG_KEY),
300
297
  DEFAULT_LLM_CONFIG,
301
298
  "enterprise_search_policy.train",
302
- EnterpriseSearchPolicy.__name__,
299
+ "EnterpriseSearchPolicy",
303
300
  )
304
- if os.getenv(LLM_API_HEALTH_CHECK_ENV_VAR, "true").lower() == "true":
305
- llm_api_health_check(
306
- llm_client,
307
- "enterprise_search_policy.train",
308
- EnterpriseSearchPolicy.__name__,
309
- )
310
301
 
311
302
  if store_type == DEFAULT_VECTOR_STORE_TYPE:
312
303
  logger.info("enterprise_search_policy.train.faiss")
@@ -1,6 +1,5 @@
1
1
  import importlib.resources
2
2
  import math
3
- import os
4
3
  from dataclasses import dataclass, field
5
4
  from typing import Any, Dict, List, Optional, Set, TYPE_CHECKING, Text, Tuple
6
5
 
@@ -32,7 +31,6 @@ from rasa.graph_components.providers.responses_provider import Responses
32
31
  from rasa.shared.constants import (
33
32
  REQUIRED_SLOTS_KEY,
34
33
  EMBEDDINGS_CONFIG_KEY,
35
- LLM_API_HEALTH_CHECK_ENV_VAR,
36
34
  LLM_CONFIG_KEY,
37
35
  MODEL_CONFIG_KEY,
38
36
  MODEL_NAME_CONFIG_KEY,
@@ -69,7 +67,6 @@ from rasa.shared.utils.llm import (
69
67
  combine_custom_and_default_config,
70
68
  embedder_factory,
71
69
  get_prompt_template,
72
- llm_api_health_check,
73
70
  llm_factory,
74
71
  sanitize_message_for_prompt,
75
72
  tracker_as_readable_transcript,
@@ -490,16 +487,12 @@ class IntentlessPolicy(Policy):
490
487
  A policy must return its resource locator so that potential children nodes
491
488
  can load the policy from the resource.
492
489
  """
493
- llm_client = try_instantiate_llm_client(
490
+ try_instantiate_llm_client(
494
491
  self.config.get(LLM_CONFIG_KEY),
495
492
  DEFAULT_LLM_CONFIG,
496
493
  "intentless_policy.train",
497
- IntentlessPolicy.__name__,
494
+ "IntentlessPolicy",
498
495
  )
499
- if os.getenv(LLM_API_HEALTH_CHECK_ENV_VAR, "true").lower() == "true":
500
- llm_api_health_check(
501
- llm_client, "intentless_policy.train", IntentlessPolicy.__name__
502
- )
503
496
 
504
497
  responses = filter_responses(responses, forms, flows or FlowsList([]))
505
498
  telemetry.track_intentless_policy_train()
rasa/core/processor.py CHANGED
@@ -101,6 +101,9 @@ logger = logging.getLogger(__name__)
101
101
  structlogger = structlog.get_logger()
102
102
 
103
103
  MAX_NUMBER_OF_PREDICTIONS = int(os.environ.get("MAX_NUMBER_OF_PREDICTIONS", "10"))
104
+ MAX_NUMBER_OF_PREDICTIONS_CALM = int(
105
+ os.environ.get("MAX_NUMBER_OF_PREDICTIONS_CALM", "1000")
106
+ )
104
107
 
105
108
 
106
109
  class MessageProcessor:
@@ -114,6 +117,7 @@ class MessageProcessor:
114
117
  generator: NaturalLanguageGenerator,
115
118
  action_endpoint: Optional[EndpointConfig] = None,
116
119
  max_number_of_predictions: int = MAX_NUMBER_OF_PREDICTIONS,
120
+ max_number_of_predictions_calm: int = MAX_NUMBER_OF_PREDICTIONS_CALM,
117
121
  on_circuit_break: Optional[LambdaType] = None,
118
122
  http_interpreter: Optional[RasaNLUHttpInterpreter] = None,
119
123
  endpoints: Optional["AvailableEndpoints"] = None,
@@ -122,7 +126,6 @@ class MessageProcessor:
122
126
  self.nlg = generator
123
127
  self.tracker_store = tracker_store
124
128
  self.lock_store = lock_store
125
- self.max_number_of_predictions = max_number_of_predictions
126
129
  self.on_circuit_break = on_circuit_break
127
130
  self.action_endpoint = action_endpoint
128
131
  self.model_filename, self.model_metadata, self.graph_runner = self._load_model(
@@ -130,6 +133,10 @@ class MessageProcessor:
130
133
  )
131
134
  self.endpoints = endpoints
132
135
 
136
+ self.max_number_of_predictions = max_number_of_predictions
137
+ self.max_number_of_predictions_calm = max_number_of_predictions_calm
138
+ self.is_calm_assistant = self._is_calm_assistant()
139
+
133
140
  if self.model_metadata.assistant_id is None:
134
141
  rasa.shared.utils.io.raise_warning(
135
142
  f"The model metadata does not contain a value for the "
@@ -972,11 +979,15 @@ class MessageProcessor:
972
979
  ) -> int:
973
980
  """Select the action limit based on the tracker state.
974
981
 
975
- Usually, we want to limit the number of predictions to the number of actions
976
- that have been executed in the conversation so far. However, if the
977
- conversation is currently in a state where the user is correcting the flow
978
- we want to allow for more predictions to be made as we might be traversing
979
- through a long flow.
982
+ This function determines the maximum number of predictions that should be
983
+ made during a dialogue conversation. Typically, the number of predictions
984
+ is limited to the number of actions executed so far in the conversation.
985
+ However, in certain states (e.g., when the user is correcting the
986
+ conversation flow), more predictions may be allowed as the system traverses
987
+ through a long dialogue flow.
988
+
989
+ Additionally, if the `ROUTE_TO_CALM_SLOT` is present in the tracker slots,
990
+ the action limit is adjusted to a separate limit for CALM-based flows.
980
991
 
981
992
  Args:
982
993
  tracker: instance of DialogueStateTracker.
@@ -984,6 +995,18 @@ class MessageProcessor:
984
995
  Returns:
985
996
  The maximum number of predictions to make.
986
997
  """
998
+ # Check if it is a CALM assistant and if so, that the `ROUTE_TO_CALM_SLOT`
999
+ # is either not present or set to `True`.
1000
+ # If it does, use the specific prediction limit for CALM assistants.
1001
+ # Otherwise, use the default prediction limit.
1002
+ if self.is_calm_assistant and (
1003
+ not tracker.has_coexistence_routing_slot
1004
+ or tracker.get_slot(ROUTE_TO_CALM_SLOT)
1005
+ ):
1006
+ max_number_of_predictions = self.max_number_of_predictions_calm
1007
+ else:
1008
+ max_number_of_predictions = self.max_number_of_predictions
1009
+
987
1010
  reversed_events = list(tracker.events)[::-1]
988
1011
  is_conversation_in_flow_correction = False
989
1012
  for e in reversed_events:
@@ -998,8 +1021,10 @@ class MessageProcessor:
998
1021
  # allow for more predictions to be made as we might be traversing through
999
1022
  # a long flow. We multiply the number of predictions by 10 to allow for
1000
1023
  # more predictions to be made - the factor is a best guess.
1001
- return self.max_number_of_predictions * 5
1002
- return self.max_number_of_predictions
1024
+ return max_number_of_predictions * 5
1025
+
1026
+ # Return the default
1027
+ return max_number_of_predictions
1003
1028
 
1004
1029
  def is_action_limit_reached(
1005
1030
  self, tracker: DialogueStateTracker, should_predict_another_action: bool
@@ -1387,3 +1412,27 @@ class MessageProcessor:
1387
1412
  ]
1388
1413
 
1389
1414
  return len(filtered_commands) > 0
1415
+
1416
+ def _is_calm_assistant(self) -> bool:
1417
+ """Inspects the nodes of the graph schema to determine whether
1418
+ any node is associated with the `FlowPolicy`, which is indicative of a
1419
+ CALM assistant setup.
1420
+
1421
+ Returns:
1422
+ bool: True if any node in the graph schema uses `FlowPolicy`.
1423
+ """
1424
+ # Get the graph schema's nodes from the graph runner.
1425
+ nodes: dict[str, Any] = self.graph_runner._graph_schema.nodes # type: ignore[attr-defined]
1426
+
1427
+ flow_policy_class_path = "rasa.core.policies.flow_policy.FlowPolicy"
1428
+ # Iterate over the nodes and check if any node uses `FlowPolicy`.
1429
+ for node_name, schema_node in nodes.items():
1430
+ if (
1431
+ schema_node.uses is not None
1432
+ and f"{schema_node.uses.__module__}.{schema_node.uses.__name__}"
1433
+ == flow_policy_class_path
1434
+ ):
1435
+ return True
1436
+
1437
+ # Return False if no node is found using `FlowPolicy`.
1438
+ return False