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,44 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from .alias_path_resolver import AliasPathResolver
5
+
6
+
7
+ class AtPathResolver(AliasPathResolver):
8
+ _DELIMITERS = [".", "["]
9
+
10
+ def __init__(self):
11
+ super().__init__(alias="@", prefix="")
12
+
13
+ self._PREFIX = "turn.recognized.entities." # pylint: disable=invalid-name
14
+
15
+ def transform_path(self, path: str):
16
+ if not path:
17
+ raise TypeError(f"Expecting: path, but received None")
18
+
19
+ path = path.strip()
20
+ if (
21
+ path.startswith("@")
22
+ and len(path) > 1
23
+ and AtPathResolver._is_path_char(path[1])
24
+ ):
25
+ end = AtPathResolver._index_of_any(path[1:], AtPathResolver._DELIMITERS)
26
+ if end == -1:
27
+ end = len(path) - 1
28
+ # +1 to offset the leading '@' we skipped in the search
29
+ end += 1
30
+
31
+ prop = path[1:end]
32
+ suffix = path[end:]
33
+ path = f"{self._PREFIX}{prop}.first(){suffix}"
34
+
35
+ return path
36
+
37
+ @staticmethod
38
+ def _index_of_any(string: str, elements_to_search_for) -> int:
39
+ for element in elements_to_search_for:
40
+ index = string.find(element)
41
+ if index != -1:
42
+ return index
43
+
44
+ return -1
@@ -0,0 +1,9 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from .alias_path_resolver import AliasPathResolver
5
+
6
+
7
+ class DollarPathResolver(AliasPathResolver):
8
+ def __init__(self):
9
+ super().__init__(alias="$", prefix="dialog.")
@@ -0,0 +1,9 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from .alias_path_resolver import AliasPathResolver
5
+
6
+
7
+ class HashPathResolver(AliasPathResolver):
8
+ def __init__(self):
9
+ super().__init__(alias="#", prefix="turn.recognized.intents.")
@@ -0,0 +1,9 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from .alias_path_resolver import AliasPathResolver
5
+
6
+
7
+ class PercentPathResolver(AliasPathResolver):
8
+ def __init__(self):
9
+ super().__init__(alias="%", prefix="class.")
@@ -0,0 +1,38 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ # User memory scope root path.
5
+ # <remarks>This property is deprecated, use ScopePath.User instead.</remarks>
6
+ USER = "user"
7
+
8
+ # Conversation memory scope root path.
9
+ # <remarks>This property is deprecated, use ScopePath.Conversation instead.</remark
10
+ CONVERSATION = "conversation"
11
+
12
+ # Dialog memory scope root path.
13
+ # <remarks>This property is deprecated, use ScopePath.Dialog instead.</remark
14
+ DIALOG = "dialog"
15
+
16
+ # DialogClass memory scope root path.
17
+ # <remarks>This property is deprecated, use ScopePath.DialogClass instead.</remark
18
+ DIALOG_CLASS = "dialogclass"
19
+
20
+ # This memory scope root path.
21
+ # <remarks>This property is deprecated, use ScopePath.This instead.</remark
22
+ THIS = "this"
23
+
24
+ # Class memory scope root path.
25
+ # <remarks>This property is deprecated, use ScopePath.Class instead.</remarks>
26
+ CLASS = "class"
27
+
28
+ # Settings memory scope root path.
29
+ # <remarks>This property is deprecated, use ScopePath.Settings instead.</remarks>
30
+
31
+ SETTINGS = "settings"
32
+
33
+ # Turn memory scope root path.
34
+ # <remarks>This property is deprecated, use ScopePath.Turn instead.</remarks>
35
+ TURN = "turn"
36
+
37
+ # DialogContext memory scope root path.
38
+ DIALOG_CONTEXT = "dialogContext"
@@ -0,0 +1,31 @@
1
+ # coding=utf-8
2
+ # --------------------------------------------------------------------------
3
+ # Copyright (c) Microsoft Corporation. All rights reserved.
4
+ # Licensed under the MIT License. See License.txt in the project root for
5
+ # license information.
6
+ # --------------------------------------------------------------------------
7
+ from .bot_state_memory_scope import BotStateMemoryScope
8
+ from .class_memory_scope import ClassMemoryScope
9
+ from .conversation_memory_scope import ConversationMemoryScope
10
+ from .dialog_class_memory_scope import DialogClassMemoryScope
11
+ from .dialog_context_memory_scope import DialogContextMemoryScope
12
+ from .dialog_memory_scope import DialogMemoryScope
13
+ from .memory_scope import MemoryScope
14
+ from .settings_memory_scope import SettingsMemoryScope
15
+ from .this_memory_scope import ThisMemoryScope
16
+ from .turn_memory_scope import TurnMemoryScope
17
+ from .user_memory_scope import UserMemoryScope
18
+
19
+ __all__ = [
20
+ "BotStateMemoryScope",
21
+ "ClassMemoryScope",
22
+ "ConversationMemoryScope",
23
+ "DialogClassMemoryScope",
24
+ "DialogContextMemoryScope",
25
+ "DialogMemoryScope",
26
+ "MemoryScope",
27
+ "SettingsMemoryScope",
28
+ "ThisMemoryScope",
29
+ "TurnMemoryScope",
30
+ "UserMemoryScope",
31
+ ]
@@ -0,0 +1,66 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ from ...dialog_context import DialogContext
10
+
11
+ from microsoft_agents.hosting.core import AgentState
12
+
13
+ from .memory_scope import MemoryScope
14
+
15
+
16
+ class BotStateMemoryScope(MemoryScope):
17
+ def __init__(self, agent_state_type: type[AgentState], name: str):
18
+ super().__init__(name, include_in_snapshot=True)
19
+ self.agent_state_type = agent_state_type
20
+
21
+ def get_memory(self, dialog_context: "DialogContext") -> object:
22
+ if not dialog_context:
23
+ raise TypeError(f"Expecting: DialogContext, but received None")
24
+
25
+ # In the new SDK, after AgentState.load() is called, turn_state contains
26
+ # a CachedAgentState (not the AgentState itself) at the context_service_key.
27
+ # Handle both cases: AgentState (before load) and CachedAgentState (after load).
28
+ turn_state_value = dialog_context.context.turn_state.get(
29
+ self.agent_state_type.__name__
30
+ )
31
+ if turn_state_value is None:
32
+ return None
33
+ if isinstance(turn_state_value, AgentState):
34
+ cached_state = turn_state_value.get_cached_state(dialog_context.context)
35
+ # If get_cached_state() returned AgentState itself (load() skipped turn_state update)
36
+ # or None, the state memory is not yet available.
37
+ if cached_state is None or isinstance(cached_state, AgentState):
38
+ return None
39
+ return cached_state.state
40
+ # It's a CachedAgentState (stored after load() was called)
41
+ return getattr(turn_state_value, "state", None)
42
+
43
+ def set_memory(self, dialog_context: "DialogContext", memory: object):
44
+ raise RuntimeError("You cannot replace the root AgentState object")
45
+
46
+ async def load(self, dialog_context: "DialogContext", force: bool = False):
47
+ agent_state: AgentState | None = self._get_agent_state(dialog_context)
48
+
49
+ if agent_state:
50
+ await agent_state.load(dialog_context.context, force)
51
+
52
+ async def save_changes(self, dialog_context: "DialogContext", force: bool = False):
53
+ agent_state: AgentState | None = self._get_agent_state(dialog_context)
54
+
55
+ if agent_state:
56
+ await agent_state.save(dialog_context.context, force)
57
+
58
+ def _get_agent_state(self, dialog_context: "DialogContext") -> AgentState | None:
59
+ value = dialog_context.context.turn_state.get(
60
+ self.agent_state_type.__name__, None
61
+ )
62
+ # After AgentState.load(), the turn_state key holds CachedAgentState, not AgentState.
63
+ # Return None in that case so callers don't try to call AgentState methods on it.
64
+ if isinstance(value, AgentState):
65
+ return value
66
+ return None
@@ -0,0 +1,64 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ from ...dialog_context import DialogContext
10
+
11
+ from collections import namedtuple
12
+
13
+ from microsoft_agents.hosting.dialogs.memory import scope_path
14
+
15
+ from .memory_scope import MemoryScope
16
+
17
+
18
+ class ClassMemoryScope(MemoryScope):
19
+ def __init__(self):
20
+ super().__init__(scope_path.CLASS, include_in_snapshot=False)
21
+
22
+ def get_memory(self, dialog_context: "DialogContext") -> object:
23
+ if not dialog_context:
24
+ raise TypeError(f"Expecting: DialogContext, but received None")
25
+
26
+ # if active dialog is a container dialog then "dialogclass" binds to it.
27
+ if dialog_context.active_dialog:
28
+ dialog = dialog_context.find_dialog_sync(dialog_context.active_dialog.id)
29
+ if dialog:
30
+ return ClassMemoryScope._bind_to_dialog_context(dialog, dialog_context)
31
+
32
+ return None
33
+
34
+ def set_memory(self, dialog_context: "DialogContext", memory: object):
35
+ raise Exception(
36
+ f"{self.__class__.__name__}.set_memory not supported (read only)"
37
+ )
38
+
39
+ @staticmethod
40
+ def _bind_to_dialog_context(obj, dialog_context: "DialogContext") -> object:
41
+ clone = {}
42
+ for prop in dir(obj):
43
+ # don't process double underscore attributes
44
+ if prop[:1] != "_":
45
+ prop_value = getattr(obj, prop)
46
+ if not callable(prop_value):
47
+ # the only objects
48
+ if hasattr(prop_value, "try_get_value"):
49
+ clone[prop] = prop_value.try_get_value(dialog_context.state)
50
+ elif hasattr(prop_value, "__dict__") and not isinstance(
51
+ prop_value, type(prop_value)
52
+ ):
53
+ clone[prop] = ClassMemoryScope._bind_to_dialog_context(
54
+ prop_value, dialog_context
55
+ )
56
+ else:
57
+ clone[prop] = prop_value
58
+ if clone:
59
+ ReadOnlyObject = namedtuple( # pylint: disable=invalid-name
60
+ "ReadOnlyObject", clone
61
+ )
62
+ return ReadOnlyObject(**clone)
63
+
64
+ return None
@@ -0,0 +1,12 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from microsoft_agents.hosting.core import ConversationState
5
+
6
+ from microsoft_agents.hosting.dialogs.memory import scope_path
7
+ from .bot_state_memory_scope import BotStateMemoryScope
8
+
9
+
10
+ class ConversationMemoryScope(BotStateMemoryScope):
11
+ def __init__(self):
12
+ super().__init__(ConversationState, scope_path.CONVERSATION)
@@ -0,0 +1,52 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ from ...dialog_context import DialogContext
10
+
11
+ from copy import deepcopy
12
+
13
+ from microsoft_agents.hosting.dialogs.memory import scope_path
14
+
15
+ from .memory_scope import MemoryScope
16
+
17
+
18
+ class DialogClassMemoryScope(MemoryScope):
19
+ def __init__(self):
20
+ # pylint: disable=import-outside-toplevel
21
+ super().__init__(scope_path.DIALOG_CLASS, include_in_snapshot=False)
22
+
23
+ # This import is to avoid circular dependency issues
24
+ from microsoft_agents.hosting.dialogs.dialog_container import DialogContainer
25
+
26
+ self._dialog_container_cls = DialogContainer
27
+
28
+ def get_memory(self, dialog_context: "DialogContext") -> object:
29
+ if not dialog_context:
30
+ raise TypeError(f"Expecting: DialogContext, but received None")
31
+
32
+ # if active dialog is a container dialog then "dialogclass" binds to it.
33
+ if dialog_context.active_dialog:
34
+ dialog = dialog_context.find_dialog_sync(dialog_context.active_dialog.id)
35
+ if isinstance(dialog, self._dialog_container_cls):
36
+ return deepcopy(dialog)
37
+
38
+ # Otherwise we always bind to parent, or if there is no parent the active dialog
39
+ parent_id = (
40
+ dialog_context.parent.active_dialog.id
41
+ if dialog_context.parent and dialog_context.parent.active_dialog
42
+ else None
43
+ )
44
+ active_id = (
45
+ dialog_context.active_dialog.id if dialog_context.active_dialog else None
46
+ )
47
+ return deepcopy(dialog_context.find_dialog_sync(parent_id or active_id))
48
+
49
+ def set_memory(self, dialog_context: "DialogContext", memory: object):
50
+ raise Exception(
51
+ f"{self.__class__.__name__}.set_memory not supported (read only)"
52
+ )
@@ -0,0 +1,68 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ from ...dialog_context import DialogContext
10
+
11
+ from microsoft_agents.hosting.dialogs.memory import scope_path
12
+
13
+ from .memory_scope import MemoryScope
14
+
15
+
16
+ class DialogContextMemoryScope(MemoryScope):
17
+ def __init__(self):
18
+ # pylint: disable=invalid-name
19
+ super().__init__(scope_path.DIALOG_CONTEXT, include_in_snapshot=False)
20
+ # Stack name.
21
+ self.STACK = "stack"
22
+
23
+ # Active dialog name.
24
+ self.ACTIVE_DIALOG = "activeDialog"
25
+
26
+ # Parent name.
27
+ self.PARENT = "parent"
28
+
29
+ def get_memory(self, dialog_context: "DialogContext") -> object:
30
+ """
31
+ Gets the backing memory for this scope.
32
+ """
33
+ if not dialog_context:
34
+ raise TypeError(f"Expecting: DialogContext, but received None")
35
+
36
+ memory = {}
37
+ stack = list([])
38
+ current_dc = dialog_context
39
+
40
+ # go to leaf node
41
+ while current_dc.child:
42
+ current_dc = current_dc.child
43
+
44
+ while current_dc:
45
+ # (PORTERS NOTE: javascript stack is reversed with top of stack on end)
46
+ for item in current_dc.stack:
47
+ # filter out ActionScope items because they are internal bookkeeping.
48
+ if not item.id.startswith("ActionScope["):
49
+ stack.append(item.id)
50
+
51
+ current_dc = current_dc.parent
52
+
53
+ # top of stack is stack[0].
54
+ memory[self.STACK] = stack
55
+ memory[self.ACTIVE_DIALOG] = (
56
+ dialog_context.active_dialog.id if dialog_context.active_dialog else None
57
+ )
58
+ memory[self.PARENT] = (
59
+ dialog_context.parent.active_dialog.id
60
+ if dialog_context.parent and dialog_context.parent.active_dialog
61
+ else None
62
+ )
63
+ return memory
64
+
65
+ def set_memory(self, dialog_context: "DialogContext", memory: object):
66
+ raise Exception(
67
+ f"{self.__class__.__name__}.set_memory not supported (read only)"
68
+ )
@@ -0,0 +1,75 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ from ...dialog_context import DialogContext
10
+
11
+ from microsoft_agents.hosting.dialogs.memory import scope_path
12
+
13
+ from .memory_scope import MemoryScope
14
+
15
+
16
+ class DialogMemoryScope(MemoryScope):
17
+ def __init__(self):
18
+ # pylint: disable=import-outside-toplevel
19
+ super().__init__(scope_path.DIALOG)
20
+
21
+ # This import is to avoid circular dependency issues
22
+ from microsoft_agents.hosting.dialogs.dialog_container import DialogContainer
23
+
24
+ self._dialog_container_cls = DialogContainer
25
+
26
+ def get_memory(self, dialog_context: "DialogContext") -> object:
27
+ if not dialog_context:
28
+ raise TypeError(f"Expecting: DialogContext, but received None")
29
+
30
+ # if active dialog is a container dialog then "dialog" binds to it.
31
+ if dialog_context.active_dialog:
32
+ dialog = dialog_context.find_dialog_sync(dialog_context.active_dialog.id)
33
+ if isinstance(dialog, self._dialog_container_cls):
34
+ return dialog_context.active_dialog.state
35
+
36
+ # Otherwise we always bind to parent, or if there is no parent the active dialog
37
+ parent_state = (
38
+ dialog_context.parent.active_dialog.state
39
+ if dialog_context.parent and dialog_context.parent.active_dialog
40
+ else None
41
+ )
42
+ dc_state = (
43
+ dialog_context.active_dialog.state if dialog_context.active_dialog else None
44
+ )
45
+ return parent_state or dc_state
46
+
47
+ def set_memory(self, dialog_context: "DialogContext", memory: object):
48
+ if not dialog_context:
49
+ raise TypeError(f"Expecting: DialogContext, but received None")
50
+
51
+ if memory is None:
52
+ raise TypeError(f"Expecting: memory object, but received None")
53
+
54
+ # If active dialog is a container dialog then "dialog" binds to it.
55
+ # Otherwise the "dialog" will bind to the dialogs parent assuming it is a container.
56
+ parent: DialogContext | None = dialog_context
57
+ if not self.is_container(parent) and self.is_container(parent.parent):
58
+ parent = parent.parent
59
+
60
+ # If there's no active dialog then throw an error.
61
+ assert parent is not None
62
+ if not parent.active_dialog:
63
+ raise Exception(
64
+ "Cannot set DialogMemoryScope. There is no active dialog or parent dialog in the context"
65
+ )
66
+
67
+ parent.active_dialog.state = memory # type: ignore[assignment]
68
+
69
+ def is_container(self, dialog_context: "DialogContext | None"):
70
+ if dialog_context and dialog_context.active_dialog:
71
+ dialog = dialog_context.find_dialog_sync(dialog_context.active_dialog.id)
72
+ if isinstance(dialog, self._dialog_container_cls):
73
+ return True
74
+
75
+ return False
@@ -0,0 +1,91 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ from ...dialog_context import DialogContext
10
+
11
+ from abc import ABC, abstractmethod
12
+
13
+
14
+ class MemoryScope(ABC):
15
+ def __init__(self, name: str, include_in_snapshot: bool = True):
16
+ # <summary>
17
+ # Gets or sets name of the scope.
18
+ # </summary>
19
+ # <value>
20
+ # Name of the scope.
21
+ # </value>
22
+ self.include_in_snapshot = include_in_snapshot
23
+ # <summary>
24
+ # Gets or sets a value indicating whether this memory should be included in snapshot.
25
+ # </summary>
26
+ # <value>
27
+ # True or false.
28
+ # </value>
29
+ self.name = name
30
+
31
+ # <summary>
32
+ # Get the backing memory for this scope.
33
+ # </summary>
34
+ # <param name="dc">dc.</param>
35
+ # <returns>memory for the scope.</returns>
36
+ @abstractmethod
37
+ def get_memory(
38
+ self, dialog_context: "DialogContext"
39
+ ) -> object: # pylint: disable=unused-argument
40
+ raise NotImplementedError()
41
+
42
+ # <summary>
43
+ # Changes the backing object for the memory scope.
44
+ # </summary>
45
+ # <param name="dc">dc.</param>
46
+ # <param name="memory">memory.</param>
47
+ @abstractmethod
48
+ def set_memory(
49
+ self, dialog_context: "DialogContext", memory: object
50
+ ): # pylint: disable=unused-argument
51
+ raise NotImplementedError()
52
+
53
+ # <summary>
54
+ # Populates the state cache for this <see cref="BotState"/> from the storage layer.
55
+ # </summary>
56
+ # <param name="dialogContext">The dialog context object for this turn.</param>
57
+ # <param name="force">Optional, <c>true</c> to overwrite any existing state cache
58
+ # or <c>false</c> to load state from storage only if the cache doesn't already exist.</param>
59
+ # <param name="cancellationToken">A cancellation token that can be used by other objects
60
+ # or threads to receive notice of cancellation.</param>
61
+ # <returns>A task that represents the work queued to execute.</returns>
62
+ async def load(
63
+ self, dialog_context: "DialogContext", force: bool = False
64
+ ): # pylint: disable=unused-argument
65
+ return
66
+
67
+ # <summary>
68
+ # Writes the state cache for this <see cref="BotState"/> to the storage layer.
69
+ # </summary>
70
+ # <param name="dialogContext">The dialog context object for this turn.</param>
71
+ # <param name="force">Optional, <c>true</c> to save the state cache to storage
72
+ # or <c>false</c> to save state to storage only if a property in the cache has changed.</param>
73
+ # <param name="cancellationToken">A cancellation token that can be used by other objects
74
+ # or threads to receive notice of cancellation.</param>
75
+ # <returns>A task that represents the work queued to execute.</returns>
76
+ async def save_changes(
77
+ self, dialog_context: "DialogContext", force: bool = False
78
+ ): # pylint: disable=unused-argument
79
+ return
80
+
81
+ # <summary>
82
+ # Deletes any state in storage and the cache for this <see cref="BotState"/>.
83
+ # </summary>
84
+ # <param name="dialogContext">The dialog context object for this turn.</param>
85
+ # <param name="cancellationToken">A cancellation token that can be used by other objects
86
+ # or threads to receive notice of cancellation.</param>
87
+ # <returns>A task that represents the work queued to execute.</returns>
88
+ async def delete(
89
+ self, dialog_context: "DialogContext"
90
+ ): # pylint: disable=unused-argument
91
+ return
@@ -0,0 +1,38 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ from ...dialog_context import DialogContext
10
+
11
+ from microsoft_agents.hosting.dialogs.memory import scope_path
12
+
13
+ from .memory_scope import MemoryScope
14
+
15
+
16
+ class SettingsMemoryScope(MemoryScope):
17
+ def __init__(self):
18
+ super().__init__(scope_path.SETTINGS)
19
+ self._empty_settings = {}
20
+ self.include_in_snapshot = False
21
+
22
+ def get_memory(self, dialog_context: "DialogContext") -> object:
23
+ if not dialog_context:
24
+ raise TypeError(f"Expecting: DialogContext, but received None")
25
+
26
+ settings: dict | None = dialog_context.context.turn_state.get( # type: ignore[assignment]
27
+ scope_path.SETTINGS, None
28
+ )
29
+
30
+ if not settings:
31
+ settings = self._empty_settings
32
+
33
+ return settings
34
+
35
+ def set_memory(self, dialog_context: "DialogContext", memory: object):
36
+ raise Exception(
37
+ f"{self.__class__.__name__}.set_memory not supported (read only)"
38
+ )
@@ -0,0 +1,36 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ from ...dialog_context import DialogContext
10
+
11
+ from microsoft_agents.hosting.dialogs.memory import scope_path
12
+
13
+ from .memory_scope import MemoryScope
14
+
15
+
16
+ class ThisMemoryScope(MemoryScope):
17
+ def __init__(self):
18
+ super().__init__(scope_path.THIS)
19
+
20
+ def get_memory(self, dialog_context: "DialogContext") -> object:
21
+ if not dialog_context:
22
+ raise TypeError(f"Expecting: DialogContext, but received None")
23
+
24
+ return (
25
+ dialog_context.active_dialog.state if dialog_context.active_dialog else None
26
+ )
27
+
28
+ def set_memory(self, dialog_context: "DialogContext", memory: object):
29
+ if not dialog_context:
30
+ raise TypeError(f"Expecting: DialogContext, but received None")
31
+
32
+ if memory is None:
33
+ raise TypeError(f"Expecting: object, but received None")
34
+
35
+ assert dialog_context.active_dialog is not None
36
+ dialog_context.active_dialog.state = memory # type: ignore[assignment]