Skip to content

[Doc Improvement][Use dialogs with bots][3930082] #12427

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jun 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
37 changes: 36 additions & 1 deletion msteams-platform/messaging-extensions/how-to/link-unfurling.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ Example of the response:

```

# [C#](#tab/dotnet)
# [.NET](#tab/dotnet)

```csharp
protected override Task<MessagingExtensionResponse> OnTeamsAppBasedLinkQueryAsync(ITurnContext<IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken)
Expand Down Expand Up @@ -234,6 +234,41 @@ contentType: "application/vnd.microsoft.card.thumbnail",

```

# [Python](#tab/python)

```python
async def on_teams_app_based_link_query(self, turn_context: TurnContext, query):
"""
Handles link unfurling when a user pastes a URL in a Teams conversation.

This method creates a ThumbnailCard displaying the pasted URL and an image,
then returns it as a Messaging Extension response.
"""
Handles unfurling links when a user pastes them in a conversation.
"""
# Create a ThumbnailCard for the unfurled link
attachment = ThumbnailCard(
title="Thumbnail Card", # Title for the card
text=query.url, # Display the URL that was pasted
images=[
# Add an image for the card (example image from GitHub)
CardImage(
url="https://raw.githubusercontent.com/microsoft/botframework-sdk/master/icon.png"
)
],
).to_attachment()

# Prepare a MessagingExtensionResult with the unfurled link
result = MessagingExtensionResult(
type="result", # Indicates this is a result
attachment_layout="list", # Use list layout
attachments=[attachment], # Include the attachment
)

# Return the response with the unfurled link
return MessagingExtensionResponse(compose_extension=result)
```

---

## Micro-capabilities for website links
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ Microsoft 365 agents provide integration with various Microsoft 365 products, su

The following code provides an example of search-based for message extensions:

# [C#](#tab/dotnet)
# [.NET](#tab/dotnet)

* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsactivityhandler.onteamsmessagingextensionqueryasync?view=botbuilder-dotnet-stable&preserve-view=true)
* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/app-hello-world/csharp/Microsoft.Teams.Samples.HelloWorld.Web/Bots/MessageExtension.cs#L26-L59)
Expand Down Expand Up @@ -197,6 +197,55 @@ async handleTeamsMessagingExtensionQuery(context, query) {
}
```

# [Python](#tab/python)

```python
async def on_teams_messaging_extension_query(self, context, query):
"""
Handles Messaging Extension queries in Teams.

This method generates a list of thumbnail cards containing random text and images when the "getRandomText" command is triggered. It creates preview cards with tap actions and returns them as a Messaging Extension response.
"""
faker = Faker()
title = query.command_id
random_image_url = "https://loremflickr.com/200/200"

if query.command_id == "getRandomText":
attachments = []
# Generate 5 results with fake text and fake images
for i in range(5):
text = faker.paragraph()
images = [f"{random_image_url}?random={i}"]

# Create a thumbnail card using ThumbnailCard
thumbnail_card = self.create_thumbnail_card(title, text, images)

# Create a preview card and add the tap action
preview_card = self.create_thumbnail_card(title, text, images)
tap_action = CardAction(
type="invoke",
value={"title": title, "text": text, "images": images},
)
preview_attachment = CardFactory.thumbnail_card(preview_card)
preview_attachment.content.tap = tap_action

# Combine the thumbnail card and the preview
attachment = MessagingExtensionAttachment(
content = thumbnail_card,
content_type=CardFactory.content_types.thumbnail_card,
preview=preview_attachment,
)
attachments.append(attachment)

return MessagingExtensionResponse(
compose_extension=MessagingExtensionResult(
type="result",
attachment_layout="list",
attachments=attachments,
)
)
```

---

## Code sample
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ author: surbhigupta
description: Learn how to respond to the search command from a message extension in a Microsoft Teams app. Understand how to respond to the user request.
ms.topic: conceptual
ms.author: anclear
ms.date: 03/06/2025
ms.localizationpriority: medium
ms.owner: slamba
ms.date: 03/11/2025
---
# Respond to search command

Expand All @@ -27,7 +26,7 @@ The request parameters are found in the `value` object in the request, which inc
| `parameters` | Array of parameters. Each parameter object contains the parameter name, along with the parameter value provided by the user. |
| `queryOptions` | Pagination parameters: <br>`skip`: Skip count for this query <br>`count`: Number of elements to return. |

# [C#/.NET](#tab/dotnet)
# [C#/.NET](#tab/dotnet1)

* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsactivityhandler.onteamsmessagingextensionqueryasync?view=botbuilder-dotnet-stable&preserve-view=true)
* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/msgext-link-unfurling/csharp/Bots/LinkUnfurlingBot.cs#L32)
Expand Down Expand Up @@ -177,7 +176,7 @@ To send an Adaptive Card or connector card for Microsoft 365 Groups, you must in

### Response example

# [C#/.NET](#tab/dotnet)
# [.NET](#tab/dotnet)

```csharp
protected override async Task<MessagingExtensionResponse> OnTeamsMessagingExtensionQueryAsync(ITurnContext<IInvokeActivity> turnContext, MessagingExtensionQuery query, CancellationToken cancellationToken)
Expand Down Expand Up @@ -211,7 +210,7 @@ protected override async Task<MessagingExtensionResponse> OnTeamsMessagingExtens
}
```

# [TypeScript/Node.js](#tab/typescript)
# [TypeScript/Node.js](#tab/typescript2)

[Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/msgext-search-quickstart/js/botActivityHandler.js#L35)

Expand Down Expand Up @@ -240,7 +239,7 @@ class TeamsMessagingExtensionsSearchBot extends TeamsActivityHandler {
}
```

# [JSON](#tab/json)
# [JSON](#tab/json2)

```json
{
Expand Down Expand Up @@ -372,11 +371,85 @@ class TeamsMessagingExtensionsSearchBot extends TeamsActivityHandler {
}
```

# [Python](#tab/python1)

```python
async def on_teams_messaging_extension_query(self, context, query):
"""
Handles a Messaging Extension query for searching NPM packages.

