fix(gui): 修复启动报错和对话列表不正确的两个关键Bug
Bug1: 'async for' requires __aiter__ method, got coroutine - EventQueue.subscribe() 在 _closed=True 时直接 return, Python 将其视为协程而非异步生成器 - 修复: 添加不可达的 yield 语句,确保函数始终为异步生成器 Bug2: 启动时对话列表全显示"对话",无法识别之前的对话 - list_conversations() 不加载消息,_derive_conversation_title 遍历空 messages 列表导致标题全为"对话" - 修复: list_conversations 从 SQLite 加载首条用户消息用于标题推导 Bug2b: WebSocket 不响应前端对话切换 - conv 变量只在首条消息时设置,之后忽略 conversation_id - 修复: 每条消息都检查 conversation_id,切换时更新 conv
This commit is contained in:
parent
771756814f
commit
b4ba65b9ca
|
|
@ -276,13 +276,25 @@ class SqliteConversationStore:
|
||||||
if conv_id in self._cache:
|
if conv_id in self._cache:
|
||||||
result.append(self._cache[conv_id])
|
result.append(self._cache[conv_id])
|
||||||
else:
|
else:
|
||||||
result.append(
|
conv = Conversation(
|
||||||
Conversation(
|
id=conv_id,
|
||||||
id=conv_id,
|
created_at=self._str_to_dt(row["created_at"]),
|
||||||
created_at=self._str_to_dt(row["created_at"]),
|
updated_at=self._str_to_dt(row["updated_at"]),
|
||||||
updated_at=self._str_to_dt(row["updated_at"]),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
# Load first user message from SQLite for title derivation
|
||||||
|
try:
|
||||||
|
title_cursor = await db.execute(
|
||||||
|
"SELECT content FROM messages "
|
||||||
|
"WHERE conversation_id = ? AND role = 'user' "
|
||||||
|
"ORDER BY timestamp ASC LIMIT 1",
|
||||||
|
(conv_id,),
|
||||||
|
)
|
||||||
|
title_row = await title_cursor.fetchone()
|
||||||
|
if title_row:
|
||||||
|
conv.messages.append(ChatMessage(role="user", content=title_row["content"]))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
result.append(conv)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
async def restore_from_store(
|
async def restore_from_store(
|
||||||
|
|
|
||||||
|
|
@ -210,7 +210,9 @@ class EventQueue:
|
||||||
保证不会遗漏或重复事件。
|
保证不会遗漏或重复事件。
|
||||||
"""
|
"""
|
||||||
if self._closed:
|
if self._closed:
|
||||||
|
# Must yield to make this an async generator, not a coroutine
|
||||||
return
|
return
|
||||||
|
yield # noqa: unreachable — makes this an async generator
|
||||||
|
|
||||||
# P1 #13 fix: enforce subscriber cap to prevent resource exhaustion
|
# P1 #13 fix: enforce subscriber cap to prevent resource exhaustion
|
||||||
# from malicious resume floods or runaway client loops.
|
# from malicious resume floods or runaway client loops.
|
||||||
|
|
|
||||||
|
|
@ -1141,9 +1141,13 @@ async def portal_websocket(websocket: WebSocket):
|
||||||
if not message_text:
|
if not message_text:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Create conversation on first message (not on connect)
|
# Create or switch conversation based on conversation_id from frontend
|
||||||
if conv is None:
|
conv_id = msg.get("conversation_id")
|
||||||
conv_id = msg.get("conversation_id")
|
if conv_id:
|
||||||
|
if conv is None or conv.id != conv_id:
|
||||||
|
conv = await _conversation_store.get_or_create(conv_id)
|
||||||
|
await websocket.send_json({"type": "connected", "conversation_id": conv.id})
|
||||||
|
elif conv is None:
|
||||||
conv = await _conversation_store.get_or_create(conv_id)
|
conv = await _conversation_store.get_or_create(conv_id)
|
||||||
await websocket.send_json({"type": "connected", "conversation_id": conv.id})
|
await websocket.send_json({"type": "connected", "conversation_id": conv.id})
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue