rasa-pro 3.13.0.dev2__py3-none-any.whl → 3.13.0.dev3__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 (48) hide show
  1. rasa/cli/run.py +10 -6
  2. rasa/cli/utils.py +7 -0
  3. rasa/core/channels/channel.py +30 -0
  4. rasa/core/channels/voice_ready/jambonz.py +25 -5
  5. rasa/core/channels/voice_ready/jambonz_protocol.py +4 -0
  6. rasa/core/information_retrieval/faiss.py +7 -68
  7. rasa/core/information_retrieval/information_retrieval.py +2 -40
  8. rasa/core/information_retrieval/milvus.py +2 -7
  9. rasa/core/information_retrieval/qdrant.py +2 -7
  10. rasa/core/nlg/contextual_response_rephraser.py +3 -0
  11. rasa/core/policies/enterprise_search_policy.py +310 -61
  12. rasa/core/policies/intentless_policy.py +3 -0
  13. rasa/dialogue_understanding/coexistence/llm_based_router.py +8 -0
  14. rasa/dialogue_understanding/commands/knowledge_answer_command.py +2 -2
  15. rasa/dialogue_understanding/generator/command_parser.py +1 -1
  16. rasa/dialogue_understanding/generator/flow_retrieval.py +1 -4
  17. rasa/dialogue_understanding/generator/llm_based_command_generator.py +1 -2
  18. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +13 -0
  19. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_template.jinja2 +1 -1
  20. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +1 -1
  21. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +2 -24
  22. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +22 -17
  23. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +27 -12
  24. rasa/dialogue_understanding_test/io.py +8 -13
  25. rasa/e2e_test/utils/validation.py +3 -3
  26. rasa/engine/recipes/default_components.py +0 -2
  27. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +3 -0
  28. rasa/shared/utils/constants.py +3 -0
  29. rasa/shared/utils/llm.py +70 -24
  30. rasa/tracing/instrumentation/attribute_extractors.py +7 -10
  31. rasa/tracing/instrumentation/instrumentation.py +12 -12
  32. rasa/version.py +1 -1
  33. {rasa_pro-3.13.0.dev2.dist-info → rasa_pro-3.13.0.dev3.dist-info}/METADATA +2 -2
  34. {rasa_pro-3.13.0.dev2.dist-info → rasa_pro-3.13.0.dev3.dist-info}/RECORD +37 -48
  35. rasa/document_retrieval/__init__.py +0 -0
  36. rasa/document_retrieval/constants.py +0 -32
  37. rasa/document_retrieval/document_post_processor.py +0 -351
  38. rasa/document_retrieval/document_post_processor_prompt_template.jinja2 +0 -0
  39. rasa/document_retrieval/document_retriever.py +0 -333
  40. rasa/document_retrieval/knowledge_base_connectors/__init__.py +0 -0
  41. rasa/document_retrieval/knowledge_base_connectors/api_connector.py +0 -39
  42. rasa/document_retrieval/knowledge_base_connectors/knowledge_base_connector.py +0 -34
  43. rasa/document_retrieval/knowledge_base_connectors/vector_store_connector.py +0 -226
  44. rasa/document_retrieval/query_rewriter.py +0 -234
  45. rasa/document_retrieval/query_rewriter_prompt_template.jinja2 +0 -8
  46. {rasa_pro-3.13.0.dev2.dist-info → rasa_pro-3.13.0.dev3.dist-info}/NOTICE +0 -0
  47. {rasa_pro-3.13.0.dev2.dist-info → rasa_pro-3.13.0.dev3.dist-info}/WHEEL +0 -0
  48. {rasa_pro-3.13.0.dev2.dist-info → rasa_pro-3.13.0.dev3.dist-info}/entry_points.txt +0 -0
@@ -52,6 +52,10 @@ from rasa.shared.exceptions import ProviderClientAPIException
52
52
  from rasa.shared.nlu.constants import TEXT
53
53
  from rasa.shared.nlu.training_data.message import Message
54
54
  from rasa.shared.providers.llm.llm_response import LLMResponse
55
+ from rasa.shared.utils.constants import (
56
+ LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON,
57
+ LOG_COMPONENT_SOURCE_METHOD_INIT,
58
+ )
55
59
  from rasa.shared.utils.io import deep_container_fingerprint, raise_deprecation_warning
