nvidia-nat-redis 1.3.dev0__py3-none-any.whl → 1.3.0rc1__py3-none-any.whl

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.
@@ -13,21 +13,19 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- import redis.asyncio as redis
17
16
  from pydantic import Field
18
17
 
19
18
  from nat.builder.builder import Builder
20
- from nat.builder.framework_enum import LLMFrameworkEnum
21
19
  from nat.cli.register_workflow import register_memory
22
20
  from nat.data_models.component_ref import EmbedderRef
23
21
  from nat.data_models.memory import MemoryBaseConfig
24
22
 
25
23
 
26
24
  class RedisMemoryClientConfig(MemoryBaseConfig, name="redis_memory"):
27
- host: str | None = Field(default="localhost", description="Redis server host")
28
- db: str | None = Field(default="0", description="Redis DB")
29
- port: str | None = Field(default="6379", description="Redis server port")
30
- key_prefix: str | None = Field(default="nat", description="Key prefix to use for redis keys")
25
+ host: str = Field(default="localhost", description="Redis server host")
26
+ db: int = Field(default=0, description="Redis DB")
27
+ port: int = Field(default=6379, description="Redis server port")
28
+ key_prefix: str = Field(default="nat", description="Key prefix to use for redis keys")
31
29
  embedder: EmbedderRef = Field(description=("Instance name of the memory client instance from the workflow "
32
30
  "configuration object."))
33
31
 
@@ -35,6 +33,9 @@ class RedisMemoryClientConfig(MemoryBaseConfig, name="redis_memory"):
35
33
  @register_memory(config_type=RedisMemoryClientConfig)
36
34
  async def redis_memory_client(config: RedisMemoryClientConfig, builder: Builder):
37
35
 
36
+ import redis.asyncio as redis
37
+
38
+ from nat.builder.framework_enum import LLMFrameworkEnum
38
39
  from nat.plugins.redis.redis_editor import RedisEditor
39
40
 
40
41
  from .schema import ensure_index_exists
@@ -0,0 +1,40 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from pydantic import Field
17
+
18
+ from nat.builder.builder import Builder
19
+ from nat.cli.register_workflow import register_object_store
20
+ from nat.data_models.object_store import ObjectStoreBaseConfig
21
+
22
+
23
+ class RedisObjectStoreClientConfig(ObjectStoreBaseConfig, name="redis"):
24
+ """
25
+ Object store that stores objects in a Redis database.
26
+ """
27
+
28
+ host: str = Field(default="localhost", description="The host of the Redis server")
29
+ db: int = Field(default=0, description="The Redis logical database number")
30
+ port: int = Field(default=6379, description="The port of the Redis server")
31
+ bucket_name: str = Field(description="The name of the bucket to use for the object store")
32
+
33
+
34
+ @register_object_store(config_type=RedisObjectStoreClientConfig)
35
+ async def redis_object_store_client(config: RedisObjectStoreClientConfig, _builder: Builder):
36
+
37
+ from .redis_object_store import RedisObjectStore
38
+
39
+ async with RedisObjectStore(**config.model_dump(exclude={"type"})) as store:
40
+ yield store
@@ -54,7 +54,7 @@ class RedisEditor(MemoryEditor):
54
54
  Insert Multiple MemoryItems into Redis.
55
55
  Each MemoryItem is stored with its metadata and tags.
