port: component registration -> bot components (#3471)

* feat: BotComponent instead of ComponentRegistration

* fix: serviceCollection sync

* feat: dialogs to bot component, shim registration

* fix: dialogs adaptive testing component registration

* fix: adaptive teams tests

* fix: dialogs declarative tests

* fix: orchestrator bot component

* fix: remove unused p-reduce dep

* fix: orchestrator rename

* fix: corebot initial turn state

* fix: turn state undefined

* fix: component load error

* fix: use no-op configuration for configure services calls

* fix: shim luis/qna component registrations

* port: collect bot component load exceptions and report once

* fix: orchestrator exports

* fix: noOpConfiguration docstring
This commit is contained in:
Josh Gummersall 2021-03-29 15:28:13 -07:00 коммит произвёл GitHub
Родитель 1bc772d54d
Коммит 85ff1febb9
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
71 изменённых файлов: 1294 добавлений и 1449 удалений

Просмотреть файл

@ -32,6 +32,7 @@
"botbuilder-dialogs": "4.1.6",
"botbuilder-dialogs-adaptive": "4.1.6",
"botbuilder-dialogs-declarative": "4.1.6",
"botbuilder-runtime-core": "4.1.6",
"orchestrator-core": "rc",
"uuid": "^8.3.2"
},

Просмотреть файл

@ -6,5 +6,5 @@
* Licensed under the MIT License.
*/
export { OrchestratorRecognizer, LabelType } from './orchestratorRecognizer';
export { OrchestratorComponentRegistration } from './orchestratorComponentRegistration';
export { LabelType, OrchestratorRecognizer } from './orchestratorRecognizer';
export { OrchestratorBotComponent } from './orchestratorBotComponent';

Просмотреть файл

@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { BotComponent } from 'botbuilder-core';
import { ComponentDeclarativeTypes } from 'botbuilder-dialogs-declarative';
import { OrchestratorRecognizer } from './orchestratorRecognizer';
import { ServiceCollection, Configuration } from 'botbuilder-runtime-core';
export class OrchestratorBotComponent extends BotComponent {
configureServices(services: ServiceCollection, _configuration: Configuration): void {
services.composeFactory<ComponentDeclarativeTypes[]>('declarativeTypes', (declarativeTypes) =>
declarativeTypes.concat({
getDeclarativeTypes() {
return [
{
kind: OrchestratorRecognizer.$kind,
type: OrchestratorRecognizer,
},
];
},
})
);
}
}

Просмотреть файл

