@microsoft/agents-hosting 1.6.0-beta.9.gce9d8facd2 → 1.7.0-beta.1.g8bcd4f11a7

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 (149) hide show
  1. package/dist/package.json +4 -9
  2. package/dist/src/agent-client/agentClient.js +2 -2
  3. package/dist/src/agent-client/agentClient.js.map +1 -1
  4. package/dist/src/agent-client/agentResponseHandler.js +2 -2
  5. package/dist/src/agent-client/agentResponseHandler.js.map +1 -1
  6. package/dist/src/app/agentApplication.js +28 -2
  7. package/dist/src/app/agentApplication.js.map +1 -1
  8. package/dist/src/app/agentApplicationOptions.d.ts +10 -0
  9. package/dist/src/app/attachmentDownloader.js +5 -10
  10. package/dist/src/app/attachmentDownloader.js.map +1 -1
  11. package/dist/src/app/auth/authorizationManager.d.ts +4 -0
  12. package/dist/src/app/auth/authorizationManager.js +94 -67
  13. package/dist/src/app/auth/authorizationManager.js.map +1 -1
  14. package/dist/src/app/auth/handlers/azureBotAuthorization.js +2 -2
  15. package/dist/src/app/auth/handlers/azureBotAuthorization.js.map +1 -1
  16. package/dist/src/app/proactive/createConversationOptionsBuilder.js +10 -6
  17. package/dist/src/app/proactive/createConversationOptionsBuilder.js.map +1 -1
  18. package/dist/src/app/proactive/proactive.d.ts +1 -0
  19. package/dist/src/app/proactive/proactive.js +30 -15
  20. package/dist/src/app/proactive/proactive.js.map +1 -1
  21. package/dist/src/app/streaming/streamingResponse.d.ts +11 -0
  22. package/dist/src/app/streaming/streamingResponse.js +21 -0
  23. package/dist/src/app/streaming/streamingResponse.js.map +1 -1
  24. package/dist/src/app/teamsAttachmentDownloader.js +6 -14
  25. package/dist/src/app/teamsAttachmentDownloader.js.map +1 -1
  26. package/dist/src/auth/MemoryCache.d.ts +2 -1
  27. package/dist/src/auth/MemoryCache.js +7 -1
  28. package/dist/src/auth/MemoryCache.js.map +1 -1
  29. package/dist/src/auth/authConfiguration.d.ts +2 -143
  30. package/dist/src/auth/authConfiguration.js +336 -257
  31. package/dist/src/auth/authConfiguration.js.map +1 -1
  32. package/dist/src/auth/authConstants.d.ts +7 -7
  33. package/dist/src/auth/authConstants.js.map +1 -1
  34. package/dist/src/auth/connectionManager.d.ts +92 -0
  35. package/dist/src/auth/{msalConnectionManager.js → connectionManager.js} +48 -33
  36. package/dist/src/auth/connectionManager.js.map +1 -0
  37. package/dist/src/auth/index.d.ts +5 -3
  38. package/dist/src/auth/index.js +5 -3
  39. package/dist/src/auth/index.js.map +1 -1
  40. package/dist/src/auth/jwt-middleware.d.ts +6 -0
  41. package/dist/src/auth/jwt-middleware.js +34 -2
  42. package/dist/src/auth/jwt-middleware.js.map +1 -1
  43. package/dist/src/auth/msal/msalConnectionManager.d.ts +17 -0
  44. package/dist/src/auth/msal/msalConnectionManager.js +50 -0
  45. package/dist/src/auth/msal/msalConnectionManager.js.map +1 -0
  46. package/dist/src/auth/msal/msalConnectionSettings.d.ts +68 -0
  47. package/dist/src/auth/msal/msalConnectionSettings.js +7 -0
  48. package/dist/src/auth/msal/msalConnectionSettings.js.map +1 -0
  49. package/dist/src/auth/{msalTokenCredential.d.ts → msal/msalTokenCredential.d.ts} +1 -1
  50. package/dist/src/auth/{msalTokenCredential.js → msal/msalTokenCredential.js} +2 -2
  51. package/dist/src/auth/msal/msalTokenCredential.js.map +1 -0
  52. package/dist/src/auth/{msalTokenProvider.d.ts → msal/msalTokenProvider.d.ts} +30 -3
  53. package/dist/src/auth/msal/msalTokenProvider.js +733 -0
  54. package/dist/src/auth/msal/msalTokenProvider.js.map +1 -0
  55. package/dist/src/auth/settings.d.ts +336 -0
  56. package/dist/src/auth/settings.js +202 -0
  57. package/dist/src/auth/settings.js.map +1 -0
  58. package/dist/src/auth/sidecar/sidecarAuthProvider.d.ts +74 -0
  59. package/dist/src/auth/sidecar/sidecarAuthProvider.js +181 -0
  60. package/dist/src/auth/sidecar/sidecarAuthProvider.js.map +1 -0
  61. package/dist/src/auth/sidecar/sidecarConnectionSettings.d.ts +65 -0
  62. package/dist/src/auth/sidecar/sidecarConnectionSettings.js +7 -0
  63. package/dist/src/auth/sidecar/sidecarConnectionSettings.js.map +1 -0
  64. package/dist/src/auth/sidecar/sidecarHttpClient.d.ts +95 -0
  65. package/dist/src/auth/sidecar/sidecarHttpClient.js +406 -0
  66. package/dist/src/auth/sidecar/sidecarHttpClient.js.map +1 -0
  67. package/dist/src/auth/sidecar/sidecarModels.d.ts +110 -0
  68. package/dist/src/auth/sidecar/sidecarModels.js +48 -0
  69. package/dist/src/auth/sidecar/sidecarModels.js.map +1 -0
  70. package/dist/src/auth/sidecar/sidecarTokenExpiry.d.ts +13 -0
  71. package/dist/src/auth/sidecar/sidecarTokenExpiry.js +39 -0
  72. package/dist/src/auth/sidecar/sidecarTokenExpiry.js.map +1 -0
  73. package/dist/src/cloudAdapter.d.ts +58 -1
  74. package/dist/src/cloudAdapter.js +233 -53
  75. package/dist/src/cloudAdapter.js.map +1 -1
  76. package/dist/src/connector-client/connectorClient.d.ts +12 -8
  77. package/dist/src/connector-client/connectorClient.js +99 -82
  78. package/dist/src/connector-client/connectorClient.js.map +1 -1
  79. package/dist/src/errorHelper.js +181 -7
  80. package/dist/src/errorHelper.js.map +1 -1
  81. package/dist/src/getProductInfo.d.ts +23 -0
  82. package/dist/src/getProductInfo.js +71 -1
  83. package/dist/src/getProductInfo.js.map +1 -1
  84. package/dist/src/headerPropagation.d.ts +17 -2
  85. package/dist/src/headerPropagation.js +46 -24
  86. package/dist/src/headerPropagation.js.map +1 -1
  87. package/dist/src/httpClient.d.ts +60 -0
  88. package/dist/src/httpClient.js +173 -0
  89. package/dist/src/httpClient.js.map +1 -0
  90. package/dist/src/index.d.ts +3 -2
  91. package/dist/src/index.js +8 -2
  92. package/dist/src/index.js.map +1 -1
  93. package/dist/src/oauth/userTokenClient.d.ts +17 -4
  94. package/dist/src/oauth/userTokenClient.js +119 -80
  95. package/dist/src/oauth/userTokenClient.js.map +1 -1
  96. package/dist/src/observability/traces.d.ts +11 -4
  97. package/dist/src/observability/traces.js +39 -7
  98. package/dist/src/observability/traces.js.map +1 -1
  99. package/dist/src/utils/env.d.ts +50 -0
  100. package/dist/src/utils/env.js +113 -0
  101. package/dist/src/utils/env.js.map +1 -0
  102. package/dist/src/utils.d.ts +10 -0
  103. package/dist/src/utils.js +18 -0
  104. package/dist/src/utils.js.map +1 -0
  105. package/package.json +4 -9
  106. package/src/agent-client/agentClient.ts +2 -2
  107. package/src/agent-client/agentResponseHandler.ts +2 -2
  108. package/src/app/agentApplication.ts +30 -3
  109. package/src/app/agentApplicationOptions.ts +11 -0
  110. package/src/app/attachmentDownloader.ts +6 -8
  111. package/src/app/auth/authorizationManager.ts +84 -41
  112. package/src/app/auth/handlers/azureBotAuthorization.ts +2 -2
  113. package/src/app/proactive/createConversationOptionsBuilder.ts +8 -4
  114. package/src/app/proactive/proactive.ts +39 -23
  115. package/src/app/streaming/streamingResponse.ts +24 -1
  116. package/src/app/teamsAttachmentDownloader.ts +7 -11
  117. package/src/auth/MemoryCache.ts +7 -1
  118. package/src/auth/authConfiguration.ts +350 -356
  119. package/src/auth/authConstants.ts +7 -7
  120. package/src/auth/{msalConnectionManager.ts → connectionManager.ts} +65 -44
  121. package/src/auth/index.ts +5 -3
  122. package/src/auth/jwt-middleware.ts +32 -2
  123. package/src/auth/msal/msalConnectionManager.ts +55 -0
  124. package/src/auth/msal/msalConnectionSettings.ts +79 -0
  125. package/src/auth/{msalTokenCredential.ts → msal/msalTokenCredential.ts} +2 -1
  126. package/src/auth/msal/msalTokenProvider.ts +881 -0
  127. package/src/auth/settings.ts +378 -0
  128. package/src/auth/sidecar/sidecarAuthProvider.ts +234 -0
  129. package/src/auth/sidecar/sidecarConnectionSettings.ts +72 -0
  130. package/src/auth/sidecar/sidecarHttpClient.ts +443 -0
  131. package/src/auth/sidecar/sidecarModels.ts +153 -0
  132. package/src/auth/sidecar/sidecarTokenExpiry.ts +35 -0
  133. package/src/cloudAdapter.ts +292 -13
  134. package/src/connector-client/connectorClient.ts +116 -94
  135. package/src/errorHelper.ts +206 -7
  136. package/src/getProductInfo.ts +79 -1
  137. package/src/headerPropagation.ts +55 -23
  138. package/src/httpClient.ts +223 -0
  139. package/src/index.ts +6 -2
  140. package/src/oauth/userTokenClient.ts +137 -84
  141. package/src/observability/traces.ts +39 -8
  142. package/src/utils/env.ts +105 -0
  143. package/src/utils.ts +14 -0
  144. package/dist/src/auth/msalConnectionManager.d.ts +0 -64
  145. package/dist/src/auth/msalConnectionManager.js.map +0 -1
  146. package/dist/src/auth/msalTokenCredential.js.map +0 -1
  147. package/dist/src/auth/msalTokenProvider.js +0 -485
  148. package/dist/src/auth/msalTokenProvider.js.map +0 -1
  149. package/src/auth/msalTokenProvider.ts +0 -562