56
56
  """
57
- logger.debug(f"Attempting to add {len(items)} items to Redis")
57
+ logger.debug("Attempting to add %d items to Redis", len(items))
58
58
 
59
59
  for memory_item in items:
60
60
  item_meta = memory_item.metadata
@@ -65,7 +65,7 @@ class RedisEditor(MemoryEditor):
65
65
 
66
66
  # Create a unique key for this memory item
67
67
  memory_key = f"{self._key_prefix}:memory:{memory_id}"
68
- logger.debug(f"Generated memory key: {memory_key}")
68
+ logger.debug("Generated memory key: %s", memory_key)
69
69
 
70
70
  # Prepare memory data
71
71
  memory_data = {
@@ -75,30 +75,30 @@ class RedisEditor(MemoryEditor):
75
75
  "metadata": item_meta,
76
76
  "memory": memory_item.memory or ""
77
77
  }
78
- logger.debug(f"Prepared memory data for key {memory_key}")
78
+ logger.debug("Prepared memory data for key %s", memory_key)
79
79
 
80
80
  # If we have memory, compute and store the embedding
81
81
  if memory_item.memory:
82
82
  logger.debug("Computing embedding for memory text")
83
83
  search_vector = await self._embedder.aembed_query(memory_item.memory)
84
- logger.debug(f"Generated embedding vector of length: {len(search_vector)}")
84
+ logger.debug("Generated embedding vector of length: %d", len(search_vector))
85
85
  memory_data["embedding"] = search_vector
86
86
 
87
87
  try:
88
88
  # Store as JSON in Redis
89
- logger.debug(f"Attempting to store memory data in Redis for key: {memory_key}")
89
+ logger.debug("Attempting to store memory data in Redis for key: %s", memory_key)
90
90
  await self._client.json().set(memory_key, "$", memory_data)
91
- logger.debug(f"Successfully stored memory data for key: {memory_key}")
91
+ logger.debug("Successfully stored memory data for key: %s", memory_key)
92
92
 
93
93
  # Verify the data was stored
94
94
  stored_data = await self._client.json().get(memory_key)
95
- logger.debug(f"Verified data storage for key {memory_key}: {bool(stored_data)}")
95
+ logger.debug("Verified data storage for key %s: %s", memory_key, bool(stored_data))
96
96
 
97
97
  except redis_exceptions.ResponseError as e:
98
- logger.error(f"Failed to store memory item: {str(e)}")
98
+ logger.error("Failed to store memory item: %s", e)
99
99
  raise
100
100
  except redis_exceptions.ConnectionError as e:
101
- logger.error(f"Redis connection error while storing memory item: {str(e)}")
101
+ logger.error("Redis connection error while storing memory item: %s", e)
102
102
  raise
103
103
 
104
104
  async def search(self, query: str, top_k: int = 5, **kwargs) -> list[MemoryItem]:
@@ -113,91 +113,86 @@ class RedisEditor(MemoryEditor):
113
113
  Returns:
114
114
  list[MemoryItem]: The most relevant MemoryItems for the given query.
115
115
  """
116
- logger.debug(f"Search called with query: {query}, top_k: {top_k}, kwargs: {kwargs}")
116
+ logger.debug("Search called with query: %s, top_k: %d, kwargs: %s", query, top_k, kwargs)
117
117
 
118
118
  user_id = kwargs.get("user_id", "redis") # TODO: remove this fallback username
119
- logger.debug(f"Using user_id: {user_id}")
119
+ logger.debug("Using user_id: %s", user_id)
120
120
 
121
121
  # Perform vector search using Redis search
122
122
  logger.debug("Using embedder for vector search")
123
123
  try:
124
- logger.debug(f"Generating embedding for query: '{query}'")
124
+ logger.debug("Generating embedding for query: '%s'", query)
125
125
  query_vector = await self._embedder.aembed_query(query)
126
- logger.debug(f"Generated embedding vector of length: {len(query_vector)}")
126
+ logger.debug("Generated embedding vector of length: %d", len(query_vector))
127
127
  except Exception as e:
128
- logger.error(f"Failed to generate embedding: {str(e)}")
128
+ logger.error("Failed to generate embedding: %s", e)
129
129
  raise
130
130
 
131
131
  # Create vector search query
132
132
  search_query = (
133
133
  Query(f"(@user_id:{user_id})=>[KNN {top_k} @embedding $vec AS score]").sort_by("score").return_fields(
134
134
  "conversation", "user_id", "tags", "metadata", "memory", "score").dialect(2))
135
- logger.debug(f"Created search query: {search_query}")
136
- logger.debug(f"Query string: {search_query.query_string()}")
135
+ logger.debug("Created search query: %s", search_query)
136
+ logger.debug("Query string: %s", search_query.query_string())
137
137
 
