Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
fecc2f1
initial changes for skill dialog
axelsrz Feb 13, 2020
2eec594
Skill dialog
axelsrz Feb 14, 2020
800835b
Initial echo skill with dialog
axelsrz Feb 19, 2020
6349deb
pylint: Initial echo skill with dialog
axelsrz Feb 19, 2020
46018b4
Merge branch 'master' into axsuarez/skill-dialog
axelsrz Feb 19, 2020
f9b80dd
made integration package for aiohttp, dialog root bot for testing
axelsrz Feb 22, 2020
91d7c6b
pylint: made integration package for aiohttp, dialog root bot for tes…
axelsrz Feb 22, 2020
10117aa
pylint: made integration package for aiohttp, dialog root bot for tes…
axelsrz Feb 22, 2020
05b46a0
Merge branch 'axsuarez/skill-dialog' of https://github.com/Microsoft/…
axelsrz Feb 22, 2020
4a2ef03
pylint: made integration package for aiohttp, dialog root bot for tes…
axelsrz Feb 22, 2020
0c92083
Initial dialog skill bot
axelsrz Feb 22, 2020
9d95a3e
Changes to skill bot
axelsrz Feb 24, 2020
8f3f55e
Merge branch 'master' into axsuarez/skill-dialog
tracyboehrer Mar 3, 2020
31717c6
Merge branch 'master' of https://github.com/microsoft/botbuilder-pyth…
axelsrz Mar 6, 2020
365541a
Updates for dialog interruption and buffered response. Pending to mov…
axelsrz Mar 6, 2020
1a921fd
Relates to in post_activity in BotFrameworkHttpClient
axelsrz Mar 6, 2020
a5670c1
fix on BeginSkillDialogOptions
axelsrz Mar 6, 2020
1561e2d
Moved SkillHttpClient to correct library with corresponding tests. Fi…
axelsrz Mar 6, 2020
a00b663
black: Moved SkillHttpClient to correct library with corresponding te…
axelsrz Mar 6, 2020
fe2ab2c
relative import fix
axelsrz Mar 6, 2020
7f99434
Removed unused import
axelsrz Mar 6, 2020
4703510
Modified TurnContext.send_trace_activity to default args.
tracyboehrer Mar 6, 2020
7aabfe4
Removed argument checks that didn't exist in C#. Fixed bug in SkillD…
tracyboehrer Mar 6, 2020
f9976a1
Added initial SkillDialog unit test.
tracyboehrer Mar 7, 2020
c4e66d9
Added remainder of SkillDialog unit tests
tracyboehrer Mar 7, 2020
b0f4578
Solved conflicts w/ master
axelsrz Mar 9, 2020
5f4323c
Merge branch 'axsuarez/skill-dialog' of https://github.com/microsoft/…
axelsrz Mar 9, 2020
5bcfd10
Updates on dialog-root-bot
axelsrz Mar 9, 2020
3e031c2
Updated buffered_replies to expect_replies
tracyboehrer Mar 9, 2020
09cd3cc
Using HTTPStatus defines.
tracyboehrer Mar 9, 2020
bf059dc
Skill OAuth only change card action for emulator
tracyboehrer Mar 9, 2020
97e691b
black
tracyboehrer Mar 9, 2020
8e9c573
skill root bot updated
axelsrz Mar 9, 2020
c224ea7
skill root bot updated
axelsrz Mar 9, 2020
e2de13e
Merge branch 'axsuarez/skill-dialog' of https://github.com/microsoft/…
axelsrz Mar 9, 2020
d9a0b05
Removed old import in dialog root bot
axelsrz Mar 9, 2020
91486b4
Dialog-to-dialog work
tracyboehrer Mar 9, 2020
36afefc
Ummm... the actual dialog-to-dialog work
tracyboehrer Mar 9, 2020
ed0817a
Corrected dialog-skill-bot AcitivyRouterDialog to actually have a Wat…
tracyboehrer Mar 9, 2020
c8c3528
dialog-to-dialog test bot changes: dialog-echo-skill-bot, corrected m…
tracyboehrer Mar 10, 2020
6b137f7
dialog-to-dialog: Handling messages with values (serialization and wh…
tracyboehrer Mar 10, 2020
d67e77d
Merge branch 'master' into axsuarez/skill-dialog
tracyboehrer Mar 10, 2020
f59e36f
Memory storage does not validate e_tag integrity anymore, following t…
axelsrz Mar 10, 2020
cc98985
Merge branch 'master' into axsuarez/skill-dialog
axelsrz Mar 10, 2020
edc2b02
pylint: Memory storage does not validate e_tag integrity anymore, fol…
axelsrz Mar 10, 2020
f293cd9
Merge branch 'axsuarez/skill-dialog' of https://github.com/microsoft/…
axelsrz Mar 10, 2020
dda4935
pylint: Memory storage does not validate e_tag integrity anymore, fol…
axelsrz Mar 11, 2020
c31fbd2
Removing samples from product code PR
axelsrz Mar 11, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ci-pr-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ jobs:
pip install -e ./libraries/botbuilder-testing
pip install -e ./libraries/botbuilder-integration-applicationinsights-aiohttp
pip install -e ./libraries/botbuilder-adapters-slack
pip install -e ./libraries/botbuilder-integration-aiohttp
pip install -r ./libraries/botframework-connector/tests/requirements.txt
pip install -r ./libraries/botbuilder-core/tests/requirements.txt
pip install coveralls
Expand Down
2 changes: 0 additions & 2 deletions libraries/botbuilder-core/botbuilder/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
from .extended_user_token_provider import ExtendedUserTokenProvider
from .intent_score import IntentScore
from .invoke_response import InvokeResponse
from .bot_framework_http_client import BotFrameworkHttpClient
from .memory_storage import MemoryStorage
from .memory_transcript_store import MemoryTranscriptStore
from .message_factory import MessageFactory
Expand Down Expand Up @@ -63,7 +62,6 @@
"ExtendedUserTokenProvider",
"IntentScore",
"InvokeResponse",
"BotFrameworkHttpClient",
"MemoryStorage",
"MemoryTranscriptStore",
"MessageFactory",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,9 @@ async def receive_activity(self, activity):
return await self.run_pipeline(context, self.logic)

def get_next_activity(self) -> Activity:
return self.activity_buffer.pop(0)
if len(self.activity_buffer) > 0:
return self.activity_buffer.pop(0)
return None

async def send(self, user_says) -> object:
"""
Expand Down
2 changes: 1 addition & 1 deletion libraries/botbuilder-core/botbuilder/core/bot_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

class BotAdapter(ABC):
BOT_IDENTITY_KEY = "BotIdentity"
BOT_OAUTH_SCOPE_KEY = "OAuthScope"
BOT_OAUTH_SCOPE_KEY = "botbuilder.core.BotAdapter.OAuthScope"
BOT_CONNECTOR_CLIENT_KEY = "ConnectorClient"
BOT_CALLBACK_HANDLER_KEY = "BotCallbackHandler"

Expand Down
12 changes: 8 additions & 4 deletions libraries/botbuilder-core/botbuilder/core/memory_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,14 @@ async def write(self, changes: Dict[str, StoreItem]):
"Etag conflict.\nOriginal: %s\r\nCurrent: %s"
% (new_value_etag, old_state_etag)
)
if isinstance(new_state, dict):
new_state["e_tag"] = str(self._e_tag)
else:
new_state.e_tag = str(self._e_tag)

# If the original object didn't have an e_tag, don't set one (C# behavior)
if old_state_etag:
if isinstance(new_state, dict):
new_state["e_tag"] = str(self._e_tag)
else:
new_state.e_tag = str(self._e_tag)

self._e_tag += 1
self.memory[key] = deepcopy(new_state)

Expand Down
2 changes: 2 additions & 0 deletions libraries/botbuilder-core/botbuilder/core/skills/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
# --------------------------------------------------------------------------

from .bot_framework_skill import BotFrameworkSkill
from .bot_framework_client import BotFrameworkClient
from .conversation_id_factory import ConversationIdFactoryBase
from .skill_handler import SkillHandler
from .skill_conversation_id_factory_options import SkillConversationIdFactoryOptions
from .skill_conversation_reference import SkillConversationReference

__all__ = [
"BotFrameworkSkill",
"BotFrameworkClient",
"ConversationIdFactoryBase",
"SkillConversationIdFactoryOptions",
"SkillConversationReference",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

from abc import ABC

from botbuilder.schema import Activity
from botbuilder.core import InvokeResponse


class BotFrameworkClient(ABC):
def post_activity(
self,
from_bot_id: str,
to_bot_id: str,
to_url: str,
service_url: str,
conversation_id: str,
activity: Activity,
) -> InvokeResponse:
raise NotImplementedError()
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,6 @@ def __init__(
activity: Activity,
bot_framework_skill: BotFrameworkSkill,
):
if from_bot_oauth_scope is None:
raise TypeError(
"SkillConversationIdFactoryOptions(): from_bot_oauth_scope cannot be None."
)

if from_bot_id is None:
raise TypeError(
"SkillConversationIdFactoryOptions(): from_bot_id cannot be None."
)

if activity is None:
raise TypeError(
"SkillConversationIdFactoryOptions(): activity cannot be None."
)

if bot_framework_skill is None:
raise TypeError(
"SkillConversationIdFactoryOptions(): bot_framework_skill cannot be None."
)

self.from_bot_oauth_scope = from_bot_oauth_scope
self.from_bot_id = from_bot_id
self.activity = activity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,5 @@ class SkillConversationReference:
"""

def __init__(self, conversation_reference: ConversationReference, oauth_scope: str):
if conversation_reference is None:
raise TypeError(
"SkillConversationReference(): conversation_reference cannot be None."
)

if oauth_scope is None:
raise TypeError("SkillConversationReference(): oauth_scope cannot be None.")

self.conversation_reference = conversation_reference
self.oauth_scope = oauth_scope
2 changes: 1 addition & 1 deletion libraries/botbuilder-core/botbuilder/core/turn_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ async def next_handler():
return await logic

async def send_trace_activity(
self, name: str, value: object, value_type: str, label: str
self, name: str, value: object = None, value_type: str = None, label: str = None
) -> ResourceResponse:
trace_activity = Activity(
type=ActivityTypes.trace,
Expand Down
5 changes: 5 additions & 0 deletions libraries/botbuilder-dialogs/botbuilder/dialogs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .about import __version__
from .component_dialog import ComponentDialog
from .dialog_context import DialogContext
from .dialog_events import DialogEvents
from .dialog_instance import DialogInstance
from .dialog_reason import DialogReason
from .dialog_set import DialogSet
Expand All @@ -17,12 +18,15 @@
from .dialog import Dialog
from .waterfall_dialog import WaterfallDialog
from .waterfall_step_context import WaterfallStepContext
from .dialog_extensions import DialogExtensions
from .prompts import *
from .choices import *
from .skills import *

__all__ = [
"ComponentDialog",
"DialogContext",
"DialogEvents",
"DialogInstance",
"DialogReason",
"DialogSet",
Expand All @@ -43,5 +47,6 @@
"Prompt",
"PromptOptions",
"TextPrompt",
"DialogExtensions",
"__version__",
]
Original file line number Diff line number Diff line change
Expand Up @@ -189,15 +189,15 @@ def add_dialog(self, dialog: Dialog) -> object:
self.initial_dialog_id = dialog.id
return self

def find_dialog(self, dialog_id: str) -> Dialog:
async def find_dialog(self, dialog_id: str) -> Dialog:
"""
Finds a dialog by ID.

:param dialog_id: The dialog to add.
:return: The dialog; or None if there is not a match for the ID.
:rtype: :class:`botbuilder.dialogs.Dialog`
"""
return self._dialogs.find(dialog_id)
return await self._dialogs.find(dialog_id)

async def on_begin_dialog(
self, inner_dc: DialogContext, options: object
Expand Down
13 changes: 13 additions & 0 deletions libraries/botbuilder-dialogs/botbuilder/dialogs/dialog_events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

from enum import Enum


class DialogEvents(str, Enum):

begin_dialog = "beginDialog"
reprompt_dialog = "repromptDialog"
cancel_dialog = "cancelDialog"
activity_received = "activityReceived"
error = "error"
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

from botbuilder.core import BotAdapter, StatePropertyAccessor, TurnContext
from botbuilder.dialogs import (
Dialog,
DialogEvents,
DialogSet,
DialogTurnStatus,
)
from botbuilder.schema import Activity, ActivityTypes
from botframework.connector.auth import ClaimsIdentity, SkillValidation


class DialogExtensions:
@staticmethod
async def run_dialog(
dialog: Dialog, turn_context: TurnContext, accessor: StatePropertyAccessor
):
dialog_set = DialogSet(accessor)
dialog_set.add(dialog)

dialog_context = await dialog_set.create_context(turn_context)

claims = turn_context.turn_state.get(BotAdapter.BOT_IDENTITY_KEY)
if isinstance(claims, ClaimsIdentity) and SkillValidation.is_skill_claim(
claims.claims
):
# The bot is running as a skill.
if (
turn_context.activity.type == ActivityTypes.end_of_conversation
and dialog_context.stack
):
await dialog_context.cancel_all_dialogs()
else:
# Process a reprompt event sent from the parent.
if (
turn_context.activity.type == ActivityTypes.event
and turn_context.activity.name == DialogEvents.reprompt_dialog
and dialog_context.stack
):
await dialog_context.reprompt_dialog()
return

# Run the Dialog with the new message Activity and capture the results
# so we can send end of conversation if needed.
result = await dialog_context.continue_dialog()
if result.status == DialogTurnStatus.Empty:
start_message_text = f"Starting {dialog.id}"
await turn_context.send_trace_activity(
f"Extension {Dialog.__name__}.run_dialog",
label=start_message_text,
)
result = await dialog_context.begin_dialog(dialog.id)

# Send end of conversation if it is completed or cancelled.
if (
result.status == DialogTurnStatus.Complete
or result.status == DialogTurnStatus.Cancelled
):
end_message_text = f"Dialog {dialog.id} has **completed**. Sending EndOfConversation."
await turn_context.send_trace_activity(
f"Extension {Dialog.__name__}.run_dialog",
label=end_message_text,
value=result.result,
)

activity = Activity(
type=ActivityTypes.end_of_conversation, value=result.result
)
await turn_context.send_activity(activity)

else:
# The bot is running as a standard bot.
results = await dialog_context.continue_dialog()
if results.status == DialogTurnStatus.Empty:
await dialog_context.begin_dialog(dialog.id)
17 changes: 17 additions & 0 deletions libraries/botbuilder-dialogs/botbuilder/dialogs/skills/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------

from .begin_skill_dialog_options import BeginSkillDialogOptions
from .skill_dialog_options import SkillDialogOptions
from .skill_dialog import SkillDialog


__all__ = [
"BeginSkillDialogOptions",
"SkillDialogOptions",
"SkillDialog",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

from botbuilder.schema import Activity


class BeginSkillDialogOptions:
def __init__(self, activity: Activity): # pylint: disable=unused-argument
self.activity = activity

@staticmethod
def from_object(obj: object) -> "BeginSkillDialogOptions":
if isinstance(obj, dict) and "activity" in obj:
return BeginSkillDialogOptions(obj["activity"])
if hasattr(obj, "activity"):
return BeginSkillDialogOptions(obj.activity)

return None
Loading