@@ -1,5 +1,8 @@
1
- /** * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */
2
- import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
3
6
  import { AuthConfiguration } from '../auth/authConfiguration'
4
7
  import { AuthProvider } from '../auth/authProvider'
5
8
  import { debug } from '@microsoft/agents-telemetry'
@@ -11,72 +14,47 @@ import { ResourceResponse } from './resourceResponse'
11
14
  import { AttachmentInfo } from './attachmentInfo'
12
15
  import { AttachmentData } from './attachmentData'
13
16
  import { normalizeOutgoingActivity } from '../activityWireCompat'
14
- import { getProductInfo } from '../getProductInfo'
17
+ import { applyUserAgentHeader, getProductInfo } from '../getProductInfo'
15
18
  import { HeaderPropagation, HeaderPropagationCollection } from '../headerPropagation'
16
19
  import { trace } from '@microsoft/agents-telemetry'
17
20
  import { ConnectorClientTraceDefinitions } from '../observability'
21
+ import { parseIntEnv } from '../utils/env'
22
+ import { HttpClient, HttpRequestConfig, HttpResponse, HttpError } from '../httpClient'
18
23
 
19
24
  const logger = debug('agents:connector-client')
20
25
 
26
+ function formatHttpErrorMessage (error: HttpError): string {
27
+ const responseData = error.response?.data
28
+ if (responseData === undefined) {
29
+ return error.message
30
+ }
31
+
32
+ try {
33
+ const serializedResponseData = JSON.stringify(responseData)
34
+ return serializedResponseData === undefined ? error.message : `${error.message}: ${serializedResponseData}`
35
+ } catch {
36
+ return error.message
37
+ }
38
+ }
39
+
21
40
  export { getProductInfo }
