openvisio-agent 0.25.3 → 0.25.4
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/CHANGELOG.md +5 -0
- package/package.json +1 -1
- package/src/watch.mjs +22 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.25.4] — 2026-09-21
|
|
4
|
+
|
|
5
|
+
- Route the backend's `agent:message` events through the same verified recipient, deduplication, queue, model, and delivery path as targeted mentions.
|
|
6
|
+
- Normalize both nested and direct targeted-message envelopes so valid requests cannot stop after the WebSocket event log without starting a cycle.
|
|
7
|
+
|
|
3
8
|
## [0.25.3] — 2026-09-21
|
|
4
9
|
|
|
5
10
|
- Normalize structured and compact Markdown MCP list results through one provider-neutral discovery path, so every runtime can resolve projects, agents, boards, tasks, task types, and channels from the same saved setup.
|
package/package.json
CHANGED
package/src/watch.mjs
CHANGED
|
@@ -747,7 +747,7 @@ export function createBackendWatcher({ backend, wsUrl, apiKey, identifier, slug,
|
|
|
747
747
|
// re-acknowledge the same assignment.
|
|
748
748
|
const seenTasks = new Set()
|
|
749
749
|
// Mentions we've already reacted to (by message id) — the backend can re-deliver
|
|
750
|
-
// an agent:mention (reconnect replay, dup fan-out), which otherwise makes the
|
|
750
|
+
// an agent:mention/agent:message (reconnect replay, dup fan-out), which otherwise makes the
|
|
751
751
|
// agent reply to the SAME message twice.
|
|
752
752
|
const replayPath = join(stateDir, 'watch-' + slug + '-replay.json')
|
|
753
753
|
let replayState = {}
|
|
@@ -1896,12 +1896,27 @@ export function createBackendWatcher({ backend, wsUrl, apiKey, identifier, slug,
|
|
|
1896
1896
|
}
|
|
1897
1897
|
}
|
|
1898
1898
|
|
|
1899
|
+
const conversationEventData = (value) => {
|
|
1900
|
+
const outer = value && typeof value === 'object' && !Array.isArray(value) ? value : {}
|
|
1901
|
+
const data = outer.data && typeof outer.data === 'object' && !Array.isArray(outer.data) ? outer.data : {}
|
|
1902
|
+
const payload = outer.payload && typeof outer.payload === 'object' && !Array.isArray(outer.payload) ? outer.payload : {}
|
|
1903
|
+
const source = { ...data, ...payload, ...outer }
|
|
1904
|
+
const messageCandidate = [outer.message, data.message, payload.message].find((item) => item && typeof item === 'object' && !Array.isArray(item))
|
|
1905
|
+
const directId = source.message_id ?? source.messageId ?? source.id
|
|
1906
|
+
const directContent = source.content ?? source.body ?? source.text ?? (typeof source.message === 'string' ? source.message : null)
|
|
1907
|
+
const message = messageCandidate || (directId != null && directContent != null ? { ...source, content: directContent } : {})
|
|
1908
|
+
const channelId = source.channel_id ?? source.channelId ?? source.channel?.id ?? message.channel_id ?? message.channelId ?? message.channel?.id
|
|
1909
|
+
return { ...source, channel_id: channelId, message }
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1899
1912
|
const mentionIntake = new Map()
|
|
1900
1913
|
function onEvent(k, d) {
|
|
1901
1914
|
if (stopping) return
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
const
|
|
1915
|
+
const conversationEvent = k === 'agent:mention' || k === 'agent:message' || k === 'channel:message'
|
|
1916
|
+
if (!conversationEvent) return trackOperation(routeEvent(k, d))
|
|
1917
|
+
const eventData = conversationEventData(d)
|
|
1918
|
+
const cid = eventData.channel_id ?? eventData.channelId
|
|
1919
|
+
const message = eventData.message || {}
|
|
1905
1920
|
const parent = messageParentId(message)
|
|
1906
1921
|
const messageId = message.message_id ?? message.messageId ?? message.id
|
|
1907
1922
|
const malformedParent = parent == null && [message.parent_id, message.parentId, message.thread_id, message.threadId, message.reply_to, message.replyTo].some((value) => value != null)
|
|
@@ -1951,7 +1966,7 @@ export function createBackendWatcher({ backend, wsUrl, apiKey, identifier, slug,
|
|
|
1951
1966
|
}
|
|
1952
1967
|
if (!stopping) {
|
|
1953
1968
|
if (!irrelevant) log(`mention timing intake=${Math.round(performance.now() - intakeStartedAt)}ms source=${k} channel=${cid} message=${messageId}`)
|
|
1954
|
-
return routeEvent('agent:mention', { ...
|
|
1969
|
+
return routeEvent('agent:mention', { ...eventData, _sourceEvent: k, _threadRootContent: rootContent })
|
|
1955
1970
|
}
|
|
1956
1971
|
}).catch((error) => { log('mention thread verification failed: ' + (error?.message || error)); return { status: 'retry' } })
|
|
1957
1972
|
.finally(() => { if (mentionIntake.get(key) === next) mentionIntake.delete(key) })
|
|
@@ -2103,9 +2118,9 @@ export function createBackendWatcher({ backend, wsUrl, apiKey, identifier, slug,
|
|
|
2103
2118
|
}
|
|
2104
2119
|
|
|
2105
2120
|
// The WebSocket drives real-time reactions (task:created/updated assigned to us,
|
|
2106
|
-
// agent:mention and channel:message). Verified organization subscriptions
|
|
2121
|
+
// agent:mention, agent:message, and channel:message). Verified organization subscriptions
|
|
2107
2122
|
// recover channel mentions even when the backend omits targeted dispatch.
|
|
2108
|
-
//
|
|
2123
|
+
// All conversation event types share recipient, ownership and deduplication guards.
|
|
2109
2124
|
log('up — backend WS watcher on ' + wsUrl + (canCode ? ' [code: ' + workdir + ']' : ''))
|
|
2110
2125
|
handle = (dependencies.connect || connectAgentWs)({ wsUrl, apiKey, identifier, onEvent,
|
|
2111
2126
|
onDisconnect: () => {
|