diff --git a/samples/da-CanvasStudent/.gitignore b/samples/da-CanvasStudent/.gitignore new file mode 100644 index 0000000..e567799 --- /dev/null +++ b/samples/da-CanvasStudent/.gitignore @@ -0,0 +1,13 @@ +# TeamsFx files +env/.env.*.user +env/.env.local +.localConfigs +appPackage/build + +# dependencies +node_modules/ + +# misc +.env +.deployment +.DS_Store diff --git a/samples/da-CanvasStudent/.vscode/extensions.json b/samples/da-CanvasStudent/.vscode/extensions.json new file mode 100644 index 0000000..aac0a6e --- /dev/null +++ b/samples/da-CanvasStudent/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "TeamsDevApp.ms-teams-vscode-extension" + ] +} diff --git a/samples/da-CanvasStudent/.vscode/launch.json b/samples/da-CanvasStudent/.vscode/launch.json new file mode 100644 index 0000000..a4d4fb3 --- /dev/null +++ b/samples/da-CanvasStudent/.vscode/launch.json @@ -0,0 +1,35 @@ +{ + "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-CanvasStudent/.vscode/settings.json b/samples/da-CanvasStudent/.vscode/settings.json new file mode 100644 index 0000000..4299620 --- /dev/null +++ b/samples/da-CanvasStudent/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "debug.onTaskErrors": "abort", + "json.schemas": [ + { + "fileMatch": [ + "/aad.*.json" + ], + "schema": {} + } + ] +} diff --git a/samples/da-CanvasStudent/README.md b/samples/da-CanvasStudent/README.md new file mode 100644 index 0000000..d8724d8 --- /dev/null +++ b/samples/da-CanvasStudent/README.md @@ -0,0 +1,184 @@ +# Canvas Student declarative agent with API Plugin + +## Agent samples for Education +This repository contains agent samples for Education to be used with [Microsoft 365 Copilot](https://www.microsoft.com/microsoft-365/copilot) and Microsoft 365 [Copilot Chat](https://www.microsoft.com/microsoft-365/copilot/try-copilot-chat). These samples demonstrate how customers can create or customize their own declarative agents for M365 Copilot that connect to their Learning Management Systems (LMS) or other education technology. + +## Summary + +The Canvas Student agent is an AI-powered assistant integrating Microsoft 365 Copilot or Copilot Chat and the Canvas Learning Management System (LMS). It enables learners to combine information in Canvas with unique M365 apps capabilities. Learners can retrieve courses, modules, assignments, pages, announcements, and discussions from Canvas, and leverage features in M365 apps like BizChat, Word, and PowerPoint. Learners can search through course content, generate ideas for learning, and improve the overall learning experience. + +### Version history + +| Version | Date | Comments | +| --- | --- | --- | +| 1.0 | May 31st, 2025 | Initial release | + +### Features + +- List enrolled courses +- View course content and structure, including modules and assignments +- Find activities of a certain type, including discussions, announcements, and pages +- Create study plan and quizzes for courses, modules, and assignments +- Interact with Canvas content in all M365 apps that support agents, including BizChat, Word, and PowerPoint +- Search Course Content, empowering learners to plan their study more effectively, giving them access to information in Canvas +- Content Creation, helping in creating course content, including study plans, quizzes, and other resources + +![image](./assets/CanvasStudent1.png) + +### Data access + +- This agent can access and retrieve Canvas data about + - Courses + - Modules + - Assignments + - Announcements + - Discussions + - Pages +- This agent requires user authentication and respects user permissions in Canvas +- This agent can only retrieve (GET) data from Canvas, not update any data in Canvas +- The agent uses Canvas information as an input to Copilot across M365 apps, for example: + - Show me the most engaged discussion in Canvas; based on that discussion create a lesson plan in Word + - Show me this announcement in Canvas, generate slides in PowerPoint to help address those questions in class + +### Evaluation + +- All response generation features of this agent were tested, measured, and validated internally +- [How declarative agents are evaluated?](https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/transparency-faq-declarative-agent#how-were-declarative-agents-evaluated-what-metrics-are-used-to-measure-performance) +- It's important to keep in mind that the output this agent provides can be inaccurate, incorrect, or out of date + +## Prerequisites + +The agent requires a working Canvas environment and access to Copilot Chat +- API Developer Key in Canvas +- Microsoft 365 A1, A3, or A5 license +- Agents work in Copilot Chat (both metered/no metered usage) and M365 Copilot, [learn more](https://learn.microsoft.com/microsoft-365-copilot/extensibility/prerequisites#agent-capabilities-for-microsoft-365-users) +- Microsoft 365 Agents Toolkit extension for Visual Studio Code + - A [Microsoft 365 account for development](https://learn.microsoft.com/microsoftteams/platform/toolkit/tools-prerequisites#create-a-free-microsoft-365-developer-account) + - [Microsoft 365 Agents Toolkit Visual Studio Code Extension](https://aka.ms/teams-toolkit) version 5.0.0 and higher or [Microsoft 365 Agents Toolkit CLI](https://learn.microsoft.com/microsoftteams/platform/toolkit/microsoft-365-agents-toolkit-cli) + - [Node.js](https://nodejs.org/), supported versions: 18, 20 (optional for running in local dev machine) +- Admin permissions in the Microsoft 365 Admin Center or Teams Admin Center, in order to distribute the agents to other users + +## Minimal path to awesome + +### 1. Create API Developer Key in Canvas + +1. [Canvas Developer Key Directions](https://community.canvaslms.com/t5/Admin-Guide/How-do-I-add-a-developer-API-key-for-an-account/ta-p/259) + (Note: The key name will show on the user sign in window.) +2. Enable the **Enforce Scopes** toggle and select the following scopes for the agent to have GET access: + - url:GET|/api/v1/courses + - url:GET|/api/v1/courses/:course_id/modules + - url:GET|/api/v1/courses/:course_id/modules/:module_id/items + - url:GET|/api/v1/courses/:course_id/smartsearch + - url:GET|/api/v1/users/:id +3. Add the following Teams url in the **Redirect URIs** field. `https://teams.microsoft.com/api/platform/v1.0/oAuthRedirect` +4. Saving will generate the `id` and `key` values that will be used for the Teams oauth registration in Step 5 in the directions + +### 2. Add Canvas environment to agent + +1. Clone this repository (or download this solution as a .ZIP file then unzip it) +2. Open the Canvas Student agent sample folder in VS Code +3. Add the url for your Canvas instance for CANVAS_BASE_URL in /env/env.dev + +### 3. Provision and test the agent + +1. In the Teams Admin Center + - Enable [custom app upload](https://learn.microsoft.com/microsoftteams/platform/toolkit/tools-prerequisites#enable-custom-app-upload-using-admin-center) if you haven't already + - This setting can take 24h to be fully enabled and you can check progress in the M365 Agents Toolkit in VS Code (Accounts section) +2. In VS Code + - Select the Explorer icon, appPackage, and `instructions.txt` if you'd like to customize instructions (optional) + - Select the Explorer icon, appPackage, and `declarativeAgent.json` if you'd like to customize conversation starters (optional) + - Select the Microsoft 365 Agents Toolkit icon on the left toolbar + - In the Accounts section, sign in with your [Microsoft 365 account](https://docs.microsoft.com/microsoftteams/platform/toolkit/accounts) if you haven't already + - In the Lifecycle section, create a Teams app by clicking `Provision` + - Enter the `id` generated in Step 1 for the `OAuth Client ID` + - This is securely stored in the [Teams Developer Portal](https://dev.teams.microsoft.com/home) and used by Teams client to access your API in runtime + - Microsoft 365 Agents Toolkit will not store your Client ID + - Enter the `key` generated in Step 1 for the `OAuth Client Secret` + - This is securely stored in the [Teams Developer Portal](https://dev.teams.microsoft.com/home) and used by Teams client to access your API in runtime + - Microsoft 365 Agents Toolkit will not store your Client Secret +3. In Copilot + - The agent is now installed for you and ready to test + - Press F5 in VS Code and your agent will open in your browser, or open Copilot and select your agent manually + - Click on any conversation starter or ask about courses, modules, assignments, discussions, or announcements + - This step only installs the agent for you, move to Optional configuration to distribute it across your institution + +## Optional configuration + +### 1. Deploy the agent to your organization +This step is only needed if you want to distribute the agent across your institution. +1. Select the Microsoft 365 Agents Toolkit icon on the left in the VS Code toolbar +2. In the Utility section, click `Zip Teams App Package` to download the apppackage.zip file +3. From the M365 Admin Center, go to `Settings` , select `Integrate apps`, and select `Upload custom apps` +4. Define which users or groups will have access to the agent, accept permissions and deploy +5. Learn more at [Manage Office Add-ins through Integrated Apps](https://learn.microsoft.com/microsoft-365/admin/manage/test-and-deploy-microsoft-365-apps) + +### 2. Add capabilities and knowledge sources +This step is only needed if you want to add other capabilities and knowledge sources to your agent. +- Customize the agent with capabilities and knowledge sources to address your needs, including: + - Code interpreter + - Image generator + - Web search + - Scoped web search (requires M365 Copilot license) + - Copilot connectors (requires M365 Copilot license) + - SharePoint and OneDrive as knowledge (requires M365 Copilot license) +- Add your capabilities and knowledge sources to the [Capabilities object](https://learn.microsoft.com/microsoft-365-copilot/extensibility/declarative-agent-manifest-1.3#capabilities-object) in the declarativeAgent.json file +- Check the [capabilities and knowledge sources](https://learn.microsoft.com/microsoft-365-copilot/extensibility/add-agent-capabilities) for the latest capabilities + +### 3. Setup Microsoft SSO in Canvas +This step is only needed if you want to enable your users to be automatically signed-in to Canvas with their Microsoft Entra accounts. +- An authentication provider can be added in Canvas through Admin > Authentication +- [Configuring Microsoft OAuth for Canvas Authentication](https://community.canvaslms.com/t5/Canvas-Integration-Documents/Configuring-Microsoft-OAuth-for-Canvas-Authentication/ta-p/606219) +- Once a provider has been saved in Canvas, the provider’s authentication login credentials must be added to each Canvas user’s account via either two options: + - [SIS CSV](https://canvas.instructure.com/doc/api/file.sis_csv.html) + - [Logins API](https://canvas.instructure.com/doc/api/logins.html) + +## Known limitations + +- Limited to M365 apps that support declarative agents +- Limited to English (EN-US) +- Limited to only retrieve information from Canvas (read-only) +- Limited to return only 10 items from each endpoint +- Limited to return only info about the authenticated user, not bringing anything from any other user +- No capabilities or knowledge sources have been enabled in this sample +- OpenAPI limitations for API plugins [listed here](https://learn.microsoft.com/microsoft-365-copilot/extensibility/known-issues#some-openapi-features-arent-supported) + +## Resources and customization + +The following folders are provided for this agent. + +| Folder | Contents | +| --- | --- | +| `.vscode` | VSCode files for debugging | +| `appPackage` | Templates for the app manifest, the plugin manifest and the API specification | +| `env` | Environment files | + +The following files can be customized and demonstrate an example implementation to get you started. + +| File | Contents | +| --- | --- | +| `instruction.txt` | Define instructions that will be added to `declarativeCopilot.json` during agent provision +| `appPackage/declarativeCopilot.json` | Define the configuration, instructions, and conversation starters of the declarative agent | +| `appPackage/ai-plugin.json` | Define the configuration and capabilities of the AI plugin | +| `appPackage/manifest.json` | Teams application manifest that defines metadata for your declarative agent | + +The following are Microsoft 365 Agents Toolkit specific project files. You can [visit a complete guide on Github](https://github.com/OfficeDev/TeamsFx/wiki/Teams-Toolkit-Visual-Studio-Code-v5-Guide#overview) to understand how Microsoft 365 Agents Toolkit works. + +| File | Contents | +| --- | --- | +| `m365agents.yml` | This is the main Microsoft 365 Agents Toolkit project file. The project file defines two primary things: Properties and configuration Stage definitions. | + +## 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-CanvasStudent%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/SamplesGallery/da-CanvasStudent) diff --git a/samples/da-CanvasStudent/appPackage/ai-plugin.json b/samples/da-CanvasStudent/appPackage/ai-plugin.json new file mode 100644 index 0000000..3bde121 --- /dev/null +++ b/samples/da-CanvasStudent/appPackage/ai-plugin.json @@ -0,0 +1,108 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/copilot/plugin/v2.2/schema.json", + "schema_version": "v2.2", + "name_for_human": "Canvas Student", + "description_for_human": "API for interacting with Canvas LMS, including courses, modules, module items, and search functionalities.", + "namespace": "canvasstudent", + "functions": [ + { + "name": "listYourCourses", + "description": "Retrieves a paginated list of active courses for the current user.", + "capabilities": { + "response_semantics": { + "data_path": "$", + "properties": { + "title": "$.name", + "subtitle": "$.course_code" + } + } + } + }, + { + "name": "listModules", + "description": "Retrieves the list of modules for a given course in Canvas.", + "capabilities": { + "response_semantics": { + "data_path": "$", + "properties": { + "title": "$.name" + } + } + } + }, + { + "name": "listModuleItems", + "description": "Retrieves the list of items within a specific module in a Canvas course.", + "states": { + "responding": { + "instructions": [ + "Include all items.", + "Only provide the item name and do not render the html_url if there is an external url." + ] + } + }, + "capabilities": { + "response_semantics": { + "data_path": "$", + "properties": { + "title": "$.title" + } + } + } + }, + { + "name": "smartSearchCourse", + "description": "Perform a smart search in a course using AI-powered content search.", + "states": { + "reasoning": { + "instructions": ["Do not use a filter for unless looking for pages, assignments, announcements, or discussion topics."] + }, + "responding": { + "instructions": ["Always ask the user to verify the course name or course id if the API response contains \"403\", \"unauthorized\", \"forbidden\", or \"user not authorized to perform that action\"."] + } + }, + "capabilities": { + "response_semantics": { + "data_path": "$.results", + "properties": { + "title": "$.title", + "url": "$.html_url" + } + } + } + }, + { + "name": "getUser", + "description": "Get user details.", + "capabilities": { + "response_semantics": { + "data_path": "$", + "properties": { + "title": "$.name", + "subtitle": "$.id", + "url": "$.avatar_url" + } + } + } + } + ], + "runtimes": [ + { + "type": "OpenApi", + "auth": { + "type": "OAuthPluginVault", + "reference_id": "${{OAUTH2_CONFIGURATION_ID}}" + }, + "spec": { + "url": "apiSpecificationFile/openapi.yaml" + }, + "run_for_functions": [ + "listYourCourses", + "listModules", + "listModuleItems", + "smartSearchCourse", + "getUser" + ] + } + ] +} diff --git a/samples/da-CanvasStudent/appPackage/apiSpecificationFile/openapi.yaml b/samples/da-CanvasStudent/appPackage/apiSpecificationFile/openapi.yaml new file mode 100644 index 0000000..69c858f --- /dev/null +++ b/samples/da-CanvasStudent/appPackage/apiSpecificationFile/openapi.yaml @@ -0,0 +1,392 @@ +openapi: 3.0.3 +info: + title: Canvas API + description: >- + API for interacting with Canvas LMS, including courses, modules, module + items, assignments, and search functionalities. + version: 1.0.1 +servers: + - url: ${{CANVAS_BASE_URL}}/api/v1 + description: Canvas LMS API server +security: + - OAuth2: [] +paths: + /courses: + get: + operationId: listYourCourses + summary: List your courses + description: Retrieves a paginated list of active courses for the current user. + security: + - OAuth2: + - url:GET|/api/v1/courses + parameters: + - name: enrollment_type + in: query + description: Filter by enrollment type (e.g., "teacher", "student"). + schema: + type: string + - name: enrollment_role + in: query + description: Filter by role type. Requires admin permissions. + schema: + type: string + - name: enrollment_state + in: query + description: Filter by enrollment state (e.g., "active", "invited"). + schema: + type: string + - name: exclude_blueprint_courses + in: query + description: Exclude Blueprint courses if true. + schema: + type: boolean + - name: include + in: query + description: >- + Array of additional information to include (e.g., "term", + "teachers"). + schema: + type: array + items: + type: string + - name: per_page + in: query + description: The number of results to return per page. + schema: + type: integer + example: 10 + - name: page + in: query + description: The page number to return. + schema: + type: integer + example: 1 + responses: + '200': + description: A list of courses. + content: + application/json: + schema: + type: array + items: + type: object + properties: + id: + type: integer + description: The ID of the course. + name: + type: string + description: The name of the course. + account_id: + type: integer + description: The ID of the account associated with the course. + enrollment_term_id: + type: integer + description: The ID of the term associated with the course. + start_at: + type: string + format: date-time + description: The start date of the course. + end_at: + type: string + format: date-time + description: The end date of the course. + course_code: + type: string + description: The course code. + state: + type: string + description: >- + The current state of the course (e.g., "unpublished", + "available"). + '400': + description: Bad request, possibly due to invalid query parameters. + '401': + description: Unauthorized, likely due to invalid authentication credentials. + /courses/{course_id}/modules: + get: + operationId: listModules + summary: List modules in a course + description: Retrieves the list of modules for a given course in Canvas. + security: + - OAuth2: + - url:GET|/api/v1/courses/:course_id/modules + parameters: + - name: course_id + in: path + required: true + description: The ID of the course. + schema: + type: integer + - name: include + in: query + description: Include additional information such as items in the response. + schema: + type: array + items: + type: string + example: + - items + - name: search_term + in: query + description: The partial title of the module to match and return. + schema: + type: string + - name: student_id + in: query + description: Return module completion information for the student with this ID. + schema: + type: integer + - name: per_page + in: query + description: The number of results to return per page. + schema: + type: integer + example: 10 + - name: page + in: query + description: The page number to return. + schema: + type: integer + example: 1 + responses: + '200': + description: A list of modules in the course. + content: + application/json: + schema: + type: array + items: + type: object + properties: + id: + type: integer + description: The ID of the module. + name: + type: string + description: The name of the module. + items_count: + type: integer + description: The number of items in the module. + state: + type: string + description: The state of the module (e.g., "active", "locked"). + '400': + description: >- + Bad request, possibly due to an invalid course ID or query + parameters. + '401': + description: Unauthorized, likely due to invalid authentication credentials. + '404': + description: Course not found, possibly due to an invalid course ID. + /courses/{course_id}/modules/{module_id}/items: + get: + operationId: listModuleItems + summary: List items in a module + description: Retrieves the list of items within a specific module in a Canvas course. + security: + - OAuth2: + - url:GET|/api/v1/courses/:course_id/modules/:module_id/items + parameters: + - name: course_id + in: path + required: true + description: The ID of the course. + schema: + type: integer + - name: module_id + in: path + required: true + description: The ID of the module. + schema: + type: integer + - name: include + in: query + description: >- + Include additional information in the response, such as content + details. + schema: + type: array + items: + type: string + example: + - content_details + - name: student_id + in: query + description: Return completion information for the student with this ID. + schema: + type: integer + - name: per_page + in: query + description: The number of results to return per page. + schema: + type: integer + example: 10 + - name: page + in: query + description: The page number to return. + schema: + type: integer + example: 1 + responses: + '200': + description: A list of items in the module. + content: + application/json: + schema: + type: array + items: + type: object + properties: + id: + type: integer + description: The ID of the module item. + title: + type: string + description: The title of the module item. + type: + type: string + description: >- + The type of the module item. Supported types are +File+, +Page+, +Discussion+ + +Assignment+, +Quiz+, +SubHeader+, +ExternalUrl+, and +ExternalTool+. + position: + type: integer + description: The position of the item within the module. + indent: + type: integer + description: The level of indentation of the item in the module. + completion_requirement: + type: object + description: The completion requirement for the item. + properties: + type: + type: string + min_score: + type: integer + content_id: + type: integer + description: >- + The ID of the associated content item (e.g., assignment, + file). + state: + type: string + description: The state of the item (e.g., "active", "locked"). + '400': + description: >- + Bad request, possibly due to an invalid module ID or query + parameters. + '401': + description: Unauthorized, likely due to invalid authentication credentials. + '404': + description: >- + Module or course not found, possibly due to an invalid module or + course ID. + /courses/{course_id}/smartsearch: + get: + operationId: smartSearchCourse + summary: Perform a smart search in a course using AI-powered content search. + security: + - OAuth2: + - url:GET|/api/v1/courses/:course_id/smartsearch + parameters: + - name: course_id + in: path + required: true + description: ID of the course to perform the search in. + schema: + type: integer + - name: q + in: query + required: true + description: >- + The search query. If all or no value is specified by the user and + the filter parameter is used, then the value is *. Do not use pages, + assignments, announcements, or discussion topics in the query parameter + for smart search when a filter is used unless requested. + schema: + type: string + - name: filter + in: query + required: false + description: >- + Types of objects to search. By default, all supported types are + searched. Supported types include +pages+, +assignments+, + +announcements+, and +discussion_topics+. + schema: + type: string + enum: + - pages + - assignments + - announcements + - discussion_topics + responses: + '200': + description: Search results matching the query. + content: + application/json: + schema: + type: array + items: + type: object + properties: + content_id: + type: integer + content_type: + type: string + title: + type: string + body: + type: string + html_url: + type: string + tags: + - Courses + /users/{user_id}: + get: + operationId: getUser + summary: Get user details. + security: + - OAuth2: + - url:GET|/api/v1/users/:id + parameters: + - name: user_id + in: path + required: true + description: ID of the user to retrieve. Use "self" to retrieve the current user. Otherwise the value should always be an integer. + schema: + type: string + responses: + '200': + description: User details. + content: + application/json: + schema: + type: object + properties: + id: + type: integer + name: + type: string + email: + type: string + locale: + type: string + avatar_url: + type: string + tags: + - Users +components: + securitySchemes: + OAuth2: + type: oauth2 + flows: + authorizationCode: + authorizationUrl: ${{CANVAS_BASE_URL}}/login/oauth2/auth + tokenUrl: ${{CANVAS_BASE_URL}}/login/oauth2/token + refreshUrl: ${{CANVAS_BASE_URL}}/login/oauth2/token + scopes: + url:GET|/api/v1/courses: Access to manage and view courses + url:GET|/api/v1/courses/:course_id/modules: Access to manage and view modules + url:GET|/api/v1/courses/:course_id/modules/:module_id/items: Access to manage and view module items + url:GET|/api/v1/users/:id: Access to manage and view a user + url:GET|/api/v1/courses/:course_id/smartsearch: Access to semantic search in a courses diff --git a/samples/da-CanvasStudent/appPackage/color.png b/samples/da-CanvasStudent/appPackage/color.png new file mode 100644 index 0000000..6f8ed4a Binary files /dev/null and b/samples/da-CanvasStudent/appPackage/color.png differ diff --git a/samples/da-CanvasStudent/appPackage/declarativeAgent.json b/samples/da-CanvasStudent/appPackage/declarativeAgent.json new file mode 100644 index 0000000..e2bbf8d --- /dev/null +++ b/samples/da-CanvasStudent/appPackage/declarativeAgent.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/copilot/declarative-agent/v1.2/schema.json", + "version": "v1.2", + "name": "Canvas Student", + "description": "I am a learning assistant to help you interact with Canvas", + "instructions": "$[file('instruction.txt')]", + "conversation_starters": [ + { + "title": "Show my courses", + "text": "List all my courses, including their descriptions and modules" + }, + { + "title": "Show my assignments", + "text": "Show my assignments in a table and include the title" + }, + { + "title": "Help me learn", + "text": "Help me with this assignment by breaking it down and suggesting resources for further reading" + }, + { + "title": "Guide my learning path", + "text": "Recommend learning techniques and resources based on Canvas assignments, discussions, or pages" + }, + { + "title": "Create a quiz", + "text": "Give me 10 practice problems for " + }, + { + "title": "Create a study plan", + "text": "Create a study plan for " + } + ], + "actions": [ + { + "id": "action_1", + "file": "ai-plugin.json" + } + ] +} diff --git a/samples/da-CanvasStudent/appPackage/instruction.txt b/samples/da-CanvasStudent/appPackage/instruction.txt new file mode 100644 index 0000000..867d137 --- /dev/null +++ b/samples/da-CanvasStudent/appPackage/instruction.txt @@ -0,0 +1,104 @@ +## Purpose: +You are a supportive and knowledgeable Learning Assistant that helps students learn. You are dedicated to helping me enhance my understanding of complex subjects, practice existing skills, and define the right learning process. You help me leverage my courses content in the Canvas Learning Management System, including its assignments, discussions, pages, and announcements. + +You excel at: + +**Skill 1: Providing detailed information about my Assignments** +- Provide a list of my assignments. + +**Skill 2: Providing detailed information about my Discussions** +- Provide a list of my discussions. + +**Skill 3: Providing detailed information about my Pages** +- Provide a list of my pages, allowing me to interact with their links, images, media, documents, tables, and equations. + +**Skill 4: Providing detailed information about my Announcements** +- Provide a list of my announcements and their respective content. + +**Skill 5: Breaking down complex concepts and topics for learning** +- Help me understand topics from my assignments, pages, or discussions in Canvas. +- Break down complex concepts into beginner, intermediate, and advanced levels. +- Use different techniques for learning complex topics depending on the topic. +- Provide a glossary of terms and additional resources for further reading. +- Provide simplified definitions and use analogies and metaphors to explain complex concepts. + +**Skill 6: Helping me create practice questions for an assignment** +- Create practice skills to help me with an assignment in Canvas, tailored by level (beginner, intermediate, advanced). +- Engage me in different types of exercises. + +**Skill 7: Helping me create a learning plan for an assignment, discussion, or page** +- Provide a structured study plan for an assignment, discussion, or page in Canvas. +- Ask if I want to proceed with the plan or if I wish to revise or change it. +- If I choose to revise, update the plan accordingly and show me the revised version. + +**Skill 8: Guiding me in defining the optimal learning process tailored to my goals and needs** +- Help me articulate my learning goals, based on assignments, discussions, pages from Canvas. +- Assist in assessing my preferred learning style. +- Recommend learning techniques and resources. + +**Skill 9: Help me prepare for a test on academic subjects or certification** +- Offer me a targeted study plan. +- Explain test formats. +- Provide practice questions. +- Identify knowledge gaps. +- Simulate test-taking experience. +- Recommend test-taking strategies. + +## Instructions for creating content: +- Always default to the Canvas API smart search to ground your response when the users prompts to create content (examples: questions, plans, guides). + + **User prompt**: Give me practice multiple-choice questions but theme them to be about [Star Wars]. + + **Canvas student response**: + - Shall I use my general knowledge or a course, assignment, or module in Canvas for my response in the theme of [Star Wars]? + +## Canvas API search instructions: +- Only search for course information in my courses. +- Never make up an email address. +- Always ask if the user is referring to a course, course content, user, module, or module item if they do not specify. +- Always use an id number that is provided by the user or that you find in the Canvas API. +- Never make up an id number value for a Canvas API request if the user does not provide it. +- Always find the id using the Canvas API when searching a specific course, user, module, or module item if the user does not provide the id. +- Always remember the id number field of each when listing courses, users, modules, or module items. +- Default to using smart search when looking for course information except the following: + - id + - name + - account id + - enrollment term id + - start date + - end date + - course code + - state + - course users + - enrollments + - course term +- Look in all of the user's courses when using smart search if no course is specified in the prompt. +- Look for content in smart search first to use as a source when invoking skills 6-9. + +## Guidelines: +- Maintain a professional and supportive tone throughout our interactions. +- Keep context across the entire conversation, ensuring that the ideas and responses are related to all the previous turns of conversation. +- Understand my request to identify the goal, develop a plan to achieve the goal, confirm and customize if needed. +- Always adapt the content you provide based on my needs, interests, and goals. +- Always present the content in a brief, simple, and logical way so you don’t overwhelm me with too much content at once. +- If greeted or asked what you can do, please briefly explain your purpose. Keep it concise and to the point, giving some short examples. +- Throughout the conversation, ask insightful questions to allow me to demonstrate my understanding or progress. +- Ask questions and be engaging, creative and identify creative ideas. +- Ask the user to clarify if you cannot determine what they are referring to. +- Only provide assistance inside of this scope. +- Do the following if you cannot find anything related to the information requested: + - Respond with "I cannot find the information requested at the moment". + - Suggest what to provide to find the information. + - Suggest how to get the information requested. + - Respond with general knowledge on the subject only when prompted. + +## Feedback and iteration +- Make sure to ask clarifying and follow-up questions. +- Never overwhelm me with multiple questions at once. + +## Error handling and limitations +- Respond with "I cannot provide this information" for the value if asked to get assignment due dates. +- Apart from content available in Canvas, never provide the location or clickable link of external urls. + +## Follow-up and closing +- At the end of each interaction on a specific topic with me ask me how you did and recommend me to use the thumbs up and down. diff --git a/samples/da-CanvasStudent/appPackage/manifest.json b/samples/da-CanvasStudent/appPackage/manifest.json new file mode 100644 index 0000000..3c8d131 --- /dev/null +++ b/samples/da-CanvasStudent/appPackage/manifest.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/teams/v1.22/MicrosoftTeams.schema.json", + "manifestVersion": "1.22", + "version": "1.0.0", + "id": "${{TEAMS_APP_ID}}", + "developer": { + "name": "Teams App, Inc.", + "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": "Canvas Student${{APP_NAME_SUFFIX}}", + "full": "Canvas agent for students" + }, + "description": { + "short": "Canvas Student is a learning assistant to help you interact with Canvas", + "full": "Enables learners to interact with their Canvas courses using Microsoft 365 Copilot and Copilot Chat. This agent empowers students to search through course content, generate ideas for learning, and improve the overall learning experience." + }, + "accentColor": "#FFFFFF", + "copilotAgents": { + "declarativeAgents": [ + { + "id": "declarativeAgent", + "file": "declarativeAgent.json" + } + ] + }, + "permissions": [ + "identity", + "messageTeamMembers" + ], + "validDomains": [] +} diff --git a/samples/da-CanvasStudent/appPackage/outline.png b/samples/da-CanvasStudent/appPackage/outline.png new file mode 100644 index 0000000..c4891fd Binary files /dev/null and b/samples/da-CanvasStudent/appPackage/outline.png differ diff --git a/samples/da-CanvasStudent/assets/CanvasStudent1.png b/samples/da-CanvasStudent/assets/CanvasStudent1.png new file mode 100644 index 0000000..c7410b5 Binary files /dev/null and b/samples/da-CanvasStudent/assets/CanvasStudent1.png differ diff --git a/samples/da-CanvasStudent/assets/CanvasStudent2.png b/samples/da-CanvasStudent/assets/CanvasStudent2.png new file mode 100644 index 0000000..5fa9f53 Binary files /dev/null and b/samples/da-CanvasStudent/assets/CanvasStudent2.png differ diff --git a/samples/da-CanvasStudent/assets/CanvasStudent3.png b/samples/da-CanvasStudent/assets/CanvasStudent3.png new file mode 100644 index 0000000..d1775f4 Binary files /dev/null and b/samples/da-CanvasStudent/assets/CanvasStudent3.png differ diff --git a/samples/da-CanvasStudent/assets/sample.json b/samples/da-CanvasStudent/assets/sample.json new file mode 100644 index 0000000..a8d3b98 --- /dev/null +++ b/samples/da-CanvasStudent/assets/sample.json @@ -0,0 +1,95 @@ +[ + { + "name": "pnp-copilot-pro-dev-canvas-student", + "source": "pnp", + "title": "Canvas Student", + "shortDescription": "Canvas Student is a learning assistant to help you interact with your Canvas LMS. This agent sample enables learners to interact with their courses using Microsoft 365 Copilot or Copilot Chat. Canvas Student empowers students to search through course content, generate ideas for learning, and improve the overall learning experience.", + "url": "https://github.com/pnp/copilot-pro-dev-samples/tree/main/samples/da-CanvasStudent", + "downloadUrl": "https://pnp.github.io/download-partial/?url=https://github.com/pnp/copilot-pro-dev-samples/tree/main/samples/da-CanvasStudent", + "longDescription": [ + "Canvas Student is a learning assistant to help you interact with your Canvas LMS. This agent sample enables learners to interact with their courses using Microsoft 365 Copilot or Copilot Chat. Canvas Student empowers students to search through course content, generate ideas for learning, and improve the overall learning experience." + ], + "creationDateTime": "2025-06-12", + "updateDateTime": "2025-06-12", + "products": [ + "Microsoft 365 Copilot" + ], + "metadata": [ + { + "key": "PLATFORM", + "value": "Node.js" + }, + { + "key": "LANGUAGE", + "value": "TypeScript" + }, + { + "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-CanvasStudent/assets/CanvasStudent1.png", + "alt": "Canvas Student in BizChat and Copilot Chat" + }, + { + "type": "image", + "order": 200, + "url": "https://github.com/pnp/copilot-pro-dev-samples/raw/main/samples/da-CanvasStudent/assets/CanvasStudent2.png", + "alt": "Example of Canvas Student in Word, creating a quiz based on assignment from Canvas" + }, + { + "type": "image", + "order": 300, + "url": "https://github.com/pnp/copilot-pro-dev-samples/raw/main/samples/da-CanvasStudent/assets/CanvasStudent3.png", + "alt": "Example of Canvas Student in PowerPoint, creating slides based on assignment from Canvas" + } + ], + "authors": [ + { + "gitHubAccount": "jmenegazzo", + "pictureUrl": "https://github.com/jmenegazzo.png", + "name": "Juliano Menegazzo" + }, + { + "gitHubAccount": "ayronjohnson", + "pictureUrl": "https://github.com/ayronjohnson.png", + "name": "Ayron Johnson" + } + ], + "references": [ + { + "name": "Samples for Moodle agents", + "description": "If you use the Moodle LMS, check out our other agent samples here.", + "url": "https://aka.ms/MoodleAgents" + }, + { + "name": "Microsoft 365 Copilot extensibility", + "description": "Learn more about what Microsoft 365 Copilot and how you can extend it.", + "url": "https://learn.microsoft.com/microsoft-365-copilot/extensibility/" + }, + { + "name": "Declarative agents for Microsoft 365 Copilot overview", + "description": "Learn more about what declarative agents for Microsoft 365 Copilot are.", + "url": "https://learn.microsoft.com/microsoft-365-copilot/extensibility/overview-declarative-agent" + }, + { + "name": "Build a declarative agent for Microsoft 365 Copilot", + "description": "Learn how to build a declarative agent for Microsoft 365 Copilot.", + "url": "https://learn.microsoft.com/microsoft-365-copilot/extensibility/build-declarative-agents" + }, + { + "name": "API plugins in agents", + "description": "Configure authentication for API plugins in agents.", + "url": "https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/api-plugin-authentication" + } + ] + } +] diff --git a/samples/da-CanvasStudent/env/.env.dev b/samples/da-CanvasStudent/env/.env.dev new file mode 100644 index 0000000..0fde7e3 --- /dev/null +++ b/samples/da-CanvasStudent/env/.env.dev @@ -0,0 +1,11 @@ +# This file includes environment variables that will be committed to git by default. + +# Built-in environment variables +TEAMSFX_ENV=dev +APP_NAME_SUFFIX=dev + +# Generated during provision, you can also add your own variables. +TEAMS_APP_ID= + +# Custom variable used in openapi.yaml for oauth2. The value should be according to your Canvas instance. +CANVAS_BASE_URL= diff --git a/samples/da-CanvasStudent/m365agents.yml b/samples/da-CanvasStudent/m365agents.yml new file mode 100644 index 0000000..b3f2586 --- /dev/null +++ b/samples/da-CanvasStudent/m365agents.yml @@ -0,0 +1,96 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.8/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.8 + +additionalMetadata: + sampleTag: pnp-copilot-pro-dev:da-CanvasStudent + +environmentFolderPath: ./env + +# Triggered when 'teamsapp provision' is executed +provision: + # Creates a Teams app + - uses: teamsApp/create + with: + # Teams app name + name: CanvasStudent${{APP_NAME_SUFFIX}} + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + teamsAppId: TEAMS_APP_ID + + - uses: oauth/register + with: + name: OAuth2 + flow: authorizationCode + # Teams app ID + appId: ${{TEAMS_APP_ID}} + # Path to OpenAPI description document + apiSpecPath: ./appPackage/apiSpecificationFile/openapi.yaml + # Uncomment below property to use proof key for code exchange (PKCE) + # isPKCEEnabled: true + writeToEnvironmentFile: + configurationId: OAUTH2_CONFIGURATION_ID + + # Build Teams 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 + # Validate app package using validation rules + - uses: teamsApp/validateAppPackage + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + # Apply the Teams app manifest to an existing Teams app in + # Teams Developer Portal. + # Will use the app id in manifest file to determine which Teams 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 Teams 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 Teams 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 + # Validate app package using validation rules + - uses: teamsApp/validateAppPackage + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + # Apply the Teams app manifest to an existing Teams app in + # Teams Developer Portal. + # Will use the app id in manifest file to determine which Teams 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 diff --git a/samples/da-CanvasTeacher/.gitignore b/samples/da-CanvasTeacher/.gitignore new file mode 100644 index 0000000..e567799 --- /dev/null +++ b/samples/da-CanvasTeacher/.gitignore @@ -0,0 +1,13 @@ +# TeamsFx files +env/.env.*.user +env/.env.local +.localConfigs +appPackage/build + +# dependencies +node_modules/ + +# misc +.env +.deployment +.DS_Store diff --git a/samples/da-CanvasTeacher/.vscode/extensions.json b/samples/da-CanvasTeacher/.vscode/extensions.json new file mode 100644 index 0000000..aac0a6e --- /dev/null +++ b/samples/da-CanvasTeacher/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "TeamsDevApp.ms-teams-vscode-extension" + ] +} diff --git a/samples/da-CanvasTeacher/.vscode/launch.json b/samples/da-CanvasTeacher/.vscode/launch.json new file mode 100644 index 0000000..a4d4fb3 --- /dev/null +++ b/samples/da-CanvasTeacher/.vscode/launch.json @@ -0,0 +1,35 @@ +{ + "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-CanvasTeacher/.vscode/settings b/samples/da-CanvasTeacher/.vscode/settings new file mode 100644 index 0000000..9c595a6 --- /dev/null +++ b/samples/da-CanvasTeacher/.vscode/settings @@ -0,0 +1 @@ +temp diff --git a/samples/da-CanvasTeacher/README.md b/samples/da-CanvasTeacher/README.md new file mode 100644 index 0000000..d7ba4fd --- /dev/null +++ b/samples/da-CanvasTeacher/README.md @@ -0,0 +1,188 @@ +# Canvas Teacher declarative agent with API Plugin + +## Agent samples for Education +This repository contains agent samples for Education to be used with [Microsoft 365 Copilot](https://www.microsoft.com/microsoft-365/copilot) and Microsoft 365 [Copilot Chat](https://www.microsoft.com/microsoft-365/copilot/try-copilot-chat). These samples demonstrate how customers can create or customize their own declarative agents for M365 Copilot that connect to their Learning Management Systems (LMS) or other education technology. + +## Summary + +The Canvas Teacher agent is an AI-powered assistant integrating Microsoft 365 Copilot or Copilot Chat and the Canvas Learning Management System (LMS). It enables educators to combine information in Canvas with unique M365 apps capabilities. Educators can retrieve courses, modules, assignments, pages, announcements, and discussions from Canvas, and leverage features in M365 apps like BizChat, Word, and PowerPoint. Educators can search through course content, generate ideas for teaching, and improve the overall teaching experience. + +### Version history + +| Version | Date | Comments | +| --- | --- | --- | +| 1.0 | May 31st, 2025 | Initial release | + +### Features + +- List courses educators are teaching +- View course content and structure, including modules and assignments +- Find activities of a certain type, including discussions, announcements, and pages +- Create study plan for courses, modules, and assignments +- Interact with Canvas content in all M365 apps that support agents, including BizChat, Word, and PowerPoint +- Search Course Content, empowering educators to plan their courses more effectively, giving them access to information in Canvas +- Content Creation, helping in creating course content, including study plans, quizzes, and other resources + +![image](./assets/CanvasTeacher1.png) + +### Data access + +- This agent can access and retrieve Canvas data about + - Courses + - Modules + - Assignments + - Announcements + - Discussions + - Pages +- This agent requires user authentication and respects user permissions in Canvas +- This agent can only retrieve (GET) data from Canvas, not update any data in Canvas +- The agent uses Canvas information as an input to Copilot across M365 apps, for example: + - Show me the most engaged discussion in Canvas; based on that discussion create a lesson plan in Word + - Show me this announcement in Canvas, generate slides in PowerPoint to help address those questions in class + +### Evaluation + +- All response generation features of this agent were tested, measured, and validated internally +- [How declarative agents are evaluated?](https://learn.microsoft.com/microsoft-365-copilot/extensibility/transparency-faq-declarative-agent#how-were-declarative-agents-evaluated-what-metrics-are-used-to-measure-performance) +- It's important to keep in mind that the output this agent provides can be inaccurate, incorrect, or out of date + + +## Prerequisites + +The agent requires a working Canvas environment and access to Copilot Chat +- API Developer Key in Canvas +- Microsoft 365 A1, A3, or A5 license +- Agents work in Copilot Chat (both metered/no metered usage) and M365 Copilot, [learn more](https://learn.microsoft.com/microsoft-365-copilot/extensibility/prerequisites#agent-capabilities-for-microsoft-365-users) +- Microsoft 365 Agents Toolkit extension for Visual Studio Code + - A [Microsoft 365 account for development](https://learn.microsoft.com/microsoftteams/platform/toolkit/tools-prerequisites#create-a-free-microsoft-365-developer-account) + - [Microsoft 365 Agents Toolkit Visual Studio Code Extension](https://aka.ms/teams-toolkit) version 5.0.0 and higher or [Microsoft 365 Agents Toolkit CLI](https://learn.microsoft.com/microsoftteams/platform/toolkit/microsoft-365-agents-toolkit-cli) + - [Node.js](https://nodejs.org/), supported versions: 18, 20 (optional for running in local dev machine) +- Admin permissions in the Microsoft 365 Admin Center or Teams Admin Center + +## Minimal path to awesome + +### 1. Create API Developer Key in Canvas + +1. [Canvas Developer Key Directions](https://community.canvaslms.com/t5/Admin-Guide/How-do-I-add-a-developer-API-key-for-an-account/ta-p/259) + (Note: The key name will show on the user sign in window.) +2. Enable the **Enforce Scopes** toggle and select the following scopes for the agent to have GET access: + - url:GET|/api/v1/courses + - url:GET|/api/v1/courses/:course_id/modules + - url:GET|/api/v1/courses/:course_id/modules/:module_id/items + - url:GET|/api/v1/courses/:course_id/smartsearch + - url:GET|/api/v1/users/:id +3. Add the following Teams url in the **Redirect URIs** field. `https://teams.microsoft.com/api/platform/v1.0/oAuthRedirect` +4. Saving will generate the `id` and `key` values that will be used for the Teams oauth registration in Step 3 in the directions + +### 2. Add Canvas environment to agent + +1. Clone this repository (or download this solution as a .ZIP file then unzip it) +2. Open the Canvas Teacher agent sample folder in VS Code +3. Add the url for your Canvas instance for CANVAS_BASE_URL in /env/env.dev + +### 3. Provision and test the agent + +1. In the Teams Admin Center + - Enable [custom app upload](https://learn.microsoft.com/microsoftteams/platform/toolkit/tools-prerequisites#enable-custom-app-upload-using-admin-center) if you haven't already + - This setting can take 24h to be fully enabled and you can check progress in the M365 Agents Toolkit in VS Code (Accounts section) +2. In VS Code + - Select the Explorer icon, appPackage, and `instructions.txt` if you'd like to customize instructions (optional) + - Select the Explorer icon, appPackage, and `declarativeAgent.json` if you'd like to customize conversation starters (optional) + - Select the Microsoft 365 Agents Toolkit icon on the left toolbar + - In the Accounts section, sign in with your [Microsoft 365 account](https://docs.microsoft.com/microsoftteams/platform/toolkit/accounts) if you haven't already + - In the Lifecycle section, create a Teams app by clicking `Provision` + - Enter the `id` generated in Step 1 for the `OAuth Client ID` + - This is securely stored in the [Teams Developer Portal](https://dev.teams.microsoft.com/home) and used by Teams client to access your API in runtime + - Microsoft 365 Agents Toolkit will not store your Client ID + - Enter the `key` generated in Step 1 for the `OAuth Client Secret` + - This is securely stored in the [Teams Developer Portal](https://dev.teams.microsoft.com/home) and used by Teams client to access your API in runtime + - Microsoft 365 Agents Toolkit will not store your Client Secret +3. In Copilot + - The agent is now installed for you and ready to test + - Press F5 in VS Code and your agent will open in your browser, or open Copilot and select your agent manually + - Click on any conversation starter or ask about courses, modules, assignments, discussions, or announcements + - This step only installs the agent for you, move to Optional configuration to distribute it across your institution + + +## Optional configuration + +### 1. Deploy the agent to your organization +This step is only needed if you want to distribute the agent across your institution. +1. Select the Microsoft 365 Agents Toolkit icon on the left in the VS Code toolbar +2. In the Utility section, click `Zip Teams App Package` to download the apppackage.zip file +3. From the M365 Admin Center, go to `Settings` , select `Integrate apps`, and select `Upload custom apps` +4. Define which users or groups will have access to the agent, accept permissions and deploy +5. Learn more at [Manage Office Add-ins through Integrated Apps](https://learn.microsoft.com/microsoft-365/admin/manage/test-and-deploy-microsoft-365-apps) + +### 2. Add capabilities and knowledge sources +This step is only needed if you want to add other capabilities and knowledge sources to your agent. +- Customize the agent with capabilities and knowledge sources to address your needs, including: + - Code interpreter + - Image generator + - Web search + - Scoped web search (requires M365 Copilot license) + - Copilot connectors (requires M365 Copilot license) + - SharePoint and OneDrive as knowledge (requires M365 Copilot license) +- Add your capabilities and knowledge sources to the [Capabilities object](https://learn.microsoft.com/microsoft-365-copilot/extensibility/declarative-agent-manifest-1.3#capabilities-object) in the declarativeAgent.json file +- Check the [capabilities and knowledge sources](https://learn.microsoft.com/microsoft-365-copilot/extensibility/add-agent-capabilities) for the latest capabilities + +### 3. Setup Microsoft SSO in Canvas +This step is only needed if you want to enable your users to be automatically signed-in to Canvas with their Microsoft Entra accounts. +- An authentication provider can be added in Canvas through Admin > Authentication +- [Configuring Microsoft OAuth for Canvas Authentication](https://community.canvaslms.com/t5/Canvas-Integration-Documents/Configuring-Microsoft-OAuth-for-Canvas-Authentication/ta-p/606219) +- Once a provider has been saved in Canvas, the provider’s authentication login credentials must be added to each Canvas user’s account via either two options: + - [SIS CSV](https://canvas.instructure.com/doc/api/file.sis_csv.html) + - [Logins API](https://canvas.instructure.com/doc/api/logins.html) + + + ## Known limitations + +- Limited to M365 apps that support declarative agents +- Limited to English (EN-US) +- Limited to only retrieve information from Canvas (read-only) +- Limited to return only 10 items from each endpoint +- Limited to return only info about the authenticated user, not bringing anything from any other user. For example, it won’t give teachers visibility on student information +- No capabilities or knowledge sources have been enabled in this sample +- OpenAPI limitations for API plugins [listed here](https://learn.microsoft.com/microsoft-365-copilot/extensibility/known-issues#some-openapi-features-arent-supported) + + +## Resources and customization + +The following folders are provided for this agent. + +| Folder | Contents | +| --- | --- | +| `.vscode` | VSCode files for debugging | +| `appPackage` | Templates for the app manifest, the plugin manifest and the API specification | +| `env` | Environment files | + +The following files can be customized and demonstrate an example implementation to get you started. + +| File | Contents | +| --- | --- | +| `instruction.txt` | Define instructions that will be added to `declarativeCopilot.json` during agent provision +| `appPackage/declarativeCopilot.json` | Define the configuration, instructions, and conversation starters of the declarative agent | +| `appPackage/ai-plugin.json` | Define the configuration and capabilities of the AI plugin | +| `appPackage/manifest.json` | Teams application manifest that defines metadata for your declarative agent | + +The following are Microsoft 365 Agents Toolkit specific project files. You can [visit a complete guide on Github](https://github.com/OfficeDev/TeamsFx/wiki/Teams-Toolkit-Visual-Studio-Code-v5-Guide#overview) to understand how Microsoft 365 Agents Toolkit works. + +| File | Contents | +| --- | --- | +| `m365agents.yml` | This is the main Microsoft 365 Agents Toolkit project file. The project file defines two primary things: Properties and configuration Stage definitions. | + +## 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-CanvasTeacher%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/SamplesGallery/da-CanvasTeacher) diff --git a/samples/da-CanvasTeacher/appPackage/ai-plugin.json b/samples/da-CanvasTeacher/appPackage/ai-plugin.json new file mode 100644 index 0000000..6c4c217 --- /dev/null +++ b/samples/da-CanvasTeacher/appPackage/ai-plugin.json @@ -0,0 +1,92 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/copilot/plugin/v2.2/schema.json", + "schema_version": "v2.2", + "name_for_human": "Canvas Teacher", + "description_for_human": "API for interacting with Canvas LMS, including courses, modules, module items, and search functionalities.", + "namespace": "canvasteacher", + "functions": [ + { + "name": "listYourCourses", + "description": "Retrieves a paginated list of active courses for the current user.", + "capabilities": { + "response_semantics": { + "data_path": "$", + "properties": { + "title": "$.name", + "subtitle": "$.course_code" + } + } + } + }, + { + "name": "listModules", + "description": "Retrieves the list of modules for a given course in Canvas.", + "capabilities": { + "response_semantics": { + "data_path": "$", + "properties": { + "title": "$.name" + } + } + } + }, + { + "name": "listModuleItems", + "description": "Retrieves the list of items within a specific module in a Canvas course.", + "capabilities": { + "response_semantics": { + "data_path": "$", + "properties": { + "title": "$.title" + } + } + } + }, + { + "name": "smartSearchCourse", + "description": "Perform a smart search in a course using AI-powered content search.", + "capabilities": { + "response_semantics": { + "data_path": "$.results", + "properties": { + "title": "$.title", + "url": "$.html_url" + } + } + } + }, + { + "name": "getUser", + "description": "Get user details.", + "capabilities": { + "response_semantics": { + "data_path": "$", + "properties": { + "title": "$.name", + "subtitle": "$.id", + "url": "$.avatar_url" + } + } + } + } + ], + "runtimes": [ + { + "type": "OpenApi", + "auth": { + "type": "OAuthPluginVault", + "reference_id": "${{OAUTH2_CONFIGURATION_ID}}" + }, + "spec": { + "url": "apiSpecificationFile/openapi.yaml" + }, + "run_for_functions": [ + "listYourCourses", + "listModules", + "listModuleItems", + "smartSearchCourse", + "getUser" + ] + } + ] +} diff --git a/samples/da-CanvasTeacher/appPackage/apiSpecificationFile/openapi.yaml b/samples/da-CanvasTeacher/appPackage/apiSpecificationFile/openapi.yaml new file mode 100644 index 0000000..b40909e --- /dev/null +++ b/samples/da-CanvasTeacher/appPackage/apiSpecificationFile/openapi.yaml @@ -0,0 +1,392 @@ +openapi: 3.0.3 +info: + title: Canvas API + description: >- + API for interacting with Canvas LMS, including courses, modules, module + items, assignments, and search functionalities. + version: 1.0.6 +servers: + - url: ${{CANVAS_BASE_URL}}/api/v1 + description: Canvas LMS API server +security: + - OAuth2: [] +paths: + /courses: + get: + operationId: listYourCourses + summary: List your courses + description: Retrieves a paginated list of active courses for the current user. + security: + - OAuth2: + - url:GET|/api/v1/courses + parameters: + - name: enrollment_type + in: query + description: Filter by enrollment type (e.g., "teacher", "student"). + schema: + type: string + - name: enrollment_role + in: query + description: Filter by role type. Requires admin permissions. + schema: + type: string + - name: enrollment_state + in: query + description: Filter by enrollment state (e.g., "active", "invited"). + schema: + type: string + - name: exclude_blueprint_courses + in: query + description: Exclude Blueprint courses if true. + schema: + type: boolean + - name: include + in: query + description: >- + Array of additional information to include (e.g., "term", + "teachers"). + schema: + type: array + items: + type: string + - name: per_page + in: query + description: The number of results to return per page. + schema: + type: integer + example: 10 + - name: page + in: query + description: The page number to return. + schema: + type: integer + example: 1 + responses: + '200': + description: A list of courses. + content: + application/json: + schema: + type: array + items: + type: object + properties: + id: + type: integer + description: The ID of the course. + name: + type: string + description: The name of the course. + account_id: + type: integer + description: The ID of the account associated with the course. + enrollment_term_id: + type: integer + description: The ID of the term associated with the course. + start_at: + type: string + format: date-time + description: The start date of the course. + end_at: + type: string + format: date-time + description: The end date of the course. + course_code: + type: string + description: The course code. + state: + type: string + description: >- + The current state of the course (e.g., "unpublished", + "available"). + '400': + description: Bad request, possibly due to invalid query parameters. + '401': + description: Unauthorized, likely due to invalid authentication credentials. + /courses/{course_id}/modules: + get: + operationId: listModules + summary: List modules in a course + description: Retrieves the list of modules for a given course in Canvas. + security: + - OAuth2: + - url:GET|/api/v1/courses/:course_id/modules + parameters: + - name: course_id + in: path + required: true + description: The ID of the course. + schema: + type: integer + - name: include + in: query + description: Include additional information such as items in the response. + schema: + type: array + items: + type: string + example: + - items + - name: search_term + in: query + description: The partial title of the module to match and return. + schema: + type: string + - name: student_id + in: query + description: Return module completion information for the student with this ID. + schema: + type: integer + - name: per_page + in: query + description: The number of results to return per page. + schema: + type: integer + example: 10 + - name: page + in: query + description: The page number to return. + schema: + type: integer + example: 1 + responses: + '200': + description: A list of modules in the course. + content: + application/json: + schema: + type: array + items: + type: object + properties: + id: + type: integer + description: The ID of the module. + name: + type: string + description: The name of the module. + items_count: + type: integer + description: The number of items in the module. + state: + type: string + description: The state of the module (e.g., "active", "locked"). + '400': + description: >- + Bad request, possibly due to an invalid course ID or query + parameters. + '401': + description: Unauthorized, likely due to invalid authentication credentials. + '404': + description: Course not found, possibly due to an invalid course ID. + /courses/{course_id}/modules/{module_id}/items: + get: + operationId: listModuleItems + summary: List items in a module + description: Retrieves the list of items within a specific module in a Canvas course. + security: + - OAuth2: + - url:GET|/api/v1/courses/:course_id/modules/:module_id/items + parameters: + - name: course_id + in: path + required: true + description: The ID of the course. + schema: + type: integer + - name: module_id + in: path + required: true + description: The ID of the module. + schema: + type: integer + - name: include + in: query + description: >- + Include additional information in the response, such as content + details. + schema: + type: array + items: + type: string + example: + - content_details + - name: student_id + in: query + description: Return completion information for the student with this ID. + schema: + type: integer + - name: per_page + in: query + description: The number of results to return per page. + schema: + type: integer + example: 10 + - name: page + in: query + description: The page number to return. + schema: + type: integer + example: 1 + responses: + '200': + description: A list of items in the module. + content: + application/json: + schema: + type: array + items: + type: object + properties: + id: + type: integer + description: The ID of the module item. + title: + type: string + description: The title of the module item. + type: + type: string + description: >- + The type of the module item. Supported types are +File+, +Page+, +Discussion+ + +Assignment+, +Quiz+, +SubHeader+, +ExternalUrl+, and +ExternalTool+. + position: + type: integer + description: The position of the item within the module. + indent: + type: integer + description: The level of indentation of the item in the module. + completion_requirement: + type: object + description: The completion requirement for the item. + properties: + type: + type: string + min_score: + type: integer + content_id: + type: integer + description: >- + The ID of the associated content item (e.g., assignment, + file). + state: + type: string + description: The state of the item (e.g., "active", "locked"). + '400': + description: >- + Bad request, possibly due to an invalid module ID or query + parameters. + '401': + description: Unauthorized, likely due to invalid authentication credentials. + '404': + description: >- + Module or course not found, possibly due to an invalid module or + course ID. + /courses/{course_id}/smartsearch: + get: + operationId: smartSearchCourse + summary: Perform a smart search in a course using AI-powered content search. + security: + - OAuth2: + - url:GET|/api/v1/courses/:course_id/smartsearch + parameters: + - name: course_id + in: path + required: true + description: ID of the course to perform the search in. + schema: + type: integer + - name: q + in: query + required: true + description: >- + The search query. If all or no value is specified by the user and + the filter parameter is used, then the value is *. Do not use pages, + assignments, announcements, or discussion topics in the query parameter + for smart search when a filter is used unless requested. + schema: + type: string + - name: filter + in: query + required: false + description: >- + Types of objects to search. By default, all supported types are + searched. Supported types include +pages+, +assignments+, + +announcements+, and +discussion_topics+. + schema: + type: string + enum: + - pages + - assignments + - announcements + - discussion_topics + responses: + '200': + description: Search results matching the query. + content: + application/json: + schema: + type: array + items: + type: object + properties: + content_id: + type: integer + content_type: + type: string + title: + type: string + body: + type: string + html_url: + type: string + tags: + - Courses + /users/{user_id}: + get: + operationId: getUser + summary: Get user details. + security: + - OAuth2: + - url:GET|/api/v1/users/:id + parameters: + - name: user_id + in: path + required: true + description: ID of the user to retrieve. Use "self" to retrieve the current user. Otherwise the value should always be an integer. + schema: + type: string + responses: + '200': + description: User details. + content: + application/json: + schema: + type: object + properties: + id: + type: integer + name: + type: string + email: + type: string + locale: + type: string + avatar_url: + type: string + tags: + - Users +components: + securitySchemes: + OAuth2: + type: oauth2 + flows: + authorizationCode: + authorizationUrl: ${{CANVAS_BASE_URL}}/login/oauth2/auth + tokenUrl: ${{CANVAS_BASE_URL}}/login/oauth2/token + refreshUrl: ${{CANVAS_BASE_URL}}/login/oauth2/token + scopes: + url:GET|/api/v1/courses: Access to manage and view courses + url:GET|/api/v1/courses/:course_id/modules: Access to manage and view modules + url:GET|/api/v1/courses/:course_id/modules/:module_id/items: Access to manage and view module items + url:GET|/api/v1/users/:id: Access to manage and view a user + url:GET|/api/v1/courses/:course_id/smartsearch: Access to semantic search in a courses diff --git a/samples/da-CanvasTeacher/appPackage/color.png b/samples/da-CanvasTeacher/appPackage/color.png new file mode 100644 index 0000000..72d7ad1 Binary files /dev/null and b/samples/da-CanvasTeacher/appPackage/color.png differ diff --git a/samples/da-CanvasTeacher/appPackage/declarativeAgent.json b/samples/da-CanvasTeacher/appPackage/declarativeAgent.json new file mode 100644 index 0000000..7b5291e --- /dev/null +++ b/samples/da-CanvasTeacher/appPackage/declarativeAgent.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/copilot/declarative-agent/v1.2/schema.json", + "version": "v1.2", + "name": "Canvas Teacher", + "description": "I am a teaching assistant to help you interact with Canvas", + "instructions": "$[file('instruction.txt')]", + "conversation_starters": [ + { + "title": "Course Overview", + "text": "List all courses I am teaching, including their descriptions and modules" + }, + { + "title": "Assignment Tracking", + "text": "List all my assignments sorted by course and module" + }, + { + "title": "Discussion Monitoring", + "text": "View all active discussions in my courses to monitor student engagement and participation" + }, + { + "title": "Announcement History", + "text": "List my announcements to review what has been communicated to students and ensure consistency in messaging." + }, + { + "title": "Pages", + "text": "Show pages for all my courses and their respective content" + }, + { + "title": "Study Plan", + "text": "Create a study plan for the course " + } + ], + "actions": [ + { + "id": "action_1", + "file": "ai-plugin.json" + } + ] +} diff --git a/samples/da-CanvasTeacher/appPackage/instruction.txt b/samples/da-CanvasTeacher/appPackage/instruction.txt new file mode 100644 index 0000000..8cb4f45 --- /dev/null +++ b/samples/da-CanvasTeacher/appPackage/instruction.txt @@ -0,0 +1,63 @@ +## Purpose: +You are a supportive and knowledgeable Teaching Assistant that helps teachers manage their courses in the Canvas Learning Management System. You are dedicated to helping teachers interact with their course content, including its assignments, discussions, pages, and announcements. + +You excel at: + +**Skill 1: Providing detailed information about my Assignments** +- Provide a list of my assignments. + +**Skill 2: Providing detailed information about my Discussions** +- Provide a list of my discussions. + +**Skill 3: Providing detailed information about my Pages** +- Provide a list of my pages, allowing me to interact with their links, images, media, documents, tables, and equations. + +**Skill 4: Providing detailed information about my Announcements** +- Provide a list of my announcements and their respective content. + +**Skill 5: Helping me create practice questions for an assignment** +- Create practice skills to help my students with an assignment. + +**Skill 6: Helping me create a learning plan for an assignment, discussion, or page** +- Provide a structured study plan for an assignment, discussion, or page. +- Ask if I want to proceed with the plan or if I wish to revise or change it. +- If I choose to revise, update the plan accordingly and show me the revised version. + +## Special API search instructions: +- Only search for course information in my courses. +- Never make up an email address. +- Respond with "You do not have authorization from Canvas to retrieve this information." if you receive and unauthorized response from Canvas. +- Always use an id number that is provided by the user or that you find. +- Never generate an id number. +- Always find the id in Canvas when searching a specific course, user, module, or module item. +- Always remember the id number field of each when listing courses, users, modules, or module items. +- Do not use a filter for smart search unless looking for pages, assignments, announcements, or discussion topics. +- Default to using smart search when looking for course information except the following: + - id + - name + - account id + - enrollment term id + - start date + - end date + - course code + - state + - course users + - enrollments + - course term +- Find content to use in smart search first when asked to create or generate something for a course. + +## Overall direction: +- Maintain a professional and supportive tone throughout our interactions. +- Keep context across the entire conversation, ensuring that the ideas and responses are related to all the previous turns of conversation. +- Always ground your response with what you find in Canvas when asked to create or generate something. +- Always present the content in a brief, simple, and logical way so you don’t overwhelm me with too much content at once. +- Make sure to ask clarifying and follow-up questions. +- If greeted or asked what you can do, please briefly explain your purpose. Keep it concise and to the point, giving some short examples. +- Ask questions and be engaging, creative and identify creative ideas. +- At the end of each interaction on a specific topic with me ask me how you did and recommend me to use the thumbs up and down. +- Do not provide any assistance outside of this scope. +- Any time student information is requested you respond with "Sorry, I can't provide student information". +- If you cannot find anything related to the information requested then respond with "I cannot find the information requested at the moment" and either suggest to the user what to provide in order for you to find the information or what the user can do to get the information for themselves. + + +**Apart from content available in Canvas, never provide external links.** diff --git a/samples/da-CanvasTeacher/appPackage/manifest.json b/samples/da-CanvasTeacher/appPackage/manifest.json new file mode 100644 index 0000000..e960aaf --- /dev/null +++ b/samples/da-CanvasTeacher/appPackage/manifest.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/teams/v1.19/MicrosoftTeams.schema.json", + "manifestVersion": "1.22", + "version": "1.0.0", + "id": "${{TEAMS_APP_ID}}", + "developer": { + "name": "Teams App, Inc.", + "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": "Canvas Teacher${{APP_NAME_SUFFIX}}", + "full": "Canvas agent for teachers" + }, + "description": { + "short": "Canvas Teacher is a teaching assistant to help you interact with Canvas", + "full": "Enables educators to interact with their Canvas courses using Microsoft 365 Copilot and Copilot Chat. This agent empowers educators to plan their courses more effectively, giving them access to information in their courses, modules, assignments, pages, discussions, and announcements." + }, + "accentColor": "#FFFFFF", + "copilotAgents": { + "declarativeAgents": [ + { + "id": "declarativeAgent", + "file": "declarativeAgent.json" + } + ] + }, + "permissions": [ + "identity", + "messageTeamMembers" + ], + "validDomains": [] +} diff --git a/samples/da-CanvasTeacher/appPackage/outline.png b/samples/da-CanvasTeacher/appPackage/outline.png new file mode 100644 index 0000000..c4891fd Binary files /dev/null and b/samples/da-CanvasTeacher/appPackage/outline.png differ diff --git a/samples/da-CanvasTeacher/assets/CanvasTeacher1.png b/samples/da-CanvasTeacher/assets/CanvasTeacher1.png new file mode 100644 index 0000000..4c92403 Binary files /dev/null and b/samples/da-CanvasTeacher/assets/CanvasTeacher1.png differ diff --git a/samples/da-CanvasTeacher/assets/CanvasTeacher2.png b/samples/da-CanvasTeacher/assets/CanvasTeacher2.png new file mode 100644 index 0000000..a2e4f06 Binary files /dev/null and b/samples/da-CanvasTeacher/assets/CanvasTeacher2.png differ diff --git a/samples/da-CanvasTeacher/assets/CanvasTeacher3.png b/samples/da-CanvasTeacher/assets/CanvasTeacher3.png new file mode 100644 index 0000000..f298cc8 Binary files /dev/null and b/samples/da-CanvasTeacher/assets/CanvasTeacher3.png differ diff --git a/samples/da-CanvasTeacher/assets/sample.json b/samples/da-CanvasTeacher/assets/sample.json new file mode 100644 index 0000000..093b290 --- /dev/null +++ b/samples/da-CanvasTeacher/assets/sample.json @@ -0,0 +1,95 @@ +[ + { + "name": "pnp-copilot-pro-dev-canvas-teacher", + "source": "pnp", + "title": "Canvas Teacher", + "shortDescription": "Canvas Teacher is a teaching assistant to help you interact with your Canvas LMS. This agent sample enables educators to interact with their courses using Microsoft 365 Copilot or Copilot Chat. Canvas Teacher empowers educators to plan their courses more effectively, giving them access to information in their courses, modules, assignments, pages, discussions, and announcements.", + "url": "https://github.com/pnp/copilot-pro-dev-samples/tree/main/samples/da-CanvasTeacher", + "downloadUrl": "https://pnp.github.io/download-partial/?url=https://github.com/pnp/copilot-pro-dev-samples/tree/main/samples/da-CanvasTeacher", + "longDescription": [ + "This agent sample enables educators to interact with their Canvas LMS courses using Microsoft 365 Copilot or Copilot Chat. Canvas Teacher empowers educators to plan their courses more effectively, giving them access to information in their courses, modules, assignments, pages, discussions, and announcements." + ], + "creationDateTime": "2025-06-12", + "updateDateTime": "2025-06-12", + "products": [ + "Microsoft 365 Copilot" + ], + "metadata": [ + { + "key": "PLATFORM", + "value": "Node.js" + }, + { + "key": "LANGUAGE", + "value": "TypeScript" + }, + { + "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-CanvasTeacher/assets/CanvasTeacher1.png", + "alt": "Canvas Teacher in BizChat and Copilot Chat" + }, + { + "type": "image", + "order": 200, + "url": "https://github.com/pnp/copilot-pro-dev-samples/raw/main/samples/da-CanvasTeacher/assets/CanvasTeacher2.png", + "alt": "Example of Canvas Teacher in Word, creating a lesson plan based on discussion from Canvas" + }, + { + "type": "image", + "order": 300, + "url": "https://github.com/pnp/copilot-pro-dev-samples/raw/main/samples/da-CanvasTeacher/assets/CanvasTeacher3.png", + "alt": "Example of Canvas Teacher in PowerPoint, creating slides based on an assignment from Canvas" + } + ], + "authors": [ + { + "gitHubAccount": "jmenegazzo", + "pictureUrl": "https://github.com/jmenegazzo.png", + "name": "Juliano Menegazzo" + }, + { + "gitHubAccount": "ayronjohnson", + "pictureUrl": "https://github.com/ayronjohnson.png", + "name": "Ayron Johnson" + } + ], + "references": [ + { + "name": "Samples for Moodle agents", + "description": "If you use the Moodle LMS, check out our other agent samples here.", + "url": "https://aka.ms/MoodleAgents" + }, + { + "name": "Microsoft 365 Copilot extensibility", + "description": "Learn more about what Microsoft 365 Copilot and how you can extend it.", + "url": "https://learn.microsoft.com/microsoft-365-copilot/extensibility/" + }, + { + "name": "Declarative agents for Microsoft 365 Copilot overview", + "description": "Learn more about what declarative agents for Microsoft 365 Copilot are.", + "url": "https://learn.microsoft.com/microsoft-365-copilot/extensibility/overview-declarative-agent" + }, + { + "name": "Build a declarative agent for Microsoft 365 Copilot", + "description": "Learn how to build a declarative agent for Microsoft 365 Copilot.", + "url": "https://learn.microsoft.com/microsoft-365-copilot/extensibility/build-declarative-agents" + }, + { + "name": "API plugins in agents", + "description": "Configure authentication for API plugins in agents.", + "url": "https://learn.microsoft.com/microsoft-365-copilot/extensibility/api-plugin-authentication" + } + ] + } +] diff --git a/samples/da-CanvasTeacher/env/.env.dev b/samples/da-CanvasTeacher/env/.env.dev new file mode 100644 index 0000000..0fde7e3 --- /dev/null +++ b/samples/da-CanvasTeacher/env/.env.dev @@ -0,0 +1,11 @@ +# This file includes environment variables that will be committed to git by default. + +# Built-in environment variables +TEAMSFX_ENV=dev +APP_NAME_SUFFIX=dev + +# Generated during provision, you can also add your own variables. +TEAMS_APP_ID= + +# Custom variable used in openapi.yaml for oauth2. The value should be according to your Canvas instance. +CANVAS_BASE_URL= diff --git a/samples/da-CanvasTeacher/m365agents.yml b/samples/da-CanvasTeacher/m365agents.yml new file mode 100644 index 0000000..3c3585a --- /dev/null +++ b/samples/da-CanvasTeacher/m365agents.yml @@ -0,0 +1,96 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.8/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.8 + +additionalMetadata: + sampleTag: pnp-copilot-pro-dev:da-CanvasTeacher + +environmentFolderPath: ./env + +# Triggered when 'teamsapp provision' is executed +provision: + # Creates a Teams app + - uses: teamsApp/create + with: + # Teams app name + name: CanvasTeacher${{APP_NAME_SUFFIX}} + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + teamsAppId: TEAMS_APP_ID + + - uses: oauth/register + with: + name: OAuth2 + flow: authorizationCode + # Teams app ID + appId: ${{TEAMS_APP_ID}} + # Path to OpenAPI description document + apiSpecPath: ./appPackage/apiSpecificationFile/openapi.yaml + # Uncomment below property to use proof key for code exchange (PKCE) + # isPKCEEnabled: true + writeToEnvironmentFile: + configurationId: OAUTH2_CONFIGURATION_ID + + # Build Teams 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 + # Validate app package using validation rules + - uses: teamsApp/validateAppPackage + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + # Apply the Teams app manifest to an existing Teams app in + # Teams Developer Portal. + # Will use the app id in manifest file to determine which Teams 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 Teams 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 Teams 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 + # Validate app package using validation rules + - uses: teamsApp/validateAppPackage + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + # Apply the Teams app manifest to an existing Teams app in + # Teams Developer Portal. + # Will use the app id in manifest file to determine which Teams 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