Fix claude-bot replying to Hermes's own messages, route Hermes through LiteLLM

Critical bug: claude-bot only ignored its OWN messages and text explicitly
addressed to @hermes — it did not ignore Hermes's own replies appearing in
the room. A single @hermes mention cascaded into claude-bot replying to
Hermes's thread messages ('Hermes says: ...'), which could itself cascade
further. Fixed with an OTHER_AGENT_USER_IDS allowlist of sender IDs to
always ignore, not just a text-prefix check.

Also point Hermes's model provider at the local litellm gateway
(OPENAI_BASE_URL/OPENAI_API_KEY) instead of OpenRouter directly, matching
claude-agent's own chat path — one place to hold the OpenRouter credential.
This does NOT grant Hermes access to the Claude subscription; that's an
Anthropic-side restriction unrelated to which proxy sits in front of it,
already proven earlier in this session.

Separately (not a code fix): the 'Billing or credits exhausted: HTTP 402'
error Hermes hit is real — the OpenRouter account currently has 0 credits.
This commit is contained in:
2026-08-23 16:02:15 +00:00
parent c88fdcc2ea
commit a2c00f6f8b
3 changed files with 27 additions and 4 deletions
+11
View File
@@ -11,6 +11,15 @@ const GITEA_URL = process.env.GITEA_URL;
// to the endpoint itself. This is also the only reliable way to filter the bot's own
// messages now that there's no command prefix to naturally exclude them by.
const BOT_USER_ID = process.env.MATRIX_BOT_USER_ID;
// Other agents sharing this room (currently just Hermes) — their own messages must be
// ignored the same way claude-bot ignores its own, or claude-bot's classifier treats
// every message another bot posts as fresh chat input and replies to it, which that
// bot may then react to in turn. Found the hard way: a single @hermes mention cascaded
// into claude-bot replying to Hermes's own thread messages ("Hermes says: ...").
const OTHER_AGENT_USER_IDS = (process.env.OTHER_AGENT_USER_IDS || "")
.split(",")
.map((id) => id.trim())
.filter(Boolean);
const KNOWN_REPOS = (process.env.KNOWN_REPOS || "")
.split(",")
.map((r) => r.trim())
@@ -47,6 +56,7 @@ export async function startMatrixBot() {
client.on("room.message", async (roomId, event) => {
if (roomId !== CONTROL_ROOM_ID) return;
if (event.sender === BOT_USER_ID) return;
if (OTHER_AGENT_USER_IDS.includes(event.sender)) return;
const body = event.content?.body;
if (!body) return;
// Messages explicitly addressed to another agent in this room (currently just
@@ -67,6 +77,7 @@ export async function startMatrixBot() {
}
const reply = await chatReply(body);
console.log("chat reply sent, length:", reply.length);
await client.sendText(roomId, truncate(reply));
} catch (err) {
console.error("message handling failed", err);