microsoft-agents-hosting-dialogs 0.10.0.dev2__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.
Files changed (91) hide show
  1. microsoft_agents/hosting/dialogs/__init__.py +76 -0
  2. microsoft_agents/hosting/dialogs/_component_registration.py +30 -0
  3. microsoft_agents/hosting/dialogs/_telemetry_client.py +78 -0
  4. microsoft_agents/hosting/dialogs/choices/__init__.py +38 -0
  5. microsoft_agents/hosting/dialogs/choices/channel.py +121 -0
  6. microsoft_agents/hosting/dialogs/choices/choice_factory.py +262 -0
  7. microsoft_agents/hosting/dialogs/choices/choice_recognizer.py +148 -0
  8. microsoft_agents/hosting/dialogs/choices/find.py +242 -0
  9. microsoft_agents/hosting/dialogs/choices/models/__init__.py +23 -0
  10. microsoft_agents/hosting/dialogs/choices/models/choice.py +14 -0
  11. microsoft_agents/hosting/dialogs/choices/models/choice_factory_options.py +13 -0
  12. microsoft_agents/hosting/dialogs/choices/models/find_choices_options.py +28 -0
  13. microsoft_agents/hosting/dialogs/choices/models/find_values_options.py +31 -0
  14. microsoft_agents/hosting/dialogs/choices/models/found_choice.py +22 -0
  15. microsoft_agents/hosting/dialogs/choices/models/found_value.py +20 -0
  16. microsoft_agents/hosting/dialogs/choices/models/list_style.py +15 -0
  17. microsoft_agents/hosting/dialogs/choices/models/model_result.py +16 -0
  18. microsoft_agents/hosting/dialogs/choices/models/sorted_value.py +16 -0
  19. microsoft_agents/hosting/dialogs/choices/models/token.py +20 -0
  20. microsoft_agents/hosting/dialogs/choices/tokenizer.py +92 -0
  21. microsoft_agents/hosting/dialogs/component_dialog.py +284 -0
  22. microsoft_agents/hosting/dialogs/dialog.py +198 -0
  23. microsoft_agents/hosting/dialogs/dialog_component_registration.py +52 -0
  24. microsoft_agents/hosting/dialogs/dialog_container.py +31 -0
  25. microsoft_agents/hosting/dialogs/dialog_context.py +426 -0
  26. microsoft_agents/hosting/dialogs/dialog_extensions.py +201 -0
  27. microsoft_agents/hosting/dialogs/dialog_manager.py +189 -0
  28. microsoft_agents/hosting/dialogs/dialog_manager_result.py +17 -0
  29. microsoft_agents/hosting/dialogs/dialog_set.py +174 -0
  30. microsoft_agents/hosting/dialogs/dialog_state.py +20 -0
  31. microsoft_agents/hosting/dialogs/memory/__init__.py +24 -0
  32. microsoft_agents/hosting/dialogs/memory/component_memory_scopes_base.py +14 -0
  33. microsoft_agents/hosting/dialogs/memory/component_path_resolvers_base.py +15 -0
  34. microsoft_agents/hosting/dialogs/memory/dialog_path.py +33 -0
  35. microsoft_agents/hosting/dialogs/memory/dialog_state_manager.py +563 -0
  36. microsoft_agents/hosting/dialogs/memory/dialog_state_manager_configuration.py +11 -0
  37. microsoft_agents/hosting/dialogs/memory/path_resolver_base.py +8 -0
  38. microsoft_agents/hosting/dialogs/memory/path_resolvers/__init__.py +19 -0
  39. microsoft_agents/hosting/dialogs/memory/path_resolvers/alias_path_resolver.py +53 -0
  40. microsoft_agents/hosting/dialogs/memory/path_resolvers/at_at_path_resolver.py +9 -0
  41. microsoft_agents/hosting/dialogs/memory/path_resolvers/at_path_resolver.py +44 -0
  42. microsoft_agents/hosting/dialogs/memory/path_resolvers/dollar_path_resolver.py +9 -0
  43. microsoft_agents/hosting/dialogs/memory/path_resolvers/hash_path_resolver.py +9 -0
  44. microsoft_agents/hosting/dialogs/memory/path_resolvers/percent_path_resolver.py +9 -0
  45. microsoft_agents/hosting/dialogs/memory/scope_path.py +38 -0
  46. microsoft_agents/hosting/dialogs/memory/scopes/__init__.py +31 -0
  47. microsoft_agents/hosting/dialogs/memory/scopes/bot_state_memory_scope.py +66 -0
  48. microsoft_agents/hosting/dialogs/memory/scopes/class_memory_scope.py +64 -0
  49. microsoft_agents/hosting/dialogs/memory/scopes/conversation_memory_scope.py +12 -0
  50. microsoft_agents/hosting/dialogs/memory/scopes/dialog_class_memory_scope.py +52 -0
  51. microsoft_agents/hosting/dialogs/memory/scopes/dialog_context_memory_scope.py +68 -0
  52. microsoft_agents/hosting/dialogs/memory/scopes/dialog_memory_scope.py +75 -0
  53. microsoft_agents/hosting/dialogs/memory/scopes/memory_scope.py +91 -0
  54. microsoft_agents/hosting/dialogs/memory/scopes/settings_memory_scope.py +38 -0
  55. microsoft_agents/hosting/dialogs/memory/scopes/this_memory_scope.py +36 -0
  56. microsoft_agents/hosting/dialogs/memory/scopes/turn_memory_scope.py +86 -0
  57. microsoft_agents/hosting/dialogs/memory/scopes/user_memory_scope.py +12 -0
  58. microsoft_agents/hosting/dialogs/models/__init__.py +15 -0
  59. microsoft_agents/hosting/dialogs/models/dialog_event.py +13 -0
  60. microsoft_agents/hosting/dialogs/models/dialog_events.py +12 -0
  61. microsoft_agents/hosting/dialogs/models/dialog_instance.py +28 -0
  62. microsoft_agents/hosting/dialogs/models/dialog_reason.py +34 -0
  63. microsoft_agents/hosting/dialogs/models/dialog_turn_result.py +17 -0
  64. microsoft_agents/hosting/dialogs/models/dialog_turn_status.py +26 -0
  65. microsoft_agents/hosting/dialogs/object_path.py +315 -0
  66. microsoft_agents/hosting/dialogs/persisted_state.py +22 -0
  67. microsoft_agents/hosting/dialogs/persisted_state_keys.py +8 -0
  68. microsoft_agents/hosting/dialogs/prompts/__init__.py +41 -0
  69. microsoft_agents/hosting/dialogs/prompts/activity_prompt.py +203 -0
  70. microsoft_agents/hosting/dialogs/prompts/attachment_prompt.py +87 -0
  71. microsoft_agents/hosting/dialogs/prompts/choice_prompt.py +156 -0
  72. microsoft_agents/hosting/dialogs/prompts/confirm_prompt.py +161 -0
  73. microsoft_agents/hosting/dialogs/prompts/datetime_prompt.py +90 -0
  74. microsoft_agents/hosting/dialogs/prompts/datetime_resolution.py +16 -0
  75. microsoft_agents/hosting/dialogs/prompts/number_prompt.py +81 -0
  76. microsoft_agents/hosting/dialogs/prompts/oauth_prompt.py +569 -0
  77. microsoft_agents/hosting/dialogs/prompts/oauth_prompt_settings.py +43 -0
  78. microsoft_agents/hosting/dialogs/prompts/prompt.py +224 -0
  79. microsoft_agents/hosting/dialogs/prompts/prompt_culture_models.py +222 -0
  80. microsoft_agents/hosting/dialogs/prompts/prompt_options.py +42 -0
  81. microsoft_agents/hosting/dialogs/prompts/prompt_recognizer_result.py +11 -0
  82. microsoft_agents/hosting/dialogs/prompts/prompt_validator.py +0 -0
  83. microsoft_agents/hosting/dialogs/prompts/prompt_validator_context.py +44 -0
  84. microsoft_agents/hosting/dialogs/prompts/text_prompt.py +82 -0
  85. microsoft_agents/hosting/dialogs/waterfall_dialog.py +266 -0
  86. microsoft_agents/hosting/dialogs/waterfall_step_context.py +109 -0
  87. microsoft_agents_hosting_dialogs-0.10.0.dev2.dist-info/METADATA +87 -0
  88. microsoft_agents_hosting_dialogs-0.10.0.dev2.dist-info/RECORD +91 -0
  89. microsoft_agents_hosting_dialogs-0.10.0.dev2.dist-info/WHEEL +5 -0
  90. microsoft_agents_hosting_dialogs-0.10.0.dev2.dist-info/licenses/LICENSE +21 -0
  91. microsoft_agents_hosting_dialogs-0.10.0.dev2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,43 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+ class OAuthPromptSettings:
