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
8 changes: 8 additions & 0 deletions docker/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,14 @@ POLAR_DB_USE_MULTI_DB=false
# PolarDB connection pool size
POLARDB_POOL_MAX_CONN=100

# bytehouse endpoint/host
BYTEHOUSE_HOST=localhost
BYTEHOUSE_PORT=19000
BYTEHOUSE_USER=bytehouse
BYTEHOUSE_PASSWORD=xxxxxx:xxxxxxxxx
BYTEHOUSE_DB_NAME=test_shared_memos_db
BYTEHOUSE_USE_MULTI_DB=false

## Related configurations of Redis
# Reddimq sends scheduling information and synchronization information for some variables
MEMSCHEDULER_REDIS_HOST= # fallback keys if not using the global ones
Expand Down
30 changes: 30 additions & 0 deletions src/memos/api/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,31 @@ def get_mysql_config() -> dict[str, Any]:
"charset": os.getenv("MYSQL_CHARSET", "utf8mb4"),
}

@staticmethod
def get_bytehouse_config(user_id: str | None = None) -> dict[str, Any]:
"""Get ByteHouse configuration."""
use_multi_db = os.getenv("BYTEHOUSE_USE_MULTI_DB", "false").lower() == "true"

if use_multi_db:
db_name = f"memos{user_id.replace('-', '')}" if user_id else "memos_default"
else:
db_name = os.getenv("BYTEHOUSE_DB_NAME", "shared_memos_db")
user_name = (
f"memos{user_id.replace('-', '')}" if user_id else "memos_default"
)

return {
"host": os.getenv("BYTEHOUSE_HOST", "localhost"),
"port": int(os.getenv("BYTEHOUSE_PORT", "9000")),
"user": os.getenv("BYTEHOUSE_USER", "default"),
"password": os.getenv("BYTEHOUSE_PASSWORD", ""),
"db_name": db_name,
"user_name": user_name,
"use_multi_db": use_multi_db,
"auto_create": True,
"embedding_dimension": int(os.getenv("EMBEDDING_DIMENSION", "1024")),
}
Comment on lines +864 to +886

@staticmethod
def get_scheduler_config() -> dict[str, Any]:
"""Get scheduler configuration."""
Expand Down Expand Up @@ -1132,11 +1157,13 @@ def create_user_config(user_name: str, user_id: str) -> tuple["MOSConfig", "Gene
else None
)
postgres_config = APIConfig.get_postgres_config(user_id=user_id)
bytehouse_config = APIConfig.get_bytehouse_config(user_id=user_id)
graph_db_backend_map = {
"neo4j-community": neo4j_community_config,
"neo4j": neo4j_config,
"polardb": polardb_config,
"postgres": postgres_config,
"bytehouse": bytehouse_config,
}
# Support both GRAPH_DB_BACKEND and legacy NEO4J_BACKEND env vars
graph_db_backend = os.getenv(
Expand Down Expand Up @@ -1210,11 +1237,14 @@ def get_default_cube_config() -> "GeneralMemCubeConfig | None":
neo4j_config = APIConfig.get_neo4j_config(user_id="default")
polardb_config = APIConfig.get_polardb_config(user_id="default")
postgres_config = APIConfig.get_postgres_config(user_id="default")
bytehouse_config = APIConfig.get_bytehouse_config(user_id="default")

graph_db_backend_map = {
"neo4j-community": neo4j_community_config,
"neo4j": neo4j_config,
"polardb": polardb_config,
"postgres": postgres_config,
"bytehouse": bytehouse_config,
}
internet_config = (
APIConfig.get_internet_config()
Expand Down
1 change: 1 addition & 0 deletions src/memos/api/handlers/config_builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def build_graph_db_config(user_id: str = "default") -> dict[str, Any]:
"neo4j": APIConfig.get_neo4j_config(user_id=user_id),
"polardb": APIConfig.get_polardb_config(user_id=user_id),
"postgres": APIConfig.get_postgres_config(user_id=user_id),
"bytehouse": APIConfig.get_bytehouse_config(user_id=user_id),
}

# Support both GRAPH_DB_BACKEND and legacy NEO4J_BACKEND env vars
Expand Down
51 changes: 51 additions & 0 deletions src/memos/configs/graph_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,56 @@ def validate_config(self):
return self


class ByteHouseGraphDBConfig(BaseConfig):
"""
ByteHouse configuration for MemOS.

Schema:
- memos_memories: Main table for memory nodes (id, memory, properties JSONB, embedding vector)
- memos_edges: Edge table for relationships (source_id, target_id, type)
Comment on lines +249 to +250

Example:
---
host = "bytehouse"
port = 9000
user = "n8n"
password = "secret"
db_name = "n8n"
user_name = "default"
"""

host: str = Field(..., description="Database host")
port: int = Field(default=9000, description="Database port")
user: str = Field(..., description="Database user")
password: str = Field(..., description="Database password")
db_name: str = Field(..., description="Database name")
user_name: str = Field(
default="bytehouse",
description="Logical user/tenant ID for data isolation",
)
use_multi_db: bool = Field(
default=False,
description="If False: use single database with logical isolation by user_name",
)
auto_create: bool = Field(
default=False,
description="Whether to auto-create the database if it does not exist",
)
embedding_dimension: int = Field(
default=1024,
description="Dimension of vector embedding (1024 for all-MiniLM-L6-v2)",
)

@model_validator(mode="after")
def validate_config(self):
"""Validate config."""
if not self.db_name:
raise ValueError("`db_name` must be provided")
if not self.use_multi_db and not self.user_name:
raise ValueError("In single-database mode, `user_name` must be provided")
return self


class GraphDBConfigFactory(BaseModel):
backend: str = Field(..., description="Backend for graph database")
config: dict[str, Any] = Field(..., description="Configuration for the graph database backend")
Expand All @@ -250,6 +300,7 @@ class GraphDBConfigFactory(BaseModel):
"neo4j-community": Neo4jCommunityGraphDBConfig,
"polardb": PolarDBGraphDBConfig,
"postgres": PostgresGraphDBConfig,
"bytehouse": ByteHouseGraphDBConfig,
}

@field_validator("backend")
Expand Down
Loading
Loading