UNPKG

@microsoft/agents-hosting-teams

Version:

Microsoft 365 Agents SDK for JavaScript

444 lines 22.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TeamsApplication = void 0; /** * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ const agents_activity_1 = require("@microsoft/agents-activity"); const agents_hosting_1 = require("@microsoft/agents-hosting"); const teamsInfo_1 = require("../teamsInfo"); const parsers_1 = require("../parsers"); const adaptive_cards_actions_1 = require("./adaptive-cards-actions"); const messages_1 = require("./messages"); const messaging_extension_1 = require("./messaging-extension"); const meeting_1 = require("./meeting"); const task_1 = require("./task"); const logger = (0, agents_hosting_1.debug)('agents:teams-application'); /** * Represents a Teams application that extends the AgentApplication class. * Provides various functionalities for handling Teams-specific events, messages, and interactions. * @template TState - The type of the turn state. */ class TeamsApplication extends agents_hosting_1.AgentApplication { /** * Initializes a new instance of the TeamsApplication class. * @param options - Partial options for configuring the Teams application. */ constructor(options) { super(); /** * Routes for handling invoke activities. */ this._invokeRoutes = []; this._teamsOptions = { ...super.options, removeRecipientMention: (options === null || options === void 0 ? void 0 : options.removeRecipientMention) !== undefined ? options.removeRecipientMention : true, taskModules: options === null || options === void 0 ? void 0 : options.taskModules }; if ((options === null || options === void 0 ? void 0 : options.storage) && (options === null || options === void 0 ? void 0 : options.authorization)) { this._teamsAuthManager = new agents_hosting_1.Authorization(this.options.storage, this.options.authorization); } this._adaptiveCards = new adaptive_cards_actions_1.AdaptiveCardsActions(this); this._messages = new messages_1.Messages(this); this._messageExtensions = new messaging_extension_1.MessageExtensions(this); this._meetings = new meeting_1.Meetings(this); this._taskModules = new task_1.TaskModules(this); } /** * Gets the Teams application options. */ get teamsOptions() { return this._teamsOptions; } /** * Gets the task modules handler. */ get taskModules() { return this._taskModules; } /** * Gets the adaptive cards actions handler. */ get adaptiveCards() { return this._adaptiveCards; } /** * Gets the messages handler. */ get messages() { return this._messages; } /** * Gets the messaging extensions handler. */ get messageExtensions() { return this._messageExtensions; } /** * Gets the meetings handler. */ get meetings() { return this._meetings; } /** * Gets the Teams OAuth flow manager. * @throws Error if no authentication options were configured. */ get teamsAuthManager() { if (!this._teamsAuthManager) { throw new Error('The Application.authentication property is unavailable because no authentication options were configured.'); } return this._teamsAuthManager; } /** * Adds a route to the application. * @param selector - The route selector. * @param handler - The route handler. * @param isInvokeRoute - Whether the route is for invoke activities. */ addRoute(selector, handler, isInvokeRoute = false) { if (isInvokeRoute) { this._invokeRoutes.push({ selector, handler }); } else { this._routes.push({ selector, handler }); } return this; } /** * Runs the application for the given turn context. * @param turnContext - The turn context. */ async run(turnContext) { await this.runInternalTeams(turnContext); } async runInternalTeams(turnContext) { return await this.startLongRunningCall(turnContext, async (context) => { var _a; this.startTypingTimer(context); try { if (this._teamsOptions.removeRecipientMention && context.activity.type === agents_activity_1.ActivityTypes.Message) { context.activity.text = context.activity.removeRecipientMention(); } const { storage, turnStateFactory } = this._teamsOptions; const state = turnStateFactory(); await state.load(context, storage); if (!(await this.callEventHandlers(context, state, this._beforeTurn))) { await state.save(context, storage); return false; } if (Array.isArray(this._teamsOptions.fileDownloaders) && this._teamsOptions.fileDownloaders.length > 0) { const inputFiles = (_a = state.temp.inputFiles) !== null && _a !== void 0 ? _a : []; for (let i = 0; i < this._teamsOptions.fileDownloaders.length; i++) { const files = await this._teamsOptions.fileDownloaders[i].downloadFiles(context, state); inputFiles.push(...files); } state.temp.inputFiles = inputFiles; } if (context.activity.type === agents_activity_1.ActivityTypes.Invoke) { for (let i = 0; i < this._invokeRoutes.length; i++) { const route = this._invokeRoutes[i]; if (await route.selector(context)) { await route.handler(context, state); if (await this.callEventHandlers(context, state, this._afterTurn)) { await state.save(context, storage); } return true; } } } for (let i = 0; i < this._routes.length; i++) { const route = this._routes[i]; if (await route.selector(context)) { await route.handler(context, state); if (await this.callEventHandlers(context, state, this._afterTurn)) { await state.save(context, storage); } return true; } } if (await this.callEventHandlers(context, state, this._afterTurn)) { await state.save(context, storage); } return false; } catch (err) { logger.error(err); throw err; } finally { this.stopTypingTimer(); } }); } /** * Handles conversation update events. * @param event - The conversation update event. * @param handler - The handler for the event. */ onConversationUpdate(event, handler) { if (typeof handler !== 'function') { throw new Error(`ConversationUpdate 'handler' for ${event} is ${typeof handler}. Type of 'handler' must be a function.`); } const selector = this.createTeamsConversationUpdateSelector(event); this.addRoute(selector, handler); return this; } /** * Handles message event updates. * @param event - The message event. * @param handler - The handler for the event. */ onMessageEventUpdate(event, handler) { if (typeof handler !== 'function') { throw new Error(`MessageUpdate 'handler' for ${event} is ${typeof handler}. Type of 'handler' must be a function.`); } const selector = this.createMessageEventUpdateSelector(event); this.addRoute(selector, handler); return this; } /** * Handles message reactions. * @param event - The message reaction event. * @param handler - The handler for the event. */ onMessageReactions(event, handler) { const selector = this.createMessageReactionSelector(event); this.addRoute(selector, handler); return this; } /** * Handles file consent accept actions. * @param handler - The handler for the file consent accept action. */ fileConsentAccept(handler) { const selector = (context) => { const valueAction = (0, parsers_1.parseValueAction)(context.activity.value); return Promise.resolve(context.activity.type === agents_activity_1.ActivityTypes.Invoke && context.activity.name === 'fileConsent/invoke' && valueAction === 'accept'); }; const handlerWrapper = async (context, state) => { await handler(context, state, context.activity.value); await context.sendActivity({ type: agents_activity_1.ActivityTypes.InvokeResponse, value: { status: 200 } }); }; this.addRoute(selector, handlerWrapper, true); return this; } /** * Handles file consent decline actions. * @param handler - The handler for the file consent decline action. */ fileConsentDecline(handler) { const selector = (context) => { const valueAction = (0, parsers_1.parseValueAction)(context.activity.value); return Promise.resolve(context.activity.type === agents_activity_1.ActivityTypes.Invoke && context.activity.name === 'fileConsent/invoke' && valueAction === 'decline'); }; const handlerWrapper = async (context, state) => { await handler(context, state, context.activity.value); await context.sendActivity({ type: agents_activity_1.ActivityTypes.InvokeResponse, value: { status: 200 } }); }; this.addRoute(selector, handlerWrapper, true); return this; } /** * Handles handoff actions. * @param handler - The handler for the handoff action. */ onHandoff(handler) { const selector = (context) => { return Promise.resolve(context.activity.type === agents_activity_1.ActivityTypes.Invoke && context.activity.name === 'handoff/action'); }; const handlerWrapper = async (context, state) => { const valueContinuation = (0, parsers_1.parseValueContinuation)(context.activity.value); await handler(context, state, valueContinuation); await context.sendActivity({ type: agents_activity_1.ActivityTypes.InvokeResponse, value: { status: 200 } }); }; this.addRoute(selector, handlerWrapper, true); return this; } /** * Gets the channels of a team. * @param context - The turn context, conversation reference, or activity. */ async getTeamChannels(context) { var _a; let teamsChannels = []; const reference = this.getConversationReference(context); if (((_a = reference.conversation) === null || _a === void 0 ? void 0 : _a.conversationType) === 'channel') { await this.continueConversationAsync(reference, async (ctx) => { var _a, _b, _c, _d, _e, _f, _g, _h; const teamId = (_d = (_c = (_b = (_a = ctx.activity) === null || _a === void 0 ? void 0 : _a.channelData) === null || _b === void 0 ? void 0 : _b.team) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : (((_f = (_e = ctx.activity) === null || _e === void 0 ? void 0 : _e.conversation) === null || _f === void 0 ? void 0 : _f.name) === undefined ? (_h = (_g = ctx.activity) === null || _g === void 0 ? void 0 : _g.conversation) === null || _h === void 0 ? void 0 : _h.id : undefined); if (teamId) { teamsChannels = await teamsInfo_1.TeamsInfo.getTeamChannels(ctx, teamId); } }); } return teamsChannels; } /** * Gets the details of a team. * @param context - The turn context, conversation reference, or activity. */ async getTeamDetails(context) { var _a; let teamDetails; const reference = this.getConversationReference(context); if (((_a = reference.conversation) === null || _a === void 0 ? void 0 : _a.conversationType) === 'channel') { await this.continueConversationAsync(reference, async (ctx) => { var _a, _b, _c, _d, _e, _f, _g, _h; const teamId = (_d = (_c = (_b = (_a = ctx.activity) === null || _a === void 0 ? void 0 : _a.channelData) === null || _b === void 0 ? void 0 : _b.team) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : (((_f = (_e = ctx.activity) === null || _e === void 0 ? void 0 : _e.conversation) === null || _f === void 0 ? void 0 : _f.name) === undefined ? (_h = (_g = ctx.activity) === null || _g === void 0 ? void 0 : _g.conversation) === null || _h === void 0 ? void 0 : _h.id : undefined); if (teamId) { teamDetails = await teamsInfo_1.TeamsInfo.getTeamDetails(ctx, teamId); } }); } return teamDetails; } /** * Gets the paged members of a team. * @param context - The turn context or conversation reference. * @param pageSize - The number of members per page. * @param continuationToken - The continuation token for pagination. */ async getPagedMembers(context, pageSize, continuationToken) { let pagedMembers = { members: [], continuationToken: '' }; await this.continueConversationAsync(context, async (ctx) => { pagedMembers = await teamsInfo_1.TeamsInfo.getPagedMembers(ctx, pageSize, continuationToken); }); return pagedMembers; } /** * Handles Teams read receipt events. * @param handler - The handler for the read receipt event. */ onTeamsReadReceipt(handler) { const selector = (context) => { return Promise.resolve(context.activity.type === agents_activity_1.ActivityTypes.Event && context.activity.channelId === 'msteams' && context.activity.name === 'application/vnd.microsoft/readReceipt'); }; const handlerWrapper = (context, state) => { const readReceiptInfo = context.activity.value; return handler(context, state, readReceiptInfo); }; this.addRoute(selector, handlerWrapper); return this; } createMessageEventUpdateSelector(event) { switch (event) { case 'editMessage': return (context) => { var _a, _b, _c; return Promise.resolve(((_a = context === null || context === void 0 ? void 0 : context.activity) === null || _a === void 0 ? void 0 : _a.type) === agents_activity_1.ActivityTypes.MessageUpdate && ((_c = (_b = context === null || context === void 0 ? void 0 : context.activity) === null || _b === void 0 ? void 0 : _b.channelData) === null || _c === void 0 ? void 0 : _c.eventType) === event); }; case 'softDeleteMessage': return (context) => { var _a, _b, _c; return Promise.resolve(((_a = context === null || context === void 0 ? void 0 : context.activity) === null || _a === void 0 ? void 0 : _a.type) === agents_activity_1.ActivityTypes.MessageDelete && ((_c = (_b = context === null || context === void 0 ? void 0 : context.activity) === null || _b === void 0 ? void 0 : _b.channelData) === null || _c === void 0 ? void 0 : _c.eventType) === event); }; case 'undeleteMessage': return (context) => { var _a, _b, _c; return Promise.resolve(((_a = context === null || context === void 0 ? void 0 : context.activity) === null || _a === void 0 ? void 0 : _a.type) === agents_activity_1.ActivityTypes.MessageUpdate && ((_c = (_b = context === null || context === void 0 ? void 0 : context.activity) === null || _b === void 0 ? void 0 : _b.channelData) === null || _c === void 0 ? void 0 : _c.eventType) === event); }; default: throw new Error(`Invalid TeamsMessageEvent type: ${event}`); } } createMessageReactionSelector(event) { switch (event) { case 'reactionsAdded': return (context) => { var _a, _b; return Promise.resolve(((_a = context === null || context === void 0 ? void 0 : context.activity) === null || _a === void 0 ? void 0 : _a.type) === agents_activity_1.ActivityTypes.MessageReaction && Array.isArray((_b = context === null || context === void 0 ? void 0 : context.activity) === null || _b === void 0 ? void 0 : _b.reactionsAdded) && context.activity.reactionsAdded.length > 0); }; case 'reactionsRemoved': return (context) => { var _a, _b; return Promise.resolve(((_a = context === null || context === void 0 ? void 0 : context.activity) === null || _a === void 0 ? void 0 : _a.type) === agents_activity_1.ActivityTypes.MessageReaction && Array.isArray((_b = context === null || context === void 0 ? void 0 : context.activity) === null || _b === void 0 ? void 0 : _b.reactionsRemoved) && context.activity.reactionsRemoved.length > 0); }; } } getConversationReference(context) { let reference; if (typeof context.activity === 'object') { reference = context.activity.getConversationReference(); } else if (typeof context.type === 'string') { reference = context.getConversationReference(); } else { reference = context; } return reference; } createTeamsConversationUpdateSelector(event) { switch (event) { case 'channelCreated': case 'channelDeleted': case 'channelRenamed': case 'channelRestored': return (context) => { var _a, _b, _c, _d, _e, _f; return Promise.resolve(((_a = context === null || context === void 0 ? void 0 : context.activity) === null || _a === void 0 ? void 0 : _a.type) === agents_activity_1.ActivityTypes.ConversationUpdate && ((_c = (_b = context === null || context === void 0 ? void 0 : context.activity) === null || _b === void 0 ? void 0 : _b.channelData) === null || _c === void 0 ? void 0 : _c.eventType) === event && ((_e = (_d = context === null || context === void 0 ? void 0 : context.activity) === null || _d === void 0 ? void 0 : _d.channelData) === null || _e === void 0 ? void 0 : _e.channel) && ((_f = context.activity.channelData) === null || _f === void 0 ? void 0 : _f.team)); }; case 'membersAdded': return (context) => { var _a, _b; return Promise.resolve(((_a = context === null || context === void 0 ? void 0 : context.activity) === null || _a === void 0 ? void 0 : _a.type) === agents_activity_1.ActivityTypes.ConversationUpdate && Array.isArray((_b = context === null || context === void 0 ? void 0 : context.activity) === null || _b === void 0 ? void 0 : _b.membersAdded) && context.activity.membersAdded.length > 0); }; case 'membersRemoved': return (context) => { var _a, _b; return Promise.resolve(((_a = context === null || context === void 0 ? void 0 : context.activity) === null || _a === void 0 ? void 0 : _a.type) === agents_activity_1.ActivityTypes.ConversationUpdate && Array.isArray((_b = context === null || context === void 0 ? void 0 : context.activity) === null || _b === void 0 ? void 0 : _b.membersRemoved) && context.activity.membersRemoved.length > 0); }; case 'teamRenamed': case 'teamDeleted': case 'teamHardDeleted': case 'teamArchived': case 'teamUnarchived': case 'teamRestored': return (context) => { var _a, _b, _c, _d, _e; return Promise.resolve(((_a = context === null || context === void 0 ? void 0 : context.activity) === null || _a === void 0 ? void 0 : _a.type) === agents_activity_1.ActivityTypes.ConversationUpdate && ((_c = (_b = context === null || context === void 0 ? void 0 : context.activity) === null || _b === void 0 ? void 0 : _b.channelData) === null || _c === void 0 ? void 0 : _c.eventType) === event && ((_e = (_d = context === null || context === void 0 ? void 0 : context.activity) === null || _d === void 0 ? void 0 : _d.channelData) === null || _e === void 0 ? void 0 : _e.team)); }; default: return (context) => { var _a, _b, _c; return Promise.resolve(((_a = context === null || context === void 0 ? void 0 : context.activity) === null || _a === void 0 ? void 0 : _a.type) === agents_activity_1.ActivityTypes.ConversationUpdate && ((_c = (_b = context === null || context === void 0 ? void 0 : context.activity) === null || _b === void 0 ? void 0 : _b.channelData) === null || _c === void 0 ? void 0 : _c.eventType) === event); }; } } } exports.TeamsApplication = TeamsApplication; //# sourceMappingURL=teamsApplication.js.map