rasa-pro 3.13.0.dev20250613__py3-none-any.whl → 3.13.0rc2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rasa-pro might be problematic. Click here for more details.
- rasa/cli/e2e_test.py +0 -7
- rasa/cli/export.py +2 -0
- rasa/cli/project_templates/tutorial/config.yml +1 -1
- rasa/cli/project_templates/tutorial/endpoints.yml +1 -1
- rasa/cli/studio/download.py +1 -23
- rasa/cli/studio/link.py +0 -17
- rasa/cli/studio/pull.py +3 -2
- rasa/cli/studio/push.py +1 -1
- rasa/cli/studio/train.py +1 -5
- rasa/cli/studio/upload.py +1 -1
- rasa/core/agent.py +6 -0
- rasa/core/channels/__init__.py +3 -0
- rasa/core/channels/development_inspector.py +1 -1
- rasa/core/channels/facebook.py +1 -4
- rasa/core/channels/inspector/README.md +3 -3
- rasa/core/channels/inspector/dist/assets/{arc-c4b064fc.js → arc-371401b1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-215b5026.js → blockDiagram-38ab4fdb-3f126156.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-2b54a0a3.js → c4Diagram-3d4e48cf-12f22eb7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-f1efda17.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-daacea5f.js → classDiagram-70f12bd4-03b1d386.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-930d4dc2.js → classDiagram-v2-f2320105-84f69d63.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-fdf164e2.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-83c206ba.js → createText-2e5e7dd3-ca47fd38.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-b0eb01d0.js → edges-e0da2a9e-f837ca8a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-17586500.js → erDiagram-9861fffd-8717ac54.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-be2a1776.js → flowDb-956e92f1-94f38b83.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-c2120ebd.js → flowDiagram-66a62f08-b616f9fb.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-7d7a1629.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-a6ab5c48.js → flowchart-elk-definition-4a651766-f5d24bb8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-ef613457.js → ganttDiagram-c361ad54-b43ba8d9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-d59185b3.js → gitGraphDiagram-72cf32ee-c3aafaa5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-0f155405.js → graph-0d0a2c10.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-d5f1d1b7.js → index-3862675e-58ea0305.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-47737d3a.js → index-cce6f8a1.js} +3 -3
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-b07d141f.js → infoDiagram-f8f76790-b8f60461.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-1936d429.js → journeyDiagram-49397b02-95be5545.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-dde8d0f3.js → layout-da885b9b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-0c2c7ee0.js → line-f1c817d3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-35dd89a4.js → linear-d42801e6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-56192851.js → mindmap-definition-fc14e90a-a38923a6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-fc21ed78.js → pieDiagram-8a3498a8-ca6e71e9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-25e98518.js → quadrantDiagram-120e2f19-b290dae9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-546ff1f5.js → requirementDiagram-deff3bca-03f02ceb.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-02d8b82d.js → sankeyDiagram-04a897e0-c49eee40.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-3ca5a92e.js → sequenceDiagram-704730f1-b2cd6a3d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-128ea07c.js → stateDiagram-587899a1-e53a2028.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-95f290af.js → stateDiagram-v2-d93cdb3a-e1982a03.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-4984898a.js → styles-6aaf32cf-d0226ca5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-1bf266ba.js → styles-9a916d00-0e21dc00.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-60521c63.js → styles-c10674c1-9588494e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-a25b6e12.js → svgDrawCommon-08f97a94-be478d4f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-0fc086bf.js → timeline-definition-85554ec2-74631749.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-44ee592e.js → xychartDiagram-e933f94c-a043552f.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +1 -1
- rasa/core/channels/socketio.py +56 -41
- rasa/core/channels/studio_chat.py +311 -8
- rasa/core/channels/voice_ready/audiocodes.py +1 -1
- rasa/core/channels/voice_ready/jambonz.py +5 -6
- rasa/core/channels/voice_ready/twilio_voice.py +13 -12
- rasa/core/channels/voice_ready/utils.py +22 -0
- rasa/core/channels/voice_stream/asr/azure.py +9 -0
- rasa/core/channels/voice_stream/audiocodes.py +5 -11
- rasa/core/channels/voice_stream/browser_audio.py +1 -1
- rasa/core/channels/voice_stream/genesys.py +35 -16
- rasa/core/channels/voice_stream/jambonz.py +232 -0
- rasa/core/channels/voice_stream/tts/__init__.py +8 -0
- rasa/core/channels/voice_stream/twilio_media_streams.py +12 -7
- rasa/core/channels/voice_stream/voice_channel.py +53 -15
- rasa/core/exporter.py +36 -0
- rasa/core/information_retrieval/faiss.py +18 -11
- rasa/core/information_retrieval/ingestion/faq_parser.py +158 -0
- rasa/core/nlg/contextual_response_rephraser.py +10 -1
- rasa/core/policies/enterprise_search_policy.py +189 -263
- rasa/core/policies/enterprise_search_policy_config.py +241 -0
- rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2 +6 -5
- rasa/core/policies/intentless_policy.py +47 -10
- rasa/core/processor.py +6 -0
- rasa/core/utils.py +11 -2
- rasa/dialogue_understanding/coexistence/llm_based_router.py +13 -11
- rasa/dialogue_understanding/commands/__init__.py +4 -0
- rasa/dialogue_understanding/commands/cancel_flow_command.py +4 -2
- rasa/dialogue_understanding/commands/clarify_command.py +2 -2
- rasa/dialogue_understanding/commands/correct_slots_command.py +5 -6
- rasa/dialogue_understanding/commands/error_command.py +1 -1
- rasa/dialogue_understanding/commands/human_handoff_command.py +1 -3
- rasa/dialogue_understanding/commands/set_slot_command.py +4 -4
- rasa/dialogue_understanding/commands/skip_question_command.py +1 -3
- rasa/dialogue_understanding/commands/start_flow_command.py +3 -3
- rasa/dialogue_understanding/generator/command_generator.py +11 -1
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +3 -2
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +2 -2
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_template.jinja2 +0 -2
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +1 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +1 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +79 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +1 -0
- rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +2 -2
- rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +2 -18
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +17 -11
- rasa/dialogue_understanding/patterns/cancel.py +1 -2
- rasa/dialogue_understanding/patterns/clarify.py +1 -1
- rasa/dialogue_understanding/patterns/correction.py +2 -2
- rasa/dialogue_understanding/processor/command_processor.py +11 -12
- rasa/dialogue_understanding/stack/utils.py +3 -1
- rasa/e2e_test/constants.py +1 -1
- rasa/e2e_test/e2e_test_coverage_report.py +1 -1
- rasa/engine/graph.py +2 -2
- rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +2 -6
- rasa/model_manager/runner_service.py +20 -4
- rasa/model_manager/trainer_service.py +6 -0
- rasa/privacy/privacy_manager.py +26 -11
- rasa/shared/constants.py +14 -0
- rasa/shared/core/command_payload_reader.py +1 -5
- rasa/shared/core/events.py +1 -3
- rasa/shared/core/flows/constants.py +2 -0
- rasa/shared/core/flows/flow.py +126 -12
- rasa/shared/core/flows/flows_list.py +18 -1
- rasa/shared/core/flows/steps/link.py +7 -2
- rasa/shared/core/flows/validation.py +25 -5
- rasa/shared/core/training_data/story_reader/yaml_story_reader.py +1 -4
- rasa/shared/providers/_configs/azure_openai_client_config.py +2 -2
- rasa/shared/providers/_configs/default_litellm_client_config.py +1 -1
- rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +1 -1
- rasa/shared/providers/_configs/openai_client_config.py +1 -1
- rasa/shared/providers/_configs/rasa_llm_client_config.py +1 -1
- rasa/shared/providers/_configs/self_hosted_llm_client_config.py +1 -1
- rasa/shared/providers/_configs/utils.py +0 -99
- rasa/shared/utils/common.py +1 -1
- rasa/shared/utils/configs.py +110 -0
- rasa/shared/utils/constants.py +0 -3
- rasa/shared/utils/llm.py +123 -8
- rasa/shared/utils/pykwalify_extensions.py +0 -9
- rasa/studio/constants.py +1 -0
- rasa/studio/data_handler.py +30 -9
- rasa/studio/download.py +171 -0
- rasa/studio/link.py +13 -2
- rasa/studio/prompts.py +221 -0
- rasa/studio/pull/__init__.py +0 -0
- rasa/studio/{download/flows.py → pull/data.py} +2 -131
- rasa/studio/{download → pull}/domains.py +1 -1
- rasa/studio/pull/pull.py +239 -0
- rasa/studio/push.py +7 -0
- rasa/studio/train.py +1 -1
- rasa/studio/upload.py +61 -5
- rasa/studio/utils.py +33 -0
- rasa/tracing/instrumentation/attribute_extractors.py +21 -7
- rasa/utils/common.py +11 -0
- rasa/version.py +1 -1
- {rasa_pro-3.13.0.dev20250613.dist-info → rasa_pro-3.13.0rc2.dist-info}/METADATA +4 -4
- {rasa_pro-3.13.0.dev20250613.dist-info → rasa_pro-3.13.0rc2.dist-info}/RECORD +155 -147
- rasa/core/channels/inspector/dist/assets/channel-3730f5fd.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-e847561e.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-efbbfe00.js +0 -1
- rasa/studio/download/download.py +0 -416
- rasa/studio/pull.py +0 -94
- /rasa/{studio/download → core/information_retrieval/ingestion}/__init__.py +0 -0
- {rasa_pro-3.13.0.dev20250613.dist-info → rasa_pro-3.13.0rc2.dist-info}/NOTICE +0 -0
- {rasa_pro-3.13.0.dev20250613.dist-info → rasa_pro-3.13.0rc2.dist-info}/WHEEL +0 -0
- {rasa_pro-3.13.0.dev20250613.dist-info → rasa_pro-3.13.0rc2.dist-info}/entry_points.txt +0 -0
rasa/shared/constants.py
CHANGED
|
@@ -104,6 +104,8 @@ UTTER_FREE_CHITCHAT_RESPONSE = "utter_free_chitchat_response"
|
|
|
104
104
|
ASSISTANT_ID_KEY = "assistant_id"
|
|
105
105
|
ASSISTANT_ID_DEFAULT_VALUE = "placeholder_default"
|
|
106
106
|
|
|
107
|
+
ENDPOINTS_NLG_KEY = "nlg"
|
|
108
|
+
|
|
107
109
|
CONFIG_MANDATORY_COMMON_KEYS = [ASSISTANT_ID_KEY]
|
|
108
110
|
CONFIG_NAME_KEY = "name"
|
|
109
111
|
CONFIG_POLICIES_KEY = "policies"
|
|
@@ -144,6 +146,7 @@ DEFAULT_ACTIONS_PATH = "actions"
|
|
|
144
146
|
DEFAULT_MODELS_PATH = "models"
|
|
145
147
|
DEFAULT_CONVERTED_DATA_PATH = "converted_data"
|
|
146
148
|
DEFAULT_DATA_PATH = "data"
|
|
149
|
+
DEFAULT_PROMPTS_PATH = "prompts"
|
|
147
150
|
DEFAULT_RESULTS_PATH = "results"
|
|
148
151
|
DEFAULT_NLU_RESULTS_PATH = "nlu_comparison_results"
|
|
149
152
|
DEFAULT_CORE_SUBDIRECTORY_NAME = "core"
|
|
@@ -295,6 +298,7 @@ CONTEXT = "context"
|
|
|
295
298
|
|
|
296
299
|
RASA_PATTERN_INTERNAL_ERROR = "pattern_internal_error"
|
|
297
300
|
RASA_PATTERN_HUMAN_HANDOFF = "pattern_human_handoff"
|
|
301
|
+
RASA_PATTERN_CHITCHAT = "pattern_chitchat"
|
|
298
302
|
|
|
299
303
|
RASA_INTERNAL_ERROR_PREFIX = "rasa_internal_error_"
|
|
300
304
|
RASA_PATTERN_INTERNAL_ERROR_DEFAULT = RASA_INTERNAL_ERROR_PREFIX + "default"
|
|
@@ -345,3 +349,13 @@ ROLE_SYSTEM = "system"
|
|
|
345
349
|
# Used for key values in ValidateSlotPatternFlowStackFrame
|
|
346
350
|
REFILL_UTTER = "refill_utter"
|
|
347
351
|
REJECTIONS = "rejections"
|
|
352
|
+
|
|
353
|
+
# Constants for extractive search FAQ parsing (QA pairs from input documents)
|
|
354
|
+
FAQ_DOCUMENT_METADATA_TITLE = "title"
|
|
355
|
+
FAQ_DOCUMENT_METADATA_ANSWER = "answer"
|
|
356
|
+
FAQ_DOCUMENT_METADATA_TYPE = "type"
|
|
357
|
+
DOCUMENT_TYPE_FAQ = "faq"
|
|
358
|
+
FAQ_INPUT_DATA_QUESTION_LINE_PREFIX = "Q:"
|
|
359
|
+
FAQ_INPUT_DATA_ANSWER_LINE_PREFIX = "A:"
|
|
360
|
+
FAQ_DOCUMENT_ENTRY_SEPARATOR = "\n\n"
|
|
361
|
+
FAQ_DOCUMENT_LINE_SEPARATOR = "\n"
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import copy
|
|
2
1
|
import re
|
|
3
2
|
from typing import List, Optional
|
|
4
3
|
|
|
@@ -35,9 +34,7 @@ class CommandPayloadReader:
|
|
|
35
34
|
|
|
36
35
|
matches = CommandPayloadReader.find_matches(user_text)
|
|
37
36
|
if not matches:
|
|
38
|
-
structlogger.warning(
|
|
39
|
-
"message.parsing.failed", user_text=copy.deepcopy(user_text)
|
|
40
|
-
)
|
|
37
|
+
structlogger.warning("message.parsing.failed")
|
|
41
38
|
return message
|
|
42
39
|
|
|
43
40
|
return CommandPayloadReader.extract_commands_from_pattern_matches(
|
|
@@ -110,7 +107,6 @@ class CommandPayloadReader:
|
|
|
110
107
|
if user_text.count("=") > MAX_NUMBER_OF_SLOTS:
|
|
111
108
|
structlogger.warning(
|
|
112
109
|
"too.many.slots",
|
|
113
|
-
user_text=copy.deepcopy(user_text),
|
|
114
110
|
slot_limit=10,
|
|
115
111
|
)
|
|
116
112
|
return True
|
rasa/shared/core/events.py
CHANGED
|
@@ -126,9 +126,7 @@ def deserialise_events(serialized_events: List[Dict[Text, Any]]) -> List["Event"
|
|
|
126
126
|
if event:
|
|
127
127
|
deserialised.append(event)
|
|
128
128
|
else:
|
|
129
|
-
structlogger.warning(
|
|
130
|
-
"event.deserialization.failed", rasa_event=copy.deepcopy(event)
|
|
131
|
-
)
|
|
129
|
+
structlogger.warning("event.deserialization.failed")
|
|
132
130
|
|
|
133
131
|
return deserialised
|
|
134
132
|
|
rasa/shared/core/flows/flow.py
CHANGED
|
@@ -4,7 +4,7 @@ import copy
|
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
5
|
from functools import cached_property
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Any, Dict, List, Optional, Set, Text, Union
|
|
7
|
+
from typing import Any, Dict, List, Optional, Set, Text, Tuple, Union
|
|
8
8
|
|
|
9
9
|
import structlog
|
|
10
10
|
from pydantic import BaseModel
|
|
@@ -15,10 +15,12 @@ from rasa.engine.language import Language
|
|
|
15
15
|
from rasa.shared.constants import RASA_DEFAULT_FLOW_PATTERN_PREFIX
|
|
16
16
|
from rasa.shared.core.flows.constants import (
|
|
17
17
|
KEY_ALWAYS_INCLUDE_IN_PROMPT,
|
|
18
|
+
KEY_CALLED_FLOW,
|
|
18
19
|
KEY_DESCRIPTION,
|
|
19
20
|
KEY_FILE_PATH,
|
|
20
21
|
KEY_ID,
|
|
21
22
|
KEY_IF,
|
|
23
|
+
KEY_LINKED_FLOW,
|
|
22
24
|
KEY_NAME,
|
|
23
25
|
KEY_NLU_TRIGGER,
|
|
24
26
|
KEY_PERSISTED_SLOTS,
|
|
@@ -41,6 +43,7 @@ from rasa.shared.core.flows.steps import (
|
|
|
41
43
|
CallFlowStep,
|
|
42
44
|
CollectInformationFlowStep,
|
|
43
45
|
EndFlowStep,
|
|
46
|
+
LinkFlowStep,
|
|
44
47
|
StartFlowStep,
|
|
45
48
|
)
|
|
46
49
|
from rasa.shared.core.flows.steps.constants import (
|
|
@@ -63,7 +66,7 @@ class FlowLanguageTranslation(BaseModel):
|
|
|
63
66
|
"""The human-readable name of the flow."""
|
|
64
67
|
|
|
65
68
|
class Config:
|
|
66
|
-
"""
|
|
69
|
+
"""Configuration for the FlowLanguageTranslation model."""
|
|
67
70
|
|
|
68
71
|
extra = "ignore"
|
|
69
72
|
|
|
@@ -262,7 +265,7 @@ class Flow:
|
|
|
262
265
|
def readable_name(self, language: Optional[Language] = None) -> str:
|
|
263
266
|
"""Returns the flow's name in the specified language if available.
|
|
264
267
|
|
|
265
|
-
Otherwise falls back to the flow's name, and finally the flow's ID.
|
|
268
|
+
Otherwise, falls back to the flow's name, and finally the flow's ID.
|
|
266
269
|
|
|
267
270
|
Args:
|
|
268
271
|
language: Preferred language code.
|
|
@@ -515,6 +518,9 @@ class Flow:
|
|
|
515
518
|
current_path: FlowPath,
|
|
516
519
|
all_paths: FlowPathsList,
|
|
517
520
|
visited_step_ids: Set[str],
|
|
521
|
+
call_stack: Optional[
|
|
522
|
+
List[Tuple[Optional[FlowStep], Optional[Flow], str]]
|
|
523
|
+
] = None,
|
|
518
524
|
) -> None:
|
|
519
525
|
"""Processes the flow steps recursively.
|
|
520
526
|
|
|
@@ -523,19 +529,25 @@ class Flow:
|
|
|
523
529
|
current_path: The current path being constructed.
|
|
524
530
|
all_paths: The list where completed paths are added.
|
|
525
531
|
visited_step_ids: A set of steps that have been visited to avoid cycles.
|
|
532
|
+
call_stack: Tuple list of (flow, path, flow_type) to track path when \
|
|
533
|
+
calling flows through call and link steps.
|
|
526
534
|
|
|
527
535
|
Returns:
|
|
528
536
|
None: This function modifies all_paths in place by appending new paths
|
|
529
537
|
as they are found.
|
|
530
538
|
"""
|
|
539
|
+
if call_stack is None:
|
|
540
|
+
call_stack = []
|
|
541
|
+
|
|
531
542
|
# Check if the step is relevant for testable_paths extraction.
|
|
532
|
-
# We only create new path nodes for
|
|
533
|
-
#
|
|
534
|
-
#
|
|
543
|
+
# We only create new path nodes for CollectInformationFlowStep,
|
|
544
|
+
# ActionFlowStep, CallFlowStep and LinkFlowStep,
|
|
545
|
+
# because these are externally visible changes
|
|
546
|
+
# in the assistant's behaviour (trackable in the e2e tests).
|
|
535
547
|
# For other flow steps, we only follow their links.
|
|
536
|
-
# We decided to ignore calls to other flows in our coverage analysis.
|
|
537
548
|
should_add_node = isinstance(
|
|
538
|
-
current_step,
|
|
549
|
+
current_step,
|
|
550
|
+
(CollectInformationFlowStep, ActionFlowStep, CallFlowStep, LinkFlowStep),
|
|
539
551
|
)
|
|
540
552
|
if should_add_node:
|
|
541
553
|
# Add current step to the current path that is being constructed.
|
|
@@ -547,10 +559,45 @@ class Flow:
|
|
|
547
559
|
)
|
|
548
560
|
)
|
|
549
561
|
|
|
562
|
+
# Check if the current step has already been visited or
|
|
563
|
+
# if the end of the path has been reached.
|
|
564
|
+
# If so, and we’re not within a called flow, we terminate the current path.
|
|
565
|
+
# This also applies for when we're inside a linked flow and reach its end.
|
|
566
|
+
# If we're inside a called flow and reach its end,
|
|
567
|
+
# continue with the next steps in its parent flow.
|
|
550
568
|
if current_step.id in visited_step_ids or self.is_end_of_path(current_step):
|
|
551
|
-
#
|
|
552
|
-
|
|
553
|
-
#
|
|
569
|
+
# Shallow copy is sufficient, since we only pop from the list and
|
|
570
|
+
# don't mutate the objects inside the tuples.
|
|
571
|
+
# The state of FlowStep and Flow does not change during the traversal.
|
|
572
|
+
call_stack_copy = call_stack.copy()
|
|
573
|
+
# parent_flow_type could be any of: None, i.e. main flow,
|
|
574
|
+
# KEY_CALLED_FLOW(=called_flow) or KEY_LINKED_FLOW(=linked_flow)
|
|
575
|
+
parent_step, parent_flow, parent_flow_type = (
|
|
576
|
+
call_stack_copy.pop() if call_stack_copy else (None, None, None)
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
# Check if within a called flow.
|
|
580
|
+
# If within linked flow, stop the traversal as this takes precedence.
|
|
581
|
+
if parent_step and parent_flow_type == KEY_CALLED_FLOW:
|
|
582
|
+
# As we have reached the END step of a called flow, we need to
|
|
583
|
+
# continue with the next links of the parent step.
|
|
584
|
+
if parent_flow is not None:
|
|
585
|
+
for link in parent_step.next.links:
|
|
586
|
+
parent_flow._handle_link(
|
|
587
|
+
current_path,
|
|
588
|
+
all_paths,
|
|
589
|
+
visited_step_ids,
|
|
590
|
+
link,
|
|
591
|
+
call_stack_copy,
|
|
592
|
+
)
|
|
593
|
+
|
|
594
|
+
else:
|
|
595
|
+
# Found a cycle, or reached an end step, do not proceed further.
|
|
596
|
+
all_paths.paths.append(copy.deepcopy(current_path))
|
|
597
|
+
|
|
598
|
+
# Backtrack: remove the last node after reaching a terminal step.
|
|
599
|
+
# Ensures the path is correctly backtracked, after a path ends or
|
|
600
|
+
# a cycle is detected.
|
|
554
601
|
if should_add_node:
|
|
555
602
|
current_path.nodes.pop()
|
|
556
603
|
return
|
|
@@ -558,6 +605,62 @@ class Flow:
|
|
|
558
605
|
# Mark current step as visited in this path.
|
|
559
606
|
visited_step_ids.add(current_step.id)
|
|
560
607
|
|
|
608
|
+
# If the current step is a call step, we need to resolve the call
|
|
609
|
+
# and continue with the steps of the called flow.
|
|
610
|
+
if isinstance(current_step, CallFlowStep):
|
|
611
|
+
# Get the steps of the called flow and continue with them.
|
|
612
|
+
called_flow = current_step.called_flow_reference
|
|
613
|
+
if called_flow and (
|
|
614
|
+
start_step_in_called_flow := called_flow.first_step_in_flow()
|
|
615
|
+
):
|
|
616
|
+
call_stack.append((current_step, self, KEY_CALLED_FLOW))
|
|
617
|
+
called_flow._go_over_steps(
|
|
618
|
+
start_step_in_called_flow,
|
|
619
|
+
current_path,
|
|
620
|
+
all_paths,
|
|
621
|
+
visited_step_ids,
|
|
622
|
+
call_stack,
|
|
623
|
+
)
|
|
624
|
+
|
|
625
|
+
# After processing the steps of the called (child) flow,
|
|
626
|
+
# remove them from the visited steps
|
|
627
|
+
# to allow the calling (parent) flow to revisit them later.
|
|
628
|
+
visited_step_ids.remove(current_step.id)
|
|
629
|
+
call_stack.pop()
|
|
630
|
+
|
|
631
|
+
# Backtrack: remove the last node
|
|
632
|
+
# after returning from a called (child) flow.
|
|
633
|
+
# Ensures the parent flow can continue exploring other branches.
|
|
634
|
+
if should_add_node:
|
|
635
|
+
current_path.nodes.pop()
|
|
636
|
+
return
|
|
637
|
+
|
|
638
|
+
# If the current step is a LinkFlowStep, step into the linked flow,
|
|
639
|
+
# process its links, and do not return from that flow anymore.
|
|
640
|
+
if isinstance(current_step, LinkFlowStep):
|
|
641
|
+
# Get the steps of the linked flow and continue with them.
|
|
642
|
+
linked_flow = current_step.linked_flow_reference
|
|
643
|
+
if linked_flow and (
|
|
644
|
+
start_step_in_linked_flow := linked_flow.first_step_in_flow()
|
|
645
|
+
):
|
|
646
|
+
call_stack.append((current_step, self, KEY_LINKED_FLOW))
|
|
647
|
+
linked_flow._go_over_steps(
|
|
648
|
+
start_step_in_linked_flow,
|
|
649
|
+
current_path,
|
|
650
|
+
all_paths,
|
|
651
|
+
visited_step_ids,
|
|
652
|
+
call_stack,
|
|
653
|
+
)
|
|
654
|
+
visited_step_ids.remove(current_step.id)
|
|
655
|
+
call_stack.pop()
|
|
656
|
+
|
|
657
|
+
# Backtrack: remove the last node
|
|
658
|
+
# after returning from a linked (child) flow.
|
|
659
|
+
# Ensures the parent can continue after the linked flow is processed.
|
|
660
|
+
if should_add_node:
|
|
661
|
+
current_path.nodes.pop()
|
|
662
|
+
return
|
|
663
|
+
|
|
561
664
|
# Iterate over all links of the current step.
|
|
562
665
|
for link in current_step.next.links:
|
|
563
666
|
self._handle_link(
|
|
@@ -565,12 +668,15 @@ class Flow:
|
|
|
565
668
|
all_paths,
|
|
566
669
|
visited_step_ids,
|
|
567
670
|
link,
|
|
671
|
+
call_stack,
|
|
568
672
|
)
|
|
569
673
|
|
|
570
674
|
# Backtrack the current step and remove it from the path.
|
|
571
675
|
visited_step_ids.remove(current_step.id)
|
|
572
676
|
|
|
573
|
-
#
|
|
677
|
+
# Backtrack: remove the last node
|
|
678
|
+
# after processing all links of the current step.
|
|
679
|
+
# Ensures the next recursion can start once all links are explored.
|
|
574
680
|
if should_add_node:
|
|
575
681
|
current_path.nodes.pop()
|
|
576
682
|
|
|
@@ -580,6 +686,9 @@ class Flow:
|
|
|
580
686
|
all_paths: FlowPathsList,
|
|
581
687
|
visited_step_ids: Set[str],
|
|
582
688
|
link: FlowStepLink,
|
|
689
|
+
call_stack: Optional[
|
|
690
|
+
List[Tuple[Optional[FlowStep], Optional[Flow], str]]
|
|
691
|
+
] = None,
|
|
583
692
|
) -> None:
|
|
584
693
|
"""Handles the next step in a flow.
|
|
585
694
|
|
|
@@ -588,6 +697,8 @@ class Flow:
|
|
|
588
697
|
all_paths: The list where completed paths are added.
|
|
589
698
|
visited_step_ids: A set of steps that have been visited to avoid cycles.
|
|
590
699
|
link: The link to be followed.
|
|
700
|
+
call_stack: Tuple list of (flow, path, flow_type) to track path when \
|
|
701
|
+
calling flows through call and link steps..
|
|
591
702
|
|
|
592
703
|
Returns:
|
|
593
704
|
None: This function modifies all_paths in place by appending new paths
|
|
@@ -602,6 +713,7 @@ class Flow:
|
|
|
602
713
|
current_path,
|
|
603
714
|
all_paths,
|
|
604
715
|
visited_step_ids,
|
|
716
|
+
call_stack,
|
|
605
717
|
)
|
|
606
718
|
return
|
|
607
719
|
# IfFlowStepLink and ElseFlowStepLink are conditional links.
|
|
@@ -615,6 +727,7 @@ class Flow:
|
|
|
615
727
|
current_path,
|
|
616
728
|
all_paths,
|
|
617
729
|
visited_step_ids,
|
|
730
|
+
call_stack,
|
|
618
731
|
)
|
|
619
732
|
return
|
|
620
733
|
else:
|
|
@@ -625,6 +738,7 @@ class Flow:
|
|
|
625
738
|
current_path,
|
|
626
739
|
all_paths,
|
|
627
740
|
visited_step_ids,
|
|
741
|
+
call_stack,
|
|
628
742
|
)
|
|
629
743
|
return
|
|
630
744
|
|
|
@@ -36,6 +36,7 @@ class FlowsList:
|
|
|
36
36
|
def __post_init__(self) -> None:
|
|
37
37
|
"""Initializes the FlowsList object."""
|
|
38
38
|
self._resolve_called_flows()
|
|
39
|
+
self._resolve_linked_flows()
|
|
39
40
|
|
|
40
41
|
def __iter__(self) -> Generator[Flow, None, None]:
|
|
41
42
|
"""Iterates over the flows."""
|
|
@@ -103,7 +104,10 @@ class FlowsList:
|
|
|
103
104
|
)
|
|
104
105
|
|
|
105
106
|
def _resolve_called_flows(self) -> None:
|
|
106
|
-
"""Resolves the called flows.
|
|
107
|
+
"""Resolves the called flows.
|
|
108
|
+
|
|
109
|
+
`Resolving` here means connecting the step to the actual `Flow` object.
|
|
110
|
+
"""
|
|
107
111
|
from rasa.shared.core.flows.steps import CallFlowStep
|
|
108
112
|
|
|
109
113
|
for flow in self.underlying_flows:
|
|
@@ -112,6 +116,19 @@ class FlowsList:
|
|
|
112
116
|
# only resolve the reference, if it isn't already resolved
|
|
113
117
|
step.called_flow_reference = self.flow_by_id(step.call)
|
|
114
118
|
|
|
119
|
+
def _resolve_linked_flows(self) -> None:
|
|
120
|
+
"""Resolves the linked flows.
|
|
121
|
+
|
|
122
|
+
`Resolving` here means connecting the step to the actual `Flow` object.
|
|
123
|
+
"""
|
|
124
|
+
from rasa.shared.core.flows.steps import LinkFlowStep
|
|
125
|
+
|
|
126
|
+
for flow in self.underlying_flows:
|
|
127
|
+
for step in flow.steps:
|
|
128
|
+
if isinstance(step, LinkFlowStep) and not step.linked_flow_reference:
|
|
129
|
+
# only resolve the reference, if it isn't already resolved
|
|
130
|
+
step.linked_flow_reference = self.flow_by_id(step.link)
|
|
131
|
+
|
|
115
132
|
def as_json_list(self) -> List[Dict[Text, Any]]:
|
|
116
133
|
"""Serialize the FlowsList object to list format and not to the original dict.
|
|
117
134
|
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Any, Dict, Text
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Dict, Text
|
|
5
5
|
|
|
6
|
-
from rasa.shared.core.flows.flow_step import FlowStep
|
|
6
|
+
from rasa.shared.core.flows.flow_step import FlowStep, Optional
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from rasa.shared.core.flows.flow import Flow
|
|
7
10
|
|
|
8
11
|
|
|
9
12
|
@dataclass
|
|
@@ -12,6 +15,8 @@ class LinkFlowStep(FlowStep):
|
|
|
12
15
|
|
|
13
16
|
link: Text
|
|
14
17
|
"""The id of the flow that should be started subsequently."""
|
|
18
|
+
linked_flow_reference: Optional["Flow"] = None
|
|
19
|
+
"""The flow that is linked to by this step."""
|
|
15
20
|
|
|
16
21
|
def does_allow_for_next_step(self) -> bool:
|
|
17
22
|
"""Returns whether this step allows for following steps.
|
|
@@ -8,6 +8,7 @@ from typing import List, Optional, Set, Text
|
|
|
8
8
|
|
|
9
9
|
from rasa.shared.constants import (
|
|
10
10
|
RASA_DEFAULT_FLOW_PATTERN_PREFIX,
|
|
11
|
+
RASA_PATTERN_CHITCHAT,
|
|
11
12
|
RASA_PATTERN_HUMAN_HANDOFF,
|
|
12
13
|
RASA_PATTERN_INTERNAL_ERROR,
|
|
13
14
|
)
|
|
@@ -186,8 +187,10 @@ class ReferenceToPatternException(RasaException):
|
|
|
186
187
|
return message + "Patterns can not be used as a target for a call step."
|
|
187
188
|
else:
|
|
188
189
|
return message + (
|
|
189
|
-
"
|
|
190
|
-
"
|
|
190
|
+
"Patterns cannot be used as a target in link steps, except for "
|
|
191
|
+
"'pattern_human_handoff', which may be linked from both user-defined "
|
|
192
|
+
"flows and other patterns. 'pattern_chitchat' may only be linked "
|
|
193
|
+
"from other patterns."
|
|
191
194
|
)
|
|
192
195
|
|
|
193
196
|
|
|
@@ -578,11 +581,18 @@ def validate_linked_flows_exists(flows: "FlowsList") -> None:
|
|
|
578
581
|
continue
|
|
579
582
|
|
|
580
583
|
# It might be that the flows do not contain the default rasa patterns, but
|
|
581
|
-
# only the user flows. Manually check for `pattern_human_handoff`
|
|
582
|
-
#
|
|
584
|
+
# only the user flows. Manually check for `pattern_human_handoff` and
|
|
585
|
+
# 'pattern_chitchat' as these patterns can be linked to and are part of the
|
|
586
|
+
# default patterns of rasa.
|
|
583
587
|
if (
|
|
584
588
|
flows.flow_by_id(step.link) is None
|
|
589
|
+
# Allow linking to human-handoff from both patterns
|
|
590
|
+
# and user-defined flows
|
|
585
591
|
and step.link != RASA_PATTERN_HUMAN_HANDOFF
|
|
592
|
+
# Allow linking to 'pattern_chitchat' only from other patterns
|
|
593
|
+
and not (
|
|
594
|
+
flow.is_rasa_default_flow and step.link == RASA_PATTERN_CHITCHAT
|
|
595
|
+
)
|
|
586
596
|
):
|
|
587
597
|
raise UnresolvedFlowException(step.link, flow.id, step.id)
|
|
588
598
|
|
|
@@ -597,7 +607,13 @@ def validate_patterns_are_not_called_or_linked(flows: "FlowsList") -> None:
|
|
|
597
607
|
if (
|
|
598
608
|
isinstance(step, LinkFlowStep)
|
|
599
609
|
and step.link.startswith(RASA_DEFAULT_FLOW_PATTERN_PREFIX)
|
|
610
|
+
# Allow linking to human-handoff from both patterns
|
|
611
|
+
# and user-defined flows
|
|
600
612
|
and step.link != RASA_PATTERN_HUMAN_HANDOFF
|
|
613
|
+
# Allow linking to 'pattern_chitchat' only from other patterns
|
|
614
|
+
and not (
|
|
615
|
+
flow.is_rasa_default_flow and step.link == RASA_PATTERN_CHITCHAT
|
|
616
|
+
)
|
|
601
617
|
):
|
|
602
618
|
raise ReferenceToPatternException(
|
|
603
619
|
step.link, flow.id, step.id, call_step=False
|
|
@@ -617,7 +633,8 @@ def validate_patterns_are_not_calling_or_linking_other_flows(
|
|
|
617
633
|
"""Validates that patterns do not contain call or link steps.
|
|
618
634
|
|
|
619
635
|
Link steps to user flows are allowed for all patterns but 'pattern_internal_error'.
|
|
620
|
-
Link steps to other patterns, except for 'pattern_human_handoff'
|
|
636
|
+
Link steps to other patterns, except for 'pattern_human_handoff' and
|
|
637
|
+
'pattern_chitchat' are forbidden.
|
|
621
638
|
"""
|
|
622
639
|
for flow in flows.underlying_flows:
|
|
623
640
|
if not flow.is_rasa_default_flow:
|
|
@@ -627,6 +644,9 @@ def validate_patterns_are_not_calling_or_linking_other_flows(
|
|
|
627
644
|
if step.link == RASA_PATTERN_HUMAN_HANDOFF:
|
|
628
645
|
# links to 'pattern_human_handoff' are allowed
|
|
629
646
|
continue
|
|
647
|
+
if step.link == RASA_PATTERN_CHITCHAT:
|
|
648
|
+
# links to 'pattern_chitchat' are allowed
|
|
649
|
+
continue
|
|
630
650
|
if step.link.startswith(RASA_DEFAULT_FLOW_PATTERN_PREFIX):
|
|
631
651
|
# all other patterns are allowed to link to user flows, but not
|
|
632
652
|
# to other patterns
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import copy
|
|
2
1
|
import functools
|
|
3
2
|
import json
|
|
4
3
|
import logging
|
|
@@ -648,9 +647,7 @@ class YAMLStoryReader(StoryReader):
|
|
|
648
647
|
# message text did start with the special prefix -- however, a user might
|
|
649
648
|
# just have decided to start their text this way.
|
|
650
649
|
if not match:
|
|
651
|
-
structlogger.warning(
|
|
652
|
-
"message.parsing.failed", user_text=copy.deepcopy(user_text)
|
|
653
|
-
)
|
|
650
|
+
structlogger.warning("message.parsing.failed")
|
|
654
651
|
return message
|
|
655
652
|
|
|
656
653
|
# Extract attributes from the match - and validate it via the domain.
|
|
@@ -46,13 +46,13 @@ from rasa.shared.providers._configs.oauth_config import (
|
|
|
46
46
|
OAUTH_TYPE_FIELD,
|
|
47
47
|
OAuth,
|
|
48
48
|
)
|
|
49
|
-
from rasa.shared.
|
|
49
|
+
from rasa.shared.utils.common import class_from_module_path
|
|
50
|
+
from rasa.shared.utils.configs import (
|
|
50
51
|
raise_deprecation_warnings,
|
|
51
52
|
resolve_aliases,
|
|
52
53
|
validate_forbidden_keys,
|
|
53
54
|
validate_required_keys,
|
|
54
55
|
)
|
|
55
|
-
from rasa.shared.utils.common import class_from_module_path
|
|
56
56
|
|
|
57
57
|
structlogger = structlog.get_logger()
|
|
58
58
|
|
|
@@ -15,7 +15,7 @@ from rasa.shared.constants import (
|
|
|
15
15
|
STREAM_CONFIG_KEY,
|
|
16
16
|
TIMEOUT_CONFIG_KEY,
|
|
17
17
|
)
|
|
18
|
-
from rasa.shared.
|
|
18
|
+
from rasa.shared.utils.configs import (
|
|
19
19
|
raise_deprecation_warnings,
|
|
20
20
|
resolve_aliases,
|
|
21
21
|
validate_forbidden_keys,
|
|
@@ -21,7 +21,7 @@ from rasa.shared.constants import (
|
|
|
21
21
|
REQUEST_TIMEOUT_CONFIG_KEY,
|
|
22
22
|
TIMEOUT_CONFIG_KEY,
|
|
23
23
|
)
|
|
24
|
-
from rasa.shared.
|
|
24
|
+
from rasa.shared.utils.configs import (
|
|
25
25
|
raise_deprecation_warnings,
|
|
26
26
|
resolve_aliases,
|
|
27
27
|
validate_required_keys,
|
|
@@ -26,7 +26,7 @@ from rasa.shared.constants import (
|
|
|
26
26
|
STREAM_CONFIG_KEY,
|
|
27
27
|
TIMEOUT_CONFIG_KEY,
|
|
28
28
|
)
|
|
29
|
-
from rasa.shared.
|
|
29
|
+
from rasa.shared.utils.configs import (
|
|
30
30
|
raise_deprecation_warnings,
|
|
31
31
|
resolve_aliases,
|
|
32
32
|
validate_forbidden_keys,
|
|
@@ -25,7 +25,7 @@ from rasa.shared.constants import (
|
|
|
25
25
|
TIMEOUT_CONFIG_KEY,
|
|
26
26
|
USE_CHAT_COMPLETIONS_ENDPOINT_CONFIG_KEY,
|
|
27
27
|
)
|
|
28
|
-
from rasa.shared.
|
|
28
|
+
from rasa.shared.utils.configs import (
|
|
29
29
|
raise_deprecation_warnings,
|
|
30
30
|
resolve_aliases,
|
|
31
31
|
validate_forbidden_keys,
|
|
@@ -1,107 +1,8 @@
|
|
|
1
1
|
import structlog
|
|
2
2
|
|
|
3
|
-
from rasa.shared.utils.io import raise_deprecation_warning
|
|
4
|
-
|
|
5
3
|
structlogger = structlog.get_logger()
|
|
6
4
|
|
|
7
5
|
|
|
8
|
-
def resolve_aliases(config: dict, deprecated_alias_mapping: dict) -> dict:
|
|
9
|
-
"""
|
|
10
|
-
Resolve aliases in the configuration to standard keys.
|
|
11
|
-
|
|
12
|
-
Args:
|
|
13
|
-
config: Dictionary containing the configuration.
|
|
14
|
-
deprecated_alias_mapping: Dictionary mapping aliases to
|
|
15
|
-
their standard keys.
|
|
16
|
-
|
|
17
|
-
Returns:
|
|
18
|
-
New dictionary containing the processed configuration.
|
|
19
|
-
"""
|
|
20
|
-
config = config.copy()
|
|
21
|
-
|
|
22
|
-
for alias, standard_key in deprecated_alias_mapping.items():
|
|
23
|
-
# We check for the alias instead of the standard key because our goal is to
|
|
24
|
-
# update the standard key when the alias is found. Since the standard key is
|
|
25
|
-
# always included in the default component configurations, we overwrite it
|
|
26
|
-
# with the alias value if the alias exists.
|
|
27
|
-
if alias in config:
|
|
28
|
-
config[standard_key] = config.pop(alias)
|
|
29
|
-
|
|
30
|
-
return config
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def raise_deprecation_warnings(config: dict, deprecated_alias_mapping: dict) -> None:
|
|
34
|
-
"""
|
|
35
|
-
Raises warnings for deprecated keys in the configuration.
|
|
36
|
-
|
|
37
|
-
Args:
|
|
38
|
-
config: Dictionary containing the configuration.
|
|
39
|
-
deprecated_alias_mapping: Dictionary mapping deprecated keys to
|
|
40
|
-
their standard keys.
|
|
41
|
-
|
|
42
|
-
Raises:
|
|
43
|
-
DeprecationWarning: If any deprecated key is found in the config.
|
|
44
|
-
"""
|
|
45
|
-
for alias, standard_key in deprecated_alias_mapping.items():
|
|
46
|
-
if alias in config:
|
|
47
|
-
raise_deprecation_warning(
|
|
48
|
-
message=(
|
|
49
|
-
f"'{alias}' is deprecated and will be removed in "
|
|
50
|
-
f"4.0.0. Use '{standard_key}' instead."
|
|
51
|
-
)
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def validate_required_keys(config: dict, required_keys: list) -> None:
|
|
56
|
-
"""
|
|
57
|
-
Validates that the passed config contains all the required keys.
|
|
58
|
-
|
|
59
|
-
Args:
|
|
60
|
-
config: Dictionary containing the configuration.
|
|
61
|
-
required_keys: List of keys that must be present in the config.
|
|
62
|
-
|
|
63
|
-
Raises:
|
|
64
|
-
ValueError: If any required key is missing.
|
|
65
|
-
"""
|
|
66
|
-
missing_keys = [key for key in required_keys if key not in config]
|
|
67
|
-
if missing_keys:
|
|
68
|
-
message = f"Missing required keys '{missing_keys}' for configuration."
|
|
69
|
-
structlogger.error(
|
|
70
|
-
"validate_required_keys",
|
|
71
|
-
message=message,
|
|
72
|
-
missing_keys=missing_keys,
|
|
73
|
-
config=config,
|
|
74
|
-
)
|
|
75
|
-
raise ValueError(message)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def validate_forbidden_keys(config: dict, forbidden_keys: list) -> None:
|
|
79
|
-
"""
|
|
80
|
-
Validates that the passed config doesn't contain any forbidden keys.
|
|
81
|
-
|
|
82
|
-
Args:
|
|
83
|
-
config: Dictionary containing the configuration.
|
|
84
|
-
forbidden_keys: List of keys that are forbidden in the config.
|
|
85
|
-
|
|
86
|
-
Raises:
|
|
87
|
-
ValueError: If any forbidden key is present.
|
|
88
|
-
"""
|
|
89
|
-
forbidden_keys_in_config = set(config.keys()).intersection(set(forbidden_keys))
|
|
90
|
-
|
|
91
|
-
if forbidden_keys_in_config:
|
|
92
|
-
message = (
|
|
93
|
-
f"Forbidden keys '{forbidden_keys_in_config}' present "
|
|
94
|
-
f"in the configuration."
|
|
95
|
-
)
|
|
96
|
-
structlogger.error(
|
|
97
|
-
"validate_forbidden_keys",
|
|
98
|
-
message=message,
|
|
99
|
-
forbidden_keys=forbidden_keys_in_config,
|
|
100
|
-
config=config,
|
|
101
|
-
)
|
|
102
|
-
raise ValueError(message)
|
|
103
|
-
|
|
104
|
-
|
|
105
6
|
def get_provider_prefixed_model_name(provider: str, model: str) -> str:
|
|
106
7
|
"""
|
|
107
8
|
Returns the model name with the provider prefixed.
|