@microsoft/agents-hosting 1.1.0-alpha.5 → 1.1.0-alpha.75

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 (144) 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 +28 -13
  10. package/dist/src/app/agentApplication.js +93 -82
  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} +33 -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 +222 -0
  29. package/dist/src/app/auth/handlers/azureBotAuthorization.js +428 -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 +2 -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 +23 -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 +31 -0
  70. package/dist/src/auth/msalTokenProvider.js +167 -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/cloudAdapter.d.ts +40 -23
  76. package/dist/src/cloudAdapter.js +128 -60
  77. package/dist/src/cloudAdapter.js.map +1 -1
  78. package/dist/src/connector-client/connectorClient.d.ts +15 -0
  79. package/dist/src/connector-client/connectorClient.js +49 -15
  80. package/dist/src/connector-client/connectorClient.js.map +1 -1
  81. package/dist/src/index.d.ts +0 -1
  82. package/dist/src/index.js +0 -1
  83. package/dist/src/index.js.map +1 -1
  84. package/dist/src/oauth/customUserTokenAPI.d.ts +1 -0
  85. package/dist/src/oauth/customUserTokenAPI.js +11 -0
  86. package/dist/src/oauth/customUserTokenAPI.js.map +1 -0
  87. package/dist/src/oauth/index.d.ts +0 -1
  88. package/dist/src/oauth/index.js +0 -1
  89. package/dist/src/oauth/index.js.map +1 -1
  90. package/dist/src/oauth/userTokenClient.d.ts +30 -13
  91. package/dist/src/oauth/userTokenClient.js +60 -26
  92. package/dist/src/oauth/userTokenClient.js.map +1 -1
  93. package/dist/src/oauth/userTokenClient.types.d.ts +19 -6
  94. package/dist/src/turnContext.d.ts +7 -1
  95. package/dist/src/turnContext.js +11 -4
  96. package/dist/src/turnContext.js.map +1 -1
  97. package/package.json +10 -6
  98. package/src/activityWireCompat.ts +12 -4
  99. package/src/agent-client/agentClient.ts +9 -3
  100. package/src/agent-client/agentResponseHandler.ts +5 -2
  101. package/src/app/agentApplication.ts +98 -77
  102. package/src/app/agentApplicationBuilder.ts +2 -2
  103. package/src/app/agentApplicationOptions.ts +10 -2
  104. package/src/app/appRoute.ts +8 -0
  105. package/src/app/auth/authorization.ts +252 -0
  106. package/src/app/auth/authorizationManager.ts +213 -0
  107. package/src/app/auth/handlerStorage.ts +61 -0
  108. package/src/app/auth/handlers/agenticAuthorization.ts +182 -0
  109. package/src/app/auth/handlers/azureBotAuthorization.ts +599 -0
  110. package/src/app/auth/handlers/index.ts +2 -0
  111. package/src/app/auth/index.ts +2 -0
  112. package/src/app/auth/types.ts +111 -0
  113. package/src/app/index.ts +2 -3
  114. package/src/app/routeList.ts +24 -5
  115. package/src/app/streaming/streamingResponse.ts +2 -1
  116. package/src/auth/MemoryCache.ts +59 -0
  117. package/src/auth/authConfiguration.ts +245 -52
  118. package/src/auth/authConstants.ts +11 -0
  119. package/src/auth/authProvider.ts +31 -0
  120. package/src/auth/connections.ts +47 -0
  121. package/src/auth/index.ts +2 -0
  122. package/src/auth/jwt-middleware.ts +38 -21
  123. package/src/auth/msalConnectionManager.ts +175 -0
  124. package/src/auth/msalTokenProvider.ts +209 -9
  125. package/src/baseAdapter.ts +10 -29
  126. package/src/cloudAdapter.ts +189 -71
  127. package/src/connector-client/connectorClient.ts +59 -15
  128. package/src/index.ts +0 -1
  129. package/src/oauth/customUserTokenAPI.ts +5 -0
  130. package/src/oauth/index.ts +0 -1
  131. package/src/oauth/userTokenClient.ts +74 -22
  132. package/src/oauth/userTokenClient.types.ts +20 -8
  133. package/src/turnContext.ts +16 -5
  134. package/dist/src/app/authorization.js +0 -387
  135. package/dist/src/app/authorization.js.map +0 -1
  136. package/dist/src/claimsIdentity.d.ts +0 -35
  137. package/dist/src/claimsIdentity.js +0 -43
  138. package/dist/src/claimsIdentity.js.map +0 -1
  139. package/dist/src/oauth/oAuthFlow.d.ts +0 -119
  140. package/dist/src/oauth/oAuthFlow.js +0 -316
  141. package/dist/src/oauth/oAuthFlow.js.map +0 -1
  142. package/src/app/authorization.ts +0 -432
  143. package/src/claimsIdentity.ts +0 -47
  144. 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,77 @@ 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
+ scope: string,
114
+ headers?: HeaderPropagationCollection) {
115
+ if (!identity?.aud) {
116
+ // anonymous
117
+ return ConnectorClient.createClientWithToken(
118
+ activity.serviceUrl!,
119
+ null!,
120
+ headers
121
+ )
122
+ }
123
+
124
+ let connectorClient
125
+ const tokenProvider = this.connectionManager.getTokenProviderFromActivity(identity, activity)
126
+ if (activity.isAgenticRequest()) {
127
+ logger.debug('Activity is from an agentic source, using special scope', activity.recipient)
128
+
129
+ if (activity.recipient?.role === RoleTypes.AgenticIdentity && activity.getAgenticInstanceId()) {
130
+ // get agentic instance token
131
+ const token = await tokenProvider.getAgenticInstanceToken(activity.getAgenticInstanceId() ?? '')
132
+ connectorClient = ConnectorClient.createClientWithToken(
133
+ activity.serviceUrl!,
134
+ token,
135
+ headers
136
+ )
137
+ } else if (activity.recipient?.role === RoleTypes.AgenticUser && activity.getAgenticInstanceId() && activity.getAgenticUser()) {
138
+ const scope = tokenProvider.connectionSettings?.scope ?? ApxProductionScope
139
+ const token = await tokenProvider.getAgenticUserToken(activity.getAgenticInstanceId() ?? '', activity.getAgenticUser() ?? '', [scope])
140
+
141
+ connectorClient = ConnectorClient.createClientWithToken(
142
+ activity.serviceUrl!,
143
+ token,
144
+ headers
145
+ )
146
+ } else {
147
+ throw new Error('Could not create connector client for agentic user')
148
+ }
149
+ } else {
150
+ const token = await tokenProvider.getAccessToken(scope)
151
+ connectorClient = ConnectorClient.createClientWithToken(
152
+ activity.serviceUrl!,
153
+ token,
154
+ headers
155
+ )
156
+ }
157
+
158
+ return connectorClient
159
+ }
160
+
161
+ static createIdentity (appId: string) : JwtPayload {
162
+ return {
163
+ aud: appId
164
+ } as JwtPayload
165
+ }
166
+
106
167
  /**
107
168
  * Sets the connector client on the turn context.
108
169
  *
@@ -110,24 +171,61 @@ export class CloudAdapter extends BaseAdapter {
110
171
  * @protected
111
172
  */
112
173
  protected setConnectorClient (
113
- context: TurnContext
174
+ context: TurnContext,
175
+ connectorClient?: ConnectorClient
114
176
  ) {
115
- context.turnState.set('connectorClient', this.connectorClient)
177
+ context.turnState.set(this.ConnectorClientKey, connectorClient)
116
178
  }
117
179
 
