@microsoft/agents-hosting 1.9.1 → 1.10.0-beta.14.ge6d1defc27

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 (173) hide show
  1. package/README.md +83 -7
  2. package/dist/package.json +4 -4
  3. package/dist/src/activityHandler.js +6 -3
  4. package/dist/src/activityHandler.js.map +1 -1
  5. package/dist/src/agent-client/agentResponseHandler.d.ts +7 -0
  6. package/dist/src/agent-client/agentResponseHandler.js.map +1 -1
  7. package/dist/src/agent-client/createAgentResponseHandler.d.ts +2 -0
  8. package/dist/src/agent-client/createAgentResponseHandler.js.map +1 -1
  9. package/dist/src/app/adaptiveCards/adaptiveCardsActions.d.ts +1 -0
  10. package/dist/src/app/adaptiveCards/adaptiveCardsActions.js +1 -0
  11. package/dist/src/app/adaptiveCards/adaptiveCardsActions.js.map +1 -1
  12. package/dist/src/app/attachmentDownloadHttpClient.d.ts +13 -0
  13. package/dist/src/app/attachmentDownloadHttpClient.js +80 -0
  14. package/dist/src/app/attachmentDownloadHttpClient.js.map +1 -0
  15. package/dist/src/app/attachmentDownloader.d.ts +2 -0
  16. package/dist/src/app/attachmentDownloader.js +6 -11
  17. package/dist/src/app/attachmentDownloader.js.map +1 -1
  18. package/dist/src/app/auth/authorization.d.ts +58 -0
  19. package/dist/src/app/auth/authorization.js.map +1 -1
  20. package/dist/src/app/proactive/conversation.d.ts +18 -0
  21. package/dist/src/app/proactive/conversation.js +6 -0
  22. package/dist/src/app/proactive/conversation.js.map +1 -1
  23. package/dist/src/app/proactive/conversationBuilder.js +2 -1
  24. package/dist/src/app/proactive/conversationBuilder.js.map +1 -1
  25. package/dist/src/app/proactive/conversationReferenceBuilder.js +8 -4
  26. package/dist/src/app/proactive/conversationReferenceBuilder.js.map +1 -1
  27. package/dist/src/app/proactive/createConversationOptionsBuilder.d.ts +1 -0
  28. package/dist/src/app/proactive/createConversationOptionsBuilder.js +2 -1
  29. package/dist/src/app/proactive/createConversationOptionsBuilder.js.map +1 -1
  30. package/dist/src/app/proactive/proactive.d.ts +6 -0
  31. package/dist/src/app/proactive/proactive.js +32 -1
  32. package/dist/src/app/proactive/proactive.js.map +1 -1
  33. package/dist/src/app/routeList.d.ts +21 -0
  34. package/dist/src/app/routeList.js +27 -3
  35. package/dist/src/app/routeList.js.map +1 -1
  36. package/dist/src/app/teamsAttachmentDownloader.d.ts +8 -0
  37. package/dist/src/app/teamsAttachmentDownloader.js +17 -12
  38. package/dist/src/app/teamsAttachmentDownloader.js.map +1 -1
  39. package/dist/src/auth/authConfiguration.d.ts +1 -0
  40. package/dist/src/auth/authConfiguration.js.map +1 -1
  41. package/dist/src/auth/authConstants.d.ts +7 -0
  42. package/dist/src/auth/authConstants.js +7 -0
  43. package/dist/src/auth/authConstants.js.map +1 -1
  44. package/dist/src/auth/authProvider.d.ts +36 -0
  45. package/dist/src/auth/connectionManager.js +2 -1
  46. package/dist/src/auth/connectionManager.js.map +1 -1
  47. package/dist/src/auth/connections.d.ts +1 -0
  48. package/dist/src/auth/msal/msalConnectionManager.d.ts +7 -0
  49. package/dist/src/auth/msal/msalConnectionManager.js +7 -0
  50. package/dist/src/auth/msal/msalConnectionManager.js.map +1 -1
  51. package/dist/src/auth/msal/msalTokenProvider.d.ts +44 -0
  52. package/dist/src/auth/msal/msalTokenProvider.js +43 -0
  53. package/dist/src/auth/msal/msalTokenProvider.js.map +1 -1
  54. package/dist/src/auth/settings.d.ts +28 -0
  55. package/dist/src/auth/settings.js +23 -0
  56. package/dist/src/auth/settings.js.map +1 -1
  57. package/dist/src/auth/sidecar/sidecarAuthProvider.d.ts +3 -0
  58. package/dist/src/auth/sidecar/sidecarAuthProvider.js.map +1 -1
  59. package/dist/src/auth/sidecar/sidecarHttpClient.d.ts +1 -9
  60. package/dist/src/auth/sidecar/sidecarHttpClient.js +3 -69
  61. package/dist/src/auth/sidecar/sidecarHttpClient.js.map +1 -1
  62. package/dist/src/baseAdapter.d.ts +6 -0
  63. package/dist/src/baseAdapter.js.map +1 -1
  64. package/dist/src/cards/taskModuleAction.d.ts +6 -0
  65. package/dist/src/cards/taskModuleAction.js +6 -0
  66. package/dist/src/cards/taskModuleAction.js.map +1 -1
  67. package/dist/src/cloudAdapter.d.ts +29 -0
  68. package/dist/src/cloudAdapter.js +45 -8
  69. package/dist/src/cloudAdapter.js.map +1 -1
  70. package/dist/src/configuration/configuration.d.ts +1 -0
  71. package/dist/src/configuration/configuration.js +2 -1
  72. package/dist/src/configuration/configuration.js.map +1 -1
  73. package/dist/src/configuration/environmentConfiguration.js +1 -1
  74. package/dist/src/configuration/environmentConfiguration.js.map +1 -1
  75. package/dist/src/connector-client/connectorClient.d.ts +8 -0
  76. package/dist/src/connector-client/connectorClient.js +8 -0
  77. package/dist/src/connector-client/connectorClient.js.map +1 -1
  78. package/dist/src/createCloudAdapter.d.ts +2 -0
  79. package/dist/src/createCloudAdapter.js.map +1 -1
  80. package/dist/src/errorHelper.d.ts +1 -0
  81. package/dist/src/errorHelper.js +9 -0
  82. package/dist/src/errorHelper.js.map +1 -1
  83. package/dist/src/headerPropagation.d.ts +38 -0
  84. package/dist/src/headerPropagation.js +33 -0
  85. package/dist/src/headerPropagation.js.map +1 -1
  86. package/dist/src/httpClient.d.ts +58 -0
  87. package/dist/src/httpClient.js +40 -0
  88. package/dist/src/httpClient.js.map +1 -1
  89. package/dist/src/interfaces/webResponse.d.ts +7 -0
  90. package/dist/src/middlewareSet.d.ts +6 -0
  91. package/dist/src/middlewareSet.js.map +1 -1
  92. package/dist/src/oauth/userTokenClient.d.ts +6 -0
  93. package/dist/src/oauth/userTokenClient.js +12 -0
  94. package/dist/src/oauth/userTokenClient.js.map +1 -1
  95. package/dist/src/outboundHostValidator.d.ts +33 -1
  96. package/dist/src/outboundHostValidator.js +60 -25
  97. package/dist/src/outboundHostValidator.js.map +1 -1
  98. package/dist/src/storage/fileStorage.d.ts +26 -0
  99. package/dist/src/storage/fileStorage.js +35 -6
  100. package/dist/src/storage/fileStorage.js.map +1 -1
  101. package/dist/src/storage/memoryStorage.d.ts +34 -0
  102. package/dist/src/storage/memoryStorage.js +41 -4
  103. package/dist/src/storage/memoryStorage.js.map +1 -1
  104. package/dist/src/storage/storage.d.ts +20 -0
  105. package/dist/src/storage/storage.js +7 -0
  106. package/dist/src/storage/storage.js.map +1 -1
  107. package/dist/src/storage/storageCompatibility.js +12 -6
  108. package/dist/src/storage/storageCompatibility.js.map +1 -1
  109. package/dist/src/storage/storageExpiry.d.ts +7 -0
  110. package/dist/src/storage/storageExpiry.js +7 -0
  111. package/dist/src/storage/storageExpiry.js.map +1 -1
  112. package/dist/src/turnContext.d.ts +10 -0
  113. package/dist/src/turnContext.js +5 -0
  114. package/dist/src/turnContext.js.map +1 -1
  115. package/dist/src/utils/env.js +22 -11
  116. package/dist/src/utils/env.js.map +1 -1
  117. package/dist/src/utils/ipAddress.d.ts +6 -0
  118. package/dist/src/utils/ipAddress.js +64 -0
  119. package/dist/src/utils/ipAddress.js.map +1 -0
  120. package/dist/src/utils/outboundUrl.d.ts +7 -0
  121. package/dist/src/utils/outboundUrl.js +52 -0
  122. package/dist/src/utils/outboundUrl.js.map +1 -0
  123. package/dist/src/utils.js +2 -1
  124. package/dist/src/utils.js.map +1 -1
  125. package/package.json +4 -4
  126. package/src/activityHandler.ts +9 -3
  127. package/src/agent-client/agentResponseHandler.ts +7 -0
  128. package/src/agent-client/createAgentResponseHandler.ts +2 -0
  129. package/src/app/adaptiveCards/adaptiveCardsActions.ts +1 -0
  130. package/src/app/attachmentDownloadHttpClient.ts +80 -0
  131. package/src/app/attachmentDownloader.ts +6 -9
  132. package/src/app/auth/authorization.ts +58 -0
  133. package/src/app/proactive/conversation.ts +24 -0
  134. package/src/app/proactive/conversationBuilder.ts +3 -1
  135. package/src/app/proactive/conversationReferenceBuilder.ts +12 -4
  136. package/src/app/proactive/createConversationOptionsBuilder.ts +5 -1
  137. package/src/app/proactive/proactive.ts +33 -1
  138. package/src/app/routeList.ts +30 -3
  139. package/src/app/teamsAttachmentDownloader.ts +17 -10
  140. package/src/auth/authConfiguration.ts +1 -0
  141. package/src/auth/authConstants.ts +7 -0
  142. package/src/auth/authProvider.ts +36 -0
  143. package/src/auth/connectionManager.ts +3 -1
  144. package/src/auth/connections.ts +1 -0
  145. package/src/auth/msal/msalConnectionManager.ts +7 -0
  146. package/src/auth/msal/msalTokenProvider.ts +59 -0
  147. package/src/auth/settings.ts +28 -0
  148. package/src/auth/sidecar/sidecarAuthProvider.ts +4 -0
  149. package/src/auth/sidecar/sidecarHttpClient.ts +3 -63
  150. package/src/baseAdapter.ts +6 -0
  151. package/src/cards/taskModuleAction.ts +6 -0
  152. package/src/cloudAdapter.ts +59 -10
  153. package/src/configuration/configuration.ts +4 -2
  154. package/src/configuration/environmentConfiguration.ts +7 -1
  155. package/src/connector-client/connectorClient.ts +8 -0
  156. package/src/createCloudAdapter.ts +2 -0
  157. package/src/errorHelper.ts +11 -0
  158. package/src/headerPropagation.ts +38 -0
  159. package/src/httpClient.ts +58 -0
  160. package/src/interfaces/webResponse.ts +7 -0
  161. package/src/middlewareSet.ts +6 -0
  162. package/src/oauth/userTokenClient.ts +13 -0
  163. package/src/outboundHostValidator.ts +84 -23
  164. package/src/storage/fileStorage.ts +46 -6
  165. package/src/storage/memoryStorage.ts +45 -4
  166. package/src/storage/storage.ts +20 -0
  167. package/src/storage/storageCompatibility.ts +18 -6
  168. package/src/storage/storageExpiry.ts +7 -0
  169. package/src/turnContext.ts +11 -0
  170. package/src/utils/env.ts +33 -11
  171. package/src/utils/ipAddress.ts +63 -0
  172. package/src/utils/outboundUrl.ts +50 -0
  173. package/src/utils.ts +3 -1