138
138
  # Convert query vector to bytes
139
139
  try:
140
140
  logger.debug("Converting query vector to bytes")
141
141
  query_vector_bytes = np.array(query_vector, dtype=np.float32).tobytes()
142
- logger.debug(f"Converted vector to bytes of length: {len(query_vector_bytes)}")
142
+ logger.debug("Converted vector to bytes of length: %d", len(query_vector_bytes))
143
143
  except Exception as e:
144
- logger.error(f"Failed to convert vector to bytes: {str(e)}")
144
+ logger.error("Failed to convert vector to bytes: %s", e)
145
145
  raise
146
146
 
147
147
  try:
148
148
  # Execute search with vector parameters
149
149
  logger.debug("Executing Redis search with vector parameters")
150
- logger.debug(f"Search query parameters: vec length={len(query_vector_bytes)}")
150
+ logger.debug("Search query parameters: vec length=%d", len(query_vector_bytes))
151
151
 
152
152
  # Log the actual query being executed
153
- logger.debug(f"Full search query: {search_query.query_string()}")
153
+ logger.debug("Full search query: %s", search_query.query_string())
154
154
 
155
155
  # Check if there are any documents in the index
156
156
  try:
157
157
  total_docs = await self._client.ft(INDEX_NAME).info()
158
- logger.debug(f"Total documents in index: {total_docs.get('num_docs', 0)}")
158
+ logger.debug("Total documents in index: %d", total_docs.get('num_docs', 0))
159
159
  except Exception as e:
160
- logger.error(f"Failed to get index info: {str(e)}")
160
+ logger.exception("Failed to get index info: %s", e)
161
161
 
162
162
  # Execute the search
163
163
  results = await self._client.ft(INDEX_NAME).search(search_query, query_params={"vec": query_vector_bytes})
164
164
 
165
165
  # Log detailed results information
166
- logger.debug(f"Search returned {len(results.docs)} results")
167
- logger.debug(f"Total results found: {results.total}")
166
+ logger.debug("Search returned %d results", len(results.docs))
167
+ logger.debug("Total results found: %d", results.total)
168
168
 
169
169
  # Convert results to MemoryItems
170
170
  memories = []
171
171
  for i, doc in enumerate(results.docs):
172
172
  try:
173
- logger.debug(f"Processing result {i+1}/{len(results.docs)}")
174
- # Get the document data from the correct attribute
175
- memory_data = {
176
- "conversation": getattr(doc, 'conversation', []),
177
- "user_id": getattr(doc, 'user_id', user_id),
178
- "tags": getattr(doc, 'tags', []),
179
- "metadata": getattr(doc, 'metadata', {}),
180
- "memory": getattr(doc, 'memory', "")
181
- }
182
- logger.debug(f"Similarity score: {getattr(doc, 'score', 0)}")
183
- logger.debug(f"Extracted data for result {i+1}: {memory_data}")
184
- memory_item = self._create_memory_item(memory_data, user_id)
173
+ logger.debug("Processing result %d/%d", i + 1, len(results.docs))
174
+ logger.debug("Similarity score: %d", getattr(doc, 'score', 0))
175
+
176
+ # Get the full document data
177
+ full_doc = await self._client.json().get(doc.id)
178
+ logger.debug("Extracted data for result %d: %s", i + 1, full_doc)
179
+ memory_item = self._create_memory_item(dict(full_doc), user_id)
185
180
  memories.append(memory_item)
186
- logger.debug(f"Successfully created MemoryItem for result {i+1}")
181
+ logger.debug("Successfully created MemoryItem for result %d", i + 1)
187
182
  except Exception as e:
188
- logger.error(f"Failed to process result {i+1}: {str(e)}")
183
+ logger.error("Failed to process result %d: %s", i + 1, e)
189
184
  raise
190
185
 
191
- logger.debug(f"Successfully processed all {len(memories)} results")
186
+ logger.debug("Successfully processed all %d results", len(memories))
192
187
  return memories
