rasa-pro 3.13.0.dev5__py3-none-any.whl → 3.13.0.dev8__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 (266) hide show
  1. rasa/__main__.py +0 -3
  2. rasa/api.py +5 -1
  3. rasa/cli/arguments/default_arguments.py +13 -1
  4. rasa/cli/arguments/train.py +2 -0
  5. rasa/cli/dialogue_understanding_test.py +1 -1
  6. rasa/cli/e2e_test.py +1 -1
  7. rasa/cli/evaluate.py +2 -2
  8. rasa/cli/export.py +3 -3
  9. rasa/cli/llm_fine_tuning.py +12 -11
  10. rasa/cli/project_templates/defaults.py +133 -0
  11. rasa/cli/run.py +1 -1
  12. rasa/cli/studio/link.py +53 -0
  13. rasa/cli/studio/pull.py +78 -0
  14. rasa/cli/studio/push.py +78 -0
  15. rasa/cli/studio/studio.py +12 -0
  16. rasa/cli/studio/upload.py +8 -0
  17. rasa/cli/train.py +2 -1
  18. rasa/cli/utils.py +1 -1
  19. rasa/cli/x.py +1 -1
  20. rasa/constants.py +4 -0
  21. rasa/core/__init__.py +0 -16
  22. rasa/core/actions/action.py +5 -1
  23. rasa/core/actions/action_repeat_bot_messages.py +18 -22
  24. rasa/core/actions/action_run_slot_rejections.py +0 -1
  25. rasa/core/agent.py +18 -3
  26. rasa/core/available_endpoints.py +146 -0
  27. rasa/core/brokers/kafka.py +4 -0
  28. rasa/core/brokers/pika.py +5 -2
  29. rasa/core/brokers/sql.py +1 -1
  30. rasa/core/channels/botframework.py +2 -2
  31. rasa/core/channels/channel.py +2 -2
  32. rasa/core/channels/hangouts.py +8 -5
  33. rasa/core/channels/inspector/.eslintrc.cjs +12 -6
  34. rasa/core/channels/inspector/.prettierrc +5 -0
  35. rasa/core/channels/inspector/README.md +10 -4
  36. rasa/core/channels/inspector/dist/assets/{arc-9f75cc3b.js → arc-c4b064fc.js} +1 -1
  37. rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-7f34db23.js → blockDiagram-38ab4fdb-215b5026.js} +1 -1
  38. rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-948bab2c.js → c4Diagram-3d4e48cf-2b54a0a3.js} +1 -1
  39. rasa/core/channels/inspector/dist/assets/channel-3730f5fd.js +1 -0
  40. rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-53b0dd0e.js → classDiagram-70f12bd4-daacea5f.js} +1 -1
  41. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-fdf789e7.js → classDiagram-v2-f2320105-930d4dc2.js} +1 -1
  42. rasa/core/channels/inspector/dist/assets/clone-e847561e.js +1 -0
  43. rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-87c4ece5.js → createText-2e5e7dd3-83c206ba.js} +1 -1
  44. rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-5a8b0749.js → edges-e0da2a9e-b0eb01d0.js} +1 -1
  45. rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-66da90e2.js → erDiagram-9861fffd-17586500.js} +1 -1
  46. rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-10044f05.js → flowDb-956e92f1-be2a1776.js} +1 -1
  47. rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-f338f66a.js → flowDiagram-66a62f08-c2120ebd.js} +1 -1
  48. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-efbbfe00.js +1 -0
  49. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-b13140aa.js → flowchart-elk-definition-4a651766-a6ab5c48.js} +1 -1
  50. rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-f2b4a55a.js → ganttDiagram-c361ad54-ef613457.js} +1 -1
  51. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-dedc298d.js → gitGraphDiagram-72cf32ee-d59185b3.js} +1 -1
  52. rasa/core/channels/inspector/dist/assets/{graph-4ede11ff.js → graph-0f155405.js} +1 -1
  53. rasa/core/channels/inspector/dist/assets/{index-3862675e-65549d37.js → index-3862675e-d5f1d1b7.js} +1 -1
  54. rasa/core/channels/inspector/dist/assets/{index-3a23e736.js → index-47737d3a.js} +123 -123
  55. rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-65439671.js → infoDiagram-f8f76790-b07d141f.js} +1 -1
  56. rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-56d03d98.js → journeyDiagram-49397b02-1936d429.js} +1 -1
  57. rasa/core/channels/inspector/dist/assets/{layout-dd48f7f4.js → layout-dde8d0f3.js} +1 -1
  58. rasa/core/channels/inspector/dist/assets/{line-1569ad2c.js → line-0c2c7ee0.js} +1 -1
  59. rasa/core/channels/inspector/dist/assets/{linear-48bf4935.js → linear-35dd89a4.js} +1 -1
  60. rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-688504c1.js → mindmap-definition-fc14e90a-56192851.js} +1 -1
  61. rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-78b6d7e6.js → pieDiagram-8a3498a8-fc21ed78.js} +1 -1
  62. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-048b84b3.js → quadrantDiagram-120e2f19-25e98518.js} +1 -1
  63. rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-dd67f107.js → requirementDiagram-deff3bca-546ff1f5.js} +1 -1
  64. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-8128436e.js → sankeyDiagram-04a897e0-02d8b82d.js} +1 -1
  65. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-1a0d1461.js → sequenceDiagram-704730f1-3ca5a92e.js} +1 -1
  66. rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-46d388ed.js → stateDiagram-587899a1-128ea07c.js} +1 -1
  67. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-ea42951a.js → stateDiagram-v2-d93cdb3a-95f290af.js} +1 -1
  68. rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-7427ed0c.js → styles-6aaf32cf-4984898a.js} +1 -1
  69. rasa/core/channels/inspector/dist/assets/{styles-9a916d00-ff5e5a16.js → styles-9a916d00-1bf266ba.js} +1 -1
  70. rasa/core/channels/inspector/dist/assets/{styles-c10674c1-7b3680cf.js → styles-c10674c1-60521c63.js} +1 -1
  71. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-f860f2ad.js → svgDrawCommon-08f97a94-a25b6e12.js} +1 -1
  72. rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-2eebf0c8.js → timeline-definition-85554ec2-0fc086bf.js} +1 -1
  73. rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-5d7f4e96.js → xychartDiagram-e933f94c-44ee592e.js} +1 -1
  74. rasa/core/channels/inspector/dist/index.html +1 -1
  75. rasa/core/channels/inspector/package.json +3 -1
  76. rasa/core/channels/inspector/src/App.tsx +91 -90
  77. rasa/core/channels/inspector/src/components/Chat.tsx +45 -41
  78. rasa/core/channels/inspector/src/components/DiagramFlow.tsx +40 -40
  79. rasa/core/channels/inspector/src/components/DialogueInformation.tsx +57 -57
  80. rasa/core/channels/inspector/src/components/DialogueStack.tsx +36 -27
  81. rasa/core/channels/inspector/src/components/ExpandIcon.tsx +4 -4
  82. rasa/core/channels/inspector/src/components/FullscreenButton.tsx +7 -7
  83. rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +28 -12
  84. rasa/core/channels/inspector/src/components/NoActiveFlow.tsx +9 -9
  85. rasa/core/channels/inspector/src/components/RasaLogo.tsx +5 -5
  86. rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +55 -60
  87. rasa/core/channels/inspector/src/components/SaraDiagrams.tsx +5 -5
  88. rasa/core/channels/inspector/src/components/Slots.tsx +22 -22
  89. rasa/core/channels/inspector/src/components/Welcome.tsx +28 -31
  90. rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +245 -0
  91. rasa/core/channels/inspector/src/helpers/audio/microphone-processor.js +12 -0
  92. rasa/core/channels/inspector/src/helpers/audio/playback-processor.js +36 -0
  93. rasa/core/channels/inspector/src/helpers/conversation.ts +7 -7
  94. rasa/core/channels/inspector/src/helpers/formatters.test.ts +181 -181
  95. rasa/core/channels/inspector/src/helpers/formatters.ts +111 -111
  96. rasa/core/channels/inspector/src/helpers/utils.ts +78 -61
  97. rasa/core/channels/inspector/src/main.tsx +8 -8
  98. rasa/core/channels/inspector/src/theme/Button/Button.ts +8 -8
  99. rasa/core/channels/inspector/src/theme/Heading/Heading.ts +7 -7
  100. rasa/core/channels/inspector/src/theme/Input/Input.ts +9 -9
  101. rasa/core/channels/inspector/src/theme/Link/Link.ts +6 -6
  102. rasa/core/channels/inspector/src/theme/Modal/Modal.ts +13 -13
  103. rasa/core/channels/inspector/src/theme/Table/Table.tsx +10 -10
  104. rasa/core/channels/inspector/src/theme/Tooltip/Tooltip.ts +5 -5
  105. rasa/core/channels/inspector/src/theme/base/breakpoints.ts +7 -7
  106. rasa/core/channels/inspector/src/theme/base/colors.ts +64 -64
  107. rasa/core/channels/inspector/src/theme/base/fonts/fontFaces.css +21 -18
  108. rasa/core/channels/inspector/src/theme/base/radii.ts +8 -8
  109. rasa/core/channels/inspector/src/theme/base/shadows.ts +5 -5
  110. rasa/core/channels/inspector/src/theme/base/sizes.ts +5 -5
  111. rasa/core/channels/inspector/src/theme/base/space.ts +12 -12
  112. rasa/core/channels/inspector/src/theme/base/styles.ts +5 -5
  113. rasa/core/channels/inspector/src/theme/base/typography.ts +12 -12
  114. rasa/core/channels/inspector/src/theme/base/zIndices.ts +3 -3
  115. rasa/core/channels/inspector/src/theme/index.ts +38 -38
  116. rasa/core/channels/inspector/src/types.ts +56 -50
  117. rasa/core/channels/inspector/yarn.lock +5 -0
  118. rasa/core/channels/mattermost.py +1 -1
  119. rasa/core/channels/rasa_chat.py +2 -4
  120. rasa/core/channels/rest.py +5 -4
  121. rasa/core/channels/studio_chat.py +3 -2
  122. rasa/core/channels/vier_cvg.py +1 -2
  123. rasa/core/channels/voice_ready/audiocodes.py +35 -25
  124. rasa/core/channels/voice_stream/audiocodes.py +7 -4
  125. rasa/core/channels/voice_stream/genesys.py +2 -2
  126. rasa/core/channels/voice_stream/twilio_media_streams.py +10 -5
  127. rasa/core/channels/voice_stream/voice_channel.py +33 -22
  128. rasa/core/evaluation/marker_tracker_loader.py +1 -1
  129. rasa/core/exporter.py +1 -1
  130. rasa/core/http_interpreter.py +3 -7
  131. rasa/core/jobs.py +2 -1
  132. rasa/core/nlg/contextual_response_rephraser.py +38 -11
  133. rasa/core/nlg/generator.py +0 -1
  134. rasa/core/nlg/interpolator.py +2 -3
  135. rasa/core/nlg/summarize.py +40 -6
  136. rasa/core/persistor.py +55 -20
  137. rasa/core/policies/enterprise_search_policy.py +290 -66
  138. rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2 +63 -0
  139. rasa/core/policies/flow_policy.py +1 -1
  140. rasa/core/policies/flows/flow_executor.py +96 -17
  141. rasa/core/policies/intentless_policy.py +24 -16
  142. rasa/core/processor.py +106 -53
  143. rasa/core/run.py +40 -13
  144. rasa/core/tracker_stores/__init__.py +0 -0
  145. rasa/core/{auth_retry_tracker_store.py → tracker_stores/auth_retry_tracker_store.py} +5 -1
  146. rasa/core/tracker_stores/dynamo_tracker_store.py +218 -0
  147. rasa/core/tracker_stores/mongo_tracker_store.py +206 -0
  148. rasa/core/tracker_stores/redis_tracker_store.py +219 -0
  149. rasa/core/tracker_stores/sql_tracker_store.py +555 -0
  150. rasa/core/tracker_stores/tracker_store.py +805 -0
  151. rasa/core/training/interactive.py +1 -1
  152. rasa/core/utils.py +24 -91
  153. rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -1
  154. rasa/dialogue_understanding/coexistence/llm_based_router.py +8 -3
  155. rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -0
  156. rasa/dialogue_understanding/commands/cancel_flow_command.py +2 -0
  157. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +2 -0
  158. rasa/dialogue_understanding/commands/clarify_command.py +6 -2
  159. rasa/dialogue_understanding/commands/command_syntax_manager.py +1 -0
  160. rasa/dialogue_understanding/commands/human_handoff_command.py +2 -0
  161. rasa/dialogue_understanding/commands/knowledge_answer_command.py +2 -0
  162. rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +2 -0
  163. rasa/dialogue_understanding/commands/set_slot_command.py +11 -1
  164. rasa/dialogue_understanding/commands/skip_question_command.py +2 -0
  165. rasa/dialogue_understanding/commands/start_flow_command.py +4 -0
  166. rasa/dialogue_understanding/commands/utils.py +26 -2
  167. rasa/dialogue_understanding/generator/__init__.py +7 -1
  168. rasa/dialogue_understanding/generator/command_generator.py +4 -2
  169. rasa/dialogue_understanding/generator/command_parser.py +2 -2
  170. rasa/dialogue_understanding/generator/command_parser_validator.py +63 -0
  171. rasa/dialogue_understanding/generator/constants.py +2 -2
  172. rasa/dialogue_understanding/generator/llm_based_command_generator.py +1 -1
  173. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +78 -0
  174. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +28 -463
  175. rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +147 -0
  176. rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +477 -0
  177. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +8 -58
  178. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +37 -25
  179. rasa/dialogue_understanding/patterns/domain_for_patterns.py +190 -0
  180. rasa/dialogue_understanding/processor/command_processor.py +3 -3
  181. rasa/dialogue_understanding/processor/command_processor_component.py +3 -3
  182. rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +17 -4
  183. rasa/dialogue_understanding/utils.py +68 -12
  184. rasa/dialogue_understanding_test/du_test_case.py +1 -1
  185. rasa/dialogue_understanding_test/du_test_runner.py +4 -22
  186. rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +2 -6
  187. rasa/e2e_test/e2e_test_runner.py +1 -1
  188. rasa/engine/constants.py +1 -1
  189. rasa/engine/recipes/default_recipe.py +26 -2
  190. rasa/engine/validation.py +3 -2
  191. rasa/hooks.py +2 -30
  192. rasa/keys +1 -0
  193. rasa/llm_fine_tuning/annotation_module.py +39 -9
  194. rasa/llm_fine_tuning/conversations.py +3 -0
  195. rasa/llm_fine_tuning/llm_data_preparation_module.py +66 -49
  196. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +4 -2
  197. rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +52 -44
  198. rasa/llm_fine_tuning/paraphrasing_module.py +10 -12
  199. rasa/llm_fine_tuning/storage.py +4 -4
  200. rasa/llm_fine_tuning/utils.py +63 -1
  201. rasa/model_manager/config.py +3 -1
  202. rasa/model_manager/model_api.py +89 -2
  203. rasa/model_manager/runner_service.py +8 -4
  204. rasa/model_manager/trainer_service.py +5 -4
  205. rasa/model_training.py +12 -3
  206. rasa/nlu/extractors/crf_entity_extractor.py +66 -16
  207. rasa/plugin.py +2 -12
  208. rasa/privacy/__init__.py +0 -0
  209. rasa/privacy/constants.py +83 -0
  210. rasa/privacy/event_broker_utils.py +77 -0
  211. rasa/privacy/privacy_config.py +281 -0
  212. rasa/privacy/privacy_config_schema.json +86 -0
  213. rasa/privacy/privacy_filter.py +340 -0
  214. rasa/privacy/privacy_manager.py +576 -0
  215. rasa/server.py +29 -4
  216. rasa/shared/constants.py +6 -0
  217. rasa/shared/core/constants.py +4 -3
  218. rasa/shared/core/domain.py +7 -0
  219. rasa/shared/core/events.py +99 -3
  220. rasa/shared/core/flows/flow.py +1 -2
  221. rasa/shared/core/flows/flows_yaml_schema.json +3 -0
  222. rasa/shared/core/flows/steps/collect.py +46 -2
  223. rasa/shared/core/slots.py +28 -0
  224. rasa/shared/exceptions.py +4 -0
  225. rasa/shared/providers/_configs/azure_openai_client_config.py +4 -0
  226. rasa/shared/providers/_configs/openai_client_config.py +4 -0
  227. rasa/shared/providers/embedding/_base_litellm_embedding_client.py +3 -0
  228. rasa/shared/providers/llm/_base_litellm_client.py +5 -2
  229. rasa/shared/utils/llm.py +161 -6
  230. rasa/shared/utils/yaml.py +32 -0
  231. rasa/studio/data_handler.py +3 -3
  232. rasa/studio/download/download.py +37 -60
  233. rasa/studio/download/flows.py +23 -31
  234. rasa/studio/link.py +200 -0
  235. rasa/studio/pull.py +94 -0
  236. rasa/studio/push.py +131 -0
  237. rasa/studio/upload.py +117 -67
  238. rasa/telemetry.py +84 -27
  239. rasa/tracing/config.py +4 -5
  240. rasa/tracing/constants.py +19 -1
  241. rasa/tracing/instrumentation/attribute_extractors.py +11 -3
  242. rasa/tracing/instrumentation/instrumentation.py +54 -3
  243. rasa/tracing/instrumentation/metrics.py +98 -15
  244. rasa/tracing/metric_instrument_provider.py +75 -3
  245. rasa/utils/common.py +1 -27
  246. rasa/utils/licensing.py +1 -2
  247. rasa/utils/log_utils.py +1 -45
  248. rasa/validator.py +2 -8
  249. rasa/version.py +1 -1
  250. {rasa_pro-3.13.0.dev5.dist-info → rasa_pro-3.13.0.dev8.dist-info}/METADATA +8 -9
  251. {rasa_pro-3.13.0.dev5.dist-info → rasa_pro-3.13.0.dev8.dist-info}/RECORD +254 -231
  252. rasa/anonymization/__init__.py +0 -2
  253. rasa/anonymization/anonymisation_rule_yaml_reader.py +0 -91
  254. rasa/anonymization/anonymization_pipeline.py +0 -286
  255. rasa/anonymization/anonymization_rule_executor.py +0 -266
  256. rasa/anonymization/anonymization_rule_orchestrator.py +0 -119
  257. rasa/anonymization/schemas/config.yml +0 -47
  258. rasa/anonymization/utils.py +0 -118
  259. rasa/core/channels/inspector/dist/assets/channel-dfa68278.js +0 -1
  260. rasa/core/channels/inspector/dist/assets/clone-edb7f119.js +0 -1
  261. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-65e7c670.js +0 -1
  262. rasa/core/channels/inspector/src/helpers/audiostream.ts +0 -191
  263. rasa/core/tracker_store.py +0 -1792
  264. {rasa_pro-3.13.0.dev5.dist-info → rasa_pro-3.13.0.dev8.dist-info}/NOTICE +0 -0
  265. {rasa_pro-3.13.0.dev5.dist-info → rasa_pro-3.13.0.dev8.dist-info}/WHEEL +0 -0
  266. {rasa_pro-3.13.0.dev5.dist-info → rasa_pro-3.13.0.dev8.dist-info}/entry_points.txt +0 -0
