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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openvisio-agent",
3
- "version": "0.16.0",
3
+ "version": "0.16.1",
4
4
  "description": "Connect Claude Code, Codex, or OpenCode to an OpenVisio team — MCP tools + optional autonomy — in one command.",
5
5
  "type": "module",
6
6
  "bin": {
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.0' } } }, false)
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) {