@microsoft/agents-hosting 1.1.0-alpha.9.g154c2c8a32 → 1.1.4-g8d884129e7

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 (152) hide show
  1. package/dist/package.json +10 -6
  2. package/dist/src/activityWireCompat.d.ts +1 -1
  3. package/dist/src/activityWireCompat.js +11 -3
  4. package/dist/src/activityWireCompat.js.map +1 -1
  5. package/dist/src/agent-client/agentClient.js +7 -3
  6. package/dist/src/agent-client/agentClient.js.map +1 -1
  7. package/dist/src/agent-client/agentResponseHandler.js +6 -2
  8. package/dist/src/agent-client/agentResponseHandler.js.map +1 -1
  9. package/dist/src/app/agentApplication.d.ts +26 -11
  10. package/dist/src/app/agentApplication.js +90 -79
  11. package/dist/src/app/agentApplication.js.map +1 -1
  12. package/dist/src/app/agentApplicationBuilder.d.ts +2 -2
  13. package/dist/src/app/agentApplicationBuilder.js.map +1 -1
  14. package/dist/src/app/agentApplicationOptions.d.ts +9 -2
  15. package/dist/src/app/appRoute.d.ts +7 -0
  16. package/dist/src/app/{authorization.d.ts → auth/authorization.d.ts} +41 -139
  17. package/dist/src/app/auth/authorization.js +188 -0
  18. package/dist/src/app/auth/authorization.js.map +1 -0
  19. package/dist/src/app/auth/authorizationManager.d.ts +71 -0
  20. package/dist/src/app/auth/authorizationManager.js +170 -0
  21. package/dist/src/app/auth/authorizationManager.js.map +1 -0
  22. package/dist/src/app/auth/handlerStorage.d.ts +36 -0
  23. package/dist/src/app/auth/handlerStorage.js +62 -0
  24. package/dist/src/app/auth/handlerStorage.js.map +1 -0
  25. package/dist/src/app/auth/handlers/agenticAuthorization.d.ts +93 -0
  26. package/dist/src/app/auth/handlers/agenticAuthorization.js +134 -0
  27. package/dist/src/app/auth/handlers/agenticAuthorization.js.map +1 -0
  28. package/dist/src/app/auth/handlers/azureBotAuthorization.d.ts +226 -0
  29. package/dist/src/app/auth/handlers/azureBotAuthorization.js +429 -0
  30. package/dist/src/app/auth/handlers/azureBotAuthorization.js.map +1 -0
  31. package/dist/src/app/auth/handlers/index.d.ts +2 -0
  32. package/dist/src/app/auth/handlers/index.js +19 -0
  33. package/dist/src/app/auth/handlers/index.js.map +1 -0
  34. package/dist/src/app/auth/index.d.ts +2 -0
  35. package/dist/src/app/auth/index.js +19 -0
  36. package/dist/src/app/auth/index.js.map +1 -0
  37. package/dist/src/app/auth/types.d.ts +104 -0
  38. package/dist/src/app/auth/types.js +24 -0
  39. package/dist/src/app/auth/types.js.map +1 -0
  40. package/dist/src/app/index.d.ts +3 -3
  41. package/dist/src/app/index.js +2 -3
  42. package/dist/src/app/index.js.map +1 -1
  43. package/dist/src/app/routeList.d.ts +1 -1
  44. package/dist/src/app/routeList.js +22 -5
  45. package/dist/src/app/routeList.js.map +1 -1
  46. package/dist/src/app/streaming/streamingResponse.js +2 -1
  47. package/dist/src/app/streaming/streamingResponse.js.map +1 -1
  48. package/dist/src/auth/MemoryCache.d.ts +16 -0
  49. package/dist/src/auth/MemoryCache.js +58 -0
  50. package/dist/src/auth/MemoryCache.js.map +1 -0
  51. package/dist/src/auth/authConfiguration.d.ts +44 -2
  52. package/dist/src/auth/authConfiguration.js +209 -53
  53. package/dist/src/auth/authConfiguration.js.map +1 -1
  54. package/dist/src/auth/authConstants.d.ts +11 -0
  55. package/dist/src/auth/authConstants.js +15 -0
  56. package/dist/src/auth/authConstants.js.map +1 -0
  57. package/dist/src/auth/authProvider.d.ts +26 -0
  58. package/dist/src/auth/connections.d.ts +41 -0
  59. package/dist/src/auth/connections.js +7 -0
  60. package/dist/src/auth/connections.js.map +1 -0
  61. package/dist/src/auth/index.d.ts +2 -0
  62. package/dist/src/auth/index.js +2 -0
  63. package/dist/src/auth/index.js.map +1 -1
  64. package/dist/src/auth/jwt-middleware.js +31 -18
  65. package/dist/src/auth/jwt-middleware.js.map +1 -1
  66. package/dist/src/auth/msalConnectionManager.d.ts +64 -0
  67. package/dist/src/auth/msalConnectionManager.js +148 -0
  68. package/dist/src/auth/msalConnectionManager.js.map +1 -0
  69. package/dist/src/auth/msalTokenProvider.d.ts +38 -0
  70. package/dist/src/auth/msalTokenProvider.js +189 -16
  71. package/dist/src/auth/msalTokenProvider.js.map +1 -1
  72. package/dist/src/baseAdapter.d.ts +10 -25
  73. package/dist/src/baseAdapter.js +2 -15
  74. package/dist/src/baseAdapter.js.map +1 -1
  75. package/dist/src/cards/cardFactory.d.ts +2 -1
  76. package/dist/src/cards/cardFactory.js +3 -2
  77. package/dist/src/cards/cardFactory.js.map +1 -1
  78. package/dist/src/cloudAdapter.d.ts +40 -23
  79. package/dist/src/cloudAdapter.js +143 -63
  80. package/dist/src/cloudAdapter.js.map +1 -1
  81. package/dist/src/connector-client/connectorClient.d.ts +15 -0
  82. package/dist/src/connector-client/connectorClient.js +49 -15
  83. package/dist/src/connector-client/connectorClient.js.map +1 -1
  84. package/dist/src/index.d.ts +0 -1
  85. package/dist/src/index.js +0 -1
  86. package/dist/src/index.js.map +1 -1
  87. package/dist/src/oauth/customUserTokenAPI.d.ts +1 -0
  88. package/dist/src/oauth/customUserTokenAPI.js +11 -0
  89. package/dist/src/oauth/customUserTokenAPI.js.map +1 -0
  90. package/dist/src/oauth/index.d.ts +0 -1
  91. package/dist/src/oauth/index.js +0 -1
  92. package/dist/src/oauth/index.js.map +1 -1
  93. package/dist/src/oauth/userTokenClient.d.ts +30 -13
  94. package/dist/src/oauth/userTokenClient.js +62 -26
  95. package/dist/src/oauth/userTokenClient.js.map +1 -1
  96. package/dist/src/oauth/userTokenClient.types.d.ts +19 -6
  97. package/dist/src/transcript/fileTranscriptLogger.d.ts +109 -0
  98. package/dist/src/transcript/fileTranscriptLogger.js +398 -0
  99. package/dist/src/transcript/fileTranscriptLogger.js.map +1 -0
  100. package/dist/src/turnContext.d.ts +7 -1
  101. package/dist/src/turnContext.js +11 -4
  102. package/dist/src/turnContext.js.map +1 -1
  103. package/package.json +10 -6
  104. package/src/activityWireCompat.ts +12 -4
  105. package/src/agent-client/agentClient.ts +9 -3
  106. package/src/agent-client/agentResponseHandler.ts +5 -2
  107. package/src/app/agentApplication.ts +95 -74
  108. package/src/app/agentApplicationBuilder.ts +2 -2
  109. package/src/app/agentApplicationOptions.ts +10 -2
  110. package/src/app/appRoute.ts +8 -0
  111. package/src/app/auth/authorization.ts +261 -0
  112. package/src/app/auth/authorizationManager.ts +213 -0
  113. package/src/app/auth/handlerStorage.ts +61 -0
  114. package/src/app/auth/handlers/agenticAuthorization.ts +183 -0
  115. package/src/app/auth/handlers/azureBotAuthorization.ts +606 -0
  116. package/src/app/auth/handlers/index.ts +2 -0
  117. package/src/app/auth/index.ts +2 -0
  118. package/src/app/auth/types.ts +111 -0
  119. package/src/app/index.ts +3 -3
  120. package/src/app/routeList.ts +24 -5
  121. package/src/app/streaming/streamingResponse.ts +2 -1
  122. package/src/auth/MemoryCache.ts +59 -0
  123. package/src/auth/authConfiguration.ts +245 -52
  124. package/src/auth/authConstants.ts +11 -0
  125. package/src/auth/authProvider.ts +34 -0
  126. package/src/auth/connections.ts +47 -0
  127. package/src/auth/index.ts +2 -0
  128. package/src/auth/jwt-middleware.ts +38 -21
  129. package/src/auth/msalConnectionManager.ts +175 -0
  130. package/src/auth/msalTokenProvider.ts +231 -9
  131. package/src/baseAdapter.ts +10 -29
  132. package/src/cards/cardFactory.ts +3 -2
  133. package/src/cloudAdapter.ts +207 -72
  134. package/src/connector-client/connectorClient.ts +59 -15
  135. package/src/index.ts +0 -1
  136. package/src/oauth/customUserTokenAPI.ts +5 -0
  137. package/src/oauth/index.ts +0 -1
  138. package/src/oauth/userTokenClient.ts +76 -22
  139. package/src/oauth/userTokenClient.types.ts +20 -8
  140. package/src/transcript/fileTranscriptLogger.ts +409 -0
  141. package/src/turnContext.ts +16 -5
  142. package/dist/src/app/authorization.js +0 -387
  143. package/dist/src/app/authorization.js.map +0 -1
  144. package/dist/src/claimsIdentity.d.ts +0 -35
  145. package/dist/src/claimsIdentity.js +0 -43
  146. package/dist/src/claimsIdentity.js.map +0 -1
  147. package/dist/src/oauth/oAuthFlow.d.ts +0 -119
  148. package/dist/src/oauth/oAuthFlow.js +0 -316
  149. package/dist/src/oauth/oAuthFlow.js.map +0 -1
  150. package/src/app/authorization.ts +0 -432
  151. package/src/claimsIdentity.ts +0 -47
  152. package/src/oauth/oAuthFlow.ts +0 -378
