Skip to content

Commit 4a80673

Browse files
committed
Merge branch 'main' into feature/implement-a-simple
2 parents 9074e0d + 57c093d commit 4a80673

File tree

18 files changed

+382
-99
lines changed

18 files changed

+382
-99
lines changed

.github/workflows/python-tests.yml

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,15 @@ jobs:
3434
strategy:
3535
fail-fast: false
3636
matrix:
37-
python-version: [3.12] # Not testing with 3.13 at the moment
38-
redis-version: ['6.2.6-v9', 'latest'] # 8.0-M03 is not working atm
37+
python-version: [3.12]
38+
redis-version: ['redis/redis-stack:6.2.6-v9', 'redis:8.0.3', 'redis:latest']
3939

4040
steps:
4141
- uses: actions/checkout@v3
4242

4343
- name: Set Redis image name
4444
run: |
45-
if [[ "${{ matrix.redis-version }}" == "8.0-M03" ]]; then
46-
echo "REDIS_IMAGE=redis:${{ matrix.redis-version }}" >> $GITHUB_ENV
47-
else
48-
echo "REDIS_IMAGE=redis/redis-stack-server:${{ matrix.redis-version }}" >> $GITHUB_ENV
49-
fi
45+
echo "REDIS_IMAGE=${{ matrix.redis-version }}" >> $GITHUB_ENV
5046
5147
- name: Set up Python
5248
uses: actions/setup-python@v4
@@ -81,6 +77,12 @@ jobs:
8177
- name: Set up Docker Buildx
8278
uses: docker/setup-buildx-action@v3
8379

80+
- name: Log in to Docker Hub
81+
uses: docker/login-action@v3
82+
with:
83+
username: ${{ secrets.DOCKER_USERNAME }}
84+
password: ${{ secrets.DOCKER_TOKEN }}
85+
8486
- name: Log in to GitHub Container Registry
8587
uses: docker/login-action@v3
8688
with:
@@ -103,6 +105,8 @@ jobs:
103105
platforms: linux/amd64,linux/arm64
104106
push: true
105107
tags: |
108+
andrewbrookins510/agent-memory-server:latest
109+
andrewbrookins510/agent-memory-server:${{ steps.version.outputs.version }}
106110
ghcr.io/${{ github.repository }}:latest
107111
ghcr.io/${{ github.repository }}:${{ steps.version.outputs.version }}
108112
cache-from: type=gha

CHANGELOG.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [0.9.0] - 2025-07-11
9+
10+
*Changes from the initial release:*
11+
12+
### Architecture Evolution
13+
- **Working Memory (formerly Short-term Memory)**:
14+
- Renamed from "short-term memory" to "working memory" to better reflect its purpose
15+
- Enhanced with automatic promotion system that moves structured memories to long-term storage in background
16+
- Added support for arbitrary JSON data storage alongside memory structures
17+
- Improved automatic conversation summarization in working memory, based on token limits
18+
19+
- **Long-term Memory Promotion**:
20+
- Implemented seamless flow from working memory to long-term memory via background task processing
21+
- Agent only has to think about working memory, long-term memory is managed automatically (but can be managed manually, too)
22+
- Use any LangChain `VectorStore` subclass for long-term storage, defaults to `RedisVectorStore`
23+
- Structured memories are automatically promoted with vector embeddings and metadata indexing
24+
- Deduplication and compaction systems for long-term memory management
25+
- Background task worker system using for reliable, scalable memory processing
26+
27+
### Client SDK and Tooling
28+
- Working and long-term memory available as tools for LLM integration (LLM can choose to persist a long-term memory or search for long-term memories, etc.)
29+
- Higher-level tools support sending in a user's input and getting back a context-enriched prompt, via `/v1/memory/prompt` endpoint
30+
- Support for namespace isolation, user separation, and session management
31+
32+
### Search and Retrieval
33+
- Vector-based similarity search using OpenAI embeddings
34+
- Rich filtering system by session, namespace, topics, entities, timestamps
35+
- Hybrid search combining semantic similarity with metadata filtering
36+
- RedisVL integration for high-performance vector operations with Redis
37+
38+
### Enhanced Memory Classification:
39+
- Semantic memories for facts and preferences
40+
- Episodic memories for time-bound events with event dates (requires a timeframe)
41+
- Message memories for long-term conversation records (optional)
42+
- Automatic topic modeling and entity recognition either using BERTopic or a configured LLM
43+
- Rich metadata extraction and indexing
44+
45+
### Authentication and Security
46+
- OAuth2/JWT Bearer token authentication with JWKS validation
47+
- Multi-provider support (Auth0, AWS Cognito, Okta, Azure AD)
48+
- Role-based access control using JWT claims
49+
- Development mode with configurable auth bypass
50+
51+
### Operational Features
52+
- **Comprehensive CLI Interface**:
53+
- Commands for server management (`api`, `mcp`, `task-worker`)
54+
- Database operations (`rebuild-index`)
55+
- Background task scheduling and management
56+
- Health monitoring and diagnostics
57+
58+
59+
## [0.0.1]
60+
61+
### Initial Release - 2025-04-07
62+
- Initial release with basic short-term and long-term memory functionality

