openvisio-agent 0.15.1 → 0.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/watch.mjs +19 -6
- package/src/ws.mjs +3 -1
package/package.json
CHANGED
package/src/watch.mjs
CHANGED
|
@@ -528,10 +528,16 @@ function createCycleRunner({ claude, agent, mcpUrl, mcpHeaders, cfgKey, mcpConfi
|
|
|
528
528
|
function loopBackendWs({ wsUrl, apiKey, identifier, slug, claude, agent, mcpConfig, mcpUrl, workdir, model, chatModel, debug }) {
|
|
529
529
|
const log = (m) => process.stdout.write('[ws ' + new Date().toISOString() + '] ' + m + '\n')
|
|
530
530
|
let handle = null
|
|
531
|
+
let statusEnabled = true
|
|
532
|
+
let lastStatusSentAt = 0
|
|
531
533
|
// Channels the agent is actively working in this cycle — drives the live
|
|
532
534
|
// agent:status broadcast (thinking → working → typing → done).
|
|
533
535
|
const statusTargets = new Set()
|
|
534
|
-
const
|
|
536
|
+
const sendStatus = (channelId, state) => {
|
|
537
|
+
if (!statusEnabled) return
|
|
538
|
+
try { if (handle) { lastStatusSentAt = Date.now(); handle.sendStatus(channelId, state) } } catch { /* best-effort */ }
|
|
539
|
+
}
|
|
540
|
+
const emitStatus = (state) => { for (const c of statusTargets) sendStatus(c, state) }
|
|
535
541
|
const canCode = !!workdir
|
|
536
542
|
// The Mastra bridge authenticates per-CALL: every openvisio-team tool needs
|
|
537
543
|
// agent_identifier + agent_api_key as arguments. Hand them over up front.
|
|
@@ -596,7 +602,7 @@ function loopBackendWs({ wsUrl, apiKey, identifier, slug, claude, agent, mcpConf
|
|
|
596
602
|
}
|
|
597
603
|
const ensureMcpSession = async () => {
|
|
598
604
|
if (mcpSessionId) return
|
|
599
|
-
const res = await mcpPost({ jsonrpc: '2.0', id: ++mcpRpcId, method: 'initialize', params: { protocolVersion: '2025-03-26', capabilities: {}, clientInfo: { name: 'openvisio-agent', version: '0.15.
|
|
605
|
+
const res = await mcpPost({ jsonrpc: '2.0', id: ++mcpRpcId, method: 'initialize', params: { protocolVersion: '2025-03-26', capabilities: {}, clientInfo: { name: 'openvisio-agent', version: '0.15.2' } } }, false)
|
|
600
606
|
if (!res.ok) throw new Error('MCP initialize HTTP ' + res.status)
|
|
601
607
|
await mcpPayload(res)
|
|
602
608
|
mcpSessionId = res.headers.get('mcp-session-id') || ''
|
|
@@ -720,7 +726,7 @@ function loopBackendWs({ wsUrl, apiKey, identifier, slug, claude, agent, mcpConf
|
|
|
720
726
|
}
|
|
721
727
|
} finally {
|
|
722
728
|
if (heartbeat) clearInterval(heartbeat)
|
|
723
|
-
for (const c of targets) {
|
|
729
|
+
for (const c of targets) { sendStatus(c, 'done'); statusTargets.delete(c) }
|
|
724
730
|
busy = false
|
|
725
731
|
if (queued || pending.length) { const next = queued || 'fast'; queued = null; void drain(next) }
|
|
726
732
|
}
|
|
@@ -837,15 +843,22 @@ function loopBackendWs({ wsUrl, apiKey, identifier, slug, claude, agent, mcpConf
|
|
|
837
843
|
log('agent:mention in channel ' + (cid != null ? cid : '?') + (threadRoot != null ? ' (thread ' + threadRoot + ')' : ''))
|
|
838
844
|
// Light up the live status the instant we pick this up (thinking → the cycle
|
|
839
845
|
// takes it to working → typing → done).
|
|
840
|
-
if (cid != null) { statusTargets.add(cid);
|
|
846
|
+
if (cid != null) { statusTargets.add(cid); sendStatus(cid, 'thinking') }
|
|
841
847
|
const codingMention = canCode && needsCode(text)
|
|
842
848
|
const ctx = cid != null
|
|
843
849
|
? `You were @mentioned in OpenVisio channel ${cid}${who ? ` by "${who}"` : ''}: "${text}". This mention is FOR YOU. ${codingMention ? 'This is repository work: complete the coding flow first, then send' : 'Send'} EXACTLY ONE reply with post_message: arguments: channel_id ${cid}${threadRoot != null ? `, parent_id ${threadRoot} (reply IN THAT THREAD, do not start a new top-level message)` : ''}, plus agent_identifier + agent_api_key from the AUTH line above, and a 1-3 sentence reply. Compose the whole answer, then post it ONCE. Do not post a first reply and then a revised version. FIRST read the recent messages in this thread: if you already answered this, or another agent was the one addressed, do NOT post at all. Be sure of your answer before sending.${who ? ` To @mention them back, write their EXACT full name "@${who}". A mention only links when the name matches exactly.` : ''} You ALREADY have the message here. Do not poll_inbox, and after your single reply, STOP.`
|
|
844
850
|
: undefined
|
|
845
851
|
void drain(codingMention ? 'full' : 'fast', ctx)
|
|
846
852
|
} else if (k === 'error') {
|
|
847
|
-
|
|
848
|
-
|
|
853
|
+
const detail = raw && (raw.message || raw.error || raw.reason || raw.code || raw.d?.message || raw.d?.error)
|
|
854
|
+
// Older backend stages reject agent_status. Stop its heartbeat after the
|
|
855
|
+
// first immediate rejection instead of producing an error every nine seconds.
|
|
856
|
+
if (statusEnabled && lastStatusSentAt && Date.now() - lastStatusSentAt < 3000) {
|
|
857
|
+
statusEnabled = false
|
|
858
|
+
log('live agent status unsupported by this backend; disabling status heartbeat' + (detail ? ': ' + String(detail).slice(0, 160) : ''))
|
|
859
|
+
} else {
|
|
860
|
+
log('error event: ' + (detail ? String(detail) : JSON.stringify(raw)).slice(0, 220))
|
|
861
|
+
}
|
|
849
862
|
} else {
|
|
850
863
|
log('event ' + k)
|
|
851
864
|
}
|
package/src/ws.mjs
CHANGED
|
@@ -79,7 +79,9 @@ export function connectAgentWs({ wsUrl, apiKey, identifier, onEvent, onConnect,
|
|
|
79
79
|
try { msg = JSON.parse(typeof ev.data === 'string' ? ev.data : String(ev.data)) } catch { return }
|
|
80
80
|
const kind = msg && msg.k
|
|
81
81
|
if (!kind || kind === 'keepalive:ack') return // keepalive round-trip, nothing to do
|
|
82
|
-
|
|
82
|
+
// Error metadata often lives on the JSON envelope rather than `d`. Preserve
|
|
83
|
+
// it so callers do not receive an unhelpful empty object.
|
|
84
|
+
try { onEvent(kind, kind === 'error' ? msg : msg.d) } catch (e) { log('event handler error: ' + (e && e.message ? e.message : e)) }
|
|
83
85
|
})
|
|
84
86
|
|
|
85
87
|
const down = (why) => {
|