@microsoft/agents-hosting 0.6.21-g3c2261b2fc → 1.0.0-ge4831811bf

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 (67) hide show
  1. package/dist/package.json +2 -2
  2. package/dist/src/app/adaptiveCards/adaptiveCardsActions.d.ts +9 -6
  3. package/dist/src/app/adaptiveCards/adaptiveCardsActions.js +3 -3
  4. package/dist/src/app/adaptiveCards/adaptiveCardsActions.js.map +1 -1
  5. package/dist/src/app/adaptiveCards/query.d.ts +1 -1
  6. package/dist/src/app/agentApplication.d.ts +10 -10
  7. package/dist/src/app/agentApplication.js +9 -9
  8. package/dist/src/app/agentApplicationBuilder.d.ts +1 -1
  9. package/dist/src/app/agentApplicationBuilder.js +1 -1
  10. package/dist/src/app/agentApplicationOptions.d.ts +10 -1
  11. package/dist/src/app/appMemory.d.ts +1 -1
  12. package/dist/src/app/appRoute.d.ts +1 -1
  13. package/dist/src/app/extensions.d.ts +1 -1
  14. package/dist/src/app/extensions.js +1 -1
  15. package/dist/src/app/turnState.d.ts +6 -6
  16. package/dist/src/app/turnState.js +6 -6
  17. package/dist/src/app/turnStateProperty.d.ts +2 -2
  18. package/dist/src/app/turnStateProperty.js +2 -2
  19. package/dist/src/auth/authConfiguration.d.ts +8 -0
  20. package/dist/src/auth/authConfiguration.js +14 -6
  21. package/dist/src/auth/authConfiguration.js.map +1 -1
  22. package/dist/src/auth/jwt-middleware.js +1 -1
  23. package/dist/src/auth/jwt-middleware.js.map +1 -1
  24. package/dist/src/auth/msalTokenProvider.js +4 -4
  25. package/dist/src/auth/msalTokenProvider.js.map +1 -1
  26. package/dist/src/cloudAdapter.d.ts +5 -2
  27. package/dist/src/cloudAdapter.js +19 -11
  28. package/dist/src/cloudAdapter.js.map +1 -1
  29. package/dist/src/connector-client/connectorClient.d.ts +9 -7
  30. package/dist/src/connector-client/connectorClient.js +27 -11
  31. package/dist/src/connector-client/connectorClient.js.map +1 -1
  32. package/dist/src/headerPropagation.d.ts +71 -0
  33. package/dist/src/headerPropagation.js +76 -0
  34. package/dist/src/headerPropagation.js.map +1 -0
  35. package/dist/src/oauth/userTokenClient.js +34 -17
  36. package/dist/src/oauth/userTokenClient.js.map +1 -1
  37. package/dist/src/state/agentState.d.ts +2 -2
  38. package/dist/src/state/agentState.js +2 -2
  39. package/dist/src/state/agentStatePropertyAccesor.d.ts +18 -21
  40. package/dist/src/state/agentStatePropertyAccesor.js +18 -21
  41. package/dist/src/state/agentStatePropertyAccesor.js.map +1 -1
  42. package/dist/src/storage/fileStorage.d.ts +12 -10
  43. package/dist/src/storage/fileStorage.js +12 -10
  44. package/dist/src/storage/fileStorage.js.map +1 -1
  45. package/dist/src/transcript/transcriptLogger.d.ts +1 -1
  46. package/package.json +2 -2
  47. package/src/app/adaptiveCards/adaptiveCardsActions.ts +9 -6
  48. package/src/app/adaptiveCards/query.ts +1 -1
  49. package/src/app/agentApplication.ts +10 -10
  50. package/src/app/agentApplicationBuilder.ts +1 -1
  51. package/src/app/agentApplicationOptions.ts +11 -1
  52. package/src/app/appMemory.ts +1 -1
  53. package/src/app/appRoute.ts +1 -1
  54. package/src/app/extensions.ts +1 -1
  55. package/src/app/turnState.ts +6 -6
  56. package/src/app/turnStateProperty.ts +2 -2
  57. package/src/auth/authConfiguration.ts +20 -5
  58. package/src/auth/jwt-middleware.ts +1 -1
  59. package/src/auth/msalTokenProvider.ts +4 -4
  60. package/src/cloudAdapter.ts +24 -12
  61. package/src/connector-client/connectorClient.ts +30 -12
  62. package/src/headerPropagation.ts +129 -0
  63. package/src/oauth/userTokenClient.ts +36 -17
  64. package/src/state/agentState.ts +2 -2
  65. package/src/state/agentStatePropertyAccesor.ts +18 -21
  66. package/src/storage/fileStorage.ts +12 -10
  67. package/src/transcript/transcriptLogger.ts +1 -1
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ /**
7
+ * A class that implements the HeaderPropagationCollection interface.
8
+ * It filters the incoming request headers based on the definition provided and loads them into the outgoing headers collection.
9
+ */
10
+ export class HeaderPropagation implements HeaderPropagationCollection {
11
+ private _incomingRequests: Record<string, string>
12
+ private _outgoingHeaders: Record<string, string> = {}
13
+
14
+ private _headersToPropagate = ['x-ms-correlation-id']
15
+
16
+ public get incoming (): Record<string, string> {
17
+ return this._incomingRequests
18
+ }
19
+
20
+ public get outgoing (): Record<string, string> {
21
+ return this._outgoingHeaders
22
+ }
23
+
24
+ constructor (headers: Record<string, string | string[] | undefined>) {
25
+ if (!headers) {
26
+ throw new Error('Headers must be provided.')
27
+ }
28
+
29
+ this._incomingRequests = this.normalizeHeaders(headers)
30
+ this.propagate(this._headersToPropagate)
31
+ }
32
+
33
+ propagate (headers: string[]) {
34
+ for (const key of headers ?? []) {
35
+ const lowerKey = key.toLowerCase()
36
+ if (this._incomingRequests[lowerKey] && !this._outgoingHeaders[lowerKey]) {
37
+ this._outgoingHeaders[lowerKey] = this._incomingRequests[lowerKey]
38
+ }
39
+ }
40
+ }
41
+
42
+ add (headers: Record<string, string>) {
43
+ for (const [key, value] of Object.entries(headers ?? {})) {
44
+ const lowerKey = key.toLowerCase()
45
+ if (!this._incomingRequests[lowerKey] && !this._outgoingHeaders[lowerKey]) {
46
+ this._outgoingHeaders[lowerKey] = value
47
+ }
48
+ }
49
+ }
50
+
51
+ concat (headers: Record<string, string>) {
52
+ for (const [key, value] of Object.entries(headers ?? {})) {
53
+ const lowerKey = key.toLowerCase()
54
+ if (this._incomingRequests[lowerKey] && !this._headersToPropagate.includes(lowerKey)) {
55
+ this._outgoingHeaders[lowerKey] = `${this._outgoingHeaders[lowerKey] ?? this._incomingRequests[lowerKey]} ${value}`.trim()
56
+ }
57
+ }
58
+ }
59
+
60
+ override (headers: Record<string, string>) {
61
+ for (const [key, value] of Object.entries(headers ?? {})) {
62
+ const lowerKey = key.toLowerCase()
63
+ if (!this._headersToPropagate.includes(lowerKey)) {
64
+ this._outgoingHeaders[lowerKey] = value
65
+ }
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Normalizes the headers by lowercasing the keys and ensuring the values are strings.
71
+ * @param headers The headers to normalize.
72
+ * @returns A new object with normalized headers.
73
+ */
74
+ private normalizeHeaders (headers: Record<string, string | string[] | undefined>) {
75
+ return Object.entries(headers).reduce((acc, [key, value]) => {
76
+ if (value) {
77
+ acc[key.toLowerCase()] = Array.isArray(value) ? value.join(' ') : value
78
+ }
79
+ return acc
80
+ }, {} as Record<string, string>)
81
+ }
82
+ }
83
+
84
+ /**
85
+ * A function type that defines how headers should be propagated.
86
+ */
87
+ export interface HeaderPropagationDefinition {
88
+ (headers: HeaderPropagationCollection): void
89
+ }
90
+
91
+ /**
92
+ * Defines the interface for managing header propagation.
93
+ */
94
+ export interface HeaderPropagationCollection {
95
+ /**
96
+ * The collection of incoming headers from the incoming request.
97
+ * @remarks This collection is built based on the headers received in the request.
98
+ */
99
+ incoming: Record<string, string>
100
+ /**
101
+ * The collection of headers that will be propagated to outgoing requests.
102
+ * @remarks This collection is built based on the incoming headers and the definition provided.
103
+ */
104
+ outgoing: Record<string, string>
105
+ /**
106
+ * Propagates the incoming header value to the outgoing collection based on the header definition key.
107
+ * @param headers List of header keys to propagate.
108
+ * @remarks If the header does not exist in the incoming headers, it will be ignored.
109
+ */
110
+ propagate(headers: string[]): void
111
+ /**
112
+ * Adds a header definition to the outgoing collection.
113
+ * @param headers Headers to add to the outgoing collection.
114
+ * @remarks If the header already exists, it will not be added.
115
+ */
116
+ add(headers: Record<string, string>): void
117
+ /**
118
+ * Concatenates a header definition to the outgoing collection.
119
+ * @param headers Headers to concatenate to the outgoing collection.
120
+ * @remarks If the header does not exist in the incoming headers, it will be ignored. Unless the header is already present in the outgoing collection.
121
+ */
122
+ concat(headers: Record<string, string>): void
123
+ /**
124
+ * Overrides a header definition in the outgoing collection.
125
+ * @param headers Headers to override in the outgoing collection.
126
+ * @remarks If the header does not exist in the incoming headers, it will be added to the outgoing collection.
127
+ */
128
+ override(headers: Record<string, string>): void
129
+ }
@@ -22,43 +22,62 @@ export class UserTokenClient {
22
22
  */
23
23
  constructor (private msAppId: string) {
24
24
  const baseURL = 'https://api.botframework.com'
25
- const axiosInstance = axios.create({
25
+ this.client = axios.create({
26
26
  baseURL,
27
27
  headers: {
28
28
  Accept: 'application/json',
29
29
  'User-Agent': getProductInfo(),
30
30
  }
31
31
  })
32
- // axiosInstance.defaults.headers.common.Authorization = `Bearer ${token}`
33
- axiosInstance.interceptors.response.use(
32
+
33
+ this.client.interceptors.request.use((config) => {
34
+ const { method, url, data, headers, params } = config
35
+ const { Authorization, authorization, ...headersToLog } = headers || {}
36
+ logger.debug('Request: ', {
37
+ host: this.client.getUri(),
38
+ url,
39
+ data,
40
+ method,
41
+ params,
42
+ headers: headersToLog
43
+ })
44
+ return config
45
+ })
46
+
47
+ this.client.interceptors.response.use(
34
48
  (config) => {
35
- const { status, statusText, config: requestConfig } = config
49
+ const { status, statusText, config: requestConfig, headers } = config
50
+ const { Authorization, authorization, ...headersToLog } = headers || {}
51
+ const { token, ...redactedData } = requestConfig?.data || {}
36
52
  logger.debug('Response: ', {
37
53
  status,
38
54
  statusText,
39
- host: axiosInstance.getUri(),
55
+ host: this.client.getUri(),
40
56
  url: requestConfig?.url,
41
- data: config.config.data,
57
+ data: redactedData,
42
58
  method: requestConfig?.method,
59
+ headers: headersToLog
43
60
  })
44
61
  return config
45
62
  },
46
63
  (error) => {
47
64
  const { code, status, message, stack, response } = error
48
- if (status !== 404) {
49
- const errorDetails = {
50
- code,
51
- host: axiosInstance.getUri(),
52
- url: error.config.url,
53
- method: error.config.method,
54
- data: error.config.data,
55
- message: message + JSON.stringify(response?.data),
56
- stack,
57
- }
65
+ const { headers } = response || {}
66
+ const errorDetails = {
67
+ code,
68
+ host: this.client.getUri(),
69
+ url: error.config.url,
70
+ method: error.config.method,
71
+ data: error.config.data,
72
+ message: message + JSON.stringify(response?.data),
73
+ headers,
74
+ stack,
75
+ }
76
+ logger.debug('Response error: ', errorDetails)
77
+ if (errorDetails.url === '/api/usertoken/GetToken' && status !== 404) {
58
78
  return Promise.reject(errorDetails)
59
79
  }
60
80
  })
61
- this.client = axiosInstance
62
81
  }
63
82
 
64
83
  /**
@@ -44,8 +44,8 @@ export interface CustomKey {
44
44
  }
45
45
 
46
46
  /**
47
- * Manages the state of an Agent across turns in a conversation.
48
- *
47
+ * @summary Manages the state of an Agent across turns in a conversation.
48
+ * @remarks
49
49
  * AgentState provides functionality to persist and retrieve state data using
50
50
  * a storage provider. It handles caching state in the turn context for performance,
51
51
  * calculating change hashes to detect modifications, and managing property accessors
@@ -73,7 +73,7 @@ export interface StatePropertyAccessor<T = any> {
73
73
  }
74
74
 
75
75
  /**
76
- * Provides typed access to an Agent state property with automatic state loading and persistence management.
76
+ * @summary Provides typed access to an Agent state property with automatic state loading and persistence management.
77
77
  *
78
78
  * @remarks
79
79
  * AgentStatePropertyAccessor simplifies working with persisted state by abstracting
@@ -86,9 +86,9 @@ export interface StatePropertyAccessor<T = any> {
86
86
  * - **Memory Management**: Efficient in-memory caching with explicit persistence control
87
87
  * - **Custom Keys**: Support for custom storage keys for advanced scenarios
88
88
  *
89
- * ## Key Features
89
+ * ### Key Features
90
90
  *
91
- * ### Type Safety
91
+ * #### Type Safety
92
92
  * The accessor provides compile-time type checking when using TypeScript:
93
93
  * ```typescript
94
94
  * interface UserProfile {
@@ -98,7 +98,7 @@ export interface StatePropertyAccessor<T = any> {
98
98
  * const userProfile = userState.createProperty<UserProfile>("userProfile");
99
99
  * ```
100
100
  *
101
- * ### Automatic Default Value Handling
101
+ * #### Automatic Default Value Handling
102
102
  * When a property doesn't exist, default values are automatically cloned and stored:
103
103
  * ```typescript
104
104
  * // If userProfile doesn't exist, the default will be cloned and saved
@@ -108,7 +108,7 @@ export interface StatePropertyAccessor<T = any> {
108
108
  * });
109
109
  * ```
110
110
  *
111
- * ### Explicit Persistence Control
111
+ * #### Explicit Persistence Control
112
112
  * Changes are kept in memory until explicitly persisted:
113
113
  * ```typescript
114
114
  * // Modify the state
@@ -120,9 +120,9 @@ export interface StatePropertyAccessor<T = any> {
120
120
  * await userState.saveChanges(context);
121
121
  * ```
122
122
  *
123
- * ## Usage Examples
123
+ * ### Usage Examples
124
124
  *
125
- * ### Basic Usage
125
+ * @example Basic Usage
126
126
  * ```typescript
127
127
  * // Create a property accessor
128
128
  * const userProfile = userState.createProperty<UserProfile>("userProfile");
@@ -141,7 +141,7 @@ export interface StatePropertyAccessor<T = any> {
141
141
  * await userState.saveChanges(context); // Persist to storage
142
142
  * ```
143
143
  *
144
- * ### Working with Primitive Types
144
+ * @example Working with Primitive Types
145
145
  * ```typescript
146
146
  * const counterProperty = userState.createProperty<number>("counter");
147
147
  *
@@ -151,7 +151,7 @@ export interface StatePropertyAccessor<T = any> {
151
151
  * await userState.saveChanges(context);
152
152
  * ```
153
153
  *
154
- * ### Conditional Logic
154
+ * @example Conditional Logic
155
155
  * ```typescript
156
156
  * const settingsProperty = userState.createProperty<Settings>("settings");
157
157
  *
@@ -163,7 +163,7 @@ export interface StatePropertyAccessor<T = any> {
163
163
  * }
164
164
  * ```
165
165
  *
166
- * ### Custom Storage Keys
166
+ * @example Custom Storage Keys
167
167
  * ```typescript
168
168
  * // Store state with a custom key for multi-tenant scenarios
169
169
  * const customKey = { key: `tenant_${tenantId}` };
@@ -171,7 +171,7 @@ export interface StatePropertyAccessor<T = any> {
171
171
  * await dataProperty.set(context, updatedData, customKey);
172
172
  * ```
173
173
  *
174
- * ## Important Notes
174
+ * ### Important Notes
175
175
  *
176
176
  * - **Thread Safety**: This class is not thread-safe. Ensure proper synchronization in concurrent scenarios.
177
177
  * - **Memory Usage**: State objects are kept in memory until the context is disposed.
@@ -206,20 +206,19 @@ export class AgentStatePropertyAccessor<T = any> implements StatePropertyAccesso
206
206
  constructor (protected readonly state: AgentState, public readonly name: string) { }
207
207
 
208
208
  /**
209
- * Deletes the property from the state storage.
210
- *
209
+ * @summary Deletes the property from the state storage.
210
+ * @remarks
211
211
  * This operation removes the property from the in-memory state object but does not
212
212
  * automatically persist the change to the underlying storage. You must call
213
213
  * `state.saveChanges(context)` afterwards to persist the deletion.
214
214
  *
215
- * @remarks
216
215
  * - If the property doesn't exist, this operation is a no-op
217
216
  * - The deletion only affects the in-memory state until `saveChanges()` is called
218
217
  * - After deletion, subsequent `get()` calls will return `undefined` (or the default value if provided)
219
218
  *
220
219
  * @param context The turn context for the current conversation turn
221
220
  * @param customKey Optional custom key for accessing state in a specific storage location.
222
- * Useful for multi-tenant scenarios or when state needs to be partitioned.
221
+ * Useful for multi-tenant scenarios or when state needs to be partitioned.
223
222
  *
224
223
  * @returns A promise that resolves when the delete operation is complete
225
224
  *
@@ -252,15 +251,14 @@ export class AgentStatePropertyAccessor<T = any> implements StatePropertyAccesso
252
251
  }
253
252
 
254
253
  /**
255
- * Retrieves the value of the property from state storage.
256
- *
254
+ * @summary Retrieves the value of the property from state storage.
255
+ * @remarks
257
256
  * This method provides intelligent default value handling:
258
257
  * - If the property exists, its value is returned
259
258
  * - If the property doesn't exist and a default value is provided, the default is deep cloned,
260
259
  * stored in state, and returned
261
260
  * - If the property doesn't exist and no default is provided, `undefined` is returned
262
261
  *
263
- * @remarks
264
262
  * **Deep Cloning**: Default values are deep cloned using JSON serialization to prevent
265
263
  * reference sharing issues. This means:
266
264
  * - Functions, symbols, and circular references will be lost
@@ -331,13 +329,12 @@ export class AgentStatePropertyAccessor<T = any> implements StatePropertyAccesso
331
329
  }
332
330
 
333
331
  /**
334
- * Sets the value of the property in state storage.
335
- *
332
+ * @summary Sets the value of the property in state storage.
333
+ * @remarks
336
334
  * This operation updates the property in the in-memory state object but does not
337
335
  * automatically persist the change to the underlying storage. You must call
338
336
  * `state.saveChanges(context)` afterwards to persist the changes.
339
337
  *
340
- * @remarks
341
338
  * **Memory vs Storage**: Changes are immediately reflected in memory and will be
342
339
  * available to subsequent `get()` calls within the same context, but are not
343
340
  * persisted to storage until `saveChanges()` is called.
@@ -8,7 +8,7 @@ import fs from 'fs'
8
8
  import { Storage, StoreItem } from './storage'
9
9
 
10
10
  /**
11
- * A file-based storage implementation that persists data to the local filesystem.
11
+ * @summary A file-based storage implementation that persists data to the local filesystem.
12
12
  *
13
13
  * @remarks
14
14
  * FileStorage stores all data in a single JSON file named 'state.json' within a specified folder.
@@ -19,6 +19,16 @@ import { Storage, StoreItem } from './storage'
19
19
  * can be any JSON-serializable data. All operations are synchronous file I/O operations
20
20
  * wrapped in Promise interfaces to match the Storage contract.
21
21
  *
22
+ * ### Warning
23
+ * This implementation does not provide:
24
+ * - Thread safety for concurrent access
25
+ * - Optimistic concurrency control (eTag support)
26
+ * - Atomic operations across multiple keys
27
+ * - Scale for large datasets
28
+ *
29
+ * For production scenarios requiring these features, consider using
30
+ * database-backed storage implementations instead.
31
+ *
22
32
  * @example
23
33
  * ```typescript
24
34
  * const storage = new FileStorage('./data');
@@ -37,15 +47,7 @@ import { Storage, StoreItem } from './storage'
37
47
  * await storage.delete(['conversation456']);
38
48
  * ```
39
49
  *
40
- * @warning
41
- * This implementation does not provide:
42
- * - Thread safety for concurrent access
43
- * - Optimistic concurrency control (eTag support)
44
- * - Atomic operations across multiple keys
45
- * - Scale for large datasets
46
- *
47
- * For production scenarios requiring these features, consider using
48
- * database-backed storage implementations instead.
50
+
49
51
  */
50
52
  export class FileStorage implements Storage {
51
53
  private _folder: string
@@ -31,7 +31,7 @@ export interface TranscriptInfo {
31
31
 
32
32
  /**
33
33
  * Paged result of items.
34
- * @template T - The type of items in the paged result.
34
+ * @typeParam T - The type of items in the paged result.
35
35
  */
36
36
  export interface PagedResult<T> {
37
37
  /**