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.
- microsoft_agents/hosting/dialogs/__init__.py +76 -0
- microsoft_agents/hosting/dialogs/_component_registration.py +30 -0
- microsoft_agents/hosting/dialogs/_telemetry_client.py +78 -0
- microsoft_agents/hosting/dialogs/choices/__init__.py +38 -0
- microsoft_agents/hosting/dialogs/choices/channel.py +121 -0
- microsoft_agents/hosting/dialogs/choices/choice_factory.py +262 -0
- microsoft_agents/hosting/dialogs/choices/choice_recognizer.py +148 -0
- microsoft_agents/hosting/dialogs/choices/find.py +242 -0
- microsoft_agents/hosting/dialogs/choices/models/__init__.py +23 -0
- microsoft_agents/hosting/dialogs/choices/models/choice.py +14 -0
- microsoft_agents/hosting/dialogs/choices/models/choice_factory_options.py +13 -0
- microsoft_agents/hosting/dialogs/choices/models/find_choices_options.py +28 -0
- microsoft_agents/hosting/dialogs/choices/models/find_values_options.py +31 -0
- microsoft_agents/hosting/dialogs/choices/models/found_choice.py +22 -0
- microsoft_agents/hosting/dialogs/choices/models/found_value.py +20 -0
- microsoft_agents/hosting/dialogs/choices/models/list_style.py +15 -0
- microsoft_agents/hosting/dialogs/choices/models/model_result.py +16 -0
- microsoft_agents/hosting/dialogs/choices/models/sorted_value.py +16 -0
- microsoft_agents/hosting/dialogs/choices/models/token.py +20 -0
- microsoft_agents/hosting/dialogs/choices/tokenizer.py +92 -0
- microsoft_agents/hosting/dialogs/component_dialog.py +284 -0
- microsoft_agents/hosting/dialogs/dialog.py +198 -0
- microsoft_agents/hosting/dialogs/dialog_component_registration.py +52 -0
- microsoft_agents/hosting/dialogs/dialog_container.py +31 -0
- microsoft_agents/hosting/dialogs/dialog_context.py +426 -0
- microsoft_agents/hosting/dialogs/dialog_extensions.py +201 -0
- microsoft_agents/hosting/dialogs/dialog_manager.py +189 -0
- microsoft_agents/hosting/dialogs/dialog_manager_result.py +17 -0
- microsoft_agents/hosting/dialogs/dialog_set.py +174 -0
- microsoft_agents/hosting/dialogs/dialog_state.py +20 -0
- microsoft_agents/hosting/dialogs/memory/__init__.py +24 -0
- microsoft_agents/hosting/dialogs/memory/component_memory_scopes_base.py +14 -0
- microsoft_agents/hosting/dialogs/memory/component_path_resolvers_base.py +15 -0
- microsoft_agents/hosting/dialogs/memory/dialog_path.py +33 -0
- microsoft_agents/hosting/dialogs/memory/dialog_state_manager.py +563 -0
- microsoft_agents/hosting/dialogs/memory/dialog_state_manager_configuration.py +11 -0
- microsoft_agents/hosting/dialogs/memory/path_resolver_base.py +8 -0
- microsoft_agents/hosting/dialogs/memory/path_resolvers/__init__.py +19 -0
- microsoft_agents/hosting/dialogs/memory/path_resolvers/alias_path_resolver.py +53 -0
- microsoft_agents/hosting/dialogs/memory/path_resolvers/at_at_path_resolver.py +9 -0
- microsoft_agents/hosting/dialogs/memory/path_resolvers/at_path_resolver.py +44 -0
- microsoft_agents/hosting/dialogs/memory/path_resolvers/dollar_path_resolver.py +9 -0
- microsoft_agents/hosting/dialogs/memory/path_resolvers/hash_path_resolver.py +9 -0
- microsoft_agents/hosting/dialogs/memory/path_resolvers/percent_path_resolver.py +9 -0
- microsoft_agents/hosting/dialogs/memory/scope_path.py +38 -0
- microsoft_agents/hosting/dialogs/memory/scopes/__init__.py +31 -0
- microsoft_agents/hosting/dialogs/memory/scopes/bot_state_memory_scope.py +66 -0
- microsoft_agents/hosting/dialogs/memory/scopes/class_memory_scope.py +64 -0
- microsoft_agents/hosting/dialogs/memory/scopes/conversation_memory_scope.py +12 -0
- microsoft_agents/hosting/dialogs/memory/scopes/dialog_class_memory_scope.py +52 -0
- microsoft_agents/hosting/dialogs/memory/scopes/dialog_context_memory_scope.py +68 -0
- microsoft_agents/hosting/dialogs/memory/scopes/dialog_memory_scope.py +75 -0
- microsoft_agents/hosting/dialogs/memory/scopes/memory_scope.py +91 -0
- microsoft_agents/hosting/dialogs/memory/scopes/settings_memory_scope.py +38 -0
- microsoft_agents/hosting/dialogs/memory/scopes/this_memory_scope.py +36 -0
- microsoft_agents/hosting/dialogs/memory/scopes/turn_memory_scope.py +86 -0
- microsoft_agents/hosting/dialogs/memory/scopes/user_memory_scope.py +12 -0
- microsoft_agents/hosting/dialogs/models/__init__.py +15 -0
- microsoft_agents/hosting/dialogs/models/dialog_event.py +13 -0
- microsoft_agents/hosting/dialogs/models/dialog_events.py +12 -0
- microsoft_agents/hosting/dialogs/models/dialog_instance.py +28 -0
- microsoft_agents/hosting/dialogs/models/dialog_reason.py +34 -0
- microsoft_agents/hosting/dialogs/models/dialog_turn_result.py +17 -0
- microsoft_agents/hosting/dialogs/models/dialog_turn_status.py +26 -0
- microsoft_agents/hosting/dialogs/object_path.py +315 -0
- microsoft_agents/hosting/dialogs/persisted_state.py +22 -0
- microsoft_agents/hosting/dialogs/persisted_state_keys.py +8 -0
- microsoft_agents/hosting/dialogs/prompts/__init__.py +41 -0
- microsoft_agents/hosting/dialogs/prompts/activity_prompt.py +203 -0
- microsoft_agents/hosting/dialogs/prompts/attachment_prompt.py +87 -0
- microsoft_agents/hosting/dialogs/prompts/choice_prompt.py +156 -0
- microsoft_agents/hosting/dialogs/prompts/confirm_prompt.py +161 -0
- microsoft_agents/hosting/dialogs/prompts/datetime_prompt.py +90 -0
- microsoft_agents/hosting/dialogs/prompts/datetime_resolution.py +16 -0
- microsoft_agents/hosting/dialogs/prompts/number_prompt.py +81 -0
- microsoft_agents/hosting/dialogs/prompts/oauth_prompt.py +569 -0
- microsoft_agents/hosting/dialogs/prompts/oauth_prompt_settings.py +43 -0
- microsoft_agents/hosting/dialogs/prompts/prompt.py +224 -0
- microsoft_agents/hosting/dialogs/prompts/prompt_culture_models.py +222 -0
- microsoft_agents/hosting/dialogs/prompts/prompt_options.py +42 -0
- microsoft_agents/hosting/dialogs/prompts/prompt_recognizer_result.py +11 -0
- microsoft_agents/hosting/dialogs/prompts/prompt_validator.py +0 -0
- microsoft_agents/hosting/dialogs/prompts/prompt_validator_context.py +44 -0
- microsoft_agents/hosting/dialogs/prompts/text_prompt.py +82 -0
- microsoft_agents/hosting/dialogs/waterfall_dialog.py +266 -0
- microsoft_agents/hosting/dialogs/waterfall_step_context.py +109 -0
- microsoft_agents_hosting_dialogs-0.10.0.dev2.dist-info/METADATA +87 -0
- microsoft_agents_hosting_dialogs-0.10.0.dev2.dist-info/RECORD +91 -0
- microsoft_agents_hosting_dialogs-0.10.0.dev2.dist-info/WHEEL +5 -0
- microsoft_agents_hosting_dialogs-0.10.0.dev2.dist-info/licenses/LICENSE +21 -0
- 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]
|