@microsoft/agents-hosting 0.2.10-g3ac88ff25e → 0.2.14

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 (70) hide show
  1. package/dist/src/activityHandler.d.ts +304 -46
  2. package/dist/src/activityHandler.js +298 -45
  3. package/dist/src/activityHandler.js.map +1 -1
  4. package/dist/src/agent-client/agentClient.d.ts +50 -0
  5. package/dist/src/agent-client/agentClient.js +28 -0
  6. package/dist/src/agent-client/agentClient.js.map +1 -1
  7. package/dist/src/app/agentApplication.d.ts +256 -3
  8. package/dist/src/app/agentApplication.js +256 -0
  9. package/dist/src/app/agentApplication.js.map +1 -1
  10. package/dist/src/app/agentApplicationBuilder.d.ts +32 -0
  11. package/dist/src/app/agentApplicationBuilder.js +32 -0
  12. package/dist/src/app/agentApplicationBuilder.js.map +1 -1
  13. package/dist/src/app/appMemory.d.ts +34 -0
  14. package/dist/src/app/{memory.js → appMemory.js} +1 -1
  15. package/dist/src/app/appMemory.js.map +1 -0
  16. package/dist/src/app/index.d.ts +3 -0
  17. package/dist/src/app/index.js +3 -0
  18. package/dist/src/app/index.js.map +1 -1
  19. package/dist/src/app/turnEvents.d.ts +6 -0
  20. package/dist/src/app/turnState.d.ts +2 -2
  21. package/dist/src/app/turnStateEntry.d.ts +32 -0
  22. package/dist/src/app/turnStateEntry.js +32 -0
  23. package/dist/src/app/turnStateEntry.js.map +1 -1
  24. package/dist/src/cards/index.d.ts +1 -0
  25. package/dist/src/cards/index.js +1 -0
  26. package/dist/src/cards/index.js.map +1 -1
  27. package/dist/src/cloudAdapter.d.ts +25 -3
  28. package/dist/src/cloudAdapter.js +25 -3
  29. package/dist/src/cloudAdapter.js.map +1 -1
  30. package/dist/src/getProductInfo.d.ts +6 -0
  31. package/dist/src/getProductInfo.js +6 -0
  32. package/dist/src/getProductInfo.js.map +1 -1
  33. package/dist/src/logger.d.ts +34 -2
  34. package/dist/src/logger.js +35 -0
  35. package/dist/src/logger.js.map +1 -1
  36. package/dist/src/state/agentState.d.ts +79 -27
  37. package/dist/src/state/agentState.js +58 -27
  38. package/dist/src/state/agentState.js.map +1 -1
  39. package/dist/src/state/agentStatePropertyAccesor.d.ts +67 -11
  40. package/dist/src/state/agentStatePropertyAccesor.js +58 -11
  41. package/dist/src/state/agentStatePropertyAccesor.js.map +1 -1
  42. package/dist/src/storage/memoryStorage.d.ts +48 -14
  43. package/dist/src/storage/memoryStorage.js +48 -14
  44. package/dist/src/storage/memoryStorage.js.map +1 -1
  45. package/dist/src/storage/storage.d.ts +43 -13
  46. package/dist/src/turnContext.d.ts +142 -56
  47. package/dist/src/turnContext.js +123 -53
  48. package/dist/src/turnContext.js.map +1 -1
  49. package/package.json +5 -5
  50. package/src/activityHandler.ts +304 -46
  51. package/src/agent-client/agentClient.ts +55 -5
  52. package/src/app/agentApplication.ts +259 -2
  53. package/src/app/agentApplicationBuilder.ts +32 -0
  54. package/src/app/appMemory.ts +38 -0
  55. package/src/app/index.ts +3 -0
  56. package/src/app/turnEvents.ts +6 -0
  57. package/src/app/turnState.ts +2 -2
  58. package/src/app/turnStateEntry.ts +32 -0
  59. package/src/cards/index.ts +1 -0
  60. package/src/cloudAdapter.ts +28 -3
  61. package/src/getProductInfo.ts +7 -0
  62. package/src/logger.ts +34 -1
  63. package/src/state/agentState.ts +81 -29
  64. package/src/state/agentStatePropertyAccesor.ts +67 -11
  65. package/src/storage/memoryStorage.ts +48 -14
  66. package/src/storage/storage.ts +51 -18
  67. package/src/turnContext.ts +142 -56
  68. package/dist/src/app/memory.d.ts +0 -10
  69. package/dist/src/app/memory.js.map +0 -1
  70. package/src/app/memory.ts +0 -14
