Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
53 changes: 53 additions & 0 deletions docs/user_guide/en/modules/memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,30 @@ memory:
agent_id: my-agent
```

### Valkey Memory Config
```yaml
memory:
- name: chatdev_memory
type: valkey
config:
host: localhost
port: 6379
index_name: chatdev_memory
ttl_seconds: 86400
embedding:
provider: openai
model: text-embedding-3-small
api_key: ${API_KEY}
```

## 3. Built-in Store Comparison
| Type | Path | Highlights | Best for |
| --- | --- | --- | --- |
| `simple` | `node/agent/memory/simple_memory.py` | Optional disk persistence (JSON) after runs; FAISS + semantic rerank; read/write capable. | Small conversation history, prototypes. |
| `file` | `node/agent/memory/file_memory.py` | Chunks files/dirs into a vector index, read-only, auto rebuilds when files change. | Knowledge bases, doc QA. |
| `blackboard` | `node/agent/memory/blackboard_memory.py` | Lightweight append-only log trimmed by time/count; no vector search. | Broadcast boards, pipeline debugging. |
| `mem0` | `node/agent/memory/mem0_memory.py` | Cloud-managed by Mem0; semantic search + graph relationships; no local embeddings or persistence needed. Requires `mem0ai` package. | Production memory, cross-session persistence, multi-agent memory sharing. |
| `valkey` | `node/agent/memory/valkey_memory.py` | HNSW vector index via Valkey Search; server-side persistence, cross-process sharing, TTL auto-expiry. Requires `valkey-glide-sync` package. | Self-hosted persistent memory, multi-process deployments, privacy-sensitive environments. |

All stores register through `register_memory_store()` so summaries show up in UI via `MemoryStoreConfig.field_specs()`.

Expand Down Expand Up @@ -117,6 +134,42 @@ This schema lets multimodal outputs flow into Memory/Thinking modules without ex
- **Persistence** – Fully cloud-managed. `load()` and `save()` are no-ops. Memories persist across runs and sessions automatically.
- **Dependencies** – Requires `mem0ai` package (`pip install mem0ai`).

### 5.5 ValkeyMemory
- **Config** – Specify connection parameters and index settings via `ValkeyMemoryConfig`.
```yaml
memory:
- name: chatdev_memory
type: valkey
config:
host: localhost
port: 6379
index_name: chatdev_memory
ttl_seconds: 86400
embedding:
provider: openai
model: text-embedding-3-small
api_key: ${API_KEY}
```
| Field | Description | Default |
| --- | --- | --- |
| `host` | Valkey server address | `localhost` |
| `port` | Port (1-65535) | `6379` |
| `username` | ACL username | `None` |
| `password` | Auth password | `None` |
| `db` | Database index (0-15) | `0` |
| `use_tls` | Enable TLS encryption for the connection | `false` |
| `index_name` | FT index name | `memory_index` |
| `key_prefix` | Hash key prefix | `memory:` |
| `ttl_seconds` | Memory expiry in seconds; `None` means never expire | `None` |
| `embedding` | Nested `EmbeddingConfig` (required) | — |
- **Index creation** – On first instantiation, automatically calls `FT.CREATE` to build an HNSW vector index (COSINE distance) with `content_summary` (TEXT), `agent_role` (TAG), `timestamp` (NUMERIC), and `embedding` (VECTOR) fields. Silently skips if the index already exists.
- **Retrieval** – Executes a KNN query via `FT.SEARCH`, returns top-k results sorted by cosine similarity. Low-relevance results are filtered by `similarity_threshold`.
- **Write** – `update()` encodes input text into a float32 vector and stores it as a Valkey Hash (`HSET`). When `ttl_seconds` is configured, `EXPIRE` is called to set the TTL.
- **Persistence** – Managed by the Valkey server. `load()` and `save()` are no-ops. Data survives process restarts, and multiple processes can concurrently read/write the same index.
- **Error handling** – If Valkey does not have the Search module loaded, initialization raises a `RuntimeError` with installation guidance.
- **Dependencies** – Requires `valkey-glide-sync` package (`pip install 'chatdev[valkey]'`).
- **Best for** – Self-hosted deployments needing persistence, cross-process sharing, and automatic expiry; a drop-in alternative to Mem0 when cloud services are not acceptable for privacy reasons.

## 6. EmbeddingConfig Notes
- Fields: `provider`, `model`, `api_key`, `base_url`, `params`.
- `provider=openai` uses the official client; override `base_url` for compatibility layers.
Expand Down
53 changes: 53 additions & 0 deletions docs/user_guide/zh/modules/memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,30 @@ memory:
agent_id: my-agent
```

### Valkey Memory 配置
```yaml
memory:
- name: chatdev_memory
type: valkey
config:
host: localhost
port: 6379
index_name: chatdev_memory
ttl_seconds: 86400
embedding:
provider: openai
model: text-embedding-3-small
api_key: ${API_KEY}
```

