diff --git a/README.md b/README.md index 74aff86a..423cc0df 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ This repository contains [Microsoft 365 Copilot](https://learn.microsoft.com/mic | [Declarative for Microsoft 365 Copilot with an API plugin connected to an API secured with OAuth](./samples/da-repairs-oauth) | This sample demonstrates how to build a declarative agent for Microsoft 365 Copilot that answers questions about repairs. The agent uses an API plugin to connect to an API secured with OAuth. The project contains an Azure Function that serves as the API and uses the built-in Azure App Service authentication and authorization capabilities (also referred to as Easy Auth) to secure access to APIs. | Waldek Mastykarz | | [Document Finder Declarative Agent for Microsoft 365 Copilot Sample](./samples/da-DocFinder) | First Party Declarative Agent Document Finder shared as a sample | Jeremy Thake | | [ESA, The Environment Sustainability Agent using Microsoft 365 Copilot](./samples/da-environmentSustainability) | This sample showcases how to build a declarative agent for Microsoft 365 Copilot connected to a SharePoint site as knowledge base, named ESA, the Environment Sustainability Agent. ESA is an intelligent assistant developed to assist organizations in monitoring and optimizing their environmental impact. | Rabia Williams | +| [Foodbank Friend](./samples/da-foodbank-friend) | A declarative agent that helps users in the UK find local food banks, see what items they need, and schedule volunteer donation visits using the GiveFood API, Outlook Calendar, and SharePoint Lists. | Lee Ford | | [Finding and apply for volunteer opportunities using Microsoft 365 Copilot with SharePoint List and Azure Ai Search - No code!](./samples/da-typespec-AzureAISearch_MsGraph-volunteeringapp) | This sample demonstrates how to build a declarative agent for Microsoft 365 Copilot using TypeSpec that allows you to find and apply for volunteer opportunities using Microsoft 365 Copilot with SharePoint List and Azure Ai Search integration and authentication. | Reshmee Auckloo, Lee Ford | | [Finding and apply for volunteer opportunities using Microsoft 365 Copilot with SharePoint List and Azure Ai Search - No code!](./samples/da-volunteeringapp) | This sample demonstrates how to build a declarative agent for Microsoft 365 Copilot that allows you to find and apply for volunteer opportunities using Microsoft 365 Copilot with SharePoint List and Azure Ai Search integration and authentication. | Reshmee Auckloo, Lee Ford | | [Geo Locator Game](./samples/da-geolocator-game) | This sample demonstrates how to create a Geo Locator Game declarative agent using Microsoft 365 Copilot. | Ayca Bas, Garry Trinder | @@ -68,8 +69,8 @@ This repository contains [Microsoft 365 Copilot](https://learn.microsoft.com/mic | [Trey Research TypeSpec](./samples/da-typespec-trey-research) | This sample demonstrates how to create an agent that interacts with a consulting API to provide information about consultants and projects. | Bob German, Rabia Williams | | [Visual Mind agent Visualizer Assistant](./samples/da-visual-mind-agent) | The Visual Mind agent is a Visualizer Assistant that will help the user with tasks related to creating clear, structured, and engaging visuals using Mermaid.js code. | Mohammad Amer | | [Writing Coach Declarative Agent for Microsoft 365 Copilot Sample](./samples/da-WritingCoach) | First Party Declarative Agent Writing Coach shared as a sample | Phi-Lay NGUYEN | - + ## Have issues or questions? @@ -92,8 +93,3 @@ This repository has adopted the [Microsoft Open Source Code of Conduct](https:// > Sharing is caring! ![](https://m365-visitor-stats.azurewebsites.net/copilot-pro-dev-samples/README.md) - - - - - diff --git a/samples/da-foodbank-friend/.gitignore b/samples/da-foodbank-friend/.gitignore new file mode 100644 index 00000000..abcba466 --- /dev/null +++ b/samples/da-foodbank-friend/.gitignore @@ -0,0 +1,20 @@ +# TeamsFx files +env/.env.*.user +env/.env.local +.localConfigs +appPackage/build + +# dependencies +node_modules/ + +# misc +.env +env/.env.* +.deployment +.DS_Store + +# generated files +appPackage/.generated + +# Allow example env files to be committed +!env/.env.*.example \ No newline at end of file diff --git a/samples/da-foodbank-friend/.vscode/extensions.json b/samples/da-foodbank-friend/.vscode/extensions.json new file mode 100644 index 00000000..aac0a6e3 --- /dev/null +++ b/samples/da-foodbank-friend/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "TeamsDevApp.ms-teams-vscode-extension" + ] +} diff --git a/samples/da-foodbank-friend/.vscode/launch.json b/samples/da-foodbank-friend/.vscode/launch.json new file mode 100644 index 00000000..6bf71a96 --- /dev/null +++ b/samples/da-foodbank-friend/.vscode/launch.json @@ -0,0 +1,29 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Preview in Copilot (Edge)", + "type": "msedge", + "request": "launch", + "url": "https://m365.cloud.microsoft/chat/entity1-d870f6cd-4aa5-4d42-9626-ab690c041429/${agent-hint}?auth=2&developerMode=Basic", + "presentation": { + "group": "remote", + "order": 1 + }, + "internalConsoleOptions": "neverOpen", + "runtimeArgs": ["--remote-debugging-port=9222", "--no-first-run"] + }, + { + "name": "Preview in Copilot (Chrome)", + "type": "chrome", + "request": "launch", + "url": "https://m365.cloud.microsoft/chat/entity1-d870f6cd-4aa5-4d42-9626-ab690c041429/${agent-hint}?auth=2&developerMode=Basic", + "presentation": { + "group": "remote", + "order": 2 + }, + "internalConsoleOptions": "neverOpen", + "runtimeArgs": ["--remote-debugging-port=9223", "--no-first-run"] + } + ] +} diff --git a/samples/da-foodbank-friend/.vscode/settings.json b/samples/da-foodbank-friend/.vscode/settings.json new file mode 100644 index 00000000..187eca2c --- /dev/null +++ b/samples/da-foodbank-friend/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "debug.onTaskErrors": "abort", + "json.schemas": [ + { + "fileMatch": ["/aad.*.json"], + "schema": {} + } + ], + "files.readonlyInclude": { + "appPackage/.generated/**/*": true + } +} diff --git a/samples/da-foodbank-friend/README.md b/samples/da-foodbank-friend/README.md new file mode 100644 index 00000000..3f5569bb --- /dev/null +++ b/samples/da-foodbank-friend/README.md @@ -0,0 +1,134 @@ +# Declarative Agent - Foodbank Friend + +![Declarative Agent - Foodbank Friend](./assets/example.gif) + +## Summary + +This repository contains a declarative agent that helps users in the UK find local food banks, see what items they need, and schedule volunteer donation visits. The agent connects to the [GiveFood API](https://www.givefood.org.uk/api/) to search for nearby food banks and their current needs, then coordinates the scheduling process by creating Outlook calendar appointments and tracking volunteer commitments in SharePoint. A key point of emphasis on this agent was combining multiple action types - **Remote MCP Servers** for Microsoft 365 services (Outlook Calendar and SharePoint Lists) alongside a traditional **OpenAPI** connector for the external GiveFood API. The agent is built using the Microsoft 365 Agents Toolkit. + +![Solution diagram](./assets/solution-diagram.png) + +## Contributors + +* [Lee Ford](https://github.com/leeford) - M365 Development MVP + +## Version history + +Version|Date|Comments +-------|----|-------- +1.0 | March 25, 2026 | Initial solution + +> **Prerequisites** +> +> To run this app template from your local dev machine, you will need: +> +> * A [Microsoft 365 account for development](https://docs.microsoft.com/microsoftteams/platform/toolkit/accounts) +> * [Microsoft 365 Agents Toolkit Visual Studio Code Extension](https://aka.ms/teams-toolkit) +> * [Microsoft 365 Copilot license](https://learn.microsoft.com/microsoft-365-copilot/extensibility/prerequisites#prerequisites) +> * A SharePoint site with a custom list for tracking volunteer commitments (see setup instructions below) + +## Minimal path to awesome + +1. Clone this repository + +2. Register an Entra ID application in Azure: + + 1. Go to [Azure portal](https://portal.azure.com/) + 2. Select **Microsoft Entra ID** > **Manage** > **App registrations** > **New registration** + 3. Enter a name for the app (e.g., Foodbank Friend) + 4. Select **Accounts in this organizational directory only** + 5. Under **Redirect URI**, select **Web** and enter `https://teams.microsoft.com/api/platform/v1.0/oAuthRedirect` + 6. Select **Register** + 7. In the app registration, go to **Certificates & secrets** and create a new client secret + 8. Copy the client secret value + 9. In the app registration, go to **API permissions** and add the following permissions: + * **agent365.svc.cloud.microsoft** > **Delegated permissions** > `McpServers.Calendar.All`, `McpServers.SharepointLists.All` + 10. Select **Grant admin consent for ** to grant the permissions + +3. Create a SharePoint list for tracking volunteer commitments: + + 1. Go to your SharePoint site + 2. Create a new list named **Volunteer Commitments** with the following columns: + * **Title** (Single line of text) - Default column + * **VolunteerName** (Single line of text) + * **FoodBankName** (Single line of text) + * **FoodBankAddress** (Multiple lines of text) + * **AppointmentDate** (Date and Time) + * **ItemsCommitted** (Multiple lines of text) + * **Status** (Choice: Scheduled, Completed, Cancelled) + * **CreatedDate** (Date and Time) + 3. Note down the **Site ID** and **List ID** (you can find these in the list settings URL or via Graph Explorer) + +4. In the [Teams developer portal](https://dev.teams.microsoft.com/) under **Tools**, create a new **OAuth client registration** with the following information (replace `` with your own tenant ID): + + **App settings** + + * **Registration name**: Foodbank Friend + * **Base URL**: `https://agent365.svc.cloud.microsoft` + * **Restrict usage by org**: My organization only + * **Restrict usage by app**: Any Teams app (when agent is deployed, use the Teams app ID) + + **OAuth settings** + * **Client ID**: <Entra ID App registration client ID> + * **Client secret**: <Entra ID App registration client secret> + * **Authorization endpoint**: `https://login.microsoftonline.com//oauth2/v2.0/authorize` + * **Token endpoint**: `https://login.microsoftonline.com//oauth2/v2.0/token` + * **Refresh endpoint**: `https://login.microsoftonline.com//oauth2/v2.0/token` + * **Scope**: `ea9ffc3e-8a23-4a7d-836d-234d7c7565c1/.default` + + Save the information. A new **OAuth client registration key** will be generated. Copy the key. + +5. Copy `env/.env.dev.example` to `env/.env.dev` and fill in the following values: + + ```bash + # Generated during provision by Microsoft 365 Agents Toolkit + TEAMS_APP_ID= + TEAMS_APP_TENANT_ID= + + # SharePoint Configuration + # Format: hostname,siteCollectionId,siteId (e.g., contoso.sharepoint.com,12345678-...,abcdef...) + SHAREPOINT_SITE_ID= + SHAREPOINT_LIST_ID= + + # OAuth Plugin Vault Reference ID - from Teams Developer Portal OAuth client registration + OAUTH_REFERENCE_ID= + ``` + +6. From Microsoft 365 Agents Toolkit, sign-in to your Microsoft 365 account. +7. From Microsoft 365 Agents Toolkit, provision the solution to create the Teams app. +8. Go to [https://www.office.com/chat?auth=2](https://www.office.com/chat?auth=2) URL and enable the developer mode by using the `-developer on` prompt. +9. Use one of the conversation starters to start the agent. + +## Features + +The following sample demonstrates the following concepts: + +* **Find Local Food Banks** - Query the GiveFood UK API to search for food banks near any UK location, displaying distance, address, and current needs +* **View Donation Needs** - Show detailed information about what items each food bank currently needs and what they have excess of +* **Schedule Volunteer Visits** - Create Outlook calendar appointments with full details including location, items to bring, and other needed items +* **Track Commitments** - Store volunteer commitments in a SharePoint list for record-keeping and history +* **View History** - Query SharePoint to show the user their past and upcoming volunteer commitments + +### APIs & Services Used + +| Service | Type | Purpose | +|---------|------|---------| +| [GiveFood UK API](https://www.givefood.org.uk/api/) | OpenAPI | Search for UK food banks and retrieve current donation needs | +| Outlook Calendar | Remote MCP Server | Create calendar appointments for volunteer visits | +| SharePoint Lists | Remote MCP Server | Track and query volunteer commitment records | + +## Help + +We do not support samples, but this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues. + +You can try looking at [issues related to this sample](https://github.com/pnp/copilot-pro-dev-samples/issues?q=label%3A%22sample%3A%20da-foodbank-friend%22) to see if anybody else is having the same issues. + +If you encounter any issues using this sample, [create a new issue](https://github.com/pnp/copilot-pro-dev-samples/issues/new). + +Finally, if you have an idea for improvement, [make a suggestion](https://github.com/pnp/copilot-pro-dev-samples/issues/new). + +## Disclaimer + +**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.** + +![](https://m365-visitor-stats.azurewebsites.net/copilot-pro-dev-samples/samples/da-foodbank-friend) diff --git a/samples/da-foodbank-friend/appPackage/ai-plugin-givefood.json b/samples/da-foodbank-friend/appPackage/ai-plugin-givefood.json new file mode 100644 index 00000000..812c4d7d --- /dev/null +++ b/samples/da-foodbank-friend/appPackage/ai-plugin-givefood.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/copilot/plugin/v2.4/schema.json", + "schema_version": "v2.4", + "name_for_human": "GiveFood UK API", + "description_for_human": "Search UK food banks and their current needs", + "description_for_model": "Search for UK food banks by location and retrieve their current donation needs using the GiveFood API", + "namespace": "givefood", + "functions": [ + { + "name": "searchFoodBanks", + "description": "Search for food banks near a UK location using address, postcode, or place name." + } + ], + "runtimes": [ + { + "type": "OpenApi", + "auth": { + "type": "None" + }, + "spec": { + "url": "apiSpecificationFile/givefood-openapi.yaml" + }, + "run_for_functions": [ + "searchFoodBanks" + ] + } + ] +} \ No newline at end of file diff --git a/samples/da-foodbank-friend/appPackage/ai-plugin-outlook.json b/samples/da-foodbank-friend/appPackage/ai-plugin-outlook.json new file mode 100644 index 00000000..88cd2cf7 --- /dev/null +++ b/samples/da-foodbank-friend/appPackage/ai-plugin-outlook.json @@ -0,0 +1,72 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/copilot/plugin/v2.4/schema.json", + "schema_version": "v2.4", + "name_for_human": "Outlook Calendar", + "description_for_human": "Create and manage Outlook calendar events", + "description_for_model": "Create Outlook calendar appointments for volunteer food bank visits", + "namespace": "outlook", + "functions": [ + { + "name": "createEvent", + "description": "Create a calendar appointment for the volunteer's food bank visit", + "parameters": { + "type": "object", + "properties": { + "subject": { + "type": "string", + "description": "The subject/title of the calendar event" + }, + "startDateTime": { + "type": "string", + "description": "Start timestamp in ISO 8601 format YYYY-MM-DDTHH:MM:SS with timezone offset. MUST use this exact format, e.g. 2026-03-29T10:00:00+01:00" + }, + "endDateTime": { + "type": "string", + "description": "End timestamp in ISO 8601 format YYYY-MM-DDTHH:MM:SS with timezone offset. MUST use this exact format, e.g. 2026-03-29T11:00:00+01:00" + }, + "location": { + "type": "string", + "description": "The plain text address of the location, e.g. \"Sutton Coldfield Baptist Church, Trinity Hill, Sutton Coldfield, West Midlands, B72 1TA\"" + }, + "isOnlineMeeting": { + "type": "boolean", + "description": "Whether to create a Teams online meeting. MUST be set to false for in-person food bank visits." + }, + "body": { + "type": "string", + "description": "JSON string representing the event body with contentType and content properties. contentType MUST be \"HTML\". Example: {\"contentType\": \"HTML\", \"content\": \"

Event details

\"}" + }, + "attendeeEmails": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of attendee email addresses. Pass an empty array [] as the organiser is already added automatically." + } + }, + "required": [ + "subject", + "startDateTime", + "endDateTime", + "attendeeEmails", + "isOnlineMeeting" + ] + } + } + ], + "runtimes": [ + { + "type": "RemoteMCPServer", + "auth": { + "type": "OAuthPluginVault", + "reference_id": "${{OAUTH_REFERENCE_ID}}" + }, + "spec": { + "url": "https://agent365.svc.cloud.microsoft/agents/servers/mcp_CalendarTools" + }, + "run_for_functions": [ + "createEvent" + ] + } + ] +} \ No newline at end of file diff --git a/samples/da-foodbank-friend/appPackage/ai-plugin-sharepoint.json b/samples/da-foodbank-friend/appPackage/ai-plugin-sharepoint.json new file mode 100644 index 00000000..d165986d --- /dev/null +++ b/samples/da-foodbank-friend/appPackage/ai-plugin-sharepoint.json @@ -0,0 +1,81 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/copilot/plugin/v2.4/schema.json", + "schema_version": "v2.4", + "name_for_human": "SharePoint Lists", + "description_for_human": "Manage SharePoint sites and lists", + "description_for_model": "Plugin for creating and querying SharePoint list items to track volunteer commitments to UK food banks.", + "namespace": "sharepoint", + "functions": [ + { + "name": "createListItem", + "description": "Create a new item in a SharePoint list.", + "parameters": { + "type": "object", + "properties": { + "siteId": { + "type": "string", + "description": "The unique ID of the site", + "default": "${{SHAREPOINT_SITE_ID}}" + }, + "listId": { + "type": "string", + "description": "The unique ID of the list", + "default": "${{SHAREPOINT_LIST_ID}}" + }, + "fields": { + "type": "string", + "description": "JSON string with field values for the list item (key/value map)" + } + }, + "required": [ + "siteId", + "listId", + "fields" + ] + } + }, + { + "name": "listListItems", + "description": "Query items from a SharePoint list.", + "parameters": { + "type": "object", + "properties": { + "siteId": { + "type": "string", + "description": "The unique ID of the site", + "default": "${{SHAREPOINT_SITE_ID}}" + }, + "listId": { + "type": "string", + "description": "The unique ID of the list", + "default": "${{SHAREPOINT_LIST_ID}}" + }, + "filter": { + "type": "string", + "description": "OData filter query (e.g., 'VolunteerName eq \\'Lee Ford\\'')" + } + }, + "required": [ + "siteId", + "listId" + ] + } + } + ], + "runtimes": [ + { + "type": "RemoteMCPServer", + "auth": { + "type": "OAuthPluginVault", + "reference_id": "${{OAUTH_REFERENCE_ID}}" + }, + "spec": { + "url": "https://agent365.svc.cloud.microsoft/agents/servers/mcp_SharepointListsTools" + }, + "run_for_functions": [ + "createListItem", + "listListItems" + ] + } + ] +} \ No newline at end of file diff --git a/samples/da-foodbank-friend/appPackage/apiSpecificationFile/givefood-openapi.yaml b/samples/da-foodbank-friend/appPackage/apiSpecificationFile/givefood-openapi.yaml new file mode 100644 index 00000000..dd190302 --- /dev/null +++ b/samples/da-foodbank-friend/appPackage/apiSpecificationFile/givefood-openapi.yaml @@ -0,0 +1,198 @@ +openapi: 3.0.0 +info: + title: GiveFood UK API + description: UK Food Bank Location and Needs API + version: 2.0.0 +servers: + - url: https://www.givefood.org.uk/api/2 +paths: + /locations/search/: + get: + operationId: searchFoodBanks + summary: Search for food banks near a UK location + description: Returns a list of food banks sorted by distance from the specified address, including current needs, contact information, and location details + parameters: + - name: address + in: query + required: true + description: Full UK address, postcode, or location to search near + schema: + type: string + example: SW1P 4QE + responses: + "200": + description: Successful response with list of nearby food banks + content: + application/json: + schema: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + description: Unique identifier for the location + example: d3268f14-4e5f-4f3d-8e3a-9b0c5d6e7f8a + type: + type: string + description: Type of location (location or organisation) + slug: + type: string + description: Slugified name of the food bank + example: hull + name: + type: string + description: Name of the food bank location + example: Sid Valley + lat_lng: + type: string + description: Comma separated latitude and longitude + example: 51.4630738,-0.1207938 + distance_m: + type: number + format: float + description: Distance from the inputted location to this food bank in metres + example: 5218 + distance_mi: + type: number + format: float + description: Distance from the inputted location to this food bank in miles to two decimal places + example: 7.12 + address: + type: string + description: Multiline string with full address + example: | + Sidmouth Youth Centre + Manstone Lane + Sidmouth + EX10 9TS + postcode: + type: string + description: UK postcode + example: GU16 7HF + phone: + type: string + description: Phone number + example: "07413858335" + email: + type: string + format: email + description: Email address + example: info@sidvalleyfoodbank.org.uk + politics: + type: object + description: Political constituency information + properties: + parliamentary_constituency: + type: string + description: Name of the parliamentary constituency the food bank's main location is in + example: Vauxhall + mp: + type: string + description: Name of the member of parliament who represents parliamentary constituency that the food bank's main location is in + example: Florence Eshalomi + mp_party: + type: string + description: Political party of the member of parliament + example: Labour + mp_parl_id: + type: integer + description: Parliamentary ID of the member of parliament + ward: + type: string + description: Name of the ward the food bank's main location is in + example: Streatham Hill + district: + type: string + description: Name of the district the food bank's main location is in + example: Lambeth + urls: + type: object + properties: + html: + type: string + format: uri + description: HTML URL of the parliamentary constituency + example: https://www.givefood.org.uk/needs/in/constituency/vauxhall/ + self: + type: string + format: uri + description: API URL of the parliamentary constituency + example: https://www.givefood.org.uk/api/2/constituency/vauxhall/ + needs: + type: object + description: Current donation needs + properties: + id: + type: string + format: uuid + description: Unique identifier for needs record + needs: + type: string + description: Linebreak separated list of items in the need. Or 'Unknown', 'Nothing' or 'Facebook' keywords + example: | + UHT Milk + Tinned Tomatoes + Tinned Sweetcorn + Custard + excess: + type: string + description: Linebreak separated list of items the food bank has excess of + example: | + Baked Beans + Pasta + number: + type: integer + description: Number of different items requested by the food bank + example: 6 + found: + type: string + format: date-time + description: Date and time of when we found what the food bank needs + example: "2020-11-27T09:55:57.877Z" + foodbank: + type: object + description: Parent food bank organization + properties: + name: + type: string + description: Name of the food bank + example: Sid Valley + slug: + type: string + description: Slugified name + example: sid-valley + network: + type: string + description: Network affiliation + example: Independent + facebook_page: + type: string + description: Facebook page handle + urls: + type: object + properties: + html: + type: string + format: uri + description: HTML URL of the food bank + example: https://www.givefood.org.uk/needs/in/sid-valley/ + self: + type: string + format: uri + description: API URL of the food bank + example: https://www.givefood.org.uk/api/2/foodbank/sid-valley/ + urls: + type: object + description: Related URLs + properties: + html: + type: string + format: uri + description: HTML URL of the location + example: https://www.givefood.org.uk/needs/at/norwoodbrixton/brixton/ + homepage: + type: string + format: uri + description: Food bank's homepage URL diff --git a/samples/da-foodbank-friend/appPackage/color.png b/samples/da-foodbank-friend/appPackage/color.png new file mode 100644 index 00000000..9f681b6e Binary files /dev/null and b/samples/da-foodbank-friend/appPackage/color.png differ diff --git a/samples/da-foodbank-friend/appPackage/declarativeAgent.json b/samples/da-foodbank-friend/appPackage/declarativeAgent.json new file mode 100644 index 00000000..28ca2162 --- /dev/null +++ b/samples/da-foodbank-friend/appPackage/declarativeAgent.json @@ -0,0 +1,35 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/copilot/declarative-agent/v1.6/schema.json", + "version": "v1.6", + "name": "Foodbank Friend", + "description": "Your friendly guide to find local food banks, see what they need, and schedule volunteer visits with calendar appointments", + "instructions": "$[file('instruction.txt')]", + "conversation_starters": [ + { + "title": "Find food banks near me", + "text": "Show me food banks in my area" + }, + { + "title": "Schedule a donation", + "text": "I want to donate to a food bank" + }, + { + "title": "My volunteer commitments", + "text": "What have I volunteered for?" + } + ], + "actions": [ + { + "id": "givefood_api", + "file": "ai-plugin-givefood.json" + }, + { + "id": "sharepoint_mcp", + "file": "ai-plugin-sharepoint.json" + }, + { + "id": "outlook_mcp", + "file": "ai-plugin-outlook.json" + } + ] +} \ No newline at end of file diff --git a/samples/da-foodbank-friend/appPackage/instruction.txt b/samples/da-foodbank-friend/appPackage/instruction.txt new file mode 100644 index 00000000..58c7da49 --- /dev/null +++ b/samples/da-foodbank-friend/appPackage/instruction.txt @@ -0,0 +1,68 @@ +You are Foodbank Friend, a cheerful volunteer coordinator that helps people in the UK find local food banks and coordinate volunteer visits to donate needed items. + +**Communication Style:** +- Keep all responses warm, friendly, and conversational +- Never show technical details - just do actions seamlessly +- Focus on outcomes, not processes + +**Your Workflow:** + +1. **Find Food Banks** + - Ask for the user's UK location (postcode, address, or area) + - Search GiveFood API and show 5-8 closest results with: + • Name and distance + • 📍 Address + • 📋 Items needed count + • 🔗 More info link + +2. **Show Details** + - When user selects a food bank, display: + • Name, address, contact info + • Current needs (bulleted list) + • Excess items to avoid + • Last updated date + +3. **Schedule Volunteer Visit** + - Ask when they'd like to volunteer + - Ask which items they'll bring + - **Then immediately do BOTH:** + + a) **Add to Calendar** - Call createEvent with: + - subject: "🎁 Food Bank Donation - [name]" + - startDateTime: ISO 8601 format YYYY-MM-DDTHH:MM:SS with timezone offset, e.g. 2026-03-29T10:00:00+01:00 (use +01:00 for BST March-October, +00:00 for GMT November-February) + - endDateTime: ISO 8601 format YYYY-MM-DDTHH:MM:SS with timezone offset, e.g. 2026-03-29T11:00:00+01:00 + - location: Food bank's full address as a plain text string (e.g. "Sutton Coldfield Baptist Church, Trinity Hill, Sutton Coldfield, West Midlands, B72 1TA") - NOT a JSON object + - isOnlineMeeting: false (ALWAYS set to false - this is an in-person visit, not a Teams meeting) + - attendeeEmails: [] (always pass an empty array - the signed-in user is already the organiser) + - body: JSON string with contentType "HTML" and the full HTML content inline. Use this exact structure: + {"contentType": "HTML", "content": "

