Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions ci/.nim_models_used.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
},
{
"model": "meta/llama-3.3-70b-instruct",
"num_configs": 27
"num_configs": 26
},
{
"model": "nvidia/nemotron-3-super-120b-a12b",
"num_configs": 16
"num_configs": 17
},
{
"model": "meta/llama-3.1-8b-instruct",
Expand Down Expand Up @@ -53,7 +53,11 @@
"embedders": [
{
"model": "nvidia/nv-embedqa-e5-v5",
"num_configs": 23
"num_configs": 22
},
{
"model": "nvidia/nemotron-3-embed-1b",
"num_configs": 1
},
{
"model": "nvidia/llama-nemotron-embed-1b-v2",
Expand Down
65 changes: 64 additions & 1 deletion docs/source/build-workflows/memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,20 @@ The NeMo Agent Toolkit Memory subsystem is designed to store and retrieve a user

The memory module is designed to be extensible, allowing developers to create custom memory back-ends, providers in NeMo Agent Toolkit terminology.

## User Identity for Memory Tools

The built-in `add_memory`, `get_memory`, and `delete_memory` tools bind every operation to an identity. Set an optional `user_id` in the tool configuration for a fixed service or single-user identity. When
it is omitted, the tool reads `Context.user_id` for the current invocation. If neither is available, the operation
fails rather than accessing an unscoped memory namespace.

```yaml
functions:
get_memory:
_type: get_memory
memory: user_memory
user_id: service_user # Optional; otherwise use the current Context.user_id
Comment thread
dagardner-nv marked this conversation as resolved.
Outdated
```

## Included Memory Modules
The NeMo Agent Toolkit includes four memory module providers, all of which are available as plugins:
* [Mem0](https://mem0.ai/) which is provided by the [`nvidia-nat-mem0ai`](https://pypi.org/project/nvidia-nat-mem0ai/) plugin.
Expand All @@ -32,6 +46,50 @@ The NeMo Agent Toolkit includes four memory module providers, all of which are a
Additional memory backends are available as community plugins:
* [Synap](https://maximem.ai) — managed memory layer with user and customer scoping, provided by the [`maximem-synap-nemo-agent-toolkit`](https://pypi.org/project/maximem-synap-nemo-agent-toolkit/) plugin. See `examples/memory/synap/` for usage. ([Open source integration package](https://github.com/maximem-ai/maximem_synap_sdk/tree/main/packages/integrations))

## Authenticating Memory Tool Users

Each of the built-in `add_memory`, `get_memory`, and `delete_memory` tools require configuring an identity source:

- Use `user_id` for a fixed, single-user memory namespace.
- Use `user_id_resolver` for a multi-user application. Its value is the import path of a trusted, zero-argument Python callable that returns the current authenticated user's stable ID. The callable can be synchronous or asynchronous and is invoked for every memory operation.

For example, application code can obtain a principal that authentication middleware has already verified:

```python
# my_application/auth.py
from my_application.request_context import get_authenticated_principal


def resolve_memory_user_id() -> str:
principal = get_authenticated_principal()
if principal is None:
raise RuntimeError("An authenticated principal is required")
return principal.stable_user_id
```

Reference that callable from each memory tool:

```yaml
functions:
add_memory:
_type: add_memory
memory: user_memory
user_id_resolver: my_application.auth.resolve_memory_user_id
get_memory:
_type: get_memory
memory: user_memory
user_id_resolver: my_application.auth.resolve_memory_user_id
delete_memory:
_type: delete_memory
memory: user_memory
user_id_resolver: my_application.auth.resolve_memory_user_id
```

The resolver is part of the application's trusted computing base. It must derive the ID from authenticated state and
enforce any required authorization. Do not return an identity supplied by the LLM or copy an unverified request header,
JWT claim, API key, or cookie value directly. NVIDIA NeMo Agent Toolkit invokes the resolver but does not authenticate
the value it returns.

## Automatic Memory Wrapper Agent

The NeMo Agent Toolkit provides an [`auto_memory_agent`](../components/agents/auto-memory-wrapper/index.md) wrapper that adds automatic memory capture and retrieval to any agent without requiring the LLM to invoke memory tools explicitly.
Expand Down Expand Up @@ -93,12 +151,17 @@ The automatic memory wrapper agent supports several configuration parameters:

User ID is automatically extracted at runtime for memory isolation via:
1. `SessionManager.session(user_id=...)` - For production with custom auth middleware (recommended)
2. `X-User-ID` HTTP header - For testing without middleware
2. `X-User-ID` HTTP header - Illustrative/testing only; assumes a trusted upstream proxy authenticates the request
and injects this header
3. Console front end `user_id` - Defaults to `"nat_run_user_id"` for `nat run`

Conversation-aware memory backends can also use `conversation_id` to isolate separate conversations for the same user.
For `nat run`, pass `--conversation_id` when testing independent memory conversations from the CLI.

Never treat a client-supplied `X-User-ID` header as authentication. The header fallback is illustrative only and is
safe in production only when a trusted upstream proxy removes any client-supplied value and injects the authenticated
identity.

For detailed configuration and usage examples, refer to the `examples/agents/auto_memory_wrapper/README.md` guide.

## Examples
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@ through the front end or session runtime, not the `auto_memory_agent` workflow b
### User ID Extraction Priority

1. **`SessionManager.session(user_id=...)`** - For production with custom auth middleware (recommended)
2. **`X-User-ID` HTTP header** - For testing without middleware
2. **`X-User-ID` HTTP header** - Illustrative/testing only; assumes a trusted upstream proxy authenticates the request
and injects the header
3. **Console front end `user_id`** - Defaults to `"nat_run_user_id"` for `nat run`

Conversation-aware memory backends can also use `conversation_id` to isolate separate conversations for the same user.
Expand Down Expand Up @@ -198,7 +199,9 @@ async def handle_request(request):

### Testing: X-User-ID Header

For quick testing without custom middleware:
This header is not authentication. The following example is illustrative only and assumes that a trusted upstream
proxy has removed any client-supplied `X-User-ID` value, authenticated the request, and injected the header before
forwarding it to the application. Do not accept this header directly from untrusted clients.

```bash
curl -X POST http://localhost:8000/chat \
Expand Down Expand Up @@ -327,7 +330,8 @@ workflow:

## Important Notes

1. **User ID is runtime/front-end scoped** - Set via `SessionManager.session(user_id=...)`, `X-User-ID`, or `nat run --user_id`
1. **User ID is runtime/front-end scoped** - Set via `SessionManager.session(user_id=...)` or `nat run --user_id`.
`X-User-ID` is illustrative only and requires a trusted upstream proxy to inject it.
2. **Memory backends are interchangeable** - Works with any implementation of `MemoryEditor` interface
3. **No memory tools needed** - The wrapped agent does not need explicit memory tools configured
4. **Transparent to inner agent** - The wrapped agent is unaware of memory operations
Expand Down
8 changes: 8 additions & 0 deletions docs/source/extend/custom-components/memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ limitations under the License.

This documentation presumes familiarity with the NeMo Agent Toolkit [memory module](../../build-workflows/memory.md), [plugin architecture](../plugins.md), the concept of "function registration" using `@register_function`, and how we define [tool](../../build-workflows/functions-and-function-groups/functions.md#agents-and-tools) and workflow configurations in the NeMo Agent Toolkit config described in the [Creating a New Tool and Workflow](../../get-started/tutorials/create-a-new-workflow.md) tutorial.

For applications that expose the built-in memory tools to multiple authenticated users, see
[Authenticating Memory Tool Users](../../build-workflows/memory.md#authenticating-memory-tool-users). Configure a trusted
`user_id_resolver`.

## Key Memory Module Components

* **Memory Data Models**
Expand Down Expand Up @@ -190,12 +194,14 @@ functions:
add_memory:
_type: add_memory
memory: saas_memory
user_id: user_12
description: |
Add any facts about user preferences to long term memory. Always use this if users mention a preference.
The input to this tool should be a string that describes the user's preference, not the question or answer.
get_memory:
_type: get_memory
memory: saas_memory
user_id: user_12
description: |
Always call this tool before calling any other tools, even if the user does not mention to use it.
The question should be about user preferences which will help you format your response.
Expand All @@ -214,6 +220,8 @@ Explanation:

- We define a memory entry named `saas_memory` with `_type: mem0_memory`, using the [Mem0](https://mem0.ai/) provider included in the [`nvidia-nat-mem0ai`](https://pypi.org/project/nvidia-nat-mem0ai/) plugin.
- Then we define two tools (functions in NeMo Agent Toolkit terminology) that reference `saas_memory`: `add_memory` and `get_memory`.
- The optional `user_id` is a fixed identity for these tools. If it is omitted, the tools use the current invocation's
`Context.user_id` and fail if no identity is available. The LLM does not provide this value.
- Finally, the `agent_memory` workflow references these two tool names.

### Automatic Memory with the Auto-Memory Wrapper
Expand Down
11 changes: 5 additions & 6 deletions examples/RAG/simple_rag/configs/milvus_memory_rag_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ functions:
add_memory:
_type: add_memory
memory: saas_memory
user_id: user_12
description: |
Add any facts about user preferences to long term memory. Always use this if users mention a preference.
The input to this tool should be a string that describes the user's preference, not the question or answer.
get_memory:
_type: get_memory
memory: saas_memory
user_id: user_12
description: |
Always call this tool before calling any other tools, even if the user does not mention to use it.
The question should be about user preferences which will help you format your response.
Expand Down Expand Up @@ -86,16 +88,14 @@ workflow:

IMPORTANT MEMORY TOOL REQUIREMENTS:
1. You MUST call get_memory tool FIRST, before calling any other tools
2. You MUST use user_id "user_12" for all memory operations
3. You MUST include ALL required parameters when calling memory tools
4. When calling add_memory or get_memory, you MUST use the exact format as below, don't include any other content,
2. You MUST include ALL required parameters when calling memory tools
3. When calling add_memory or get_memory, you MUST use the exact format as below, don't include any other content,
and make sure the input is a valid JSON object.

For get_memory tool, you MUST use this exact format:
{{
"query": "user preferences",
"top_k": 1,
"user_id": "user_12"
"top_k": 1
}}

For add_memory tool, you MUST use this exact format:
Expand All @@ -110,7 +110,6 @@ workflow:
"content": "Hello Alex! I've noted you are looking for a trip to New York."
}}
],
"user_id": "user_12",
"metadata": {{
"key_value_pairs": {{
"type": "travel",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ functions:
add_memory:
_type: add_memory
memory: saas_memory
user_id: user_12
description: |
Add any facts about user preferences to long term memory. Always use this if users mention a preference.
The input to this tool should be a string that describes the user's preference, not the question or answer.
get_memory:
_type: get_memory
memory: saas_memory
user_id: user_12
description: |
Always call this tool before calling any other tools, even if the user does not mention to use it.
The question should be about user preferences which will help you format your response.
Expand Down
12 changes: 8 additions & 4 deletions examples/agents/auto_memory_wrapper/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ User ID is extracted at runtime for memory isolation. Configure it through the f
### User ID Extraction Priority

1. **`SessionManager.session(user_id=...)`** - For production with custom auth middleware (recommended)
2. **`X-User-ID` HTTP header** - For testing without middleware
2. **`X-User-ID` HTTP header** - Illustrative/testing only; assumes a trusted upstream proxy authenticates the request
and injects the header
3. **Console front end `user_id`** - Defaults to `"nat_run_user_id"` for `nat run`

Conversation-aware memory backends can also use `conversation_id` to isolate separate conversations for the same user.
Expand Down Expand Up @@ -163,9 +164,11 @@ async def handle_request(request):
return result
```

### Testing: X-User-ID Header
### Illustrative X-User-ID Header

For quick testing without custom middleware:
This header is not authentication. The following example is illustrative only and assumes that a trusted upstream
proxy has removed any client-supplied `X-User-ID` value, authenticated the request, and injected the header before
forwarding it to the application. Do not accept this header directly from untrusted clients.

```bash
curl -X POST http://localhost:8000/chat \
Expand Down Expand Up @@ -213,7 +216,8 @@ workflow:

## Important Notes

1. **User ID is runtime/front-end scoped** - Set via `SessionManager.session(user_id=...)`, `X-User-ID`, or `nat run --user_id`
1. **User ID is runtime/front-end scoped** - Set via `SessionManager.session(user_id=...)` or `nat run --user_id`.
`X-User-ID` is illustrative only and requires a trusted upstream proxy to inject it.
2. **Memory backends are interchangeable** - Works with any implementation of `MemoryEditor` interface

## Examples
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@ functions:
add_memory:
_type: add_memory
memory: saas_memory
user_id: user_1
description: |
Add any facts about user preferences to long term memory. Always use this if users mention a preference.
The input to this tool should be a string that describes the user's preference, not the question or answer.

get_memory:
_type: get_memory
memory: saas_memory
user_id: user_1
description: |
Always call this tool before calling any other tools, even if the user does not mention to use it.
The question should be about user preferences which will help you format your response.
Expand Down Expand Up @@ -82,16 +84,14 @@ workflow:
You have access to long term memory.
IMPORTANT MEMORY TOOL REQUIREMENTS:
1. You MUST call get_memory tool FIRST, before calling any other tools
2. You MUST use user_id "user_1" for all memory operations
3. You MUST include ALL required parameters when calling memory tools
4. When calling add_memory or get_memory, you MUST use the exact format as below, don't include any other content,
2. You MUST include ALL required parameters when calling memory tools
3. When calling add_memory or get_memory, you MUST use the exact format as below, don't include any other content,
and make sure the input is a valid JSON object.

For get_memory tool, you MUST use this exact format:
{
"query": "user preferences",
"top_k": 1,
"user_id": "user_1"
"top_k": 1
}

For add_memory tool, you MUST use this exact format:
Expand All @@ -106,7 +106,6 @@ workflow:
"content": "Hello Alex! I've noted you are looking for a trip to New York."
}
],
"user_id": "user_1",
"metadata": {
"key_value_pairs": {
"type": "travel",
Expand Down
6 changes: 4 additions & 2 deletions examples/memory/memmachine/memmachine_memory_example.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -435,17 +435,19 @@
" get_memory:\n",
" _type: get_memory\n",
" memory: memmachine_memory\n",
" user_id: \"{user_id}\"\n",
" description: |\n",
" Retrieve memories relevant to a query. Always call this tool first to check\n",
" for existing user preferences or facts.\n",
" Use the exact JSON format with user_id, query, and top_k parameters.\n",
" Use the exact JSON format with query and top_k parameters.\n",
"\n",
" add_memory:\n",
" _type: add_memory\n",
" memory: memmachine_memory\n",
" user_id: \"{user_id}\"\n",
" description: |\n",
" Add facts about user preferences or information to long-term memory.\n",
" Use the exact JSON format with user_id, memory, conversation (optional), metadata, and tags.\n",
" Use the exact JSON format with memory, conversation (optional), metadata, and tags.\n",
"\n",
"workflow:\n",
" _type: react_agent\n",
Expand Down
Loading
Loading