Files
xianyu-hunter-hermes-skill/skill/xianyu-hunter-monitor/references/hermes-send-message-notifications-2026-05.md
T

5.2 KiB

Xianyu-hunter Hermes send_message notifications (2026-05)

Session learning: BOSS wanted xianyu-hunter notification settings changed from a Hermes webhook URL to a Web-visible platform selector that sends through Hermes send_message directly.

Implementation pattern

  • Backend file: /Users/chick/.Hermes/workspace/research/xianyu-hunter/lib/notifier.mjs.
  • Keep GET/PUT /api/notify-config, but add targetOptions to the returned config for UI dropdowns.
  • Use channel type hermes-send-message instead of hermes-webhook.
  • Migrate existing hermes-webhook channels to hermes-send-message and map bare feishu to the current Feishu DM when appropriate.
  • Server-side send implementation can spawn Hermes Agent's Python venv and call the tool handler:
const script = `import json\nfrom tools.send_message_tool import send_message_tool\nprint(send_message_tool({"action":"send","target":${JSON.stringify(target)},"message":${JSON.stringify(message)}}))\n`;
const child = spawn(
  process.env.HERMES_PYTHON || '/Users/chick/.hermes/hermes-agent/venv/bin/python3',
  ['-c', script],
  { cwd: process.env.HERMES_AGENT_DIR || '/Users/chick/.hermes/hermes-agent' }
);

UI pattern

  • Frontend files: public/app.js, public/index.html.
  • In notification modal, label Hermes channel as Hermes 平台消息.
  • Provide a dropdown populated from notifyConfig.targetOptions and a separate optional custom target input.
  • Target examples:
    • feishu:oc_3e963a150d98f254d8f38881bcfa1812
    • weixin:o9cq809DWSYDlvbA9pj1akncjrhY@im.wechat
    • weixin:o9cq808qCd1W-cIDo0iWjteE5lHY@im.wechat
    • qqbot if configured
  • Bump static cache query strings (app.js?v=..., style.css?v=...) after UI edits.

Verification

cd /Users/chick/.Hermes/workspace/research/xianyu-hunter
node --check server.mjs
node --check lib/notifier.mjs
node --check public/app.js
node tools/xianyu_ops.mjs stop || true
node tools/xianyu_ops.mjs start --port 3000
curl -sS http://127.0.0.1:3000/api/notify-config | python3 -m json.tool | head -90

Smoke-test notifier without running a real task:

node --input-type=module <<'JS'
import { sendNotifications } from './lib/notifier.mjs';
const task = { id: 'smoke-test', name: '通知配置 smoke test' };
const summary = {
  minScore: 75, total: 1, recommendedCount: 1, cautionCount: 0, rejectedCount: 0,
  reportPath: 'smoke-test',
  topItems: [{ title: 'xianyu-hunter 通知测试', score: 99, verdict: 'recommend', price: '测试', location: '本机', reason: '验证服务端可直接调用 Hermes send_message', href: '' }]
};
const config = { enabled: true, notifyOnlyGood: false, minScore: 75, channels: [{ id:'smoke-feishu', type:'hermes-send-message', name:'飞书 smoke', enabled:true, target:'feishu:oc_3e963a150d98f254d8f38881bcfa1812' }] };
const r = await sendNotifications(task, summary, { force: true, config });
console.log(JSON.stringify(r, null, 2));
if (!r.ok) process.exit(1);
JS

Test notification channel

When BOSS asks to add/test notification channels, add a Web-visible test path rather than relying on real task analysis:

  • Backend route in server.mjs:
    • POST /api/notify-test
    • Accepts { config, title } where config has the same shape as /api/notify-config.
    • Builds a fake task { id: 'notify-test', name: '通知渠道测试' } plus a one-item summary.
    • Calls sendNotifications(task, summary, { force: true, config: { ...config, enabled: true, notifyOnlyGood: false } }) so the test bypasses score/good-only gating.
    • Return HTTP 200 if result.ok, otherwise 500 with per-channel errors.
  • Frontend in public/app.js:
    • Add testNotifyConfigFromForm() beside saveNotifyConfigFromForm().
    • It calls collectNotifyConfig(), requires at least one enabled channel, posts to /api/notify-test, and writes / per-channel results into #notify-log.
    • It should not require saving first; this lets BOSS test temporary target edits directly from the modal.
  • UI in public/index.html:
    • Add a modal footer button: 发送测试通知 wired to testNotifyConfigFromForm().
    • Bump static cache query strings (app.js?v=..., style.css?v=...).

Verification command:

curl -sS -X POST http://127.0.0.1:3000/api/notify-test \
  -H 'Content-Type: application/json' \
  -d '{"config":{"enabled":true,"notifyOnlyGood":false,"minScore":75,"channels":[{"id":"api-test-feishu","type":"hermes-send-message","name":"API测试飞书","enabled":true,"target":"feishu:oc_3e963a150d98f254d8f38881bcfa1812"}]},"title":"xianyu-hunter API 测试通知"}' \
  | python3 -m json.tool

A known-good result has ok: true and results[0].ok: true; in the 2026-05 run this sent a real Feishu test message successfully.

Do not spawn Homebrew Python such as /Users/chick/homebrew/opt/python@3.11/bin/python3.11 for Hermes send_message. It may lack Hermes dependencies (yaml, gateway modules) and fail with:

Failed to load gateway config: No module named 'yaml'

Use Hermes' own venv interpreter:

/Users/chick/.hermes/hermes-agent/venv/bin/python3

You can verify it with:

/Users/chick/.hermes/hermes-agent/venv/bin/python3 - <<'PY'
import yaml
import gateway.config
from tools.send_message_tool import send_message_tool
print(send_message_tool({'action':'list'}))
PY