diff --git a/nodejs/devin/sample-agent/.gitignore b/nodejs/devin/sample-agent/.gitignore new file mode 100644 index 00000000..ddfa31e6 --- /dev/null +++ b/nodejs/devin/sample-agent/.gitignore @@ -0,0 +1,24 @@ +# TeamsFx files +env/.env.*.user +env/.env.local +env/.env.sandbox +.localConfigs +.localConfigs.playground +.notification.localstore.json +.notification.playgroundstore.json +.notification.testtoolstore.json +appPackage/build + +# dependencies +node_modules/ + +# misc +.env +.deployment +.DS_Store + +# build +dist/ + +# Dev tool directories +/devTools/ diff --git a/nodejs/devin/sample-agent/.vscode/extensions.json b/nodejs/devin/sample-agent/.vscode/extensions.json new file mode 100644 index 00000000..aac0a6e3 --- /dev/null +++ b/nodejs/devin/sample-agent/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "TeamsDevApp.ms-teams-vscode-extension" + ] +} diff --git a/nodejs/devin/sample-agent/.vscode/launch.json b/nodejs/devin/sample-agent/.vscode/launch.json new file mode 100644 index 00000000..20f088e2 --- /dev/null +++ b/nodejs/devin/sample-agent/.vscode/launch.json @@ -0,0 +1,31 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to Local Service", + "type": "node", + "request": "attach", + "port": 9239, + "restart": true, + "presentation": { + "group": "all", + "hidden": true + }, + "internalConsoleOptions": "neverOpen" + } + ], + "compounds": [ + { + "name": "Debug in Microsoft 365 Agents Playground", + "configurations": [ + "Attach to Local Service" + ], + "preLaunchTask": "Start App in Microsoft 365 Agents Playground", + "presentation": { + "group": "1-playground", + "order": 1 + }, + "stopAll": true + } + ] +} diff --git a/nodejs/devin/sample-agent/.vscode/scripts/refresh-bearer-token.ps1 b/nodejs/devin/sample-agent/.vscode/scripts/refresh-bearer-token.ps1 new file mode 100644 index 00000000..2fee52fa --- /dev/null +++ b/nodejs/devin/sample-agent/.vscode/scripts/refresh-bearer-token.ps1 @@ -0,0 +1,77 @@ +$ErrorActionPreference = 'Stop' + +$workspace = Get-Location +$playgroundEnvPath = Join-Path $workspace 'env/.env.playground' +$playgroundUserEnvPath = Join-Path $workspace 'env/.env.playground.user' + +$a365Command = Get-Command a365 -ErrorAction SilentlyContinue +if (-not $a365Command) { + throw "a365 CLI is not installed or not on PATH. Install with: dotnet tool install --global Microsoft.Agents.A365.DevTools.Cli" +} + +if (-not (Test-Path $playgroundEnvPath)) { + throw "Missing env file: $playgroundEnvPath" +} + +$appIdLine = Get-Content $playgroundEnvPath | Where-Object { $_ -match '^\s*CLIENT_APP_ID\s*=\s*.+$' } | Select-Object -First 1 +if (-not $appIdLine) { + throw "CLIENT_APP_ID is required in env/.env.playground" +} + +$appId = ($appIdLine -split '=', 2)[1].Trim() +if ([string]::IsNullOrWhiteSpace($appId)) { + throw "CLIENT_APP_ID in env/.env.playground is empty" +} + +Write-Host "Running a365 develop add-permissions for app id $appId" +& a365 develop add-permissions --app-id $appId +if ($LASTEXITCODE -ne 0) { + throw "a365 develop add-permissions failed" +} + +Write-Host "Getting bearer token via a365..." +Write-Host "This may complete silently using cached credentials, or it may require interactive Windows sign-in (WAM)." +Write-Host "If interactive sign-in is required and no prompt appears, check the taskbar for a hidden sign-in window and bring it to front." +Write-Host "Running a365 develop get-token for app id $appId" +$tokenOutput = & a365 develop get-token --app-id $appId --output raw +if ($LASTEXITCODE -ne 0) { + throw "a365 develop get-token failed" +} + +$rawOutput = [string]::Join("`n", $tokenOutput) +$rawOutput = $rawOutput -replace "`r", '' + +$bearerToken = $null +$jwtRegex = '(?[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)' +$jwtMatches = [regex]::Matches($rawOutput, $jwtRegex) +if ($jwtMatches.Count -gt 0) { + $bearerToken = ($jwtMatches | ForEach-Object { $_.Groups['token'].Value } | Sort-Object Length -Descending | Select-Object -First 1).Trim() +} + +if ([string]::IsNullOrWhiteSpace($bearerToken)) { + throw "Unable to extract a bearer token from a365 develop get-token output" +} + +$userEnvLines = @() +if (Test-Path $playgroundUserEnvPath) { + $userEnvLines = Get-Content $playgroundUserEnvPath +} + +$updated = $false +for ($i = 0; $i -lt $userEnvLines.Count; $i++) { + if ($userEnvLines[$i] -match '^\s*SECRET_BEARER_TOKEN\s*=') { + $userEnvLines[$i] = "SECRET_BEARER_TOKEN=$bearerToken" + $updated = $true + break + } +} + +if (-not $updated) { + if ($userEnvLines.Count -gt 0 -and -not [string]::IsNullOrWhiteSpace($userEnvLines[$userEnvLines.Count - 1])) { + $userEnvLines += '' + } + $userEnvLines += "SECRET_BEARER_TOKEN=$bearerToken" +} + +Set-Content -Path $playgroundUserEnvPath -Value $userEnvLines -Encoding UTF8 +Write-Host 'SECRET_BEARER_TOKEN has been updated in env/.env.playground.user' diff --git a/nodejs/devin/sample-agent/.vscode/tasks.json b/nodejs/devin/sample-agent/.vscode/tasks.json new file mode 100644 index 00000000..c08b1c64 --- /dev/null +++ b/nodejs/devin/sample-agent/.vscode/tasks.json @@ -0,0 +1,117 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Start App in Microsoft 365 Agents Playground", + "dependsOn": [ + "Validate prerequisites (Microsoft 365 Agents Playground)", + "Refresh bearer token (Microsoft 365 Agents Playground)", + "Deploy (Microsoft 365 Agents Playground)", + "Start application (Microsoft 365 Agents Playground)", + "Start Microsoft 365 Agents Playground" + ], + "dependsOrder": "sequence" + }, + { + "label": "Validate prerequisites (Microsoft 365 Agents Playground)", + "type": "teamsfx", + "command": "debug-check-prerequisites", + "args": { + "prerequisites": [ + "nodejs", + "portOccupancy" + ], + "portOccupancy": [ + 3978, + 9239, + 56150 + ] + } + }, + { + "label": "Refresh bearer token (Microsoft 365 Agents Playground)", + "type": "shell", + "command": "powershell", + "args": [ + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-File", + "${workspaceFolder}/.vscode/scripts/refresh-bearer-token.ps1" + ], + "options": { + "cwd": "${workspaceFolder}" + } + }, + { + "label": "Deploy (Microsoft 365 Agents Playground)", + "dependsOrder": "sequence", + "type": "teamsfx", + "command": "deploy", + "args": { + "env": "playground" + } + }, + { + "label": "Start application (Microsoft 365 Agents Playground)", + "type": "shell", + "command": "npm run dev:teamsfx:playground", + "isBackground": true, + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": { + "pattern": [ + { + "regexp": "^.*$", + "file": 0, + "location": 1, + "message": 2 + } + ], + "background": { + "activeOnStart": true, + "beginsPattern": "[nodemon] starting", + "endsPattern": "Server listening on|Bot/ME service listening at|[nodemon] app crashed" + } + } + }, + { + "label": "Start Microsoft 365 Agents Playground", + "type": "shell", + "command": "npm run dev:teamsfx:launch-playground", + "isBackground": true, + "options": { + "env": { + "PATH": "${workspaceFolder}/devTools/playground/node_modules/.bin;${env:PATH}" + } + }, + "windows": { + "options": { + "env": { + "PATH": "${workspaceFolder}/devTools/playground/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" + } + } + ] +} diff --git a/nodejs/devin/sample-agent/README.md b/nodejs/devin/sample-agent/README.md index 07a042cf..c22fe117 100644 --- a/nodejs/devin/sample-agent/README.md +++ b/nodejs/devin/sample-agent/README.md @@ -17,6 +17,16 @@ For comprehensive documentation and guidance on building agents with the Microso - Microsoft Agent 365 SDK - Devin API credentials +## Running the Agent in Microsoft 365 Agents Playground + +1. First, select the Microsoft 365 Agents Toolkit icon on the left in the VS Code toolbar. +1. In file *env/.env.playground.user*, fill in your Devin API key `SECRET_DEVIN_API_KEY=`. +1. In file *env/.env.playground*, fill in your custom app registration client id `CLIENT_APP_ID`. +1. Press F5 to start debugging which launches your agent in Microsoft 365 Agents Playground using a web browser. Select `Debug in Microsoft 365 Agents Playground`. +1. You can send any message to get a response from the agent. + +**Congratulations**! You are running an agent that can now interact with users in Microsoft 365 Agents Playground. + ## Working with User Identity On every incoming message, the A365 platform populates `activity.from` with basic user diff --git a/nodejs/devin/sample-agent/env/.env.playground b/nodejs/devin/sample-agent/env/.env.playground new file mode 100644 index 00000000..81496a1c --- /dev/null +++ b/nodejs/devin/sample-agent/env/.env.playground @@ -0,0 +1,33 @@ +# 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=playground + +# Environment variables used by Microsoft 365 Agents Playground +TEAMSAPPTESTER_PORT=56150 +TEAMSFX_NOTIFICATION_STORE_FILENAME=.notification.testtoolstore.json + +# Custom app registration needed for bearer token +CLIENT_APP_ID= + +# Use Agentic Authentication rather than OBO +USE_AGENTIC_AUTH=false + +# Set service connection as default +connectionsMap__0__serviceUrl=* +connectionsMap__0__connection=serviceConnection + +# AgenticAuthentication Options +agentic_type=agentic +agentic_scopes=https://graph.microsoft.com/.default +agentic_connectionName=serviceConnection + +# Devin Configuration +DEVIN_BASE_URL=https://api.devin.ai/v1 +POLLING_INTERVAL_SECONDS=10 + +# Observability Configuration +ENABLE_OBSERVABILITY=true +ENABLE_A365_OBSERVABILITY=true +ENABLE_A365_OBSERVABILITY_EXPORTER=true +CLUSTER_CATEGORY=dev diff --git a/nodejs/devin/sample-agent/env/.env.playground.user b/nodejs/devin/sample-agent/env/.env.playground.user new file mode 100644 index 00000000..b873d96f --- /dev/null +++ b/nodejs/devin/sample-agent/env/.env.playground.user @@ -0,0 +1,4 @@ +# Devin Configuration +SECRET_DEVIN_API_KEY= + +SECRET_BEARER_TOKEN= diff --git a/nodejs/devin/sample-agent/m365agents.playground.yml b/nodejs/devin/sample-agent/m365agents.playground.yml new file mode 100644 index 00000000..6cfc480a --- /dev/null +++ b/nodejs/devin/sample-agent/m365agents.playground.yml @@ -0,0 +1,39 @@ +# yaml-language-server: $schema=https://aka.ms/m365-agents-toolkits/v1.11/yaml.schema.json +# Visit https://aka.ms/teamsfx-v5.0-guide for details on this file +# Visit https://aka.ms/teamsfx-actions for details on actions +version: v1.11 + +environmentFolderPath: ./env + +deploy: + # Install development tool(s) + - uses: devTool/install + with: + testTool: + version: ~0.2.7 + symlinkDir: ./devTools/playground + + # Run npm command + - uses: cli/runNpmCommand + with: + args: install + + - uses: file/createOrUpdateEnvironmentFile + with: + target: ./.localConfigs.playground + envs: + NODE_ENV: local + PORT: 3978 + TEAMSFX_NOTIFICATION_STORE_FILENAME: ${{TEAMSFX_NOTIFICATION_STORE_FILENAME}} + DEVIN_API_KEY: ${{SECRET_DEVIN_API_KEY}} + DEVIN_BASE_URL: ${{DEVIN_BASE_URL}} + POLLING_INTERVAL_SECONDS: ${{POLLING_INTERVAL_SECONDS}} + BEARER_TOKEN: ${{SECRET_BEARER_TOKEN}} + USE_AGENTIC_AUTH: ${{USE_AGENTIC_AUTH}} + connectionsMap__0__serviceUrl: ${{connectionsMap__0__serviceUrl}} + connectionsMap__0__connection: ${{connectionsMap__0__connection}} + agentic_type: ${{agentic_type}} + agentic_scopes: ${{agentic_scopes}} + connections__service_connection__settings__clientId: "" + connections__service_connection__settings__clientSecret: "" + connections__service_connection__settings__tenantId: "" diff --git a/nodejs/devin/sample-agent/m365agents.yml b/nodejs/devin/sample-agent/m365agents.yml new file mode 100644 index 00000000..50d15fc3 --- /dev/null +++ b/nodejs/devin/sample-agent/m365agents.yml @@ -0,0 +1,4 @@ +# yaml-language-server: $schema=https://aka.ms/m365-agents-toolkits/v1.11/yaml.schema.json +# Visit https://aka.ms/teamsfx-v5.0-guide for details on this file +# Visit https://aka.ms/teamsfx-actions for details on actions +version: v1.11 diff --git a/nodejs/devin/sample-agent/package.json b/nodejs/devin/sample-agent/package.json index 426bb851..c96b33dd 100644 --- a/nodejs/devin/sample-agent/package.json +++ b/nodejs/devin/sample-agent/package.json @@ -5,7 +5,10 @@ "scripts": { "build": "tsc", "start": "node --env-file=.env dist/index.js", - "test-tool": "agentsplayground" + "dev": "nodemon --exec node --inspect=9239 --signal SIGINT -r ts-node/register src/index.ts", + "test-tool": "agentsplayground", + "dev:teamsfx:playground": "env-cmd --silent -f .localConfigs.playground npm run dev", + "dev:teamsfx:launch-playground": "env-cmd --silent -f env/.env.playground agentsplayground start" }, "engines": { "node": ">=24.0.0" @@ -23,6 +26,10 @@ }, "devDependencies": { "@microsoft/m365agentsplayground": "^0.2.20", + "@types/node": "^20.14.9", + "env-cmd": "^11.0.0", + "nodemon": "^3.1.10", + "ts-node": "^10.9.2", "typescript": "^5.9.2" } } diff --git a/nodejs/n8n/sample-agent/.gitignore b/nodejs/n8n/sample-agent/.gitignore new file mode 100644 index 00000000..ddfa31e6 --- /dev/null +++ b/nodejs/n8n/sample-agent/.gitignore @@ -0,0 +1,24 @@ +# TeamsFx files +env/.env.*.user +env/.env.local +env/.env.sandbox +.localConfigs +.localConfigs.playground +.notification.localstore.json +.notification.playgroundstore.json +.notification.testtoolstore.json +appPackage/build + +# dependencies +node_modules/ + +# misc +.env +.deployment +.DS_Store + +# build +dist/ + +# Dev tool directories +/devTools/ diff --git a/nodejs/n8n/sample-agent/.vscode/extensions.json b/nodejs/n8n/sample-agent/.vscode/extensions.json new file mode 100644 index 00000000..aac0a6e3 --- /dev/null +++ b/nodejs/n8n/sample-agent/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "TeamsDevApp.ms-teams-vscode-extension" + ] +} diff --git a/nodejs/n8n/sample-agent/.vscode/launch.json b/nodejs/n8n/sample-agent/.vscode/launch.json new file mode 100644 index 00000000..20f088e2 --- /dev/null +++ b/nodejs/n8n/sample-agent/.vscode/launch.json @@ -0,0 +1,31 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to Local Service", + "type": "node", + "request": "attach", + "port": 9239, + "restart": true, + "presentation": { + "group": "all", + "hidden": true + }, + "internalConsoleOptions": "neverOpen" + } + ], + "compounds": [ + { + "name": "Debug in Microsoft 365 Agents Playground", + "configurations": [ + "Attach to Local Service" + ], + "preLaunchTask": "Start App in Microsoft 365 Agents Playground", + "presentation": { + "group": "1-playground", + "order": 1 + }, + "stopAll": true + } + ] +} diff --git a/nodejs/n8n/sample-agent/.vscode/scripts/refresh-bearer-token.ps1 b/nodejs/n8n/sample-agent/.vscode/scripts/refresh-bearer-token.ps1 new file mode 100644 index 00000000..2fee52fa --- /dev/null +++ b/nodejs/n8n/sample-agent/.vscode/scripts/refresh-bearer-token.ps1 @@ -0,0 +1,77 @@ +$ErrorActionPreference = 'Stop' + +$workspace = Get-Location +$playgroundEnvPath = Join-Path $workspace 'env/.env.playground' +$playgroundUserEnvPath = Join-Path $workspace 'env/.env.playground.user' + +$a365Command = Get-Command a365 -ErrorAction SilentlyContinue +if (-not $a365Command) { + throw "a365 CLI is not installed or not on PATH. Install with: dotnet tool install --global Microsoft.Agents.A365.DevTools.Cli" +} + +if (-not (Test-Path $playgroundEnvPath)) { + throw "Missing env file: $playgroundEnvPath" +} + +$appIdLine = Get-Content $playgroundEnvPath | Where-Object { $_ -match '^\s*CLIENT_APP_ID\s*=\s*.+$' } | Select-Object -First 1 +if (-not $appIdLine) { + throw "CLIENT_APP_ID is required in env/.env.playground" +} + +$appId = ($appIdLine -split '=', 2)[1].Trim() +if ([string]::IsNullOrWhiteSpace($appId)) { + throw "CLIENT_APP_ID in env/.env.playground is empty" +} + +Write-Host "Running a365 develop add-permissions for app id $appId" +& a365 develop add-permissions --app-id $appId +if ($LASTEXITCODE -ne 0) { + throw "a365 develop add-permissions failed" +} + +Write-Host "Getting bearer token via a365..." +Write-Host "This may complete silently using cached credentials, or it may require interactive Windows sign-in (WAM)." +Write-Host "If interactive sign-in is required and no prompt appears, check the taskbar for a hidden sign-in window and bring it to front." +Write-Host "Running a365 develop get-token for app id $appId" +$tokenOutput = & a365 develop get-token --app-id $appId --output raw +if ($LASTEXITCODE -ne 0) { + throw "a365 develop get-token failed" +} + +$rawOutput = [string]::Join("`n", $tokenOutput) +$rawOutput = $rawOutput -replace "`r", '' + +$bearerToken = $null +$jwtRegex = '(?[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)' +$jwtMatches = [regex]::Matches($rawOutput, $jwtRegex) +if ($jwtMatches.Count -gt 0) { + $bearerToken = ($jwtMatches | ForEach-Object { $_.Groups['token'].Value } | Sort-Object Length -Descending | Select-Object -First 1).Trim() +} + +if ([string]::IsNullOrWhiteSpace($bearerToken)) { + throw "Unable to extract a bearer token from a365 develop get-token output" +} + +$userEnvLines = @() +if (Test-Path $playgroundUserEnvPath) { + $userEnvLines = Get-Content $playgroundUserEnvPath +} + +$updated = $false +for ($i = 0; $i -lt $userEnvLines.Count; $i++) { + if ($userEnvLines[$i] -match '^\s*SECRET_BEARER_TOKEN\s*=') { + $userEnvLines[$i] = "SECRET_BEARER_TOKEN=$bearerToken" + $updated = $true + break + } +} + +if (-not $updated) { + if ($userEnvLines.Count -gt 0 -and -not [string]::IsNullOrWhiteSpace($userEnvLines[$userEnvLines.Count - 1])) { + $userEnvLines += '' + } + $userEnvLines += "SECRET_BEARER_TOKEN=$bearerToken" +} + +Set-Content -Path $playgroundUserEnvPath -Value $userEnvLines -Encoding UTF8 +Write-Host 'SECRET_BEARER_TOKEN has been updated in env/.env.playground.user' diff --git a/nodejs/n8n/sample-agent/.vscode/tasks.json b/nodejs/n8n/sample-agent/.vscode/tasks.json new file mode 100644 index 00000000..c08b1c64 --- /dev/null +++ b/nodejs/n8n/sample-agent/.vscode/tasks.json @@ -0,0 +1,117 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Start App in Microsoft 365 Agents Playground", + "dependsOn": [ + "Validate prerequisites (Microsoft 365 Agents Playground)", + "Refresh bearer token (Microsoft 365 Agents Playground)", + "Deploy (Microsoft 365 Agents Playground)", + "Start application (Microsoft 365 Agents Playground)", + "Start Microsoft 365 Agents Playground" + ], + "dependsOrder": "sequence" + }, + { + "label": "Validate prerequisites (Microsoft 365 Agents Playground)", + "type": "teamsfx", + "command": "debug-check-prerequisites", + "args": { + "prerequisites": [ + "nodejs", + "portOccupancy" + ], + "portOccupancy": [ + 3978, + 9239, + 56150 + ] + } + }, + { + "label": "Refresh bearer token (Microsoft 365 Agents Playground)", + "type": "shell", + "command": "powershell", + "args": [ + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-File", + "${workspaceFolder}/.vscode/scripts/refresh-bearer-token.ps1" + ], + "options": { + "cwd": "${workspaceFolder}" + } + }, + { + "label": "Deploy (Microsoft 365 Agents Playground)", + "dependsOrder": "sequence", + "type": "teamsfx", + "command": "deploy", + "args": { + "env": "playground" + } + }, + { + "label": "Start application (Microsoft 365 Agents Playground)", + "type": "shell", + "command": "npm run dev:teamsfx:playground", + "isBackground": true, + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": { + "pattern": [ + { + "regexp": "^.*$", + "file": 0, + "location": 1, + "message": 2 + } + ], + "background": { + "activeOnStart": true, + "beginsPattern": "[nodemon] starting", + "endsPattern": "Server listening on|Bot/ME service listening at|[nodemon] app crashed" + } + } + }, + { + "label": "Start Microsoft 365 Agents Playground", + "type": "shell", + "command": "npm run dev:teamsfx:launch-playground", + "isBackground": true, + "options": { + "env": { + "PATH": "${workspaceFolder}/devTools/playground/node_modules/.bin;${env:PATH}" + } + }, + "windows": { + "options": { + "env": { + "PATH": "${workspaceFolder}/devTools/playground/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" + } + } + ] +} diff --git a/nodejs/n8n/sample-agent/env/.env.playground b/nodejs/n8n/sample-agent/env/.env.playground new file mode 100644 index 00000000..c1d20191 --- /dev/null +++ b/nodejs/n8n/sample-agent/env/.env.playground @@ -0,0 +1,23 @@ +# 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=playground + +# Environment variables used by Microsoft 365 Agents Playground +TEAMSAPPTESTER_PORT=56150 +TEAMSFX_NOTIFICATION_STORE_FILENAME=.notification.testtoolstore.json + +# Custom app registration needed for bearer token +CLIENT_APP_ID= + +# Use Agentic Authentication rather than OBO +USE_AGENTIC_AUTH=false + +# Set service connection as default +connectionsMap__0__serviceUrl=* +connectionsMap__0__connection=service_connection + +# AgenticAuthentication Options +agentic_type=agentic +agentic_altBlueprintConnectionName=service_connection +agentic_scopes=ea9ffc3e-8a23-4a7d-836d-234d7c7565c1/.default # Prod Agentic scope diff --git a/nodejs/n8n/sample-agent/m365agents.playground.yml b/nodejs/n8n/sample-agent/m365agents.playground.yml new file mode 100644 index 00000000..24d89b94 --- /dev/null +++ b/nodejs/n8n/sample-agent/m365agents.playground.yml @@ -0,0 +1,37 @@ +# yaml-language-server: $schema=https://aka.ms/m365-agents-toolkits/v1.11/yaml.schema.json +# Visit https://aka.ms/teamsfx-v5.0-guide for details on this file +# Visit https://aka.ms/teamsfx-actions for details on actions +version: v1.11 + +environmentFolderPath: ./env + +deploy: + # Install development tool(s) + - uses: devTool/install + with: + testTool: + version: ~0.2.7 + symlinkDir: ./devTools/playground + + # Run npm command + - uses: cli/runNpmCommand + with: + args: install + + - uses: file/createOrUpdateEnvironmentFile + with: + target: ./.localConfigs.playground + envs: + NODE_ENV: local + PORT: 3978 + TEAMSFX_NOTIFICATION_STORE_FILENAME: ${{TEAMSFX_NOTIFICATION_STORE_FILENAME}} + BEARER_TOKEN: ${{SECRET_BEARER_TOKEN}} + USE_AGENTIC_AUTH: ${{USE_AGENTIC_AUTH}} + connectionsMap__0__serviceUrl: ${{connectionsMap__0__serviceUrl}} + connectionsMap__0__connection: ${{connectionsMap__0__connection}} + agentic_type: ${{agentic_type}} + agentic_altBlueprintConnectionName: ${{agentic_altBlueprintConnectionName}} + agentic_scopes: ${{agentic_scopes}} + connections__service_connection__settings__clientId: "" + connections__service_connection__settings__clientSecret: "" + connections__service_connection__settings__tenantId: "" diff --git a/nodejs/n8n/sample-agent/m365agents.yml b/nodejs/n8n/sample-agent/m365agents.yml new file mode 100644 index 00000000..50d15fc3 --- /dev/null +++ b/nodejs/n8n/sample-agent/m365agents.yml @@ -0,0 +1,4 @@ +# yaml-language-server: $schema=https://aka.ms/m365-agents-toolkits/v1.11/yaml.schema.json +# Visit https://aka.ms/teamsfx-v5.0-guide for details on this file +# Visit https://aka.ms/teamsfx-actions for details on actions +version: v1.11 diff --git a/nodejs/openai/sample-agent/.gitignore b/nodejs/openai/sample-agent/.gitignore new file mode 100644 index 00000000..ddfa31e6 --- /dev/null +++ b/nodejs/openai/sample-agent/.gitignore @@ -0,0 +1,24 @@ +# TeamsFx files +env/.env.*.user +env/.env.local +env/.env.sandbox +.localConfigs +.localConfigs.playground +.notification.localstore.json +.notification.playgroundstore.json +.notification.testtoolstore.json +appPackage/build + +# dependencies +node_modules/ + +# misc +.env +.deployment +.DS_Store + +# build +dist/ + +# Dev tool directories +/devTools/ diff --git a/nodejs/openai/sample-agent/.vscode/extensions.json b/nodejs/openai/sample-agent/.vscode/extensions.json new file mode 100644 index 00000000..aac0a6e3 --- /dev/null +++ b/nodejs/openai/sample-agent/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "TeamsDevApp.ms-teams-vscode-extension" + ] +} diff --git a/nodejs/openai/sample-agent/.vscode/launch.json b/nodejs/openai/sample-agent/.vscode/launch.json new file mode 100644 index 00000000..20f088e2 --- /dev/null +++ b/nodejs/openai/sample-agent/.vscode/launch.json @@ -0,0 +1,31 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to Local Service", + "type": "node", + "request": "attach", + "port": 9239, + "restart": true, + "presentation": { + "group": "all", + "hidden": true + }, + "internalConsoleOptions": "neverOpen" + } + ], + "compounds": [ + { + "name": "Debug in Microsoft 365 Agents Playground", + "configurations": [ + "Attach to Local Service" + ], + "preLaunchTask": "Start App in Microsoft 365 Agents Playground", + "presentation": { + "group": "1-playground", + "order": 1 + }, + "stopAll": true + } + ] +} diff --git a/nodejs/openai/sample-agent/.vscode/scripts/refresh-bearer-token.ps1 b/nodejs/openai/sample-agent/.vscode/scripts/refresh-bearer-token.ps1 new file mode 100644 index 00000000..2fee52fa --- /dev/null +++ b/nodejs/openai/sample-agent/.vscode/scripts/refresh-bearer-token.ps1 @@ -0,0 +1,77 @@ +$ErrorActionPreference = 'Stop' + +$workspace = Get-Location +$playgroundEnvPath = Join-Path $workspace 'env/.env.playground' +$playgroundUserEnvPath = Join-Path $workspace 'env/.env.playground.user' + +$a365Command = Get-Command a365 -ErrorAction SilentlyContinue +if (-not $a365Command) { + throw "a365 CLI is not installed or not on PATH. Install with: dotnet tool install --global Microsoft.Agents.A365.DevTools.Cli" +} + +if (-not (Test-Path $playgroundEnvPath)) { + throw "Missing env file: $playgroundEnvPath" +} + +$appIdLine = Get-Content $playgroundEnvPath | Where-Object { $_ -match '^\s*CLIENT_APP_ID\s*=\s*.+$' } | Select-Object -First 1 +if (-not $appIdLine) { + throw "CLIENT_APP_ID is required in env/.env.playground" +} + +$appId = ($appIdLine -split '=', 2)[1].Trim() +if ([string]::IsNullOrWhiteSpace($appId)) { + throw "CLIENT_APP_ID in env/.env.playground is empty" +} + +Write-Host "Running a365 develop add-permissions for app id $appId" +& a365 develop add-permissions --app-id $appId +if ($LASTEXITCODE -ne 0) { + throw "a365 develop add-permissions failed" +} + +Write-Host "Getting bearer token via a365..." +Write-Host "This may complete silently using cached credentials, or it may require interactive Windows sign-in (WAM)." +Write-Host "If interactive sign-in is required and no prompt appears, check the taskbar for a hidden sign-in window and bring it to front." +Write-Host "Running a365 develop get-token for app id $appId" +$tokenOutput = & a365 develop get-token --app-id $appId --output raw +if ($LASTEXITCODE -ne 0) { + throw "a365 develop get-token failed" +} + +$rawOutput = [string]::Join("`n", $tokenOutput) +$rawOutput = $rawOutput -replace "`r", '' + +$bearerToken = $null +$jwtRegex = '(?[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)' +$jwtMatches = [regex]::Matches($rawOutput, $jwtRegex) +if ($jwtMatches.Count -gt 0) { + $bearerToken = ($jwtMatches | ForEach-Object { $_.Groups['token'].Value } | Sort-Object Length -Descending | Select-Object -First 1).Trim() +} + +if ([string]::IsNullOrWhiteSpace($bearerToken)) { + throw "Unable to extract a bearer token from a365 develop get-token output" +} + +$userEnvLines = @() +if (Test-Path $playgroundUserEnvPath) { + $userEnvLines = Get-Content $playgroundUserEnvPath +} + +$updated = $false +for ($i = 0; $i -lt $userEnvLines.Count; $i++) { + if ($userEnvLines[$i] -match '^\s*SECRET_BEARER_TOKEN\s*=') { + $userEnvLines[$i] = "SECRET_BEARER_TOKEN=$bearerToken" + $updated = $true + break + } +} + +if (-not $updated) { + if ($userEnvLines.Count -gt 0 -and -not [string]::IsNullOrWhiteSpace($userEnvLines[$userEnvLines.Count - 1])) { + $userEnvLines += '' + } + $userEnvLines += "SECRET_BEARER_TOKEN=$bearerToken" +} + +Set-Content -Path $playgroundUserEnvPath -Value $userEnvLines -Encoding UTF8 +Write-Host 'SECRET_BEARER_TOKEN has been updated in env/.env.playground.user' diff --git a/nodejs/openai/sample-agent/.vscode/tasks.json b/nodejs/openai/sample-agent/.vscode/tasks.json new file mode 100644 index 00000000..c08b1c64 --- /dev/null +++ b/nodejs/openai/sample-agent/.vscode/tasks.json @@ -0,0 +1,117 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Start App in Microsoft 365 Agents Playground", + "dependsOn": [ + "Validate prerequisites (Microsoft 365 Agents Playground)", + "Refresh bearer token (Microsoft 365 Agents Playground)", + "Deploy (Microsoft 365 Agents Playground)", + "Start application (Microsoft 365 Agents Playground)", + "Start Microsoft 365 Agents Playground" + ], + "dependsOrder": "sequence" + }, + { + "label": "Validate prerequisites (Microsoft 365 Agents Playground)", + "type": "teamsfx", + "command": "debug-check-prerequisites", + "args": { + "prerequisites": [ + "nodejs", + "portOccupancy" + ], + "portOccupancy": [ + 3978, + 9239, + 56150 + ] + } + }, + { + "label": "Refresh bearer token (Microsoft 365 Agents Playground)", + "type": "shell", + "command": "powershell", + "args": [ + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-File", + "${workspaceFolder}/.vscode/scripts/refresh-bearer-token.ps1" + ], + "options": { + "cwd": "${workspaceFolder}" + } + }, + { + "label": "Deploy (Microsoft 365 Agents Playground)", + "dependsOrder": "sequence", + "type": "teamsfx", + "command": "deploy", + "args": { + "env": "playground" + } + }, + { + "label": "Start application (Microsoft 365 Agents Playground)", + "type": "shell", + "command": "npm run dev:teamsfx:playground", + "isBackground": true, + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": { + "pattern": [ + { + "regexp": "^.*$", + "file": 0, + "location": 1, + "message": 2 + } + ], + "background": { + "activeOnStart": true, + "beginsPattern": "[nodemon] starting", + "endsPattern": "Server listening on|Bot/ME service listening at|[nodemon] app crashed" + } + } + }, + { + "label": "Start Microsoft 365 Agents Playground", + "type": "shell", + "command": "npm run dev:teamsfx:launch-playground", + "isBackground": true, + "options": { + "env": { + "PATH": "${workspaceFolder}/devTools/playground/node_modules/.bin;${env:PATH}" + } + }, + "windows": { + "options": { + "env": { + "PATH": "${workspaceFolder}/devTools/playground/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" + } + } + ] +} diff --git a/nodejs/openai/sample-agent/README.md b/nodejs/openai/sample-agent/README.md index b14c29e2..711a18af 100644 --- a/nodejs/openai/sample-agent/README.md +++ b/nodejs/openai/sample-agent/README.md @@ -18,6 +18,17 @@ For comprehensive documentation and guidance on building agents with the Microso - OpenAI Agents SDK - Azure/OpenAI API credentials +## Running the Agent in Microsoft 365 Agents Playground + +1. First, select the Microsoft 365 Agents Toolkit icon on the left in the VS Code toolbar. +1. In file *env/.env.playground.user*, fill in your OpenAI key `SECRET_OPENAI_API_KEY=` if you're using OpenAI. +1. In file *env/.env.playground.user*, fill in your Azure OpenAI key `SECRET_AZURE_OPENAI_API_KEY=`, endpoint `AZURE_OPENAI_ENDPOINT=`, and deployment `AZURE_OPENAI_DEPLOYMENT=` if you're using Azure OpenAI. +1. In file *env/.env.playground*, fill in your custom app registration client id `CLIENT_APP_ID`. +1. Press F5 to start debugging which launches your agent in Microsoft 365 Agents Playground using a web browser. Select `Debug in Microsoft 365 Agents Playground`. +1. You can send any message to get a response from the agent. + +**Congratulations**! You are running an agent that can now interact with users in Microsoft 365 Agents Playground. + ## Working with User Identity On every incoming message, the A365 platform populates `activity.from` with basic user diff --git a/nodejs/openai/sample-agent/env/.env.playground b/nodejs/openai/sample-agent/env/.env.playground new file mode 100644 index 00000000..051b37c5 --- /dev/null +++ b/nodejs/openai/sample-agent/env/.env.playground @@ -0,0 +1,31 @@ +# 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=playground + +# Environment variables used by Microsoft 365 Agents Playground +TEAMSAPPTESTER_PORT=56150 +TEAMSFX_NOTIFICATION_STORE_FILENAME=.notification.testtoolstore.json + +# Custom app registration needed for bearer token +CLIENT_APP_ID= + +# Use Agentic Authentication rather than OBO +USE_AGENTIC_AUTH=false + +# Set service connection as default +connectionsMap__0__serviceUrl=* +connectionsMap__0__connection=service_connection + +# AgenticAuthentication Options +agentic_type=agentic +agentic_altBlueprintConnectionName=service_connection +agentic_scopes=ea9ffc3e-8a23-4a7d-836d-234d7c7565c1/.default # Prod Agentic scope + +# Observability Configuration +ENABLE_A365_OBSERVABILITY_EXPORTER=false +Use_Custom_Resolver=true +A365_OBSERVABILITY_LOG_LEVEL= + +# Telemetry and Tracing Configuration +DEBUG=agents:* diff --git a/nodejs/openai/sample-agent/env/.env.playground.user b/nodejs/openai/sample-agent/env/.env.playground.user new file mode 100644 index 00000000..2558a548 --- /dev/null +++ b/nodejs/openai/sample-agent/env/.env.playground.user @@ -0,0 +1,12 @@ +# OpenAI Configuration +# Option 1: Standard OpenAI API +SECRET_OPENAI_API_KEY= +OPENAI_MODEL=gpt-4o + +# Option 2: Azure OpenAI (takes precedence if SECRET_AZURE_OPENAI_API_KEY is set) +SECRET_AZURE_OPENAI_API_KEY= +AZURE_OPENAI_ENDPOINT= +AZURE_OPENAI_DEPLOYMENT= +AZURE_OPENAI_API_VERSION=2024-10-21 + +SECRET_BEARER_TOKEN= diff --git a/nodejs/openai/sample-agent/m365agents.playground.yml b/nodejs/openai/sample-agent/m365agents.playground.yml new file mode 100644 index 00000000..0621f6b6 --- /dev/null +++ b/nodejs/openai/sample-agent/m365agents.playground.yml @@ -0,0 +1,44 @@ +# yaml-language-server: $schema=https://aka.ms/m365-agents-toolkits/v1.11/yaml.schema.json +# Visit https://aka.ms/teamsfx-v5.0-guide for details on this file +# Visit https://aka.ms/teamsfx-actions for details on actions +version: v1.11 + +environmentFolderPath: ./env + +deploy: + # Install development tool(s) + - uses: devTool/install + with: + testTool: + version: ~0.2.7 + symlinkDir: ./devTools/playground + + # Run npm command + - uses: cli/runNpmCommand + with: + args: install + + - uses: file/createOrUpdateEnvironmentFile + with: + target: ./.localConfigs.playground + envs: + NODE_ENV: local + PORT: 3978 + HOST: 127.0.0.1 + TEAMSFX_NOTIFICATION_STORE_FILENAME: ${{TEAMSFX_NOTIFICATION_STORE_FILENAME}} + # OPENAI_API_KEY: ${{SECRET_OPENAI_API_KEY}} + # OPENAI_MODEL: ${{OPENAI_MODEL}} + AZURE_OPENAI_API_KEY: ${{SECRET_AZURE_OPENAI_API_KEY}} + AZURE_OPENAI_ENDPOINT: ${{AZURE_OPENAI_ENDPOINT}} + AZURE_OPENAI_DEPLOYMENT: ${{AZURE_OPENAI_DEPLOYMENT}} + AZURE_OPENAI_API_VERSION: ${{AZURE_OPENAI_API_VERSION}} + BEARER_TOKEN: ${{SECRET_BEARER_TOKEN}} + USE_AGENTIC_AUTH: ${{USE_AGENTIC_AUTH}} + connectionsMap__0__serviceUrl: ${{connectionsMap__0__serviceUrl}} + connectionsMap__0__connection: ${{connectionsMap__0__connection}} + agentic_type: ${{agentic_type}} + agentic_altBlueprintConnectionName: ${{agentic_altBlueprintConnectionName}} + agentic_scopes: ${{agentic_scopes}} + connections__service_connection__settings__clientId: "" + connections__service_connection__settings__clientSecret: "" + connections__service_connection__settings__tenantId: "" diff --git a/nodejs/openai/sample-agent/m365agents.yml b/nodejs/openai/sample-agent/m365agents.yml new file mode 100644 index 00000000..50d15fc3 --- /dev/null +++ b/nodejs/openai/sample-agent/m365agents.yml @@ -0,0 +1,4 @@ +# yaml-language-server: $schema=https://aka.ms/m365-agents-toolkits/v1.11/yaml.schema.json +# Visit https://aka.ms/teamsfx-v5.0-guide for details on this file +# Visit https://aka.ms/teamsfx-actions for details on actions +version: v1.11 diff --git a/nodejs/openai/sample-agent/package.json b/nodejs/openai/sample-agent/package.json index 89df73ed..8d152125 100644 --- a/nodejs/openai/sample-agent/package.json +++ b/nodejs/openai/sample-agent/package.json @@ -5,11 +5,13 @@ "type": "commonjs", "scripts": { "start": "node dist/index.js", - "dev": "nodemon --watch src --exec ts-node src/index.ts", + "dev": "nodemon --exec node --inspect=9239 --signal SIGINT -r ts-node/register src/index.ts", "test-tool": "agentsplayground", "install:clean": "npm run clean && npm install", "clean": "rimraf dist node_modules package-lock.json", - "build": "tsc" + "build": "tsc", + "dev:teamsfx:playground": "env-cmd --silent -f .localConfigs.playground npm run dev", + "dev:teamsfx:launch-playground": "env-cmd --silent -f env/.env.playground agentsplayground start" }, "keywords": [], "license": "MIT", @@ -33,6 +35,7 @@ "@microsoft/m365agentsplayground": "^0.2.18", "@types/express": "^4.17.21", "@types/node": "^20.14.9", + "env-cmd": "^11.0.0", "nodemon": "^3.1.10", "rimraf": "^5.0.0", "ts-node": "^10.9.2", diff --git a/nodejs/perplexity/sample-agent/.gitignore b/nodejs/perplexity/sample-agent/.gitignore new file mode 100644 index 00000000..ddfa31e6 --- /dev/null +++ b/nodejs/perplexity/sample-agent/.gitignore @@ -0,0 +1,24 @@ +# TeamsFx files +env/.env.*.user +env/.env.local +env/.env.sandbox +.localConfigs +.localConfigs.playground +.notification.localstore.json +.notification.playgroundstore.json +.notification.testtoolstore.json +appPackage/build + +# dependencies +node_modules/ + +# misc +.env +.deployment +.DS_Store + +# build +dist/ + +# Dev tool directories +/devTools/ diff --git a/nodejs/perplexity/sample-agent/.vscode/extensions.json b/nodejs/perplexity/sample-agent/.vscode/extensions.json new file mode 100644 index 00000000..aac0a6e3 --- /dev/null +++ b/nodejs/perplexity/sample-agent/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "TeamsDevApp.ms-teams-vscode-extension" + ] +} diff --git a/nodejs/perplexity/sample-agent/.vscode/launch.json b/nodejs/perplexity/sample-agent/.vscode/launch.json new file mode 100644 index 00000000..20f088e2 --- /dev/null +++ b/nodejs/perplexity/sample-agent/.vscode/launch.json @@ -0,0 +1,31 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to Local Service", + "type": "node", + "request": "attach", + "port": 9239, + "restart": true, + "presentation": { + "group": "all", + "hidden": true + }, + "internalConsoleOptions": "neverOpen" + } + ], + "compounds": [ + { + "name": "Debug in Microsoft 365 Agents Playground", + "configurations": [ + "Attach to Local Service" + ], + "preLaunchTask": "Start App in Microsoft 365 Agents Playground", + "presentation": { + "group": "1-playground", + "order": 1 + }, + "stopAll": true + } + ] +} diff --git a/nodejs/perplexity/sample-agent/.vscode/scripts/refresh-bearer-token.ps1 b/nodejs/perplexity/sample-agent/.vscode/scripts/refresh-bearer-token.ps1 new file mode 100644 index 00000000..2fee52fa --- /dev/null +++ b/nodejs/perplexity/sample-agent/.vscode/scripts/refresh-bearer-token.ps1 @@ -0,0 +1,77 @@ +$ErrorActionPreference = 'Stop' + +$workspace = Get-Location +$playgroundEnvPath = Join-Path $workspace 'env/.env.playground' +$playgroundUserEnvPath = Join-Path $workspace 'env/.env.playground.user' + +$a365Command = Get-Command a365 -ErrorAction SilentlyContinue +if (-not $a365Command) { + throw "a365 CLI is not installed or not on PATH. Install with: dotnet tool install --global Microsoft.Agents.A365.DevTools.Cli" +} + +if (-not (Test-Path $playgroundEnvPath)) { + throw "Missing env file: $playgroundEnvPath" +} + +$appIdLine = Get-Content $playgroundEnvPath | Where-Object { $_ -match '^\s*CLIENT_APP_ID\s*=\s*.+$' } | Select-Object -First 1 +if (-not $appIdLine) { + throw "CLIENT_APP_ID is required in env/.env.playground" +} + +$appId = ($appIdLine -split '=', 2)[1].Trim() +if ([string]::IsNullOrWhiteSpace($appId)) { + throw "CLIENT_APP_ID in env/.env.playground is empty" +} + +Write-Host "Running a365 develop add-permissions for app id $appId" +& a365 develop add-permissions --app-id $appId +if ($LASTEXITCODE -ne 0) { + throw "a365 develop add-permissions failed" +} + +Write-Host "Getting bearer token via a365..." +Write-Host "This may complete silently using cached credentials, or it may require interactive Windows sign-in (WAM)." +Write-Host "If interactive sign-in is required and no prompt appears, check the taskbar for a hidden sign-in window and bring it to front." +Write-Host "Running a365 develop get-token for app id $appId" +$tokenOutput = & a365 develop get-token --app-id $appId --output raw +if ($LASTEXITCODE -ne 0) { + throw "a365 develop get-token failed" +} + +$rawOutput = [string]::Join("`n", $tokenOutput) +$rawOutput = $rawOutput -replace "`r", '' + +$bearerToken = $null +$jwtRegex = '(?[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)' +$jwtMatches = [regex]::Matches($rawOutput, $jwtRegex) +if ($jwtMatches.Count -gt 0) { + $bearerToken = ($jwtMatches | ForEach-Object { $_.Groups['token'].Value } | Sort-Object Length -Descending | Select-Object -First 1).Trim() +} + +if ([string]::IsNullOrWhiteSpace($bearerToken)) { + throw "Unable to extract a bearer token from a365 develop get-token output" +} + +$userEnvLines = @() +if (Test-Path $playgroundUserEnvPath) { + $userEnvLines = Get-Content $playgroundUserEnvPath +} + +$updated = $false +for ($i = 0; $i -lt $userEnvLines.Count; $i++) { + if ($userEnvLines[$i] -match '^\s*SECRET_BEARER_TOKEN\s*=') { + $userEnvLines[$i] = "SECRET_BEARER_TOKEN=$bearerToken" + $updated = $true + break + } +} + +if (-not $updated) { + if ($userEnvLines.Count -gt 0 -and -not [string]::IsNullOrWhiteSpace($userEnvLines[$userEnvLines.Count - 1])) { + $userEnvLines += '' + } + $userEnvLines += "SECRET_BEARER_TOKEN=$bearerToken" +} + +Set-Content -Path $playgroundUserEnvPath -Value $userEnvLines -Encoding UTF8 +Write-Host 'SECRET_BEARER_TOKEN has been updated in env/.env.playground.user' diff --git a/nodejs/perplexity/sample-agent/.vscode/tasks.json b/nodejs/perplexity/sample-agent/.vscode/tasks.json new file mode 100644 index 00000000..c08b1c64 --- /dev/null +++ b/nodejs/perplexity/sample-agent/.vscode/tasks.json @@ -0,0 +1,117 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Start App in Microsoft 365 Agents Playground", + "dependsOn": [ + "Validate prerequisites (Microsoft 365 Agents Playground)", + "Refresh bearer token (Microsoft 365 Agents Playground)", + "Deploy (Microsoft 365 Agents Playground)", + "Start application (Microsoft 365 Agents Playground)", + "Start Microsoft 365 Agents Playground" + ], + "dependsOrder": "sequence" + }, + { + "label": "Validate prerequisites (Microsoft 365 Agents Playground)", + "type": "teamsfx", + "command": "debug-check-prerequisites", + "args": { + "prerequisites": [ + "nodejs", + "portOccupancy" + ], + "portOccupancy": [ + 3978, + 9239, + 56150 + ] + } + }, + { + "label": "Refresh bearer token (Microsoft 365 Agents Playground)", + "type": "shell", + "command": "powershell", + "args": [ + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-File", + "${workspaceFolder}/.vscode/scripts/refresh-bearer-token.ps1" + ], + "options": { + "cwd": "${workspaceFolder}" + } + }, + { + "label": "Deploy (Microsoft 365 Agents Playground)", + "dependsOrder": "sequence", + "type": "teamsfx", + "command": "deploy", + "args": { + "env": "playground" + } + }, + { + "label": "Start application (Microsoft 365 Agents Playground)", + "type": "shell", + "command": "npm run dev:teamsfx:playground", + "isBackground": true, + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": { + "pattern": [ + { + "regexp": "^.*$", + "file": 0, + "location": 1, + "message": 2 + } + ], + "background": { + "activeOnStart": true, + "beginsPattern": "[nodemon] starting", + "endsPattern": "Server listening on|Bot/ME service listening at|[nodemon] app crashed" + } + } + }, + { + "label": "Start Microsoft 365 Agents Playground", + "type": "shell", + "command": "npm run dev:teamsfx:launch-playground", + "isBackground": true, + "options": { + "env": { + "PATH": "${workspaceFolder}/devTools/playground/node_modules/.bin;${env:PATH}" + } + }, + "windows": { + "options": { + "env": { + "PATH": "${workspaceFolder}/devTools/playground/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" + } + } + ] +} diff --git a/nodejs/perplexity/sample-agent/README.md b/nodejs/perplexity/sample-agent/README.md index 50e7d9d8..436bbc1e 100644 --- a/nodejs/perplexity/sample-agent/README.md +++ b/nodejs/perplexity/sample-agent/README.md @@ -17,6 +17,16 @@ For comprehensive documentation and guidance on building agents with the Microso - Microsoft Agent 365 SDK - Perplexity API credentials +## Running the Agent in Microsoft 365 Agents Playground + +1. First, select the Microsoft 365 Agents Toolkit icon on the left in the VS Code toolbar. +1. In file *env/.env.playground.user*, fill in your Perplexity API key `SECRET_PERPLEXITY_API_KEY=`. +1. In file *env/.env.playground*, fill in your custom app registration client id `CLIENT_APP_ID`. +1. Press F5 to start debugging which launches your agent in Microsoft 365 Agents Playground using a web browser. Select `Debug in Microsoft 365 Agents Playground`. +1. You can send any message to get a response from the agent. + +**Congratulations**! You are running an agent that can now interact with users in Microsoft 365 Agents Playground. + ## Working with User Identity On every incoming message, the A365 platform populates `activity.from` with basic user diff --git a/nodejs/perplexity/sample-agent/env/.env.playground b/nodejs/perplexity/sample-agent/env/.env.playground new file mode 100644 index 00000000..c549f30c --- /dev/null +++ b/nodejs/perplexity/sample-agent/env/.env.playground @@ -0,0 +1,38 @@ +# 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=playground + +# Environment variables used by Microsoft 365 Agents Playground +TEAMSAPPTESTER_PORT=56150 +TEAMSFX_NOTIFICATION_STORE_FILENAME=.notification.testtoolstore.json + +# Custom app registration needed for bearer token +CLIENT_APP_ID= + +# Use Agentic Authentication rather than OBO +USE_AGENTIC_AUTH=false + +# Set service connection as default +connectionsMap__0__serviceUrl=* +connectionsMap__0__connection=serviceConnection + +# AgenticAuthentication Options +agentic_type=agentic +agentic_scopes=https://graph.microsoft.com/.default +agentic_connectionName=serviceConnection +agentic_altBlueprintConnectionName=serviceConnection + +# Perplexity Configuration +PERPLEXITY_MODEL=sonar + +# Observability Configuration +A365_OBSERVABILITY_LOG_LEVEL=info +ENABLE_OBSERVABILITY=false +ENABLE_A365_OBSERVABILITY=false +ENABLE_A365_OBSERVABILITY_EXPORTER=false +CLUSTER_CATEGORY=prod +DEBUG=false + +# Presence Configuration +PRESENCE_CLIENTID=<> diff --git a/nodejs/perplexity/sample-agent/env/.env.playground.user b/nodejs/perplexity/sample-agent/env/.env.playground.user new file mode 100644 index 00000000..b4081d39 --- /dev/null +++ b/nodejs/perplexity/sample-agent/env/.env.playground.user @@ -0,0 +1,7 @@ +# Perplexity Configuration +SECRET_PERPLEXITY_API_KEY= + +SECRET_BEARER_TOKEN= + +# Presence Configuration (secret) +PRESENCE_CLIENTSECRET=<> diff --git a/nodejs/perplexity/sample-agent/m365agents.playground.yml b/nodejs/perplexity/sample-agent/m365agents.playground.yml new file mode 100644 index 00000000..c21514cb --- /dev/null +++ b/nodejs/perplexity/sample-agent/m365agents.playground.yml @@ -0,0 +1,42 @@ +# yaml-language-server: $schema=https://aka.ms/m365-agents-toolkits/v1.11/yaml.schema.json +# Visit https://aka.ms/teamsfx-v5.0-guide for details on this file +# Visit https://aka.ms/teamsfx-actions for details on actions +version: v1.11 + +environmentFolderPath: ./env + +deploy: + # Install development tool(s) + - uses: devTool/install + with: + testTool: + version: ~0.2.7 + symlinkDir: ./devTools/playground + + # Run npm command + - uses: cli/runNpmCommand + with: + args: install + + - uses: file/createOrUpdateEnvironmentFile + with: + target: ./.localConfigs.playground + envs: + NODE_ENV: local + PORT: 3978 + TEAMSFX_NOTIFICATION_STORE_FILENAME: ${{TEAMSFX_NOTIFICATION_STORE_FILENAME}} + PERPLEXITY_API_KEY: ${{SECRET_PERPLEXITY_API_KEY}} + PERPLEXITY_MODEL: ${{PERPLEXITY_MODEL}} + BEARER_TOKEN: ${{SECRET_BEARER_TOKEN}} + USE_AGENTIC_AUTH: ${{USE_AGENTIC_AUTH}} + PRESENCE_CLIENTID: ${{PRESENCE_CLIENTID}} + PRESENCE_CLIENTSECRET: ${{PRESENCE_CLIENTSECRET}} + connectionsMap__0__serviceUrl: ${{connectionsMap__0__serviceUrl}} + connectionsMap__0__connection: ${{connectionsMap__0__connection}} + agentic_type: ${{agentic_type}} + agentic_scopes: ${{agentic_scopes}} + agentic_connectionName: ${{agentic_connectionName}} + agentic_altBlueprintConnectionName: ${{agentic_altBlueprintConnectionName}} + connections__service_connection__settings__clientId: "" + connections__service_connection__settings__clientSecret: "" + connections__service_connection__settings__tenantId: "" diff --git a/nodejs/perplexity/sample-agent/m365agents.yml b/nodejs/perplexity/sample-agent/m365agents.yml new file mode 100644 index 00000000..50d15fc3 --- /dev/null +++ b/nodejs/perplexity/sample-agent/m365agents.yml @@ -0,0 +1,4 @@ +# yaml-language-server: $schema=https://aka.ms/m365-agents-toolkits/v1.11/yaml.schema.json +# Visit https://aka.ms/teamsfx-v5.0-guide for details on this file +# Visit https://aka.ms/teamsfx-actions for details on actions +version: v1.11 diff --git a/nodejs/perplexity/sample-agent/package.json b/nodejs/perplexity/sample-agent/package.json index a99e253a..61bf8486 100644 --- a/nodejs/perplexity/sample-agent/package.json +++ b/nodejs/perplexity/sample-agent/package.json @@ -4,11 +4,13 @@ "description": "Perplexity AI Agent with Microsoft Agent 365 SDK", "scripts": { "start": "node dist/index.js", - "dev": "nodemon --watch src --exec ts-node src/index.ts", + "dev": "nodemon --exec node --inspect=9239 --signal SIGINT -r ts-node/register src/index.ts", "test-tool": "agentsplayground", "install:clean": "npm run clean && npm install", "clean": "rimraf dist node_modules package-lock.json", - "build": "tsc" + "build": "tsc", + "dev:teamsfx:playground": "env-cmd --silent -f .localConfigs.playground npm run dev", + "dev:teamsfx:launch-playground": "env-cmd --silent -f env/.env.playground agentsplayground start" }, "keywords": [ "perplexity", @@ -37,6 +39,7 @@ "@microsoft/m365agentsplayground": "^0.2.18", "@types/express": "^4.17.21", "@types/node": "^20.14.9", + "env-cmd": "^11.0.0", "nodemon": "^3.1.10", "rimraf": "^5.0.0", "ts-node": "^10.9.2", diff --git a/nodejs/vercel-sdk/sample-agent/.gitignore b/nodejs/vercel-sdk/sample-agent/.gitignore new file mode 100644 index 00000000..ddfa31e6 --- /dev/null +++ b/nodejs/vercel-sdk/sample-agent/.gitignore @@ -0,0 +1,24 @@ +# TeamsFx files +env/.env.*.user +env/.env.local +env/.env.sandbox +.localConfigs +.localConfigs.playground +.notification.localstore.json +.notification.playgroundstore.json +.notification.testtoolstore.json +appPackage/build + +# dependencies +node_modules/ + +# misc +.env +.deployment +.DS_Store + +# build +dist/ + +# Dev tool directories +/devTools/ diff --git a/nodejs/vercel-sdk/sample-agent/.vscode/extensions.json b/nodejs/vercel-sdk/sample-agent/.vscode/extensions.json new file mode 100644 index 00000000..aac0a6e3 --- /dev/null +++ b/nodejs/vercel-sdk/sample-agent/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "TeamsDevApp.ms-teams-vscode-extension" + ] +} diff --git a/nodejs/vercel-sdk/sample-agent/.vscode/launch.json b/nodejs/vercel-sdk/sample-agent/.vscode/launch.json new file mode 100644 index 00000000..20f088e2 --- /dev/null +++ b/nodejs/vercel-sdk/sample-agent/.vscode/launch.json @@ -0,0 +1,31 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to Local Service", + "type": "node", + "request": "attach", + "port": 9239, + "restart": true, + "presentation": { + "group": "all", + "hidden": true + }, + "internalConsoleOptions": "neverOpen" + } + ], + "compounds": [ + { + "name": "Debug in Microsoft 365 Agents Playground", + "configurations": [ + "Attach to Local Service" + ], + "preLaunchTask": "Start App in Microsoft 365 Agents Playground", + "presentation": { + "group": "1-playground", + "order": 1 + }, + "stopAll": true + } + ] +} diff --git a/nodejs/vercel-sdk/sample-agent/.vscode/scripts/refresh-bearer-token.ps1 b/nodejs/vercel-sdk/sample-agent/.vscode/scripts/refresh-bearer-token.ps1 new file mode 100644 index 00000000..2fee52fa --- /dev/null +++ b/nodejs/vercel-sdk/sample-agent/.vscode/scripts/refresh-bearer-token.ps1 @@ -0,0 +1,77 @@ +$ErrorActionPreference = 'Stop' + +$workspace = Get-Location +$playgroundEnvPath = Join-Path $workspace 'env/.env.playground' +$playgroundUserEnvPath = Join-Path $workspace 'env/.env.playground.user' + +$a365Command = Get-Command a365 -ErrorAction SilentlyContinue +if (-not $a365Command) { + throw "a365 CLI is not installed or not on PATH. Install with: dotnet tool install --global Microsoft.Agents.A365.DevTools.Cli" +} + +if (-not (Test-Path $playgroundEnvPath)) { + throw "Missing env file: $playgroundEnvPath" +} + +$appIdLine = Get-Content $playgroundEnvPath | Where-Object { $_ -match '^\s*CLIENT_APP_ID\s*=\s*.+$' } | Select-Object -First 1 +if (-not $appIdLine) { + throw "CLIENT_APP_ID is required in env/.env.playground" +} + +$appId = ($appIdLine -split '=', 2)[1].Trim() +if ([string]::IsNullOrWhiteSpace($appId)) { + throw "CLIENT_APP_ID in env/.env.playground is empty" +} + +Write-Host "Running a365 develop add-permissions for app id $appId" +& a365 develop add-permissions --app-id $appId +if ($LASTEXITCODE -ne 0) { + throw "a365 develop add-permissions failed" +} + +Write-Host "Getting bearer token via a365..." +Write-Host "This may complete silently using cached credentials, or it may require interactive Windows sign-in (WAM)." +Write-Host "If interactive sign-in is required and no prompt appears, check the taskbar for a hidden sign-in window and bring it to front." +Write-Host "Running a365 develop get-token for app id $appId" +$tokenOutput = & a365 develop get-token --app-id $appId --output raw +if ($LASTEXITCODE -ne 0) { + throw "a365 develop get-token failed" +} + +$rawOutput = [string]::Join("`n", $tokenOutput) +$rawOutput = $rawOutput -replace "`r", '' + +$bearerToken = $null +$jwtRegex = '(?[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)' +$jwtMatches = [regex]::Matches($rawOutput, $jwtRegex) +if ($jwtMatches.Count -gt 0) { + $bearerToken = ($jwtMatches | ForEach-Object { $_.Groups['token'].Value } | Sort-Object Length -Descending | Select-Object -First 1).Trim() +} + +if ([string]::IsNullOrWhiteSpace($bearerToken)) { + throw "Unable to extract a bearer token from a365 develop get-token output" +} + +$userEnvLines = @() +if (Test-Path $playgroundUserEnvPath) { + $userEnvLines = Get-Content $playgroundUserEnvPath +} + +$updated = $false +for ($i = 0; $i -lt $userEnvLines.Count; $i++) { + if ($userEnvLines[$i] -match '^\s*SECRET_BEARER_TOKEN\s*=') { + $userEnvLines[$i] = "SECRET_BEARER_TOKEN=$bearerToken" + $updated = $true + break + } +} + +if (-not $updated) { + if ($userEnvLines.Count -gt 0 -and -not [string]::IsNullOrWhiteSpace($userEnvLines[$userEnvLines.Count - 1])) { + $userEnvLines += '' + } + $userEnvLines += "SECRET_BEARER_TOKEN=$bearerToken" +} + +Set-Content -Path $playgroundUserEnvPath -Value $userEnvLines -Encoding UTF8 +Write-Host 'SECRET_BEARER_TOKEN has been updated in env/.env.playground.user' diff --git a/nodejs/vercel-sdk/sample-agent/.vscode/tasks.json b/nodejs/vercel-sdk/sample-agent/.vscode/tasks.json new file mode 100644 index 00000000..c08b1c64 --- /dev/null +++ b/nodejs/vercel-sdk/sample-agent/.vscode/tasks.json @@ -0,0 +1,117 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Start App in Microsoft 365 Agents Playground", + "dependsOn": [ + "Validate prerequisites (Microsoft 365 Agents Playground)", + "Refresh bearer token (Microsoft 365 Agents Playground)", + "Deploy (Microsoft 365 Agents Playground)", + "Start application (Microsoft 365 Agents Playground)", + "Start Microsoft 365 Agents Playground" + ], + "dependsOrder": "sequence" + }, + { + "label": "Validate prerequisites (Microsoft 365 Agents Playground)", + "type": "teamsfx", + "command": "debug-check-prerequisites", + "args": { + "prerequisites": [ + "nodejs", + "portOccupancy" + ], + "portOccupancy": [ + 3978, + 9239, + 56150 + ] + } + }, + { + "label": "Refresh bearer token (Microsoft 365 Agents Playground)", + "type": "shell", + "command": "powershell", + "args": [ + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-File", + "${workspaceFolder}/.vscode/scripts/refresh-bearer-token.ps1" + ], + "options": { + "cwd": "${workspaceFolder}" + } + }, + { + "label": "Deploy (Microsoft 365 Agents Playground)", + "dependsOrder": "sequence", + "type": "teamsfx", + "command": "deploy", + "args": { + "env": "playground" + } + }, + { + "label": "Start application (Microsoft 365 Agents Playground)", + "type": "shell", + "command": "npm run dev:teamsfx:playground", + "isBackground": true, + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": { + "pattern": [ + { + "regexp": "^.*$", + "file": 0, + "location": 1, + "message": 2 + } + ], + "background": { + "activeOnStart": true, + "beginsPattern": "[nodemon] starting", + "endsPattern": "Server listening on|Bot/ME service listening at|[nodemon] app crashed" + } + } + }, + { + "label": "Start Microsoft 365 Agents Playground", + "type": "shell", + "command": "npm run dev:teamsfx:launch-playground", + "isBackground": true, + "options": { + "env": { + "PATH": "${workspaceFolder}/devTools/playground/node_modules/.bin;${env:PATH}" + } + }, + "windows": { + "options": { + "env": { + "PATH": "${workspaceFolder}/devTools/playground/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" + } + } + ] +} diff --git a/nodejs/vercel-sdk/sample-agent/README.md b/nodejs/vercel-sdk/sample-agent/README.md index 3b5b9509..35517059 100644 --- a/nodejs/vercel-sdk/sample-agent/README.md +++ b/nodejs/vercel-sdk/sample-agent/README.md @@ -18,6 +18,16 @@ For comprehensive documentation and guidance on building agents with the Microso - Vercel AI SDK (ai) 5.0.72 or higher - Azure/OpenAI API credentials +## Running the Agent in Microsoft 365 Agents Playground + +1. First, select the Microsoft 365 Agents Toolkit icon on the left in the VS Code toolbar. +1. In file *env/.env.playground.user*, fill in your Anthropic API key `SECRET_ANTHROPIC_API_KEY=`. +1. In file *env/.env.playground*, fill in your custom app registration client id `CLIENT_APP_ID`. +1. Press F5 to start debugging which launches your agent in Microsoft 365 Agents Playground using a web browser. Select `Debug in Microsoft 365 Agents Playground`. +1. You can send any message to get a response from the agent. + +**Congratulations**! You are running an agent that can now interact with users in Microsoft 365 Agents Playground. + ## Working with User Identity On every incoming message, the A365 platform populates `activity.from` with basic user diff --git a/nodejs/vercel-sdk/sample-agent/env/.env.playground b/nodejs/vercel-sdk/sample-agent/env/.env.playground new file mode 100644 index 00000000..dd0658a0 --- /dev/null +++ b/nodejs/vercel-sdk/sample-agent/env/.env.playground @@ -0,0 +1,26 @@ +# 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=playground + +# Environment variables used by Microsoft 365 Agents Playground +TEAMSAPPTESTER_PORT=56150 +TEAMSFX_NOTIFICATION_STORE_FILENAME=.notification.testtoolstore.json + +# Custom app registration needed for bearer token +CLIENT_APP_ID= + +# Use Agentic Authentication rather than OBO +USE_AGENTIC_AUTH=false + +# Set service connection as default +connectionsMap__0__serviceUrl=* +connectionsMap__0__connection=service_connection + +# AgenticAuthentication Options +agentic_type=agentic +agentic_altBlueprintConnectionName=service_connection +agentic_scopes=ea9ffc3e-8a23-4a7d-836d-234d7c7565c1/.default # Prod Agentic scope + +# Telemetry and Tracing Configuration +DEBUG=agents:* diff --git a/nodejs/vercel-sdk/sample-agent/env/.env.playground.user b/nodejs/vercel-sdk/sample-agent/env/.env.playground.user new file mode 100644 index 00000000..ac051992 --- /dev/null +++ b/nodejs/vercel-sdk/sample-agent/env/.env.playground.user @@ -0,0 +1,4 @@ +# Anthropic Configuration +SECRET_ANTHROPIC_API_KEY= + +SECRET_BEARER_TOKEN= diff --git a/nodejs/vercel-sdk/sample-agent/m365agents.playground.yml b/nodejs/vercel-sdk/sample-agent/m365agents.playground.yml new file mode 100644 index 00000000..b9dabdef --- /dev/null +++ b/nodejs/vercel-sdk/sample-agent/m365agents.playground.yml @@ -0,0 +1,38 @@ +# yaml-language-server: $schema=https://aka.ms/m365-agents-toolkits/v1.11/yaml.schema.json +# Visit https://aka.ms/teamsfx-v5.0-guide for details on this file +# Visit https://aka.ms/teamsfx-actions for details on actions +version: v1.11 + +environmentFolderPath: ./env + +deploy: + # Install development tool(s) + - uses: devTool/install + with: + testTool: + version: ~0.2.7 + symlinkDir: ./devTools/playground + + # Run npm command + - uses: cli/runNpmCommand + with: + args: install + + - uses: file/createOrUpdateEnvironmentFile + with: + target: ./.localConfigs.playground + envs: + NODE_ENV: local + PORT: 3978 + TEAMSFX_NOTIFICATION_STORE_FILENAME: ${{TEAMSFX_NOTIFICATION_STORE_FILENAME}} + ANTHROPIC_API_KEY: ${{SECRET_ANTHROPIC_API_KEY}} + BEARER_TOKEN: ${{SECRET_BEARER_TOKEN}} + USE_AGENTIC_AUTH: ${{USE_AGENTIC_AUTH}} + connectionsMap__0__serviceUrl: ${{connectionsMap__0__serviceUrl}} + connectionsMap__0__connection: ${{connectionsMap__0__connection}} + agentic_type: ${{agentic_type}} + agentic_altBlueprintConnectionName: ${{agentic_altBlueprintConnectionName}} + agentic_scopes: ${{agentic_scopes}} + connections__service_connection__settings__clientId: "" + connections__service_connection__settings__clientSecret: "" + connections__service_connection__settings__tenantId: "" diff --git a/nodejs/vercel-sdk/sample-agent/m365agents.yml b/nodejs/vercel-sdk/sample-agent/m365agents.yml new file mode 100644 index 00000000..50d15fc3 --- /dev/null +++ b/nodejs/vercel-sdk/sample-agent/m365agents.yml @@ -0,0 +1,4 @@ +# yaml-language-server: $schema=https://aka.ms/m365-agents-toolkits/v1.11/yaml.schema.json +# Visit https://aka.ms/teamsfx-v5.0-guide for details on this file +# Visit https://aka.ms/teamsfx-actions for details on actions +version: v1.11 diff --git a/nodejs/vercel-sdk/sample-agent/package.json b/nodejs/vercel-sdk/sample-agent/package.json index 69a48a93..95355828 100644 --- a/nodejs/vercel-sdk/sample-agent/package.json +++ b/nodejs/vercel-sdk/sample-agent/package.json @@ -6,10 +6,12 @@ "type": "commonjs", "scripts": { "start": "node dist/index.js", - "dev": "nodemon --watch src --exec ts-node src/index.ts", + "dev": "nodemon --exec node --inspect=9239 --signal SIGINT -r ts-node/register src/index.ts", "test-tool": "agentsplayground", "eval": "node --env-file .env src/evals/index.js", - "build": "tsc" + "build": "tsc", + "dev:teamsfx:playground": "env-cmd --silent -f .localConfigs.playground npm run dev", + "dev:teamsfx:launch-playground": "env-cmd --silent -f env/.env.playground agentsplayground start" }, "keywords": [ "vercel-ai-sdk", @@ -40,6 +42,7 @@ "@babel/preset-env": "^7.28.3", "@microsoft/m365agentsplayground": "^0.2.16", "@types/express": "^5.0.6", + "env-cmd": "^11.0.0", "nodemon": "^3.1.10", "ts-node": "^10.9.2" }