💝 Thank you for volunteering!

📍 LOCATION
[Food bank name]
[Full address]

🛒 ITEMS YOU'RE BRINGING
• [Item 1]
• [Item 2]
• [Item 3]

📋 OTHER ITEMS NEEDED
• [Needed item 1]
• [Needed item 2]
• [Needed item 3]

🔗 More info: [GiveFood URL]

"} + + b) **Add to SharePoint** - Call createListItem with: + - siteId: ${{SHAREPOINT_SITE_ID}} + - listId: ${{SHAREPOINT_LIST_ID}} + - fields: JSON string with: + { + "Title": "[Food Bank Name] - [Date]", + "VolunteerName": [User's name], + "FoodBankName": [Name from API], + "FoodBankAddress": [Full address], + "AppointmentDate": [ISO 8601 datetime], + "ItemsCommitted": [Comma-separated items], + "Status": "Scheduled", + "CreatedDate": [Current ISO 8601 datetime] + } + + - After both complete: "✅ All set! Your appointment is in your calendar and tracked in our system." + - Optionally offer to add a shopping reminder + +4. **View Commitments** + - When user asks about their volunteer history, call listListItems with: + - siteId: ${{SHAREPOINT_SITE_ID}} + - listId: ${{SHAREPOINT_LIST_ID}} + - filter: "VolunteerName eq '[User Name]'" + - Display results in friendly format with emojis + +**Important:** +- Both calendar and SharePoint updates must complete before confirming to user +- Keep responses warm and encouraging +- Make volunteering easy! \ No newline at end of file diff --git a/samples/da-foodbank-friend/appPackage/manifest.json b/samples/da-foodbank-friend/appPackage/manifest.json new file mode 100644 index 00000000..d7d97354 --- /dev/null +++ b/samples/da-foodbank-friend/appPackage/manifest.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/teams/v1.25/MicrosoftTeams.schema.json", + "manifestVersion": "1.25", + "version": "1.0.0", + "id": "${{TEAMS_APP_ID}}", + "developer": { + "name": "Lee Ford", + "websiteUrl": "https://www.example.com", + "privacyUrl": "https://www.example.com/privacy", + "termsOfUseUrl": "https://www.example.com/termofuse" + }, + "icons": { + "color": "color.png", + "outline": "outline.png" + }, + "name": { + "short": "Foodbank Friend", + "full": "Foodbank Friend - Volunteer Coordinator" + }, + "description": { + "short": "Help local food banks easily", + "full": "Foodbank Friend connects you with local food banks, shows what they need, and schedules your donation visit with a calendar appointment including shopping list and directions." + }, + "accentColor": "#FFFFFF", + "composeExtensions": [], + "copilotAgents": { + "declarativeAgents": [ + { + "id": "declarativeAgent", + "file": "declarativeAgent.json" + } + ] + }, + "permissions": [ + "identity", + "messageTeamMembers" + ], + "validDomains": [] +} \ No newline at end of file diff --git a/samples/da-foodbank-friend/appPackage/outline.png b/samples/da-foodbank-friend/appPackage/outline.png new file mode 100644 index 00000000..18dede4b Binary files /dev/null and b/samples/da-foodbank-friend/appPackage/outline.png differ diff --git a/samples/da-foodbank-friend/assets/example.gif b/samples/da-foodbank-friend/assets/example.gif new file mode 100644 index 00000000..ff29813e Binary files /dev/null and b/samples/da-foodbank-friend/assets/example.gif differ diff --git a/samples/da-foodbank-friend/assets/sample.json b/samples/da-foodbank-friend/assets/sample.json new file mode 100644 index 00000000..1ebf9663 --- /dev/null +++ b/samples/da-foodbank-friend/assets/sample.json @@ -0,0 +1,72 @@ +[ + { + "name": "pnp-copilot-pro-dev-da-foodbank-friend", + "source": "pnp", + "title": "Foodbank Friend", + "shortDescription": "A declarative agent that helps users in the UK find local food banks, see what items they need, and schedule volunteer donation visits.", + "url": "https://github.com/pnp/copilot-pro-dev-samples/tree/main/samples/da-foodbank-friend", + "downloadUrl": "https://pnp.github.io/download-partial/?url=https://github.com/pnp/copilot-pro-dev-samples/tree/main/samples/da-foodbank-friend", + "longDescription": [ + "Foodbank Friend connects users with local food banks across the UK using the GiveFood API, shows what donation items are currently needed, and coordinates volunteer visits by creating Outlook calendar appointments and tracking commitments in a SharePoint list. The agent demonstrates combining multiple action types: Remote MCP Servers for Microsoft 365 services (Outlook Calendar and SharePoint Lists) alongside a traditional OpenAPI connector for an external API." + ], + "creationDateTime": "2026-01-19", + "updateDateTime": "2026-03-25", + "products": [ + "Microsoft 365 Copilot" + ], + "metadata": [ + { + "key": "PLATFORM", + "value": "Node.js" + }, + { + "key": "LANGUAGE", + "value": "JSON" + }, + { + "key": "AGENT-TYPE", + "value": "Declarative Agent" + }, + { + "key": "API-PLUGIN", + "value": "Yes" + }, + { + "key": "GRAPH-CONNECTOR", + "value": "No" + } + ], + "thumbnails": [ + { + "type": "image", + "order": 100, + "url": "https://github.com/pnp/copilot-pro-dev-samples/raw/main/samples/da-foodbank-friend/assets/example.gif", + "alt": "Screenshot of the Foodbank Friend declarative agent in action" + } + ], + "authors": [ + { + "gitHubAccount": "leeford", + "pictureUrl": "https://github.com/leeford.png", + "name": "Lee Ford" + } + ], + "references": [ + { + "name": "Microsoft 365 Copilot extensibility", + "description": "Learn more about extending Microsoft 365 Copilot.", + "url": "https://learn.microsoft.com/microsoft-365-copilot/extensibility/" + }, + { + "name": "Declarative agents for Microsoft 365 Copilot", + "description": "Learn how to build declarative agents for Microsoft 365 Copilot.", + "url": "https://learn.microsoft.com/microsoft-365-copilot/extensibility/overview-declarative-agent" + }, + { + "name": "GiveFood API", + "description": "The GiveFood API provides data on UK food banks and their current donation needs.", + "url": "https://www.givefood.org.uk/api/" + } + ] + } +] \ No newline at end of file diff --git a/samples/da-foodbank-friend/assets/solution-diagram.png b/samples/da-foodbank-friend/assets/solution-diagram.png new file mode 100644 index 00000000..e49c3dd4 Binary files /dev/null and b/samples/da-foodbank-friend/assets/solution-diagram.png differ diff --git a/samples/da-foodbank-friend/env/.env.dev.example b/samples/da-foodbank-friend/env/.env.dev.example new file mode 100644 index 00000000..a9669b33 --- /dev/null +++ b/samples/da-foodbank-friend/env/.env.dev.example @@ -0,0 +1,22 @@ +# Copy this file to .env.dev and fill in the values below. + +# Built-in environment variables +TEAMSFX_ENV=dev +APP_NAME_SUFFIX=dev + +# Generated during provision by Microsoft 365 Agents Toolkit +TEAMS_APP_ID= +TEAMS_APP_TENANT_ID= +M365_TITLE_ID= +M365_APP_ID= + +# SharePoint Configuration +# Format: hostname,siteCollectionId,siteId (e.g., contoso.sharepoint.com,12345678-...,abcdef...) +SHAREPOINT_SITE_ID= + +# SharePoint List ID for "Volunteer Commitments" list (GUID) +# Example: 12345678-1234-1234-1234-123456789012 +SHAREPOINT_LIST_ID= + +# OAuth Plugin Vault Reference ID - from Teams Developer Portal OAuth client registration +OAUTH_REFERENCE_ID= diff --git a/samples/da-foodbank-friend/m365agents.yml b/samples/da-foodbank-friend/m365agents.yml new file mode 100644 index 00000000..593e06ea --- /dev/null +++ b/samples/da-foodbank-friend/m365agents.yml @@ -0,0 +1,72 @@ +# yaml-language-server: $schema=https://aka.ms/m365-agents-toolkits/v1.11/yaml.schema.json +# Visit https://aka.ms/teamsfx-v5.0-guide for details on this file +# Visit https://aka.ms/teamsfx-actions for details on actions +version: v1.11 +additionalMetadata: + sampleTag: pnp-copilot-pro-dev:da-foodbank-friend + +environmentFolderPath: ./env + +# Triggered when 'teamsapp provision' is executed +provision: + # Creates an app + - uses: teamsApp/create + with: + # app name + name: Foodbank Friend + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + teamsAppId: TEAMS_APP_ID + + # Build app package with latest env value + - uses: teamsApp/zipAppPackage + with: + # Path to manifest template + manifestPath: ./appPackage/manifest.json + outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + outputFolder: ./appPackage/build + # Apply the app manifest to an existing app in + # Developer Portal. + # Will use the app id in manifest file to determine which app to update. + - uses: teamsApp/update + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + # Extend your app to Outlook and the Microsoft 365 app + - uses: teamsApp/extendToM365 + with: + # Relative path to the build app package. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + titleId: M365_TITLE_ID + appId: M365_APP_ID + +# Triggered when 'teamsapp publish' is executed +publish: + # Build app package with latest env value + - uses: teamsApp/zipAppPackage + with: + # Path to manifest template + manifestPath: ./appPackage/manifest.json + outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + outputFolder: ./appPackage/build + # Apply the app manifest to an existing app in + # Developer Portal. + # Will use the app id in manifest file to determine which app to update. + - uses: teamsApp/update + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + # Publish the app to + # Teams Admin Center (https://admin.teams.microsoft.com/policies/manage-apps) + # for review and approval + - uses: teamsApp/publishAppPackage + with: + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + publishedAppId: TEAMS_APP_PUBLISHED_APP_ID