@ -1,21 +0,0 @@
/**
* @module botbuilder-ai-orchestrator
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { ComponentDeclarativeTypes, DeclarativeType } from 'botbuilder-dialogs-declarative';
import { OrchestratorRecognizer } from './orchestratorRecognizer';
export class OrchestratorComponentRegistration implements ComponentDeclarativeTypes {
public getDeclarativeTypes(_resourceExplorer: unknown): DeclarativeType[] {
return [
{
kind: OrchestratorRecognizer.$kind,
type: OrchestratorRecognizer,
},
];
}
}

Просмотреть файл

@ -33,6 +33,8 @@
"adaptive-expressions": "4.1.6",
"botbuilder-core": "4.1.6",
"botbuilder-dialogs": "4.1.6",
"botbuilder-dialogs-declarative": "4.1.6",
"botbuilder-runtime-core": "4.1.6",
"lodash": "^4.17.21",
"node-fetch": "^2.6.0",
"url-parse": "^1.5.1"
@ -59,4 +61,4 @@
"schemas",
"src"
]
}
}

Просмотреть файл

@ -14,12 +14,22 @@ export * from './instanceData';
export * from './intentData';
export * from './listElement';
export * from './luisAdaptiveRecognizer';
export * from './luisBotComponent';
export * from './luisComponentRegistration';
export * from './luisRecognizer';
export * from './luisTelemetryConstants';
export * from './numberWithUnits';
export * from './ordinalV2';
export * from './qnaCardBuilder';
export * from './qnaMakerBotComponent';
export * from './qnaMakerComponentRegistration';
export * from './qnaMakerRecognizer';
// BindToActivity, GenerateAnswerUtils, HttpRequestUtils and TrainUtils are internal.
export { ActiveLearningUtils } from './qnamaker-utils';
export { QnAMakerDialog, QnAMakerDialogOptions, QnAMakerDialogResponseOptions } from './qnaMakerDialog';
export {
QNAMAKER_TRACE_TYPE,
QNAMAKER_TRACE_NAME,
@ -29,6 +39,7 @@ export {
QnAMakerClientKey,
QnAMaker,
} from './qnaMaker';
export {
FeedbackRecord,
FeedbackRecords,
@ -43,9 +54,3 @@ export {
QnAResponseContext,
RankerTypes,
} from './qnamaker-interfaces';
export { QnAMakerDialog, QnAMakerDialogOptions, QnAMakerDialogResponseOptions } from './qnaMakerDialog';
export * from './qnaMakerComponentRegistration';
export * from './qnaMakerRecognizer';
// BindToActivity, GenerateAnswerUtils, HttpRequestUtils and TrainUtils are internal.
export { ActiveLearningUtils } from './qnamaker-utils';

Просмотреть файл

@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { BotComponent } from 'botbuilder-core';
import { ComponentDeclarativeTypes } from 'botbuilder-dialogs-declarative';
import { Configuration, ServiceCollection } from 'botbuilder-runtime-core';
import { LuisAdaptiveRecognizer } from './luisAdaptiveRecognizer';
export class LuisBotComponent extends BotComponent {
configureServices(services: ServiceCollection, _configuration: Configuration): void {
services.composeFactory<ComponentDeclarativeTypes[]>('declarativeTypes', (declarativeTypes) =>
declarativeTypes.concat({
getDeclarativeTypes() {
return [
{
kind: LuisAdaptiveRecognizer.$kind,
type: LuisAdaptiveRecognizer,
},
];
},
})
);
}
}

Просмотреть файл

@ -6,25 +6,32 @@
* Licensed under the MIT License.
*/
import { ComponentDeclarativeTypes } from 'botbuilder-dialogs-declarative';
import { ComponentRegistration } from 'botbuilder-core';
import { LuisAdaptiveRecognizer } from './luisAdaptiveRecognizer';
import { LuisBotComponent } from './luisBotComponent';
import { ServiceCollection, noOpConfiguration } from 'botbuilder-runtime-core';
/**
* Define component assets for Luis.
*/
export class LuisComponentRegistration extends ComponentRegistration {
private readonly services = new ServiceCollection({
declarativeTypes: [],
});
constructor() {
super();
new LuisBotComponent().configureServices(this.services, noOpConfiguration);
}
/**
* Get declarative types for LUIS component registration.
*
* @param {any} _resourceExplorer resource explorer
* @returns {ComponentRegistration[]} component registrations
* @param _resourceExplorer resource explorer
* @returns component registrations
*/
public getDeclarativeTypes(_resourceExplorer: unknown): ComponentRegistration[] {
return [
{
kind: LuisAdaptiveRecognizer.$kind,
type: LuisAdaptiveRecognizer,
},
];
public getDeclarativeTypes(_resourceExplorer: unknown): ComponentDeclarativeTypes[] {
return this.services.mustMakeInstance<ComponentDeclarativeTypes[]>('declarativeTypes');
}
}

Просмотреть файл

@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { BotComponent } from 'botbuilder-core';
import { ComponentDeclarativeTypes } from 'botbuilder-dialogs-declarative';
import { Configuration, ServiceCollection } from 'botbuilder-runtime-core';
import { QnAMakerDialog } from './qnaMakerDialog';
import { QnAMakerRecognizer } from './qnaMakerRecognizer';
export class QnAMakerBotComponent extends BotComponent {
configureServices(services: ServiceCollection, _configuration: Configuration): void {
services.composeFactory<ComponentDeclarativeTypes[]>('declarativeTypes', (declarativeTypes) =>
declarativeTypes.concat({
getDeclarativeTypes() {
return [
{
kind: QnAMakerRecognizer.$kind,
type: QnAMakerRecognizer,
},
{
kind: QnAMakerDialog.$kind,
type: QnAMakerDialog,
},
];
},
})
);
}
}

Просмотреть файл

@ -6,24 +6,32 @@
* Licensed under the MIT License.
*/
import { ComponentDeclarativeTypes } from 'botbuilder-dialogs-declarative';
import { ComponentRegistration } from 'botbuilder-core';
import { QnAMakerDialog } from './qnaMakerDialog';
import { QnAMakerRecognizer } from './qnaMakerRecognizer';
import { QnAMakerBotComponent } from './qnaMakerBotComponent';
import { ServiceCollection, noOpConfiguration } from 'botbuilder-runtime-core';
/**
* Define component assets for QnAMaker.
*/
export class QnAMakerComponentRegistration extends ComponentRegistration {
public getDeclarativeTypes(_resourceExplorer: unknown): unknown[] {
return [
{
kind: QnAMakerRecognizer.$kind,
type: QnAMakerRecognizer,
},
{
kind: QnAMakerDialog.$kind,
type: QnAMakerDialog,
},
];
private readonly services = new ServiceCollection({
declarativeTypes: [],
});
constructor() {
super();
new QnAMakerBotComponent().configureServices(this.services, noOpConfiguration);
}
/**
* Get declarative types for QnAMaker component registration.
*
* @param _resourceExplorer resource explorer
* @returns component registrations
*/
public getDeclarativeTypes(_resourceExplorer: unknown): ComponentDeclarativeTypes[] {
return this.services.mustMakeInstance<ComponentDeclarativeTypes[]>('declarativeTypes');
}
}

Просмотреть файл

@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { Assertion, assert } from 'botbuilder-stdlib';
import { Configuration, ServiceCollection } from 'botbuilder-runtime-core';
import { Test, tests } from 'botbuilder-stdlib';
/**
* Definition of a BotComponent that allows registration of services, custom actions, memory scopes and adapters.
@ -15,6 +15,7 @@ export abstract class BotComponent {
abstract configureServices(services: ServiceCollection, configuration: Configuration): void;
}
export const isBotComponent: Test<BotComponent> = (val): val is BotComponent => {
return tests.unsafe.isObjectAs<BotComponent>(val) && tests.isFunc(val.configureServices);
export const assertBotComponent: Assertion<BotComponent> = (val, path) => {
assert.unsafe.castObjectAs<BotComponent>(val, path);
assert.func(val.configureServices, path.concat('configureServices'));
};

Просмотреть файл

@ -33,6 +33,7 @@
"botbuilder-dialogs": "4.1.6",
"botbuilder-dialogs-adaptive": "4.1.6",
"botbuilder-dialogs-declarative": "4.1.6",
"botbuilder-runtime-core": "4.1.6",
"botbuilder-stdlib": "4.1.6",
"lodash": "^4.17.19"
},

Просмотреть файл

@ -14,7 +14,6 @@ export * from './getTeamChannels';
export * from './getTeamDetails';
export * from './getTeamMember';
export * from './sendAppBasedLinkQueryResponse';
export * from './sendMessageToTeamsChannel';
export * from './sendMEActionResponse';
export * from './sendMEAttachmentsResponse';
export * from './sendMEAuthResponse';
@ -22,6 +21,9 @@ export * from './sendMEBotMessagePreviewResponse';
export * from './sendMEConfigQuerySettingUrlResponse';
export * from './sendMEMessageResponse';
export * from './sendMESelectItemResponse';
export * from './sendMessageToTeamsChannel';
export * from './sendTabAuthResponse';
export * from './sendTabCardResponse';
export * from './sendTaskModuleCardResponse';
export * from './sendTaskModuleMessageResponse';
export * from './sendTaskModuleUrlResponse';

Просмотреть файл

@ -0,0 +1,126 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { BotComponent } from 'botbuilder';
import { ComponentDeclarativeTypes } from 'botbuilder-dialogs-declarative';
import { Configuration, ServiceCollection } from 'botbuilder-runtime-core';
import {
GetMeetingParticipant,
GetMember,
GetPagedMembers,
GetPagedTeamMembers,
GetTeamChannels,
GetTeamDetails,
GetTeamMember,
SendAppBasedLinkQueryResponse,
SendMEActionResponse,
SendMEAttachmentsResponse,
SendMEAuthResponse,
SendMEBotMessagePreviewResponse,
SendMEConfigQuerySettingUrlResponse,
SendMEMessageResponse,
SendMESelectItemResponse,
SendMessageToTeamsChannel,
SendTabAuthResponse,
SendTabCardResponse,
SendTaskModuleCardResponse,
SendTaskModuleMessageResponse,
SendTaskModuleUrlResponse,
} from './actions';
import {
OnTeamsAppBasedLinkQuery,
OnTeamsCardAction,
OnTeamsChannelCreated,
OnTeamsChannelDeleted,
OnTeamsChannelRenamed,
OnTeamsChannelRestored,
OnTeamsFileConsent,
OnTeamsMEBotMessagePreviewEdit,
OnTeamsMEBotMessagePreviewSend,
OnTeamsMECardButtonClicked,
OnTeamsMEConfigQuerySettingUrl,
OnTeamsMEConfigSetting,
OnTeamsMEConfigurationSetting,
OnTeamsMEFetchTask,
OnTeamsMEQuery,
OnTeamsMESelectItem,
OnTeamsMESubmitAction,
OnTeamsO365ConnectorCardAction,
OnTeamsTabFetch,
OnTeamsTabSubmit,
OnTeamsTaskModuleFetch,
OnTeamsTaskModuleSubmit,
OnTeamsTeamArchived,
OnTeamsTeamDeleted,
OnTeamsTeamHardDeleted,
OnTeamsTeamRenamed,
OnTeamsTeamRestored,
OnTeamsTeamUnarchived,
} from './conditions';
export class AdaptiveTeamsBotComponent extends BotComponent {
configureServices(services: ServiceCollection, _configuration: Configuration): void {
services.composeFactory<ComponentDeclarativeTypes[]>('declarativeTypes', (declarativeTypes) =>
declarativeTypes.concat({
getDeclarativeTypes() {
return [
// Actions
{ kind: GetMeetingParticipant.$kind, type: GetMeetingParticipant },
{ kind: GetMember.$kind, type: GetMember },
{ kind: GetPagedMembers.$kind, type: GetPagedMembers },
{ kind: GetPagedTeamMembers.$kind, type: GetPagedTeamMembers },
{ kind: GetTeamChannels.$kind, type: GetTeamChannels },
{ kind: GetTeamDetails.$kind, type: GetTeamDetails },
{ kind: GetTeamMember.$kind, type: GetTeamMember },
{ kind: SendAppBasedLinkQueryResponse.$kind, type: SendAppBasedLinkQueryResponse },
{ kind: SendMEActionResponse.$kind, type: SendMEActionResponse },
{ kind: SendMEAttachmentsResponse.$kind, type: SendMEAttachmentsResponse },
{ kind: SendMEAuthResponse.$kind, type: SendMEAuthResponse },
{ kind: SendMEBotMessagePreviewResponse.$kind, type: SendMEBotMessagePreviewResponse },
{ kind: SendMEConfigQuerySettingUrlResponse.$kind, type: SendMEConfigQuerySettingUrlResponse },
{ kind: SendMEMessageResponse.$kind, type: SendMEMessageResponse },
{ kind: SendMESelectItemResponse.$kind, type: SendMESelectItemResponse },
{ kind: SendMessageToTeamsChannel.$kind, type: SendMessageToTeamsChannel },
{ kind: SendTabAuthResponse.$kind, type: SendTabAuthResponse },
{ kind: SendTabCardResponse.$kind, type: SendTabCardResponse },
{ kind: SendTaskModuleCardResponse.$kind, type: SendTaskModuleCardResponse },
{ kind: SendTaskModuleMessageResponse.$kind, type: SendTaskModuleMessageResponse },
{ kind: SendTaskModuleUrlResponse.$kind, type: SendTaskModuleUrlResponse },
// Conditions
{ kind: OnTeamsAppBasedLinkQuery.$kind, type: OnTeamsAppBasedLinkQuery },
{ kind: OnTeamsCardAction.$kind, type: OnTeamsCardAction },
{ kind: OnTeamsChannelCreated.$kind, type: OnTeamsChannelCreated },
{ kind: OnTeamsChannelDeleted.$kind, type: OnTeamsChannelDeleted },
{ kind: OnTeamsChannelRenamed.$kind, type: OnTeamsChannelRenamed },
{ kind: OnTeamsChannelRestored.$kind, type: OnTeamsChannelRestored },
{ kind: OnTeamsFileConsent.$kind, type: OnTeamsFileConsent },
{ kind: OnTeamsMEBotMessagePreviewEdit.$kind, type: OnTeamsMEBotMessagePreviewEdit },
{ kind: OnTeamsMEBotMessagePreviewSend.$kind, type: OnTeamsMEBotMessagePreviewSend },
{ kind: OnTeamsMECardButtonClicked.$kind, type: OnTeamsMECardButtonClicked },
{ kind: OnTeamsMEConfigSetting.$kind, type: OnTeamsMEConfigSetting },
{ kind: OnTeamsMEConfigQuerySettingUrl.$kind, type: OnTeamsMEConfigQuerySettingUrl },
{ kind: OnTeamsMEFetchTask.$kind, type: OnTeamsMEFetchTask },
{ kind: OnTeamsMEQuery.$kind, type: OnTeamsMEQuery },
{ kind: OnTeamsMESelectItem.$kind, type: OnTeamsMESelectItem },
{ kind: OnTeamsMEConfigurationSetting.$kind, type: OnTeamsMEConfigurationSetting },
{ kind: OnTeamsMESubmitAction.$kind, type: OnTeamsMESubmitAction },
{ kind: OnTeamsO365ConnectorCardAction.$kind, type: OnTeamsO365ConnectorCardAction },
{ kind: OnTeamsTabFetch.$kind, type: OnTeamsTabFetch },
{ kind: OnTeamsTabSubmit.$kind, type: OnTeamsTabSubmit },
{ kind: OnTeamsTaskModuleFetch.$kind, type: OnTeamsTaskModuleFetch },
{ kind: OnTeamsTaskModuleSubmit.$kind, type: OnTeamsTaskModuleSubmit },
{ kind: OnTeamsTeamArchived.$kind, type: OnTeamsTeamArchived },
{ kind: OnTeamsTeamDeleted.$kind, type: OnTeamsTeamDeleted },
{ kind: OnTeamsTeamHardDeleted.$kind, type: OnTeamsTeamHardDeleted },
{ kind: OnTeamsTeamRenamed.$kind, type: OnTeamsTeamRenamed },
{ kind: OnTeamsTeamRestored.$kind, type: OnTeamsTeamRestored },
{ kind: OnTeamsTeamUnarchived.$kind, type: OnTeamsTeamUnarchived },
];
},
})
);
}
}

Просмотреть файл

@ -6,6 +6,7 @@
* Licensed under the MIT License.
*/
export * from './onTeamsAppBasedLinkQuery';
export * from './onTeamsAppBasedLinkQuery';
export * from './onTeamsCardAction';
export * from './onTeamsChannelCreated';
@ -17,6 +18,7 @@ export * from './onTeamsMEBotMessagePreviewEdit';
export * from './onTeamsMEBotMessagePreviewSend';
export * from './onTeamsMECardButtonClicked';
export * from './onTeamsMEConfigQuerySettingUrl';
export * from './onTeamsMEConfigSetting';
export * from './onTeamsMEConfigurationSetting';
export * from './onTeamsMEFetchTask';
export * from './onTeamsMEQuery';
@ -28,9 +30,9 @@ export * from './onTeamsTabSubmit';
export * from './onTeamsTaskModuleFetch';
export * from './onTeamsTaskModuleSubmit';
export * from './onTeamsTeamArchived';
export * from './onTeamsTeamArchived';
export * from './onTeamsTeamDeleted';
export * from './onTeamsTeamHardDeleted';
export * from './onTeamsTeamRenamed';
export * from './onTeamsTeamRestored';
export * from './onTeamsTeamArchived';
export * from './onTeamsTeamUnarchived';

Просмотреть файл

@ -7,5 +7,5 @@
*/
export * from './actions';
export * from './adaptiveTeamsBotComponent';
export * from './conditions';
export * from './teamsComponentRegistration';

Просмотреть файл

@ -1,188 +0,0 @@
/**
* @module botbuilder-dialogs-adaptive-teams
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { OnTeamsAppBasedLinkQuery } from './conditions/onTeamsAppBasedLinkQuery';
import {
ComponentDeclarativeTypes,
CustomDeserializer,
DeclarativeType,
ResourceExplorer,
} from 'botbuilder-dialogs-declarative';
import { OnActivityConfiguration } from 'botbuilder-dialogs-adaptive';
import {
OnTeamsCardAction,
OnTeamsChannelCreated,
OnTeamsChannelDeleted,
OnTeamsChannelRenamed,
OnTeamsChannelRestored,
OnTeamsFileConsent,
OnTeamsMEBotMessagePreviewEdit,
OnTeamsMEBotMessagePreviewSend,
OnTeamsMECardButtonClicked,
OnTeamsMEConfigQuerySettingUrl,
OnTeamsMEConfigurationSetting,
OnTeamsMEFetchTask,
OnTeamsMEQuery,
OnTeamsMESelectItem,
OnTeamsMESubmitAction,
OnTeamsO365ConnectorCardAction,
OnTeamsTabFetch,
OnTeamsTabSubmit,
OnTeamsTaskModuleFetch,
OnTeamsTaskModuleSubmit,
OnTeamsTeamArchived,
OnTeamsTeamDeleted,
OnTeamsTeamHardDeleted,
OnTeamsTeamRenamed,
OnTeamsTeamRestored,
OnTeamsTeamUnarchived,
} from './conditions';
import {
GetMeetingParticipant,
GetMeetingParticipantConfiguration,
GetMember,
GetMemberConfiguration,
GetPagedMembers,
GetPagedMembersConfiguration,
GetPagedTeamMembers,
GetPagedTeamMembersConfiguration,
GetTeamChannels,
GetTeamChannelsConfiguration,
GetTeamDetails,
GetTeamDetailsConfiguration,
GetTeamMember,
GetTeamMemberConfiguration,
SendAppBasedLinkQueryResponse,
SendAppBasedLinkQueryResponseConfiguration,
SendMessageToTeamsChannel,
SendMEActionResponse,
SendMEActionResponseConfiguration,
SendMEAttachmentsResponse,
SendMEAttachmentsResponseConfiguration,
SendMEAuthResponse,
SendMEBotMessagePreviewResponse,
SendMEBotMessagePreviewResponseConfiguration,
SendMEConfigQuerySettingUrlResponse,
SendMEConfigQuerySettingUrlResponseConfiguration,
SendMEMessageResponse,
SendMEMessageResponseConfiguration,
SendMESelectItemResponse,
SendMESelectItemResponseConfiguration,
SendTaskModuleCardResponse,
SendTaskModuleCardResponseConfiguration,
SendTaskModuleMessageResponse,
SendTaskModuleMessageResponseConfiguration,
SendTaskModuleUrlResponse,
SendTaskModuleUrlResponseConfiguration,
} from './actions';
import { ComponentRegistration } from 'botbuilder';
import { Dialog } from 'botbuilder-dialogs';
import { BaseAuthResponseDialogConfiguration } from './actions/baseAuthResponseDialog';
import { SendTabAuthResponse } from './actions/sendTabAuthResponse';
import { SendTabCardResponse } from './actions/sendTabCardResponse';
import { OnTeamsMEConfigSetting } from './conditions/onTeamsMEConfigSetting';
type ActionType<T> = {
$kind: string;
new (dialogId?: string | undefined): T;
};
type ConditionType<T> = {
$kind: string;
new (actions?: Dialog<Record<string, unknown>>[] | undefined, condition?: string | undefined): T;
};
type Type<T> = {
$kind: string;
new (...args: unknown[]): T;
};
/* eslint-disable prettier/prettier */
/* eslint-reason It's extremely difficult to read with limited line widths.*/
export class TeamsComponentRegistration extends ComponentRegistration implements ComponentDeclarativeTypes {
private _declarativeTypes: DeclarativeType<unknown, unknown>[] = [];
/**
* Initializes a new instance of `TeamsComponentRegistration`.
*/
public constructor() {
super();
// Actions
this._addDeclarativeType<GetMeetingParticipant, GetMeetingParticipantConfiguration>(GetMeetingParticipant);
this._addDeclarativeType<GetMember, GetMemberConfiguration>(GetMember);
this._addDeclarativeType<GetPagedMembers, GetPagedMembersConfiguration>(GetPagedMembers);
this._addDeclarativeType<GetPagedTeamMembers, GetPagedTeamMembersConfiguration>(GetPagedTeamMembers);
this._addDeclarativeType<GetTeamChannels, GetTeamChannelsConfiguration>(GetTeamChannels);
this._addDeclarativeType<GetTeamDetails, GetTeamDetailsConfiguration>(GetTeamDetails);
this._addDeclarativeType<GetTeamMember, GetTeamMemberConfiguration>(GetTeamMember);
this._addDeclarativeType<SendAppBasedLinkQueryResponse, SendAppBasedLinkQueryResponseConfiguration>(SendAppBasedLinkQueryResponse);
this._addDeclarativeType<SendMessageToTeamsChannel, SendMessageToTeamsChannel>(SendMessageToTeamsChannel);
this._addDeclarativeType<SendMEActionResponse, SendMEActionResponseConfiguration>(SendMEActionResponse);
this._addDeclarativeType<SendMEAttachmentsResponse,SendMEAttachmentsResponseConfiguration>(SendMEAttachmentsResponse);
this._addDeclarativeType<SendMEAuthResponse, BaseAuthResponseDialogConfiguration>(SendMEAuthResponse);
this._addDeclarativeType<SendMEBotMessagePreviewResponse,SendMEBotMessagePreviewResponseConfiguration>(SendMEBotMessagePreviewResponse);
this._addDeclarativeType<SendMEConfigQuerySettingUrlResponse,SendMEConfigQuerySettingUrlResponseConfiguration>(SendMEConfigQuerySettingUrlResponse);
this._addDeclarativeType<SendMEMessageResponse,SendMEMessageResponseConfiguration>(SendMEMessageResponse);
this._addDeclarativeType<SendMESelectItemResponse,SendMESelectItemResponseConfiguration>(SendMESelectItemResponse);
this._addDeclarativeType<SendTaskModuleCardResponse, SendTaskModuleCardResponseConfiguration>(SendTaskModuleCardResponse);
this._addDeclarativeType<SendTaskModuleMessageResponse, SendTaskModuleMessageResponseConfiguration>(SendTaskModuleMessageResponse);
this._addDeclarativeType<SendTaskModuleUrlResponse, SendTaskModuleUrlResponseConfiguration>(SendTaskModuleUrlResponse);
this._addDeclarativeType<SendTabAuthResponse, BaseAuthResponseDialogConfiguration>(SendTabAuthResponse);
this._addDeclarativeType<SendTabCardResponse, BaseAuthResponseDialogConfiguration>(SendTabCardResponse);
// Conditions
this._addDeclarativeType<OnTeamsAppBasedLinkQuery, OnActivityConfiguration>(OnTeamsAppBasedLinkQuery);
this._addDeclarativeType<OnTeamsCardAction, OnActivityConfiguration>(OnTeamsCardAction);
this._addDeclarativeType<OnTeamsChannelCreated, OnActivityConfiguration>(OnTeamsChannelCreated);
this._addDeclarativeType<OnTeamsChannelDeleted, OnActivityConfiguration>(OnTeamsChannelDeleted);
this._addDeclarativeType<OnTeamsChannelRenamed, OnActivityConfiguration>(OnTeamsChannelRenamed);
this._addDeclarativeType<OnTeamsChannelRestored, OnActivityConfiguration>(OnTeamsChannelRestored);
this._addDeclarativeType<OnTeamsFileConsent, OnActivityConfiguration>(OnTeamsFileConsent);
this._addDeclarativeType<OnTeamsMEBotMessagePreviewEdit, OnActivityConfiguration>(OnTeamsMEBotMessagePreviewEdit);
this._addDeclarativeType<OnTeamsMEBotMessagePreviewSend, OnActivityConfiguration>(OnTeamsMEBotMessagePreviewSend);
this._addDeclarativeType<OnTeamsMECardButtonClicked, OnActivityConfiguration>(OnTeamsMECardButtonClicked);
this._addDeclarativeType<OnTeamsMEConfigSetting, OnActivityConfiguration>(OnTeamsMEConfigSetting);
this._addDeclarativeType<OnTeamsMEConfigQuerySettingUrl, OnActivityConfiguration>(OnTeamsMEConfigQuerySettingUrl);
this._addDeclarativeType<OnTeamsMEFetchTask, OnActivityConfiguration>(OnTeamsMEFetchTask);
this._addDeclarativeType<OnTeamsMEQuery, OnActivityConfiguration>(OnTeamsMEQuery);
this._addDeclarativeType<OnTeamsMESelectItem, OnActivityConfiguration>(OnTeamsMESelectItem);
this._addDeclarativeType<OnTeamsMEConfigurationSetting, OnActivityConfiguration>(OnTeamsMEConfigurationSetting);
this._addDeclarativeType<OnTeamsMESubmitAction, OnActivityConfiguration>(OnTeamsMESubmitAction);
this._addDeclarativeType<OnTeamsO365ConnectorCardAction, OnActivityConfiguration>(OnTeamsO365ConnectorCardAction);
this._addDeclarativeType<OnTeamsTabFetch, OnActivityConfiguration>(OnTeamsTabFetch);
this._addDeclarativeType<OnTeamsTabSubmit, OnActivityConfiguration>(OnTeamsTabSubmit);
this._addDeclarativeType<OnTeamsTaskModuleFetch, OnActivityConfiguration>(OnTeamsTaskModuleFetch);
this._addDeclarativeType<OnTeamsTaskModuleSubmit, OnActivityConfiguration>(OnTeamsTaskModuleSubmit);
this._addDeclarativeType<OnTeamsTeamArchived, OnActivityConfiguration>(OnTeamsTeamArchived);
this._addDeclarativeType<OnTeamsTeamDeleted, OnActivityConfiguration>(OnTeamsTeamDeleted);
this._addDeclarativeType<OnTeamsTeamHardDeleted, OnActivityConfiguration>(OnTeamsTeamHardDeleted);
this._addDeclarativeType<OnTeamsTeamRenamed, OnActivityConfiguration>(OnTeamsTeamRenamed);
this._addDeclarativeType<OnTeamsTeamRestored, OnActivityConfiguration>(OnTeamsTeamRestored);
this._addDeclarativeType<OnTeamsTeamUnarchived, OnActivityConfiguration>(OnTeamsTeamUnarchived);
}
/**
* Gets adaptive testing `DeclarativeType` resources.
*
* @param {ResourceExplorer} _resourceExplorer `ResourceExplorer` with expected path to get all resources.
* @returns {DeclarativeType[]} Adaptive testing `DeclarativeType` resources.
*/
public getDeclarativeTypes(_resourceExplorer: ResourceExplorer): DeclarativeType[] {
return this._declarativeTypes;
}
private _addDeclarativeType<T, C>(type: ActionType<T> | ConditionType<T>, loader?: CustomDeserializer<T, C>): void {
const declarativeType: DeclarativeType<T, C> = {
kind: type.$kind,
type: <Type<T>>type,
loader,
};
this._declarativeTypes.push(declarativeType);
}
}

Просмотреть файл

@ -1,8 +1,18 @@
// Licensed under the MIT License.
// Copyright (c) Microsoft Corporation. All rights reserved.
import nock = require('nock');
import path = require('path');
import { AdaptiveBotComponent } from 'botbuilder-dialogs-adaptive';
import { AdaptiveTeamsBotComponent } from '../src/adaptiveTeamsBotComponent';
import { AdaptiveTestBotComponent, TestUtils } from 'botbuilder-dialogs-adaptive-testing';
import { ConnectorClient, MicrosoftAppCredentials } from 'botframework-connector';
import { ComponentDeclarativeTypes, ResourceExplorer } from 'botbuilder-dialogs-declarative';
import { ServiceCollection, noOpConfiguration } from 'botbuilder-runtime-core';
import { jwt } from 'botbuilder-test-utils';
import { ok } from 'assert';
import {
ComponentRegistration,
ConversationState,
TestAdapter,
useBotState,
@ -13,15 +23,6 @@ import {
ChannelAccount,
ConversationAccount,
} from 'botbuilder';
import { ResourceExplorer } from 'botbuilder-dialogs-declarative';
import { TeamsComponentRegistration } from '../lib';
import { AdaptiveTestComponentRegistration, TestUtils } from 'botbuilder-dialogs-adaptive-testing';
import { AdaptiveComponentRegistration } from 'botbuilder-dialogs-adaptive';
import { ConnectorClient, MicrosoftAppCredentials } from 'botframework-connector';
import { ok } from 'assert';
import path = require('path');
import nock = require('nock');
import { jwt } from 'botbuilder-test-utils';
const getTeamsTestAdapter = (convo?: Partial<ConversationReference>): TestAdapter => {
const adapter = new TestAdapter(convo as ConversationReference);
@ -118,11 +119,24 @@ const generateTeamMembers = (amount: number): Record<string, unknown>[] => {
describe('Actions', function () {
jwt.mocha();
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new TeamsComponentRegistration());
let resourceExplorer: ResourceExplorer;
beforeEach(function () {
const services = new ServiceCollection({
declarativeTypes: [],
});
const resourceExplorer = new ResourceExplorer().addFolder(path.join(__dirname, 'actionTests'), true, false);
new AdaptiveBotComponent().configureServices(services, noOpConfiguration);
new AdaptiveTeamsBotComponent().configureServices(services, noOpConfiguration);
new AdaptiveTestBotComponent().configureServices(services, noOpConfiguration);
const declarativeTypes = services.mustMakeInstance<ComponentDeclarativeTypes[]>('declarativeTypes');
resourceExplorer = new ResourceExplorer({ declarativeTypes }).addFolder(
path.join(__dirname, 'actionTests'),
true,
false
);
});
/**
* Note: With mocha, `this.test?.title` refers to the test's name, so runTestScript

Просмотреть файл

@ -1,20 +1,32 @@
// Licensed under the MIT License.
// Copyright (c) Microsoft Corporation. All rights reserved.
import 'mocha';
import { ComponentRegistration } from 'botbuilder';
import { ResourceExplorer } from 'botbuilder-dialogs-declarative';
import { TeamsComponentRegistration } from '../lib';
import path = require('path');
import { AdaptiveTestComponentRegistration, TestUtils } from 'botbuilder-dialogs-adaptive-testing';
import { AdaptiveComponentRegistration } from 'botbuilder-dialogs-adaptive';
import { AdaptiveBotComponent } from 'botbuilder-dialogs-adaptive';
import { AdaptiveTeamsBotComponent } from '../src';
import { AdaptiveTestBotComponent, TestUtils } from 'botbuilder-dialogs-adaptive-testing';
import { ComponentDeclarativeTypes, ResourceExplorer } from 'botbuilder-dialogs-declarative';
import { ServiceCollection, noOpConfiguration } from 'botbuilder-runtime-core';
describe('Conditional Tests', function () {
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new TeamsComponentRegistration());
let resourceExplorer: ResourceExplorer;
beforeEach(function () {
const services = new ServiceCollection({
declarativeTypes: [],
});
const resourceExplorer = new ResourceExplorer().addFolder(path.join(__dirname, 'conditionalTests'), true, false);
new AdaptiveBotComponent().configureServices(services, noOpConfiguration);
new AdaptiveTeamsBotComponent().configureServices(services, noOpConfiguration);
new AdaptiveTestBotComponent().configureServices(services, noOpConfiguration);
const declarativeTypes = services.mustMakeInstance<ComponentDeclarativeTypes[]>('declarativeTypes');
resourceExplorer = new ResourceExplorer({ declarativeTypes }).addFolder(
path.join(__dirname, 'conditionalTests'),
true,
false
);
});
it('OnTeamsActivityTypes', async () => {
await TestUtils.runTestScript(resourceExplorer, 'ConditionalsTests_OnTeamsActivityTypes');

Просмотреть файл

@ -28,6 +28,7 @@
"botbuilder-dialogs": "4.1.6",
"botbuilder-dialogs-adaptive": "4.1.6",
"botbuilder-dialogs-declarative": "4.1.6",
"botbuilder-runtime-core": "4.1.6",
"murmurhash-js": "^1.0.0",
"nock": "^11.9.1",
"url-parse": "^1.5.1"

Просмотреть файл

@ -0,0 +1,58 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { BotComponent } from 'botbuilder-core';
import { ComponentDeclarativeTypes } from 'botbuilder-dialogs-declarative';
import { ServiceCollection, Configuration } from 'botbuilder-runtime-core';
import { AssertCondition } from './actions';
import {
AssertNoActivity,
AssertReply,
AssertReplyActivity,
AssertReplyOneOf,
CustomEvent,
MemoryAssertions,
SetProperties,
UserActivity,
UserConversationUpdate,
UserDelay,
UserSays,
UserTyping,
} from './testActions';
import { HttpRequestSequenceMock } from './httpRequestMocks/httpRequestSequenceMock';
import { SettingStringMock } from './settingMocks/settingStringMock';
import { TestScript } from './testScript';
import { UserTokenBasicMock } from './userTokenMocks';
export class AdaptiveTestBotComponent extends BotComponent {
configureServices(services: ServiceCollection, _configuration: Configuration): void {
services.composeFactory<ComponentDeclarativeTypes[]>('declarativeTypes', (declarativeTypes) =>
declarativeTypes.concat({
getDeclarativeTypes() {
return [
{ kind: AssertCondition.$kind, type: AssertCondition },
{ kind: AssertNoActivity.$kind, type: AssertNoActivity },
{ kind: AssertReply.$kind, type: AssertReply },
{ kind: AssertReplyActivity.$kind, type: AssertReplyActivity },
{ kind: AssertReplyOneOf.$kind, type: AssertReplyOneOf },
{ kind: CustomEvent.$kind, type: CustomEvent },
{ kind: MemoryAssertions.$kind, type: MemoryAssertions },
{ kind: HttpRequestSequenceMock.$kind, type: HttpRequestSequenceMock },
{ kind: SetProperties.$kind, type: SetProperties },
{ kind: SettingStringMock.$kind, type: SettingStringMock },
{ kind: UserActivity.$kind, type: UserActivity },
{ kind: UserConversationUpdate.$kind, type: UserConversationUpdate },
{ kind: UserDelay.$kind, type: UserDelay },
{ kind: UserSays.$kind, type: UserSays },
{ kind: UserTyping.$kind, type: UserTyping },
{ kind: TestScript.$kind, type: TestScript },
{ kind: UserTokenBasicMock.$kind, type: UserTokenBasicMock },
];
},
})
);
}
}

Просмотреть файл

@ -1,108 +0,0 @@
/**
* @module botbuilder-dialogs-adaptive-testing
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { ComponentRegistration } from 'botbuilder-core';
import {
ComponentDeclarativeTypes,
CustomDeserializer,
DeclarativeType,
ResourceExplorer,
} from 'botbuilder-dialogs-declarative';
import {
AssertNoActivity,
AssertNoActivityConfiguration,
AssertReply,
AssertReplyActivity,
AssertReplyActivityConfiguration,
AssertReplyConfiguration,
AssertReplyOneOf,
AssertReplyOneOfConfiguration,
CustomEvent,
CustomEventConfiguration,
MemoryAssertions,
MemoryAssertionsConfiguration,
SetProperties,
SetPropertiesConfiguration,
UserActivity,
UserActivityConfiguration,
UserConversationUpdate,
UserConversationUpdateConfiguration,
UserDelay,
UserDelayConfiguration,
UserSays,
UserSaysConfiguration,
UserTyping,
UserTypingConfiguration,
} from './testActions';
import { AssertCondition, AssertConditionConfiguration } from './actions';
import { TestScript, TestScriptConfiguration } from './testScript';
import { UserTokenBasicMock, UserTokenBasicMockConfiguration } from './userTokenMocks';
import {
HttpRequestSequenceMock,
HttpRequestSequenceMockConfiguration,
} from './httpRequestMocks/httpRequestSequenceMock';
import { SettingStringMock, SettingStringMockConfiguration } from './settingMocks/settingStringMock';
type Type<T> = {
$kind: string;
new (...args: unknown[]): T;
};
/**
* `ComponentRegistration` implementation for adaptive testing resources.
*/
export class AdaptiveTestComponentRegistration extends ComponentRegistration implements ComponentDeclarativeTypes {
private _declarativeTypes: DeclarativeType<unknown, unknown>[] = [];
/**
* Initializes a new instance of `AdaptiveTestComponentRegistration`.
*/
public constructor() {
super();
this._addDeclarativeType<AssertCondition, AssertConditionConfiguration>(AssertCondition);
this._addDeclarativeType<AssertNoActivity, AssertNoActivityConfiguration>(AssertNoActivity);
this._addDeclarativeType<AssertReply, AssertReplyConfiguration>(AssertReply);
this._addDeclarativeType<AssertReplyActivity, AssertReplyActivityConfiguration>(AssertReplyActivity);
this._addDeclarativeType<AssertReplyOneOf, AssertReplyOneOfConfiguration>(AssertReplyOneOf);
this._addDeclarativeType<CustomEvent, CustomEventConfiguration>(CustomEvent);
this._addDeclarativeType<MemoryAssertions, MemoryAssertionsConfiguration>(MemoryAssertions);
this._addDeclarativeType<HttpRequestSequenceMock, HttpRequestSequenceMockConfiguration>(
HttpRequestSequenceMock
);
this._addDeclarativeType<SetProperties, SetPropertiesConfiguration>(SetProperties);
this._addDeclarativeType<SettingStringMock, SettingStringMockConfiguration>(SettingStringMock);
this._addDeclarativeType<UserActivity, UserActivityConfiguration>(UserActivity);
this._addDeclarativeType<UserConversationUpdate, UserConversationUpdateConfiguration>(UserConversationUpdate);
this._addDeclarativeType<UserDelay, UserDelayConfiguration>(UserDelay);
this._addDeclarativeType<UserSays, UserSaysConfiguration>(UserSays);
this._addDeclarativeType<UserTyping, UserTypingConfiguration>(UserTyping);
this._addDeclarativeType<TestScript, TestScriptConfiguration>(TestScript);
this._addDeclarativeType<UserTokenBasicMock, UserTokenBasicMockConfiguration>(UserTokenBasicMock);
}
/**
* Gets adaptive testing `DeclarativeType` resources.
* @param resourceExplorer `ResourceExplorer` with expected path to get all resources.
* @returns Adaptive testing `DeclarativeType` resources.
*/
public getDeclarativeTypes(_resourceExplorer: ResourceExplorer): DeclarativeType[] {
return this._declarativeTypes;
}
/**
* @private
*/
private _addDeclarativeType<T, C>(type: Type<T>, loader?: CustomDeserializer<T, C>): void {
const declarativeType: DeclarativeType<T, C> = {
kind: type.$kind,
type,
loader,
};
this._declarativeTypes.push(declarativeType);
}
}

Просмотреть файл

@ -6,7 +6,7 @@
* Licensed under the MIT License.
*/
export * from './adaptiveTestComponentRegistration';
export * from './adaptiveTestBotComponent';
export * from './actions';
export * from './mocks';
export * from './testScript';

Просмотреть файл

@ -1,21 +1,15 @@
const { createHash } = require('crypto');
const path = require('path');
const nock = require('nock');
const { ActivityTypes, MessageFactory, SkillConversationIdFactoryBase, TurnContext } = require('botbuilder-core');
const { TestUtils } = require('..');
const { createHash } = require('crypto');
const { makeResourceExplorer } = require('./utils');
const {
ActivityTypes,
ComponentRegistration,
MessageFactory,
SkillConversationIdFactoryBase,
TurnContext,
} = require('botbuilder-core');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { AdaptiveTestComponentRegistration, TestUtils } = require('../lib');
const {
AdaptiveComponentRegistration,
LanguageGenerationComponentRegistration,
LanguageGenerationBotComponent,
skillConversationIdFactoryKey,
skillClientKey,
} = require('botbuilder-dialogs-adaptive');
class MockSkillConversationIdFactory extends SkillConversationIdFactoryBase {
constructor(opts = { useCreateSkillConversationId: false }) {
super();
@ -113,17 +107,10 @@ class SetSkillBotFrameworkClientMiddleware {
}
describe('ActionTests', function () {
this.timeout(10000);
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new LanguageGenerationComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/ActionTests'),
true,
false
);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('ActionTests', LanguageGenerationBotComponent);
});
it('AttachmentInput', async () => {
await TestUtils.runTestScript(resourceExplorer, 'Action_AttachmentInput');

Просмотреть файл

@ -1,20 +1,11 @@
const path = require('path');
const { ComponentRegistration } = require('botbuilder-core');
const { AdaptiveComponentRegistration } = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { AdaptiveTestComponentRegistration, TestUtils } = require('../lib');
const { TestUtils } = require('../lib');
const { makeResourceExplorer } = require('./utils');
describe('ActionScopeTests', function () {
this.timeout(5000);
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/ActionScopeTests'),
true,
false
);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('ActionScopeTests');
});
it('Break', async () => {
await TestUtils.runTestScript(resourceExplorer, 'ActionScope_Break');

Просмотреть файл

@ -1,20 +1,11 @@
const path = require('path');
const { ComponentRegistration } = require('botbuilder-core');
const { AdaptiveComponentRegistration } = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { AdaptiveTestComponentRegistration, TestUtils } = require('../lib');
const { TestUtils } = require('../lib');
const { makeResourceExplorer } = require('./utils');
describe('AdaptiveDialogTests', function () {
this.timeout(10000);
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/AdaptiveDialogTests'),
true,
false
);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('AdaptiveDialogTests');
});
it('ActivityAndIntentEvents', async () => {
await TestUtils.runTestScript(resourceExplorer, 'AdaptiveDialog_ActivityAndIntentEvents');

Просмотреть файл

@ -1,20 +1,11 @@
const path = require('path');
const { ComponentRegistration } = require('botbuilder-core');
const { AdaptiveComponentRegistration } = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { AdaptiveTestComponentRegistration, TestUtils } = require('../lib');
const { TestUtils } = require('../lib');
const { makeResourceExplorer } = require('./utils');
describe('ConditionalsTests', function () {
this.timeout(5000);
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/ConditionalsTests'),
true,
false
);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('ConditionalsTests');
});
it('OnActivityTypes', async () => {
await TestUtils.runTestScript(resourceExplorer, 'ConditionalsTests_OnActivityTypes');

Просмотреть файл

@ -1,13 +1,5 @@
const path = require('path');
const { ComponentRegistration } = require('botbuilder-core');
const {
AdaptiveComponentRegistration,
CrossTrainedRecognizerSet,
RegexRecognizer,
IntentPattern,
} = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { AdaptiveTestComponentRegistration, TestUtils } = require('../lib');
const { CrossTrainedRecognizerSet, RegexRecognizer, IntentPattern } = require('botbuilder-dialogs-adaptive');
const { TestUtils } = require('../lib');
const {
crossTrainText,
xIntentText,
@ -15,6 +7,8 @@ const {
spyOnTelemetryClientTrackEvent,
} = require('./recognizerTelemetryUtils');
const { makeResourceExplorer } = require('./utils');
const createRecognizer = () =>
new CrossTrainedRecognizerSet().configure({
recognizers: [
@ -34,16 +28,10 @@ const createRecognizer = () =>
});
describe('CrossTrainedRecognizerSetTests', function () {
this.timeout(5000);
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/CrossTrainedRecognizerSetTests'),
true,
false
);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('CrossTrainedRecognizerSetTests');
});
it('AllNone', async () => {
await TestUtils.runTestScript(resourceExplorer, 'CrossTrainedRecognizerSetTests_AllNone');

Просмотреть файл

@ -1,20 +1,11 @@
const path = require('path');
const { ComponentRegistration } = require('botbuilder-core');
const { AdaptiveComponentRegistration } = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { AdaptiveTestComponentRegistration, TestUtils } = require('../lib');
const { TestUtils } = require('../lib');
const { makeResourceExplorer } = require('./utils');
describe('ActionScopeTests', function () {
this.timeout(5000);
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/FunctionsTests'),
true,
false
);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('FunctionsTests');
});
it('HasPendingActions', async () => {
await TestUtils.runTestScript(resourceExplorer, 'hasPendingActions');

Просмотреть файл

@ -1,20 +1,11 @@
const path = require('path');
const { ComponentRegistration } = require('botbuilder-core');
const { AdaptiveComponentRegistration } = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { AdaptiveTestComponentRegistration, TestUtils } = require('../lib');
const { TestUtils } = require('../lib');
const { makeResourceExplorer } = require('./utils');
describe('ActionScopeTests', function () {
this.timeout(5000);
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/InjectLGTests'),
true,
false
);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('InjectLGTests');
});
it('InjectLGTest', async () => {
await TestUtils.runTestScript(resourceExplorer, 'inject');

Просмотреть файл

@ -1,20 +1,11 @@
const path = require('path');
const { ComponentRegistration } = require('botbuilder-core');
const { AdaptiveComponentRegistration } = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { AdaptiveTestComponentRegistration, TestUtils } = require('../lib');
const { TestUtils } = require('../lib');
const { makeResourceExplorer } = require('./utils');
describe('LGGeneratorTests', function () {
this.timeout(5000);
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/LGGeneratorTests'),
true,
false
);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('LGGeneratorTests');
});
it('MultiLandE2E', async () => {
await TestUtils.runTestScript(resourceExplorer, 'MultiLangE2E');

Просмотреть файл

@ -1,31 +1,13 @@
const path = require('path');
const { ComponentRegistration } = require('botbuilder-core');
const { LuisComponentRegistration, LuisAdaptiveRecognizer } = require('botbuilder-ai');
const { AdaptiveComponentRegistration } = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const {
AdaptiveTestComponentRegistration,
MockLuisLoader,
MockLuisRecognizer,
TestUtils,
useMockLuisSettings,
} = require('../lib');
const { LuisAdaptiveRecognizer, LuisBotComponent } = require('botbuilder-ai');
const { MockLuisLoader, MockLuisRecognizer, TestUtils, useMockLuisSettings } = require('../lib');
const { makeResourceExplorer } = require('./utils');
describe('LuisAdaptiveRecognizerTests', function () {
this.timeout(5000);
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
ComponentRegistration.add(new LuisComponentRegistration());
it('Dynamic lists', async () => {
const resourceDir = path.join(__dirname, 'resources/LuisAdaptiveRecognizerTests');
const config = useMockLuisSettings(resourceDir);
const explorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/LuisAdaptiveRecognizerTests'),
true,
false
);
const explorer = makeResourceExplorer('LuisAdaptiveRecognizerTests', LuisBotComponent);
explorer.registerType(LuisAdaptiveRecognizer.$kind, MockLuisRecognizer, new MockLuisLoader(explorer, config));
await TestUtils.runTestScript(explorer, 'DynamicLists', undefined, config);
});
@ -33,11 +15,7 @@ describe('LuisAdaptiveRecognizerTests', function () {
it('Dynamic lists expression', async () => {
const resourceDir = path.join(__dirname, 'resources/LuisAdaptiveRecognizerTests');
const config = useMockLuisSettings(resourceDir);
const explorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/LuisAdaptiveRecognizerTests'),
true,
false
);
const explorer = makeResourceExplorer('LuisAdaptiveRecognizerTests', LuisBotComponent);
explorer.registerType(LuisAdaptiveRecognizer.$kind, MockLuisRecognizer, new MockLuisLoader(explorer, config));
await TestUtils.runTestScript(explorer, 'DynamicListsExpression', undefined, config);
});
@ -45,11 +23,7 @@ describe('LuisAdaptiveRecognizerTests', function () {
it('ExternalEntities', async () => {
const resourceDir = path.join(__dirname, 'resources/LuisAdaptiveRecognizerTests');
const config = useMockLuisSettings(resourceDir);
const explorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/LuisAdaptiveRecognizerTests'),
true,
false
);
const explorer = makeResourceExplorer('LuisAdaptiveRecognizerTests', LuisBotComponent);
explorer.registerType(LuisAdaptiveRecognizer.$kind, MockLuisRecognizer, new MockLuisLoader(explorer, config));
await TestUtils.runTestScript(explorer, 'ExternalEntities', undefined, config);
});

Просмотреть файл

@ -1,16 +1,11 @@
const path = require('path');
const { ComponentRegistration } = require('botbuilder-core');
const { AdaptiveComponentRegistration } = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { AdaptiveTestComponentRegistration, TestUtils } = require('../lib');
const { TestUtils } = require('../lib');
const { makeResourceExplorer } = require('./utils');
describe('MiscTests', function () {
this.timeout(10000);
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(path.join(__dirname, 'resources/MiscTests'), true, false);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('MiscTests');
});
it('IfCondition_EndDialog', async () => {
await TestUtils.runTestScript(resourceExplorer, 'IfCondition_EndDialog');

Просмотреть файл

@ -1,18 +1,11 @@
const path = require('path');
const { ComponentRegistration } = require('botbuilder-core');
const { AdaptiveComponentRegistration } = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { AdaptiveTestComponentRegistration, TestUtils } = require('../lib');
const { TestUtils } = require('../lib');
const { makeResourceExplorer } = require('./utils');
describe('MultiLanguageGeneratorTests', function () {
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/MultiLanguageGeneratorTests'),
true,
false
);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('MultiLanguageGeneratorTests');
});
it('Switch Language Activity', async () => {
await TestUtils.runTestScript(resourceExplorer, 'SwitchLanguageActivity');

Просмотреть файл

@ -1,13 +1,7 @@
const path = require('path');
const { ComponentRegistration } = require('botbuilder-core');
const {
AdaptiveComponentRegistration,
MultiLanguageRecognizer,
RegexRecognizer,
IntentPattern,
} = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { AdaptiveTestComponentRegistration, TestUtils } = require('../lib');
const { MultiLanguageRecognizer, RegexRecognizer, IntentPattern } = require('botbuilder-dialogs-adaptive');
const { TestUtils } = require('../lib');
const { makeResourceExplorer } = require('./utils');
const {
greetingIntentTextEnUs,
recognizeIntentAndValidateTelemetry,
@ -30,16 +24,10 @@ const createRecognizer = () =>
});
describe('MultiLanguageRecognizerTests', function () {
this.timeout(5000);
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/MultiLanguageRecognizerTests'),
true,
false
);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('MultiLanguageRecognizerTests');
});
it('DefaultFallback', async () => {
await TestUtils.runTestScript(resourceExplorer, 'MultiLanguageRecognizerTest_DefaultFallback');

Просмотреть файл

@ -1,23 +1,15 @@
const path = require('path');
const nock = require('nock');
const { ComponentRegistration } = require('botbuilder-core');
const { QnAMakerComponentRegistration } = require('botbuilder-ai');
const { AdaptiveComponentRegistration } = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { AdaptiveTestComponentRegistration, TestUtils } = require('../lib');
const path = require('path');
const { QnAMakerBotComponent } = require('botbuilder-ai');
const { TestUtils } = require('../lib');
const { makeResourceExplorer } = require('./utils');
describe('QnAMakerRecognizerTests', function () {
this.timeout(5000);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('QnAMakerRecognizerTests', QnAMakerBotComponent);
});
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
ComponentRegistration.add(new QnAMakerComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/QnAMakerRecognizerTests'),
true,
false
);
const hostname = 'https://dummy-hostname.azurewebsites.net';
it('returns answer', async () => {

Просмотреть файл

@ -1,14 +1,7 @@
const path = require('path');
const { ComponentRegistration } = require('botbuilder-core');
const {
AdaptiveComponentRegistration,
EntityRecognizerSet,
RecognizerSet,
RegexRecognizer,
IntentPattern,
} = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { AdaptiveTestComponentRegistration, TestUtils } = require('../lib');
const { EntityRecognizerSet, RecognizerSet, RegexRecognizer, IntentPattern } = require('botbuilder-dialogs-adaptive');
const { TestUtils } = require('../lib');
const { makeResourceExplorer } = require('./utils');
const {
AgeEntityRecognizer,
NumberEntityRecognizer,
@ -55,16 +48,10 @@ const createRecognizer = () =>
});
describe('RecognizerSetTests', function () {
this.timeout(5000);
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/RecognizerSetTests'),
true,
false
);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('RecognizerSetTests');
});
it('Merge', async () => {
await TestUtils.runTestScript(resourceExplorer, 'RecognizerSetTests_Merge');

Просмотреть файл

@ -1,20 +1,11 @@
const path = require('path');
const { ComponentRegistration } = require('botbuilder-core');
const { AdaptiveComponentRegistration } = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { AdaptiveTestComponentRegistration, TestUtils } = require('../lib');
const { TestUtils } = require('../lib');
const { makeResourceExplorer } = require('./utils');
describe('RegexRecognizerTests', function () {
this.timeout(5000);
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/RegexRecognizerTests'),
true,
false
);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('RegexRecognizerTests');
});
it('Entities', async () => {
await TestUtils.runTestScript(resourceExplorer, 'RegexRecognizerTests_Entities');

Просмотреть файл

@ -1,20 +1,11 @@
const path = require('path');
const { ComponentRegistration } = require('botbuilder-core');
const { AdaptiveComponentRegistration } = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { AdaptiveTestComponentRegistration, TestUtils } = require('../lib');
const { TestUtils } = require('..');
const { makeResourceExplorer } = require('./utils');
describe('SelectorTests', function () {
this.timeout(10000);
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/SelectorTests'),
true,
false
);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('SelectorTests');
});
it('ConditionalSelector', async () => {
await TestUtils.runTestScript(resourceExplorer, 'SelectorTests_ConditionalSelector');

Просмотреть файл

@ -1,20 +1,12 @@
const path = require('path');
const { ComponentRegistration } = require('botbuilder-core');
const { AdaptiveComponentRegistration } = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { AdaptiveTestComponentRegistration, TestUtils } = require('../lib');
const { TestUtils } = require('..');
const { makeResourceExplorer } = require('./utils');
describe('SettingsStateTests', function () {
this.timeout(10000);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('SettingsStateTests');
});
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/SettingsStateTests'),
true,
false
);
process.env['MicrosoftAppId'] = 'MICROSOFT_APP_ID';
process.env['MicrosoftAppPassword'] = 'MICROSOFT_APP_PASSWORD';
process.env['ApplicationInsightsInstrumentationKey'] = '00000000-0000-0000-0000-000000000000';

Просмотреть файл

@ -1,28 +1,14 @@
const assert = require('assert');
const path = require('path');
const { ComponentRegistration } = require('botbuilder-core');
const { AdaptiveComponentRegistration } = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const {
AdaptiveTestComponentRegistration,
MockLuisLoader,
MockLuisRecognizer,
TestUtils,
useMockLuisSettings,
} = require('../lib');
const { LuisAdaptiveRecognizer } = require('botbuilder-ai');
const { LuisAdaptiveRecognizer, QnAMakerBotComponent } = require('botbuilder-ai');
const { MockLuisLoader, MockLuisRecognizer, TestUtils, useMockLuisSettings } = require('../lib');
const { makeResourceExplorer } = require('./utils');
describe('TestScriptTests', function () {
this.timeout(5000);
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/TestScriptTests'),
true,
false
);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('TestScriptTests', QnAMakerBotComponent);
});
it('AssertReply_Assertions', async () => {
await TestUtils.runTestScript(resourceExplorer, 'TestScriptTests_AssertReply_Assertions');
@ -83,13 +69,12 @@ describe('TestScriptTests', function () {
it('HttpRequestLuisMock', async () => {
const resourceDir = path.join(__dirname, 'resources/TestScriptTests/LuisMock');
const config = useMockLuisSettings(resourceDir);
const explorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/TestScriptTests'),
true,
false
resourceExplorer.registerType(
LuisAdaptiveRecognizer.$kind,
MockLuisRecognizer,
new MockLuisLoader(resourceExplorer, config)
);
explorer.registerType(LuisAdaptiveRecognizer.$kind, MockLuisRecognizer, new MockLuisLoader(explorer, config));
await TestUtils.runTestScript(explorer, 'TestScriptTests_HttpRequestLuisMock', undefined, config);
await TestUtils.runTestScript(resourceExplorer, 'TestScriptTests_HttpRequestLuisMock', undefined, config);
});
it('HttpRequestMock', async () => {

Просмотреть файл

@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
const path = require('path');
const { AdaptiveBotComponent } = require('botbuilder-dialogs-adaptive');
const { AdaptiveTestBotComponent } = require('..');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { ServiceCollection, noOpConfiguration } = require('botbuilder-runtime-core');
function makeResourceExplorer(resourceFolder, ...botComponents) {
const services = new ServiceCollection({
declarativeTypes: [],
});
new AdaptiveBotComponent().configureServices(services, noOpConfiguration);
new AdaptiveTestBotComponent().configureServices(services, noOpConfiguration);
botComponents.forEach((BotComponent) => {
new BotComponent().configureServices(services, noOpConfiguration);
});
const declarativeTypes = services.mustMakeInstance('declarativeTypes');
return new ResourceExplorer({
declarativeTypes,
}).addFolder(path.join(__dirname, 'resources', resourceFolder), true, false);
}
module.exports = { makeResourceExplorer };

Просмотреть файл

@ -1,20 +1,11 @@
const path = require('path');
const { ComponentRegistration } = require('botbuilder-core');
const { AdaptiveComponentRegistration } = require('botbuilder-dialogs-adaptive');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { AdaptiveTestComponentRegistration, TestUtils } = require('../lib');
const { TestUtils } = require('..');
const { makeResourceExplorer } = require('./utils');
describe('ValueRecognizerTests', function () {
this.timeout(5000);
ComponentRegistration.add(new AdaptiveComponentRegistration());
ComponentRegistration.add(new AdaptiveTestComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
path.join(__dirname, 'resources/ValueRecognizerTests'),
true,
false
);
let resourceExplorer;
before(function () {
resourceExplorer = makeResourceExplorer('ValueRecognizerTests');
});
it('WithIntent', async () => {
await TestUtils.runTestScript(resourceExplorer, 'ValueRecognizerTests_WithIntent');

Просмотреть файл

@ -34,6 +34,7 @@
"botbuilder-dialogs": "4.1.6",
"botbuilder-dialogs-declarative": "4.1.6",
"botbuilder-lg": "4.1.6",
"botbuilder-runtime-core": "4.1.6",
"botframework-connector": "4.1.6",
"botframework-schema": "4.1.6",
"lodash": "^4.17.21",

Просмотреть файл

@ -0,0 +1,268 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { AdaptiveDialog } from './adaptiveDialog';
import { BotComponent } from 'botbuilder';
import { ComponentDeclarativeTypes } from 'botbuilder-dialogs-declarative';
import { ConditionalSelector, FirstSelector, MostSpecificSelector, RandomSelector, TrueSelector } from './selectors';
import { Configuration, ServiceCollection } from 'botbuilder-runtime-core';
import { DynamicBeginDialogDeserializer } from './dynamicBeginDialogDeserializer';
import { Expression } from 'adaptive-expressions';
import { HasPendingActionsFunction, IsDialogActiveFunction } from './functions';
import { ResourceMultiLanguageGenerator, TemplateEngineLanguageGenerator } from './generators';
import {
BeginDialog,
BeginSkill,
BreakLoop,
CancelAllDialogs,
CancelDialog,
ContinueConversation,
ContinueConversationLater,
ContinueLoop,
DeleteActivity,
DeleteProperties,
DeleteProperty,
DynamicBeginDialog,
EditActions,
EditArray,
EmitEvent,
EndDialog,
EndTurn,
ForEach,
ForEachPage,
GetActivityMembers,
GetConversationMembers,
GetConversationReference,
GotoAction,
HttpRequest,
IfCondition,
LogAction,
RepeatDialog,
ReplaceDialog,
SendActivity,
SendHandoffActivity,
SetProperties,
SetProperty,
SignOutUser,
SwitchCondition,
TelemetryTrackEventAction,
TraceActivity,
ThrowException,
UpdateActivity,
} from './actions';
import {
OnActivity,
OnAssignEntity,
OnBeginDialog,
OnCancelDialog,
OnChooseEntity,
OnChooseIntent,
OnChooseProperty,
OnCondition,
OnContinueConversation,
OnConversationUpdateActivity,
OnDialogEvent,
OnEndOfActions,
OnEndOfConversationActivity,
OnError,
OnEventActivity,
OnHandoffActivity,
OnInstallationUpdateActivity,
OnIntent,
OnInvokeActivity,
OnMessageActivity,
OnMessageDeleteActivity,
OnMessageReactionActivity,
OnMessageUpdateActivity,
OnQnAMatch,
OnRepromptDialog,
OnTypingActivity,
OnUnknownIntent,
} from './conditions';
import {
Ask,
AttachmentInput,
ChoiceInput,
ConfirmInput,
DateTimeInput,
NumberInput,
OAuthInput,
TextInput,
} from './input';
import {
AgeEntityRecognizer,
ChannelMentionEntityRecognizer,
ConfirmationEntityRecognizer,
CrossTrainedRecognizerSet,
CurrencyEntityRecognizer,
DateTimeEntityRecognizer,
DimensionEntityRecognizer,
EmailEntityRecognizer,
EntityRecognizerSet,
GuidEntityRecognizer,
HashtagEntityRecognizer,
IpEntityRecognizer,
MentionEntityRecognizer,
MultiLanguageRecognizer,
NumberEntityRecognizer,
OrdinalEntityRecognizer,
PercentageEntityRecognizer,
PhoneNumberEntityRecognizer,
RecognizerSet,
RegexEntityRecognizer,
RegexRecognizer,
TemperatureEntityRecognizer,
UrlEntityRecognizer,
} from './recognizers';
export class AdaptiveBotComponent extends BotComponent {
configureServices(services: ServiceCollection, _configuration: Configuration): void {
Expression.functions.add(IsDialogActiveFunction.functionName, new IsDialogActiveFunction());
Expression.functions.add(IsDialogActiveFunction.functionAlias, new IsDialogActiveFunction());
Expression.functions.add(HasPendingActionsFunction.functionName, new HasPendingActionsFunction());
services.composeFactory<ComponentDeclarativeTypes[]>('declarativeTypes', (declarativeTypes) =>
declarativeTypes.concat(
{
getDeclarativeTypes() {
return [
// Adaptive Dialog
{ kind: AdaptiveDialog.$kind, type: AdaptiveDialog },
// Actions
{ kind: BeginDialog.$kind, type: BeginDialog },
{ kind: BeginSkill.$kind, type: BeginSkill },
{ kind: BreakLoop.$kind, type: BreakLoop },
{ kind: CancelAllDialogs.$kind, type: CancelAllDialogs },
{ kind: CancelDialog.$kind, type: CancelDialog },
{ kind: ContinueConversation.$kind, type: ContinueConversation },
{ kind: ContinueConversationLater.$kind, type: ContinueConversation },
{ kind: ContinueLoop.$kind, type: ContinueLoop },
{ kind: DeleteActivity.$kind, type: DeleteActivity },
{ kind: DeleteProperties.$kind, type: DeleteProperties },
{ kind: DeleteProperty.$kind, type: DeleteProperty },
{ kind: EditActions.$kind, type: EditActions },
{ kind: EditArray.$kind, type: EditArray },
{ kind: EmitEvent.$kind, type: EmitEvent },
{ kind: EndDialog.$kind, type: EndDialog },
{ kind: EndTurn.$kind, type: EndTurn },
{ kind: ForEach.$kind, type: ForEach },
{ kind: ForEachPage.$kind, type: ForEachPage },
{ kind: GetActivityMembers.$kind, type: GetActivityMembers },
{ kind: GetConversationMembers.$kind, type: GetConversationMembers },
{ kind: GetConversationReference.$kind, type: GetConversationReference },
{ kind: GotoAction.$kind, type: GotoAction },
{ kind: HttpRequest.$kind, type: HttpRequest },
{ kind: IfCondition.$kind, type: IfCondition },
{ kind: LogAction.$kind, type: LogAction },
{ kind: RepeatDialog.$kind, type: RepeatDialog },
{ kind: ReplaceDialog.$kind, type: ReplaceDialog },
{ kind: SendActivity.$kind, type: SendActivity },
{ kind: SendHandoffActivity.$kind, type: SendHandoffActivity },
{ kind: SetProperties.$kind, type: SetProperties },
{ kind: SetProperty.$kind, type: SetProperty },
{ kind: SignOutUser.$kind, type: SignOutUser },
{ kind: SwitchCondition.$kind, type: SwitchCondition },
{ kind: TelemetryTrackEventAction.$kind, type: TelemetryTrackEventAction },
{ kind: ThrowException.$kind, type: ThrowException },
{ kind: TraceActivity.$kind, type: TraceActivity },
{ kind: UpdateActivity.$kind, type: UpdateActivity },
// Trigger conditions
{ kind: OnActivity.$kind, type: OnActivity },
{ kind: OnAssignEntity.$kind, type: OnAssignEntity },
{ kind: OnBeginDialog.$kind, type: OnBeginDialog },
{ kind: OnCancelDialog.$kind, type: OnCancelDialog },
{ kind: OnChooseEntity.$kind, type: OnChooseEntity },
{ kind: OnChooseIntent.$kind, type: OnChooseIntent },
{ kind: OnChooseProperty.$kind, type: OnChooseProperty },
{ kind: OnCondition.$kind, type: OnCondition },
{ kind: OnContinueConversation.$kind, type: OnContinueConversation },
{ kind: OnConversationUpdateActivity.$kind, type: OnConversationUpdateActivity },
{ kind: OnDialogEvent.$kind, type: OnDialogEvent },
{ kind: OnEndOfActions.$kind, type: OnEndOfActions },
{ kind: OnEndOfConversationActivity.$kind, type: OnEndOfConversationActivity },
{ kind: OnError.$kind, type: OnError },
{ kind: OnEventActivity.$kind, type: OnEventActivity },
{ kind: OnHandoffActivity.$kind, type: OnHandoffActivity },
{ kind: OnInstallationUpdateActivity.$kind, type: OnInstallationUpdateActivity },
{ kind: OnIntent.$kind, type: OnIntent },
{ kind: OnInvokeActivity.$kind, type: OnInvokeActivity },
{ kind: OnMessageActivity.$kind, type: OnMessageActivity },
{ kind: OnMessageDeleteActivity.$kind, type: OnMessageDeleteActivity },
{ kind: OnMessageReactionActivity.$kind, type: OnMessageReactionActivity },
{ kind: OnMessageUpdateActivity.$kind, type: OnMessageUpdateActivity },
{ kind: OnQnAMatch.$kind, type: OnQnAMatch },
{ kind: OnRepromptDialog.$kind, type: OnRepromptDialog },
{ kind: OnTypingActivity.$kind, type: OnTypingActivity },
{ kind: OnUnknownIntent.$kind, type: OnUnknownIntent },
// Inputs
{ kind: Ask.$kind, type: Ask },
{ kind: AttachmentInput.$kind, type: AttachmentInput },
{ kind: ChoiceInput.$kind, type: ChoiceInput },
{ kind: ConfirmInput.$kind, type: ConfirmInput },
{ kind: DateTimeInput.$kind, type: DateTimeInput },
{ kind: NumberInput.$kind, type: NumberInput },
{ kind: OAuthInput.$kind, type: OAuthInput },
{ kind: TextInput.$kind, type: TextInput },
// Recognizers
{ kind: CrossTrainedRecognizerSet.$kind, type: CrossTrainedRecognizerSet },
{ kind: MultiLanguageRecognizer.$kind, type: MultiLanguageRecognizer },
{ kind: RecognizerSet.$kind, type: RecognizerSet },
{ kind: RegexRecognizer.$kind, type: RegexRecognizer },
{ kind: AgeEntityRecognizer.$kind, type: AgeEntityRecognizer },
{ kind: ChannelMentionEntityRecognizer.$kind, type: ChannelMentionEntityRecognizer },
{ kind: ConfirmationEntityRecognizer.$kind, type: ConfirmationEntityRecognizer },
{ kind: CurrencyEntityRecognizer.$kind, type: CurrencyEntityRecognizer },
{ kind: DateTimeEntityRecognizer.$kind, type: DateTimeEntityRecognizer },
{ kind: DimensionEntityRecognizer.$kind, type: DimensionEntityRecognizer },
{ kind: EmailEntityRecognizer.$kind, type: EmailEntityRecognizer },
{ kind: EntityRecognizerSet.$kind, type: EntityRecognizerSet },
{ kind: GuidEntityRecognizer.$kind, type: GuidEntityRecognizer },
{ kind: HashtagEntityRecognizer.$kind, type: HashtagEntityRecognizer },
{ kind: IpEntityRecognizer.$kind, type: IpEntityRecognizer },
{ kind: MentionEntityRecognizer.$kind, type: MentionEntityRecognizer },
{ kind: NumberEntityRecognizer.$kind, type: NumberEntityRecognizer },
{ kind: OrdinalEntityRecognizer.$kind, type: OrdinalEntityRecognizer },
{ kind: PercentageEntityRecognizer.$kind, type: PercentageEntityRecognizer },
{ kind: PhoneNumberEntityRecognizer.$kind, type: PhoneNumberEntityRecognizer },
{ kind: RegexEntityRecognizer.$kind, type: RegexEntityRecognizer },
{ kind: TemperatureEntityRecognizer.$kind, type: TemperatureEntityRecognizer },
{ kind: UrlEntityRecognizer.$kind, type: UrlEntityRecognizer },
// Generators
{ kind: TemplateEngineLanguageGenerator.$kind, type: TemplateEngineLanguageGenerator },
{ kind: ResourceMultiLanguageGenerator.$kind, type: ResourceMultiLanguageGenerator },
// Selectors
{ kind: ConditionalSelector.$kind, type: ConditionalSelector },
{ kind: FirstSelector.$kind, type: FirstSelector },
{ kind: RandomSelector.$kind, type: RandomSelector },
{ kind: TrueSelector.$kind, type: TrueSelector },
{ kind: MostSpecificSelector.$kind, type: MostSpecificSelector },
];
},
},
{
getDeclarativeTypes(resourceExplorer) {
return resourceExplorer
.getResources('.schema')
.map((schema) => schema.id.replace(/.schema$/, ''))
.filter((resourceId) => resourceId.endsWith('.dialog'))
.map((resourceId) => ({
kind: resourceId,
type: DynamicBeginDialog,
loader: new DynamicBeginDialogDeserializer(resourceExplorer, resourceId),
}));
},
}
)
);
}
}

Просмотреть файл

@ -1,380 +0,0 @@
/**
* @module botbuilder-dialogs-adaptive
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { Expression } from 'adaptive-expressions';
import { ComponentRegistration } from 'botbuilder';
import {
ResourceExplorer,
ComponentDeclarativeTypes,
DeclarativeType,
CustomDeserializer,
} from 'botbuilder-dialogs-declarative';
import { AdaptiveDialog, AdaptiveDialogConfiguration } from './adaptiveDialog';
import {
BeginDialog,
BeginDialogConfiguration,
BeginSkill,
BeginSkillConfiguration,
BreakLoop,
BreakLoopConfiguration,
CancelAllDialogs,
CancelDialog,
CancelAllDialogsBaseConfiguration,
ContinueConversation,
ContinueConversationConfiguration,
ContinueConversationLater,
ContinueConversationLaterConfiguration,
ContinueLoop,
ContinueLoopConfiguration,
DeleteActivity,
DeleteActivityConfiguration,
DeleteProperties,
DeletePropertiesConfiguration,
DeleteProperty,
DeletePropertyConfiguration,
DynamicBeginDialog,
EditActions,
EditActionsConfiguration,
EditArray,
EditArrayConfiguration,
EmitEvent,
EmitEventConfiguration,
EndDialog,
EndDialogConfiguration,
EndTurn,
EndTurnConfiguration,
ForEach,
ForEachConfiguration,
ForEachPage,
ForEachPageConfiguration,
GetActivityMembers,
GetActivityMembersConfiguration,
GetConversationMembers,
GetConversationMembersConfiguration,
GetConversationReference,
GetConversationReferenceConfiguration,
GotoAction,
GotoActionConfiguration,
HttpRequest,
HttpRequestConfiguration,
IfCondition,
IfConditionConfiguration,
LogAction,
LogActionConfiguration,
RepeatDialog,
RepeatDialogConfiguration,
ReplaceDialog,
ReplaceDialogConfiguration,
SendActivity,
SendActivityConfiguration,
SendHandoffActivity,
SendHandoffActivityConfiguration,
SetProperties,
SetPropertiesConfiguration,
SetProperty,
SetPropertyConfiguration,
SignOutUser,
SignOutUserConfiguration,
SwitchCondition,
SwitchConditionConfiguration,
TelemetryTrackEventAction,
TelemetryTrackEventActionConfiguration,
TraceActivity,
TraceActivityConfiguration,
ThrowException,
ThrowExceptionConfiguration,
UpdateActivity,
UpdateActivityConfiguration,
} from './actions';
import {
OnActivity,
OnActivityConfiguration,
OnAssignEntity,
OnAssignEntityConfiguration,
OnBeginDialog,
OnCancelDialog,
OnChooseEntity,
OnChooseEntityConfiguration,
OnChooseIntent,
OnChooseIntentConfiguration,
OnChooseProperty,
OnCondition,
OnConditionConfiguration,
OnContinueConversation,
OnConversationUpdateActivity,
OnDialogEvent,
OnDialogEventConfiguration,
OnEndOfActions,
OnEndOfConversationActivity,
OnError,
OnEventActivity,
OnHandoffActivity,
OnInstallationUpdateActivity,
OnIntent,
OnIntentConfiguration,
OnInvokeActivity,
OnMessageActivity,
OnMessageDeleteActivity,
OnMessageReactionActivity,
OnMessageUpdateActivity,
OnQnAMatch,
OnRepromptDialog,
OnTypingActivity,
OnUnknownIntent,
} from './conditions';
import {
Ask,
AskConfiguration,
AttachmentInput,
AttachmentInputConfiguration,
ChoiceInput,
ChoiceInputConfiguration,
ConfirmInput,
ConfirmInputConfiguration,
DateTimeInput,
DateTimeInputConfiguration,
NumberInput,
NumberInputConfiguration,
OAuthInput,
OAuthInputConfiguration,
TextInput,
TextInputConfiguration,
} from './input';
import {
AgeEntityRecognizer,
ChannelMentionEntityRecognizer,
ConfirmationEntityRecognizer,
CrossTrainedRecognizerSet,
CrossTrainedRecognizerSetConfiguration,
CurrencyEntityRecognizer,
DateTimeEntityRecognizer,
DimensionEntityRecognizer,
EmailEntityRecognizer,
EntityRecognizerSet,
GuidEntityRecognizer,
HashtagEntityRecognizer,
IpEntityRecognizer,
MentionEntityRecognizer,
MultiLanguageRecognizer,
MultiLanguageRecognizerConfiguration,
NumberEntityRecognizer,
OrdinalEntityRecognizer,
PercentageEntityRecognizer,
PhoneNumberEntityRecognizer,
RecognizerSet,
RecognizerSetConfiguration,
RegexEntityRecognizer,
RegexEntityRecognizerConfiguration,
RegexRecognizer,
RegexRecognizerConfiguration,
TemperatureEntityRecognizer,
UrlEntityRecognizer,
} from './recognizers';
import {
ResourceMultiLanguageGenerator,
ResourceMultiLanguageGeneratorConfiguration,
TemplateEngineLanguageGenerator,
TemplateEngineLanguageGeneratorConfiguration,
} from './generators';
import {
ConditionalSelector,
ConditionalSelectorConfiguration,
FirstSelector,
MostSpecificSelector,
MostSpecificSelectorConfiguration,
RandomSelector,
TrueSelector,
} from './selectors';
import { DynamicBeginDialogDeserializer } from './dynamicBeginDialogDeserializer';
import { HasPendingActionsFunction, IsDialogActiveFunction } from './functions';
type Type<T> = {
$kind: string;
new(...args: unknown[]): T;
};
/**
* `ComponentRegistration` implementation for adaptive components.
*/
export class AdaptiveComponentRegistration extends ComponentRegistration implements ComponentDeclarativeTypes {
private _declarativeTypes: DeclarativeType<unknown, unknown>[] = [];
/**
* Initializes a new instance of `AdaptiveComponentRegistration`.
*/
public constructor() {
super();
// AdaptiveDialog
this._addDeclarativeType<AdaptiveDialog, AdaptiveDialogConfiguration>(AdaptiveDialog);
// Actions
this._addDeclarativeType<BeginDialog, BeginDialogConfiguration>(BeginDialog);
this._addDeclarativeType<BeginSkill, BeginSkillConfiguration>(BeginSkill);
this._addDeclarativeType<BreakLoop, BreakLoopConfiguration>(BreakLoop);
this._addDeclarativeType<CancelAllDialogs, CancelAllDialogsBaseConfiguration>(CancelAllDialogs);
this._addDeclarativeType<CancelDialog, CancelAllDialogsBaseConfiguration>(CancelDialog);
this._addDeclarativeType<ContinueConversation, ContinueConversationConfiguration>(ContinueConversation);
this._addDeclarativeType<ContinueConversationLater, ContinueConversationLaterConfiguration>(
ContinueConversationLater
);
this._addDeclarativeType<ContinueLoop, ContinueLoopConfiguration>(ContinueLoop);
this._addDeclarativeType<DeleteActivity, DeleteActivityConfiguration>(DeleteActivity);
this._addDeclarativeType<DeleteProperties, DeletePropertiesConfiguration>(DeleteProperties);
this._addDeclarativeType<DeleteProperty, DeletePropertyConfiguration>(DeleteProperty);
this._addDeclarativeType<EditActions, EditActionsConfiguration>(EditActions);
this._addDeclarativeType<EditArray, EditArrayConfiguration>(EditArray);
this._addDeclarativeType<EmitEvent, EmitEventConfiguration>(EmitEvent);
this._addDeclarativeType<EndDialog, EndDialogConfiguration>(EndDialog);
this._addDeclarativeType<EndTurn, EndTurnConfiguration>(EndTurn);
this._addDeclarativeType<ForEach, ForEachConfiguration>(ForEach);
this._addDeclarativeType<ForEachPage, ForEachPageConfiguration>(ForEachPage);
this._addDeclarativeType<GetActivityMembers, GetActivityMembersConfiguration>(GetActivityMembers);
this._addDeclarativeType<GetConversationMembers, GetConversationMembersConfiguration>(GetConversationMembers);
this._addDeclarativeType<GetConversationReference, GetConversationReferenceConfiguration>(
GetConversationReference
);
this._addDeclarativeType<GotoAction, GotoActionConfiguration>(GotoAction);
this._addDeclarativeType<HttpRequest, HttpRequestConfiguration>(HttpRequest);
this._addDeclarativeType<IfCondition, IfConditionConfiguration>(IfCondition);
this._addDeclarativeType<LogAction, LogActionConfiguration>(LogAction);
this._addDeclarativeType<RepeatDialog, RepeatDialogConfiguration>(RepeatDialog);
this._addDeclarativeType<ReplaceDialog, ReplaceDialogConfiguration>(ReplaceDialog);
this._addDeclarativeType<SendActivity, SendActivityConfiguration>(SendActivity);
this._addDeclarativeType<SendHandoffActivity, SendHandoffActivityConfiguration>(SendHandoffActivity);
this._addDeclarativeType<SetProperties, SetPropertiesConfiguration>(SetProperties);
this._addDeclarativeType<SetProperty, SetPropertyConfiguration>(SetProperty);
this._addDeclarativeType<SignOutUser, SignOutUserConfiguration>(SignOutUser);
this._addDeclarativeType<SwitchCondition, SwitchConditionConfiguration>(SwitchCondition);
this._addDeclarativeType<TelemetryTrackEventAction, TelemetryTrackEventActionConfiguration>(
TelemetryTrackEventAction
);
this._addDeclarativeType<ThrowException, ThrowExceptionConfiguration>(ThrowException);
this._addDeclarativeType<TraceActivity, TraceActivityConfiguration>(TraceActivity);
this._addDeclarativeType<UpdateActivity, UpdateActivityConfiguration>(UpdateActivity);
// Trigger conditions
this._addDeclarativeType<OnActivity, OnActivityConfiguration>(OnActivity);
this._addDeclarativeType<OnAssignEntity, OnAssignEntityConfiguration>(OnAssignEntity);
this._addDeclarativeType<OnBeginDialog, OnDialogEventConfiguration>(OnBeginDialog);
this._addDeclarativeType<OnCancelDialog, OnDialogEventConfiguration>(OnCancelDialog);
this._addDeclarativeType<OnChooseEntity, OnChooseEntityConfiguration>(OnChooseEntity);
this._addDeclarativeType<OnChooseIntent, OnChooseIntentConfiguration>(OnChooseIntent);
this._addDeclarativeType<OnChooseProperty, OnDialogEventConfiguration>(OnChooseProperty);
this._addDeclarativeType<OnCondition, OnConditionConfiguration>(OnCondition);
this._addDeclarativeType<OnContinueConversation, OnActivityConfiguration>(OnContinueConversation);
this._addDeclarativeType<OnConversationUpdateActivity, OnActivityConfiguration>(OnConversationUpdateActivity);
this._addDeclarativeType<OnDialogEvent, OnDialogEventConfiguration>(OnDialogEvent);
this._addDeclarativeType<OnEndOfActions, OnDialogEventConfiguration>(OnEndOfActions);
this._addDeclarativeType<OnEndOfConversationActivity, OnActivityConfiguration>(OnEndOfConversationActivity);
this._addDeclarativeType<OnError, OnDialogEventConfiguration>(OnError);
this._addDeclarativeType<OnEventActivity, OnActivityConfiguration>(OnEventActivity);
this._addDeclarativeType<OnHandoffActivity, OnActivityConfiguration>(OnHandoffActivity);
this._addDeclarativeType<OnInstallationUpdateActivity, OnActivityConfiguration>(OnInstallationUpdateActivity);
this._addDeclarativeType<OnIntent, OnIntentConfiguration>(OnIntent);
this._addDeclarativeType<OnInvokeActivity, OnActivityConfiguration>(OnInvokeActivity);
this._addDeclarativeType<OnMessageActivity, OnActivityConfiguration>(OnMessageActivity);
this._addDeclarativeType<OnMessageDeleteActivity, OnActivityConfiguration>(OnMessageDeleteActivity);
this._addDeclarativeType<OnMessageReactionActivity, OnActivityConfiguration>(OnMessageReactionActivity);
this._addDeclarativeType<OnMessageUpdateActivity, OnActivityConfiguration>(OnMessageUpdateActivity);
this._addDeclarativeType<OnQnAMatch, OnIntentConfiguration>(OnQnAMatch);
this._addDeclarativeType<OnRepromptDialog, OnDialogEventConfiguration>(OnRepromptDialog);
this._addDeclarativeType<OnTypingActivity, OnActivityConfiguration>(OnTypingActivity);
this._addDeclarativeType<OnUnknownIntent, OnDialogEventConfiguration>(OnUnknownIntent);
// Inputs
this._addDeclarativeType<Ask, AskConfiguration>(Ask);
this._addDeclarativeType<AttachmentInput, AttachmentInputConfiguration>(AttachmentInput);
this._addDeclarativeType<ChoiceInput, ChoiceInputConfiguration>(ChoiceInput);
this._addDeclarativeType<ConfirmInput, ConfirmInputConfiguration>(ConfirmInput);
this._addDeclarativeType<DateTimeInput, DateTimeInputConfiguration>(DateTimeInput);
this._addDeclarativeType<NumberInput, NumberInputConfiguration>(NumberInput);
this._addDeclarativeType<OAuthInput, OAuthInputConfiguration>(OAuthInput);
this._addDeclarativeType<TextInput, TextInputConfiguration>(TextInput);
// Recognizers
this._addDeclarativeType<CrossTrainedRecognizerSet, CrossTrainedRecognizerSetConfiguration>(
CrossTrainedRecognizerSet
);
this._addDeclarativeType<MultiLanguageRecognizer, MultiLanguageRecognizerConfiguration>(
MultiLanguageRecognizer
);
this._addDeclarativeType<RecognizerSet, RecognizerSetConfiguration>(RecognizerSet);
this._addDeclarativeType<RegexRecognizer, RegexRecognizerConfiguration>(RegexRecognizer);
this._addDeclarativeType<AgeEntityRecognizer, unknown>(AgeEntityRecognizer);
this._addDeclarativeType<ChannelMentionEntityRecognizer, unknown>(ChannelMentionEntityRecognizer);
this._addDeclarativeType<ConfirmationEntityRecognizer, unknown>(ConfirmationEntityRecognizer);
this._addDeclarativeType<CurrencyEntityRecognizer, unknown>(CurrencyEntityRecognizer);
this._addDeclarativeType<DateTimeEntityRecognizer, unknown>(DateTimeEntityRecognizer);
this._addDeclarativeType<DimensionEntityRecognizer, unknown>(DimensionEntityRecognizer);
this._addDeclarativeType<EmailEntityRecognizer, unknown>(EmailEntityRecognizer);
this._addDeclarativeType<EntityRecognizerSet, unknown>(EntityRecognizerSet);
this._addDeclarativeType<GuidEntityRecognizer, unknown>(GuidEntityRecognizer);
this._addDeclarativeType<HashtagEntityRecognizer, unknown>(HashtagEntityRecognizer);
this._addDeclarativeType<IpEntityRecognizer, unknown>(IpEntityRecognizer);
this._addDeclarativeType<MentionEntityRecognizer, unknown>(MentionEntityRecognizer);
this._addDeclarativeType<NumberEntityRecognizer, unknown>(NumberEntityRecognizer);
this._addDeclarativeType<OrdinalEntityRecognizer, unknown>(OrdinalEntityRecognizer);
this._addDeclarativeType<PercentageEntityRecognizer, unknown>(PercentageEntityRecognizer);
this._addDeclarativeType<PhoneNumberEntityRecognizer, unknown>(PhoneNumberEntityRecognizer);
this._addDeclarativeType<RegexEntityRecognizer, RegexEntityRecognizerConfiguration>(RegexEntityRecognizer);
this._addDeclarativeType<TemperatureEntityRecognizer, unknown>(TemperatureEntityRecognizer);
this._addDeclarativeType<UrlEntityRecognizer, unknown>(UrlEntityRecognizer);
// Generators
this._addDeclarativeType<TemplateEngineLanguageGenerator, TemplateEngineLanguageGeneratorConfiguration>(
TemplateEngineLanguageGenerator
);
this._addDeclarativeType<ResourceMultiLanguageGenerator, ResourceMultiLanguageGeneratorConfiguration>(
ResourceMultiLanguageGenerator
);
// Selectors
this._addDeclarativeType<ConditionalSelector, ConditionalSelectorConfiguration>(ConditionalSelector);
this._addDeclarativeType<FirstSelector, unknown>(FirstSelector);
this._addDeclarativeType<RandomSelector, unknown>(RandomSelector);
this._addDeclarativeType<TrueSelector, unknown>(TrueSelector);
this._addDeclarativeType<MostSpecificSelector, MostSpecificSelectorConfiguration>(MostSpecificSelector);
Expression.functions.add(IsDialogActiveFunction.functionName, new IsDialogActiveFunction());
Expression.functions.add(IsDialogActiveFunction.functionAlias, new IsDialogActiveFunction());
Expression.functions.add(HasPendingActionsFunction.functionName, new HasPendingActionsFunction());
}
/**
* Gets adaptive `DeclarativeType` resources.
* @param resourceExplorer `ResourceExplorer` with expected path to get all resources.
* @returns Adaptive `DeclarativeType` resources.
*/
public getDeclarativeTypes(resourceExplorer: ResourceExplorer): DeclarativeType[] {
const declarativeTypes: DeclarativeType[] = [...this._declarativeTypes];
resourceExplorer.getResources('.schema').forEach((schema) => {
const resourceId = schema.id.replace(/.schema$/, '');
if (resourceId.endsWith('.dialog')) {
declarativeTypes.push({
kind: resourceId,
type: DynamicBeginDialog,
loader: new DynamicBeginDialogDeserializer(resourceExplorer, resourceId),
});
}
});
return declarativeTypes;
}
/**
* @private
*/
private _addDeclarativeType<T, C>(type: Type<T>, loader?: CustomDeserializer<T, C>): void {
const declarativeType: DeclarativeType<T, C> = {
kind: type.$kind,
type,
loader,
};
this._declarativeTypes.push(declarativeType);
}
}

Просмотреть файл

@ -6,18 +6,17 @@
* Licensed under the MIT License.
*/
export * from './actions';
export * from './actionContext';
export * from './actions';
export * from './adaptiveBotComponent';
export * from './adaptiveDialog';
export * from './adaptiveComponentRegistration';
export * from './adaptiveEvents';
export * from './conditions';
export { DialogExpressionConverter } from './converters';
export * from './expressions';
export * from './functions';
export * from './generators';
export * from './input';
export * from './languageGenerationComponentRegistration';
export * from './languageGenerationBotComponent';
export * from './languageGenerator';
export * from './languageGeneratorExtensions';
export * from './languagePolicy';
@ -31,3 +30,5 @@ export * from './skillExtensions';
export * from './telemetryExtensions';
export * from './templates';
export * from './triggerSelector';
export { DialogExpressionConverter } from './converters';

Просмотреть файл

@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { ActivityTemplate, StaticActivityTemplate, TextTemplate } from './templates';
import { BotComponent } from 'botbuilder';
import { ComponentDeclarativeTypes } from 'botbuilder-dialogs-declarative';
import { Configuration, ServiceCollection } from 'botbuilder-runtime-core';
export class LanguageGenerationBotComponent extends BotComponent {
configureServices(services: ServiceCollection, _configuration: Configuration): void {
services.composeFactory<ComponentDeclarativeTypes[]>('declarativeTypes', (declarativeTypes) =>
declarativeTypes.concat({
getDeclarativeTypes() {
return [
{
kind: TextTemplate.$kind,
type: TextTemplate,
},
{
kind: ActivityTemplate.$kind,
type: ActivityTemplate,
},
{
kind: StaticActivityTemplate.$kind,
type: StaticActivityTemplate,
},
];
},
})
);
}
}

Просмотреть файл

@ -1,44 +0,0 @@
/**
* @module botbuilder-dialogs-adaptive
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { Activity, ComponentRegistration } from 'botbuilder-core';
import { TemplateInterface } from 'botbuilder-dialogs';
import { ComponentDeclarativeTypes, DeclarativeType, ResourceExplorer } from 'botbuilder-dialogs-declarative';
import { ActivityTemplate, StaticActivityTemplate, TextTemplate } from './templates';
/**
* ComponentRegistration class for language generation resources.
*/
export class LanguageGenerationComponentRegistration
extends ComponentRegistration
implements ComponentDeclarativeTypes {
/**
* Return declarative types for language generation.
*
* @param {ResourceExplorer} _resourceExplorer Resource explorer to use for resolving references.
* @returns {DeclarativeType<TemplateInterface<string | Partial<Activity>, ?>, Record<string, ?>>[]} Declarative types.
*/
public getDeclarativeTypes(
_resourceExplorer: ResourceExplorer
): DeclarativeType<TemplateInterface<string | Partial<Activity>, unknown>, Record<string, unknown>>[] {
return [
{
kind: TextTemplate.$kind,
type: TextTemplate,
},
{
kind: ActivityTemplate.$kind,
type: ActivityTemplate,
},
{
kind: StaticActivityTemplate.$kind,
type: StaticActivityTemplate,
},
];
}
}

Просмотреть файл

@ -7,8 +7,8 @@
*/
import { Configurable } from 'botbuilder-dialogs';
import { Newable } from 'botbuilder-stdlib';
import { CustomDeserializer } from './customDeserializer';
import { Newable } from 'botbuilder-stdlib';
import { ResourceExplorer } from './resources';
/**
@ -32,6 +32,7 @@ export class DefaultLoader implements CustomDeserializer<Configurable, Record<st
public load(config: Record<string, unknown>, type: Newable<Configurable>): Configurable {
return Object.entries(config).reduce((instance, [key, value]) => {
let converter = instance.getConverter(key);
if (converter) {
if (typeof converter === 'function') {
converter = new converter(this._resourceExplorer);
@ -40,6 +41,7 @@ export class DefaultLoader implements CustomDeserializer<Configurable, Record<st
} else {
instance[`${key}`] = value;
}
return instance;
}, new type());
}

Просмотреть файл

@ -6,7 +6,6 @@
* Licensed under the MIT License.
*/
import { ComponentRegistration } from 'botbuilder-core';
import { Dialog } from 'botbuilder-dialogs';
import { Newable } from 'botbuilder-stdlib';
import { normalize, join } from 'path';
@ -324,26 +323,19 @@ export class ResourceExplorer {
return result as T;
}
private getComponentRegistrations(): ComponentRegistration[] {
return (
this._declarativeTypes ??
ComponentRegistration.components.filter((component: ComponentRegistration) =>
isComponentDeclarativeTypes(component)
)
);
}
private registerTypeInternal<T, C>(kind: string, type: Newable<T>, loader?: CustomDeserializer<T, C>): void {
this._kindToType.set(kind, type);
this._kindDeserializer.set(kind, loader || new DefaultLoader(this));
this._kindDeserializer.set(kind, loader ?? new DefaultLoader(this));
}
private registerComponentTypes(): void {
if (this._typesLoaded) {
return;
}
this._typesLoaded = true;
this.getComponentRegistrations().forEach((component: ComponentDeclarativeTypes) => {
this._declarativeTypes.forEach((component: ComponentDeclarativeTypes) => {
component.getDeclarativeTypes(this).forEach((declarativeType: DeclarativeType) => {
const { kind, type, loader } = declarativeType;
this.registerTypeInternal(kind, type, loader);

Просмотреть файл

@ -1,5 +1,11 @@
const assert = require('assert');
const path = require('path');
const { ResourceExplorer } = require('../lib');
const { DialogManager } = require('botbuilder-dialogs');
const { QnACardBuilder, RankerTypes, QnAMakerClientKey, QnAMakerBotComponent } = require('botbuilder-ai');
const { ServiceCollection, noOpConfiguration } = require('botbuilder-runtime-core');
const { StringExpression } = require('adaptive-expressions');
const {
TestFlow,
MemoryStorage,
@ -9,11 +15,12 @@ const {
useBotState,
ActivityTypes,
} = require('botbuilder-core');
const { DialogManager } = require('botbuilder-dialogs');
const { ResourceExtensions, LanguageGeneratorExtensions } = require('../../botbuilder-dialogs-adaptive/lib');
const { QnACardBuilder, RankerTypes, QnAMakerClientKey } = require('../../botbuilder-ai/lib');
const { ResourceExplorer } = require('../lib');
const { StringExpression } = require('adaptive-expressions');
const {
AdaptiveBotComponent,
ResourceExtensions,
LanguageGeneratorExtensions,
} = require('botbuilder-dialogs-adaptive');
class MockQnAMakerClient {
getAnswers(_turnContext, _options, _telemetryProperties, _telemetryMetrics) {
@ -81,8 +88,6 @@ class MockQnAMakerClient {
}
}
const resourceExplorer = new ResourceExplorer().addFolder(path.join(__dirname, 'resources/JsonDialog'), true, false);
const initializeAdapter = (testName, sendTrace = false) => {
const storage = new MemoryStorage();
const convoState = new ConversationState(storage);
@ -92,7 +97,7 @@ const initializeAdapter = (testName, sendTrace = false) => {
return adapter;
};
const getTestFlow = (dialog, adapter) => {
const getTestFlow = (resourceExplorer, dialog, adapter) => {
const dm = new DialogManager(dialog);
ResourceExtensions.useResourceExplorer(dm, resourceExplorer);
LanguageGeneratorExtensions.useLanguageGeneration(dm);
@ -104,37 +109,53 @@ const getTestFlow = (dialog, adapter) => {
});
};
const buildTestFlow = (resourceName, testName, sendTrace = false) => {
const buildTestFlow = (resourceExplorer, resourceName, testName, sendTrace = false) => {
const adapter = initializeAdapter(testName, sendTrace);
const dialog = resourceExplorer.loadType(resourceName);
return getTestFlow(dialog, adapter);
return getTestFlow(resourceExplorer, dialog, adapter);
};
const buildQnAMakerTestFlow = (testName) => {
const buildQnAMakerTestFlow = (resourceExplorer, testName) => {
const adapter = initializeAdapter(testName);
const dialog = resourceExplorer.loadType('QnAMakerBot.main.dialog');
return getTestFlow(dialog, adapter);
return getTestFlow(resourceExplorer, dialog, adapter);
};
const buildQnAMakerTestFlowIsTest = (testName) => {
const buildQnAMakerTestFlowIsTest = (resourceExplorer, testName) => {
const adapter = initializeAdapter(testName);
const dialog = resourceExplorer.loadType('QnAMakerBot.main.dialog');
dialog.triggers[0].actions[0].isTest = true;
return getTestFlow(dialog, adapter);
return getTestFlow(resourceExplorer, dialog, adapter);
};
const buildQnAMakerTestFlowRankerTypeQuestionOnly = (testName) => {
const buildQnAMakerTestFlowRankerTypeQuestionOnly = (resourceExplorer, testName) => {
const adapter = initializeAdapter(testName);
const dialog = resourceExplorer.loadType('QnAMakerBot.main.dialog');
dialog.triggers[0].actions[0].rankerType = new StringExpression(RankerTypes.questionOnly);
return getTestFlow(dialog, adapter);
return getTestFlow(resourceExplorer, dialog, adapter);
};
describe('Json load tests', function () {
this.timeout(5000);
let resourceExplorer;
beforeEach(function () {
const services = new ServiceCollection({
declarativeTypes: [],
});
new AdaptiveBotComponent().configureServices(services, noOpConfiguration);
new QnAMakerBotComponent().configureServices(services, noOpConfiguration);
const declarativeTypes = services.mustMakeInstance('declarativeTypes');
resourceExplorer = new ResourceExplorer({ declarativeTypes }).addFolder(
path.join(__dirname, 'resources/JsonDialog'),
true,
false
);
});
it('DoubleReference', async () => {
await buildTestFlow('DoubleReference.dialog', this.fullTitle())
await buildTestFlow(resourceExplorer, 'DoubleReference.dialog', this.fullTitle())
.sendConversationUpdate()
.assertReply('what is your name?')
.send('c')
@ -143,7 +164,7 @@ describe('Json load tests', function () {
});
it('CycleDetection', async () => {
await buildTestFlow('Root.dialog', this.fullTitle())
await buildTestFlow(resourceExplorer, 'Root.dialog', this.fullTitle())
.sendConversationUpdate()
.assertReply('Hello')
.send('Hello what?')
@ -162,7 +183,7 @@ describe('Json load tests', function () {
});
it('Actions', async () => {
await buildTestFlow('Actions.main.dialog', this.fullTitle())
await buildTestFlow(resourceExplorer, 'Actions.main.dialog', this.fullTitle())
.sendConversationUpdate()
.assertReply('Action 1')
.assertReply('Action 2')
@ -171,7 +192,7 @@ describe('Json load tests', function () {
});
it('EndTurn', async () => {
await buildTestFlow('EndTurn.main.dialog', this.fullTitle())
await buildTestFlow(resourceExplorer, 'EndTurn.main.dialog', this.fullTitle())
.send('hello')
.assertReply("What's up?")
.send('Nothing')
@ -180,7 +201,7 @@ describe('Json load tests', function () {
});
it('IfProerty', async () => {
await buildTestFlow('IfCondition.main.dialog', this.fullTitle())
await buildTestFlow(resourceExplorer, 'IfCondition.main.dialog', this.fullTitle())
.sendConversationUpdate()
.assertReply("Hello, I'm Zoidberg. What is your name?")
.send('Carlos')
@ -189,14 +210,14 @@ describe('Json load tests', function () {
});
it('SwitchCondition', async () => {
await buildTestFlow('SwitchCondition.main.dialog', this.fullTitle())
await buildTestFlow(resourceExplorer, 'SwitchCondition.main.dialog', this.fullTitle())
.send('Hi')
.assertReply('Age is 22!')
.startTest();
});
it('TextInputWithoutProperty', async () => {
await buildTestFlow('TextInput.WithoutProperty.main.dialog', this.fullTitle())
await buildTestFlow(resourceExplorer, 'TextInput.WithoutProperty.main.dialog', this.fullTitle())
.sendConversationUpdate()
.assertReply("Hello, I'm Zoidberg. What is your name?")
.send('Carlos')
@ -205,7 +226,7 @@ describe('Json load tests', function () {
});
it('TextInput', async () => {
await buildTestFlow('TextInput.main.dialog', this.fullTitle())
await buildTestFlow(resourceExplorer, 'TextInput.main.dialog', this.fullTitle())
.sendConversationUpdate()
.assertReply("Hello, I'm Zoidberg. What is your name?")
.send('Cancel')
@ -220,7 +241,7 @@ describe('Json load tests', function () {
});
it('NumberInput', async () => {
await buildTestFlow('NumberInput.main.dialog', this.fullTitle())
await buildTestFlow(resourceExplorer, 'NumberInput.main.dialog', this.fullTitle())
.sendConversationUpdate()
.assertReply('What is your age?')
.send('Blablabla')
@ -234,7 +255,7 @@ describe('Json load tests', function () {
});
it('RepeatDialog', async () => {
await buildTestFlow('RepeatDialog.main.dialog', this.fullTitle())
await buildTestFlow(resourceExplorer, 'RepeatDialog.main.dialog', this.fullTitle())
.sendConversationUpdate()
.assertReply('RepeatDialog.main.dialog starting')
.assertReply('Hello, what is your name?')
@ -247,7 +268,7 @@ describe('Json load tests', function () {
});
it('TraceAndLog', async () => {
await buildTestFlow('TraceAndLog.main.dialog', this.fullTitle(), true)
await buildTestFlow(resourceExplorer, 'TraceAndLog.main.dialog', this.fullTitle(), true)
.sendConversationUpdate()
.assertReply('Hello, what is your name?')
.send('Carlos')
@ -264,7 +285,7 @@ describe('Json load tests', function () {
});
it('DoActions', async () => {
await buildTestFlow('DoActions.main.dialog', this.fullTitle())
await buildTestFlow(resourceExplorer, 'DoActions.main.dialog', this.fullTitle())
.send({ type: ActivityTypes.ConversationUpdate, membersAdded: [{ id: 'bot', name: 'Bot' }] })
.sendConversationUpdate()
.assertReply("Hello, I'm Zoidberg. What is your name?")
@ -283,7 +304,7 @@ describe('Json load tests', function () {
});
it('BeginDialog', async () => {
await buildTestFlow('BeginDialog.main.dialog', this.fullTitle())
await buildTestFlow(resourceExplorer, 'BeginDialog.main.dialog', this.fullTitle())
.send({ type: ActivityTypes.ConversationUpdate, membersAdded: [{ id: 'bot', name: 'Bot' }] })
.sendConversationUpdate()
.assertReply("Hello, I'm Zoidberg. What is your name?")
@ -302,7 +323,7 @@ describe('Json load tests', function () {
});
it('ChoiceInput', async () => {
await buildTestFlow('ChoiceInput.main.dialog', this.fullTitle())
await buildTestFlow(resourceExplorer, 'ChoiceInput.main.dialog', this.fullTitle())
.sendConversationUpdate()
.assertReply('Please select a value from below:\n\n 1. Test1\n 2. Test2\n 3. Test3')
.send('Test1')
@ -311,7 +332,7 @@ describe('Json load tests', function () {
});
it('ExternalLanguage', async () => {
await buildTestFlow('ExternalLanguage.main.dialog', this.fullTitle())
await buildTestFlow(resourceExplorer, 'ExternalLanguage.main.dialog', this.fullTitle())
.sendConversationUpdate()
.assertReplyOneOf([
'Zoidberg here, welcome to my world!',
@ -334,7 +355,7 @@ describe('Json load tests', function () {
});
it('ToDoBot', async () => {
await buildTestFlow('ToDoBot.main.dialog', this.fullTitle())
await buildTestFlow(resourceExplorer, 'ToDoBot.main.dialog', this.fullTitle())
.send({ type: ActivityTypes.ConversationUpdate, membersAdded: [{ id: 'bot', name: 'Bot' }] })
.sendConversationUpdate()
.assertReply('Hi! I\'m a ToDo bot. Say "add a todo named first" to get started.')
@ -366,7 +387,7 @@ describe('Json load tests', function () {
});
it('HttpRequest', async () => {
await buildTestFlow('HttpRequest.main.dialog', this.fullTitle())
await buildTestFlow(resourceExplorer, 'HttpRequest.main.dialog', this.fullTitle())
.send({ type: ActivityTypes.ConversationUpdate, membersAdded: [{ id: 'bot', name: 'Bot' }] })
.assertReply('Welcome! Here is a http request sample, please enter a name for you visual pet.')
.send('TestPetName')
@ -387,7 +408,7 @@ describe('Json load tests', function () {
'Did you mean:',
'None of the above.'
);
await buildQnAMakerTestFlow(this.fullTitle())
await buildQnAMakerTestFlow(resourceExplorer, this.fullTitle())
.send('Q11')
.assertReply((reply, _description) => {
assert(reply.attachments);
@ -406,7 +427,7 @@ describe('Json load tests', function () {
'None of the above.'
);
const noAnswerActivity = 'Answers not found in kb.';
await buildQnAMakerTestFlow(this.fullTitle())
await buildQnAMakerTestFlow(resourceExplorer, this.fullTitle())
.send('Q11')
.assertReply((reply, _description) => {
assert(reply.attachments);
@ -424,7 +445,7 @@ describe('Json load tests', function () {
'Did you mean:',
'None of the above.'
);
await buildQnAMakerTestFlow(this.fullTitle())
await buildQnAMakerTestFlow(resourceExplorer, this.fullTitle())
.send('Q11')
.assertReply((reply, _description) => {
assert(reply.attachments);
@ -436,14 +457,14 @@ describe('Json load tests', function () {
});
it('QnAMakerDialog_isTest', async () => {
await buildQnAMakerTestFlowIsTest(this.fullTitle())
await buildQnAMakerTestFlowIsTest(resourceExplorer, this.fullTitle())
.send('Surface book 2 price')
.assertReply('Surface book 2 price is $1400.')
.startTest();
});
it('QnAMakerDialog_RankerType_QuestionOnly', async () => {
await buildQnAMakerTestFlowRankerTypeQuestionOnly(this.fullTitle())
await buildQnAMakerTestFlowRankerTypeQuestionOnly(resourceExplorer, this.fullTitle())
.send('What ranker do you want to use?')
.assertReply('We are using QuestionOnly ranker.')
.startTest();

Просмотреть файл

@ -1,17 +1,11 @@
const {
ComponentRegistration,
TestAdapter,
MemoryStorage,
useBotState,
UserState,
ConversationState,
} = require('botbuilder-core');
const { DialogManager } = require('botbuilder-dialogs');
const { AdaptiveComponentRegistration } = require('../../botbuilder-dialogs-adaptive/lib');
const { ResourceExplorer, FolderResourceProvider, ResourceChangeEvent } = require('../lib');
const assert = require('assert');
const { writeFileSync, existsSync, unlinkSync } = require('fs');
const { AdaptiveBotComponent } = require('botbuilder-dialogs-adaptive');
const { DialogManager } = require('botbuilder-dialogs');
const { ResourceExplorer, FolderResourceProvider, ResourceChangeEvent } = require('../lib');
const { ServiceCollection, noOpConfiguration } = require('botbuilder-runtime-core');
const { TestAdapter, MemoryStorage, useBotState, UserState, ConversationState } = require('botbuilder-core');
const { extname, join } = require('path');
const { writeFileSync, existsSync, unlinkSync } = require('fs');
function assertResourceType(explorer, resourceType) {
const resources = explorer.getResources(resourceType);
@ -23,30 +17,34 @@ function assertResourceFound(explorer, id) {
const resource = explorer.getResource(id);
assert(resource, `getResource(${id}) should return resource`);
const dialogs = explorer.getResources('dialog');
assert(dialogs.some(dialog => dialog.id == id), `getResources('dialog') should return resources`);
assert(
dialogs.some((dialog) => dialog.id == id),
`getResources('dialog') should return resources`
);
}
function assertResourceNotFound(explorer, id) {
const resource = explorer.getResource(id);
assert.strictEqual(resource, undefined, `getResource(${id}) should not return resource`);
const dialogs = explorer.getResources('dialog');
assert(dialogs.every(dialog => dialog.id != id), `getResouces('dialog') should not return resources`);
assert(
dialogs.every((dialog) => dialog.id != id),
`getResouces('dialog') should not return resources`
);
}
function assertResourceContents(explorer, id, contents) {
const resource = explorer.getResource(id);
let text = resource.readText();
assert.strictEqual(text, contents, `getResource(${id}) contents not the same`);
const dialogs = explorer.getResources('dialog').filter(dialog => dialog.id == id);
const dialogs = explorer.getResources('dialog').filter((dialog) => dialog.id == id);
assert(dialogs.length == 1, `getResouces('dialog') should return resources`);
const dialog = dialogs[0];
text = dialog.readText();
assert.strictEqual(text, contents, `getResouces('dialog') contents not the same`);
}
describe('ResourecExplorer', function () {
this.timeout(5000);
describe('ResourceExplorer', function () {
it('add folders recursively', async () => {
const explorer = new ResourceExplorer();
explorer.addFolder(join(__dirname, 'resources'), true, false);
@ -99,12 +97,21 @@ describe('ResourecExplorer', function () {
});
it('dialog id assignment', async () => {
const explorer = new ResourceExplorer();
explorer.addFolders(join(__dirname, 'resources'), [], false);
ComponentRegistration.add(new AdaptiveComponentRegistration());
const services = new ServiceCollection({
declarativeTypes: [],
});
new AdaptiveBotComponent().configureServices(services, noOpConfiguration);
const declarativeTypes = services.mustMakeInstance('declarativeTypes');
const explorer = new ResourceExplorer({ declarativeTypes }).addFolders(join(__dirname, 'resources'), [], false);
const dialog = explorer.loadType('test.dialog');
assert.strictEqual(dialog.id, 'test.dialog', 'resource id should be used as default dialog id if none assigned.');
assert.strictEqual(
dialog.id,
'test.dialog',
'resource id should be used as default dialog id if none assigned.'
);
assert.strictEqual(dialog.triggers[0].actions[0].id, '1234567890');
assert.strictEqual(dialog.triggers[0].actions[1].id, 'test3.dialog');
@ -126,13 +133,17 @@ describe('ResourecExplorer', function () {
let event, resource;
explorer.changed = (e, resources) => {
if (!event) { event = e; }
if (!resource) { resource = resources[0]; }
if (!event) {
event = e;
}
if (!resource) {
resource = resources[0];
}
};
// write test file
writeFileSync(testPath, '{"test": 123}');
await new Promise(resolve => setTimeout(resolve, 200));
await new Promise((resolve) => setTimeout(resolve, 200));
assert.strictEqual(event, ResourceChangeEvent.added);
assert.strictEqual(resource.id, 'file_to_be_added.dialog');
@ -155,17 +166,21 @@ describe('ResourecExplorer', function () {
// write test file
writeFileSync(testPath, '{"test": 123}');
await new Promise(resolve => setTimeout(resolve, 100));
await new Promise((resolve) => setTimeout(resolve, 100));
let event, resource;
explorer.changed = (e, resources) => {
if (!event) { event = e; }
if (!resource) { resource = resources[0]; }
if (!event) {
event = e;
}
if (!resource) {
resource = resources[0];
}
};
// change test file
writeFileSync(testPath, '{"test": 1234}');
await new Promise(resolve => setTimeout(resolve, 200));
await new Promise((resolve) => setTimeout(resolve, 200));
assert.strictEqual(event, ResourceChangeEvent.changed);
assert.strictEqual(resource.id, 'file_to_be_changed.dialog');
@ -188,17 +203,21 @@ describe('ResourecExplorer', function () {
// write test file
writeFileSync(testPath, '{"test": 123}');
await new Promise(resolve => setTimeout(resolve, 100));
await new Promise((resolve) => setTimeout(resolve, 100));
let event, resource;
explorer.changed = (e, resources) => {
if (!event) { event = e; }
if (!resource) { resource = resources[0]; }
if (!event) {
event = e;
}
if (!resource) {
resource = resources[0];
}
};
// remove test file
unlinkSync(testPath);
await new Promise(resolve => setTimeout(resolve, 200));
await new Promise((resolve) => setTimeout(resolve, 200));
assert.strictEqual(event, ResourceChangeEvent.removed);
assert.strictEqual(resource.id, 'file_to_be_removed.dialog');
@ -222,7 +241,7 @@ describe('ResourecExplorer', function () {
writeFileSync(testPath, '{"test": 123}');
// wait 200ms for file changes
await new Promise(resolve => setTimeout(resolve, 200));
await new Promise((resolve) => setTimeout(resolve, 200));
assertResourceFound(explorer, 'foobar.dialog');
assertResourceContents(explorer, 'foobar.dialog', '{"test": 123}');
@ -230,7 +249,7 @@ describe('ResourecExplorer', function () {
writeFileSync(testPath, '{"test": 1234}');
// wait 200ms for file changes
await new Promise(resolve => setTimeout(resolve, 200));
await new Promise((resolve) => setTimeout(resolve, 200));
assertResourceFound(explorer, 'foobar.dialog');
assertResourceContents(explorer, 'foobar.dialog', '{"test": 1234}');
@ -238,7 +257,7 @@ describe('ResourecExplorer', function () {
unlinkSync(testPath);
// wait 200ms for file changes
await new Promise(resolve => setTimeout(resolve, 200));
await new Promise((resolve) => setTimeout(resolve, 200));
assertResourceNotFound(explorer, 'foobar.dialog');
const resourceProvider = explorer.resourceProviders[0];
@ -246,12 +265,19 @@ describe('ResourecExplorer', function () {
});
it('cycle reference', async () => {
ComponentRegistration.add(new AdaptiveComponentRegistration());
const resourceExplorer = new ResourceExplorer().addFolder(
const services = new ServiceCollection({
declarativeTypes: [],
});
new AdaptiveBotComponent().configureServices(services, noOpConfiguration);
const declarativeTypes = services.mustMakeInstance('declarativeTypes');
const resourceExplorer = new ResourceExplorer({ declarativeTypes }).addFolder(
join(__dirname, './resources/CycleDetection'),
false,
false
);
const root = resourceExplorer.loadType('root.dialog');
const dm = new DialogManager(root);
const adapter = new TestAdapter(async (context) => {

Просмотреть файл

@ -32,6 +32,7 @@
"@microsoft/recognizers-text-number": "1.1.4",
"@microsoft/recognizers-text-suite": "1.1.4",
"botbuilder-core": "4.1.6",
"botbuilder-runtime-core": "4.1.6",
"botbuilder-stdlib": "4.1.6",
"botframework-connector": "4.1.6",
"globalize": "^1.4.2",
@ -49,7 +50,8 @@
"clean": "rimraf _ts3.4 lib tsconfig.tsbuildinfo",
"lint": "eslint . --ext .js,.ts",
"postbuild": "downlevel-dts lib _ts3.4/lib --checksum",
"test": "yarn build && nyc mocha tests/",
"test": "npm-run-all build test:mocha",
"test:mocha": "nyc mocha tests",
"test:compat": "api-extractor run --verbose"
},
"files": [

Просмотреть файл

@ -0,0 +1,54 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { BotComponent } from 'botbuilder-core';
import { Configuration, ServiceCollection } from 'botbuilder-runtime-core';
import { MemoryScope, PathResolver } from './memory';
import {
ClassMemoryScope,
ConversationMemoryScope,
DialogClassMemoryScope,
DialogContextMemoryScope,
DialogMemoryScope,
SettingsMemoryScope,
ThisMemoryScope,
TurnMemoryScope,
UserMemoryScope,
} from './memory/scopes';
import {
AtAtPathResolver,
AtPathResolver,
DollarPathResolver,
HashPathResolver,
PercentPathResolver,
} from './memory/pathResolvers';
export class DialogsBotComponent extends BotComponent {
configureServices(services: ServiceCollection, _configuration: Configuration): void {
services.composeFactory<MemoryScope[]>('memoryScopes', (memoryScopes) => {
return memoryScopes.concat(
new TurnMemoryScope(),
new SettingsMemoryScope(),
new DialogMemoryScope(),
new DialogContextMemoryScope(),
new DialogClassMemoryScope(),
new ClassMemoryScope(),
new ThisMemoryScope(),
new ConversationMemoryScope(),
new UserMemoryScope()
);
});
services.composeFactory<PathResolver[]>('pathResolvers', (pathResolvers) =>
pathResolvers.concat(
new DollarPathResolver(),
new HashPathResolver(),
new AtAtPathResolver(),
new AtPathResolver(),
new PercentPathResolver()
)
);
}
}

Просмотреть файл

@ -7,31 +7,34 @@
*/
import { ComponentRegistration } from 'botbuilder-core';
import { ServiceCollection, noOpConfiguration } from 'botbuilder-runtime-core';
import { DialogsBotComponent } from './dialogsBotComponent';
import { ComponentMemoryScopes, ComponentPathResolvers, MemoryScope, PathResolver } from './memory';
import { AtAtPathResolver, AtPathResolver, DollarPathResolver, HashPathResolver, PercentPathResolver } from './memory/pathResolvers';
import { ClassMemoryScope, ConversationMemoryScope, DialogClassMemoryScope, DialogContextMemoryScope, DialogMemoryScope, SettingsMemoryScope, ThisMemoryScope, TurnMemoryScope, UserMemoryScope } from './memory/scopes';
/**
* Makes dialogs component available to the system registering functionality.
*/
export class DialogsComponentRegistration extends ComponentRegistration implements ComponentMemoryScopes, ComponentPathResolvers {
export class DialogsComponentRegistration
extends ComponentRegistration
implements ComponentMemoryScopes, ComponentPathResolvers {
private readonly services = new ServiceCollection({
memoryScopes: [],
pathResolvers: [],
});
constructor() {
super();
new DialogsBotComponent().configureServices(this.services, noOpConfiguration);
}
/**
* Gets the dialogs memory scopes.
*
* @returns {MemoryScope[]} A list of [MemoryScope](xref:botbuilder-dialogs.MemoryScope).
*/
public getMemoryScopes(): MemoryScope[] {
return [
new TurnMemoryScope(),
new SettingsMemoryScope(),
new DialogMemoryScope(),
new DialogContextMemoryScope(),
new DialogClassMemoryScope(),
new ClassMemoryScope(),
new ThisMemoryScope(),
new ConversationMemoryScope(),
new UserMemoryScope(),
];
return this.services.mustMakeInstance<MemoryScope[]>('memoryScopes');
}
/**
@ -40,13 +43,6 @@ export class DialogsComponentRegistration extends ComponentRegistration implemen
* @returns {PathResolver[]} A list of [PathResolver](xref:botbuilder-dialogs.PathResolver).
*/
public getPathResolvers(): PathResolver[] {
return [
new DollarPathResolver(),
new HashPathResolver(),
new AtAtPathResolver(),
new AtPathResolver(),
new PercentPathResolver(),
];
return this.services.mustMakeInstance<PathResolver[]>('pathResolvers');
}
}

Просмотреть файл

@ -16,11 +16,10 @@ export * from './dialogContainer';
export * from './dialogContext';
export * from './dialogContextError';
export * from './dialogEvents';
export { runDialog } from './dialogHelper';
export * from './dialogManager';
export * from './dialogsComponentRegistration';
export * from './dialogSet';
export * from './dialogTurnStateConstants';
export * from './dialogsBotComponent';
export * from './memory';
export * from './prompts';
export * from './recognizer';
@ -29,3 +28,5 @@ export * from './skillDialogOptions';
export * from './template';
export * from './waterfallDialog';
export * from './waterfallStepContext';
export { runDialog } from './dialogHelper';

Просмотреть файл

@ -5,14 +5,15 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { PathResolver } from './pathResolvers';
import { MemoryScope } from './scopes';
import { DialogContext } from '../dialogContext';
import { DialogPath } from './dialogPath';
import { ComponentRegistration } from 'botbuilder-core';
import { DialogsComponentRegistration } from '../dialogsComponentRegistration';
import { ComponentMemoryScopes, isComponentMemoryScopes } from './componentMemoryScopes';
import { ComponentPathResolvers, isComponentPathResolvers } from './componentPathResolvers';
import { ComponentRegistration } from 'botbuilder-core';
import { DialogContext } from '../dialogContext';
import { DialogPath } from './dialogPath';
import { DialogsComponentRegistration } from '../dialogsComponentRegistration';
import { MemoryScope } from './scopes';
import { PathResolver } from './pathResolvers';
export interface DialogStateManagerConfiguration {
/**
@ -43,6 +44,7 @@ export class DialogStateManager {
/**
* Initializes a new instance of the [DialogStateManager](xref:botbuilder-dialogs.DialogStateManager) class.
*
* @param dc The dialog context for the current turn of the conversation.
* @param configuration Configuration for the dialog state manager.
*/
@ -51,22 +53,31 @@ export class DialogStateManager {
this.dialogContext = dc;
this.configuration = configuration ?? dc.context.turnState.get(DIALOG_STATE_MANAGER_CONFIGURATION);
if (!this.configuration) {
this.configuration = { memoryScopes: [], pathResolvers: [] };
// get all of the component memory scopes.
ComponentRegistration.components.filter((component: ComponentRegistration) =>
isComponentMemoryScopes(component)
).forEach((component: ComponentMemoryScopes) => {
this.configuration.memoryScopes.push(...component.getMemoryScopes());
})
ComponentRegistration.components
.filter((component: ComponentRegistration) => isComponentMemoryScopes(component))
.forEach((component: ComponentMemoryScopes) => {
this.configuration.memoryScopes.push(...component.getMemoryScopes());
});
// merge in turn state memory scopes
const memoryScopes = dc.context.turnState.get<MemoryScope[]>('memoryScopes') ?? [];
this.configuration.memoryScopes.push(...memoryScopes);
// get all of the component path resolvers.
ComponentRegistration.components.filter((component: ComponentRegistration) =>
isComponentPathResolvers(component)
).forEach((component: ComponentPathResolvers) => {
this.configuration.pathResolvers.push(...component.getPathResolvers());
});
ComponentRegistration.components
.filter((component: ComponentRegistration) => isComponentPathResolvers(component))
.forEach((component: ComponentPathResolvers) => {
this.configuration.pathResolvers.push(...component.getPathResolvers());
});
// merge in turn state ones path resolvers
const pathResolvers = dc.context.turnState.get<PathResolver[]>('pathResolvers') ?? [];
this.configuration.pathResolvers.push(...pathResolvers);
// cache for any other new dialogStateManager instances in this turn
dc.context.turnState.set(DIALOG_STATE_MANAGER_CONFIGURATION, this.configuration);

Просмотреть файл

@ -5,10 +5,11 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { MemoryScope } from './memoryScope';
import { ScopePath } from '../scopePath';
import { DialogContext } from '../../dialogContext';
import { DialogTurnStateConstants } from '../../dialogTurnStateConstants';
import { MemoryScope } from './memoryScope';
import { ScopePath } from '../scopePath';
/**
* The setting node.
@ -58,12 +59,15 @@ export class SettingsMemoryScope extends MemoryScope {
return dc.context.turnState.get(ScopePath.settings) ?? {};
} else {
const configuration = dc.context.turnState.get(DialogTurnStateConstants.configuration) ?? {};
Object.entries(process.env).reduce((result, [key, value]) => {
result[`${key}`] = value;
return result;
}, configuration);
const settings = SettingsMemoryScope.loadSettings(configuration);
dc.context.turnState.set(ScopePath.settings, settings);
return settings;
}
}
@ -76,6 +80,7 @@ export class SettingsMemoryScope extends MemoryScope {
*/
protected static loadSettings(configuration: Record<string, string>): Record<string, unknown> {
const settings = {};
if (configuration) {
// load configuration into settings
const root = this.convertFlattenSettingToNode(Object.entries(configuration));
@ -84,6 +89,7 @@ export class SettingsMemoryScope extends MemoryScope {
return result;
}, settings);
}
return settings;
}

Просмотреть файл

@ -29,7 +29,6 @@
},
"dependencies": {
"dependency-graph": "^0.10.0",
"p-reduce": "^2.1.0",
"runtypes": "^5.0.1"
},
"devDependencies": {

Просмотреть файл

@ -21,3 +21,15 @@ export interface Configuration {
*/
set(path: string[], value: unknown): void;
}
/**
* Useful for shimming BotComponents into ComponentRegistrations
*/
export const noOpConfiguration: Configuration = {
get(_path: string[]): unknown | undefined {
return undefined;
},
set(_path: string[], _value: unknown): void {
// no-op
},
};

Просмотреть файл

@ -2,7 +2,6 @@
// Licensed under the MIT License.
import assert from 'assert';
import preduce from 'p-reduce';
import { DepGraph } from 'dependency-graph';
import { ok } from 'assert';
import { stringify } from './util';
@ -15,7 +14,7 @@ import { stringify } from './util';
*/
export type Factory<Type, Initial extends boolean> = (
initialValue: Initial extends true ? Type : Type | undefined
) => Type | Promise<Type>;
) => Type;
/**
* DependencyFactory is a function signature that produces an instance that depends on a set of
@ -28,7 +27,7 @@ export type Factory<Type, Initial extends boolean> = (
export type DependencyFactory<Type, Dependencies, Initial extends boolean> = (
dependencies: Dependencies,
initialValue: Initial extends true ? Type : Type | undefined
) => Type | Promise<Type>;
) => Type;
/**
* ServiceCollection is an interface that describes a set of methods to register services. This, in a lighter way,
@ -188,10 +187,10 @@ export class ServiceCollection {
// Register dependencies and then build nodes. Note: `nodes` is a function because ordering may
// depend on results of dependency registration
private async buildNodes<ReturnType = Record<string, unknown>>(
private buildNodes<ReturnType = Record<string, unknown>>(
generateNodes: () => string[],
reuseServices: Record<string, unknown> = {}
): Promise<ReturnType> {
): ReturnType {
// Consume all dependencies and then reset so updating registrations without re-registering
// dependencies works
this.dependencies.forEach((dependencies, node) =>
@ -201,40 +200,32 @@ export class ServiceCollection {
// Generate nodes after registering dependencies so ordering is correct
const nodes = generateNodes();
const services = await preduce(
nodes,
async (services, service) => {
// Extra precaution
if (!this.graph.hasNode(service)) {
return services;
}
const services = nodes.reduce((services, service) => {
// Extra precaution
if (!this.graph.hasNode(service)) {
return services;
}
// Helper to generate return value
const assignValue = (value: unknown) => ({
...services,
[service]: value,
});
// Helper to generate return value
const assignValue = (value: unknown) => ({
...services,
[service]: value,
});
// Optionally reuse existing service
const reusedService = reuseServices[service];
if (reusedService !== undefined) {
return assignValue(reusedService);
}
// Optionally reuse existing service
const reusedService = reuseServices[service];
if (reusedService !== undefined) {
return assignValue(reusedService);
}
// Each node stores a list of factory methods.
const factories = this.graph.getNodeData(service);
// Each node stores a list of factory methods.
const factories = this.graph.getNodeData(service);
// Produce the instance by reducing those factories, passing the instance along for composition.
const instance = await preduce(
factories,
(value, factory) => factory(services, value),
<unknown>services[service]
);
// Produce the instance by reducing those factories, passing the instance along for composition.
const instance = factories.reduce((value, factory) => factory(services, value), <unknown>services[service]);
return assignValue(instance);
},
<Record<string, unknown>>{}
);
return assignValue(instance);
}, <Record<string, unknown>>{});
// Cache results for subsequent invocations that may desire pre-constructed instances
Object.assign(this.cache, services);
@ -249,7 +240,7 @@ export class ServiceCollection {
* @param deep reconstruct all dependencies
* @returns the service instance, or undefined
*/
async makeInstance<InstanceType = unknown>(key: string, deep = false): Promise<InstanceType | undefined> {
makeInstance<InstanceType = unknown>(key: string, deep = false): InstanceType | undefined {
// If this is not a deep reconstruction, reuse any services that `key` depends on
let initialServices: Record<string, unknown> | undefined;
if (!deep) {
@ -257,7 +248,7 @@ export class ServiceCollection {
initialServices = cached;
}
const services = await this.buildNodes<Record<string, InstanceType | undefined>>(
const services = this.buildNodes<Record<string, InstanceType | undefined>>(
() => this.graph.dependenciesOf(key).concat(key),
initialServices
);
@ -272,8 +263,8 @@ export class ServiceCollection {
* @param deep reconstruct all dependencies
* @returns the service instance
*/
async mustMakeInstance<InstanceType = unknown>(key: string, deep = false): Promise<InstanceType> {
const instance = await this.makeInstance<InstanceType>(key, deep);
mustMakeInstance<InstanceType = unknown>(key: string, deep = false): InstanceType {
const instance = this.makeInstance<InstanceType>(key, deep);
assert.ok(instance, `\`${key}\` instance undefined!`);
return instance;
@ -284,7 +275,7 @@ export class ServiceCollection {
*
* @returns all resolved services
*/
makeInstances<InstancesType>(): Promise<InstancesType> {
makeInstances<InstancesType>(): InstancesType {
return this.buildNodes<InstancesType>(() => this.graph.overallOrder());
}
@ -294,10 +285,10 @@ export class ServiceCollection {
* @param keys instances that must be not undefined
* @returns all resolve services
*/
async mustMakeInstances<InstancesType extends Record<string, unknown> = Record<string, unknown>>(
mustMakeInstances<InstancesType extends Record<string, unknown> = Record<string, unknown>>(
...keys: string[]
): Promise<InstancesType> {
const instances = await this.makeInstances<InstancesType>();
): InstancesType {
const instances = this.makeInstances<InstancesType>();
keys.forEach((key) => {
assert.ok(instances[key], `\`${key}\` instance undefined!`);

Просмотреть файл

@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import assert from 'assert';
import { ServiceCollection } from '../src/serviceCollection';
import { deepStrictEqual, notStrictEqual, ok, rejects, strictEqual } from 'assert';
class Foo {}
@ -26,98 +26,98 @@ describe('ServiceCollection', () => {
const services = new ServiceCollection(defaultServices);
services.addInstance('foo', new Foo());
services.addFactory<Bar, { foo: Foo }>('bar', ['foo'], async ({ foo }) => new Bar(foo));
services.addFactory<Bar, { foo: Foo }>('bar', ['foo'], ({ foo }) => new Bar(foo));
services.addFactory<Baz, { foo: Foo; bar: Bar }>('baz', ['foo', 'bar'], ({ foo, bar }) => new Baz(foo, bar));
return services;
};
describe('makeInstances', () => {
it('works', async () => {
it('works', () => {
const services = makeServiceCollection();
const { foo, bar, baz, bil } = await services.mustMakeInstances<{
const { foo, bar, baz, bil } = services.mustMakeInstances<{
foo: Foo;
bar: Bar;
baz: Baz;
bil?: unknown;
}>('foo', 'bar', 'baz');
ok(bil === undefined);
assert.ok(bil === undefined);
strictEqual(bar.foo, foo);
strictEqual(baz.bar, bar);
strictEqual(baz.bar.foo, foo);
assert.strictEqual(bar.foo, foo);
assert.strictEqual(baz.bar, bar);
assert.strictEqual(baz.bar.foo, foo);
});
describe('providing defaults', () => {
it('initialValue style', async () => {
it('initialValue style', () => {
const services = new ServiceCollection();
services.addFactory<number[]>('values', async (values = [1]) => values.concat(2));
services.composeFactory<number[]>('values', async (values) => values.concat(3));
services.addFactory<number[]>('values', (values = [1]) => values.concat(2));
services.composeFactory<number[]>('values', (values) => values.concat(3));
const { values } = await services.makeInstances();
deepStrictEqual(values, [1, 2, 3]);
const { values } = services.makeInstances();
assert.deepStrictEqual(values, [1, 2, 3]);
});
it('constructor style', async () => {
it('constructor style', () => {
const services = new ServiceCollection({
values: [1],
});
services.composeFactory<number[]>('values', async (values) => values.concat(2));
services.composeFactory<number[]>('values', async (values) => values.concat(3));
services.composeFactory<number[]>('values', (values) => values.concat(2));
services.composeFactory<number[]>('values', (values) => values.concat(3));
const { values } = await services.makeInstances();
deepStrictEqual(values, [1, 2, 3]);
const { values } = services.makeInstances();
assert.deepStrictEqual(values, [1, 2, 3]);
});
});
});
describe('mustMakeInstances', () => {
it('throws if a service instance is undefined', async () => {
it('throws if a service instance is undefined', () => {
const services = new ServiceCollection();
await rejects(services.mustMakeInstances('value'));
assert.throws(() => services.mustMakeInstances('value'));
});
});
describe('makeInstance', () => {
it('uses cached dependencies by default', async () => {
it('uses cached dependencies by default', () => {
const services = makeServiceCollection();
const { bar, baz } = await services.mustMakeInstances<{ bar: Bar; baz: Baz }>('bar', 'baz');
const newBaz = await services.mustMakeInstance<Baz>('baz');
const { bar, baz } = services.mustMakeInstances<{ bar: Bar; baz: Baz }>('bar', 'baz');
const newBaz = services.mustMakeInstance<Baz>('baz');
notStrictEqual(newBaz, baz);
strictEqual(newBaz.bar, bar);
assert.notStrictEqual(newBaz, baz);
assert.strictEqual(newBaz.bar, bar);
});
it('optionally fully reconstructs dependencies', async () => {
it('optionally fully reconstructs dependencies', () => {
const services = makeServiceCollection();
const { foo, bar, baz } = await services.makeInstances();
ok(foo);
ok(bar);
ok(baz);
const { foo, bar, baz } = services.makeInstances();
assert.ok(foo);
assert.ok(bar);
assert.ok(baz);
const newBaz = await services.makeInstance<Baz>('baz', true);
ok(newBaz);
const newBaz = services.makeInstance<Baz>('baz', true);
assert.ok(newBaz);
notStrictEqual(newBaz, baz);
notStrictEqual(newBaz.bar, bar);
assert.notStrictEqual(newBaz, baz);
assert.notStrictEqual(newBaz.bar, bar);
});
});
describe('mustMakeInstance', () => {
it('throws if a service instance is undefined', async () => {
it('throws if a service instance is undefined', () => {
const services = new ServiceCollection();
await rejects(services.mustMakeInstance('value'));
assert.throws(() => services.mustMakeInstance('value'));
});
});
describe('factory handling', () => {
it('works', async () => {
it('works', () => {
const services = new ServiceCollection({
a: {},
b: {},
@ -133,11 +133,11 @@ describe('ServiceCollection', () => {
({ a }, b) => ({ ...a, ...b })
);
const a = await services.mustMakeInstance('a');
deepStrictEqual(a, { key: 'value' });
const a = services.mustMakeInstance('a');
assert.deepStrictEqual(a, { key: 'value' });
});
it('throws for undefined initial value', async () => {
it('throws for undefined initial value', () => {
const services = new ServiceCollection({
a: {},
});
@ -147,7 +147,7 @@ describe('ServiceCollection', () => {
['a'],
({ a }, b) => ({ ...a, ...b })
);
await rejects(services.makeInstance('b'));
assert.throws(() => services.makeInstance('b'));
});
});
});

Просмотреть файл

@ -63,17 +63,14 @@ export async function makeApp(
): Promise<[app: express.Application, listen: (callback?: () => void) => http.Server]> {
const configOverrides: Partial<Options> = {};
const port = (await Promise.all(['port', 'PORT'].map((key) => configuration.string([key])))).find(
(port) => port !== undefined
);
const port = ['port', 'PORT'].map((key) => configuration.string([key])).find((port) => port !== undefined);
if (port !== undefined) {
configOverrides.port = port;
}
const validatedOptions = TypedOptions.check(Object.assign({}, defaultOptions, configOverrides, options));
const { adapter, bot, customAdapters } = await services.mustMakeInstances<{
const { adapter, bot, customAdapters } = services.mustMakeInstances<{
adapter: BotFrameworkAdapter;
bot: ActivityHandlerBase;
customAdapters: Map<string, BotFrameworkAdapter>;
@ -125,7 +122,8 @@ export async function makeApp(
);
server.on('upgrade', async (req, socket, head) => {
const adapter = await services.mustMakeInstance<BotFrameworkAdapter>('adapter');
const adapter = services.mustMakeInstance<BotFrameworkAdapter>('adapter');
adapter.useWebSocket(req, socket, head, async (context) => {
await bot.run(context);
});

Просмотреть файл

@ -32,10 +32,7 @@ const defaultOptions: Options = {
async function resolveOptions(options: Partial<Options>, configuration: Configuration): Promise<Options> {
const configOverrides: Partial<Options> = {};
const port = (await Promise.all(['port', 'PORT'].map((key) => configuration.string([key])))).find(
(port) => port !== undefined
);
const port = ['port', 'PORT'].map((key) => configuration.string([key])).find((port) => port !== undefined);
if (port !== undefined) {
configOverrides.port = port;
}
@ -77,14 +74,13 @@ export async function makeServer(
configuration: Configuration,
options: Partial<Options> = {}
): Promise<restify.Server> {
const [{ adapter, bot, customAdapters }, resolvedOptions] = await Promise.all([
services.mustMakeInstances<{
adapter: BotFrameworkAdapter;
bot: ActivityHandlerBase;
customAdapters: Map<string, BotFrameworkAdapter>;
}>('adapter', 'bot', 'customAdapters'),
resolveOptions(options, configuration),
]);
const { adapter, bot, customAdapters } = services.mustMakeInstances<{
adapter: BotFrameworkAdapter;
bot: ActivityHandlerBase;
customAdapters: Map<string, BotFrameworkAdapter>;
}>('adapter', 'bot', 'customAdapters');
const resolvedOptions = await resolveOptions(options, configuration);
const server = restify.createServer();
@ -122,7 +118,8 @@ export async function makeServer(
});
server.on('upgrade', async (req, socket, head) => {
const adapter = await services.mustMakeInstance<BotFrameworkAdapter>('adapter');
const adapter = services.mustMakeInstance<BotFrameworkAdapter>('adapter');
adapter.useWebSocket(req, socket, head, async (context) => {
await bot.run(context);
});

Просмотреть файл

@ -41,6 +41,11 @@ export class Configuration implements CoreConfiguration {
* @returns the value, or undefined
*/
get(path: string[]): unknown | undefined {
// Note: empty path should yield the entire configuration
if (!path.length) {
return this.provider.get();
}
return this.provider.get(this.key(path));
}

Просмотреть файл

@ -2,14 +2,14 @@
// Licensed under the MIT License.
import { Configuration } from './configuration';
import { FolderResourceProvider, ResourceExplorer } from 'botbuilder-dialogs-declarative';
import { ComponentDeclarativeTypes, FolderResourceProvider, ResourceExplorer } from 'botbuilder-dialogs-declarative';
import { ok } from 'assert';
export class ConfigurationResourceExporer extends ResourceExplorer {
private readonly folderResourceProvider: FolderResourceProvider;
constructor(configuration: Configuration) {
super();
constructor(configuration: Configuration, declarativeTypes: ComponentDeclarativeTypes[]) {
super({ declarativeTypes });
const applicationRoot = configuration.string(['applicationRoot']);
ok(applicationRoot);

Просмотреть файл

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { DialogManager } from 'botbuilder-dialogs';
import { DialogManager, MemoryScope, PathResolver } from 'botbuilder-dialogs';
import { ResourceExplorer } from 'botbuilder-dialogs-declarative';
import {
@ -31,7 +31,9 @@ export class CoreBot extends ActivityHandler {
skillConversationIdFactory: SkillConversationIdFactoryBase,
botTelemetryClient: BotTelemetryClient,
defaultLocale: string,
defaultRootDialog: string
defaultRootDialog: string,
memoryScopes: MemoryScope[],
pathResolvers: PathResolver[]
) {
super();
@ -50,6 +52,21 @@ export class CoreBot extends ActivityHandler {
SkillExtensions.useSkillConversationIdFactory(dialogManager, skillConversationIdFactory);
useTelemetry(dialogManager, botTelemetryClient);
/* TODO(jgummersall) reconcile:
* _dialogManager.InitialTurnState.Set(botFrameworkClient);
* _dialogManager.InitialTurnState.Set(conversationIdfactory);
* _dialogManager.InitialTurnState.Set(_userState); (handled by useBotState?)
* _dialogManager.InitialTurnState.Set(_conversationState); (handled by useBotState?)
*/
if (memoryScopes.length) {
dialogManager.initialTurnState.set('memoryScopes', memoryScopes);
}
if (pathResolvers.length) {
dialogManager.initialTurnState.set('pathResolvers', pathResolvers);
}
this.onTurn(async (turnContext) => {
await dialogManager.onTurn(turnContext);
await conversationState.saveChanges(turnContext, false);

Просмотреть файл

@ -6,15 +6,16 @@ import fs from 'fs';
import path from 'path';
import { Configuration } from './configuration';
import { AdaptiveComponentRegistration } from 'botbuilder-dialogs-adaptive';
import { DialogsBotComponent, MemoryScope, PathResolver } from 'botbuilder-dialogs';
import { AdaptiveBotComponent, LanguageGenerationBotComponent } from 'botbuilder-dialogs-adaptive';
import { ApplicationInsightsTelemetryClient, TelemetryInitializerMiddleware } from 'botbuilder-applicationinsights';
import { BlobsStorage, BlobsTranscriptStore } from 'botbuilder-azure-blobs';
import { ConfigurationResourceExporer } from './configurationResourceExplorer';
import { CoreBot } from './coreBot';
import { CoreBotAdapter } from './coreBotAdapter';
import { CosmosDbPartitionedStorage } from 'botbuilder-azure';
import { LuisComponentRegistration, QnAMakerComponentRegistration } from 'botbuilder-ai';
import { ResourceExplorer } from 'botbuilder-dialogs-declarative';
import { ComponentDeclarativeTypes, ResourceExplorer } from 'botbuilder-dialogs-declarative';
import { LuisBotComponent, QnAMakerBotComponent } from 'botbuilder-ai';
import { ServiceCollection } from 'botbuilder-runtime-core';
import {
@ -28,11 +29,9 @@ import {
ActivityHandlerBase,
BotAdapter,
BotComponent,
isBotComponent,
BotFrameworkAdapter,
BotTelemetryClient,
ChannelServiceHandler,
ComponentRegistration,
ConsoleTranscriptLogger,
ConversationState,
InspectionMiddleware,
@ -51,6 +50,7 @@ import {
TelemetryLoggerMiddleware,
TranscriptLoggerMiddleware,
UserState,
assertBotComponent,
} from 'botbuilder';
function addFeatures(services: ServiceCollection, configuration: Configuration): void {
@ -237,6 +237,8 @@ function addCoreBot(services: ServiceCollection, configuration: Configuration):
{
botTelemetryClient: BotTelemetryClient;
conversationState: ConversationState;
memoryScopes: MemoryScope[];
pathResolvers: PathResolver[];
resourceExplorer: ResourceExplorer;
skillClient: SkillHttpClient;
skillConversationIdFactory: SkillConversationIdFactoryBase;
@ -245,12 +247,14 @@ function addCoreBot(services: ServiceCollection, configuration: Configuration):
>(
'bot',
[
'resourceExplorer',
'userState',
'botTelemetryClient',
'conversationState',
'memoryScopes',
'pathResolvers',
'resourceExplorer',
'skillClient',
'skillConversationIdFactory',
'botTelemetryClient',
'userState',
],
(dependencies) =>
new CoreBot(
@ -261,7 +265,9 @@ function addCoreBot(services: ServiceCollection, configuration: Configuration):
dependencies.skillConversationIdFactory,
dependencies.botTelemetryClient,
configuration.string(['defaultLocale']) ?? 'en-US',
configuration.string(['defaultRootDialog']) ?? 'main.dialog'
configuration.string(['defaultRootDialog']) ?? 'main.dialog',
dependencies.memoryScopes,
dependencies.pathResolvers
)
);
@ -292,21 +298,22 @@ function addCoreBot(services: ServiceCollection, configuration: Configuration):
);
}
async function addBotComponents(services: ServiceCollection, configuration: Configuration): Promise<void> {
const loadBotComponent = async (name: string): Promise<BotComponent | undefined> => {
try {
const DefaultExport = (await import(name))?.default;
if (DefaultExport) {
const instance = new DefaultExport();
if (isBotComponent(instance)) {
return instance;
}
}
} catch (_err) {
// no-op
async function addSettingsBotComponents(services: ServiceCollection, configuration: Configuration): Promise<void> {
const loadBotComponent = async (name: string): Promise<BotComponent> => {
const Export = await import(name);
if (!Export) {
throw new Error(`Unable to import ${name}`);
}
return undefined;
const DefaultExport = Export.default;
if (!DefaultExport) {
throw new Error(`${name} has no default export`);
}
const instance = new DefaultExport();
assertBotComponent(instance, [`import(${name})`, 'default']);
return instance;
};
const components =
@ -320,13 +327,20 @@ async function addBotComponents(services: ServiceCollection, configuration: Conf
)
) ?? [];
for (const { name, settingsPrefix } of components) {
const botComponent = await loadBotComponent(name);
if (!botComponent) {
throw new TypeError(`Unable to load ${botComponent} component`);
}
const errs: Error[] = [];
await Promise.resolve(botComponent.configureServices(services, configuration.bind([settingsPrefix ?? name])));
for (const { name, settingsPrefix } of components) {
try {
const botComponent = await loadBotComponent(name);
botComponent.configureServices(services, configuration.bind([settingsPrefix ?? name]));
} catch (err) {
errs.push(err);
}
}
if (errs.length) {
throw new Error(errs.map((err) => `[${err}]`).join(', '));
}
}
@ -346,25 +360,21 @@ async function normalizeConfiguration(configuration: Configuration, applicationR
);
}
function registerAdaptiveComponents(services: ServiceCollection): void {
services.composeFactory<typeof ComponentRegistration>('componentRegistration', (componentRegistration) => {
componentRegistration.add(new AdaptiveComponentRegistration());
return componentRegistration;
});
function registerAdaptiveComponents(services: ServiceCollection, configuration: Configuration): void {
new AdaptiveBotComponent().configureServices(services, configuration);
new LanguageGenerationBotComponent().configureServices(services, configuration);
}
function registerLuisComponents(services: ServiceCollection): void {
services.composeFactory<typeof ComponentRegistration>('componentRegistration', (componentRegistration) => {
componentRegistration.add(new LuisComponentRegistration());
return componentRegistration;
});
function registerDialogsComponents(services: ServiceCollection, configuration: Configuration): void {
new DialogsBotComponent().configureServices(services, configuration);
}
function registerQnAComponents(services: ServiceCollection): void {
services.composeFactory<typeof ComponentRegistration>('componentRegistration', (componentRegistration) => {
componentRegistration.add(new QnAMakerComponentRegistration());
return componentRegistration;
});
function registerLuisComponents(services: ServiceCollection, configuration: Configuration): void {
new LuisBotComponent().configureServices(services, configuration);
}
function registerQnAComponents(services: ServiceCollection, configuration: Configuration): void {
new QnAMakerBotComponent().configureServices(services, configuration);
}
/**
@ -413,20 +423,23 @@ export async function getRuntimeServices(
await normalizeConfiguration(configuration, applicationRoot);
const services = new ServiceCollection({
componentRegistration: ComponentRegistration,
customAdapters: new Map(),
declarativeTypes: [],
memoryScopes: [],
middlewares: new MiddlewareSet(),
pathResolvers: [],
});
services.addFactory(
services.addFactory<ResourceExplorer, { declarativeTypes: ComponentDeclarativeTypes[] }>(
'resourceExplorer',
['componentRegistration'], // implicit dependency
() => new ConfigurationResourceExporer(configuration)
['declarativeTypes'],
({ declarativeTypes }) => new ConfigurationResourceExporer(configuration, declarativeTypes)
);
registerAdaptiveComponents(services);
registerLuisComponents(services);
registerQnAComponents(services);
registerAdaptiveComponents(services, configuration);
registerDialogsComponents(services, configuration);
registerLuisComponents(services, configuration);
registerQnAComponents(services, configuration);
const runtimeSettings = configuration.bind(['runtimeSettings']);
@ -435,7 +448,7 @@ export async function getRuntimeServices(
addSkills(services, runtimeSettings.bind(['skills']));
addStorage(services, configuration);
addTelemetry(services, runtimeSettings.bind(['telemetry']));
await addBotComponents(services, configuration);
await addSettingsBotComponents(services, configuration);
return [services, configuration];
}

Просмотреть файл

@ -12,19 +12,19 @@ describe('getRuntimeServices', () => {
it('works', async () => {
const [services] = await getRuntimeServices(__dirname, __dirname);
ok(services);
ok(await services.makeInstances());
ok(services.makeInstances());
});
it('works with preset configuration', async () => {
const [services] = await getRuntimeServices(__dirname, new Configuration());
ok(services);
ok(await services.makeInstances());
ok(services.makeInstances());
});
it('supports bot components and late binding configuration', async () => {
class MyComponent extends BotComponent {
configureServices(services: ServiceCollection, configuration: CoreConfiguration): void {
services.composeFactory<Map<string, BotFrameworkAdapter>>('customAdapters', async (customAdapters) => {
services.composeFactory<Map<string, BotFrameworkAdapter>>('customAdapters', (customAdapters) => {
const name = configuration.get(['customAdapter', 'name']);
ok(typeof name === 'string');
@ -43,7 +43,7 @@ describe('getRuntimeServices', () => {
configuration.set(['customAdapter', 'name'], 'foo');
const customAdapter = await services.mustMakeInstance<Map<string, BotFrameworkAdapter>>('customAdapters');
const customAdapter = services.mustMakeInstance<Map<string, BotFrameworkAdapter>>('customAdapters');
ok(customAdapter.get('foo'));
});
@ -52,7 +52,7 @@ describe('getRuntimeServices', () => {
const [services] = await getRuntimeServices(__dirname, __dirname);
ok(services);
const storage = await services.mustMakeInstance('storage');
const storage = services.mustMakeInstance('storage');
ok(storage instanceof MemoryStorage);
});
@ -69,7 +69,7 @@ describe('getRuntimeServices', () => {
const [services] = await getRuntimeServices(__dirname, configuration);
ok(services);
const storage = await services.mustMakeInstance('storage');
const storage = services.mustMakeInstance('storage');
ok(storage instanceof BlobsStorage);
});
@ -88,7 +88,7 @@ describe('getRuntimeServices', () => {
const [services] = await getRuntimeServices(__dirname, configuration);
ok(services);
const storage = await services.mustMakeInstance('storage');
const storage = services.mustMakeInstance('storage');
ok(storage instanceof CosmosDbPartitionedStorage);
});
});

Просмотреть файл

@ -9428,10 +9428,10 @@ ora@^4.0.3:
strip-ansi "^6.0.0"
wcwidth "^1.0.1"
orchestrator-core@4.12.0-preview:
version "4.12.0-preview"
resolved "https://registry.yarnpkg.com/orchestrator-core/-/orchestrator-core-4.12.0-preview.tgz#e16703ff0fe45a96cd7b637fcec7697448584a36"
integrity sha512-RHQM5UK7xZuV9eN+NJKv/iGKBeQ/Pvxkki1j2Bgm1pq845Icor51MrlJKmAeJSIVxIUY0r4JBBNulLfq3I4UPA==
orchestrator-core@next:
version "4.13.0-dev.20210325.421845fh"
resolved "https://registry.yarnpkg.com/orchestrator-core/-/orchestrator-core-4.13.0-dev.20210325.421845fh.tgz#8d7481c7a48d3c144fc1611bb735c2b7e507fa1a"
integrity sha512-wnWEuWC4iR78F7j1p0R7v0YfKIv21atpmz0gTIcvfT7WrQudAFIlmp2uRUUx3AFdV+SngZiLBxTZ7lOKnp/Q9Q==
dependencies:
bindings "1.2.1"
node-addon-api "^3.0.0"
@ -9574,11 +9574,6 @@ p-map@^4.0.0:
dependencies:
aggregate-error "^3.0.0"
p-reduce@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a"
integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==
p-timeout@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038"