feat(memory-gateway): merge memory mode with main

This commit is contained in:
2026-06-16 18:04:44 +08:00
30 changed files with 3170 additions and 18 deletions

View File

@ -3,6 +3,7 @@
from __future__ import annotations
import asyncio
import logging
import os
from dataclasses import dataclass, field
from pathlib import Path
@ -15,6 +16,13 @@ from beaver.foundation.config import BeaverConfig, load_config
from beaver.foundation.utils.file_lock import WorkspaceWriteLock, WorkspaceWriteLockBusy
from beaver.integrations.mcp import MCPConnectionManager
from beaver.memory.curated.store import MemoryStore
from beaver.memory.gateway import (
MemoryGatewayConfig,
MemoryGatewayCredentialStore,
MemoryGatewayService,
MemoryGatewayUserCredential,
default_memory_gateway_users_path,
)
from beaver.memory.runs import RunMemoryStore
from beaver.memory.skills import SkillLearningStore
from beaver.plugins.discovery import discover_plugins
@ -63,6 +71,8 @@ from beaver.tools.builtins import (
WriteFileTool,
)
logger = logging.getLogger(__name__)
@dataclass(slots=True)
class EngineLoadResult:
@ -84,6 +94,9 @@ class EngineLoadResult:
session_manager: SessionManager | None = None
curated_memory_store: MemoryStore | None = None
memory_service: MemoryService | None = None
memory_gateway_config: MemoryGatewayConfig | None = None
memory_gateway_credentials: MemoryGatewayCredentialStore | None = None
memory_gateway_service_factory: Callable[[MemoryGatewayUserCredential], MemoryGatewayService] | None = None
run_memory_store: RunMemoryStore | None = None
skill_learning_store: SkillLearningStore | None = None
tool_registry: ToolRegistry | None = None
@ -161,6 +174,8 @@ class EngineLoader:
session_manager: SessionManager | None = None,
curated_memory_store: MemoryStore | None = None,
memory_service: MemoryService | None = None,
memory_gateway_credentials: MemoryGatewayCredentialStore | None = None,
memory_gateway_service_factory: Callable[[MemoryGatewayConfig, MemoryGatewayUserCredential], MemoryGatewayService] | None = None,
run_memory_store: RunMemoryStore | None = None,
skill_learning_store: SkillLearningStore | None = None,
tool_registry: ToolRegistry | None = None,
@ -187,6 +202,8 @@ class EngineLoader:
self._session_manager = session_manager
self._curated_memory_store = curated_memory_store
self._memory_service = memory_service
self._memory_gateway_credentials = memory_gateway_credentials
self._memory_gateway_service_factory = memory_gateway_service_factory
self._run_memory_store = run_memory_store
self._skill_learning_store = skill_learning_store
self._tool_registry = tool_registry
@ -210,6 +227,11 @@ class EngineLoader:
"""装配当前主链需要的最小 runtime 对象。"""
workspace = self.workspace
(
memory_gateway_config,
memory_gateway_credentials,
memory_gateway_service_factory,
) = self._resolve_memory_gateway_components()
session_manager = self._session_manager or SessionManager(workspace)
curated_root = workspace / "memory" / "curated"
@ -329,11 +351,14 @@ class EngineLoader:
config=self.config,
tools=[spec.name for spec in tool_registry.list_specs()],
skills=[record.name for record in skills_loader.list_skills(filter_unavailable=False)],
memory_stores=["curated"],
memory_stores=["curated", *(["memory_gateway"] if memory_gateway_service_factory is not None else [])],
permissions=[],
session_manager=session_manager,
curated_memory_store=memory_service.get_store(),
memory_service=memory_service,
memory_gateway_config=memory_gateway_config,
memory_gateway_credentials=memory_gateway_credentials,
memory_gateway_service_factory=memory_gateway_service_factory,
run_memory_store=run_memory_store,
skill_learning_store=skill_learning_store,
tool_registry=tool_registry,
@ -361,6 +386,39 @@ class EngineLoader:
result.register_closeable("mcp_manager", lambda: _close_mcp_manager(mcp_manager))
return result
def _resolve_memory_gateway_components(
self,
) -> tuple[
MemoryGatewayConfig | None,
MemoryGatewayCredentialStore | None,
Callable[[MemoryGatewayUserCredential], MemoryGatewayService] | None,
]:
memory_config = self.config.memory
if memory_config.mode == "curated":
return None, None, None
gateway_config = memory_config.gateway
if memory_config.explicit and not gateway_config.is_configured:
raise ValueError(
"Explicit hybrid memory requires complete Memory Gateway configuration"
)
if not gateway_config.is_configured:
logger.warning(
"Memory Gateway is not configured; continuing with curated memory only"
)
return None, None, None
credential_store = self._memory_gateway_credentials or MemoryGatewayCredentialStore(
default_memory_gateway_users_path()
)
def factory(credential: MemoryGatewayUserCredential) -> MemoryGatewayService:
if self._memory_gateway_service_factory is not None:
return self._memory_gateway_service_factory(gateway_config, credential)
return MemoryGatewayService(gateway_config, credential)
return gateway_config, credential_store, factory
def _close_mcp_manager(manager: MCPConnectionManager) -> None:
try: