@microsoft/agents-hosting 0.4.3 → 0.5.4-ga4d0401645

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 (107) hide show
  1. package/dist/src/activityWireCompat.js +1 -1
  2. package/dist/src/activityWireCompat.js.map +1 -1
  3. package/dist/src/app/adaptiveCards/activityValueParsers.d.ts +115 -0
  4. package/dist/src/app/adaptiveCards/activityValueParsers.js +224 -0
  5. package/dist/src/app/adaptiveCards/activityValueParsers.js.map +1 -0
  6. package/dist/src/app/adaptiveCards/adaptiveCardActionExecuteResponseType.d.ts +21 -0
  7. package/dist/src/app/adaptiveCards/adaptiveCardActionExecuteResponseType.js +26 -0
  8. package/dist/src/app/adaptiveCards/adaptiveCardActionExecuteResponseType.js.map +1 -0
  9. package/dist/src/app/adaptiveCards/adaptiveCardsActions.d.ts +57 -0
  10. package/dist/src/app/adaptiveCards/adaptiveCardsActions.js +272 -0
  11. package/dist/src/app/adaptiveCards/adaptiveCardsActions.js.map +1 -0
  12. package/dist/src/app/adaptiveCards/adaptiveCardsOptions.d.ts +20 -0
  13. package/dist/src/app/adaptiveCards/adaptiveCardsOptions.js +7 -0
  14. package/dist/src/app/adaptiveCards/adaptiveCardsOptions.js.map +1 -0
  15. package/dist/src/app/adaptiveCards/adaptiveCardsSearchParams.d.ts +31 -0
  16. package/dist/src/app/adaptiveCards/adaptiveCardsSearchParams.js +16 -0
  17. package/dist/src/app/adaptiveCards/adaptiveCardsSearchParams.js.map +1 -0
  18. package/dist/src/app/adaptiveCards/index.d.ts +3 -0
  19. package/dist/src/app/adaptiveCards/index.js +20 -0
  20. package/dist/src/app/adaptiveCards/index.js.map +1 -0
  21. package/dist/src/app/adaptiveCards/query.d.ts +22 -0
  22. package/dist/src/app/adaptiveCards/query.js +7 -0
  23. package/dist/src/app/adaptiveCards/query.js.map +1 -0
  24. package/dist/src/app/agentApplication.d.ts +56 -8
  25. package/dist/src/app/agentApplication.js +88 -11
  26. package/dist/src/app/agentApplication.js.map +1 -1
  27. package/dist/src/app/agentApplicationBuilder.d.ts +2 -2
  28. package/dist/src/app/agentApplicationBuilder.js.map +1 -1
  29. package/dist/src/app/agentApplicationOptions.d.ts +17 -2
  30. package/dist/src/app/appRoute.d.ts +5 -0
  31. package/dist/src/app/attachmentDownloader.js +1 -0
  32. package/dist/src/app/attachmentDownloader.js.map +1 -1
  33. package/dist/src/app/extensions.d.ts +9 -0
  34. package/dist/src/app/extensions.js +16 -0
  35. package/dist/src/app/extensions.js.map +1 -0
  36. package/dist/src/app/index.d.ts +2 -0
  37. package/dist/src/app/index.js +2 -0
  38. package/dist/src/app/index.js.map +1 -1
  39. package/dist/src/app/streaming/AIEntity.d.ts +36 -0
  40. package/dist/src/app/streaming/AIEntity.js +7 -0
  41. package/dist/src/app/streaming/AIEntity.js.map +1 -0
  42. package/dist/src/app/streaming/actionCall.d.ts +33 -0
  43. package/dist/src/app/streaming/actionCall.js +7 -0
  44. package/dist/src/app/streaming/actionCall.js.map +1 -0
  45. package/dist/src/app/streaming/clientCitation.d.ts +68 -0
  46. package/dist/src/app/streaming/clientCitation.js +10 -0
  47. package/dist/src/app/streaming/clientCitation.js.map +1 -0
  48. package/dist/src/app/streaming/message.d.ts +106 -0
  49. package/dist/src/app/streaming/message.js +7 -0
  50. package/dist/src/app/streaming/message.js.map +1 -0
  51. package/dist/src/app/streaming/sensitivityUsageInfo.d.ts +40 -0
  52. package/dist/src/app/streaming/sensitivityUsageInfo.js +3 -0
  53. package/dist/src/app/streaming/sensitivityUsageInfo.js.map +1 -0
  54. package/dist/src/app/streaming/streamingResponse.d.ts +141 -0
  55. package/dist/src/app/streaming/streamingResponse.js +331 -0
  56. package/dist/src/app/streaming/streamingResponse.js.map +1 -0
  57. package/dist/src/app/streaming/utilities.d.ts +31 -0
  58. package/dist/src/app/streaming/utilities.js +101 -0
  59. package/dist/src/app/streaming/utilities.js.map +1 -0
  60. package/dist/src/auth/jwt-middleware.js +1 -0
  61. package/dist/src/auth/jwt-middleware.js.map +1 -1
  62. package/dist/src/baseAdapter.js +1 -1
  63. package/dist/src/baseAdapter.js.map +1 -1
  64. package/dist/src/cards/adaptiveCard.d.ts +15 -0
  65. package/dist/src/cards/adaptiveCard.js +7 -0
  66. package/dist/src/cards/adaptiveCard.js.map +1 -0
  67. package/dist/src/cards/index.d.ts +1 -0
  68. package/dist/src/cards/index.js +1 -0
  69. package/dist/src/cards/index.js.map +1 -1
  70. package/dist/src/cloudAdapter.js +6 -7
  71. package/dist/src/cloudAdapter.js.map +1 -1
  72. package/dist/src/connector-client/connectorClient.d.ts +6 -4
  73. package/dist/src/connector-client/connectorClient.js +34 -17
  74. package/dist/src/connector-client/connectorClient.js.map +1 -1
  75. package/dist/src/turnContext.d.ts +3 -0
  76. package/dist/src/turnContext.js +5 -0
  77. package/dist/src/turnContext.js.map +1 -1
  78. package/package.json +2 -2
  79. package/src/activityWireCompat.ts +1 -1
  80. package/src/app/adaptiveCards/activityValueParsers.ts +249 -0
  81. package/src/app/adaptiveCards/adaptiveCardActionExecuteResponseType.ts +24 -0
  82. package/src/app/adaptiveCards/adaptiveCardsActions.ts +320 -0
  83. package/src/app/adaptiveCards/adaptiveCardsOptions.ts +23 -0
  84. package/src/app/adaptiveCards/adaptiveCardsSearchParams.ts +28 -0
  85. package/src/app/adaptiveCards/index.ts +3 -0
  86. package/src/app/adaptiveCards/query.ts +25 -0
  87. package/src/app/agentApplication.ts +109 -29
  88. package/src/app/agentApplicationBuilder.ts +2 -2
  89. package/src/app/agentApplicationOptions.ts +20 -2
  90. package/src/app/appRoute.ts +6 -0
  91. package/src/app/attachmentDownloader.ts +1 -0
  92. package/src/app/extensions.ts +19 -0
  93. package/src/app/index.ts +2 -0
  94. package/src/app/streaming/AIEntity.ts +44 -0
  95. package/src/app/streaming/actionCall.ts +37 -0
  96. package/src/app/streaming/clientCitation.ts +102 -0
  97. package/src/app/streaming/message.ts +125 -0
  98. package/src/app/streaming/sensitivityUsageInfo.ts +48 -0
  99. package/src/app/streaming/streamingResponse.ts +406 -0
  100. package/src/app/streaming/utilities.ts +108 -0
  101. package/src/auth/jwt-middleware.ts +1 -1
  102. package/src/baseAdapter.ts +2 -2
  103. package/src/cards/adaptiveCard.ts +16 -0
  104. package/src/cards/index.ts +1 -0
  105. package/src/cloudAdapter.ts +5 -7
  106. package/src/connector-client/connectorClient.ts +38 -19
  107. package/src/turnContext.ts +7 -1