118
180
  /**
181
+ * Creates a user token client for a specific service URL and scope.
182
+ *
183
+ * @param serviceUrl - The URL of the service to connect to
184
+ * @param scope - The authentication scope to use
185
+ * @param headers - Optional headers to propagate in the request
186
+ * @returns A promise that resolves to a ConnectorClient instance
187
+ * @protected
188
+ */
189
+ protected async createUserTokenClient (
190
+ identity: JwtPayload,
191
+ tokenServiceEndpoint: string = getTokenServiceEndpoint(),
192
+ scope: string = 'https://api.botframework.com',
193
+ audience: string = 'https://api.botframework.com',
194
+ headers?: HeaderPropagationCollection
195
+ ): Promise<UserTokenClient> {
196
+ // get the correct token provider
197
+ const tokenProvider = this.connectionManager.getTokenProvider(identity, tokenServiceEndpoint)
198
+
199
+ return UserTokenClient.createClientWithScope(
200
+ tokenServiceEndpoint,
201
+ tokenProvider,
202
+ scope,
203
+ headers
204
+ )
205
+ }
206
+
207
+ /**
208
+ * Sets the user token client on the turn context.
209
+ *
210
+ * @param context - The current turn context
211
+ * @protected
212
+ */
213
+ protected setUserTokenClient (
214
+ context: TurnContext,
215
+ userTokenClient?: UserTokenClient
216
+ ) {
217
+ context.turnState.set(this.UserTokenClientKey, userTokenClient)
218
+ }
219
+
220
+ /**
221
+ * @deprecated This function will not be supported in future versions. Create TurnContext directly.
119
222
  * Creates a TurnContext for the given activity and logic.
120
223
  * @param activity - The activity to process.
121
224
  * @param logic - The logic to execute.
122
225
  * @returns The created TurnContext.
123
226
  */
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)
227
+ createTurnContext (activity: Activity, logic: AgentHandler, identity?: JwtPayload): TurnContext {
228
+ return new TurnContext(this, activity, identity)
131
229
  }
132
230
 
133
231
  /**
@@ -154,9 +252,7 @@ export class CloudAdapter extends BaseAdapter {
154
252
  delete activity.id
155
253
  let response: ResourceResponse = { id: '' }
156
254
 
157
- if (activity.type === ActivityTypes.Delay) {
158
- await setTimeout(() => { }, typeof activity.value === 'number' ? activity.value : 1000)
159
- } else if (activity.type === ActivityTypes.InvokeResponse) {
255
+ if (activity.type === ActivityTypes.InvokeResponse) {
160
256
  context.turnState.set(INVOKE_RESPONSE_KEY, activity)
161
257
  } else if (activity.type === ActivityTypes.Trace && activity.channelId !== Channels.Emulator) {
162
258
  // no-op
@@ -165,12 +261,10 @@ export class CloudAdapter extends BaseAdapter {
165
261
  throw new Error('Invalid activity object')
166
262
  }
167
263
 
168
- this.connectorClient = await this.createConnectorClient(activity.serviceUrl, 'https://api.botframework.com')
169
-
170
264
  if (activity.replyToId) {
171
- response = await this.connectorClient.replyToActivity(activity.conversation.id, activity.replyToId, activity)
265
+ response = await context.turnState.get(this.ConnectorClientKey).replyToActivity(activity.conversation.id, activity.replyToId, activity)
172
266
  } else {
173
- response = await this.connectorClient.sendToConversation(activity.conversation.id, activity)
267
+ response = await context.turnState.get(this.ConnectorClientKey).sendToConversation(activity.conversation.id, activity)
174
268
  }
175
269
  }
176
270
 
@@ -184,18 +278,6 @@ export class CloudAdapter extends BaseAdapter {
184
278
  return responses
185
279
  }
186
280
 
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
281
  /**
200
282
  * Processes an incoming request and sends the response.
201
283
  * @param request - The incoming request.
@@ -236,14 +318,18 @@ export class CloudAdapter extends BaseAdapter {
236
318
  }
237
319
 
238
320
  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
321
 
322
+ const context = new TurnContext(this, activity, request.user!)
323
+ const scope = request.user?.azp ?? request.user?.appid ?? 'https://api.botframework.com'
242
324
  // if Delivery Mode == ExpectReplies, we don't need a connector client.
243
325
  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)
326
+ const connectorClient = await this.createConnectorClientWithIdentity(request.user!, activity, scope, headers)
327
+ this.setConnectorClient(context, connectorClient)
328
+ }
329
+
330
+ if (!activity.isAgenticRequest()) {
331
+ const userTokenClient = await this.createUserTokenClient(request.user!)
332
+ this.setUserTokenClient(context, userTokenClient)
247
333
  }
248
334
 
249
335
  if (
@@ -259,7 +345,6 @@ export class CloudAdapter extends BaseAdapter {
259
345
 
260
346
  await this.runMiddleware(context, logic)
261
347
  const invokeResponse = this.processTurnResults(context)
262
-
263
348
  return end(invokeResponse?.status ?? StatusCodes.OK, invokeResponse?.body)
264
349
  }
265
350
 
@@ -301,7 +386,7 @@ export class CloudAdapter extends BaseAdapter {
301
386
  throw new Error('Invalid activity object')
302
387
  }
303
388
 
304
- const response = await this.connectorClient.updateActivity(
389
+ const response = await context.turnState.get(this.ConnectorClientKey).updateActivity(
305
390
  activity.conversation.id,
306
391
  activity.id,
307
392
  activity
@@ -325,7 +410,7 @@ export class CloudAdapter extends BaseAdapter {
325
410
  throw new Error('Invalid conversation reference object')
326
411
  }
327
412
 
328
- await this.connectorClient.deleteActivity(reference.conversation.id, reference.activityId)
413
+ await context.turnState.get(this.ConnectorClientKey).deleteActivity(reference.conversation.id, reference.activityId)
329
414
  }
330
415
 
331
416
  /**
@@ -334,25 +419,39 @@ export class CloudAdapter extends BaseAdapter {
334
419
  * @param logic - The logic to execute.
335
420
  * @returns A promise representing the completion of the continue operation.
336
421
  */
