Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ PORT=3010
QODER_DATA_DIR=/data
QODER_RUNTIME_DIR=/tmp/cli2api-runtime
QODER_WORKER_BASE_PORT=32100
QODER_MAX_INFLIGHT=4
# When 1/true, bare model IDs can route across Qoder and WorkBuddy accounts.
# CROSS_PROVIDER_MODEL_POOL=0

Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,20 @@ Write each change in both `### English` and `### 中文` under `## Unreleased`.

### English

- Add console-selectable account routing strategies: round-robin, weighted round-robin, and fill-first
- Recover failed account runtimes with exponential backoff, and surface starting, recovering, and auth-failed states on account cards
- Show session-affinity TTL, hits, misses, escapes, and the last miss/escape reason on the System page
- Configure per-account concurrency in the console instead of the global `QODER_MAX_INFLIGHT` environment variable
- Align the README and deployment documentation with current provider capabilities, session affinity, API routes, and per-account concurrency settings

### 中文

- 控制台可选择账号调度策略:轮询、加权轮询、填满优先
- 账号运行时启动失败后按指数退避自动恢复,并在账号卡片上展示启动中、恢复中、登录失败状态
- 在系统页展示会话粘性 TTL、命中、未命中、逃逸,以及最近一次未命中/逃逸原因
- 账号并发改为控制台按账号配置,不再使用全局环境变量 `QODER_MAX_INFLIGHT`
- 同步 README 与部署文档,修正当前 Provider 能力、会话粘性、API 端点和账号级并发配置说明

## 0.2.44 - 2026-09-04

### English
Expand Down
11 changes: 7 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Contributing

CLI2API is Qoder-first. Keep changes focused and do not add other providers until the
current Qoder milestone is complete. Hard rules live in `AGENTS.md`.
CLI2API keeps the Qoder execution path stable while supporting provider-specific
adapters for Qoder, WorkBuddy, and Trae. Keep new provider work behind the shared
account, routing, and protocol contracts. Hard rules live in `AGENTS.md`.

## Setup

Expand Down Expand Up @@ -39,7 +40,8 @@ The favicon set and OG social card live in `frontend/public/`. After editing the
1. `cd frontend && npm run sync` — copies the assets into `internal/webui/static/` (embedded into the Go binary by `//go:embed`).
2. Add a matching entry under `## Unreleased` in `CHANGELOG.md` in both `### English` and `### 中文`.

The READMEs instead show `docs/assets/overview-card.png`, which is hand-maintained; regenerate it when login methods, account types, endpoints, or deployment targets change.
Keep README diagrams and provider lists aligned with the supported account types,
endpoints, and deployment targets.

Adding a new file to the favicon suite? Update three places:

Expand All @@ -62,7 +64,8 @@ by hand.
## Rules

- Keep the Go layers: auth / endpoint / executor / translate / api
- Keep one Qoder HOME and one Node daemon per enabled account
- Keep one isolated runtime per enabled account: Qoder uses one HOME and Node daemon;
in-process providers use their adapter and must not spawn a child daemon
- Keep qodercli compatibility checks in `worker/src/compat.mjs`
- Preserve the proven WASM encode and HTTP/SSE request path
- Use HeroUI for console components
Expand Down
28 changes: 12 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

支持 **Qoder 国际版**、**Qoder 国内版**、**WorkBuddy 国际版**、**WorkBuddy 国内版** 和 **Trae 国内版 Solo**。

常驻 worker、多账号调度,Docker 一键启动。
常驻运行时、多账号调度,Docker 一键启动。