193
188
  except redis_exceptions.ResponseError as e:
194
- logger.error(f"Search failed with ResponseError: {str(e)}")
189
+ logger.error("Search failed with ResponseError: %s", e)
195
190
  raise
196
191
  except redis_exceptions.ConnectionError as e:
197
- logger.error(f"Search failed with ConnectionError: {str(e)}")
192
+ logger.error("Search failed with ConnectionError: %s", e)
198
193
  raise
199
194
  except Exception as e:
200
- logger.error(f"Unexpected error during search: {str(e)}")
195
+ logger.error("Unexpected error during search: %s", e)
201
196
  raise
202
197
 
203
198
  def _create_memory_item(self, memory_data: dict, user_id: str) -> MemoryItem:
@@ -226,8 +221,8 @@ class RedisEditor(MemoryEditor):
226
221
  if keys:
227
222
  await self._client.delete(*keys)
228
223
  except redis_exceptions.ResponseError as e:
229
- logger.error(f"Failed to remove items: {str(e)}")
224
+ logger.error("Failed to remove items: %s", e)
230
225
  raise
231
226
  except redis_exceptions.ConnectionError as e:
232
- logger.error(f"Redis connection error while removing items: {str(e)}")
227
+ logger.error("Redis connection error while removing items: %s", e)
233
228
  raise
@@ -0,0 +1,126 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ import logging
17
+
18
+ import redis.asyncio as redis
19
+
20
+ from nat.data_models.object_store import KeyAlreadyExistsError
21
+ from nat.data_models.object_store import NoSuchKeyError
22
+ from nat.object_store.interfaces import ObjectStore
23
+ from nat.object_store.models import ObjectStoreItem
24
+ from nat.utils.type_utils import override
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ class RedisObjectStore(ObjectStore):
30
+ """
31
+ Implementation of ObjectStore that stores objects in Redis.
32
+
33
+ Each object is stored as a single binary value at key "nat/object_store/{bucket_name}/{object_key}".
34
+ """
35
+
36
+ def __init__(self, *, bucket_name: str, host: str, port: int, db: int):
37
+
38
+ super().__init__()
39
+
40
+ self._bucket_name = bucket_name
41
+ self._host = host
42
+ self._port = port
43
+ self._db = db
44
+ self._client: redis.Redis | None = None
45
+
46
+ async def __aenter__(self) -> "RedisObjectStore":
47
+
48
+ if self._client is not None:
49
+ raise RuntimeError("Connection already established")
50
+
51
+ self._client = redis.Redis(
52
+ host=self._host,
53
+ port=self._port,
54
+ db=self._db,
55
+ socket_timeout=5.0,
56
+ socket_connect_timeout=5.0,
57
+ )
58
+
59
+ # Ping to ensure connectivity
60
+ res = await self._client.ping()
61
+ if not res:
62
+ raise RuntimeError("Failed to connect to Redis")
63
+
64
+ logger.info("Connected Redis client for %s at %s:%s/%s", self._bucket_name, self._host, self._port, self._db)
65
+
66
+ return self
67
+
68
+ async def __aexit__(self, exc_type, exc_value, traceback) -> None:
69
+
70
+ if not self._client:
71
+ raise RuntimeError("Connection not established")
72
+
73
+ await self._client.close()
74
+ self._client = None
75
+
76
+ def _make_key(self, key: str) -> str:
77
+ return f"nat/object_store/{self._bucket_name}/{key}"
78
+
79
+ @override
80
+ async def put_object(self, key: str, item: ObjectStoreItem):
81
+
82
+ if not self._client:
83
+ raise RuntimeError("Connection not established")
84
+
85
+ full_key = self._make_key(key)
86
+
87
+ item_json = item.model_dump_json()
88
+ # Redis SET with NX ensures we do not overwrite existing keys
89
+ if not await self._client.set(full_key, item_json, nx=True):
90
+ raise KeyAlreadyExistsError(key=key,
91
+ additional_message=f"Redis bucket {self._bucket_name} already has key {key}")
92
+
93
+ @override
94
+ async def upsert_object(self, key: str, item: ObjectStoreItem):
95
+
96
+ if not self._client:
97
+ raise RuntimeError("Connection not established")
98
+
99
+ full_key = self._make_key(key)
100
+ item_json = item.model_dump_json()
101
+ await self._client.set(full_key, item_json)
102
+
103
+ @override
104
+ async def get_object(self, key: str) -> ObjectStoreItem:
105
+
106
+ if not self._client:
107
+ raise RuntimeError("Connection not established")
108
+
109
+ full_key = self._make_key(key)
110
+ data = await self._client.get(full_key)
111
+ if data is None:
112
+ raise NoSuchKeyError(key=key,
113
+ additional_message=f"Redis bucket {self._bucket_name} does not have key {key}")
114
+ return ObjectStoreItem.model_validate_json(data)
115
+
116
+ @override
117
+ async def delete_object(self, key: str):
118
+
119
+ if not self._client:
120
+ raise RuntimeError("Connection not established")
121
+
122
+ full_key = self._make_key(key)
123
+ deleted = await self._client.delete(full_key)
124
+ if deleted == 0:
125
+ raise NoSuchKeyError(key=key,
126
+ additional_message=f"Redis bucket {self._bucket_name} does not have key {key}")
@@ -13,10 +13,10 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- # pylint: disable=unused-import
17
16
  # flake8: noqa
