Skip to content
Open
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
1 change: 1 addition & 0 deletions authoring/solutions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Importable Power Platform solutions in PnP format. Each solution includes packag
| Folder | Description |
|--------|-------------|
| [account-contact-lookup/](./account-contact-lookup/) | Multi-agent Dataverse account and contact lookup |
| [adaptive-card-refresh/](./adaptive-card-refresh/) | Refresh/replace an Adaptive Card after submission in Teams (Universal Actions) |
| [auto-detect-language/](./auto-detect-language/) | Automatically detect user language |
| [dataverse-indexer/](./dataverse-indexer/) | Index Dataverse tables for agent knowledge |
| [feedback-analyzer/](./feedback-analyzer/) | Analyze agent conversation feedback with MDA and workflows |
Expand Down
21 changes: 21 additions & 0 deletions authoring/solutions/adaptive-card-refresh/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023 Nghiem Doan

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
82 changes: 82 additions & 0 deletions authoring/solutions/adaptive-card-refresh/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
title: Adaptive Card Refresh
parent: Solutions
grand_parent: Authoring
nav_order: 7
---
# Adaptive Card Refresh (Universal Actions)

Refresh or replace an Adaptive Card the moment a user submits it in Microsoft Teams,
so a completed form can't be filled in or submitted twice.

