feat: add memory primitive#2366
Conversation
c40ff59 to
15204a7
Compare
|
Assessment: Request Changes This PR introduces a well-designed Review Categories
The implementation quality is high — clean separation of concerns, good use of |
| /** Default max results per query for this store. Defaults to 3. */ | ||
| readonly limit?: number | ||
| /** Search the store for entries matching the query, ordered by relevance. */ | ||
| search(query: string, options?: SearchOptions): Promise<MemoryEntry[]> |
There was a problem hiding this comment.
Issue: The MemoryStore interface requires only search as mandatory, with add being optional. However, there's no mechanism for stores to declare other capabilities (e.g., delete, update, list). If these are planned for follow-up PRs, that's fine, but it's worth noting.
More importantly: the search method only accepts SearchOptions with limit. Real vector stores typically need additional parameters like score_threshold, filter (metadata-based filtering), etc. The SearchOptions interface is very minimal.
Suggestion: Consider whether SearchOptions should be generic/extensible (e.g., SearchOptions & Record<string, unknown>) or if the intent is for store implementations to accept additional params through their own constructors. Documenting this design choice would help implementors.
|
|
||
| const scopedNames = this._storeStores.map((s) => s.name) | ||
|
|
||
| const inputSchema = z.object({ |
There was a problem hiding this comment.
Issue: The entries schema allows an empty array (z.array(z.string())). If the model passes entries: [], the tool will return { stored: 0, failed: 0 } — a no-op that wastes a tool call.
Suggestion: Add .min(1) to prevent empty invocations:
entries: z.array(z.string()).min(1).describe('Data to store in long-term memory'),| key, | ||
| value: { type: 'BOOLEAN' as const, booleanValue: value }, | ||
| }) | ||
| } |
There was a problem hiding this comment.
Issue: The metadata loop silently drops values that aren't string, number, or boolean. Since MemoryStore.add accepts Record<string, JSONValue>, callers can pass arrays and objects which will be lost without warning. This could be confusing when debugging why metadata isn't appearing in the knowledge base.
Suggestion: Either log a warning for skipped keys, or serialize complex values (e.g., JSON.stringify) into a STRING attribute so they're not silently lost:
} else {
logger.warn(`key=<${key}> | skipping non-primitive metadata value for Bedrock KB attribute`)
}|
Issue: This PR introduces a new public API primitive ( The PR description template is unfilled — no motivation, no linked issue, no use cases, no API design documentation. Suggestion:
|
| * Memory manager for cross-session knowledge retrieval and storage. | ||
| * Manages one or more knowledge stores and exposes search/store tools. | ||
| * Accepts a {@link MemoryManager} instance or a {@link MemoryManagerConfig} object (auto-wrapped). | ||
| */ |
There was a problem hiding this comment.
Issue: AgentConfig.sessionManager only accepts a SessionManager instance, while memoryManager accepts both MemoryManager | MemoryManagerConfig. This ergonomic shorthand is nice but creates an inconsistency in the Agent constructor API.
Suggestion: Document why this inconsistency exists (presumably because MemoryManagerConfig is a pure data object while SessionManager requires a storage instance that can't be auto-constructed). If this pattern is intended to be retroactively applied to sessionManager in a follow-up, note that in the PR description.
|
Note: Several of my earlier comments (the ones referencing
|
| this.name = config.name | ||
| if (config.description !== undefined) this.description = config.description | ||
| if (config.maxSearchResults !== undefined) this.maxSearchResults = config.maxSearchResults | ||
| this.writable = config.writable ?? false |
There was a problem hiding this comment.
Issue: The store can be configured with writable: true but without dataSourceId, which means add() will throw at runtime with "dataSourceId is required for write operations." This creates a configuration-time success but runtime failure pattern. Since the MemoryManager validates writable stores have add at construction, users would expect the store to actually be writable.
Suggestion: Consider validating that dataSourceId is present when writable: true in the constructor:
if (this.writable && !this._dataSourceId) {
throw new Error('BedrockKnowledgeBaseStore: dataSourceId is required when writable is true')
}This gives immediate feedback rather than a cryptic runtime error on first write.
|
Assessment: Request Changes This PR introduces a well-architected Review Categories
The |
Description
Related Issues
Documentation PR
Type of Change
Bug fix
New feature
Breaking change
Documentation update
Other (please describe):
Testing
How have you tested the change? Verify that the changes do not break functionality or introduce warnings in consuming repositories: agents-docs, agents-tools, agents-cli
hatch run prepareChecklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.