@microsoft/agents-hosting 1.6.0-beta.4.g8ab0e486bc → 1.6.0-beta.41.g36be9b7b46
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/dist/package.json +5 -9
- package/dist/src/agent-client/agentClient.js +2 -2
- package/dist/src/agent-client/agentClient.js.map +1 -1
- package/dist/src/agent-client/agentResponseHandler.js +2 -2
- package/dist/src/agent-client/agentResponseHandler.js.map +1 -1
- package/dist/src/app/agentApplication.js +27 -2
- package/dist/src/app/agentApplication.js.map +1 -1
- package/dist/src/app/auth/authorizationManager.d.ts +4 -0
- package/dist/src/app/auth/authorizationManager.js +94 -67
- package/dist/src/app/auth/authorizationManager.js.map +1 -1
- package/dist/src/app/auth/handlers/azureBotAuthorization.js +2 -2
- package/dist/src/app/auth/handlers/azureBotAuthorization.js.map +1 -1
- package/dist/src/app/proactive/createConversationOptionsBuilder.js +10 -6
- package/dist/src/app/proactive/createConversationOptionsBuilder.js.map +1 -1
- package/dist/src/app/teamsAttachmentDownloader.js +7 -1
- package/dist/src/app/teamsAttachmentDownloader.js.map +1 -1
- package/dist/src/auth/authConfiguration.d.ts +2 -143
- package/dist/src/auth/authConfiguration.js +301 -257
- package/dist/src/auth/authConfiguration.js.map +1 -1
- package/dist/src/auth/jwt-middleware.js +2 -1
- package/dist/src/auth/jwt-middleware.js.map +1 -1
- package/dist/src/auth/msalConnectionManager.js +27 -14
- package/dist/src/auth/msalConnectionManager.js.map +1 -1
- package/dist/src/auth/msalTokenProvider.d.ts +7 -0
- package/dist/src/auth/msalTokenProvider.js +156 -38
- package/dist/src/auth/msalTokenProvider.js.map +1 -1
- package/dist/src/auth/settings.d.ts +327 -0
- package/dist/src/auth/settings.js +158 -0
- package/dist/src/auth/settings.js.map +1 -0
- package/dist/src/cloudAdapter.d.ts +51 -1
- package/dist/src/cloudAdapter.js +219 -50
- package/dist/src/cloudAdapter.js.map +1 -1
- package/dist/src/connector-client/connectorClient.d.ts +2 -2
- package/dist/src/connector-client/connectorClient.js +7 -8
- package/dist/src/connector-client/connectorClient.js.map +1 -1
- package/dist/src/errorHelper.js +50 -0
- package/dist/src/errorHelper.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +6 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/oauth/userTokenClient.js +1 -1
- package/dist/src/oauth/userTokenClient.js.map +1 -1
- package/dist/src/observability/traces.d.ts +1 -1
- package/dist/src/observability/traces.js +2 -2
- package/dist/src/observability/traces.js.map +1 -1
- package/dist/src/utils/env.d.ts +50 -0
- package/dist/src/utils/env.js +113 -0
- package/dist/src/utils/env.js.map +1 -0
- package/dist/src/utils.d.ts +10 -0
- package/dist/src/utils.js +18 -0
- package/dist/src/utils.js.map +1 -0
- package/package.json +5 -9
- package/src/agent-client/agentClient.ts +2 -2
- package/src/agent-client/agentResponseHandler.ts +2 -2
- package/src/app/agentApplication.ts +28 -3
- package/src/app/auth/authorizationManager.ts +84 -41
- package/src/app/auth/handlers/azureBotAuthorization.ts +2 -2
- package/src/app/proactive/createConversationOptionsBuilder.ts +8 -4
- package/src/app/teamsAttachmentDownloader.ts +6 -1
- package/src/auth/authConfiguration.ts +317 -356
- package/src/auth/jwt-middleware.ts +1 -1
- package/src/auth/msalConnectionManager.ts +27 -10
- package/src/auth/msalTokenProvider.ts +143 -33
- package/src/auth/settings.ts +323 -0
- package/src/cloudAdapter.ts +272 -10
- package/src/connector-client/connectorClient.ts +8 -8
- package/src/errorHelper.ts +57 -0
- package/src/index.ts +4 -1
- package/src/oauth/userTokenClient.ts +1 -1
- package/src/observability/traces.ts +2 -2
- package/src/utils/env.ts +105 -0
- package/src/utils.ts +14 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { Activity, ExceptionHelper } from '@microsoft/agents-activity'
|
|
7
|
-
import { debug } from '@microsoft/agents-telemetry'
|
|
7
|
+
import { debug, redactScopes } from '@microsoft/agents-telemetry'
|
|
8
8
|
import { AgentApplication } from '../agentApplication'
|
|
9
9
|
import { AgenticAuthorization, AzureBotAuthorization } from './handlers'
|
|
10
10
|
import { TurnContext } from '../../turnContext'
|
|
@@ -13,7 +13,8 @@ import { Errors } from '../../errorHelper'
|
|
|
13
13
|
import { ActiveAuthorizationHandler, AuthorizationHandlerStatus, AuthorizationHandler, AuthorizationHandlerSettings, AuthorizationOptions } from './types'
|
|
14
14
|
import { Connections } from '../../auth/connections'
|
|
15
15
|
import { sendInvokeResponse } from './utils'
|
|
16
|
-
import { envParser, envParserUtils } from '../../auth'
|
|
16
|
+
import { envParser, envParserUtils } from '../../auth/settings'
|
|
17
|
+
import { prune } from '../../utils'
|
|
17
18
|
|
|
18
19
|
const logger = debug('agents:authorization:manager')
|
|
19
20
|
|
|
@@ -155,10 +156,6 @@ export class AuthorizationManager {
|
|
|
155
156
|
if (this.handlers.length === 0 && app.options.authorization !== undefined) {
|
|
156
157
|
throw ExceptionHelper.generateException(Error, Errors.NoAuthHandlersConfigured)
|
|
157
158
|
}
|
|
158
|
-
|
|
159
|
-
for (const [id, handler] of Object.entries(this._handlers)) {
|
|
160
|
-
logger.debug('auth handler "%s" type=%s scopes=%o', id, handler.type, handler.scopes)
|
|
161
|
-
}
|
|
162
159
|
}
|
|
163
160
|
|
|
164
161
|
/**
|
|
@@ -320,7 +317,7 @@ export class AuthorizationManager {
|
|
|
320
317
|
private createHandlers () {
|
|
321
318
|
let legacyMessage = ''
|
|
322
319
|
const settings: AuthorizationHandlerSettings = { storage: this.app.options.storage!, connections: this.connections }
|
|
323
|
-
|
|
320
|
+
const runtimeOptionEntries = Object.entries(this.app.options.authorization ?? {})
|
|
324
321
|
const result = { latest: {}, legacy: {} } as {
|
|
325
322
|
latest: Record<string, Record<string, any> | undefined>;
|
|
326
323
|
legacy: Record<string, Record<string, any> | undefined>;
|
|
@@ -335,7 +332,7 @@ export class AuthorizationManager {
|
|
|
335
332
|
|
|
336
333
|
// Legacy: extract handler ID, handler options key and its value, and assign it to the correct runtime handler ID.
|
|
337
334
|
if (!upperEnvKey.startsWith(this._envLatest.key.prefix.toUpperCase())) {
|
|
338
|
-
const [id] =
|
|
335
|
+
const [id] = runtimeOptionEntries.find(([id]) => upperEnvKey.startsWith(`${id.toUpperCase()}${this._envLegacy.key.separator}`)) ?? []
|
|
339
336
|
if (!id) {
|
|
340
337
|
continue
|
|
341
338
|
}
|
|
@@ -386,7 +383,7 @@ export class AuthorizationManager {
|
|
|
386
383
|
const fixTypes = (entries: [string, any][]) => entries
|
|
387
384
|
.map(([id, options]) => [id, { ...options, type: this.fixType(id, options?.type) }] as [string, AuthorizationOptions[string]])
|
|
388
385
|
|
|
389
|
-
runtimeEntries = fixTypes(
|
|
386
|
+
const runtimeEntries = fixTypes(runtimeOptionEntries)
|
|
390
387
|
const latestEntries = fixTypes(Object.entries(result.latest))
|
|
391
388
|
const legacyEntries = fixTypes(Object.entries(result.legacy))
|
|
392
389
|
|
|
@@ -396,39 +393,27 @@ export class AuthorizationManager {
|
|
|
396
393
|
continue
|
|
397
394
|
}
|
|
398
395
|
|
|
399
|
-
|
|
400
|
-
const [, runtime] = runtimeEntries.find(([key]) => key.toLowerCase() === id.toLowerCase()) ?? []
|
|
401
|
-
const [, latest] = latestEntries.find(([key]) => key.toLowerCase() === id.toLowerCase()) ?? []
|
|
402
|
-
const [, legacy] = legacyEntries.find(([key]) => key.toLowerCase() === id.toLowerCase()) ?? []
|
|
396
|
+
const { options, format } = this.resolveHandlerConfiguration(id, runtimeEntries, latestEntries, legacyEntries)
|
|
403
397
|
|
|
404
|
-
if (
|
|
405
|
-
|
|
398
|
+
if (options.type === AZURE_BOT) {
|
|
399
|
+
// Set default values if not provided
|
|
400
|
+
options.title ||= 'Sign-in'
|
|
401
|
+
options.text ||= 'Please sign-in to continue'
|
|
402
|
+
options.oboScopes ??= []
|
|
403
|
+
options.enableSso = options.enableSso !== false // default value is true if undefined.
|
|
406
404
|
}
|
|
407
405
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
runtime.invalidSignInRetryMessage ??= runtime.messages?.invalidCode
|
|
413
|
-
runtime.invalidSignInRetryMessageFormat ??= runtime.messages?.invalidCodeFormat
|
|
414
|
-
runtime.invalidSignInRetryMaxExceededMessage ??= runtime.messages?.maxAttemptsExceeded
|
|
415
|
-
runtime.oboConnectionName ??= runtime.obo?.connection
|
|
416
|
-
runtime.oboScopes ??= runtime.obo?.scopes
|
|
417
|
-
delete runtime.name
|
|
418
|
-
delete runtime.maxAttempts
|
|
419
|
-
delete runtime.messages
|
|
420
|
-
delete runtime.obo
|
|
406
|
+
const maskedOptions: any = {}
|
|
407
|
+
|
|
408
|
+
if ('oboScopes' in options && options.oboScopes && options.oboScopes.length > 0) {
|
|
409
|
+
maskedOptions.oboScopes = redactScopes(options.oboScopes)
|
|
421
410
|
}
|
|
422
411
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
const entries = Object.entries(obj).filter(([, e]) => e !== undefined)
|
|
426
|
-
return Object.fromEntries(entries) as T
|
|
412
|
+
if ('scopes' in options && options.scopes && options.scopes.length > 0) {
|
|
413
|
+
maskedOptions.scopes = redactScopes(options.scopes)
|
|
427
414
|
}
|
|
428
415
|
|
|
429
|
-
|
|
430
|
-
// Pruning done individually to avoid overwriting with undefined when merging.
|
|
431
|
-
const options: AuthorizationOptions[string] = runtime ? { ...prune(legacy || {}), ...prune(runtime) } : prune(latest || {})
|
|
416
|
+
logger.info(this.prefix(id, 'settings loaded from \'%s\''), format, { ...options, ...maskedOptions })
|
|
432
417
|
|
|
433
418
|
if (!settings.storage) {
|
|
434
419
|
throw ExceptionHelper.generateException(Error, Errors.StorageRequiredForAuthorization)
|
|
@@ -437,12 +422,6 @@ export class AuthorizationManager {
|
|
|
437
422
|
if (options.type === AGENTIC) {
|
|
438
423
|
this._handlers[id] = new AgenticAuthorization(id, options, settings)
|
|
439
424
|
} else if (options.type === AZURE_BOT) {
|
|
440
|
-
// Set default values if not provided
|
|
441
|
-
options.title ||= 'Sign-in'
|
|
442
|
-
options.text ||= 'Please sign-in to continue'
|
|
443
|
-
options.oboScopes ??= []
|
|
444
|
-
options.enableSso = options.enableSso !== false // default value is true if undefined.
|
|
445
|
-
|
|
446
425
|
this._handlers[id] = new AzureBotAuthorization(id, options, settings)
|
|
447
426
|
}
|
|
448
427
|
|
|
@@ -473,4 +452,68 @@ export class AuthorizationManager {
|
|
|
473
452
|
|
|
474
453
|
throw ExceptionHelper.generateException(Error, Errors.UnsupportedAuthHandlerType, undefined, { handlerType: type })
|
|
475
454
|
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Resolves the effective handler configuration for a given handler ID.
|
|
458
|
+
*/
|
|
459
|
+
private resolveHandlerConfiguration (
|
|
460
|
+
id: string,
|
|
461
|
+
runtimeEntries: Array<[string, AuthorizationOptions[string]]>,
|
|
462
|
+
latestEntries: Array<[string, AuthorizationOptions[string]]>,
|
|
463
|
+
legacyEntries: Array<[string, AuthorizationOptions[string]]>
|
|
464
|
+
): {
|
|
465
|
+
options: AuthorizationOptions[string];
|
|
466
|
+
format: string;
|
|
467
|
+
} {
|
|
468
|
+
const matchesId = ([_id]: [string, AuthorizationOptions[string]]) => _id.toLowerCase() === id.toLowerCase()
|
|
469
|
+
|
|
470
|
+
// Find entries case-insensitively for later processing
|
|
471
|
+
const [, runtime] = runtimeEntries.find(matchesId) ?? []
|
|
472
|
+
const [, latest] = latestEntries.find(matchesId) ?? []
|
|
473
|
+
const [, legacy] = legacyEntries.find(matchesId) ?? []
|
|
474
|
+
|
|
475
|
+
if (runtime !== undefined && latest !== undefined) {
|
|
476
|
+
logger.warn(this.prefix(id, 'Both runtime options and latest environment variable configurations detected. Runtime configuration will take precedence over latest environment variables.'))
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const runtimeLegacyKeys = ['name', 'maxAttempts', 'messages', 'obo']
|
|
480
|
+
const isRuntimeLegacy = runtime !== undefined && Object.keys(runtime).some(key => runtimeLegacyKeys.includes(key))
|
|
481
|
+
|
|
482
|
+
let runtimeLegacyFormat = ''
|
|
483
|
+
if (isRuntimeLegacy && runtime.type === AZURE_BOT) {
|
|
484
|
+
runtime.azureBotOAuthConnectionName ??= runtime.name
|
|
485
|
+
runtime.invalidSignInRetryMax ??= runtime.maxAttempts
|
|
486
|
+
runtime.invalidSignInRetryMessage ??= runtime.messages?.invalidCode
|
|
487
|
+
runtime.invalidSignInRetryMessageFormat ??= runtime.messages?.invalidCodeFormat
|
|
488
|
+
runtime.invalidSignInRetryMaxExceededMessage ??= runtime.messages?.maxAttemptsExceeded
|
|
489
|
+
runtime.oboConnectionName ??= runtime.obo?.connection
|
|
490
|
+
runtime.oboScopes ??= runtime.obo?.scopes
|
|
491
|
+
delete runtime.name
|
|
492
|
+
delete runtime.maxAttempts
|
|
493
|
+
delete runtime.messages
|
|
494
|
+
delete runtime.obo
|
|
495
|
+
runtimeLegacyFormat = 'runtime options (legacy)'
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (runtime !== undefined && legacy !== undefined) {
|
|
499
|
+
return { format: `${runtimeLegacyFormat || 'runtime options'} + .env variables (legacy)`, options: { ...prune(legacy), ...prune(runtime) } }
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (runtime !== undefined) {
|
|
503
|
+
return { format: runtimeLegacyFormat || 'runtime options', options: prune(runtime) }
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (latest !== undefined) {
|
|
507
|
+
return { format: '.env variables', options: prune(latest) }
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
if (legacy !== undefined) {
|
|
511
|
+
// Note: this should never happen, as legacy requires runtime to be present.
|
|
512
|
+
// However, we show a warning just in case to detect if something goes wrong.
|
|
513
|
+
logger.warn(this.prefix(id, 'Legacy environment variable configuration detected without a corresponding runtime options configuration.'))
|
|
514
|
+
return { format: '.env variables (legacy)', options: prune(legacy) }
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
return { format: 'empty options', options: {} }
|
|
518
|
+
}
|
|
476
519
|
}
|
|
@@ -334,7 +334,7 @@ export class AzureBotAuthorization implements AuthorizationHandler {
|
|
|
334
334
|
const { activity } = context
|
|
335
335
|
const userTokenClient = await this.getUserTokenClient(context)
|
|
336
336
|
// Using getTokenOrSignInResource instead of getUserToken to avoid HTTP 404 errors.
|
|
337
|
-
const { tokenResponse } = await userTokenClient.getTokenOrSignInResource(activity.from?.id!, this.options.azureBotOAuthConnectionName!, activity.channelId!, activity.getConversationReference(), activity.relatesTo!, '')
|
|
337
|
+
const { tokenResponse } = await userTokenClient.getTokenOrSignInResource(activity.from?.id!, this.options.azureBotOAuthConnectionName!, activity.channelId!, activity.getConversationReference({ forceBaseChannel: true }), activity.relatesTo!, '')
|
|
338
338
|
return tokenResponse?.token
|
|
339
339
|
}
|
|
340
340
|
|
|
@@ -399,7 +399,7 @@ export class AzureBotAuthorization implements AuthorizationHandler {
|
|
|
399
399
|
const { activity } = context
|
|
400
400
|
|
|
401
401
|
const userTokenClient = await this.getUserTokenClient(context)
|
|
402
|
-
const { tokenResponse, signInResource } = await userTokenClient.getTokenOrSignInResource(activity.from?.id!, this.options.azureBotOAuthConnectionName!, activity.channelId!, activity.getConversationReference(), activity.relatesTo!, code ?? '')
|
|
402
|
+
const { tokenResponse, signInResource } = await userTokenClient.getTokenOrSignInResource(activity.from?.id!, this.options.azureBotOAuthConnectionName!, activity.channelId!, activity.getConversationReference({ forceBaseChannel: true }), activity.relatesTo!, code ?? '')
|
|
403
403
|
|
|
404
404
|
if (!tokenResponse && active && code) {
|
|
405
405
|
reason.message = 'Invalid code entered. Restarting sign-in flow'
|
|
@@ -66,6 +66,9 @@ export class CreateConversationOptionsBuilder {
|
|
|
66
66
|
const builder = new CreateConversationOptionsBuilder(claims, channelId, serviceUrl)
|
|
67
67
|
if (parameters) {
|
|
68
68
|
builder._parameters = { ...builder._parameters, ...parameters }
|
|
69
|
+
if (parameters.activity) {
|
|
70
|
+
builder._activity = parameters.activity
|
|
71
|
+
}
|
|
69
72
|
}
|
|
70
73
|
|
|
71
74
|
// Set parameters.agent if not already provided — matches C# behavior
|
|
@@ -161,9 +164,10 @@ export class CreateConversationOptionsBuilder {
|
|
|
161
164
|
throw ExceptionHelper.generateException(Error, Errors.CreateConversationBuilderMembersRequired)
|
|
162
165
|
}
|
|
163
166
|
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
+
const isTeamsChannel = this._channelId === Channels.Msteams &&
|
|
168
|
+
Boolean((this._parameters.channelData as Record<string, any>)?.channel?.id)
|
|
169
|
+
if (isTeamsChannel && !this._activity) {
|
|
170
|
+
throw ExceptionHelper.generateException(Error, Errors.CreateConversationBuilderChannelActivityRequired)
|
|
167
171
|
}
|
|
168
172
|
|
|
169
173
|
return {
|
|
@@ -174,7 +178,7 @@ export class CreateConversationOptionsBuilder {
|
|
|
174
178
|
storeConversation: this._storeConversation,
|
|
175
179
|
parameters: {
|
|
176
180
|
...this._parameters,
|
|
177
|
-
activity:
|
|
181
|
+
activity: this._activity ? { type: 'message', ...this._activity } as Activity : undefined,
|
|
178
182
|
},
|
|
179
183
|
}
|
|
180
184
|
}
|
|
@@ -72,7 +72,12 @@ export class M365AttachmentDownloader<TState extends TurnState = TurnState> impl
|
|
|
72
72
|
const response = await this._httpClient.get(downloadUrl, { responseType: 'arraybuffer' })
|
|
73
73
|
|
|
74
74
|
const content = Buffer.from(response.data, 'binary')
|
|
75
|
-
const
|
|
75
|
+
const contentTypeHeader = typeof response.headers.get === 'function'
|
|
76
|
+
? response.headers.get('content-type')
|
|
77
|
+
: response.headers['content-type']
|
|
78
|
+
const contentType = Array.isArray(contentTypeHeader)
|
|
79
|
+
? (contentTypeHeader[0] ?? 'application/octet-stream')
|
|
80
|
+
: (typeof contentTypeHeader === 'string' ? contentTypeHeader : 'application/octet-stream')
|
|
76
81
|
inputFile = { content, contentType, contentUrl: attachment.contentUrl }
|
|
77
82
|
} catch (error) {
|
|
78
83
|
logger.error(`Failed to download Teams attachment: ${error}`)
|