22
41
 
23
42
  /**
24
43
  * ConnectorClient is a client for interacting with the Microsoft Connector API.
25
44
  */
26
45
  export class ConnectorClient {
27
- protected readonly _axiosInstance: AxiosInstance
46
+ protected readonly _httpClient: HttpClient
28
47
 
29
48
  /**
30
49
  * Private constructor for the ConnectorClient.
31
- * @param axInstance - The AxiosInstance to use for HTTP requests.
50
+ * @param httpClient - The HttpClient instance to use for HTTP requests.
32
51
  */
33
- protected constructor (axInstance: AxiosInstance) {
34
- this._axiosInstance = axInstance
35
- this._axiosInstance.interceptors.request.use((config) => {
36
- const { method, url, data, headers, params } = config
37
- // Clone headers and remove Authorization before logging
38
- const { Authorization, authorization, ...headersToLog } = headers || {}
39
- logger.debug('Request: ', {
40
- host: this._axiosInstance.getUri(),
41
- url,
42
- data,
43
- method,
44
- params,
45
- headers: headersToLog
46
- })
47
- return config
48
- })
49
- this._axiosInstance.interceptors.response.use(
50
- (config) => {
51
- const { status, statusText, config: requestConfig } = config
52
- logger.debug('Response: ', {
53
- status,
54
- statusText,
55
- host: this._axiosInstance.getUri(),
56
- url: requestConfig?.url,
57
- data: config.config.data,
58
- method: requestConfig?.method,
59
- })
60
- return config
61
- },
62
- (error) => {
63
- const { code, message, stack, response } = error
64
- const errorDetails = {
65
- code,
66
- host: this._axiosInstance.getUri(),
67
- url: error.config.url,
68
- method: error.config.method,
69
- data: error.config.data,
70
- message: message + JSON.stringify(response?.data),
71
- stack,
72
- }
73
- return Promise.reject(errorDetails)
74
- }
75
- )
52
+ protected constructor (httpClient: HttpClient) {
53
+ this._httpClient = httpClient
76
54
  }
77
55
 
78
- public get axiosInstance (): AxiosInstance {
79
- return this._axiosInstance
56
+ public get httpClient (): HttpClient {
57
+ return this._httpClient
80
58
  }
81
59
 
82
60
  /**
@@ -112,28 +90,23 @@ export class ConnectorClient {
112
90
  headers?: HeaderPropagationCollection
113
91
  ): ConnectorClient {
114
92
  const headerPropagation = headers ?? new HeaderPropagation({})
115
- const userAgent = headerPropagation.outgoing['user-agent']
116
- const productInfo = getProductInfo()
117
- if (!userAgent) {
118
- headerPropagation.add({ 'User-Agent': productInfo })
119
- } else if (!userAgent.includes(productInfo)) {
120
- headerPropagation.concat({ 'User-Agent': productInfo })
121
- }
93
+ applyUserAgentHeader(headerPropagation)
122
94
  headerPropagation.override({
123
95
  Accept: 'application/json',
124
- 'Content-Type': 'application/json', // Required by transformRequest
125
- })
126
-
127
- const axiosInstance = axios.create({
128
- baseURL,
129
- headers: headerPropagation.outgoing,
96
+ 'Content-Type': 'application/json',
130
97
  })
131
98
 
99
+ const clientHeaders: Record<string, string> = { ...headerPropagation.outgoing }
132
100
  if (token && token.length > 1) {
133
- axiosInstance.defaults.headers.common.Authorization = `Bearer ${token}`
101
+ clientHeaders.Authorization = `Bearer ${token}`
134
102
  }
135
103
 
136
- return new ConnectorClient(axiosInstance)
104
+ const httpClient = new HttpClient({
105
+ baseURL,
106
+ headers: clientHeaders,
107
+ })
108
+
109
+ return new ConnectorClient(httpClient)
137
110
  }
138
111
 
139
112
  /**
@@ -143,12 +116,12 @@ export class ConnectorClient {
143
116
  */
144
117
  public async getConversations (continuationToken?: string): Promise<ConversationsResult> {
145
118
  return trace(ConnectorClientTraceDefinitions.getConversations, async ({ record }) => {
146
- const config: AxiosRequestConfig = {
119
+ const config: HttpRequestConfig = {
147
120
  method: 'get',
148
121
  url: '/v3/conversations',
149
122
  params: continuationToken ? { continuationToken } : undefined
150
123
  }
151
- const response = await this._axiosInstance(config)
124
+ const response = await this.executeRequest<ConversationsResult>(config)
152
125
  record({ httpStatusCode: response.status?.toString() })
153
126
  return response.data
154
127
  })
@@ -159,14 +132,14 @@ export class ConnectorClient {
159
132
  if (!userId || !conversationId) {
160
133
  throw ExceptionHelper.generateException(Error, Errors.UserIdAndConversationIdRequired)
161
134
  }
162
- const config: AxiosRequestConfig = {
135
+ const config: HttpRequestConfig = {
163
136
  method: 'get',
164
137
  url: `v3/conversations/${conversationId}/members/${userId}`,
165
138
  headers: {
166
139
  'Content-Type': 'application/json'
167
140
  }
168
141
  }
169
- const response = await this._axiosInstance(config)
142
+ const response = await this.executeRequest<ChannelAccount>(config)
170
143
  record({ httpStatusCode: response.status?.toString() })
171
144
  return response.data
172
145
  })
@@ -183,7 +156,7 @@ export class ConnectorClient {
183
156
  ...body,
184
157
  activity: normalizeOutgoingActivity(body.activity)
185
158
  }
186
- const config: AxiosRequestConfig = {
159
+ const config: HttpRequestConfig = {
187
160
  method: 'post',
188
161
  url: '/v3/conversations',
189
162
  headers: {
@@ -191,7 +164,7 @@ export class ConnectorClient {
191
164
  },
192
165
  data: payload
193
166
  }
194
- const response: AxiosResponse = await this._axiosInstance(config)
167
+ const response = await this.executeRequest<ConversationResourceResponse>(config)
195
168
  record({ httpStatusCode: response.status?.toString() })
196
169
  return response.data
197
170
  })
@@ -219,7 +192,7 @@ export class ConnectorClient {
219
192
 
220
193
  const trimmedConversationId: string = this.conditionallyTruncateConversationId(conversationId, body)
221
194
 
222
- const config: AxiosRequestConfig = {
195
+ const config: HttpRequestConfig = {
223
196
  method: 'post',
224
197
  url: `v3/conversations/${trimmedConversationId}/activities/${encodeURIComponent(activityId)}`,
225
198
  headers: {
@@ -228,7 +201,7 @@ export class ConnectorClient {
228
201
  data: normalizeOutgoingActivity(body),
229
202
  ...(body.channelId === Channels.Msteams && body.isTargetedActivity() ? { params: { isTargetedActivity: 'true' } } : {})
230
203
  }
231
- const response = await this._axiosInstance(config)
204
+ const response = await this.executeRequest<ResourceResponse>(config)
232
205
  record({ httpStatusCode: response.status?.toString() })
233
206
  logger.info('Reply to conversation/activity: ', response.data.id!, activityId)
234
207
  return response.data
@@ -236,20 +209,19 @@ export class ConnectorClient {
236
209
  }
237
210
 
238
211
  /**
239
- * Trim the conversationId to a fixed length when creating the URL. This is applied only in specific API calls for agentic calls.
212
+ * Trim and sanitize the conversationId when creating the URL for agentic calls in agents channels.
240
213
  * @param conversationId The ID of the conversation to potentially truncate.
241
214
  * @param activity The activity object used to determine if truncation is necessary.
242
- * @returns The original or truncated conversationId, depending on the channel and activity role.
215
+ * @returns The original conversationId for non-agents channels/non-agentic roles, otherwise a trimmed and sanitized value.
243
216
  */
244
217
  private conditionallyTruncateConversationId (conversationId: string, activity: Activity): string {
245
218
  if (
246
- (activity.channelIdChannel === Channels.Msteams || activity.channelIdChannel === Channels.Agents) &&
219
+ activity.channelIdChannel === Channels.Agents &&
247
220
  (activity.from?.role === RoleTypes.AgenticIdentity || activity.from?.role === RoleTypes.AgenticUser)) {
248
- let maxLength = 150
249
- if (process.env.MAX_APX_CONVERSATION_ID_LENGTH && !isNaN(parseInt(process.env.MAX_APX_CONVERSATION_ID_LENGTH, 10))) {
250
- maxLength = parseInt(process.env.MAX_APX_CONVERSATION_ID_LENGTH, 10)
251
- }
252
- return conversationId.length > maxLength ? conversationId.substring(0, maxLength) : conversationId
221
+ const maxLength = parseIntEnv(process.env.MAX_APX_CONVERSATION_ID_LENGTH, 150)
222
+ const trimmedConversationId = conversationId.length > maxLength ? conversationId.substring(0, maxLength) : conversationId
223
+
224
+ return trimmedConversationId.replace(/[/\\#?]/g, '_')
253
225
  } else {
254
226
  return conversationId
255
227
  }
@@ -275,7 +247,7 @@ export class ConnectorClient {
275
247
 
276
248
  const trimmedConversationId: string = this.conditionallyTruncateConversationId(conversationId, body)
277
249
 
278
- const config: AxiosRequestConfig = {
250
+ const config: HttpRequestConfig = {
279
251
  method: 'post',
280
252
  url: `v3/conversations/${trimmedConversationId}/activities`,
281
253
  headers: {
@@ -285,7 +257,7 @@ export class ConnectorClient {
285
257
  ...(body.channelId === Channels.Msteams && body.isTargetedActivity() ? { params: { isTargetedActivity: 'true' } } : {})
286
258
 
287
259
  }
288
- const response = await this._axiosInstance(config)
260
+ const response = await this.executeRequest<ResourceResponse>(config)
289
261
  record({ httpStatusCode: response.status?.toString() })
290
262
  return response.data
291
263
  })
@@ -308,7 +280,7 @@ export class ConnectorClient {
308
280
  throw ExceptionHelper.generateException(Error, Errors.ConversationIdAndActivityIdRequired)
309
281
  }
310
282
  record({ conversationId, activityId })
311
- const config: AxiosRequestConfig = {
283
+ const config: HttpRequestConfig = {
312
284
  method: 'put',
313
285
  url: `v3/conversations/${conversationId}/activities/${activityId}`,
314
286
  headers: {
@@ -317,7 +289,7 @@ export class ConnectorClient {
317
289
  data: normalizeOutgoingActivity(body),
318
290
  ...(body.channelId === Channels.Msteams && body.isTargetedActivity() ? { params: { isTargetedActivity: 'true' } } : {})
319
291
  }
320
- const response = await this._axiosInstance(config)
292
+ const response = await this.executeRequest<ResourceResponse>(config)
321
293
  record({ httpStatusCode: response.status?.toString() })
322
294
  return response.data
323
295
  })
@@ -341,7 +313,7 @@ export class ConnectorClient {
341
313
  if (!conversationId || !activityId) {
342
314
  throw ExceptionHelper.generateException(Error, Errors.ConversationIdAndActivityIdRequired)
343
315
  }
344
- const config: AxiosRequestConfig = {
316
+ const config: HttpRequestConfig = {
345
317
  method: 'delete',
346
318
  url: `v3/conversations/${conversationId}/activities/${activityId}`,
347
319
  headers: {
@@ -349,7 +321,7 @@ export class ConnectorClient {
349
321
  },
350
322
  ...(isTargetedActivity ? { params: { isTargetedActivity: 'true' } } : {})
351
323
  }
352
- const response = await this._axiosInstance(config)
324
+ const response = await this.executeRequest<void>(config)
353
325
  record({ httpStatusCode: response.status?.toString() })
354
326
  return response.data
355
327
  })
@@ -370,7 +342,7 @@ export class ConnectorClient {
370
342
  if (conversationId === undefined) {
371
343
  throw ExceptionHelper.generateException(Error, Errors.ConversationIdRequired)
372
344
  }
373
- const config: AxiosRequestConfig = {
345
+ const config: HttpRequestConfig = {
374
346
  method: 'post',
375
347
  url: `v3/conversations/${conversationId}/attachments`,
376
348
  headers: {
@@ -378,7 +350,7 @@ export class ConnectorClient {
378
350
  },
379
351
  data: body
380
352
  }
381
- const response = await this._axiosInstance(config)
353
+ const response = await this.executeRequest<ResourceResponse>(config)
382
354
  record({ httpStatusCode: response.status?.toString() })
383
355
  return response.data
384
356
  })
@@ -397,14 +369,14 @@ export class ConnectorClient {
397
369
  if (attachmentId === undefined) {
398
370
  throw ExceptionHelper.generateException(Error, Errors.AttachmentIdRequired)
399
371
  }
400
- const config: AxiosRequestConfig = {
372
+ const config: HttpRequestConfig = {
401
373
  method: 'get',
402
374
  url: `v3/attachments/${attachmentId}`,
403
375
  headers: {
404
376
  'Content-Type': 'application/json'
405
377
  }
406
378
  }
407
- const response = await this._axiosInstance(config)
379
+ const response = await this.executeRequest<AttachmentInfo>(config)
408
380
  record({ httpStatusCode: response.status?.toString() })
409
381
  return response.data
410
382
  })
@@ -428,16 +400,66 @@ export class ConnectorClient {
428
400
  if (viewId === undefined) {
429
401
  throw ExceptionHelper.generateException(Error, Errors.ViewIdRequired)
430
402
  }
431
- const config: AxiosRequestConfig = {
403
+ const config: HttpRequestConfig = {
432
404
  method: 'get',
433
405
  url: `v3/attachments/${attachmentId}/views/${viewId}`,
434
406
  headers: {
435
407
  'Content-Type': 'application/json'
436
- }
408
+ },
409
+ responseType: 'stream'
437
410
  }
438
- const response = await this._axiosInstance(config)
411
+ const response = await this.executeRequest<NodeJS.ReadableStream>(config)
439
412
  record({ httpStatusCode: response.status?.toString() })
440
413
  return response.data
441
414
  })
442
415
  }
416
+
417
+ private async executeRequest<T = unknown> (config: HttpRequestConfig): Promise<HttpResponse<T>> {
418
+ const { method, url, data, headers, params } = config
419
+ const { Authorization, authorization, ...headersToLog } = { ...this._httpClient.defaultHeaders, ...headers } as Record<string, string>
420
+ logger.debug('Request: ', {
421
+ host: this._httpClient.baseURL,
422
+ url,
423
+ data,
424
+ method,
425
+ params,
426
+ headers: headersToLog
427
+ })
428
+
429
+ try {
430
+ const response = await this._httpClient.request<T>(config)
431
+ logger.debug('Response: ', {
432
+ status: response.status,
433
+ statusText: response.statusText,
434
+ host: this._httpClient.baseURL,
435
+ url: response.config?.url,
436
+ data: response.config?.data,
437
+ method: response.config?.method,
438
+ })
439
+ return response
440
+ } catch (error) {
441
+ if (error instanceof HttpError) {
442
+ const message = formatHttpErrorMessage(error)
443
+ logger.debug('Response error: ', {
444
+ host: this._httpClient.baseURL,
445
+ url: error.config.url,
446
+ method: error.config.method,
447
+ data: error.config.data,
448
+ message,
449
+ stack: error.stack,
450
+ })
451
+
452
+ Object.assign(error, {
453
+ host: this._httpClient.baseURL,
454
+ url: error.config.url,
455
+ method: error.config.method,
456
+ data: error.config.data,
457
+ message,
458
+ })
459
+
460
+ throw error
461
+ }
462
+ throw error
463
+ }
464
+ }
443
465
  }
@@ -232,6 +232,14 @@ export const Errors: { [key: string]: AgentErrorDefinition } = {
232
232
  description: 'attachmentId is required'
233
233
  },
234
234
 
235
+ /**
236
+ * Error thrown when attachment is null or undefined.
237
+ */
238
+ AttachmentNullOrUndefined: {
239
+ code: -120265,
240
+ description: 'attachment cannot be null or undefined.'
241
+ },
242
+
235
243
  /**
236
244
  * Error thrown when viewId is required but missing.
237
245
  */
@@ -256,6 +264,14 @@ export const Errors: { [key: string]: AgentErrorDefinition } = {
256
264
  description: 'request.body parameter required'
257
265
  },
258
266
 
267
+ /**
268
+ * Error thrown when HttpClient is given a relative URL without a configured base URL.
269
+ */
270
+ HttpClientRelativeUrlRequiresBaseUrl: {
271
+ code: -120291,
272
+ description: 'HttpClient requires baseURL when using a relative URL: {url}'
273
+ },
274
+
259
275
  // ============================================================================
260
276
  // Connection and Authentication Errors (-120300 to -120590)
261
277
  // ============================================================================
@@ -516,8 +532,166 @@ export const Errors: { [key: string]: AgentErrorDefinition } = {
516
532
  description: "The current token for the '{connectionName}' AzureBot connection is not exchangeable for an on-behalf-of flow. Ensure the base token audience is for the bot/resource app, such as an App ID URI like 'api://...' or otherwise includes the app's client id."
517
533
  },
518
534
 
535
+ /**
536
+ * Error thrown when an unsupported authentication type is specified in authConfig.
537
+ */
538
+ UnsupportedAuthType: {
539
+ code: -120593,
540
+ description: 'Unsupported authentication type: {authType}'
541
+ },
542
+
543
+ /**
544
+ * Error thrown when WorkloadIdentity authentication requires `federatedTokenFile` or the deprecated `WIDAssertionFile` to be configured.
545
+ */
546
+ WorkloadIdentityTokenFileRequired: {
547
+ code: -120594,
548
+ description: 'WorkloadIdentity authentication requires `federatedTokenFile` or the deprecated `WIDAssertionFile` to be configured'
549
+ },
550
+
551
+ /**
552
+ * Error thrown when ClientSecret authentication is specified but `clientSecret` is not configured.
553
+ */
554
+ ClientSecretRequired: {
555
+ code: -120595,
556
+ description: 'ClientSecret authentication requires `clientSecret` to be configured'
557
+ },
558
+
559
+ /**
560
+ * Error thrown when Certificate authentication is specified but `certPemFile` or `certKeyFile` is not configured.
561
+ */
562
+ CertificateFilesRequired: {
563
+ code: -120596,
564
+ description: 'Certificate authentication requires both `certPemFile` and `certKeyFile` to be configured'
565
+ },
566
+
567
+ /**
568
+ * Error thrown when FederatedCredentials authentication is specified but `federatedClientId` or the deprecated `FICClientId` is not configured.
569
+ */
570
+ FICClientIdRequired: {
571
+ code: -120597,
572
+ description: 'FederatedCredentials authentication requires `federatedClientId` or the deprecated `FICClientId` to be configured'
573
+ },
574
+
575
+ /**
576
+ * Error thrown when UserManagedIdentity authentication is specified but `clientId` is not configured.
577
+ */
578
+ ClientIdRequiredForUserManagedIdentity: {
579
+ code: -120598,
580
+ description: 'UserManagedIdentity authentication requires `clientId` to be configured'
581
+ },
582
+
583
+ /**
584
+ * Error thrown when there's a timeout during a token request.
585
+ */
586
+ TokenRequestTimeout: {
587
+ code: -120599,
588
+ description: 'Token request timed out after {timeoutMs} ms'
589
+ },
590
+
519
591
  // ============================================================================
520
- // Agent and Client Errors (-120600 to -120630)
592
+ // Entra Agent ID Sidecar Authentication Errors (-120800 to -120849)
593
+ // ============================================================================
594
+
595
+ /**
596
+ * Error thrown when the Entra sidecar auth provider is used without connection settings.
597
+ */
598
+ SidecarConnectionSettingsRequired: {
599
+ code: -120800,
600
+ description: 'Connection settings must be provided when using the Entra sidecar auth provider'
601
+ },
602
+
603
+ /**
604
+ * Error thrown when the resolved sidecar base URL is not a valid absolute URL.
605
+ */
606
+ SidecarBaseUrlInvalid: {
607
+ code: -120801,
608
+ description: 'The resolved sidecar base URL `{url}` is not a valid absolute URL'
609
+ },
610
+
611
+ /**
612
+ * Error thrown when the resolved sidecar base URL does not use the http or https scheme.
613
+ */
614
+ SidecarBaseUrlInsecureScheme: {
615
+ code: -120802,
616
+ description: 'The resolved sidecar base URL `{url}` must use the http or https scheme'
617
+ },
618
+
619
+ /**
620
+ * Error thrown when the resolved sidecar base URL contains userinfo (credentials).
621
+ */
622
+ SidecarBaseUrlUserInfo: {
623
+ code: -120803,
624
+ description: 'The resolved sidecar base URL `{url}` must not contain userinfo (credentials)'
625
+ },
626
+
627
+ /**
628
+ * Error thrown when the resolved sidecar base URL points to a non-loopback, non-private address.
629
+ */
630
+ SidecarBaseUrlNotLocal: {
631
+ code: -120804,
632
+ description: 'The resolved sidecar base URL `{url}` points to a non-loopback, non-private address. The Entra Agent ID sidecar (agent container) must be reachable only from within the agent\'s network boundary. Set `bypassLocalNetworkRestriction` to true in the connection configuration to override this safety check (UNSAFE: only for carefully validated private-network configurations)'
633
+ },
634
+
635
+ /**
636
+ * Error thrown when both AgentUsername and AgentUserId are supplied on a sidecar request (mutually exclusive).
637
+ */
638
+ SidecarUserIdentityMutuallyExclusive: {
639
+ code: -120805,
640
+ description: 'AgentUsername and AgentUserId are mutually exclusive; set only one on the sidecar request options'
641
+ },
642
+
643
+ /**
644
+ * Error thrown when a sidecar request fails after exhausting all retry attempts.
645
+ */
646
+ SidecarRequestFailed: {
647
+ code: -120806,
648
+ description: 'Sidecar request failed after {attempts} attempt(s): {message}'
649
+ },
650
+
651
+ /**
652
+ * Error thrown when the sidecar responds with a non-success status code.
653
+ */
654
+ SidecarErrorResponse: {
655
+ code: -120807,
656
+ description: 'Sidecar returned error status {status}: {message}'
657
+ },
658
+
659
+ /**
660
+ * Error thrown when the sidecar response is missing the authorizationHeader field.
661
+ */
662
+ SidecarResponseMissingAuthorizationHeader: {
663
+ code: -120808,
664
+ description: 'Sidecar response missing `authorizationHeader` field'
665
+ },
666
+
667
+ /**
668
+ * Error thrown when the sidecar response body cannot be parsed.
669
+ */
670
+ SidecarResponseUnparsable: {
671
+ code: -120809,
672
+ description: 'Sidecar returned an unparsable response body'
673
+ },
674
+
675
+ /**
676
+ * Error thrown when acquireTokenOnBehalfOf is called on the sidecar provider, which does not support OBO in Phase 1.
677
+ */
678
+ OnBehalfOfNotSupportedBySidecar: {
679
+ code: -120810,
680
+ description: 'acquireTokenOnBehalfOf is not supported by the Entra sidecar auth provider in Phase 1'
681
+ },
682
+
683
+ /**
684
+ * Error thrown when the sidecar returns a token with an authorization scheme other than Bearer.
685
+ * The hosting stack always transmits tokens as `Bearer {token}`, so a non-Bearer scheme cannot be
686
+ * honored and is rejected rather than silently sent as an invalid Authorization header.
687
+ */
688
+ SidecarUnsupportedAuthScheme: {
689
+ code: -120811,
690
+ description: 'The Entra Agent ID sidecar returned an unsupported authorization scheme `{scheme}`. Only the Bearer scheme is supported'
691
+ },
692
+
693
+ // ============================================================================
694
+ // Agent and Client Errors (-120600 to -120650)
521
695
  // ============================================================================
522
696
 
523
697
  /**
@@ -537,18 +711,34 @@ export const Errors: { [key: string]: AgentErrorDefinition } = {
537
711
  },
538
712
 
539
713
  /**
540
- * Error thrown when failed to post activity to agent.
541
- */
542
- FailedToPostActivityToAgent: {
714
+ * Error thrown when agent ID is required.
715
+ */
716
+ AgentIdRequired: {
543
717
  code: -120620,
718
+ description: 'Agent ID is required to apply outbound agent headers'
719
+ },
720
+
721
+ /**
722
+ * Error thrown when agent name contains invalid characters.
723
+ */
724
+ AgentNameInvalid: {
725
+ code: -120630,
726
+ description: 'Agent name contains invalid characters: {agentName}'
727
+ },
728
+
729
+ /**
730
+ * Error thrown when failed to post activity to agent.
731
+ */
732
+ FailedToPostActivityToAgent: {
733
+ code: -120640,
544
734
  description: 'Failed to post activity to agent: {statusText}'
545
735
  },
546
736
 
547
737
  /**
548
- * Error thrown when logic parameter must be defined.
549
- */
738
+ * Error thrown when logic parameter must be defined.
739
+ */
550
740
  LogicParameterRequired: {
551
- code: -120630,
741
+ code: -120650,
552
742
  description: 'logic must be defined'
553
743
  },
554
744
 
@@ -784,6 +974,15 @@ export const Errors: { [key: string]: AgentErrorDefinition } = {
784
974
  description: 'This proactive operation requires app storage to load and save TurnState. Set options.storage on AgentApplication.'
785
975
  },
786
976
 
977
+ /**
978
+ * Error thrown when CreateConversationOptionsBuilder.build() is called for a Teams channel
979
+ * conversation (withTeamsChannelId) without an activity set via withActivity().
980
+ */
981
+ CreateConversationBuilderChannelActivityRequired: {
982
+ code: -120753,
983
+ description: 'CreateConversationOptionsBuilder: Teams channel conversations require an initial activity. Call withActivity() before build().'
984
+ },
985
+
787
986
  // ============================================================================
788
987
  // General Errors (-120990)
789
988
  // ============================================================================