-
Notifications
You must be signed in to change notification settings - Fork 0
Migrates the current redis package from NAT repo to this repo #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
2f12638
3b7be1d
e7a613e
c34e334
c3204a0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,25 @@ | ||
| # Configuration | ||
|
|
||
| This package ships two Redis Agent Memory surfaces for NAT: | ||
| This package ships Redis Agent Memory surfaces and direct Redis plugins (migrated | ||
| from the NeMo Agent Toolkit `nvidia_nat_redis` package). | ||
|
|
||
| 1. A long-term memory backend: `_type: redis_agent_memory_backend` | ||
| 2. A native automatic wrapper: `_type: redis_agent_memory_auto_memory` | ||
| Redis Agent Memory is a production-ready agent memory layer that extracts and stores | ||
| relevant information and learns over time. | ||
|
|
||
| Direct Redis memory provides a more standard semantic memory layer for LLM applications. | ||
|
|
||
| **Full Redis Agent Memory auto wrapper** | ||
|
|
||
| 1. Long-term memory backend: `_type: redis_agent_memory_backend` | ||
| 2. Native automatic wrapper: `_type: redis_agent_memory_auto_memory` | ||
|
|
||
| **Direct Redis (entry point `nat_redis` → `nat.plugins.redis.register`)** | ||
|
|
||
| 3. In-Redis vector memory: `_type: redis_memory` | ||
| 4. Object store: `_type: redis` | ||
|
|
||
| For Python code, use **`nat.plugins.redis.*`** — the same module layout as NeMo | ||
| Agent Toolkit’s in-tree package. | ||
|
|
||
| ## Long-Term Memory Backend | ||
|
|
||
|
|
@@ -116,6 +132,50 @@ Wrapper flow: | |
| 2. Create or load Redis Agent Memory working memory for that identity. | ||
| 3. Call `memory_prompt(...)`, invoke the inner chat function with the hydrated request, and append the finished turn back into working memory. | ||
|
|
||
| ## Direct Redis memory (`redis_memory`) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should have a good look at the readme -- maybe dream a bit with codex/claude -- to think about how to make it easier, and clearer to understand that there are two redis memory types here and some different flavors. Maybe we LEAD with the plugin approach (MemoryEditor) and then underneath list the two options and clearly highlight tradeoffs of each and how they work. I also think we need a bit more front matter (maybe logos) and hype to draw a bit more attention when landing on the readme. Thanks!!!
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Made some additions to the README. Let me know what you think |
||
|
|
||
| Use `_type: redis_memory` for the lightweight Redis-backed `MemoryEditor` that | ||
| stores JSON documents and uses RediSearch vector queries. This matches the | ||
| behavior of the standalone | ||
| [`nvidia_nat_redis` package in NeMo Agent Toolkit](https://github.com/NVIDIA/NeMo-Agent-Toolkit/tree/develop/packages/nvidia_nat_redis). | ||
|
|
||
| Requirements: | ||
|
|
||
| - Redis with **JSON** and **search** (for example Redis Stack), because the implementation creates a JSON index and runs vector KNN queries. | ||
| - A workflow **embedder** instance; `embedder` must reference its name in the workflow configuration. | ||
|
|
||
| ```yaml | ||
| memory: | ||
| redis_ltm: | ||
| _type: redis_memory | ||
| host: localhost | ||
| port: 6379 | ||
| db: 0 | ||
| key_prefix: nat | ||
| embedder: my_openai_embedder | ||
| ``` | ||
|
|
||
| Supported config fields: | ||
|
|
||
| - `host`, `port`, `db`, `password` (optional secret), `key_prefix` | ||
| - `embedder`: `EmbedderRef` to a configured embedder (LangChain wrapper) | ||
|
|
||
| ## Direct Redis object store (`redis`) | ||
|
|
||
| Use `_type: redis` for the NAT object store that persists `ObjectStoreItem` | ||
| JSON at keys under `nat/object_store/{bucket_name}/...`, with optional TTL. | ||
|
|
||
| ```yaml | ||
| object_store: | ||
| artifacts: | ||
| _type: redis | ||
| host: localhost | ||
| port: 6379 | ||
| db: 0 | ||
| bucket_name: my_bucket | ||
| ttl: 3600 | ||
| ``` | ||
|
|
||
| ## Examples | ||
|
|
||
| - [Redis Agent Memory native wrapper](../examples/agent_auto_memory/README.md) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| """Direct Redis memory and object-store NAT components (NeMo ``nat.plugins.redis`` layout).""" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| from nat.builder.builder import Builder | ||
| from nat.cli.register_workflow import register_memory | ||
| from nat.data_models.common import OptionalSecretStr, get_secret_value | ||
| from nat.data_models.component_ref import EmbedderRef | ||
| from nat.data_models.memory import MemoryBaseConfig | ||
| from pydantic import Field | ||
|
|
||
|
|
||
| class RedisMemoryClientConfig(MemoryBaseConfig, name="redis_memory"): | ||
| host: str = Field(default="localhost", description="Redis server host") | ||
| db: int = Field(default=0, description="Redis DB") | ||
| port: int = Field(default=6379, description="Redis server port") | ||
| password: OptionalSecretStr = Field(default=None, description="Password for the Redis server") | ||
| key_prefix: str = Field(default="nat", description="Key prefix to use for redis keys") | ||
| embedder: EmbedderRef = Field(description=("Instance name of the memory client instance from the workflow " | ||
| "configuration object.")) | ||
|
|
||
|
|
||
| @register_memory(config_type=RedisMemoryClientConfig) | ||
| async def redis_memory_client(config: RedisMemoryClientConfig, builder: Builder): | ||
|
|
||
| from nat.builder.framework_enum import LLMFrameworkEnum | ||
|
|
||
| import redis.asyncio as redis | ||
|
|
||
| from .redis_editor import RedisEditor | ||
| from .schema import ensure_index_exists | ||
|
|
||
| redis_client = redis.Redis(host=config.host, | ||
| port=config.port, | ||
| db=config.db, | ||
| password=get_secret_value(config.password), | ||
| decode_responses=True, | ||
| socket_timeout=5.0, | ||
| socket_connect_timeout=5.0) | ||
|
|
||
| embedder = await builder.get_embedder(config.embedder, wrapper_type=LLMFrameworkEnum.LANGCHAIN) | ||
|
|
||
| test_embedding = await embedder.aembed_query("test") | ||
| embedding_dim = len(test_embedding) | ||
| await ensure_index_exists(client=redis_client, key_prefix=config.key_prefix, embedding_dim=embedding_dim) | ||
|
|
||
| memory_editor = RedisEditor(redis_client=redis_client, key_prefix=config.key_prefix, embedder=embedder) | ||
|
|
||
| yield memory_editor | ||
|
justin-cechmanek marked this conversation as resolved.
|
||
Uh oh!
There was an error while loading. Please reload this page.