@@ -16,14 +16,72 @@ import { AuthorizationHandlerTokenOptions } from './types'
16
16
 
17
17
  const logger = debug('agents:authorization')
18
18
 
19
+ /** Provides user authorization, token exchange, and sign-in lifecycle operations. */
19
20
  export interface Authorization {
21
+ /**
22
+ * Gets the user token for an authorization handler.
23
+ *
24
+ * @param context - Context for the current turn.
25
+ * @param authHandlerId - Authorization handler ID.
26
+ * @returns The token response.
27
+ */
20
28
  getToken(context: TurnContext, authHandlerId: string): Promise<TokenResponse>
29
+ /**
30
+ * Creates a credential backed by the current turn's user token.
31
+ *
32
+ * @param context - Context for the current turn.
33
+ * @param authHandlerId - Authorization handler ID.
34
+ * @returns A turn-scoped token credential.
35
+ */
21
36
  getTokenAsTokenCredential?(context: TurnContext, authHandlerId: string): TokenCredential
37
+ /**
38
+ * Exchanges the user token for the requested scopes.
39
+ *
40
+ * @param context - Context for the current turn.
41
+ * @param scopes - Scopes requested for the exchanged token.
42
+ * @param authHandlerId - Authorization handler ID.
43
+ * @returns The exchanged token response.
44
+ * @deprecated Use the overload that accepts an authorization handler ID followed by options.
45
+ */
22
46
  exchangeToken(context: TurnContext, scopes: string[], authHandlerId: string): Promise<TokenResponse>
47
+ /**
48
+ * Exchanges the user token using an authorization handler.
49
+ *
50
+ * @param context - Context for the current turn.
51
+ * @param authHandlerId - Authorization handler ID.
52
+ * @param options - Optional connection and scope overrides.
53
+ * @returns The exchanged token response.
54
+ */
23
55
  exchangeToken(context: TurnContext, authHandlerId: string, options?: AuthorizationHandlerTokenOptions): Promise<TokenResponse>
56
+ /**
57
+ * Creates a credential that exchanges the current turn's user token.
58
+ *
59
+ * @param context - Context for the current turn.
60
+ * @param authHandlerId - Authorization handler ID.
61
+ * @param options - Optional connection and scope overrides.
62
+ * @returns A turn-scoped token credential.
63
+ */
24
64
  exchangeTokenAsTokenCredential?(context: TurnContext, authHandlerId: string, options?: AuthorizationHandlerTokenOptions): TokenCredential
65
+ /**
66
+ * Signs out the user from one or all authorization handlers.
67
+ *
68
+ * @param context - Context for the current turn.
69
+ * @param state - State for the current turn.
70
+ * @param authHandlerId - Handler to sign out from, or `undefined` for all handlers.
71
+ * @returns A promise that resolves after sign-out completes.
72
+ */
25
73
  signOut(context: TurnContext, state: TurnState, authHandlerId?: string): Promise<void>
74
+ /**
75
+ * Registers a callback for successful sign-in.
76
+ *
77
+ * @param handler - Callback invoked after sign-in succeeds.
78
+ */
26
79
  onSignInSuccess(handler: (context: TurnContext, state: TurnState, authHandlerId?: string) => Promise<void>): void
80
+ /**
81
+ * Registers a callback for failed sign-in.
82
+ *
83
+ * @param handler - Callback invoked after sign-in fails.
84
+ */
27
85
  onSignInFailure(handler: (context: TurnContext, state: TurnState, authHandlerId?: string, errorMessage?: string) => Promise<void>): void
28
86
  }
