@microsoft/agents-hosting-extensions-msteams 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/README.md +147 -0
  2. package/dist/package.json +46 -0
  3. package/dist/src/activity-extensions/index.d.ts +1 -0
  4. package/dist/src/activity-extensions/index.js +8 -0
  5. package/dist/src/activity-extensions/index.js.map +1 -0
  6. package/dist/src/activity-extensions/teamsChannelData.d.ts +12 -0
  7. package/dist/src/activity-extensions/teamsChannelData.js +29 -0
  8. package/dist/src/activity-extensions/teamsChannelData.js.map +1 -0
  9. package/dist/src/app/index.d.ts +1 -0
  10. package/dist/src/app/index.js +20 -0
  11. package/dist/src/app/index.js.map +1 -0
  12. package/dist/src/app/teamsAppExtensions.d.ts +145 -0
  13. package/dist/src/app/teamsAppExtensions.js +201 -0
  14. package/dist/src/app/teamsAppExtensions.js.map +1 -0
  15. package/dist/src/channels/index.d.ts +1 -0
  16. package/dist/src/channels/index.js +20 -0
  17. package/dist/src/channels/index.js.map +1 -0
  18. package/dist/src/channels/teamsChannel.d.ts +100 -0
  19. package/dist/src/channels/teamsChannel.js +210 -0
  20. package/dist/src/channels/teamsChannel.js.map +1 -0
  21. package/dist/src/config/config.d.ts +37 -0
  22. package/dist/src/config/config.js +71 -0
  23. package/dist/src/config/config.js.map +1 -0
  24. package/dist/src/config/index.d.ts +1 -0
  25. package/dist/src/config/index.js +20 -0
  26. package/dist/src/config/index.js.map +1 -0
  27. package/dist/src/errorHelper.d.ts +19 -0
  28. package/dist/src/errorHelper.js +96 -0
  29. package/dist/src/errorHelper.js.map +1 -0
  30. package/dist/src/fileConsents/fileConsent.d.ts +37 -0
  31. package/dist/src/fileConsents/fileConsent.js +79 -0
  32. package/dist/src/fileConsents/fileConsent.js.map +1 -0
  33. package/dist/src/fileConsents/index.d.ts +1 -0
  34. package/dist/src/fileConsents/index.js +20 -0
  35. package/dist/src/fileConsents/index.js.map +1 -0
  36. package/dist/src/graphClientFactory.d.ts +10 -0
  37. package/dist/src/graphClientFactory.js +98 -0
  38. package/dist/src/graphClientFactory.js.map +1 -0
  39. package/dist/src/index.d.ts +20 -0
  40. package/dist/src/index.js +39 -0
  41. package/dist/src/index.js.map +1 -0
  42. package/dist/src/meetings/index.d.ts +1 -0
  43. package/dist/src/meetings/index.js +20 -0
  44. package/dist/src/meetings/index.js.map +1 -0
  45. package/dist/src/meetings/meeting.d.ts +84 -0
  46. package/dist/src/meetings/meeting.js +107 -0
  47. package/dist/src/meetings/meeting.js.map +1 -0
  48. package/dist/src/messageExtensions/index.d.ts +2 -0
  49. package/dist/src/messageExtensions/index.js +24 -0
  50. package/dist/src/messageExtensions/index.js.map +1 -0
  51. package/dist/src/messageExtensions/messageExtension.d.ts +133 -0
  52. package/dist/src/messageExtensions/messageExtension.js +326 -0
  53. package/dist/src/messageExtensions/messageExtension.js.map +1 -0
  54. package/dist/src/messageExtensions/messagingExtensionQuery.d.ts +87 -0
  55. package/dist/src/messageExtensions/messagingExtensionQuery.js +35 -0
  56. package/dist/src/messageExtensions/messagingExtensionQuery.js.map +1 -0
  57. package/dist/src/messages/index.d.ts +1 -0
  58. package/dist/src/messages/index.js +20 -0
  59. package/dist/src/messages/index.js.map +1 -0
  60. package/dist/src/messages/message.d.ts +67 -0
  61. package/dist/src/messages/message.js +129 -0
  62. package/dist/src/messages/message.js.map +1 -0
  63. package/dist/src/models/index.d.ts +1 -0
  64. package/dist/src/models/index.js +20 -0
  65. package/dist/src/models/index.js.map +1 -0
  66. package/dist/src/models/readReceiptInfo.d.ts +27 -0
  67. package/dist/src/models/readReceiptInfo.js +44 -0
  68. package/dist/src/models/readReceiptInfo.js.map +1 -0
  69. package/dist/src/taskModules/index.d.ts +1 -0
  70. package/dist/src/taskModules/index.js +20 -0
  71. package/dist/src/taskModules/index.js.map +1 -0
  72. package/dist/src/taskModules/taskModule.d.ts +42 -0
  73. package/dist/src/taskModules/taskModule.js +102 -0
  74. package/dist/src/taskModules/taskModule.js.map +1 -0
  75. package/dist/src/teams/index.d.ts +1 -0
  76. package/dist/src/teams/index.js +20 -0
  77. package/dist/src/teams/index.js.map +1 -0
  78. package/dist/src/teams/teamsTeam.d.ts +82 -0
  79. package/dist/src/teams/teamsTeam.js +172 -0
  80. package/dist/src/teams/teamsTeam.js.map +1 -0
  81. package/dist/src/teamsActivity.d.ts +15 -0
  82. package/dist/src/teamsActivity.js +5 -0
  83. package/dist/src/teamsActivity.js.map +1 -0
  84. package/dist/src/teamsActivityExtensions.d.ts +53 -0
  85. package/dist/src/teamsActivityExtensions.js +101 -0
  86. package/dist/src/teamsActivityExtensions.js.map +1 -0
  87. package/dist/src/teamsAgentExtension.d.ts +105 -0
  88. package/dist/src/teamsAgentExtension.js +178 -0
  89. package/dist/src/teamsAgentExtension.js.map +1 -0
  90. package/dist/src/teamsApiClientExtensions.d.ts +13 -0
  91. package/dist/src/teamsApiClientExtensions.js +41 -0
  92. package/dist/src/teamsApiClientExtensions.js.map +1 -0
  93. package/dist/src/teamsHeaderPropagation.d.ts +14 -0
  94. package/dist/src/teamsHeaderPropagation.js +35 -0
  95. package/dist/src/teamsHeaderPropagation.js.map +1 -0
  96. package/dist/src/teamsModelExtensions.d.ts +19 -0
  97. package/dist/src/teamsModelExtensions.js +38 -0
  98. package/dist/src/teamsModelExtensions.js.map +1 -0
  99. package/dist/src/teamsProactiveServiceEndpoints.d.ts +15 -0
  100. package/dist/src/teamsProactiveServiceEndpoints.js +21 -0
  101. package/dist/src/teamsProactiveServiceEndpoints.js.map +1 -0
  102. package/dist/src/teamsRouteHandler.d.ts +13 -0
  103. package/dist/src/teamsRouteHandler.js +18 -0
  104. package/dist/src/teamsRouteHandler.js.map +1 -0
  105. package/dist/src/teamsTurnContext.d.ts +64 -0
  106. package/dist/src/teamsTurnContext.js +113 -0
  107. package/dist/src/teamsTurnContext.js.map +1 -0
  108. package/package.json +46 -0
  109. package/src/activity-extensions/index.ts +4 -0
  110. package/src/activity-extensions/teamsChannelData.ts +30 -0
  111. package/src/app/index.ts +4 -0
  112. package/src/app/teamsAppExtensions.ts +369 -0
  113. package/src/channels/index.ts +4 -0
  114. package/src/channels/teamsChannel.ts +229 -0
  115. package/src/config/config.ts +79 -0
  116. package/src/config/index.ts +4 -0
  117. package/src/errorHelper.ts +104 -0
  118. package/src/fileConsents/fileConsent.ts +85 -0
  119. package/src/fileConsents/index.ts +4 -0
  120. package/src/graphClientFactory.ts +127 -0
  121. package/src/index.ts +23 -0
  122. package/src/meetings/index.ts +4 -0
  123. package/src/meetings/meeting.ts +146 -0
  124. package/src/messageExtensions/index.ts +5 -0
  125. package/src/messageExtensions/messageExtension.ts +370 -0
  126. package/src/messageExtensions/messagingExtensionQuery.ts +34 -0
  127. package/src/messages/index.ts +4 -0
  128. package/src/messages/message.ts +148 -0
  129. package/src/models/index.ts +4 -0
  130. package/src/models/readReceiptInfo.ts +50 -0
  131. package/src/taskModules/index.ts +4 -0
  132. package/src/taskModules/taskModule.ts +113 -0
  133. package/src/teams/index.ts +4 -0
  134. package/src/teams/teamsTeam.ts +189 -0
  135. package/src/teamsActivity.ts +19 -0
  136. package/src/teamsActivityExtensions.ts +99 -0
  137. package/src/teamsAgentExtension.ts +205 -0
  138. package/src/teamsApiClientExtensions.ts +47 -0
  139. package/src/teamsHeaderPropagation.ts +32 -0
  140. package/src/teamsModelExtensions.ts +42 -0
  141. package/src/teamsProactiveServiceEndpoints.ts +18 -0
  142. package/src/teamsRouteHandler.ts +22 -0
  143. package/src/teamsTurnContext.ts +125 -0