By default, an Adaptive Card stays interactive after a user clicks **Submit**: the
inputs clear, the card still looks fillable, and the user gets no confirmation that
their response was received. This solution fixes that using the
[Universal Action model](https://learn.microsoft.com/en-us/adaptive-cards/authoring-cards/universal-action-model):
the card's buttons use `Action.Execute` with a unique `verb`, a listener topic
catches the resulting invoke activity, branches on the verb, and returns a
replacement card that Teams swaps in place.

![Adaptive Card refresh demo](./assets/RefreshAdaptiveCard.gif)

{: .note }
> **Attribution.** This solution was authored by **Nghiem Doan** and is included here
> under its original MIT license (see [`LICENSE`](./LICENSE)). Original repository:
> [nghiemdoan-msft/AdaptiveCardInCopilotStudio](https://github.com/nghiemdoan-msft/AdaptiveCardInCopilotStudio).

## How it works

1. **Design the card with `Action.Execute`.** Instead of `Action.Submit`, each button
uses `Action.Execute` with a unique `verb` (for example `feedbackSubmitForm` and
`feedbackSkipForm`) and `"fallback": "Action.Submit"` for clients that don't
support Universal Actions.
2. **Display it with a "Send a message" node.** Do not use "Ask with Adaptive Card" —
that node uses `Action.Submit` internally and won't trigger the invoke/refresh flow.
3. **Listen for the invoke.** A topic triggered by **Invoke Received** parses the
activity payload and reads `resultData.action.verb`.
4. **Return a replacement card.** The listener branches on the verb and returns the
Universal Action response format, and Teams replaces the original card in place:

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

## What's in the solution

| Topic | Role |
|---|---|
| `CaptureFeedbackV2` | Displays the survey Adaptive Card (`Action.Execute` buttons) |
| `CardListenerV2` | Listens for the invoke activity and returns the replacement card |

Unpacked source (PnP format) is in [`sourcecode/`](./sourcecode/); the importable
package is in [`solution/`](./solution/).

## Importing

1. Download [`solution/FeedbackAgent_1_0_0_5.zip`](./solution/FeedbackAgent_1_0_0_5.zip).
2. Go to [make.powerapps.com](https://make.powerapps.com) > **Solutions** > **Import solution**.
3. Select the zip, then **Next** > **Import**.
4. Open the imported **FeedbackAgent** in Copilot Studio and **Publish** it.
5. Add the **Microsoft Teams** channel.

{: .warning }
> Test in **Teams**, not the Copilot Studio test canvas. The invoke/refresh flow only
> runs in a published channel, so the card replacement won't appear in the test panel.

## Notes and trade-offs

- **Teams-specific.** The invoke/refresh flow relies on the Teams channel. For custom
web portals built on BotFramework-WebChat, use the client-side attachment middleware
pattern instead. Neither pattern applies in the Microsoft 365 Copilot channel today.
- **Publish to debug.** Because the invoke response only works in a published channel,
you'll need to publish the agent to test each change.

## Related reading

- Blog walkthrough: [Disabling Adaptive Cards After Submission in Copilot Studio Agents](https://microsoft.github.io/mcscatblog/posts/disable-adaptive-cards-after-submission/)
- [Universal Action model](https://learn.microsoft.com/en-us/adaptive-cards/authoring-cards/universal-action-model)
- [Send a message node](https://learn.microsoft.com/microsoft-copilot-studio/authoring-send-message)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<ImportExportXml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" OrganizationVersion="9.2.26061.153" OrganizationSchemaType="Standard" CRMServerServiceabilityVersion="9.2.26061.00153">
<Entities />
<Roles />
<Workflows />
<FieldSecurityProfiles />
<Templates />
<EntityMaps />
<EntityRelationships />
<OrganizationSettings />
<optionsets />
<CustomControls />
<EntityDataProviders />
<Languages>
<Language>1033</Language>
</Languages>
</ImportExportXml>
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<ImportExportXml version="9.2.26061.153" SolutionPackageVersion="9.2" languagecode="1033" generatedBy="CrmLive" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" OrganizationVersion="9.2.26061.153" OrganizationSchemaType="Standard" CRMServerServiceabilityVersion="9.2.26061.00153">
<SolutionManifest>
<UniqueName>FeedbackAgent</UniqueName>
<LocalizedNames>
<LocalizedName description="Feedback Agent" languagecode="1033" />
</LocalizedNames>
<Descriptions />
<Version>1.0.0.5</Version>
<Managed>0</Managed>
<Publisher>
<UniqueName>MicrosoftPowerAccelerator</UniqueName>
<LocalizedNames>
<LocalizedName description="Microsoft Power Accelerator" languagecode="1033" />
</LocalizedNames>
<Descriptions />
<EMailAddress xsi:nil="true"></EMailAddress>
<SupportingWebsiteUrl xsi:nil="true"></SupportingWebsiteUrl>
<CustomizationPrefix>mpa</CustomizationPrefix>
<CustomizationOptionValuePrefix>86542</CustomizationOptionValuePrefix>
<Addresses>
<Address>
<AddressNumber>1</AddressNumber>
<AddressTypeCode>1</AddressTypeCode>
<City xsi:nil="true"></City>
<County xsi:nil="true"></County>
<Country xsi:nil="true"></Country>
<Fax xsi:nil="true"></Fax>
<FreightTermsCode xsi:nil="true"></FreightTermsCode>
<ImportSequenceNumber xsi:nil="true"></ImportSequenceNumber>
<Latitude xsi:nil="true"></Latitude>
<Line1 xsi:nil="true"></Line1>
<Line2 xsi:nil="true"></Line2>
<Line3 xsi:nil="true"></Line3>
<Longitude xsi:nil="true"></Longitude>
<Name xsi:nil="true"></Name>
<PostalCode xsi:nil="true"></PostalCode>
<PostOfficeBox xsi:nil="true"></PostOfficeBox>
<PrimaryContactName xsi:nil="true"></PrimaryContactName>
<ShippingMethodCode>1</ShippingMethodCode>
<StateOrProvince xsi:nil="true"></StateOrProvince>
<Telephone1 xsi:nil="true"></Telephone1>
<Telephone2 xsi:nil="true"></Telephone2>
<Telephone3 xsi:nil="true"></Telephone3>
<TimeZoneRuleVersionNumber xsi:nil="true"></TimeZoneRuleVersionNumber>
<UPSZone xsi:nil="true"></UPSZone>
<UTCOffset xsi:nil="true"></UTCOffset>
<UTCConversionTimeZoneCode xsi:nil="true"></UTCConversionTimeZoneCode>
</Address>
<Address>
<AddressNumber>2</AddressNumber>
<AddressTypeCode>1</AddressTypeCode>
<City xsi:nil="true"></City>
<County xsi:nil="true"></County>
<Country xsi:nil="true"></Country>
<Fax xsi:nil="true"></Fax>
<FreightTermsCode xsi:nil="true"></FreightTermsCode>
<ImportSequenceNumber xsi:nil="true"></ImportSequenceNumber>
<Latitude xsi:nil="true"></Latitude>
<Line1 xsi:nil="true"></Line1>
<Line2 xsi:nil="true"></Line2>
<Line3 xsi:nil="true"></Line3>
<Longitude xsi:nil="true"></Longitude>
<Name xsi:nil="true"></Name>
<PostalCode xsi:nil="true"></PostalCode>
<PostOfficeBox xsi:nil="true"></PostOfficeBox>
<PrimaryContactName xsi:nil="true"></PrimaryContactName>
<ShippingMethodCode>1</ShippingMethodCode>
<StateOrProvince xsi:nil="true"></StateOrProvince>
<Telephone1 xsi:nil="true"></Telephone1>
<Telephone2 xsi:nil="true"></Telephone2>
<Telephone3 xsi:nil="true"></Telephone3>
<TimeZoneRuleVersionNumber xsi:nil="true"></TimeZoneRuleVersionNumber>
<UPSZone xsi:nil="true"></UPSZone>
<UTCOffset xsi:nil="true"></UTCOffset>
<UTCConversionTimeZoneCode xsi:nil="true"></UTCConversionTimeZoneCode>
</Address>
</Addresses>
</Publisher>
<RootComponents />
<MissingDependencies />
</SolutionManifest>
</ImportExportXml>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<botcomponent schemaname="mpa_FeedbackAgent.knowledge.httpslearnmicrosoftcom_PzjBlx5MtLj91xzrCByAR">
<componenttype>16</componenttype>
<description>This knowledge source searches information on the web found in https://learn.microsoft.com/ website</description>
<iscustomizable>0</iscustomizable>
<name>https://learn.microsoft.com/</name>
<parentbotid>
<schemaname>mpa_FeedbackAgent</schemaname>
</parentbotid>
<statecode>0</statecode>
<statuscode>1</statuscode>
</botcomponent>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
kind: KnowledgeSourceConfiguration
source:
kind: PublicSiteSearchSource
site: https://learn.microsoft.com/
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<botcomponent schemaname="mpa_FeedbackAgent.topic.CaptureFeedbackV2">
<componenttype>9</componenttype>
<iscustomizable>0</iscustomizable>
<name>Capture Feedback</name>
<parentbotid>
<schemaname>mpa_FeedbackAgent</schemaname>
</parentbotid>
<statecode>0</statecode>
<statuscode>1</statuscode>
</botcomponent>
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
kind: AdaptiveDialog
modelDescription: Regarding feedback or survey
beginDialog:
kind: OnRecognizedIntent
id: main
intent:
displayName: Untitled (Copy)

actions:
- kind: SendActivity
id: sendActivity_XauhTN
activity:
text:
- Please share your feedback with us!
attachments:
- kind: AdaptiveCardTemplate
cardContent: |-
{
"type": "AdaptiveCard",
"$schema": "https://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.5",
"body": [
{
"type": "Container",
"items": [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "auto",
"items": [
{
"type": "Icon",
"name": "TaskListSquareRtl",
"size": "Small"
}
],
"spacing": "Small"
},
{
"type": "Column",
"width": "stretch",
"spacing": "Small",
"items": [
{
"type": "TextBlock",
"text": "Survey",
"wrap": true,
"weight": "Bolder"
}
],
"verticalContentAlignment": "Center"
}
]
}
],
"showBorder": false
},
{
"type": "Container",
"separator": true,
"spacing": "Medium",
"items": [
{
"type": "TextBlock",
"text": "Experience Feedback",
"wrap": true,
"size": "Large",
"weight": "Bolder"
}
]
},
{
"type": "Input.Rating",
"isRequired": true,
"errorMessage": "Please select rating stars.",
"id": "ratingStars",
"color": "Marigold",
"label": "How was your overall experience?"
},
{
"id": "txtComments",
"type": "Input.Text",
"placeholder": "Provide your comments",
"isMultiline": true,
"maxLength": 255,
"label": "Any other comments?"
},
{
"type": "ActionSet",
"actions": [
{
"type": "Action.Execute",
"title": "Submit",
"data": {
"actionType": "submitted"
},
"verb": "feedbackSubmitForm",
"fallback": "Action.Submit",
"style": "positive"
},
{
"type": "Action.Execute",
"title": "Skip",
"data": {
"actionType": "skipped"
},
"associatedInputs": "none",
"verb": "feedbackSkipForm",
"fallback": "Action.Submit"
}
]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<botcomponent schemaname="mpa_FeedbackAgent.topic.CardListenerV2">
<componenttype>9</componenttype>
<iscustomizable>0</iscustomizable>
<name>Card Listener</name>
<parentbotid>
<schemaname>mpa_FeedbackAgent</schemaname>
</parentbotid>
<statecode>0</statecode>
<statuscode>1</statuscode>
</botcomponent>
Loading