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,92 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from .models.token import Token
5
+
6
+
7
+ class Tokenizer:
8
+ """Provides a default tokenizer implementation."""
9
+
10
+ @staticmethod
11
+ def default_tokenizer( # pylint: disable=unused-argument
12
+ text: str, locale: str | None = None
13
+ ) -> list[Token]:
14
+ """
15
+ Simple tokenizer that breaks on spaces and punctuation. The only normalization is to lowercase.
16
+
17
+ Parameter:
18
+ ---------
19
+
20
+ text: The input text.
21
+
22
+ locale: (Optional) Identifies the locale of the input text.
23
+ """
24
+ tokens: list[Token] = []
25
+ token: Token | None = None
26
+
27
+ # Parse text
28
+ length: int = len(text) if text else 0
29
+ i: int = 0
30
+
31
+ while i < length:
32
+ # Get both the UNICODE value of the current character and the complete character itself
33
+ # which can potentially be multiple segments
34
+ code_point = ord(text[i])
35
+ char = chr(code_point)
36
+
37
+ # Process current character
38
+ if Tokenizer._is_breaking_char(code_point):
39
+ # Character is in Unicode Plane 0 and is in an excluded block
40
+ Tokenizer._append_token(tokens, token, i - 1)
41
+ token = None
42
+ elif code_point > 0xFFFF:
43
+ # Character is in a Supplementary Unicode Plane. This is where emoji live so
44
+ # we're going to just break each character in this range out as its own token
45
+ Tokenizer._append_token(tokens, token, i - 1)
46
+ token = None
47
+ tokens.append(Token(start=i, end=i, text=char, normalized=char))
48
+ elif token is None:
49
+ # Start a new token
50
+ token = Token(start=i, end=0, text=char, normalized=None)
51
+ else:
52
+ # Add onto current token
53
+ token.text += char
54
+
55
+ i += 1
56
+
57
+ Tokenizer._append_token(tokens, token, length - 1)
58
+
59
+ return tokens
60
+
61
+ @staticmethod
62
+ def _is_breaking_char(code_point) -> bool:
63
+ return (
64
+ Tokenizer._is_between(code_point, 0x0000, 0x002F)
65
+ or Tokenizer._is_between(code_point, 0x003A, 0x0040)
66
+ or Tokenizer._is_between(code_point, 0x005B, 0x0060)
67
+ or Tokenizer._is_between(code_point, 0x007B, 0x00BF)
68
+ or Tokenizer._is_between(code_point, 0x02B9, 0x036F)
69
+ or Tokenizer._is_between(code_point, 0x2000, 0x2BFF)
70
+ or Tokenizer._is_between(code_point, 0x2E00, 0x2E7F)
71
+ )
72
+
73
+ @staticmethod
74
+ def _is_between(value: int, from_val: int, to_val: int) -> bool:
75
+ """
76
+ Parameters
77
+ -----------
78
+
79
+ value: number value
80
+
81
+ from: low range
82
+
83
+ to: high range
84
+ """
85
+ return from_val <= value <= to_val
86
+
87
+ @staticmethod
88
+ def _append_token(tokens: list[Token], token: Token | None, end: int):
89
+ if token is not None:
90
+ token.end = end
91
+ token.normalized = token.text.lower()
92
+ tokens.append(token)
@@ -0,0 +1,284 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from typing import Any
5
+
6
+ from microsoft_agents.hosting.core import TurnContext
7
+
8
+ from .dialog import Dialog
9
+ from .dialog_context import DialogContext
10
+ from .models.dialog_turn_result import DialogTurnResult
11
+ from .dialog_state import DialogState
12
+ from .models.dialog_turn_status import DialogTurnStatus
13
+ from .models.dialog_reason import DialogReason
14
+ from .dialog_set import DialogSet
15
+ from .models.dialog_instance import DialogInstance
16
+
17
+
18
+ class ComponentDialog(Dialog):
19
+ """
20
+ A :class:`microsoft_agents.hosting.dialogs.Dialog` that is composed of other dialogs
21
+
22
+ :var persisted_dialog state:
23
+ :vartype persisted_dialog_state: str
24
+ """
25
+
26
+ persisted_dialog_state = "dialogs"
27
+
28
+ def __init__(self, dialog_id: str):
29
+ """
30
+ Initializes a new instance of the :class:`ComponentDialog`
31
+
32
+ :param dialog_id: The ID to assign to the new dialog within the parent dialog set.
33
+ :type dialog_id: str
34
+ """
35
+ super(ComponentDialog, self).__init__(dialog_id)
36
+
37
+ if dialog_id is None:
38
+ raise TypeError("ComponentDialog(): dialog_id cannot be None.")
39
+
40
+ self._dialogs = DialogSet()
41
+ self.initial_dialog_id = None
42
+
43
+ # TODO: Add TelemetryClient
44
+
45
+ async def begin_dialog(
46
+ self, dialog_context: DialogContext, options: Any = None
47
+ ) -> DialogTurnResult:
48
+ """
49
+ Called when the dialog is started and pushed onto the parent's dialog stack.
50
+
51
+ If the task is successful, the result indicates whether the dialog is still
52
+ active after the turn has been processed by the dialog.
53
+
54
+ :param dialog_context: The :class:`botbuilder.dialogs.DialogContext` for the current turn of the conversation.
55
+ :type dialog_context: :class:`botbuilder.dialogs.DialogContext`
56
+ :param options: Optional, initial information to pass to the dialog.
57
+ :type options: Any
58
+ :return: Signals the end of the turn
59
+ :rtype: :class:`microsoft_agents.hosting.dialogs.Dialog.end_of_turn`
60
+ """
61
+ if dialog_context is None:
62
+ raise TypeError("ComponentDialog.begin_dialog(): outer_dc cannot be None.")
63
+
64
+ # Start the inner dialog.
65
+ dialog_state = DialogState()
66
+ assert dialog_context.active_dialog is not None
67
+ dialog_context.active_dialog.state[self.persisted_dialog_state] = dialog_state
68
+ inner_dc = DialogContext(self._dialogs, dialog_context.context, dialog_state)
69
+ inner_dc.parent = dialog_context
70
+ turn_result = await self.on_begin_dialog(inner_dc, options)
71
+
72
+ # Check for end of inner dialog
73
+ if turn_result.status != DialogTurnStatus.Waiting:
74
+ # Return result to calling dialog
75
+ return await self.end_component(dialog_context, turn_result.result)
76
+
77
+ # Just signal waiting
78
+ return Dialog.end_of_turn
79
+
80
+ async def continue_dialog(self, dialog_context: DialogContext) -> DialogTurnResult:
81
+ """
82
+ Called when the dialog is continued, where it is the active dialog and the
83
+ user replies with a new activity.
84
+
85
+ .. remarks::
86
+ If the task is successful, the result indicates whether the dialog is still
87
+ active after the turn has been processed by the dialog. The result may also
88
+ contain a return value.
89
+
90
+ If this method is *not* overriden the component dialog calls the
91
+ :meth:`microsoft_agents.hosting.dialogs.DialogContext.continue_dialog` method on it's inner dialog
92
+ context. If the inner dialog stack is empty, the component dialog ends,
93
+ and if a :class:`microsoft_agents.hosting.dialogs.DialogTurnResult.result` is available, the component dialog
94
+ uses that as it's return value.
95
+
96
+
97
+ :param dialog_context: The parent dialog context for the current turn of the conversation.
98
+ :type dialog_context: :class:`microsoft_agents.hosting.dialogs.DialogContext`
99
+ :return: Signals the end of the turn
100
+ :rtype: :class:`microsoft_agents.hosting.dialogs.Dialog.end_of_turn`
101
+ """
102
+ if dialog_context is None:
103
+ raise TypeError("ComponentDialog.begin_dialog(): outer_dc cannot be None.")
104
+
105
+ # Continue execution of inner dialog.
106
+ assert dialog_context.active_dialog is not None
107
+ dialog_state = dialog_context.active_dialog.state[self.persisted_dialog_state]
108
+ inner_dc = DialogContext(self._dialogs, dialog_context.context, dialog_state)
109
+ inner_dc.parent = dialog_context
110
+ turn_result = await self.on_continue_dialog(inner_dc)
111
+
112
+ if turn_result.status != DialogTurnStatus.Waiting:
113
+ return await self.end_component(dialog_context, turn_result.result)
114
+
115
+ return Dialog.end_of_turn
116
+
117
+ async def resume_dialog(
118
+ self, dialog_context: DialogContext, reason: DialogReason, result: object = None
119
+ ) -> DialogTurnResult:
120
+ """
121
+ Called when a child dialog on the parent's dialog stack completed this turn, returning
122
+ control to this dialog component.
123
+
124
+ .. remarks::
125
+ Containers are typically leaf nodes on the stack but the dev is free to push other dialogs
126
+ on top of the stack which will result in the container receiving an unexpected call to
127
+ :meth:`ComponentDialog.resume_dialog()` when the pushed on dialog ends.
128
+ To avoid the container prematurely ending we need to implement this method and simply
129
+ ask our inner dialog stack to re-prompt.
130
+
131
+ :param dialog_context: The dialog context for the current turn of the conversation.
132
+ :type dialog_context: :class:`microsoft_agents.hosting.dialogs.DialogContext`
133
+ :param reason: Reason why the dialog resumed.
134
+ :type reason: :class:`microsoft_agents.hosting.dialogs.DialogReason`
135
+ :param result: Optional, value returned from the dialog that was called.
136
+ :type result: object
137
+ :return: Signals the end of the turn
138
+ :rtype: :class:`microsoft_agents.hosting.dialogs.Dialog.end_of_turn`
139
+ """
140
+
141
+ assert dialog_context.active_dialog is not None
142
+ await self.reprompt_dialog(dialog_context.context, dialog_context.active_dialog)
143
+ return Dialog.end_of_turn
144
+
145
+ async def reprompt_dialog(
146
+ self, context: TurnContext, instance: DialogInstance
147
+ ) -> None:
148
+ """
149
+ Called when the dialog should re-prompt the user for input.
150
+
151
+ :param context: The context object for this turn.
152
+ :type context: :class:`microsoft_agents.hosting.dialogs.TurnContext`
153
+ :param instance: State information for this dialog.
154
+ :type instance: :class:`microsoft_agents.hosting.dialogs.DialogInstance`
155
+ """
156
+ # Delegate to inner dialog.
157
+ dialog_state = instance.state[self.persisted_dialog_state]
158
+ inner_dc = DialogContext(self._dialogs, context, dialog_state)
159
+ await inner_dc.reprompt_dialog()
160
+
161
+ # Notify component
162
+ await self.on_reprompt_dialog(context, instance)
163
+
164
+ async def end_dialog(
165
+ self, context: TurnContext, instance: DialogInstance, reason: DialogReason
166
+ ) -> None:
167
+ """
168
+ Called when the dialog is ending.
169
+
170
+ :param context: The context object for this turn.
171
+ :type context: :class:`microsoft_agents.hosting.dialogs.TurnContext`
172
+ :param instance: State information associated with the instance of this component dialog.
173
+ :type instance: :class:`microsoft_agents.hosting.dialogs.DialogInstance`
174
+ :param reason: Reason why the dialog ended.
175
+ :type reason: :class:`microsoft_agents.hosting.dialogs.DialogReason`
176
+ """
177
+ # Forward cancel to inner dialog
178
+ if reason == DialogReason.CancelCalled:
179
+ dialog_state = instance.state[self.persisted_dialog_state]
180
+ inner_dc = DialogContext(self._dialogs, context, dialog_state)
181
+ await inner_dc.cancel_all_dialogs()
182
+ await self.on_end_dialog(context, instance, reason)
183
+
184
+ def add_dialog(self, dialog: Dialog) -> object:
185
+ """
186
+ Adds a :class:`Dialog` to the component dialog and returns the updated component.
187
+
188
+ :param dialog: The dialog to add.
189
+ :return: The updated :class:`ComponentDialog`.
190
+ :rtype: :class:`ComponentDialog`
191
+ """
192
+ self._dialogs.add(dialog)
193
+ if not self.initial_dialog_id:
194
+ self.initial_dialog_id = dialog.id
195
+ return self
196
+
197
+ async def find_dialog(self, dialog_id: str | None) -> Dialog | None:
198
+ """
199
+ Finds a dialog by ID.
200
+
201
+ :param dialog_id: The dialog to add.
202
+ :return: The dialog; or None if there is not a match for the ID.
203
+ :rtype: :class:`botbuilder.dialogs.Dialog`
204
+ """
205
+ return await self._dialogs.find(dialog_id)
206
+
207
+ async def on_begin_dialog(
208
+ self, inner_dc: DialogContext, options: object
209
+ ) -> DialogTurnResult:
210
+ """
211
+ Called when the dialog is started and pushed onto the parent's dialog stack.
212
+
213
+ .. remarks::
214
+ If the task is successful, the result indicates whether the dialog is still
215
+ active after the turn has been processed by the dialog.
216
+
217
+ By default, this calls the :meth:`microsoft_agents.hosting.dialogs.Dialog.begin_dialog()`
218
+ method of the component dialog's initial dialog.
219
+
220
+ Override this method in a derived class to implement interrupt logic.
221
+
222
+ :param inner_dc: The inner dialog context for the current turn of conversation.
223
+ :type inner_dc: :class:`microsoft_agents.hosting.dialogs.DialogContext`
224
+ :param options: Optional, initial information to pass to the dialog.
225
+ :type options: object
226
+ """
227
+ assert (
228
+ self.initial_dialog_id is not None
229
+ ), "ComponentDialog: initial_dialog_id must be set before begin_dialog is called."
230
+ return await inner_dc.begin_dialog(self.initial_dialog_id, options)
231
+
232
+ async def on_continue_dialog(self, inner_dc: DialogContext) -> DialogTurnResult:
233
+ """
234
+ Called when the dialog is continued, where it is the active dialog and the user replies with a new activity.
235
+
236
+ :param inner_dc: The inner dialog context for the current turn of conversation.
237
+ :type inner_dc: :class:`botbuilder.dialogs.DialogContext`
238
+ """
239
+ return await inner_dc.continue_dialog()
240
+
241
+ async def on_end_dialog( # pylint: disable=unused-argument
242
+ self, context: TurnContext, instance: DialogInstance, reason: DialogReason
243
+ ) -> None:
244
+ """
245
+ Ends the component dialog in its parent's context.
246
+
247
+ :param turn_context: The :class:`botbuilder.core.TurnContext` for the current turn of the conversation.
248
+ :type turn_context: :class:`botbuilder.core.TurnContext`
249
+ :param instance: State information associated with the inner dialog stack of this component dialog.
250
+ :type instance: :class:`botbuilder.dialogs.DialogInstance`
251
+ :param reason: Reason why the dialog ended.
252
+ :type reason: :class:`botbuilder.dialogs.DialogReason`
253
+ """
254
+ return
255
+
256
+ async def on_reprompt_dialog( # pylint: disable=unused-argument
257
+ self, turn_context: TurnContext, instance: DialogInstance
258
+ ) -> None:
259
+ """
260
+ :param turn_context: The :class:`botbuilder.core.TurnContext` for the current turn of the conversation.
261
+ :type turn_context: :class:`botbuilder.dialogs.DialogInstance`
262
+ :param instance: State information associated with the inner dialog stack of this component dialog.
263
+ :type instance: :class:`botbuilder.dialogs.DialogInstance`
264
+ """
265
+ return
266
+
267
+ async def end_component(
268
+ self, outer_dc: DialogContext, result: object # pylint: disable=unused-argument
269
+ ) -> DialogTurnResult:
270
+ """
271
+ Ends the component dialog in its parent's context.
272
+
273
+ .. remarks::
274
+ If the task is successful, the result indicates that the dialog ended after the
275
+ turn was processed by the dialog.
276
+
277
+ :param outer_dc: The parent dialog context for the current turn of conversation.
278
+ :type outer_dc: class:`botbuilder.dialogs.DialogContext`
279
+ :param result: Optional, value to return from the dialog component to the parent context.
280
+ :type result: object
281
+ :return: Value to return.
282
+ :rtype: :class:`botbuilder.dialogs.DialogTurnResult.result`
283
+ """
284
+ return await outer_dc.end_dialog(result)
@@ -0,0 +1,198 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from __future__ import annotations
5
+
6
+ from abc import ABC, abstractmethod
7
+ from typing import TYPE_CHECKING
8
+
9
+ from microsoft_agents.hosting.core import TurnContext
10
+
11
+ from ._telemetry_client import AgentTelemetryClient, NullTelemetryClient
12
+ from .models.dialog_reason import DialogReason
13
+ from .models.dialog_event import DialogEvent
14
+ from .models.dialog_turn_status import DialogTurnStatus
15
+ from .models.dialog_turn_result import DialogTurnResult
16
+ from .models.dialog_instance import DialogInstance
17
+
18
+ if TYPE_CHECKING:
19
+ from .dialog_context import DialogContext
20
+
21
+
22
+ class Dialog(ABC):
23
+
24
+ def __init__(self, dialog_id: str):
25
+ if dialog_id is None or not dialog_id.strip():
26
+ raise TypeError("Dialog(): dialogId cannot be None.")
27
+
28
+ self._telemetry_client = NullTelemetryClient()
29
+ self._id = dialog_id
30
+
31
+ end_of_turn = DialogTurnResult(DialogTurnStatus.Waiting)
32
+ """DialogTurnResult indicating the dialog is waiting for new activity."""
33
+
34
+ @property
35
+ def id(self) -> str: # pylint: disable=invalid-name
36
+ return self._id
37
+
38
+ @property
39
+ def telemetry_client(self) -> AgentTelemetryClient:
40
+ """
41
+ Gets the telemetry client for logging events.
42
+ """
43
+ return self._telemetry_client
44
+
45
+ @telemetry_client.setter
46
+ def telemetry_client(self, value: AgentTelemetryClient) -> None:
47
+ """
48
+ Sets the telemetry client for logging events.
49
+ """
50
+ if value is None:
51
+ self._telemetry_client = NullTelemetryClient()
52
+ else:
53
+ self._telemetry_client = value
54
+
55
+ @abstractmethod
56
+ async def begin_dialog(
57
+ self, dialog_context: "DialogContext", options: object = None
58
+ ):
59
+ """
60
+ Method called when a new dialog has been pushed onto the stack and is being activated.
61
+ :param dialog_context: The dialog context for the current turn of conversation.
62
+ :param options: (Optional) additional argument(s) to pass to the dialog being started.
63
+ """
64
+ raise NotImplementedError()
65
+
66
+ async def continue_dialog(self, dialog_context: "DialogContext"):
67
+ """
68
+ Method called when an instance of the dialog is the "current" dialog and the
69
+ user replies with a new activity. The dialog will generally continue to receive the user's
70
+ replies until it calls either `end_dialog()` or `begin_dialog()`.
71
+ If this method is NOT implemented then the dialog will automatically be ended when the user replies.
72
+ :param dialog_context: The dialog context for the current turn of conversation.
73
+ :return:
74
+ """
75
+ # By default just end the current dialog.
76
+ return await dialog_context.end_dialog(None)
77
+
78
+ async def resume_dialog( # pylint: disable=unused-argument
79
+ self, dialog_context: "DialogContext", reason: DialogReason, result: object
80
+ ):
81
+ """
82
+ Method called when an instance of the dialog is being returned to from another
83
+ dialog that was started by the current instance using `begin_dialog()`.
84
+ If this method is NOT implemented then the dialog will be automatically ended with a call
85
+ to `end_dialog()`. Any result passed from the called dialog will be passed
86
+ to the current dialog's parent. If there are no more parent dialogs on the stack then
87
+ processing of the turn will end.
88
+ :param dialog_context: The dialog context for the current turn of conversation.
89
+ :param reason: Reason why the dialog resumed.
90
+ :param result: (Optional) value returned from the dialog that was called.
91
+ :return:
92
+ """
93
+ # By default just end the current dialog and return result to parent.
94
+ return await dialog_context.end_dialog(result)
95
+
96
+ async def reprompt_dialog( # pylint: disable=unused-argument
97
+ self, context: TurnContext, instance: DialogInstance
98
+ ):
99
+ """Called when the dialog should re-prompt the user for input.
100
+
101
+ Override this method to send a repeat of the most recent prompt activity.
102
+ The default implementation is a no-op.
103
+
104
+ :param context: The context for the current turn.
105
+ :param instance: The dialog instance on the stack.
106
+ """
107
+ # No-op by default
108
+ return
109
+
110
+ async def end_dialog( # pylint: disable=unused-argument
111
+ self, context: TurnContext, instance: DialogInstance, reason: DialogReason
112
+ ):
113
+ """Called when the dialog is ending. Override to perform cleanup or send an
114
+ EndOfConversation activity.
115
+
116
+ The default implementation is a no-op; subclasses should call ``super()``
117
+ only if they need the no-op behaviour to remain in derived chains.
118
+
119
+ :param context: The context for the current turn.
120
+ :param instance: The dialog instance being ended.
121
+ :param reason: Why the dialog is ending (EndCalled, CancelCalled, or ReplaceCalled).
122
+ """
123
+ # No-op by default
124
+ return
125
+
126
+ def get_version(self) -> str:
127
+ """Gets a string that uniquely describes this dialog's version. Changing the version
128
+ indicates that a stored instance of the dialog may be incompatible with the current
129
+ definition. By default this returns the dialog's ID.
130
+
131
+ :return: Version string for this dialog.
132
+ """
133
+ return self.id
134
+
135
+ async def on_dialog_event(
136
+ self, dialog_context: "DialogContext", dialog_event: DialogEvent
137
+ ) -> bool:
138
+ """
139
+ Called when an event has been raised, using `DialogContext.emitEvent()`, by either the current dialog or a
140
+ dialog that the current dialog started.
141
+ :param dialog_context: The dialog context for the current turn of conversation.
142
+ :param dialog_event: The event being raised.
143
+ :return: True if the event is handled by the current dialog and bubbling should stop.
144
+ """
145
+ # Before bubble
146
+ handled = await self._on_pre_bubble_event(dialog_context, dialog_event)
147
+
148
+ # Bubble as needed
149
+ if (not handled) and dialog_event.bubble and dialog_context.parent:
150
+ handled = await dialog_context.parent.emit_event(
151
+ dialog_event.name, dialog_event.value, True, False
152
+ )
153
+
154
+ # Post bubble
155
+ if not handled:
156
+ handled = await self._on_post_bubble_event(dialog_context, dialog_event)
157
+
158
+ return handled
159
+
160
+ async def _on_pre_bubble_event( # pylint: disable=unused-argument
161
+ self, dialog_context: "DialogContext", dialog_event: DialogEvent
162
+ ) -> bool:
163
+ """
164
+ Called before an event is bubbled to its parent.
165
+ :param dialog_context: The dialog context for the current turn of conversation.
166
+ :param dialog_event: The event being raised.
167
+ :return: Whether the event is handled by the current dialog and further processing should stop.
168
+ """
169
+ return False
170
+
171
+ async def _on_post_bubble_event( # pylint: disable=unused-argument
172
+ self, dialog_context: "DialogContext", dialog_event: DialogEvent
173
+ ) -> bool:
174
+ """
175
+ Called after an event was bubbled to all parents and wasn't handled.
176
+ :param dialog_context: The dialog context for the current turn of conversation.
177
+ :param dialog_event: The event being raised.
178
+ :return: Whether the event is handled by the current dialog and further processing should stop.
179
+ """
180
+ return False
181
+
182
+ def _on_compute_id(self) -> str:
183
+ """
184
+ Computes an unique ID for a dialog.
185
+ :return: An unique ID for a dialog
186
+ """
187
+ return self.__class__.__name__
188
+
189
+ def _register_source_location(
190
+ self, path: str, line_number: int
191
+ ): # pylint: disable=unused-argument
192
+ """
193
+ Registers a SourceRange in the provided location.
194
+ :param path: The path to the source file.
195
+ :param line_number: The line number where the source will be located on the file.
196
+ """
197
+ if path:
198
+ pass
@@ -0,0 +1,52 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from typing import Iterable
5
+
6
+ from microsoft_agents.hosting.dialogs.memory import (
7
+ ComponentMemoryScopesBase,
8
+ ComponentPathResolversBase,
9
+ PathResolverBase,
10
+ )
11
+ from microsoft_agents.hosting.dialogs.memory.scopes import (
12
+ TurnMemoryScope,
13
+ SettingsMemoryScope,
14
+ DialogMemoryScope,
15
+ DialogContextMemoryScope,
16
+ DialogClassMemoryScope,
17
+ ClassMemoryScope,
18
+ MemoryScope,
19
+ ThisMemoryScope,
20
+ ConversationMemoryScope,
21
+ UserMemoryScope,
22
+ )
23
+
24
+ from microsoft_agents.hosting.dialogs.memory.path_resolvers import (
25
+ AtAtPathResolver,
26
+ AtPathResolver,
27
+ DollarPathResolver,
28
+ HashPathResolver,
29
+ PercentPathResolver,
30
+ )
31
+
32
+
33
+ class DialogsComponentRegistration(
34
+ ComponentMemoryScopesBase, ComponentPathResolversBase
35
+ ):
36
+ def get_memory_scopes(self) -> Iterable[MemoryScope]:
37
+ yield TurnMemoryScope()
38
+ yield SettingsMemoryScope()
39
+ yield DialogMemoryScope()
40
+ yield DialogContextMemoryScope()
41
+ yield DialogClassMemoryScope()
42
+ yield ClassMemoryScope()
43
+ yield ThisMemoryScope()
44
+ yield ConversationMemoryScope()
45
+ yield UserMemoryScope()
46
+
47
+ def get_path_resolvers(self) -> Iterable[PathResolverBase]:
48
+ yield AtAtPathResolver()
49
+ yield AtPathResolver()
50
+ yield DollarPathResolver()
51
+ yield HashPathResolver()
52
+ yield PercentPathResolver()
@@ -0,0 +1,31 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from __future__ import annotations
5
+
6
+ from abc import ABC, abstractmethod
7
+ from typing import TYPE_CHECKING
8
+
9
+ from .dialog import Dialog
10
+ from .dialog_set import DialogSet
11
+
12
+ if TYPE_CHECKING:
13
+ from .dialog_context import DialogContext
14
+
15
+
16
+ class DialogContainer(Dialog, ABC):
17
+
18
+ def __init__(self, dialog_id: str):
19
+ super().__init__(dialog_id)
20
+ self.dialogs = DialogSet()
21
+
22
+ @abstractmethod
23
+ def create_child_context(self, dialog_context: DialogContext) -> DialogContext:
24
+ """
25
+ Creates the inner dialog context for the active child dialog, if there is one.
26
+ :param dialog_context: The parent dialog context.
27
+ :return: The child dialog context, or None if there is no active child.
28
+ """
29
+ raise NotImplementedError(
30
+ "DialogContainer.create_child_context(): not implemented."
31
+ )