Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion extensions/runtimes/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ export default async (composer: any): Promise<void> => {
const schemaFolderInRuntime = path.join(destPath, 'schemas');
await removeDirAndFiles(schemaFolderInRuntime);

return path.relative(path.join(project.dir, 'settings'), destPath);
return path.relative(project.dir, destPath);
}
throw new Error(`Runtime already exists at ${destPath}`);
},
Expand Down
2,581 changes: 1,583 additions & 998 deletions runtime/node/package-lock.json

Large diffs are not rendered by default.

14 changes: 8 additions & 6 deletions runtime/node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@
"license": "ISC",
"dependencies": {
"@azure/functions": "^1.2.2",
"adaptive-expressions": "4.12.0-rc3",
"botbuilder": "4.12.0-rc3",
"botbuilder-ai": "4.12.0-rc3",
"botbuilder-dialogs": "4.12.0-rc3",
"botbuilder-dialogs-adaptive": "4.12.0-rc3-preview",
"botbuilder-dialogs-declarative": "4.12.0-rc3-preview",
"adaptive-expressions": "4.12.0",
"botbuilder": "4.12.0",
"botbuilder-ai": "4.12.0",
"botbuilder-applicationinsights": "4.12.0",
"botbuilder-azure-blobs": "4.12.0-preview",
"botbuilder-dialogs": "4.12.0",
"botbuilder-dialogs-adaptive": "4.12.0-preview",
"botbuilder-dialogs-declarative": "4.12.0-preview",
"debug": "^4.1.1",
"lodash": "^4.17.19",
"minimist": "1.2.5",
Expand Down
14 changes: 11 additions & 3 deletions runtime/node/src/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from 'botbuilder';
import { AuthenticationConfiguration, SimpleCredentialProvider } from 'botframework-connector';
import { ComposerBot } from './shared/composerBot';
import { getBotAdapter, getSettings } from './shared/helpers';
import { configureTelemetry, getBotAdapter, getSettings, getTelemetryClient } from './shared/helpers';
import { SkillConversationIdFactory } from './shared/skillConversationIdFactory';

// Create shared memory storage.
Expand All @@ -27,10 +27,18 @@ const conversationState = new ConversationState(memoryStorage);
const skillConversationIdFactory = new SkillConversationIdFactory();

// Get botframework adapter.
const adapter = getBotAdapter(userState, conversationState);
const adapter = getBotAdapter(memoryStorage, userState, conversationState);

// Get bot telemetry client.
const telemetryClient = getTelemetryClient();

// Create composer bot instance with root dialog.
const bot = new ComposerBot(userState, conversationState, skillConversationIdFactory);
const bot = new ComposerBot(userState, conversationState, skillConversationIdFactory, telemetryClient);

// Configure telemetry client.
if (telemetryClient) {
configureTelemetry(adapter, telemetryClient);
}

export const messagesTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
context.log('Messages endpoint triggerd.');
Expand Down
12 changes: 10 additions & 2 deletions runtime/node/src/shared/composerBot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import {
ActivityHandler,
ActivityTypes,
BotTelemetryClient,
ComponentRegistration,
ConversationState,
SkillHttpClient,
Expand All @@ -19,6 +20,7 @@ import {
LanguagePolicy,
ResourceExtensions,
SkillExtensions,
useTelemetry,
} from 'botbuilder-dialogs-adaptive';
import { ResourceExplorer } from 'botbuilder-dialogs-declarative';
import { SimpleCredentialProvider, SkillValidation } from 'botframework-connector';
Expand All @@ -36,6 +38,7 @@ export class ComposerBot extends ActivityHandler {
private readonly userState: UserState;
private readonly conversationState: ConversationState;
private readonly skillConversationIdFactory: SkillConversationIdFactory;
private readonly telemetryClient: BotTelemetryClient;
private readonly projectRoot: string;
private readonly settings: BotSettings;
private readonly resourceExplorer: ResourceExplorer;
Expand All @@ -44,12 +47,14 @@ export class ComposerBot extends ActivityHandler {
public constructor(
userState: UserState,
conversationState: ConversationState,
skillConversationIdFactory: SkillConversationIdFactory
skillConversationIdFactory: SkillConversationIdFactory,
telemetryClient: BotTelemetryClient
) {
super();
this.userState = userState;
this.conversationState = conversationState;
this.skillConversationIdFactory = skillConversationIdFactory;
this.telemetryClient = telemetryClient;
this.projectRoot = getProjectRoot();
this.settings = getSettings(this.projectRoot);

Expand All @@ -76,7 +81,7 @@ export class ComposerBot extends ActivityHandler {
rootDialog.configure({ autoEndDialog: true });
}

const removeRecipientMention = (this.settings.feature && this.settings.feature.removeRecipientMention) || false;
const removeRecipientMention = this.settings.feature?.RemoveRecipientMention ?? false;
if (removeRecipientMention && turnContext.activity.type == ActivityTypes.Message) {
TurnContext.removeRecipientMention(turnContext.activity);
}
Expand All @@ -92,6 +97,9 @@ export class ComposerBot extends ActivityHandler {
this.dialogManager = new DialogManager(rootDialog);
ResourceExtensions.useResourceExplorer(this.dialogManager, this.resourceExplorer);
this.dialogManager.initialTurnState.set('settings', this.settings);
if (this.telemetryClient) {
useTelemetry(this.dialogManager, this.telemetryClient);
}
}

private configureLanguageGeneration() {
Expand Down
66 changes: 65 additions & 1 deletion runtime/node/src/shared/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,25 @@ import {
ChannelServiceRoutes,
ConversationState,
InputHints,
InspectionMiddleware,
InspectionState,
SkillHandler,
Storage,
TranscriptLoggerMiddleware,
TurnContext,
UserState,
useBotState,
WebRequest,
WebResponse,
ShowTypingMiddleware,
TelemetryLoggerMiddleware,
BotTelemetryClient,
} from 'botbuilder';
import {
ApplicationInsightsTelemetryClient,
TelemetryInitializerMiddleware,
} from 'botbuilder-applicationinsights';
import { BlobsTranscriptStore } from 'botbuilder-azure-blobs';
import { AuthenticationConfiguration, SimpleCredentialProvider } from 'botframework-connector';
import { ComposerBot } from './composerBot';
import { BotSettings } from './settings';
Expand Down Expand Up @@ -113,14 +125,40 @@ export const getRootDialog = (folderPath: string): string => {
* @param userState User state required by a botframework adapter.
* @param conversationState Conversation state required by a botframework adapter.
*/
export const getBotAdapter = (userState: UserState, conversationState: ConversationState): BotFrameworkAdapter => {
export const getBotAdapter = (
storage: Storage,
userState: UserState,
conversationState: ConversationState
): BotFrameworkAdapter => {
const settings = getSettings();
const adapterSettings: Partial<BotFrameworkAdapterSettings> = {
appId: settings.MicrosoftAppId,
appPassword: settings.MicrosoftAppPassword,
};
const adapter = new BotFrameworkAdapter(adapterSettings);
useBotState(adapter, userState, conversationState);

// Configure Middlewares
if (settings.blobStorage?.connectionString && settings.blobStorage?.container) {
adapter.use(
new TranscriptLoggerMiddleware(
new BlobsTranscriptStore(settings.blobStorage?.connectionString, settings.blobStorage?.container)
)
);
}

if (settings.feature?.UseInspectionMiddleware) {
adapter.use(new InspectionMiddleware(new InspectionState(storage)));
}

if (settings.feature?.UseShowTypingMiddleware) {
adapter.use(new ShowTypingMiddleware());
}

if (settings.feature?.UseSetSpeakMiddleware && settings.speech) {
// TODO: add SetSpeakMiddleware (not available in botbuilder 4.12)
}

adapter.onTurnError = async (turnContext: TurnContext, error: Error) => {
try {
// Send a message to the user.
Expand All @@ -146,6 +184,14 @@ export const getBotAdapter = (userState: UserState, conversationState: Conversat
return adapter;
};

export const getTelemetryClient = (): BotTelemetryClient => {
const settings = getSettings();
if (settings.applicationInsights?.InstrumentationKey) {
return new ApplicationInsightsTelemetryClient(settings.applicationInsights?.InstrumentationKey);
}
return undefined;
};

/**
* Configure a server to work with botframework message requests.
* @param server Web server to be configured.
Expand Down Expand Up @@ -204,3 +250,21 @@ export const configureManifestsEndpoint = (server: Server) => {
}
}
};

/**
* Configure botframework adapter to use telemetry client.
* @param adapter Botframework adapter to be configured.
* @param telemetryClient Telemetry client.
*/
export const configureTelemetry = (adapter: BotFrameworkAdapter, telemetryClient: BotTelemetryClient): void => {
const settings = getSettings();

const telemetryLoggerMiddleware = new TelemetryLoggerMiddleware(
telemetryClient,
settings.telemetry?.logPersonalInformation ?? false
);

adapter.use(
new TelemetryInitializerMiddleware(telemetryLoggerMiddleware, settings.telemetry?.logActivities ?? false)
);
};
8 changes: 4 additions & 4 deletions runtime/node/src/shared/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ export interface BotSettings {
}

export interface BotFeatureSettings {
useShowTypingMiddleware: boolean;
useInspectionMiddleware: boolean;
removeRecipientMention: boolean;
useSetSpeakMiddleware: boolean;
UseShowTypingMiddleware: boolean;
UseInspectionMiddleware: boolean;
RemoveRecipientMention: boolean;
UseSetSpeakMiddleware: boolean;
}

export interface BotSkillSettings {
Expand Down
16 changes: 14 additions & 2 deletions runtime/node/src/webapp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@

import * as restify from 'restify';
import { ConversationState, MemoryStorage, UserState } from 'botbuilder';
import { ApplicationInsightsWebserverMiddleware } from 'botbuilder-applicationinsights';
import { ComposerBot } from './shared/composerBot';
import {
getBotAdapter,
configureSkillEndpoint,
configureMessageEndpoint,
getServerPort,
configureManifestsEndpoint,
configureTelemetry,
getTelemetryClient,
} from './shared/helpers';
import { SkillConversationIdFactory } from './shared/skillConversationIdFactory';
import debug from 'debug';
Expand All @@ -30,10 +33,13 @@ const skillConversationIdFactory = new SkillConversationIdFactory();
const server = restify.createServer({ maxParamLength: 1000 });

// Get botframework adapter.
const adapter = getBotAdapter(userState, conversationState);
const adapter = getBotAdapter(memoryStorage, userState, conversationState);

// Get bot telemetry client.
const telemetryClient = getTelemetryClient();

// Create composer bot instance with root dialog.
const bot = new ComposerBot(userState, conversationState, skillConversationIdFactory);
const bot = new ComposerBot(userState, conversationState, skillConversationIdFactory, telemetryClient);

// Configure message endpoint.
configureMessageEndpoint(server, adapter, bot);
Expand All @@ -44,6 +50,12 @@ configureSkillEndpoint(server, adapter, bot, skillConversationIdFactory);
// Configure manifests endpoint.
configureManifestsEndpoint(server);

// Configure telemetry client, initializers and middleware.
if (telemetryClient) {
server.use(ApplicationInsightsWebserverMiddleware);
configureTelemetry(adapter, telemetryClient);
}

// Get port and listen.
const port = getServerPort();
server.listen(port, (): void => {
Expand Down