mirror of
https://github.com/KeygraphHQ/shannon.git
synced 2026-02-12 17:22:50 +00:00
feat: add claude-code-router support for multi-model testing
- Add ROUTER=true flag to route requests through claude-code-router - Add router service to docker-compose with profile-based activation - Support OpenAI (gpt-4o) and Google Gemini (gemini-2.5-pro) as alternatives - Add router-config.json with provider configuration template - Update .env.example with provider API key options - Document router mode limitations (cost tracking shows $0)
This commit is contained in:
27
.env.example
27
.env.example
@@ -1,8 +1,33 @@
|
||||
# Shannon Environment Configuration
|
||||
# Copy this file to .env and fill in your credentials
|
||||
|
||||
# Anthropic API Key (required - choose one)
|
||||
# Recommended output token configuration for larger tool outputs
|
||||
CLAUDE_CODE_MAX_OUTPUT_TOKENS=64000
|
||||
|
||||
# =============================================================================
|
||||
# OPTION 1: Direct Anthropic (default, no router)
|
||||
# =============================================================================
|
||||
ANTHROPIC_API_KEY=your-api-key-here
|
||||
|
||||
# OR use OAuth token instead
|
||||
# CLAUDE_CODE_OAUTH_TOKEN=your-oauth-token-here
|
||||
|
||||
# =============================================================================
|
||||
# OPTION 2: Router Mode (use alternative providers)
|
||||
# =============================================================================
|
||||
# Enable router mode by running: ./shannon start ... ROUTER=true
|
||||
# Then configure ONE of the providers below:
|
||||
|
||||
# --- OpenAI ---
|
||||
# OPENAI_API_KEY=sk-your-openai-key
|
||||
# ROUTER_DEFAULT=openai,gpt-4o
|
||||
|
||||
# --- Google Gemini ---
|
||||
GEMINI_API_KEY=your-gemini-key
|
||||
ROUTER_DEFAULT=gemini,gemini-2.5-pro
|
||||
|
||||
# =============================================================================
|
||||
# Available Models
|
||||
# =============================================================================
|
||||
# OpenAI: gpt-4o, gpt-4o-mini
|
||||
# Gemini: gemini-2.5-pro, gemini-2.5-flash
|
||||
|
||||
11
CLAUDE.md
11
CLAUDE.md
@@ -50,6 +50,7 @@ CONFIG=<file> YAML configuration file for authentication and testing pa
|
||||
OUTPUT=<path> Custom output directory for session folder (default: ./audit-logs/)
|
||||
PIPELINE_TESTING=true Use minimal prompts and fast retry intervals (10s instead of 5min)
|
||||
REBUILD=true Force Docker rebuild with --no-cache (use when code changes aren't picked up)
|
||||
ROUTER=true Route requests through claude-code-router for multi-model support (see limitations below)
|
||||
```
|
||||
|
||||
### Generate TOTP for Authentication
|
||||
@@ -284,6 +285,16 @@ Missing tools can be skipped using `PIPELINE_TESTING=true` mode during developme
|
||||
- `subfinder` - Subdomain discovery
|
||||
- `whatweb` - Web technology detection
|
||||
|
||||
### Router Mode Limitations
|
||||
When using `ROUTER=true` to route requests through claude-code-router (e.g., to use OpenAI models):
|
||||
|
||||
**Cost tracking shows $0.00**: The Claude Agent SDK expects `total_cost_usd` in the result message, which is Anthropic-specific. OpenAI's API returns token counts in `usage` but not a cost field, and the router doesn't translate this. This is a known limitation of the router, not a Shannon bug.
|
||||
|
||||
**Workarounds:**
|
||||
- Accept $0 costs when using router mode (recommended for dev/testing)
|
||||
- Use Anthropic directly for production runs where cost tracking matters
|
||||
- Use external tools like `ccusage` for post-hoc token analysis
|
||||
|
||||
### Diagnostic & Utility Scripts
|
||||
```bash
|
||||
# View Temporal workflow history
|
||||
|
||||
31
configs/router-config.json
Normal file
31
configs/router-config.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"HOST": "0.0.0.0",
|
||||
"APIKEY": "shannon-router-key",
|
||||
"LOG": true,
|
||||
"LOG_LEVEL": "info",
|
||||
"NON_INTERACTIVE_MODE": true,
|
||||
"API_TIMEOUT_MS": 600000,
|
||||
"Providers": [
|
||||
{
|
||||
"name": "openai",
|
||||
"api_base_url": "https://api.openai.com/v1/chat/completions",
|
||||
"api_key": "$OPENAI_API_KEY",
|
||||
"models": ["gpt-4o", "gpt-4o-mini"],
|
||||
"transformer": {
|
||||
"use": [["maxtoken", { "max_tokens": 16384 }]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gemini",
|
||||
"api_base_url": "https://generativelanguage.googleapis.com/v1beta/models/",
|
||||
"api_key": "$GEMINI_API_KEY",
|
||||
"models": ["gemini-2.5-pro", "gemini-2.5-flash"],
|
||||
"transformer": {
|
||||
"use": ["gemini"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"Router": {
|
||||
"default": "$ROUTER_DEFAULT"
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,8 @@ services:
|
||||
environment:
|
||||
- TEMPORAL_ADDRESS=temporal:7233
|
||||
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
|
||||
- ANTHROPIC_BASE_URL=${ANTHROPIC_BASE_URL:-} # Optional: route through claude-code-router
|
||||
- ANTHROPIC_AUTH_TOKEN=${ANTHROPIC_AUTH_TOKEN:-} # Auth token for router
|
||||
- CLAUDE_CODE_OAUTH_TOKEN=${CLAUDE_CODE_OAUTH_TOKEN:-}
|
||||
- CLAUDE_CODE_MAX_OUTPUT_TOKENS=${CLAUDE_CODE_MAX_OUTPUT_TOKENS:-64000}
|
||||
depends_on:
|
||||
@@ -36,5 +38,33 @@ services:
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
|
||||
# Optional: claude-code-router for multi-model support
|
||||
# Start with: ROUTER=true ./shannon start ...
|
||||
router:
|
||||
image: node:20-slim
|
||||
profiles: ["router"] # Only starts when explicitly requested
|
||||
command: >
|
||||
sh -c "apt-get update && apt-get install -y gettext-base &&
|
||||
npm install -g @musistudio/claude-code-router &&
|
||||
mkdir -p /root/.claude-code-router &&
|
||||
envsubst < /config/router-config.json > /root/.claude-code-router/config.json &&
|
||||
ccr start"
|
||||
ports:
|
||||
- "3456:3456"
|
||||
volumes:
|
||||
- ./configs/router-config.json:/config/router-config.json:ro
|
||||
environment:
|
||||
- HOST=0.0.0.0
|
||||
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
|
||||
- OPENAI_API_KEY=${OPENAI_API_KEY:-}
|
||||
- GEMINI_API_KEY=${GEMINI_API_KEY:-}
|
||||
- ROUTER_DEFAULT=${ROUTER_DEFAULT:-openai,gpt-4o}
|
||||
healthcheck:
|
||||
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3456/health', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
|
||||
volumes:
|
||||
temporal-data:
|
||||
|
||||
45
shannon
45
shannon
@@ -35,6 +35,7 @@ Options for 'start':
|
||||
CONFIG=<path> Configuration file (YAML)
|
||||
OUTPUT=<path> Output directory for reports (default: ./audit-logs/)
|
||||
PIPELINE_TESTING=true Use minimal prompts for fast testing
|
||||
ROUTER=true Route requests through claude-code-router (multi-model support)
|
||||
|
||||
Options for 'stop':
|
||||
CLEAN=true Remove all data including volumes
|
||||
@@ -63,6 +64,7 @@ parse_args() {
|
||||
CLEAN=*) CLEAN="${arg#CLEAN=}" ;;
|
||||
PIPELINE_TESTING=*) PIPELINE_TESTING="${arg#PIPELINE_TESTING=}" ;;
|
||||
REBUILD=*) REBUILD="${arg#REBUILD=}" ;;
|
||||
ROUTER=*) ROUTER="${arg#ROUTER=}" ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
@@ -121,10 +123,16 @@ cmd_start() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for API key
|
||||
# Check for API key (router mode can use OPENAI_API_KEY or GEMINI_API_KEY instead)
|
||||
if [ -z "$ANTHROPIC_API_KEY" ] && [ -z "$CLAUDE_CODE_OAUTH_TOKEN" ]; then
|
||||
echo "ERROR: Set ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN in .env"
|
||||
exit 1
|
||||
if [ "$ROUTER" = "true" ] && { [ -n "$OPENAI_API_KEY" ] || [ -n "$GEMINI_API_KEY" ]; }; then
|
||||
# Router mode with alternative provider - set a placeholder for SDK init
|
||||
export ANTHROPIC_API_KEY="router-mode"
|
||||
else
|
||||
echo "ERROR: Set ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN in .env"
|
||||
echo " (or use ROUTER=true with OPENAI_API_KEY or GEMINI_API_KEY)"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Determine container path for REPO
|
||||
@@ -149,6 +157,33 @@ cmd_start() {
|
||||
export OUTPUT_DIR="$OUTPUT"
|
||||
fi
|
||||
|
||||
# Handle ROUTER flag - start claude-code-router for multi-model support
|
||||
if [ "$ROUTER" = "true" ]; then
|
||||
# Check if router is already running
|
||||
if docker compose -f "$COMPOSE_FILE" --profile router ps router 2>/dev/null | grep -q "running"; then
|
||||
echo "Router already running, skipping startup..."
|
||||
else
|
||||
echo "Starting claude-code-router..."
|
||||
|
||||
# Check for OpenAI API key
|
||||
if [ -z "$OPENAI_API_KEY" ] && [ -z "$GEMINI_API_KEY" ]; then
|
||||
echo "WARNING: Neither OPENAI_API_KEY nor GEMINI_API_KEY set. Router may not work."
|
||||
fi
|
||||
|
||||
# Start router with profile
|
||||
docker compose -f "$COMPOSE_FILE" --profile router up -d router
|
||||
|
||||
# Give router a few seconds to start (health check disabled for now - TODO: debug later)
|
||||
echo "Waiting for router to start..."
|
||||
sleep 5
|
||||
fi
|
||||
|
||||
# Set ANTHROPIC_BASE_URL to route through router
|
||||
export ANTHROPIC_BASE_URL="http://router:3456"
|
||||
# Set auth token to match router's APIKEY
|
||||
export ANTHROPIC_AUTH_TOKEN="shannon-router-key"
|
||||
fi
|
||||
|
||||
# Ensure containers are running (starts them if needed)
|
||||
ensure_containers
|
||||
|
||||
@@ -226,9 +261,9 @@ cmd_stop() {
|
||||
parse_args "$@"
|
||||
|
||||
if [ "$CLEAN" = "true" ]; then
|
||||
docker compose -f "$COMPOSE_FILE" down -v
|
||||
docker compose -f "$COMPOSE_FILE" --profile router down -v
|
||||
else
|
||||
docker compose -f "$COMPOSE_FILE" down
|
||||
docker compose -f "$COMPOSE_FILE" --profile router down
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user