337
- async continueConversation (reference: ConversationReference, logic: (revocableContext: TurnContext) => Promise<void>, isResponse: Boolean = false): Promise<void> {
422
+ async continueConversation (
423
+ botAppIdOrIdentity: string | JwtPayload,
424
+ reference: ConversationReference,
425
+ logic: (revocableContext: TurnContext) => Promise<void>,
426
+ isResponse: Boolean = false): Promise<void> {
338
427
  if (!reference || !reference.serviceUrl || (reference.conversation == null) || !reference.conversation.id) {
339
428
  throw new Error('Invalid conversation reference object')
340
429
  }
341
430
 
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)
347
- }
431
+ const botAppId = typeof botAppIdOrIdentity === 'string' ? botAppIdOrIdentity : botAppIdOrIdentity.aud as string
432
+
433
+ const identity =
434
+ typeof botAppIdOrIdentity !== 'string'
435
+ ? botAppIdOrIdentity
436
+ : CloudAdapter.createIdentity(botAppId)
437
+
438
+ const continuationActivity = Activity.getContinuationActivity(reference)
439
+ const context = new TurnContext(this, Activity.getContinuationActivity(reference), identity)
440
+ const scope = identity.azp ?? identity.appid ?? 'https://api.botframework.com'
441
+ const connectorClient = await this.createConnectorClientWithIdentity(identity, continuationActivity, scope)
442
+ this.setConnectorClient(context, connectorClient)
443
+
444
+ const userTokenClient = await this.createUserTokenClient(identity)
445
+ this.setUserTokenClient(context, userTokenClient)
446
+
348
447
  await this.runMiddleware(context, logic)
349
448
  }
350
449
 
