This commit is contained in:
musistudio
2025-12-27 07:58:01 +08:00
parent 085ee97cdc
commit 160594a8d6
64 changed files with 17205 additions and 15 deletions

4
.gitignore vendored
View File

@@ -6,3 +6,7 @@ dist
.DS_Store .DS_Store
.vscode .vscode
tsconfig.tsbuildinfo tsconfig.tsbuildinfo
# Documentation build output
docs/build
docs/.docusaurus

29
docs/.gitignore vendored Normal file
View File

@@ -0,0 +1,29 @@
# Docusaurus build output
build/
dist/
# Docusaurus generated files
.docusaurus/
# Node modules
node_modules/
# Environment variables
.env
.env.local
.env.*.local
# IDE
.vscode/
.idea/
# OS
.DS_Store
Thumbs.db
# Logs
*.log
# Misc
*.swp
*.swo

104
docs/README.md Normal file
View File

@@ -0,0 +1,104 @@
# Claude Code Router Documentation
This directory contains the documentation website built with [Docusaurus](https://docusaurus.io/).
## Development
### Install Dependencies
```bash
cd docs
pnpm install
```
### Start Development Server
```bash
# From docs directory
pnpm start
# Or from root directory
pnpm dev:docs
```
Open [http://localhost:3000](http://localhost:3000) to view the documentation.
## Build
```bash
# From docs directory
pnpm build
# Or from root directory
pnpm build:docs
```
The built files will be in the `build/` directory.
## Serve Built Files
```bash
# From docs directory
pnpm serve
# Or from root directory
pnpm serve:docs
```
## Structure
```
docs/
├── docs/ # Markdown documentation files
│ ├── intro.md # Introduction page
│ ├── installation.md
│ ├── config/ # Configuration docs
│ ├── advanced/ # Advanced topics
│ └── cli/ # CLI reference
├── src/ # React components and pages
│ ├── components/ # Custom React components
│ ├── pages/ # Additional pages
│ ├── css/ # Custom CSS
│ └── theme/ # Docusaurus theme customization
├── static/ # Static assets (images, etc.)
├── i18n/ # Internationalization files
├── docusaurus.config.ts # Docusaurus configuration
└── sidebars.ts # Documentation sidebar structure
```
## Adding Documentation
### Adding New Docs
Create a new Markdown file in the `docs/` directory and add it to `sidebars.ts`.
### Adding New Pages
Add React components to `src/pages/`.
### Customizing Styles
Edit `src/css/custom.css`.
## Internationalization
Documentation supports both English and Chinese.
- English: `docs/` and `src/`
- Chinese: `i18n/zh/docusaurus-plugin-content-docs/current/`
To add Chinese translations:
1. Create corresponding files in `i18n/zh/docusaurus-plugin-content-docs/current/`
2. Translate the content
## Deployment
The documentation can be deployed to:
- GitHub Pages
- Netlify
- Vercel
- Any static hosting service
See [Docusaurus deployment docs](https://docusaurus.io/docs/deployment) for details.

View File

@@ -0,0 +1,108 @@
---
sidebar_position: 2
---
# ccr model
Interactive model selection and configuration.
## Usage
```bash
ccr model [command]
```
## Commands
### Select Model
Interactively select a model:
```bash
ccr model
```
This will display an interactive menu with available providers and models.
### Set Default Model
Set the default model directly:
```bash
ccr model set <provider>,<model>
```
Example:
```bash
ccr model set deepseek,deepseek-chat
```
### List Models
List all configured models:
```bash
ccr model list
```
### Add Model
Add a new model to configuration:
```bash
ccr model add <provider>,<model>
```
Example:
```bash
ccr model add groq,llama-3.3-70b-versatile
```
### Remove Model
Remove a model from configuration:
```bash
ccr model remove <provider>,<model>
```
## Examples
### Interactive selection
```bash
$ ccr model
? Select a provider: deepseek
? Select a model: deepseek-chat
Default model set to: deepseek,deepseek-chat
```
### Direct configuration
```bash
ccr model set deepseek,deepseek-chat
```
### View current configuration
```bash
ccr model list
```
Output:
```
Configured Models:
deepseek,deepseek-chat (default)
groq,llama-3.3-70b-versatile
gemini,gemini-1.5-pro
```
## Related Commands
- [ccr start](/docs/cli/start) - Start the server
- [ccr config](/docs/cli/other-commands#ccr-config) - Edit configuration

View File

@@ -0,0 +1,178 @@
---
sidebar_position: 4
---
# Other Commands
Additional CLI commands for managing Claude Code Router.
## ccr stop
Stop the running server.
```bash
ccr stop
```
## ccr restart
Restart the server.
```bash
ccr restart
```
## ccr code
Execute a claude command through the router.
```bash
ccr code [args...]
```
## ccr activate
Output shell environment variables for integration.
```bash
ccr activate
```
Output:
```bash
export ANTHROPIC_API_URL="http://localhost:8080/v1"
export ANTHROPIC_API_KEY="sk-xxxxx"
```
To use in your shell:
```bash
eval "$(ccr activate)"
```
## ccr ui
Open the Web UI in your browser.
```bash
ccr ui
```
## ccr statusline
Integrated statusline (reads JSON from stdin).
```bash
echo '{"status":"running"}' | ccr statusline
```
## ccr config
Configuration management commands.
### Edit Configuration
```bash
ccr config edit
```
Opens the configuration file in your default editor.
### Validate Configuration
```bash
ccr config validate
```
Validates the current configuration file.
### Show Configuration
```bash
ccr config show
```
Displays the current configuration (with sensitive values masked).
## ccr preset
Preset management commands.
### List Presets
```bash
ccr preset list
```
### Apply Preset
```bash
ccr preset apply <name>
```
### Save Preset
```bash
ccr preset save <name>
```
## ccr log
View server logs.
```bash
ccr log [options]
```
Options:
- `-f, --follow`: Follow log output (like `tail -f`)
- `-n <lines>`: Number of lines to show
## Global Options
These options can be used with any command:
| Option | Description |
|--------|-------------|
| `-h, --help` | Show help |
| `-v, --version` | Show version number |
| `--config <path>` | Path to configuration file |
| `--verbose` | Enable verbose output |
## Examples
### Stop the server
```bash
ccr stop
```
### Restart with custom config
```bash
ccr restart --config /path/to/config.json
```
### View and set environment variables
```bash
eval "$(ccr activate)"
```
### Open Web UI
```bash
ccr ui
```
### Follow logs
```bash
ccr log -f
```
## Related Documentation
- [Getting Started](/docs/intro) - Introduction to Claude Code Router
- [Configuration](/docs/config/basic) - Configuration guide

View File

@@ -0,0 +1,81 @@
---
sidebar_position: 1
---
# ccr start
Start the Claude Code Router server.
## Usage
```bash
ccr start [options]
```
## Options
| Option | Alias | Description |
|--------|-------|-------------|
| `--port <number>` | `-p` | Port to listen on (default: 8080) |
| `--config <path>` | `-c` | Path to configuration file |
| `--daemon` | `-d` | Run as daemon (background process) |
| `--log-level <level>` | `-l` | Log level (fatal/error/warn/info/debug/trace) |
## Examples
### Start with default settings
```bash
ccr start
```
### Start on custom port
```bash
ccr start --port 3000
```
### Start with custom config
```bash
ccr start --config /path/to/config.json
```
### Start as daemon
```bash
ccr start --daemon
```
### Start with debug logging
```bash
ccr start --log-level debug
```
## Environment Variables
You can also configure the server using environment variables:
| Variable | Description |
|----------|-------------|
| `PORT` | Port to listen on |
| `CONFIG_PATH` | Path to configuration file |
| `LOG_LEVEL` | Logging level |
| `CUSTOM_ROUTER_PATH` | Path to custom router function |
| `HOST` | Host to bind to (default: 0.0.0.0) |
## Output
When started successfully, you'll see:
```
Claude Code Router is running on http://localhost:8080
API endpoint: http://localhost:8080/v1
```
## Related Commands
- [ccr stop](/docs/cli/other-commands#ccr-stop) - Stop the server
- [ccr restart](/docs/cli/other-commands#ccr-restart) - Restart the server
- [ccr status](/docs/cli/other-commands#ccr-status) - Check server status

View File

@@ -0,0 +1,62 @@
---
sidebar_position: 3
---
# ccr status
Show the current status of the Claude Code Router server.
## Usage
```bash
ccr status
```
## Output
### Running Server
When the server is running:
```
Claude Code Router Status: Running
Version: 2.0.0
PID: 12345
Port: 8080
Uptime: 2h 34m
Configuration: /home/user/.claude-code-router/config.json
```
### Stopped Server
When the server is not running:
```
Claude Code Router Status: Stopped
```
## Exit Codes
| Code | Description |
|------|-------------|
| 0 | Server is running |
| 1 | Server is stopped |
| 2 | Error checking status |
## Examples
```bash
$ ccr status
Claude Code Router Status: Running
Version: 2.0.0
PID: 12345
Port: 8080
Uptime: 2h 34m
```
## Related Commands
- [ccr start](/docs/cli/start) - Start the server
- [ccr stop](/docs/cli/other-commands#ccr-stop) - Stop the server
- [ccr restart](/docs/cli/other-commands#ccr-restart) - Restart the server

View File

@@ -0,0 +1,208 @@
# CLI 基础配置
CLI 使用与 Server 相同的配置文件:`~/.claude-code-router/config.json`
## 配置文件位置
```bash
~/.claude-code-router/config.json
```
## 快速配置
使用交互式命令配置:
```bash
ccr model
```
这将引导你完成:
1. 选择 LLM 提供商
2. 配置 API Key
3. 选择模型
4. 设置路由规则
## 手动配置
### 编辑配置文件
```bash
# 打开配置文件
nano ~/.claude-code-router/config.json
```
### 最小配置示例
```json5
{
// API 密钥(可选,用于保护服务)
"APIKEY": "your-api-key-here",
// LLM 提供商
"Providers": [
{
"name": "openai",
"baseUrl": "https://api.openai.com/v1",
"apiKey": "$OPENAI_API_KEY",
"models": ["gpt-4", "gpt-3.5-turbo"]
}
],
// 默认路由
"Router": {
"default": "openai,gpt-4"
}
}
```
## 环境变量
配置支持环境变量插值:
```json5
{
"Providers": [
{
"apiKey": "$OPENAI_API_KEY" // 从环境变量读取
}
]
}
```
`.bashrc``.zshrc` 中设置:
```bash
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
```
## 常用配置项
### HOST 和 PORT
```json5
{
"HOST": "127.0.0.1", // 监听地址
"PORT": 3456 // 监听端口
}
```
### 日志配置
```json5
{
"LOG": true, // 启用日志
"LOG_LEVEL": "info" // 日志级别
}
```
### 路由配置
```json5
{
"Router": {
"default": "openai,gpt-4",
"background": "openai,gpt-3.5-turbo",
"think": "openai,gpt-4",
"longContext": "anthropic,claude-3-opus"
}
}
```
## 配置验证
配置文件会自动验证。常见错误:
- **缺少 Providers**:必须至少配置一个提供商
- **API Key 缺失**:如果配置了 Providers必须提供 API Key
- **模型不存在**:确保模型在提供商的 models 列表中
## 配置备份
每次更新配置时会自动备份:
```
~/.claude-code-router/config.backup.{timestamp}.json
```
## 重新加载配置
修改配置后需要重启服务:
```bash
ccr restart
```
## 查看当前配置
```bash
# 通过 API 查看
curl http://localhost:3456/api/config
# 或查看配置文件
cat ~/.claude-code-router/config.json
```
## 示例配置
### OpenAI
```json5
{
"Providers": [
{
"name": "openai",
"baseUrl": "https://api.openai.com/v1",
"apiKey": "$OPENAI_API_KEY",
"models": ["gpt-4", "gpt-3.5-turbo"]
}
],
"Router": {
"default": "openai,gpt-4"
}
}
```
### Anthropic
```json5
{
"Providers": [
{
"name": "anthropic",
"baseUrl": "https://api.anthropic.com/v1",
"apiKey": "$ANTHROPIC_API_KEY",
"models": ["claude-3-5-sonnet-20241022", "claude-3-opus-20240229"]
}
],
"Router": {
"default": "anthropic,claude-3-5-sonnet-20241022"
}
}
```
### 多提供商
```json5
{
"Providers": [
{
"name": "openai",
"baseUrl": "https://api.openai.com/v1",
"apiKey": "$OPENAI_API_KEY",
"models": ["gpt-4", "gpt-3.5-turbo"]
},
{
"name": "anthropic",
"baseUrl": "https://api.anthropic.com/v1",
"apiKey": "$ANTHROPIC_API_KEY",
"models": ["claude-3-5-sonnet-20241022", "claude-3-opus-20240229"]
}
],
"Router": {
"default": "openai,gpt-4",
"think": "anthropic,claude-3-5-sonnet-20241022",
"background": "openai,gpt-3.5-turbo"
}
}
```

View File

@@ -0,0 +1,213 @@
# 项目级配置
除了全局配置,`ccr` 还支持为特定项目设置不同的路由规则。
## 项目配置文件
项目配置文件位于:
```
~/.claude/projects/<project-id>/claude-code-router.json
```
其中 `<project-id>` 是 Claude Code 项目的唯一标识符。
## 项目配置结构
```json5
{
"Router": {
"default": "openai,gpt-4",
"background": "openai,gpt-3.5-turbo"
}
}
```
## 查找项目 ID
### 方法一:使用 CLI
```bash
# 在项目目录中运行
ccr status
```
输出会显示当前项目 ID
```
Project: my-project (abc123def456)
```
### 方法二:查看 Claude Code 配置
```bash
cat ~/.claude.json
```
找到你的项目 ID
```json
{
"projects": {
"abc123def456": {
"path": "/path/to/your/project",
"name": "my-project"
}
}
}
```
## 创建项目配置
### 手动创建
```bash
# 创建项目配置目录
mkdir -p ~/.claude/projects/abc123def456
# 创建配置文件
cat > ~/.claude/projects/abc123def456/claude-code-router.json << 'EOF'
{
"Router": {
"default": "anthropic,claude-3-5-sonnet-20241022",
"background": "openai,gpt-3.5-turbo"
}
}
EOF
```
### 使用 ccr model 命令
```bash
# 在项目目录中运行
cd /path/to/your/project
ccr model --project
```
## 配置优先级
路由配置的优先级(从高到低):
1. **自定义路由函数** (`CUSTOM_ROUTER_PATH`)
2. **项目级配置** (`~/.claude/projects/<id>/claude-code-router.json`)
3. **全局配置** (`~/.claude-code-router/config.json`)
4. **内置路由规则**
## 使用场景
### 场景一:不同项目使用不同模型
```json5
// Web 项目使用 GPT-4
~/.claude/projects/web-project-id/claude-code-router.json:
{
"Router": {
"default": "openai,gpt-4"
}
}
// AI 项目使用 Claude
~/.claude/projects/ai-project-id/claude-code-router.json:
{
"Router": {
"default": "anthropic,claude-3-5-sonnet-20241022"
}
}
```
### 场景二:测试项目使用低成本模型
```json5
~/.claude/projects/test-project-id/claude-code-router.json:
{
"Router": {
"default": "openai,gpt-3.5-turbo",
"background": "openai,gpt-3.5-turbo"
}
}
```
### 场景三:长上下文项目
```json5
~/.claude/projects/long-context-project-id/claude-code-router.json:
{
"Router": {
"default": "anthropic,claude-3-opus-20240229",
"longContext": "anthropic,claude-3-opus-20240229"
}
}
```
## 验证项目配置
```bash
# 查看当前项目使用的路由
ccr status
# 查看日志确认路由决策
tail -f ~/.claude-code-router/claude-code-router.log
```
## 删除项目配置
```bash
rm ~/.claude/projects/<project-id>/claude-code-router.json
```
删除后会回退到全局配置。
## 完整示例
假设你有两个项目:
### 全局配置(`~/.claude-code-router/config.json`
```json5
{
"Providers": [
{
"name": "openai",
"baseUrl": "https://api.openai.com/v1",
"apiKey": "$OPENAI_API_KEY",
"models": ["gpt-4", "gpt-3.5-turbo"]
},
{
"name": "anthropic",
"baseUrl": "https://api.anthropic.com/v1",
"apiKey": "$ANTHROPIC_API_KEY",
"models": ["claude-3-5-sonnet-20241022"]
}
],
"Router": {
"default": "openai,gpt-4",
"background": "openai,gpt-3.5-turbo"
}
}
```
### Web 项目配置
```json5
{
"Router": {
"default": "openai,gpt-4"
}
}
```
### AI 项目配置
```json5
{
"Router": {
"default": "anthropic,claude-3-5-sonnet-20241022",
"think": "anthropic,claude-3-5-sonnet-20241022"
}
}
```
这样:
- Web 项目使用 GPT-4
- AI 项目使用 Claude
- 所有项目的后台任务使用 GPT-3.5-turbo继承全局配置

View File

@@ -0,0 +1,45 @@
---
sidebar_position: 2
---
# Installation
Install Claude Code Router globally using your preferred package manager.
## Prerequisites
- **Node.js**: >= 18.0.0
- **pnpm**: >= 8.0.0 (if using pnpm)
- An API key from your preferred LLM provider
## Install via npm
```bash
npm install -g @musistudio/claude-code-router-cli
```
## Install via pnpm
```bash
pnpm add -g @musistudio/claude-code-router-cli
```
## Install via Yarn
```bash
yarn global add @musistudio/claude-code-router-cli
```
## Verify Installation
After installation, verify that `ccr` is available:
```bash
ccr --version
```
You should see the version number displayed.
## Next Steps
Once installed, proceed to [Quick Start](/docs/quick-start) to configure and start using the router.

83
docs/docs/cli/intro.md Normal file
View File

@@ -0,0 +1,83 @@
# CLI 简介
Claude Code Router CLI (`ccr`) 是一个命令行工具,用于管理和控制 Claude Code Router 服务。
## 功能概述
`ccr` 提供以下功能:
- **服务管理**:启动、停止、重启服务
- **配置管理**:交互式配置模型选择
- **状态查看**:查看服务运行状态
- **代码执行**:直接执行 `claude` 命令
- **环境集成**:输出环境变量用于 shell 集成
- **Web UI**:打开 Web 管理界面
- **状态栏**:集成到编辑器状态栏
## 安装
```bash
npm install -g @musistudio/claude-code-router-cli
```
或使用项目别名:
```bash
npm install -g claude-code-router
```
## 基本使用
### 启动服务
```bash
ccr start
```
### 查看状态
```bash
ccr status
```
### 停止服务
```bash
ccr stop
```
### 查看模型
```bash
ccr model
```
## 与 Claude Code 集成
`ccr` 可以与 Claude Code 无缝集成,将请求路由到你选择的 LLM 提供商。
### 方式一:设置 API 地址
```bash
export ANTHROPIC_BASE_URL="http://localhost:3456/v1"
export ANTHROPIC_API_KEY="your-api-key"
```
### 方式二:使用 activate 命令
```bash
eval "$(ccr activate)"
```
## 配置文件
`ccr` 使用与 Server 相同的配置文件:`~/.claude-code-router/config.json`
配置一次CLI 和 Server 都会使用。
## 下一步
- [安装指南](/docs/cli/installation) - 详细安装说明
- [快速开始](/docs/cli/quick-start) - 5 分钟上手
- [命令参考](/docs/category/cli-commands) - 完整命令列表
- [配置说明](/docs/category/cli-config) - 配置文件详解

View File

@@ -0,0 +1,81 @@
---
sidebar_position: 3
---
# Quick Start
Get up and running with Claude Code Router in 5 minutes.
## 1. Start the Router
```bash
ccr start
```
The router will start on `http://localhost:8080` by default.
## 2. Configure Environment Variables
Set the following environment variables in your shell:
```bash
export ANTHROPIC_API_URL="http://localhost:8080/v1"
export ANTHROPIC_API_KEY="your-provider-api-key"
```
Or use the `ccr activate` command to get the environment variables:
```bash
eval "$(ccr activate)"
```
## 3. Use Claude Code
Now you can use Claude Code normally:
```bash
claude code
```
Your requests will be routed through Claude Code Router to your configured provider.
## 4. Configure Providers (Optional)
To configure multiple providers or custom routing, use:
```bash
ccr model
```
This will open an interactive menu to select and configure models.
Or edit the configuration file directly:
```bash
# Open config in your default editor
ccr config edit
```
Example configuration (`~/.claude-code-router/config.json`):
```json
{
"Providers": [
{
"NAME": "deepseek",
"HOST": "https://api.deepseek.com",
"APIKEY": "your-deepseek-api-key",
"MODELS": ["deepseek-chat", "deepseek-coder"]
}
],
"Router": {
"default": "deepseek,deepseek-chat"
}
}
```
## What's Next?
- [Basic Configuration](/docs/config/basic) - Learn about configuration options
- [Routing](/docs/config/routing) - Configure smart routing rules
- [CLI Commands](/docs/cli/start) - Explore all CLI commands

View File

@@ -0,0 +1,40 @@
---
sidebar_position: 2
---
# Agents
Extend functionality with the agent system.
## What are Agents?
Agents are pluggable feature modules that can:
- Detect whether to handle a request
- Modify requests
- Provide custom tools
## Built-in Agents
### Image Agent
Handles image-related tasks by detecting image URLs or file paths in requests.
## Agent Configuration
Agents are configured in the server configuration and automatically loaded.
## Agent Tool Call Flow
1. Detect and mark agents in `preHandler` hook
2. Add agent tools to the request
3. Intercept tool call events in `onSend` hook
4. Execute agent tool and initiate new LLM request
5. Stream results back
## Creating Custom Agents
Coming soon! Custom agent support is under development.
## Next Steps
- [Presets](/docs/advanced/presets) - Use predefined configurations

View File

@@ -0,0 +1,126 @@
---
sidebar_position: 1
---
# Custom Router
Write your own routing logic in JavaScript.
## Creating a Custom Router
Create a JavaScript file that exports a routing function:
```javascript
// custom-router.js
module.exports = function(config, context) {
const { scenario, projectId, tokenCount, request } = context;
// Your custom logic here
if (scenario === 'background') {
return 'groq,llama-3.3-70b-versatile';
}
if (tokenCount > 100000) {
return 'gemini,gemini-1.5-pro';
}
// Check request content
if (request && request.system && request.system.includes('code')) {
return 'deepseek,deepseek-coder';
}
// Default
return 'deepseek,deepseek-chat';
};
```
## Context Object
The router function receives a context object with:
| Field | Type | Description |
|-------|------|-------------|
| `scenario` | string | Detected scenario (background, think, webSearch, image, etc.) |
| `projectId` | string | Project ID from Claude Code |
| `tokenCount` | number | Estimated token count of the request |
| `request` | object | Full request object |
## Configuration
Set the environment variable to use your custom router:
```bash
export CUSTOM_ROUTER_PATH="/path/to/custom-router.js"
```
Or set it in your shell configuration:
```bash
# ~/.bashrc or ~/.zshrc
export CUSTOM_ROUTER_PATH="/path/to/custom-router.js"
```
## Return Format
The router function should return a string in the format:
```
{provider-name},{model-name}
```
Example:
```
deepseek,deepseek-chat
```
## Error Handling
If your router function throws an error or returns an invalid format, the router will fall back to the default routing configuration.
## Example: Time-Based Routing
```javascript
module.exports = function(config, context) {
const hour = new Date().getHours();
// Use faster models during work hours
if (hour >= 9 && hour <= 18) {
return 'groq,llama-3.3-70b-versatile';
}
// Use more capable models outside work hours
return 'deepseek,deepseek-chat';
};
```
## Example: Cost Optimization
```javascript
module.exports = function(config, context) {
const { tokenCount } = context;
// Use cheaper models for large requests
if (tokenCount > 50000) {
return 'groq,llama-3.3-70b-versatile';
}
// Use default for smaller requests
return 'deepseek,deepseek-chat';
};
```
## Testing Your Router
Test your custom router by checking the logs:
```bash
tail -f ~/.claude-code-router/claude-code-router.log
```
Look for routing decisions to see which model is being selected.
## Next Steps
- [Agents](/docs/advanced/agents) - Extend functionality with agents
- [Presets](/docs/advanced/presets) - Use predefined configurations

View File

@@ -0,0 +1,64 @@
---
sidebar_position: 3
---
# Presets
Use predefined configurations for quick setup.
## What are Presets?
Presets are pre-configured settings that include provider configurations, routing rules, and transformers optimized for specific use cases.
## Available Presets
### Development
Optimized for software development tasks:
- Fast response times
- Good for code generation
- Cost-effective
### Research
Optimized for research and analysis:
- Long context support
- High-quality responses
- More capable models
### Balanced
A balance between speed and quality:
- Good general-purpose performance
- Reasonable costs
- Wide model support
## Using Presets
Use the CLI to apply a preset:
```bash
ccr preset apply development
```
List available presets:
```bash
ccr preset list
```
## Creating Custom Presets
You can create custom presets by saving your configuration and reloading it later:
```bash
# Save current configuration as a preset
ccr preset save my-preset
# Load a saved preset
ccr preset apply my-preset
```
## Next Steps
- [CLI Reference](/docs/cli/start) - Complete CLI command reference

View File

@@ -0,0 +1,220 @@
# 配置 API
## GET /api/config
获取当前服务器配置。
### 请求示例
```bash
curl http://localhost:3456/api/config \
-H "x-api-key: your-api-key"
```
### 响应示例
```json
{
"HOST": "0.0.0.0",
"PORT": 3456,
"APIKEY": "sk-xxxxx",
"Providers": [
{
"name": "openai",
"baseUrl": "https://api.openai.com/v1",
"apiKey": "sk-...",
"models": ["gpt-4", "gpt-3.5-turbo"]
}
],
"Router": {
"default": "openai,gpt-4"
},
"transformers": [
"anthropic"
]
}
```
## POST /api/config
更新服务器配置。更新后会自动备份旧配置。
### 请求示例
```bash
curl -X POST http://localhost:3456/api/config \
-H "x-api-key: your-api-key" \
-H "content-type: application/json" \
-d '{
"HOST": "0.0.0.0",
"PORT": 3456,
"Providers": [
{
"name": "openai",
"baseUrl": "https://api.openai.com/v1",
"apiKey": "$OPENAI_API_KEY",
"models": ["gpt-4"]
}
],
"Router": {
"default": "openai,gpt-4"
}
}'
```
### 配置对象结构
#### 基础配置
| 字段 | 类型 | 必需 | 说明 |
|------|------|------|------|
| `HOST` | string | 否 | 监听地址(默认 127.0.0.1 |
| `PORT` | integer | 否 | 监听端口(默认 3456 |
| `APIKEY` | string | 否 | API 密钥 |
| `LOG` | boolean | 否 | 是否启用日志(默认 true |
| `LOG_LEVEL` | string | 否 | 日志级别debug/info/warn/error |
#### Providers 配置
```json
{
"Providers": [
{
"name": "provider-name",
"baseUrl": "https://api.example.com/v1",
"apiKey": "your-api-key",
"models": ["model-1", "model-2"]
}
]
}
```
| 字段 | 类型 | 必需 | 说明 |
|------|------|------|------|
| `name` | string | 是 | 提供商名称 |
| `baseUrl` | string | 是 | API 基础 URL |
| `apiKey` | string | 是 | API 密钥 |
| `models` | array | 是 | 支持的模型列表 |
#### Router 配置
```json
{
"Router": {
"default": "provider,model",
"longContextThreshold": 100000,
"routes": {
"background": "lightweight-model",
"think": "powerful-model",
"longContext": "long-context-model",
"webSearch": "search-model",
"image": "vision-model"
}
}
}
```
#### Transformers 配置
```json
{
"transformers": [
{
"name": "anthropic",
"provider": "provider-name",
"models": ["model-1"],
"options": {}
}
]
}
```
### 响应示例
成功:
```json
{
"success": true,
"message": "Config saved successfully"
}
```
### 配置备份
每次更新配置时,旧配置会自动备份到:
```
~/.claude-code-router/config.backup.{timestamp}.json
```
保留最近 3 个备份。
## GET /api/transformers
获取服务器加载的所有转换器列表。
### 请求示例
```bash
curl http://localhost:3456/api/transformers \
-H "x-api-key: your-api-key"
```
### 响应示例
```json
{
"transformers": [
{
"name": "anthropic",
"endpoint": null
},
{
"name": "openai",
"endpoint": null
},
{
"name": "gemini",
"endpoint": "https://generativelanguage.googleapis.com"
}
]
}
```
### 转换器列表
内置转换器:
- `anthropic` - Anthropic Claude 格式
- `openai` - OpenAI 格式
- `deepseek` - DeepSeek 格式
- `gemini` - Google Gemini 格式
- `openrouter` - OpenRouter 格式
- `groq` - Groq 格式
- `maxtoken` - 调整 max_tokens 参数
- `tooluse` - 工具使用转换
- `reasoning` - 推理模式转换
- `enhancetool` - 增强工具功能
## 环境变量插值
配置支持环境变量插值:
```json
{
"Providers": [
{
"apiKey": "$OPENAI_API_KEY"
}
]
}
```
或使用 `${VAR_NAME}` 格式:
```json
{
"baseUrl": "${API_BASE_URL}"
}
```

View File

@@ -0,0 +1,190 @@
# 日志 API
## GET /api/logs/files
获取所有可用的日志文件列表。
### 请求示例
```bash
curl http://localhost:3456/api/logs/files \
-H "x-api-key: your-api-key"
```
### 响应示例
```json
[
{
"name": "ccr-20241226143022.log",
"path": "/home/user/.claude-code-router/logs/ccr-20241226143022.log",
"size": 1024000,
"lastModified": "2024-12-26T14:30:22.000Z"
},
{
"name": "ccr-20241226143021.log",
"path": "/home/user/.claude-code-router/logs/ccr-20241226143021.log",
"size": 980000,
"lastModified": "2024-12-26T14:30:21.000Z"
}
]
```
### 字段说明
| 字段 | 类型 | 说明 |
|------|------|------|
| `name` | string | 文件名 |
| `path` | string | 完整文件路径 |
| `size` | integer | 文件大小(字节) |
| `lastModified` | string | 最后修改时间ISO 8601 |
文件按修改时间倒序排列。
## GET /api/logs
获取指定日志文件的内容。
### 查询参数
| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| `file` | string | 否 | 日志文件路径(默认使用 app.log |
### 请求示例(获取默认日志)
```bash
curl "http://localhost:3456/api/logs" \
-H "x-api-key: your-api-key"
```
### 请求示例(获取指定文件)
```bash
curl "http://localhost:3456/api/logs?file=/home/user/.claude-code-router/logs/ccr-20241226143022.log" \
-H "x-api-key: your-api-key"
```
### 响应示例
```json
[
"{\"level\":30,\"time\":1703550622000,\"pid\":12345,\"hostname\":\"server\",\"msg\":\"Incoming request\",\"req\":{\"id\":1,\"method\":\"POST\",\"url\":\"/v1/messages\",\"remoteAddress\":\"127.0.0.1\"}}",
"{\"level\":30,\"time\":1703550622500,\"pid\":12345,\"hostname\":\"server\",\"msg\":\"Request completed\",\"res\":{\"statusCode\":200,\"responseTime\":500}}",
"..."
]
```
返回的是日志行数组,每行是一个 JSON 字符串。
### 日志格式
日志使用 Pino 格式:
```json
{
"level": 30,
"time": 1703550622000,
"pid": 12345,
"hostname": "server",
"msg": "Incoming request",
"req": {
"id": 1,
"method": "POST",
"url": "/v1/messages",
"remoteAddress": "127.0.0.1"
}
}
```
### 日志级别
| 级别 | 值 | 说明 |
|------|------|------|
| `trace` | 10 | 最详细的日志 |
| `debug` | 20 | 调试信息 |
| `info` | 30 | 一般信息 |
| `warn` | 40 | 警告信息 |
| `error` | 50 | 错误信息 |
| `fatal` | 60 | 致命错误 |
## DELETE /api/logs
清除指定日志文件的内容。
### 查询参数
| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| `file` | string | 否 | 日志文件路径(默认使用 app.log |
### 请求示例(清除默认日志)
```bash
curl -X DELETE "http://localhost:3456/api/logs" \
-H "x-api-key: your-api-key"
```
### 请求示例(清除指定文件)
```bash
curl -X DELETE "http://localhost:3456/api/logs?file=/home/user/.claude-code-router/logs/ccr-20241226143022.log" \
-H "x-api-key: your-api-key"
```
### 响应示例
```json
{
"success": true,
"message": "Logs cleared successfully"
}
```
## 日志位置
### 服务器日志
位置:`~/.claude-code-router/logs/`
文件命名:`ccr-{YYYYMMDD}{HH}{MM}{SS}.log`
内容HTTP 请求、API 调用、服务器事件
### 应用日志
位置:`~/.claude-code-router/claude-code-router.log`
内容:路由决策、业务逻辑事件
## 日志轮转
服务器日志使用 rotating-file-stream 自动轮转:
- **maxFiles**: 3 - 保留最近 3 个日志文件
- **interval**: 1d - 每天轮转
- **maxSize**: 50M - 单个文件最大 50MB
## 日志分析
### 使用 jq 分析日志
```bash
# 查看所有错误日志
curl "http://localhost:3456/api/logs" \
-H "x-api-key: your-api-key" | \
jq -r '.[] | fromjson | select(.level >= 40)'
# 统计请求次数
curl "http://localhost:3456/api/logs" \
-H "x-api-key: your-api-key" | \
jq -r '.[] | fromjson | .req.method' | \
sort | uniq -c
```
### 实时监控日志
```bash
# 通过 API 实时获取最新日志
watch -n 5 'curl -s "http://localhost:3456/api/logs" -H "x-api-key: your-api-key" | jq -r ".[-10:]"'
```

View File

@@ -0,0 +1,220 @@
# 消息 API
## POST /v1/messages
发送消息到 LLM兼容 Anthropic Claude API 格式。
### 请求格式
```bash
curl -X POST http://localhost:3456/v1/messages \
-H "x-api-key: your-api-key" \
-H "content-type: application/json" \
-d '{
"model": "claude-3-5-sonnet-20241022",
"max_tokens": 1024,
"messages": [
{
"role": "user",
"content": "Hello, Claude!"
}
]
}'
```
### 请求参数
| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| `model` | string | 是 | 模型名称(会被路由到实际提供商) |
| `messages` | array | 是 | 消息数组 |
| `max_tokens` | integer | 是 | 最大生成 Token 数 |
| `system` | string | 否 | 系统提示词 |
| `tools` | array | 否 | 可用工具列表 |
| `stream` | boolean | 否 | 是否使用流式响应(默认 false |
| `temperature` | number | 否 | 温度参数0-1 |
### 消息对象格式
```json
{
"role": "user|assistant",
"content": "string | array"
}
```
### 响应格式(非流式)
```json
{
"id": "msg_xxx",
"type": "message",
"role": "assistant",
"content": [
{
"type": "text",
"text": "Hello! How can I help you today?"
}
],
"model": "claude-3-5-sonnet-20241022",
"stop_reason": "end_turn",
"usage": {
"input_tokens": 10,
"output_tokens": 20
}
}
```
### 流式响应
设置 `stream: true` 启用流式响应:
```json
{
"model": "claude-3-5-sonnet-20241022",
"max_tokens": 1024,
"messages": [...],
"stream": true
}
```
流式响应事件类型:
- `message_start` - 消息开始
- `content_block_start` - 内容块开始
- `content_block_delta` - 内容增量
- `content_block_stop` - 内容块结束
- `message_delta` - 消息元数据usage
- `message_stop` - 消息结束
### 工具使用
支持函数调用Tool Use
```json
{
"model": "claude-3-5-sonnet-20241022",
"max_tokens": 1024,
"messages": [
{
"role": "user",
"content": "What's the weather like?"
}
],
"tools": [
{
"name": "get_weather",
"description": "Get the current weather",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name"
}
},
"required": ["location"]
}
}
]
}
```
### 多模态支持
支持图片输入:
```json
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": "iVBORw0KGgo..."
}
},
{
"type": "text",
"text": "Describe this image"
}
]
}
```
## POST /v1/messages/count_tokens
计算消息的 Token 数量。
### 请求格式
```bash
curl -X POST http://localhost:3456/v1/messages/count_tokens \
-H "x-api-key: your-api-key" \
-H "content-type: application/json" \
-d '{
"model": "claude-3-5-sonnet-20241022",
"messages": [
{
"role": "user",
"content": "Hello!"
}
],
"tools": [],
"system": "You are a helpful assistant."
}'
```
### 请求参数
| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| `model` | string | 是 | 模型名称 |
| `messages` | array | 是 | 消息数组 |
| `tools` | array | 否 | 工具列表 |
| `system` | string | 否 | 系统提示词 |
### 响应格式
```json
{
"input_tokens": 42
}
```
## 错误响应
### 400 Bad Request
```json
{
"error": {
"type": "invalid_request_error",
"message": "messages is required"
}
}
```
### 401 Unauthorized
```json
{
"error": {
"type": "authentication_error",
"message": "Invalid API key"
}
}
```
### 500 Internal Server Error
```json
{
"error": {
"type": "api_error",
"message": "Failed to connect to provider"
}
}
```

View File

@@ -0,0 +1,129 @@
# API 概览
Claude Code Router Server 提供了完整的 HTTP API支持
- **消息 API**:兼容 Anthropic Claude API 的消息接口
- **配置 API**:读取和更新服务器配置
- **日志 API**:查看和管理服务日志
- **工具 API**:计算 Token 数量
## 基础信息
**Base URL**: `http://localhost:3456`
**认证方式**: API Key通过 `x-api-key` 请求头)
```bash
curl -H "x-api-key: your-api-key" http://localhost:3456/api/config
```
## API 端点列表
### 消息相关
| 端点 | 方法 | 描述 |
|------|------|------|
| `/v1/messages` | POST | 发送消息(兼容 Anthropic API |
| `/v1/messages/count_tokens` | POST | 计算消息的 Token 数量 |
### 配置管理
| 端点 | 方法 | 描述 |
|------|------|------|
| `/api/config` | GET | 获取当前配置 |
| `/api/config` | POST | 更新配置 |
| `/api/transformers` | GET | 获取可用的转换器列表 |
### 日志管理
| 端点 | 方法 | 描述 |
|------|------|------|
| `/api/logs/files` | GET | 获取日志文件列表 |
| `/api/logs` | GET | 获取日志内容 |
| `/api/logs` | DELETE | 清除日志 |
### 服务管理
| 端点 | 方法 | 描述 |
|------|------|------|
| `/api/restart` | POST | 重启服务 |
| `/ui` | GET | Web 管理界面 |
| `/ui/` | GET | Web 管理界面(重定向) |
## 错误响应
所有 API 在发生错误时返回统一的错误格式:
```json
{
"error": {
"type": "invalid_request_error",
"message": "错误描述"
}
}
```
常见 HTTP 状态码:
- `200` - 成功
- `400` - 请求参数错误
- `401` - 未授权API Key 无效)
- `404` - 资源不存在
- `500` - 服务器内部错误
## 认证
### API Key 认证
在请求头中添加 API Key
```bash
curl -X POST http://localhost:3456/v1/messages \
-H "x-api-key: your-api-key" \
-H "content-type: application/json" \
-d '...'
```
### 无认证模式
当没有配置 Providers 时,服务器会监听在 `0.0.0.0` 且无需认证:
```json5
{
"Providers": []
}
```
## 流式响应
消息 API 支持流式响应Server-Sent Events
```bash
curl -X POST http://localhost:3456/v1/messages \
-H "x-api-key: your-api-key" \
-H "content-type: application/json" \
-d '{"stream": true, ...}'
```
流式响应格式:
```
event: message_start
data: {"type":"message_start","message":{...}}
event: content_block_delta
data: {"type":"content_block_delta","delta":{"type":"text_delta","text":"Hello"}}
event: message_stop
data: {"type":"message_stop"}
```
## 速率限制
服务器本身不实现速率限制,建议通过反向代理(如 Nginx配置。
## 版本管理
当前 API 版本:`v1`
所有 `/v1/*` 端点保持向后兼容。

View File

@@ -0,0 +1,146 @@
---
sidebar_position: 1
---
# Basic Configuration
Learn how to configure Claude Code Router to suit your needs.
## Configuration File Location
The configuration file is located at:
```
~/.claude-code-router/config.json
```
## Configuration Structure
### Providers
Configure LLM providers to route requests to:
```json
{
"Providers": [
{
"NAME": "deepseek",
"HOST": "https://api.deepseek.com",
"APIKEY": "your-api-key",
"MODELS": ["deepseek-chat", "deepseek-coder"]
},
{
"NAME": "groq",
"HOST": "https://api.groq.com/openai/v1",
"APIKEY": "your-groq-api-key",
"MODELS": ["llama-3.3-70b-versatile"]
}
]
}
```
### Router
Configure which model to use by default:
```json
{
"Router": {
"default": "deepseek,deepseek-chat"
}
}
```
Format: `{provider-name},{model-name}`
### Transformers
Apply transformations to requests/responses:
```json
{
"transformers": [
{
"name": "anthropic",
"providers": ["deepseek", "groq"]
}
]
}
```
### Environment Variables
Use environment variables in your configuration:
```json
{
"Providers": [
{
"NAME": "deepseek",
"HOST": "https://api.deepseek.com",
"APIKEY": "$DEEPSEEK_API_KEY"
}
]
}
```
Both `$VAR_NAME` and `${VAR_NAME}` syntax are supported.
## Complete Example
```json
{
"port": 8080,
"Providers": [
{
"NAME": "deepseek",
"HOST": "https://api.deepseek.com",
"APIKEY": "$DEEPSEEK_API_KEY",
"MODELS": ["deepseek-chat", "deepseek-coder"],
"transformers": ["anthropic"]
},
{
"NAME": "groq",
"HOST": "https://api.groq.com/openai/v1",
"APIKEY": "$GROQ_API_KEY",
"MODELS": ["llama-3.3-70b-versatile"],
"transformers": ["anthropic"]
}
],
"Router": {
"default": "deepseek,deepseek-chat",
"longContextThreshold": 100000,
"background": "groq,llama-3.3-70b-versatile"
},
"transformers": [
{
"name": "anthropic",
"providers": ["deepseek", "groq"]
}
]
}
```
## Editing Configuration
Use the CLI to edit the configuration:
```bash
ccr config edit
```
This will open the configuration file in your default editor.
## Reloading Configuration
After editing the configuration, restart the router:
```bash
ccr restart
```
## Next Steps
- [Providers Configuration](/docs/config/providers) - Detailed provider configuration
- [Routing Configuration](/docs/config/routing) - Configure routing rules
- [Transformers](/docs/config/transformers) - Apply transformations

View File

@@ -0,0 +1,86 @@
---
sidebar_position: 2
---
# Providers Configuration
Detailed guide for configuring LLM providers.
## Supported Providers
### DeepSeek
```json
{
"NAME": "deepseek",
"HOST": "https://api.deepseek.com",
"APIKEY": "your-api-key",
"MODELS": ["deepseek-chat", "deepseek-coder"],
"transformers": ["anthropic"]
}
```
### Groq
```json
{
"NAME": "groq",
"HOST": "https://api.groq.com/openai/v1",
"APIKEY": "your-api-key",
"MODELS": ["llama-3.3-70b-versatile"],
"transformers": ["anthropic"]
}
```
### Gemini
```json
{
"NAME": "gemini",
"HOST": "https://generativelanguage.googleapis.com/v1beta",
"APIKEY": "your-api-key",
"MODELS": ["gemini-1.5-pro"],
"transformers": ["anthropic"]
}
```
### OpenRouter
```json
{
"NAME": "openrouter",
"HOST": "https://openrouter.ai/api/v1",
"APIKEY": "your-api-key",
"MODELS": ["anthropic/claude-3.5-sonnet"],
"transformers": ["anthropic"]
}
```
## Provider Configuration Options
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `NAME` | string | Yes | Unique provider identifier |
| `HOST` | string | Yes | API base URL |
| `APIKEY` | string | Yes | API authentication key |
| `MODELS` | string[] | No | List of available models |
| `transformers` | string[] | No | List of transformers to apply |
## Model Selection
When selecting a model in routing, use the format:
```
{provider-name},{model-name}
```
For example:
```
deepseek,deepseek-chat
```
## Next Steps
- [Routing Configuration](/docs/config/routing) - Configure how requests are routed
- [Transformers](/docs/config/transformers) - Apply transformations to requests

View File

@@ -0,0 +1,148 @@
---
sidebar_position: 3
---
# Routing Configuration
Configure how requests are routed to different models.
## Default Routing
Set the default model for all requests:
```json
{
"Router": {
"default": "deepseek,deepseek-chat"
}
}
```
## Built-in Scenarios
### Background Tasks
Route background tasks to a lightweight model:
```json
{
"Router": {
"background": "groq,llama-3.3-70b-versatile"
}
}
```
### Thinking Mode (Plan Mode)
Route thinking-intensive tasks to a more capable model:
```json
{
"Router": {
"think": "deepseek,deepseek-chat"
}
}
```
### Long Context
Route requests with long context:
```json
{
"Router": {
"longContextThreshold": 100000,
"longContext": "gemini,gemini-1.5-pro"
}
}
```
### Web Search
Route web search tasks:
```json
{
"Router": {
"webSearch": "deepseek,deepseek-chat"
}
}
```
### Image Tasks
Route image-related tasks:
```json
{
"Router": {
"image": "gemini,gemini-1.5-pro"
}
}
```
## Project-Level Routing
Configure routing per project in `~/.claude/projects/<project-id>/claude-code-router.json`:
```json
{
"Router": {
"default": "groq,llama-3.3-70b-versatile"
}
}
```
Project-level configuration takes precedence over global configuration.
## Custom Router
Create a custom JavaScript router function:
1. Create a router file (e.g., `custom-router.js`):
```javascript
module.exports = function(config, context) {
// Analyze the request context
const { scenario, projectId, tokenCount } = context;
// Custom routing logic
if (scenario === 'background') {
return 'groq,llama-3.3-70b-versatile';
}
if (tokenCount > 100000) {
return 'gemini,gemini-1.5-pro';
}
// Default
return 'deepseek,deepseek-chat';
};
```
2. Set the `CUSTOM_ROUTER_PATH` environment variable:
```bash
export CUSTOM_ROUTER_PATH="/path/to/custom-router.js"
```
## Token Counting
The router uses `tiktoken` (cl100k_base) to estimate request token count. This is used for:
- Determining if a request exceeds `longContextThreshold`
- Custom routing logic based on token count
## Subagent Routing
Specify models for subagents using special tags:
```
<CCR-SUBAGENT-MODEL>provider,model</CCR-SUBAGENT-MODEL>
Please help me analyze this code...
```
## Next Steps
- [Transformers](/docs/config/transformers) - Apply transformations to requests
- [Custom Router](/docs/advanced/custom-router) - Advanced custom routing

View File

@@ -0,0 +1,176 @@
---
sidebar_position: 4
---
# Transformers
Transformers adapt API differences between providers.
## Built-in Transformers
### anthropic
Transforms requests to be compatible with Anthropic-style APIs:
```json
{
"transformers": [
{
"name": "anthropic",
"providers": ["deepseek", "groq"]
}
]
}
```
### deepseek
Specialized transformer for DeepSeek API:
```json
{
"transformers": [
{
"name": "deepseek",
"providers": ["deepseek"]
}
]
}
```
### gemini
Transformer for Google Gemini API:
```json
{
"transformers": [
{
"name": "gemini",
"providers": ["gemini"]
}
]
}
```
### groq
Transformer for Groq API:
```json
{
"transformers": [
{
"name": "groq",
"providers": ["groq"]
}
]
}
```
### openrouter
Transformer for OpenRouter API:
```json
{
"transformers": [
{
"name": "openrouter",
"providers": ["openrouter"]
}
]
}
```
## Applying Transformers
### Global Application
Apply to all requests for a provider:
```json
{
"Providers": [
{
"NAME": "deepseek",
"HOST": "https://api.deepseek.com",
"APIKEY": "your-api-key",
"transformers": ["anthropic"]
}
]
}
```
### Model-Specific Application
Apply to specific models:
```json
{
"transformers": [
{
"name": "maxtoken",
"options": {
"max_tokens": 8192
},
"models": ["deepseek,deepseek-chat"]
}
]
}
```
### Passing Options
Some transformers accept options:
```json
{
"transformers": [
{
"name": "maxtoken",
"options": {
"max_tokens": 8192
}
}
]
}
```
## Custom Transformers
Create custom transformer plugins:
1. Create a transformer file:
```javascript
module.exports = {
name: 'my-transformer',
transformRequest: async (req, config) => {
// Modify request
return req;
},
transformResponse: async (res, config) => {
// Modify response
return res;
}
};
```
2. Load in configuration:
```json
{
"transformers": [
{
"name": "my-transformer",
"path": "/path/to/transformer.js"
}
]
}
```
## Next Steps
- [Advanced Topics](/docs/advanced/custom-router) - Advanced routing customization
- [Agents](/docs/advanced/agents) - Extending with agents

View File

@@ -0,0 +1,182 @@
# Server 部署
Claude Code Router Server 支持多种部署方式,从本地开发到生产环境。
## Docker 部署(推荐)
### 使用 Docker Hub 镜像
```bash
docker run -d \
--name claude-code-router \
-p 3456:3456 \
-v ~/.claude-code-router:/app/.claude-code-router \
musistudio/claude-code-router:latest
```
### 使用 Docker Compose
创建 `docker-compose.yml`
```yaml
version: '3.8'
services:
claude-code-router:
image: musistudio/claude-code-router:latest
container_name: claude-code-router
ports:
- "3456:3456"
volumes:
- ./config:/app/.claude-code-router
environment:
- LOG_LEVEL=info
- HOST=0.0.0.0
- PORT=3456
restart: unless-stopped
```
启动服务:
```bash
docker-compose up -d
```
### 自定义构建
从源码构建 Docker 镜像:
```bash
git clone https://github.com/musistudio/claude-code-router.git
cd claude-code-router
docker build -t claude-code-router:latest .
```
## 配置文件挂载
将配置文件挂载到容器中:
```bash
docker run -d \
--name claude-code-router \
-p 3456:3456 \
-v $(pwd)/config.json:/app/.claude-code-router/config.json \
musistudio/claude-code-router:latest
```
配置文件示例:
```json5
{
// 服务器配置
"HOST": "0.0.0.0",
"PORT": 3456,
"APIKEY": "your-api-key-here",
// 日志配置
"LOG": true,
"LOG_LEVEL": "info",
// LLM 提供商配置
"Providers": [
{
"name": "openai",
"baseUrl": "https://api.openai.com/v1",
"apiKey": "$OPENAI_API_KEY",
"models": ["gpt-4", "gpt-3.5-turbo"]
}
],
// 路由配置
"Router": {
"default": "openai,gpt-4"
}
}
```
## 环境变量
支持通过环境变量覆盖配置:
| 变量名 | 说明 | 默认值 |
|--------|------|--------|
| `HOST` | 监听地址 | `127.0.0.1` |
| `PORT` | 监听端口 | `3456` |
| `APIKEY` | API 密钥 | - |
| `LOG_LEVEL` | 日志级别 | `debug` |
| `LOG` | 是否启用日志 | `true` |
## 生产环境建议
### 1. 使用反向代理
使用 Nginx 作为反向代理:
```nginx
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://localhost:3456;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache_bypass $http_upgrade;
}
}
```
### 2. 配置 HTTPS
使用 Let's Encrypt 获取免费证书:
```bash
sudo certbot --nginx -d your-domain.com
```
### 3. 日志管理
配置日志轮转和持久化:
```yaml
version: '3.8'
services:
claude-code-router:
image: musistudio/claude-code-router:latest
volumes:
- ./logs:/app/.claude-code-router/logs
environment:
- LOG_LEVEL=warn
```
### 4. 健康检查
配置 Docker 健康检查:
```yaml
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3456/api/config"]
interval: 30s
timeout: 10s
retries: 3
```
## 访问 Web UI
部署完成后,访问 Web UI
```
http://localhost:3456/ui/
```
通过 Web UI 可以:
- 查看和管理配置
- 监控日志
- 查看服务状态
## 二次开发
如果需要基于 CCR Server 进行二次开发,请查看 [API 参考](/docs/category/api)。

77
docs/docs/server/intro.md Normal file
View File

@@ -0,0 +1,77 @@
# Server 简介
Claude Code Router Server 是一个核心服务组件,负责将 Claude Code 的 API 请求路由到不同的 LLM 提供商。它提供了完整的 HTTP API支持
- **API 请求路由**:将 Anthropic 格式的请求转换为各种提供商的 API 格式
- **认证与授权**:支持 API Key 认证
- **配置管理**:动态配置提供商、路由规则和转换器
- **Web UI**:内置管理界面
- **日志系统**:完整的请求日志记录
## 架构概述
```
┌─────────────┐ ┌──────────────────┐ ┌──────────────┐
│ Claude Code │────▶│ CCR Server │────▶│ LLM Provider │
│ Client │ │ (Router + │ │ (OpenAI/ │
└─────────────┘ │ Transformer) │ │ Gemini/etc)│
└──────────────────┘ └──────────────┘
├─ Web UI
├─ Config API
└─ Logs API
```
## 核心功能
### 1. 请求路由
- 基于 Token 数量的智能路由
- 项目级路由配置
- 自定义路由函数
- 场景化路由background、think、longContext 等)
### 2. 请求转换
- 支持多种 LLM 提供商的 API 格式转换
- 内置转换器Anthropic、DeepSeek、Gemini、OpenRouter、Groq 等
- 可扩展的转换器系统
### 3. Agent 系统
- 插件式的 Agent 架构
- 内置图片处理 Agent
- 自定义 Agent 支持
### 4. 配置管理
- JSON5 格式配置文件
- 环境变量插值
- 配置热更新(需重启服务)
## 使用场景
### 场景一:个人本地服务
在本地运行服务,供个人 Claude Code 使用:
```bash
ccr start
```
### 场景二:团队共享服务
使用 Docker 部署,为团队成员提供共享服务:
```bash
docker run -d -p 3456:3456 musistudio/claude-code-router
```
### 场景三:二次开发
基于暴露的 API 构建自定义应用:
```bash
GET /api/config
POST /v1/messages
GET /api/logs
```
## 下一步
- [Docker 部署指南](/docs/server/deployment) - 学习如何部署服务
- [API 参考](/docs/category/api) - 查看完整的 API 文档
- [配置说明](/docs/category/server-config) - 了解服务器配置选项

123
docs/docusaurus.config.ts Normal file
View File

@@ -0,0 +1,123 @@
import type { Config } from '@docusaurus/types';
import type * as Preset from '@docusaurus/preset-classic';
import { themes as prismThemes } from 'prism-react-renderer';
const config: Config = {
title: 'Claude Code Router',
tagline: 'Use Claude Code without an Anthropics account and route it to another LLM provider',
favicon: 'img/favicon.ico',
url: 'https://claude-code-router.js.org',
baseUrl: '/',
organizationName: 'musistudio',
projectName: 'claude-code-router',
onBrokenLinks: 'warn',
onBrokenMarkdownLinks: 'warn',
onBrokenAnchors: 'warn',
i18n: {
defaultLocale: 'en',
locales: ['en', 'zh-CN'],
},
presets: [
[
'classic',
{
docs: {
sidebarPath: './sidebars.ts',
editUrl:
'https://github.com/musistudio/claude-code-router/tree/main/docs',
},
blog: {
showReadingTime: true,
editUrl:
'https://github.com/musistudio/claude-code-router/tree/main/docs',
},
theme: {
customCss: './src/css/custom.css',
},
} satisfies Preset.Options,
],
],
themeConfig: {
// Disable dark mode
colorMode: {
defaultMode: 'light',
disableSwitch: true,
respectPrefersColorScheme: false,
},
image: 'img/docusaurus-social-card.jpg',
navbar: {
title: 'Claude Code Router',
logo: {
alt: 'Claude Code Router Logo',
src: 'img/ccr.svg',
width: 32,
height: 32,
},
items: [
{
type: 'docSidebar',
sidebarId: 'tutorialSidebar',
position: 'left',
label: 'Documentation',
},
{ to: '/blog', label: 'Blog', position: 'left' },
{
type: 'localeDropdown',
position: 'right',
},
{
href: 'https://github.com/musistudio/claude-code-router',
label: 'GitHub',
position: 'right',
},
],
},
footer: {
style: 'light',
links: [
{
title: 'Docs',
items: [
{
label: 'Tutorial',
to: '/docs/intro',
},
],
},
{
title: 'Community',
items: [
{
label: 'GitHub',
href: 'https://github.com/musistudio/claude-code-router',
},
],
},
{
title: 'More',
items: [
{
label: 'Blog',
to: '/blog',
},
],
},
],
copyright: `Copyright © ${new Date().getFullYear()} Claude Code Router. Built with Docusaurus.`,
},
prism: {
theme: prismThemes.github,
darkTheme: prismThemes.dracula,
additionalLanguages: ['bash', 'typescript', 'javascript', 'json'],
},
} satisfies Preset.ThemeConfig,
};
export default config;

329
docs/i18n/zh-CN/code.json Normal file
View File

@@ -0,0 +1,329 @@
{
"theme.ErrorPageContent.title": {
"message": "页面已崩溃。",
"description": "The title of the fallback page when the page crashed"
},
"theme.BackToTopButton.buttonAriaLabel": {
"message": "回到顶部",
"description": "The ARIA label for the back to top button"
},
"theme.blog.archive.title": {
"message": "历史博文",
"description": "The page & hero title of the blog archive page"
},
"theme.blog.archive.description": {
"message": "历史博文",
"description": "The page & hero description of the blog archive page"
},
"theme.blog.paginator.navAriaLabel": {
"message": "博文列表分页导航",
"description": "The ARIA label for the blog pagination"
},
"theme.blog.paginator.newerEntries": {
"message": "较新的博文",
"description": "The label used to navigate to the newer blog posts page (previous page)"
},
"theme.blog.paginator.olderEntries": {
"message": "较旧的博文",
"description": "The label used to navigate to the older blog posts page (next page)"
},
"theme.blog.post.paginator.navAriaLabel": {
"message": "博文分页导航",
"description": "The ARIA label for the blog posts pagination"
},
"theme.blog.post.paginator.newerPost": {
"message": "较新一篇",
"description": "The blog post button label to navigate to the newer/previous post"
},
"theme.blog.post.paginator.olderPost": {
"message": "较旧一篇",
"description": "The blog post button label to navigate to the older/next post"
},
"theme.tags.tagsPageLink": {
"message": "查看所有标签",
"description": "The label of the link targeting the tag list page"
},
"theme.colorToggle.ariaLabel.mode.system": {
"message": "system mode",
"description": "The name for the system color mode"
},
"theme.colorToggle.ariaLabel.mode.light": {
"message": "浅色模式",
"description": "The name for the light color mode"
},
"theme.colorToggle.ariaLabel.mode.dark": {
"message": "暗黑模式",
"description": "The name for the dark color mode"
},
"theme.colorToggle.ariaLabel": {
"message": "切换浅色/暗黑模式(当前为{mode}",
"description": "The ARIA label for the color mode toggle"
},
"theme.docs.breadcrumbs.navAriaLabel": {
"message": "页面路径",
"description": "The ARIA label for the breadcrumbs"
},
"theme.docs.DocCard.categoryDescription.plurals": {
"message": "{count} 个项目",
"description": "The default description for a category card in the generated index about how many items this category includes"
},
"theme.docs.paginator.navAriaLabel": {
"message": "文件选项卡",
"description": "The ARIA label for the docs pagination"
},
"theme.docs.paginator.previous": {
"message": "上一页",
"description": "The label used to navigate to the previous doc"
},
"theme.docs.paginator.next": {
"message": "下一页",
"description": "The label used to navigate to the next doc"
},
"theme.docs.tagDocListPageTitle.nDocsTagged": {
"message": "{count} 篇文档带有标签",
"description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
},
"theme.docs.tagDocListPageTitle": {
"message": "{nDocsTagged}「{tagName}」",
"description": "The title of the page for a docs tag"
},
"theme.docs.versionBadge.label": {
"message": "版本:{versionLabel}"
},
"theme.docs.versions.unreleasedVersionLabel": {
"message": "此为 {siteTitle} {versionLabel} 版尚未发行的文档。",
"description": "The label used to tell the user that he's browsing an unreleased doc version"
},
"theme.docs.versions.unmaintainedVersionLabel": {
"message": "此为 {siteTitle} {versionLabel} 版的文档,现已不再积极维护。",
"description": "The label used to tell the user that he's browsing an unmaintained doc version"
},
"theme.docs.versions.latestVersionSuggestionLabel": {
"message": "最新的文档请参阅 {latestVersionLink} ({versionLabel})。",
"description": "The label used to tell the user to check the latest version"
},
"theme.docs.versions.latestVersionLinkLabel": {
"message": "最新版本",
"description": "The label used for the latest version suggestion link label"
},
"theme.common.headingLinkTitle": {
"message": "{heading}的直接链接",
"description": "Title for link to heading"
},
"theme.common.editThisPage": {
"message": "编辑此页",
"description": "The link label to edit the current page"
},
"theme.lastUpdated.atDate": {
"message": "于 {date} ",
"description": "The words used to describe on which date a page has been last updated"
},
"theme.lastUpdated.byUser": {
"message": "由 {user} ",
"description": "The words used to describe by who the page has been last updated"
},
"theme.lastUpdated.lastUpdatedAtBy": {
"message": "最后{byUser}{atDate}更新",
"description": "The sentence used to display when a page has been last updated, and by who"
},
"theme.NotFound.title": {
"message": "找不到页面",
"description": "The title of the 404 page"
},
"theme.navbar.mobileVersionsDropdown.label": {
"message": "选择版本",
"description": "The label for the navbar versions dropdown on mobile view"
},
"theme.tags.tagsListLabel": {
"message": "标签:",
"description": "The label alongside a tag list"
},
"theme.AnnouncementBar.closeButtonAriaLabel": {
"message": "关闭",
"description": "The ARIA label for close button of announcement bar"
},
"theme.admonition.caution": {
"message": "警告",
"description": "The default label used for the Caution admonition (:::caution)"
},
"theme.admonition.danger": {
"message": "危险",
"description": "The default label used for the Danger admonition (:::danger)"
},
"theme.admonition.info": {
"message": "信息",
"description": "The default label used for the Info admonition (:::info)"
},
"theme.admonition.note": {
"message": "备注",
"description": "The default label used for the Note admonition (:::note)"
},
"theme.admonition.tip": {
"message": "提示",
"description": "The default label used for the Tip admonition (:::tip)"
},
"theme.admonition.warning": {
"message": "注意",
"description": "The default label used for the Warning admonition (:::warning)"
},
"theme.blog.sidebar.navAriaLabel": {
"message": "最近博文导航",
"description": "The ARIA label for recent posts in the blog sidebar"
},
"theme.DocSidebarItem.expandCategoryAriaLabel": {
"message": "展开侧边栏分类 '{label}'",
"description": "The ARIA label to expand the sidebar category"
},
"theme.DocSidebarItem.collapseCategoryAriaLabel": {
"message": "折叠侧边栏分类 '{label}'",
"description": "The ARIA label to collapse the sidebar category"
},
"theme.IconExternalLink.ariaLabel": {
"message": "(opens in new tab)",
"description": "The ARIA label for the external link icon"
},
"theme.NavBar.navAriaLabel": {
"message": "主导航",
"description": "The ARIA label for the main navigation"
},
"theme.NotFound.p1": {
"message": "我们找不到您要找的页面。",
"description": "The first paragraph of the 404 page"
},
"theme.NotFound.p2": {
"message": "请联系原始链接来源网站的所有者,并告知他们链接已损坏。",
"description": "The 2nd paragraph of the 404 page"
},
"theme.navbar.mobileLanguageDropdown.label": {
"message": "选择语言",
"description": "The label for the mobile language switcher dropdown"
},
"theme.TOCCollapsible.toggleButtonLabel": {
"message": "本页总览",
"description": "The label used by the button on the collapsible TOC component"
},
"theme.blog.post.readMore": {
"message": "阅读更多",
"description": "The label used in blog post item excerpts to link to full blog posts"
},
"theme.blog.post.readMoreLabel": {
"message": "阅读 {title} 的全文",
"description": "The ARIA label for the link to full blog posts from excerpts"
},
"theme.CodeBlock.copy": {
"message": "复制",
"description": "The copy button label on code blocks"
},
"theme.CodeBlock.copied": {
"message": "复制成功",
"description": "The copied button label on code blocks"
},
"theme.CodeBlock.copyButtonAriaLabel": {
"message": "复制代码到剪贴板",
"description": "The ARIA label for copy code blocks button"
},
"theme.CodeBlock.wordWrapToggle": {
"message": "切换自动换行",
"description": "The title attribute for toggle word wrapping button of code block lines"
},
"theme.blog.post.readingTime.plurals": {
"message": "阅读需 {readingTime} 分钟",
"description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
},
"theme.docs.breadcrumbs.home": {
"message": "主页面",
"description": "The ARIA label for the home page in the breadcrumbs"
},
"theme.docs.sidebar.navAriaLabel": {
"message": "文档侧边栏",
"description": "The ARIA label for the sidebar navigation"
},
"theme.docs.sidebar.collapseButtonTitle": {
"message": "收起侧边栏",
"description": "The title attribute for collapse button of doc sidebar"
},
"theme.docs.sidebar.collapseButtonAriaLabel": {
"message": "收起侧边栏",
"description": "The title attribute for collapse button of doc sidebar"
},
"theme.docs.sidebar.closeSidebarButtonAriaLabel": {
"message": "关闭导航栏",
"description": "The ARIA label for close button of mobile sidebar"
},
"theme.navbar.mobileDropdown.collapseButton.expandAriaLabel": {
"message": "Expand the dropdown",
"description": "The ARIA label of the button to expand the mobile dropdown navbar item"
},
"theme.navbar.mobileDropdown.collapseButton.collapseAriaLabel": {
"message": "Collapse the dropdown",
"description": "The ARIA label of the button to collapse the mobile dropdown navbar item"
},
"theme.docs.sidebar.toggleSidebarButtonAriaLabel": {
"message": "切换导航栏",
"description": "The ARIA label for hamburger menu button of mobile navigation"
},
"theme.docs.sidebar.expandButtonTitle": {
"message": "展开侧边栏",
"description": "The ARIA label and title attribute for expand button of doc sidebar"
},
"theme.docs.sidebar.expandButtonAriaLabel": {
"message": "展开侧边栏",
"description": "The ARIA label and title attribute for expand button of doc sidebar"
},
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": {
"message": "← 回到主菜单",
"description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"
},
"theme.blog.post.plurals": {
"message": "{count} 篇博文",
"description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
},
"theme.blog.tagTitle": {
"message": "{nPosts} 含有标签「{tagName}」",
"description": "The title of the page for a blog tag"
},
"theme.blog.author.pageTitle": {
"message": "{authorName} - {nPosts}",
"description": "The title of the page for a blog author"
},
"theme.blog.authorsList.pageTitle": {
"message": "作者",
"description": "The title of the authors page"
},
"theme.blog.authorsList.viewAll": {
"message": "查看所有作者",
"description": "The label of the link targeting the blog authors page"
},
"theme.blog.author.noPosts": {
"message": "该作者尚未撰写任何文章。",
"description": "The text for authors with 0 blog post"
},
"theme.contentVisibility.unlistedBanner.title": {
"message": "未列出页",
"description": "The unlisted content banner title"
},
"theme.contentVisibility.unlistedBanner.message": {
"message": "此页面未列出。搜索引擎不会对其索引,只有拥有直接链接的用户才能访问。",
"description": "The unlisted content banner message"
},
"theme.contentVisibility.draftBanner.title": {
"message": "草稿页",
"description": "The draft content banner title"
},
"theme.contentVisibility.draftBanner.message": {
"message": "此页面是草稿,仅在开发环境中可见,不会包含在正式版本中。",
"description": "The draft content banner message"
},
"theme.ErrorPageContent.tryAgain": {
"message": "重试",
"description": "The label of the button to try again rendering when the React error boundary captures an error"
},
"theme.common.skipToMainContent": {
"message": "跳到主要内容",
"description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation"
},
"theme.tags.tagsPageTitle": {
"message": "标签",
"description": "The title of the tag list page"
}
}

View File

@@ -0,0 +1,14 @@
{
"title": {
"message": "Blog",
"description": "The title for the blog used in SEO"
},
"description": {
"message": "Blog",
"description": "The description for the blog used in SEO"
},
"sidebar.title": {
"message": "Recent posts",
"description": "The label for the left sidebar"
}
}

View File

@@ -0,0 +1,112 @@
---
id: advanced/agents
title: Agent 系统
sidebar_position: 2
---
# Agent 系统
使用 Agent 系统扩展功能。
## 什么是 Agent
Agent 是可插拔的功能模块,可以:
- 检测是否应处理请求
- 修改请求
- 提供自定义工具
## 内置 Agent
### Image Agent
通过检测请求中的图像 URL 或文件路径来处理图像相关任务。
当检测到图像相关内容时Image Agent 会:
1. 标记请求需要图像处理
2. 添加图像分析工具到请求中
3. 拦截工具调用事件
4. 执行图像分析并返回结果
## Agent 配置
Agent 在服务器配置中配置并自动加载。
### 启用 Image Agent
Image Agent 内置于服务器中,无需额外配置。当请求包含图像内容时自动激活。
### 强制使用 Image Agent
如果您的模型不支持工具调用,可以在配置中设置 `config.forceUseImageAgent``true`
```json
{
"Router": {
"image": "gemini,gemini-2.5-pro"
},
"forceUseImageAgent": true
}
```
## Agent 工具调用流程
1. **检测阶段**:在 `preHandler` 钩子中检测并标记 agents
2. **准备阶段**:将 agent 工具添加到请求中
3. **拦截阶段**:在 `onSend` 钩子中拦截工具调用事件
4. **执行阶段**:执行 agent 工具并发起新的 LLM 请求
5. **返回阶段**:将结果流式返回
## Agent 类型定义
```typescript
interface IAgent {
name: string;
shouldHandle: (req: any, config: any) => boolean;
reqHandler: (req: any, config: any) => void;
tools: Map<string, ITool>;
}
interface ITool {
name: string;
description: string;
input_schema: object;
handler: (args: any, context: any) => Promise<any>;
}
```
## 创建自定义 Agent
自定义 Agent 支持正在开发中!
## 使用示例
### 图像分析请求
当您发送包含图像的请求时:
```
请分析这张图片:/path/to/image.png
```
Image Agent 将:
1. 检测到图像路径
2. 添加图像分析工具
3. 调用配置的图像处理模型
4. 返回分析结果
### 路由到支持图像的模型
在配置中指定用于图像任务的模型:
```json
{
"Router": {
"image": "gemini,gemini-2.5-pro"
}
}
```
## 下一步
- [预设](/zh/docs/advanced/presets) - 使用预定义配置
- [自定义路由器](/zh/docs/advanced/custom-router) - 编写自定义路由逻辑

View File

@@ -0,0 +1,149 @@
---
id: advanced/custom-router
title: 自定义路由器
sidebar_position: 1
---
# 自定义路由器
使用 JavaScript 编写自己的路由逻辑。
## 创建自定义路由器
创建一个导出路由函数的 JavaScript 文件:
```javascript
// custom-router.js
module.exports = async function(req, config) {
// 获取用户消息
const userMessage = req.body.messages.find(m => m.role === 'user')?.content;
// 自定义逻辑
if (userMessage && userMessage.includes('解释代码')) {
return 'openrouter,anthropic/claude-3.5-sonnet';
}
// 返回 null 以使用默认路由
return null;
};
```
## 参数说明
路由函数接收以下参数:
| 参数 | 类型 | 说明 |
|------|------|------|
| `req` | object | 来自 Claude Code 的请求对象,包含请求体 |
| `config` | object | 应用程序的配置对象 |
## 配置
`config.json` 中设置 `CUSTOM_ROUTER_PATH` 以使用您的自定义路由器:
```json
{
"CUSTOM_ROUTER_PATH": "/path/to/custom-router.js"
}
```
## 返回格式
路由函数应返回以下格式的字符串:
```
{provider-name},{model-name}
```
示例:
```
deepseek,deepseek-chat
```
如果返回 `null`,则回退到默认路由配置。
## 错误处理
如果路由函数抛出错误或返回无效格式,路由器将回退到默认路由配置。
## 示例:基于时间的路由
```javascript
module.exports = async function(req, config) {
const hour = new Date().getHours();
// 工作时间使用更快的模型
if (hour >= 9 && hour <= 18) {
return 'groq,llama-3.3-70b-versatile';
}
// 非工作时间使用更强大的模型
return 'deepseek,deepseek-chat';
};
```
## 示例:成本优化
```javascript
module.exports = async function(req, config) {
const userMessage = req.body.messages.find(m => m.role === 'user')?.content;
// 简单任务使用较便宜的模型
if (userMessage && userMessage.length < 100) {
return 'groq,llama-3.3-70b-versatile';
}
// 复杂任务使用默认模型
return null;
};
```
## 示例:任务类型路由
```javascript
module.exports = async function(req, config) {
const userMessage = req.body.messages.find(m => m.role === 'user')?.content;
if (!userMessage) return null;
// 代码相关任务
if (userMessage.includes('代码') || userMessage.includes('code')) {
return 'deepseek,deepseek-coder';
}
// 解释任务
if (userMessage.includes('解释') || userMessage.includes('explain')) {
return 'openrouter,anthropic/claude-3.5-sonnet';
}
// 默认
return null;
};
```
## 测试您的路由器
通过检查日志来测试您的自定义路由器:
```bash
tail -f ~/.claude-code-router/claude-code-router.log
```
查找路由决策以查看正在选择哪个模型。
## 子代理路由
对于子代理内的路由,您必须在子代理提示词的**开头**包含 `<CCR-SUBAGENT-MODEL>provider,model</CCR-SUBAGENT-MODEL>` 来指定特定的提供商和模型。
**示例:**
```
<CCR-SUBAGENT-MODEL>openrouter,anthropic/claude-3.5-sonnet</CCR-SUBAGENT-MODEL>
请帮我分析这段代码是否存在潜在的优化空间...
```
## 下一步
- [Agent](/zh/docs/advanced/agents) - 使用 Agent 扩展功能
- [预设](/zh/docs/advanced/presets) - 使用预定义配置

View File

@@ -0,0 +1,174 @@
---
id: advanced/presets
title: 预设配置
sidebar_position: 3
---
# 预设配置
使用预定义配置进行快速设置。
## 什么是预设?
预设是预配置的设置,包括针对特定用例优化的提供商配置、路由规则和转换器。
## 可用预设
### Development开发
针对软件开发任务优化:
- 快速响应时间
- 适合代码生成
- 成本效益高
配置特点:
- 使用轻量级模型处理后台任务
- 为代码任务选择专用模型
- 优化的超时设置
### Research研究
针对研究和分析优化:
- 支持长上下文
- 高质量响应
- 更强大的模型
配置特点:
- 使用具有大上下文窗口的模型
- 为分析任务选择高级模型
- 较长的超时时间
### Balanced平衡
在速度和质量之间取得平衡:
- 良好的通用性能
- 合理的成本
- 广泛的模型支持
配置特点:
- 混合使用快速和高质量的模型
- 适合大多数日常任务
- 平衡的成本效益
## 使用预设
使用 CLI 应用预设:
```bash
ccr preset apply development
```
列出可用预设:
```bash
ccr preset list
```
## 创建自定义预设
您可以通过保存配置并稍后重新加载来创建自定义预设:
```bash
# 将当前配置保存为预设
ccr preset save my-preset
# 加载已保存的预设
ccr preset apply my-preset
```
## 预设管理
### 列出所有预设
```bash
ccr preset list
```
输出示例:
```
可用预设:
development - 开发优化配置
research - 研究优化配置
balanced - 平衡配置
my-preset - 自定义预设
```
### 应用预设
```bash
ccr preset apply <预设名称>
```
应用预设后,服务器将自动重启以加载新配置。
### 删除预设
```bash
ccr preset delete <预设名称>
```
## 预设文件位置
预设保存在:
```
~/.claude-code-router/presets/
```
每个预设都是一个 JSON 文件,包含完整的配置。
## 预设文件示例
```json
{
"name": "development",
"description": "针对软件开发优化的配置",
"Providers": [
{
"name": "deepseek",
"api_base_url": "https://api.deepseek.com/chat/completions",
"api_key": "$DEEPSEEK_API_KEY",
"models": ["deepseek-chat", "deepseek-coder"]
},
{
"name": "groq",
"api_base_url": "https://api.groq.com/openai/v1/chat/completions",
"api_key": "$GROQ_API_KEY",
"models": ["llama-3.3-70b-versatile"]
}
],
"Router": {
"default": "deepseek,deepseek-chat",
"background": "groq,llama-3.3-70b-versatile",
"think": "deepseek,deepseek-chat"
}
}
```
## 导出和导入预设
### 导出当前配置
```bash
ccr config show > my-config.json
```
### 导入配置
```bash
ccr config edit
# 然后粘贴导入的配置
```
## 最佳实践
1. **为不同项目创建预设**:为不同的工作流程创建专门的预设
2. **版本控制**:将常用预设保存在版本控制中
3. **文档化**:为自定义预设添加描述
4. **测试**:在应用预设后验证配置
## 下一步
- [CLI 参考](/zh/docs/cli/start) - 完整的 CLI 命令参考
- [配置](/zh/docs/config/basic) - 详细配置指南

View File

@@ -0,0 +1,128 @@
---
id: cli/model
title: ccr model
sidebar_position: 2
---
# ccr model
交互式模型选择和配置。
## 用法
```bash
ccr model [命令]
```
## 命令
### 选择模型
交互式选择模型:
```bash
ccr model
```
这将显示一个包含可用提供商和模型的交互式菜单。
### 设置默认模型
直接设置默认模型:
```bash
ccr model set <provider>,<model>
```
示例:
```bash
ccr model set deepseek,deepseek-chat
```
### 列出模型
列出所有配置的模型:
```bash
ccr model list
```
### 添加模型
添加新模型到配置:
```bash
ccr model add <provider>,<model>
```
示例:
```bash
ccr model add groq,llama-3.3-70b-versatile
```
### 删除模型
从配置中删除模型:
```bash
ccr model remove <provider>,<model>
```
## 示例
### 交互式选择
```bash
$ ccr model
? 选择一个提供商: deepseek
? 选择一个模型: deepseek-chat
默认模型设置为: deepseek,deepseek-chat
```
### 直接配置
```bash
ccr model set deepseek,deepseek-chat
```
### 查看当前配置
```bash
ccr model list
```
输出:
```
已配置的模型:
deepseek,deepseek-chat (默认)
groq,llama-3.3-70b-versatile
gemini,gemini-2.5-pro
```
## 交互式功能
`ccr model` 命令提供以下功能:
1. **查看当前配置**:查看所有已配置的模型和路由器设置
2. **切换模型**:快速更改每个路由器类型使用的模型
3. **添加新模型**:向现有提供商添加模型
4. **创建新提供商**:设置完整的提供商配置,包括:
- 提供商名称和 API 端点
- API 密钥
- 可用模型
- 转换器配置,支持:
- 多个转换器openrouter、deepseek、gemini 等)
- 转换器选项(例如,带自定义限制的 maxtoken
- 提供商特定路由例如OpenRouter 提供商偏好)
CLI 工具会验证所有输入并提供有用的提示来引导您完成配置过程,使管理复杂设置变得容易,无需手动编辑 JSON 文件。
## 相关命令
- [ccr start](/zh/docs/cli/start) - 启动服务器
- [ccr config](/zh/docs/cli/other-commands#ccr-config) - 编辑配置

View File

@@ -0,0 +1,203 @@
---
id: cli/other-commands
title: 其他命令
sidebar_position: 4
---
# 其他命令
管理 Claude Code Router 的其他 CLI 命令。
## ccr stop
停止运行中的服务器。
```bash
ccr stop
```
## ccr restart
重启服务器。
```bash
ccr restart
```
## ccr code
通过路由器执行 claude 命令。
```bash
ccr code [参数...]
```
## ccr activate
输出 shell 环境变量以供集成使用。
```bash
ccr activate
```
输出:
```bash
export ANTHROPIC_API_URL="http://localhost:3456/v1"
export ANTHROPIC_API_KEY="sk-xxxxx"
```
在 shell 中使用:
```bash
eval "$(ccr activate)"
```
`activate` 命令设置以下环境变量:
- `ANTHROPIC_AUTH_TOKEN`: 来自配置的 API 密钥
- `ANTHROPIC_BASE_URL`: 本地路由器端点(默认:`http://127.0.0.1:3456`
- `NO_PROXY`: 设置为 `127.0.0.1` 以防止代理干扰
- `DISABLE_TELEMETRY`: 禁用遥测
- `DISABLE_COST_WARNINGS`: 禁用成本警告
- `API_TIMEOUT_MS`: 来自配置的 API 超时时间
## ccr ui
在浏览器中打开 Web UI。
```bash
ccr ui
```
## ccr statusline
集成状态栏(从 stdin 读取 JSON
```bash
echo '{"status":"running"}' | ccr statusline
```
## ccr config
配置管理命令。
### 编辑配置
```bash
ccr config edit
```
在默认编辑器中打开配置文件。
### 验证配置
```bash
ccr config validate
```
验证当前配置文件。
### 显示配置
```bash
ccr config show
```
显示当前配置(敏感值已隐藏)。
## ccr preset
预设管理命令。
### 列出预设
```bash
ccr preset list
```
### 应用预设
```bash
ccr preset apply <名称>
```
### 保存预设
```bash
ccr preset save <名称>
```
保存当前配置为预设。
## ccr log
查看服务器日志。
```bash
ccr log [选项]
```
选项:
- `-f, --follow`: 跟踪日志输出(类似 `tail -f`
- `-n <行数>`: 显示的行数
## 全局选项
这些选项可用于任何命令:
| 选项 | 说明 |
|------|------|
| `-h, --help` | 显示帮助 |
| `-v, --version` | 显示版本号 |
| `--config <路径>` | 配置文件路径 |
| `--verbose` | 启用详细输出 |
## 示例
### 停止服务器
```bash
ccr stop
```
### 使用自定义配置重启
```bash
ccr restart --config /path/to/config.json
```
### 查看并设置环境变量
```bash
eval "$(ccr activate)"
```
### 打开 Web UI
```bash
ccr ui
```
### 跟踪日志
```bash
ccr log -f
```
### 列出可用预设
```bash
ccr preset list
```
### 应用预设
```bash
ccr preset apply development
```
## 相关文档
- [入门](/zh/docs/intro) - Claude Code Router 简介
- [配置](/zh/docs/config/basic) - 配置指南

View File

@@ -0,0 +1,83 @@
---
id: cli/start
title: ccr start
sidebar_position: 1
---
# ccr start
启动 Claude Code Router 服务器。
## 用法
```bash
ccr start [选项]
```
## 选项
| 选项 | 别名 | 说明 |
|------|------|------|
| `--port <number>` | `-p` | 监听端口号默认3456 |
| `--config <path>` | `-c` | 配置文件路径 |
| `--daemon` | `-d` | 作为守护进程运行(后台进程) |
| `--log-level <level>` | `-l` | 日志级别fatal/error/warn/info/debug/trace |
## 示例
### 使用默认设置启动
```bash
ccr start
```
### 在自定义端口启动
```bash
ccr start --port 3000
```
### 使用自定义配置启动
```bash
ccr start --config /path/to/config.json
```
### 作为守护进程启动
```bash
ccr start --daemon
```
### 启用调试日志
```bash
ccr start --log-level debug
```
## 环境变量
您也可以使用环境变量配置服务器:
| 变量 | 说明 |
|------|------|
| `PORT` | 监听端口号 |
| `CONFIG_PATH` | 配置文件路径 |
| `LOG_LEVEL` | 日志级别 |
| `CUSTOM_ROUTER_PATH` | 自定义路由器函数路径 |
| `HOST` | 绑定主机地址默认0.0.0.0 |
## 输出
启动成功后,您将看到:
```
Claude Code Router is running on http://localhost:3456
API endpoint: http://localhost:3456/v1
```
## 相关命令
- [ccr stop](/zh/docs/cli/other-commands#ccr-stop) - 停止服务器
- [ccr restart](/zh/docs/cli/other-commands#ccr-restart) - 重启服务器
- [ccr status](/zh/docs/cli/other-commands#ccr-status) - 检查服务器状态

View File

@@ -0,0 +1,64 @@
---
id: cli/status
title: ccr status
sidebar_position: 3
---
# ccr status
显示 Claude Code Router 服务器的当前状态。
## 用法
```bash
ccr status
```
## 输出
### 运行中的服务器
当服务器正在运行时:
```
Claude Code Router 状态: 运行中
版本: 2.0.0
PID: 12345
端口: 3456
运行时间: 2小时34分钟
配置: /home/user/.claude-code-router/config.json
```
### 已停止的服务器
当服务器未运行时:
```
Claude Code Router 状态: 已停止
```
## 退出代码
| 代码 | 说明 |
|------|------|
| 0 | 服务器正在运行 |
| 1 | 服务器已停止 |
| 2 | 检查状态时出错 |
## 示例
```bash
$ ccr status
Claude Code Router 状态: 运行中
版本: 2.0.0
PID: 12345
端口: 3456
运行时间: 2小时34分钟
```
## 相关命令
- [ccr start](/zh/docs/cli/start) - 启动服务器
- [ccr stop](/zh/docs/cli/other-commands#ccr-stop) - 停止服务器
- [ccr restart](/zh/docs/cli/other-commands#ccr-restart) - 重启服务器

View File

@@ -0,0 +1,161 @@
---
id: config/basic
title: 基础配置
sidebar_position: 1
---
# 基础配置
学习如何配置 Claude Code Router 以满足您的需求。
## 配置文件位置
配置文件位于:
```
~/.claude-code-router/config.json
```
## 配置结构
### Providers提供商
配置 LLM 提供商以将请求路由到:
```json
{
"Providers": [
{
"name": "deepseek",
"api_base_url": "https://api.deepseek.com/chat/completions",
"api_key": "your-api-key",
"models": ["deepseek-chat", "deepseek-coder"]
},
{
"name": "groq",
"api_base_url": "https://api.groq.com/openai/v1/chat/completions",
"api_key": "your-groq-api-key",
"models": ["llama-3.3-70b-versatile"]
}
]
}
```
### Router路由器
配置默认使用的模型:
```json
{
"Router": {
"default": "deepseek,deepseek-chat"
}
}
```
格式:`{provider-name},{model-name}`
### Transformers转换器
对请求/响应应用转换:
```json
{
"transformers": [
{
"path": "/path/to/custom-transformer.js",
"options": {
"key": "value"
}
}
]
}
```
### 环境变量
在配置中使用环境变量:
```json
{
"Providers": [
{
"name": "deepseek",
"api_base_url": "https://api.deepseek.com/chat/completions",
"api_key": "$DEEPSEEK_API_KEY"
}
]
}
```
同时支持 `$VAR_NAME``${VAR_NAME}` 语法。
## 完整示例
```json
{
"PORT": 8080,
"APIKEY": "your-secret-key",
"PROXY_URL": "http://127.0.0.1:7890",
"LOG": true,
"LOG_LEVEL": "debug",
"API_TIMEOUT_MS": 600000,
"Providers": [
{
"name": "deepseek",
"api_base_url": "https://api.deepseek.com/chat/completions",
"api_key": "$DEEPSEEK_API_KEY",
"models": ["deepseek-chat", "deepseek-coder"],
"transformer": {
"use": ["deepseek"]
}
},
{
"name": "groq",
"api_base_url": "https://api.groq.com/openai/v1/chat/completions",
"api_key": "$GROQ_API_KEY",
"models": ["llama-3.3-70b-versatile"]
}
],
"Router": {
"default": "deepseek,deepseek-chat",
"longContextThreshold": 100000,
"background": "groq,llama-3.3-70b-versatile"
}
}
```
## 编辑配置
使用 CLI 编辑配置:
```bash
ccr config edit
```
这将在您的默认编辑器中打开配置文件。
## 重新加载配置
编辑配置后,重启路由器:
```bash
ccr restart
```
## 配置选项说明
- **PORT**: 服务器端口号默认3456
- **APIKEY**: API 密钥,用于身份验证
- **HOST**: 服务器监听地址默认127.0.0.1,如果配置了 Providers 且没有设置 APIKEY则强制为 127.0.0.1
- **PROXY_URL**: 代理服务器地址
- **LOG**: 是否启用日志默认true
- **LOG_LEVEL**: 日志级别fatal/error/warn/info/debug/trace
- **API_TIMEOUT_MS**: API 请求超时时间(毫秒)
- **NON_INTERACTIVE_MODE**: 非交互模式(用于 CI/CD 环境)
## 下一步
- [提供商配置](/zh/docs/config/providers) - 详细的提供商配置
- [路由配置](/zh/docs/config/routing) - 配置路由规则
- [转换器](/zh/docs/config/transformers) - 应用转换

View File

@@ -0,0 +1,213 @@
---
id: config/providers
title: 提供商配置
sidebar_position: 2
---
# 提供商配置
配置 LLM 提供商的详细指南。
## 支持的提供商
### DeepSeek
```json
{
"name": "deepseek",
"api_base_url": "https://api.deepseek.com/chat/completions",
"api_key": "your-api-key",
"models": ["deepseek-chat", "deepseek-coder", "deepseek-reasoner"],
"transformer": {
"use": ["deepseek"]
}
}
```
### Groq
```json
{
"name": "groq",
"api_base_url": "https://api.groq.com/openai/v1/chat/completions",
"api_key": "your-api-key",
"models": ["llama-3.3-70b-versatile"]
}
```
### Gemini
```json
{
"name": "gemini",
"api_base_url": "https://generativelanguage.googleapis.com/v1beta/models/",
"api_key": "your-api-key",
"models": ["gemini-2.5-flash", "gemini-2.5-pro"],
"transformer": {
"use": ["gemini"]
}
}
```
### OpenRouter
```json
{
"name": "openrouter",
"api_base_url": "https://openrouter.ai/api/v1/chat/completions",
"api_key": "your-api-key",
"models": [
"anthropic/claude-3.5-sonnet",
"google/gemini-2.5-pro-preview"
],
"transformer": {
"use": ["openrouter"]
}
}
```
### Ollama本地模型
```json
{
"name": "ollama",
"api_base_url": "http://localhost:11434/v1/chat/completions",
"api_key": "ollama",
"models": ["qwen2.5-coder:latest"]
}
```
### 火山引擎
```json
{
"name": "volcengine",
"api_base_url": "https://ark.cn-beijing.volces.com/api/v3/chat/completions",
"api_key": "your-api-key",
"models": ["deepseek-v3-250324", "deepseek-r1-250528"],
"transformer": {
"use": ["deepseek"]
}
}
```
### ModelScope
```json
{
"name": "modelscope",
"api_base_url": "https://api-inference.modelscope.cn/v1/chat/completions",
"api_key": "",
"models": [
"Qwen/Qwen3-Coder-480B-A35B-Instruct",
"Qwen/Qwen3-235B-A22B-Thinking-2507"
],
"transformer": {
"use": [
["maxtoken", { "max_tokens": 65536 }],
"enhancetool"
],
"Qwen/Qwen3-235B-A22B-Thinking-2507": {
"use": ["reasoning"]
}
}
}
```
### DashScope阿里云
```json
{
"name": "dashscope",
"api_base_url": "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions",
"api_key": "your-api-key",
"models": ["qwen3-coder-plus"],
"transformer": {
"use": [
["maxtoken", { "max_tokens": 65536 }],
"enhancetool"
]
}
}
```
## 提供商配置选项
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `name` | string | 是 | 提供商的唯一标识符 |
| `api_base_url` | string | 是 | API 基础 URL |
| `api_key` | string | 是 | API 认证密钥 |
| `models` | string[] | 否 | 可用模型列表 |
| `transformer` | object | 否 | 应用的转换器配置 |
## 模型选择
在路由中选择模型时,使用以下格式:
```
{provider-name},{model-name}
```
例如:
```
deepseek,deepseek-chat
```
## 使用环境变量
您可以在配置中使用环境变量来保护 API 密钥:
```json
{
"Providers": [
{
"name": "deepseek",
"api_base_url": "https://api.deepseek.com/chat/completions",
"api_key": "$DEEPSEEK_API_KEY",
"models": ["deepseek-chat"]
}
]
}
```
支持 `$VAR_NAME``${VAR_NAME}` 两种语法。
## 转换器配置
转换器用于适配不同提供商的 API 差异。您可以在提供商级别或模型级别配置转换器:
### 提供商级别转换器
应用于提供商的所有模型:
```json
{
"name": "openrouter",
"transformer": {
"use": ["openrouter"]
}
}
```
### 模型级别转换器
应用于特定模型:
```json
{
"name": "deepseek",
"transformer": {
"use": ["deepseek"],
"deepseek-chat": {
"use": ["tooluse"]
}
}
}
```
## 下一步
- [路由配置](/zh/docs/config/routing) - 配置请求如何路由
- [转换器](/zh/docs/config/transformers) - 对请求应用转换

View File

@@ -0,0 +1,165 @@
---
id: config/routing
title: 路由配置
sidebar_position: 3
---
# 路由配置
配置如何将请求路由到不同的模型。
## 默认路由
为所有请求设置默认模型:
```json
{
"Router": {
"default": "deepseek,deepseek-chat"
}
}
```
## 内置场景
### 后台任务
将后台任务路由到轻量级模型:
```json
{
"Router": {
"background": "groq,llama-3.3-70b-versatile"
}
}
```
### 思考模式(计划模式)
将思考密集型任务路由到更强大的模型:
```json
{
"Router": {
"think": "deepseek,deepseek-reasoner"
}
}
```
### 长上下文
路由长上下文请求:
```json
{
"Router": {
"longContextThreshold": 100000,
"longContext": "gemini,gemini-2.5-pro"
}
}
```
### 网络搜索
路由网络搜索任务:
```json
{
"Router": {
"webSearch": "gemini,gemini-2.5-flash"
}
}
```
### 图像任务
路由图像相关任务:
```json
{
"Router": {
"image": "gemini,gemini-2.5-pro"
}
}
```
## 项目级路由
`~/.claude/projects/<project-id>/claude-code-router.json` 中为每个项目配置路由:
```json
{
"Router": {
"default": "groq,llama-3.3-70b-versatile"
}
}
```
项目级配置优先于全局配置。
## 自定义路由器
创建自定义 JavaScript 路由器函数:
1. 创建路由器文件(例如 `custom-router.js`
```javascript
module.exports = async function(req, config) {
// 分析请求上下文
const userMessage = req.body.messages.find(m => m.role === 'user')?.content;
// 自定义路由逻辑
if (userMessage && userMessage.includes('解释代码')) {
return 'openrouter,anthropic/claude-3.5-sonnet';
}
// 返回 null 以使用默认路由
return null;
};
```
2.`config.json` 中设置 `CUSTOM_ROUTER_PATH`
```json
{
"CUSTOM_ROUTER_PATH": "/path/to/custom-router.js"
}
```
## Token 计数
路由器使用 `tiktoken` (cl100k_base) 来估算请求 token 数量。这用于:
- 确定请求是否超过 `longContextThreshold`
- 基于 token 数量的自定义路由逻辑
## 子代理路由
使用特殊标签为子代理指定模型:
```
<CCR-SUBAGENT-MODEL>provider,model</CCR-SUBAGENT-MODEL>
请帮我分析这段代码...
```
## 动态模型切换
在 Claude Code 中使用 `/model` 命令动态切换模型:
```
/model provider_name,model_name
```
示例:`/model openrouter,anthropic/claude-3.5-sonnet`
## 路由优先级
1. 项目级配置
2. 自定义路由器
3. 内置场景路由
4. 默认路由
## 下一步
- [转换器](/zh/docs/config/transformers) - 对请求应用转换
- [自定义路由器](/zh/docs/advanced/custom-router) - 高级自定义路由

View File

@@ -0,0 +1,283 @@
---
id: config/transformers
title: 转换器
sidebar_position: 4
---
# 转换器
转换器用于适配不同提供商之间的 API 差异。
## 内置转换器
### anthropic
将请求转换为兼容 Anthropic 风格的 API
```json
{
"transformer": {
"use": ["anthropic"]
}
}
```
如果只使用这一个转换器,它将直接透传请求和响应(您可以用来接入其他支持 Anthropic 端点的服务商)。
### deepseek
专门用于 DeepSeek API 的转换器:
```json
{
"transformer": {
"use": ["deepseek"]
}
}
```
### gemini
用于 Google Gemini API 的转换器:
```json
{
"transformer": {
"use": ["gemini"]
}
}
```
### groq
用于 Groq API 的转换器:
```json
{
"transformer": {
"use": ["groq"]
}
}
```
### openrouter
用于 OpenRouter API 的转换器:
```json
{
"transformer": {
"use": ["openrouter"]
}
}
```
OpenRouter 转换器还支持 `provider` 路由参数,以指定 OpenRouter 应使用哪些底层提供商:
```json
{
"transformer": {
"use": ["openrouter"],
"moonshotai/kimi-k2": {
"use": [
["openrouter", {
"provider": {
"only": ["moonshotai/fp8"]
}
}]
]
}
}
}
```
### maxtoken
设置特定的 `max_tokens` 值:
```json
{
"transformer": {
"use": [
["maxtoken", { "max_tokens": 65536 }]
]
}
}
```
### tooluse
通过 `tool_choice` 参数优化某些模型的工具使用:
```json
{
"transformer": {
"use": ["tooluse"]
}
}
```
### reasoning
用于处理 `reasoning_content` 字段:
```json
{
"transformer": {
"use": ["reasoning"]
}
}
```
### sampling
用于处理采样信息字段,如 `temperature``top_p``top_k``repetition_penalty`
```json
{
"transformer": {
"use": ["sampling"]
}
}
```
### enhancetool
对 LLM 返回的工具调用参数增加一层容错处理(注意:这会导致不再流式返回工具调用信息):
```json
{
"transformer": {
"use": ["enhancetool"]
}
}
```
### cleancache
清除请求中的 `cache_control` 字段:
```json
{
"transformer": {
"use": ["cleancache"]
}
}
```
### vertex-gemini
处理使用 Vertex 鉴权的 Gemini API
```json
{
"transformer": {
"use": ["vertex-gemini"]
}
}
```
## 应用转换器
### 全局应用
应用于提供商的所有请求:
```json
{
"Providers": [
{
"name": "deepseek",
"api_base_url": "https://api.deepseek.com/chat/completions",
"api_key": "your-api-key",
"transformer": {
"use": ["deepseek"]
}
}
]
}
```
### 模型特定应用
应用于特定模型:
```json
{
"name": "deepseek",
"transformer": {
"use": ["deepseek"],
"deepseek-chat": {
"use": ["tooluse"]
}
}
}
```
### 传递选项
某些转换器接受选项:
```json
{
"transformer": {
"use": [
["maxtoken", { "max_tokens": 8192 }]
]
}
}
```
## 自定义转换器
创建自定义转换器插件:
1. 创建转换器文件:
```javascript
module.exports = {
name: 'my-transformer',
transformRequest: async (req, config) => {
// 修改请求
return req;
},
transformResponse: async (res, config) => {
// 修改响应
return res;
}
};
```
2. 在配置中加载:
```json
{
"transformers": [
{
"path": "/path/to/transformer.js",
"options": {
"key": "value"
}
}
]
}
```
## 实验性转换器
### gemini-cli实验性
通过 Gemini CLI 对 Gemini 的非官方支持。
### qwen-cli实验性
通过 Qwen CLI 对 qwen3-coder-plus 的非官方支持。
### rovo-cli实验性
通过 Atlassian Rovo Dev CLI 对 GPT-5 的非官方支持。
## 下一步
- [高级主题](/zh/docs/advanced/custom-router) - 高级路由自定义
- [Agent](/zh/docs/advanced/agents) - 使用 Agent 扩展功能

View File

@@ -0,0 +1,54 @@
{
"version.label": {
"message": "Next",
"description": "The label for version current"
},
"sidebar.tutorialSidebar.category.Getting Started": {
"message": "Getting Started",
"description": "The label for category 'Getting Started' in sidebar 'tutorialSidebar'"
},
"sidebar.tutorialSidebar.category.Getting Started.link.generated-index.title": {
"message": "Getting Started",
"description": "The generated-index page title for category 'Getting Started' in sidebar 'tutorialSidebar'"
},
"sidebar.tutorialSidebar.category.Getting Started.link.generated-index.description": {
"message": "Learn the basics of Claude Code Router",
"description": "The generated-index page description for category 'Getting Started' in sidebar 'tutorialSidebar'"
},
"sidebar.tutorialSidebar.category.Configuration": {
"message": "Configuration",
"description": "The label for category 'Configuration' in sidebar 'tutorialSidebar'"
},
"sidebar.tutorialSidebar.category.Configuration.link.generated-index.title": {
"message": "Configuration",
"description": "The generated-index page title for category 'Configuration' in sidebar 'tutorialSidebar'"
},
"sidebar.tutorialSidebar.category.Configuration.link.generated-index.description": {
"message": "Configure Claude Code Router to suit your needs",
"description": "The generated-index page description for category 'Configuration' in sidebar 'tutorialSidebar'"
},
"sidebar.tutorialSidebar.category.Advanced": {
"message": "Advanced",
"description": "The label for category 'Advanced' in sidebar 'tutorialSidebar'"
},
"sidebar.tutorialSidebar.category.Advanced.link.generated-index.title": {
"message": "Advanced Topics",
"description": "The generated-index page title for category 'Advanced' in sidebar 'tutorialSidebar'"
},
"sidebar.tutorialSidebar.category.Advanced.link.generated-index.description": {
"message": "Advanced features and customization",
"description": "The generated-index page description for category 'Advanced' in sidebar 'tutorialSidebar'"
},
"sidebar.tutorialSidebar.category.CLI Reference": {
"message": "CLI Reference",
"description": "The label for category 'CLI Reference' in sidebar 'tutorialSidebar'"
},
"sidebar.tutorialSidebar.category.CLI Reference.link.generated-index.title": {
"message": "CLI Commands",
"description": "The generated-index page title for category 'CLI Reference' in sidebar 'tutorialSidebar'"
},
"sidebar.tutorialSidebar.category.CLI Reference.link.generated-index.description": {
"message": "Complete reference for all CLI commands",
"description": "The generated-index page description for category 'CLI Reference' in sidebar 'tutorialSidebar'"
}
}

View File

@@ -0,0 +1,47 @@
---
id: installation
title: 安装
sidebar_position: 2
---
# 安装
使用您喜欢的包管理器全局安装 Claude Code Router。
## 前置要求
- **Node.js**: >= 18.0.0
- **pnpm**: >= 8.0.0(如果使用 pnpm
- 来自您偏好的 LLM 提供商的 API 密钥
## 通过 npm 安装
```bash
npm install -g @musistudio/claude-code-router-cli
```
## 通过 pnpm 安装
```bash
pnpm add -g @musistudio/claude-code-router-cli
```
## 通过 Yarn 安装
```bash
yarn global add @musistudio/claude-code-router-cli
```
## 验证安装
安装完成后,验证 `ccr` 命令是否可用:
```bash
ccr --version
```
您应该看到版本号显示。
## 下一步
安装完成后,前往 [快速开始](/zh/docs/quick-start) 了解如何配置和使用路由器。

View File

@@ -0,0 +1,71 @@
---
id: intro
title: 欢迎使用 Claude Code Router
sidebar_position: 1
slug: /
---
# 欢迎使用 Claude Code Router
[![npm version](https://badge.fury.io/js/%40musistudio%2Fclaude-code-router-cli.svg)](https://www.npmjs.com/package/@musistudio/claude-code-router-cli)
![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)
![Node Version](https://img.shields.io/node/v/@musistudio/claude-code-router-cli.svg)
**Claude Code Router** 是一个强大的工具,允许你在没有 Anthropic 账户的情况下使用 [Claude Code](https://claude.ai/code),并将请求路由到其他 LLM 提供商。
## 特性
- **多提供商支持**: 路由到 DeepSeek、Gemini、Groq、OpenRouter 等
- **智能路由**: 内置不同任务类型的场景(后台、思考、网络搜索、图像)
- **项目级配置**: 每个项目自定义路由
- **自定义路由函数**: 编写 JavaScript 定义自己的路由逻辑
- **转换器系统**: 无缝适配不同提供商之间的 API 差异
- **代理系统**: 可扩展的插件架构,实现自定义功能
- **Web UI**: 内置管理界面,方便配置
- **CLI 集成**: 与现有的 Claude Code 工作流无缝集成
## 快速开始
### 安装
```bash
npm install -g @musistudio/claude-code-router-cli
# 或
pnpm add -g @musistudio/claude-code-router-cli
# 或
yarn global add @musistudio/claude-code-router-cli
```
### 基本使用
```bash
# 启动路由器服务器
ccr start
# 配置 Claude Code 使用路由器
export ANTHROPIC_API_URL="http://localhost:8080/v1"
export ANTHROPIC_API_KEY="your-api-key"
# 现在可以正常使用 Claude Code
claude code
```
## 下一步
- [安装指南](/docs/installation) - 详细安装说明
- [快速开始](/docs/quick-start) - 5 分钟入门
- [配置](/docs/config/basic) - 了解如何配置路由器
- [CLI 参考](/docs/cli/start) - 完整的 CLI 命令参考
## 架构
Claude Code Router 由四个主要组件组成:
- **CLI** (`@musistudio/claude-code-router-cli`): 提供 `ccr` 命令的命令行工具
- **Server** (`@musistudio/claude-code-router-server`): 处理 API 路由和转换的核心服务器
- **Shared** (`@musistudio/claude-code-router-shared`): 共享常量和工具
- **UI** (`@musistudio/claude-code-router-ui`): Web 管理界面React + Vite
## 许可证
MIT © [musistudio](https://github.com/musistudio)

View File

@@ -0,0 +1,83 @@
---
id: quick-start
title: 快速开始
sidebar_position: 3
---
# 快速开始
5 分钟内启动并运行 Claude Code Router。
## 1. 启动路由器
```bash
ccr start
```
路由器默认将在 `http://localhost:8080` 上启动。
## 2. 配置环境变量
在您的 shell 中设置以下环境变量:
```bash
export ANTHROPIC_API_URL="http://localhost:8080/v1"
export ANTHROPIC_API_KEY="your-provider-api-key"
```
或者使用 `ccr activate` 命令获取环境变量:
```bash
eval "$(ccr activate)"
```
## 3. 使用 Claude Code
现在您可以正常使用 Claude Code
```bash
claude code
```
您的请求将通过 Claude Code Router 路由到您配置的提供商。
## 4. 配置提供商(可选)
要配置多个提供商或自定义路由,使用:
```bash
ccr model
```
这将打开一个交互式菜单来选择和配置模型。
或者直接编辑配置文件:
```bash
# 在默认编辑器中打开配置
ccr config edit
```
配置文件示例 (`~/.claude-code-router/config.json`)
```json
{
"Providers": [
{
"name": "deepseek",
"api_base_url": "https://api.deepseek.com/chat/completions",
"api_key": "your-deepseek-api-key",
"models": ["deepseek-chat", "deepseek-coder"]
}
],
"Router": {
"default": "deepseek,deepseek-chat"
}
}
```
## 下一步
- [基础配置](/zh/docs/config/basic) - 了解配置选项
- [路由配置](/zh/docs/config/routing) - 配置智能路由规则
- [CLI 命令](/zh/docs/cli/start) - 探索所有 CLI 命令

View File

@@ -0,0 +1,50 @@
{
"link.title.Documentation": {
"message": "文档",
"description": "The title of the footer links column with title=Documentation in the footer"
},
"link.title.Community": {
"message": "社区",
"description": "The title of the footer links column with title=Community in the footer"
},
"link.title.Resources": {
"message": "资源",
"description": "The title of the footer links column with title=Resources in the footer"
},
"link.item.label.Introduction": {
"message": "简介",
"description": "The label of footer link with label=Introduction linking to /docs/intro"
},
"link.item.label.Installation": {
"message": "安装",
"description": "The label of footer link with label=Installation linking to /docs/cli/installation"
},
"link.item.label.Quick Start": {
"message": "快速开始",
"description": "The label of footer link with label=Quick Start linking to /docs/cli/quick-start"
},
"link.item.label.GitHub": {
"message": "GitHub",
"description": "The label of footer link with label=GitHub linking to https://github.com/musistudio/claude-code-router"
},
"link.item.label.Issues": {
"message": "问题反馈",
"description": "The label of footer link with label=Issues linking to https://github.com/musistudio/claude-code-router/issues"
},
"link.item.label.Releases": {
"message": "发布版本",
"description": "The label of footer link with label=Releases linking to https://github.com/musistudio/claude-code-router/releases"
},
"link.item.label.Blog": {
"message": "博客",
"description": "The label of footer link with label=Blog linking to /blog"
},
"link.item.label.NPM Package": {
"message": "NPM 包",
"description": "The label of footer link with label=NPM Package linking to https://www.npmjs.com/package/@musistudio/claude-code-router-cli"
},
"copyright": {
"message": "Copyright © 2025 Claude Code Router. 保留所有权利。",
"description": "The footer copyright"
}
}

View File

@@ -0,0 +1,22 @@
{
"title": {
"message": "Claude Code Router",
"description": "The title in the navbar"
},
"logo.alt": {
"message": "Claude Code Router Logo",
"description": "The alt text of navbar logo"
},
"item.label.Documentation": {
"message": "Documentation",
"description": "Navbar item with label Documentation"
},
"item.label.Blog": {
"message": "Blog",
"description": "Navbar item with label Blog"
},
"item.label.GitHub": {
"message": "GitHub",
"description": "Navbar item with label GitHub"
}
}

45
docs/package.json Normal file
View File

@@ -0,0 +1,45 @@
{
"name": "claude-code-router-docs",
"version": "0.0.0",
"private": true,
"scripts": {
"docusaurus": "docusaurus",
"start": "docusaurus start",
"build": "docusaurus build",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy",
"clear": "docusaurus clear",
"serve": "docusaurus serve",
"write-translations": "docusaurus write-translations",
"write-heading-ids": "docusaurus write-heading-ids"
},
"dependencies": {
"@docusaurus/core": "^3.9.2",
"@docusaurus/preset-classic": "^3.9.2",
"@mdx-js/react": "^3.0.0",
"prism-react-renderer": "^2.4.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.9.2",
"@docusaurus/types": "^3.9.2",
"autoprefixer": "^10.4.21",
"tailwindcss": "3"
},
"browserslist": {
"production": [
">0.5%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"engines": {
"node": ">=18.0"
}
}

6
docs/postcss.config.js Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

114
docs/sidebars.ts Normal file
View File

@@ -0,0 +1,114 @@
import type { SidebarsConfig } from '@docusaurus/plugin-content-docs';
const sidebars: SidebarsConfig = {
tutorialSidebar: [
{
type: 'category',
label: 'Server',
link: {
type: 'generated-index',
title: 'Claude Code Router Server',
description: '部署和管理 Claude Code Router 服务',
slug: 'category/server',
},
items: [
'server/intro',
'server/deployment',
{
type: 'category',
label: 'API Reference',
link: {
type: 'generated-index',
title: 'API Reference',
description: '服务器 API 接口文档',
slug: 'category/api',
},
items: [
'server/api/overview',
'server/api/messages-api',
'server/api/config-api',
'server/api/logs-api',
],
},
{
type: 'category',
label: 'Configuration',
link: {
type: 'generated-index',
title: 'Server Configuration',
description: '服务器配置说明',
slug: 'category/server-config',
},
items: [
'server/config/basic',
'server/config/providers',
'server/config/routing',
'server/config/transformers',
],
},
{
type: 'category',
label: 'Advanced',
link: {
type: 'generated-index',
title: 'Advanced Topics',
description: '高级功能和自定义',
slug: 'category/server-advanced',
},
items: [
'server/advanced/custom-router',
'server/advanced/agents',
'server/advanced/presets',
],
},
],
},
{
type: 'category',
label: 'CLI',
link: {
type: 'generated-index',
title: 'Claude Code Router CLI',
description: '命令行工具使用指南',
slug: 'category/cli',
},
items: [
'cli/intro',
'cli/installation',
'cli/quick-start',
{
type: 'category',
label: 'Commands',
link: {
type: 'generated-index',
title: 'CLI Commands',
description: '完整的命令参考',
slug: 'category/cli-commands',
},
items: [
'cli/commands/start',
'cli/commands/model',
'cli/commands/status',
'cli/commands/other',
],
},
{
type: 'category',
label: 'Configuration',
link: {
type: 'generated-index',
title: 'CLI Configuration',
description: 'CLI 配置说明',
slug: 'category/cli-config',
},
items: [
'cli/config/basic',
'cli/config/project-level',
],
},
],
},
],
};
export default sidebars;

View File

@@ -0,0 +1,59 @@
.features {
display: flex;
align-items: center;
padding: 2rem 0;
width: 100%;
}
.featureSvg {
height: 160px;
width: 160px;
transition: transform 0.3s ease;
}
.feature:hover .featureSvg {
transform: scale(1.05);
}
.feature {
padding: 1.5rem;
border-radius: 12px;
background: var(--ifm-background-surface-color);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
height: 100%;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
}
.feature::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(90deg, var(--ifm-color-primary), var(--ifm-color-primary-dark));
transform: scaleX(0);
transform-origin: left;
transition: transform 0.3s ease;
}
.feature:hover::before {
transform: scaleX(1);
}
.feature:hover {
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.12);
transform: translateY(-4px);
}
@media (prefers-reduced-motion: reduce) {
.feature,
.featureSvg,
.feature:hover,
.feature:hover .featureSvg {
transition: none;
transform: none;
}
}

View File

@@ -0,0 +1,71 @@
import Heading from '@theme/Heading';
import styles from './HomepageFeatures.module.css';
type FeatureItem = {
title: string;
Svg: React.ComponentType<React.ComponentProps<'svg'>>;
description: JSX.Element;
};
const FeatureList: FeatureItem[] = [
{
title: 'Easy to Use',
Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default,
description: (
<>
Install and configure Claude Code Router in minutes with our simple CLI.
Start routing your Claude Code requests to any LLM provider instantly.
</>
),
},
{
title: 'Flexible Routing',
Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default,
description: (
<>
Configure custom routing logic based on project, context length, or task type.
Built-in scenarios for background tasks, thinking mode, web search, and more.
</>
),
},
{
title: 'Provider Agnostic',
Svg: require('@site/static/img/undraw_docusaurus_react.svg').default,
description: (
<>
Support for multiple LLM providers including DeepSeek, Gemini, Groq, and OpenRouter.
Easy to extend with custom transformers for new providers.
</>
),
},
];
function Feature({title, Svg, description}: FeatureItem) {
return (
<div className={styles.feature}>
<div className="text--center">
<Svg className={styles.featureSvg} role="img" />
</div>
<div className="text--center padding-horiz--md">
<Heading as="h3">{title}</Heading>
<p>{description}</p>
</div>
</div>
);
}
export default function HomepageFeatures(): JSX.Element {
return (
<section className={styles.features}>
<div className="container">
<div className="row">
{FeatureList.map((props, idx) => (
<div key={idx} className="col col--4">
<Feature {...props} />
</div>
))}
</div>
</div>
</section>
);
}

253
docs/src/css/custom.css Normal file
View File

@@ -0,0 +1,253 @@
/**
* Any CSS included here will be global. The classic template
* bundles Infima by default. Infima is a CSS framework designed to
* work well for content-centric websites.
*/
/* Tailwind CSS directives */
@tailwind base;
@tailwind components;
@tailwind utilities;
/* You can override the default Infima variables here. */
:root {
--ifm-color-primary: #CC7C5E;
--ifm-color-primary-dark: #BC5C3E;
--ifm-color-primary-darker: #964630;
--ifm-color-primary-darkest: #7A3B2C;
--ifm-color-primary-light: #F28B68;
--ifm-color-primary-lighter: #F7AC92;
--ifm-color-primary-lightest: #FEF6F3;
--ifm-code-font-size: 95%;
--docusaurus-highlighted-code-line-bg: rgba(204, 124, 94, 0.1);
/* Custom animations */
--animation-duration-slow: 0.6s;
--animation-duration-normal: 0.3s;
--animation-duration-fast: 0.15s;
}
/* Custom styles */
.hero {
padding: 4rem 0;
text-align: center;
}
.hero__title {
font-size: 3rem;
font-weight: 700;
margin-bottom: 1.5rem;
}
.hero__subtitle {
font-size: 1.5rem;
color: var(--ifm-color-emphasis-600);
margin-bottom: 2rem;
}
.features {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
margin-top: 3rem;
}
.feature {
padding: 1.5rem;
border-radius: 8px;
background: var(--ifm-background-surface-color);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.feature__title {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 0.75rem;
}
.feature__text {
color: var(--ifm-color-emphasis-600);
}
/* Smooth scroll behavior */
html {
scroll-behavior: smooth;
}
/* Custom scrollbar for webkit browsers */
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background: var(--ifm-background-surface-color);
}
::-webkit-scrollbar-thumb {
background: var(--ifm-color-primary);
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--ifm-color-primary-dark);
}
/* Enhanced animations */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slideInLeft {
from {
opacity: 0;
transform: translateX(-30px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.9);
}
to {
opacity: 1;
transform: scale(1);
}
}
.animate-fade-in-up {
animation: fadeInUp var(--animation-duration-slow) ease-out forwards;
opacity: 0;
}
.animate-fade-in {
animation: fadeIn var(--animation-duration-slow) ease-out forwards;
opacity: 0;
}
.animate-slide-in-left {
animation: slideInLeft var(--animation-duration-slow) ease-out forwards;
opacity: 0;
}
.animate-scale-in {
animation: scaleIn var(--animation-duration-slow) ease-out forwards;
opacity: 0;
}
/* Hover effects for cards */
.hover-lift {
transition: transform var(--animation-duration-normal) ease,
box-shadow var(--animation-duration-normal) ease;
}
.hover-lift:hover {
transform: translateY(-4px);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
}
/* Gradient text */
.gradient-text {
background: linear-gradient(135deg, var(--ifm-color-primary) 0%, var(--ifm-color-primary-dark) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Glass morphism effect */
.glass {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
/* Focus styles for accessibility */
:focus-visible {
outline: 2px solid var(--ifm-color-primary);
outline-offset: 2px;
}
/* Button hover effects */
button,
a {
transition: all var(--animation-duration-fast) ease;
}
/* Prevent navbar items from wrapping */
.navbar__item,
.navbar__link {
white-space: nowrap;
}
/* Ensure navbar links with icons stay on same line */
.navbar__link {
display: inline-flex;
align-items: center;
gap: 0.25rem;
}
.dropdown > .navbar__link:after{
top: 4px;
}
/* Prevent footer links from wrapping */
.footer__link-item {
display: inline-flex;
align-items: center;
gap: 0.25rem;
white-space: nowrap;
}
/* Responsive improvements */
@media (max-width: 996px) {
.features {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 768px) {
.features {
grid-template-columns: 1fr;
}
.hero__title {
font-size: 2rem;
}
/* Reduce animation on mobile for better performance */
.animate-fade-in-up,
.animate-fade-in,
.animate-slide-in-left,
.animate-scale-in {
animation-duration: 0.3s;
}
}
/* Print styles */
@media print {
.hero,
.features {
page-break-inside: avoid;
}
}

674
docs/src/pages/index.tsx Normal file
View File

@@ -0,0 +1,674 @@
import Link from '@docusaurus/Link';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import Layout from '@theme/Layout';
import Heading from '@theme/Heading';
function HomepageHeader() {
const {siteConfig, i18n} = useDocusaurusContext();
const currentLocale = i18n.currentLocale;
const content = {
en: {
title: 'Route Claude Code',
highlight: 'to Any LLM',
subtitle: 'Use Claude Code without an Anthropic account. Connect to DeepSeek, Gemini, Groq, and more.',
getStarted: 'Get Started',
github: 'View on GitHub',
},
'zh-CN': {
title: '将 Claude Code',
highlight: '路由到任何 LLM',
subtitle: '无需 Anthropic 账户即可使用 Claude Code。支持连接 DeepSeek、Gemini、Groq 等提供商。',
getStarted: '开始使用',
github: '查看 GitHub',
}
};
const t = content[currentLocale as keyof typeof content] || content.en;
return (
<header className="relative min-h-[90vh] flex items-center justify-center overflow-hidden bg-gradient-to-b from-gray-50 to-white">
{/* Background Elements */}
<div
className="absolute inset-0"
style={{
backgroundImage: `
linear-gradient(rgba(204, 124, 94, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(204, 124, 94, 0.03) 1px, transparent 1px)
`,
backgroundSize: '50px 50px'
}}
></div>
{/* Hero Content */}
<div className="relative z-10 container mx-auto px-4 py-20">
<div className="max-w-4xl mx-auto text-center">
{/* Badge */}
<div className="animate-fade-in-up inline-flex items-center gap-2 px-4 py-2 bg-primary text-white rounded-full text-sm font-semibold mb-8">
<span className="animate-pulse"></span>
<span>{currentLocale === 'zh-CN' ? '开源免费' : 'Open Source'}</span>
</div>
{/* Title */}
<Heading
as="h1"
className="text-5xl sm:text-6xl md:text-7xl lg:text-8xl font-extrabold mb-6 leading-tight animate-fade-in-up"
style={{ animationDelay: '0.1s' }}
>
<span className="text-gray-900">{t.title}</span>
<br />
<span className="text-transparent bg-clip-text bg-gradient-to-r from-primary to-primary/70">
{t.highlight}
</span>
</Heading>
{/* Subtitle */}
<p
className="text-lg sm:text-xl md:text-2xl text-gray-600 mb-10 leading-relaxed max-w-3xl mx-auto animate-fade-in-up"
style={{ animationDelay: '0.2s' }}
>
{t.subtitle}
</p>
{/* CTA Buttons */}
<div
className="flex flex-col sm:flex-row gap-4 justify-center items-center mb-12 animate-fade-in-up"
style={{ animationDelay: '0.3s' }}
>
<Link
className="px-6 sm:px-8 py-3 sm:py-4 bg-primary text-white hover:text-white rounded-lg text-base sm:text-lg font-semibold transition-all duration-300 shadow-lg hover:shadow-xl hover:scale-105"
to={currentLocale === 'zh-CN' ? '/zh-CN/docs/intro' : '/docs/intro'}
>
{t.getStarted}
</Link>
<Link
className="px-6 sm:px-8 py-3 sm:py-4 bg-white hover:bg-gray-50 text-gray-900 border border-gray-300 rounded-lg text-base sm:text-lg font-semibold transition-all duration-300 hover:border-primary hover:scale-105"
to="https://github.com/musistudio/claude-code-router"
>
{t.github}
</Link>
</div>
{/* Install Command */}
<div
className="animate-fade-in-up max-w-3xl mx-auto mt-16"
style={{ animationDelay: '0.4s' }}
>
<div
className="rounded-xl overflow-hidden"
style={{
background: 'linear-gradient(145deg, #1e1e1e 0%, #0d0d0d 100%)',
boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.1)',
}}
>
{/* Terminal Header */}
<div
className="px-5 py-3 flex items-center justify-between"
style={{
background: 'linear-gradient(180deg, #2a2a2a 0%, #1f1f1f 100%)',
borderBottom: '1px solid rgba(255, 255, 255, 0.1)',
}}
>
<div className="flex items-center gap-2">
<div className="flex gap-2">
<div className="w-3 h-3 rounded-full bg-red-500 hover:bg-red-400 transition-colors"></div>
<div className="w-3 h-3 rounded-full bg-yellow-500 hover:bg-yellow-400 transition-colors"></div>
<div className="w-3 h-3 rounded-full bg-green-500 hover:bg-green-400 transition-colors"></div>
</div>
<span className="ml-4 text-xs text-gray-400 font-mono flex items-center gap-2">
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M2 5a2 2 0 012-2h12a2 2 0 012 2v10a2 2 0 01-2 2H4a2 2 0 01-2-2V5zm3.293 1.293a1 1 0 011.414 0l3 3a1 1 0 010 1.414l-3 3a1 1 0 01-1.414-1.414L7.586 10 5.293 7.707a1 1 0 010-1.414zM11 12a1 1 0 100 2h3a1 1 0 100-2h-3z" clipRule="evenodd" />
</svg>
terminal
</span>
</div>
{/* Copy Button */}
<button
onClick={() => navigator.clipboard.writeText('npm install -g @musistudio/claude-code-router-cli')}
className="flex items-center gap-2 px-3 py-1.5 rounded-lg text-xs font-mono transition-all duration-200 hover:bg-white/10"
style={{ color: '#9ca3af' }}
title="Copy to clipboard"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
</svg>
<span>Copy</span>
</button>
</div>
{/* Terminal Body */}
<div className="p-8" style={{ background: '#0d0d0d' }}>
<div className="font-mono text-base md:text-lg leading-relaxed text-left">
{/* Prompt */}
<div className="flex items-start gap-3">
<span style={{ color: '#22c55e', fontWeight: '600' }}>$</span>
<span className="flex-1">
<span style={{ color: '#60a5fa' }}>npm</span>
<span style={{ color: '#f97583', marginLeft: '0.5rem' }}>install</span>
<span style={{ color: '#fbbf24', marginLeft: '0.5rem' }}>-g</span>
<span style={{ color: '#e5e7eb', marginLeft: '0.5rem' }}>
@musistudio/claude-code-router-cli
</span>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Scroll Indicator */}
<div className="absolute bottom-8 left-1/2 -translate-x-1/2 animate-bounce">
<svg className="w-6 h-6 text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 14l-7 7m0 0l-7-7m7 7V3" />
</svg>
</div>
</header>
);
}
function FeatureSection() {
const {i18n} = useDocusaurusContext();
const currentLocale = i18n.currentLocale;
const content = {
en: {
title: 'Why Claude Code Router?',
features: [
{
emoji: '⚡',
title: 'Lightning Fast',
description: 'Get started in minutes with just one command. No complicated configuration required.'
},
{
emoji: '🎯',
title: 'Smart Routing',
description: 'Automatically route requests to the best model based on context length, task type, and custom rules.'
},
{
emoji: '🔌',
title: 'Multi-Provider',
description: 'Support for DeepSeek, Gemini, Groq, OpenRouter, and more. Easy to extend with custom transformers.'
},
{
emoji: '💰',
title: 'Cost Effective',
description: 'Use more affordable models for routine tasks while reserving Claude for complex scenarios.'
},
{
emoji: '🛠️',
title: 'Agent System',
description: 'Extendable agent architecture for custom tools and workflows. Built-in support for image tasks.'
},
{
emoji: '🔧',
title: 'Highly Customizable',
description: 'Configure routing per project, set up transformers, and fine-tune every aspect of your workflow.'
}
]
},
'zh-CN': {
title: '为什么选择 Claude Code Router',
features: [
{
emoji: '⚡',
title: '快速上手',
description: '只需一条命令即可开始使用,无需复杂配置。'
},
{
emoji: '🎯',
title: '智能路由',
description: '基于上下文长度、任务类型和自定义规则,自动将请求路由到最佳模型。'
},
{
emoji: '🔌',
title: '多提供商支持',
description: '支持 DeepSeek、Gemini、Groq、OpenRouter 等多个提供商,易于扩展。'
},
{
emoji: '💰',
title: '节省成本',
description: '常规任务使用更经济的模型,复杂场景再使用 Claude。'
},
{
emoji: '🛠️',
title: 'Agent 系统',
description: '可扩展的 agent 架构,支持自定义工具和工作流。内置图像任务支持。'
},
{
emoji: '🔧',
title: '高度可定制',
description: '按项目配置路由、设置转换器,微调工作流的每个细节。'
}
]
}
};
const t = content[currentLocale as keyof typeof content] || content.en;
return (
<section className="py-16 sm:py-24 bg-white">
<div className="container mx-auto px-4">
<div className="text-center mb-12 sm:mb-16">
<Heading as="h2" className="text-3xl sm:text-4xl md:text-5xl font-bold text-gray-900 mb-4">
{t.title}
</Heading>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8 max-w-7xl mx-auto">
{t.features.map((feature, idx) => (
<div
key={idx}
className="group p-6 sm:p-8 bg-white rounded-2xl border border-gray-200 hover:border-primary transition-all duration-300 hover:shadow-2xl hover:-translate-y-2"
style={{ animationDelay: `${idx * 0.1}s` }}
>
<div className="text-4xl sm:text-5xl mb-4">{feature.emoji}</div>
<Heading as="h3" className="text-lg sm:text-xl font-bold text-gray-900 mb-3">
{feature.title}
</Heading>
<p className="text-gray-600 leading-relaxed text-sm sm:text-base">
{feature.description}
</p>
</div>
))}
</div>
</div>
</section>
);
}
function CodeDemo() {
const {i18n} = useDocusaurusContext();
const currentLocale = i18n.currentLocale;
const content = {
en: {
title: 'Simple Configuration',
subtitle: 'Configure your providers and routing logic with a single JSON file.'
},
'zh-CN': {
title: '简单配置',
subtitle: '使用单个 JSON 文件配置提供商和路由逻辑。'
}
};
const t = content[currentLocale as keyof typeof content] || content.en;
return (
<section className="py-16 sm:py-24 bg-gray-50">
<div className="container mx-auto px-4">
<div className="text-center mb-12 sm:mb-16">
<Heading as="h2" className="text-3xl sm:text-4xl md:text-5xl font-bold text-gray-900 mb-4">
{t.title}
</Heading>
<p className="text-lg sm:text-xl text-gray-600 max-w-2xl mx-auto">
{t.subtitle}
</p>
</div>
<div className="max-w-4xl mx-auto">
<div
className="rounded-2xl overflow-hidden shadow-2xl"
style={{
background: '#1a1a1a',
border: '2px solid #374151'
}}
>
<div
className="px-6 py-4 flex items-center gap-2"
style={{ background: '#2d2d2d', borderBottom: '1px solid #374151' }}
>
<div className="w-3 h-3 rounded-full bg-red-500"></div>
<div className="w-3 h-3 rounded-full bg-yellow-500"></div>
<div className="w-3 h-3 rounded-full bg-green-500"></div>
<span className="ml-4 text-sm text-gray-300 font-mono">config.json</span>
</div>
<pre className="p-8 overflow-x-auto text-sm md:text-base" style={{ background: '#1a1a1a' }}>
<code className="font-mono" style={{ lineHeight: '1.6' }}>
<span style={{ color: '#f97583' }}>{'{'}</span>
<span style={{ color: '#e5e7eb' }}>
{'\n '}
<span style={{ color: '#79c0ff' }}>"Providers"</span>
<span style={{ color: '#f97583' }}>: </span>
<span style={{ color: '#f97583' }}>[</span>
{'\n '}
<span style={{ color: '#f97583' }}>{'{'}</span>
{'\n '}
<span style={{ color: '#79c0ff' }}>"NAME"</span>
<span style={{ color: '#f97583' }}>: </span>
<span style={{ color: '#a5d6ff' }}>"deepseek"</span>
<span style={{ color: '#f97583' }}>,</span>
{'\n '}
<span style={{ color: '#79c0ff' }}>"HOST"</span>
<span style={{ color: '#f97583' }}>: </span>
<span style={{ color: '#a5d6ff' }}>"https://api.deepseek.com"</span>
<span style={{ color: '#f97583' }}>,</span>
{'\n '}
<span style={{ color: '#79c0ff' }}>"APIKEY"</span>
<span style={{ color: '#f97583' }}>: </span>
<span style={{ color: '#a5d6ff' }}>"your-api-key"</span>
<span style={{ color: '#f97583' }}>,</span>
{'\n '}
<span style={{ color: '#79c0ff' }}>"MODELS"</span>
<span style={{ color: '#f97583' }}>: </span>
<span style={{ color: '#f97583' }}>[</span>
<span style={{ color: '#a5d6ff' }}>"deepseek-chat"</span>
<span style={{ color: '#f97583' }}>, </span>
<span style={{ color: '#a5d6ff' }}>"deepseek-coder"</span>
<span style={{ color: '#f97583' }}>]</span>
{'\n '}
<span style={{ color: '#f97583' }}>{'}'}</span>
<span style={{ color: '#f97583' }}>,</span>
{'\n '}
<span style={{ color: '#f97583' }}>{'{'}</span>
{'\n '}
<span style={{ color: '#79c0ff' }}>"NAME"</span>
<span style={{ color: '#f97583' }}>: </span>
<span style={{ color: '#a5d6ff' }}>"groq"</span>
<span style={{ color: '#f97583' }}>,</span>
{'\n '}
<span style={{ color: '#79c0ff' }}>"HOST"</span>
<span style={{ color: '#f97583' }}>: </span>
<span style={{ color: '#a5d6ff' }}>"https://api.groq.com/openai/v1"</span>
<span style={{ color: '#f97583' }}>,</span>
{'\n '}
<span style={{ color: '#79c0ff' }}>"APIKEY"</span>
<span style={{ color: '#f97583' }}>: </span>
<span style={{ color: '#a5d6ff' }}>"your-groq-key"</span>
<span style={{ color: '#f97583' }}>,</span>
{'\n '}
<span style={{ color: '#79c0ff' }}>"MODELS"</span>
<span style={{ color: '#f97583' }}>: </span>
<span style={{ color: '#f97583' }}>[</span>
<span style={{ color: '#a5d6ff' }}>"llama-3.3-70b-versatile"</span>
<span style={{ color: '#f97583' }}>]</span>
{'\n '}
<span style={{ color: '#f97583' }}>{'}'}</span>
{'\n '}
<span style={{ color: '#f97583' }}>]</span>
<span style={{ color: '#f97583' }}>,</span>
{'\n '}
<span style={{ color: '#79c0ff' }}>"Router"</span>
<span style={{ color: '#f97583' }}>: </span>
<span style={{ color: '#f97583' }}>{'{'}</span>
{'\n '}
<span style={{ color: '#79c0ff' }}>"default"</span>
<span style={{ color: '#f97583' }}>: </span>
<span style={{ color: '#a5d6ff' }}>"deepseek,deepseek-chat"</span>
<span style={{ color: '#f97583' }}>,</span>
{'\n '}
<span style={{ color: '#79c0ff' }}>"background"</span>
<span style={{ color: '#f97583' }}>: </span>
<span style={{ color: '#a5d6ff' }}>"groq,llama-3.3-70b-versatile"</span>
{'\n '}
<span style={{ color: '#f97583' }}>{'}'}</span>
{'\n'}
<span style={{ color: '#f97583' }}>{'}'}</span>
</span>
</code>
</pre>
</div>
</div>
</div>
</section>
);
}
function UseCases() {
const {i18n} = useDocusaurusContext();
const currentLocale = i18n.currentLocale;
const content = {
en: {
title: 'Perfect For',
subtitle: 'See how Claude Code Router fits your workflow',
cases: [
{
icon: '💰',
title: 'Cost-Conscious Developers',
description: 'Reduce API costs by 10x while maintaining quality for most tasks'
},
{
icon: '🔒',
title: 'Privacy-Focused Teams',
description: 'Keep code local with self-hosted models while using Claude when needed'
},
{
icon: '🔄',
title: 'Multi-Model Workflows',
description: 'Use different models for different tasks without switching tools'
},
{
icon: '⚡',
title: 'Claude Code Power Users',
description: 'Extend Claude Code with custom providers and routing strategies'
}
]
},
'zh-CN': {
title: '适用场景',
subtitle: '看看 Claude Code Router 如何融入您的工作流程',
cases: [
{
icon: '💰',
title: '注重成本的开发者',
description: '在大多数任务上保持质量的同时,将 API 成本降低 10 倍'
},
{
icon: '🔒',
title: '注重隐私的团队',
description: '使用自托管模型保持代码本地化,需要时再使用 Claude'
},
{
icon: '🔄',
title: '多模型工作流',
description: '为不同任务使用不同模型,无需切换工具'
},
{
icon: '⚡',
title: 'Claude Code 高级用户',
description: '使用自定义提供商和路由策略扩展 Claude Code'
}
]
}
};
const t = content[currentLocale as keyof typeof content] || content.en;
return (
<section className="py-16 sm:py-24 bg-gradient-to-b from-white to-gray-50">
<div className="container mx-auto px-4">
<div className="text-center mb-12 sm:mb-16">
<Heading as="h2" className="text-3xl sm:text-4xl md:text-5xl font-bold text-gray-900 mb-4">
{t.title}
</Heading>
<p className="text-lg sm:text-xl text-gray-600 max-w-2xl mx-auto">
{t.subtitle}
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 sm:gap-8 max-w-5xl mx-auto">
{t.cases.map((useCase, idx) => (
<div
key={idx}
className="group relative p-6 sm:p-8 bg-white rounded-2xl border-2 border-gray-100 hover:border-primary transition-all duration-300 hover:shadow-2xl hover:-translate-y-1 overflow-hidden"
style={{ animationDelay: `${idx * 0.1}s` }}
>
{/* Background decoration */}
<div
className="absolute top-0 right-0 w-32 h-32 rounded-full opacity-5 group-hover:opacity-10 transition-opacity"
style={{
background: 'linear-gradient(135deg, #CC7C5E 0%, transparent 70%)',
transform: 'translate(30%, -30%)'
}}
></div>
{/* Number badge */}
<div className="absolute top-4 sm:top-6 right-4 sm:right-6 w-8 h-8 sm:w-10 sm:h-10 flex items-center justify-center rounded-full text-base sm:text-lg font-bold transition-all duration-300 group-hover:scale-110"
style={{
background: 'linear-gradient(135deg, #CC7C5E 0%, #BC5C3E 100%)',
color: 'white',
boxShadow: '0 4px 12px rgba(204, 124, 94, 0.3)'
}}
>
{idx + 1}
</div>
{/* Icon */}
<div className="text-4xl sm:text-5xl mb-4 group-hover:scale-110 transition-transform duration-300">
{useCase.icon}
</div>
{/* Content */}
<div>
<Heading as="h3" className="text-lg sm:text-xl font-bold text-gray-900 mb-3 group-hover:text-primary transition-colors">
{useCase.title}
</Heading>
<p className="text-gray-600 leading-relaxed text-sm sm:text-base">
{useCase.description}
</p>
</div>
{/* Hover accent line */}
<div
className="absolute bottom-0 left-0 h-1 bg-gradient-to-r from-primary to-primary/70 transition-all duration-300 group-hover:w-full"
style={{ width: '0%' }}
></div>
</div>
))}
</div>
</div>
</section>
);
}
function CTASection() {
const {i18n} = useDocusaurusContext();
const currentLocale = i18n.currentLocale;
const content = {
en: {
title: 'Ready to Get Started?',
subtitle: 'Join thousands of developers using Claude Code Router to build better software.',
getStarted: 'Get Started',
docs: 'Read the Docs',
github: 'Star on GitHub',
community: 'Join Community'
},
'zh-CN': {
title: '准备开始了吗?',
subtitle: '加入数千名使用 Claude Code Router 的开发者,构建更好的软件。',
getStarted: '开始使用',
docs: '阅读文档',
github: '在 GitHub 上点赞',
community: '加入社区'
}
};
const t = content[currentLocale as keyof typeof content] || content.en;
return (
<section className="relative py-20 sm:py-32 overflow-hidden">
{/* Animated background */}
<div className="absolute inset-0">
<div className="absolute inset-0 bg-gradient-to-br from-primary via-primary/90 to-primary/80"></div>
{/* Pattern overlay */}
<div
className="absolute inset-0 opacity-10"
style={{
backgroundImage: `
radial-gradient(circle at 25% 25%, white 1%, transparent 1%),
radial-gradient(circle at 75% 75%, white 1%, transparent 1%)
`,
backgroundSize: '40px 40px'
}}
></div>
{/* Floating orbs */}
<div className="absolute top-20 left-10 w-64 h-64 bg-white/10 rounded-full blur-3xl animate-pulse"></div>
<div className="absolute bottom-20 right-10 w-96 h-96 bg-white/5 rounded-full blur-3xl animate-pulse" style={{ animationDelay: '1s' }}></div>
</div>
<div className="relative container mx-auto px-4">
<div className="max-w-4xl mx-auto text-center">
{/* Main title */}
<Heading as="h2" className="text-4xl sm:text-5xl md:text-6xl font-bold text-white mb-6 leading-tight">
{t.title}
</Heading>
{/* Subtitle */}
<p className="text-lg sm:text-xl md:text-2xl text-white/95 mb-10 sm:mb-12 max-w-3xl mx-auto leading-relaxed">
{t.subtitle}
</p>
{/* Primary CTA buttons */}
<div className="flex flex-col sm:flex-row gap-4 justify-center mb-8 sm:mb-12">
<Link
className="group px-8 sm:px-10 py-4 sm:py-5 bg-white text-primary hover:bg-gray-50 rounded-xl text-base sm:text-lg font-bold transition-all duration-300 shadow-2xl hover:shadow-white/20 hover:scale-105 flex items-center justify-center gap-2"
to={currentLocale === 'zh-CN' ? '/zh-CN/docs/intro' : '/docs/intro'}
>
{t.getStarted}
<svg className="w-5 h-5 group-hover:translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 7l5 5m0 0l-5 5m5-5H6" />
</svg>
</Link>
<Link
className="px-8 sm:px-10 py-4 sm:py-5 bg-white/10 backdrop-blur-sm text-white border-2 border-white/30 hover:bg-primary hover:border-primary hover:text-white rounded-xl text-base sm:text-lg font-bold transition-all duration-300 hover:scale-105 flex items-center justify-center gap-2"
to={currentLocale === 'zh-CN' ? '/zh-CN/docs' : '/docs'}
>
{t.docs}
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
</svg>
</Link>
</div>
{/* Secondary links */}
<div className="flex flex-col sm:flex-row gap-6 justify-center items-center text-white/80">
<a
href="https://github.com/musistudio/claude-code-router"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 hover:text-white transition-colors group"
>
<svg className="w-5 h-5 group-hover:scale-110 transition-transform" fill="currentColor" viewBox="0 0 24 24">
<path fillRule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clipRule="evenodd" />
</svg>
<span className="text-sm font-medium">{t.github}</span>
</a>
<div className="hidden sm:block w-px h-4 bg-white/30"></div>
<Link
to={currentLocale === 'zh-CN' ? '/zh-CN/docs' : '/docs'}
className="flex items-center gap-2 hover:text-white transition-colors group"
>
<svg className="w-5 h-5 group-hover:scale-110 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
</svg>
<span className="text-sm font-medium">{t.community}</span>
</Link>
</div>
</div>
</div>
</section>
);
}
export default function Home(): JSX.Element {
const {siteConfig} = useDocusaurusContext();
return (
<Layout
title={`${siteConfig.title}`}
description="Use Claude Code without an Anthropics account and route it to another LLM provider">
<HomepageHeader />
<main>
<FeatureSection />
<CodeDemo />
<UseCases />
<CTASection />
</main>
</Layout>
);
}

4
docs/static/img/ccr.svg vendored Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 726 KiB

View File

@@ -0,0 +1 @@
[Placeholder for social card image]

1
docs/static/img/favicon.ico vendored Normal file
View File

@@ -0,0 +1 @@
[Placeholder for favicon]

4
docs/static/img/logo.svg vendored Normal file
View File

@@ -0,0 +1,4 @@
<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<rect width="100" height="100" rx="10" fill="#2e8555"/>
<text x="50" y="65" text-anchor="middle" font-family="sans-serif" font-size="40" font-weight="bold" fill="white">CCR</text>
</svg>

After

Width:  |  Height:  |  Size: 279 B

View File

@@ -0,0 +1,6 @@
<svg width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
<rect width="500" height="500" fill="#f8f9fa"/>
<path d="M250 100 L400 350 L100 350 Z" fill="#2e8555" opacity="0.8"/>
<circle cx="250" cy="150" r="30" fill="#25c2a0"/>
<text x="250" y="400" text-anchor="middle" font-family="sans-serif" font-size="24" fill="#333">Easy to Use</text>
</svg>

After

Width:  |  Height:  |  Size: 385 B

View File

@@ -0,0 +1,7 @@
<svg width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
<rect width="500" height="500" fill="#f8f9fa"/>
<circle cx="200" cy="200" r="60" fill="#2e8555" opacity="0.6"/>
<circle cx="300" cy="200" r="60" fill="#25c2a0" opacity="0.6"/>
<circle cx="250" cy="300" r="60" fill="#21af90" opacity="0.6"/>
<text x="250" y="420" text-anchor="middle" font-family="sans-serif" font-size="24" fill="#333">Provider Agnostic</text>
</svg>

After

Width:  |  Height:  |  Size: 465 B

View File

@@ -0,0 +1,7 @@
<svg width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
<rect width="500" height="500" fill="#f8f9fa"/>
<circle cx="250" cy="120" r="80" fill="#2e8555" opacity="0.6"/>
<rect x="230" y="180" width="40" height="200" fill="#8B4513"/>
<path d="M250 280 L350 350 L150 350 Z" fill="#2e8555" opacity="0.8"/>
<text x="250" y="420" text-anchor="middle" font-family="sans-serif" font-size="24" fill="#333">Flexible Routing</text>
</svg>

After

Width:  |  Height:  |  Size: 469 B

46
docs/tailwind.config.js Normal file
View File

@@ -0,0 +1,46 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./src/**/*.{js,jsx,ts,tsx}',
],
darkMode: 'class',
theme: {
extend: {
colors: {
primary: {
DEFAULT: '#CC7C5E',
50: '#FEF6F3',
100: '#FDE8E0',
200: '#FBD2C1',
300: '#F7AC92',
400: '#F28B68',
500: '#CC7C5E',
600: '#BC5C3E',
700: '#964630',
800: '#7A3B2C',
900: '#643528',
},
},
animation: {
'fade-in-up': 'fadeInUp 0.6s ease-out',
'fade-in': 'fadeIn 0.6s ease-out',
'slide-in': 'slideIn 0.6s ease-out',
},
keyframes: {
fadeInUp: {
'0%': { opacity: '0', transform: 'translateY(20px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
},
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
},
slideIn: {
'0%': { transform: 'translateX(-100%)' },
'100%': { transform: 'translateX(0)' },
},
},
},
},
plugins: [],
}

22
docs/tsconfig.json Normal file
View File

@@ -0,0 +1,22 @@
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"composite": true,
"jsx": "react",
"jsxFactory": "React.createElement",
"jsxFragmentFactory": "React.Fragment",
"module": "ESNext",
"moduleResolution": "Bundler",
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true
},
"include": ["src", "docs"],
"exclude": ["node_modules", "build"]
}

View File

@@ -8,12 +8,15 @@
"build:cli": "pnpm --filter @CCR/cli build", "build:cli": "pnpm --filter @CCR/cli build",
"build:server": "pnpm --filter @CCR/server build", "build:server": "pnpm --filter @CCR/server build",
"build:ui": "pnpm --filter @CCR/ui build", "build:ui": "pnpm --filter @CCR/ui build",
"build:docs": "pnpm --filter claude-code-router-docs build",
"release": "pnpm build && bash scripts/release.sh all", "release": "pnpm build && bash scripts/release.sh all",
"release:npm": "bash scripts/release.sh npm", "release:npm": "bash scripts/release.sh npm",
"release:docker": "bash scripts/release.sh docker", "release:docker": "bash scripts/release.sh docker",
"dev:cli": "pnpm --filter @CCR/cli dev", "dev:cli": "pnpm --filter @CCR/cli dev",
"dev:server": "pnpm --filter @CCR/server dev", "dev:server": "pnpm --filter @CCR/server dev",
"dev:ui": "pnpm --filter @CCR/ui dev" "dev:ui": "pnpm --filter @CCR/ui dev",
"dev:docs": "pnpm --filter claude-code-router-docs start",
"serve:docs": "pnpm --filter claude-code-router-docs serve"
}, },
"bin": { "bin": {
"ccr": "dist/cli.js" "ccr": "dist/cli.js"

10366
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +1,3 @@
packages: packages:
- 'packages/*' - 'packages/*'
- 'docs'