neutralize upstream service branding

This commit is contained in:
2026-06-12 16:31:08 +08:00
parent 126ae4eafa
commit 42de7f9da0
18 changed files with 340 additions and 256 deletions

View File

@ -1,4 +1,4 @@
"""Lightweight Memory Gateway for EverOS."""
"""Lightweight user resource memory gateway."""
from __future__ import annotations

View File

@ -13,7 +13,7 @@ from starlette.responses import Response
from .config import GatewayConfig
from .db import init_db
from .everos_client import EverOSClient
from .backend_client import BackendClient
from .repository import MemoryRepository
from .service import MemoryGatewayService, UnsupportedContentType, UploadTooLarge
@ -181,21 +181,21 @@ def _body_for_log(body: bytes, content_type: str | None) -> Any:
def create_app(
*,
config: GatewayConfig | None = None,
everos_client: Any | None = None,
backend_client: Any | None = None,
) -> FastAPI:
cfg = config or GatewayConfig.from_env()
init_db(cfg.database_path)
repository = MemoryRepository(cfg.database_path)
client = everos_client or EverOSClient(
cfg.everos_base_url,
timeout=cfg.everos_timeout_seconds,
client = backend_client or BackendClient(
cfg.backend_base_url,
timeout=cfg.backend_timeout_seconds,
)
service = MemoryGatewayService(cfg, repository, client)
app = FastAPI(title="memory-gateway", version="0.1.0")
app.state.config = cfg
app.state.repository = repository
app.state.everos_client = client
app.state.backend_client = client
app.state.gateway_service = service
router = APIRouter()
@ -278,24 +278,24 @@ def create_app(
@router.get("/health")
async def health() -> dict[str, Any]:
try:
everos_health = await client.health_check()
backend_health = await client.health_check()
except Exception as exc:
return {
"status": "degraded",
"api": {"status": "ok"},
"everos": {
"backend": {
"status": "unavailable",
"base_url": cfg.everos_base_url,
"base_url": cfg.backend_base_url,
"error": str(exc),
},
}
return {
"status": "ok",
"api": {"status": "ok"},
"everos": {
"backend": {
"status": "ok",
"base_url": cfg.everos_base_url,
"data": everos_health,
"base_url": cfg.backend_base_url,
"data": backend_health,
},
}

View File

@ -5,7 +5,7 @@ from typing import Any
import httpx
class EverOSClient:
class BackendClient:
def __init__(self, base_url: str, timeout: float = 120.0) -> None:
self.base_url = base_url.rstrip("/")
self.timeout = timeout

View File

@ -27,15 +27,15 @@ _DEFAULT_ALLOWED_MIME_TYPES = (
@dataclass(frozen=True)
class GatewayConfig:
everos_base_url: str = "http://127.0.0.1:1995"
backend_base_url: str = "http://127.0.0.1:1995"
database_path: Path = _PROJECT_ROOT / "data" / "memory_gateway.sqlite3"
storage_dir: Path = _PROJECT_ROOT / "data" / "storage"
resource_search_batch_size: int = 50
max_upload_bytes: int = 25 * 1024 * 1024
allowed_mime_types: tuple[str, ...] = _DEFAULT_ALLOWED_MIME_TYPES
everos_ingest_attempts: int = 3
everos_retry_delay_seconds: float = 0.25
everos_timeout_seconds: float = 120.0
backend_ingest_attempts: int = 3
backend_retry_delay_seconds: float = 0.25
backend_timeout_seconds: float = 120.0
@classmethod
def from_env(cls) -> GatewayConfig:
@ -48,8 +48,8 @@ class GatewayConfig:
if item.strip()
)
return cls(
everos_base_url=os.environ.get(
"EVEROS_BASE_URL",
backend_base_url=os.environ.get(
"MEMORY_GATEWAY_BACKEND_BASE_URL",
"http://127.0.0.1:1995",
).rstrip("/"),
database_path=Path(
@ -71,13 +71,13 @@ class GatewayConfig:
os.environ.get("MEMORY_GATEWAY_MAX_UPLOAD_BYTES", str(25 * 1024 * 1024))
),
allowed_mime_types=allowed_mime_types,
everos_ingest_attempts=int(
os.environ.get("MEMORY_GATEWAY_EVEROS_INGEST_ATTEMPTS", "3")
backend_ingest_attempts=int(
os.environ.get("MEMORY_GATEWAY_BACKEND_INGEST_ATTEMPTS", "3")
),
everos_retry_delay_seconds=float(
os.environ.get("MEMORY_GATEWAY_EVEROS_RETRY_DELAY_SECONDS", "0.25")
backend_retry_delay_seconds=float(
os.environ.get("MEMORY_GATEWAY_BACKEND_RETRY_DELAY_SECONDS", "0.25")
),
everos_timeout_seconds=float(
os.environ.get("MEMORY_GATEWAY_EVEROS_TIMEOUT_SECONDS", "120")
backend_timeout_seconds=float(
os.environ.get("MEMORY_GATEWAY_BACKEND_TIMEOUT_SECONDS", "120")
),
)

View File

@ -127,11 +127,11 @@ class MemoryGatewayService:
self,
config: GatewayConfig,
repository: MemoryRepository,
everos_client: Any,
backend_client: Any,
) -> None:
self.config = config
self.repository = repository
self.everos_client = everos_client
self.backend_client = backend_client
def create_user(self, user_id: str) -> dict[str, Any]:
user_key = f"uk_{secrets.token_urlsafe(32)}"
@ -204,8 +204,8 @@ class MemoryGatewayService:
)
try:
await self._retry_everos_call(
lambda: self.everos_client.add_memory(
await self._retry_backend_call(
lambda: self.backend_client.add_memory(
self._build_add_payload(
resource=resource,
user_id=user_id,
@ -215,8 +215,8 @@ class MemoryGatewayService:
)
)
)
await self._retry_everos_call(
lambda: self.everos_client.flush_memory(session_id, app_id, project_id)
await self._retry_backend_call(
lambda: self.backend_client.flush_memory(session_id, app_id, project_id)
)
except Exception as exc:
failed = self.repository.update_resource_status(
@ -229,8 +229,8 @@ class MemoryGatewayService:
extracted = self.repository.update_resource_status(resource_id, "extracted")
return self._resource_summary(extracted or resource)
async def _retry_everos_call(self, operation: Any) -> Any:
attempts = max(1, self.config.everos_ingest_attempts)
async def _retry_backend_call(self, operation: Any) -> Any:
attempts = max(1, self.config.backend_ingest_attempts)
last_error: Exception | None = None
for attempt in range(attempts):
try:
@ -239,11 +239,11 @@ class MemoryGatewayService:
last_error = exc
if attempt == attempts - 1:
break
delay = self.config.everos_retry_delay_seconds
delay = self.config.backend_retry_delay_seconds
if delay > 0:
await asyncio.sleep(delay)
if last_error is None:
raise RuntimeError("EverOS operation failed")
raise RuntimeError("upstream memory service operation failed")
raise last_error
def _build_add_payload(
@ -367,7 +367,7 @@ class MemoryGatewayService:
)
results.extend(
self._extract_results(
await self.everos_client.search_memory(payload),
await self.backend_client.search_memory(payload),
source_scope="current_chat",
session_resource_map=session_resource_map,
user_id=user_id,
@ -393,7 +393,7 @@ class MemoryGatewayService:
)
results.extend(
self._extract_results(
await self.everos_client.search_memory(payload),
await self.backend_client.search_memory(payload),
source_scope="resources",
session_resource_map=session_resource_map,
user_id=user_id,
@ -411,7 +411,7 @@ class MemoryGatewayService:
)
results.extend(
self._extract_results(
await self.everos_client.search_memory(payload),
await self.backend_client.search_memory(payload),
source_scope="all_user_memory",
session_resource_map=session_resource_map,
user_id=user_id,
@ -438,7 +438,7 @@ class MemoryGatewayService:
}
return {
"session_id": session_id,
"everos": await self.everos_client.add_memory(payload),
"backend": await self.backend_client.add_memory(payload),
}
async def flush_memory(
@ -450,7 +450,7 @@ class MemoryGatewayService:
) -> dict[str, Any]:
return {
"session_id": session_id,
"everos": await self.everos_client.flush_memory(
"backend": await self.backend_client.flush_memory(
session_id,
app_id,
project_id,