feat: implement process-local internal authentication for Gateway and enhance CSRF handling

This commit is contained in:
JeffJiang
2026-04-26 22:15:43 +08:00
parent 897dae5475
commit da174dfd4d
15 changed files with 134 additions and 26 deletions
@@ -70,6 +70,7 @@ class MemoryUpdateQueue:
thread_id=thread_id,
messages=messages,
agent_name=agent_name,
user_id=user_id,
correction_detected=correction_detected,
reinforcement_detected=reinforcement_detected,
)
@@ -82,6 +83,7 @@ class MemoryUpdateQueue:
thread_id: str,
messages: list[Any],
agent_name: str | None = None,
user_id: str | None = None,
correction_detected: bool = False,
reinforcement_detected: bool = False,
) -> None:
@@ -95,6 +97,7 @@ class MemoryUpdateQueue:
thread_id=thread_id,
messages=messages,
agent_name=agent_name,
user_id=user_id,
correction_detected=correction_detected,
reinforcement_detected=reinforcement_detected,
)
@@ -108,6 +111,7 @@ class MemoryUpdateQueue:
thread_id: str,
messages: list[Any],
agent_name: str | None,
user_id: str | None,
correction_detected: bool,
reinforcement_detected: bool,
) -> None:
@@ -121,6 +125,7 @@ class MemoryUpdateQueue:
thread_id=thread_id,
messages=messages,
agent_name=agent_name,
user_id=user_id,
correction_detected=merged_correction_detected,
reinforcement_detected=merged_reinforcement_detected,
)
@@ -66,7 +66,7 @@ class FileMemoryStorage(MemoryStorage):
"""Initialize the file memory storage."""
# Per-user/agent memory cache: keyed by (user_id, agent_name) tuple (None = global)
# Value: (memory_data, file_mtime)
self._memory_cache: dict[str | None, tuple[dict[str, Any], float | None]] = {}
self._memory_cache: dict[tuple[str | None, str | None], tuple[dict[str, Any], float | None]] = {}
# Guards all reads and writes to _memory_cache across concurrent callers.
self._cache_lock = threading.Lock()
@@ -116,9 +116,14 @@ class FileMemoryStorage(MemoryStorage):
logger.warning("Failed to load memory file: %s", e)
return create_empty_memory()
@staticmethod
def _cache_key(agent_name: str | None = None, *, user_id: str | None = None) -> tuple[str | None, str | None]:
return (user_id, agent_name)
def load(self, agent_name: str | None = None, *, user_id: str | None = None) -> dict[str, Any]:
"""Load memory data (cached with file modification time check)."""
file_path = self._get_memory_file_path(agent_name, user_id=user_id)
cache_key = self._cache_key(agent_name, user_id=user_id)
try:
current_mtime = file_path.stat().st_mtime if file_path.exists() else None
@@ -126,14 +131,14 @@ class FileMemoryStorage(MemoryStorage):
current_mtime = None
with self._cache_lock:
cached = self._memory_cache.get(agent_name)
cached = self._memory_cache.get(cache_key)
if cached is not None and cached[1] == current_mtime:
return cached[0]
memory_data = self._load_memory_from_file(agent_name)
memory_data = self._load_memory_from_file(agent_name, user_id=user_id)
with self._cache_lock:
self._memory_cache[agent_name] = (memory_data, current_mtime)
self._memory_cache[cache_key] = (memory_data, current_mtime)
return memory_data
@@ -141,6 +146,7 @@ class FileMemoryStorage(MemoryStorage):
"""Reload memory data from file, forcing cache invalidation."""
file_path = self._get_memory_file_path(agent_name, user_id=user_id)
memory_data = self._load_memory_from_file(agent_name, user_id=user_id)
cache_key = self._cache_key(agent_name, user_id=user_id)
try:
mtime = file_path.stat().st_mtime if file_path.exists() else None
@@ -148,12 +154,13 @@ class FileMemoryStorage(MemoryStorage):
mtime = None
with self._cache_lock:
self._memory_cache[agent_name] = (memory_data, mtime)
self._memory_cache[cache_key] = (memory_data, mtime)
return memory_data
def save(self, memory_data: dict[str, Any], agent_name: str | None = None, *, user_id: str | None = None) -> bool:
"""Save memory data to file and update cache."""
file_path = self._get_memory_file_path(agent_name, user_id=user_id)
cache_key = self._cache_key(agent_name, user_id=user_id)
try:
file_path.parent.mkdir(parents=True, exist_ok=True)
@@ -174,7 +181,7 @@ class FileMemoryStorage(MemoryStorage):
mtime = None
with self._cache_lock:
self._memory_cache[agent_name] = (memory_data, mtime)
self._memory_cache[cache_key] = (memory_data, mtime)
logger.info("Memory saved to %s", file_path)
return True
except OSError as e:
@@ -141,7 +141,7 @@ class RunJournal(BaseCallbackHandler):
logger.info(f"on_chat_model_start {run_id}: tags={tags} serialized={serialized} messages={messages}")
# Capture the first human message sent to any LLM in this run.
if not self._first_human_msg:
if not self._first_human_msg and not messages:
for batch in messages.reversed():
for m in batch.reversed():
if isinstance(m, HumanMessage) and m.name != "summary":
@@ -66,7 +66,10 @@ def _normalize_presented_filepath(
virtual_prefix = VIRTUAL_PATH_PREFIX.lstrip("/")
if stripped == virtual_prefix or stripped.startswith(virtual_prefix + "/"):
actual_path = get_paths().resolve_virtual_path(thread_id, filepath, user_id=get_effective_user_id())
try:
actual_path = get_paths().resolve_virtual_path(thread_id, filepath, user_id=get_effective_user_id())
except TypeError:
actual_path = get_paths().resolve_virtual_path(thread_id, filepath)
else:
actual_path = Path(filepath).expanduser().resolve()