JSPM

openrouter-provider-shim

0.1.1
    • ESM via JSPM
    • ES Module Entrypoint
    • Export Map
    • Keywords
    • License
    • Repository URL
    • TypeScript Types
    • README
    • Created
    • Published
    • Downloads 6
    • Score
      100M100P100Q52193F
    • License MIT

    Local npx shim that injects OpenRouter provider routing for Claude Code and OpenAI-compatible harnesses

    Package Exports

      This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (openrouter-provider-shim) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

      Readme

      openrouter-provider-shim

      Local npx-runnable shim that enforces OpenRouter provider routing (e.g., Fireworks-only) for AI agent tools that cannot configure it natively. Primarily for Claude Code and Droid - other tools like OpenCode and OpenHands have native OpenRouter provider support.

      Why this shim exists

      Some AI agent harnesses can point at an OpenAI-compatible base URL, but they cannot attach OpenRouter's per-request provider routing object. This includes Claude Code, which uses the Anthropic Messages API and has no way to specify provider preferences.

      OpenRouter supports a provider object for routing preferences including only, order, ignore, sort (price, throughput, latency), performance thresholds, and max price. This shim injects these fields server-side, so end users do not need OpenRouter account-wide settings.

      Note: Tools like OpenCode and OpenHands have native OpenRouter provider configuration and don't need this shim. See When You DON'T Need This Shim below.

      Features

      • Multi-protocol support: Anthropic Messages API, OpenAI Chat Completions, and OpenAI Responses API
      • Provider routing enforcement: Merge, override, or strict modes for provider policies
      • Flexible authentication: Passthrough or upstream-key auth modes
      • Zero dependencies for runtime: Uses only Node.js built-ins
      • Privacy-first logging: Logs metadata only, never prompt content
      • Cross-platform: Works on macOS, Linux, and Windows

      Installation

      # Run without installing
      npx openrouter-provider-shim serve --port 8787 --provider-only fireworks --sort throughput --no-fallbacks
      
      # Or install globally
      npm install -g openrouter-provider-shim
      openrouter-provider-shim serve --port 8787

      Quick Start

      Claude Code

      Automatic key substitution

      If you have both ANTHROPIC_API_KEY and OPENROUTER_API_KEY set, the shim will automatically detect and substitute your Anthropic key with your OpenRouter key:

      export OPENROUTER_API_KEY="sk-or-v1-..."
      export ANTHROPIC_MODEL="moonshotai/kimi-k2.5"
      npx openrouter-provider-shim serve --port 8787 --provider-only fireworks --sort throughput --no-fallbacks &
      
      export ANTHROPIC_BASE_URL="http://127.0.0.1:8787"
      claude

      Known Limitations

      Rate limiting: The shim includes automatic retry with custom backoff delays for Claude Code (detected by its use of the Anthropic Messages API). Retries use delays: 1s, 2s, 4s, 8s, 12s, 18s, 24s, 32s. If you hit rate limits:

      • Add your own Fireworks API key to OpenRouter (BYOK) at https://openrouter.ai/settings/integrations
      • Use the --provider-order option to allow fallback providers
      • Wait a moment between requests and manually retry or prompt "Continue"

      When You DON'T Need This Shim

      Some AI tools have native OpenRouter provider routing support and don't need this shim:

      OpenCode - Has built-in OpenRouter provider configuration. In ~/.config/opencode/opencode.json:

      {
        "provider": {
          "openrouter": {
            "models": {
              "moonshotai/kimi-k2.5": {
                "options": {
                  "provider": {
                    "order": ["fireworks"],
                    "allow_fallbacks": false
                  }
                }
              }
            }
          }
        }
      }

      OpenHands - Uses LiteLLM in-process and supports provider routing via LLM_LITELLM_EXTRA_BODY:

      export LLM_LITELLM_EXTRA_BODY='{"provider":{"order":["fireworks"],"allow_fallbacks":false}}'
      export LLM_API_KEY="$OPENROUTER_API_KEY"
      export LLM_MODEL="openrouter/moonshotai/kimi-k2.5"
      openhands --override-with-envs

      When You DO Need This Shim

      Use this shim for tools that cannot configure OpenRouter's per-request provider routing:

      Claude Code (Primary Use Case)

      Uses Anthropic Messages API - cannot set OpenRouter provider routing. This is the primary use case for this shim.

      export OPENROUTER_API_KEY="your-api-key"
      npx openrouter-provider-shim serve --port 8787 --provider-only fireworks
      
      export ANTHROPIC_BASE_URL="http://127.0.0.1:8787"
      export ANTHROPIC_MODEL="moonshotai/kimi-k2.5"
      claude

      Droid (Factory) - When Tool Calls Fail

      Droid supports OpenRouter via generic-chat-completion-api, but tool calls may not work reliably with native OpenRouter integration. If they ever address this, you should be able to simply configure a custom model with OpenRouter provider settings like this:

      {
        "model": "moonshotai/kimi-k2.5",
        "id": "custom:Kimi-K2.5-[OR-->-Fireworks]-2",
        "index": 2,
        "baseUrl": "https://openrouter.ai/api/v1",
        "apiKey": "sk-or-v1-REDACTED",
        "displayName": "Kimi K2.5 [OR -> Fireworks]",
        "maxOutputTokens": 131072,
        "extraArgs": {
          "provider": {
            "order": [
              "fireworks"
            ],
            "allow_fallbacks": false
          }
        },
        "noImageSupport": false,
        "provider": "generic-chat-completion-api"
      }

      For the time being, however, testing has shown tool calls to fail with the above setup, however. Use this shim for better compatibility.

      1. Start the shim:

      export OPENROUTER_API_KEY="sk-or-v1-..."
      npx openrouter-provider-shim serve --port 8787 --provider-only fireworks

      2. Add to ~/.factory/settings.json in the customModels array:

      {
        "model": "moonshotai/kimi-k2.5",
        "id": "custom:Kimi-K2.5-[shim-->-Fireworks]-2",
        "index": 2,
        "baseUrl": "http://127.0.0.1:8787/v1",
        "apiKey": "sk-or-v1-REDACTED",
        "displayName": "Kimi K2.5 [shim -> Fireworks]",
        "maxOutputTokens": 131072,
        "noImageSupport": false,
        "provider": "generic-chat-completion-api"
      }

      CLI Commands

      serve (default)

      Starts the local shim server.

      npx openrouter-provider-shim serve \
        --port 8787 \
        --provider-only fireworks \
        --sort throughput \
        --no-fallbacks \
        --auth-mode passthrough

      doctor

      Validates config and checks connectivity to OpenRouter.

      npx openrouter-provider-shim doctor --provider-only fireworks

      Prints copy-paste environment variables for Claude Code and OpenAI clients.

      npx openrouter-provider-shim print-env --port 8787

      Configuration

      Configuration can be provided via:

      1. CLI flags (highest priority)
      2. Environment variables
      3. Config file (lowest priority)

      Authentication

      The shim supports several authentication modes:

      passthrough mode (default)

      • Forwards the Authorization header from the inbound request to OpenRouter
      • Smart substitution: If the inbound auth looks like an Anthropic API key (starts with sk-ant-) and you have OPENROUTER_API_KEY set, the shim automatically substitutes it with your OpenRouter key
      • This allows you to keep ANTHROPIC_API_KEY set for other tools while using OpenRouter via the shim

      upstream-key mode

      • Always uses the configured OpenRouter API key, ignoring inbound auth
      • Useful when you don't want clients to know the OpenRouter key
      # Default passthrough with smart substitution
      npx openrouter-provider-shim serve --port 8787
      
      # Explicit upstream key (never use inbound auth)
      npx openrouter-provider-shim serve --port 8787 --auth-mode upstream-key --upstream-key "sk-or-v1-..."

      CLI Options

      Option Description
      --config <path> Path to config JSON file
      --host <host> Host to bind (default: 127.0.0.1)
      --port <port> Port to bind (default: 8787)
      --merge-mode <mode> Provider merge mode: merge, override, strict
      --provider-only <list> Comma-separated list of allowed providers
      --provider-order <list> Comma-separated provider priority order
      --provider-ignore <list> Comma-separated list of providers to skip
      --sort <sort> Sort by: price, throughput, latency
      --no-fallbacks Disable fallback providers
      --require-parameters Require providers to support all parameters
      --data-collection <allow|deny> Data collection policy
      --zdr Enforce Zero Data Retention
      --quantizations <list> Comma-separated quantization list
      --auth-mode <mode> passthrough or upstream-key
      --upstream-key <key> OpenRouter API key
      --local-api-key <key> Local authentication key

      Environment Variables

      Variable Description
      OPENROUTER_API_KEY Your OpenRouter API key
      SHIM_HOST Host to bind
      SHIM_PORT Port to bind
      SHIM_AUTH_MODE passthrough or upstream-key
      SHIM_LOCAL_API_KEY Local authentication key
      SHIM_MERGE_MODE merge, override, or strict
      SHIM_PROVIDER_ONLY Comma-separated allowed providers
      SHIM_PROVIDER_ORDER Comma-separated provider order
      SHIM_PROVIDER_IGNORE Comma-separated ignored providers
      SHIM_PROVIDER_SORT price, throughput, or latency
      SHIM_PROVIDER_ALLOW_FALLBACKS true or false
      SHIM_PROVIDER_REQUIRE_PARAMETERS true or false
      SHIM_PROVIDER_DATA_COLLECTION allow or deny
      SHIM_PROVIDER_ZDR true or false
      SHIM_PROVIDER_QUANTIZATIONS Comma-separated quantizations
      SHIM_PROVIDER_PREFERRED_MIN_THROUGHPUT Number or JSON thresholds
      SHIM_PROVIDER_PREFERRED_MAX_LATENCY Number or JSON thresholds
      SHIM_PROVIDER_MAX_PRICE JSON: {"prompt":1.0,"completion":4.0}

      Config File

      Create a shim-config.json:

      {
        "host": "127.0.0.1",
        "port": 8787,
        "merge_mode": "merge",
        "policy": {
          "only": ["fireworks"],
          "sort": "throughput",
          "allow_fallbacks": false
        },
        "auth_mode": "passthrough",
        "log_level": "info"
      }

      Run with: npx openrouter-provider-shim serve --config shim-config.json

      Merge Modes

      merge (default)

      • If request has no provider, inject the configured policy
      • If request has provider, merge missing fields from policy without overriding

      override

      • Replace request provider entirely with policy provider (hard enforcement)

      strict

      • If request provider exists and differs from policy for any enforced fields, reject with HTTP 422
      • Useful for regulated enterprise policies

      API Endpoints

      Endpoint Description
      POST /v1/messages Anthropic Messages API
      POST /v1/chat/completions OpenAI Chat Completions API
      POST /v1/responses OpenAI Responses API
      GET /v1/models List available models (pass-through)
      GET /healthz Health check
      GET /version Version information
      GET /config Current configuration (sanitized)

      Testing

      # Chat Completions
      curl http://127.0.0.1:8787/v1/chat/completions \
        -H "Authorization: Bearer $OPENROUTER_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "moonshotai/kimi-k2.5",
          "messages": [{"role":"user","content":"Say hello"}],
          "stream": false
        }'
      
      # Anthropic Messages
      curl http://127.0.0.1:8787/v1/messages \
        -H "Authorization: Bearer $OPENROUTER_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "moonshotai/kimi-k2.5",
          "max_tokens": 256,
          "messages": [{"role":"user","content":"Hello from anthropic messages"}]
        }'
      
      # Responses API
      curl http://127.0.0.1:8787/v1/responses \
        -H "Authorization: Bearer $OPENROUTER_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "moonshotai/kimi-k2.5",
          "input": "Hello from responses"
        }'

      License

      MIT