[![License](https://img.shields.io/github/license/caigee-cmd/cli2api)](LICENSE)
[![LINUX DO](https://img.shields.io/badge/LINUX%20DO-community-ff6a00)](https://linux.do)
Expand All @@ -17,14 +17,12 @@

</div>

![CLI2API 支持的登录方式、账号类型、端点和部署形态](docs/assets/overview-card.png)

## 功能

- **OpenAI / Anthropic 兼容代理**:`/v1/chat/completions`、`/v1/responses`、`/v1/messages`、`/v1/models`;支持流式/非流式、文本、图片与函数工具调用;文件输入会明确拒绝。`messages` / `responses` 当前为无状态适配层,不支持服务端会话或上游专属工具。
- **OpenAI / Anthropic 兼容代理**:`/v1/chat/completions`、`/v1/responses`、`/v1/messages`、`/v1/models`;支持流式/非流式、文本与函数工具调用;图片能力取决于 provider(当前 Qoder 支持,WorkBuddy / Trae 不支持);文件输入会明确拒绝。`messages` / `responses` 当前为无状态适配层,不支持服务端会话或上游专属工具。
- **多渠道账号池**:Qoder 国际版 / 国内版、WorkBuddy 国际版 / 国内版、Trae 国内版 Solo;地域隔离、账号固定、并发限制、冷却与同族故障切换
- **常驻热 worker**:每账号独立 Node 进程与运行目录,鉴权、WASM 编码和云端 SSE 连接保持热;预热后小对话延迟约 1-2 秒,按请求拉起 CLI 的方案通常要 10 秒以上
- **多种登录方式**:浏览器 Device Flow OAuth、PAT、`qoder-native-v1` 凭证导入/导出
- **账号级常驻运行时**:Qoder 账号使用独立 Node 进程、HOME 与 WASM 上下文;WorkBuddy / Trae 使用进程内 HTTP/SSE 适配器。登录态、云端连接和账号隔离由各 provider 的运行时负责
- **按 provider 支持多种登录方式**:浏览器 Device Flow OAuth、PAT,以及适用 provider 的凭证导入/导出
- **Web 控制台**:账号、模型、接入、请求历史与运行时日志,明暗主题
- **部署与运维**:Docker Compose 单容器、安全托管更新(升级前快照、失败自动回滚、逐版本升级)、默认只监听 `127.0.0.1`
- **跨平台**:`linux/amd64` / `linux/arm64` 镜像;macOS、Windows 通过 Docker Desktop 运行
Expand All @@ -50,23 +48,23 @@ Base URL: http://127.0.0.1:3010/v1
API Key: <首次启动时生成的 Key>
```

不指定账号时,调度器自动选择可用账号;需要固定账号时加请求头 `X-Qoder-Account: acc_...`。除 Chat Completions 外,也可使用 Anthropic `POST /v1/messages` 与 OpenAI `POST /v1/responses`;两者要求请求携带完整对话,不支持 `previous_response_id` / `conversation` 服务端续接。curl / PowerShell 示例见 [部署说明](deploy/README.md)。
不指定账号时,调度器自动选择可用账号;需要固定账号时加请求头 `X-Qoder-Account: acc_...`(历史命名,适用于所有 provider)。除 Chat Completions 外,也可使用 Anthropic `POST /v1/messages` 与 OpenAI `POST /v1/responses`;两者要求请求携带完整对话,不支持 `previous_response_id` / `conversation` 服务端续接。需要会话粘性时,可设置 `X-CLI2API-Session`;curl / PowerShell 示例见 [部署说明](deploy/README.md)。

## 工作方式

<p align="center">
<img src="./docs/assets/readme/architecture-zh.svg" width="100%" alt="CLI2API 架构:OpenAI 客户端经 Go 控制面路由到每账号独立 Node worker,再连接 Qoder 云端">
<img src="./docs/assets/readme/architecture-zh.svg" width="100%" alt="CLI2API 架构:OpenAI 客户端经 Go 控制面路由到每账号独立运行时,再连接各 provider 上游">
</p>

每个启用账号拥有独立的 Node 进程和运行目录,避免共享 Qoder WASM 上下文。Go 负责账号持久化、调度、并发限制、冷却、失败切换和子进程生命周期
每个启用账号拥有独立运行时:Qoder 使用独立 Node 进程、HOME 和 WASM 上下文,WorkBuddy / Trae 使用进程内适配器。Go 负责账号持久化、调度、并发限制、冷却、失败切换,并管理需要子进程的 provider 生命周期

## 控制台

<p align="center">
<img src="./docs/assets/readme/console-window-zh.svg" width="100%" alt="CLI2API 控制台 Accounts 页:每个账号显示登录方式、就绪状态与额度,右侧 Access 面板提供 Base URL 与快速验证">
</p>

账号、模型、接入和日志都在同一个 Web 控制台里管理:每个账号独立登录(浏览器 OAuth、PAT 或凭证导入),就绪状态和额度一目了然,Access 页可以直接复制 Base URL 并做一次快速验证。
账号、模型、接入和日志都在同一个 Web 控制台里管理:每个账号按 provider 支持的方式登录(浏览器 OAuth、PAT 或凭证导入),就绪状态和额度一目了然,Access 页可以直接复制 Base URL 并做一次快速验证。

## 适合什么场景

Expand All @@ -82,15 +80,13 @@ CLI2API 是本地网关:不提供账号、额度或官方 API 服务,不做
**进行中**

- Qoder 国内版与 WorkBuddy 的真账号验收(登录、故障切换、混合账号池)

**已支持**

- Anthropic `/v1/messages` 与 OpenAI `/v1/responses` 的无状态文本 / 函数工具适配层
- WorkBuddy 每日签到与 token 保活(账号级开关,默认关闭;控制台可立即签到 / 刷新积分)

**规划中**

- 会话粘性路由:同一会话优先复用同一账号,提升上游缓存命中率
- 请求历史增强:按账号过滤与用量统计
- 会话粘性路由:通过 `X-CLI2API-Session` 优先复用同一账号,并在失败时按规则切换
- 请求历史按账号过滤,以及请求状态、延迟、Token 和用量统计

**长期**

Expand All @@ -104,7 +100,7 @@ CLI2API 是本地网关:不提供账号、额度或官方 API 服务,不做

## 安全

默认只监听 `127.0.0.1:3010`,全接口需要 API Key。不要提交 `.qoder`、Token、Cookie、登录 Blob 或原始抓包;凭证导出是显式敏感操作,请妥善保管导出文件。上游 API 或 CLI 更新可能导致兼容性变化,项目会固定并检查 qodercli 版本。发现安全问题请按 [SECURITY.md](SECURITY.md) 私下报告。
默认只监听 `127.0.0.1:3010`;除 `/health` 和静态前端资源外,所有 API 与控制台数据接口均需要 API Key。不要提交 `.qoder`、Token、Cookie、登录 Blob 或原始抓包;凭证导出是显式敏感操作,请妥善保管导出文件。上游 API 或 CLI 更新可能导致兼容性变化,项目会固定并检查 qodercli 版本。发现安全问题请按 [SECURITY.md](SECURITY.md) 私下报告。

## 社区

Expand Down
30 changes: 13 additions & 17 deletions README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

Supports **Qoder Global**, **Qoder CN**, **WorkBuddy Global**, **WorkBuddy CN**, and **Trae CN Solo**.

Long-lived workers, multi-account scheduling, one-command Docker start.
Long-lived account runtimes, multi-account scheduling, one-command Docker start.

[![License](https://img.shields.io/github/license/caigee-cmd/cli2api)](LICENSE)
[![LINUX DO](https://img.shields.io/badge/LINUX%20DO-community-ff6a00)](https://linux.do)
Expand All @@ -17,14 +17,12 @@ Long-lived workers, multi-account scheduling, one-command Docker start.

</div>

![Supported login methods, account types, endpoints, and deployment targets](docs/assets/overview-card.png)

## Features

- **OpenAI / Anthropic-compatible proxy**: `/v1/chat/completions`, `/v1/responses`, `/v1/messages`, `/v1/models` — streaming/non-streaming text, images, and function tools; file inputs are rejected explicitly. `messages` / `responses` are stateless adapters today and do not support server-side conversations or upstream-specific tools.
- **OpenAI / Anthropic-compatible proxy**: `/v1/chat/completions`, `/v1/responses`, `/v1/messages`, `/v1/models` — streaming/non-streaming text and function tools; image support depends on the provider (currently supported by Qoder, not WorkBuddy / Trae); file inputs are rejected explicitly. `messages` / `responses` are stateless adapters today and do not support server-side conversations or upstream-specific tools.
- **Multi-channel account pool**: Qoder Global / Qoder CN, WorkBuddy Global / WorkBuddy CN, Trae CN Solo — region isolation, account pinning, concurrency limits, cooldowns, and same-family failover
- **Long-lived warm workers**: one isolated Node process and runtime directory per account keeps authentication, WASM encoding, and cloud SSE connections warm. Typical small-chat latency is ~1-2s after warmup, versus ~10s+ for spawn-per-request wrappers
- **Multiple login methods**: browser Device Flow OAuth, PAT, and `qoder-native-v1` credential import/export
- **Account-level runtimes**: Qoder accounts use an isolated Node process, HOME, and WASM context; WorkBuddy / Trae use in-process HTTP/SSE adapters. Each provider owns its login and upstream runtime boundary
- **Provider-specific login methods**: browser Device Flow OAuth, PAT, and credential import/export where supported
- **Web console**: accounts, models, access, request history, and runtime logs, with light and dark themes
- **Deployment and ops**: single Docker Compose container, safe managed updates (pre-update snapshot, automatic rollback on failure, next-version-only upgrades), binds `127.0.0.1` by default
- **Cross-platform**: `linux/amd64` / `linux/arm64` images; macOS and Windows run them through Docker Desktop
Expand All @@ -50,23 +48,23 @@ Base URL: http://127.0.0.1:3010/v1
API Key: <the key printed on first startup>
```

Without an account header the scheduler picks a ready account; pin a request with the `X-Qoder-Account: acc_...` header. Anthropic `POST /v1/messages` and OpenAI `POST /v1/responses` are also available; both require the complete conversation in each request and do not support server-side continuation through `previous_response_id` / `conversation`. curl / PowerShell examples in the [deployment guide](deploy/README.md).
Without an account header the scheduler picks a ready account; pin a request with the `X-Qoder-Account: acc_...` header (a historical name that applies to every provider). Anthropic `POST /v1/messages` and OpenAI `POST /v1/responses` are also available; both require the complete conversation in each request and do not support server-side continuation through `previous_response_id` / `conversation`. Use `X-CLI2API-Session` when session-sticky routing is desired. curl / PowerShell examples in the [deployment guide](deploy/README.md).

## How it works

<p align="center">
<img src="./docs/assets/readme/architecture-en.svg" width="100%" alt="CLI2API architecture: OpenAI clients are routed by the Go control plane to one isolated Node worker per account, then to the Qoder cloud">
<img src="./docs/assets/readme/architecture-en.svg" width="100%" alt="CLI2API architecture: OpenAI clients are routed by the Go control plane to one isolated runtime per account, then to the provider upstream">
</p>

Each enabled account gets its own Node process and runtime directory so Qoder WASM state is not shared across accounts. Go owns persistence, scheduling, concurrency limits, cooldowns, failover, and child-process lifecycle.
Each enabled account gets an isolated runtime: Qoder uses its own Node process, HOME, and WASM context, while WorkBuddy / Trae use in-process adapters. Go owns persistence, scheduling, concurrency limits, cooldowns, failover, and the lifecycle of providers that need child processes.

## Console

<p align="center">
<img src="./docs/assets/readme/console-window-en.svg" width="100%" alt="CLI2API console Accounts page: each account shows its login method, ready state, and quota, with an Access panel offering the Base URL and a quick check">
</p>

Accounts, models, access, and logs all live in one web console. Each account signs in on its own (browser OAuth, PAT, or credential import), readiness and quota are visible at a glance, and the Access page lets you copy the Base URL and run a quick check.
Accounts, models, access, and logs all live in one web console. Each account signs in through the methods supported by its provider (browser OAuth, PAT, or credential import), readiness and quota are visible at a glance, and the Access page lets you copy the Base URL and run a quick check.

## Use cases

Expand All @@ -82,15 +80,13 @@ CLI2API is a local gateway: it does not provide accounts, quotas, or an official
**In progress**

- Live-account acceptance for Qoder CN and WorkBuddy (login, failover, mixed account pools)

**Supported**

- Stateless text, image, and function-tool adapters for Anthropic `/v1/messages` and OpenAI `/v1/responses`
- Stateless text and function-tool adapters for Anthropic `/v1/messages` and OpenAI `/v1/responses`; image input where the provider supports it
- WorkBuddy daily check-in and token keepalive (per-account opt-in, off by default; console can check in now / refresh credits)

**Planned**

- Session-sticky routing: prefer reusing one account per session to improve upstream cache hit rates
- Request history improvements: per-account filtering and usage statistics
- Session-sticky routing via `X-CLI2API-Session`, with rule-based failover when the bound account cannot serve the request
- Request history filtering by account, plus request status, latency, token, and usage statistics

**Longer term**

Expand All @@ -104,7 +100,7 @@ CLI2API is a local gateway: it does not provide accounts, quotas, or an official

## Security

The service binds `127.0.0.1:3010` by default and every endpoint requires the API key. Never commit `.qoder`, tokens, cookies, auth blobs, or raw captures; credential export is an explicit sensitive operation — protect exported files. Upstream API or CLI changes may affect compatibility; qodercli is pinned and checked. Please report security issues privately according to [SECURITY.md](SECURITY.md).
The service binds `127.0.0.1:3010` by default; all APIs and console data endpoints require the API key except `/health` and static frontend assets. Never commit `.qoder`, tokens, cookies, auth blobs, or raw captures; credential export is an explicit sensitive operation — protect exported files. Upstream API or CLI changes may affect compatibility; qodercli is pinned and checked. Please report security issues privately according to [SECURITY.md](SECURITY.md).

## Community

Expand Down
1 change: 0 additions & 1 deletion deploy/.env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# CLI2API_IMAGE=ghcr.io/caigee-cmd/cli2api:latest
# QODER_WORKER_BASE_PORT=32100
# QODER_MAX_INFLIGHT=4
# When 1/true, bare model IDs can route across Qoder and WorkBuddy accounts.
# Prefixed IDs (qoder/... / workbuddy/...) still pin one family.
# CROSS_PROVIDER_MODEL_POOL=0
Expand Down
Loading
Loading