## 3. 内置 Memory Store 对比
| 类型 | 路径 | 特点 | 适用场景 |
| --- | --- | --- | --- |
| `simple` | `node/agent/memory/simple_memory.py` | 运行结束后可选择落盘(JSON);使用向量搜索(FAISS)+语义重打分;支持读写 | 小规模对话记忆、快速原型 |
| `file` | `node/agent/memory/file_memory.py` | 将指定文件/目录切片为向量索引,只读;自动检测文件变更并更新索引 | 知识库、文档问答 |
| `blackboard` | `node/agent/memory/blackboard_memory.py` | 轻量附加日志,按时间/条数裁剪;不依赖向量检索 | 简易广播板、流水线调试 |
| `mem0` | `node/agent/memory/mem0_memory.py` | 由 Mem0 云端托管;支持语义搜索 + 图关系;无需本地 embedding 或持久化。需安装 `mem0ai` 包。 | 生产级记忆、跨会话持久化、多 Agent 记忆共享 |
| `valkey` | `node/agent/memory/valkey_memory.py` | 使用 Valkey Search 的 HNSW 向量索引;服务端持久化、跨进程共享、支持 TTL 自动过期。需安装 `valkey-glide-sync` 包。 | 自托管持久记忆、多进程部署、隐私敏感环境 |

> 所有内置 store 都会在 `register_memory_store()` 中注册,摘要可通过 `MemoryStoreConfig.field_specs()` 在 UI 中展示。

Expand Down Expand Up @@ -119,6 +136,42 @@ nodes:
- **持久化**:完全由云端托管。`load()` 和 `save()` 为空操作(no-op)。记忆在不同运行和会话间自动持久化。
- **依赖**:需安装 `mem0ai` 包(`pip install mem0ai`)。

### 5.5 ValkeyMemory
- **配置**:通过 `ValkeyMemoryConfig` 指定连接参数和索引设置。
```yaml
memory:
- name: chatdev_memory
type: valkey
config:
host: localhost
port: 6379
index_name: chatdev_memory
ttl_seconds: 86400
embedding:
provider: openai
model: text-embedding-3-small
api_key: ${API_KEY}
```
| 字段 | 说明 | 默认值 |
| --- | --- | --- |
| `host` | Valkey 服务器地址 | `localhost` |
| `port` | 端口(1-65535) | `6379` |
| `username` | ACL 用户名 | `None` |
| `password` | 认证密码 | `None` |
| `db` | 数据库索引(0-15) | `0` |
| `use_tls` | 启用 TLS 加密连接 | `false` |
| `index_name` | FT 索引名称 | `memory_index` |
| `key_prefix` | Hash key 前缀 | `memory:` |
| `ttl_seconds` | 记忆过期时间(秒),`None` 表示永不过期 | `None` |
| `embedding` | `EmbeddingConfig` 嵌套配置(必须提供) | — |
- **索引创建**:首次实例化时自动调用 `FT.CREATE` 创建 HNSW 向量索引(COSINE 距离),包含 `content_summary`(TEXT)、`agent_role`(TAG)、`timestamp`(NUMERIC)、`embedding`(VECTOR)字段。若索引已存在则静默跳过。
- **检索**:使用 `FT.SEARCH` 执行 KNN 查询,返回 top-k 结果并按余弦相似度排序。通过 `similarity_threshold` 过滤低相关结果。
- **写入**:`update()` 将输入文本编码为 float32 向量,存储为 Valkey Hash(`HSET`)。若配置了 `ttl_seconds`,同时调用 `EXPIRE` 设置过期时间。
- **持久化**:由 Valkey 服务端管理。`load()` 和 `save()` 为空操作(no-op)。数据在进程重启后自动保留,多进程可并发读写同一索引。
- **错误处理**:若 Valkey 未加载 Search 模块,初始化时抛出 `RuntimeError` 并给出安装提示。
- **依赖**:需安装 `valkey-glide-sync` 包(`pip install 'chatdev[valkey]'`)。
- **适用场景**:需要持久化、跨进程共享、自动过期的自托管部署;隐私敏感环境中 Mem0 云服务不可用时的替代方案。

## 6. EmbeddingConfig 提示
- 字段:`provider`, `model`, `api_key`, `base_url`, `params`。
- `provider=openai` 时使用 `openai.OpenAI` 客户端,可配置 `base_url` 以兼容兼容层。
Expand Down
149 changes: 149 additions & 0 deletions entity/configs/node/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,155 @@ def from_dict(cls, data: Mapping[str, Any], *, path: str) -> "SimpleMemoryConfig
}


@dataclass
class ValkeyMemoryConfig(BaseConfig):
"""Configuration for Valkey-backed memory store."""

host: str = "localhost"
port: int = 6379
username: str | None = None
password: str | None = None
db: int = 0
use_tls: bool = False
index_name: str = "memory_index"
key_prefix: str = "memory:"
ttl_seconds: int | None = None
embedding: EmbeddingConfig | None = None