@@ -9,11 +9,12 @@ import { TurnContext } from './turnContext'
9
9
  import { Response } from 'express'
10
10
  import { Request } from './auth/request'
11
11
  import { ConnectorClient } from './connector-client/connectorClient'
12
- import { AuthConfiguration, loadAuthConfigFromEnv } from './auth/authConfiguration'
12
+ import { AuthConfiguration, getAuthConfigWithDefaults } from './auth/authConfiguration'
13
13
  import { AuthProvider } from './auth/authProvider'
14
- import { Activity, ActivityEventNames, ActivityTypes, Channels, ConversationReference, DeliveryModes, ConversationParameters } from '@microsoft/agents-activity'
14
+ import { ApxProductionScope } from './auth/authConstants'
15
+ import { MsalConnectionManager } from './auth/msalConnectionManager'
16
+ import { Activity, ActivityEventNames, ActivityTypes, Channels, ConversationReference, DeliveryModes, ConversationParameters, RoleTypes } from '@microsoft/agents-activity'
15
17
  import { ResourceResponse } from './connector-client/resourceResponse'
16
- import { MsalTokenProvider } from './auth/msalTokenProvider'
17
18
  import * as uuid from 'uuid'
18
19
  import { debug } from '@microsoft/agents-activity/logger'
19
20
  import { StatusCodes } from './statusCodes'
