diff options
| author | Agando <roduccomm@gmail.com> | 2026-10-23 19:36:52 +0200 |
|---|---|---|
| committer | Agando <roduccomm@gmail.com> | 2026-10-23 19:36:52 +0200 |
| commit | c9924e45d765b5c28ac0abcf78339b828b4ef0a0 (patch) | |
| tree | 8dcfe6589e7bfc4429f78a3e8474c4735650a434 /modules/core/module-aiassist.js | |
| parent | 0d2365ab202ba5c9b1d0604467af0594dc7360de (diff) | |
feat(newos4): hermes command, auto-poll, chat_hermes tool, token reset (v4.6.73)
Phase C as repo edits (browser edits in _mods/ do not survive a reload).
- `hermes <msg>`: sends through the chat endpoint and always prints an outcome β
'π¨ Sendingβ¦' then either 'β
sent id=β¦ epoch=β¦' or a coded error with a hint
(429 retry later, 503 host busy, 401 run hermes-reset). `feedback` stays as the alias.
- NOT named `chat`: ChatStudioModule already registers `chat` and dispatch walks modules
in order, so a second `chat` was silently unreachable. Found by test, not by reading.
- `hermes-poll` / `feedback-inbox`, `hermes-reset` (token rotation).
- Poller: 30 s, paused while the tab is hidden, polls on visibilitychange, first poll
adopts the cursor and prints nothing, cursor persisted in webx11_chat_state.
- `chat_hermes` tool: send + read from inside the agent loop.
- Contract/help updated for the rename.
Acceptance: 'hermes acceptance test' in the browser, reply written host-side with
scripts/chat.py, appeared in the terminal by itself 30 s later with no command typed
(cursor 1792776973800).
Diffstat (limited to 'modules/core/module-aiassist.js')
| -rw-r--r-- | modules/core/module-aiassist.js | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/modules/core/module-aiassist.js b/modules/core/module-aiassist.js index f5895f3..ce650b9 100644 --- a/modules/core/module-aiassist.js +++ b/modules/core/module-aiassist.js @@ -433,6 +433,20 @@ buildSystemPrompt() { }, { type: 'function', function: { + name: 'chat_hermes', + description: 'Send a message to Hermes, the platform operator agent, and read replies. Use when a task needs a decision only the operator can make: policy, a deploy approval, scope. Replies are asynchronous β call with action "read" to check for an answer.', + parameters: { + type: 'object', + properties: { + action: { type: 'string', enum: ['send', 'read'], description: 'send a message, or read replies' }, + text: { type: 'string', description: 'message body, required for send' } + }, + required: ['action'] + } + } + }, { + type: 'function', + function: { name: 'spawn_agent', description: '(DESTRUCTIVE) Spawn a new worker agent with a role and capabilities', parameters: { @@ -2676,6 +2690,41 @@ buildSystemPrompt() { } return JSON.stringify({ agents: results, count: results.length }); } + case 'chat_hermes': { + // v4.6.71: one channel, one store. Contract: _docs/chat-contract.md + const ds = this.terminal.moduleManager.modules['DebugSupervisorModule']; + if (!ds || typeof ds._chatPost !== 'function') { + return JSON.stringify({ error: 'chat bridge unavailable' }); + } + try { + if ((a.action || 'read') === 'send') { + const text = String(a.text || '').trim(); + if (!text) return JSON.stringify({ error: 'text is required for send' }); + const j = await ds._chatPost(text, 'agent'); + return JSON.stringify({ + sent: true, id: j.id, epoch: j.epoch, + note: 'asynchronous β call chat_hermes with action read for the answer' + }); + } + const st = ds._chatThread(); + const resp = await fetch( + '/spaces/newos4/api/chat/poll.php' + (st.cursor ? '?since=' + st.cursor : ''), + { 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 || '' }); + return JSON.stringify({ + awaiting: j.awaiting, + messages: (j.messages || []).slice(-10).map(m => ({ + author: m.author, ts: m.ts, text: m.text + })) + }); + } catch (e) { + return JSON.stringify({ error: e.message }); + } + } case 'delegate_task': { const task = a.task || ''; if (!task) return JSON.stringify({ error: 'No task provided' }); |