@classmethod
def from_dict(cls, data: Mapping[str, Any], *, path: str) -> "ValkeyMemoryConfig":
mapping = require_mapping(data, path)
host = optional_str(mapping, "host", path) or "localhost"

port_value = mapping.get("port", 6379)
if not isinstance(port_value, int) or port_value < 1 or port_value > 65535:
raise ConfigError("port must be a valid port number (1-65535)", extend_path(path, "port"))

username = optional_str(mapping, "username", path)
password = optional_str(mapping, "password", path)

db_value = mapping.get("db", 0)
if not isinstance(db_value, int) or db_value < 0 or db_value > 15:
raise ConfigError("db must be a valid database index (0-15)", extend_path(path, "db"))

use_tls = bool(mapping.get("use_tls", False))

index_name = optional_str(mapping, "index_name", path) or "memory_index"

key_prefix = optional_str(mapping, "key_prefix", path) or "memory:"

ttl_seconds: int | None = None
ttl_raw = mapping.get("ttl_seconds")
if ttl_raw is not None:
if not isinstance(ttl_raw, int) or ttl_raw <= 0:
raise ConfigError("ttl_seconds must be a positive integer", extend_path(path, "ttl_seconds"))
ttl_seconds = ttl_raw

embedding_cfg = None
if "embedding" in mapping and mapping["embedding"] is not None:
embedding_cfg = EmbeddingConfig.from_dict(mapping["embedding"], path=extend_path(path, "embedding"))

return cls(
host=host,
port=port_value,
username=username,
password=password,
db=db_value,
use_tls=use_tls,
index_name=index_name,
key_prefix=key_prefix,
ttl_seconds=ttl_seconds,
embedding=embedding_cfg,
path=path,
)

FIELD_SPECS = {
"host": ConfigFieldSpec(
name="host",
display_name="Host",
type_hint="str",
required=False,
default="localhost",
description="Valkey server hostname or IP address",
),
"port": ConfigFieldSpec(
name="port",
display_name="Port",
type_hint="int",
required=False,
default=6379,
description="Valkey server port",
),
"username": ConfigFieldSpec(
name="username",
display_name="Username",
type_hint="str",
required=False,
description="Valkey ACL username (required for ACL-based auth)",
advance=True,
),
"password": ConfigFieldSpec(
name="password",
display_name="Password",
type_hint="str",
required=False,
description="Valkey server password",
default="${VALKEY_PASSWORD}",
advance=True,
),
"db": ConfigFieldSpec(
name="db",
display_name="Database Index",
type_hint="int",
required=False,
default=0,
description="Valkey database index",
advance=True,
),
"use_tls": ConfigFieldSpec(
name="use_tls",
display_name="Use TLS",
type_hint="bool",
required=False,
default=False,
description="Enable TLS encryption for the Valkey connection",
advance=True,
),
"index_name": ConfigFieldSpec(
name="index_name",
display_name="Index Name",
type_hint="str",
required=False,
default="memory_index",
description="Name of the Valkey Search index for vector similarity queries",
),
"key_prefix": ConfigFieldSpec(
name="key_prefix",
display_name="Key Prefix",
type_hint="str",
required=False,
default="memory:",
description="Prefix for all keys stored in Valkey",
advance=True,
),
"ttl_seconds": ConfigFieldSpec(
name="ttl_seconds",
display_name="TTL (seconds)",
type_hint="int",
required=False,
description="Time-to-live for memory entries in seconds (no expiry if omitted)",
),
"embedding": ConfigFieldSpec(
name="embedding",
display_name="Embedding Configuration",
type_hint="EmbeddingConfig",
required=False,
description="Optional embedding configuration for vector similarity search",
child=EmbeddingConfig,
),
}


@dataclass
class FileMemoryConfig(BaseConfig):
index_path: str | None = None
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ dependencies = [
"mem0ai>=1.0.9",
]

[project.optional-dependencies]
valkey = ["valkey-glide-sync>=2.4"]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
Expand Down
14 changes: 14 additions & 0 deletions runtime/node/agent/memory/builtin_stores.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
FileMemoryConfig,
Mem0MemoryConfig,
SimpleMemoryConfig,
ValkeyMemoryConfig,
MemoryStoreConfig,
)
from runtime.node.agent.memory.blackboard_memory import BlackboardMemory
Expand Down Expand Up @@ -48,6 +49,19 @@ def _create_mem0_memory(store):
)


def _create_valkey_memory(store):
from runtime.node.agent.memory.valkey_memory import ValkeyMemory
return ValkeyMemory(store)


register_memory_store(
"valkey",
config_cls=ValkeyMemoryConfig,
factory=_create_valkey_memory,
summary="Valkey-backed memory store with vector similarity search",
)


class MemoryFactory:
@staticmethod
def create_memory(store: MemoryStoreConfig) -> MemoryBase:
Expand Down
Loading