18
17
  # isort:skip_file
19
18
 
20
19
  # Import any providers which need to be automatically registered here
21
20
 
22
21
  from . import memory
22
+ from . import object_store
@@ -39,7 +39,7 @@ def create_schema(embedding_dim: int = DEFAULT_DIM):
39
39
  Returns:
40
40
  tuple: Schema definition for Redis search
41
41
  """
42
- logger.info(f"Creating schema with embedding dimension: {embedding_dim}")
42
+ logger.info("Creating schema with embedding dimension: %d", embedding_dim)
43
43
 
44
44
  embedding_field = VectorField("$.embedding",
45
45
  "HNSW",
@@ -53,19 +53,20 @@ def create_schema(embedding_dim: int = DEFAULT_DIM):
53
53
  "EF_RUNTIME": 10
54
54
  },
55
55
  as_name="embedding")
56
- logger.info(f"Created embedding field with dimension {embedding_dim}")
56
+ logger.info("Created embedding field with dimension %d", embedding_dim)
57
57
 
58
58
  schema = (
59
+ # Redis search can't directly index complex objects (e.g. conversation and metadata) in return_fields
60
+ # They need to be retrieved via json().get() for full object access
59
61
  TextField("$.user_id", as_name="user_id"),
60
62
  TagField("$.tags[*]", as_name="tags"),
61
63
  TextField("$.memory", as_name="memory"),
62
- # TextField("$.conversations[*]", as_name="conversations"), # TODO: figure out if/how this should be done
63
64
  embedding_field)
64
65
 
65
66
  # Log the schema details
66
67
  logger.info("Schema fields:")
67
68
  for field in schema:
68
- logger.info(f" - {field.name}: {type(field).__name__}")
69
+ logger.info(" - %s: %s", field.name, type(field).__name__)
69
70
 
70
71
  return schema
71
72
 
@@ -81,55 +82,55 @@ async def ensure_index_exists(client: redis.Redis, key_prefix: str, embedding_di
81
82
  """
82
83
  try:
83
84
  # Check if index exists
84
- logger.info(f"Checking if index '{INDEX_NAME}' exists...")
85
+ logger.info("Checking if index '%s' exists...", INDEX_NAME)
85
86
  info = await client.ft(INDEX_NAME).info()
86
- logger.info(f"Redis search index '{INDEX_NAME}' exists.")
87
+ logger.info("Redis search index '%s' exists.", INDEX_NAME)
87
88
 
88
89
  # Verify the schema
89
90
  schema = info.get('attributes', [])
