openvisio-agent 0.16.0 → 0.16.1
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/events.mjs +21 -0
- package/src/watch.mjs +6 -2
package/package.json
CHANGED
package/src/events.mjs
CHANGED
|
@@ -25,3 +25,24 @@ export function taskAgentId(task) {
|
|
|
25
25
|
if (!task || typeof task !== 'object') return null
|
|
26
26
|
return task.agent_id != null ? task.agent_id : (task.agentId != null ? task.agentId : null)
|
|
27
27
|
}
|
|
28
|
+
|
|
29
|
+
// A mention event means this agent's name appeared somewhere, not necessarily
|
|
30
|
+
// that the request was addressed to it. Reject a later-agent hand-off before a
|
|
31
|
+
// model starts, while keeping explicitly shared requests addressed to both.
|
|
32
|
+
export function requestTargetsLaterAgent(text, selfAliases) {
|
|
33
|
+
const value = String(text || '')
|
|
34
|
+
const aliases = new Set((selfAliases || []).map((v) => String(v || '').toLowerCase().replace(/^@/, '')).filter(Boolean))
|
|
35
|
+
if (!value || !aliases.size) return false
|
|
36
|
+
|
|
37
|
+
const mentions = [...value.matchAll(/@([a-z0-9](?:[a-z0-9_.-]*[a-z0-9_-])?)/gi)].map((match) => ({ name: match[1].toLowerCase(), index: match.index ?? 0, end: (match.index ?? 0) + match[0].length }))
|
|
38
|
+
const self = mentions.find((mention) => aliases.has(mention.name))
|
|
39
|
+
if (!self) return false
|
|
40
|
+
const later = mentions.find((mention) => mention.index > self.index && !aliases.has(mention.name))
|
|
41
|
+
if (!later) return false
|
|
42
|
+
|
|
43
|
+
const bridge = value.slice(self.end, later.index).toLowerCase()
|
|
44
|
+
const suffix = value.slice(later.end).trim().toLowerCase()
|
|
45
|
+
const shared = /\b(?:and|with|alongside)\s*$/.test(bridge.trim()) && /\b(?:both|together|you (?:two|all)|everyone)\b/.test(suffix)
|
|
46
|
+
if (shared) return false
|
|
47
|
+
return /\?|^(?:[,.:;-]\s*)?(?:please\s+)?(?:can|could|would|will|do|write|create|make|send|fix|check|review|prepare|give|tell|help|handle|take|move|update|implement)\b/i.test(suffix)
|
|
48
|
+
}
|
package/src/watch.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import { homedir } from 'node:os'
|
|
|
10
10
|
import { join, dirname } from 'node:path'
|
|
11
11
|
import { OV_DIR, DEFAULT_WORKSPACE, readConfig, writeJson, configPath, onPath, fail, ok, info, slugify, stripSlash, chmodSafe } from './lib.mjs'
|
|
12
12
|
import { connectAgentWs, assertWebSocket } from './ws.mjs'
|
|
13
|
-
import { taskAgentId, taskFromEvent } from './events.mjs'
|
|
13
|
+
import { requestTargetsLaterAgent, taskAgentId, taskFromEvent } from './events.mjs'
|
|
14
14
|
|
|
15
15
|
// Behaviour prompts. The openvisio-team MCP bridge requires the agent's
|
|
16
16
|
// credentials as ARGUMENTS on every tool call — those are injected at runtime by
|
|
@@ -610,7 +610,7 @@ function loopBackendWs({ wsUrl, apiKey, identifier, slug, claude, agent, mcpConf
|
|
|
610
610
|
}
|
|
611
611
|
const ensureMcpSession = async () => {
|
|
612
612
|
if (mcpSessionId) return
|
|
613
|
-
const res = await mcpPost({ jsonrpc: '2.0', id: ++mcpRpcId, method: 'initialize', params: { protocolVersion: '2025-03-26', capabilities: {}, clientInfo: { name: 'openvisio-agent', version: '0.16.
|
|
613
|
+
const res = await mcpPost({ jsonrpc: '2.0', id: ++mcpRpcId, method: 'initialize', params: { protocolVersion: '2025-03-26', capabilities: {}, clientInfo: { name: 'openvisio-agent', version: '0.16.1' } } }, false)
|
|
614
614
|
if (!res.ok) throw new Error('MCP initialize HTTP ' + res.status)
|
|
615
615
|
await mcpPayload(res)
|
|
616
616
|
mcpSessionId = res.headers.get('mcp-session-id') || ''
|
|
@@ -828,6 +828,10 @@ function loopBackendWs({ wsUrl, apiKey, identifier, slug, claude, agent, mcpConf
|
|
|
828
828
|
const dedupeKey = mid != null ? 'id:' + mid : 'sig:' + (cid != null ? cid : '?') + '|' + text.slice(0, 100)
|
|
829
829
|
if (seenMentions.has(dedupeKey)) { log('agent:mention (dup) — skipped'); return }
|
|
830
830
|
seenMentions.add(dedupeKey); if (seenMentions.size > 500) seenMentions.clear()
|
|
831
|
+
if (requestTargetsLaterAgent(text, [slug, identifier])) {
|
|
832
|
+
log('agent:mention addressed to a later-mentioned agent — skipped')
|
|
833
|
+
return
|
|
834
|
+
}
|
|
831
835
|
// Under-the-hood model control from chat (view / switch the model the agent runs).
|
|
832
836
|
const mcmd = cid != null ? parseModelCmd(text) : null
|
|
833
837
|
if (mcmd) {
|