@@ -0,0 +1,406 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { Activity, Attachment, Entity } from '@microsoft/agents-activity'
7
+ import { TurnContext } from '../../turnContext'
8
+ import { ClientCitation } from './clientCitation'
9
+ import { SensitivityUsageInfo } from './sensitivityUsageInfo'
10
+ import { Citation } from './message'
11
+ import { Utilities } from './utilities'
12
+
13
+ /**
14
+ * A helper class for streaming responses to the client.
15
+ * @remarks
16
+ * This class is used to send a series of updates to the client in a single response. The expected
17
+ * sequence of calls is:
18
+ *
19
+ * `sendInformativeUpdate()`, `sendTextChunk()`, `sendTextChunk()`, ..., `endStream()`.
20
+ *
21
+ * Once `endStream()` is called, the stream is considered ended and no further updates can be sent.
22
+ */
23
+ export class StreamingResponse {
24
+ private readonly _context: TurnContext
25
+ private _nextSequence: number = 1
26
+ private _streamId?: string
27
+ private _message: string = ''
28
+ private _attachments?: Attachment[]
29
+ private _ended = false
30
+
31
+ // Queue for outgoing activities
32
+ private _queue: Array<() => Activity> = []
33
+ private _queueSync: Promise<void> | undefined
34
+ private _chunkQueued = false
35
+
36
+ // Powered by AI feature flags
37
+ private _enableFeedbackLoop = false
38
+ private _feedbackLoopType?: 'default' | 'custom'
39
+ private _enableGeneratedByAILabel = false
40
+ private _citations?: ClientCitation[] = []
41
+ private _sensitivityLabel?: SensitivityUsageInfo
42
+
43
+ /**
44
+ * Creates a new StreamingResponse instance.
45
+ * @param {TurnContext} context - Context for the current turn of conversation with the user.
46
+ * @returns {TurnContext} - The context for the current turn of conversation with the user.
47
+ */
48
+ public constructor (context: TurnContext) {
49
+ this._context = context
50
+ }
51
+
52
+ /**
53
+ * Gets the stream ID of the current response.
54
+ * @returns {string | undefined} - The stream ID of the current response.
55
+ * @remarks
56
+ * Assigned after the initial update is sent.
57
+ */
58
+ public get streamId (): string | undefined {
59
+ return this._streamId
60
+ }
61
+
62
+ /**
63
+ * Gets the citations of the current response.
64
+ */
65
+ public get citations (): ClientCitation[] | undefined {
66
+ return this._citations
67
+ }
68
+
69
+ /**
70
+ * Gets the number of updates sent for the stream.
71
+ * @returns {number} - The number of updates sent for the stream.
72
+ */
73
+ public get updatesSent (): number {
74
+ return this._nextSequence - 1
75
+ }
76
+
77
+ /**
78
+ * Queues an informative update to be sent to the client.
79
+ * @param {string} text Text of the update to send.
80
+ */
81
+ public queueInformativeUpdate (text: string): void {
82
+ if (this._ended) {
83
+ throw new Error('The stream has already ended.')
84
+ }
85
+
86
+ // Queue a typing activity
87
+ this.queueActivity(() => Activity.fromObject({
88
+ type: 'typing',
89
+ text,
90
+ channelData: {
91
+ streamType: 'informative',
92
+ streamSequence: this._nextSequence++
93
+ } as StreamingChannelData
94
+ }))
95
+ }
96
+
97
+ /**
98
+ * Queues a chunk of partial message text to be sent to the client
99
+ * @remarks
100
+ * The text we be sent as quickly as possible to the client. Chunks may be combined before
101
+ * delivery to the client.
102
+ * @param {string} text Partial text of the message to send.
103
+ * @param {Citation[]} citations Citations to be included in the message.
104
+ */
105
+ public queueTextChunk (text: string, citations?: Citation[]): void {
106
+ if (this._ended) {
107
+ throw new Error('The stream has already ended.')
108
+ }
109
+
110
+ // Update full message text
111
+ this._message += text
112
+
113
+ // If there are citations, modify the content so that the sources are numbers instead of [doc1], [doc2], etc.
114
+ this._message = Utilities.formatCitationsResponse(this._message)
115
+
116
+ // Queue the next chunk
117
+ this.queueNextChunk()
118
+ }
119
+
120
+ /**
121
+ * Ends the stream by sending the final message to the client.
122
+ * @returns {Promise<void>} - A promise representing the async operation
123
+ */
124
+ public endStream (): Promise<void> {
125
+ if (this._ended) {
126
+ throw new Error('The stream has already ended.')
127
+ }
128
+
129
+ // Queue final message
130
+ this._ended = true
131
+ this.queueNextChunk()
132
+
133
+ // Wait for the queue to drain
134
+ return this.waitForQueue()
135
+ }
136
+
137
+ /**
138
+ * Sets the attachments to attach to the final chunk.
139
+ * @param attachments List of attachments.
140
+ */
141
+ public setAttachments (attachments: Attachment[]): void {
142
+ this._attachments = attachments
143
+ }
144
+
145
+ /**
146
+ * Sets the sensitivity label to attach to the final chunk.
147
+ * @param sensitivityLabel The sensitivty label.
148
+ */
149
+ public setSensitivityLabel (sensitivityLabel: SensitivityUsageInfo): void {
150
+ this._sensitivityLabel = sensitivityLabel
151
+ }
152
+
153
+ /**
154
+ * Sets the citations for the full message.
155
+ * @param {Citation[]} citations Citations to be included in the message.
156
+ */
157
+ public setCitations (citations: Citation[]): void {
158
+ if (citations.length > 0) {
159
+ if (!this._citations) {
160
+ this._citations = []
161
+ }
162
+ let currPos = this._citations.length
163
+
164
+ for (const citation of citations) {
165
+ const clientCitation: ClientCitation = {
166
+ '@type': 'Claim',
167
+ position: currPos + 1,
168
+ appearance: {
169
+ '@type': 'DigitalDocument',
170
+ name: citation.title || `Document #${currPos + 1}`,
171
+ abstract: Utilities.snippet(citation.content, 477)
172
+ }
173
+ }
174
+ currPos++
175
+ this._citations.push(clientCitation)
176
+ }
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Sets the Feedback Loop in Teams that allows a user to
182
+ * give thumbs up or down to a response.
183
+ * Default is `false`.
184
+ * @param enableFeedbackLoop If true, the feedback loop is enabled.
185
+ */
186
+ public setFeedbackLoop (enableFeedbackLoop: boolean): void {
187
+ this._enableFeedbackLoop = enableFeedbackLoop
188
+ }
189
+
190
+ /**
191
+ * Sets the type of UI to use for the feedback loop.
192
+ * @param feedbackLoopType The type of the feedback loop.
193
+ */
194
+ public setFeedbackLoopType (feedbackLoopType: 'default' | 'custom'): void {
195
+ this._feedbackLoopType = feedbackLoopType
196
+ }
197
+
198
+ /**
199
+ * Sets the the Generated by AI label in Teams
200
+ * Default is `false`.
201
+ * @param enableGeneratedByAILabel If true, the label is added.
202
+ */
203
+ public setGeneratedByAILabel (enableGeneratedByAILabel: boolean): void {
204
+ this._enableGeneratedByAILabel = enableGeneratedByAILabel
205
+ }
206
+
207
+ /**
208
+ * Returns the most recently streamed message.
209
+ * @returns The streamed message.
210
+ */
211
+ public getMessage (): string {
212
+ return this._message
213
+ }
214
+
215
+ /**
216
+ * Waits for the outgoing activity queue to be empty.
217
+ * @returns {Promise<void>} - A promise representing the async operation.
218
+ */
219
+ public waitForQueue (): Promise<void> {
220
+ return this._queueSync || Promise.resolve()
221
+ }
222
+
223
+ /**
224
+ * Queues the next chunk of text to be sent to the client.
225
+ * @private
226
+ */
227
+ private queueNextChunk (): void {
228
+ // Are we already waiting to send a chunk?
229
+ if (this._chunkQueued) {
230
+ return
231
+ }
232
+
233
+ // Queue a chunk of text to be sent
234
+ this._chunkQueued = true
235
+ this.queueActivity(() => {
236
+ this._chunkQueued = false
237
+ if (this._ended) {
238
+ // Send final message
239
+ return Activity.fromObject({
240
+ type: 'message',
241
+ text: this._message,
242
+ attachments: this._attachments,
243
+ channelData: {
244
+ streamType: 'final'
245
+ } as StreamingChannelData
246
+ })
247
+ } else {
248
+ // Send typing activity
249
+ return Activity.fromObject({
250
+ type: 'typing',
251
+ text: this._message,
252
+ channelData: {
253
+ streamType: 'streaming',
254
+ streamSequence: this._nextSequence++
255
+ } as StreamingChannelData
256
+ })
257
+ }
258
+ })
259
+ }
260
+
261
+ /**
262
+ * Queues an activity to be sent to the client.
263
+ */
264
+ private queueActivity (factory: () => Activity): void {
265
+ this._queue.push(factory)
266
+
267
+ // If there's no sync in progress, start one
268
+ if (!this._queueSync) {
269
+ this._queueSync = this.drainQueue().catch((err) => {
270
+ console.error(`Error occured when sending activity while streaming: "${err}".`)
271
+ throw err
272
+ })
273
+ }
274
+ }
275
+
276
+ /**
277
+ * Sends any queued activities to the client until the queue is empty.
278
+ * @returns {Promise<void>} - A promise that will be resolved once the queue is empty.
279
+ * @private
280
+ */
281
+ private async drainQueue (): Promise<void> {
282
+ // eslint-disable-next-line no-async-promise-executor
283
+ return new Promise<void>(async (resolve, reject) => {
284
+ try {
285
+ while (this._queue.length > 0) {
286
+ // Get next activity from queue
287
+ const factory = this._queue.shift()!
288
+ const activity = factory()
289
+
290
+ // Send activity
291
+ await this.sendActivity(activity)
292
+ }
293
+
294
+ resolve()
295
+ } catch (err) {
296
+ reject(err)
297
+ } finally {
298
+ // Queue is empty, mark as idle
299
+ this._queueSync = undefined
300
+ }
301
+ })
302
+ }
303
+
304
+ /**
305
+ * Sends an activity to the client and saves the stream ID returned.
306
+ * @param {Activity} activity - The activity to send.
307
+ * @returns {Promise<void>} - A promise representing the async operation.
308
+ * @private
309
+ */
310
+ private async sendActivity (activity: Activity): Promise<void> {
311
+ // Set activity ID to the assigned stream ID
312
+ if (this._streamId) {
313
+ activity.id = this._streamId
314
+ activity.channelData = Object.assign({}, activity.channelData, { streamId: this._streamId })
315
+ }
316
+
317
+ activity.entities = [
318
+ {
319
+ type: 'streaminfo',
320
+ ...activity.channelData
321
+ } as Entity
322
+ ]
323
+
324
+ if (this._citations && this._citations.length > 0 && !this._ended) {
325
+ // Filter out the citations unused in content.
326
+ const currCitations = Utilities.getUsedCitations(this._message, this._citations) ?? undefined
327
+ activity.entities.push({
328
+ type: 'https://schema.org/Message',
329
+ '@type': 'Message',
330
+ '@context': 'https://schema.org',
331
+ '@id': '',
332
+ citation: currCitations
333
+ } as unknown as Entity)
334
+ }
335
+
336
+ // Add in Powered by AI feature flags
337
+ if (this._ended) {
338
+ if (this._enableFeedbackLoop && this._feedbackLoopType) {
339
+ activity.channelData = Object.assign({}, activity.channelData, {
340
+ feedbackLoop: { type: this._feedbackLoopType }
341
+ })
342
+ } else {
343
+ activity.channelData = Object.assign({}, activity.channelData, {
344
+ feedbackLoopEnabled: this._enableFeedbackLoop
345
+ })
346
+ }
347
+
348
+ // Add in Generated by AI
349
+ if (this._enableGeneratedByAILabel) {
350
+ activity.entities.push({
351
+ type: 'https://schema.org/Message',
352
+ '@type': 'Message',
353
+ '@context': 'https://schema.org',
354
+ '@id': '',
355
+ additionalType: ['AIGeneratedContent'],
356
+ citation: this._citations && this._citations.length > 0 ? this._citations : [],
357
+ usageInfo: this._sensitivityLabel
358
+ } as unknown as Entity)
359
+ }
360
+ }
361
+
362
+ // Send activity
363
+ const response = await this._context.sendActivity(activity)
364
+ // await new Promise((resolve) => setTimeout(resolve, 1500))
365
+
366
+ // Save assigned stream ID
367
+ if (!this._streamId) {
368
+ this._streamId = response?.id
369
+ }
370
+ }
371
+ }
372
+
373
+ /**
374
+ * @private
375
+ * Structure of the outgoing channelData field for streaming responses.
376
+ * @remarks
377
+ * The expected sequence of streamTypes is:
378
+ *
379
+ * `informative`, `streaming`, `streaming`, ..., `final`.
380
+ *
381
+ * Once a `final` message is sent, the stream is considered ended.
382
+ */
383
+ interface StreamingChannelData {
384
+ /**
385
+ * The type of message being sent.
386
+ * @remarks
387
+ * `informative` - An informative update.
388
+ * `streaming` - A chunk of partial message text.
389
+ * `final` - The final message.
390
+ */
391
+ streamType: 'informative' | 'streaming' | 'final';
392
+
393
+ /**
394
+ * Sequence number of the message in the stream.
395
+ * @remarks
396
+ * Starts at 1 for the first message and increments from there.
397
+ */
398
+ streamSequence: number;
399
+
400
+ /**
401
+ * ID of the stream.
402
+ * @remarks
403
+ * Assigned after the initial update is sent.
404
+ */
405
+ streamId?: string;
406
+ }
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { ClientCitation } from './clientCitation'
7
+
8
+ // import { stringify } from 'yaml'
9
+
10
+ // import { Tokenizer } from './tokenizers'
11
+
12
+ /**
13
+ * Utility functions for manipulating .
14
+ */
15
+ export class Utilities {
16
+ // /**
17
+ // * Converts a value to a string.
18
+ // * @remarks
19
+ // * Dates are converted to ISO strings and Objects are converted to JSON or YAML, whichever is shorter.
20
+ // * @param {Tokenizer} tokenizer Tokenizer to use for encoding.
21
+ // * @param {any} value Value to convert.
22
+ // * @param {boolean} asJSON Optional. If true objects will always be converted to JSON instead of YAML. Defaults to false.
23
+ // * @returns {string} Converted value.
24
+ // */
25
+ // public static toString (tokenizer: Tokenizer, value: any, asJSON: boolean = false): string {
26
+ // if (value === undefined || value === null) {
27
+ // return ''
28
+ // } else if (typeof value === 'object') {
29
+ // if (typeof value.toISOString === 'function') {
30
+ // return value.toISOString()
31
+ // } else if (asJSON) {
32
+ // return JSON.stringify(value)
33
+ // } else {
34
+ // // Return shorter version of object
35
+ // const asYaml = stringify(value)
36
+ // const asJSON = JSON.stringify(value)
37
+ // if (tokenizer.encode(asYaml).length <= tokenizer.encode(asJSON).length) {
38
+ // return asYaml
39
+ // } else {
40
+ // return asJSON
41
+ // }
42
+ // }
43
+ // } else {
44
+ // return value.toString()
45
+ // }
46
+ // }
47
+
48
+ /**
49
+ *
50
+ * Clips the text to a maximum length in case it exceeds the limit.
51
+ * @param {string} text The text to clip.
52
+ * @param {number} maxLength The maximum length of the text to return, cutting off the last whole word.
53
+ * @returns {string} The modified text
54
+ */
55
+ public static snippet (text: string, maxLength: number): string {
56
+ if (text.length <= maxLength) {
57
+ return text
58
+ }
59
+ let snippet = text.slice(0, maxLength)
60
+ snippet = snippet.slice(0, Math.min(snippet.length, snippet.lastIndexOf(' ')))
61
+ snippet += '...'
62
+ return snippet
63
+ }
64
+
65
+ /**
66
+ * Convert citation tags `[doc(s)n]` to `[n]` where n is a number.
67
+ * @param {string} text The text to format.
68
+ * @returns {string} The formatted text.
69
+ */
70
+ public static formatCitationsResponse (text: string): string {
71
+ return text.replace(/\[docs?(\d+)\]/gi, '[$1]')
72
+ }
73
+
74
+ /**
75
+ * Get the citations used in the text. This will remove any citations that are included in the citations array from the response but not referenced in the text.
76
+ * @param {string} text - The text to search for citation references, i.e. [1], [2], etc.
77
+ * @param {ClientCitation[]} citations - The list of citations to search for.
78
+ * @returns {ClientCitation[] | undefined} The list of citations used in the text.
79
+ */
80
+ public static getUsedCitations (text: string, citations: ClientCitation[]): ClientCitation[] | undefined {
81
+ const regex = /\[(\d+)\]/gi
82
+ const matches = text.match(regex)
83
+
84
+ if (!matches) {
85
+ return undefined
86
+ }
87
+
88
+ // Remove duplicates
89
+ const filteredMatches = new Set()
90
+ matches.forEach((match) => {
91
+ if (filteredMatches.has(match)) {
92
+ return
93
+ }
94
+
95
+ filteredMatches.add(match)
96
+ })
97
+
98
+ // Add citations
99
+ const usedCitations: ClientCitation[] = []
100
+ filteredMatches.forEach((match) => {
101
+ const found = citations.find((citation) => `[${citation.position}]` === match)
102
+ if (found) {
103
+ usedCitations.push(found)
104
+ }
105
+ })
106
+ return usedCitations
107
+ }
108
+ }
@@ -21,7 +21,7 @@ const logger = debug('agents:jwt-middleware')
21
21
  const verifyToken = async (raw: string, config: AuthConfiguration): Promise<JwtPayload> => {
22
22
  const getKey: GetPublicKeyOrSecret = (header: JwtHeader, callback: SignCallback) => {
23
23
  const payload = jwt.decode(raw) as JwtPayload
24
-
24
+ logger.info('jwt.decode ', JSON.stringify(payload))
25
25
  const jwksUri: string = payload.iss === 'https://api.botframework.com'
26
26
  ? 'https://login.botframework.com/v1/.well-known/keys'
27
27
  : `https://login.microsoftonline.com/${config.tenantId}/discovery/v2.0/keys`
@@ -175,12 +175,12 @@ export abstract class BaseAdapter {
175
175
 
176
176
  try {
177
177
  await this.middleware.run(pContext.proxy, async () => await next(pContext.proxy))
178
- } catch (err) {
178
+ } catch (err: Error | any) {
179
179
  if (this.onTurnError) {
180
180
  if (err instanceof Error) {
181
181
  await this.onTurnError(pContext.proxy, err)
182
182
  } else {
183
- throw new Error('Unknown error type')
183
+ throw new Error('Unknown error type: ' + err.message)
184
184
  }
185
185
  } else {
186
186
  throw err
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ /**
7
+ * Represents an Adaptive Card, which is a card framework that enables developers to exchange UI content in a common and consistent way.
8
+ * @see {@link https://learn.microsoft.com/adaptive-cards/ | Adaptive Cards Documentation}
9
+ */
10
+ export interface AdaptiveCard {
11
+ /**
12
+ * The type of the card, which must always be 'AdaptiveCard'.
13
+ */
14
+ type: 'AdaptiveCard'
15
+ [key: string]: any
16
+ }
@@ -16,3 +16,4 @@ export * from './taskModuleAction'
16
16
  export * from './thumbnailCard'
17
17
  export * from './videoCard'
18
18
  export * from './thumbnailUrl'
19
+ export * from './adaptiveCard'
@@ -198,25 +198,23 @@ export class CloudAdapter extends BaseAdapter {
198
198
  }
199
199
 
200
200
  logger.debug('Received activity: ', activity)
201
+ const context = this.createTurnContext(activity, logic)
202
+ const scope = request.user?.azp ?? request.user?.appid ?? 'https://api.botframework.com'
203
+ logger.debug('Creating connector client with scope: ', scope)
204
+ this.connectorClient = await this.createConnectorClient(activity.serviceUrl!, scope)
205
+ this.setConnectorClient(context)
201
206
 
202
207
  if (
203
208
  activity?.type === ActivityTypes.InvokeResponse ||
204
209
  activity?.type === ActivityTypes.Invoke ||
205
210
  activity?.deliveryMode === DeliveryModes.ExpectReplies
206
211
  ) {
207
- const context = this.createTurnContext(activity, logic)
208
212
  await this.runMiddleware(context, logic)
209
213
  const invokeResponse = this.processTurnResults(context)
210
214
  logger.debug('Activity Response (invoke/expect replies): ', invokeResponse)
211
215
  return end(invokeResponse?.status ?? StatusCodes.OK, JSON.stringify(invokeResponse?.body), true)
212
216
  }
213
217
 
214
- const scope = request.user?.azp ?? request.user?.appid ?? 'https://api.botframework.com'
215
- logger.debug('Creating connector client with scope: ', scope)
216
- this.connectorClient = await this.createConnectorClient(activity.serviceUrl!, scope)
217
-
218
- const context = this.createTurnContext(activity, logic)
219
- this.setConnectorClient(context)
220
218
  await this.runMiddleware(context, logic)
221
219
  const invokeResponse = this.processTurnResults(context)
222
220