@microsoft/agents-hosting 0.2.14 → 0.4.1
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.
- package/README.md +17 -1
- package/dist/src/app/agentApplication.d.ts +27 -15
- package/dist/src/app/agentApplication.js +36 -31
- package/dist/src/app/agentApplication.js.map +1 -1
- package/dist/src/app/agentApplicationBuilder.d.ts +3 -4
- package/dist/src/app/agentApplicationBuilder.js +7 -7
- package/dist/src/app/agentApplicationBuilder.js.map +1 -1
- package/dist/src/app/agentApplicationOptions.d.ts +26 -2
- package/dist/src/app/appRoute.d.ts +6 -0
- package/dist/src/app/attachmentDownloader.d.ts +18 -0
- package/dist/src/app/attachmentDownloader.js +18 -0
- package/dist/src/app/attachmentDownloader.js.map +1 -1
- package/dist/src/app/conversationUpdateEvents.d.ts +6 -0
- package/dist/src/app/index.d.ts +1 -1
- package/dist/src/app/index.js +1 -1
- package/dist/src/app/index.js.map +1 -1
- package/dist/src/app/inputFileDownloader.d.ts +22 -0
- package/dist/src/app/oauth/authorization.d.ts +87 -0
- package/dist/src/app/oauth/authorization.js +135 -0
- package/dist/src/app/oauth/authorization.js.map +1 -0
- package/dist/src/app/routeHandler.d.ts +8 -0
- package/dist/src/app/routeSelector.d.ts +9 -0
- package/dist/src/app/turnState.d.ts +128 -15
- package/dist/src/app/turnState.js +114 -16
- package/dist/src/app/turnState.js.map +1 -1
- package/dist/src/auth/authConfiguration.d.ts +24 -0
- package/dist/src/auth/authConfiguration.js.map +1 -1
- package/dist/src/auth/request.d.ts +12 -0
- package/dist/src/baseAdapter.d.ts +17 -0
- package/dist/src/baseAdapter.js +17 -0
- package/dist/src/baseAdapter.js.map +1 -1
- package/dist/src/cards/cardFactory.d.ts +3 -0
- package/dist/src/cards/cardFactory.js +3 -0
- package/dist/src/cards/cardFactory.js.map +1 -1
- package/dist/src/cards/o365ConnectorCardActionBase.d.ts +8 -0
- package/dist/src/oauth/oAuthFlow.d.ts +32 -3
- package/dist/src/oauth/oAuthFlow.js +38 -14
- package/dist/src/oauth/oAuthFlow.js.map +1 -1
- package/dist/src/oauth/userTokenClient.d.ts +2 -2
- package/dist/src/oauth/userTokenClient.js +3 -3
- package/dist/src/oauth/userTokenClient.js.map +1 -1
- package/dist/src/state/agentStatePropertyAccesor.d.ts +1 -1
- package/dist/src/state/agentStatePropertyAccesor.js +1 -1
- package/dist/src/statusCodes.d.ts +39 -0
- package/dist/src/statusCodes.js +39 -0
- package/dist/src/statusCodes.js.map +1 -1
- package/dist/src/storage/fileStorage.d.ts +9 -0
- package/dist/src/storage/fileStorage.js +62 -0
- package/dist/src/storage/fileStorage.js.map +1 -0
- package/dist/src/storage/index.d.ts +1 -0
- package/dist/src/storage/index.js +1 -0
- package/dist/src/storage/index.js.map +1 -1
- package/dist/src/tokenResponseEventName.d.ts +3 -0
- package/dist/src/tokenResponseEventName.js +3 -0
- package/dist/src/tokenResponseEventName.js.map +1 -1
- package/package.json +4 -4
- package/src/app/agentApplication.ts +36 -32
- package/src/app/agentApplicationBuilder.ts +8 -8
- package/src/app/agentApplicationOptions.ts +33 -2
- package/src/app/appRoute.ts +7 -0
- package/src/app/attachmentDownloader.ts +18 -0
- package/src/app/conversationUpdateEvents.ts +6 -0
- package/src/app/index.ts +1 -1
- package/src/app/inputFileDownloader.ts +24 -0
- package/src/app/oauth/authorization.ts +162 -0
- package/src/app/routeHandler.ts +8 -0
- package/src/app/routeSelector.ts +9 -0
- package/src/app/turnState.ts +129 -33
- package/src/auth/authConfiguration.ts +32 -1
- package/src/auth/request.ts +15 -0
- package/src/baseAdapter.ts +18 -0
- package/src/cards/cardFactory.ts +3 -0
- package/src/cards/o365ConnectorCardActionBase.ts +8 -0
- package/src/oauth/oAuthFlow.ts +59 -18
- package/src/oauth/userTokenClient.ts +4 -4
- package/src/state/agentStatePropertyAccesor.ts +1 -1
- package/src/statusCodes.ts +51 -0
- package/src/storage/fileStorage.ts +59 -0
- package/src/storage/index.ts +1 -0
- package/src/tokenResponseEventName.ts +3 -0
- package/dist/src/app/oauth/userIdentity.d.ts +0 -43
- package/dist/src/app/oauth/userIdentity.js +0 -54
- package/dist/src/app/oauth/userIdentity.js.map +0 -1
- package/src/app/oauth/userIdentity.ts +0 -78
|
@@ -15,8 +15,7 @@ import { AppRoute } from './appRoute'
|
|
|
15
15
|
import { TurnContext } from '../turnContext'
|
|
16
16
|
import { ResourceResponse } from '../connector-client'
|
|
17
17
|
import { debug } from '../logger'
|
|
18
|
-
import {
|
|
19
|
-
import { MemoryStorage } from '../storage'
|
|
18
|
+
import { Authorization } from './oauth/authorization'
|
|
20
19
|
|
|
21
20
|
const logger = debug('agents:agent-application')
|
|
22
21
|
|
|
@@ -46,14 +45,14 @@ export class AgentApplication<TState extends TurnState> {
|
|
|
46
45
|
protected readonly _beforeTurn: ApplicationEventHandler<TState>[] = []
|
|
47
46
|
protected readonly _afterTurn: ApplicationEventHandler<TState>[] = []
|
|
48
47
|
private readonly _adapter?: BaseAdapter
|
|
48
|
+
private readonly _authorization?: Authorization
|
|
49
49
|
private _typingTimer: any
|
|
50
|
-
private readonly _userIdentity?: UserIdentity
|
|
51
50
|
|
|
52
51
|
public constructor (options?: Partial<AgentApplicationOptions<TState>>) {
|
|
53
52
|
this._options = {
|
|
54
53
|
...options,
|
|
55
54
|
turnStateFactory: options?.turnStateFactory || (() => new TurnState() as TState),
|
|
56
|
-
startTypingTimer: options?.startTypingTimer !== undefined ? options.startTypingTimer :
|
|
55
|
+
startTypingTimer: options?.startTypingTimer !== undefined ? options.startTypingTimer : false,
|
|
57
56
|
longRunningMessages: options?.longRunningMessages !== undefined ? options.longRunningMessages : false
|
|
58
57
|
}
|
|
59
58
|
|
|
@@ -61,8 +60,8 @@ export class AgentApplication<TState extends TurnState> {
|
|
|
61
60
|
this._adapter = this._options.adapter
|
|
62
61
|
}
|
|
63
62
|
|
|
64
|
-
if (this._options.
|
|
65
|
-
this.
|
|
63
|
+
if (this._options.authorization) {
|
|
64
|
+
this._authorization = new Authorization(this._options.storage!, this._options.authorization)
|
|
66
65
|
}
|
|
67
66
|
|
|
68
67
|
if (this._options.longRunningMessages && !this._adapter && !this._options.agentAppId) {
|
|
@@ -72,6 +71,10 @@ export class AgentApplication<TState extends TurnState> {
|
|
|
72
71
|
}
|
|
73
72
|
}
|
|
74
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Gets the adapter associated with the application.
|
|
76
|
+
* @throws Error if the adapter is not configured.
|
|
77
|
+
*/
|
|
75
78
|
public get adapter (): BaseAdapter {
|
|
76
79
|
if (!this._adapter) {
|
|
77
80
|
throw new Error(
|
|
@@ -82,16 +85,24 @@ export class AgentApplication<TState extends TurnState> {
|
|
|
82
85
|
return this._adapter
|
|
83
86
|
}
|
|
84
87
|
|
|
85
|
-
|
|
86
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Gets the authorization instance for the application.
|
|
90
|
+
* @throws Error if no authentication options were configured.
|
|
91
|
+
*/
|
|
92
|
+
public get authorization (): Authorization {
|
|
93
|
+
if (!this._authorization) {
|
|
87
94
|
throw new Error(
|
|
88
|
-
'The Application.
|
|
95
|
+
'The Application.authorization property is unavailable because no authentication options were configured.'
|
|
89
96
|
)
|
|
90
97
|
}
|
|
91
98
|
|
|
92
|
-
return this.
|
|
99
|
+
return this._authorization
|
|
93
100
|
}
|
|
94
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Gets the options used to configure the application.
|
|
104
|
+
* @returns The application options.
|
|
105
|
+
*/
|
|
95
106
|
public get options (): AgentApplicationOptions<TState> {
|
|
96
107
|
return this._options
|
|
97
108
|
}
|
|
@@ -108,13 +119,13 @@ export class AgentApplication<TState extends TurnState> {
|
|
|
108
119
|
*
|
|
109
120
|
* Example usage:
|
|
110
121
|
* ```typescript
|
|
111
|
-
* app.
|
|
122
|
+
* app.onError(async (context, error) => {
|
|
112
123
|
* console.error(`An error occurred: ${error.message}`);
|
|
113
124
|
* await context.sendActivity('Sorry, something went wrong!');
|
|
114
125
|
* });
|
|
115
126
|
* ```
|
|
116
127
|
*/
|
|
117
|
-
public
|
|
128
|
+
public onError (handler: (context: TurnContext, error: Error) => Promise<void>): this {
|
|
118
129
|
if (this._adapter) {
|
|
119
130
|
this._adapter.onTurnError = handler
|
|
120
131
|
}
|
|
@@ -160,12 +171,12 @@ export class AgentApplication<TState extends TurnState> {
|
|
|
160
171
|
*
|
|
161
172
|
* Example usage:
|
|
162
173
|
* ```typescript
|
|
163
|
-
* app.
|
|
174
|
+
* app.onActivity(ActivityTypes.Message, async (context, state) => {
|
|
164
175
|
* await context.sendActivity('I received your message');
|
|
165
176
|
* });
|
|
166
177
|
* ```
|
|
167
178
|
*/
|
|
168
|
-
public
|
|
179
|
+
public onActivity (
|
|
169
180
|
type: string | RegExp | RouteSelector | (string | RegExp | RouteSelector)[],
|
|
170
181
|
handler: (context: TurnContext, state: TState) => Promise<void>
|
|
171
182
|
): this {
|
|
@@ -189,7 +200,7 @@ export class AgentApplication<TState extends TurnState> {
|
|
|
189
200
|
*
|
|
190
201
|
* Example usage:
|
|
191
202
|
* ```typescript
|
|
192
|
-
* app.
|
|
203
|
+
* app.onConversationUpdate('membersAdded', async (context, state) => {
|
|
193
204
|
* const membersAdded = context.activity.membersAdded;
|
|
194
205
|
* for (const member of membersAdded) {
|
|
195
206
|
* if (member.id !== context.activity.recipient.id) {
|
|
@@ -199,7 +210,7 @@ export class AgentApplication<TState extends TurnState> {
|
|
|
199
210
|
* });
|
|
200
211
|
* ```
|
|
201
212
|
*/
|
|
202
|
-
public
|
|
213
|
+
public onConversationUpdate (
|
|
203
214
|
event: ConversationUpdateEvents,
|
|
204
215
|
handler: (context: TurnContext, state: TState) => Promise<void>
|
|
205
216
|
): this {
|
|
@@ -262,16 +273,16 @@ export class AgentApplication<TState extends TurnState> {
|
|
|
262
273
|
*
|
|
263
274
|
* Example usage:
|
|
264
275
|
* ```typescript
|
|
265
|
-
* app.
|
|
276
|
+
* app.onMessage('hello', async (context, state) => {
|
|
266
277
|
* await context.sendActivity('Hello there!');
|
|
267
278
|
* });
|
|
268
279
|
*
|
|
269
|
-
* app.
|
|
280
|
+
* app.onMessage(/help., async (context, state) => {
|
|
270
281
|
* await context.sendActivity('How can I help you?');
|
|
271
282
|
* });
|
|
272
283
|
* ```
|
|
273
284
|
*/
|
|
274
|
-
public
|
|
285
|
+
public onMessage (
|
|
275
286
|
keyword: string | RegExp | RouteSelector | (string | RegExp | RouteSelector)[],
|
|
276
287
|
handler: (context: TurnContext, state: TState) => Promise<void>
|
|
277
288
|
): this {
|
|
@@ -300,9 +311,9 @@ export class AgentApplication<TState extends TurnState> {
|
|
|
300
311
|
* });
|
|
301
312
|
* ```
|
|
302
313
|
*/
|
|
303
|
-
public onSignInSuccess (handler: (context: TurnContext, state: TurnState) => void): this {
|
|
304
|
-
if (this.
|
|
305
|
-
this.
|
|
314
|
+
public onSignInSuccess (handler: (context: TurnContext, state: TurnState, id?: string) => void): this {
|
|
315
|
+
if (this.options.authorization) {
|
|
316
|
+
this.authorization.onSignInSuccess(handler)
|
|
306
317
|
} else {
|
|
307
318
|
throw new Error(
|
|
308
319
|
'The Application.authentication property is unavailable because no authentication options were configured.'
|
|
@@ -355,10 +366,6 @@ export class AgentApplication<TState extends TurnState> {
|
|
|
355
366
|
return false
|
|
356
367
|
}
|
|
357
368
|
|
|
358
|
-
if (typeof state.temp.input !== 'string') {
|
|
359
|
-
state.temp.input = context.activity.text ?? ''
|
|
360
|
-
}
|
|
361
|
-
|
|
362
369
|
if (Array.isArray(this._options.fileDownloaders) && this._options.fileDownloaders.length > 0) {
|
|
363
370
|
const inputFiles = state.temp.inputFiles ?? []
|
|
364
371
|
for (let i = 0; i < this._options.fileDownloaders.length; i++) {
|
|
@@ -368,10 +375,6 @@ export class AgentApplication<TState extends TurnState> {
|
|
|
368
375
|
state.temp.inputFiles = inputFiles
|
|
369
376
|
}
|
|
370
377
|
|
|
371
|
-
if (state.temp.actionOutputs === undefined) {
|
|
372
|
-
state.temp.actionOutputs = {}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
378
|
for (let i = 0; i < this._routes.length; i++) {
|
|
376
379
|
const route = this._routes[i]
|
|
377
380
|
if (await route.selector(context)) {
|
|
@@ -532,19 +535,20 @@ export class AgentApplication<TState extends TurnState> {
|
|
|
532
535
|
*
|
|
533
536
|
* Example usage:
|
|
534
537
|
* ```typescript
|
|
535
|
-
* app.
|
|
538
|
+
* app.onTurn('beforeTurn', async (context, state) => {
|
|
536
539
|
* console.log('Processing before turn');
|
|
537
540
|
* return true; // Continue execution
|
|
538
541
|
* });
|
|
539
542
|
* ```
|
|
540
543
|
*/
|
|
541
|
-
public
|
|
544
|
+
public onTurn (
|
|
542
545
|
event: TurnEvents | TurnEvents[],
|
|
543
546
|
handler: (context: TurnContext, state: TState) => Promise<boolean>
|
|
544
547
|
): this {
|
|
545
548
|
(Array.isArray(event) ? event : [event]).forEach((e) => {
|
|
546
549
|
switch (e) {
|
|
547
550
|
case 'beforeTurn':
|
|
551
|
+
this._beforeTurn.push(handler)
|
|
548
552
|
break
|
|
549
553
|
case 'afterTurn':
|
|
550
554
|
this._afterTurn.push(handler)
|
|
@@ -7,7 +7,7 @@ import { AgentApplication } from './agentApplication'
|
|
|
7
7
|
import { AgentApplicationOptions } from './agentApplicationOptions'
|
|
8
8
|
import { TurnState } from './turnState'
|
|
9
9
|
import { Storage } from '../storage'
|
|
10
|
-
import {
|
|
10
|
+
import { AuthorizationHandlers } from './oauth/authorization'
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Builder class for creating and configuring AgentApplication instances.
|
|
@@ -49,18 +49,18 @@ export class AgentApplicationBuilder<TState extends TurnState = TurnState> {
|
|
|
49
49
|
* @param startTypingTimer Whether to show typing indicators
|
|
50
50
|
* @returns This builder instance for chaining
|
|
51
51
|
*/
|
|
52
|
-
public setStartTypingTimer (startTypingTimer: boolean): this {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
52
|
+
// public setStartTypingTimer (startTypingTimer: boolean): this {
|
|
53
|
+
// this._options.startTypingTimer = startTypingTimer
|
|
54
|
+
// return this
|
|
55
|
+
// }
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* Sets authentication options for the AgentApplication.
|
|
59
|
-
* @param
|
|
59
|
+
* @param authHandlers The user identity authentication options
|
|
60
60
|
* @returns This builder instance for chaining
|
|
61
61
|
*/
|
|
62
|
-
public
|
|
63
|
-
this._options.
|
|
62
|
+
public withAuthorization (authHandlers: AuthorizationHandlers): this {
|
|
63
|
+
this._options.authorization = authHandlers
|
|
64
64
|
return this
|
|
65
65
|
}
|
|
66
66
|
|
|
@@ -7,15 +7,46 @@ import { CloudAdapter } from '../cloudAdapter'
|
|
|
7
7
|
import { InputFileDownloader } from './inputFileDownloader'
|
|
8
8
|
import { TurnState } from './turnState'
|
|
9
9
|
import { Storage } from '../storage'
|
|
10
|
-
import {
|
|
10
|
+
import { AuthorizationHandlers } from './oauth/authorization'
|
|
11
11
|
|
|
12
12
|
export interface AgentApplicationOptions<TState extends TurnState> {
|
|
13
|
+
/**
|
|
14
|
+
* The adapter used for handling bot interactions.
|
|
15
|
+
*/
|
|
13
16
|
adapter?: CloudAdapter;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The application ID of the agent.
|
|
20
|
+
*/
|
|
14
21
|
agentAppId?: string;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The storage mechanism for persisting state.
|
|
25
|
+
*/
|
|
15
26
|
storage?: Storage;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Whether to start a typing timer for the bot.
|
|
30
|
+
*/
|
|
16
31
|
startTypingTimer: boolean;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Whether to enable long-running messages.
|
|
35
|
+
*/
|
|
17
36
|
longRunningMessages: boolean;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* A factory function to create the turn state.
|
|
40
|
+
*/
|
|
18
41
|
turnStateFactory: () => TState;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* An array of file downloaders for handling input files.
|
|
45
|
+
*/
|
|
19
46
|
fileDownloaders?: InputFileDownloader<TState>[];
|
|
20
|
-
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Handlers for managing authorization.
|
|
50
|
+
*/
|
|
51
|
+
authorization?: AuthorizationHandlers;
|
|
21
52
|
}
|
package/src/app/appRoute.ts
CHANGED
|
@@ -8,6 +8,13 @@ import { RouteSelector } from './routeSelector'
|
|
|
8
8
|
import { TurnState } from './turnState'
|
|
9
9
|
|
|
10
10
|
export interface AppRoute<TState extends TurnState> {
|
|
11
|
+
/**
|
|
12
|
+
* The selector function used to determine if this route should handle the current activity.
|
|
13
|
+
*/
|
|
11
14
|
selector: RouteSelector;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The handler function that processes the activity if the selector matches.
|
|
18
|
+
*/
|
|
12
19
|
handler: RouteHandler<TState>;
|
|
13
20
|
}
|
|
@@ -14,13 +14,31 @@ import { loadAuthConfigFromEnv, MsalTokenProvider } from '../auth'
|
|
|
14
14
|
|
|
15
15
|
const logger = debug('agents:attachmentDownloader')
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* A utility class for downloading input files from activity attachments.
|
|
19
|
+
*
|
|
20
|
+
* This class provides functionality to filter and download attachments from a turn context,
|
|
21
|
+
* supporting various content types and handling authentication for secure URLs.
|
|
22
|
+
*
|
|
23
|
+
* @typeParam TState - The type of the turn state used in the application.
|
|
24
|
+
*/
|
|
17
25
|
export class AttachmentDownloader<TState extends TurnState = TurnState> implements InputFileDownloader<TState> {
|
|
18
26
|
private _httpClient: AxiosInstance
|
|
19
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Creates an instance of AttachmentDownloader.
|
|
30
|
+
* This class is responsible for downloading input files from attachments.
|
|
31
|
+
*/
|
|
20
32
|
public constructor () {
|
|
21
33
|
this._httpClient = axios.create()
|
|
22
34
|
}
|
|
23
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Downloads files from the attachments in the current turn context.
|
|
38
|
+
* @param context The turn context containing the activity with attachments.
|
|
39
|
+
* @param state The turn state for the current conversation.
|
|
40
|
+
* @returns A promise that resolves to an array of downloaded input files.
|
|
41
|
+
*/
|
|
24
42
|
public async downloadFiles (context: TurnContext, state: TState): Promise<InputFile[]> {
|
|
25
43
|
const attachments = context.activity.attachments?.filter((a) => !a.contentType.startsWith('text/html'))
|
|
26
44
|
if (!attachments || attachments.length === 0) {
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Represents the types of conversation update events that can occur.
|
|
8
|
+
*
|
|
9
|
+
* - `membersAdded`: Triggered when new members are added to the conversation.
|
|
10
|
+
* - `membersRemoved`: Triggered when members are removed from the conversation.
|
|
11
|
+
*/
|
|
6
12
|
export type ConversationUpdateEvents =
|
|
7
13
|
| 'membersAdded'
|
|
8
14
|
| 'membersRemoved'
|
package/src/app/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ export * from './agentApplicationBuilder'
|
|
|
3
3
|
export * from './agentApplicationOptions'
|
|
4
4
|
export * from './appRoute'
|
|
5
5
|
export * from './attachmentDownloader'
|
|
6
|
-
export * from './oauth/
|
|
6
|
+
export * from './oauth/authorization'
|
|
7
7
|
export * from './conversationUpdateEvents'
|
|
8
8
|
export * from './routeHandler'
|
|
9
9
|
export * from './routeSelector'
|
|
@@ -6,12 +6,36 @@
|
|
|
6
6
|
import { TurnContext } from '../turnContext'
|
|
7
7
|
import { TurnState } from './turnState'
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Represents a file input with its content, type, and optional URL.
|
|
11
|
+
*/
|
|
9
12
|
export interface InputFile {
|
|
13
|
+
/**
|
|
14
|
+
* The content of the file as a Buffer.
|
|
15
|
+
*/
|
|
10
16
|
content: Buffer;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The MIME type of the file content.
|
|
20
|
+
*/
|
|
11
21
|
contentType: string;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* An optional URL pointing to the file content.
|
|
25
|
+
*/
|
|
12
26
|
contentUrl?: string;
|
|
13
27
|
}
|
|
14
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Interface for downloading input files in a specific turn context and state.
|
|
31
|
+
*/
|
|
15
32
|
export interface InputFileDownloader<TState extends TurnState = TurnState> {
|
|
33
|
+
/**
|
|
34
|
+
* Downloads files based on the provided turn context and state.
|
|
35
|
+
*
|
|
36
|
+
* @param context - The turn context for the current operation.
|
|
37
|
+
* @param state - The state associated with the current turn.
|
|
38
|
+
* @returns A promise that resolves to an array of input files.
|
|
39
|
+
*/
|
|
16
40
|
downloadFiles(context: TurnContext, state: TState): Promise<InputFile[]>;
|
|
17
41
|
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { TurnContext } from '../../turnContext'
|
|
7
|
+
import { debug } from '../../logger'
|
|
8
|
+
import { TurnState } from '../turnState'
|
|
9
|
+
import { Storage } from '../../storage'
|
|
10
|
+
import { OAuthFlow, TokenRequestStatus, TokenResponse } from '../../oauth'
|
|
11
|
+
import { UserState } from '../../state'
|
|
12
|
+
|
|
13
|
+
const logger = debug('agents:authorization')
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Interface defining an authorization handler for OAuth flows
|
|
17
|
+
* @interface AuthHandler
|
|
18
|
+
*/
|
|
19
|
+
export interface AuthHandler {
|
|
20
|
+
/** Connection name for the auth provider */
|
|
21
|
+
name?: string,
|
|
22
|
+
/** Whether authorization should be triggered automatically */
|
|
23
|
+
auto?: boolean,
|
|
24
|
+
/** The OAuth flow implementation */
|
|
25
|
+
flow?: OAuthFlow,
|
|
26
|
+
/** Title to display on auth cards/UI */
|
|
27
|
+
title?: string,
|
|
28
|
+
/** Text to display on auth cards/UI */
|
|
29
|
+
text?: string,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Options for configuring user authorization.
|
|
34
|
+
* Contains settings to configure OAuth connections.
|
|
35
|
+
*/
|
|
36
|
+
export interface AuthorizationHandlers extends Record<string, AuthHandler> {}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Class responsible for managing authorization and OAuth flows
|
|
40
|
+
* @class Authorization
|
|
41
|
+
*/
|
|
42
|
+
export class Authorization {
|
|
43
|
+
_authHandlers: AuthorizationHandlers
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Creates a new instance of UserAuthorization.
|
|
47
|
+
* @param {Storage} storage - The storage system to use for state management.
|
|
48
|
+
* @param {AuthorizationHandlers} authHandlers - Configuration for OAuth providers
|
|
49
|
+
* @throws {Error} If storage is null/undefined or no auth handlers are provided
|
|
50
|
+
*/
|
|
51
|
+
constructor (storage: Storage, authHandlers: AuthorizationHandlers) {
|
|
52
|
+
if (storage === undefined || storage === null) {
|
|
53
|
+
throw new Error('Storage is required for UserAuthorization')
|
|
54
|
+
}
|
|
55
|
+
const userState = new UserState(storage)
|
|
56
|
+
if (authHandlers === undefined || Object.keys(authHandlers).length === 0) {
|
|
57
|
+
throw new Error('The authorization does not have any auth handlers')
|
|
58
|
+
}
|
|
59
|
+
this._authHandlers = authHandlers
|
|
60
|
+
for (const ah in this._authHandlers) {
|
|
61
|
+
if (this._authHandlers![ah].name === undefined && process.env[ah + '_connectionName'] === undefined) {
|
|
62
|
+
throw new Error(`AuthHandler name ${ah}_connectionName not set in autorization and not found in env vars.`)
|
|
63
|
+
}
|
|
64
|
+
const currentAuthHandler = this._authHandlers![ah]
|
|
65
|
+
currentAuthHandler.name = currentAuthHandler.name ?? process.env[ah + '_connectionName'] as string
|
|
66
|
+
currentAuthHandler.title = currentAuthHandler.title ?? process.env[ah + '_connectionTitle'] as string
|
|
67
|
+
currentAuthHandler.text = currentAuthHandler.text ?? process.env[ah + '_connectionText'] as string
|
|
68
|
+
currentAuthHandler.auto = currentAuthHandler.auto ?? process.env[ah + '_connectionAuto'] === 'true'
|
|
69
|
+
currentAuthHandler.flow = new OAuthFlow(userState, currentAuthHandler.name, null!, currentAuthHandler.title, currentAuthHandler.text)
|
|
70
|
+
}
|
|
71
|
+
logger.info('Authorization handlers configured with', this._authHandlers.length, 'handlers')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Gets the token for a specific auth handler
|
|
76
|
+
* @param {TurnContext} context - The context object for the current turn
|
|
77
|
+
* @param {string} [authHandlerId] - Optional ID of the auth handler to use, defaults to first handler
|
|
78
|
+
* @returns {Promise<TokenResponse>} The token response from the OAuth provider
|
|
79
|
+
*/
|
|
80
|
+
public async getToken (context: TurnContext, authHandlerId?: string): Promise<TokenResponse> {
|
|
81
|
+
logger.info('getToken from user token service for authHandlerId:', authHandlerId)
|
|
82
|
+
const authHandler = this.resolverHandler(authHandlerId)
|
|
83
|
+
return await authHandler.flow?.getUserToken(context)!
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Begins or continues an OAuth flow
|
|
88
|
+
* @param {TurnContext} context - The context object for the current turn
|
|
89
|
+
* @param {TurnState} state - The state object for the current turn
|
|
90
|
+
* @param {string} [authHandlerId] - Optional ID of the auth handler to use, defaults to first handler
|
|
91
|
+
* @returns {Promise<TokenResponse>} The token response from the OAuth provider
|
|
92
|
+
*/
|
|
93
|
+
public async beginOrContinueFlow (context: TurnContext, state: TurnState, authHandlerId?: string) : Promise<TokenResponse> {
|
|
94
|
+
logger.info('beginOrContinueFlow for authHandlerId:', authHandlerId)
|
|
95
|
+
const flow = this.resolverHandler(authHandlerId).flow!
|
|
96
|
+
let tokenResponse: TokenResponse
|
|
97
|
+
if (flow.state!.flowStarted === false) {
|
|
98
|
+
tokenResponse = await flow.beginFlow(context)
|
|
99
|
+
} else {
|
|
100
|
+
tokenResponse = await flow.continueFlow(context)
|
|
101
|
+
if (tokenResponse.status === TokenRequestStatus.Success) {
|
|
102
|
+
if (this._signInHandler) {
|
|
103
|
+
await this._signInHandler(context, state, authHandlerId)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return tokenResponse
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Gets the current state of the OAuth flow
|
|
112
|
+
* @param {string} [authHandlerId] - Optional ID of the auth handler to check, defaults to first handler
|
|
113
|
+
* @returns {boolean} Whether the flow has started
|
|
114
|
+
*/
|
|
115
|
+
public getFlowState (authHandlerId?: string) : boolean {
|
|
116
|
+
const flow = this.resolverHandler(authHandlerId).flow!
|
|
117
|
+
return flow.state?.flowStarted!
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Resolves the auth handler to use based on the provided ID
|
|
122
|
+
* @param {string} [authHandlerId] - Optional ID of the auth handler to resolve, defaults to first handler
|
|
123
|
+
* @returns {AuthHandler} The resolved auth handler
|
|
124
|
+
*/
|
|
125
|
+
resolverHandler = (authHandlerId?: string) : AuthHandler => {
|
|
126
|
+
if (authHandlerId) {
|
|
127
|
+
return this._authHandlers![authHandlerId]
|
|
128
|
+
}
|
|
129
|
+
return this._authHandlers![Object.keys(this._authHandlers)[0]]
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Signs out the current user.
|
|
134
|
+
* This method clears the user's token and resets the SSO state.
|
|
135
|
+
*
|
|
136
|
+
* @param {TurnContext} context - The context object for the current turn.
|
|
137
|
+
* @param {TurnState} state - The state object for the current turn.
|
|
138
|
+
* @param {string} [authHandlerId] - Optional ID of the auth handler to use for sign out
|
|
139
|
+
* @returns {Promise<void>}
|
|
140
|
+
*/
|
|
141
|
+
async signOut (context: TurnContext, state: TurnState, authHandlerId?: string) : Promise<void> {
|
|
142
|
+
logger.info('signOut for authHandlerId:', authHandlerId)
|
|
143
|
+
if (authHandlerId === undefined) { // aw
|
|
144
|
+
for (const ah in this._authHandlers) {
|
|
145
|
+
const flow = this._authHandlers[ah].flow
|
|
146
|
+
await flow?.signOut(context)
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
await this.resolverHandler(authHandlerId).flow?.signOut(context)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
_signInHandler: ((context: TurnContext, state: TurnState, authHandlerId?: string) => void) | null = null
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Sets a handler to be called when sign-in is successfully completed
|
|
157
|
+
* @param {Function} handler - The handler function to call on successful sign-in
|
|
158
|
+
*/
|
|
159
|
+
public onSignInSuccess (handler: (context: TurnContext, state: TurnState, authHandlerId?: string) => void) {
|
|
160
|
+
this._signInHandler = handler
|
|
161
|
+
}
|
|
162
|
+
}
|
package/src/app/routeHandler.ts
CHANGED
|
@@ -6,4 +6,12 @@
|
|
|
6
6
|
import { TurnContext } from '../turnContext'
|
|
7
7
|
import { TurnState } from './turnState'
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* A handler function for routing operations in a specific turn context and state.
|
|
11
|
+
*
|
|
12
|
+
* @typeParam TState - The type of the turn state.
|
|
13
|
+
* @param context - The turn context for the current operation.
|
|
14
|
+
* @param state - The state associated with the current turn.
|
|
15
|
+
* @returns A promise that resolves when the routing operation is complete.
|
|
16
|
+
*/
|
|
9
17
|
export type RouteHandler<TState extends TurnState> = (context: TurnContext, state: TState) => Promise<void>
|
package/src/app/routeSelector.ts
CHANGED
|
@@ -5,6 +5,15 @@
|
|
|
5
5
|
|
|
6
6
|
import { TurnContext } from '../turnContext'
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* A function that determines whether a specific condition is met in the given turn context.
|
|
10
|
+
*
|
|
11
|
+
* @param context - The turn context for the current operation.
|
|
12
|
+
* @returns A promise that resolves to a boolean indicating whether the condition is met.
|
|
13
|
+
*/
|
|
8
14
|
export type Selector = (context: TurnContext) => Promise<boolean>
|
|
9
15
|
|
|
16
|
+
/**
|
|
17
|
+
* A specialized selector for routing operations.
|
|
18
|
+
*/
|
|
10
19
|
export type RouteSelector = Selector
|