2026-10-22 20:50:10 +08:00
|
|
|
"""会话业务状态 repository(作业 6-1/6-2)。
|
|
|
|
|
|
|
|
|
|
抽象出 repository 接口,使应用服务不依赖具体存储;
|
|
|
|
|
作业 6 用内存实现跑通四接口,作业 7 再替换为 PostgreSQL 实现
|
|
|
|
|
(对话 checkpoint 已由 LangGraph checkpointer 承担,本层只管
|
|
|
|
|
业务字段——单一事实来源,图每轮读取最新值)。
|
|
|
|
|
|
|
|
|
|
语义约定:
|
|
|
|
|
- 业务状态按外部业务键(hphm1、ywrysw...)扁平存储,值为内部强类型;
|
|
|
|
|
- 不存在的会话视为空状态(读取返回 {}),与首轮 checkpoint 无字段一致;
|
|
|
|
|
- delete 幂等:重复删除固定成功,不抛异常(行为进测试)。
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from typing import Protocol
|
|
|
|
|
|
|
|
|
|
|
2026-10-23 19:48:29 +08:00
|
|
|
class CheckpointNotFoundError(Exception):
|
|
|
|
|
"""存储适配器明确确认线程不存在;不能用一般存储异常代替。"""
|
|
|
|
|
|
|
|
|
|
|
2026-10-22 20:50:10 +08:00
|
|
|
class SessionRepository(Protocol):
|
|
|
|
|
"""业务字段存储接口(作业 7 由 PostgreSQL 实现替换)。"""
|
|
|
|
|
|
|
|
|
|
def load(self, session_id: str) -> dict:
|
|
|
|
|
"""读取会话业务字段;无记录时返回空 dict。"""
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
def apply_update(self, session_id: str, patch: dict) -> dict:
|
|
|
|
|
"""合并差量并返回合并后的完整业务字段。"""
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
def delete(self, session_id: str) -> None:
|
|
|
|
|
"""删除会话业务状态;幂等,重复删除不抛异常。"""
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InMemorySessionRepository:
|
|
|
|
|
"""内存实现:字典存储,仅用于单进程开发与测试。"""
|
|
|
|
|
|
|
|
|
|
def __init__(self) -> None:
|
|
|
|
|
self._store: dict[str, dict] = {}
|
|
|
|
|
|
|
|
|
|
def load(self, session_id: str) -> dict:
|
|
|
|
|
return dict(self._store.get(session_id) or {})
|
|
|
|
|
|
|
|
|
|
def apply_update(self, session_id: str, patch: dict) -> dict:
|
|
|
|
|
state = self._store.setdefault(session_id, {})
|
|
|
|
|
state.update(patch)
|
|
|
|
|
return dict(state)
|
|
|
|
|
|
|
|
|
|
def delete(self, session_id: str) -> None:
|
|
|
|
|
# 幂等:pop 的缺省值吞掉不存在的情况,重复删除行为固定为成功
|
|
|
|
|
self._store.pop(session_id, None)
|
|
|
|
|
|
|
|
|
|
|
2026-10-23 19:48:29 +08:00
|
|
|
__all__ = ["CheckpointNotFoundError", "SessionRepository", "InMemorySessionRepository"]
|