29
87
 
@@ -12,10 +12,15 @@ import { Errors } from '../../errorHelper'
12
12
  * `aud` (the agent's client ID) is required; all other fields are optional.
13
13
  */
14
14
  export interface ConversationClaims {
15
+ /** Audience identifying the agent client. */
15
16
  aud: string
17
+ /** Authorized-party client ID, when supplied by the token. */
16
18
  azp?: string
19
+ /** Calling application ID, when supplied by the token. */
17
20
  appid?: string
21
+ /** Microsoft Entra tenant ID, when supplied by the token. */
18
22
  tid?: string
23
+ /** Additional string-valued identity claims. */
19
24
  [key: string]: string | undefined
20
25
  }
21
26
 
@@ -28,11 +33,30 @@ export interface ConversationClaims {
28
33
  * `adapter.continueConversation()`.
29
34
  */
30
35
  export class Conversation {
36
+ /** Reference used to resume the conversation. */
31
37
  reference: ConversationReference
38
+ /** Identity claims used to authenticate proactive operations. */
32
39
  claims: ConversationClaims
33
40
 
41
+ /**
42
+ * Creates a conversation from the current turn.
43
+ *
44
+ * @param context - Turn context from which to capture the reference and identity.
45
+ */
34
46
  constructor (context: TurnContext)
47
+ /**
48
+ * Creates a conversation from explicit claims and a conversation reference.
49
+ *
50
+ * @param claims - Claims used to authenticate proactive operations.
51
+ * @param reference - Reference used to resume the conversation.
52
+ */
35
53
  constructor (claims: ConversationClaims, reference: ConversationReference)
54
+ /**
55
+ * Creates a conversation from a turn context or explicit claims and a reference.
56
+ *
57
+ * @param contextOrClaims - Turn context to capture, or authentication claims.
58
+ * @param reference - Reference paired with explicit claims.
59
+ */
36
60
  constructor (
37
61
  contextOrClaims: TurnContext | ConversationClaims,
38
62
  reference?: ConversationReference
@@ -55,7 +55,9 @@ export class ConversationBuilder {
55
55
  requestorId?: string
56
56
  ): ConversationBuilder {
57
57
  const claims: ConversationClaims = { aud: agentClientId }
58
- if (requestorId) claims.appid = requestorId
58
+ if (requestorId) {
59
+ claims.appid = requestorId
60
+ }
59
61
  return new ConversationBuilder(agentClientId, channelId, serviceUrl ?? '', claims, ConversationReferenceBuilder.create(agentClientId, channelId, serviceUrl).build())
60
62
  }
61
63
 
@@ -71,8 +71,12 @@ export class ConversationReferenceBuilder {
71
71
  * `https://{channelId}.botframework.com/` pattern (matching C# behavior).
72
72
  */
73
73
  static serviceUrlForChannel (channelId: string): string {
74
- if (!channelId) return ''
75
- if (channelId === Channels.Msteams) return TeamsServiceEndpoints.publicGlobal
74
+ if (!channelId) {
75
+ return ''
76
+ }
77
+ if (channelId === Channels.Msteams) {
78
+ return TeamsServiceEndpoints.publicGlobal
79
+ }
76
80
  if (!knownChannelIds.has(channelId)) {
77
81
  logger.warn(
78
82
  `serviceUrlForChannel: unrecognized channelId '${channelId}' — constructing fallback URL ` +
@@ -141,8 +145,12 @@ export class ConversationReferenceBuilder {
141
145
  user: this._user ?? { role: RoleTypes.User },
142
146
  }
143
147
 
144
- if (this._activityId !== undefined) ref.activityId = this._activityId
145
- if (this._locale !== undefined) ref.locale = this._locale
148
+ if (this._activityId !== undefined) {
149
+ ref.activityId = this._activityId
150
+ }
151
+ if (this._locale !== undefined) {
152
+ ref.locale = this._locale
153
+ }
146
154
 
147
155
  return ref
148
156
  }
@@ -81,6 +81,8 @@ export class CreateConversationOptionsBuilder {
81
81
 
82
82
  /** Adds a member (the target user) to `parameters.members`. */
83
83
  withUser (userId: string, userName?: string): this
84
+
85
+ /** Adds a channel account as a member in `parameters.members`. */
84
86
  withUser (account: ChannelAccount): this
85
87
  withUser (userIdOrAccount: string | ChannelAccount, userName?: string): this {
86
88
  const account: ChannelAccount =
@@ -125,7 +127,9 @@ export class CreateConversationOptionsBuilder {
125
127
  * Only has effect on `msteams` channels.
126
128
  */
127
129
  withTeamsChannelId (teamsChannelId: string): this {
128
- if (this._channelId !== Channels.Msteams) return this
130
+ if (this._channelId !== Channels.Msteams) {
131
+ return this
132
+ }
129
133
  this._parameters = { ...this._parameters, isGroup: true }
130
134
  this.withChannelData({ channel: { id: teamsChannelId } })
131
135
  return this
@@ -49,6 +49,12 @@ export class Proactive<TState extends TurnState> {
49
49
  private readonly _options: ProactiveOptions
50
50
  private readonly _storage?: StorageV2
51
51
 
52
+ /**
53
+ * Creates a proactive conversation manager.
54
+ *
55
+ * @param app - Application that owns the proactive operations.
56
+ * @param options - Proactive messaging configuration.
57
+ */
52
58
  constructor (app: AgentApplication<TState>, options: ProactiveOptions) {
53
59
  this._app = app
54
60
  this._options = options
@@ -113,6 +119,12 @@ export class Proactive<TState extends TurnState> {
113
119
  * ```
114
120
  */
115
121
  storeConversation (conversation: Conversation): Promise<string>
122
+ /**
123
+ * Stores a conversation captured from a turn context or supplied explicitly.
124
+ *
125
+ * @param contextOrConversation - Turn context or conversation to store.
126
+ * @returns The stored conversation ID.
127
+ */
116
128
  async storeConversation (contextOrConversation: TurnContext | Conversation): Promise<string> {
117
129
  return trace(ProactiveTraceDefinitions.storeConversation, async ({ record, actions }) => {
118
130
  const conv =
@@ -243,6 +255,14 @@ export class Proactive<TState extends TurnState> {
243
255
  * ```
244
256
  */
245
257
  sendActivity (adapter: BaseAdapter, conversation: Conversation, activity: Partial<Activity>): Promise<ResourceResponse>
258
+ /**
259
+ * Sends an activity to a stored or explicitly supplied conversation.
260
+ *
261
+ * @param adapter - Channel adapter used to continue the conversation.
262
+ * @param conversationOrId - Conversation or stored conversation ID.
263
+ * @param activity - Activity fields to send.
264
+ * @returns The channel resource response.
265
+ */
246
266
  async sendActivity (
247
267
  adapter: BaseAdapter,
248
268
  conversationOrId: Conversation | string,
@@ -285,7 +305,9 @@ export class Proactive<TState extends TurnState> {
285
305
  logger.warn('sendActivity: failed for conversation=%s: %s', id, caughtError)
286
306
  throw caughtError
287
307
  }
288
- if (response === undefined) throw ExceptionHelper.generateException(Error, Errors.ProactiveSendActivityNoResponse)
308
+ if (response === undefined) {
309
+ throw ExceptionHelper.generateException(Error, Errors.ProactiveSendActivityNoResponse)
310
+ }
289
311
  logger.debug('sendActivity: sent activity id=%s', response.id)
290
312
  return response
291
313
  })
@@ -359,6 +381,16 @@ export class Proactive<TState extends TurnState> {
359
381
  * ```
360
382
  */
361
383
  continueConversation (adapter: BaseAdapter, conversation: Conversation, handler: RouteHandler<TState>, autoSignInHandlers?: string[], continuationActivity?: Partial<Activity>): Promise<void>
384
+ /**
385
+ * Continues a stored or explicitly supplied conversation.
386
+ *
387
+ * @param adapter - Channel adapter used to continue the conversation.
388
+ * @param conversationOrId - Conversation or stored conversation ID.
389
+ * @param handler - Handler to execute in the continued turn.
390
+ * @param autoSignInHandlers - Connections for which tokens are acquired before the handler runs.
391
+ * @param continuationActivity - Activity fields merged into the continuation activity.
392
+ * @returns A promise that resolves after the continued turn completes.
393
+ */
362
394
  async continueConversation (
363
395
  adapter: BaseAdapter,
364
396
  conversationOrId: Conversation | string,
@@ -9,9 +9,25 @@ import { RouteRank } from './routeRank'
9
9
  import { RouteSelector } from './routeSelector'
10
10
  import { TurnState } from './turnState'
11
11
 
12
+ /**
13
+ * Maintains application routes in dispatch priority order.
14
+ *
15
+ * @typeParam TState - Turn state supplied to route handlers.
16
+ */
12
17
  export class RouteList<TState extends TurnState> {
13
18
  private _routes: Array<AppRoute<TState>> = []
14
19
 
20
+ /**
21
+ * Adds a route and orders it by route kind and rank.
22
+ *
23
+ * @param selector - Selector that determines whether the route matches.
24
+ * @param handler - Handler invoked for a matching route.
25
+ * @param isInvokeRoute - Whether the route handles invoke activities.
26
+ * @param rank - Rank used to order routes of the same kind.
27
+ * @param authHandlers - Authentication handlers required by the route.
28
+ * @param isAgenticRoute - Whether the route handles agentic requests.
29
+ * @returns This route list.
30
+ */
15
31
  public addRoute (
16
32
  selector: RouteSelector,
17
33
  handler: RouteHandler<TState>,
@@ -30,9 +46,15 @@ export class RouteList<TState extends TurnState> {
30
46
  // Then by Rank
31
47
  this._routes.sort((a, b) => {
32
48
  const getPriority = (route: AppRoute<TState>) => {
33
- if (route.isAgenticRoute && route.isInvokeRoute) return 0
34
- if (route.isInvokeRoute) return 1
35
- if (route.isAgenticRoute) return 2
49
+ if (route.isAgenticRoute && route.isInvokeRoute) {
50
+ return 0
51
+ }
52
+ if (route.isInvokeRoute) {
53
+ return 1
54
+ }
55
+ if (route.isAgenticRoute) {
56
+ return 2
57
+ }
36
58
  return 3
37
59
  }
38
60
 
@@ -50,6 +72,11 @@ export class RouteList<TState extends TurnState> {
50
72
  return this
51
73
  }
52
74
 
75
+ /**
76
+ * Iterates over routes in dispatch priority order.
77
+ *
78
+ * @returns An iterator over the registered routes.
79
+ */
53
80
  public [Symbol.iterator] (): Iterator<AppRoute<TState>> {
54
81
  return this._routes[Symbol.iterator]()
55
82
  }
@@ -12,17 +12,26 @@ import { TurnState } from './turnState'
12
12
  import { HttpClient } from '../httpClient'
13
13
  import { z } from 'zod'
14
14
  import { createOutboundHostValidator, OutboundUrlPolicy } from '../outboundHostValidator'
15
+ import { AttachmentDownloadHttpClient } from './attachmentDownloadHttpClient'
15
16
 
16
17
  const logger = debug('agents:M365AttachmentDownloader')
17
18
 
18
19
  /**
19
20
  * Downloads attachments from Teams and M365 using the bots access token.
21
+ * Enabled outbound validation requires HTTPS and validates addresses at every redirect.
22
+ * Initial request credentials are not forwarded to redirects when validation is enabled.
20
23
  */
21
24
  export class M365AttachmentDownloader<TState extends TurnState = TurnState> implements InputFileDownloader<TState> {
22
25
  private _httpClient: HttpClient
23
26
  private _stateKey: string
24
27
  private readonly _hostValidator: OutboundUrlPolicy
25
28
 
29
+ /**
30
+ * Creates an attachment downloader.
31
+ *
32
+ * @param stateKey - Turn-state key used by {@link downloadAndStoreFiles}.
33
+ * @param outboundHostValidator - Policy used to validate attachment download URLs.
34
+ */
26
35
  public constructor (stateKey: string = 'inputFiles', outboundHostValidator?: OutboundUrlPolicy) {
27
36
  this._httpClient = new HttpClient()
28
37
  this._stateKey = stateKey
@@ -46,11 +55,11 @@ export class M365AttachmentDownloader<TState extends TurnState = TurnState> impl
46
55
  }
47
56
 
48
57
  const connectorClient : ConnectorClient = context.turnState.get<ConnectorClient>(context.adapter.ConnectorClientKey)
49
- this._httpClient.defaultHeaders = { ...connectorClient.httpClient.defaultHeaders }
58
+ const headers = { ...connectorClient.httpClient.defaultHeaders }
50
59
 
51
60
  const files: InputFile[] = []
52
61
  for (const attachment of attachments) {
53
- const file = await this.downloadFile(attachment)
62
+ const file = await this.downloadFile(attachment, headers)
54
63
  if (file) {
55
64
  files.push(file)
56
65
  }
@@ -64,7 +73,7 @@ export class M365AttachmentDownloader<TState extends TurnState = TurnState> impl
64
73
  * @param {Attachment} attachment - Attachment to download.
65
74
  * @returns {Promise<InputFile>} - Promise that resolves to the downloaded input file.
66
75
  */
67
- private async downloadFile (attachment: Attachment): Promise<InputFile | undefined> {
76
+ private async downloadFile (attachment: Attachment, headers: Record<string, string> = {}): Promise<InputFile | undefined> {
68
77
  let inputFile: InputFile | undefined
69
78
 
70
79
  if (attachment.contentUrl && attachment.contentUrl.startsWith('https://')) {
@@ -72,21 +81,19 @@ export class M365AttachmentDownloader<TState extends TurnState = TurnState> impl
72
81
  const contentSchema = z.object({ downloadUrl: z.string().url() })
73
82
  const parsed = contentSchema.safeParse(attachment.content)
74
83
  const downloadUrl = parsed.success ? parsed.data.downloadUrl : attachment.contentUrl
75
- if (!this._hostValidator.isAllowed(downloadUrl)) {
76
- let host = '[invalid-url]'
77
- try { host = new URL(downloadUrl).hostname } catch { /* invalid */ }
78
- logger.warn(`Attachment downloadUrl host is not in the configured allowed hosts. Host='${host}'`)
84
+ const response = await new AttachmentDownloadHttpClient(this._httpClient, this._hostValidator)
85
+ .get(downloadUrl, headers)
86
+ if (!response) {
79
87
  return undefined
80
88
  }
81
89
 
82
- const response = await this._httpClient.get(downloadUrl, { responseType: 'arraybuffer' })
83
-
84
90
  const content = Buffer.from(response.data as ArrayBuffer)
85
91
  const contentTypeHeader = response.headers.get('content-type')
86
92
  const contentType = typeof contentTypeHeader === 'string' ? contentTypeHeader : 'application/octet-stream'
87
93
  inputFile = { content, contentType, contentUrl: attachment.contentUrl }
88
94
  } catch (error) {
89
- logger.error(`Failed to download Teams attachment: ${error}`)
95
+ const code = error instanceof Error && 'code' in error && typeof error.code === 'number' ? error.code : 'unavailable'
96
+ logger.error(`Failed to download Teams attachment. Error type='${error instanceof Error ? error.name : 'unknown'}', Code='${code}'`)
90
97
  return undefined
91
98
  }
92
99
  } else {
@@ -441,6 +441,7 @@ let globalEnv = loadEnv()
441
441
  * Optional host-scoped inputs used while resolving authentication settings.
442
442
  */
443
443
  export interface AuthConfigurationResolutionOptions {
444
+ /** Host-scoped configuration layers to include during resolution. */
444
445
  configurationContext?: ConfigurationContext
445
446
  }
446
447
 
@@ -2,10 +2,17 @@
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
+ /** APX OAuth scope for local development. */
5
6
  export const ApxLocalScope: string = 'c16e153d-5d2b-4c21-b7f4-b05ee5d516f1/.default'
7
+ /** APX OAuth scope for the development environment. */
6
8
  export const ApxDevScope: string = '0d94caae-b412-4943-8a68-83135ad6d35f/.default'
9
+ /** APX OAuth scope for the production environment. */
7
10
  export const ApxProductionScope: string = '5a807f24-c9de-44ee-a3a7-329e88a00ffc/.default'
11
+ /** APX OAuth scope for the US Government Community Cloud environment. */
8
12
  export const ApxGCCScope: string = 'c9475445-9789-4fef-9ec5-cde4a9bcd446/.default'
13
+ /** APX OAuth scope for the US Government Community Cloud High environment. */
9
14
  export const ApxGCCHScope: string = '6f669b9e-7701-4e2b-b624-82c9207fde26/.default'
15
+ /** APX OAuth scope for the US Department of Defense environment. */
10
16
  export const ApxDoDScope: string = '0a069c81-8c7c-4712-886b-9c542d673ffb/.default'
17
+ /** APX OAuth scope for the Microsoft Cloud operated by 21Vianet. */
11
18
  export const ApxGallatinScope: string = 'bd004c8e-5acf-4c48-8570-4e7d46b2f63b/.default'
@@ -21,7 +21,20 @@ export interface AuthProvider {
21
21
  * @returns A promise that resolves to the access token.
22
22
  */
23
23
  getAccessToken (authConfig: AuthConfiguration, scope: string): Promise<string>
24
+ /**
25
+ * Gets an access token using this provider's connection settings.
26
+ *
27
+ * @param scope - Scope for which the access token is requested.
28
+ * @returns A promise that resolves to the access token.
29
+ */
24
30
  getAccessToken (scope: string): Promise<string>
31
+ /**
32
+ * Gets an access token using explicit or provider-level settings.
33
+ *
34
+ * @param authConfigOrScope - Authentication configuration, or the scope when using provider settings.
35
+ * @param scope - Scope used with an explicit authentication configuration.
36
+ * @returns A promise that resolves to the access token.
37
+ */
25
38
  getAccessToken (authConfigOrScope: AuthConfiguration | string, scope?: string): Promise<string>
26
39
 
27
40
  /**
@@ -50,8 +63,31 @@ export interface AuthProvider {
50
63
  */
51
64
  getAgenticUserToken: (tenantId: string, agentAppInstanceId: string, upn: string, scopes: string[]) => Promise<string>
52
65
 
66
+ /**
67
+ * Acquires a token on behalf of a user using this provider's connection settings.
68
+ *
69
+ * @param scopes - Scopes requested for the delegated token.
70
+ * @param oboAssertion - User assertion exchanged for the token.
71
+ * @returns A promise that resolves to the delegated access token.
72
+ */
53
73
  acquireTokenOnBehalfOf (scopes: string[], oboAssertion: string): Promise<string>
74
+ /**
75
+ * Acquires a token on behalf of a user using explicit authentication settings.
76
+ *
77
+ * @param authConfig - Authentication configuration.
78
+ * @param scopes - Scopes requested for the delegated token.
79
+ * @param oboAssertion - User assertion exchanged for the token.
80
+ * @returns A promise that resolves to the delegated access token.
81
+ */
54
82
  acquireTokenOnBehalfOf (authConfig: AuthConfiguration, scopes: string[], oboAssertion: string): Promise<string>
83
+ /**
84
+ * Acquires a delegated token using explicit or provider-level settings.
85
+ *
86
+ * @param authConfigOrScopes - Authentication configuration, or requested scopes when using provider settings.
87
+ * @param scopesOrOboAssertion - Requested scopes or the user assertion, depending on the overload.
88
+ * @param oboAssertion - User assertion used with explicit authentication settings.
89
+ * @returns A promise that resolves to the delegated access token.
90
+ */
55
91
  acquireTokenOnBehalfOf (
56
92
  authConfigOrScopes: AuthConfiguration | string[],
57
93
  scopesOrOboAssertion?: string[] | string,
@@ -146,7 +146,9 @@ export class ConnectionManager implements Connections {
146
146
  audience = identity.aud
147
147
  }
148
148
 
149
- if (!audience || !serviceUrl) throw ExceptionHelper.generateException(Error, Errors.AudienceAndServiceUrlRequiredForTokenProvider)
149
+ if (!audience || !serviceUrl) {
150
+ throw ExceptionHelper.generateException(Error, Errors.AudienceAndServiceUrlRequiredForTokenProvider)
151
+ }
150
152
 
151
153
  if (this._connectionsMap.length === 0) {
152
154
  logger.debug('no connectionsMap, using default connection for serviceUrl=%s', serviceUrl)
@@ -8,6 +8,7 @@ import { AuthConfiguration } from './authConfiguration'
8
8
  import { AuthProvider } from './authProvider'
9
9
  import { JwtPayload } from 'jsonwebtoken'
10
10
 
11
+ /** Provides configured authentication connections and token providers. */
11
12
  export interface Connections {
12
13
  /**
13
14
  * Get the OAuth connection for the agent.
@@ -14,6 +14,13 @@ import { ConnectionManager, defaultAuthProviderFactory } from '../connectionMana
14
14
  * provider factory and applies MSAL-specific connection defaults.
15
15
  */
16
16
  export class MsalConnectionManager extends ConnectionManager {
17
+ /**
18
+ * Creates an MSAL connection manager.
19
+ *
20
+ * @param connectionsConfigurations - Authentication settings keyed by connection name.
21
+ * @param connectionsMap - Rules that map service URLs and audiences to connections.
22
+ * @param configuration - Default authentication configuration.
23
+ */
17
24
  constructor (
18
25
  connectionsConfigurations: Map<string, AuthConfiguration> = new Map(),
19
26
  connectionsMap: ConnectionMapItem[] = [],
@@ -37,8 +37,14 @@ export class MsalTokenProvider implements AuthProvider {
37
37
  private static readonly _agenticTokenCache = new MemoryCache<string>()
38
38
  private static readonly _confidentialClients = new Map<string, ConfidentialClientApplication>()
39
39
  private static readonly _maxConfidentialClients = 100
40
+ /** Authentication settings used by overloads that do not accept an explicit configuration. */
40
41
  public readonly connectionSettings?: AuthConfiguration
41
42
 
43
+ /**
44
+ * Creates an MSAL token provider.
45
+ *
46
+ * @param connectionSettings - Default authentication settings for token acquisition.
47
+ */
42
48
  constructor (connectionSettings?: AuthConfiguration) {
43
49
  this.connectionSettings = connectionSettings
44
50
  }
@@ -281,6 +287,13 @@ export class MsalTokenProvider implements AuthProvider {
281
287
  * @returns A promise that resolves to the access token.
282
288
  */
283
289
  public async getAccessToken (authConfig: AuthConfiguration, scope: string): Promise<string>
290
+ /**
291
+ * Gets an access token using explicit or provider-level settings.
292
+ *
293
+ * @param authConfigOrScope - Authentication configuration, or the scope when using provider settings.
294
+ * @param scope - Scope used with an explicit authentication configuration.
295
+ * @returns The access token.
296
+ */
284
297
  public async getAccessToken (authConfigOrScope: AuthConfiguration | string, scope?: string): Promise<string> {
285
298
  return trace(AuthenticationTraceDefinitions.getAccessToken, async ({ record }) => {
286
299
  let authConfig: AuthConfiguration
@@ -368,8 +381,31 @@ export class MsalTokenProvider implements AuthProvider {
368
381
  })
369
382
  }
370
383
 
384
+ /**
385
+ * Acquires a delegated token using this provider's connection settings.
386
+ *
387
+ * @param scopes - Scopes requested for the delegated token.
388
+ * @param oboAssertion - User assertion exchanged for the token.
389
+ * @returns The delegated access token.
390
+ */
371
391
  public async acquireTokenOnBehalfOf (scopes: string[], oboAssertion: string): Promise<string>
392
+ /**
393
+ * Acquires a delegated token using explicit authentication settings.
394
+ *
395
+ * @param authConfig - Authentication configuration.
396
+ * @param scopes - Scopes requested for the delegated token.
397
+ * @param oboAssertion - User assertion exchanged for the token.
398
+ * @returns The delegated access token.
399
+ */
372
400
  public async acquireTokenOnBehalfOf (authConfig: AuthConfiguration, scopes: string[], oboAssertion: string): Promise<string>
401
+ /**
402
+ * Acquires a delegated token using explicit or provider-level settings.
403
+ *
404
+ * @param authConfigOrScopes - Authentication configuration, or requested scopes when using provider settings.
405
+ * @param scopesOrOboAssertion - Requested scopes or the user assertion, depending on the overload.
406
+ * @param oboAssertion - User assertion used with explicit authentication settings.
407
+ * @returns The delegated access token.
408
+ */
373
409
  public async acquireTokenOnBehalfOf (
374
410
  authConfigOrScopes: AuthConfiguration | string[],
375
411
  scopesOrOboAssertion?: string[] | string,
@@ -411,6 +447,13 @@ export class MsalTokenProvider implements AuthProvider {
411
447
  })
412
448
  }
413
449
 
450
+ /**
451
+ * Gets a federated token for an agent application instance.
452
+ *
453
+ * @param tenantId - Microsoft Entra tenant ID.
454
+ * @param agentAppInstanceId - Agent application instance ID.
455
+ * @returns The agent instance token.
456
+ */
414
457
  public async getAgenticInstanceToken (tenantId: string, agentAppInstanceId: string): Promise<string> {
415
458
  return trace(AuthenticationTraceDefinitions.getAgenticInstanceToken, async ({ record }) => {
416
459
  logger.debug('getAgenticInstanceToken tenantId=%s agentAppInstanceId=%s', tenantId, agentAppInstanceId)
@@ -566,6 +609,15 @@ export class MsalTokenProvider implements AuthProvider {
566
609
  return token.access_token
567
610
  }
568
611
 
612
+ /**
613
+ * Gets a delegated token for an agentic user.
614
+ *
615
+ * @param tenantId - Microsoft Entra tenant ID.
616
+ * @param agentAppInstanceId - Agent application instance ID.
617
+ * @param agenticUserId - ID of the user represented by the token.
618
+ * @param scopes - Scopes requested for the token.
619
+ * @returns The agentic user token.
620
+ */
569
621
  public async getAgenticUserToken (tenantId: string, agentAppInstanceId: string, agenticUserId: string, scopes: string[]): Promise<string> {
570
622
  return trace(AuthenticationTraceDefinitions.getAgenticUserToken, async ({ record }) => {
571
623
  logger.debug('getAgenticUserToken tenantId=%s agentAppInstanceId=%s scopes=%o', tenantId, agentAppInstanceId, scopes)
@@ -597,6 +649,13 @@ export class MsalTokenProvider implements AuthProvider {
597
649
  })
598
650
  }
599
651
 
652
+ /**
653
+ * Gets the application token used to authenticate an agent application instance.
654
+ *
655
+ * @param tenantId - Microsoft Entra tenant ID.
656
+ * @param agentAppInstanceId - Agent application instance ID.
657
+ * @returns The agentic application token.
658
+ */
600
659
  public async getAgenticApplicationToken (tenantId: string, agentAppInstanceId: string): Promise<string> {
601
660
  if (!this.connectionSettings?.clientId) {
602
661
  throw ExceptionHelper.generateException(Error, Errors.ConnectionSettingsRequiredForGetAgenticApplicationToken)