@@ -1,7 +1,8 @@
1
+ import dataclasses
1
2
  import importlib.resources
2
3
  import json
3
4
  import re
4
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Text
5
+ from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, Text
5
6
 
6
7
  import dotenv
7
8
  import structlog
@@ -9,6 +10,7 @@ from jinja2 import Template
9
10
  from pydantic import ValidationError
10
11
 
11
12
  import rasa.shared.utils.io
13
+ from rasa.core.available_endpoints import AvailableEndpoints
12
14
  from rasa.core.constants import (
13
15
  POLICY_MAX_HISTORY,
14
16
  POLICY_PRIORITY,
@@ -23,7 +25,6 @@ from rasa.core.information_retrieval import (
23
25
  )
24
26
  from rasa.core.information_retrieval.faiss import FAISS_Store
25
27
  from rasa.core.policies.policy import Policy, PolicyPrediction
26
- from rasa.core.utils import AvailableEndpoints
27
28
  from rasa.dialogue_understanding.generator.constants import (
28
29
  LLM_CONFIG_KEY,
29
30
  )
@@ -46,12 +47,17 @@ from rasa.graph_components.providers.forms_provider import Forms
46
47
  from rasa.graph_components.providers.responses_provider import Responses
47
48
  from rasa.shared.constants import (
48
49
  EMBEDDINGS_CONFIG_KEY,
50
+ MAX_COMPLETION_TOKENS_CONFIG_KEY,
51
+ MAX_RETRIES_CONFIG_KEY,
49
52
  MODEL_CONFIG_KEY,
50
53
  MODEL_GROUP_ID_CONFIG_KEY,
51
54
  MODEL_NAME_CONFIG_KEY,
52
55
  OPENAI_PROVIDER,
53
56
  PROMPT_CONFIG_KEY,
57
+ PROMPT_TEMPLATE_CONFIG_KEY,
54
58
  PROVIDER_CONFIG_KEY,
59
+ RASA_PATTERN_CANNOT_HANDLE_NO_RELEVANT_ANSWER,
60
+ TEMPERATURE_CONFIG_KEY,
55
61
  TIMEOUT_CONFIG_KEY,
56
62
  )
57
63
  from rasa.shared.core.constants import (
@@ -75,7 +81,6 @@ from rasa.shared.nlu.training_data.training_data import TrainingData
75
81
  from rasa.shared.providers.embedding._langchain_embedding_client_adapter import (
76
82
  _LangchainEmbeddingClientAdapter,
77
83
  )
78
- from rasa.shared.providers.llm.llm_client import LLMClient
79
84
  from rasa.shared.providers.llm.llm_response import LLMResponse, measure_llm_latency
80
85
  from rasa.shared.utils.cli import print_error_and_exit
81
86
  from rasa.shared.utils.constants import (
@@ -110,7 +115,7 @@ if TYPE_CHECKING:
110
115
 
111
116
  from rasa.utils.log_utils import log_llm
112
117
 
113
- logger = structlog.get_logger()
118
+ structlogger = structlog.get_logger()
114
119
 
115
120
  dotenv.load_dotenv("./.env")
116
121
 
@@ -121,6 +126,7 @@ VECTOR_STORE_THRESHOLD_PROPERTY = "threshold"
121
126
  TRACE_TOKENS_PROPERTY = "trace_prompt_tokens"
122
127
  CITATION_ENABLED_PROPERTY = "citation_enabled"
123
128
  USE_LLM_PROPERTY = "use_generative_llm"
129
+ CHECK_RELEVANCY_PROPERTY = "check_relevancy"
124
130
  MAX_MESSAGES_IN_QUERY_KEY = "max_messages_in_query"
125
131
 
126
132
  DEFAULT_VECTOR_STORE_TYPE = "faiss"
@@ -131,18 +137,22 @@ DEFAULT_VECTOR_STORE = {
131
137
  VECTOR_STORE_THRESHOLD_PROPERTY: DEFAULT_VECTOR_STORE_THRESHOLD,
132
138
  }
133
139
 
140
+ DEFAULT_CHECK_RELEVANCY_PROPERTY = False
141
+ DEFAULT_USE_LLM_PROPERTY = True
142
+ DEFAULT_CITATION_ENABLED_PROPERTY = False
143
+
134
144
  DEFAULT_LLM_CONFIG = {
135
145
  PROVIDER_CONFIG_KEY: OPENAI_PROVIDER,
136
146
  MODEL_CONFIG_KEY: DEFAULT_OPENAI_CHAT_MODEL_NAME,
137
147
  TIMEOUT_CONFIG_KEY: 10,
138
- "temperature": 0.0,
139
- "max_tokens": 256,
140
- "max_retries": 1,
148
+ TEMPERATURE_CONFIG_KEY: 0.0,
149
+ MAX_COMPLETION_TOKENS_CONFIG_KEY: 256,
150
+ MAX_RETRIES_CONFIG_KEY: 1,
141
151
  }
142
152
 
143
153
  DEFAULT_EMBEDDINGS_CONFIG = {
144
154
  PROVIDER_CONFIG_KEY: OPENAI_PROVIDER,
145
- "model": DEFAULT_OPENAI_EMBEDDING_MODEL_NAME,
155
+ MODEL_CONFIG_KEY: DEFAULT_OPENAI_EMBEDDING_MODEL_NAME,
146
156
  }
147
157
 
148
158
  ENTERPRISE_SEARCH_PROMPT_FILE_NAME = "enterprise_search_policy_prompt.jinja2"
@@ -159,6 +169,18 @@ DEFAULT_ENTERPRISE_SEARCH_PROMPT_WITH_CITATION_TEMPLATE = importlib.resources.re
159
169
  "rasa.core.policies", "enterprise_search_prompt_with_citation_template.jinja2"
160
170
  )
161
171
 
172
+ DEFAULT_ENTERPRISE_SEARCH_PROMPT_WITH_RELEVANCY_CHECK_AND_CITATION_TEMPLATE = (
173
+ importlib.resources.read_text(
174
+ "rasa.core.policies",
175
+ "enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2",
176
+ )
177
+ )
178
+
179
+ # TODO: Update this pattern once the experiments are done
180
+ _ENTERPRISE_SEARCH_ANSWER_NOT_RELEVANT_PATTERN = re.compile(
181
+ r"\[NO_RELEVANT_ANSWER_FOUND\]"
182
+ )
183
+
162
184
 
163
185
  class VectorStoreConnectionError(RasaException):
164
186
  """Exception raised for errors in connecting to the vector store."""
@@ -168,6 +190,12 @@ class VectorStoreConfigurationError(RasaException):
168
190
  """Exception raised for errors in vector store configuration."""
169
191
 
170
192
 
193
+ @dataclasses.dataclass
194
+ class _RelevancyCheckResponse:
195
+ answer: Optional[str]
196
+ relevant: bool
197
+
198
+
171
199
  @DefaultV1Recipe.register(
172
200
  DefaultV1Recipe.ComponentType.POLICY_WITH_END_TO_END_SUPPORT, is_trainable=True
173
201
  )
@@ -217,6 +245,11 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
217
245
  """Constructs a new Policy object."""
218
246
  super().__init__(config, model_storage, resource, execution_context, featurizer)
219
247
 
248
+ # Check for deprecated keys and issue a warning if those are used
249
+ self._check_config_keys_and_warn_if_deprecated()
250
+ # Check for mutual exclusivity of extractive and generative search
251
+ self._check_and_warn_mutual_exclusivity_of_extractive_and_generative_search()
252
+
220
253
  # Resolve LLM config
221
254
  self.config[LLM_CONFIG_KEY] = resolve_model_client_config(
222
255
  self.config.get(LLM_CONFIG_KEY), EnterpriseSearchPolicy.__name__
@@ -231,6 +264,9 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
231
264
  self.vector_store_config = self.config.get(
232
265
  VECTOR_STORE_PROPERTY, DEFAULT_VECTOR_STORE
233
266
  )
267
+ self.vector_search_threshold = self.vector_store_config.get(
268
+ VECTOR_STORE_THRESHOLD_PROPERTY, DEFAULT_VECTOR_STORE_THRESHOLD
269
+ )
234
270
 
235
271
  # Embeddings configuration for encoding the search query
236
272
  self.embeddings_config = (
@@ -246,30 +282,77 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
246
282
  # Maximum number of messages to include in the search query
247
283
  self.max_messages_in_query = self.config.get(MAX_MESSAGES_IN_QUERY_KEY, 2)
248
284
 
249
- # boolean to enable/disable tracing of prompt tokens
285
+ # Boolean to enable/disable tracing of prompt tokens
250
286
  self.trace_prompt_tokens = self.config.get(TRACE_TOKENS_PROPERTY, False)
251
287
 
252
- # boolean to enable/disable the use of LLM for response generation
253
- self.use_llm = self.config.get(USE_LLM_PROPERTY, True)
288
+ # Boolean to enable/disable the use of LLM for response generation
289
+ self.use_llm = self.config.get(USE_LLM_PROPERTY, DEFAULT_USE_LLM_PROPERTY)
254
290
 
255
- # boolean to enable/disable citation generation
256
- self.citation_enabled = self.config.get(CITATION_ENABLED_PROPERTY, False)
291
+ # Boolean to enable/disable citation generation. This flag enables citation
292
+ # logic, but it only takes effect if `use_llm` is True.
293
+ self.citation_enabled = self.config.get(
294
+ CITATION_ENABLED_PROPERTY, DEFAULT_CITATION_ENABLED_PROPERTY
295
+ )
257
296
 
258
- self.prompt_template = prompt_template or get_prompt_template(
259
- self.config.get(PROMPT_CONFIG_KEY),
260
- DEFAULT_ENTERPRISE_SEARCH_PROMPT_TEMPLATE,
261
- log_source_component=EnterpriseSearchPolicy.__name__,
262
- log_source_method=LOG_COMPONENT_SOURCE_METHOD_INIT,
297
+ # Boolean to enable/disable the use of relevancy check alongside answer
298
+ # generation. This flag enables citation logic, but it only takes effect if
299
+ # `use_llm` is True.
300
+ self.relevancy_check_enabled = self.config.get(
301
+ CHECK_RELEVANCY_PROPERTY, DEFAULT_CHECK_RELEVANCY_PROPERTY
263
302
  )
264
- self.citation_prompt_template = get_prompt_template(
265
- self.config.get(PROMPT_CONFIG_KEY),
266
- DEFAULT_ENTERPRISE_SEARCH_PROMPT_WITH_CITATION_TEMPLATE,
267
- log_source_component=EnterpriseSearchPolicy.__name__,
268
- log_source_method=LOG_COMPONENT_SOURCE_METHOD_INIT,
303
+
304
+ # Resolve the prompt template. The prompt will only be used if the 'use_llm' is
305
+ # set to True.
306
+ self.prompt_template = prompt_template or self._resolve_prompt_template(
307
+ self.config, LOG_COMPONENT_SOURCE_METHOD_INIT
269
308
  )
270
- # If citation is enabled, use the citation prompt template
271
- if self.citation_enabled:
272
- self.prompt_template = self.citation_prompt_template
309
+
310
+ def _check_config_keys_and_warn_if_deprecated(self) -> None:
311
+ """Checks and warns about deprecated config parameters."""
312
+ if (
313
+ PROMPT_CONFIG_KEY in self.config
314
+ and PROMPT_TEMPLATE_CONFIG_KEY in self.config
315
+ ):
316
+ structlogger.warning(
317
+ "enterprise_search_policy.init"
318
+ ".both_deprecated_and_non_deprecated_config_keys_used_at_the_same_time",
319
+ event_info=(
320
+ f"Both '{PROMPT_CONFIG_KEY}' and '{PROMPT_TEMPLATE_CONFIG_KEY}' "
321
+ f"are present in the config. '{PROMPT_CONFIG_KEY}' will be ignored "
322
+ f"in favor of {PROMPT_TEMPLATE_CONFIG_KEY}."
323
+ ),
324
+ )
325
+
326
+ # 'prompt' config key is deprecated in favor of 'prompt_template'
327
+ if PROMPT_CONFIG_KEY in self.config:
328
+ structlogger.warning(
329
+ "enterprise_search_policy.init.deprecated_config_key",
330
+ event_info=(
331
+ f"The config parameter '{PROMPT_CONFIG_KEY}' is deprecated "
332
+ "and will be removed in Rasa 4.0.0. "
333
+ f"Please use the config parameter '{PROMPT_TEMPLATE_CONFIG_KEY}'"
334
+ f"instead. "
335
+ ),
336
+ )
337
+
338
+ def _check_and_warn_mutual_exclusivity_of_extractive_and_generative_search(
339
+ self,
340
+ ) -> None:
341
+ if self.config.get(
342
+ CHECK_RELEVANCY_PROPERTY, DEFAULT_CHECK_RELEVANCY_PROPERTY
343
+ ) and not self.config.get(USE_LLM_PROPERTY, DEFAULT_USE_LLM_PROPERTY):
344
+ structlogger.warning(
345
+ "enterprise_search_policy.init"
346
+ ".relevancy_check_enabled_with_disabled_generative_search",
347
+ event_info=(
348
+ f"The config parameter '{CHECK_RELEVANCY_PROPERTY}' is set to"
349
+ f"'True', but the generative search is disabled (config"
350
+ f"parameter '{USE_LLM_PROPERTY}' is set to 'False'). As a result, "
351
+ "the relevancy check for the generative search will be disabled. "
352
+ f"To use this check, set the config parameter '{USE_LLM_PROPERTY}' "
353
+ f"to `True`."
354
+ ),
355
+ )
273
356
 
274
357
  @classmethod
275
358
  def _create_plain_embedder(cls, config: Dict[Text, Any]) -> "Embeddings":
@@ -363,7 +446,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
363
446
  try:
364
447
  embeddings = self._create_plain_embedder(self.config)
365
448
  except (ValidationError, Exception) as e:
366
- logger.error(
449
+ structlogger.error(
367
450
  "enterprise_search_policy.train.embedder_instantiation_failed",
368
451
  message="Unable to instantiate the embedding client.",
369
452
  error=e,
@@ -374,7 +457,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
374
457
  )
375
458
 
376
459
  if store_type == DEFAULT_VECTOR_STORE_TYPE:
377
- logger.info("enterprise_search_policy.train.faiss")
460
+ structlogger.info("enterprise_search_policy.train.faiss")
378
461
  with self._model_storage.write_to(self._resource) as path:
379
462
  self.vector_store = FAISS_Store(
380
463
  docs_folder=self.vector_store_config.get(SOURCE_PROPERTY),
@@ -383,7 +466,9 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
383
466
  create_index=True,
384
467
  )
385
468
  else:
386
- logger.info("enterprise_search_policy.train.custom", store_type=store_type)
469
+ structlogger.info(
470
+ "enterprise_search_policy.train.custom", store_type=store_type
471
+ )
387
472
 
388
473
  # telemetry call to track training completion
389
474
  track_enterprise_search_policy_train_completed(
@@ -399,6 +484,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
399
484
  or self.llm_config.get(MODEL_NAME_CONFIG_KEY),
400
485
  llm_model_group_id=self.llm_config.get(MODEL_GROUP_ID_CONFIG_KEY),
401
486
  citation_enabled=self.citation_enabled,
487
+ relevancy_check_enabled=self.relevancy_check_enabled,
402
488
  )
403
489
  self.persist()
404
490
  return self._resource
@@ -451,7 +537,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
451
537
  config = endpoints.vector_store if endpoints else None
452
538
  store_type = self.vector_store_config.get(VECTOR_STORE_TYPE_PROPERTY)
453
539
  if config is None and store_type != DEFAULT_VECTOR_STORE_TYPE:
454
- logger.error(
540
+ structlogger.error(
455
541
  "enterprise_search_policy._connect_vector_store_or_raise.no_config"
456
542
  )
457
543
  raise VectorStoreConfigurationError(
@@ -461,7 +547,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
461
547
  try:
462
548
  self.vector_store.connect(config) # type: ignore
463
549
  except Exception as e:
464
- logger.error(
550
+ structlogger.error(
465
551
  "enterprise_search_policy._connect_vector_store_or_raise.connect_error",
466
552
  error=e,
467
553
  config=config,
@@ -487,14 +573,14 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
487
573
  transcript.append(sanitize_message_for_prompt(event.text))
488
574
 
489
575
  search_query = " ".join(transcript[-history:][::-1])
490
- logger.debug("search_query", search_query=search_query)
576
+ structlogger.debug("search_query", search_query=search_query)
491
577
  return search_query
492
578
 
493
579
  async def predict_action_probabilities( # type: ignore[override]
494
580
  self,
495
581
  tracker: DialogueStateTracker,
496
582
  domain: Domain,
497
- endpoints: Optional[AvailableEndpoints],
583
+ endpoints: Optional[AvailableEndpoints] = None,
498
584
  rule_only_data: Optional[Dict[Text, Any]] = None,
499
585
  **kwargs: Any,
500
586
  ) -> PolicyPrediction:
@@ -513,23 +599,20 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
513
599
  The prediction.
514
600
  """
515
601
  logger_key = "enterprise_search_policy.predict_action_probabilities"
516
- vector_search_threshold = self.vector_store_config.get(
517
- VECTOR_STORE_THRESHOLD_PROPERTY, DEFAULT_VECTOR_STORE_THRESHOLD
518
- )
519
- llm = llm_factory(self.config.get(LLM_CONFIG_KEY), DEFAULT_LLM_CONFIG)
602
+
520
603
  if not self.supports_current_stack_frame(
521
604
  tracker, False, False
522
605
  ) or self.should_abstain_in_coexistence(tracker, True):
523
606
  return self._prediction(self._default_predictions(domain))
524
607
 
525
608
  if not self.vector_store:
526
- logger.error(f"{logger_key}.no_vector_store")
609
+ structlogger.error(f"{logger_key}.no_vector_store")
527
610
  return self._create_prediction_internal_error(domain, tracker)
528
611
 
529
612
  try:
530
613
  self._connect_vector_store_or_raise(endpoints)
531
614
  except (VectorStoreConfigurationError, VectorStoreConnectionError) as e:
532
- logger.error(f"{logger_key}.connection_error", error=e)
615
+ structlogger.error(f"{logger_key}.connection_error", error=e)
533
616
  return self._create_prediction_internal_error(domain, tracker)
534
617
 
535
618
  search_query = self._prepare_search_query(
@@ -541,20 +624,19 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
541
624
  documents = await self.vector_store.search(
542
625
  query=search_query,
543
626
  tracker_state=tracker_state,
544
- threshold=vector_search_threshold,
627
+ threshold=self.vector_search_threshold,
545
628
  )
546
629
  except InformationRetrievalException as e:
547
- logger.error(f"{logger_key}.search_error", error=e)
630
+ structlogger.error(f"{logger_key}.search_error", error=e)
548
631
  return self._create_prediction_internal_error(domain, tracker)
549
632
 
550
633
  if not documents.results:
551
- logger.info(f"{logger_key}.no_documents")
634
+ structlogger.info(f"{logger_key}.no_documents")
552
635
  return self._create_prediction_cannot_handle(domain, tracker)
553
636
 
554
637
  if self.use_llm:
555
638
  prompt = self._render_prompt(tracker, documents.results)
556
- llm_response = await self._generate_llm_answer(llm, prompt)
557
- llm_response = LLMResponse.ensure_llm_response(llm_response)
639
+ llm_response = await self._invoke_llm(prompt)
558
640
 
559
641
  self._add_prompt_and_llm_response_to_latest_message(
560
642
  tracker=tracker,
@@ -564,24 +646,38 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
564
646
  )
565
647
 
566
648
  if llm_response is None or not llm_response.choices:
567
- logger.debug(f"{logger_key}.no_llm_response")
649
+ structlogger.debug(f"{logger_key}.no_llm_response")
568
650
  response = None
569
651
  else:
570
652
  llm_answer = llm_response.choices[0]
571
653
 
654
+ if self.relevancy_check_enabled:
655
+ relevancy_response = self._parse_llm_relevancy_check_response(
656
+ llm_answer
657
+ )
658
+ if not relevancy_response.relevant:
659
+ structlogger.debug(f"{logger_key}.answer_not_relevant")
660
+ return self._create_prediction_cannot_handle(
661
+ domain,
662
+ tracker,
663
+ RASA_PATTERN_CANNOT_HANDLE_NO_RELEVANT_ANSWER,
664
+ )
665
+
572
666
  if self.citation_enabled:
573
667
  llm_answer = self.post_process_citations(llm_answer)
574
668
 
575
- logger.debug(f"{logger_key}.llm_answer", llm_answer=llm_answer)
669
+ structlogger.debug(
670
+ f"{logger_key}.llm_answer", prompt=prompt, llm_answer=llm_answer
671
+ )
576
672
  response = llm_answer
577
673
  else:
578
674
  response = documents.results[0].metadata.get("answer", None)
579
675
  if not response:
580
- logger.error(
676
+ structlogger.error(
581
677
  f"{logger_key}.answer_key_missing_in_metadata",
582
678
  search_results=documents.results,
583
679
  )
584
- logger.debug(
680
+ structlogger.debug(
585
681
  "enterprise_search_policy.predict_action_probabilities.no_llm",
586
682
  search_results=documents,
587
683
  )
@@ -613,6 +709,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
613
709
  or self.llm_config.get(MODEL_NAME_CONFIG_KEY),
614
710
  llm_model_group_id=self.llm_config.get(MODEL_GROUP_ID_CONFIG_KEY),
615
711
  citation_enabled=self.citation_enabled,
712
+ relevancy_check_enabled=self.relevancy_check_enabled,
616
713
  )
617
714
  return self._create_prediction(
618
715
  domain=domain, tracker=tracker, action_metadata=action_metadata
@@ -636,11 +733,12 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
636
733
  ),
637
734
  "docs": documents,
638
735
  "slots": self._prepare_slots_for_template(tracker),
736
+ "check_relevancy": self.relevancy_check_enabled,
639
737
  "citation_enabled": self.citation_enabled,
640
738
  }
641
739
  prompt = Template(self.prompt_template).render(**inputs)
642
740
  log_llm(
643
- logger=logger,
741
+ logger=structlogger,
644
742
  log_module="EnterpriseSearchPolicy",
645
743
  log_event="enterprise_search_policy._render_prompt.prompt_rendered",
646
744
  prompt=prompt,
@@ -648,9 +746,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
648
746
  return prompt
649
747
 
650
748
  @measure_llm_latency
651
- async def _generate_llm_answer(
652
- self, llm: LLMClient, prompt: Text
653
- ) -> Optional[LLMResponse]:
749
+ async def _invoke_llm(self, prompt: Text) -> Optional[LLMResponse]:
654
750
  """Fetches an LLM completion for the provided prompt.
655
751
 
656
752
  Args:
@@ -660,17 +756,32 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
660
756
  Returns:
661
757
  An LLMResponse object, or None if the call fails.
662
758
  """
759
+ llm = llm_factory(self.config.get(LLM_CONFIG_KEY), DEFAULT_LLM_CONFIG)
663
760
  try:
664
- return await llm.acompletion(prompt)
761
+ response = await llm.acompletion(prompt)
762
+ return LLMResponse.ensure_llm_response(response)
665
763
  except Exception as e:
666
764
  # unfortunately, langchain does not wrap LLM exceptions which means
667
765
  # we have to catch all exceptions here
668
- logger.error(
766
+ structlogger.error(
669
767
  "enterprise_search_policy._generate_llm_answer.llm_error",
670
768
  error=e,
671
769
  )
672
770
  return None
673
771
 
772
+ def _parse_llm_relevancy_check_response(
773
+ self, llm_answer: str
774
+ ) -> _RelevancyCheckResponse:
775
+ """Checks if the LLM response is relevant by parsing it."""
776
+ answer_relevant = not _ENTERPRISE_SEARCH_ANSWER_NOT_RELEVANT_PATTERN.search(
777
+ llm_answer
778
+ )
779
+ structlogger.debug("")
780
+ return _RelevancyCheckResponse(
781
+ answer=llm_answer if answer_relevant else None,
782
+ relevant=answer_relevant,
783
+ )
784
+
674
785
  def _create_prediction(
675
786
  self,
676
787
  domain: Domain,
@@ -705,10 +816,18 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
705
816
  )
706
817
 
707
818
  def _create_prediction_cannot_handle(
708
- self, domain: Domain, tracker: DialogueStateTracker
819
+ self,
820
+ domain: Domain,
821
+ tracker: DialogueStateTracker,
822
+ reason: Optional[str] = None,
709
823
  ) -> PolicyPrediction:
824
+ cannot_handle_stack_frame = (
825
+ CannotHandlePatternFlowStackFrame(reason=reason)
826
+ if reason is not None
827
+ else CannotHandlePatternFlowStackFrame()
828
+ )
710
829
  return self._create_prediction_for_pattern(
711
- domain, tracker, CannotHandlePatternFlowStackFrame()
830
+ domain, tracker, cannot_handle_stack_frame
712
831
  )
713
832
 
714
833
  def _create_prediction_for_pattern(
@@ -777,7 +896,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
777
896
  path / ENTERPRISE_SEARCH_PROMPT_FILE_NAME
778
897
  )
779
898
  except (FileNotFoundError, FileIOException) as e:
780
- logger.warning(
899
+ structlogger.warning(
781
900
  "enterprise_search_policy.load.failed", error=e, resource=resource.name
782
901
  )
783
902
 
@@ -787,7 +906,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
787
906
 
788
907
  embeddings = cls._create_plain_embedder(config)
789
908
 
790
- logger.info("enterprise_search_policy.load", config=config)
909
+ structlogger.info("enterprise_search_policy.load", config=config)
791
910
  if store_type == DEFAULT_VECTOR_STORE_TYPE:
792
911
  # if a vector store is not specified,
793
912
  # default to using FAISS with the index stored in the model
@@ -846,15 +965,12 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
846
965
  @classmethod
847
966
  def fingerprint_addon(cls, config: Dict[str, Any]) -> Optional[str]:
848
967
  """Add a fingerprint of enterprise search policy for the graph."""
849
- local_knowledge_data = cls._get_local_knowledge_data(config)
850
-
851
- prompt_template = get_prompt_template(
852
- config.get(PROMPT_CONFIG_KEY),
853
- DEFAULT_ENTERPRISE_SEARCH_PROMPT_TEMPLATE,
854
- log_source_component=EnterpriseSearchPolicy.__name__,
855
- log_source_method=LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON,
968
+ prompt_template = cls._resolve_prompt_template(
969
+ config, LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON
856
970
  )
857
971
 
972
+ local_knowledge_data = cls._get_local_knowledge_data(config)
973
+
858
974
  llm_config = resolve_model_client_config(
859
975
  config.get(LLM_CONFIG_KEY), EnterpriseSearchPolicy.__name__
860
976
  )
@@ -878,7 +994,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
878
994
  Returns:
879
995
  The post-processed LLM answer.
880
996
  """
881
- logger.debug(
997
+ structlogger.debug(
882
998
  "enterprise_search_policy.post_process_citations", llm_answer=llm_answer
883
999
  )
884
1000
 
@@ -979,3 +1095,111 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
979
1095
  log_source_method,
980
1096
  EnterpriseSearchPolicy.__name__,
981
1097
  )
1098
+
1099
+ @classmethod
1100
+ def get_system_default_prompt_based_on_config(cls, config: Dict[str, Any]) -> str:
1101
+ """
1102
+ Resolves the default prompt template for Enterprise Search Policy based on
1103
+ the component's configuration.
1104
+
1105
+ - The old prompt is selected when both citation and relevancy check are either
1106
+ disabled or not set in the configuration.
1107
+ - The citation prompt is used when citation is enabled and relevancy check is
1108
+ either disabled or not set in the configuration.
1109
+ - The relevancy check prompt is only used when relevancy check is enabled.
1110
+
1111
+ Args:
1112
+ config: The component's configuration.
1113
+
1114
+ Returns:
1115
+ The resolved jinja prompt template as a string.
1116
+ """
1117
+
1118
+ # Get the feature flags
1119
+ citation_enabled = config.get(
1120
+ CITATION_ENABLED_PROPERTY, DEFAULT_CITATION_ENABLED_PROPERTY
1121
+ )
1122
+ relevancy_check_enabled = config.get(
1123
+ CHECK_RELEVANCY_PROPERTY, DEFAULT_CHECK_RELEVANCY_PROPERTY
1124
+ )
1125
+
1126
+ # Based on the enabled features (citation, relevancy check) fetch the
1127
+ # appropriate default prompt
1128
+ default_prompt = cls._select_default_prompt_template_based_on_features(
1129
+ relevancy_check_enabled, citation_enabled
1130
+ )
1131
+
1132
+ return default_prompt
1133
+
1134
+ @classmethod
1135
+ def _resolve_prompt_template(
1136
+ cls,
1137
+ config: dict,
1138
+ log_source_method: Literal["init", "fingerprint"],
1139
+ ) -> str:
1140
+ """
1141
+ Resolves the prompt template to use for the Enterprise Search Policy's
1142
+ generative search.
1143
+
1144
+ Checks if a custom template is provided via component's configuration. If not,
1145
+ it selects the appropriate default template based on the enabled features
1146
+ (citation and relevancy check).
1147
+
1148
+ Args:
1149
+ config: The component's configuration.
1150
+ log_source_method: The name of the method or function emitting the log for
1151
+ better traceability.
1152
+ Returns:
1153
+ The resolved jinja prompt template as a string.
1154
+ """
1155
+
1156
+ # Read the template path from the configuration if available.
1157
+ # The deprecated 'prompt' has a lower priority compared to 'prompt_template'
1158
+ config_defined_prompt = (
1159
+ config.get(PROMPT_TEMPLATE_CONFIG_KEY)
1160
+ or config.get(PROMPT_CONFIG_KEY)
1161
+ or None
1162
+ )
1163
+ # Select the default prompt based on the features set in the config.
1164
+ default_prompt = cls.get_system_default_prompt_based_on_config(config)
1165
+
1166
+ return get_prompt_template(
1167
+ config_defined_prompt,
1168
+ default_prompt,
1169
+ log_source_component=EnterpriseSearchPolicy.__name__,
1170
+ log_source_method=log_source_method,
1171
+ )
1172
+
1173
+ @classmethod
1174
+ def _select_default_prompt_template_based_on_features(
1175
+ cls,
1176
+ relevancy_check_enabled: bool,
1177
+ citation_enabled: bool,
1178
+ ) -> str:
1179
+ """
1180
+ Returns the appropriate default prompt template based on the feature flags.
1181
+
1182
+ The selection follows this priority:
1183
+ 1. If relevancy check is enabled, return the prompt that includes both relevancy
1184
+ and citation blocks.
1185
+ 2. If only citation is enabled, return the prompt with citation blocks.
1186
+ 3. Otherwise, fall back to the legacy default prompt template.
1187
+
1188
+ Args:
1189
+ relevancy_check_enabled: Whether the LLM-generated answer should undergo
1190
+ relevancy evaluation.
1191
+ citation_enabled: Whether citations should be included in the generated
1192
+ answer.
1193
+
1194
+ Returns:
1195
+ The default prompt template corresponding to the enabled features.
1196
+ """
1197
+ if relevancy_check_enabled:
1198
+ # ES prompt that has relevancy check and citations blocks
1199
+ return DEFAULT_ENTERPRISE_SEARCH_PROMPT_WITH_RELEVANCY_CHECK_AND_CITATION_TEMPLATE # noqa: E501
1200
+ elif citation_enabled:
1201
+ # ES prompt with citation's block - backward compatibility
1202
+ return DEFAULT_ENTERPRISE_SEARCH_PROMPT_WITH_CITATION_TEMPLATE
1203
+ else:
1204
+ # Legacy ES prompt - backward compatibility
1205
+ return DEFAULT_ENTERPRISE_SEARCH_PROMPT_TEMPLATE