mirror of
https://github.com/turnstonelabs/turnstone.git
synced 2026-08-12 23:12:23 -06:00
fix: auto-titler SSE event + SSE reconnection after restart (#125)
* fix: auto-titler SSE event + SSE reconnection after restart _generate_title() now calls self.ui.on_rename() after persisting the title, so the tab bar, bridge, and console all update in real time. Also handles multi-part (vision) content and replaces silent except with log.debug. SSE onerror handler now parses the workstreams response, replaces the stale workstreams map, and switches to the first available workstream if the current ws_id no longer exists (e.g. after server restart). Previously it retried the stale ws_id forever. * fix: address PR #125 review — avoid double reconnect + sync tab bar Return immediately after switchTab/showDashboard on stale ws_id to prevent scheduling a redundant connectContentSSE via setTimeout. Always re-render tab bar after replacing the workstreams map so DOM stays in sync even when currentWsId is still valid.
This commit is contained in:
@@ -628,10 +628,14 @@ class ChatSession:
|
||||
user_msg = ""
|
||||
asst_msg = ""
|
||||
for m in self.messages:
|
||||
content = m.get("content") or ""
|
||||
# Handle multi-part content (vision messages)
|
||||
if isinstance(content, list):
|
||||
content = " ".join(p.get("text", "") for p in content if isinstance(p, dict))
|
||||
if m["role"] == "user" and not user_msg:
|
||||
user_msg = (m.get("content") or "")[:300]
|
||||
user_msg = content[:300]
|
||||
elif m["role"] == "assistant" and not asst_msg:
|
||||
asst_msg = (m.get("content") or "")[:200]
|
||||
asst_msg = content[:200]
|
||||
if user_msg and asst_msg:
|
||||
break
|
||||
if not user_msg:
|
||||
@@ -667,8 +671,9 @@ class ChatSession:
|
||||
title = raw.split("\n")[0].strip().strip('"').strip("'")
|
||||
if title:
|
||||
update_workstream_title(self._ws_id, title[:80])
|
||||
self.ui.on_rename(title[:80])
|
||||
except Exception:
|
||||
pass # Title generation is non-critical
|
||||
log.debug("Title generation failed for ws=%s", self._ws_id, exc_info=True)
|
||||
|
||||
def resume(self, ws_id: str) -> bool:
|
||||
"""Load messages from a previous workstream and resume it.
|
||||
|
||||
@@ -592,10 +592,31 @@ function connectContentSSE(wsId) {
|
||||
showLogin();
|
||||
return;
|
||||
}
|
||||
setTimeout(function () {
|
||||
connectContentSSE(currentWsId);
|
||||
}, contentRetryDelay);
|
||||
contentRetryDelay = Math.min(contentRetryDelay * 2, 30000);
|
||||
return r.json().then(function (data) {
|
||||
// Replace workstream list — IDs may have changed after restart
|
||||
var freshIds = {};
|
||||
workstreams = {};
|
||||
(data.workstreams || []).forEach(function (ws) {
|
||||
workstreams[ws.id] = { name: ws.name, state: ws.state };
|
||||
freshIds[ws.id] = true;
|
||||
});
|
||||
// Always re-render tabs since workstreams map was replaced
|
||||
renderTabBar();
|
||||
// If current ws_id is stale, switch to first available
|
||||
if (currentWsId && !freshIds[currentWsId]) {
|
||||
var ids = Object.keys(freshIds);
|
||||
if (ids.length) {
|
||||
switchTab(ids[0]);
|
||||
} else {
|
||||
showDashboard();
|
||||
}
|
||||
return; // switchTab/showDashboard handles SSE connection
|
||||
}
|
||||
setTimeout(function () {
|
||||
connectContentSSE(currentWsId);
|
||||
}, contentRetryDelay);
|
||||
contentRetryDelay = Math.min(contentRetryDelay * 2, 30000);
|
||||
});
|
||||
})
|
||||
.catch(function () {
|
||||
setTimeout(function () {
|
||||
|
||||
Reference in New Issue
Block a user