feat(phase4): permanent cache-control & asset versioning, canonical nabil stored_session_id & resume, dsh session persistence fix, dsh dialogue/files toggle, and collapsible conv sidebar
This commit is contained in:
+27
-6
@@ -114,7 +114,7 @@ async def list_universe_conversations(universe_id: str) -> List[Dict[str, Any]]:
|
||||
for s in backend_sessions:
|
||||
sid = str(s.get("id") or s.get("session_id") or "")
|
||||
if sid:
|
||||
stitle = s.get("title") or s.get("display_name") or f"Session {sid[:8]}"
|
||||
stitle = s.get("title") or s.get("display_name") or f"Session {sid[:15]}"
|
||||
spinned = 1 if s.get("pinned") else 0
|
||||
started_at = s.get("started_at")
|
||||
c_at = int(started_at * 1000) if isinstance(started_at, (int, float)) and started_at < 1e11 else int(time.time() * 1000)
|
||||
@@ -171,9 +171,10 @@ async def create_universe_conversation(universe_id: str, title: Optional[str] =
|
||||
data = json.loads(raw)
|
||||
if data.get("id") == req_id and "result" in data:
|
||||
res = data["result"]
|
||||
session_key = res.get("session_id") or res.get("stored_session_id")
|
||||
# Prioritize durable stored_session_id (format YYYYMMDD_HHMMSS_xxxxxx) over ephemeral handle
|
||||
session_key = res.get("stored_session_id") or res.get("session_id")
|
||||
break
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
# Fallback if WS fails
|
||||
session_key = f"nabil_{uuid.uuid4().hex[:12]}"
|
||||
|
||||
@@ -234,7 +235,6 @@ async def get_conversation_messages(universe_id: str, session_key: str) -> List[
|
||||
|
||||
async def stream_chat_messages(universe_id: str, session_key: str, message: str) -> AsyncGenerator[str, None]:
|
||||
"""Streams chat chunks using Server-Sent Events (SSE)."""
|
||||
# Touch conversation in SQLite and update title if first message
|
||||
existing = get_conversation(universe_id, session_key)
|
||||
if existing and existing.get("title") in ("Nouvelle conversation", "Untitled", None):
|
||||
summary_title = (message[:38] + "...") if len(message) > 38 else message
|
||||
@@ -272,13 +272,35 @@ async def stream_chat_messages(universe_id: str, session_key: str, message: str)
|
||||
ping_interval=20,
|
||||
ping_timeout=20
|
||||
) as ws:
|
||||
# 1. First resume/activate the session to get the active live handle
|
||||
resume_req_id = f"res-{uuid.uuid4().hex[:8]}"
|
||||
await ws.send(json.dumps({
|
||||
"jsonrpc": "2.0",
|
||||
"id": resume_req_id,
|
||||
"method": "session.resume",
|
||||
"params": {"session_id": session_key}
|
||||
}))
|
||||
|
||||
active_sid = session_key
|
||||
try:
|
||||
while True:
|
||||
raw_res = await asyncio.wait_for(ws.recv(), timeout=4.0)
|
||||
data_res = json.loads(raw_res)
|
||||
if data_res.get("id") == resume_req_id:
|
||||
if "result" in data_res:
|
||||
active_sid = data_res["result"].get("session_id") or session_key
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 2. Submit prompt with active_sid
|
||||
req_id = f"prompt-{uuid.uuid4().hex[:8]}"
|
||||
send_payload = {
|
||||
"jsonrpc": "2.0",
|
||||
"id": req_id,
|
||||
"method": "prompt.submit",
|
||||
"params": {
|
||||
"session_id": session_key,
|
||||
"session_id": active_sid,
|
||||
"text": message
|
||||
}
|
||||
}
|
||||
@@ -300,7 +322,6 @@ async def stream_chat_messages(universe_id: str, session_key: str, message: str)
|
||||
yield f"event: chunk\ndata: {json.dumps({'text': accumulated_text, 'chunk': delta, 'fullReplace': True})}\n\n"
|
||||
elif ev_type in ("reasoning.delta", "thinking.delta"):
|
||||
delta = payload.get("text", "")
|
||||
# We can stream reasoning as needed
|
||||
elif ev_type in ("message.finish", "session.idle", "reasoning.available") or data.get("method") in ("chat.done", "session.done"):
|
||||
yield f"event: done\ndata: {json.dumps({'state': 'complete', 'text': accumulated_text})}\n\n"
|
||||
break
|
||||
|
||||
Reference in New Issue
Block a user