From 8be11a69ccc855c41d38402bf89f750a313cf458 Mon Sep 17 00:00:00 2001 From: CeciliaAvila Date: Mon, 1 Sep 2025 13:51:29 -0300 Subject: [PATCH 1/3] Update console sample --- samples/nodejs/copilotstudio-client/README.md | 13 ++- .../nodejs/copilotstudio-client/env.TEMPLATE | 27 ++++-- .../copilotstudio-client/package-lock.json | 45 +++++---- .../nodejs/copilotstudio-client/package.json | 6 +- .../nodejs/copilotstudio-client/src/index.ts | 92 +++++++++++++------ .../src/sampleConnectionSettings.ts | 37 ++++++++ 6 files changed, 160 insertions(+), 60 deletions(-) create mode 100644 samples/nodejs/copilotstudio-client/src/sampleConnectionSettings.ts diff --git a/samples/nodejs/copilotstudio-client/README.md b/samples/nodejs/copilotstudio-client/README.md index b90d39fa..a8ae7c02 100644 --- a/samples/nodejs/copilotstudio-client/README.md +++ b/samples/nodejs/copilotstudio-client/README.md @@ -68,9 +68,20 @@ With the above information, you can now run the client `CopilostStudioClient` sa ```bash environmentId="" # Environment ID of environment with the CopilotStudio App. - agentIdentifier="" # Schema Name of the Copilot to use + schemaName="" # Schema Name of the Copilot to use tenantId="" # Tenant ID of the App Registration used to login, this should be in the same tenant as the Copilot. appClientId="" # App ID of the App Registration used to login, this should be in the same tenant as the CopilotStudio environment. + directConnectUrl="" # The URL to connect directly to the Copilot Studio service. When provided, `environmentId` + `schemaName` are ignored. +``` + +#### Optional Configuration +This sample lets you configure the following settings in the .env file: +```bash + authorityEndpoint="" # The login authority to use for the connection. Default: "https://login.microsoftonline.com". + cloud="" # The cloud hosting the Power Platform Services. Default: "Prod". + customPowerPlatformCloud="" # The Power Platform API endpoint when cloud is set to "Other". + copilotAgentType="" # The type of Copilot Studio Agent (Published or Prebuilt). Default: "Published". + useExperimentalEndpoint="" # The flag to use the URL provided via the "x-ms-d2e-experimental" header for subsequent calls to the Copilot Studio service. ``` 3. Run the CopilotStudioClient sample using `npm start`, which will install the packages, build the project and run it. diff --git a/samples/nodejs/copilotstudio-client/env.TEMPLATE b/samples/nodejs/copilotstudio-client/env.TEMPLATE index ea2982e7..f0037269 100644 --- a/samples/nodejs/copilotstudio-client/env.TEMPLATE +++ b/samples/nodejs/copilotstudio-client/env.TEMPLATE @@ -1,8 +1,19 @@ -environmentId= -agentIdentifier= -tenantId= -appClientId= -# cloud= # PowerPlatformCloud. eg 'Cloud | Gov' -# customPowerPlatformCloud= # Power Platform API endpoint to use if Cloud is configured as "Other" -# agentType="" # AgentType enum. eg 'Published' -DEBUG=copilot-studio-client:error \ No newline at end of file +# rename to .env + +# Authentication settings (MSAL) +appClientId="" # App ID of the App Registration used to log in; should be in the same tenant as the Copilot Studio agent. +tenantId="" # Tenant ID of the App Registration used to log in; must match the Copilot's tenant. +authorityEndpoint="" # Login authority to use for the connection. Default value is "https://login.microsoftonline.com". +useS2SConnection=false # Flag to enable token acquisition with an "appClientSecret". +appClientSecret="" # Client secret of the App Registration used for the S2S connection. + +# Copilot Studio Agent Configuration +environmentId="" # Environment ID of the Copilot Studio App (required if directConnectUrl is empty). +schemaName="" # Schema Name of the Copilot Studio App (required if directConnectUrl is empty). +directConnectUrl="" # URL used to connect to the Copilot Studio service (use this OR environmentId + schemaName). +cloud="" # Cloud hosting the Power Platform Services. Default value is "Prod". Set to "Other" when using customPowerPlatformCloud. +customPowerPlatformCloud="" # Power Platform API endpoint to use if Cloud is configured as "Other". +copilotAgentType="" # Type of Copilot Studio Agent (Published or Prebuilt). Default value is "Published". +useExperimentalEndpoint=false # Flag to use the "x-ms-d2e-experimental" header URL on subsequent calls to the Copilot Studio service. + +DEBUG=copilot-studio-client:error diff --git a/samples/nodejs/copilotstudio-client/package-lock.json b/samples/nodejs/copilotstudio-client/package-lock.json index 59ed1402..e7df7d59 100644 --- a/samples/nodejs/copilotstudio-client/package-lock.json +++ b/samples/nodejs/copilotstudio-client/package-lock.json @@ -9,30 +9,32 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "@azure/msal-node": "^3.5.3", + "@azure/msal-node": "^3.7.2", "@microsoft/agents-copilotstudio-client": "^1.0.0", "open": "^10.1.2" }, "devDependencies": { "@types/debug": "^4.1.12", - "@types/node": "^22.13.4", - "typescript": "^5.7.3" + "@types/node": "^24.3.0", + "typescript": "^5.9.2" } }, "node_modules/@azure/msal-common": { - "version": "15.11.0", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.11.0.tgz", - "integrity": "sha512-1IseGNH6XGWe+5xhZlhasTJP6Ob7tnVSlfFUnjdeH4Kik0n1SORTmdB6xxTwbx9Ro8EuO0XaRzpdABWSf15sdg==", + "version": "15.12.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.12.0.tgz", + "integrity": "sha512-4ucXbjVw8KJ5QBgnGJUeA07c8iznwlk5ioHIhI4ASXcXgcf2yRFhWzYOyWg/cI49LC9ekpFJeQtO3zjDTbl6TQ==", + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/@azure/msal-node": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.7.1.tgz", - "integrity": "sha512-ZTopY+BmE/OubqTXEQ5Eq+h6M5NKTchQBtvLj1tgiAf26lk2C+9jJTvtHjcyzE3iWn3wzySJLa4ArcjHJaZMQw==", + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.7.3.tgz", + "integrity": "sha512-MoJxkKM/YpChfq4g2o36tElyzNUMG8mfD6u8NbuaPAsqfGpaw249khAcJYNoIOigUzRw45OjXCOrexE6ImdUxg==", + "license": "MIT", "dependencies": { - "@azure/msal-common": "15.11.0", + "@azure/msal-common": "15.12.0", "jsonwebtoken": "^9.0.0", "uuid": "^8.3.0" }, @@ -44,6 +46,7 @@ "version": "1.0.13", "resolved": "https://registry.npmjs.org/@microsoft/agents-activity/-/agents-activity-1.0.13.tgz", "integrity": "sha512-G0QnQUN/QU0JBOsICRAVRSmFL7sboA2vSoFcWnL5fN5spqLcnXkNmiUhYJqSXDMZqqFWCnCq4jkcbxJD7v+w1g==", + "license": "MIT", "dependencies": { "debug": "^4.3.7", "uuid": "^11.1.0", @@ -61,6 +64,7 @@ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], + "license": "MIT", "bin": { "uuid": "dist/esm/bin/uuid" } @@ -69,6 +73,7 @@ "version": "1.0.13", "resolved": "https://registry.npmjs.org/@microsoft/agents-copilotstudio-client/-/agents-copilotstudio-client-1.0.13.tgz", "integrity": "sha512-k5nCUiEH5OvRQYHggwnAK14IkuudPdu8R9KjECVnZN98CS9lIg69klI8VgSpx8WQU45aDWkjNZ3+sRWJimZe1Q==", + "license": "MIT", "dependencies": { "@microsoft/agents-activity": "1.0.13", "axios": "^1.9.0", @@ -107,12 +112,13 @@ "dev": true }, "node_modules/@types/node": { - "version": "22.17.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.17.2.tgz", - "integrity": "sha512-gL6z5N9Jm9mhY+U2KXZpteb+09zyffliRkZyZOHODGATyC5B1Jt/7TzuuiLkFsSUMLbS1OLmlj/E+/3KF4Q/4w==", + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", + "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==", "dev": true, + "license": "MIT", "dependencies": { - "undici-types": "~6.21.0" + "undici-types": "~7.10.0" } }, "node_modules/asynckit": { @@ -176,6 +182,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -661,10 +668,11 @@ } }, "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "dev": true, + "license": "MIT" }, "node_modules/uuid": { "version": "8.3.2", @@ -692,6 +700,7 @@ "version": "3.25.75", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.75.tgz", "integrity": "sha512-OhpzAmVzabPOL6C3A3gpAifqr9MqihV/Msx3gor2b2kviCgcb+HM9SEOpMWwwNp9MRunWnhtAKUoo0AHhjyPPg==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/samples/nodejs/copilotstudio-client/package.json b/samples/nodejs/copilotstudio-client/package.json index 4ec60c48..0e66d415 100644 --- a/samples/nodejs/copilotstudio-client/package.json +++ b/samples/nodejs/copilotstudio-client/package.json @@ -14,14 +14,14 @@ "start": "node --env-file .env ./dist/index.js" }, "dependencies": { - "@azure/msal-node": "^3.5.3", + "@azure/msal-node": "^3.7.2", "@microsoft/agents-copilotstudio-client": "^1.0.0", "open": "^10.1.2" }, "devDependencies": { "@types/debug": "^4.1.12", - "@types/node": "^22.13.4", - "typescript": "^5.7.3" + "@types/node": "^24.3.0", + "typescript": "^5.9.2" }, "keywords": [] } diff --git a/samples/nodejs/copilotstudio-client/src/index.ts b/samples/nodejs/copilotstudio-client/src/index.ts index ec2acb82..20be712b 100644 --- a/samples/nodejs/copilotstudio-client/src/index.ts +++ b/samples/nodejs/copilotstudio-client/src/index.ts @@ -5,7 +5,7 @@ import * as msal from '@azure/msal-node' import { Activity, ActivityTypes, CardAction } from '@microsoft/agents-activity' -import { ConnectionSettings, loadCopilotStudioConnectionSettingsFromEnv, CopilotStudioClient } from '@microsoft/agents-copilotstudio-client' +import { ConnectionSettings, CopilotStudioClient } from '@microsoft/agents-copilotstudio-client' import pkg from '@microsoft/agents-copilotstudio-client/package.json' with { type: 'json' } import readline from 'readline' import open from 'open' @@ -13,57 +13,90 @@ import os from 'os' import path from 'path' import { MsalCachePlugin } from './msalCachePlugin.js' +import { SampleConnectionSettings } from './sampleConnectionSettings.js' -async function acquireToken (settings: ConnectionSettings): Promise { - const msalConfig = { +interface S2SConnectionSettings extends ConnectionSettings { + appClientSecret?: string +} + +async function acquireS2SToken (baseConfig: msal.Configuration, settings: S2SConnectionSettings): Promise { + const cca = new msal.ConfidentialClientApplication({ + ...baseConfig, auth: { - clientId: settings.appClientId, - authority: `https://login.microsoftonline.com/${settings.tenantId}`, - }, - cache: { - cachePlugin: new MsalCachePlugin(path.join(os.tmpdir(), 'mcssample.tockencache.json')) - }, - system: { - loggerOptions: { - loggerCallback (loglevel: msal.LogLevel, message: string, containsPii: boolean) { - if (!containsPii) { - console.log(loglevel, message) - } - }, - piiLoggingEnabled: false, - logLevel: msal.LogLevel.Verbose, - } + ...baseConfig.auth, + clientSecret: settings.appClientSecret! + } + }) + + try { + const response = await cca.acquireTokenByClientCredential({ scopes: [CopilotStudioClient.scopeFromSettings(settings)] }) + if (!response?.accessToken) { + throw new Error('Failed to acquire token') } + + return response?.accessToken + } catch (error) { + console.error('Error acquiring token for client credential:', error) + throw error } - const pca = new msal.PublicClientApplication(msalConfig) +} + +async function acquireToken (baseConfig: msal.Configuration, settings: ConnectionSettings): Promise { const tokenRequest = { - scopes: ['https://api.powerplatform.com/.default'], - redirectUri: 'http://localhost', + scopes: [CopilotStudioClient.scopeFromSettings(settings)], openBrowser: async (url: string) => { await open(url) } } - let token + + const pca = new msal.PublicClientApplication(baseConfig) + try { const accounts = await pca.getAllAccounts() if (accounts.length > 0) { const response2 = await pca.acquireTokenSilent({ account: accounts[0], scopes: tokenRequest.scopes }) - token = response2.accessToken + return response2.accessToken } else { const response = await pca.acquireTokenInteractive(tokenRequest) - token = response.accessToken + return response.accessToken } } catch (error) { console.error('Error acquiring token interactively:', error) const response = await pca.acquireTokenInteractive(tokenRequest) - token = response.accessToken + return response.accessToken + } +} + +function getToken (settings: SampleConnectionSettings) : Promise { + const msalConfig: msal.Configuration = { + auth: { + clientId: settings.appClientId!, + authority: `${settings.authority}/${settings.tenantId}`, + }, + cache: { + cachePlugin: new MsalCachePlugin(path.join(os.tmpdir(), 'msal.usercache.json')) + }, + system: { + loggerOptions: { + loggerCallback (loglevel: msal.LogLevel, message: string, containsPii: boolean) { + console.log(message) + }, + piiLoggingEnabled: false, + logLevel: msal.LogLevel.Verbose, + } + } } - return token + + if (settings.useS2SConnection) { + return acquireS2SToken(msalConfig, settings) + } + + return acquireToken(msalConfig, settings) } const createClient = async (): Promise => { - const settings = loadCopilotStudioConnectionSettingsFromEnv() - const token = await acquireToken(settings) + const settings = new SampleConnectionSettings() + const token = await getToken(settings) const copilotClient = new CopilotStudioClient(settings, token) console.log(`Copilot Studio Client Version: ${pkg.version}, running with settings: ${JSON.stringify(settings, null, 2)}`) return copilotClient @@ -98,7 +131,6 @@ const askQuestion = async (copilotClient: CopilotStudioClient, conversationId: s const main = async () => { const copilotClient = await createClient() const act: Activity = await copilotClient.startConversationAsync(true) - console.log('\nSuggested Actions: ') act.suggestedActions?.actions.forEach((action: CardAction) => console.log(action.value)) await askQuestion(copilotClient, act.conversation?.id!) } diff --git a/samples/nodejs/copilotstudio-client/src/sampleConnectionSettings.ts b/samples/nodejs/copilotstudio-client/src/sampleConnectionSettings.ts new file mode 100644 index 00000000..d5e5c175 --- /dev/null +++ b/samples/nodejs/copilotstudio-client/src/sampleConnectionSettings.ts @@ -0,0 +1,37 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ + +import { ConnectionSettings, loadCopilotStudioConnectionSettingsFromEnv } from '@microsoft/agents-copilotstudio-client' + +export class SampleConnectionSettings extends ConnectionSettings { + public readonly appClientId: string = '' + public readonly tenantId: string = '' + public readonly authority: string = 'https://login.microsoftonline.com' + public readonly useS2SConnection: boolean = false + public readonly appClientSecret: string = '' + + constructor () { + const settings = loadCopilotStudioConnectionSettingsFromEnv() + super(settings) + + if (!process.env.appClientId) { + throw new Error('appClientId is required') + } + + if (!process.env.tenantId) { + throw new Error('tenantId is required') + } + + this.appClientId = process.env.appClientId! + this.tenantId = process.env.tenantId! + this.authority = process.env.authority ?? 'https://login.microsoftonline.com' + this.useS2SConnection = process.env.useS2SConnection === 'true' + this.appClientSecret = process.env.appClientSecret ?? '' + + if (this.useS2SConnection && !this.appClientSecret) { + throw new Error('appClientSecret is required for S2S connection') + } + } +} From 7e7ff7cb93ff96fd7db4a505c56a09fe885f3714 Mon Sep 17 00:00:00 2001 From: CeciliaAvila Date: Mon, 1 Sep 2025 15:29:02 -0300 Subject: [PATCH 2/3] Update webchat-react sample --- .../copilotstudio-webchat-react/README.md | 4 +- .../copilotstudio-webchat-react/src/Chat.tsx | 13 +++-- .../src/acquireToken.ts | 10 ++-- .../src/settings.EXAMPLE.js | 48 ++++++++++--------- 4 files changed, 43 insertions(+), 32 deletions(-) diff --git a/samples/nodejs/copilotstudio-webchat-react/README.md b/samples/nodejs/copilotstudio-webchat-react/README.md index f1ecf9d9..afbe2750 100644 --- a/samples/nodejs/copilotstudio-webchat-react/README.md +++ b/samples/nodejs/copilotstudio-webchat-react/README.md @@ -76,7 +76,7 @@ This step requires permissions to create application identities in your Azure te appClientId: 'your-app-client-id-here', tenantId: 'your-tenant-id-here', environmentId: 'your-environment-id-here', - agentIdentifier: 'your-schema-name-here', + schemaName: 'your-schema-name-here', } } ``` @@ -151,7 +151,7 @@ Configuration is handled through `settings.js` which emulates Node.js process.en process.env.appClientId // Your Azure AD app registration ID process.env.tenantId // Your Azure AD tenant ID process.env.environmentId // Copilot Studio environment ID -process.env.agentIdentifier // Copilot Studio schema name +process.env.schemaName // Copilot Studio schema name // ... other configuration options ``` diff --git a/samples/nodejs/copilotstudio-webchat-react/src/Chat.tsx b/samples/nodejs/copilotstudio-webchat-react/src/Chat.tsx index 6f2228bb..dbb5eb6b 100644 --- a/samples/nodejs/copilotstudio-webchat-react/src/Chat.tsx +++ b/samples/nodejs/copilotstudio-webchat-react/src/Chat.tsx @@ -6,24 +6,29 @@ import { Components } from 'botframework-webchat' import { FluentThemeProvider } from 'botframework-webchat-fluent-theme' import React, { useState, useEffect } from 'react' -import { ConnectionSettings, CopilotStudioClient, CopilotStudioWebChat, CopilotStudioWebChatConnection } from '@microsoft/agents-copilotstudio-client' +import { CopilotStudioClient, CopilotStudioWebChat, CopilotStudioWebChatConnection } from '@microsoft/agents-copilotstudio-client' import { acquireToken } from './acquireToken' +import { SampleConnectionSettings } from './settings' const { BasicWebChat, Composer } = Components function Chat () { - let agentsSettings: ConnectionSettings + let agentsSettings: SampleConnectionSettings try { - agentsSettings = require('./settings.js').settings + agentsSettings = new SampleConnectionSettings() + + if (!agentsSettings.authority) { + agentsSettings.authority = 'https://login.microsoftonline.com' + } } catch (error) { console.error(error + '\nsettings.js Not Found. Rename settings.EXAMPLE.js to settings.js and fill out necessary fields') agentsSettings = { appClientId: '', tenantId: '', environmentId: '', - agentIdentifier: '', + schemaName: '', directConnectUrl: '', } } diff --git a/samples/nodejs/copilotstudio-webchat-react/src/acquireToken.ts b/samples/nodejs/copilotstudio-webchat-react/src/acquireToken.ts index b49f7e8d..b2c135b9 100644 --- a/samples/nodejs/copilotstudio-webchat-react/src/acquireToken.ts +++ b/samples/nodejs/copilotstudio-webchat-react/src/acquireToken.ts @@ -3,19 +3,21 @@ * Licensed under the MIT License. */ import { PublicClientApplication, InteractionRequiredAuthError } from '@azure/msal-browser' -import { ConnectionSettings } from '@microsoft/agents-copilotstudio-client' +import { CopilotStudioClient } from '@microsoft/agents-copilotstudio-client' -export async function acquireToken (settings: ConnectionSettings) { +import { SampleConnectionSettings } from './settings' + +export async function acquireToken (settings: SampleConnectionSettings) { const msalInstance = new PublicClientApplication({ auth: { clientId: settings.appClientId, - authority: `https://login.microsoftonline.com/${settings.tenantId}`, + authority: `${settings.authority}/${settings.tenantId}`, }, }) await msalInstance.initialize() const loginRequest = { - scopes: ['https://api.powerplatform.com/.default'], + scopes: [CopilotStudioClient.scopeFromSettings(settings)], redirectUri: window.location.origin, } // When there are not accounts or the acquireTokenSilent fails, diff --git a/samples/nodejs/copilotstudio-webchat-react/src/settings.EXAMPLE.js b/samples/nodejs/copilotstudio-webchat-react/src/settings.EXAMPLE.js index 351baa75..06918530 100644 --- a/samples/nodejs/copilotstudio-webchat-react/src/settings.EXAMPLE.js +++ b/samples/nodejs/copilotstudio-webchat-react/src/settings.EXAMPLE.js @@ -11,25 +11,29 @@ import { ConnectionSettings } from '@microsoft/agents-copilotstudio-client' // Copilot Studio Client uses the "debug" library for logging (https://github.com/debug-js/debug?tab=readme-ov-file#browser-support). window.localStorage.debug = 'copilot-studio:*' -export const settings = new ConnectionSettings({ - // App ID of the App Registration used to log in, this should be in the same tenant as the Copilot. - appClientId: '', - // Tenant ID of the App Registration used to log in, this should be in the same tenant as the Copilot. - tenantId: '', - // Authority endpoint for the Azure AD login. Default is 'https://login.microsoftonline.com'. - authority: '', - // Environment ID of the environment with the Copilot Studio App. - environmentId: '', - // Schema Name of the Copilot to use. - agentIdentifier: '', - // PowerPlatformCloud enum key. - cloud: undefined, - // Power Platform API endpoint to use if Cloud is configured as "Other". - customPowerPlatformCloud: undefined, - // AgentType enum key. - copilotAgentType: undefined, - // URL used to connect to the Copilot Studio service. - directConnectUrl: undefined, - // Flag to use the "x-ms-d2e-experimental" header URL on subsequent calls to the Copilot Studio service. - useExperimentalEndpoint: false -}) +export class SampleConnectionSettings extends ConnectionSettings { + constructor () { + super({ + // Environment ID of the Copilot Studio App (required if directConnectUrl is empty). + environmentId: '', + // Schema Name of the Copilot Studio App (required if directConnectUrl is empty). + schemaName: '', + // URL used to connect to the Copilot Studio service (use this OR environmentId + schemaName). + directConnectUrl: '', + // Cloud hosting the Power Platform Services. Default value is "Prod". Set to "Other" when using customPowerPlatformCloud. + cloud: '', + // Power Platform API endpoint to use if Cloud is configured as "Other". + customPowerPlatformCloud: '', + // Type of Copilot Studio Agent (Published or Prebuilt). Default value is "Published". + copilotAgentType: '', + // Flag to use the "x-ms-d2e-experimental" header URL on subsequent calls to the Copilot Studio service. + useExperimentalEndpoint: false + }) + // App ID of the App Registration used to log in; should be in the same tenant as the Copilot Studio agent. + this.appClientId = '' + // Tenant ID of the App Registration used to log in; must match the Copilot’s tenant. + this.tenantId = '' + // Authority endpoint for the Azure AD login. Default is 'https://login.microsoftonline.com'. + this.authority = '' + } +} From 57483636ce13806900aea03004286e4f7ea0549b Mon Sep 17 00:00:00 2001 From: CeciliaAvila Date: Mon, 1 Sep 2025 16:23:52 -0300 Subject: [PATCH 3/3] Update webclient sample --- .../nodejs/copilotstudio-webclient/README.md | 17 ++++++- .../web/acquireToken.js | 6 ++- .../copilotstudio-webclient/web/index.js | 17 ++++++- .../web/settings.TEMPLATE.js | 48 ++++++++++--------- 4 files changed, 60 insertions(+), 28 deletions(-) diff --git a/samples/nodejs/copilotstudio-webclient/README.md b/samples/nodejs/copilotstudio-webclient/README.md index 3c76d4c8..3c662aff 100644 --- a/samples/nodejs/copilotstudio-webclient/README.md +++ b/samples/nodejs/copilotstudio-webclient/README.md @@ -57,9 +57,22 @@ With the above information, you can now configure the web client in the `web` fo ```bash environmentId="" # Environment ID of environment with the CopilotStudio App. - agentIdentifier="" # Schema Name of the Copilot to use + schemaName="" # Schema Name of the Copilot to use tenantId="" # Tenant ID of the App Registration used to login, this should be in the same tenant as the Copilot. appClientId="" # App ID of the App Registration used to login, this should be in the same tenant as the CopilotStudio environment. + # Alternatively, you can provide a direct URL to connect to Copilot Studio instead of specifying the `environmentId` and `schemaName` values: + directConnectUrl="" # The URL to connect to the Copilot Studio service. If set, overrides `environmentId` and `schemaName`. +``` + +#### Optional Configuration + +This sample lets you configure the following settings in the .env file: +```bash +authorityEndpoint="" # The login authority to use for the connection. Default: "https://login.microsoftonline.com". +cloud="" # The cloud hosting the Power Platform Services. Default: "Prod". +customPowerPlatformCloud="" # The Power Platform API endpoint when cloud is set to "Other". +copilotAgentType="" # The type of Copilot Studio Agent (Published or Prebuilt). Default: "Published". +useExperimentalEndpoint="" # The flag to use the URL provided via the "x-ms-d2e-experimental" header for subsequent calls to the Copilot Studio service. ``` 3. Use a web server to serve the files in the `web` folder. If you are using [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer), right click `index.html` and select `Open with Live Server` @@ -70,4 +83,4 @@ With the above information, you can now configure the web client in the `web` fo 6. In the pop-up window, authenticate with your user credentials. -7. You should see a Web Page with WebChat component to talk with your agent. \ No newline at end of file +7. You should see a Web Page with WebChat component to talk with your agent. diff --git a/samples/nodejs/copilotstudio-webclient/web/acquireToken.js b/samples/nodejs/copilotstudio-webclient/web/acquireToken.js index 049f840c..421e3c4d 100644 --- a/samples/nodejs/copilotstudio-webclient/web/acquireToken.js +++ b/samples/nodejs/copilotstudio-webclient/web/acquireToken.js @@ -3,17 +3,19 @@ * Licensed under the MIT License. */ +import { CopilotStudioClient } from '@microsoft/agents-copilotstudio-client' + export async function acquireToken (settings) { const msalInstance = new window.msal.PublicClientApplication({ auth: { clientId: settings.appClientId, - authority: `https://login.microsoftonline.com/${settings.tenantId}`, + authority: `${settings.authority}/${settings.tenantId}`, }, }) await msalInstance.initialize() const loginRequest = { - scopes: ['https://api.powerplatform.com/.default'], + scopes: [CopilotStudioClient.scopeFromSettings(settings)], redirectUri: window.location.origin, } diff --git a/samples/nodejs/copilotstudio-webclient/web/index.js b/samples/nodejs/copilotstudio-webclient/web/index.js index 0b02ee1b..399684f9 100644 --- a/samples/nodejs/copilotstudio-webclient/web/index.js +++ b/samples/nodejs/copilotstudio-webclient/web/index.js @@ -9,15 +9,28 @@ import { } from '@microsoft/agents-copilotstudio-client' import { acquireToken } from './acquireToken.js' -import { settings } from './settings.js' +import { SampleConnectionSettings } from './settings.js' try { + const settings = new SampleConnectionSettings() + + if (!settings.appClientId) { + throw new Error('appClientId is required in settings.js') + } + if (!settings.tenantId) { + throw new Error('tenantId is required in settings.js') + } + if (!settings.authority) { + settings.authority = 'https://login.microsoftonline.com' + } const token = await acquireToken(settings) const client = new CopilotStudioClient(settings, token) window.WebChat.renderWebChat( { - directLine: CopilotStudioWebChat.createConnection(client, { typingIndicator: true }), + directLine: CopilotStudioWebChat.createConnection(client, { + showTyping: true, + }), }, document.getElementById('webchat') ) diff --git a/samples/nodejs/copilotstudio-webclient/web/settings.TEMPLATE.js b/samples/nodejs/copilotstudio-webclient/web/settings.TEMPLATE.js index acd67353..f62029ed 100644 --- a/samples/nodejs/copilotstudio-webclient/web/settings.TEMPLATE.js +++ b/samples/nodejs/copilotstudio-webclient/web/settings.TEMPLATE.js @@ -11,25 +11,29 @@ import { ConnectionSettings } from '@microsoft/agents-copilotstudio-client' // Copilot Studio Client uses the "debug" library for logging (https://github.com/debug-js/debug?tab=readme-ov-file#browser-support). window.localStorage.debug = 'copilot-studio-client' -export const settings = new ConnectionSettings({ - // App ID of the App Registration used to log in, this should be in the same tenant as the Copilot. - appClientId: '', - // Tenant ID of the App Registration used to log in, this should be in the same tenant as the Copilot. - tenantId: '', - // Authority endpoint for the Azure AD login. Default is 'https://login.microsoftonline.com'. - authority: '', - // Environment ID of the environment with the Copilot Studio App. - environmentId: '', - // Schema Name of the Copilot to use. - agentIdentifier: '', - // PowerPlatformCloud enum key. - cloud: undefined, - // Power Platform API endpoint to use if Cloud is configured as "Other". - customPowerPlatformCloud: undefined, - // AgentType enum key. - copilotAgentType: undefined, - // URL used to connect to the Copilot Studio service. - directConnectUrl: undefined, - // Flag to use the "x-ms-d2e-experimental" header URL on subsequent calls to the Copilot Studio service. - useExperimentalEndpoint: false -}) +export class SampleConnectionSettings extends ConnectionSettings { + constructor () { + super({ + // Environment ID of the Copilot Studio App (required if directConnectUrl is empty). + environmentId: '', + // Schema Name of the Copilot Studio App (required if directConnectUrl is empty). + schemaName: '', + // URL used to connect to the Copilot Studio service (use this OR environmentId + schemaName). + directConnectUrl: '', + // Cloud hosting the Power Platform Services. Default value is "Prod". Set to "Other" when using customPowerPlatformCloud. + cloud: '', + // Power Platform API endpoint to use if Cloud is configured as "Other". + customPowerPlatformCloud: '', + // Type of Copilot Studio Agent (Published or Prebuilt). Default value is "Published". + copilotAgentType: '', + // Flag to use the "x-ms-d2e-experimental" header URL on subsequent calls to the Copilot Studio service. + useExperimentalEndpoint: false + }) + // App ID of the App Registration used to log in; should be in the same tenant as the Copilot Studio agent. + this.appClientId = '' + // Tenant ID of the App Registration used to log in; must match the Copilot’s tenant. + this.tenantId = '' + // Authority endpoint for the Azure AD login. Default is 'https://login.microsoftonline.com'. + this.authority = '' + } +}