This commit is contained in:
@@ -28,11 +28,14 @@ class ThreadHistoryService:
|
||||
try:
|
||||
# 查询 checkpoints 表获取用户的线程列表
|
||||
async with self.checkpointer.conn.cursor() as cur:
|
||||
# 查询每个线程的最新 checkpoint 和创建时间
|
||||
# 在较新的 LangGraph 版本中,AsyncPostgresSaver 创建的 checkpoints 表
|
||||
# 没有 created_at 列,而是使用 checkpoint_id 作为时间排序依据。
|
||||
# 我们可以直接按 thread_id 去重,并用 checkpoint_id 排序。
|
||||
# 另外,用户的 metadata 存储在 metadata JSONB 列中。
|
||||
query = """
|
||||
SELECT
|
||||
thread_id,
|
||||
MAX(created_at) as last_updated
|
||||
MAX(checkpoint_id) as last_updated
|
||||
FROM checkpoints
|
||||
WHERE metadata->>'user_id' = %s
|
||||
GROUP BY thread_id
|
||||
@@ -49,17 +52,20 @@ class ThreadHistoryService:
|
||||
# 获取该线程的状态
|
||||
state = await self.checkpointer.aget_tuple({"configurable": {"thread_id": thread_id}})
|
||||
|
||||
if state and state.values:
|
||||
messages = state.values.get("messages", [])
|
||||
summary = self._extract_summary(messages)
|
||||
message_count = len([m for m in messages if hasattr(m, 'type') and m.type in ["human", "ai"]])
|
||||
if state and hasattr(state, 'checkpoint') and isinstance(state.checkpoint, dict):
|
||||
messages = state.checkpoint.get("channel_values", {}).get("messages", [])
|
||||
|
||||
threads.append({
|
||||
"thread_id": thread_id,
|
||||
"last_updated": row['last_updated'].isoformat() if row['last_updated'] else "",
|
||||
"summary": summary,
|
||||
"message_count": message_count
|
||||
})
|
||||
if messages:
|
||||
summary = self._extract_summary(messages)
|
||||
message_count = len([m for m in messages if hasattr(m, 'type') and m.type in ["human", "ai"]])
|
||||
|
||||
threads.append({
|
||||
"thread_id": thread_id,
|
||||
# checkpoint_id 是一个类似于 uuid 的字符串,其中可能包含时间戳信息,也可以直接作为唯一标识
|
||||
"last_updated": row['last_updated'] if row['last_updated'] else "",
|
||||
"summary": summary,
|
||||
"message_count": message_count
|
||||
})
|
||||
|
||||
return threads
|
||||
|
||||
@@ -80,10 +86,13 @@ class ThreadHistoryService:
|
||||
try:
|
||||
state = await self.checkpointer.aget_tuple({"configurable": {"thread_id": thread_id}})
|
||||
|
||||
if state is None or not state.values:
|
||||
if state is None:
|
||||
return []
|
||||
|
||||
messages = state.values.get("messages", [])
|
||||
messages = state.checkpoint.get("channel_values", {}).get("messages", []) if hasattr(state, 'checkpoint') and isinstance(state.checkpoint, dict) else []
|
||||
|
||||
if not messages:
|
||||
return []
|
||||
|
||||
# 转换 LangChain 消息对象为字典
|
||||
result = []
|
||||
|
||||
Reference in New Issue
Block a user