diff --git a/.env.example b/.env.example index 4c01091..7e16af1 100644 --- a/.env.example +++ b/.env.example @@ -13,7 +13,14 @@ ANTHROPIC_API_KEY=your-api-key-here # CLAUDE_CODE_OAUTH_TOKEN=your-oauth-token-here # ============================================================================= -# OPTION 2: Router Mode (use alternative providers) +# OPTION 2: Custom Base URL (compatible proxies, gateways, etc.) +# ============================================================================= +# Point the SDK at an alternative Anthropic-compatible endpoint. +# ANTHROPIC_BASE_URL=https://your-proxy.example.com +# ANTHROPIC_AUTH_TOKEN=your-auth-token # Auth token for the custom endpoint + +# ============================================================================= +# OPTION 3: Router Mode (use alternative providers) # ============================================================================= # Enable router mode by running: ./shannon start ... ROUTER=true # Then configure ONE of the providers below: @@ -27,15 +34,16 @@ ANTHROPIC_API_KEY=your-api-key-here # ROUTER_DEFAULT=openrouter,google/gemini-3-flash-preview # ============================================================================= -# Model Tier Overrides (Anthropic API / OAuth / Bedrock) +# Model Tier Overrides (Anthropic API / OAuth / Custom Base URL / Bedrock) # ============================================================================= # Override which model is used for each tier. Defaults are used if not set. +# Optional for direct Anthropic and custom base URL modes. Required for Bedrock/Vertex. # ANTHROPIC_SMALL_MODEL=... # Small tier (default: claude-haiku-4-5-20251001) # ANTHROPIC_MEDIUM_MODEL=... # Medium tier (default: claude-sonnet-4-6) # ANTHROPIC_LARGE_MODEL=... # Large tier (default: claude-opus-4-6) # ============================================================================= -# OPTION 3: AWS Bedrock +# OPTION 4: AWS Bedrock # ============================================================================= # https://aws.amazon.com/blogs/machine-learning/accelerate-ai-development-with-amazon-bedrock-api-keys/ # Requires the model tier overrides above to be set with Bedrock-specific model IDs. @@ -49,7 +57,7 @@ ANTHROPIC_API_KEY=your-api-key-here # AWS_BEARER_TOKEN_BEDROCK=your-bearer-token # ============================================================================= -# OPTION 4: Google Vertex AI +# OPTION 5: Google Vertex AI # ============================================================================= # https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/use-partner-models # Requires a GCP service account with roles/aiplatform.user. diff --git a/README.md b/README.md index 55cc05f..271d5ce 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,7 @@ Shannon Pro supports a self-hosted runner model (similar to GitHub Actions self- - [Configuration (Optional)](#configuration-optional) - [AWS Bedrock](#aws-bedrock) - [Google Vertex AI](#google-vertex-ai) + - [Custom Base URL](#custom-base-url) - [[EXPERIMENTAL - UNSUPPORTED] Router Mode (Alternative Providers)](#experimental---unsupported-router-mode-alternative-providers) - [Output and Results](#output-and-results) - [Sample Reports](#-sample-reports) @@ -454,6 +455,33 @@ ANTHROPIC_LARGE_MODEL=claude-opus-4-6 Set `CLOUD_ML_REGION=global` for global endpoints, or a specific region like `us-east5`. Some models may not be available on global endpoints — see the [Vertex AI Model Garden](https://console.cloud.google.com/vertex-ai/model-garden) for region availability. +### Custom Base URL + +Shannon supports pointing the SDK at any Anthropic-compatible endpoint (proxies, gateways, etc.) via `ANTHROPIC_BASE_URL`. + +#### Quick Setup + +1. Add your endpoint and auth token to `.env`: + +```bash +ANTHROPIC_BASE_URL=https://your-proxy.example.com +ANTHROPIC_AUTH_TOKEN=your-auth-token +``` + +2. Optionally override model tiers (defaults are used if not set): + +```bash +ANTHROPIC_SMALL_MODEL=claude-haiku-4-5-20251001 +ANTHROPIC_MEDIUM_MODEL=claude-sonnet-4-6 +ANTHROPIC_LARGE_MODEL=claude-opus-4-6 +``` + +3. Run Shannon as usual: + +```bash +./shannon start URL=https://example.com REPO=repo-name +``` + ### [EXPERIMENTAL - UNSUPPORTED] Router Mode (Alternative Providers) Shannon can experimentally route requests through alternative AI providers using claude-code-router. This mode is not officially supported and is intended primarily for: diff --git a/shannon b/shannon index 0a96eba..8655cdc 100755 --- a/shannon +++ b/shannon @@ -142,9 +142,12 @@ cmd_start() { exit 1 fi - # Check for API key (Bedrock and router modes can bypass this) + # Check for API key (Bedrock, Vertex, router, and custom base URL modes can bypass this) if [ -z "$ANTHROPIC_API_KEY" ] && [ -z "$CLAUDE_CODE_OAUTH_TOKEN" ]; then - if [ "$CLAUDE_CODE_USE_BEDROCK" = "1" ]; then + if [ -n "$ANTHROPIC_BASE_URL" ] && [ -n "$ANTHROPIC_AUTH_TOKEN" ]; then + # Custom base URL mode — use auth token as API key for SDK initialization + echo "Using custom base URL: $ANTHROPIC_BASE_URL" + elif [ "$CLAUDE_CODE_USE_BEDROCK" = "1" ]; then # Bedrock mode — validate required AWS credentials MISSING="" [ -z "$AWS_REGION" ] && MISSING="$MISSING AWS_REGION" diff --git a/src/services/preflight.ts b/src/services/preflight.ts index d050d05..e1b6dbe 100644 --- a/src/services/preflight.ts +++ b/src/services/preflight.ts @@ -160,10 +160,35 @@ function classifySdkError( async function validateCredentials( logger: ActivityLogger ): Promise> { - // 1. Router mode — can't validate provider keys, just warn + // 1. Custom base URL — validate endpoint is reachable via SDK query if (process.env.ANTHROPIC_BASE_URL) { - logger.warn('Router mode detected — skipping API credential validation'); - return ok(undefined); + const baseUrl = process.env.ANTHROPIC_BASE_URL; + logger.info(`Validating custom base URL: ${baseUrl}`); + + try { + for await (const message of query({ prompt: 'hi', options: { model: resolveModel('small'), maxTurns: 1 } })) { + if (message.type === 'assistant' && message.error) { + return classifySdkError(message.error, `custom endpoint (${baseUrl})`); + } + if (message.type === 'result') { + break; + } + } + + logger.info('Custom base URL OK'); + return ok(undefined); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + return err( + new PentestError( + `Custom base URL unreachable: ${baseUrl} — ${message}`, + 'network', + false, + { baseUrl }, + ErrorCode.AUTH_FAILED + ) + ); + } } // 2. Bedrock mode — validate required AWS credentials are present