Skip to content

Commit

Permalink
Samples/node skill (#69)
Browse files Browse the repository at this point in the history
* Add node-echo-skill sample with Docker support and configuration files

* Add privacy documentation and update Docker configuration for node-echo-skill

* Add Microsoft Graph client integration and user info retrieval to Echo Skill

* Add user photo display and launch configuration for debugging in node-echo-skill

* Rename echo-skill to node-echo-skill and fix privacy URL formatting in manifest

* Add TypeScript checking and clean up user info retrieval function

* Fix dependency version format for agents-bot-hosting in package.json

* Update agents-bot-hosting dependency version in package.json

* use public feed

* configur debugger to stepinto TS files

* Remove node-echo-skill files and add copilotstudio-skill structure
  • Loading branch information
rido-min authored Feb 21, 2025
1 parent 8541c2f commit 6be0d9b
Show file tree
Hide file tree
Showing 11 changed files with 229 additions and 0 deletions.
20 changes: 20 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [

{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/samples/skill/node-echo-skill/src/index.js",
"outFiles": [ "${workspaceFolder}/samples/skill/node-echo-skill/node_modules/@microsoft/**/*.js" ]

}
]
}
4 changes: 4 additions & 0 deletions samples/complex/copilotstudio-skill/nodejs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/
dist/
.env
package-lock.json
2 changes: 2 additions & 0 deletions samples/complex/copilotstudio-skill/nodejs/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@microsoft:registry=https://pkgs.dev.azure.com/ConversationalAI/BotFramework/_packaging/SDK/npm/registry/
package-lock=false
19 changes: 19 additions & 0 deletions samples/complex/copilotstudio-skill/nodejs/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Debug index",
"program": "${workspaceFolder}/src/index.js",
"request": "launch",
"skipFiles": [
"<node_internals>/**"
],
"type": "node",
"envFile": "${workspaceFolder}/.env"
},

]
}
57 changes: 57 additions & 0 deletions samples/complex/copilotstudio-skill/nodejs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# copilotstudio-skill

This sample shows how to create an Agent that can be consumed from CopilotStudio as a skill.

## Prerequisites