@@ -23,34 +24,34 @@ import { AttachmentData } from './connector-client/attachmentData'
23
24
  import { normalizeIncomingActivity } from './activityWireCompat'
24
25
  import { UserTokenClient } from './oauth'
25
26
  import { HeaderPropagation, HeaderPropagationCollection, HeaderPropagationDefinition } from './headerPropagation'
26
-
27
+ import { JwtPayload } from 'jsonwebtoken'
28
+ import { getTokenServiceEndpoint } from './oauth/customUserTokenAPI'
27
29
  const logger = debug('agents:cloud-adapter')
28
30
 
29
31
  /**
30
32
  * Adapter for handling agent interactions with various channels through cloud-based services.
31
33
  *
32
34
  * @remarks
33
- * CloudAdapter processes incoming HTTP requests from Microsoft Bot Framework channels,
35
+ * CloudAdapter processes incoming HTTP requests from Azure Bot Service channels,
34
36
  * authenticates them, and generates outgoing responses. It manages the communication
35
37
  * flow between agents and users across different channels, handling activities, attachments,
36
38
  * and conversation continuations.
37
39
  */
38
40
  export class CloudAdapter extends BaseAdapter {
39
41
  /**
40
- * Client for connecting to the Bot Framework Connector service
42
+ * Client for connecting to the Azure Bot Service
41
43
  */
42
- public connectorClient!: ConnectorClient
43
- authConfig: AuthConfiguration
44
+ connectionManager: MsalConnectionManager
45
+
44
46
  /**
45
47
  * Creates an instance of CloudAdapter.
46
48
  * @param authConfig - The authentication configuration for securing communications
47
- * @param authProvider - Optional custom authentication provider. If not specified, a default MsalTokenProvider will be used
49
+ * @param authProvider - No longer used
48
50
  */
49
51
  constructor (authConfig?: AuthConfiguration, authProvider?: AuthProvider, userTokenClient?: UserTokenClient) {
50
52
  super()
51
- this.authConfig = authConfig ?? loadAuthConfigFromEnv()
52
- this.authProvider = authProvider ?? new MsalTokenProvider()
53
- this.userTokenClient = userTokenClient ?? new UserTokenClient(this.authConfig.clientId)
53
+ authConfig = getAuthConfigWithDefaults(authConfig)
54
+ this.connectionManager = new MsalConnectionManager(undefined, undefined, authConfig)
54
55
  }
55
56
 
56
57
  /**
@@ -92,17 +93,80 @@ export class CloudAdapter extends BaseAdapter {
92
93
  protected async createConnectorClient (
93
94
  serviceUrl: string,
94
95
  scope: string,
96
+ identity: JwtPayload,
95
97
  headers?: HeaderPropagationCollection
96
98
  ): Promise<ConnectorClient> {
97
- return ConnectorClient.createClientWithAuth(
99
+ // get the correct token provider
100
+ const tokenProvider = this.connectionManager.getTokenProvider(identity, serviceUrl)
101
+
102
+ const token = await tokenProvider.getAccessToken(scope)
103
+ return ConnectorClient.createClientWithToken(
98
104
  serviceUrl,
99
- this.authConfig,
100
- this.authProvider,
101
- scope,
105
+ token,
102
106
  headers
103
107
  )
104
108
  }
105
109
 
110
+ protected async createConnectorClientWithIdentity (
111
+ identity: JwtPayload,
112
+ activity: Activity,
113
+ headers?: HeaderPropagationCollection) {
114
+ if (!identity?.aud) {
115
+ // anonymous
116
+ return ConnectorClient.createClientWithToken(
117
+ activity.serviceUrl!,
118
+ null!,
119
+ headers
120
+ )
121
+ }
122
+
123
+ let connectorClient
124
+ const tokenProvider = this.connectionManager.getTokenProviderFromActivity(identity, activity)
125
+ if (activity.isAgenticRequest()) {
126
+ logger.debug('Activity is from an agentic source, using special scope', activity.recipient)
127
+ const agenticInstanceId = activity.getAgenticInstanceId()
128
+ const agenticUserId = activity.getAgenticUser()
129
+
130
+ if (activity.recipient?.role?.toLowerCase() === RoleTypes.AgenticIdentity.toLowerCase() && agenticInstanceId) {
131
+ // get agentic instance token
132
+ const token = await tokenProvider.getAgenticInstanceToken(activity.getAgenticTenantId() ?? '', agenticInstanceId)
133
+ connectorClient = ConnectorClient.createClientWithToken(
134
+ activity.serviceUrl!,
135
+ token,
136
+ headers
137
+ )
138
+ } else if (activity.recipient?.role?.toLowerCase() === RoleTypes.AgenticUser.toLowerCase() && agenticInstanceId && agenticUserId) {
139
+ const scope = tokenProvider.connectionSettings?.scope ?? ApxProductionScope
140
+ const token = await tokenProvider.getAgenticUserToken(activity.getAgenticTenantId() ?? '', agenticInstanceId, agenticUserId, [scope])
141
+
142
+ connectorClient = ConnectorClient.createClientWithToken(
143
+ activity.serviceUrl!,
144
+ token,
145
+ headers
146
+ )
147
+ } else {
148
+ throw new Error('Could not create connector client for agentic user')
149
+ }
150
+ } else {
151
+ // ABS tokens will not have an azp/appid so use the botframework scope.
152
+ // Otherwise use the appId. This will happen when communicating back to another agent.
153
+ const scope = identity.azp ?? identity.appid ?? 'https://api.botframework.com'
154
+ const token = await tokenProvider.getAccessToken(scope)
155
+ connectorClient = ConnectorClient.createClientWithToken(
156
+ activity.serviceUrl!,
157
+ token,
158
+ headers
159
+ )
160
+ }
161
+ return connectorClient
162
+ }
163
+
164
+ static createIdentity (appId: string) : JwtPayload {
165
+ return {
166
+ aud: appId
167
+ } as JwtPayload
168
+ }
169
+
106
170
  /**
107
171
  * Sets the connector client on the turn context.
108
172
  *
@@ -110,24 +174,71 @@ export class CloudAdapter extends BaseAdapter {
110
174
  * @protected
111
175
  */
112
176
  protected setConnectorClient (
113
- context: TurnContext
177
+ context: TurnContext,
178
+ connectorClient?: ConnectorClient
179
+ ) {
180
+ context.turnState.set(this.ConnectorClientKey, connectorClient)
181
+ }
182
+
183
+ /**
184
+ * Creates a user token client for a specific service URL and scope.
185
+ *
186
+ * @param serviceUrl - The URL of the service to connect to
187
+ * @param scope - The authentication scope to use
188
+ * @param headers - Optional headers to propagate in the request
189
+ * @returns A promise that resolves to a ConnectorClient instance
190
+ * @protected
191
+ */
192
+ protected async createUserTokenClient (
193
+ identity: JwtPayload,
194
+ tokenServiceEndpoint: string = getTokenServiceEndpoint(),
195
+ scope: string = 'https://api.botframework.com',
196
+ audience: string = 'https://api.botframework.com',
197
+ headers?: HeaderPropagationCollection
198
+ ): Promise<UserTokenClient> {
199
+ if (!identity?.aud) {
200
+ // anonymous
201
+ return UserTokenClient.createClientWithScope(
202
+ tokenServiceEndpoint,
203
+ null!,
204
+ scope,
205
+ headers
206
+ )
207
+ }
208
+
209
+ // get the correct token provider
210
+ const tokenProvider = this.connectionManager.getTokenProvider(identity, tokenServiceEndpoint)
211
+
212
+ return UserTokenClient.createClientWithScope(
213
+ tokenServiceEndpoint,
214
+ tokenProvider,
215
+ scope,
216
+ headers
217
+ )
218
+ }
219
+
220
+ /**
221
+ * Sets the user token client on the turn context.
222
+ *
223
+ * @param context - The current turn context
224
+ * @protected
225
+ */
226
+ protected setUserTokenClient (
227
+ context: TurnContext,
228
+ userTokenClient?: UserTokenClient
114
229
  ) {
115
- context.turnState.set('connectorClient', this.connectorClient)
230
+ context.turnState.set(this.UserTokenClientKey, userTokenClient)
116
231
  }
117
232
 
118
233
  /**
234
+ * @deprecated This function will not be supported in future versions. Create TurnContext directly.
119
235
  * Creates a TurnContext for the given activity and logic.
120
236
  * @param activity - The activity to process.
121
237
  * @param logic - The logic to execute.
122
238
  * @returns The created TurnContext.
123
239
  */
124
- createTurnContext (activity: Activity, logic: AgentHandler): TurnContext {
125
- return new TurnContext(this, activity)
126
- }
127
-
128
- async createTurnContextWithScope (activity: Activity, logic: AgentHandler, scope: string): Promise<TurnContext> {
129
- this.connectorClient = await ConnectorClient.createClientWithAuth(activity.serviceUrl!, this.authConfig!, this.authProvider, scope)
130
- return new TurnContext(this, activity)
240
+ createTurnContext (activity: Activity, logic: AgentHandler, identity?: JwtPayload): TurnContext {
241
+ return new TurnContext(this, activity, identity)
131
242
  }
132
243
 
133
244
  /**
@@ -154,9 +265,7 @@ export class CloudAdapter extends BaseAdapter {
154
265
  delete activity.id
155
266
  let response: ResourceResponse = { id: '' }
156
267
 
157
- if (activity.type === ActivityTypes.Delay) {
158
- await setTimeout(() => { }, typeof activity.value === 'number' ? activity.value : 1000)
159
- } else if (activity.type === ActivityTypes.InvokeResponse) {
268
+ if (activity.type === ActivityTypes.InvokeResponse) {
160
269
  context.turnState.set(INVOKE_RESPONSE_KEY, activity)
161
270
  } else if (activity.type === ActivityTypes.Trace && activity.channelId !== Channels.Emulator) {
162
271
  // no-op
@@ -165,12 +274,10 @@ export class CloudAdapter extends BaseAdapter {
165
274
  throw new Error('Invalid activity object')
166
275
  }
167
276
 
168
- this.connectorClient = await this.createConnectorClient(activity.serviceUrl, 'https://api.botframework.com')
169
-
170
277
  if (activity.replyToId) {
171
- response = await this.connectorClient.replyToActivity(activity.conversation.id, activity.replyToId, activity)
278
+ response = await context.turnState.get(this.ConnectorClientKey).replyToActivity(activity.conversation.id, activity.replyToId, activity)
172
279
  } else {
173
- response = await this.connectorClient.sendToConversation(activity.conversation.id, activity)
280
+ response = await context.turnState.get(this.ConnectorClientKey).sendToConversation(activity.conversation.id, activity)
174
281
  }
175
282
  }
176
283
 
@@ -184,18 +291,6 @@ export class CloudAdapter extends BaseAdapter {
184
291
  return responses
185
292
  }
186
293
 
187
- /**
188
- * Replies to an activity.
189
- * @param activity - The activity to reply to.
190
- * @returns A promise representing the ResourceResponse for the sent activity.
191
- */
192
- async replyToActivity (activity: Activity): Promise<ResourceResponse> {
193
- if (!activity.serviceUrl || (activity.conversation == null) || !activity.conversation.id || !activity.id) {
194
- throw new Error('Invalid activity object')
195
- }
196
- return await this.connectorClient.replyToActivity(activity.conversation.id, activity.id, activity)
197
- }
198
-
199
294
  /**
200
295
  * Processes an incoming request and sends the response.
201
296
  * @param request - The incoming request.
@@ -236,14 +331,17 @@ export class CloudAdapter extends BaseAdapter {
236
331
  }
237
332
 
238
333
  logger.debug('Received activity: ', activity)
239
- const context = this.createTurnContext(activity, logic)
240
- const scope = request.user?.azp ?? request.user?.appid ?? 'https://api.botframework.com'
241
334
 
335
+ const context = new TurnContext(this, activity, request.user!)
242
336
  // if Delivery Mode == ExpectReplies, we don't need a connector client.
243
337
  if (this.resolveIfConnectorClientIsNeeded(activity)) {
244
- logger.debug('Creating connector client with scope: ', scope)
245
- this.connectorClient = await this.createConnectorClient(activity.serviceUrl!, scope, headers)
246
- this.setConnectorClient(context)
338
+ const connectorClient = await this.createConnectorClientWithIdentity(request.user!, activity, headers)
339
+ this.setConnectorClient(context, connectorClient)
340
+ }
341
+
342
+ if (!activity.isAgenticRequest()) {
343
+ const userTokenClient = await this.createUserTokenClient(request.user!)
344
+ this.setUserTokenClient(context, userTokenClient)
247
345
  }
248
346
 
249
347
  if (
@@ -254,12 +352,11 @@ export class CloudAdapter extends BaseAdapter {
254
352
  await this.runMiddleware(context, logic)
255
353
  const invokeResponse = this.processTurnResults(context)
256
354
  logger.debug('Activity Response (invoke/expect replies): ', invokeResponse)
257
- return end(invokeResponse?.status ?? StatusCodes.OK, JSON.stringify(invokeResponse?.body), true)
355
+ return end(invokeResponse?.status ?? StatusCodes.OK, invokeResponse?.body, true)
258
356
  }
259
357
 
260
358
  await this.runMiddleware(context, logic)
261
359
  const invokeResponse = this.processTurnResults(context)
262
-
263
360
  return end(invokeResponse?.status ?? StatusCodes.OK, invokeResponse?.body)
264
361
  }
265
362
 
@@ -301,7 +398,7 @@ export class CloudAdapter extends BaseAdapter {
301
398
  throw new Error('Invalid activity object')
302
399
  }
303
400
 
304
- const response = await this.connectorClient.updateActivity(
401
+ const response = await context.turnState.get(this.ConnectorClientKey).updateActivity(
305
402
  activity.conversation.id,
306
403
  activity.id,
307
404
  activity
@@ -325,7 +422,7 @@ export class CloudAdapter extends BaseAdapter {
325
422
  throw new Error('Invalid conversation reference object')
326
423
  }
327
424
 
328
- await this.connectorClient.deleteActivity(reference.conversation.id, reference.activityId)
425
+ await context.turnState.get(this.ConnectorClientKey).deleteActivity(reference.conversation.id, reference.activityId)
329
426
  }
330
427
 
331
428
  /**
@@ -334,25 +431,44 @@ export class CloudAdapter extends BaseAdapter {
334
431
  * @param logic - The logic to execute.
335
432
  * @returns A promise representing the completion of the continue operation.
336
433
  */
337
- async continueConversation (reference: ConversationReference, logic: (revocableContext: TurnContext) => Promise<void>, isResponse: Boolean = false): Promise<void> {
434
+ async continueConversation (
435
+ botAppIdOrIdentity: string | JwtPayload,
436
+ reference: ConversationReference,
437
+ logic: (revocableContext: TurnContext) => Promise<void>,
438
+ isResponse: Boolean = false): Promise<void> {
338
439
  if (!reference || !reference.serviceUrl || (reference.conversation == null) || !reference.conversation.id) {
339
- throw new Error('Invalid conversation reference object')
440
+ throw new Error('continueConversation: Invalid conversation reference object')
340
441
  }
341
442
 
342
- let context
343
- if (isResponse) {
344
- context = await this.createTurnContextWithScope(Activity.getContinuationActivity(reference), logic, 'https://api.botframework.com')
345
- } else {
346
- context = this.createTurnContext(Activity.getContinuationActivity(reference), logic)
443
+ if (!botAppIdOrIdentity) {
444
+ throw new TypeError('continueConversation: botAppIdOrIdentity is required')
445
+ }
446
+ const botAppId = typeof botAppIdOrIdentity === 'string' ? botAppIdOrIdentity : botAppIdOrIdentity.aud as string
447
+
448
+ // Only having the botId will only work against ABS or Agentic. Proactive to other agents will
449
+ // not work with just botId. Use a JwtPayload with property aud (which is botId) and appid populated.
450
+ const identity =
451
+ typeof botAppIdOrIdentity !== 'string'
452
+ ? botAppIdOrIdentity
453
+ : CloudAdapter.createIdentity(botAppId)
454
+
455
+ const context = new TurnContext(this, Activity.getContinuationActivity(reference), identity)
456
+ const connectorClient = await this.createConnectorClientWithIdentity(identity, context.activity)
457
+ this.setConnectorClient(context, connectorClient)
458
+
459
+ if (!context.activity.isAgenticRequest()) {
460
+ const userTokenClient = await this.createUserTokenClient(identity)
461
+ this.setUserTokenClient(context, userTokenClient)
347
462
  }
463
+
348
464
  await this.runMiddleware(context, logic)
349
465
  }
350
466
 
351
467
  /**
352
- * Processes the turn results and returns an InvokeResponse if applicable.
353
- * @param context - The TurnContext for the current turn.
354
- * @returns The InvokeResponse if applicable, otherwise undefined.
355
- */
468
+ * Processes the turn results and returns an InvokeResponse if applicable.
469
+ * @param context - The TurnContext for the current turn.
470
+ * @returns The InvokeResponse if applicable, otherwise undefined.
471
+ */
356
472
  protected processTurnResults (context: TurnContext): InvokeResponse | undefined {
357
473
  logger.info('<--Sending back turn results')
358
474
  // Handle ExpectedReplies scenarios where all activities have been buffered and sent back at once in an invoke response.
@@ -437,7 +553,9 @@ export class CloudAdapter extends BaseAdapter {
437
553
  if (!conversationParameters) throw new TypeError('`conversationParameters` must be defined')
438
554
  if (!logic) throw new TypeError('`logic` must be defined')
439
555
 
440
- const restClient = await this.createConnectorClient(serviceUrl, audience)
556
+ const identity = CloudAdapter.createIdentity(audience)
557
+ const restClient = await this.createConnectorClient(serviceUrl, audience, identity)
558
+ const userTokenClient = await this.createUserTokenClient(identity)
441
559
  const createConversationResult = await restClient.createConversation(conversationParameters)
442
560
  const createActivity = this.createCreateActivity(
443
561
  createConversationResult.id,
@@ -445,17 +563,24 @@ export class CloudAdapter extends BaseAdapter {
445
563
  serviceUrl,
446
564
  conversationParameters
447
565
  )
448
- const context = new TurnContext(this, createActivity)
566
+ const context = new TurnContext(this, createActivity, CloudAdapter.createIdentity(agentAppId))
567
+ this.setConnectorClient(context, restClient)
568
+ this.setUserTokenClient(context, userTokenClient)
449
569
  await this.runMiddleware(context, logic)
450
570
  }
451
571
 
452
572
  /**
573
+ * @deprecated This function will not be supported in future versions. Use TurnContext.turnState.get<ConnectorClient>(CloudAdapter.ConnectorClientKey).
453
574
  * Uploads an attachment.
454
575
  * @param conversationId - The conversation ID.
455
576
  * @param attachmentData - The attachment data.
456
577
  * @returns A promise representing the ResourceResponse for the uploaded attachment.
457
578
  */
458
- async uploadAttachment (conversationId: string, attachmentData: AttachmentData): Promise<ResourceResponse> {
579
+ async uploadAttachment (context: TurnContext, conversationId: string, attachmentData: AttachmentData): Promise<ResourceResponse> {
580
+ if (context === undefined) {
581
+ throw new Error('context is required')
582
+ }
583
+
459
584
  if (conversationId === undefined) {
460
585
  throw new Error('conversationId is required')
461
586
  }
@@ -464,29 +589,39 @@ export class CloudAdapter extends BaseAdapter {
464
589
  throw new Error('attachmentData is required')
465
590
  }
466
591
 
467
- return await this.connectorClient.uploadAttachment(conversationId, attachmentData)
592
+ return await context.turnState.get<ConnectorClient>(this.ConnectorClientKey).uploadAttachment(conversationId, attachmentData)
468
593
  }
469
594
 
470
595
  /**
596
+ * @deprecated This function will not be supported in future versions. Use TurnContext.turnState.get<ConnectorClient>(CloudAdapter.ConnectorClientKey).
471
597
  * Gets attachment information.
472
598
  * @param attachmentId - The attachment ID.
473
599
  * @returns A promise representing the AttachmentInfo for the requested attachment.
474
600
  */
475
- async getAttachmentInfo (attachmentId: string): Promise<AttachmentInfo> {
601
+ async getAttachmentInfo (context: TurnContext, attachmentId: string): Promise<AttachmentInfo> {
602
+ if (context === undefined) {
603
+ throw new Error('context is required')
604
+ }
605
+
476
606
  if (attachmentId === undefined) {
477
607
  throw new Error('attachmentId is required')
478
608
  }
479
609
 
480
- return await this.connectorClient.getAttachmentInfo(attachmentId)
610
+ return await context.turnState.get<ConnectorClient>(this.ConnectorClientKey).getAttachmentInfo(attachmentId)
481
611
  }
482
612
 
483
613
  /**
614
+ * @deprecated This function will not be supported in future versions. Use TurnContext.turnState.get<ConnectorClient>(CloudAdapter.ConnectorClientKey).
484
615
  * Gets an attachment.
485
616
  * @param attachmentId - The attachment ID.
486
617
  * @param viewId - The view ID.
487
618
  * @returns A promise representing the NodeJS.ReadableStream for the requested attachment.
488
619
  */
489
- async getAttachment (attachmentId: string, viewId: string): Promise<NodeJS.ReadableStream> {
620
+ async getAttachment (context: TurnContext, attachmentId: string, viewId: string): Promise<NodeJS.ReadableStream> {
621
+ if (context === undefined) {
622
+ throw new Error('context is required')
623
+ }
624
+
490
625
  if (attachmentId === undefined) {
491
626
  throw new Error('attachmentId is required')
492
627
  }
@@ -495,6 +630,6 @@ export class CloudAdapter extends BaseAdapter {
495
630
  throw new Error('viewId is required')
496
631
  }
497
632
 
498
- return await this.connectorClient.getAttachment(attachmentId, viewId)
633
+ return await context.turnState.get<ConnectorClient>(this.ConnectorClientKey).getAttachment(attachmentId, viewId)
499
634
  }
500
635
  }
@@ -3,7 +3,7 @@ import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
3
3
  import { AuthConfiguration } from '../auth/authConfiguration'
4
4
  import { AuthProvider } from '../auth/authProvider'
5
5
  import { debug } from '@microsoft/agents-activity/logger'
6
- import { Activity, ChannelAccount, ConversationParameters } from '@microsoft/agents-activity'
6
+ import { Activity, ChannelAccount, ConversationParameters, RoleTypes, Channels } from '@microsoft/agents-activity'
7
7
  import { ConversationsResult } from './conversationsResult'
8
8
  import { ConversationResourceResponse } from './conversationResourceResponse'
9
9
  import { ResourceResponse } from './resourceResponse'
@@ -91,23 +91,38 @@ export class ConnectorClient {
91
91
  scope: string,
92
92
  headers?: HeaderPropagationCollection
93
93
  ): Promise<ConnectorClient> {
94
+ const token = await authProvider.getAccessToken(authConfig, scope)
95
+ return this.createClientWithToken(baseURL, token, headers)
96
+ }
97
+
98
+ /**
99
+ * Creates a new instance of ConnectorClient with token.
100
+ * @param baseURL - The base URL for the API.
101
+ * @param token - The authentication token.
102
+ * @param headers - Optional headers to propagate in the request.
103
+ * @returns A new instance of ConnectorClient.
104
+ */
105
+ static createClientWithToken (
106
+ baseURL: string,
107
+ token: string,
108
+ headers?: HeaderPropagationCollection
109
+ ): ConnectorClient {
94
110
  const headerPropagation = headers ?? new HeaderPropagation({ 'User-Agent': '' })
95
111
  headerPropagation.concat({ 'User-Agent': getProductInfo() })
96
- headerPropagation.override({ Accept: 'application/json' })
112
+ headerPropagation.override({
113
+ Accept: 'application/json',
114
+ 'Content-Type': 'application/json', // Required by transformRequest
115
+ })
97
116
 
98
117
  const axiosInstance = axios.create({
99
118
  baseURL,
100
119
  headers: headerPropagation.outgoing,
101
- transformRequest: [
102
- (data, headers) => {
103
- return JSON.stringify(normalizeOutgoingActivity(data))
104
- }]
105
120
  })
106
121
 
107
- const token = await authProvider.getAccessToken(authConfig, scope)
108
- if (token.length > 1) {
122
+ if (token && token.length > 1) {
109
123
  axiosInstance.defaults.headers.common.Authorization = `Bearer ${token}`
110
124
  }
125
+
111
126
  return new ConnectorClient(axiosInstance)
112
127
  }
113
128
 
@@ -147,14 +162,17 @@ export class ConnectorClient {
147
162
  * @returns The conversation resource response.
148
163
  */
149
164
  public async createConversation (body: ConversationParameters): Promise<ConversationResourceResponse> {
150
- // const payload = normalizeOutgoingConvoParams(body)
165
+ const payload = {
166
+ ...body,
167
+ activity: normalizeOutgoingActivity(body.activity)
168
+ }
151
169
  const config: AxiosRequestConfig = {
152
170
  method: 'post',
153
171
  url: '/v3/conversations',
154
172
  headers: {
155
173
  'Content-Type': 'application/json'
156
174
  },
157
- data: body
175
+ data: payload
158
176
  }
159
177
  const response: AxiosResponse = await this._axiosInstance(config)
160
178
  return response.data
@@ -176,19 +194,42 @@ export class ConnectorClient {
176
194
  if (!conversationId || !activityId) {
177
195
  throw new Error('conversationId and activityId are required')
178
196
  }
197
+
198
+ const trimmedConversationId: string = this.conditionallyTruncateConversationId(conversationId, body)
199
+
179
200
  const config: AxiosRequestConfig = {
180
201
  method: 'post',
181
- url: `v3/conversations/${conversationId}/activities/${encodeURIComponent(activityId)}`,
202
+ url: `v3/conversations/${trimmedConversationId}/activities/${encodeURIComponent(activityId)}`,
182
203
  headers: {
183
204
  'Content-Type': 'application/json'
184
205
  },
185
- data: body
206
+ data: normalizeOutgoingActivity(body)
186
207
  }
187
208
  const response = await this._axiosInstance(config)
188
209
  logger.info('Reply to conversation/activity: ', response.data.id!, activityId)
189
210
  return response.data
190
211
  }
191
212
 
213
+ /**
214
+ * Trim the conversationId to a fixed length when creating the URL. This is applied only in specific API calls for agentic calls.
215
+ * @param conversationId The ID of the conversation to potentially truncate.
216
+ * @param activity The activity object used to determine if truncation is necessary.
217
+ * @returns The original or truncated conversationId, depending on the channel and activity role.
218
+ */
219
+ private conditionallyTruncateConversationId (conversationId: string, activity: Activity): string {
220
+ if (
221
+ (activity.channelIdChannel === Channels.Msteams || activity.channelIdChannel === Channels.Agents) &&
222
+ (activity.from?.role === RoleTypes.AgenticIdentity || activity.from?.role === RoleTypes.AgenticUser)) {
223
+ let maxLength = 150
224
+ if (process.env.MAX_APX_CONVERSATION_ID_LENGTH && !isNaN(parseInt(process.env.MAX_APX_CONVERSATION_ID_LENGTH, 10))) {
225
+ maxLength = parseInt(process.env.MAX_APX_CONVERSATION_ID_LENGTH, 10)
226
+ }
227
+ return conversationId.length > maxLength ? conversationId.substring(0, maxLength) : conversationId
228
+ } else {
229
+ return conversationId
230
+ }
231
+ }
232
+
192
233
  /**
193
234
  * Sends an activity to a conversation.
194
235
  * @param conversationId - The ID of the conversation.
@@ -203,13 +244,16 @@ export class ConnectorClient {
203
244
  if (!conversationId) {
204
245
  throw new Error('conversationId is required')
205
246
  }
247
+
248
+ const trimmedConversationId: string = this.conditionallyTruncateConversationId(conversationId, body)
249
+
206
250
  const config: AxiosRequestConfig = {
207
251
  method: 'post',
208
- url: `v3/conversations/${conversationId}/activities`,
252
+ url: `v3/conversations/${trimmedConversationId}/activities`,
209
253
  headers: {
210
254
  'Content-Type': 'application/json'
211
255
  },
212
- data: body
256
+ data: normalizeOutgoingActivity(body)
213
257
  }
214
258
  const response = await this._axiosInstance(config)
215
259
  return response.data
@@ -236,7 +280,7 @@ export class ConnectorClient {
236
280
  headers: {
237
281
  'Content-Type': 'application/json'
238
282
  },
239
- data: body
283
+ data: normalizeOutgoingActivity(body)
240
284
  }
241
285
  const response = await this._axiosInstance(config)
242
286
  return response.data
package/src/index.ts CHANGED
@@ -19,7 +19,6 @@ export * from './activityHandler'
19
19
  export * from './baseAdapter'
20
20
  export * from './cloudAdapter'
21
21
  export * from './middlewareSet'
22
- export * from './claimsIdentity'
23
22
  export * from './messageFactory'
24
23
  export * from './statusCodes'
25
24
  export * from './turnContext'
@@ -0,0 +1,5 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+ export const getTokenServiceEndpoint = (): string => {
4
+ return process.env.TOKEN_SERVICE_ENDPOINT ?? 'https://api.botframework.com'
5
+ }
@@ -1,3 +1,2 @@
1
1
  export * from './userTokenClient'
2
- export * from './oAuthFlow'
3
2
  export * from './userTokenClient.types'