@microsoft/agents-hosting 0.6.1 → 0.6.11
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.
- package/dist/src/activityHandler.d.ts +29 -5
- package/dist/src/activityHandler.js +30 -6
- package/dist/src/activityHandler.js.map +1 -1
- package/dist/src/agent-client/agentClient.js +1 -1
- package/dist/src/agent-client/agentClient.js.map +1 -1
- package/dist/src/agent-client/agentResponseHandler.d.ts +34 -0
- package/dist/src/agent-client/agentResponseHandler.js +35 -1
- package/dist/src/agent-client/agentResponseHandler.js.map +1 -1
- package/dist/src/app/adaptiveCards/adaptiveCardsActions.d.ts +23 -2
- package/dist/src/app/adaptiveCards/adaptiveCardsActions.js.map +1 -1
- package/dist/src/app/adaptiveCards/adaptiveCardsSearchParams.d.ts +1 -1
- package/dist/src/app/agentApplication.d.ts +46 -34
- package/dist/src/app/agentApplication.js +64 -40
- package/dist/src/app/agentApplication.js.map +1 -1
- package/dist/src/app/agentApplicationOptions.d.ts +74 -13
- package/dist/src/app/appRoute.d.ts +56 -2
- package/dist/src/app/attachmentDownloader.d.ts +1 -0
- package/dist/src/app/attachmentDownloader.js +2 -1
- package/dist/src/app/attachmentDownloader.js.map +1 -1
- package/dist/src/app/authorization.d.ts +1 -1
- package/dist/src/app/authorization.js +1 -1
- package/dist/src/app/authorization.js.map +1 -1
- package/dist/src/app/extensions.d.ts +37 -1
- package/dist/src/app/extensions.js +38 -2
- package/dist/src/app/extensions.js.map +1 -1
- package/dist/src/app/index.d.ts +2 -0
- package/dist/src/app/index.js +2 -0
- package/dist/src/app/index.js.map +1 -1
- package/dist/src/app/routeList.d.ts +13 -0
- package/dist/src/app/routeList.js +30 -0
- package/dist/src/app/routeList.js.map +1 -0
- package/dist/src/app/routeRank.d.ts +51 -0
- package/dist/src/app/routeRank.js +56 -0
- package/dist/src/app/routeRank.js.map +1 -0
- package/dist/src/app/streaming/streamingResponse.js +29 -41
- package/dist/src/app/streaming/streamingResponse.js.map +1 -1
- package/dist/src/app/turnState.d.ts +2 -0
- package/dist/src/app/turnState.js +3 -1
- package/dist/src/app/turnState.js.map +1 -1
- package/dist/src/auth/authConfiguration.d.ts +4 -0
- package/dist/src/auth/authConfiguration.js +4 -0
- package/dist/src/auth/authConfiguration.js.map +1 -1
- package/dist/src/auth/authProvider.d.ts +1 -1
- package/dist/src/auth/jwt-middleware.js +1 -1
- package/dist/src/auth/jwt-middleware.js.map +1 -1
- package/dist/src/auth/msalTokenCredential.d.ts +14 -0
- package/dist/src/auth/msalTokenCredential.js +14 -0
- package/dist/src/auth/msalTokenCredential.js.map +1 -1
- package/dist/src/auth/msalTokenProvider.js +4 -2
- package/dist/src/auth/msalTokenProvider.js.map +1 -1
- package/dist/src/baseAdapter.d.ts +22 -1
- package/dist/src/baseAdapter.js +23 -2
- package/dist/src/baseAdapter.js.map +1 -1
- package/dist/src/cards/adaptiveCard.d.ts +2 -0
- package/dist/src/cards/animationCard.d.ts +1 -1
- package/dist/src/cards/audioCard.d.ts +1 -1
- package/dist/src/cards/cardImage.d.ts +1 -1
- package/dist/src/cards/fact.d.ts +1 -1
- package/dist/src/cards/heroCard.d.ts +1 -1
- package/dist/src/cards/o365ConnectorCardSection.d.ts +5 -0
- package/dist/src/cloudAdapter.d.ts +11 -0
- package/dist/src/cloudAdapter.js +33 -4
- package/dist/src/cloudAdapter.js.map +1 -1
- package/dist/src/connector-client/connectorClient.js +1 -1
- package/dist/src/connector-client/connectorClient.js.map +1 -1
- package/dist/src/index.d.ts +0 -2
- package/dist/src/index.js +0 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/middlewareSet.js +1 -1
- package/dist/src/middlewareSet.js.map +1 -1
- package/dist/src/oauth/oAuthFlow.js +1 -1
- package/dist/src/oauth/oAuthFlow.js.map +1 -1
- package/dist/src/oauth/userTokenClient.js +1 -1
- package/dist/src/oauth/userTokenClient.js.map +1 -1
- package/dist/src/state/agentState.js +1 -1
- package/dist/src/state/agentState.js.map +1 -1
- package/dist/src/state/agentStatePropertyAccesor.d.ts +269 -38
- package/dist/src/state/agentStatePropertyAccesor.js +269 -38
- package/dist/src/state/agentStatePropertyAccesor.js.map +1 -1
- package/dist/src/statusCodes.d.ts +30 -0
- package/dist/src/statusCodes.js +30 -0
- package/dist/src/statusCodes.js.map +1 -1
- package/dist/src/storage/fileStorage.d.ts +97 -0
- package/dist/src/storage/fileStorage.js +97 -0
- package/dist/src/storage/fileStorage.js.map +1 -1
- package/dist/src/storage/memoryStorage.d.ts +2 -1
- package/dist/src/storage/memoryStorage.js +3 -2
- package/dist/src/storage/memoryStorage.js.map +1 -1
- package/dist/src/storage/storage.d.ts +1 -0
- package/dist/src/transcript/transcriptLoggerMiddleware.js +1 -1
- package/dist/src/transcript/transcriptLoggerMiddleware.js.map +1 -1
- package/dist/src/turnContext.d.ts +1 -0
- package/dist/src/turnContext.js +1 -0
- package/dist/src/turnContext.js.map +1 -1
- package/package.json +4 -5
- package/src/activityHandler.ts +30 -6
- package/src/agent-client/agentClient.ts +1 -1
- package/src/agent-client/agentResponseHandler.ts +35 -1
- package/src/app/adaptiveCards/adaptiveCardsActions.ts +23 -2
- package/src/app/adaptiveCards/adaptiveCardsSearchParams.ts +1 -1
- package/src/app/agentApplication.ts +70 -41
- package/src/app/agentApplicationOptions.ts +75 -13
- package/src/app/appRoute.ts +57 -2
- package/src/app/attachmentDownloader.ts +2 -1
- package/src/app/authorization.ts +2 -2
- package/src/app/extensions.ts +45 -2
- package/src/app/index.ts +2 -0
- package/src/app/routeList.ts +37 -0
- package/src/app/routeRank.ts +54 -0
- package/src/app/streaming/streamingResponse.ts +22 -69
- package/src/app/turnState.ts +3 -1
- package/src/auth/authConfiguration.ts +4 -0
- package/src/auth/authProvider.ts +1 -1
- package/src/auth/jwt-middleware.ts +1 -1
- package/src/auth/msalTokenCredential.ts +15 -0
- package/src/auth/msalTokenProvider.ts +4 -2
- package/src/baseAdapter.ts +25 -2
- package/src/cards/adaptiveCard.ts +2 -0
- package/src/cards/animationCard.ts +1 -1
- package/src/cards/audioCard.ts +1 -1
- package/src/cards/cardImage.ts +1 -1
- package/src/cards/fact.ts +1 -1
- package/src/cards/heroCard.ts +1 -1
- package/src/cards/o365ConnectorCardSection.ts +5 -0
- package/src/cloudAdapter.ts +36 -4
- package/src/connector-client/connectorClient.ts +1 -1
- package/src/index.ts +0 -2
- package/src/middlewareSet.ts +1 -1
- package/src/oauth/oAuthFlow.ts +1 -1
- package/src/oauth/userTokenClient.ts +1 -1
- package/src/state/agentState.ts +1 -1
- package/src/state/agentStatePropertyAccesor.ts +269 -38
- package/src/statusCodes.ts +30 -0
- package/src/storage/fileStorage.ts +99 -0
- package/src/storage/memoryStorage.ts +3 -2
- package/src/storage/storage.ts +1 -0
- package/src/transcript/transcriptLoggerMiddleware.ts +1 -1
- package/src/turnContext.ts +1 -0
- package/dist/src/logger.d.ts +0 -44
- package/dist/src/logger.js +0 -77
- package/dist/src/logger.js.map +0 -1
- package/src/logger.ts +0 -76
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import axios, { AxiosInstance } from 'axios'
|
|
5
5
|
import { ConversationReference } from '@microsoft/agents-activity'
|
|
6
|
-
import { debug } from '
|
|
6
|
+
import { debug } from '@microsoft/agents-activity/src/logger'
|
|
7
7
|
import { normalizeTokenExchangeState } from '../activityWireCompat'
|
|
8
8
|
import { AadResourceUrls, SignInResource, TokenExchangeRequest, TokenOrSinginResourceResponse, TokenResponse, TokenStatus } from './userTokenClient.types'
|
|
9
9
|
import { getProductInfo } from '../getProductInfo'
|
package/src/state/agentState.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { Storage, StorageKeyFactory, StoreItem } from '../storage/storage'
|
|
|
7
7
|
import { TurnContext } from '../turnContext'
|
|
8
8
|
import { createHash } from 'node:crypto'
|
|
9
9
|
import { AgentStatePropertyAccessor } from './agentStatePropertyAccesor'
|
|
10
|
-
import { debug } from '
|
|
10
|
+
import { debug } from '@microsoft/agents-activity/src/logger'
|
|
11
11
|
|
|
12
12
|
const logger = debug('agents:state')
|
|
13
13
|
|
|
@@ -73,56 +73,176 @@ export interface StatePropertyAccessor<T = any> {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
|
-
* Provides typed access to an Agent state property with automatic state loading.
|
|
76
|
+
* Provides typed access to an Agent state property with automatic state loading and persistence management.
|
|
77
77
|
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
78
|
+
* @remarks
|
|
79
|
+
* AgentStatePropertyAccessor simplifies working with persisted state by abstracting
|
|
80
|
+
* the complexity of loading state from storage and manipulating specific properties.
|
|
81
|
+
* It provides a type-safe interface for state management with automatic handling of:
|
|
81
82
|
*
|
|
82
|
-
* - Loading
|
|
83
|
-
* -
|
|
84
|
-
* -
|
|
85
|
-
* -
|
|
83
|
+
* - **Lazy Loading**: State is loaded from storage only when first accessed
|
|
84
|
+
* - **Type Safety**: Full TypeScript support with generic type parameters
|
|
85
|
+
* - **Default Values**: Automatic deep cloning of default values to prevent reference issues
|
|
86
|
+
* - **Memory Management**: Efficient in-memory caching with explicit persistence control
|
|
87
|
+
* - **Custom Keys**: Support for custom storage keys for advanced scenarios
|
|
86
88
|
*
|
|
87
|
-
*
|
|
89
|
+
* ## Key Features
|
|
88
90
|
*
|
|
91
|
+
* ### Type Safety
|
|
92
|
+
* The accessor provides compile-time type checking when using TypeScript:
|
|
89
93
|
* ```typescript
|
|
90
|
-
*
|
|
94
|
+
* interface UserProfile {
|
|
95
|
+
* name: string;
|
|
96
|
+
* preferences: { theme: string; language: string };
|
|
97
|
+
* }
|
|
91
98
|
* const userProfile = userState.createProperty<UserProfile>("userProfile");
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* ### Automatic Default Value Handling
|
|
102
|
+
* When a property doesn't exist, default values are automatically cloned and stored:
|
|
103
|
+
* ```typescript
|
|
104
|
+
* // If userProfile doesn't exist, the default will be cloned and saved
|
|
105
|
+
* const profile = await userProfile.get(context, {
|
|
106
|
+
* name: "Anonymous",
|
|
107
|
+
* preferences: { theme: "light", language: "en" }
|
|
108
|
+
* });
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* ### Explicit Persistence Control
|
|
112
|
+
* Changes are kept in memory until explicitly persisted:
|
|
113
|
+
* ```typescript
|
|
114
|
+
* // Modify the state
|
|
115
|
+
* const counter = await counterProperty.get(context, 0);
|
|
116
|
+
* await counterProperty.set(context, counter + 1);
|
|
117
|
+
*
|
|
118
|
+
* // Changes are only in memory at this point
|
|
119
|
+
* // Persist to storage
|
|
120
|
+
* await userState.saveChanges(context);
|
|
121
|
+
* ```
|
|
92
122
|
*
|
|
93
|
-
*
|
|
94
|
-
* const profile = await userProfile.get(context, { name: "", preferences: {} });
|
|
123
|
+
* ## Usage Examples
|
|
95
124
|
*
|
|
96
|
-
*
|
|
125
|
+
* ### Basic Usage
|
|
126
|
+
* ```typescript
|
|
127
|
+
* // Create a property accessor
|
|
128
|
+
* const userProfile = userState.createProperty<UserProfile>("userProfile");
|
|
129
|
+
*
|
|
130
|
+
* // Get with default value
|
|
131
|
+
* const profile = await userProfile.get(context, {
|
|
132
|
+
* name: "",
|
|
133
|
+
* preferences: { theme: "light", language: "en" }
|
|
134
|
+
* });
|
|
135
|
+
*
|
|
136
|
+
* // Modify the profile
|
|
97
137
|
* profile.preferences.theme = "dark";
|
|
98
138
|
*
|
|
99
|
-
* // Save the
|
|
139
|
+
* // Save the changes
|
|
100
140
|
* await userProfile.set(context, profile);
|
|
141
|
+
* await userState.saveChanges(context); // Persist to storage
|
|
142
|
+
* ```
|
|
143
|
+
*
|
|
144
|
+
* ### Working with Primitive Types
|
|
145
|
+
* ```typescript
|
|
146
|
+
* const counterProperty = userState.createProperty<number>("counter");
|
|
101
147
|
*
|
|
102
|
-
* //
|
|
148
|
+
* // Increment counter
|
|
149
|
+
* const currentCount = await counterProperty.get(context, 0);
|
|
150
|
+
* await counterProperty.set(context, currentCount + 1);
|
|
151
|
+
* await userState.saveChanges(context);
|
|
103
152
|
* ```
|
|
104
153
|
*
|
|
105
|
-
*
|
|
154
|
+
* ### Conditional Logic
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const settingsProperty = userState.createProperty<Settings>("settings");
|
|
157
|
+
*
|
|
158
|
+
* // Check if property exists
|
|
159
|
+
* const settings = await settingsProperty.get(context);
|
|
160
|
+
* if (settings === undefined) {
|
|
161
|
+
* // Property doesn't exist, initialize with defaults
|
|
162
|
+
* await settingsProperty.set(context, getDefaultSettings());
|
|
163
|
+
* }
|
|
164
|
+
* ```
|
|
165
|
+
*
|
|
166
|
+
* ### Custom Storage Keys
|
|
167
|
+
* ```typescript
|
|
168
|
+
* // Store state with a custom key for multi-tenant scenarios
|
|
169
|
+
* const customKey = { key: `tenant_${tenantId}` };
|
|
170
|
+
* const tenantData = await dataProperty.get(context, defaultData, customKey);
|
|
171
|
+
* await dataProperty.set(context, updatedData, customKey);
|
|
172
|
+
* ```
|
|
173
|
+
*
|
|
174
|
+
* ## Important Notes
|
|
175
|
+
*
|
|
176
|
+
* - **Thread Safety**: This class is not thread-safe. Ensure proper synchronization in concurrent scenarios.
|
|
177
|
+
* - **Memory Usage**: State objects are kept in memory until the context is disposed.
|
|
178
|
+
* - **Persistence**: Always call `state.saveChanges(context)` to persist changes to storage.
|
|
179
|
+
* - **Deep Cloning**: Default values are deep cloned using JSON serialization, which may not work with complex objects containing functions or circular references.
|
|
180
|
+
*
|
|
181
|
+
* @typeParam T The type of the property being accessed. Can be any serializable type.
|
|
182
|
+
*
|
|
183
|
+
* @see {@link AgentState.createProperty} for creating property accessors
|
|
184
|
+
* @see {@link StatePropertyAccessor} for the interface definition
|
|
106
185
|
*/
|
|
107
186
|
export class AgentStatePropertyAccessor<T = any> implements StatePropertyAccessor<T> {
|
|
108
187
|
/**
|
|
109
188
|
* Creates a new instance of AgentStatePropertyAccessor.
|
|
110
189
|
*
|
|
111
|
-
* @
|
|
112
|
-
*
|
|
190
|
+
* @remarks
|
|
191
|
+
* This constructor is typically not called directly. Instead, use {@link AgentState.createProperty}
|
|
192
|
+
* to create property accessors, which ensures proper integration with the state management system.
|
|
193
|
+
*
|
|
194
|
+
* @param state The agent state object that manages the backing storage for this property
|
|
195
|
+
* @param name The unique name of the property within the state object. This name is used as the key in the state storage.
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* ```typescript
|
|
199
|
+
* // Recommended way - use AgentState.createProperty
|
|
200
|
+
* const userProfile = userState.createProperty<UserProfile>("userProfile");
|
|
201
|
+
*
|
|
202
|
+
* // Direct construction (not recommended)
|
|
203
|
+
* const accessor = new AgentStatePropertyAccessor<UserProfile>(userState, "userProfile");
|
|
204
|
+
* ```
|
|
113
205
|
*/
|
|
114
206
|
constructor (protected readonly state: AgentState, public readonly name: string) { }
|
|
115
207
|
|
|
116
208
|
/**
|
|
117
|
-
* Deletes the property from the state.
|
|
209
|
+
* Deletes the property from the state storage.
|
|
118
210
|
*
|
|
119
|
-
* This removes the property from the state object but does not
|
|
120
|
-
* persist the change to storage.
|
|
121
|
-
* persist
|
|
211
|
+
* This operation removes the property from the in-memory state object but does not
|
|
212
|
+
* automatically persist the change to the underlying storage. You must call
|
|
213
|
+
* `state.saveChanges(context)` afterwards to persist the deletion.
|
|
214
|
+
*
|
|
215
|
+
* @remarks
|
|
216
|
+
* - If the property doesn't exist, this operation is a no-op
|
|
217
|
+
* - The deletion only affects the in-memory state until `saveChanges()` is called
|
|
218
|
+
* - After deletion, subsequent `get()` calls will return `undefined` (or the default value if provided)
|
|
219
|
+
*
|
|
220
|
+
* @param context The turn context for the current conversation turn
|
|
221
|
+
* @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.
|
|
122
223
|
*
|
|
123
|
-
* @param context The turn context
|
|
124
|
-
* @param customKey Optional custom key for storing the state in a specific location
|
|
125
224
|
* @returns A promise that resolves when the delete operation is complete
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```typescript
|
|
228
|
+
* const userSettings = userState.createProperty<UserSettings>("settings");
|
|
229
|
+
*
|
|
230
|
+
* // Delete the user settings
|
|
231
|
+
* await userSettings.delete(context);
|
|
232
|
+
*
|
|
233
|
+
* // Persist the deletion to storage
|
|
234
|
+
* await userState.saveChanges(context);
|
|
235
|
+
*
|
|
236
|
+
* // Verify deletion
|
|
237
|
+
* const settings = await userSettings.get(context); // Returns undefined
|
|
238
|
+
* ```
|
|
239
|
+
*
|
|
240
|
+
* @example Custom key usage
|
|
241
|
+
* ```typescript
|
|
242
|
+
* const tenantKey = { key: `tenant_${tenantId}` };
|
|
243
|
+
* await userSettings.delete(context, tenantKey);
|
|
244
|
+
* await userState.saveChanges(context);
|
|
245
|
+
* ```
|
|
126
246
|
*/
|
|
127
247
|
async delete (context: TurnContext, customKey?: CustomKey): Promise<void> {
|
|
128
248
|
const obj: any = await this.state.load(context, false, customKey)
|
|
@@ -132,16 +252,70 @@ export class AgentStatePropertyAccessor<T = any> implements StatePropertyAccesso
|
|
|
132
252
|
}
|
|
133
253
|
|
|
134
254
|
/**
|
|
135
|
-
*
|
|
255
|
+
* Retrieves the value of the property from state storage.
|
|
256
|
+
*
|
|
257
|
+
* This method provides intelligent default value handling:
|
|
258
|
+
* - If the property exists, its value is returned
|
|
259
|
+
* - If the property doesn't exist and a default value is provided, the default is deep cloned,
|
|
260
|
+
* stored in state, and returned
|
|
261
|
+
* - If the property doesn't exist and no default is provided, `undefined` is returned
|
|
262
|
+
*
|
|
263
|
+
* @remarks
|
|
264
|
+
* **Deep Cloning**: Default values are deep cloned using JSON serialization to prevent
|
|
265
|
+
* reference sharing issues. This means:
|
|
266
|
+
* - Functions, symbols, and circular references will be lost
|
|
267
|
+
* - Dates become strings (use Date constructor to restore)
|
|
268
|
+
* - Complex objects with prototypes lose their prototype chain
|
|
269
|
+
*
|
|
270
|
+
* **Performance**: The first access loads state from storage; subsequent accesses use
|
|
271
|
+
* the in-memory cached version until the context is disposed.
|
|
272
|
+
*
|
|
273
|
+
* @param context The turn context for the current conversation turn
|
|
274
|
+
* @param defaultValue Optional default value to use if the property doesn't exist.
|
|
275
|
+
* When provided, this value is deep cloned and stored in state.
|
|
276
|
+
* @param customKey Optional custom key for accessing state in a specific storage location.
|
|
277
|
+
* Useful for multi-tenant scenarios or when state needs to be partitioned.
|
|
136
278
|
*
|
|
137
|
-
*
|
|
138
|
-
* of the default value will be stored in state and returned. This ensures that
|
|
139
|
-
* modifications to the returned object will be properly tracked.
|
|
279
|
+
* @returns A promise that resolves to the property value, the cloned default value, or `undefined`
|
|
140
280
|
*
|
|
141
|
-
* @
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
281
|
+
* @example Basic usage
|
|
282
|
+
* ```typescript
|
|
283
|
+
* const counterProperty = userState.createProperty<number>("counter");
|
|
284
|
+
*
|
|
285
|
+
* // Get with default value
|
|
286
|
+
* const count = await counterProperty.get(context, 0);
|
|
287
|
+
* console.log(count); // 0 if property doesn't exist, otherwise the stored value
|
|
288
|
+
* ```
|
|
289
|
+
*
|
|
290
|
+
* @example Complex object with default
|
|
291
|
+
* ```typescript
|
|
292
|
+
* interface UserProfile {
|
|
293
|
+
* name: string;
|
|
294
|
+
* preferences: { theme: string; notifications: boolean };
|
|
295
|
+
* }
|
|
296
|
+
*
|
|
297
|
+
* const userProfile = userState.createProperty<UserProfile>("profile");
|
|
298
|
+
* const profile = await userProfile.get(context, {
|
|
299
|
+
* name: "Anonymous",
|
|
300
|
+
* preferences: { theme: "light", notifications: true }
|
|
301
|
+
* });
|
|
302
|
+
* ```
|
|
303
|
+
*
|
|
304
|
+
* @example Checking for existence
|
|
305
|
+
* ```typescript
|
|
306
|
+
* const profile = await userProfile.get(context);
|
|
307
|
+
* if (profile === undefined) {
|
|
308
|
+
* console.log("Profile has not been set yet");
|
|
309
|
+
* } else {
|
|
310
|
+
* console.log(`Welcome back, ${profile.name}!`);
|
|
311
|
+
* }
|
|
312
|
+
* ```
|
|
313
|
+
*
|
|
314
|
+
* @example Custom key usage
|
|
315
|
+
* ```typescript
|
|
316
|
+
* const tenantKey = { key: `tenant_${tenantId}` };
|
|
317
|
+
* const tenantData = await dataProperty.get(context, defaultData, tenantKey);
|
|
318
|
+
* ```
|
|
145
319
|
*/
|
|
146
320
|
async get (context: TurnContext, defaultValue?: T, customKey?: CustomKey): Promise<T> {
|
|
147
321
|
const obj: any = await this.state.load(context, false, customKey)
|
|
@@ -157,15 +331,72 @@ export class AgentStatePropertyAccessor<T = any> implements StatePropertyAccesso
|
|
|
157
331
|
}
|
|
158
332
|
|
|
159
333
|
/**
|
|
160
|
-
* Sets the value of the property in
|
|
334
|
+
* Sets the value of the property in state storage.
|
|
161
335
|
*
|
|
162
|
-
* This updates the property in the in-memory state object but does not
|
|
163
|
-
* persist the change to
|
|
336
|
+
* This operation updates the property in the in-memory state object but does not
|
|
337
|
+
* automatically persist the change to the underlying storage. You must call
|
|
338
|
+
* `state.saveChanges(context)` afterwards to persist the changes.
|
|
339
|
+
*
|
|
340
|
+
* @remarks
|
|
341
|
+
* **Memory vs Storage**: Changes are immediately reflected in memory and will be
|
|
342
|
+
* available to subsequent `get()` calls within the same context, but are not
|
|
343
|
+
* persisted to storage until `saveChanges()` is called.
|
|
344
|
+
*
|
|
345
|
+
* **Value References**: The exact value reference is stored (no cloning occurs).
|
|
346
|
+
* Ensure you don't modify objects after setting them unless you intend for those
|
|
347
|
+
* changes to be reflected in state.
|
|
348
|
+
*
|
|
349
|
+
* **Type Safety**: When using TypeScript, the value must match the property's
|
|
350
|
+
* declared type parameter.
|
|
351
|
+
*
|
|
352
|
+
* @param context The turn context for the current conversation turn
|
|
353
|
+
* @param value The value to assign to the property. Can be any serializable value.
|
|
354
|
+
* @param customKey Optional custom key for accessing state in a specific storage location.
|
|
355
|
+
* Useful for multi-tenant scenarios or when state needs to be partitioned.
|
|
164
356
|
*
|
|
165
|
-
* @param context The turn context
|
|
166
|
-
* @param value The value to set
|
|
167
|
-
* @param customKey Optional custom key for storing the state in a specific location
|
|
168
357
|
* @returns A promise that resolves when the set operation is complete
|
|
358
|
+
*
|
|
359
|
+
* @example Basic usage
|
|
360
|
+
* ```typescript
|
|
361
|
+
* const counterProperty = userState.createProperty<number>("counter");
|
|
362
|
+
*
|
|
363
|
+
* // Set a new value
|
|
364
|
+
* await counterProperty.set(context, 42);
|
|
365
|
+
*
|
|
366
|
+
* // Persist to storage
|
|
367
|
+
* await userState.saveChanges(context);
|
|
368
|
+
* ```
|
|
369
|
+
*
|
|
370
|
+
* @example Complex object
|
|
371
|
+
* ```typescript
|
|
372
|
+
* const userProfile = userState.createProperty<UserProfile>("profile");
|
|
373
|
+
*
|
|
374
|
+
* const newProfile: UserProfile = {
|
|
375
|
+
* name: "John Doe",
|
|
376
|
+
* preferences: { theme: "dark", notifications: false }
|
|
377
|
+
* };
|
|
378
|
+
*
|
|
379
|
+
* await userProfile.set(context, newProfile);
|
|
380
|
+
* await userState.saveChanges(context);
|
|
381
|
+
* ```
|
|
382
|
+
*
|
|
383
|
+
* @example Incremental updates
|
|
384
|
+
* ```typescript
|
|
385
|
+
* // Get current value, modify, then set
|
|
386
|
+
* const settings = await settingsProperty.get(context, getDefaultSettings());
|
|
387
|
+
* settings.theme = "dark";
|
|
388
|
+
* settings.lastUpdated = new Date();
|
|
389
|
+
*
|
|
390
|
+
* await settingsProperty.set(context, settings);
|
|
391
|
+
* await userState.saveChanges(context);
|
|
392
|
+
* ```
|
|
393
|
+
*
|
|
394
|
+
* @example Custom key usage
|
|
395
|
+
* ```typescript
|
|
396
|
+
* const tenantKey = { key: `tenant_${tenantId}` };
|
|
397
|
+
* await dataProperty.set(context, updatedData, tenantKey);
|
|
398
|
+
* await userState.saveChanges(context);
|
|
399
|
+
* ```
|
|
169
400
|
*/
|
|
170
401
|
async set (context: TurnContext, value: T, customKey?: CustomKey): Promise<void> {
|
|
171
402
|
const obj: any = await this.state.load(context, false, customKey)
|
package/src/statusCodes.ts
CHANGED
|
@@ -3,69 +3,99 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* HTTP status codes enumeration for agent hosting responses.
|
|
8
|
+
*
|
|
9
|
+
* This enum provides a comprehensive set of HTTP status codes commonly used
|
|
10
|
+
* in agent hosting scenarios, including success, redirection, client error,
|
|
11
|
+
* and server error status codes.
|
|
12
|
+
*/
|
|
6
13
|
export enum StatusCodes {
|
|
7
14
|
/**
|
|
8
15
|
* The request has succeeded.
|
|
16
|
+
* Standard response for successful HTTP requests.
|
|
9
17
|
*/
|
|
10
18
|
OK = 200,
|
|
11
19
|
|
|
12
20
|
/**
|
|
13
21
|
* The request has been fulfilled and resulted in a new resource being created.
|
|
22
|
+
* Typically returned when a new agent, conversation, or resource is successfully created.
|
|
14
23
|
*/
|
|
15
24
|
CREATED = 201,
|
|
16
25
|
|
|
17
26
|
/**
|
|
18
27
|
* Indicates multiple options for the resource that the client may follow.
|
|
28
|
+
* Used when there are multiple possible responses or resource locations available.
|
|
19
29
|
*/
|
|
20
30
|
MULTIPLE_CHOICES = 300,
|
|
21
31
|
|
|
22
32
|
/**
|
|
23
33
|
* The server cannot or will not process the request due to a client error.
|
|
34
|
+
* Returned when the request contains invalid syntax, malformed parameters,
|
|
35
|
+
* or violates agent hosting protocol requirements.
|
|
24
36
|
*/
|
|
25
37
|
BAD_REQUEST = 400,
|
|
26
38
|
|
|
27
39
|
/**
|
|
28
40
|
* The request requires user authentication.
|
|
41
|
+
* Indicates that the client must authenticate itself to get the requested response.
|
|
42
|
+
* Common in agent scenarios requiring valid authentication tokens or credentials.
|
|
29
43
|
*/
|
|
30
44
|
UNAUTHORIZED = 401,
|
|
31
45
|
|
|
32
46
|
/**
|
|
33
47
|
* The requested resource could not be found.
|
|
48
|
+
* Returned when the specified agent, conversation, or endpoint does not exist
|
|
49
|
+
* or is not accessible with the current permissions.
|
|
34
50
|
*/
|
|
35
51
|
NOT_FOUND = 404,
|
|
36
52
|
|
|
37
53
|
/**
|
|
38
54
|
* The request method is not allowed for the requested resource.
|
|
55
|
+
* Indicates that the HTTP method used is not supported for the specific
|
|
56
|
+
* agent endpoint or resource being accessed.
|
|
39
57
|
*/
|
|
40
58
|
METHOD_NOT_ALLOWED = 405,
|
|
41
59
|
|
|
42
60
|
/**
|
|
43
61
|
* The request could not be completed due to a conflict with the current state of the resource.
|
|
62
|
+
* Common when attempting to create duplicate resources or when agent state
|
|
63
|
+
* conflicts prevent the operation from completing.
|
|
44
64
|
*/
|
|
45
65
|
CONFLICT = 409,
|
|
46
66
|
|
|
47
67
|
/**
|
|
48
68
|
* The server does not meet one of the preconditions specified by the client.
|
|
69
|
+
* Returned when conditional requests fail, such as when required headers
|
|
70
|
+
* or agent capabilities are not present or valid.
|
|
49
71
|
*/
|
|
50
72
|
PRECONDITION_FAILED = 412,
|
|
51
73
|
|
|
52
74
|
/**
|
|
53
75
|
* The client should switch to a different protocol.
|
|
76
|
+
* Used to indicate that the agent hosting service requires a protocol upgrade
|
|
77
|
+
* or different communication method to fulfill the request.
|
|
54
78
|
*/
|
|
55
79
|
UPGRADE_REQUIRED = 426,
|
|
56
80
|
|
|
57
81
|
/**
|
|
58
82
|
* The server encountered an unexpected condition that prevented it from fulfilling the request.
|
|
83
|
+
* Generic error message when an unexpected agent hosting error occurs
|
|
84
|
+
* and no more specific message is suitable.
|
|
59
85
|
*/
|
|
60
86
|
INTERNAL_SERVER_ERROR = 500,
|
|
61
87
|
|
|
62
88
|
/**
|
|
63
89
|
* The server does not support the functionality required to fulfill the request.
|
|
90
|
+
* Returned when the agent hosting service does not implement the requested
|
|
91
|
+
* feature or capability.
|
|
64
92
|
*/
|
|
65
93
|
NOT_IMPLEMENTED = 501,
|
|
66
94
|
|
|
67
95
|
/**
|
|
68
96
|
* The server received an invalid response from the upstream server.
|
|
97
|
+
* Common when agent hosting services depend on external services
|
|
98
|
+
* that return invalid or malformed responses.
|
|
69
99
|
*/
|
|
70
100
|
BAD_GATEWAY = 502,
|
|
71
101
|
}
|
|
@@ -1,10 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
import path from 'path'
|
|
2
7
|
import fs from 'fs'
|
|
3
8
|
import { Storage, StoreItem } from './storage'
|
|
4
9
|
|
|
10
|
+
/**
|
|
11
|
+
* A file-based storage implementation that persists data to the local filesystem.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* FileStorage stores all data in a single JSON file named 'state.json' within a specified folder.
|
|
15
|
+
* This implementation is suitable for development scenarios, local testing, and single-instance
|
|
16
|
+
* deployments where shared state across multiple instances is not required.
|
|
17
|
+
*
|
|
18
|
+
* The storage format is a simple key-value JSON object where keys are strings and values
|
|
19
|
+
* can be any JSON-serializable data. All operations are synchronous file I/O operations
|
|
20
|
+
* wrapped in Promise interfaces to match the Storage contract.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* const storage = new FileStorage('./data');
|
|
25
|
+
*
|
|
26
|
+
* // Write some data
|
|
27
|
+
* await storage.write({
|
|
28
|
+
* 'user123': { name: 'John', lastSeen: new Date().toISOString() },
|
|
29
|
+
* 'conversation456': { turn: 5, context: 'discussing weather' }
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // Read specific keys
|
|
33
|
+
* const data = await storage.read(['user123']);
|
|
34
|
+
* console.log(data.user123); // { name: 'John', lastSeen: '...' }
|
|
35
|
+
*
|
|
36
|
+
* // Delete data
|
|
37
|
+
* await storage.delete(['conversation456']);
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
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.
|
|
49
|
+
*/
|
|
5
50
|
export class FileStorage implements Storage {
|
|
6
51
|
private _folder: string
|
|
7
52
|
private _stateFile: Record<string, string>
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Creates a new FileStorage instance that stores data in the specified folder.
|
|
56
|
+
*
|
|
57
|
+
* @param folder The absolute or relative path to the folder where the state.json file will be stored
|
|
58
|
+
*
|
|
59
|
+
* @remarks
|
|
60
|
+
* The constructor performs the following initialization steps:
|
|
61
|
+
* 1. Creates the target folder if it doesn't exist (including parent directories)
|
|
62
|
+
* 2. Creates an empty state.json file if it doesn't exist
|
|
63
|
+
* 3. Loads existing data from state.json into memory for fast access
|
|
64
|
+
*
|
|
65
|
+
* @throws May throw filesystem errors if the folder cannot be created or accessed
|
|
66
|
+
*/
|
|
8
67
|
constructor (folder: string) {
|
|
9
68
|
this._folder = folder
|
|
10
69
|
if (!fs.existsSync(folder)) {
|
|
@@ -17,6 +76,19 @@ export class FileStorage implements Storage {
|
|
|
17
76
|
this._stateFile = JSON.parse(data)
|
|
18
77
|
}
|
|
19
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Reads store items from the filesystem storage.
|
|
81
|
+
*
|
|
82
|
+
* @param keys Array of keys to read from storage
|
|
83
|
+
* @returns Promise resolving to an object containing the requested items (keys that don't exist are omitted)
|
|
84
|
+
*
|
|
85
|
+
* @throws ReferenceError if keys array is empty or undefined
|
|
86
|
+
*
|
|
87
|
+
* @remarks
|
|
88
|
+
* This method reads from the in-memory cache that was loaded during construction,
|
|
89
|
+
* making it very fast but potentially returning stale data if the file was
|
|
90
|
+
* modified by external processes.
|
|
91
|
+
*/
|
|
20
92
|
read (keys: string[]) : Promise<StoreItem> {
|
|
21
93
|
return new Promise((resolve, reject) => {
|
|
22
94
|
if (!keys || keys.length === 0) {
|
|
@@ -34,6 +106,20 @@ export class FileStorage implements Storage {
|
|
|
34
106
|
})
|
|
35
107
|
}
|
|
36
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Writes store items to the filesystem storage.
|
|
111
|
+
*
|
|
112
|
+
* @param changes Object containing key-value pairs to write to storage
|
|
113
|
+
* @returns Promise that resolves when the write operation completes
|
|
114
|
+
*
|
|
115
|
+
* @remarks
|
|
116
|
+
* This method updates both the in-memory cache and writes the entire state
|
|
117
|
+
* to the state.json file. The file is written with pretty-printing (2-space indentation)
|
|
118
|
+
* for better readability during development and debugging.
|
|
119
|
+
*
|
|
120
|
+
* Note: This implementation does not support eTag-based optimistic concurrency control.
|
|
121
|
+
* Any eTag values in the changes object are ignored.
|
|
122
|
+
*/
|
|
37
123
|
write (changes: StoreItem) : Promise<void> {
|
|
38
124
|
const keys = Object.keys(changes)
|
|
39
125
|
for (const key of keys) {
|
|
@@ -43,6 +129,19 @@ export class FileStorage implements Storage {
|
|
|
43
129
|
return Promise.resolve()
|
|
44
130
|
}
|
|
45
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Deletes store items from the filesystem storage.
|
|
134
|
+
*
|
|
135
|
+
* @param keys Array of keys to delete from storage
|
|
136
|
+
* @returns Promise that resolves when the delete operation completes
|
|
137
|
+
*
|
|
138
|
+
* @throws ReferenceError if keys array is empty or undefined
|
|
139
|
+
*
|
|
140
|
+
* @remarks
|
|
141
|
+
* This method removes the specified keys from both the in-memory cache
|
|
142
|
+
* and writes the updated state to the state.json file. Keys that don't
|
|
143
|
+
* exist in storage are silently ignored.
|
|
144
|
+
*/
|
|
46
145
|
delete (keys: string[]) : Promise<void> {
|
|
47
146
|
return new Promise((resolve, reject) => {
|
|
48
147
|
if (!keys || keys.length === 0) {
|
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { Storage, StoreItem } from './storage'
|
|
7
|
-
import { debug } from '
|
|
7
|
+
import { debug } from '@microsoft/agents-activity/src/logger'
|
|
8
8
|
|
|
9
9
|
const logger = debug('agents:memory-storage')
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* A simple in-memory storage provider that implements the Storage interface.
|
|
13
13
|
*
|
|
14
|
+
* @remarks
|
|
14
15
|
* This class provides a volatile storage solution that keeps data in memory,
|
|
15
16
|
* which means data is lost when the process terminates. It's primarily useful for:
|
|
16
17
|
* - Development and testing scenarios
|
|
@@ -18,7 +19,7 @@ const logger = debug('agents:memory-storage')
|
|
|
18
19
|
* - Stateless environments where external storage isn't available
|
|
19
20
|
*
|
|
20
21
|
* MemoryStorage supports optimistic concurrency control through eTags and
|
|
21
|
-
* can be used as a singleton through the getSingleInstance() method to
|
|
22
|
+
* can be used as a singleton through the {@link MemoryStorage.getSingleInstance | getSingleInstance() method} to
|
|
22
23
|
* share state across different parts of an application.
|
|
23
24
|
*/
|
|
24
25
|
export class MemoryStorage implements Storage {
|
package/src/storage/storage.ts
CHANGED
|
@@ -48,6 +48,7 @@ export type StorageKeyFactory = (context: TurnContext) => string | Promise<strin
|
|
|
48
48
|
/**
|
|
49
49
|
* Defines the interface for storage operations in the Agents platform.
|
|
50
50
|
*
|
|
51
|
+
* @remarks
|
|
51
52
|
* Storage providers persist state data across conversation turns, enabling
|
|
52
53
|
* agents to maintain context over time. Different implementations may store
|
|
53
54
|
* data in memory, databases, blob storage, or other persistence mechanisms.
|
|
@@ -3,7 +3,7 @@ import { ResourceResponse } from '../connector-client'
|
|
|
3
3
|
import { Middleware } from '../middlewareSet'
|
|
4
4
|
import { TranscriptLogger } from './transcriptLogger'
|
|
5
5
|
import { Activity, ActivityEventNames, ActivityTypes, ConversationReference, RoleTypes } from '@microsoft/agents-activity'
|
|
6
|
-
import { debug } from '
|
|
6
|
+
import { debug } from '@microsoft/agents-activity/src/logger'
|
|
7
7
|
|
|
8
8
|
const appLogger = debug('agents:rest-client')
|
|
9
9
|
|
package/src/turnContext.ts
CHANGED
|
@@ -51,6 +51,7 @@ export interface TurnContext {}
|
|
|
51
51
|
/**
|
|
52
52
|
* Represents the context for a single turn in a conversation between a user and an agent.
|
|
53
53
|
*
|
|
54
|
+
* @remarks
|
|
54
55
|
* TurnContext is a central concept in the Agents framework - it contains:
|
|
55
56
|
* - The incoming activity that started the turn
|
|
56
57
|
* - Access to the adapter that can be used to send responses
|