README.md

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,15 @@ A Redis-powered memory server built for AI agents and applications. It manages b
77
- **Working Memory**
88

99
- Session-scoped storage for messages, structured memories, context, and metadata
10-
- Automatically summarizes conversations when they exceed a client-configured window size
10+
- Automatically summarizes conversations when they exceed a client-configured (or server-managed) window size
1111
- Supports all major OpenAI and Anthropic models
1212
- Automatic (background) promotion of structured memories to long-term storage
1313

1414
- **Long-Term Memory**
1515

1616
- Persistent storage for memories across sessions
17-
- **Pluggable Vector Store Backends** - Support for multiple vector databases through LangChain VectorStore interface:
18-
- **Redis** (default) - RedisStack with RediSearch
19-
- **Chroma** - Open-source vector database
20-
- **Pinecone** - Managed vector database service
21-
- **Weaviate** - Open-source vector search engine
22-
- **Qdrant** - Vector similarity search engine
23-
- **Milvus** - Cloud-native vector database
24-
- **PostgreSQL/PGVector** - PostgreSQL with vector extensions
25-
- **LanceDB** - Embedded vector database
26-
- **OpenSearch** - Open-source search and analytics suite
27-
- Semantic search to retrieve memories with advanced filtering system
17+
- Pluggable Vector Store Backends - Support for any LangChain VectorStore (defaults to Redis)
18+
- Semantic search to retrieve memories with advanced filtering
2819
- Filter by session, user ID, namespace, topics, entities, timestamps, and more
2920
- Supports both exact match and semantic similarity search
3021
- Automatic topic modeling for stored memories with BERTopic or configured LLM
@@ -63,11 +54,7 @@ This project is under active development and is **pre-release** software. Think
6354

6455
### Roadmap
6556

66-
- [x] Long-term memory deduplication and compaction
67-
- [x] Use a background task system instead of `BackgroundTask`
68-
- [x] Authentication/authorization hooks (OAuth2/JWT support)
69-
- [ ] Configurable strategy for moving working memory to long-term memory
70-
- [ ] Separate Redis connections for long-term and working memory
57+
- [] Easier RBAC customization: role definitions, more hooks
7158

7259
## REST API Endpoints
7360

agent-memory-client/agent_memory_client/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
memory management capabilities for AI agents and applications.
66
"""
77

8-
__version__ = "0.9.0b7"
8+
__version__ = "0.9.1"
99

1010
from .client import MemoryAPIClient, MemoryClientConfig, create_memory_client
1111
from .exceptions import (

agent-memory-client/agent_memory_client/models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,8 @@ class WorkingMemory(BaseModel):
183183
)
184184

185185
# TTL and timestamps
186-
ttl_seconds: int = Field(
187-
default=3600, # 1 hour default
186+
ttl_seconds: int | None = Field(
187+
default=None, # Persistent by default
188188
description="TTL for the working memory in seconds",
189189
)
190190
last_accessed: datetime = Field(

agent_memory_server/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""Redis Agent Memory Server - A memory system for conversational AI."""
22

