Skip to content

Instantly share code, notes, and snippets.

@rido-min
Last active February 4, 2025 05:21
Show Gist options
  • Save rido-min/fa22d090f60440053e69e46345942bd0 to your computer and use it in GitHub Desktop.
Save rido-min/fa22d090f60440053e69e46345942bd0 to your computer and use it in GitHub Desktop.
minimal-bot
node_modules/
dist/
.env
.npmrc
package-lock.json
*.log

bb-agent

bot / agent starter

setup

Configure .npmrc

echo "registry=https://pkgs.dev.azure.com/dynamicscrm/OneCRM/_packaging/DPX-Tools-Upstream/npm/registry/" > .npmrc

Install

npm -dd i

Provision / Configure ABS

$botName = Read-Host "BotName in ABS"
$appId = az ad app create --display-name $botName --sign-in-audience "AzureADMyOrg" --query appId | ConvertFrom-Json
$secretJson = az ad app credential reset --id $appId | ConvertFrom-Json
echo .env
echo "tenantId=$($secretJson.tenant)" >> .env
echo "clientId=$($secretJson.appId)" >> .env
echo "clientSecret=$($secretJson.password)" >> .env

Run

node --env-file .env app.js
// @ts-check
const express = require('express')
const {
CloudAdapter,
loadAuthConfigFromEnv,
authorizeJWT,
} = require('@microsoft/agents-bot-hosting')
const { SuggestedActionsBot } = require('./bot')
const config = loadAuthConfigFromEnv()
const adapter = new CloudAdapter(config);
const myBot = new SuggestedActionsBot()
const server = express()
server.use(authorizeJWT(config))
server.use(express.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 lisenting on ${ port } for bot ${ process.env.clientId }`);
})
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const { ActivityHandler, MessageFactory, ActionTypes } = require('@microsoft/agents-bot-hosting');
class SuggestedActionsBot extends ActivityHandler {
constructor() {
super();
this.onMembersAdded(async (context, next) => {
await this.sendWelcomeMessage(context);
// By calling next() you ensure that the next BotHandler is run.
await next();
});
this.onMessage(async (context, next) => {
const text = context.activity.text;
// Create an array with the valid color options.
const validColors = ['Red', 'Blue', 'Yellow'];
// If the `text` is in the Array, a valid color was selected and send agreement.
if (validColors.includes(text)) {
await context.sendActivity(`I agree, ${ text } is the best color.`);
} else {
await context.sendActivity('Please select a color.');
}
// After the bot has responded send the suggested actions.
await this.sendSuggestedActions(context);
// By calling next() you ensure that the next BotHandler is run.
await next();
});
}
/**
* Send a welcome message along with suggested actions for the user to click.
* @param {TurnContext} turnContext A TurnContext instance containing all the data needed for processing this conversation turn.
*/
async sendWelcomeMessage(turnContext) {
const { activity } = turnContext;
// Iterate over all new members added to the conversation.
for (const idx in activity.membersAdded) {
if (activity.membersAdded[idx].id !== activity.recipient.id) {
const welcomeMessage = `Welcome to suggestedActionsBot ${ activity.membersAdded[idx].name }. ` +
'This bot will introduce you to Suggested Actions. ' +
'Please select an option:';
await turnContext.sendActivity(welcomeMessage);
await this.sendSuggestedActions(turnContext);
}
}
}
/**
* Send suggested actions to the user.
* @param {TurnContext} turnContext A TurnContext instance containing all the data needed for processing this conversation turn.
*/
async sendSuggestedActions(turnContext) {
const cardActions = [
{
type: ActionTypes.PostBack,
title: 'Red',
value: 'Red',
image: 'https://via.placeholder.com/20/FF0000?text=R',
imageAltText: 'R'
},
{
type: ActionTypes.PostBack,
title: 'Yellow',
value: 'Yellow',
image: 'https://via.placeholder.com/20/FFFF00?text=Y',
imageAltText: 'Y'
},
{
type: ActionTypes.PostBack,
title: 'Blue',
value: 'Blue',
image: 'https://via.placeholder.com/20/0000FF?text=B',
imageAltText: 'B'
}
];
var reply = MessageFactory.suggestedActions(cardActions, 'What is the best color?');
await turnContext.sendActivity(reply);
}
}
module.exports.SuggestedActionsBot = SuggestedActionsBot;
## This script will create a Bot Service instance, using Azure Container Apps and Azure Bot Service
## Variables can be configured as EnvVars, if not found should be provided by the user
function Get-EnvOrPrompt {
param (
[string]$envVarName,
[string]$promptMessage
)
$envVarValue = [System.Environment]::GetEnvironmentVariable($envVarName)
if (-not $envVarValue) {
$envVarValue = Read-Host $promptMessage
}
return $envVarValue
}
# Initialize variables
$resourceGroup = Get-EnvOrPrompt -envVarName "RESOURCE_GROUP" -promptMessage "Enter the name of the resource group, eg my-test-rg, it has to exist"
$acrName = Get-EnvOrPrompt -envVarName "ACR_NAME" -promptMessage "Enter the name of the ACR, eg my-test-acr, it has to exist"
$acrImage = Get-EnvOrPrompt -envVarName "ACR_IMAGE" -promptMessage "Enter the name of the image, eg my-test-bot:latest, it has to exist in the ACR $acrName"
$botName = Get-EnvOrPrompt -envVarName "BOT_NAME" -promptMessage "Enter the name of the bot, eg my-test-bot"
$containerName = "$botName-app"
$botImage = "$acrName.azurecr.io/$acrImage"
echo "Creating Bot $botName from image $botImage in $containerName, RG $resourceGroup"
## Create the AppId and Secret
$appId = az ad app create --display-name $botName --sign-in-audience "AzureADMyOrg" --query appId | ConvertFrom-Json
echo "Created AppId: " $appId
$secretJson = az ad app credential reset --id $appId | ConvertFrom-Json
## Create the Azure Container App
az containerapp up `
--resource-group $resourceGroup `
--name $containerName `
--image $botImage `
--environment bot-apps-$resourceGroup `
--ingress external `
--env-vars `
tenantId=$($secretJson.tenant) `
DEBUG="*"
$fqdn = az containerapp show --resource-g $resourceGroup --name $containerName --query properties.configuration.ingress.fqdn -o tsv
$endpoint = "https://$fqdn/api/messages"
echo "Created ACA app, listenting in endpoint: $endpoint"
## Create the Bot Service
$botJson = az bot create `
--app-type UserAssignedMSI `
--appid $appId `
--tenant-id $($secretJson.tenant) `
--name $botName `
--resource-group $resourceGroup `
--endpoint $endpoint
$teamsBotJson = az bot msteams create -n $botName -g $resourceGroup
echo $teamsBotJson
FROM node:alpine
WORKDIR /app
COPY dist/bundle.js .
CMD ["node", "bundle.js"]
{
"scripts": {
"test-tool": "teamsapptester start",
"start": "node --env-file .env app.js",
"test": "npm-run-all -p -r start test-tool",
"bundle": "esbuild app.js --bundle --platform=node --metafile=dist/meta.json --outfile=dist/bundle.js --tree-shaking=true --keep-names",
"docker": "docker build -t botagents.azurecr.io/node-echo-bot:latest ."
},
"dependencies": {
"@microsoft/agents-bot-hosting": "^0.2.17-alpha",
"express": "^5.0.1"
},
"devDependencies": {
"@microsoft/teams-app-test-tool": "^0.2.4",
"esbuild": "^0.24.0",
"npm-run-all": "^4.1.5"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment