diff options
| author | Agando <roduccomm@gmail.com> | 2026-10-23 20:25:19 +0200 |
|---|---|---|
| committer | Agando <roduccomm@gmail.com> | 2026-10-23 20:25:19 +0200 |
| commit | bc013618059fb5b4d08f23fb039252918c1aec99 (patch) | |
| tree | d0a8e81b7457e76520ba282d7f10b8d8be6205ec | |
| parent | a803cc418260f977d8086f113bcc8008839400f5 (diff) | |
fix(newos4): agent read gets its own chat cursor (v4.6.76)
Two readers shared one cursor. The 30 s UI poller printed each reply and advanced
webx11_chat_state.cursor, so the agent's chat_hermes read then asked for 'since=<that>'
and got an empty list — the answer appeared on the terminal and never reached the model.
That is the reported symptom exactly.
chat_hermes read now uses webx11_chat_agent_cursor, starts from 0 on first use so the
whole thread is visible, and never touches the display cursor. Empty reads say why
('still awaiting Hermes' vs 'no new messages since your last read').
Proven: UI poll consumed the reply (printed to terminal), then chat_hermes read still
returned both the agent's question and Hermes's answer.
| -rw-r--r-- | main.html | 6 | ||||
| -rw-r--r-- | modules/core/core-bundle.js | 20 | ||||
| -rw-r--r-- | modules/core/module-aiassist.js | 20 | ||||
| -rw-r--r-- | modules/core/module-loader.js | 2 |
4 files changed, 34 insertions, 14 deletions
@@ -1349,13 +1349,13 @@ </script> <!-- v4.5.63: A2A scratchpad fixes + agent-register arg fix --> -<script src="modules/core/core-bundle.js?v=v4.6.75"></script> +<script src="modules/core/core-bundle.js?v=v4.6.76"></script> <!-- Async dependency-ordered module loader now only initializes terminal and loads optional ext modules --> -<script src="modules/core/module-loader.js?v=v4.6.75"></script> +<script src="modules/core/module-loader.js?v=v4.6.76"></script> <!-- Critical ext bundle loads AFTER webx11 exists so registerModule calls work --> -<script src="modules/ext/critical-ext-bundle.js?v=v4.6.75"></script> +<script src="modules/ext/critical-ext-bundle.js?v=v4.6.76"></script> <script> // ═══ ONE TRUE VERSION SOURCE ═══ diff --git a/modules/core/core-bundle.js b/modules/core/core-bundle.js index a689774..697b5ec 100644 --- a/modules/core/core-bundle.js +++ b/modules/core/core-bundle.js @@ -11094,19 +11094,29 @@ buildSystemPrompt() { }); } const st = ds._chatThread(); + // v4.6.76: a SEPARATE cursor from the terminal display. The UI poller + // runs every 30 s and advances the shared cursor, so a read that used it + // returned nothing — the answer was printed for the human and the model + // never saw it. Two readers, two cursors. First read is from 0. + let ac = 0; + try { ac = parseInt(localStorage.getItem('webx11_chat_agent_cursor') || '0', 10) || 0; } catch (e) { ac = 0; } const resp = await fetch( - '/spaces/newos4/api/chat/poll.php' + (st.cursor ? '?since=' + st.cursor : ''), + '/spaces/newos4/api/chat/poll.php' + (ac ? '?since=' + ac : ''), { headers: { 'X-Chat-Token': st.token } }); const j = await resp.json().catch(() => null); if (!resp.ok || !j || !j.success) { return JSON.stringify({ error: (j && j.error) || ('HTTP ' + resp.status) }); } - if (j.cursor) ds._chatSaveState({ token: st.token, cursor: j.cursor, thread: j.thread || '' }); + if (j.cursor) { try { localStorage.setItem('webx11_chat_agent_cursor', String(j.cursor)); } catch (e) {} } + const msgs = (j.messages || []).slice(-10).map(m => ({ + author: m.author, ts: m.ts, text: m.text + })); return JSON.stringify({ awaiting: j.awaiting, - messages: (j.messages || []).slice(-10).map(m => ({ - author: m.author, ts: m.ts, text: m.text - })) + messages: msgs, + note: msgs.length ? undefined + : (j.awaiting ? 'no reply yet — still awaiting Hermes' + : 'no new messages since your last read') }); } catch (e) { return JSON.stringify({ error: e.message }); diff --git a/modules/core/module-aiassist.js b/modules/core/module-aiassist.js index ce650b9..cefff5d 100644 --- a/modules/core/module-aiassist.js +++ b/modules/core/module-aiassist.js @@ -2707,19 +2707,29 @@ buildSystemPrompt() { }); } const st = ds._chatThread(); + // v4.6.76: a SEPARATE cursor from the terminal display. The UI poller + // runs every 30 s and advances the shared cursor, so a read that used it + // returned nothing — the answer was printed for the human and the model + // never saw it. Two readers, two cursors. First read is from 0. + let ac = 0; + try { ac = parseInt(localStorage.getItem('webx11_chat_agent_cursor') || '0', 10) || 0; } catch (e) { ac = 0; } const resp = await fetch( - '/spaces/newos4/api/chat/poll.php' + (st.cursor ? '?since=' + st.cursor : ''), + '/spaces/newos4/api/chat/poll.php' + (ac ? '?since=' + ac : ''), { headers: { 'X-Chat-Token': st.token } }); const j = await resp.json().catch(() => null); if (!resp.ok || !j || !j.success) { return JSON.stringify({ error: (j && j.error) || ('HTTP ' + resp.status) }); } - if (j.cursor) ds._chatSaveState({ token: st.token, cursor: j.cursor, thread: j.thread || '' }); + if (j.cursor) { try { localStorage.setItem('webx11_chat_agent_cursor', String(j.cursor)); } catch (e) {} } + const msgs = (j.messages || []).slice(-10).map(m => ({ + author: m.author, ts: m.ts, text: m.text + })); return JSON.stringify({ awaiting: j.awaiting, - messages: (j.messages || []).slice(-10).map(m => ({ - author: m.author, ts: m.ts, text: m.text - })) + messages: msgs, + note: msgs.length ? undefined + : (j.awaiting ? 'no reply yet — still awaiting Hermes' + : 'no new messages since your last read') }); } catch (e) { return JSON.stringify({ error: e.message }); diff --git a/modules/core/module-loader.js b/modules/core/module-loader.js index 678cdda..e52a846 100644 --- a/modules/core/module-loader.js +++ b/modules/core/module-loader.js @@ -4,7 +4,7 @@ // Core module bundle loaded synchronously in main.html. // This loader only handles version cache-busting, splash, terminal init, and optional ext modules. - const LATEST_VER = 'v4.6.75'; + const LATEST_VER = 'v4.6.76'; const CACHE = '?v=' + LATEST_VER; const stored = localStorage.getItem('webx11_cache_ver'); if (stored !== LATEST_VER) { |