Creating Dialogs
If you're not familiar with how to build Adaptive Cards, check out the cards guide. Understanding their basics is a prerequisite for this guide.
Entry Point
To open a dialog, you need to supply a special type of action as to the Adaptive Card. Once this button is clicked, the dialog will open and ask the application what to show.
@app.on_message
async def handle_message(ctx: ActivityContext[MessageActivity]):
await ctx.reply(TypingActivityInput())
card = AdaptiveCard(
schema="http://adaptivecards.io/schemas/adaptive-card.json",
body=[
TextBlock(
text="Select the examples you want to see!",
size="Large",
weight="Bolder",
)
]
).with_actions([
# Special type of action to open a dialog
TaskFetchAction(value={"OpenDialogType": "webpage_dialog"}).with_title("Webpage Dialog"),
# This data will be passed back in an event, so we can handle what to show in the dialog
TaskFetchAction(value={"OpenDialogType": "multi_step_form"}).with_title("Multi-step Form"),
TaskFetchAction(value={"OpenDialogType": "mixed_example"}).with_title("Mixed Example")
])
# Send the card as an attachment
message = MessageActivityInput(text="Enter this form").add_card(card)
await ctx.send(message)
Handling Dialog Open Events
Once an action is executed to open a dialog, the Teams client will send an event to the agent to request what the content of the dialog should be. Here is how to handle this event:
@app.on_dialog_open
async def handle_dialog_open(ctx: ActivityContext[TaskFetchInvokeActivity]):
"""Handle dialog open events for all dialog types."""
card = AdaptiveCard(...)
# Return an object with the task value that renders a card
return InvokeResponse(
body=TaskModuleResponse(
task=TaskModuleContinueResponse(
value=CardTaskModuleTaskInfo(
title="Title of Dialog",
card=card_attachment(AdaptiveCardAttachment(content=card)),
)
)
)
)
Rendering A Card
You can render an Adaptive Card in a dialog by returning a card response.
@app.on_dialog_open
async def handle_dialog_open(ctx: ActivityContext[TaskFetchInvokeActivity]):
"""Handle dialog open events for all dialog types."""
dialog_card = AdaptiveCard(
schema="http://adaptivecards.io/schemas/adaptive-card.json",
body=[
TextBlock(text="This is a simple form", size="Large", weight="Bolder"),
TextInput().with_label("Name").with_is_required(True).with_id("name").with_placeholder("Enter your name"),
],
actions=[
SubmitAction().with_title("Submit").with_data(SubmitActionData(ms_teams={"SubmissionDialogType": "simple_form"}))
]
)
# Return an object with the task value that renders a card
return InvokeResponse(
body=TaskModuleResponse(
task=TaskModuleContinueResponse(
value=CardTaskModuleTaskInfo(
title="Simple Form Dialog",
card=card_attachment(AdaptiveCardAttachment(content=dialog_card)),
)
)
)
)
The action type for submitting a dialog must be Action.Submit
. This is a requirement of the Teams client. If you use a different action type, the dialog will not be submitted and the agent will not receive the submission event.
Rendering A Webpage
You can render a webpage in a dialog as well. There are some security requirements to be aware of:
- The webpage must be hosted on a domain that is allow-listed as
validDomains
in the Teams app manifest for the agent - The webpage must also host the teams-js client library. The reason for this is that for security purposes, the Teams client will not render arbitrary webpages. As such, the webpage must explicitly opt-in to being rendered in the Teams client. Setting up the teams-js client library handles this for you.
return InvokeResponse(
body=TaskModuleResponse(
task=TaskModuleContinueResponse(
value=UrlTaskModuleTaskInfo(
title="Webpage Dialog",
# Here we are using a webpage that is hosted in the same
# server as the agent. This server needs to be publicly accessible,
# needs to set up teams.js client library (https://www.npmjs.com/package/@microsoft/teams-js)
# and needs to be registered in the manifest.
url=f"{os.getenv('BOT_ENDPOINT')}/tabs/dialog-webpage",
width=1000,
height=800,
)
)
)
)