This method takes a search query from Teams, fetches matching NPM packages using
the NPM registry API, and returns a list of thumbnail cards displaying package
details with action buttons.
"""
search_query = query.parameters[0].value

response = requests.get(
"http://registry.npmjs.com/-/v1/search",
params={"text": search_query, "size": 8}, # Limit results to top 8
)
response.raise_for_status() # Raise an error if the API call fails
data = response.json() # Parse the JSON response from the API

attachments = []
for obj in data["objects"][:8]: # Iterate through the first 5 search results
package = obj.get("package", {})
package_name = package.get("name", "Unknown Package") # Fallback if name is missing
description = package.get("description", "No description available") # Fallback for missing description
homepage = package.get("links", {}).get("homepage", "https://www.npmjs.com") # Default link

thumbnail_card = ThumbnailCard(
title = package_name, # Package name as card title
text = description, # Package description
buttons=[
# Button to view the package on NPM
CardAction(
type="openUrl",
title="View on NPM",
value=f"https://www.npmjs.com/package/{package_name}",
),
# Button to visit the package's homepage
CardAction(
type="openUrl",
title="Homepage",
value=homepage,
),
],
)

preview_card = ThumbnailCard(
title=package_name,
text = description,
)
preview_attachment = CardFactory.thumbnail_card(preview_card)

preview_attachment.content.tap = CardAction(
type="invoke", # Invoke action triggers a bot command
value={"title": package_name, "description": description},
)

attachment = MessagingExtensionAttachment(
content=thumbnail_card,
content_type=CardFactory.content_types.thumbnail_card,
preview=preview_attachment,
)

attachments.append(attachment)

return MessagingExtensionResponse(
compose_extension=MessagingExtensionResult(
type="result", # Indicates this is a list of results
attachment_layout="list", # Layout style for results
attachments=attachments,
)
)
```

* * *

### Enable and handle tap actions

# [C#/.NET](#tab/dotnet)
# [.NET](#tab/csharp3)

* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/msgext-search/csharp/Bots/TeamsMessagingExtensionsSearchBot.cs#L80)

Expand Down Expand Up @@ -410,7 +483,7 @@ protected override Task<MessagingExtensionResponse> OnTeamsMessagingExtensionSel
}
```

# [TypeScript/Node.js](#tab/typescript)
# [TypeScript/Node.js](#tab/typescript3)

* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/msgext-search/nodejs/bots/teamsMessagingExtensionsSearchBot.js#L115)

Expand All @@ -426,7 +499,7 @@ async handleTeamsMessagingExtensionSelectItem(context, obj) {
}
```

# [JSON](#tab/json)
# [JSON](#tab/json3)

```json
{
Expand All @@ -443,6 +516,32 @@ async handleTeamsMessagingExtensionSelectItem(context, obj) {
}
```

# [Python](#tab/python3)

```python
async def on_teams_messaging_extension_select_item(
self, turn_context: TurnContext, query
) -> MessagingExtensionResponse:

thumbnail_card = ThumbnailCard(
title = query.get("title") # Extract title from the query
text = query.get("description"), # Extract description from the query
)

attachment = MessagingExtensionAttachment(
content_type=CardFactory.content_types.thumbnail_card,
content=thumbnail_card,
)

return MessagingExtensionResponse(
compose_extension=MessagingExtensionResult(
type="result", # Indicates this is a single result
attachment_layout="list", # Use list layout
attachments=[attachment], # Include the single attachment
)
)
```

* * *

## Default query
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ The following code provides an example of an invoke request received on bot side

The following code provides an example of an invoke response to return Adaptive Cards:

# [.NET](#tab/csharp)

```C#
string cardJson = "<adaptive card json>";
var card = JsonConvert.DeserializeObject(cardJson);
Expand All @@ -119,6 +121,21 @@ var adaptiveCardResponse = JObject.FromObject(new
});
```

# [Python](#tab/python)

```python
card_json = "<adaptive card json>"
card = json.loads(card_json)

adaptive_card_response = {
"statusCode": 200,
"type": "application/vnd.microsoft.adaptive.card",
"value": card
}
```

---

## Code samples

|Sample name | Description | .NET | Node.js | Manifest|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ The following code provides an example of an adaptiveCard/action invoke response

The following code provides an example of an invoke response to return Adaptive Cards:

### [C#](#tab/C)
### [.NET](#tab/C)

```csharp
string cardJson = "<adaptive card json>";
Expand Down Expand Up @@ -214,9 +214,29 @@ const cardRes = {

```

***
### [Python](#tab/python)

The following list provides card design guidelines for User Specific Views:
```python
card = "<adaptive card json>"

card_body = {
"statusCode": 200,
"type": "application/vnd.microsoft.card.adaptive",
"value": card
}

result = {
"status": 200,
"body": card_body
}

return result

```

---

The following list provides card design guidelines for User Specific Views:

* Refresh behavior: You can create a maximum of 60 User Specific Views for a particular card sent to a conversation by specifying their `userIds` in the `Refresh` property.

Expand All @@ -234,18 +254,18 @@ The following list provides card design guidelines for User Specific Views:

* For scenarios with larger groups where users switch to a view on action, which needs dynamic updates for responders, you can keep adding up to 60 users to the `userIds` list. You can remove the first responder from the list when the 61st user responds. For the users who get removed from the `userIds` list, you can provide a manual **Refresh** to get the latest result.

* Give prompt to the users to get a User Specific View, where they see only a particular view of the card or some actions.
* Give prompt to the users to get a User Specific View, where they see only a particular view of the card or some actions.

> [!NOTE]
> The User Specific Card returned by the bot is sent only to the specific client that requested for it. For example, if a user switches to a different client, such as from desktop to mobile, then another invoke event is triggered to fetch the refreshed card.
> The User Specific Card returned by the bot is sent only to the specific client that requested for it. For example, if a user switches to a different client, such as from desktop to mobile, then another invoke event is triggered to fetch the refreshed card.

## Code sample

|Sample name | Description | .NET | Node.js | Manifest
|----------------|-----------------|--------------|--------------|--------------|
| Sequential Workflows Adaptive Cards | This sample demonstrates the implementation of Sequential Workflows, User Specific Views, and current Adaptive Cards in bots. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/bot-sequential-flow-adaptive-cards/csharp) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/bot-sequential-flow-adaptive-cards/nodejs) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-sequential-flow-adaptive-cards/csharp/demo-manifest/bot-sequential-flow-adaptive-cards.zip) |

## See also
## See also:

* [Cards and dialogs](../../cards-and-task-modules.md)
* [Work with Universal Actions for Adaptive Cards](Work-with-Universal-Actions-for-Adaptive-Cards.md)
Expand Down
Loading