90
91
 
91
92
  return
92
- except redis_exceptions.ResponseError as e:
93
- error_msg = str(e)
93
+ except redis_exceptions.ResponseError as ex:
94
+ error_msg = str(ex)
94
95
  if "no such index" not in error_msg.lower() and "Index needs recreation" not in error_msg:
95
- logger.error(f"Unexpected Redis error: {error_msg}")
96
+ logger.error("Unexpected Redis error: %s", error_msg)
96
97
  raise
97
98
 
98
99
  # Index doesn't exist or needs recreation
99
- logger.info(f"Creating Redis search index '{INDEX_NAME}' with prefix '{key_prefix}'")
100
+ logger.info("Creating Redis search index '%s' with prefix '%s'", INDEX_NAME, key_prefix)
100
101
 
101
102
  # Drop any existing index
102
103
  try:
103
- logger.info(f"Attempting to drop existing index '{INDEX_NAME}' if it exists")
104
+ logger.info("Attempting to drop existing index '%s' if it exists", INDEX_NAME)
104
105
  await client.ft(INDEX_NAME).dropindex()
105
- logger.info(f"Successfully dropped existing index '{INDEX_NAME}'")
106
+ logger.info("Successfully dropped existing index '%s'", INDEX_NAME)
106
107
  except redis_exceptions.ResponseError as e:
107
108
  if "no such index" not in str(e).lower():
108
- logger.warning(f"Error while dropping index: {str(e)}")
109
+ logger.warning("Error while dropping index: %s", str(e))
109
110
 
110
111
  # Create new schema and index
111
112
  schema = create_schema(embedding_dim or DEFAULT_DIM)
112
- logger.info(f"Created schema with embedding dimension: {embedding_dim or DEFAULT_DIM}")
113
+ logger.info("Created schema with embedding dimension: %d", embedding_dim or DEFAULT_DIM)
113
114
 
114
115
  try:
115
116
  # Create the index
116
- logger.info(f"Creating new index '{INDEX_NAME}' with schema")
117
+ logger.info("Creating new index '%s' with schema", INDEX_NAME)
117
118
  await client.ft(INDEX_NAME).create_index(schema,
118
119
  definition=IndexDefinition(prefix=[f"{key_prefix}:"],
119
120
  index_type=IndexType.JSON))
120
121
 
121
122
  # Verify index was created
122
123
  info = await client.ft(INDEX_NAME).info()
123
- logger.info(f"Successfully created Redis search index '{INDEX_NAME}'")
124
- logger.debug(f"Redis search index info: {info}")
124
+ logger.info("Successfully created Redis search index '%s'", INDEX_NAME)
125
+ logger.debug("Redis search index info: %s", info)
125
126
 
126
127
  # Verify the schema
127
128
  schema = info.get('attributes', [])
128
- logger.debug(f"New index schema: {schema}")
129
+ logger.debug("New index schema: %s", schema)
129
130
 
130
131
  except redis_exceptions.ResponseError as e:
131
- logger.error(f"Failed to create index: {str(e)}")
132
+ logger.error("Failed to create index: %s", str(e))
132
133
  raise
133
134
  except redis_exceptions.ConnectionError as e:
134
- logger.error(f"Redis connection error while creating index: {str(e)}")
135
+ logger.error("Redis connection error while creating index: %s", str(e))
135
136
  raise
@@ -1,12 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nvidia-nat-redis
3
- Version: 1.3.dev0
3
+ Version: 1.3.0rc1
4
4
  Summary: Subpackage for Redis integration in NeMo Agent toolkit
5
5
  Keywords: ai,agents,memory
6
6
  Classifier: Programming Language :: Python
7
- Requires-Python: <3.13,>=3.11
7
+ Classifier: Programming Language :: Python :: 3.11
8
+ Classifier: Programming Language :: Python :: 3.12
9
+ Classifier: Programming Language :: Python :: 3.13
10
+ Requires-Python: <3.14,>=3.11
8
11
  Description-Content-Type: text/markdown