@@ -0,0 +1,369 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ import { Activity, ActivityTypes, Channels } from '@microsoft/agents-activity'
5
+ import { AgentApplication, ConversationUpdateEvents, RouteHandler, RouteRank, RouteSelector, TurnContext, TurnState } from '@microsoft/agents-hosting'
6
+ import { createTeamsRouteHandler, TeamsRouteHandler } from '../teamsRouteHandler'
7
+ import { TeamsTurnContext } from '../teamsTurnContext'
8
+
9
+ /**
10
+ * Value submitted by a Teams feedback loop action.
11
+ */
12
+ export interface FeedbackActionValue {
13
+ /**
14
+ * Feedback reaction selected by the user.
15
+ */
16
+ reaction?: string;
17
+ /**
18
+ * Optional feedback text or structured feedback data.
19
+ */
20
+ feedback?: string | Record<string, unknown>;
21
+ }
22
+
23
+ /**
24
+ * Payload supplied to Teams feedback loop handlers.
25
+ */
26
+ export interface FeedbackData {
27
+ /**
28
+ * Name of the submitted action.
29
+ */
30
+ actionName?: string;
31
+ /**
32
+ * Value submitted with the feedback action.
33
+ */
34
+ actionValue?: FeedbackActionValue;
35
+ /**
36
+ * ID of the activity that the feedback applies to.
37
+ */
38
+ replyToId?: string;
39
+ }
40
+
41
+ /**
42
+ * Handler for Teams handoff invoke activities.
43
+ */
44
+ export type TeamsHandoffHandler<TState extends TurnState> = (context: TeamsTurnContext, state: TState, continuation: string) => Promise<void>
45
+ /**
46
+ * Handler for Teams feedback loop invoke activities.
47
+ */
48
+ export type TeamsFeedbackLoopHandler<TState extends TurnState> = (context: TeamsTurnContext, state: TState, feedbackData: FeedbackData) => Promise<void>
49
+
50
+ function isTeamsRouteContext (context: TurnContext, isAgenticRoute: boolean): boolean {
51
+ return context.activity.channelId === Channels.Msteams &&
52
+ (!isAgenticRoute || (isAgenticRoute && context.activity.isAgenticRequest()))
53
+ }
54
+
55
+ function matchesValue (actual: string | undefined, expected: string | RegExp): boolean {
56
+ if (typeof expected === 'string') {
57
+ return expected.toLocaleLowerCase() === actual?.toLocaleLowerCase()
58
+ }
59
+
60
+ return actual != null && expected.test(actual)
61
+ }
62
+
63
+ function addTeamsRoute<TState extends TurnState> (
64
+ app: AgentApplication<TState>,
65
+ selector: RouteSelector,
66
+ handler: RouteHandler<TState>,
67
+ isInvokeRoute: boolean,
68
+ rank: number,
69
+ authHandlers: string[],
70
+ isAgenticRoute: boolean
71
+ ): AgentApplication<TState> {
72
+ return app.addRoute(selector, handler, isInvokeRoute, rank, authHandlers, isAgenticRoute)
73
+ }
74
+
75
+ function addTeamsRouteHandler<TState extends TurnState> (
76
+ app: AgentApplication<TState>,
77
+ selector: RouteSelector,
78
+ handler: TeamsRouteHandler<TState>,
79
+ rank: number,
80
+ authHandlers: string[],
81
+ isAgenticRoute: boolean
82
+ ): AgentApplication<TState> {
83
+ return addTeamsRoute(app, selector, createTeamsRouteHandler(handler), false, rank, authHandlers, isAgenticRoute)
84
+ }
85
+
86
+ function createInvokeResponse (): Activity {
87
+ const invokeResponse = new Activity(ActivityTypes.InvokeResponse)
88
+ invokeResponse.value = { status: 200 }
89
+ return invokeResponse
90
+ }
91
+
92
+ /**
93
+ * Registers a route that handles Teams activities by activity type.
94
+ *
95
+ * @param app - The agent application that receives the route.
96
+ * @param type - Activity type or regular expression to match.
97
+ * @param handler - Handler invoked with a Teams turn context and turn state.
98
+ * @param rank - Optional route rank used for route ordering.
99
+ * @param authHandlers - Optional authorization handlers required by the route.
100
+ * @param isAgenticRoute - Indicates whether the route should handle agentic requests only.
101
+ * @returns The agent application for chaining.
102
+ */
103
+ export function onTeamsActivity<TState extends TurnState> (
104
+ app: AgentApplication<TState>,
105
+ type: string | RegExp,
106
+ handler: TeamsRouteHandler<TState>,
107
+ rank: number = RouteRank.Unspecified,
108
+ authHandlers: string[] = [],
109
+ isAgenticRoute: boolean = false
110
+ ): AgentApplication<TState> {
111
+ const selector: RouteSelector = async (context) =>
112
+ isTeamsRouteContext(context, isAgenticRoute) &&
113
+ matchesValue(context.activity.type, type)
114
+
115
+ return addTeamsRouteHandler(app, selector, handler, rank, authHandlers, isAgenticRoute)
116
+ }
117
+
118
+ /**
119
+ * Registers a route that handles Teams conversation update activities.
120
+ *
121
+ * @param app - The agent application that receives the route.
122
+ * @param event - Conversation update event name to match.
123
+ * @param handler - Handler invoked with a Teams turn context and turn state.
124
+ * @param rank - Optional route rank used for route ordering.
125
+ * @param authHandlers - Optional authorization handlers required by the route.
126
+ * @param isAgenticRoute - Indicates whether the route should handle agentic requests only.
127
+ * @returns The agent application for chaining.
128
+ */
129
+ export function onTeamsConversationUpdate<TState extends TurnState> (
130
+ app: AgentApplication<TState>,
131
+ event: ConversationUpdateEvents | string,
132
+ handler: TeamsRouteHandler<TState>,
133
+ rank: number = RouteRank.Unspecified,
134
+ authHandlers: string[] = [],
135
+ isAgenticRoute: boolean = false
136
+ ): AgentApplication<TState> {
137
+ const selector: RouteSelector = async (context) => {
138
+ if (!isTeamsRouteContext(context, isAgenticRoute) ||
139
+ context.activity.type !== ActivityTypes.ConversationUpdate) {
140
+ return false
141
+ }
142
+
143
+ if (event === 'membersAdded') {
144
+ return Array.isArray(context.activity.membersAdded) && context.activity.membersAdded.length > 0
145
+ }
146
+
147
+ if (event === 'membersRemoved') {
148
+ return Array.isArray(context.activity.membersRemoved) && context.activity.membersRemoved.length > 0
149
+ }
150
+
151
+ return true
152
+ }
153
+
154
+ return addTeamsRouteHandler(app, selector, handler, rank, authHandlers, isAgenticRoute)
155
+ }
156
+
157
+ /**
158
+ * Registers a route that handles Teams message activities by text.
159
+ *
160
+ * @param app - The agent application that receives the route.
161
+ * @param text - Message text or regular expression to match.
162
+ * @param handler - Handler invoked with a Teams turn context and turn state.
163
+ * @param rank - Optional route rank used for route ordering.
164
+ * @param authHandlers - Optional authorization handlers required by the route.
165
+ * @param isAgenticRoute - Indicates whether the route should handle agentic requests only.
166
+ * @returns The agent application for chaining.
167
+ */
168
+ export function onTeamsMessage<TState extends TurnState> (
169
+ app: AgentApplication<TState>,
170
+ text: string | RegExp,
171
+ handler: TeamsRouteHandler<TState>,
172
+ rank: number = RouteRank.Unspecified,
173
+ authHandlers: string[] = [],
174
+ isAgenticRoute: boolean = false
175
+ ): AgentApplication<TState> {
176
+ const selector: RouteSelector = async (context) =>
177
+ isTeamsRouteContext(context, isAgenticRoute) &&
178
+ context.activity.type === ActivityTypes.Message &&
179
+ matchesValue(context.activity.text, text)
180
+
181
+ return addTeamsRouteHandler(app, selector, handler, rank, authHandlers, isAgenticRoute)
182
+ }
183
+
184
+ /**
185
+ * Registers a route that handles Teams event activities by event name.
186
+ *
187
+ * @param app - The agent application that receives the route.
188
+ * @param name - Event name or regular expression to match.
189
+ * @param handler - Handler invoked with a Teams turn context and turn state.
190
+ * @param rank - Optional route rank used for route ordering.
191
+ * @param authHandlers - Optional authorization handlers required by the route.
192
+ * @param isAgenticRoute - Indicates whether the route should handle agentic requests only.
193
+ * @returns The agent application for chaining.
194
+ */
195
+ export function onTeamsEvent<TState extends TurnState> (
196
+ app: AgentApplication<TState>,
197
+ name: string | RegExp,
198
+ handler: TeamsRouteHandler<TState>,
199
+ rank?: number,
200
+ authHandlers?: string[],
201
+ isAgenticRoute?: boolean
202
+ ): AgentApplication<TState>
203
+ /**
204
+ * Registers a route that handles Teams event activities by custom selector.
205
+ *
206
+ * @param app - The agent application that receives the route.
207
+ * @param selector - Selector used to decide whether the route should run.
208
+ * @param handler - Handler invoked with a Teams turn context and turn state.
209
+ * @param rank - Optional route rank used for route ordering.
210
+ * @param authHandlers - Optional authorization handlers required by the route.
211
+ * @param isAgenticRoute - Indicates whether the route should handle agentic requests only.
212
+ * @returns The agent application for chaining.
213
+ */
214
+ export function onTeamsEvent<TState extends TurnState> (
215
+ app: AgentApplication<TState>,
216
+ selector: RouteSelector,
217
+ handler: TeamsRouteHandler<TState>,
218
+ rank?: number,
219
+ authHandlers?: string[],
220
+ isAgenticRoute?: boolean
221
+ ): AgentApplication<TState>
222
+ export function onTeamsEvent<TState extends TurnState> (
223
+ app: AgentApplication<TState>,
224
+ nameOrSelector: string | RegExp | RouteSelector,
225
+ handler: TeamsRouteHandler<TState>,
226
+ rank: number = RouteRank.Unspecified,
227
+ authHandlers: string[] = [],
228
+ isAgenticRoute: boolean = false
229
+ ): AgentApplication<TState> {
230
+ const selector: RouteSelector = async (context) => {
231
+ if (!isTeamsRouteContext(context, isAgenticRoute) ||
232
+ context.activity.type !== ActivityTypes.Event) {
233
+ return false
234
+ }
235
+
236
+ if (typeof nameOrSelector === 'function') {
237
+ return await nameOrSelector(context)
238
+ }
239
+
240
+ return matchesValue(context.activity.name, nameOrSelector)
241
+ }
242
+
243
+ return addTeamsRouteHandler(app, selector, handler, rank, authHandlers, isAgenticRoute)
244
+ }
245
+
246
+ /**
247
+ * Registers a route that handles Teams message reaction added activities.
248
+ *
249
+ * @param app - The agent application that receives the route.
250
+ * @param handler - Handler invoked with a Teams turn context and turn state.
251
+ * @param rank - Optional route rank used for route ordering.
252
+ * @param authHandlers - Optional authorization handlers required by the route.
253
+ * @param isAgenticRoute - Indicates whether the route should handle agentic requests only.
254
+ * @returns The agent application for chaining.
255
+ */
256
+ export function onTeamsMessageReactionsAdded<TState extends TurnState> (
257
+ app: AgentApplication<TState>,
258
+ handler: TeamsRouteHandler<TState>,
259
+ rank: number = RouteRank.Unspecified,
260
+ authHandlers: string[] = [],
261
+ isAgenticRoute: boolean = false
262
+ ): AgentApplication<TState> {
263
+ const selector: RouteSelector = async (context) =>
264
+ isTeamsRouteContext(context, isAgenticRoute) &&
265
+ context.activity.type === ActivityTypes.MessageReaction &&
266
+ Array.isArray(context.activity.reactionsAdded) &&
267
+ context.activity.reactionsAdded.length > 0
268
+
269
+ return addTeamsRouteHandler(app, selector, handler, rank, authHandlers, isAgenticRoute)
270
+ }
271
+
272
+ /**
273
+ * Registers a route that handles Teams message reaction removed activities.
274
+ *
275
+ * @param app - The agent application that receives the route.
276
+ * @param handler - Handler invoked with a Teams turn context and turn state.
277
+ * @param rank - Optional route rank used for route ordering.
278
+ * @param authHandlers - Optional authorization handlers required by the route.
279
+ * @param isAgenticRoute - Indicates whether the route should handle agentic requests only.
280
+ * @returns The agent application for chaining.
281
+ */
282
+ export function onTeamsMessageReactionsRemoved<TState extends TurnState> (
283
+ app: AgentApplication<TState>,
284
+ handler: TeamsRouteHandler<TState>,
285
+ rank: number = RouteRank.Unspecified,
286
+ authHandlers: string[] = [],
287
+ isAgenticRoute: boolean = false
288
+ ): AgentApplication<TState> {
289
+ const selector: RouteSelector = async (context) =>
290
+ isTeamsRouteContext(context, isAgenticRoute) &&
291
+ context.activity.type === ActivityTypes.MessageReaction &&
292
+ Array.isArray(context.activity.reactionsRemoved) &&
293
+ context.activity.reactionsRemoved.length > 0
294
+
295
+ return addTeamsRouteHandler(app, selector, handler, rank, authHandlers, isAgenticRoute)
296
+ }
297
+
298
+ /**
299
+ * Registers a route that handles Teams handoff invoke activities.
300
+ *
301
+ * @param app - The agent application that receives the route.
302
+ * @param handler - Handler invoked with the handoff continuation value.
303
+ * @param rank - Optional route rank used for route ordering.
304
+ * @param authHandlers - Optional authorization handlers required by the route.
305
+ * @param isAgenticRoute - Indicates whether the route should handle agentic requests only.
306
+ * @returns The agent application for chaining.
307
+ */
308
+ export function onTeamsHandoff<TState extends TurnState> (
309
+ app: AgentApplication<TState>,
310
+ handler: TeamsHandoffHandler<TState>,
311
+ rank: number = RouteRank.Unspecified,
312
+ authHandlers: string[] = [],
313
+ isAgenticRoute: boolean = false
314
+ ): AgentApplication<TState> {
315
+ const selector: RouteSelector = async (context) =>
316
+ isTeamsRouteContext(context, isAgenticRoute) &&
317
+ context.activity.type === ActivityTypes.Invoke &&
318
+ context.activity.name?.toLocaleLowerCase() === 'handoff/action'
319
+
320
+ const routeHandler: RouteHandler<TState> = async (context, state) => {
321
+ const value = context.activity.value as { continuation?: unknown, Continuation?: unknown } | undefined
322
+ const continuation = typeof value?.continuation === 'string'
323
+ ? value.continuation
324
+ : typeof value?.Continuation === 'string' ? value.Continuation : ''
325
+
326
+ await handler(new TeamsTurnContext(context), state, continuation)
327
+ await context.sendActivity(createInvokeResponse())
328
+ }
329
+
330
+ return addTeamsRoute(app, selector, routeHandler, true, rank, authHandlers, isAgenticRoute)
331
+ }
332
+
333
+ /**
334
+ * Registers a route that handles Teams feedback loop invoke activities.
335
+ *
336
+ * @param app - The agent application that receives the route.
337
+ * @param handler - Handler invoked with feedback loop data.
338
+ * @param rank - Optional route rank used for route ordering.
339
+ * @param authHandlers - Optional authorization handlers required by the route.
340
+ * @param isAgenticRoute - Indicates whether the route should handle agentic requests only.
341
+ * @returns The agent application for chaining.
342
+ */
343
+ export function onTeamsFeedbackLoop<TState extends TurnState> (
344
+ app: AgentApplication<TState>,
345
+ handler: TeamsFeedbackLoopHandler<TState>,
346
+ rank: number = RouteRank.Unspecified,
347
+ authHandlers: string[] = [],
348
+ isAgenticRoute: boolean = false
349
+ ): AgentApplication<TState> {
350
+ const selector: RouteSelector = async (context) => {
351
+ const actionName = (context.activity.value as { actionName?: unknown } | undefined)?.actionName
352
+ return isTeamsRouteContext(context, isAgenticRoute) &&
353
+ context.activity.type === ActivityTypes.Invoke &&
354
+ context.activity.name === 'message/submitAction' &&
355
+ actionName === 'feedback'
356
+ }
357
+
358
+ const routeHandler: RouteHandler<TState> = async (context, state) => {
359
+ const feedbackData = {
360
+ ...(context.activity.value as FeedbackData),
361
+ replyToId: context.activity.replyToId
362
+ }
363
+
364
+ await handler(new TeamsTurnContext(context), state, feedbackData)
365
+ await context.sendActivity(createInvokeResponse())
366
+ }
367
+
368
+ return addTeamsRoute(app, selector, routeHandler, true, rank, authHandlers, isAgenticRoute)
369
+ }
@@ -0,0 +1,4 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ export * from './teamsChannel'
@@ -0,0 +1,229 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ import { ActivityTypes } from '@microsoft/agents-activity'
5
+ import { AgentApplication, RouteHandler, RouteRank, RouteSelector, TurnContext, TurnState } from '@microsoft/agents-hosting'
6
+ import { parseTeamsChannelData } from '../activity-extensions'
7
+ import type { ChannelInfo } from '@microsoft/teams.api'
8
+ import { TeamsTurnContext } from '../teamsTurnContext'
9
+
10
+ const CHANNEL_CREATED_EVENT = 'channelCreated'
11
+ const CHANNEL_DELETED_EVENT = 'channelDeleted'
12
+ const CHANNEL_RENAMED_EVENT = 'channelRenamed'
13
+ const CHANNEL_RESTORED_EVENT = 'channelRestored'
14
+ const CHANNEL_SHARED_EVENT = 'channelShared'
15
+ const CHANNEL_UNSHARED_EVENT = 'channelUnshared'
16
+ const CHANNEL_MEMBER_ADDED_EVENT = 'channelMemberAdded'
17
+ const CHANNEL_MEMBER_REMOVED_EVENT = 'channelMemberRemoved'
18
+
19
+ type ChannelUpdateHandler<TState extends TurnState> = (context: TeamsTurnContext, state: TState, data: ChannelInfo) => Promise<void>
20
+
21
+ function isChannelUpdateEvent (context: TurnContext, eventType?: string): boolean {
22
+ const channelData = parseTeamsChannelData(context.activity.channelData)
23
+ const actualEventType = typeof channelData?.eventType === 'string' ? channelData.eventType.toLowerCase() : undefined
24
+ const expectedEventType = eventType?.toLowerCase()
25
+
26
+ return (
27
+ context.activity.type === ActivityTypes.ConversationUpdate &&
28
+ context.activity.channelId === 'msteams' &&
29
+ channelData?.channel != null &&
30
+ (
31
+ expectedEventType != null
32
+ ? actualEventType === expectedEventType
33
+ : actualEventType?.startsWith('channel') === true
34
+ )
35
+ )
36
+ }
37
+
38
+ function getChannelInfo (context: TurnContext): ChannelInfo {
39
+ return parseTeamsChannelData(context.activity.channelData).channel as ChannelInfo
40
+ }
41
+
42
+ /**
43
+ * Registers handlers for Microsoft Teams channel lifecycle and membership events.
44
+ *
45
+ * @typeParam TState - The turn state type used by the agent application.
46
+ */
47
+ export class TeamsChannel<TState extends TurnState = TurnState> {
48
+ private _app: AgentApplication<TState>
49
+
50
+ /**
51
+ * Creates a Teams channel route helper.
52
+ *
53
+ * @param app - The agent application that receives the registered routes.
54
+ */
55
+ constructor (app: AgentApplication<TState>) {
56
+ this._app = app
57
+ }
58
+
59
+ /**
60
+ * Registers a handler for any Teams channel update event.
61
+ *
62
+ * @param handler - Handler invoked with the Teams turn context, turn state, and channel information.
63
+ * @param rank - Optional route rank used for route ordering.
64
+ * @param authHandlers - Optional authorization handlers required by the route.
65
+ * @returns This channel helper for chaining.
66
+ */
67
+ onChannelEventReceived (handler: ChannelUpdateHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
68
+ const routeSel: RouteSelector = (context: TurnContext) => {
69
+ return Promise.resolve(isChannelUpdateEvent(context))
70
+ }
71
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
72
+ await handler(new TeamsTurnContext(context), state, getChannelInfo(context))
73
+ }
74
+ this._app.addRoute(routeSel, routeHandler, false, rank, authHandlers)
75
+ return this
76
+ }
77
+
78
+ /**
79
+ * Registers a handler for Teams channel created events.
80
+ *
81
+ * @param handler - Handler invoked with the created channel information.
82
+ * @param rank - Optional route rank used for route ordering.
83
+ * @param authHandlers - Optional authorization handlers required by the route.
84
+ * @returns This channel helper for chaining.
85
+ */
86
+ onCreated (handler: ChannelUpdateHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
87
+ const routeSel: RouteSelector = (context: TurnContext) => {
88
+ return Promise.resolve(isChannelUpdateEvent(context, CHANNEL_CREATED_EVENT))
89
+ }
90
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
91
+ await handler(new TeamsTurnContext(context), state, getChannelInfo(context))
92
+ }
93
+ this._app.addRoute(routeSel, routeHandler, false, rank, authHandlers)
94
+ return this
95
+ }
96
+
97
+ /**
98
+ * Registers a handler for Teams channel deleted events.
99
+ *
100
+ * @param handler - Handler invoked with the deleted channel information.
101
+ * @param rank - Optional route rank used for route ordering.
102
+ * @param authHandlers - Optional authorization handlers required by the route.
103
+ * @returns This channel helper for chaining.
104
+ */
105
+ onDeleted (handler: ChannelUpdateHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
106
+ const routeSel: RouteSelector = (context: TurnContext) => {
107
+ return Promise.resolve(isChannelUpdateEvent(context, CHANNEL_DELETED_EVENT))
108
+ }
109
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
110
+ await handler(new TeamsTurnContext(context), state, getChannelInfo(context))
111
+ }
112
+ this._app.addRoute(routeSel, routeHandler, false, rank, authHandlers)
113
+ return this
114
+ }
115
+
116
+ /**
117
+ * Registers a handler for Teams channel renamed events.
118
+ *
119
+ * @param handler - Handler invoked with the renamed channel information.
120
+ * @param rank - Optional route rank used for route ordering.
121
+ * @param authHandlers - Optional authorization handlers required by the route.
122
+ * @returns This channel helper for chaining.
123
+ */
124
+ onRenamed (handler: ChannelUpdateHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
125
+ const routeSel: RouteSelector = (context: TurnContext) => {
126
+ return Promise.resolve(isChannelUpdateEvent(context, CHANNEL_RENAMED_EVENT))
127
+ }
128
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
129
+ await handler(new TeamsTurnContext(context), state, getChannelInfo(context))
130
+ }
131
+ this._app.addRoute(routeSel, routeHandler, false, rank, authHandlers)
132
+ return this
133
+ }
134
+
135
+ /**
136
+ * Registers a handler for Teams channel restored events.
137
+ *
138
+ * @param handler - Handler invoked with the restored channel information.
139
+ * @param rank - Optional route rank used for route ordering.
140
+ * @param authHandlers - Optional authorization handlers required by the route.
141
+ * @returns This channel helper for chaining.
142
+ */
143
+ onRestored (handler: ChannelUpdateHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
144
+ const routeSel: RouteSelector = (context: TurnContext) => {
145
+ return Promise.resolve(isChannelUpdateEvent(context, CHANNEL_RESTORED_EVENT))
146
+ }
147
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
148
+ await handler(new TeamsTurnContext(context), state, getChannelInfo(context))
149
+ }
150
+ this._app.addRoute(routeSel, routeHandler, false, rank, authHandlers)
151
+ return this
152
+ }
153
+
154
+ /**
155
+ * Registers a handler for Teams channel shared events.
156
+ *
157
+ * @param handler - Handler invoked with the shared channel information.
158
+ * @param rank - Optional route rank used for route ordering.
159
+ * @param authHandlers - Optional authorization handlers required by the route.
160
+ * @returns This channel helper for chaining.
161
+ */
162
+ onShared (handler: ChannelUpdateHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
163
+ const routeSel: RouteSelector = (context: TurnContext) => {
164
+ return Promise.resolve(isChannelUpdateEvent(context, CHANNEL_SHARED_EVENT))
165
+ }
166
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
167
+ await handler(new TeamsTurnContext(context), state, getChannelInfo(context))
168
+ }
169
+ this._app.addRoute(routeSel, routeHandler, false, rank, authHandlers)
170
+ return this
171
+ }
172
+
173
+ /**
174
+ * Registers a handler for Teams channel unshared events.
175
+ *
176
+ * @param handler - Handler invoked with the unshared channel information.
177
+ * @param rank - Optional route rank used for route ordering.
178
+ * @param authHandlers - Optional authorization handlers required by the route.
179
+ * @returns This channel helper for chaining.
180
+ */
181
+ onUnshared (handler: ChannelUpdateHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
182
+ const routeSel: RouteSelector = (context: TurnContext) => {
183
+ return Promise.resolve(isChannelUpdateEvent(context, CHANNEL_UNSHARED_EVENT))
184
+ }
185
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
186
+ await handler(new TeamsTurnContext(context), state, getChannelInfo(context))
187
+ }
188
+ this._app.addRoute(routeSel, routeHandler, false, rank, authHandlers)
189
+ return this
190
+ }
191
+
192
+ /**
193
+ * Registers a handler for member-added events in a Teams channel.
194
+ *
195
+ * @param handler - Handler invoked with channel information for the membership event.
196
+ * @param rank - Optional route rank used for route ordering.
197
+ * @param authHandlers - Optional authorization handlers required by the route.
198
+ * @returns This channel helper for chaining.
199
+ */
200
+ onMemberAdded (handler: ChannelUpdateHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
201
+ const routeSel: RouteSelector = (context: TurnContext) => {
202
+ return Promise.resolve(isChannelUpdateEvent(context, CHANNEL_MEMBER_ADDED_EVENT))
203
+ }
204
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
205
+ await handler(new TeamsTurnContext(context), state, getChannelInfo(context))
206
+ }
207
+ this._app.addRoute(routeSel, routeHandler, false, rank, authHandlers)
208
+ return this
209
+ }
210
+
211
+ /**
212
+ * Registers a handler for member-removed events in a Teams channel.
213
+ *
214
+ * @param handler - Handler invoked with channel information for the membership event.
215
+ * @param rank - Optional route rank used for route ordering.
216
+ * @param authHandlers - Optional authorization handlers required by the route.
217
+ * @returns This channel helper for chaining.
218
+ */
219
+ onMemberRemoved (handler: ChannelUpdateHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
220
+ const routeSel: RouteSelector = (context: TurnContext) => {
221
+ return Promise.resolve(isChannelUpdateEvent(context, CHANNEL_MEMBER_REMOVED_EVENT))
222
+ }
223
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
224
+ await handler(new TeamsTurnContext(context), state, getChannelInfo(context))
225
+ }
226
+ this._app.addRoute(routeSel, routeHandler, false, rank, authHandlers)
227
+ return this
228
+ }
229
+ }
@@ -0,0 +1,79 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ import { Activity, ActivityTypes } from '@microsoft/agents-activity'
5
+ import { AgentApplication, RouteHandler, RouteRank, RouteSelector, TurnContext, TurnState } from '@microsoft/agents-hosting'
6
+ import type { ConfigResponse } from '@microsoft/teams.api'
7
+ import { TeamsTurnContext } from '../teamsTurnContext'
8
+
9
+ type ConfigHandler<TState extends TurnState> = (context: TeamsTurnContext, state: TState, configData: unknown) => Promise<ConfigResponse>
10
+
11
+ /**
12
+ * Registers handlers for Microsoft Teams app configuration invokes.
13
+ *
14
+ * @typeParam TState - The turn state type used by the agent application.
15
+ */
16
+ export class TeamsConfig<TState extends TurnState = TurnState> {
17
+ private _app: AgentApplication<TState>
18
+
19
+ /**
20
+ * Creates a Teams configuration route helper.
21
+ *
22
+ * @param app - The agent application that receives the registered routes.
23
+ */
24
+ constructor (app: AgentApplication<TState>) {
25
+ this._app = app
26
+ }
27
+
28
+ /**
29
+ * Registers a handler for Teams config/fetch invokes.
30
+ *
31
+ * @param handler - Handler invoked with the config fetch payload.
32
+ * @param rank - Optional route rank used for route ordering.
33
+ * @param authHandlers - Optional authorization handlers required by the route.
34
+ * @returns This config helper for chaining.
35
+ */
36
+ onConfigFetch (handler: ConfigHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
37
+ const routeSel: RouteSelector = (context: TurnContext) => {
38
+ return Promise.resolve(
39
+ context.activity.type === ActivityTypes.Invoke &&
40
+ context.activity.channelId === 'msteams' &&
41
+ context.activity.name === 'config/fetch'
42
+ )
43
+ }
44
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
45
+ const response: ConfigResponse = await handler(new TeamsTurnContext(context), state, context.activity.value)
46
+ const invokeResponse = new Activity(ActivityTypes.InvokeResponse)
47
+ invokeResponse.value = { status: 200, body: response }
48
+ await context.sendActivity(invokeResponse)
49
+ }
50
+ this._app.addRoute(routeSel, routeHandler, true, rank, authHandlers)
51
+ return this
52
+ }
53
+
54
+ /**
55
+ * Registers a handler for Teams config/submit invokes.
56
+ *
57
+ * @param handler - Handler invoked with the config submit payload.
58
+ * @param rank - Optional route rank used for route ordering.
59
+ * @param authHandlers - Optional authorization handlers required by the route.
60
+ * @returns This config helper for chaining.
61
+ */
62
+ onConfigSubmit (handler: ConfigHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
63
+ const routeSel: RouteSelector = (context: TurnContext) => {
64
+ return Promise.resolve(
65
+ context.activity.type === ActivityTypes.Invoke &&
66
+ context.activity.channelId === 'msteams' &&
67
+ context.activity.name === 'config/submit'
68
+ )
69
+ }
70
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
71
+ const response: ConfigResponse = await handler(new TeamsTurnContext(context), state, context.activity.value)
72
+ const invokeResponse = new Activity(ActivityTypes.InvokeResponse)
73
+ invokeResponse.value = { status: 200, body: response }
74
+ await context.sendActivity(invokeResponse)
75
+ }
76
+ this._app.addRoute(routeSel, routeHandler, true, rank, authHandlers)
77
+ return this
78
+ }
79
+ }
@@ -0,0 +1,4 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ export * from './config'