UNPKG

@microsoft/teams-ai

Version:

SDK focused on building AI based applications for Microsoft Teams.

275 lines 14.4 kB
"use strict"; /** * @module teams-ai */ /** * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.TaskModules = exports.TaskModuleInvokeNames = void 0; const botbuilder_1 = require("botbuilder"); var TaskModuleInvokeNames; (function (TaskModuleInvokeNames) { TaskModuleInvokeNames["CONFIG_FETCH_INVOKE_NAME"] = "config/fetch"; TaskModuleInvokeNames["CONFIG_SUBMIT_INVOKE_NAME"] = "config/submit"; TaskModuleInvokeNames["FETCH_INVOKE_NAME"] = "task/fetch"; TaskModuleInvokeNames["SUBMIT_INVOKE_NAME"] = "task/submit"; TaskModuleInvokeNames["DEFAULT_TASK_DATA_FILTER"] = "verb"; })(TaskModuleInvokeNames || (exports.TaskModuleInvokeNames = TaskModuleInvokeNames = {})); /** * TaskModules class to enable fluent style registration of handlers related to Task Modules. * @template TState Type of the turn state object being persisted. */ class TaskModules { _app; /** * Creates a new instance of the TaskModules class. * @param {Application} app Top level application class to register handlers with. */ constructor(app) { this._app = app; } /** * Registers a handler to process the initial fetch of the task module. * @remarks * Handlers should respond with either an initial TaskInfo object or a string containing * a message to display to the user. * @template TData Optional. Type of the data object being passed to the handler. * @param {string | RegExp | RouteSelector | string[] | RegExp[] | RouteSelector[]} verb - Name of the verb(s) to register the handler for. * @param {(context: TurnContext, state: TState, data: TData) => Promise<TaskModuleTaskInfo | string>} handler - Function to call when the handler is triggered. * @param {TurnContext} handler.context - Context for the current turn of conversation with the user. * @param {TState} handler.state - Current state of the turn. * @param {TData} handler.data - Data object passed to the handler. * @returns {Application<TState>} The application for chaining purposes. */ fetch(verb, handler) { (Array.isArray(verb) ? verb : [verb]).forEach((v) => { const { DEFAULT_TASK_DATA_FILTER, FETCH_INVOKE_NAME } = TaskModuleInvokeNames; const filterField = this._app.options.taskModules?.taskDataFilter ?? DEFAULT_TASK_DATA_FILTER; const selector = createTaskSelector(v, filterField, FETCH_INVOKE_NAME); this._app.addRoute(selector, async (context, state) => { if (context?.activity?.channelId === botbuilder_1.Channels.Msteams) { // Insure that we're in an invoke as expected if (context?.activity?.type !== botbuilder_1.ActivityTypes.Invoke || context?.activity?.name !== FETCH_INVOKE_NAME) { throw new Error(`Unexpected TaskModules.fetch() triggered for activity type: ${context?.activity?.type}`); } // Call handler and then check to see if an invoke response has already been added const result = await handler(context, state, context.activity.value?.data ?? {}); if (!context.turnState.get(botbuilder_1.INVOKE_RESPONSE_KEY)) { // Format invoke response let response; if (typeof result == 'string') { // Return message response = { task: { type: 'message', value: result } }; } else { // Return card response = { task: { type: 'continue', value: result } }; } // Queue up invoke response await context.sendActivity({ value: { body: response, status: 200 }, type: botbuilder_1.ActivityTypes.InvokeResponse }); } } }, true); }); return this._app; } /** * Registers a handler to process the submission of a task module. * @remarks * Handlers should respond with another TaskInfo object, message string, or `null` to indicate * the task is completed. * @template TData Optional. Type of the data object being passed to the handler. * @param {string | RegExp | RouteSelector | string[] | RegExp[] | RouteSelector[]} verb - Name of the verb(s) to register the handler for. * @param {(context: TurnContext, state: TState, data: TData) => Promise<TaskModuleTaskInfo | string | null | undefined>} handler - Function to call when the handler is triggered. * @param {TurnContext} handler.context - Context for the current turn of conversation with the user. * @param {TState} handler.state - Current state of the turn. * @param {TData} handler.data - Data object passed to the handler. * @returns {Application<TState>} The application for chaining purposes. */ submit(verb, handler) { (Array.isArray(verb) ? verb : [verb]).forEach((v) => { const { DEFAULT_TASK_DATA_FILTER, SUBMIT_INVOKE_NAME } = TaskModuleInvokeNames; const filterField = this._app.options.taskModules?.taskDataFilter ?? DEFAULT_TASK_DATA_FILTER; const selector = createTaskSelector(v, filterField, SUBMIT_INVOKE_NAME); this._app.addRoute(selector, async (context, state) => { if (context?.activity?.channelId === botbuilder_1.Channels.Msteams) { // Insure that we're in an invoke as expected if (context?.activity?.type !== botbuilder_1.ActivityTypes.Invoke || context?.activity?.name !== SUBMIT_INVOKE_NAME) { throw new Error(`Unexpected TaskModules.submit() triggered for activity type: ${context?.activity?.type}`); } // Call handler and then check to see if an invoke response has already been added const result = await handler(context, state, context.activity.value?.data ?? {}); if (!result) { await context.sendActivity({ value: { status: 200 }, type: botbuilder_1.ActivityTypes.InvokeResponse }); } if (!context.turnState.get(botbuilder_1.INVOKE_RESPONSE_KEY)) { // Format invoke response let response = undefined; if (typeof result == 'string') { // Return message response = { task: { type: 'message', value: result } }; } else if (typeof result == 'object') { // Return card response = { task: { type: 'continue', value: result } }; } // Queue up invoke response await context.sendActivity({ value: { body: response, status: 200 }, type: botbuilder_1.ActivityTypes.InvokeResponse }); } } }, true); }); return this._app; } /** * Registers a handler for fetching Teams config data for Auth or Task Modules * @template TData Optional. Type of the data object being passed to the handler. * @param {(context: TurnContext, state: TState, data: TData) => Promise<TaskModuleTaskInfo | string | null | undefined>} handler - Function to call when the handler is triggered. * @param {TurnContext} handler.context - Context for the current turn of conversation with the user. * @param {TState} handler.state - Current state of the turn. * @param {TData} handler.data - Data object passed to the handler. * @returns {Application<TState>} The application for chaining purposes. */ configFetch(handler) { const selector = (context) => { const { CONFIG_FETCH_INVOKE_NAME } = TaskModuleInvokeNames; return Promise.resolve(context?.activity?.type === botbuilder_1.ActivityTypes.Invoke && context?.activity?.name === CONFIG_FETCH_INVOKE_NAME); }; this._app.addRoute(selector, async (context, state) => { if (context?.activity?.channelId === botbuilder_1.Channels.Msteams) { // Call handler and then check to see if an invoke response has already been added const result = await handler(context, state, context.activity.value?.data ?? {}); let response; if (!context.turnState.get(botbuilder_1.INVOKE_RESPONSE_KEY)) { // Format invoke response) response = { responseType: 'config', config: result }; if ('cacheInfo' in result) { response.cacheInfo = result.cacheInfo; } // Queue up invoke response await context.sendActivity({ value: { body: response, status: 200 }, type: botbuilder_1.ActivityTypes.InvokeResponse }); } } }, true); return this._app; } /** * Registers a handler for submitting Teams config data for Auth or Task Modules * @template TData Optional. Type of the data object being passed to the handler. * @param {(context: TurnContext, state: TState, data: TData) => Promise<TaskModuleTaskInfo | string | null | undefined>} handler - Function to call when the handler is triggered. * @param {TurnContext} handler.context - Context for the current turn of conversation with the user. * @param {TState} handler.state - Current state of the turn. * @param {TData} handler.data - Data object passed to the handler. * @returns {Application<TState>} The application for chaining purposes. */ configSubmit(handler) { const selector = (context) => { const { CONFIG_SUBMIT_INVOKE_NAME } = TaskModuleInvokeNames; return Promise.resolve(context?.activity?.type === botbuilder_1.ActivityTypes.Invoke && context?.activity?.name === CONFIG_SUBMIT_INVOKE_NAME); }; this._app.addRoute(selector, async (context, state) => { if (context?.activity?.channelId === botbuilder_1.Channels.Msteams) { // Call handler and then check to see if an invoke response has already been added const result = await handler(context, state, context.activity.value?.data ?? {}); let response; if (!context.turnState.get(botbuilder_1.INVOKE_RESPONSE_KEY)) { // Format invoke response) response = { responseType: 'config', config: result }; if ('cacheInfo' in result) { response.cacheInfo = result.cacheInfo; } // Queue up invoke response await context.sendActivity({ value: { body: response, status: 200 }, type: botbuilder_1.ActivityTypes.InvokeResponse }); } } }, true); return this._app; } } exports.TaskModules = TaskModules; /** * Creates a route selector function for a given verb, filter field, and invoke name. * @param {string | RegExp | RouteSelector} verb - The verb to match. * @param {string} filterField - The field to use for filtering. * @param {string} invokeName - The name of the invoke action. * @returns {RouteSelector} The route selector function. * @private * @remarks * This function is used to create a route selector function for a given verb, filter field, and invoke name. * The route selector function is used to match incoming requests to the appropriate handler function. */ function createTaskSelector(verb, filterField, invokeName) { if (typeof verb == 'function') { // Return the passed in selector function return verb; } else if (verb instanceof RegExp) { // Return a function that matches the verb using a RegExp return (context) => { const isTeams = context.activity.channelId == botbuilder_1.Channels.Msteams; const isInvoke = context?.activity?.type == botbuilder_1.ActivityTypes.Invoke && context?.activity?.name == invokeName; const data = context?.activity?.value?.data; if (isInvoke && isTeams && typeof data == 'object' && typeof data[filterField] == 'string') { return Promise.resolve(verb.test(data[filterField])); } else { return Promise.resolve(false); } }; } else { // Return a function that attempts to match verb return (context) => { const isInvoke = context?.activity?.type == botbuilder_1.ActivityTypes.Invoke && context?.activity?.name == invokeName; const data = context?.activity?.value?.data; return Promise.resolve(isInvoke && typeof data == 'object' && data[filterField] == verb); }; } } //# sourceMappingURL=TaskModules.js.map