feat(redstone): add OpenRouter primary AI with Gemini fallback

Redstone now hits OpenRouter's `openrouter/free` auto-router first,
falling back to direct Gemini if the OpenRouter call fails (no key,
network error, or `:free` upstream rejected tool use). The auto-
router filters its free-model pool by the request's tool-calling
requirement, so we don't have to pin a specific free model.

- bot/bot.ts:
  - OPENROUTER_API_KEY / _FILE env (mirrors GEMINI_API_KEY_FILE)
  - OPENROUTER_MODEL defaults to "openrouter/free"
  - openRouterTools[] derived from existing geminiFunctionDeclarations
    (OpenAI-style {type:"function", function:{name,description,parameters}})
  - callOpenRouterOnce + runRedstoneTurnViaOpenRouter (parses JSON-string
    tool_calls.arguments, replies with role:"tool" + tool_call_id)
  - Existing Gemini path moved into runRedstoneTurnViaGemini
  - runRedstoneTurn dispatches OpenRouter first, Gemini on null
  - Early-return gate now passes if either key is configured

- docker-compose.yml:
  - new openrouter_token secret -> ./openrouter.token (gitignored)
  - OPENROUTER_API_KEY_FILE + OPENROUTER_MODEL env wired to the bot

- .gitignore: add openrouter.token (plus pre-existing gitea.token entry
  that was sitting uncommitted).

The key file itself is NOT committed (verified via git check-ignore).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-13 22:42:33 +02:00
parent cab5337e3f
commit 4ebbcef76b
3 changed files with 278 additions and 9 deletions

View File

@@ -50,12 +50,25 @@ services:
environment:
BOT_TOKEN_FILE: /run/secrets/bot_token
GEMINI_API_KEY_FILE: /run/secrets/google_key
GEMINI_MODEL: "${GEMINI_MODEL:-gemma-4-26b-a4b-it}"
GEMINI_MODEL: "${GEMINI_MODEL:-gemini-2.5-flash-lite}"
# OpenRouter primary; Gemini stays as fallback. `openrouter/free` auto-
# selects a free model that supports tool calling for this request.
OPENROUTER_API_KEY_FILE: /run/secrets/openrouter_token
OPENROUTER_MODEL: "${OPENROUTER_MODEL:-openrouter/free}"
MC_DIR: /mc
DB_PATH: /data/users.db
ADMIN_BOOTSTRAP: "${ADMIN_BOOTSTRAP:-1311866578:Paul}"
COMPOSE_HOST_DIR: "${COMPOSE_HOST_DIR:-/home/paul/containers/minecraft}"
TZ: Africa/Johannesburg
# Gitea release upload from inside the container. The token is mounted
# as a docker secret (see `secrets:` below + ./gitea.token, gitignored);
# backup.sh reads it via $GITEA_TOKEN_FILE. GITEA_API_BASE / GITEA_REPO
# let backup.sh skip its `git config remote.origin.url` parse — needed
# because the host's origin URL points at localhost:3000, which the bot
# container can't reach.
GITEA_TOKEN_FILE: /run/secrets/gitea_token
GITEA_API_BASE: "${GITEA_API_BASE:-https://thinkstation-web.spot-bot.co.za/api/v1}"
GITEA_REPO: "${GITEA_REPO:-paul/Minecraft-Server}"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- .:/mc
@@ -63,9 +76,15 @@ services:
secrets:
- bot_token
- google_key
- gitea_token
- openrouter_token
secrets:
bot_token:
file: ./bot.token
google_key:
file: ./google_key.txt
gitea_token:
file: ./gitea.token
openrouter_token:
file: ./openrouter.token