4
+ def __init__(
5
+ self,
6
+ connection_name: str,
7
+ title: str,
8
+ text: str | None = None,
9
+ timeout: int | None = None,
10
+ oauth_app_credentials=None,
11
+ end_on_invalid_message: bool = False,
12
+ ):
13
+ """
14
+ Settings used to configure an `OAuthPrompt` instance.
15
+ Parameters:
16
+ connection_name (str): Name of the OAuth connection being used.
17
+ title (str): The title of the cards signin button.
18
+ text (str): (Optional) additional text included on the signin card.
19
+ timeout (int): (Optional) number of milliseconds the prompt will wait for the user to authenticate.
20
+ `OAuthPrompt` defaults value to `900,000` ms (15 minutes).
21
+ oauth_app_credentials (AppCredentials): (Optional) AppCredentials to use for OAuth. If None,
22
+ the Agent credentials are used.
23
+ end_on_invalid_message (bool): (Optional) value indicating whether the OAuthPrompt should end upon
24
+ receiving an invalid message. Generally the OAuthPrompt will ignore incoming messages from the
25
+ user during the auth flow, if they are not related to the auth flow. This flag enables ending the
26
+ OAuthPrompt rather than ignoring the user's message. Typically, this flag will be set to 'true',
27
+ but is 'false' by default for backwards compatibility.
28
+ """
29
+ self.connection_name = connection_name
30
+ self.title = title
31
+ self.text = text
32
+ self.timeout = timeout
33
+ self.oauth_app_credentials = oauth_app_credentials
34
+ self.end_on_invalid_message = end_on_invalid_message
35
+
36
+ @property
37
+ def oath_app_credentials(self):
38
+ """Backward-compatible alias for the misspelled attribute name."""
39
+ return self.oauth_app_credentials
40
+
41
+ @oath_app_credentials.setter
42
+ def oath_app_credentials(self, value):
43
+ self.oauth_app_credentials = value
@@ -0,0 +1,224 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from abc import abstractmethod
5
+ import copy
6
+ from typing import Any, Callable, Awaitable, cast
7
+
8
+ from microsoft_agents.hosting.core import TurnContext
9
+ from microsoft_agents.activity import InputHints, ActivityTypes, Activity
10
+
11
+ from ..choices import (
12
+ Choice,
13
+ ChoiceFactory,
14
+ ChoiceFactoryOptions,
15
+ ListStyle,
16
+ )
17
+ from .prompt_options import PromptOptions
18
+ from .prompt_recognizer_result import PromptRecognizerResult
19
+ from .prompt_validator_context import PromptValidatorContext
20
+ from ..models.dialog_reason import DialogReason
21
+ from ..dialog import Dialog
22
+ from ..models.dialog_instance import DialogInstance
23
+ from ..models.dialog_turn_result import DialogTurnResult
24
+ from ..dialog_context import DialogContext
25
+
26
+
27
+ class Prompt(Dialog):
28
+ """
29
+ Defines the core behavior of prompt dialogs. Extends the Dialog base class.
30
+ """
31
+
32
+ ATTEMPT_COUNT_KEY = "AttemptCount"
33
+ persisted_options = "options"
34
+ persisted_state = "state"
35
+
36
+ def __init__(
37
+ self,
38
+ dialog_id: str,
39
+ validator: Callable[[PromptValidatorContext], Any] | None = None,
40
+ ):
41
+ """
42
+ Creates a new Prompt instance.
43
+ """
44
+ super(Prompt, self).__init__(dialog_id)
45
+ self._validator = validator
46
+
47
+ async def begin_dialog(
48
+ self, dialog_context: DialogContext, options: object = None
49
+ ) -> DialogTurnResult:
50
+ if not dialog_context:
51
+ raise TypeError("Prompt(): dc cannot be None.")
52
+ if not isinstance(options, PromptOptions):
53
+ raise TypeError("Prompt(): Prompt options are required for Prompt dialogs.")
54
+
55
+ # Ensure prompts have input hint set
56
+ if options.prompt is not None and not options.prompt.input_hint:
57
+ options.prompt.input_hint = InputHints.expecting_input
58
+
59
+ if options.retry_prompt is not None and not options.retry_prompt.input_hint:
60
+ options.retry_prompt.input_hint = InputHints.expecting_input
61
+
62
+ # Initialize prompt state
63
+ assert dialog_context.active_dialog is not None
64
+ state = dialog_context.active_dialog.state
65
+ state[self.persisted_options] = options
66
+ state[self.persisted_state] = {self.ATTEMPT_COUNT_KEY: 0}
67
+
68
+ # Send initial prompt
69
+ await self.on_prompt(
70
+ dialog_context.context,
71
+ state[self.persisted_state],
72
+ state[self.persisted_options],
73
+ False,
74
+ )
75
+
76
+ return Dialog.end_of_turn
77
+
78
+ async def continue_dialog(self, dialog_context: DialogContext):
79
+ if not dialog_context:
80
+ raise TypeError("Prompt(): dc cannot be None.")
81
+
82
+ # Don't do anything for non-message activities
83
+ if dialog_context.context.activity.type != ActivityTypes.message:
84
+ return Dialog.end_of_turn
85
+
86
+ # Perform base recognition
87
+ instance = dialog_context.active_dialog
88
+ assert instance is not None
89
+ state = cast(dict[str, object], instance.state[self.persisted_state])
90
+ options = cast(PromptOptions, instance.state[self.persisted_options])
91
+ recognized = await self.on_recognize(dialog_context.context, state, options)
92
+
93
+ # Validate the return value
94
+ is_valid = False
95
+ state[self.ATTEMPT_COUNT_KEY] = (
96
+ int(cast(int, state.get(self.ATTEMPT_COUNT_KEY, 0))) + 1
97
+ )
98
+ if self._validator is not None:
99
+ prompt_context = PromptValidatorContext(
100
+ dialog_context.context, recognized, state, options
101
+ )
102
+ is_valid = await self._validator(prompt_context)
103
+ if options is None:
104
+ options = PromptOptions()
105
+ options.number_of_attempts += 1
106
+ else:
107
+ if recognized.succeeded:
108
+ is_valid = True
109
+
110
+ # Return recognized value or re-prompt
111
+ if is_valid:
112
+ return await dialog_context.end_dialog(recognized.value)
113
+
114
+ if not dialog_context.context.responded:
115
+ await self.on_prompt(dialog_context.context, state, options, True)
116
+ return Dialog.end_of_turn
117
+
118
+ async def resume_dialog(
119
+ self, dialog_context: DialogContext, reason: DialogReason, result: object
120
+ ) -> DialogTurnResult:
121
+ assert dialog_context.active_dialog is not None
122
+ await self.reprompt_dialog(dialog_context.context, dialog_context.active_dialog)
123
+ return Dialog.end_of_turn
124
+
125
+ async def reprompt_dialog(self, context: TurnContext, instance: DialogInstance):
126
+ state = instance.state[self.persisted_state]
127
+ options = instance.state[self.persisted_options]
128
+ await self.on_prompt(context, state, options, False)
129
+
130
+ @abstractmethod
131
+ async def on_prompt(
132
+ self,
133
+ turn_context: TurnContext,
134
+ state: dict[str, object],
135
+ options: PromptOptions,
136
+ is_retry: bool,
137
+ ):
138
+ pass
139
+
140
+ @abstractmethod
141
+ async def on_recognize(
142
+ self,
143
+ turn_context: TurnContext,
144
+ state: dict[str, object],
145
+ options: PromptOptions,
146
+ ) -> PromptRecognizerResult:
147
+ pass
148
+
149
+ def append_choices(
150
+ self,
151
+ prompt: Activity | None,
152
+ channel_id: str,
153
+ choices: list[Choice],
154
+ style: ListStyle | int,
155
+ options: ChoiceFactoryOptions | None = None,
156
+ ) -> Activity:
157
+ """
158
+ Composes an output activity containing a set of choices.
159
+ """
160
+ # Get base prompt text (if any)
161
+ text = prompt.text if prompt is not None and prompt.text else ""
162
+
163
+ # Create temporary msg
164
+ def inline() -> Activity:
165
+ return ChoiceFactory.inline(choices, text, None, options)
166
+
167
+ def list_style() -> Activity:
168
+ return ChoiceFactory.list_style(choices, text, None, options)
169
+
170
+ def suggested_action() -> Activity:
171
+ return ChoiceFactory.suggested_action(choices, text)
172
+
173
+ def hero_card() -> Activity:
174
+ return ChoiceFactory.hero_card(choices, text)
175
+
176
+ def list_style_none() -> Activity:
177
+ from microsoft_agents.activity import (
178
+ Activity as _Activity,
179
+ ActivityTypes as _AT,
180
+ )
181
+
182
+ activity = _Activity(type=_AT.message) # type: ignore[call-arg]
183
+ activity.text = text
184
+ return activity
185
+
186
+ def default() -> Activity:
187
+ return ChoiceFactory.for_channel(channel_id, choices, text, None, options)
188
+
189
+ # Maps to values in ListStyle Enum
190
+ switcher = {
191
+ 0: list_style_none,
192
+ 1: default,
193
+ 2: inline,
194
+ 3: list_style,
195
+ 4: suggested_action,
196
+ 5: hero_card,
197
+ }
198
+
199
+ msg = switcher.get(int(style), default)()
200
+
201
+ # Update prompt with text, actions and attachments
202
+ if prompt:
203
+ # clone the prompt set in the options
204
+ prompt = copy.copy(prompt)
205
+
206
+ prompt.text = msg.text
207
+
208
+ if (
209
+ msg.suggested_actions is not None
210
+ and msg.suggested_actions.actions is not None
211
+ and msg.suggested_actions.actions
212
+ ):
213
+ prompt.suggested_actions = msg.suggested_actions
214
+
215
+ if msg.attachments:
216
+ if prompt.attachments:
217
+ prompt.attachments.extend(msg.attachments)
218
+ else:
219
+ prompt.attachments = msg.attachments
220
+
221
+ return prompt
222
+
223
+ msg.input_hint = None # type: ignore[assignment]
224
+ return msg
@@ -0,0 +1,222 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from recognizers_text import Culture
5
+
6
+
7
+ class PromptCultureModel:
8
+ """
9
+ Culture model used in Choice and Confirm Prompts.
10
+ """
11
+
12
+ def __init__(
13
+ self,
14
+ locale: str,
15
+ separator: str,
16
+ inline_or: str,
17
+ inline_or_more: str,
18
+ yes_in_language: str,
19
+ no_in_language: str,
20
+ ):
21
+ """
22
+
23
+ :param locale: Culture Model's Locale. Example: "en-US".
24
+ :param separator: Culture Model's Inline Separator. Example: ", ".
25
+ :param inline_or: Culture Model's Inline Or. Example: " or ".
26
+ :param inline_or_more Culture Model's Inline Or More. Example: ", or ".
27
+ :param yes_in_language: Equivalent of "Yes" in Culture Model's Language. Example: "Yes".
28
+ :param no_in_language: Equivalent of "No" in Culture Model's Language. Example: "No".
29
+ """
30
+ self.locale = locale
31
+ self.separator = separator
32
+ self.inline_or = inline_or
33
+ self.inline_or_more = inline_or_more
34
+ self.yes_in_language = yes_in_language
35
+ self.no_in_language = no_in_language
36
+
37
+
38
+ class PromptCultureModels:
39
+ """
40
+ Class container for currently-supported Culture Models in Confirm and Choice Prompt.
41
+ """
42
+
43
+ Bulgarian = PromptCultureModel(
44
+ # TODO: Replace with Culture.Bulgarian after Recognizers-Text package updates.
45
+ locale="bg-bg",
46
+ inline_or=" или ",
47
+ inline_or_more=", или ",
48
+ separator=", ",
49
+ no_in_language="Не",
50
+ yes_in_language="да",
51
+ )
52
+
53
+ Chinese = PromptCultureModel(
54
+ locale=Culture.Chinese,
55
+ inline_or=" 要么 ",
56
+ inline_or_more=", 要么 ",
57
+ separator=", ",
58
+ no_in_language="不",
59
+ yes_in_language="是的",
60
+ )
61
+
62
+ Dutch = PromptCultureModel(
63
+ locale=Culture.Dutch,
64
+ inline_or=" of ",
65
+ inline_or_more=", of ",
66
+ separator=", ",
67
+ no_in_language="Nee",
68
+ yes_in_language="Ja",
69
+ )
70
+
71
+ English = PromptCultureModel(
72
+ locale=Culture.English,
73
+ inline_or=" or ",
74
+ inline_or_more=", or ",
75
+ separator=", ",
76
+ no_in_language="No",
77
+ yes_in_language="Yes",
78
+ )
79
+
80
+ Hindi = PromptCultureModel(
81
+ # TODO: Replace with Culture.Hindi after Recognizers-Text package updates.
82
+ locale="hi-in",
83
+ inline_or=" या ",
84
+ inline_or_more=", या ",
85
+ separator=", ",
86
+ no_in_language="नहीं",
87
+ yes_in_language="हां",
88
+ )
89
+
90
+ French = PromptCultureModel(
91
+ locale=Culture.French,
92
+ inline_or=" ou ",
93
+ inline_or_more=", ou ",
94
+ separator=", ",
95
+ no_in_language="Non",
96
+ yes_in_language="Oui",
97
+ )
98
+
99
+ German = PromptCultureModel(
100
+ # TODO: Replace with Culture.German after Recognizers-Text package updates.
101
+ locale="de-de",
102
+ inline_or=" oder ",
103
+ inline_or_more=", oder ",
104
+ separator=", ",
105
+ no_in_language="Nein",
106
+ yes_in_language="Ja",
107
+ )
108
+
109
+ Italian = PromptCultureModel(
110
+ locale=Culture.Italian,
111
+ inline_or=" o ",
112
+ inline_or_more=" o ",
113
+ separator=", ",
114
+ no_in_language="No",
115
+ yes_in_language="Si",
116
+ )
117
+
118
+ Japanese = PromptCultureModel(
119
+ locale=Culture.Japanese,
120
+ inline_or=" または ",
121
+ inline_or_more="、 または ",
122
+ separator="、 ",
123
+ no_in_language="いいえ",
124
+ yes_in_language="はい",
125
+ )
126
+
127
+ Korean = PromptCultureModel(
128
+ locale=Culture.Korean,
129
+ inline_or=" 또는 ",
130
+ inline_or_more=" 또는 ",
131
+ separator=", ",
132
+ no_in_language="아니",
133
+ yes_in_language="예",
134
+ )
135
+
136
+ Portuguese = PromptCultureModel(
137
+ locale=Culture.Portuguese,
138
+ inline_or=" ou ",
139
+ inline_or_more=", ou ",
140
+ separator=", ",
141
+ no_in_language="Não",
142
+ yes_in_language="Sim",
143
+ )
144
+
145
+ Spanish = PromptCultureModel(
146
+ locale=Culture.Spanish,
147
+ inline_or=" o ",
148
+ inline_or_more=", o ",
149
+ separator=", ",
150
+ no_in_language="No",
151
+ yes_in_language="Sí",
152
+ )
153
+
154
+ Swedish = PromptCultureModel(
155
+ # TODO: Replace with Culture.Swedish after Recognizers-Text package updates.
156
+ locale="sv-se",
157
+ inline_or=" eller ",
158
+ inline_or_more=" eller ",
159
+ separator=", ",
160
+ no_in_language="Nej",
161
+ yes_in_language="Ja",
162
+ )
163
+
164
+ Turkish = PromptCultureModel(
165
+ locale=Culture.Turkish,
166
+ inline_or=" veya ",
167
+ inline_or_more=" veya ",
168
+ separator=", ",
169
+ no_in_language="Hayır",
170
+ yes_in_language="Evet",
171
+ )
172
+
173
+ @classmethod
174
+ def map_to_nearest_language(cls, culture_code: str) -> str:
175
+ """
176
+ Normalize various potential locale strings to a standard.
177
+ :param culture_code: Represents locale. Examples: "en-US, en-us, EN".
178
+ :return: Normalized locale.
179
+ :rtype: str
180
+
181
+ .. remarks::
182
+ In our other SDKs, this method is a copy/paste of the ones from the Recognizers-Text library.
183
+ However, that doesn't exist in Python.
184
+ """
185
+ if culture_code:
186
+ culture_code = culture_code.lower()
187
+ supported_culture_codes = cls._get_supported_locales()
188
+
189
+ if culture_code not in supported_culture_codes:
190
+ culture_prefix = culture_code.split("-")[0]
191
+
192
+ for supported_culture_code in supported_culture_codes:
193
+ if supported_culture_code.startswith(culture_prefix):
194
+ culture_code = supported_culture_code
195
+
196
+ return culture_code
197
+
198
+ @classmethod
199
+ def get_supported_cultures(cls) -> list[PromptCultureModel]:
200
+ """
201
+ Gets a list of the supported culture models.
202
+ """
203
+ return [
204
+ cls.Bulgarian,
205
+ cls.Chinese,
206
+ cls.Dutch,
207
+ cls.English,
208
+ cls.French,
209
+ cls.German,
210
+ cls.Hindi,
211
+ cls.Italian,
212
+ cls.Japanese,
213
+ cls.Korean,
214
+ cls.Portuguese,
215
+ cls.Spanish,
216
+ cls.Swedish,
217
+ cls.Turkish,
218
+ ]
219
+
220
+ @classmethod
221
+ def _get_supported_locales(cls) -> list[str]:
222
+ return [c.locale for c in cls.get_supported_cultures()]
@@ -0,0 +1,42 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from microsoft_agents.activity import Activity
5
+ from microsoft_agents.hosting.dialogs.choices import Choice, ListStyle
6
+
7
+
8
+ class PromptOptions:
9
+ """
10
+ Contains settings to pass to a :class:`Prompt` object when the prompt is started.
11
+ """
12
+
13
+ def __init__(
14
+ self,
15
+ prompt: Activity | None = None,
16
+ retry_prompt: Activity | None = None,
17
+ choices: list[Choice] | None = None,
18
+ style: ListStyle | None = None,
19
+ validations: object = None,
20
+ number_of_attempts: int = 0,
21
+ ):
22
+ """
23
+ Contains settings to pass to a :class:`Prompt` when the prompt is started.
24
+
25
+ :param prompt: The initial prompt activity to send to the user.
26
+ :type prompt: :class:`microsoft_agents.activity.Activity`
27
+ :param retry_prompt: The activity to send when the user's input fails validation.
28
+ :type retry_prompt: :class:`microsoft_agents.activity.Activity`
29
+ :param choices: The list of choices presented to the user (used by :class:`ChoicePrompt`).
30
+ :type choices: list[:class:`microsoft_agents.hosting.dialogs.choices.Choice`]
31
+ :param style: Controls how the choice list is rendered.
32
+ :type style: :class:`microsoft_agents.hosting.dialogs.choices.ListStyle`
33
+ :param validations: Additional validation data passed through to a custom validator.
34
+ :param number_of_attempts: Running count of how many times the prompt has been retried.
35
+ :type number_of_attempts: int
36
+ """
37
+ self.prompt = prompt
38
+ self.retry_prompt = retry_prompt
39
+ self.choices = choices
40
+ self.style = style
41
+ self.validations = validations
42
+ self.number_of_attempts = number_of_attempts
@@ -0,0 +1,11 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ """Result returned by a prompts recognizer function."""
5
+
6
+
7
+ class PromptRecognizerResult:
8
+ def __init__(self, succeeded: bool = False, value: object = None):
9
+ """Creates result returned by a prompts recognizer function."""
10
+ self.succeeded = succeeded
11
+ self.value = value
@@ -0,0 +1,44 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+ from typing import Dict, cast
4
+ from microsoft_agents.hosting.core import TurnContext
5
+ from .prompt_options import PromptOptions
6
+ from .prompt_recognizer_result import PromptRecognizerResult
7
+
8
+
9
+ class PromptValidatorContext:
10
+ def __init__(
11
+ self,
12
+ turn_context: TurnContext,
13
+ recognized: PromptRecognizerResult,
14
+ state: Dict[str, object],
15
+ options: PromptOptions,
16
+ ):
17
+ """Creates contextual information passed to a custom `PromptValidator`.
18
+ Parameters
19
+ ----------
20
+ turn_context
21
+ The context for the current turn of conversation with the user.
22
+ recognized
23
+ Result returned from the prompts recognizer function.
24
+ state
25
+ A dictionary of values persisted for each conversational turn while the prompt is active.
26
+ options
27
+ Original set of options passed to the prompt by the calling dialog.
28
+ """
29
+ self.context = turn_context
30
+ self.recognized = recognized
31
+ self.state = state
32
+ self.options = options
33
+
34
+ @property
35
+ def attempt_count(self) -> int:
36
+ """Gets the number of times the validator has been called for this prompt.
37
+
38
+ The counter starts at 1 on the first validation call and increments with
39
+ each subsequent user reply.
40
+ """
41
+ # pylint: disable=import-outside-toplevel
42
+ from microsoft_agents.hosting.dialogs.prompts.prompt import Prompt
43
+
44
+ return int(cast(int, self.state.get(Prompt.ATTEMPT_COUNT_KEY, 0)))
@@ -0,0 +1,82 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from microsoft_agents.hosting.core import TurnContext
5
+ from microsoft_agents.activity import ActivityTypes
6
+
7
+ from .prompt import Prompt
8
+ from .prompt_options import PromptOptions
9
+ from .prompt_recognizer_result import PromptRecognizerResult
10
+
11
+
12
+ class TextPrompt(Prompt):
13
+ """Prompts a user to enter any text.
14
+
15
+ Succeeds whenever the user sends a message activity whose ``text`` field is
16
+ not ``None``. Empty strings are accepted as valid because some channels
17
+ send an empty ``text`` alongside attachments. There is no built-in
18
+ recognizer: the raw ``activity.text`` string is returned as the result.
19
+
20
+ Pass an optional ``validator`` at construction time to apply additional
21
+ constraints (e.g. minimum length, allow-list, non-empty enforcement).
22
+
23
+ .. note::
24
+ Non-message activities and messages where ``activity.text`` is ``None``
25
+ cause recognition to fail and will trigger the retry prompt if one was
26
+ provided.
27
+ """
28
+
29
+ async def on_prompt(
30
+ self,
31
+ turn_context: TurnContext,
32
+ state: dict[str, object],
33
+ options: PromptOptions,
34
+ is_retry: bool,
35
+ ):
36
+ """Sends the initial or retry prompt activity to the user.
37
+
38
+ :param turn_context: The context for the current turn.
39
+ :param state: Persisted prompt state (unused by TextPrompt).
40
+ :param options: Prompt options containing the prompt and optional retry prompt.
41
+ :param is_retry: ``True`` when re-prompting after a failed validation.
42
+ """
43
+ if not turn_context:
44
+ raise TypeError("TextPrompt.on_prompt(): turn_context cannot be None.")
45
+ if not options:
46
+ raise TypeError("TextPrompt.on_prompt(): options cannot be None.")
47
+
48
+ if is_retry and options.retry_prompt is not None:
49
+ await turn_context.send_activity(options.retry_prompt)
50
+ else:
51
+ if options.prompt is not None:
52
+ await turn_context.send_activity(options.prompt)
53
+
54
+ async def on_recognize(
55
+ self,
56
+ turn_context: TurnContext,
57
+ state: dict[str, object],
58
+ options: PromptOptions,
59
+ ) -> PromptRecognizerResult:
60
+ """Attempts to recognise text from the incoming activity.
61
+
62
+ Succeeds only when the activity is a message **and** ``activity.text``
63
+ is not ``None``. Empty strings are considered valid (``succeeded=True``
64
+ with an empty string value), since some channels send empty text with
65
+ attachments.
66
+
67
+ :param turn_context: The context for the current turn.
68
+ :param state: Persisted prompt state (unused by TextPrompt).
69
+ :param options: Prompt options (unused by TextPrompt).
70
+ :return: Recognition result with ``succeeded=True`` and the raw text when
71
+ a message with text is received; ``succeeded=False`` otherwise.
72
+ """
73
+ if not turn_context:
74
+ raise TypeError("TextPrompt.on_recognize(): turn_context cannot be None.")
75
+
76
+ result = PromptRecognizerResult()
77
+ if turn_context.activity.type == ActivityTypes.message:
78
+ message = turn_context.activity
79
+ if message.text is not None:
80
+ result.succeeded = True
81
+ result.value = message.text
82
+ return result