diff --git a/scripts/restore-chat-js-with-preview.py b/scripts/restore-chat-js-with-preview.py index 9709d70..af0f26c 100644 --- a/scripts/restore-chat-js-with-preview.py +++ b/scripts/restore-chat-js-with-preview.py @@ -352,7 +352,7 @@ CHAT_HTML_AND_JS = r""" if (!skipSave && role !== 'thinking') { session.messages = session.messages || []; session.messages.push({ role: role, text: text }); - if (session.messages.length > 40) session.messages = session.messages.slice(-40); + if (session.messages.length > 200) session.messages = session.messages.slice(-200); saveSession(session); } return el; @@ -388,26 +388,36 @@ CHAT_HTML_AND_JS = r""" } if (turnstileVerified && !session._cfSent) { session._cfSent = true; } try { - var hist = (session.messages || []).slice(-20).filter(function(m){ return m.role !== 'thinking'; }).map(function(m){ + var hist = (session.messages || []).slice(-50).filter(function(m){ return m.role !== 'thinking'; }).map(function(m){ return {role: m.role === 'ai' ? 'assistant' : 'user', content: m.text}; }); var activated_nodes = _ra(session._m, msg); var questionsRemaining = (MAX - msgCount) - 1; if (questionsRemaining < 0) questionsRemaining = 0; - var r = await fetch('/api/demo', { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({ - message: msg, - history: hist, - cf_token: turnstileVerified && !session._cfSent ? turnstileToken : '', - uid: session.uid || '', - activated_nodes: activated_nodes, - engram_node_count: (session._m && session._m.nodes) ? session._m.nodes.length : 0, - questions_remaining: questionsRemaining, - is_last_question: questionsRemaining === 0 - }) - }); + // 30s frontend timeout — surfaces a real error if the soul hangs + // instead of leaving the thinking bubble spinning forever. + var ctrl = new AbortController(); + var timeoutId = setTimeout(function() { ctrl.abort(); }, 30000); + var r; + try { + r = await fetch('/api/demo', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + signal: ctrl.signal, + body: JSON.stringify({ + message: msg, + history: hist, + cf_token: turnstileVerified && !session._cfSent ? turnstileToken : '', + uid: session.uid || '', + activated_nodes: activated_nodes, + engram_node_count: (session._m && session._m.nodes) ? session._m.nodes.length : 0, + questions_remaining: questionsRemaining, + is_last_question: questionsRemaining === 0 + }) + }); + } finally { + clearTimeout(timeoutId); + } var d = await r.json(); if (thinking) thinking.remove(); _um(session, d.sn, d.se); @@ -426,7 +436,10 @@ CHAT_HTML_AND_JS = r""" addMsg('ai', reply || 'Stepped out for a moment. Try again.'); } catch(e) { if (thinking) thinking.remove(); - addMsg('ai', 'Stepped out for a moment. Try again.'); + var msg = (e && e.name === 'AbortError') + ? 'Took too long to respond — try again.' + : 'Stepped out for a moment. Try again.'; + addMsg('ai', msg); } if (msgCount < MAX && btn) btn.disabled = false; if (input) input.focus(); @@ -451,12 +464,41 @@ OLD_LINE = '' def main(): src = STYLES_EL.read_text(encoding="utf-8") - if MARKER in src: - print("styles.el already contains the share preview modal - skipping") + # If the anchor `