56
60
  from rasa.shared.utils.llm import (
57
61
  allowed_values_for_slot,
@@ -330,6 +334,8 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
330
334
  return get_prompt_template(
331
335
  config.get("prompt_templates", {}).get(key, {}).get(FILE_PATH_KEY),
332
336
  default_value,
337
+ log_source_component=MultiStepLLMCommandGenerator.__name__,
338
+ log_source_method=LOG_COMPONENT_SOURCE_METHOD_INIT,
333
339
  )
334
340
 
335
341
  @classmethod
@@ -786,17 +792,24 @@ class MultiStepLLMCommandGenerator(LLMBasedCommandGenerator):
786
792
  @classmethod
787
793
  def fingerprint_addon(cls, config: Dict[str, Any]) -> Optional[str]:
788
794
  """Add a fingerprint for the graph."""
795
+ get_prompt_template_log_params = {
796
+ "log_source_component": MultiStepLLMCommandGenerator.__name__,
797
+ "log_source_method": LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON,
798
+ }
799
+
789
800
  handle_flows_template = get_prompt_template(
790
801
  config.get("prompt_templates", {})
791
802
  .get(HANDLE_FLOWS_KEY, {})
792
803
  .get(FILE_PATH_KEY),
793
804
  DEFAULT_HANDLE_FLOWS_TEMPLATE,
805
+ **get_prompt_template_log_params,
794
806
  )
795
807
  fill_slots_template = get_prompt_template(
796
808
  config.get("prompt_templates", {})
797
809
  .get(FILL_SLOTS_KEY, {})
798
810
  .get(FILE_PATH_KEY),
799
811
  DEFAULT_FILL_SLOTS_TEMPLATE,
812
+ **get_prompt_template_log_params,
800
813
  )
801
814
 
802
815
  llm_config = resolve_model_client_config(
@@ -57,4 +57,4 @@ Strictly adhere to the provided action types listed above.
57
57
  Focus on the last message and take it one step at a time.
58
58
  Use the previous conversation steps only to aid understanding.
59
59
 
60
- Your action list:
60
+ Your action list:
@@ -8,7 +8,7 @@ Your task is to analyze the current conversation context and generate a list of
8
8
  * `set slot slot_name slot_value`: Slot setting. For example, `set slot transfer_money_recipient Freddy`. Can be used to correct and change previously set values.
9
9
  * `cancel flow`: Cancelling the current flow.
10
10
  * `disambiguate flows flow_name1 flow_name2 ... flow_name_n`: Disambiguate which flow should be started when user input is ambiguous by listing the potential flows as options. For example, `disambiguate flows list_contacts add_contact remove_contact ...` if the user just wrote "contacts".
11
- * `search and reply`: Responding to the user's questions by supplying relevant information, such as answering FAQs or explaining services.
11
+ * `provide info`: Responding to the user's questions by supplying relevant information, such as answering FAQs or explaining services.
12
12
  * `offtopic reply`: Responding to casual or social user messages that are unrelated to any flows, engaging in friendly conversation and addressing off-topic remarks.
13
13
  * `hand over`: Handing over to a human, in case the user seems frustrated or explicitly asks to speak to one.
14
14
 
@@ -16,9 +16,7 @@ Use the following structured data:
16
16
  * `set slot slot_name slot_value`: Slot setting. For example, `set slot transfer_money_recipient Freddy`. Can be used to correct and change previously set values.
17
17
  * `cancel flow`: Cancelling the current flow.
18
18
  * `disambiguate flows flow_name1 flow_name2 ... flow_name_n`: Disambiguate which flow should be started when user input is ambiguous by listing the potential flows as options. For example, `disambiguate flows list_contacts add_contact remove_contact ...` if the user just wrote "contacts".
19
- {%- if relevant_documents.results %}
20
- * `search and reply`: Responding to the user's message by using the relevant FAQs (included in this prompt) retrieved from the knowledge base.
21
- {%- endif %}
19
+ * `provide info`: Responding to the user's questions by supplying relevant information, such as answering FAQs or explaining services.
22
20
  * `offtopic reply`: Responding to casual or social user messages that are unrelated to any flows, engaging in friendly conversation and addressing off-topic remarks.
23
21
  * `hand over`: Handing over to a human, in case the user seems frustrated or explicitly asks to speak to one.
24
22
 
@@ -29,36 +27,16 @@ Use the following structured data:
29
27
  * For categorical slots try to match the user message with allowed slot values. Use "other" if you cannot match it.
30
28
  * Set the boolean slots based on the user response. Map positive responses to `True`, and negative to `False`.
31
29
  * Extract text slot values exactly as provided by the user. Avoid assumptions, format changes, or partial extractions.
32
- * Use clarification in ambiguous cases.
33
- * Use `disambiguate flows` only when multiple flows could fit the same message (e.g., "card" could mean `block_card` or `replace_card`).
34
- {%- if relevant_documents.results %}
35
- * A user asking a question does not automatically imply that they want `search and reply`. The objective is to help them complete a business process if its possible to do so via a flow.
36
- * **Flow Priority**: If a user message can be addressed by starting a flow (even if it looks like a general question), ALWAYS start the flow first. Example: If the user says "How do I activate my card?", use `start flow activate_card` instead of `search and reply`. Only use `search and reply` if no flow matches the request.
37
- {%- endif %}
38
30
  * Only use information provided by the user.
31
+ * Use clarification in ambiguous cases.
39
32
  * Multiple flows can be started. If a user wants to digress into a second flow, you do not need to cancel the current flow.
40
33
  * Do not cancel the flow unless the user explicitly requests it.
41
34
  * Strictly adhere to the provided action format.
42
35
  * Focus on the last message and take it one step at a time.
43
36
  * Use the previous conversation steps only to aid understanding.
44
37
 
45
- {%- if relevant_documents.results %}
46
-
47
- ---
48
-
49
- ## Relevant FAQs from the knowledge base
50
- ```json
51
- {"documents":[{% for document in relevant_documents.results %}{"Q":"{{ document.text }}","A":"{{ document.metadata.answer }}"},{% endfor %}]}
52
- ```
53
-
54
- ---
55
-
56
- {% else %}
57
-
58
38
  ---
59
39
 
60
- {% endif -%}
61
-
62
40
  ## Current State
63
41
  {% if current_flow != None %}Use the following structured data:
64
42
  ```json
@@ -1,10 +1,9 @@
1
1
  import copy
2
- from typing import Any, Dict, List, Optional, Text
2
+ from typing import Any, Dict, List, Literal, Optional, Text
3
3
 
4
4
  import structlog
5
5
 
6
6
  import rasa.shared.utils.io
7
- from rasa.core.information_retrieval import SearchResultList
8
7
  from rasa.dialogue_understanding.commands import (
9
8
  CannotHandleCommand,
10
9
  Command,
@@ -39,7 +38,6 @@ from rasa.dialogue_understanding.utils import (
39
38
  add_commands_to_message_parse_data,
40
39
  add_prompt_to_message_parse_data,
41
40
  )
42
- from rasa.document_retrieval.constants import POST_PROCESSED_DOCUMENTS_KEY
43
41
  from rasa.engine.graph import ExecutionContext
44
42
  from rasa.engine.recipes.default_recipe import DefaultV1Recipe
45
43
  from rasa.engine.storage.resource import Resource
@@ -60,6 +58,10 @@ from rasa.shared.exceptions import ProviderClientAPIException
60
58
  from rasa.shared.nlu.constants import LLM_COMMANDS, LLM_PROMPT, TEXT
61
59
  from rasa.shared.nlu.training_data.message import Message
62
60
  from rasa.shared.providers.llm.llm_response import LLMResponse
61
+ from rasa.shared.utils.constants import (
62
+ LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON,
63
+ LOG_COMPONENT_SOURCE_METHOD_INIT,
64
+ )
63
65
  from rasa.shared.utils.io import deep_container_fingerprint
64
66
  from rasa.shared.utils.llm import (
65
67
  allowed_values_for_slot,
@@ -189,8 +191,8 @@ class CompactLLMCommandGenerator(LLMBasedCommandGenerator):
189
191
  )
190
192
 
191
193
  # Get the prompt template from the config or the default prompt template.
192
- self.prompt_template = self.resolve_component_prompt_template(
193
- self.config, prompt_template
194
+ self.prompt_template = self._resolve_component_prompt_template(
195
+ self.config, prompt_template, log_context=LOG_COMPONENT_SOURCE_METHOD_INIT
194
196
  )
195
197
 
196
198
  # Set the command syntax version to v2
@@ -495,10 +497,6 @@ class CompactLLMCommandGenerator(LLMBasedCommandGenerator):
495
497
  latest_user_message = sanitize_message_for_prompt(message.get(TEXT))
496
498
  current_conversation += f"\nUSER: {latest_user_message}"
497
499
 
498
- relevant_documents = SearchResultList.from_dict(
499
- message.get(POST_PROCESSED_DOCUMENTS_KEY, [])
500
- )
501
-
502
500
  inputs = {
503
501
  "available_flows": self.prepare_flows_for_template(
504
502
  startable_flows, tracker
@@ -512,7 +510,6 @@ class CompactLLMCommandGenerator(LLMBasedCommandGenerator):
512
510
  "current_slot_allowed_values": current_slot_allowed_values,
513
511
  "user_message": latest_user_message,
514
512
  "is_repeat_command_enabled": self.repeat_command_enabled,
515
- "relevant_documents": relevant_documents,
516
513
  }
517
514
 
518
515
  return self.compile_template(self.prompt_template).render(**inputs)
@@ -546,7 +543,9 @@ class CompactLLMCommandGenerator(LLMBasedCommandGenerator):
546
543
  # and update the llm config with the resolved llm config.
547
544
  _config_copy = copy.deepcopy(config)
548
545
  _config_copy[LLM_CONFIG_KEY] = llm_config
549
- prompt_template = cls.resolve_component_prompt_template(_config_copy)
546
+ prompt_template = cls._resolve_component_prompt_template(
547
+ _config_copy, log_context=LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON
548
+ )
550
549
 
551
550
  return deep_container_fingerprint(
552
551
  [prompt_template, llm_config, embedding_config]
@@ -562,20 +561,26 @@ class CompactLLMCommandGenerator(LLMBasedCommandGenerator):
562
561
  return CommandSyntaxVersion.v2
563
562
 
564
563
  @staticmethod
565
- def resolve_component_prompt_template(
566
- config: Dict[str, Any], prompt_template: Optional[str] = None
564
+ def _resolve_component_prompt_template(
565
+ config: Dict[str, Any],
566
+ prompt_template: Optional[str] = None,
567
+ log_context: Optional[Literal["init", "fingerprint_addon"]] = None,
567
568
  ) -> Optional[str]:
568
569
  """Get the prompt template from the config or the default prompt template."""
569
570
  # Get the default prompt template based on the model name.
570
571
  default_command_prompt_template = get_default_prompt_template_based_on_model(
571
- config.get(LLM_CONFIG_KEY, {}) or {},
572
- MODEL_PROMPT_MAPPER,
573
- DEFAULT_COMMAND_PROMPT_TEMPLATE_FILE_NAME,
574
- FALLBACK_COMMAND_PROMPT_TEMPLATE_FILE_NAME,
572
+ llm_config=config.get(LLM_CONFIG_KEY, {}) or {},
573
+ model_prompt_mapping=MODEL_PROMPT_MAPPER,
574
+ default_prompt_path=DEFAULT_COMMAND_PROMPT_TEMPLATE_FILE_NAME,
575
+ fallback_prompt_path=FALLBACK_COMMAND_PROMPT_TEMPLATE_FILE_NAME,
576
+ log_source_component=CompactLLMCommandGenerator.__name__,
577
+ log_source_method=log_context,
575
578
  )
576
579
 
577
580
  # Return the prompt template either from the config or the default prompt.
578
581
  return prompt_template or get_prompt_template(
579
582
  config.get(PROMPT_TEMPLATE_CONFIG_KEY),
580
583
  default_command_prompt_template,
584
+ log_source_component=CompactLLMCommandGenerator.__name__,
585
+ log_source_method=log_context,
581
586
  )
@@ -1,5 +1,5 @@
1
1
  import importlib.resources
2
- from typing import Any, Dict, Optional, Text
2
+ from typing import Any, Dict, Literal, Optional, Text
3
3
 
4
4
  import structlog
5
5
 
@@ -25,8 +25,12 @@ from rasa.shared.constants import (
25
25
  PROMPT_CONFIG_KEY,
26
26
  PROMPT_TEMPLATE_CONFIG_KEY,
27
27
  )
28
+ from rasa.shared.utils.constants import LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON
28
29
  from rasa.shared.utils.io import deep_container_fingerprint
29
- from rasa.shared.utils.llm import get_prompt_template, resolve_model_client_config
30
+ from rasa.shared.utils.llm import (
31
+ get_prompt_template,
32
+ resolve_model_client_config,
33
+ )
30
34
 
31
35
  DEFAULT_COMMAND_PROMPT_TEMPLATE = importlib.resources.read_text(
32
36
  "rasa.dialogue_understanding.generator.prompt_templates",
@@ -72,9 +76,6 @@ class SingleStepLLMCommandGenerator(CompactLLMCommandGenerator):
72
76
  "Please use the config parameter 'prompt_template' instead. "
73
77
  ),
74
78
  )
75
- self.prompt_template = self.resolve_component_prompt_template(
76
- config, prompt_template
77
- )
78
79
 
79
80
  # Set the command syntax version to v1
80
81
  CommandSyntaxManager.set_syntax_version(
@@ -95,7 +96,9 @@ class SingleStepLLMCommandGenerator(CompactLLMCommandGenerator):
95
96
  @classmethod
96
97
  def fingerprint_addon(cls: Any, config: Dict[str, Any]) -> Optional[str]:
97
98
  """Add a fingerprint for the graph."""
98
- prompt_template = cls.resolve_component_prompt_template(config)
99
+ prompt_template = cls._resolve_component_prompt_template(
100
+ config, log_context=LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON
101
+ )
99
102
  llm_config = resolve_model_client_config(
100
103
  config.get(LLM_CONFIG_KEY), SingleStepLLMCommandGenerator.__name__
101
104
  )
@@ -117,17 +120,29 @@ class SingleStepLLMCommandGenerator(CompactLLMCommandGenerator):
117
120
  return CommandSyntaxVersion.v1
118
121
 
119
122
  @staticmethod
120
- def resolve_component_prompt_template(
121
- config: Dict[str, Any], prompt_template: Optional[str] = None
123
+ def _resolve_component_prompt_template(
124
+ config: Dict[str, Any],
125
+ prompt_template: Optional[str] = None,
126
+ log_context: Optional[Literal["init", "fingerprint_addon"]] = None,
122
127
  ) -> Optional[str]:
123
128
  """Get the prompt template from the config or the default prompt template."""
124
- # Get the default prompt template based on the model name.
125
- config_prompt = (
129
+ # Case when model is being loaded
130
+ if prompt_template is not None:
131
+ return prompt_template
132
+
133
+ # The prompt can be configured in the config via the "prompt" (deprecated) or
134
+ # "prompt_template" properties
135
+ prompt_template_path = (
126
136
  config.get(PROMPT_CONFIG_KEY)
127
137
  or config.get(PROMPT_TEMPLATE_CONFIG_KEY)
128
138
  or None
129
139
  )
130
- return prompt_template or get_prompt_template(
131
- config_prompt,
140
+
141
+ # Try to load the template from the given path or fallback to the default for
142
+ # the component
143
+ return get_prompt_template(
144
+ prompt_template_path,
132
145
  DEFAULT_COMMAND_PROMPT_TEMPLATE,
146
+ log_source_component=SingleStepLLMCommandGenerator.__name__,
147
+ log_source_method=log_context,
133
148
  )
@@ -329,19 +329,14 @@ def print_prompt(step: FailedTestStep) -> None:
329
329
  rich.print(
330
330
  f"[bold] prompt name [/bold]: {prompt_data[KEY_PROMPT_NAME]}"
331
331
  )
332
- if KEY_PROMPT_TOKENS in prompt_data:
333
- rich.print(
334
- f"[bold] prompt tokens [/bold]: {prompt_data[KEY_PROMPT_TOKENS]}" # noqa: E501
335
- )
336
- if KEY_COMPLETION_TOKENS in prompt_data:
337
- rich.print(
338
- f"[bold] completion tokens[/bold]: "
339
- f"{prompt_data[KEY_COMPLETION_TOKENS]}"
340
- )
341
- if KEY_LATENCY in prompt_data:
342
- rich.print(
343
- f"[bold] latency [/bold]: {prompt_data[KEY_LATENCY]}"
344
- )
332
+ rich.print(
333
+ f"[bold] prompt tokens [/bold]: {prompt_data[KEY_PROMPT_TOKENS]}"
334
+ )
335
+ rich.print(
336
+ f"[bold] completion tokens[/bold]: "
337
+ f"{prompt_data[KEY_COMPLETION_TOKENS]}"
338
+ )
339
+ rich.print(f"[bold] latency [/bold]: {prompt_data[KEY_LATENCY]}")
345
340
  if KEY_SYSTEM_PROMPT in prompt_data:
346
341
  rich.print(
347
342
  f"[bold] system prompt [/bold]: "
@@ -7,6 +7,7 @@ import structlog
7
7
  import rasa.shared.utils.io
8
8
  from rasa.e2e_test.constants import SCHEMA_FILE_PATH
9
9
  from rasa.e2e_test.e2e_test_case import Fixture, Metadata
10
+ from rasa.exceptions import ModelNotFound
10
11
  from rasa.shared.utils.yaml import read_schema_file
11
12
 
12
13
  if TYPE_CHECKING:
@@ -152,10 +153,9 @@ def validate_model_path(model_path: Optional[str], parameter: str, default: str)
152
153
  return model_path
153
154
 
154
155
  if model_path and not Path(model_path).exists():
155
- rasa.shared.utils.io.raise_warning(
156
+ raise ModelNotFound(
156
157
  f"The provided model path '{model_path}' could not be found. "
157
- f"Using default location '{default}' instead.",
158
- UserWarning,
158
+ "Provide an existing model path."
159
159
  )
160
160
 
161
161
  elif model_path is None:
@@ -13,7 +13,6 @@ from rasa.dialogue_understanding.generator import (
13
13
  LLMCommandGenerator,
14
14
  )
15
15
  from rasa.dialogue_understanding.generator.nlu_command_adapter import NLUCommandAdapter
16
- from rasa.document_retrieval.document_retriever import DocumentRetriever
17
16
  from rasa.nlu.classifiers.diet_classifier import DIETClassifier
18
17
  from rasa.nlu.classifiers.fallback_classifier import FallbackClassifier
19
18
  from rasa.nlu.classifiers.keyword_intent_classifier import KeywordIntentClassifier
@@ -93,5 +92,4 @@ DEFAULT_COMPONENTS = [
93
92
  FlowPolicy,
94
93
  EnterpriseSearchPolicy,
95
94
  IntentlessPolicy,
96
- DocumentRetriever,
97
95
  ]
@@ -19,6 +19,7 @@ from rasa.shared.constants import (
19
19
  )
20
20
  from rasa.shared.exceptions import ProviderClientAPIException
21
21
  from rasa.shared.providers.mappings import OPENAI_PROVIDER
22
+ from rasa.shared.utils.constants import LOG_COMPONENT_SOURCE_METHOD_INIT
22
23
  from rasa.shared.utils.llm import (
23
24
  USER,
24
25
  get_prompt_template,
@@ -54,6 +55,8 @@ class ConversationRephraser:
54
55
  self.prompt_template = get_prompt_template(
55
56
  self.config.get(PROMPT_TEMPLATE_CONFIG_KEY),
56
57
  DEFAULT_REPHRASING_PROMPT_TEMPLATE,
58
+ log_source_component=ConversationRephraser.__name__,
59
+ log_source_method=LOG_COMPONENT_SOURCE_METHOD_INIT,
57
60
  )
58
61
 
59
62
  @staticmethod
@@ -5,3 +5,6 @@ DEFAULT_READ_YAML_FILE_CACHE_MAXSIZE = 256
5
5
  RASA_PRO_BETA_PREDICATES_IN_RESPONSE_CONDITIONS_ENV_VAR_NAME = (
6
6
  "RASA_PRO_BETA_PREDICATES_IN_RESPONSE_CONDITIONS"
7
7
  )
8
+
9
+ LOG_COMPONENT_SOURCE_METHOD_INIT = "init"
10
+ LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON = "fingerprint_addon"
rasa/shared/utils/llm.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import importlib.resources
2
2
  import json
3
+ import logging
3
4
  from copy import deepcopy
4
5
  from functools import wraps
5
6
  from typing import (
@@ -7,6 +8,7 @@ from typing import (
7
8
  Any,
8
9
  Callable,
9
10
  Dict,
11
+ Literal,
10
12
  Optional,
11
13
  Text,
12
14
  Type,
@@ -59,6 +61,7 @@ from rasa.shared.providers.mappings import (
59
61
  get_embedding_client_from_provider,
60
62
  get_llm_client_from_provider,
61
63
  )
64
+ from rasa.shared.utils.constants import LOG_COMPONENT_SOURCE_METHOD_INIT
62
65
 
63
66
  if TYPE_CHECKING:
64
67
  from rasa.shared.core.trackers import DialogueStateTracker
@@ -654,35 +657,59 @@ def embedder_client_factory(
654
657
 
655
658
 
656
659
  def get_prompt_template(
657
- jinja_file_path: Optional[Text], default_prompt_template: Text
660
+ jinja_file_path: Optional[Text],
661
+ default_prompt_template: Text,
662
+ *,
663
+ log_source_component: Optional[Text] = None,
664
+ log_source_method: Optional[Literal["init", "fingerprint_addon"]] = None,
658
665
  ) -> Text:
659
666
  """Returns the jinja template.
660
667
 
661
668
  Args:
662
- jinja_file_path: the path to the jinja file
663
- default_prompt_template: the default prompt template
669
+ jinja_file_path: The path to the jinja template file. If not provided, the
670
+ default template will be used.
671
+ default_prompt_template: The fallback prompt template to use if no file is
672
+ found or specified.
673
+ log_source_component: The name of the component emitting the log, used to
674
+ identify the source in structured logging.
675
+ log_source_method: The name of the method or function emitting the log for
676
+ better traceability.
664
677
 
665
678
  Returns:
666
679
  The prompt template.
667
680
  """
681
+
668
682
  try:
669
683
  if jinja_file_path is not None:
670
684
  prompt_template = rasa.shared.utils.io.read_file(jinja_file_path)
671
- structlogger.info(
672
- "utils.llm.get_prompt_template.custom_prompt_template_read_successfull",
685
+
686
+ log_level = (
687
+ logging.INFO
688
+ if log_source_method == LOG_COMPONENT_SOURCE_METHOD_INIT
689
+ else logging.DEBUG
690
+ )
691
+
692
+ structlogger.log(
693
+ log_level,
694
+ "utils.llm.get_prompt_template"
695
+ ".custom_prompt_template_read_successfully",
673
696
  event_info=(
674
697
  f"Custom prompt template read successfully from "
675
698
  f"`{jinja_file_path}`."
676
699
  ),
677
700
  prompt_file_path=jinja_file_path,
701
+ log_source_component=log_source_component,
702
+ log_source_method=log_source_method,
678
703
  )
679
704
  return prompt_template
680
705
  except (FileIOException, FileNotFoundException):
681
706
  structlogger.warning(
682
- "utils.llm.get_prompt_template.failed_to_read_custom_prompt_template",
707
+ "utils.llm.get_prompt_template" ".failed_to_read_custom_prompt_template",
683
708
  event_info=(
684
709
  "Failed to read custom prompt template. Using default template instead."
685
710
  ),
711
+ log_source_component=log_source_component,
712
+ log_source_method=log_source_method,
686
713
  )
687
714
  return default_prompt_template
688
715
 
@@ -692,50 +719,66 @@ def get_default_prompt_template_based_on_model(
692
719
  model_prompt_mapping: Dict[str, Any],
693
720
  default_prompt_path: str,
694
721
  fallback_prompt_path: str,
722
+ *,
723
+ log_source_component: Optional[Text] = None,
724
+ log_source_method: Optional[Literal["init", "fingerprint_addon"]] = None,
695
725
  ) -> Text:
696
726
  """Returns the default prompt template based on the model name.
697
727
 
698
728
  Args:
699
729
  llm_config: The model config.
700
- model_prompt_mapping: The mapping of model name to prompt template.
701
- default_prompt_path: The default prompt path of the component.
702
- fallback_prompt_path: The fallback prompt path for all other models
703
- that do not have a mapping in the model_prompt_mapping.
730
+ model_prompt_mapping: The model name -> prompt template mapping.
731
+ default_prompt_path: The path to the default prompt template for the component.
732
+ fallback_prompt_path: The fallback prompt path for all other models that do not
733
+ have a mapping in the model_prompt_mapping.
734
+ log_source_component: The name of the component emitting the log, used to
735
+ identify the source in structured logging.
736
+ log_source_method: The name of the method or function emitting the log for
737
+ better traceability.
704
738
 
705
739
  Returns:
706
740
  The default prompt template.
707
741
  """
742
+ # Extract the provider and model name information from the configuration
708
743
  _llm_config = deepcopy(llm_config)
709
744
  if MODELS_CONFIG_KEY in _llm_config:
710
745
  _llm_config = _llm_config[MODELS_CONFIG_KEY][0]
711
746
  provider = _llm_config.get(PROVIDER_CONFIG_KEY)
712
747
  model = _llm_config.get(MODEL_CONFIG_KEY)
748
+
749
+ # If the model is not defined, we default to the default prompt template.
713
750
  if not model:
714
- # If the model is not defined, we default to the default prompt template.
715
- structlogger.info(
716
- "utils.llm.get_default_prompt_template_based_on_model.using_default_prompt_template",
751
+ structlogger.debug(
752
+ "utils.llm.get_default_prompt_template_based_on_model"
753
+ ".using_default_prompt_template",
717
754
  event_info=(
718
755
  f"Model not defined in the config. Default prompt template read from"
719
756
  f" - `{default_prompt_path}`."
720
757
  ),
721
758
  default_prompt_path=default_prompt_path,
759
+ log_source_component=log_source_component,
760
+ log_source_method=log_source_method,
722
761
  )
723
762
  return importlib.resources.read_text(
724
763
  DEFAULT_PROMPT_PACKAGE_NAME, default_prompt_path
725
764
  )
726
765
 
727
- model_name = model if provider and provider in model else f"{provider}/{model}"
728
- if prompt_file_path := model_prompt_mapping.get(model_name):
729
- # If the model is found in the mapping, we use the model-specific prompt
730
- # template.
731
- structlogger.info(
732
- "utils.llm.get_default_prompt_template_based_on_model.using_model_specific_prompt_template",
766
+ full_model_name = model if provider and provider in model else f"{provider}/{model}"
767
+
768
+ # If the model is found in the mapping, we use the model-specific prompt
769
+ # template.
770
+ if prompt_file_path := model_prompt_mapping.get(full_model_name):
771
+ structlogger.debug(
772
+ "utils.llm.get_default_prompt_template_based_on_model"
773
+ ".using_model_specific_prompt_template",
733
774
  event_info=(
734
775
  f"Using model-specific default prompt template. Default prompt "
735
776
  f"template read from - `{prompt_file_path}`."
736
777
  ),
737
778
  default_prompt_path=prompt_file_path,
738
- model_name=model_name,
779
+ model_name=full_model_name,
780
+ log_source_component=log_source_component,
781
+ log_source_method=log_source_method,
739
782
  )
740
783
  return importlib.resources.read_text(
741
784
  DEFAULT_PROMPT_PACKAGE_NAME, prompt_file_path
@@ -743,14 +786,17 @@ def get_default_prompt_template_based_on_model(
743
786
 
744
787
  # If the model is not found in the mapping, we default to the fallback prompt
745
788
  # template.
746
- structlogger.info(
747
- "utils.llm.get_default_prompt_template_based_on_model.using_fallback_prompt_template",
789
+ structlogger.debug(
790
+ "utils.llm.get_default_prompt_template_based_on_model"
791
+ ".using_fallback_prompt_template",
748
792
  event_info=(
749
793
  f"Model not found in the model prompt mapping. Fallback prompt template "
750
794
  f"read from - `{fallback_prompt_path}`."
751
795
  ),
752
796
  fallback_prompt_path=fallback_prompt_path,
753
- model_name=model_name,
797
+ model_name=full_model_name,
798
+ log_source_component=log_source_component,
799
+ log_source_method=log_source_method,
754
800
  )
755
801
  return importlib.resources.read_text(
756
802
  DEFAULT_PROMPT_PACKAGE_NAME, fallback_prompt_path
@@ -762,7 +808,7 @@ def allowed_values_for_slot(slot: Slot) -> Union[str, None]:
762
808
  if isinstance(slot, BooleanSlot):
763
809
  return str([True, False])
764
810
  if isinstance(slot, CategoricalSlot):
765
- return str([v for v in slot.values if v != "__other__"] + ["other"])
811
+ return str([v for v in slot.values if v != "__other__"])
766
812
  else:
767
813
  return None
768
814
 
@@ -326,7 +326,7 @@ def extract_attrs_for_command(
326
326
  def extract_llm_config(
327
327
  self: Any,
328
328
  default_llm_config: Dict[str, Any],
329
- default_embeddings_config: Optional[Dict[str, Any]],
329
+ default_embeddings_config: Dict[str, Any],
330
330
  ) -> Dict[str, Any]:
331
331
  if isinstance(self, ContextualResponseRephraser):
332
332
  # ContextualResponseRephraser is not a graph component, so it's
@@ -346,12 +346,8 @@ def extract_llm_config(
346
346
  default_embeddings_config,
347
347
  )
348
348
  else:
349
- embeddings_property = (
350
- combine_custom_and_default_config(
351
- config.get(EMBEDDINGS_CONFIG_KEY), default_embeddings_config
352
- )
353
- if default_embeddings_config is not None
354
- else {}
349
+ embeddings_property = combine_custom_and_default_config(
350
+ config.get(EMBEDDINGS_CONFIG_KEY), default_embeddings_config
355
351
  )
356
352
 
357
353
  attributes = {
@@ -406,7 +402,7 @@ def extract_attrs_for_contextual_response_rephraser(
406
402
  self,
407
403
  default_llm_config=DEFAULT_LLM_CONFIG,
408
404
  # rephraser is not using embeddings
409
- default_embeddings_config=None,
405
+ default_embeddings_config={},
410
406
  )
411
407
 
412
408
  return extend_attributes_with_prompt_tokens_length(self, attributes, prompt)
@@ -422,7 +418,7 @@ def extract_attrs_for_create_history(
422
418
  self,
423
419
  default_llm_config=DEFAULT_LLM_CONFIG,
424
420
  # rephraser is not using embeddings
425
- default_embeddings_config=None,
421
+ default_embeddings_config={},
426
422
  )
427
423
 
428
424
 
@@ -775,13 +771,14 @@ def extract_attrs_for_enterprise_search_generate_llm_answer(
775
771
  self: "EnterpriseSearchPolicy", llm: "BaseLLM", prompt: str
776
772
  ) -> Dict[str, Any]:
777
773
  from rasa.core.policies.enterprise_search_policy import (
774
+ DEFAULT_EMBEDDINGS_CONFIG,
778
775
  DEFAULT_LLM_CONFIG,
779
776
  )
780
777
 
781
778
  attributes = extract_llm_config(
782
779
  self,
783
780
  default_llm_config=DEFAULT_LLM_CONFIG,
784
- default_embeddings_config=None,
781
+ default_embeddings_config=DEFAULT_EMBEDDINGS_CONFIG,
785
782
  )
786
783
 
787
784
  return extend_attributes_with_prompt_tokens_length(self, attributes, prompt)