9
- Requires-Dist: nvidia-nat==v1.3-dev
12
+ Requires-Dist: nvidia-nat==v1.3.0-rc1
10
13
  Requires-Dist: redis~=4.3.4
11
14
 
12
15
  <!--
@@ -0,0 +1,13 @@
1
+ nat/meta/pypi.md,sha256=TpeNbVZJxzvEf0Gh3BGvLHPYsKnXjgM_KQVCayBPXso,1090
2
+ nat/plugins/redis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ nat/plugins/redis/memory.py,sha256=wqj_UYqnllc4kTCtFDz3eu-OZnyPWXxNZ3e6G992OGQ,2546
4
+ nat/plugins/redis/object_store.py,sha256=f_GtCTZ3KHfxE4f0lAzKaoAoInAZZki4Dfo7hrKCAHA,1681
5
+ nat/plugins/redis/redis_editor.py,sha256=nkSIWi1HUPald088fXTuF0rmZ0uS_3V65Vxy20vLSgk,9746
6
+ nat/plugins/redis/redis_object_store.py,sha256=DX46GEQl4H1Ivf2wrRaSimNcq6EfvRsm-xhyiECudoQ,4302
7
+ nat/plugins/redis/register.py,sha256=dJBKi-7W72ipkmZTOIo1E3ETffmJIlYhQTOlrkiFH3A,834
8
+ nat/plugins/redis/schema.py,sha256=Zcas3hIIqG7wuR94baYRFycmnccB3CuGmTs4p8Vv4mA,5589
9
+ nvidia_nat_redis-1.3.0rc1.dist-info/METADATA,sha256=0xSt8p37SkfhqrAtg0ofilzl_GgUTfs0DOPXZW72xIQ,1577
10
+ nvidia_nat_redis-1.3.0rc1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
+ nvidia_nat_redis-1.3.0rc1.dist-info/entry_points.txt,sha256=nyS8t8L9CbRFIMlE70RQBtJXrflBP4Ltl5zAkIl44So,56
12
+ nvidia_nat_redis-1.3.0rc1.dist-info/top_level.txt,sha256=8-CJ2cP6-f0ZReXe5Hzqp-5pvzzHz-5Ds5H2bGqh1-U,4
13
+ nvidia_nat_redis-1.3.0rc1.dist-info/RECORD,,
@@ -1,11 +0,0 @@
1
- nat/meta/pypi.md,sha256=TpeNbVZJxzvEf0Gh3BGvLHPYsKnXjgM_KQVCayBPXso,1090
2
- nat/plugins/redis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- nat/plugins/redis/memory.py,sha256=2AbG29r6tul4RVvGnSVrQnT96Hvm725i1X23zvDGWTg,2569
4
- nat/plugins/redis/redis_editor.py,sha256=BskJN5R0h1xzz7w5Ic8IVvd4z-qdBp9ZBIpGYNiSwE8,10080
5
- nat/plugins/redis/register.py,sha256=_ffKNKnMfkB2HzX4Nk_9EW0pwebg3GuzAE-iB-CoC3E,839
6
- nat/plugins/redis/schema.py,sha256=lcazZKzWEoJEJmGEt6rk135zJ6kGqw6v2b1B5l1xg7o,5494
7
- nvidia_nat_redis-1.3.dev0.dist-info/METADATA,sha256=vklxlIqGIZR0iqNwCO6a086CiA7e2hTmYTcz4ZsK4BQ,1422
8
- nvidia_nat_redis-1.3.dev0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
9
- nvidia_nat_redis-1.3.dev0.dist-info/entry_points.txt,sha256=nyS8t8L9CbRFIMlE70RQBtJXrflBP4Ltl5zAkIl44So,56
10
- nvidia_nat_redis-1.3.dev0.dist-info/top_level.txt,sha256=8-CJ2cP6-f0ZReXe5Hzqp-5pvzzHz-5Ds5H2bGqh1-U,4
11
- nvidia_nat_redis-1.3.dev0.dist-info/RECORD,,