AgentStatePropertyAccessor class
Provides typed access to an Agent state property with automatic state loading and persistence management.
Example
Basic Usage
// Create a property accessor
const userProfile = userState.createProperty<UserProfile>("userProfile");
// Get with default value
const profile = await userProfile.get(context, {
name: "",
preferences: { theme: "light", language: "en" }
});
// Modify the profile
profile.preferences.theme = "dark";
// Save the changes
await userProfile.set(context, profile);
await userState.saveChanges(context); // Persist to storage
Example
Working with Primitive Types
const counterProperty = userState.createProperty<number>("counter");
// Increment counter
const currentCount = await counterProperty.get(context, 0);
await counterProperty.set(context, currentCount + 1);
await userState.saveChanges(context);
Example
Conditional Logic
const settingsProperty = userState.createProperty<Settings>("settings");
// Check if property exists
const settings = await settingsProperty.get(context);
if (settings === undefined) {
// Property doesn't exist, initialize with defaults
await settingsProperty.set(context, getDefaultSettings());
}
Example
Custom Storage Keys
// Store state with a custom key for multi-tenant scenarios
const customKey = { key: `tenant_${tenantId}` };
const tenantData = await dataProperty.get(context, defaultData, customKey);
await dataProperty.set(context, updatedData, customKey);
Important Notes
- Thread Safety: This class is not thread-safe. Ensure proper synchronization in concurrent scenarios.
- Memory Usage: State objects are kept in memory until the context is disposed.
- Persistence: Always call
state.saveChanges(context)to persist changes to storage. - Deep Cloning: Default values are deep cloned using JSON serialization, which may not work with complex objects containing functions or circular references.
See createProperty for creating property accessors See StatePropertyAccessor for the interface definition
Remarks
AgentStatePropertyAccessor simplifies working with persisted state by abstracting
the complexity of loading state from storage and manipulating specific properties.
It provides a type-safe interface for state management with automatic handling of:
- Lazy Loading: State is loaded from storage only when first accessed
- Type Safety: Full TypeScript support with generic type parameters
- Default Values: Automatic deep cloning of default values to prevent reference issues
- Memory Management: Efficient in-memory caching with explicit persistence control
- Custom Keys: Support for custom storage keys for advanced scenarios
Key Features
Key features of AgentStatePropertyAccessor include:
Type Safety
The accessor provides compile-time type checking when using TypeScript:
interface UserProfile {
name: string;
preferences: { theme: string; language: string };
}
const userProfile = userState.createProperty<UserProfile>("userProfile");
Automatic Default Value Handling
When a property doesn't exist, default values are automatically cloned and stored:
// If userProfile doesn't exist, the default will be cloned and saved
const profile = await userProfile.get(context, {
name: "Anonymous",
preferences: { theme: "light", language: "en" }
});
Explicit Persistence Control
Changes are kept in memory until explicitly persisted:
// Modify the state
const counter = await counterProperty.get(context, 0);
await counterProperty.set(context, counter + 1);
// Changes are only in memory at this point
// Persist to storage
await userState.saveChanges(context);
Usage Examples
Constructors
| Agent |
Creates a new instance of AgentStatePropertyAccessor. Example
|
Properties
| name |
Methods
| delete(Turn |
Deletes the property from the state storage. Example Basic usage
Example Custom key usage
|
| get(Turn |
Retrieves the value of the property from state storage. Example Basic usage
Example Complex object with default
Example Checking for existence
Example Custom key usage
|
| set(Turn |
Sets the value of the property in state storage. Example Basic usage
Example Complex object
Example Incremental updates
Example Custom key usage
|
Constructor Details
AgentStatePropertyAccessor<T>(AgentState, string)
Creates a new instance of AgentStatePropertyAccessor.
Example
// Recommended way - use AgentState.createProperty
const userProfile = userState.createProperty<UserProfile>("userProfile");
// Direct construction (not recommended)
const accessor = new AgentStatePropertyAccessor<UserProfile>(userState, "userProfile");
new AgentStatePropertyAccessor(state: AgentState, name: string)
Parameters
- state
- AgentState
The agent state object that manages the backing storage for this property
- name
-
string
The unique name of the property within the state object. This name is used as the key in the state storage.
Remarks
This constructor is typically not called directly. Instead, use createProperty to create property accessors, which ensures proper integration with the state management system.
Property Details
name
name: string
Property Value
string
Method Details
delete(TurnContext, CustomKey)
Deletes the property from the state storage.
Example
Basic usage
const userSettings = userState.createProperty<UserSettings>("settings");
// Delete the user settings
await userSettings.delete(context);
// Persist the deletion to storage
await userState.saveChanges(context);
// Verify deletion
const settings = await userSettings.get(context); // Returns undefined
Example
Custom key usage
const tenantKey = { key: `tenant_${tenantId}` };
await userSettings.delete(context, tenantKey);
await userState.saveChanges(context);
function delete(context: TurnContext, customKey?: CustomKey): Promise<void>
Parameters
- context
- TurnContext
The turn context for the current conversation turn
- customKey
- CustomKey
Optional custom key for accessing state in a specific storage location. Useful for multi-tenant scenarios or when state needs to be partitioned.
Returns
Promise<void>
A promise that resolves when the delete operation is complete
Remarks
This operation removes the property from the in-memory state object but does not
automatically persist the change to the underlying storage. You must call
state.saveChanges(context) afterwards to persist the deletion.
- If the property doesn't exist, this operation is a no-op
- The deletion only affects the in-memory state until
saveChanges()is called - After deletion, subsequent
get()calls will returnundefined(or the default value if provided)
get(TurnContext, T, CustomKey)
Retrieves the value of the property from state storage.
Example
Basic usage
const counterProperty = userState.createProperty<number>("counter");
// Get with default value
const count = await counterProperty.get(context, 0);
console.log(count); // 0 if property doesn't exist, otherwise the stored value
Example
Complex object with default
interface UserProfile {
name: string;
preferences: { theme: string; notifications: boolean };
}
const userProfile = userState.createProperty<UserProfile>("profile");
const profile = await userProfile.get(context, {
name: "Anonymous",
preferences: { theme: "light", notifications: true }
});
Example
Checking for existence
const profile = await userProfile.get(context);
if (profile === undefined) {
console.log("Profile has not been set yet");
} else {
console.log(`Welcome back, ${profile.name}!`);
}
Example
Custom key usage
const tenantKey = { key: `tenant_${tenantId}` };
const tenantData = await dataProperty.get(context, defaultData, tenantKey);
function get(context: TurnContext, defaultValue?: T, customKey?: CustomKey): Promise<T>
Parameters
- context
- TurnContext
The turn context for the current conversation turn
- defaultValue
-
T
Optional default value to use if the property doesn't exist. When provided, this value is deep cloned and stored in state.
- customKey
- CustomKey
Optional custom key for accessing state in a specific storage location. Useful for multi-tenant scenarios or when state needs to be partitioned.
Returns
Promise<T>
A promise that resolves to the property value, the cloned default value, or undefined
Remarks
This method provides intelligent default value handling:
- If the property exists, its value is returned
- If the property doesn't exist and a default value is provided, the default is deep cloned, stored in state, and returned
- If the property doesn't exist and no default is provided,
undefinedis returned
Deep Cloning: Default values are deep cloned using JSON serialization to prevent reference sharing issues. This means:
- Functions, symbols, and circular references will be lost
- Dates become strings (use Date constructor to restore)
- Complex objects with prototypes lose their prototype chain
Performance: The first access loads state from storage; subsequent accesses use the in-memory cached version until the context is disposed.
set(TurnContext, T, CustomKey)
Sets the value of the property in state storage.
Example
Basic usage
const counterProperty = userState.createProperty<number>("counter");
// Set a new value
await counterProperty.set(context, 42);
// Persist to storage
await userState.saveChanges(context);
Example
Complex object
const userProfile = userState.createProperty<UserProfile>("profile");
const newProfile: UserProfile = {
name: "John Doe",
preferences: { theme: "dark", notifications: false }
};
await userProfile.set(context, newProfile);
await userState.saveChanges(context);
Example
Incremental updates
// Get current value, modify, then set
const settings = await settingsProperty.get(context, getDefaultSettings());
settings.theme = "dark";
settings.lastUpdated = new Date();
await settingsProperty.set(context, settings);
await userState.saveChanges(context);
Example
Custom key usage
const tenantKey = { key: `tenant_${tenantId}` };
await dataProperty.set(context, updatedData, tenantKey);
await userState.saveChanges(context);
function set(context: TurnContext, value: T, customKey?: CustomKey): Promise<void>
Parameters
- context
- TurnContext
The turn context for the current conversation turn
- value
-
T
The value to assign to the property. Can be any serializable value.
- customKey
- CustomKey
Optional custom key for accessing state in a specific storage location. Useful for multi-tenant scenarios or when state needs to be partitioned.
Returns
Promise<void>
A promise that resolves when the set operation is complete
Remarks
This operation updates the property in the in-memory state object but does not
automatically persist the change to the underlying storage. You must call
state.saveChanges(context) afterwards to persist the changes.
Memory vs Storage: Changes are immediately reflected in memory and will be
available to subsequent get() calls within the same context, but are not
persisted to storage until saveChanges() is called.
Value References: The exact value reference is stored (no cloning occurs). Ensure you don't modify objects after setting them unless you intend for those changes to be reflected in state.
Type Safety: When using TypeScript, the value must match the property's declared type parameter.