From 9f3f330b0bb75d36ac41bc2576531385db28ec3b Mon Sep 17 00:00:00 2001 From: Kuojian Lu Date: Wed, 6 Mar 2024 11:09:55 +0800 Subject: [PATCH] feat: add custom copilot assistant with assistants api template (#10906) * feat: add custom copilot assistant with assistants api template --- .../.gitignore | 24 +++ .../.localConfigs | 5 + .../.localConfigs.testTool | 6 + .../.vscode/extensions.json | 5 + .../.vscode/launch.json.tpl | 122 +++++++++++ .../.vscode/settings.json | 11 + .../.vscode/tasks.json | 204 ++++++++++++++++++ .../.webappignore | 27 +++ .../README.md.tpl | 123 +++++++++++ .../appPackage/color.png | Bin 0 -> 5131 bytes .../appPackage/manifest.json.tpl | 43 ++++ .../appPackage/outline.png | Bin 0 -> 327 bytes .../env/.env.dev | 16 ++ .../env/.env.dev.user.tpl | 11 + .../env/.env.local | 11 + .../env/.env.local.user.tpl | 12 ++ .../env/.env.testtool | 8 + .../env/.env.testtool.user.tpl | 11 + .../infra/azure.bicep | 96 +++++++++ .../infra/azure.parameters.json.tpl | 27 +++ .../infra/botRegistration/azurebot.bicep | 37 ++++ .../infra/botRegistration/readme.md | 1 + .../package.json.tpl | 37 ++++ .../src/adapter.js | 50 +++++ .../src/app/actions.js | 40 ++++ .../src/app/app.js | 39 ++++ .../src/app/messages.js | 8 + .../src/config.js | 8 + .../src/creator.js | 64 ++++++ .../src/index.js | 25 +++ .../teamsapp.local.yml.tpl | 80 +++++++ .../teamsapp.testtool.yml | 26 +++ .../teamsapp.yml.tpl | 141 ++++++++++++ .../web.config | 60 ++++++ .../.gitignore | 24 +++ .../.localConfigs | 5 + .../.localConfigs.testTool | 6 + .../.vscode/extensions.json | 5 + .../.vscode/launch.json.tpl | 122 +++++++++++ .../.vscode/settings.json | 11 + .../.vscode/tasks.json | 204 ++++++++++++++++++ .../.webappignore | 27 +++ .../README.md.tpl | 124 +++++++++++ .../appPackage/color.png | Bin 0 -> 5131 bytes .../appPackage/manifest.json.tpl | 43 ++++ .../appPackage/outline.png | Bin 0 -> 327 bytes .../env/.env.dev | 16 ++ .../env/.env.dev.user.tpl | 11 + .../env/.env.local | 11 + .../env/.env.local.user.tpl | 12 ++ .../env/.env.testtool | 8 + .../env/.env.testtool.user.tpl | 11 + .../infra/azure.bicep | 96 +++++++++ .../infra/azure.parameters.json.tpl | 27 +++ .../infra/botRegistration/azurebot.bicep | 37 ++++ .../infra/botRegistration/readme.md | 1 + .../package.json.tpl | 43 ++++ .../src/adapter.ts | 51 +++++ .../src/app/actions.ts | 56 +++++ .../src/app/app.ts | 40 ++++ .../src/app/messages.ts | 7 + .../src/config.ts | 8 + .../src/creator.ts | 64 ++++++ .../src/index.ts | 25 +++ .../teamsapp.local.yml.tpl | 80 +++++++ .../teamsapp.testtool.yml | 26 +++ .../teamsapp.yml.tpl | 141 ++++++++++++ .../tsconfig.json | 13 ++ .../web.config | 60 ++++++ 69 files changed, 2793 insertions(+) create mode 100644 templates/js/custom-copilot-assistant-assistants-api/.gitignore create mode 100644 templates/js/custom-copilot-assistant-assistants-api/.localConfigs create mode 100644 templates/js/custom-copilot-assistant-assistants-api/.localConfigs.testTool create mode 100644 templates/js/custom-copilot-assistant-assistants-api/.vscode/extensions.json create mode 100644 templates/js/custom-copilot-assistant-assistants-api/.vscode/launch.json.tpl create mode 100644 templates/js/custom-copilot-assistant-assistants-api/.vscode/settings.json create mode 100644 templates/js/custom-copilot-assistant-assistants-api/.vscode/tasks.json create mode 100644 templates/js/custom-copilot-assistant-assistants-api/.webappignore create mode 100644 templates/js/custom-copilot-assistant-assistants-api/README.md.tpl create mode 100644 templates/js/custom-copilot-assistant-assistants-api/appPackage/color.png create mode 100644 templates/js/custom-copilot-assistant-assistants-api/appPackage/manifest.json.tpl create mode 100644 templates/js/custom-copilot-assistant-assistants-api/appPackage/outline.png create mode 100644 templates/js/custom-copilot-assistant-assistants-api/env/.env.dev create mode 100644 templates/js/custom-copilot-assistant-assistants-api/env/.env.dev.user.tpl create mode 100644 templates/js/custom-copilot-assistant-assistants-api/env/.env.local create mode 100644 templates/js/custom-copilot-assistant-assistants-api/env/.env.local.user.tpl create mode 100644 templates/js/custom-copilot-assistant-assistants-api/env/.env.testtool create mode 100644 templates/js/custom-copilot-assistant-assistants-api/env/.env.testtool.user.tpl create mode 100644 templates/js/custom-copilot-assistant-assistants-api/infra/azure.bicep create mode 100644 templates/js/custom-copilot-assistant-assistants-api/infra/azure.parameters.json.tpl create mode 100644 templates/js/custom-copilot-assistant-assistants-api/infra/botRegistration/azurebot.bicep create mode 100644 templates/js/custom-copilot-assistant-assistants-api/infra/botRegistration/readme.md create mode 100644 templates/js/custom-copilot-assistant-assistants-api/package.json.tpl create mode 100644 templates/js/custom-copilot-assistant-assistants-api/src/adapter.js create mode 100644 templates/js/custom-copilot-assistant-assistants-api/src/app/actions.js create mode 100644 templates/js/custom-copilot-assistant-assistants-api/src/app/app.js create mode 100644 templates/js/custom-copilot-assistant-assistants-api/src/app/messages.js create mode 100644 templates/js/custom-copilot-assistant-assistants-api/src/config.js create mode 100644 templates/js/custom-copilot-assistant-assistants-api/src/creator.js create mode 100644 templates/js/custom-copilot-assistant-assistants-api/src/index.js create mode 100644 templates/js/custom-copilot-assistant-assistants-api/teamsapp.local.yml.tpl create mode 100644 templates/js/custom-copilot-assistant-assistants-api/teamsapp.testtool.yml create mode 100644 templates/js/custom-copilot-assistant-assistants-api/teamsapp.yml.tpl create mode 100644 templates/js/custom-copilot-assistant-assistants-api/web.config create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/.gitignore create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/.localConfigs create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/.localConfigs.testTool create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/.vscode/extensions.json create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/.vscode/launch.json.tpl create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/.vscode/settings.json create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/.vscode/tasks.json create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/.webappignore create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/README.md.tpl create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/appPackage/color.png create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/appPackage/manifest.json.tpl create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/appPackage/outline.png create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/env/.env.dev create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/env/.env.dev.user.tpl create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/env/.env.local create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/env/.env.local.user.tpl create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/env/.env.testtool create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/env/.env.testtool.user.tpl create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/infra/azure.bicep create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/infra/azure.parameters.json.tpl create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/infra/botRegistration/azurebot.bicep create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/infra/botRegistration/readme.md create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/package.json.tpl create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/src/adapter.ts create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/src/app/actions.ts create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/src/app/app.ts create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/src/app/messages.ts create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/src/config.ts create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/src/creator.ts create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/src/index.ts create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/teamsapp.local.yml.tpl create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/teamsapp.testtool.yml create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/teamsapp.yml.tpl create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/tsconfig.json create mode 100644 templates/ts/custom-copilot-assistant-assistants-api/web.config diff --git a/templates/js/custom-copilot-assistant-assistants-api/.gitignore b/templates/js/custom-copilot-assistant-assistants-api/.gitignore new file mode 100644 index 0000000000..0a23a2bb0e --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/.gitignore @@ -0,0 +1,24 @@ +# TeamsFx files +env/.env.*.user +env/.env.local +appPackage/build + +# dependencies +node_modules/ + +# misc +.env +.deployment +.DS_Store + +# build +lib/ + +# devTools +devTools/ + +# Local data +.localConfigs +.localConfigs.testTool +.notification.localstore.json +.notification.testtoolstore.json \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/.localConfigs b/templates/js/custom-copilot-assistant-assistants-api/.localConfigs new file mode 100644 index 0000000000..4c5c0a4f9f --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/.localConfigs @@ -0,0 +1,5 @@ +# A gitignored place holder file for local runtime configurations +BOT_ID= +BOT_PASSWORD= +OPENAI_API_KEY= +OPENAI_ASSISTANT_ID= \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/.localConfigs.testTool b/templates/js/custom-copilot-assistant-assistants-api/.localConfigs.testTool new file mode 100644 index 0000000000..0354f77cc9 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/.localConfigs.testTool @@ -0,0 +1,6 @@ +# A gitignored place holder file for local runtime configurations +BOT_ID= +BOT_PASSWORD= +OPENAI_API_KEY= +OPENAI_ASSISTANT_ID= +TEAMSFX_NOTIFICATION_STORE_FILENAME=.notification.testtoolstore.json diff --git a/templates/js/custom-copilot-assistant-assistants-api/.vscode/extensions.json b/templates/js/custom-copilot-assistant-assistants-api/.vscode/extensions.json new file mode 100644 index 0000000000..1b70a39308 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "TeamsDevApp.ms-teams-vscode-extension" + ] +} \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/.vscode/launch.json.tpl b/templates/js/custom-copilot-assistant-assistants-api/.vscode/launch.json.tpl new file mode 100644 index 0000000000..9e3b45ee1f --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/.vscode/launch.json.tpl @@ -0,0 +1,122 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Remote (Edge)", + "type": "msedge", + "request": "launch", + "url": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}", + "presentation": { + "group": "3-remote", + "order": 1 + }, + "internalConsoleOptions": "neverOpen" + }, + { + "name": "Launch Remote (Chrome)", + "type": "chrome", + "request": "launch", + "url": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}", + "presentation": { + "group": "3-remote", + "order": 2 + }, + "internalConsoleOptions": "neverOpen" + }, + { + "name": "Launch App (Edge)", + "type": "msedge", + "request": "launch", + "url": "https://teams.microsoft.com/l/app/${{local:TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}", + "cascadeTerminateToConfigurations": [ + "Attach to Local Service" + ], + "presentation": { + "group": "all", + "hidden": true + }, + "internalConsoleOptions": "neverOpen" + }, + { + "name": "Launch App (Chrome)", + "type": "chrome", + "request": "launch", + "url": "https://teams.microsoft.com/l/app/${{local:TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}", + "cascadeTerminateToConfigurations": [ + "Attach to Local Service" + ], + "presentation": { + "group": "all", + "hidden": true + }, + "internalConsoleOptions": "neverOpen" + }, + { + "name": "Attach to Local Service", + "type": "node", + "request": "attach", + "port": 9239, + "restart": true, + "presentation": { + "group": "all", + "hidden": true + }, + "internalConsoleOptions": "neverOpen" + } + ], + "compounds": [ + { + "name": "Debug in Teams (Edge)", + "configurations": [ + "Launch App (Edge)", + "Attach to Local Service" + ], + "preLaunchTask": "Start Teams App Locally", + "presentation": { +{{#enableTestToolByDefault}} + "group": "2-local", +{{/enableTestToolByDefault}} +{{^enableTestToolByDefault}} + "group": "1-local", +{{/enableTestToolByDefault}} + "order": 1 + }, + "stopAll": true + }, + { + "name": "Debug in Teams (Chrome)", + "configurations": [ + "Launch App (Chrome)", + "Attach to Local Service" + ], + "preLaunchTask": "Start Teams App Locally", + "presentation": { +{{#enableTestToolByDefault}} + "group": "2-local", +{{/enableTestToolByDefault}} +{{^enableTestToolByDefault}} + "group": "1-local", +{{/enableTestToolByDefault}} + "order": 2 + }, + "stopAll": true + }, + { + "name": "Debug in Test Tool (Preview)", + "configurations": [ + "Attach to Local Service" + ], + "preLaunchTask": "Start Teams App (Test Tool)", + "presentation": { +{{#enableTestToolByDefault}} + "group": "1-local", +{{/enableTestToolByDefault}} +{{^enableTestToolByDefault}} + "group": "2-local", +{{/enableTestToolByDefault}} + "order": 1 + }, + "stopAll": true + } + ] +} diff --git a/templates/js/custom-copilot-assistant-assistants-api/.vscode/settings.json b/templates/js/custom-copilot-assistant-assistants-api/.vscode/settings.json new file mode 100644 index 0000000000..0d3ba10b02 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "debug.onTaskErrors": "abort", + "json.schemas": [ + { + "fileMatch": [ + "/aad.*.json" + ], + "schema": {} + } + ] +} \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/.vscode/tasks.json b/templates/js/custom-copilot-assistant-assistants-api/.vscode/tasks.json new file mode 100644 index 0000000000..1c3e241f27 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/.vscode/tasks.json @@ -0,0 +1,204 @@ +// This file is automatically generated by Teams Toolkit. +// The teamsfx tasks defined in this file require Teams Toolkit version >= 5.0.0. +// See https://aka.ms/teamsfx-tasks for details on how to customize each task. +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Start Teams App (Test Tool)", + "dependsOn": [ + "Validate prerequisites (Test Tool)", + "Deploy (Test Tool)", + "Start application (Test Tool)", + "Start Test Tool", + ], + "dependsOrder": "sequence" + }, + { + // Check all required prerequisites. + // See https://aka.ms/teamsfx-tasks/check-prerequisites to know the details and how to customize the args. + "label": "Validate prerequisites (Test Tool)", + "type": "teamsfx", + "command": "debug-check-prerequisites", + "args": { + "prerequisites": [ + "nodejs", // Validate if Node.js is installed. + "portOccupancy" // Validate available ports to ensure those debug ones are not occupied. + ], + "portOccupancy": [ + 3978, // app service port + 9239, // app inspector port for Node.js debugger + 56150, // test tool port + ] + } + }, + { + // Build project. + // See https://aka.ms/teamsfx-tasks/deploy to know the details and how to customize the args. + "label": "Deploy (Test Tool)", + "type": "teamsfx", + "command": "deploy", + "args": { + "env": "testtool", + } + }, + { + "label": "Start application (Test Tool)", + "type": "shell", + "command": "npm run dev:teamsfx:testtool", + "isBackground": true, + "options": { + "cwd": "${workspaceFolder}", + }, + "problemMatcher": { + "pattern": [ + { + "regexp": "^.*$", + "file": 0, + "location": 1, + "message": 2 + } + ], + "background": { + "activeOnStart": true, + "beginsPattern": "[nodemon] starting", + "endsPattern": "restify listening to|Bot/ME service listening at|[nodemon] app crashed" + } + } + }, + { + "label": "Start Test Tool", + "type": "shell", + "command": "npm run dev:teamsfx:launch-testtool", + "isBackground": true, + "options": { + "env": { + "PATH": "${workspaceFolder}/devTools/teamsapptester/node_modules/.bin:${env:PATH}" + } + }, + "windows": { + "options": { + "env": { + "PATH": "${workspaceFolder}/devTools/teamsapptester/node_modules/.bin;${env:PATH}" + } + } + }, + "problemMatcher": { + "pattern": [ + { + "regexp": "^.*$", + "file": 0, + "location": 1, + "message": 2 + } + ], + "background": { + "activeOnStart": true, + "beginsPattern": ".*", + "endsPattern": "Listening on" + } + }, + "presentation": { + "panel": "dedicated", + "reveal": "silent" + } + }, + { + "label": "Start Teams App Locally", + "dependsOn": [ + "Validate prerequisites", + "Start local tunnel", + "Provision", + "Deploy", + "Start application" + ], + "dependsOrder": "sequence" + }, + { + // Check all required prerequisites. + // See https://aka.ms/teamsfx-tasks/check-prerequisites to know the details and how to customize the args. + "label": "Validate prerequisites", + "type": "teamsfx", + "command": "debug-check-prerequisites", + "args": { + "prerequisites": [ + "nodejs", // Validate if Node.js is installed. + "m365Account", // Sign-in prompt for Microsoft 365 account, then validate if the account enables the sideloading permission. + "portOccupancy" // Validate available ports to ensure those debug ones are not occupied. + ], + "portOccupancy": [ + 3978, // app service port + 9239 // app inspector port for Node.js debugger + ] + } + }, + { + // Start the local tunnel service to forward public URL to local port and inspect traffic. + // See https://aka.ms/teamsfx-tasks/local-tunnel for the detailed args definitions. + "label": "Start local tunnel", + "type": "teamsfx", + "command": "debug-start-local-tunnel", + "args": { + "type": "dev-tunnel", + "ports": [ + { + "portNumber": 3978, + "protocol": "http", + "access": "public", + "writeToEnvironmentFile": { + "endpoint": "BOT_ENDPOINT", // output tunnel endpoint as BOT_ENDPOINT + "domain": "BOT_DOMAIN" // output tunnel domain as BOT_DOMAIN + } + } + ], + "env": "local" + }, + "isBackground": true, + "problemMatcher": "$teamsfx-local-tunnel-watch" + }, + { + // Create the debug resources. + // See https://aka.ms/teamsfx-tasks/provision to know the details and how to customize the args. + "label": "Provision", + "type": "teamsfx", + "command": "provision", + "args": { + "env": "local" + } + }, + { + // Build project. + // See https://aka.ms/teamsfx-tasks/deploy to know the details and how to customize the args. + "label": "Deploy", + "type": "teamsfx", + "command": "deploy", + "args": { + "env": "local" + } + }, + { + "label": "Start application", + "type": "shell", + "command": "npm run dev:teamsfx", + "isBackground": true, + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": { + "pattern": [ + { + "regexp": "^.*$", + "file": 0, + "location": 1, + "message": 2 + } + ], + "background": { + "activeOnStart": true, + "beginsPattern": "[nodemon] starting", + "endsPattern": "restify listening to|Bot/ME service listening at|[nodemon] app crashed" + } + } + } + ] +} \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/.webappignore b/templates/js/custom-copilot-assistant-assistants-api/.webappignore new file mode 100644 index 0000000000..3e9dfd4d90 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/.webappignore @@ -0,0 +1,27 @@ +.webappignore +.fx +.deployment +.localConfigs +.localConfigs.testTool +.notification.localstore.json +.notification.testtoolstore.json +.vscode +*.js.map +*.ts.map +*.ts +.git* +.tsbuildinfo +CHANGELOG.md +readme.md +local.settings.json +test +tsconfig.json +.DS_Store +teamsapp.yml +teamsapp.*.yml +/env/ +/node_modules/.bin +/node_modules/ts-node +/node_modules/typescript +/appPackage/ +/infra/ \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/README.md.tpl b/templates/js/custom-copilot-assistant-assistants-api/README.md.tpl new file mode 100644 index 0000000000..cd206c294a --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/README.md.tpl @@ -0,0 +1,123 @@ +# Overview of the AI Assistant Bot template + +This app template is built on top of [Teams AI library](https://aka.ms/teams-ai-library) and [OpenAI Assistants API](https://platform.openai.com/docs/assistants/overview). +It showcases how to build an intelligent chat bot in Teams capable of helping users accomplish specific tasks using natural language right in the Teams conversations, such as solving a math problem, call functions to get city weather, etc. + +- [Overview of the AI Assistant Bot template](#overview-of-the-ai-assistant-bot-template) + - [Get started with the AI Assistant Bot template](#get-started-with-the-ai-assistant-bot-template) + - [What's included in the template](#whats-included-in-the-template) + - [Extend the AI Assistant Bot template with more AI capabilities](#extend-the-ai-assistant-bot-template-with-more-ai-capabilities) + - [Additional information and references](#additional-information-and-references) + +## Get started with the AI Assistant Bot template + +> **Prerequisites** +> +> To run the AI Assistant Bot template in your local dev machine, you will need: +> +> - [Node.js](https://nodejs.org/), supported versions: 16, 18 +{{^enableTestToolByDefault}} +> - A [Microsoft 365 account for development](https://docs.microsoft.com/microsoftteams/platform/toolkit/accounts) +{{/enableTestToolByDefault}} +> - [Teams Toolkit Visual Studio Code Extension](https://aka.ms/teams-toolkit) version 5.0.0 and higher or [Teams Toolkit CLI](https://aka.ms/teamsfx-toolkit-cli) +> - An account with [OpenAI](https://platform.openai.com/). +> +> **Note** +> +> The `AssistantsPlanner` in Teams AI Library is currently in preview version. + +### Create your own OpenAI Assistant + +Before running or debugging your bot, please follow these steps to setup your own [OpenAI Assistant](https://platform.openai.com/docs/assistants/overview). + +**If you haven't setup any Assistant yet** + +> This app template provides script `src/creator.js` to help create assistant. You can change the instructions and settings in the script to customize the assistant. +> +> After creation, you can change and manage your assistants on [OpenAI](https://platform.openai.com/assistants). + +1. Open terminal and run command `npm install` to install all dependency packages + ``` + > npm install + ``` +1. After `npm install` completed, run command `npm run assistant:create -- ` + ``` + > npm run assistant:create -- xxxxxx + ``` +1. The above command will output something like "*Created a new assistant with an ID of: **asst_xxx...***" +1. Fill in both OpenAI API Key and the created Assistant ID into `env/.env.*.user` + ``` + SECRET_OPENAI_API_KEY= + SECRET_OPENAI_ASSISTANT_ID= + ``` + +**If you already have an Assistant created** + +1. Fill in both OpenAI API Key and the created Assistant ID into `env/.env.*.user` + ``` + SECRET_OPENAI_API_KEY= + SECRET_OPENAI_ASSISTANT_ID= + ``` + +### Run Teams Bot locally + +1. First, select the Teams Toolkit icon on the left in the VS Code toolbar. +{{#enableTestToolByDefault}} +1. Press F5 to start debugging which launches your app in Teams App Test Tool using a web browser. Select `Debug in Test Tool (Preview)`. +1. You can send any message to get a response from the bot. + +**Congratulations**! You are running an application that can now interact with users in Teams App Test Tool: + +![ai assistant bot in Teams App Test Tool](https://github.com/OfficeDev/TeamsFx/assets/15644078/90868166-115b-4394-a0d2-272bd985d0aa) +{{/enableTestToolByDefault}} +{{^enableTestToolByDefault}} +1. In the Account section, sign in with your [Microsoft 365 account](https://docs.microsoft.com/microsoftteams/platform/toolkit/accounts) if you haven't yet. +1. Press F5 to start debugging which launches your app in Teams using a web browser. Select `Debug in Teams (Edge)` or `Debug in Teams (Chrome)`. +1. When Teams launches in the browser, select the Add button in the dialog to install your app to Teams. +1. You can send any message to get a response from the bot. + +**Congratulations**! You are running an application that can now interact with users in Teams: + +![ai assistant bot in Teams](https://github.com/OfficeDev/TeamsFx/assets/37978464/ccff0457-726a-486b-9247-c7f53e0a80ab) +{{/enableTestToolByDefault}} + +## What's included in the template + +| Folder | Contents | +| - | - | +| `.vscode` | VSCode files for debugging | +| `appPackage` | Templates for the Teams application manifest | +| `env` | Environment files | +| `infra` | Templates for provisioning Azure resources | +| `src` | The source code for the application | + +The following files can be customized and demonstrate an example implementation to get you started. + +| File | Contents | +| - | - | +|`src/index.js`| Sets up the bot app server.| +|`src/adapter.js`| Sets up the bot adapter.| +|`src/config.js`| Defines the environment variables.| +|`src/creator.js`| One-time tool to create OpenAI Assistant.| +|`src/app/app.js`| Handles business logics for the AI Assistant Bot.| +|`src/app/messages.js`| Defines the message activity handlers.| +|`src/app/actions.js`| Defines the AI actions.| + +The following are Teams 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 Teams Toolkit works. + +| File | Contents | +| - | - | +|`teamsapp.yml`|This is the main Teams Toolkit project file. The project file defines two primary things: Properties and configuration Stage definitions. | +|`teamsapp.local.yml`|This overrides `teamsapp.yml` with actions that enable local execution and debugging.| +|`teamsapp.testtool.yml`|This overrides `teamsapp.yml` with actions that enable local execution and debugging in Teams App Test Tool.| + +## Extend the AI Assistant Bot template with more AI capabilities + +You can follow [AI assistant bot in Teams](https://aka.ms/teamsfx-ai-assistant-bot) to extend the AI Assistant Bot template with more AI capabilities. + +## Additional information and references +- [Teams AI library](https://aka.ms/teams-ai-library) +- [Teams Toolkit Documentations](https://docs.microsoft.com/microsoftteams/platform/toolkit/teams-toolkit-fundamentals) +- [Teams Toolkit CLI](https://aka.ms/teamsfx-toolkit-cli) +- [Teams Toolkit Samples](https://github.com/OfficeDev/TeamsFx-Samples) +- [OpenAI Assistants API](https://platform.openai.com/docs/assistants/overview) diff --git a/templates/js/custom-copilot-assistant-assistants-api/appPackage/color.png b/templates/js/custom-copilot-assistant-assistants-api/appPackage/color.png new file mode 100644 index 0000000000000000000000000000000000000000..2d7e85c9e9886c96e20fbb469c3c196ae8b5de42 GIT binary patch literal 5131 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 literal 0 HcmV?d00001 diff --git a/templates/js/custom-copilot-assistant-assistants-api/appPackage/manifest.json.tpl b/templates/js/custom-copilot-assistant-assistants-api/appPackage/manifest.json.tpl new file mode 100644 index 0000000000..85018e9501 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/appPackage/manifest.json.tpl @@ -0,0 +1,43 @@ +{ + "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.16/MicrosoftTeams.schema.json", + "manifestVersion": "1.16", + "version": "1.0.0", + "id": "${{TEAMS_APP_ID}}", + "packageName": "com.microsoft.teams.extension", + "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": "{{appName}}${{APP_NAME_SUFFIX}}", + "full": "full name for {{appName}}" + }, + "description": { + "short": "short description for {{appName}}", + "full": "full description for {{appName}}" + }, + "accentColor": "#FFFFFF", + "bots": [ + { + "botId": "${{BOT_ID}}", + "scopes": [ + "personal" + ], + "supportsFiles": false, + "isNotificationOnly": false + } + ], + "composeExtensions": [], + "configurableTabs": [], + "staticTabs": [], + "permissions": [ + "identity" + ], + "validDomains": [] +} \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/appPackage/outline.png b/templates/js/custom-copilot-assistant-assistants-api/appPackage/outline.png new file mode 100644 index 0000000000000000000000000000000000000000..245fa194db6e08d30511fdbf26aec3c6e2c3c3c8 GIT binary patch literal 327 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?3oVGw3ym^DWND9BhG z9;9t*EM+Qm zy2D^Lfp=fIpwQyAe|y)?x-or<+J~Ptr@l6Mq%piHi4jOQ$W@+cm^^pek{T^R1~YT6 z#nC6He`LE*@cXCq-bL3hdgYxF$=uQYd!tVN6U(~0f70B<4PQ*lTGqqND0QE8cCxF; zrA^=emkHKQ+WI8@(#FJB4wBw$4jk;^oXcu!J2!Q;MX2;5u|xv~4xueIx7{LTWE)P* zx>U9|_qXolm|MHJvl^rhh$n1mem7%r%A<3y&veM1y2!zda7l7b Ve3c}0;w{jh44$rjF6*2UngINOfUy7o literal 0 HcmV?d00001 diff --git a/templates/js/custom-copilot-assistant-assistants-api/env/.env.dev b/templates/js/custom-copilot-assistant-assistants-api/env/.env.dev new file mode 100644 index 0000000000..4b07861c03 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/env/.env.dev @@ -0,0 +1,16 @@ +# This file includes environment variables that will be committed to git by default. + +# Built-in environment variables +TEAMSFX_ENV=dev +APP_NAME_SUFFIX=dev + +# Updating AZURE_SUBSCRIPTION_ID or AZURE_RESOURCE_GROUP_NAME after provision may also require an update to RESOURCE_SUFFIX, because some services require a globally unique name across subscriptions/resource groups. +AZURE_SUBSCRIPTION_ID= +AZURE_RESOURCE_GROUP_NAME= +RESOURCE_SUFFIX= + +# Generated during provision, you can also add your own variables. +BOT_ID= +TEAMS_APP_ID= +BOT_AZURE_APP_SERVICE_RESOURCE_ID= +BOT_DOMAIN= \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/env/.env.dev.user.tpl b/templates/js/custom-copilot-assistant-assistants-api/env/.env.dev.user.tpl new file mode 100644 index 0000000000..0c40fe9abe --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/env/.env.dev.user.tpl @@ -0,0 +1,11 @@ +# This file includes environment variables that will not be committed to git by default. You can set these environment variables in your CI/CD system for your project. + +# Secrets. Keys prefixed with `SECRET_` will be masked in Teams Toolkit logs. +SECRET_BOT_PASSWORD= +{{#openAIKey}} +SECRET_OPENAI_API_KEY='{{{openAIKey}}}' +{{/openAIKey}} +{{^openAIKey}} +SECRET_OPENAI_API_KEY=' ' +{{/openAIKey}} +SECRET_OPENAI_ASSISTANT_ID=' ' # See README.md for how to fill in this value. \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/env/.env.local b/templates/js/custom-copilot-assistant-assistants-api/env/.env.local new file mode 100644 index 0000000000..f3a75f8723 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/env/.env.local @@ -0,0 +1,11 @@ +# This file includes environment variables that can be committed to git. It's gitignored by default because it represents your local development environment. + +# Built-in environment variables +TEAMSFX_ENV=local +APP_NAME_SUFFIX=local + +# Generated during provision, you can also add your own variables. +BOT_ID= +TEAMS_APP_ID= +BOT_DOMAIN= +BOT_ENDPOINT= \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/env/.env.local.user.tpl b/templates/js/custom-copilot-assistant-assistants-api/env/.env.local.user.tpl new file mode 100644 index 0000000000..5a12d089b9 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/env/.env.local.user.tpl @@ -0,0 +1,12 @@ +# This file includes environment variables that will not be committed to git by default. You can set these environment variables in your CI/CD system for your project. + +# If you're adding a secret value, add SECRET_ prefix to the name so Teams Toolkit can handle them properly +# Secrets. Keys prefixed with `SECRET_` will be masked in Teams Toolkit logs. +SECRET_BOT_PASSWORD= +{{#openAIKey}} +SECRET_OPENAI_API_KEY='{{{openAIKey}}}' +{{/openAIKey}} +{{^openAIKey}} +SECRET_OPENAI_API_KEY=' ' +{{/openAIKey}} +SECRET_OPENAI_ASSISTANT_ID=' ' # See README.md for how to fill in this value. \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/env/.env.testtool b/templates/js/custom-copilot-assistant-assistants-api/env/.env.testtool new file mode 100644 index 0000000000..53abad07db --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/env/.env.testtool @@ -0,0 +1,8 @@ +# This file includes environment variables that can be committed to git. It's gitignored by default because it represents your local development environment. + +# Built-in environment variables +TEAMSFX_ENV=testtool + +# Environment variables used by test tool +TEAMSAPPTESTER_PORT=56150 +TEAMSFX_NOTIFICATION_STORE_FILENAME=.notification.testtoolstore.json \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/env/.env.testtool.user.tpl b/templates/js/custom-copilot-assistant-assistants-api/env/.env.testtool.user.tpl new file mode 100644 index 0000000000..15ee278c2b --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/env/.env.testtool.user.tpl @@ -0,0 +1,11 @@ +# This file includes environment variables that will not be committed to git by default. You can set these environment variables in your CI/CD system for your project. + +# If you're adding a secret value, add SECRET_ prefix to the name so Teams Toolkit can handle them properly +# Secrets. Keys prefixed with `SECRET_` will be masked in Teams Toolkit logs. +{{#openAIKey}} +SECRET_OPENAI_API_KEY='{{{openAIKey}}}' +{{/openAIKey}} +{{^openAIKey}} +SECRET_OPENAI_API_KEY=' ' +{{/openAIKey}} +SECRET_OPENAI_ASSISTANT_ID=' ' # See README.md for how to fill in this value. \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/infra/azure.bicep b/templates/js/custom-copilot-assistant-assistants-api/infra/azure.bicep new file mode 100644 index 0000000000..a2feeed47a --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/infra/azure.bicep @@ -0,0 +1,96 @@ +@maxLength(20) +@minLength(4) +@description('Used to generate names for all resources in this file') +param resourceBaseName string + +@description('Required when create Azure Bot service') +param botAadAppClientId string + +@secure() +@description('Required by Bot Framework package in your bot project') +param botAadAppClientSecret string + +@secure() +param openAIKey string + +@secure() +param openAIAssistantId string + +param webAppSKU string + +@maxLength(42) +param botDisplayName string + +param serverfarmsName string = resourceBaseName +param webAppName string = resourceBaseName +param location string = resourceGroup().location + +// Compute resources for your Web App +resource serverfarm 'Microsoft.Web/serverfarms@2021-02-01' = { + kind: 'app' + location: location + name: serverfarmsName + sku: { + name: webAppSKU + } +} + +// Web App that hosts your bot +resource webApp 'Microsoft.Web/sites@2021-02-01' = { + kind: 'app' + location: location + name: webAppName + properties: { + serverFarmId: serverfarm.id + httpsOnly: true + siteConfig: { + alwaysOn: true + appSettings: [ + { + name: 'WEBSITE_RUN_FROM_PACKAGE' + value: '1' // Run Azure App Service from a package file + } + { + name: 'WEBSITE_NODE_DEFAULT_VERSION' + value: '~18' // Set NodeJS version to 18.x for your site + } + { + name: 'RUNNING_ON_AZURE' + value: '1' + } + { + name: 'BOT_ID' + value: botAadAppClientId + } + { + name: 'BOT_PASSWORD' + value: botAadAppClientSecret + } + { + name: 'OPENAI_API_KEY' + value: openAIKey + } + { + name: 'OPENAI_ASSISTANT_ID' + value: openAIAssistantId + } + ] + ftpsState: 'FtpsOnly' + } + } +} + +// Register your web service as a bot with the Bot Framework +module azureBotRegistration './botRegistration/azurebot.bicep' = { + name: 'Azure-Bot-registration' + params: { + resourceBaseName: resourceBaseName + botAadAppClientId: botAadAppClientId + botAppDomain: webApp.properties.defaultHostName + botDisplayName: botDisplayName + } +} + +// The output will be persisted in .env.{envName}. Visit https://aka.ms/teamsfx-actions/arm-deploy for more details. +output BOT_AZURE_APP_SERVICE_RESOURCE_ID string = webApp.id +output BOT_DOMAIN string = webApp.properties.defaultHostName diff --git a/templates/js/custom-copilot-assistant-assistants-api/infra/azure.parameters.json.tpl b/templates/js/custom-copilot-assistant-assistants-api/infra/azure.parameters.json.tpl new file mode 100644 index 0000000000..2be5c43052 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/infra/azure.parameters.json.tpl @@ -0,0 +1,27 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "resourceBaseName": { + "value": "bot${{RESOURCE_SUFFIX}}" + }, + "botAadAppClientId": { + "value": "${{BOT_ID}}" + }, + "botAadAppClientSecret": { + "value": "${{SECRET_BOT_PASSWORD}}" + }, + "openAIKey": { + "value": "${{SECRET_OPENAI_API_KEY}}" + }, + "openAIAssistantId": { + "value": "${{SECRET_OPENAI_ASSISTANT_ID}}" + }, + "webAppSKU": { + "value": "B1" + }, + "botDisplayName": { + "value": "{{appName}}" + } + } +} \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/infra/botRegistration/azurebot.bicep b/templates/js/custom-copilot-assistant-assistants-api/infra/botRegistration/azurebot.bicep new file mode 100644 index 0000000000..ab67c7a56b --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/infra/botRegistration/azurebot.bicep @@ -0,0 +1,37 @@ +@maxLength(20) +@minLength(4) +@description('Used to generate names for all resources in this file') +param resourceBaseName string + +@maxLength(42) +param botDisplayName string + +param botServiceName string = resourceBaseName +param botServiceSku string = 'F0' +param botAadAppClientId string +param botAppDomain string + +// Register your web service as a bot with the Bot Framework +resource botService 'Microsoft.BotService/botServices@2021-03-01' = { + kind: 'azurebot' + location: 'global' + name: botServiceName + properties: { + displayName: botDisplayName + endpoint: 'https://${botAppDomain}/api/messages' + msaAppId: botAadAppClientId + } + sku: { + name: botServiceSku + } +} + +// Connect the bot service to Microsoft Teams +resource botServiceMsTeamsChannel 'Microsoft.BotService/botServices/channels@2021-03-01' = { + parent: botService + location: 'global' + name: 'MsTeamsChannel' + properties: { + channelName: 'MsTeamsChannel' + } +} diff --git a/templates/js/custom-copilot-assistant-assistants-api/infra/botRegistration/readme.md b/templates/js/custom-copilot-assistant-assistants-api/infra/botRegistration/readme.md new file mode 100644 index 0000000000..d5416243cd --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/infra/botRegistration/readme.md @@ -0,0 +1 @@ +The `azurebot.bicep` module is provided to help you create Azure Bot service when you don't use Azure to host your app. If you use Azure as infrastrcture for your app, `azure.bicep` under infra folder already leverages this module to create Azure Bot service for you. You don't need to deploy `azurebot.bicep` again. \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/package.json.tpl b/templates/js/custom-copilot-assistant-assistants-api/package.json.tpl new file mode 100644 index 0000000000..d32337d813 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/package.json.tpl @@ -0,0 +1,37 @@ +{ + "name": "{{SafeProjectNameLowerCase}}", + "version": "1.0.0", + "msteams": { + "teamsAppId": null + }, + "description": "Microsoft Teams Toolkit AI Assistant Bot sample with OpenAI Assistants API and Teams AI Library's built-in coordination", + "engines": { + "node": "16 || 18" + }, + "author": "Microsoft", + "license": "MIT", + "main": "./src/index.js", + "scripts": { + "dev:teamsfx": "env-cmd --silent -f .localConfigs npm run dev", + "dev:teamsfx:testtool": "env-cmd --silent -f .localConfigs.testTool npm run dev", + "dev:teamsfx:launch-testtool": "env-cmd --silent -f env/.env.testtool teamsapptester start", + "dev": "nodemon --inspect=9239 --signal SIGINT ./src/index.js", + "start": "node ./src/index.js", + "test": "echo \"Error: no test specified\" && exit 1", + "watch": "nodemon --exec \"npm run start\"", + "assistant:create": "node ./src/creator.js" + }, + "repository": { + "type": "git", + "url": "https://github.com" + }, + "dependencies": { + "@microsoft/teams-ai": "^1.1.0", + "botbuilder": "^4.20.0", + "restify": "^10.0.0" + }, + "devDependencies": { + "env-cmd": "^10.1.0", + "nodemon": "^2.0.7" + } +} \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/src/adapter.js b/templates/js/custom-copilot-assistant-assistants-api/src/adapter.js new file mode 100644 index 0000000000..c0929d1888 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/src/adapter.js @@ -0,0 +1,50 @@ +// Import required bot services. +// See https://aka.ms/bot-services to learn more about the different parts of a bot. +const { + CloudAdapter, + ConfigurationServiceClientCredentialFactory, + ConfigurationBotFrameworkAuthentication, +} = require("botbuilder"); + +const config = require("./config"); + +const botFrameworkAuthentication = new ConfigurationBotFrameworkAuthentication( + {}, + new ConfigurationServiceClientCredentialFactory({ + MicrosoftAppId: config.botId, + MicrosoftAppPassword: process.env.BOT_PASSWORD, + MicrosoftAppType: "MultiTenant", + }) +); + +// Create adapter. +// See https://aka.ms/about-bot-adapter to learn more about how bots work. +const adapter = new CloudAdapter(botFrameworkAuthentication); + +// Catch-all for errors. +const onTurnErrorHandler = async (context, error) => { + // This check writes out errors to console log .vs. app insights. + // NOTE: In production environment, you should consider logging this to Azure + // application insights. + console.error(`\n [onTurnError] unhandled error: ${error}`); + + // Only send error message for user messages, not for other message types so the bot doesn't spam a channel or chat. + if (context.activity.type === "message") { + // Send a trace activity, which will be displayed in Bot Framework Emulator + await context.sendTraceActivity( + "OnTurnError Trace", + `${error}`, + "https://www.botframework.com/schemas/error", + "TurnError" + ); + + // Send a message to the user + await context.sendActivity("The bot encountered an error or bug."); + await context.sendActivity("To continue to run this bot, please fix the bot source code."); + } +}; + +// Set the onTurnError for the singleton CloudAdapter. +adapter.onTurnError = onTurnErrorHandler; + +module.exports = adapter; diff --git a/templates/js/custom-copilot-assistant-assistants-api/src/app/actions.js b/templates/js/custom-copilot-assistant-assistants-api/src/app/actions.js new file mode 100644 index 0000000000..fbcea6e12c --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/src/app/actions.js @@ -0,0 +1,40 @@ +const { AI } = require("@microsoft/teams-ai"); + +async function httpErrorAction(context, state, data) { + await context.sendActivity("An AI request failed. Please try again later."); + return AI.StopCommandName; +} + +async function getCurrentWeather(context, state, parameters) { + const weatherData = { + "San Francisco, CA": { + f: "71.6F", + c: "22C", + }, + "Los Angeles": { + f: "75.2F", + c: "24C", + }, + }; + + if (weatherData[parameters.location] === undefined) { + return `No weather data for ${location} found`; + } + + return weatherData[parameters.location][parameters.unit ?? "f"]; +} + +async function getNickname(context, state, parameters) { + const nicknames = { + "San Francisco": "The Golden City", + "Los Angeles": "LA", + }; + + return nicknames[parameters.location] ?? `No nickname for ${location} found`; +} + +module.exports = { + httpErrorAction, + getCurrentWeather, + getNickname, +}; diff --git a/templates/js/custom-copilot-assistant-assistants-api/src/app/app.js b/templates/js/custom-copilot-assistant-assistants-api/src/app/app.js new file mode 100644 index 0000000000..83d9521289 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/src/app/app.js @@ -0,0 +1,39 @@ +const { MemoryStorage } = require("botbuilder"); +const config = require("../config"); + +// See https://aka.ms/teams-ai-library to learn more about the Teams AI library. +const { Application, AI, preview } = require("@microsoft/teams-ai"); + +// See README.md to prepare your own OpenAI Assistant +if (!config.openAIKey || !config.openAIAssistantId) { + throw new Error( + "Missing OPENAI_API_KEY or OPENAI_ASSISTANT_ID. See README.md to prepare your own OpenAI Assistant." + ); +} + +const { resetMessage } = require("./messages"); +const { httpErrorAction, getCurrentWeather, getNickname } = require("./actions"); + +// Create AI components +// Use OpenAI +const planner = new preview.AssistantsPlanner({ + apiKey: config.openAIKey, + assistant_id: config.openAIAssistantId, +}); + +// Define storage and application +const storage = new MemoryStorage(); +const app = new Application({ + storage, + ai: { + planner, + }, +}); + +app.message("/reset", resetMessage); + +app.ai.action(AI.HttpErrorActionName, httpErrorAction); +app.ai.action("getCurrentWeather", getCurrentWeather); +app.ai.action("getNickname", getNickname); + +module.exports = app; diff --git a/templates/js/custom-copilot-assistant-assistants-api/src/app/messages.js b/templates/js/custom-copilot-assistant-assistants-api/src/app/messages.js new file mode 100644 index 0000000000..2395080053 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/src/app/messages.js @@ -0,0 +1,8 @@ +async function resetMessage(context, state) { + state.deleteConversationState(); + await context.sendActivity("Ok lets start this over."); +} + +module.exports = { + resetMessage, +}; diff --git a/templates/js/custom-copilot-assistant-assistants-api/src/config.js b/templates/js/custom-copilot-assistant-assistants-api/src/config.js new file mode 100644 index 0000000000..ae6ce88733 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/src/config.js @@ -0,0 +1,8 @@ +const config = { + botId: process.env.BOT_ID, + botPassword: process.env.BOT_PASSWORD, + openAIKey: process.env.OPENAI_API_KEY, + openAIAssistantId: process.env.OPENAI_ASSISTANT_ID, +}; + +module.exports = config; diff --git a/templates/js/custom-copilot-assistant-assistants-api/src/creator.js b/templates/js/custom-copilot-assistant-assistants-api/src/creator.js new file mode 100644 index 0000000000..f99f9cff2f --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/src/creator.js @@ -0,0 +1,64 @@ +const { preview } = require("@microsoft/teams-ai"); + +const openAIKey = process.argv[2]; +if (!openAIKey) { + throw new Error("Missing input OpenAI Key"); +} + +// Create new Assistant +(async () => { + const assistant = await preview.AssistantsPlanner.createAssistant(openAIKey, { + name: "Assistant", + instructions: [ + "You are an intelligent bot that can", + "- write and run code to answer math questions", + "- use the provided functions to answer questions", + ].join("\n"), + tools: [ + { + type: "code_interpreter", + }, + { + type: "function", + function: { + name: "getCurrentWeather", + description: "Get the weather in location", + parameters: { + type: "object", + properties: { + location: { + type: "string", + description: "The city and state e.g. San Francisco, CA", + }, + unit: { + type: "string", + enum: ["c", "f"], + }, + }, + required: ["location"], + }, + }, + }, + { + type: "function", + function: { + name: "getNickname", + description: "Get the nickname of a city", + parameters: { + type: "object", + properties: { + location: { + type: "string", + description: "The city and state e.g. San Francisco, CA", + }, + }, + required: ["location"], + }, + }, + }, + ], + model: "gpt-3.5-turbo", + }); + + console.log(`Created a new assistant with an ID of: ${assistant.id}`); +})(); diff --git a/templates/js/custom-copilot-assistant-assistants-api/src/index.js b/templates/js/custom-copilot-assistant-assistants-api/src/index.js new file mode 100644 index 0000000000..d1e686f00d --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/src/index.js @@ -0,0 +1,25 @@ +// Import required packages +const restify = require("restify"); + +// This bot's adapter +const adapter = require("./adapter"); + +// This bot's main dialog. +const app = require("./app/app"); + +// Create HTTP server. +const server = restify.createServer(); +server.use(restify.plugins.bodyParser()); + +server.listen(process.env.port || process.env.PORT || 3978, () => { + console.log(`\nBot Started, ${server.name} listening to ${server.url}`); +}); + +// Listen for incoming server requests. +server.post("/api/messages", async (req, res) => { + // Route received a request to adapter for processing + await adapter.process(req, res, async (context) => { + // Dispatch to application for routing + await app.run(context); + }); +}); diff --git a/templates/js/custom-copilot-assistant-assistants-api/teamsapp.local.yml.tpl b/templates/js/custom-copilot-assistant-assistants-api/teamsapp.local.yml.tpl new file mode 100644 index 0000000000..1e877247d9 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/teamsapp.local.yml.tpl @@ -0,0 +1,80 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/1.0.0/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: 1.0.0 + +provision: + # Creates a Teams app + - uses: teamsApp/create + with: + # Teams app name + name: {{appName}}${{APP_NAME_SUFFIX}} + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + teamsAppId: TEAMS_APP_ID + + # Create or reuse an existing Microsoft Entra application for bot. + - uses: botAadApp/create + with: + # The Microsoft Entra application's display name + name: {{appName}}${{APP_NAME_SUFFIX}} + writeToEnvironmentFile: + # The Microsoft Entra application's client id created for bot. + botId: BOT_ID + # The Microsoft Entra application's client secret created for bot. + botPassword: SECRET_BOT_PASSWORD + + # Create or update the bot registration on dev.botframework.com + - uses: botFramework/create + with: + botId: ${{BOT_ID}} + name: {{appName}} + messagingEndpoint: ${{BOT_ENDPOINT}}/api/messages + description: "" + channels: + - name: msteams + + # Validate using manifest schema + - uses: teamsApp/validateManifest + with: + # Path to manifest template + manifestPath: ./appPackage/manifest.json + + # 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 + outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json + # 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 + +deploy: + # Run npm command + - uses: cli/runNpmCommand + name: install dependencies + with: + args: install --no-audit + + # Generate runtime environment variables + - uses: file/createOrUpdateEnvironmentFile + with: + target: ./.localConfigs + envs: + BOT_ID: ${{BOT_ID}} + BOT_PASSWORD: ${{SECRET_BOT_PASSWORD}} + OPENAI_API_KEY: ${{SECRET_OPENAI_API_KEY}} + OPENAI_ASSISTANT_ID: ${{SECRET_OPENAI_ASSISTANT_ID}} \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/teamsapp.testtool.yml b/templates/js/custom-copilot-assistant-assistants-api/teamsapp.testtool.yml new file mode 100644 index 0000000000..e53a7bc322 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/teamsapp.testtool.yml @@ -0,0 +1,26 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.3/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.3 + +deploy: + # Install development tool(s) + - uses: devTool/install + with: + testTool: + version: ~0.1.0-beta + symlinkDir: ./devTools/teamsapptester + + # Run npm command + - uses: cli/runNpmCommand + with: + args: install --no-audit + + # Generate runtime environment variables + - uses: file/createOrUpdateEnvironmentFile + with: + target: ./.localConfigs.testTool + envs: + OPENAI_API_KEY: ${{SECRET_OPENAI_API_KEY}} + OPENAI_ASSISTANT_ID: ${{SECRET_OPENAI_ASSISTANT_ID}} + TEAMSFX_NOTIFICATION_STORE_FILENAME: ${{TEAMSFX_NOTIFICATION_STORE_FILENAME}} \ No newline at end of file diff --git a/templates/js/custom-copilot-assistant-assistants-api/teamsapp.yml.tpl b/templates/js/custom-copilot-assistant-assistants-api/teamsapp.yml.tpl new file mode 100644 index 0000000000..ad88b620cc --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/teamsapp.yml.tpl @@ -0,0 +1,141 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/1.0.0/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: 1.0.0 + +environmentFolderPath: ./env + +# Triggered when 'teamsapp provision' is executed +provision: + # Creates a Teams app + - uses: teamsApp/create + with: + # Teams app name + name: {{appName}}${{APP_NAME_SUFFIX}} + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + teamsAppId: TEAMS_APP_ID + + # Create or reuse an existing Microsoft Entra application for bot. + - uses: botAadApp/create + with: + # The Microsoft Entra application's display name + name: {{appName}}${{APP_NAME_SUFFIX}} + writeToEnvironmentFile: + # The Microsoft Entra application's client id created for bot. + botId: BOT_ID + # The Microsoft Entra application's client secret created for bot. + botPassword: SECRET_BOT_PASSWORD + + - uses: arm/deploy # Deploy given ARM templates parallelly. + with: + # AZURE_SUBSCRIPTION_ID is a built-in environment variable, + # if its value is empty, TeamsFx will prompt you to select a subscription. + # Referencing other environment variables with empty values + # will skip the subscription selection prompt. + subscriptionId: ${{AZURE_SUBSCRIPTION_ID}} + # AZURE_RESOURCE_GROUP_NAME is a built-in environment variable, + # if its value is empty, TeamsFx will prompt you to select or create one + # resource group. + # Referencing other environment variables with empty values + # will skip the resource group selection prompt. + resourceGroupName: ${{AZURE_RESOURCE_GROUP_NAME}} + templates: + - path: ./infra/azure.bicep # Relative path to this file + # Relative path to this yaml file. + # Placeholders will be replaced with corresponding environment + # variable before ARM deployment. + parameters: ./infra/azure.parameters.json + # Required when deploying ARM template + deploymentName: Create-resources-for-bot + # Teams Toolkit will download this bicep CLI version from github for you, + # will use bicep CLI in PATH if you remove this config. + bicepCliVersion: v0.9.1 + + # Validate using manifest schema + - uses: teamsApp/validateManifest + with: + # Path to manifest template + manifestPath: ./appPackage/manifest.json + # 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 + outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json + # 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 + +# Triggered when 'teamsapp deploy' is executed +deploy: + # Run npm command + - uses: cli/runNpmCommand + name: install dependencies + with: + args: install + - uses: cli/runNpmCommand + name: build app + with: + args: run build --if-present + # Deploy your application to Azure App Service using the zip deploy feature. + # For additional details, refer to https://aka.ms/zip-deploy-to-app-services. + - uses: azureAppService/zipDeploy + with: + # Deploy base folder + artifactFolder: . + # Ignore file location, leave blank will ignore nothing + ignoreFile: .webappignore + # The resource id of the cloud resource to be deployed to. + # This key will be generated by arm/deploy action automatically. + # You can replace it with your existing Azure Resource id + # or add it to your environment variable file. + resourceId: ${{BOT_AZURE_APP_SERVICE_RESOURCE_ID}} + +# Triggered when 'teamsapp publish' is executed +publish: + # Validate using manifest schema + - uses: teamsApp/validateManifest + with: + # Path to manifest template + manifestPath: ./appPackage/manifest.json + # 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 + outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json + # 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/templates/js/custom-copilot-assistant-assistants-api/web.config b/templates/js/custom-copilot-assistant-assistants-api/web.config new file mode 100644 index 0000000000..0c09f2f869 --- /dev/null +++ b/templates/js/custom-copilot-assistant-assistants-api/web.config @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/.gitignore b/templates/ts/custom-copilot-assistant-assistants-api/.gitignore new file mode 100644 index 0000000000..0a23a2bb0e --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/.gitignore @@ -0,0 +1,24 @@ +# TeamsFx files +env/.env.*.user +env/.env.local +appPackage/build + +# dependencies +node_modules/ + +# misc +.env +.deployment +.DS_Store + +# build +lib/ + +# devTools +devTools/ + +# Local data +.localConfigs +.localConfigs.testTool +.notification.localstore.json +.notification.testtoolstore.json \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/.localConfigs b/templates/ts/custom-copilot-assistant-assistants-api/.localConfigs new file mode 100644 index 0000000000..4c5c0a4f9f --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/.localConfigs @@ -0,0 +1,5 @@ +# A gitignored place holder file for local runtime configurations +BOT_ID= +BOT_PASSWORD= +OPENAI_API_KEY= +OPENAI_ASSISTANT_ID= \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/.localConfigs.testTool b/templates/ts/custom-copilot-assistant-assistants-api/.localConfigs.testTool new file mode 100644 index 0000000000..0354f77cc9 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/.localConfigs.testTool @@ -0,0 +1,6 @@ +# A gitignored place holder file for local runtime configurations +BOT_ID= +BOT_PASSWORD= +OPENAI_API_KEY= +OPENAI_ASSISTANT_ID= +TEAMSFX_NOTIFICATION_STORE_FILENAME=.notification.testtoolstore.json diff --git a/templates/ts/custom-copilot-assistant-assistants-api/.vscode/extensions.json b/templates/ts/custom-copilot-assistant-assistants-api/.vscode/extensions.json new file mode 100644 index 0000000000..1b70a39308 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "TeamsDevApp.ms-teams-vscode-extension" + ] +} \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/.vscode/launch.json.tpl b/templates/ts/custom-copilot-assistant-assistants-api/.vscode/launch.json.tpl new file mode 100644 index 0000000000..9e3b45ee1f --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/.vscode/launch.json.tpl @@ -0,0 +1,122 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Remote (Edge)", + "type": "msedge", + "request": "launch", + "url": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}", + "presentation": { + "group": "3-remote", + "order": 1 + }, + "internalConsoleOptions": "neverOpen" + }, + { + "name": "Launch Remote (Chrome)", + "type": "chrome", + "request": "launch", + "url": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}", + "presentation": { + "group": "3-remote", + "order": 2 + }, + "internalConsoleOptions": "neverOpen" + }, + { + "name": "Launch App (Edge)", + "type": "msedge", + "request": "launch", + "url": "https://teams.microsoft.com/l/app/${{local:TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}", + "cascadeTerminateToConfigurations": [ + "Attach to Local Service" + ], + "presentation": { + "group": "all", + "hidden": true + }, + "internalConsoleOptions": "neverOpen" + }, + { + "name": "Launch App (Chrome)", + "type": "chrome", + "request": "launch", + "url": "https://teams.microsoft.com/l/app/${{local:TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}", + "cascadeTerminateToConfigurations": [ + "Attach to Local Service" + ], + "presentation": { + "group": "all", + "hidden": true + }, + "internalConsoleOptions": "neverOpen" + }, + { + "name": "Attach to Local Service", + "type": "node", + "request": "attach", + "port": 9239, + "restart": true, + "presentation": { + "group": "all", + "hidden": true + }, + "internalConsoleOptions": "neverOpen" + } + ], + "compounds": [ + { + "name": "Debug in Teams (Edge)", + "configurations": [ + "Launch App (Edge)", + "Attach to Local Service" + ], + "preLaunchTask": "Start Teams App Locally", + "presentation": { +{{#enableTestToolByDefault}} + "group": "2-local", +{{/enableTestToolByDefault}} +{{^enableTestToolByDefault}} + "group": "1-local", +{{/enableTestToolByDefault}} + "order": 1 + }, + "stopAll": true + }, + { + "name": "Debug in Teams (Chrome)", + "configurations": [ + "Launch App (Chrome)", + "Attach to Local Service" + ], + "preLaunchTask": "Start Teams App Locally", + "presentation": { +{{#enableTestToolByDefault}} + "group": "2-local", +{{/enableTestToolByDefault}} +{{^enableTestToolByDefault}} + "group": "1-local", +{{/enableTestToolByDefault}} + "order": 2 + }, + "stopAll": true + }, + { + "name": "Debug in Test Tool (Preview)", + "configurations": [ + "Attach to Local Service" + ], + "preLaunchTask": "Start Teams App (Test Tool)", + "presentation": { +{{#enableTestToolByDefault}} + "group": "1-local", +{{/enableTestToolByDefault}} +{{^enableTestToolByDefault}} + "group": "2-local", +{{/enableTestToolByDefault}} + "order": 1 + }, + "stopAll": true + } + ] +} diff --git a/templates/ts/custom-copilot-assistant-assistants-api/.vscode/settings.json b/templates/ts/custom-copilot-assistant-assistants-api/.vscode/settings.json new file mode 100644 index 0000000000..0d3ba10b02 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "debug.onTaskErrors": "abort", + "json.schemas": [ + { + "fileMatch": [ + "/aad.*.json" + ], + "schema": {} + } + ] +} \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/.vscode/tasks.json b/templates/ts/custom-copilot-assistant-assistants-api/.vscode/tasks.json new file mode 100644 index 0000000000..1c3e241f27 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/.vscode/tasks.json @@ -0,0 +1,204 @@ +// This file is automatically generated by Teams Toolkit. +// The teamsfx tasks defined in this file require Teams Toolkit version >= 5.0.0. +// See https://aka.ms/teamsfx-tasks for details on how to customize each task. +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Start Teams App (Test Tool)", + "dependsOn": [ + "Validate prerequisites (Test Tool)", + "Deploy (Test Tool)", + "Start application (Test Tool)", + "Start Test Tool", + ], + "dependsOrder": "sequence" + }, + { + // Check all required prerequisites. + // See https://aka.ms/teamsfx-tasks/check-prerequisites to know the details and how to customize the args. + "label": "Validate prerequisites (Test Tool)", + "type": "teamsfx", + "command": "debug-check-prerequisites", + "args": { + "prerequisites": [ + "nodejs", // Validate if Node.js is installed. + "portOccupancy" // Validate available ports to ensure those debug ones are not occupied. + ], + "portOccupancy": [ + 3978, // app service port + 9239, // app inspector port for Node.js debugger + 56150, // test tool port + ] + } + }, + { + // Build project. + // See https://aka.ms/teamsfx-tasks/deploy to know the details and how to customize the args. + "label": "Deploy (Test Tool)", + "type": "teamsfx", + "command": "deploy", + "args": { + "env": "testtool", + } + }, + { + "label": "Start application (Test Tool)", + "type": "shell", + "command": "npm run dev:teamsfx:testtool", + "isBackground": true, + "options": { + "cwd": "${workspaceFolder}", + }, + "problemMatcher": { + "pattern": [ + { + "regexp": "^.*$", + "file": 0, + "location": 1, + "message": 2 + } + ], + "background": { + "activeOnStart": true, + "beginsPattern": "[nodemon] starting", + "endsPattern": "restify listening to|Bot/ME service listening at|[nodemon] app crashed" + } + } + }, + { + "label": "Start Test Tool", + "type": "shell", + "command": "npm run dev:teamsfx:launch-testtool", + "isBackground": true, + "options": { + "env": { + "PATH": "${workspaceFolder}/devTools/teamsapptester/node_modules/.bin:${env:PATH}" + } + }, + "windows": { + "options": { + "env": { + "PATH": "${workspaceFolder}/devTools/teamsapptester/node_modules/.bin;${env:PATH}" + } + } + }, + "problemMatcher": { + "pattern": [ + { + "regexp": "^.*$", + "file": 0, + "location": 1, + "message": 2 + } + ], + "background": { + "activeOnStart": true, + "beginsPattern": ".*", + "endsPattern": "Listening on" + } + }, + "presentation": { + "panel": "dedicated", + "reveal": "silent" + } + }, + { + "label": "Start Teams App Locally", + "dependsOn": [ + "Validate prerequisites", + "Start local tunnel", + "Provision", + "Deploy", + "Start application" + ], + "dependsOrder": "sequence" + }, + { + // Check all required prerequisites. + // See https://aka.ms/teamsfx-tasks/check-prerequisites to know the details and how to customize the args. + "label": "Validate prerequisites", + "type": "teamsfx", + "command": "debug-check-prerequisites", + "args": { + "prerequisites": [ + "nodejs", // Validate if Node.js is installed. + "m365Account", // Sign-in prompt for Microsoft 365 account, then validate if the account enables the sideloading permission. + "portOccupancy" // Validate available ports to ensure those debug ones are not occupied. + ], + "portOccupancy": [ + 3978, // app service port + 9239 // app inspector port for Node.js debugger + ] + } + }, + { + // Start the local tunnel service to forward public URL to local port and inspect traffic. + // See https://aka.ms/teamsfx-tasks/local-tunnel for the detailed args definitions. + "label": "Start local tunnel", + "type": "teamsfx", + "command": "debug-start-local-tunnel", + "args": { + "type": "dev-tunnel", + "ports": [ + { + "portNumber": 3978, + "protocol": "http", + "access": "public", + "writeToEnvironmentFile": { + "endpoint": "BOT_ENDPOINT", // output tunnel endpoint as BOT_ENDPOINT + "domain": "BOT_DOMAIN" // output tunnel domain as BOT_DOMAIN + } + } + ], + "env": "local" + }, + "isBackground": true, + "problemMatcher": "$teamsfx-local-tunnel-watch" + }, + { + // Create the debug resources. + // See https://aka.ms/teamsfx-tasks/provision to know the details and how to customize the args. + "label": "Provision", + "type": "teamsfx", + "command": "provision", + "args": { + "env": "local" + } + }, + { + // Build project. + // See https://aka.ms/teamsfx-tasks/deploy to know the details and how to customize the args. + "label": "Deploy", + "type": "teamsfx", + "command": "deploy", + "args": { + "env": "local" + } + }, + { + "label": "Start application", + "type": "shell", + "command": "npm run dev:teamsfx", + "isBackground": true, + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": { + "pattern": [ + { + "regexp": "^.*$", + "file": 0, + "location": 1, + "message": 2 + } + ], + "background": { + "activeOnStart": true, + "beginsPattern": "[nodemon] starting", + "endsPattern": "restify listening to|Bot/ME service listening at|[nodemon] app crashed" + } + } + } + ] +} \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/.webappignore b/templates/ts/custom-copilot-assistant-assistants-api/.webappignore new file mode 100644 index 0000000000..3e9dfd4d90 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/.webappignore @@ -0,0 +1,27 @@ +.webappignore +.fx +.deployment +.localConfigs +.localConfigs.testTool +.notification.localstore.json +.notification.testtoolstore.json +.vscode +*.js.map +*.ts.map +*.ts +.git* +.tsbuildinfo +CHANGELOG.md +readme.md +local.settings.json +test +tsconfig.json +.DS_Store +teamsapp.yml +teamsapp.*.yml +/env/ +/node_modules/.bin +/node_modules/ts-node +/node_modules/typescript +/appPackage/ +/infra/ \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/README.md.tpl b/templates/ts/custom-copilot-assistant-assistants-api/README.md.tpl new file mode 100644 index 0000000000..d46844de92 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/README.md.tpl @@ -0,0 +1,124 @@ +# Overview of the AI Assistant Bot template + +This app template is built on top of [Teams AI library](https://aka.ms/teams-ai-library) and [OpenAI Assistants API](https://platform.openai.com/docs/assistants/overview). +It showcases how to build an intelligent chat bot in Teams capable of helping users accomplish specific tasks using natural language right in the Teams conversations, such as solving a math problem, call functions to get city weather, etc. + +- [Overview of the AI Assistant Bot template](#overview-of-the-ai-assistant-bot-template) + - [Get started with the AI Assistant Bot template](#get-started-with-the-ai-assistant-bot-template) + - [What's included in the template](#whats-included-in-the-template) + - [Extend the AI Assistant Bot template with more AI capabilities](#extend-the-ai-assistant-bot-template-with-more-ai-capabilities) + - [Additional information and references](#additional-information-and-references) + +## Get started with the AI Assistant Bot template + +> **Prerequisites** +> +> To run the AI Assistant Bot template in your local dev machine, you will need: +> +> - [Node.js](https://nodejs.org/), supported versions: 16, 18 +{{^enableTestToolByDefault}} +> - A [Microsoft 365 account for development](https://docs.microsoft.com/microsoftteams/platform/toolkit/accounts) +{{/enableTestToolByDefault}} +> - [Teams Toolkit Visual Studio Code Extension](https://aka.ms/teams-toolkit) version 5.0.0 and higher or [Teams Toolkit CLI](https://aka.ms/teamsfx-toolkit-cli) +> - An account with [OpenAI](https://platform.openai.com/). +> +> **Note** +> +> The `AssistantsPlanner` in Teams AI Library is currently in preview version. + +### Create your own OpenAI Assistant + +Before running or debugging your bot, please follow these steps to setup your own [OpenAI Assistant](https://platform.openai.com/docs/assistants/overview). + +**If you haven't setup any Assistant yet** + +> This app template provides script `src/creator.ts` to help create assistant. You can change the instructions and settings in the script to customize the assistant. +> +> After creation, you can change and manage your assistants on [OpenAI](https://platform.openai.com/assistants). + +1. Open terminal and run command `npm install` to install all dependency packages + + ``` + > npm install + ``` +1. After `npm install` completed, run command `npm run assistant:create -- ` + ``` + > npm run assistant:create -- xxxxxx + ``` +1. The above command will output something like "*Created a new assistant with an ID of: **asst_xxx...***" +1. Fill in both OpenAI API Key and the created Assistant ID into `env/.env.*.user` + ``` + SECRET_OPENAI_API_KEY= + SECRET_OPENAI_ASSISTANT_ID= + ``` + +**If you already have an Assistant created** + +1. Fill in both OpenAI API Key and the created Assistant ID into `env/.env.*.user` + ``` + SECRET_OPENAI_API_KEY= + SECRET_OPENAI_ASSISTANT_ID= + ``` + +### Run Teams Bot locally + +1. First, select the Teams Toolkit icon on the left in the VS Code toolbar. +{{#enableTestToolByDefault}} +1. Press F5 to start debugging which launches your app in Teams App Test Tool using a web browser. Select `Debug in Test Tool (Preview)`. +1. You can send any message to get a response from the bot. + +**Congratulations**! You are running an application that can now interact with users in Teams App Test Tool: + +![ai assistant bot in Teams App Test Tool](https://github.com/OfficeDev/TeamsFx/assets/37978464/e3b458f3-5e74-460d-9df2-bf77ed8d9c54) +{{/enableTestToolByDefault}} +{{^enableTestToolByDefault}} +1. In the Account section, sign in with your [Microsoft 365 account](https://docs.microsoft.com/microsoftteams/platform/toolkit/accounts) if you haven't yet. +1. Press F5 to start debugging which launches your app in Teams using a web browser. Select `Debug in Teams (Edge)` or `Debug in Teams (Chrome)`. +1. When Teams launches in the browser, select the Add button in the dialog to install your app to Teams. +1. You can send any message to get a response from the bot. + +**Congratulations**! You are running an application that can now interact with users in Teams: + +![ai assistant bot in Teams](https://github.com/OfficeDev/TeamsFx/assets/37978464/ccff0457-726a-486b-9247-c7f53e0a80ab) +{{/enableTestToolByDefault}} + +## What's included in the template + +| Folder | Contents | +| - | - | +| `.vscode` | VSCode files for debugging | +| `appPackage` | Templates for the Teams application manifest | +| `env` | Environment files | +| `infra` | Templates for provisioning Azure resources | +| `src` | The source code for the application | + +The following files can be customized and demonstrate an example implementation to get you started. + +| File | Contents | +| - | - | +|`src/index.ts`| Sets up the bot app server.| +|`src/adapter.ts`| Sets up the bot adapter.| +|`src/config.ts`| Defines the environment variables.| +|`src/creator.ts`| One-time tool to create OpenAI Assistant.| +|`src/app/app.ts`| Handles business logics for the AI Assistant Bot.| +|`src/app/messages.ts`| Defines the message activity handlers.| +|`src/app/actions.ts`| Defines the AI actions.| + +The following are Teams 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 Teams Toolkit works. + +| File | Contents | +| - | - | +|`teamsapp.yml`|This is the main Teams Toolkit project file. The project file defines two primary things: Properties and configuration Stage definitions. | +|`teamsapp.local.yml`|This overrides `teamsapp.yml` with actions that enable local execution and debugging.| +|`teamsapp.testtool.yml`|This overrides `teamsapp.yml` with actions that enable local execution and debugging in Teams App Test Tool.| + +## Extend the AI Assistant Bot template with more AI capabilities + +You can follow [AI assistant bot in Teams](https://aka.ms/teamsfx-ai-assistant-bot) to extend the AI Assistant Bot template with more AI capabilities. + +## Additional information and references +- [Teams AI library](https://aka.ms/teams-ai-library) +- [Teams Toolkit Documentations](https://docs.microsoft.com/microsoftteams/platform/toolkit/teams-toolkit-fundamentals) +- [Teams Toolkit CLI](https://aka.ms/teamsfx-toolkit-cli) +- [Teams Toolkit Samples](https://github.com/OfficeDev/TeamsFx-Samples) +- [OpenAI Assistants API](https://platform.openai.com/docs/assistants/overview) \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/appPackage/color.png b/templates/ts/custom-copilot-assistant-assistants-api/appPackage/color.png new file mode 100644 index 0000000000000000000000000000000000000000..2d7e85c9e9886c96e20fbb469c3c196ae8b5de42 GIT binary patch literal 5131 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 literal 0 HcmV?d00001 diff --git a/templates/ts/custom-copilot-assistant-assistants-api/appPackage/manifest.json.tpl b/templates/ts/custom-copilot-assistant-assistants-api/appPackage/manifest.json.tpl new file mode 100644 index 0000000000..85018e9501 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/appPackage/manifest.json.tpl @@ -0,0 +1,43 @@ +{ + "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.16/MicrosoftTeams.schema.json", + "manifestVersion": "1.16", + "version": "1.0.0", + "id": "${{TEAMS_APP_ID}}", + "packageName": "com.microsoft.teams.extension", + "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": "{{appName}}${{APP_NAME_SUFFIX}}", + "full": "full name for {{appName}}" + }, + "description": { + "short": "short description for {{appName}}", + "full": "full description for {{appName}}" + }, + "accentColor": "#FFFFFF", + "bots": [ + { + "botId": "${{BOT_ID}}", + "scopes": [ + "personal" + ], + "supportsFiles": false, + "isNotificationOnly": false + } + ], + "composeExtensions": [], + "configurableTabs": [], + "staticTabs": [], + "permissions": [ + "identity" + ], + "validDomains": [] +} \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/appPackage/outline.png b/templates/ts/custom-copilot-assistant-assistants-api/appPackage/outline.png new file mode 100644 index 0000000000000000000000000000000000000000..245fa194db6e08d30511fdbf26aec3c6e2c3c3c8 GIT binary patch literal 327 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?3oVGw3ym^DWND9BhG z9;9t*EM+Qm zy2D^Lfp=fIpwQyAe|y)?x-or<+J~Ptr@l6Mq%piHi4jOQ$W@+cm^^pek{T^R1~YT6 z#nC6He`LE*@cXCq-bL3hdgYxF$=uQYd!tVN6U(~0f70B<4PQ*lTGqqND0QE8cCxF; zrA^=emkHKQ+WI8@(#FJB4wBw$4jk;^oXcu!J2!Q;MX2;5u|xv~4xueIx7{LTWE)P* zx>U9|_qXolm|MHJvl^rhh$n1mem7%r%A<3y&veM1y2!zda7l7b Ve3c}0;w{jh44$rjF6*2UngINOfUy7o literal 0 HcmV?d00001 diff --git a/templates/ts/custom-copilot-assistant-assistants-api/env/.env.dev b/templates/ts/custom-copilot-assistant-assistants-api/env/.env.dev new file mode 100644 index 0000000000..4b07861c03 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/env/.env.dev @@ -0,0 +1,16 @@ +# This file includes environment variables that will be committed to git by default. + +# Built-in environment variables +TEAMSFX_ENV=dev +APP_NAME_SUFFIX=dev + +# Updating AZURE_SUBSCRIPTION_ID or AZURE_RESOURCE_GROUP_NAME after provision may also require an update to RESOURCE_SUFFIX, because some services require a globally unique name across subscriptions/resource groups. +AZURE_SUBSCRIPTION_ID= +AZURE_RESOURCE_GROUP_NAME= +RESOURCE_SUFFIX= + +# Generated during provision, you can also add your own variables. +BOT_ID= +TEAMS_APP_ID= +BOT_AZURE_APP_SERVICE_RESOURCE_ID= +BOT_DOMAIN= \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/env/.env.dev.user.tpl b/templates/ts/custom-copilot-assistant-assistants-api/env/.env.dev.user.tpl new file mode 100644 index 0000000000..0c40fe9abe --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/env/.env.dev.user.tpl @@ -0,0 +1,11 @@ +# This file includes environment variables that will not be committed to git by default. You can set these environment variables in your CI/CD system for your project. + +# Secrets. Keys prefixed with `SECRET_` will be masked in Teams Toolkit logs. +SECRET_BOT_PASSWORD= +{{#openAIKey}} +SECRET_OPENAI_API_KEY='{{{openAIKey}}}' +{{/openAIKey}} +{{^openAIKey}} +SECRET_OPENAI_API_KEY=' ' +{{/openAIKey}} +SECRET_OPENAI_ASSISTANT_ID=' ' # See README.md for how to fill in this value. \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/env/.env.local b/templates/ts/custom-copilot-assistant-assistants-api/env/.env.local new file mode 100644 index 0000000000..f3a75f8723 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/env/.env.local @@ -0,0 +1,11 @@ +# This file includes environment variables that can be committed to git. It's gitignored by default because it represents your local development environment. + +# Built-in environment variables +TEAMSFX_ENV=local +APP_NAME_SUFFIX=local + +# Generated during provision, you can also add your own variables. +BOT_ID= +TEAMS_APP_ID= +BOT_DOMAIN= +BOT_ENDPOINT= \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/env/.env.local.user.tpl b/templates/ts/custom-copilot-assistant-assistants-api/env/.env.local.user.tpl new file mode 100644 index 0000000000..5a12d089b9 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/env/.env.local.user.tpl @@ -0,0 +1,12 @@ +# This file includes environment variables that will not be committed to git by default. You can set these environment variables in your CI/CD system for your project. + +# If you're adding a secret value, add SECRET_ prefix to the name so Teams Toolkit can handle them properly +# Secrets. Keys prefixed with `SECRET_` will be masked in Teams Toolkit logs. +SECRET_BOT_PASSWORD= +{{#openAIKey}} +SECRET_OPENAI_API_KEY='{{{openAIKey}}}' +{{/openAIKey}} +{{^openAIKey}} +SECRET_OPENAI_API_KEY=' ' +{{/openAIKey}} +SECRET_OPENAI_ASSISTANT_ID=' ' # See README.md for how to fill in this value. \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/env/.env.testtool b/templates/ts/custom-copilot-assistant-assistants-api/env/.env.testtool new file mode 100644 index 0000000000..53abad07db --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/env/.env.testtool @@ -0,0 +1,8 @@ +# This file includes environment variables that can be committed to git. It's gitignored by default because it represents your local development environment. + +# Built-in environment variables +TEAMSFX_ENV=testtool + +# Environment variables used by test tool +TEAMSAPPTESTER_PORT=56150 +TEAMSFX_NOTIFICATION_STORE_FILENAME=.notification.testtoolstore.json \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/env/.env.testtool.user.tpl b/templates/ts/custom-copilot-assistant-assistants-api/env/.env.testtool.user.tpl new file mode 100644 index 0000000000..15ee278c2b --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/env/.env.testtool.user.tpl @@ -0,0 +1,11 @@ +# This file includes environment variables that will not be committed to git by default. You can set these environment variables in your CI/CD system for your project. + +# If you're adding a secret value, add SECRET_ prefix to the name so Teams Toolkit can handle them properly +# Secrets. Keys prefixed with `SECRET_` will be masked in Teams Toolkit logs. +{{#openAIKey}} +SECRET_OPENAI_API_KEY='{{{openAIKey}}}' +{{/openAIKey}} +{{^openAIKey}} +SECRET_OPENAI_API_KEY=' ' +{{/openAIKey}} +SECRET_OPENAI_ASSISTANT_ID=' ' # See README.md for how to fill in this value. \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/infra/azure.bicep b/templates/ts/custom-copilot-assistant-assistants-api/infra/azure.bicep new file mode 100644 index 0000000000..a2feeed47a --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/infra/azure.bicep @@ -0,0 +1,96 @@ +@maxLength(20) +@minLength(4) +@description('Used to generate names for all resources in this file') +param resourceBaseName string + +@description('Required when create Azure Bot service') +param botAadAppClientId string + +@secure() +@description('Required by Bot Framework package in your bot project') +param botAadAppClientSecret string + +@secure() +param openAIKey string + +@secure() +param openAIAssistantId string + +param webAppSKU string + +@maxLength(42) +param botDisplayName string + +param serverfarmsName string = resourceBaseName +param webAppName string = resourceBaseName +param location string = resourceGroup().location + +// Compute resources for your Web App +resource serverfarm 'Microsoft.Web/serverfarms@2021-02-01' = { + kind: 'app' + location: location + name: serverfarmsName + sku: { + name: webAppSKU + } +} + +// Web App that hosts your bot +resource webApp 'Microsoft.Web/sites@2021-02-01' = { + kind: 'app' + location: location + name: webAppName + properties: { + serverFarmId: serverfarm.id + httpsOnly: true + siteConfig: { + alwaysOn: true + appSettings: [ + { + name: 'WEBSITE_RUN_FROM_PACKAGE' + value: '1' // Run Azure App Service from a package file + } + { + name: 'WEBSITE_NODE_DEFAULT_VERSION' + value: '~18' // Set NodeJS version to 18.x for your site + } + { + name: 'RUNNING_ON_AZURE' + value: '1' + } + { + name: 'BOT_ID' + value: botAadAppClientId + } + { + name: 'BOT_PASSWORD' + value: botAadAppClientSecret + } + { + name: 'OPENAI_API_KEY' + value: openAIKey + } + { + name: 'OPENAI_ASSISTANT_ID' + value: openAIAssistantId + } + ] + ftpsState: 'FtpsOnly' + } + } +} + +// Register your web service as a bot with the Bot Framework +module azureBotRegistration './botRegistration/azurebot.bicep' = { + name: 'Azure-Bot-registration' + params: { + resourceBaseName: resourceBaseName + botAadAppClientId: botAadAppClientId + botAppDomain: webApp.properties.defaultHostName + botDisplayName: botDisplayName + } +} + +// The output will be persisted in .env.{envName}. Visit https://aka.ms/teamsfx-actions/arm-deploy for more details. +output BOT_AZURE_APP_SERVICE_RESOURCE_ID string = webApp.id +output BOT_DOMAIN string = webApp.properties.defaultHostName diff --git a/templates/ts/custom-copilot-assistant-assistants-api/infra/azure.parameters.json.tpl b/templates/ts/custom-copilot-assistant-assistants-api/infra/azure.parameters.json.tpl new file mode 100644 index 0000000000..2be5c43052 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/infra/azure.parameters.json.tpl @@ -0,0 +1,27 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "resourceBaseName": { + "value": "bot${{RESOURCE_SUFFIX}}" + }, + "botAadAppClientId": { + "value": "${{BOT_ID}}" + }, + "botAadAppClientSecret": { + "value": "${{SECRET_BOT_PASSWORD}}" + }, + "openAIKey": { + "value": "${{SECRET_OPENAI_API_KEY}}" + }, + "openAIAssistantId": { + "value": "${{SECRET_OPENAI_ASSISTANT_ID}}" + }, + "webAppSKU": { + "value": "B1" + }, + "botDisplayName": { + "value": "{{appName}}" + } + } +} \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/infra/botRegistration/azurebot.bicep b/templates/ts/custom-copilot-assistant-assistants-api/infra/botRegistration/azurebot.bicep new file mode 100644 index 0000000000..ab67c7a56b --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/infra/botRegistration/azurebot.bicep @@ -0,0 +1,37 @@ +@maxLength(20) +@minLength(4) +@description('Used to generate names for all resources in this file') +param resourceBaseName string + +@maxLength(42) +param botDisplayName string + +param botServiceName string = resourceBaseName +param botServiceSku string = 'F0' +param botAadAppClientId string +param botAppDomain string + +// Register your web service as a bot with the Bot Framework +resource botService 'Microsoft.BotService/botServices@2021-03-01' = { + kind: 'azurebot' + location: 'global' + name: botServiceName + properties: { + displayName: botDisplayName + endpoint: 'https://${botAppDomain}/api/messages' + msaAppId: botAadAppClientId + } + sku: { + name: botServiceSku + } +} + +// Connect the bot service to Microsoft Teams +resource botServiceMsTeamsChannel 'Microsoft.BotService/botServices/channels@2021-03-01' = { + parent: botService + location: 'global' + name: 'MsTeamsChannel' + properties: { + channelName: 'MsTeamsChannel' + } +} diff --git a/templates/ts/custom-copilot-assistant-assistants-api/infra/botRegistration/readme.md b/templates/ts/custom-copilot-assistant-assistants-api/infra/botRegistration/readme.md new file mode 100644 index 0000000000..d5416243cd --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/infra/botRegistration/readme.md @@ -0,0 +1 @@ +The `azurebot.bicep` module is provided to help you create Azure Bot service when you don't use Azure to host your app. If you use Azure as infrastrcture for your app, `azure.bicep` under infra folder already leverages this module to create Azure Bot service for you. You don't need to deploy `azurebot.bicep` again. \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/package.json.tpl b/templates/ts/custom-copilot-assistant-assistants-api/package.json.tpl new file mode 100644 index 0000000000..4da8a2bfde --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/package.json.tpl @@ -0,0 +1,43 @@ +{ + "name": "{{SafeProjectNameLowerCase}}", + "version": "1.0.0", + "msteams": { + "teamsAppId": null + }, + "description": "Microsoft Teams Toolkit AI Assistant Bot sample with OpenAI Assistants API and Teams AI Library's built-in coordination", + "engines": { + "node": "16 || 18" + }, + "author": "Microsoft", + "license": "MIT", + "main": "./lib/src/index.js", + "scripts": { + "dev:teamsfx": "env-cmd --silent -f .localConfigs npm run dev", + "dev:teamsfx:testtool": "env-cmd --silent -f .localConfigs.testTool npm run dev", + "dev:teamsfx:launch-testtool": "env-cmd --silent -f env/.env.testtool teamsapptester start", + "dev": "nodemon --exec node --inspect=9239 --signal SIGINT -r ts-node/register ./src/index.ts", + "build": "tsc --build", + "start": "node ./lib/src/index.js", + "test": "echo \"Error: no test specified\" && exit 1", + "watch": "nodemon --exec \"npm run start\"", + "assistant:create": "node -r ts-node/register ./src/creator.ts" + }, + "repository": { + "type": "git", + "url": "https://github.com" + }, + "dependencies": { + "@microsoft/teams-ai": "^1.1.0", + "botbuilder": "^4.20.0", + "restify": "^10.0.0" + }, + "devDependencies": { + "@types/restify": "^8.5.5", + "@types/node": "^14.0.0", + "env-cmd": "^10.1.0", + "ts-node": "^10.4.0", + "typescript": "^4.4.4", + "nodemon": "^2.0.7", + "shx": "^0.3.3" + } +} \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/src/adapter.ts b/templates/ts/custom-copilot-assistant-assistants-api/src/adapter.ts new file mode 100644 index 0000000000..1cf10f4bb8 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/src/adapter.ts @@ -0,0 +1,51 @@ +// Import required bot services. +// See https://aka.ms/bot-services to learn more about the different parts of a bot. +import { + CloudAdapter, + ConfigurationBotFrameworkAuthentication, + ConfigurationServiceClientCredentialFactory, +} from "botbuilder"; + +// This bot's main dialog. +import config from "./config"; + +const botFrameworkAuthentication = new ConfigurationBotFrameworkAuthentication( + {}, + new ConfigurationServiceClientCredentialFactory({ + MicrosoftAppId: config.botId, + MicrosoftAppPassword: process.env.BOT_PASSWORD, + MicrosoftAppType: "MultiTenant", + }) +); + +// Create adapter. +// See https://aka.ms/about-bot-adapter to learn more about how bots work. +const adapter = new CloudAdapter(botFrameworkAuthentication); + +// Catch-all for errors. +const onTurnErrorHandler = async (context, error) => { + // This check writes out errors to console log .vs. app insights. + // NOTE: In production environment, you should consider logging this to Azure + // application insights. + console.error(`\n [onTurnError] unhandled error: ${error}`); + + // Only send error message for user messages, not for other message types so the bot doesn't spam a channel or chat. + if (context.activity.type === "message") { + // Send a trace activity, which will be displayed in Bot Framework Emulator + await context.sendTraceActivity( + "OnTurnError Trace", + `${error}`, + "https://www.botframework.com/schemas/error", + "TurnError" + ); + + // Send a message to the user + await context.sendActivity("The bot encountered an error or bug."); + await context.sendActivity("To continue to run this bot, please fix the bot source code."); + } +}; + +// Set the onTurnError for the singleton CloudAdapter. +adapter.onTurnError = onTurnErrorHandler; + +export default adapter; diff --git a/templates/ts/custom-copilot-assistant-assistants-api/src/app/actions.ts b/templates/ts/custom-copilot-assistant-assistants-api/src/app/actions.ts new file mode 100644 index 0000000000..6754d9e1ba --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/src/app/actions.ts @@ -0,0 +1,56 @@ +import { TurnContext } from "botbuilder"; +import { AI, TurnState } from "@microsoft/teams-ai"; + +export async function httpErrorAction( + context: TurnContext, + state: TurnState, + data +): Promise { + await context.sendActivity("An AI request failed. Please try again later."); + return AI.StopCommandName; +} + +interface WeatherParameters { + location: string; + unit?: "c" | "f"; +} + +export async function getCurrentWeather( + context: TurnContext, + state: TurnState, + parameters: WeatherParameters +): Promise { + const weatherData = { + "San Francisco, CA": { + f: "71.6F", + c: "22C", + }, + "Los Angeles": { + f: "75.2F", + c: "24C", + }, + }; + + if (weatherData[parameters.location] === undefined) { + return `No weather data for ${location} found`; + } + + return weatherData[parameters.location][parameters.unit ?? "f"]; +} + +interface NicknameParameters { + location: string; +} + +export async function getNickname( + context: TurnContext, + state: TurnState, + parameters: NicknameParameters +): Promise { + const nicknames = { + "San Francisco": "The Golden City", + "Los Angeles": "LA", + }; + + return nicknames[parameters.location] ?? `No nickname for ${location} found`; +} diff --git a/templates/ts/custom-copilot-assistant-assistants-api/src/app/app.ts b/templates/ts/custom-copilot-assistant-assistants-api/src/app/app.ts new file mode 100644 index 0000000000..cae1f398a7 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/src/app/app.ts @@ -0,0 +1,40 @@ +import { MemoryStorage } from "botbuilder"; + +// See https://aka.ms/teams-ai-library to learn more about the Teams AI library. +import { Application, AI, preview } from "@microsoft/teams-ai"; + +import config from "../config"; + +// See README.md to prepare your own OpenAI Assistant +if (!config.openAIKey || !config.openAIAssistantId) { + throw new Error( + "Missing OPENAI_API_KEY or OPENAI_ASSISTANT_ID. See README.md to prepare your own OpenAI Assistant." + ); +} + +import { resetMessage } from "./messages"; +import { httpErrorAction, getCurrentWeather, getNickname } from "./actions"; + +// Create AI components +// Use OpenAI +const planner = new preview.AssistantsPlanner({ + apiKey: config.openAIKey, + assistant_id: config.openAIAssistantId, +}); + +// Define storage and application +const storage = new MemoryStorage(); +const app = new Application({ + storage, + ai: { + planner, + }, +}); + +app.message("reset", resetMessage); + +app.ai.action(AI.HttpErrorActionName, httpErrorAction); +app.ai.action("getCurrentWeather", getCurrentWeather); +app.ai.action("getNickname", getNickname); + +export default app; diff --git a/templates/ts/custom-copilot-assistant-assistants-api/src/app/messages.ts b/templates/ts/custom-copilot-assistant-assistants-api/src/app/messages.ts new file mode 100644 index 0000000000..0cabdc6f83 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/src/app/messages.ts @@ -0,0 +1,7 @@ +import { TurnContext } from "botbuilder"; +import { TurnState } from "@microsoft/teams-ai"; + +export async function resetMessage(context: TurnContext, state: TurnState) { + state.deleteConversationState(); + await context.sendActivity("Ok lets start this over."); +} diff --git a/templates/ts/custom-copilot-assistant-assistants-api/src/config.ts b/templates/ts/custom-copilot-assistant-assistants-api/src/config.ts new file mode 100644 index 0000000000..d6f3a322cf --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/src/config.ts @@ -0,0 +1,8 @@ +const config = { + botId: process.env.BOT_ID, + botPassword: process.env.BOT_PASSWORD, + openAIKey: process.env.OPENAI_API_KEY, + openAIAssistantId: process.env.OPENAI_ASSISTANT_ID, +}; + +export default config; diff --git a/templates/ts/custom-copilot-assistant-assistants-api/src/creator.ts b/templates/ts/custom-copilot-assistant-assistants-api/src/creator.ts new file mode 100644 index 0000000000..802c43d419 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/src/creator.ts @@ -0,0 +1,64 @@ +import { preview } from "@microsoft/teams-ai"; + +const openAIKey = process.argv[2]; +if (!openAIKey) { + throw new Error("Missing input OpenAI Key"); +} + +// Create new Assistant +(async () => { + const assistant = await preview.AssistantsPlanner.createAssistant(openAIKey, { + name: "Assistant", + instructions: [ + "You are an intelligent bot that can", + "- write and run code to answer math questions", + "- use the provided functions to answer questions", + ].join("\n"), + tools: [ + { + type: "code_interpreter", + }, + { + type: "function", + function: { + name: "getCurrentWeather", + description: "Get the weather in location", + parameters: { + type: "object", + properties: { + location: { + type: "string", + description: "The city and state e.g. San Francisco, CA", + }, + unit: { + type: "string", + enum: ["c", "f"], + }, + }, + required: ["location"], + }, + }, + }, + { + type: "function", + function: { + name: "getNickname", + description: "Get the nickname of a city", + parameters: { + type: "object", + properties: { + location: { + type: "string", + description: "The city and state e.g. San Francisco, CA", + }, + }, + required: ["location"], + }, + }, + }, + ], + model: "gpt-3.5-turbo", + }); + + console.log(`Created a new assistant with an ID of: ${assistant.id}`); +})(); diff --git a/templates/ts/custom-copilot-assistant-assistants-api/src/index.ts b/templates/ts/custom-copilot-assistant-assistants-api/src/index.ts new file mode 100644 index 0000000000..0db519818e --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/src/index.ts @@ -0,0 +1,25 @@ +// Import required packages +import * as restify from "restify"; + +// This bot's adapter +import adapter from "./adapter"; + +// This bot's main dialog. +import app from "./app/app"; + +// Create HTTP server. +const server = restify.createServer(); +server.use(restify.plugins.bodyParser()); + +server.listen(process.env.port || process.env.PORT || 3978, () => { + console.log(`\nBot Started, ${server.name} listening to ${server.url}`); +}); + +// Listen for incoming server requests. +server.post("/api/messages", async (req, res) => { + // Route received a request to adapter for processing + await adapter.process(req, res as any, async (context) => { + // Dispatch to application for routing + await app.run(context); + }); +}); diff --git a/templates/ts/custom-copilot-assistant-assistants-api/teamsapp.local.yml.tpl b/templates/ts/custom-copilot-assistant-assistants-api/teamsapp.local.yml.tpl new file mode 100644 index 0000000000..1e877247d9 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/teamsapp.local.yml.tpl @@ -0,0 +1,80 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/1.0.0/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: 1.0.0 + +provision: + # Creates a Teams app + - uses: teamsApp/create + with: + # Teams app name + name: {{appName}}${{APP_NAME_SUFFIX}} + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + teamsAppId: TEAMS_APP_ID + + # Create or reuse an existing Microsoft Entra application for bot. + - uses: botAadApp/create + with: + # The Microsoft Entra application's display name + name: {{appName}}${{APP_NAME_SUFFIX}} + writeToEnvironmentFile: + # The Microsoft Entra application's client id created for bot. + botId: BOT_ID + # The Microsoft Entra application's client secret created for bot. + botPassword: SECRET_BOT_PASSWORD + + # Create or update the bot registration on dev.botframework.com + - uses: botFramework/create + with: + botId: ${{BOT_ID}} + name: {{appName}} + messagingEndpoint: ${{BOT_ENDPOINT}}/api/messages + description: "" + channels: + - name: msteams + + # Validate using manifest schema + - uses: teamsApp/validateManifest + with: + # Path to manifest template + manifestPath: ./appPackage/manifest.json + + # 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 + outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json + # 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 + +deploy: + # Run npm command + - uses: cli/runNpmCommand + name: install dependencies + with: + args: install --no-audit + + # Generate runtime environment variables + - uses: file/createOrUpdateEnvironmentFile + with: + target: ./.localConfigs + envs: + BOT_ID: ${{BOT_ID}} + BOT_PASSWORD: ${{SECRET_BOT_PASSWORD}} + OPENAI_API_KEY: ${{SECRET_OPENAI_API_KEY}} + OPENAI_ASSISTANT_ID: ${{SECRET_OPENAI_ASSISTANT_ID}} \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/teamsapp.testtool.yml b/templates/ts/custom-copilot-assistant-assistants-api/teamsapp.testtool.yml new file mode 100644 index 0000000000..e53a7bc322 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/teamsapp.testtool.yml @@ -0,0 +1,26 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.3/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.3 + +deploy: + # Install development tool(s) + - uses: devTool/install + with: + testTool: + version: ~0.1.0-beta + symlinkDir: ./devTools/teamsapptester + + # Run npm command + - uses: cli/runNpmCommand + with: + args: install --no-audit + + # Generate runtime environment variables + - uses: file/createOrUpdateEnvironmentFile + with: + target: ./.localConfigs.testTool + envs: + OPENAI_API_KEY: ${{SECRET_OPENAI_API_KEY}} + OPENAI_ASSISTANT_ID: ${{SECRET_OPENAI_ASSISTANT_ID}} + TEAMSFX_NOTIFICATION_STORE_FILENAME: ${{TEAMSFX_NOTIFICATION_STORE_FILENAME}} \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/teamsapp.yml.tpl b/templates/ts/custom-copilot-assistant-assistants-api/teamsapp.yml.tpl new file mode 100644 index 0000000000..ad88b620cc --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/teamsapp.yml.tpl @@ -0,0 +1,141 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/1.0.0/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: 1.0.0 + +environmentFolderPath: ./env + +# Triggered when 'teamsapp provision' is executed +provision: + # Creates a Teams app + - uses: teamsApp/create + with: + # Teams app name + name: {{appName}}${{APP_NAME_SUFFIX}} + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + teamsAppId: TEAMS_APP_ID + + # Create or reuse an existing Microsoft Entra application for bot. + - uses: botAadApp/create + with: + # The Microsoft Entra application's display name + name: {{appName}}${{APP_NAME_SUFFIX}} + writeToEnvironmentFile: + # The Microsoft Entra application's client id created for bot. + botId: BOT_ID + # The Microsoft Entra application's client secret created for bot. + botPassword: SECRET_BOT_PASSWORD + + - uses: arm/deploy # Deploy given ARM templates parallelly. + with: + # AZURE_SUBSCRIPTION_ID is a built-in environment variable, + # if its value is empty, TeamsFx will prompt you to select a subscription. + # Referencing other environment variables with empty values + # will skip the subscription selection prompt. + subscriptionId: ${{AZURE_SUBSCRIPTION_ID}} + # AZURE_RESOURCE_GROUP_NAME is a built-in environment variable, + # if its value is empty, TeamsFx will prompt you to select or create one + # resource group. + # Referencing other environment variables with empty values + # will skip the resource group selection prompt. + resourceGroupName: ${{AZURE_RESOURCE_GROUP_NAME}} + templates: + - path: ./infra/azure.bicep # Relative path to this file + # Relative path to this yaml file. + # Placeholders will be replaced with corresponding environment + # variable before ARM deployment. + parameters: ./infra/azure.parameters.json + # Required when deploying ARM template + deploymentName: Create-resources-for-bot + # Teams Toolkit will download this bicep CLI version from github for you, + # will use bicep CLI in PATH if you remove this config. + bicepCliVersion: v0.9.1 + + # Validate using manifest schema + - uses: teamsApp/validateManifest + with: + # Path to manifest template + manifestPath: ./appPackage/manifest.json + # 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 + outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json + # 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 + +# Triggered when 'teamsapp deploy' is executed +deploy: + # Run npm command + - uses: cli/runNpmCommand + name: install dependencies + with: + args: install + - uses: cli/runNpmCommand + name: build app + with: + args: run build --if-present + # Deploy your application to Azure App Service using the zip deploy feature. + # For additional details, refer to https://aka.ms/zip-deploy-to-app-services. + - uses: azureAppService/zipDeploy + with: + # Deploy base folder + artifactFolder: . + # Ignore file location, leave blank will ignore nothing + ignoreFile: .webappignore + # The resource id of the cloud resource to be deployed to. + # This key will be generated by arm/deploy action automatically. + # You can replace it with your existing Azure Resource id + # or add it to your environment variable file. + resourceId: ${{BOT_AZURE_APP_SERVICE_RESOURCE_ID}} + +# Triggered when 'teamsapp publish' is executed +publish: + # Validate using manifest schema + - uses: teamsApp/validateManifest + with: + # Path to manifest template + manifestPath: ./appPackage/manifest.json + # 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 + outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json + # 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/templates/ts/custom-copilot-assistant-assistants-api/tsconfig.json b/templates/ts/custom-copilot-assistant-assistants-api/tsconfig.json new file mode 100644 index 0000000000..a68afb21f7 --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "declaration": true, + "target": "es2017", + "module": "commonjs", + "outDir": "./lib", + "rootDir": "./", + "sourceMap": true, + "incremental": true, + "tsBuildInfoFile": "./lib/.tsbuildinfo", + "esModuleInterop": true + } +} \ No newline at end of file diff --git a/templates/ts/custom-copilot-assistant-assistants-api/web.config b/templates/ts/custom-copilot-assistant-assistants-api/web.config new file mode 100644 index 0000000000..793a3a982b --- /dev/null +++ b/templates/ts/custom-copilot-assistant-assistants-api/web.config @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file