3-
__version__ = "0.9.0b7"
3+
__version__ = "0.9.1"

agent_memory_server/long_term_memory.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,9 @@ async def deduplicate_by_semantic_search(
10131013

10141014
vector_search_result = search_result.memories if search_result else []
10151015

1016+
# Filter out the memory itself from the search results (avoid self-duplication)
1017+
vector_search_result = [m for m in vector_search_result if m.id != memory.id]
1018+
10161019
if vector_search_result and len(vector_search_result) > 0:
10171020
# Found semantically similar memories
10181021
similar_memory_ids = [memory.id for memory in vector_search_result]
@@ -1079,8 +1082,6 @@ async def promote_working_memory_to_long_term(
10791082
logger.debug(f"No working memory found for session {session_id}")
10801083
return 0
10811084

1082-
print("Current working memory: ", current_working_memory)
1083-
10841085
# Find memories with no persisted_at (eligible for promotion)
10851086
unpersisted_memories = [
10861087
memory

agent_memory_server/mcp.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,14 @@ async def run_sse_async(self):
137137

138138
redis = await get_redis_conn()
139139
await ensure_search_index_exists(redis)
140-
return await super().run_sse_async()
140+
141+
# Run the SSE server using our custom implementation
142+
import uvicorn
143+
144+
app = self.sse_app()
145+
await uvicorn.Server(
146+
uvicorn.Config(app, host="0.0.0.0", port=int(self.settings.port))
147+
).serve()
141148

142149
async def run_stdio_async(self):
143150
"""Ensure Redis search index exists before starting STDIO MCP server."""

agent_memory_server/models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,8 @@ class WorkingMemory(BaseModel):
201201
)
202202

203203
# TTL and timestamps
204-
ttl_seconds: int = Field(
205-
default=3600, # 1 hour default
204+
ttl_seconds: int | None = Field(
205+
default=None, # Persistent by default
206206
description="TTL for the working memory in seconds",
207207
)
208208
last_accessed: datetime = Field(

agent_memory_server/working_memory.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ async def get_working_memory(
121121
tokens=working_memory_data.get("tokens", 0),
122122
session_id=session_id,
123123
namespace=namespace,
124-
ttl_seconds=working_memory_data.get("ttl_seconds", 3600),
124+
ttl_seconds=working_memory_data.get("ttl_seconds", None),
125125
data=working_memory_data.get("data") or {},
126126
last_accessed=datetime.fromtimestamp(
127127
working_memory_data.get("last_accessed", int(time.time())), UTC
@@ -188,18 +188,24 @@ async def set_working_memory(
188188
}
189189

190190
try:
191-
# Store with TTL
192-
await redis_client.setex(
193-
key,
194-
working_memory.ttl_seconds,
195-
json.dumps(
196-
data, default=json_datetime_handler
197-
), # Add custom handler for any remaining datetime objects
198-
)
199-
logger.info(
200-
f"Set working memory for session {working_memory.session_id} with TTL {working_memory.ttl_seconds}s"
201-
)
202-
191+
if working_memory.ttl_seconds is not None:
192+
# Store with TTL
193+
await redis_client.setex(
194+
key,
195+
working_memory.ttl_seconds,
196+
json.dumps(data, default=json_datetime_handler),
197+
)
198+
logger.info(
199+
f"Set working memory for session {working_memory.session_id} with TTL {working_memory.ttl_seconds}s"
200+
)
201+
else:
202+
await redis_client.set(
203+
key,
204+
json.dumps(data, default=json_datetime_handler),
205+
)
206+
logger.info(
207+
f"Set working memory for session {working_memory.session_id} with no TTL"
208+
)
203209
except Exception as e:
204210
logger.error(
205211
f"Error setting working memory for session {working_memory.session_id}: {e}"

0 commit comments

Comments
 (0)