Skip to content

ffflyZzz/opencode-anyrouter-cc

Repository files navigation

opencode-anyrouter-cc

An OpenCode plugin for using AnyRouter as a Claude API provider with OpenCode.

OpenCode sends tool names in lowercase (e.g. todowrite, webfetch), which causes compatibility issues when using AnyRouter's Claude API. This plugin transparently converts tool names to PascalCase and fixes array serialization problems, making OpenCode work seamlessly with AnyRouter.

Problems Solved

1. Tool Name Casing

OpenCode uses lowercase tool names, but AnyRouter's Claude API requires correct casing. This plugin converts them automatically:

OpenCode (lowercase) Converted (PascalCase)
todowrite TodoWrite
webfetch WebFetch
google_search Google_Search
Other names First letter capitalized

Transformation covers:

  • Request body: tools[].name and messages[].content[].name (tool_use blocks)
  • Response body: content[].name (tool_use blocks)
  • SSE stream: content_block_start events with tool_use type

2. Array Serialization Fix

Fixes an issue where arrays/objects in tool_use input fields are serialized as JSON strings. The plugin detects string values starting with [ or { and parses them back to proper JSON objects.

Installation

Prerequisites

Option 1: Local Link (Recommended for Development)

git clone <repo-url> opencode-anyrouter-cc
cd opencode-anyrouter-cc
bun install
bun run build

This outputs dist/index.js. You can then reference it directly in opencode.json:

{
  "plugin": ["/path/to/opencode-anyrouter-cc/dist/index.js"]
}

Option 2: Global Plugin Directory

bun install
bun run build
cp dist/index.js ~/.config/opencode/plugins/opencode-anyrouter-cc.js

Option 3: npm Package (After Publishing)

Add to your project's opencode.json:

{
  "plugin": ["opencode-anyrouter-cc"]
}

Or install globally in ~/.config/opencode/opencode.json:

{
  "plugin": ["opencode-anyrouter-cc"]
}

OpenCode Configuration for AnyRouter

Use either project-level opencode.json or global ~/.config/opencode/opencode.json.

Minimal working config

{
  "plugin": [
    "opencode-anyrouter-cc"
  ],
  "anthropic": {
    "options": {
      "baseURL": "https://anyrouter.top/v1",
      "apiKey": "sk-",
      "headers": { "Authorization": "Bearer sk-" }
    }
  }
}

Full config example

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": [
    "opencode-anyrouter-cc"
  ],
  "anthropic": {
    "options": {
      "baseURL": "https://anyrouter.top/v1",
      "apiKey": "sk-your-anyrouter-key",
      "headers": {
        "Authorization": "Bearer sk-your-anyrouter-key"
      }
    }
  }
}

If you use a local plugin file, replace "opencode-anyrouter-cc" with your relative path (for example "./opencode-anthropic-tool-name-transformer.mjs").

Development

Note: mise.toml is only for the maintainer's local toolchain. Windows users and general contributors do not need mise.

Build with Bun (cross-platform)

bun install
bun run build

Build with Node.js + npm (cross-platform)

npm install
npm run build

Both commands output to dist/index.js.

Build with mise (macOS / Linux only)

bun install          # Install dependencies
mise run build       # Build the plugin
mise run test        # Run tests
mise run link        # Symlink to OpenCode plugin dir

How It Works

The plugin monkey-patches globalThis.fetch at initialization time. It only intercepts requests to URLs containing /v1/messages (the Anthropic Messages API endpoint). All other requests pass through unchanged.

Request flow:
  OpenCode (lowercase) -> patchedFetch (PascalCase) -> AnyRouter API
                                                            |
  OpenCode <- transformResponse/SSE <-----------------------+

License

MIT

About

An OpenCode plugin for using AnyRouter as a Claude API provider with OpenCode.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors