fix: feat: Matrix notifications — contextual, linked, conversational (#76)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
openhands 2026-03-18 00:20:11 +00:00
parent 7cc9ce1b39
commit 814706bf90
3 changed files with 137 additions and 17 deletions

View file

@ -74,12 +74,13 @@ wpdb() {
-t "$@" 2>/dev/null
}
# Matrix messaging helper — usage: matrix_send <prefix> <message> [thread_event_id]
# Matrix messaging helper — usage: matrix_send <prefix> <message> [thread_event_id] [context_tag]
# Returns event_id on stdout. Registers threads for listener dispatch.
# context_tag is stored in the thread map (e.g. issue number) for routing replies.
MATRIX_THREAD_MAP="${MATRIX_THREAD_MAP:-/tmp/matrix-thread-map}"
matrix_send() {
[ -z "${MATRIX_TOKEN:-}" ] && return 0
local prefix="$1" msg="$2" thread_id="${3:-}"
local prefix="$1" msg="$2" thread_id="${3:-}" ctx_tag="${4:-}"
local room_encoded="${MATRIX_ROOM_ID//!/%21}"
local txn="$(date +%s%N)$$"
local body
@ -101,7 +102,42 @@ matrix_send() {
printf '%s' "$event_id"
# Register thread root for listener dispatch (escalations only)
if [ -z "$thread_id" ]; then
printf '%s\t%s\t%s\n' "$event_id" "$prefix" "$(date +%s)" >> "$MATRIX_THREAD_MAP" 2>/dev/null || true
printf '%s\t%s\t%s\t%s\n' "$event_id" "$prefix" "$(date +%s)" "${ctx_tag}" >> "$MATRIX_THREAD_MAP" 2>/dev/null || true
fi
fi
}
# matrix_send_ctx — Send rich Matrix message with HTML formatting
# Usage: matrix_send_ctx <prefix> <plain_text> <html_body> [thread_event_id]
# Use for notifications that benefit from links, code blocks, or structured content.
matrix_send_ctx() {
[ -z "${MATRIX_TOKEN:-}" ] && return 0
local prefix="$1" plain="$2" html="$3" thread_id="${4:-}"
local room_encoded="${MATRIX_ROOM_ID//!/%21}"
local txn
txn="$(date +%s%N)$$"
local body
if [ -n "$thread_id" ]; then
body=$(jq -nc \
--arg m "[${prefix}] ${plain}" \
--arg h "<b>[${prefix}]</b> ${html}" \
--arg t "$thread_id" \
'{msgtype:"m.text",body:$m,format:"org.matrix.custom.html",formatted_body:$h,"m.relates_to":{rel_type:"m.thread",event_id:$t}}')
else
body=$(jq -nc \
--arg m "[${prefix}] ${plain}" \
--arg h "<b>[${prefix}]</b> ${html}" \
'{msgtype:"m.text",body:$m,format:"org.matrix.custom.html",formatted_body:$h}')
fi
local response
response=$(curl -s -X PUT \
-H "Authorization: Bearer ${MATRIX_TOKEN}" \
-H "Content-Type: application/json" \
"${MATRIX_HOMESERVER}/_matrix/client/v3/rooms/${room_encoded}/send/m.room.message/${txn}" \
-d "$body" 2>/dev/null) || return 0
local event_id
event_id=$(printf '%s' "$response" | jq -r '.event_id // empty' 2>/dev/null)
if [ -n "$event_id" ]; then
printf '%s' "$event_id"
fi
}