package/src/logger.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  import createDebug, { Debugger } from 'debug'
2
2
 
3
- class Logger {
3
+ /**
4
+ * Logger class that provides colored logging functionality using the debug package.
5
+ * Supports different log levels: info, warn, error, and debug.
6
+ */
7
+ export class Logger {
4
8
  private loggers: { [level: string]: Debugger } = {}
5
9
  private readonly levelColors: { [level: string]: string } = {
6
10
  info: '2', // Green
@@ -9,6 +13,10 @@ class Logger {
9
13
  debug: '4' // Blue
10
14
  }
11
15
 
16
+ /**
17
+ * Creates a new Logger instance with the specified namespace.
18
+ * @param namespace The namespace to use for the logger
19
+ */
12
20
  constructor (namespace: string = '') {
13
21
  this.initializeLoggers(namespace)
14
22
  }
@@ -21,23 +29,48 @@ class Logger {
21
29
  }
22
30
  }
23
31
 
32
+ /**
33
+ * Logs an informational message.
34
+ * @param message The message to log
35
+ * @param args Additional arguments to include in the log
36
+ */
24
37
  info (message: string, ...args: any[]) {
25
38
  this.loggers.info(message, ...args)
26
39
  }
27
40
 
41
+ /**
42
+ * Logs a warning message.
43
+ * @param message The message to log
44
+ * @param args Additional arguments to include in the log
45
+ */
28
46
  warn (message: string, ...args: any[]) {
29
47
  this.loggers.warn(message, ...args)
30
48
  }
31
49
 
50
+ /**
51
+ * Logs an error message.
52
+ * @param message The message to log
53
+ * @param args Additional arguments to include in the log
54
+ */
32
55
  error (message: string, ...args: any[]) {
33
56
  this.loggers.error(message, ...args)
34
57
  }
35
58
 
59
+ /**
60
+ * Logs a debug message.
61
+ * @param message The message to log
62
+ * @param args Additional arguments to include in the log
63
+ */
36
64
  debug (message: string, ...args: any[]) {
37
65
  this.loggers.debug(message, ...args)
38
66
  }
39
67
  }
40
68
 
69
+ /**
70
+ * Creates a new Logger instance with the specified namespace.
71
+ * @param namespace The namespace to use for the logger
72
+ * @returns A new Logger instance
73
+ */
41
74
  export function debug (namespace: string): Logger {
42
75
  return new Logger(namespace)
43
76
  }
@@ -11,34 +11,63 @@ import { debug } from '../logger'
11
11
 
12
12
  const logger = debug('agents:state')
13
13
 
14
+ /**
15
+ * Represents agent state that has been cached in the turn context.
16
+ * Used internally to track state changes and avoid unnecessary storage operations.
17
+ */
14
18
  export interface CachedAgentState {
15
- state: { [id: string]: any }
16
- hash: string
19
+ /**
20
+ * The state object containing all properties and their values
21
+ */
22
+ state: { [id: string]: any };
23
+ /**
24
+ * Hash of the state used to detect changes
25
+ */
26
+ hash: string;
17
27
  }
18
28
 
29
+ /**
30
+ * Represents a custom key for storing state in a specific location.
31
+ * Allows state to be persisted with channel and conversation identifiers
32
+ * independent of the current context.
33
+ */
19
34
  export interface CustomKey {
35
+ /**
36
+ * The ID of the channel where the state should be stored
37
+ */
20
38
  channelId: string;
39
+ /**
40
+ * The ID of the conversation where the state should be stored
41
+ */
21
42
  conversationId: string;
22
43
  // TODO: namespace needs to be added
23
44
  }
24
45
 
25
46
  /**
26
- * Manages the state of an Agent.
47
+ * Manages the state of an Agent across turns in a conversation.
48
+ *
49
+ * AgentState provides functionality to persist and retrieve state data using
50
+ * a storage provider. It handles caching state in the turn context for performance,
51
+ * calculating change hashes to detect modifications, and managing property accessors
52
+ * for typed access to state properties.
27
53
  */
28
54
  export class AgentState {
29
55
  private readonly stateKey = Symbol('state')
30
56
 
31
57
  /**
32
- * Creates a new instance of AgentState.
33
- * @param storage The storage provider.
34
- * @param storageKey The storage key factory.
35
- */
58
+ * Creates a new instance of AgentState.
59
+ *
60
+ * @param storage The storage provider used to persist state between turns
61
+ * @param storageKey A factory function that generates keys for storing state data
62
+ */
36
63
  constructor (protected storage: Storage, protected storageKey: StorageKeyFactory) { }
37
64
 
38
65
  /**
39
66
  * Creates a property accessor for the specified property.
40
- * @param name The name of the property.
41
- * @returns A property accessor for the specified property.
67
+ * Property accessors provide typed access to properties within the state object.
68
+ *
69
+ * @param name The name of the property to access
70
+ * @returns A property accessor for the specified property
42
71
  */
43
72
  createProperty<T = any>(name: string): AgentStatePropertyAccessor<T> {
44
73
  const prop: AgentStatePropertyAccessor<T> = new AgentStatePropertyAccessor<T>(this, name)
@@ -46,10 +75,13 @@ export class AgentState {
46
75
  }
47
76
 
48
77
  /**
49
- * Loads the state from storage.
50
- * @param context The turn context.
51
- * @param force Whether to force loading the state.
52
- * @returns A promise that resolves to the loaded state.
78
+ * Loads the state from storage into the turn context.
79
+ * If state is already cached in the turn context and force is not set, the cached version will be used.
80
+ *
81
+ * @param context The turn context to load state into
82
+ * @param force If true, forces a reload from storage even if state is cached
83
+ * @param customKey Optional custom storage key to use instead of the default
84
+ * @returns A promise that resolves to the loaded state object
53
85
  */
54
86
  public async load (context: TurnContext, force = false, customKey?: CustomKey): Promise<any> {
55
87
  const cached: CachedAgentState = context.turnState.get(this.stateKey)
@@ -70,10 +102,13 @@ export class AgentState {
70
102
  }
71
103
 
72
104
  /**
73
- * Saves the state to storage.
74
- * @param context The turn context.
75
- * @param force Whether to force saving the state.
76
- * @returns A promise that resolves when the save operation is complete.
105
+ * Saves the state to storage if it has changed since it was loaded.
106
+ * Change detection uses a hash of the state object to determine if saving is necessary.
107
+ *
108
+ * @param context The turn context containing the state to save
109
+ * @param force If true, forces a save to storage even if no changes are detected
110
+ * @param customKey Optional custom storage key to use instead of the default
111
+ * @returns A promise that resolves when the save operation is complete
77
112
  */
78
113
  public async saveChanges (context: TurnContext, force = false, customKey?: CustomKey): Promise<void> {
79
114
  let cached: CachedAgentState = context.turnState.get(this.stateKey)
@@ -95,6 +130,14 @@ export class AgentState {
95
130
  }
96
131
  }
97
132
 
133
+ /**
134
+ * Determines whether to use a custom key or generate one from the context.
135
+ *
136
+ * @param customKey Optional custom key with channel and conversation IDs
137
+ * @param context The turn context used to generate a key if no custom key is provided
138
+ * @returns The storage key to use
139
+ * @private
140
+ */
98
141
  private async getStorageOrCustomKey (customKey: CustomKey | undefined, context: TurnContext) {
99
142
  let key: string | undefined
100
143
  if (customKey && customKey.channelId && customKey.conversationId) {
@@ -107,9 +150,12 @@ export class AgentState {
107
150
  }
108
151
 
109
152
  /**
110
- * Clears the state from the turn context.
111
- * @param context The turn context.
112
- * @returns A promise that resolves when the clear operation is complete.
153
+ * Clears the state by setting it to an empty object in the turn context.
154
+ * Note: This does not remove the state from storage, it only clears the in-memory representation.
155
+ * Call saveChanges() after this to persist the empty state to storage.
156
+ *
157
+ * @param context The turn context containing the state to clear
158
+ * @returns A promise that resolves when the clear operation is complete
113
159
  */
114
160
  public async clear (context: TurnContext): Promise<void> {
115
161
  const emptyObjectToForceSave = { state: {}, hash: '' }
@@ -118,9 +164,11 @@ export class AgentState {
118
164
  }
119
165
 
120
166
  /**
121
- * Deletes the state from storage.
122
- * @param context The turn context.
123
- * @returns A promise that resolves when the delete operation is complete.
167
+ * Deletes the state from both the turn context and storage.
168
+ *
169
+ * @param context The turn context containing the state to delete
170
+ * @param customKey Optional custom storage key to use instead of the default
171
+ * @returns A promise that resolves when the delete operation is complete
124
172
  */
125
173
  public async delete (context: TurnContext, customKey?: CustomKey): Promise<void> {
126
174
  if (context.turnState.has(this.stateKey)) {
@@ -132,9 +180,10 @@ export class AgentState {
132
180
  }
133
181
 
134
182
  /**
135
- * Gets the state from the turn context.
136
- * @param context The turn context.
137
- * @returns The state, or undefined if the state is not found.
183
+ * Gets the state from the turn context without loading it from storage.
184
+ *
185
+ * @param context The turn context containing the state to get
186
+ * @returns The state object, or undefined if no state is found in the turn context
138
187
  */
139
188
  public get (context: TurnContext): any | undefined {
140
189
  const cached: CachedAgentState = context.turnState.get(this.stateKey)
@@ -143,9 +192,12 @@ export class AgentState {
143
192
  }
144
193
 
145
194
  /**
146
- * Calculates the change hash for the specified item.
147
- * @param item The item to calculate the hash for.
148
- * @returns The calculated hash.
195
+ * Calculates a hash for the specified state object to detect changes.
196
+ * The eTag property is excluded from the hash calculation.
197
+ *
198
+ * @param item The state object to calculate the hash for
199
+ * @returns A string hash representing the state
200
+ * @private
149
201
  */
150
202
  private readonly calculateChangeHash = (item: StoreItem): string => {
151
203
  const { eTag, ...rest } = item
@@ -6,6 +6,15 @@
6
6
  import { TurnContext } from '../turnContext'
7
7
  import { AgentState, CustomKey } from './agentState'
8
8
 
9
+ /**
10
+ * Interface for accessing a property in state storage with type safety.
11
+ *
12
+ * The interface defines standard methods for working with persisted state properties,
13
+ * allowing property access with strong typing to reduce errors when working with
14
+ * complex state objects.
15
+ *
16
+ * @typeParam T The type of the property being accessed
17
+ */
9
18
  export interface StatePropertyAccessor<T = any> {
10
19
  /**
11
20
  * Deletes the persisted property from its backing storage object.
@@ -64,20 +73,56 @@ export interface StatePropertyAccessor<T = any> {
64
73
  }
65
74
 
66
75
  /**
67
- * Provides access to an Agent state property.
76
+ * Provides typed access to an Agent state property with automatic state loading.
77
+ *
78
+ * The AgentStatePropertyAccessor simplifies working with state by abstracting
79
+ * the details of loading state from storage and manipulating specific properties.
80
+ * It automatically handles:
81
+ *
82
+ * - Loading state when needed
83
+ * - Deep cloning of default values to prevent reference issues
84
+ * - Type checking for properties (when using TypeScript)
85
+ * - Ensuring properties exist before access
86
+ *
87
+ * Property accessors are created through the AgentState.createProperty() method:
88
+ *
89
+ * ```typescript
90
+ * // Create a property accessor for a user profile
91
+ * const userProfile = userState.createProperty<UserProfile>("userProfile");
92
+ *
93
+ * // Get the profile with a default if not exists
94
+ * const profile = await userProfile.get(context, { name: "", preferences: {} });
95
+ *
96
+ * // Update a value
97
+ * profile.preferences.theme = "dark";
98
+ *
99
+ * // Save the change
100
+ * await userProfile.set(context, profile);
101
+ *
102
+ * // Later, call userState.saveChanges(context) to persist to storage
103
+ * ```
104
+ *
105
+ * @typeParam T The type of the property being accessed
68
106
  */
69
107
  export class AgentStatePropertyAccessor<T = any> implements StatePropertyAccessor<T> {
70
108
  /**
71
109
  * Creates a new instance of AgentStatePropertyAccessor.
72
- * @param state The agent state.
73
- * @param name The name of the property.
110
+ *
111
+ * @param state The agent state object that will contain this property
112
+ * @param name The name of the property in the state object
74
113
  */
75
114
  constructor (protected readonly state: AgentState, public readonly name: string) { }
76
115
 
77
116
  /**
78
117
  * Deletes the property from the state.
79
- * @param context The turn context.
80
- * @returns A promise that resolves when the delete operation is complete.
118
+ *
119
+ * This removes the property from the state object but does not automatically
120
+ * persist the change to storage. Call state.saveChanges() afterwards to
121
+ * persist changes.
122
+ *
123
+ * @param context The turn context
124
+ * @param customKey Optional custom key for storing the state in a specific location
125
+ * @returns A promise that resolves when the delete operation is complete
81
126
  */
82
127
  async delete (context: TurnContext, customKey?: CustomKey): Promise<void> {
83
128
  const obj: any = await this.state.load(context, false, customKey)
@@ -88,9 +133,15 @@ export class AgentStatePropertyAccessor<T = any> implements StatePropertyAccesso
88
133
 
89
134
  /**
90
135
  * Gets the value of the property from the state.
91
- * @param context The turn context.
92
- * @param defaultValue The default value to return if the property is not found.
93
- * @returns A promise that resolves to the value of the property.
136
+ *
137
+ * If the property doesn't exist and a default value is provided, a deep clone
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.
140
+ *
141
+ * @param context The turn context
142
+ * @param defaultValue Optional default value to use if the property doesn't exist
143
+ * @param customKey Optional custom key for storing the state in a specific location
144
+ * @returns A promise that resolves to the value of the property or undefined
94
145
  */
95
146
  async get (context: TurnContext, defaultValue?: T, customKey?: CustomKey): Promise<T> {
96
147
  const obj: any = await this.state.load(context, false, customKey)
@@ -107,9 +158,14 @@ export class AgentStatePropertyAccessor<T = any> implements StatePropertyAccesso
107
158
 
108
159
  /**
109
160
  * Sets the value of the property in the state.
110
- * @param context The turn context.
111
- * @param value The value to set.
112
- * @returns A promise that resolves when the set operation is complete.
161
+ *
162
+ * This updates the property in the in-memory state object but does not automatically
163
+ * persist the change to storage. Call state.saveChanges() afterwards to persist changes.
164
+ *
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
+ * @returns A promise that resolves when the set operation is complete
113
169
  */
114
170
  async set (context: TurnContext, value: T, customKey?: CustomKey): Promise<void> {
115
171
  const obj: any = await this.state.load(context, false, customKey)
@@ -9,20 +9,39 @@ import { debug } from '../logger'
9
9
  const logger = debug('agents:memory-storage')
10
10
 
11
11
  /**
12
- * A simple in-memory storage provider.
12
+ * A simple in-memory storage provider that implements the Storage interface.
13
+ *
14
+ * This class provides a volatile storage solution that keeps data in memory,
15
+ * which means data is lost when the process terminates. It's primarily useful for:
16
+ * - Development and testing scenarios
17
+ * - Simple applications that don't require data persistence across restarts
18
+ * - Stateless environments where external storage isn't available
19
+ *
20
+ * MemoryStorage supports optimistic concurrency control through eTags and
21
+ * can be used as a singleton through the getSingleInstance() method to
22
+ * share state across different parts of an application.
13
23
  */
14
24
  export class MemoryStorage implements Storage {
15
25
  private static instance: MemoryStorage
26
+ /**
27
+ * Counter used to generate unique eTags for stored items
28
+ */
16
29
  private etag: number = 1
17
30
 
18
31
  /**
19
32
  * Creates a new instance of the MemoryStorage class.
20
- * @param memory An optional initial memory store.
33
+ *
34
+ * @param memory An optional initial memory store to seed the storage with data
21
35
  */
22
36
  constructor (private memory: { [k: string]: string } = {}) { }
23
37
 
24
38
  /**
25
- * Gets a single instance of the MemoryStorage class.
39
+ * Gets a single shared instance of the MemoryStorage class.
40
+ *
41
+ * Using this method ensures that the same storage instance is used across
42
+ * the application, allowing for shared state without passing references.
43
+ *
44
+ * @returns The singleton instance of MemoryStorage
26
45
  */
27
46
  static getSingleInstance (): MemoryStorage {
28
47
  if (!MemoryStorage.instance) {
@@ -33,9 +52,10 @@ export class MemoryStorage implements Storage {
33
52
 
34
53
  /**
35
54
  * Reads storage items from memory.
36
- * @param keys The keys of the items to read.
37
- * @returns A promise that resolves to the read items.
38
- * @throws Will throw an error if keys are not provided.
55
+ *
56
+ * @param keys The keys of the items to read
57
+ * @returns A promise that resolves to the read items
58
+ * @throws Will throw an error if keys are not provided or the array is empty
39
59
  */
40
60
  async read (keys: string[]): Promise<StoreItem> {
41
61
  if (!keys || keys.length === 0) {
@@ -56,9 +76,15 @@ export class MemoryStorage implements Storage {
56
76
 
57
77
  /**
58
78
  * Writes storage items to memory.
59
- * @param changes The items to write.
60
- * @returns A promise that resolves when the write operation is complete.
61
- * @throws Will throw an error if changes are not provided.
79
+ *
80
+ * This method supports optimistic concurrency control through eTags.
81
+ * If an item has an eTag, it will only be updated if the existing item
82
+ * has the same eTag. If an item has an eTag of '*' or no eTag, it will
83
+ * always be written regardless of the current state.
84
+ *
85
+ * @param changes The items to write, indexed by key
86
+ * @returns A promise that resolves when the write operation is complete
87
+ * @throws Will throw an error if changes are not provided or if there's an eTag conflict
62
88
  */
63
89
  async write (changes: StoreItem): Promise<void> {
64
90
  if (!changes || changes.length === 0) {
@@ -83,8 +109,9 @@ export class MemoryStorage implements Storage {
83
109
 
84
110
  /**
85
111
  * Deletes storage items from memory.
86
- * @param keys The keys of the items to delete.
87
- * @returns A promise that resolves when the delete operation is complete.
112
+ *
113
+ * @param keys The keys of the items to delete
114
+ * @returns A promise that resolves when the delete operation is complete
88
115
  */
89
116
  async delete (keys: string[]): Promise<void> {
90
117
  logger.info(`Deleting keys: ${keys.join(', ')}`)
@@ -94,9 +121,16 @@ export class MemoryStorage implements Storage {
94
121
  }
95
122
 
96
123
  /**
97
- * Saves an item to memory.
98
- * @param key The key of the item to save.
99
- * @param item The item to save.
124
+ * Saves an item to memory with a new eTag.
125
+ *
126
+ * This private method handles the details of:
127
+ * - Creating a clone of the item to prevent modification of the original
128
+ * - Generating a new eTag for optimistic concurrency control
129
+ * - Converting the item to a JSON string for storage
130
+ *
131
+ * @param key The key of the item to save
132
+ * @param item The item to save
133
+ * @private
100
134
  */
101
135
  private saveItem (key: string, item: unknown): void {
102
136
  const clone = Object.assign({}, item, { eTag: (this.etag++).toString() })
@@ -6,47 +6,80 @@
6
6
  import { TurnContext } from '../turnContext'
7
7
 
8
8
  /**
9
- * Represents an item to be stored.
9
+ * Represents an item to be stored in a storage provider.
10
+ * Each item can contain arbitrary data along with an optional eTag for optimistic concurrency control.
10
11
  */
11
12
  export interface StoreItem {
12
- eTag?: string
13
- [key: string]: any
13
+ /**
14
+ * Optional eTag used for optimistic concurrency control.
15
+ * When set to '*', it indicates that the write should proceed regardless of existing data.
16
+ * When comparing eTags, exact string matching is used to determine if data has changed.
17
+ */
18
+ eTag?: string;
19
+
20
+ /**
21
+ * Additional properties can be stored in the item.
22
+ * Each storage provider may have specific requirements or limitations on property names and values.
23
+ */
24
+ [key: string]: any;
14
25
  }
15
26
 
16
27
  /**
17
- * Represents a collection of store items.
28
+ * Represents a collection of store items indexed by key.
29
+ * Used as the return type for storage read operations.
18
30
  */
19
31
  export interface StoreItems {
32
+ /**
33
+ * Keys are the storage item identifiers, and values are the stored items.
34
+ * If a requested key is not found during a read operation, it will not appear in this collection.
35
+ */
20
36
  [key: string]: any;
21
37
  }
22
38
 
23
39
  /**
24
- * A factory function to generate storage keys based on the context.
25
- * @param context The TurnContext for the current turn of conversation.
26
- * @returns A string key for storage.
40
+ * A factory function to generate storage keys based on the conversation context.
41
+ * Allows different storage strategies based on the conversation state.
42
+ *
43
+ * @param context The TurnContext for the current turn of conversation
44
+ * @returns A string key for storage that uniquely identifies where to store the data
27
45
  */
28
- export type StorageKeyFactory = (context: TurnContext) => string
46
+ export type StorageKeyFactory = (context: TurnContext) => string | Promise<string>
29
47
 
30
48
  /**
31
- * Defines the interface for storage operations.
49
+ * Defines the interface for storage operations in the Agents platform.
50
+ *
51
+ * Storage providers persist state data across conversation turns, enabling
52
+ * agents to maintain context over time. Different implementations may store
53
+ * data in memory, databases, blob storage, or other persistence mechanisms.
54
+ *
55
+ * The interface is designed to be simple with just three core operations:
56
+ * read, write, and delete. All operations are asynchronous to support both
57
+ * in-memory and remote storage providers.
32
58
  */
33
59
  export interface Storage {
34
60
  /**
35
61
  * Reads store items from storage.
36
- * @param keys The keys of the items to read.
37
- * @returns A promise that resolves to the store items.
62
+ *
63
+ * @param keys The keys of the items to read
64
+ * @returns A promise that resolves to the store items. Items that don't exist in storage will not be included in the result.
65
+ * @throws If the keys array is empty or undefined
38
66
  */
39
- read: (keys: string[]) => Promise<StoreItem>
67
+ read: (keys: string[]) => Promise<StoreItem>;
68
+
40
69
  /**
41
70
  * Writes store items to storage.
42
- * @param changes The items to write to storage.
43
- * @returns A promise that resolves when the write operation is complete.
71
+ *
72
+ * @param changes The items to write to storage, indexed by key
73
+ * @returns A promise that resolves when the write operation is complete
74
+ * @throws If the changes object is empty or undefined, or if an eTag conflict occurs and optimistic concurrency is enabled
44
75
  */
45
- write: (changes: StoreItem) => Promise<void>
76
+ write: (changes: StoreItem) => Promise<void>;
77
+
46
78
  /**
47
79
  * Deletes store items from storage.
48
- * @param keys The keys of the items to delete.
49
- * @returns A promise that resolves when the delete operation is complete.
80
+ *
81
+ * @param keys The keys of the items to delete
82
+ * @returns A promise that resolves when the delete operation is complete
50
83
  */
51
- delete: (keys: string[]) => Promise<void>
84
+ delete: (keys: string[]) => Promise<void>;
52
85
  }