351
450
  /**
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
- */
451
+ * Processes the turn results and returns an InvokeResponse if applicable.
452
+ * @param context - The TurnContext for the current turn.
453
+ * @returns The InvokeResponse if applicable, otherwise undefined.
454
+ */
356
455
  protected processTurnResults (context: TurnContext): InvokeResponse | undefined {
357
456
  logger.info('<--Sending back turn results')
358
457
  // Handle ExpectedReplies scenarios where all activities have been buffered and sent back at once in an invoke response.
@@ -437,7 +536,9 @@ export class CloudAdapter extends BaseAdapter {
437
536
  if (!conversationParameters) throw new TypeError('`conversationParameters` must be defined')
438
537
  if (!logic) throw new TypeError('`logic` must be defined')
439
538
 
440
- const restClient = await this.createConnectorClient(serviceUrl, audience)
539
+ const identity = CloudAdapter.createIdentity(audience)
540
+ const restClient = await this.createConnectorClient(serviceUrl, audience, identity)
541
+ const userTokenClient = await this.createUserTokenClient(identity)
441
542
  const createConversationResult = await restClient.createConversation(conversationParameters)
442
543
  const createActivity = this.createCreateActivity(
443
544
  createConversationResult.id,
@@ -445,17 +546,24 @@ export class CloudAdapter extends BaseAdapter {
445
546
  serviceUrl,
446
547
  conversationParameters
447
548
  )
448
- const context = new TurnContext(this, createActivity)
549
+ const context = new TurnContext(this, createActivity, CloudAdapter.createIdentity(agentAppId))
550
+ this.setConnectorClient(context, restClient)
551
+ this.setUserTokenClient(context, userTokenClient)
449
552
  await this.runMiddleware(context, logic)
450
553
  }
451
554
 
452
555
  /**
556
+ * @deprecated This function will not be supported in future versions. Use TurnContext.turnState.get<ConnectorClient>(CloudAdapter.ConnectorClientKey).
453
557
  * Uploads an attachment.
454
558
  * @param conversationId - The conversation ID.
455
559
  * @param attachmentData - The attachment data.
456
560
  * @returns A promise representing the ResourceResponse for the uploaded attachment.
457
561
  */
458
- async uploadAttachment (conversationId: string, attachmentData: AttachmentData): Promise<ResourceResponse> {
562
+ async uploadAttachment (context: TurnContext, conversationId: string, attachmentData: AttachmentData): Promise<ResourceResponse> {
563
+ if (context === undefined) {
564
+ throw new Error('context is required')
565
+ }
566
+
459
567
  if (conversationId === undefined) {
460
568
  throw new Error('conversationId is required')
461
569
  }
@@ -464,29 +572,39 @@ export class CloudAdapter extends BaseAdapter {
464
572
  throw new Error('attachmentData is required')
465
573
  }
466
574
 
467
- return await this.connectorClient.uploadAttachment(conversationId, attachmentData)
575
+ return await context.turnState.get<ConnectorClient>(this.ConnectorClientKey).uploadAttachment(conversationId, attachmentData)
468
576
  }
469
577
 
470
578
  /**
579
+ * @deprecated This function will not be supported in future versions. Use TurnContext.turnState.get<ConnectorClient>(CloudAdapter.ConnectorClientKey).
471
580
  * Gets attachment information.
472
581
  * @param attachmentId - The attachment ID.
473
582
  * @returns A promise representing the AttachmentInfo for the requested attachment.
474
583
  */
475
- async getAttachmentInfo (attachmentId: string): Promise<AttachmentInfo> {
584
+ async getAttachmentInfo (context: TurnContext, attachmentId: string): Promise<AttachmentInfo> {
585
+ if (context === undefined) {
586
+ throw new Error('context is required')
587
+ }
588
+
476
589
  if (attachmentId === undefined) {
477
590
  throw new Error('attachmentId is required')
478
591
  }
479
592
 
480
- return await this.connectorClient.getAttachmentInfo(attachmentId)
593
+ return await context.turnState.get<ConnectorClient>(this.ConnectorClientKey).getAttachmentInfo(attachmentId)
481
594
  }
482
595
 
483
596
  /**
597
+ * @deprecated This function will not be supported in future versions. Use TurnContext.turnState.get<ConnectorClient>(CloudAdapter.ConnectorClientKey).
484
598
  * Gets an attachment.
485
599
  * @param attachmentId - The attachment ID.
486
600
  * @param viewId - The view ID.
487
601
  * @returns A promise representing the NodeJS.ReadableStream for the requested attachment.
488
602
  */
489
- async getAttachment (attachmentId: string, viewId: string): Promise<NodeJS.ReadableStream> {
603
+ async getAttachment (context: TurnContext, attachmentId: string, viewId: string): Promise<NodeJS.ReadableStream> {
604
+ if (context === undefined) {
605
+ throw new Error('context is required')
606
+ }
607
+
490
608
  if (attachmentId === undefined) {
491
609
  throw new Error('attachmentId is required')
492
610
  }
@@ -495,6 +613,6 @@ export class CloudAdapter extends BaseAdapter {
495
613
  throw new Error('viewId is required')
496
614
  }
497
615
 
498
- return await this.connectorClient.getAttachment(attachmentId, viewId)
616
+ return await context.turnState.get<ConnectorClient>(this.ConnectorClientKey).getAttachment(attachmentId, viewId)
499
617
  }
500
618
  }
@@ -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'