- [Node.js](https://nodejs.org) version 20 or higher

```bash
# determine node version
node --version
```

- Access to CopilotStudio to [create an Agent](https://learn.microsoft.com/en-us/microsoft-copilot-studio/fundamentals-get-started?tabs=web)

## Deploy in localhost

The first time you setup the agent to be consumed as a skill, you might want to do it in `localhost`, so you can debug and revisit the desired configuration before deploying to azure.
To do so you can use the tool [Dev Tunnels](https://aka.ms/devtunnels) to expose an endpoint in your machine to the internet.

```bash
devtunnel host -a -p 3978
```

Take note of the tunnelUrl

1. Create an EntraID app registration, and save the authentication information in the `.env` file, following any of the [available options](https://microsoft.github.io/Agents/HowTo/azurebot-auth-for-js.html) for Single Tenant.
1. Update the Home page URL in the app registration with the tunnel url.
1. Update the manifest replacing the `{baseUrl}` with the `{tunnelUrl}` and `{clientId}` with the `{appId}` from EntraID
1. - [Configure a skill](https://learn.microsoft.com/en-us/microsoft-copilot-studio/configuration-add-skills#configure-a-skill)
1. In CopilotStudio navigate to the Agent settings, skills, and register the skill with the URL `{tunnelUrl}/manifest.json`
1. In CopilotStudio navigate to the Agent topics, add a new trigger to invoke an action to call the skill

## Deploy in Azure

1. Deploy the express application to Azure, using AppService, AzureVMs or Azure Container Apps.
1. Update the Home page URL in the app registration with the Azure service URL.
1. Create an EntraID app registration, and configure the Azure instance following any of the [available options](https://microsoft.github.io/Agents/HowTo/azurebot-auth-for-js.html) for SingleTenant.
1. - [Configure a skill](https://learn.microsoft.com/en-us/microsoft-copilot-studio/configuration-add-skills#configure-a-skill)
1. In CopilotStudio navigate to the Agent settings, skills, and register the skill with the URL `{azureServiceUrl}/manifest.json`
1. In CopilotStudio navigate to the Agent topics, add a new trigger to invoke an action to call the skill


## Running this sample

1. Once the express app is running, in localhost or in Azure
1. Use the CopilotStudio _Test your agent_ chat UI, and use the trigger defined to invoke the skill

# Helper Scripts

Replace Manifest Values

```ps
$url='{tunnelUrl}'
$clientId='{clientId}'
(Get-Content public/manifest.template.json).Replace('{baseUrl}', $url).Replace('{clientId}', $clientId) | Set-Content public/manifest.json
```
22 changes: 22 additions & 0 deletions samples/complex/copilotstudio-skill/nodejs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "node-echo-skill",
"version": "1.0.0",
"main": "index.js",
"type": "module",
"scripts": {
"lint": "eslint src",
"start": "node --env-file .env src/index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"@microsoft/agents-bot-hosting": "0.1.20",
"@microsoft/microsoft-graph-client": "^3.0.7",
"express": "^5.0.1"
},
"devDependencies": {
"globals": "^15.14.0"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"$schema": "https://schemas.botframework.com/schemas/skills/skill-manifest-2.0.0.json",
"$id": "EchoSkill",
"name": "Echo Skill",
"version": "1.0",
"description": "This is a sample echo skill",
"publisherName": "Microsoft",
"privacyUrl": "{baseUrl}/privacy.html",
"copyright": "Copyright (c) Microsoft Corporation. All rights reserved.",
"license": "",
"iconUrl": "{baseUrl}/icon.png",
"tags": [
"sample",
"skill"
],
"endpoints": [
{
"name": "default",
"protocol": "BotFrameworkV3",
"description": "Default endpoint for the bot",
"endpointUrl": "https://{baseUrl}/api/messages",
"msAppId": "{clientId}"
}
],
"activities": {
"message": {
"type": "message",
"description": "Echo messages from user"
}
}
}
13 changes: 13 additions & 0 deletions samples/complex/copilotstudio-skill/nodejs/public/privacy.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Privacy</title>
</head>
<body>
<h1>Privacy Doc</h1>

<p>Privacy is important to us. We do not collect any personal information from you. We do not use cookies. We do not track you. We do not store any information about you.</p>
</body>
</html>
32 changes: 32 additions & 0 deletions samples/complex/copilotstudio-skill/nodejs/src/bot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// @ts-check

import { ActivityHandler, MessageFactory, MsalTokenProvider } from '@microsoft/agents-bot-hosting'
import { default as pjson } from '../node_modules/@microsoft/agents-bot-hosting/package.json' with { type: "json" }

export class EchoBot extends ActivityHandler {
constructor() {
super()
this.onMessage(async (context, next) => {
const text = context.activity.text
const replyText = `Echo: ${ text }`
await context.sendActivity(MessageFactory.text(replyText, replyText))
if (text?.includes('version')) {
await context.sendActivity(MessageFactory.text('Running on version ' + pjson.version, 'Running on version ' + pjson.version))
}
await next()
});

this.onMembersAdded(async (context, next) => {
const welcomeText = `Hello from echo bot, running on version ${ pjson.version }`
const membersAdded = context.activity.membersAdded
if (membersAdded) {
for (let cnt = 0; cnt < membersAdded.length; ++cnt) {
if (membersAdded[cnt].id !== context.activity.recipient?.id) {
await context.sendActivity(MessageFactory.text(welcomeText, welcomeText))
}
}
}
await next()
})
}
}
29 changes: 29 additions & 0 deletions samples/complex/copilotstudio-skill/nodejs/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// @ts-check
import express, { json } from 'express';

import { CloudAdapter, loadAuthConfigFromEnv, authorizeJWT } from '@microsoft/agents-bot-hosting';

import { EchoBot } from './bot.js';
import { default as pjson } from '../node_modules/@microsoft/agents-bot-hosting/package.json' with { type: "json" }

const config = loadAuthConfigFromEnv()
const adapter = new CloudAdapter(config);
const myBot = new EchoBot()


const server = express()
server.use(express.static('public'))
server.use(authorizeJWT(config))

server.use(json())
server.post('/api/messages',
async (req, res) => {
await adapter.process(req, res, (context) => myBot.run(context));
}
)

const port = process.env.PORT || 3978

server.listen(port, () => {
console.log(`\n echo bot, running on sdk version ${ pjson.version } lisenting on ${ port } for bot ${ process.env.clientId }`);
})

0 comments on commit 6be0d9b

Please sign in to comment.