Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4f785e0bb | ||
|
|
c88fdcc2ea | ||
|
|
98762e764a | ||
|
|
5507192ee6 | ||
|
|
9fa025f7d5 | ||
|
|
5461754f23 |
@@ -40,6 +40,17 @@ OPENROUTER_API_KEY=
|
||||
# Any random string; also used as litellm's general_settings.master_key.
|
||||
LITELLM_MASTER_KEY=
|
||||
|
||||
# --- hermes (autonomous agent with its own native Matrix presence) ---
|
||||
# Your own Matrix ID — Hermes only responds to this user, and only when @mentioned
|
||||
# in a shared room (e.g. "@hermes <task>" in the control room).
|
||||
MATRIX_HUMAN_USER_ID=@william:matrix.apps.williamturner.eu
|
||||
# Access token for the @hermes bot account (register it the same way as claude-bot —
|
||||
# see README — then log in as it via /_matrix/client/v3/login to get this token).
|
||||
HERMES_MATRIX_ACCESS_TOKEN=
|
||||
# Any random string — bearer key for Hermes's own OpenAI-compatible API server
|
||||
# (internal network only, not published anywhere).
|
||||
HERMES_API_SERVER_KEY=
|
||||
|
||||
# --- portainer (GitOps redeploy) ---
|
||||
PORTAINER_STACK_WEBHOOK_URL=
|
||||
|
||||
|
||||
@@ -49,6 +49,10 @@ export async function startMatrixBot() {
|
||||
if (event.sender === BOT_USER_ID) return;
|
||||
const body = event.content?.body;
|
||||
if (!body) return;
|
||||
// Messages explicitly addressed to another agent in this room (currently just
|
||||
// @hermes) are that agent's to answer — without this, claude-bot's classifier would
|
||||
// also see and reply to them, since it otherwise treats every message as its own.
|
||||
if (/^@hermes\b/i.test(body.trim())) return;
|
||||
|
||||
try {
|
||||
const decision = await routeMessage(body, KNOWN_REPOS);
|
||||
|
||||
@@ -61,6 +61,38 @@ services:
|
||||
# Internal only — no Traefik labels. No reason to expose an LLM gateway holding a
|
||||
# master key and OAuth-forwarding config to the public internet.
|
||||
|
||||
hermes:
|
||||
# Pinned to a specific dated release, not :latest — same rationale as litellm above.
|
||||
image: nousresearch/hermes-agent:v2026.8.19
|
||||
container_name: hermes
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
HERMES_UID: "1000"
|
||||
HERMES_GID: "1000"
|
||||
# Internal container address, not the public HTTPS one — same docker network as
|
||||
# matrix-homeserver, no reason to round-trip through Traefik/TLS for this.
|
||||
MATRIX_HOMESERVER: http://matrix-homeserver:8008
|
||||
MATRIX_ACCESS_TOKEN: ${HERMES_MATRIX_ACCESS_TOKEN}
|
||||
# Only you can trigger it; and only with an explicit @hermes mention in shared
|
||||
# rooms (DMs to it would respond unprompted, per Hermes's own default behavior).
|
||||
MATRIX_ALLOWED_USERS: ${MATRIX_HUMAN_USER_ID}
|
||||
MATRIX_REQUIRE_MENTION: "true"
|
||||
OPENROUTER_API_KEY: ${OPENROUTER_API_KEY}
|
||||
# Left disabled: Hermes itself warns that a network-reachable API server combined
|
||||
# with the default unsandboxed ('local') terminal backend gives any caller full
|
||||
# terminal/file access within the container. Matrix is the actual interface in use;
|
||||
# re-enable (API_SERVER_HOST: 0.0.0.0) only alongside terminal.backend: docker if
|
||||
# claude-agent ever needs to call Hermes programmatically.
|
||||
API_SERVER_ENABLED: "false"
|
||||
volumes:
|
||||
- /home/william/hermes-data:/opt/data
|
||||
networks:
|
||||
- web
|
||||
# Without this the image's default command launches the interactive CLI, which
|
||||
# immediately exits ("Input is not a terminal") since a detached container has no
|
||||
# stdin — the container then just sits there having done nothing, every restart.
|
||||
command: ["gateway", "run"]
|
||||
|
||||
claude-agent:
|
||||
image: ${GITEA_REGISTRY_IMAGE}
|
||||
depends_on:
|
||||
|
||||
+13
-7
@@ -11,13 +11,19 @@ model_list:
|
||||
model: openrouter/openai/gpt-4o-mini
|
||||
api_key: os.environ/OPENROUTER_API_KEY
|
||||
|
||||
# NOT included: a "claude-subscription" route forwarding the Claude Pro/Max OAuth token
|
||||
# (from `claude setup-token`) through to Anthropic's raw API. Tested and confirmed
|
||||
# non-functional — Anthropic returns a generic rate_limit_error for ANY direct API call
|
||||
# using this token type outside the real Claude Code CLI client (reproduced with plain
|
||||
# curl straight to api.anthropic.com, bypassing LiteLLM entirely, same result). The
|
||||
# subscription token only works through the actual Claude Code CLI, which is what
|
||||
# claude-agent already uses directly for code tasks — it was never routed through here.
|
||||
# Routes to Anthropic using the CALLER's forwarded Authorization header (the Claude
|
||||
# Pro/Max subscription OAuth token) instead of a LiteLLM-held API key — billed against
|
||||
# the subscription, not per-token. CONFIRMED WORKING, but only for the real `claude`
|
||||
# CLI binary as caller (tested: `claude -p` with ANTHROPIC_BASE_URL pointed here
|
||||
# returned a real completion). An earlier test with plain curl replicating the same
|
||||
# request shape failed — Anthropic apparently requires header/fingerprint details only
|
||||
# the real CLI sends, which LiteLLM faithfully relays but a hand-built request won't
|
||||
# have. Do NOT expect this to work for other callers (Hermes, generic HTTP clients) —
|
||||
# they aren't the real CLI and can't reproduce that fingerprint.
|
||||
- model_name: anthropic-claude
|
||||
litellm_params:
|
||||
model: anthropic/claude-sonnet-5
|
||||
|
||||
general_settings:
|
||||
forward_client_headers_to_llm_api: true
|
||||
master_key: os.environ/LITELLM_MASTER_KEY
|
||||
|
||||
Reference in New Issue
Block a user