Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
8f9e662
fix(util): forward custom Host header to upstream
muzhi1991 Apr 16, 2026
d9a3b3e
fix(tests): update model lookup references and enhance Claude executo…
hkfires Apr 17, 2026
da43f63
fix(tests): update Gemini family test case numbers for consistency
hkfires Apr 17, 2026
eba561b
fix(util): also keep Host in header map for synthetic requests
muzhi1991 Apr 17, 2026
894baad
feat(api): integrate auth index into key retrieval endpoints for Gemi…
LTbinglingfeng Apr 18, 2026
c26936e
fix(management): stabilize auth-index mapping
LTbinglingfeng Apr 18, 2026
a64141a
fix(tests): remove obsolete config_auth_index_test file
LTbinglingfeng Apr 18, 2026
c6baa64
Merge pull request #2892 from router-for-me/fix-provider
LTbinglingfeng Apr 18, 2026
86c856f
feat(translator): add partial and full image generation support in Co…
luispater Apr 18, 2026
f4eb161
fix(executor): drop obsolete context-1m-2025-08-07 beta header (fixes…
octo-patch Apr 19, 2026
e05abec
Merge pull request #2898 from octo-patch/fix/issue-2866-remove-obsole…
luispater Apr 19, 2026
8f4a4ea
feat(docs): add VisionCoder sponsorship details and optimize external…
luispater Apr 19, 2026
e6866ff
feat(auth): add refresh backoff for ineffective token updates
luispater Apr 20, 2026
bb8408c
fix(codex): backfill streaming response output
stringer07 Apr 21, 2026
b6781d6
perf(codex): avoid repeated output patch writes
stringer07 Apr 21, 2026
1716a84
feat(api): add support for `HEAD` requests to `/healthz` endpoint
luispater Apr 21, 2026
3444820
Merge pull request #2939 from stringer07/fix/codex-stream-output-back…
luispater Apr 21, 2026
8ced7a5
Merge pull request #2834 from muzhi1991/fix/openai-compat-host-header
luispater Apr 21, 2026
4fc2c61
feat(models): add Kimi K2.6 model entry to registry JSON
luispater Apr 21, 2026
e935196
feat(models): add hardcoded GPT-Image-2 model support in Codex
luispater Apr 22, 2026
fd71960
fix(handlers): remove handling of unsupported `n` parameter in OpenAI…
luispater Apr 22, 2026
a188159
fix(handlers): remove references to unsupported `n` parameter in Open…
luispater Apr 22, 2026
31934ae
feat(codex): enable image generation for all Codex upstream requests
MoYeRanqianzhi Apr 22, 2026
14d46a0
feat(antigravity): conductor-level credits fallback for Claude models
sususu98 Apr 23, 2026
4de5c29
fix(antigravity): remove credits fallback from CountTokens, fix gofmt
sususu98 Apr 23, 2026
e75daa2
fix(antigravity): respect pinned auth in credits fallback, release de…
sususu98 Apr 23, 2026
920b6ef
refactor(logging): strip unrelated deferred body changes, keep credit…
sususu98 Apr 23, 2026
f130846
fix(auth): break credits cold-start deadlock by keeping unknown-hint …
sususu98 Apr 23, 2026
8eb56e5
Merge pull request #2962 from MoYeRanqianzhi/feat/codex-image-generat…
luispater Apr 23, 2026
7ad1900
perf(antigravity): async credits hint refresh for warm tokens
sususu98 Apr 23, 2026
25137b1
feat(logging): add AI API path support for image routes
luispater Apr 23, 2026
12195a2
Merge pull request #2971 from sususu98/feat/antigravity-credits-fallback
sususu98 Apr 23, 2026
7d5f6d9
feat(models): add GPT-5.5 model entry to registry JSON
luispater Apr 23, 2026
736018a
Add GPT-5.5 Codex model support
ben-vargas Apr 23, 2026
1576d14
Merge pull request #2989 from ben-vargas/gpt-5-5-support
luispater Apr 23, 2026
7b89583
chore(models): remove GPT-5.5 model entry from registry JSON
luispater Apr 23, 2026
f1ba615
feat(codex): pass base model to enable conditional image_generation t…
luispater Apr 23, 2026
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
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ Get 10% OFF GLM CODING PLAN:https://z.ai/subscribe?ic=8JVLJQFSKB
<td width="180"><a href="https://poixe.com/i/m8kvep"><img src="./assets/poixeai.png" alt="PoixeAI" width="150"></a></td>
<td>Thanks to Poixe AI for sponsoring this project! Poixe AI provides reliable LLM API services. You can leverage the platform's API endpoints to seamlessly build AI-powered products. Additionally, you can become a vendor by providing AI API resources to the platform and earn revenue. Register through the exclusive CLIProxyAPI <a href="https://poixe.com/i/m8kvep">referral link</a> and receive a bonus of $5 USD on your first top-up.</td>
</tr>
<tr>
<td width="180"><a href="https://coder.visioncoder.cn"><img src="./assets/visioncoder.png" alt="VisionCoder" width="150"></a></td>
<td>Thanks to VisionCoder for supporting this project. <a href="https://coder.visioncoder.cn" target="_blank">VisionCoder Developer Platform</a> is a reliable and efficient API relay service provider, offering access to mainstream AI models such as Claude Code, Codex, and Gemini. It helps developers and teams integrate AI capabilities more easily and improve productivity.
<p></p>
VisionCoder is also offering our users a limited-time <a href="https://coder.visioncoder.cn" target="_blank">Token Plan</a> promotion: buy 1 month and get 1 month free.</td>
</tr>
</tbody>
</table>

Expand Down
16 changes: 11 additions & 5 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,29 @@ GLM CODING PLAN 是专为AI编码打造的订阅套餐,每月最低仅需20元
<tbody>
<tr>
<td width="180"><a href="https://www.packyapi.com/register?aff=cliproxyapi"><img src="./assets/packycode.png" alt="PackyCode" width="150"></a></td>
<td>感谢 PackyCode 对本项目的赞助!PackyCode 是一家可靠高效的 API 中转服务商,提供 Claude Code、Codex、Gemini 等多种服务的中转。PackyCode 为本软件用户提供了特别优惠:使用<a href="https://www.packyapi.com/register?aff=cliproxyapi">此链接</a>注册,并在充值时输入 "cliproxyapi" 优惠码即可享受九折优惠。</td>
<td>感谢 PackyCode 对本项目的赞助!PackyCode 是一家可靠高效的 API 中转服务商,提供 Claude Code、Codex、Gemini 等多种服务的中转。PackyCode 为本软件用户提供了特别优惠:使用<a href="https://www.packyapi.com/register?aff=cliproxyapi" target="_blank">此链接</a>注册,并在充值时输入 "cliproxyapi" 优惠码即可享受九折优惠。</td>
</tr>
<tr>
<td width="180"><a href="https://www.aicodemirror.com/register?invitecode=TJNAIF"><img src="./assets/aicodemirror.png" alt="AICodeMirror" width="150"></a></td>
<td>感谢 AICodeMirror 赞助了本项目!AICodeMirror 提供 Claude Code / Codex / Gemini CLI 官方高稳定中转服务,支持企业级高并发、极速开票、7×24 专属技术支持。 Claude Code / Codex / Gemini 官方渠道低至 3.8 / 0.2 / 0.9 折,充值更有折上折!AICodeMirror 为 CLIProxyAPI 的用户提供了特别福利,通过<a href="https://www.aicodemirror.com/register?invitecode=TJNAIF">此链接</a>注册的用户,可享受首充8折,企业客户最高可享 7.5 折!</td>
<td>感谢 AICodeMirror 赞助了本项目!AICodeMirror 提供 Claude Code / Codex / Gemini CLI 官方高稳定中转服务,支持企业级高并发、极速开票、7×24 专属技术支持。 Claude Code / Codex / Gemini 官方渠道低至 3.8 / 0.2 / 0.9 折,充值更有折上折!AICodeMirror 为 CLIProxyAPI 的用户提供了特别福利,通过<a href="https://www.aicodemirror.com/register?invitecode=TJNAIF" target="_blank">此链接</a>注册的用户,可享受首充8折,企业客户最高可享 7.5 折!</td>
</tr>
<tr>
<td width="180"><a href="https://shop.bmoplus.com/?utm_source=github"><img src="./assets/bmoplus.png" alt="BmoPlus" width="150"></a></td>
<td>感谢 BmoPlus 赞助了本项目!BmoPlus 是一家专为AI订阅重度用户打造的可靠 AI 账号代充服务商,提供稳定的 ChatGPT Plus / ChatGPT Pro(全程质保) / Claude Pro / Super Grok / Gemini Pro 的官方代充&成品账号。 通过<a href="https://shop.bmoplus.com/?utm_source=github">BmoPlus AI成品号专卖/代充</a>注册下单的用户,可享GPT <b>官网订阅一折</b> 的震撼价格!</td>
<td>感谢 BmoPlus 赞助了本项目!BmoPlus 是一家专为AI订阅重度用户打造的可靠 AI 账号代充服务商,提供稳定的 ChatGPT Plus / ChatGPT Pro(全程质保) / Claude Pro / Super Grok / Gemini Pro 的官方代充&成品账号。 通过<a href="https://shop.bmoplus.com/?utm_source=github" target="_blank">BmoPlus AI成品号专卖/代充</a>注册下单的用户,可享GPT <b>官网订阅一折</b> 的震撼价格!</td>
</tr>
<tr>
<td width="180"><a href="https://www.lingtrue.com/register"><img src="./assets/lingtrue.png" alt="LingtrueAPI" width="150"></a></td>
<td>感谢 LingtrueAPI 对本项目的赞助!LingtrueAPI 是一家全球大模型API中转服务平台,提供Claude Code、Codex、Gemini 等多种顶级模型API调用服务,致力于让用户以低成本、高稳定性链接全球AI能力。LingtrueAPI为本软件用户提供了特别优惠:使用<a href="https://www.lingtrue.com/register">此链接</a>注册,并在首次充值时输入 "LingtrueAPI" 优惠码即可享受9折优惠。</td>
<td>感谢 LingtrueAPI 对本项目的赞助!LingtrueAPI 是一家全球大模型API中转服务平台,提供Claude Code、Codex、Gemini 等多种顶级模型API调用服务,致力于让用户以低成本、高稳定性链接全球AI能力。LingtrueAPI为本软件用户提供了特别优惠:使用<a href="https://www.lingtrue.com/register" target="_blank">此链接</a>注册,并在首次充值时输入 "LingtrueAPI" 优惠码即可享受9折优惠。</td>
</tr>
<tr>
<td width="180"><a href="https://poixe.com/i/m8kvep"><img src="./assets/poixeai.png" alt="PoixeAI" width="150"></a></td>
<td>感谢 Poixe AI 对本项目的赞助!Poixe AI 提供可靠的 AI 模型接口服务,您可以使用平台提供的 LLM API 接口轻松构建 AI 产品,同时也可以成为供应商,为平台提供大模型资源以赚取收益。通过 CLIProxyAPI <a href="https://poixe.com/i/m8kvep">专属链接</a>注册,充值额外赠送 $5 美金</td>
<td>感谢 Poixe AI 对本项目的赞助!Poixe AI 提供可靠的 AI 模型接口服务,您可以使用平台提供的 LLM API 接口轻松构建 AI 产品,同时也可以成为供应商,为平台提供大模型资源以赚取收益。通过 CLIProxyAPI <a href="https://poixe.com/i/m8kvep" target="_blank">专属链接</a>注册,充值额外赠送 $5 美金</td>
</tr>
<tr>
<td width="180"><a href="https://coder.visioncoder.cn"><img src="./assets/visioncoder.png" alt="VisionCoder" width="150"></a></td>
<td>感谢 VisionCoder 对本项目的支持。<a href="https://coder.visioncoder.cn" target="_blank">VisionCoder 开发平台</a> 是一个可靠高效的 API 中继服务提供商,提供 Claude Code、Codex、Gemini 等主流 AI 模型,帮助开发者和团队更轻松地集成 AI 功能,提升工作效率。
<p></p>
VisionCoder 还为我们的用户提供 <a href="https://coder.visioncoder.cn" target="_blank">Token Plan</a> 限时活动:购买 1 个月,赠送 1 个月。</td>
</tr>
</tbody>
</table>
Expand Down
4 changes: 4 additions & 0 deletions README_JA.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ GLM CODING PLANを10%割引で取得:https://z.ai/subscribe?ic=8JVLJQFSKB
<td width="180"><a href="https://poixe.com/i/m8kvep"><img src="./assets/poixeai.png" alt="PoixeAI" width="150"></a></td>
<td>Poixe AIのスポンサーシップに感謝します!Poixe AIは信頼できるAIモデルAPIサービスを提供しており、プラットフォームが提供するLLM APIを使って簡単にAI製品を構築できます。また、サプライヤーとしてプラットフォームに大規模モデルのリソースを提供し、収益を得ることも可能です。CLIProxyAPIの<a href="https://poixe.com/i/m8kvep">専用リンク</a>から登録すると、チャージ時に追加で$5が付与されます。</td>
</tr>
<tr>
<td width="180"><a href="https://coder.visioncoder.cn"><img src="./assets/visioncoder.png" alt="VisionCoder" width="150"></a></td>
<td>VisionCoderのご支援に感謝します!<a href="https://coder.visioncoder.cn">VisionCoder 開発プラットフォーム</a> は、信頼性が高く効率的なAPIリレーサービスプロバイダーで、Claude Code、Codex、Geminiなどの主要AIモデルを提供し、開発者やチームがより簡単にAI機能を統合して生産性を向上できるよう支援します。さらに、VisionCoderはユーザー向けに <a href="https://coder.visioncoder.cn">Token Plan</a> の期間限定キャンペーン(1か月購入で1か月分プレゼント)も提供しています。</td>
</tr>
</tbody>
</table>

Expand Down
Binary file added assets/visioncoder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ disable-cooling: false
quota-exceeded:
switch-project: true # Whether to automatically switch to another project when a quota is exceeded
switch-preview-model: true # Whether to automatically switch to a preview model when a quota is exceeded
antigravity-credits: true # Whether to retry Antigravity quota_exhausted 429s once with enabledCreditTypes=["GOOGLE_ONE_AI"]
antigravity-credits: true # Whether to use credits as last-resort fallback when all free-tier auths are exhausted for Claude models

# Routing strategy for selecting credentials when multiple match.
routing:
Expand Down
241 changes: 241 additions & 0 deletions internal/api/handlers/management/config_auth_index.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
package management

import (
"fmt"
"strings"

"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
"github.com/router-for-me/CLIProxyAPI/v6/internal/watcher/synthesizer"
)

type geminiKeyWithAuthIndex struct {
config.GeminiKey
AuthIndex string `json:"auth-index,omitempty"`
}

type claudeKeyWithAuthIndex struct {
config.ClaudeKey
AuthIndex string `json:"auth-index,omitempty"`
}

type codexKeyWithAuthIndex struct {
config.CodexKey
AuthIndex string `json:"auth-index,omitempty"`
}

type vertexCompatKeyWithAuthIndex struct {
config.VertexCompatKey
AuthIndex string `json:"auth-index,omitempty"`
}

type openAICompatibilityAPIKeyWithAuthIndex struct {
config.OpenAICompatibilityAPIKey
AuthIndex string `json:"auth-index,omitempty"`
}

type openAICompatibilityWithAuthIndex struct {
Name string `json:"name"`
Priority int `json:"priority,omitempty"`
Prefix string `json:"prefix,omitempty"`
BaseURL string `json:"base-url"`
APIKeyEntries []openAICompatibilityAPIKeyWithAuthIndex `json:"api-key-entries,omitempty"`
Models []config.OpenAICompatibilityModel `json:"models,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
AuthIndex string `json:"auth-index,omitempty"`
}

func (h *Handler) liveAuthIndexByID() map[string]string {
out := map[string]string{}
if h == nil {
return out
}
h.mu.Lock()
manager := h.authManager
h.mu.Unlock()
if manager == nil {
return out
}
// authManager.List() returns clones, so EnsureIndex only affects these copies.
for _, auth := range manager.List() {
if auth == nil {
continue
}
id := strings.TrimSpace(auth.ID)
if id == "" {
continue
}
idx := strings.TrimSpace(auth.Index)
if idx == "" {
idx = auth.EnsureIndex()
}
if idx == "" {
continue
}
out[id] = idx
}
return out
}

func (h *Handler) geminiKeysWithAuthIndex() []geminiKeyWithAuthIndex {
if h == nil {
return nil
}
liveIndexByID := h.liveAuthIndexByID()

h.mu.Lock()
defer h.mu.Unlock()
if h.cfg == nil {
return nil
}

idGen := synthesizer.NewStableIDGenerator()
out := make([]geminiKeyWithAuthIndex, len(h.cfg.GeminiKey))
for i := range h.cfg.GeminiKey {
entry := h.cfg.GeminiKey[i]
authIndex := ""
if key := strings.TrimSpace(entry.APIKey); key != "" {
id, _ := idGen.Next("gemini:apikey", key, entry.BaseURL)
authIndex = liveIndexByID[id]
}
out[i] = geminiKeyWithAuthIndex{
GeminiKey: entry,
AuthIndex: authIndex,
}
}
return out
}

func (h *Handler) claudeKeysWithAuthIndex() []claudeKeyWithAuthIndex {
if h == nil {
return nil
}
liveIndexByID := h.liveAuthIndexByID()

h.mu.Lock()
defer h.mu.Unlock()
if h.cfg == nil {
return nil
}

idGen := synthesizer.NewStableIDGenerator()
out := make([]claudeKeyWithAuthIndex, len(h.cfg.ClaudeKey))
for i := range h.cfg.ClaudeKey {
entry := h.cfg.ClaudeKey[i]
authIndex := ""
if key := strings.TrimSpace(entry.APIKey); key != "" {
id, _ := idGen.Next("claude:apikey", key, entry.BaseURL)
authIndex = liveIndexByID[id]
}
out[i] = claudeKeyWithAuthIndex{
ClaudeKey: entry,
AuthIndex: authIndex,
}
}
return out
}

func (h *Handler) codexKeysWithAuthIndex() []codexKeyWithAuthIndex {
if h == nil {
return nil
}
liveIndexByID := h.liveAuthIndexByID()

h.mu.Lock()
defer h.mu.Unlock()
if h.cfg == nil {
return nil
}

idGen := synthesizer.NewStableIDGenerator()
out := make([]codexKeyWithAuthIndex, len(h.cfg.CodexKey))
for i := range h.cfg.CodexKey {
entry := h.cfg.CodexKey[i]
authIndex := ""
if key := strings.TrimSpace(entry.APIKey); key != "" {
id, _ := idGen.Next("codex:apikey", key, entry.BaseURL)
authIndex = liveIndexByID[id]
}
out[i] = codexKeyWithAuthIndex{
CodexKey: entry,
AuthIndex: authIndex,
}
}
return out
}

func (h *Handler) vertexCompatKeysWithAuthIndex() []vertexCompatKeyWithAuthIndex {
if h == nil {
return nil
}
liveIndexByID := h.liveAuthIndexByID()

h.mu.Lock()
defer h.mu.Unlock()
if h.cfg == nil {
return nil
}

idGen := synthesizer.NewStableIDGenerator()
out := make([]vertexCompatKeyWithAuthIndex, len(h.cfg.VertexCompatAPIKey))
for i := range h.cfg.VertexCompatAPIKey {
entry := h.cfg.VertexCompatAPIKey[i]
id, _ := idGen.Next("vertex:apikey", entry.APIKey, entry.BaseURL, entry.ProxyURL)
authIndex := liveIndexByID[id]
out[i] = vertexCompatKeyWithAuthIndex{
VertexCompatKey: entry,
AuthIndex: authIndex,
}
}
return out
}

func (h *Handler) openAICompatibilityWithAuthIndex() []openAICompatibilityWithAuthIndex {
if h == nil {
return nil
}
liveIndexByID := h.liveAuthIndexByID()

h.mu.Lock()
defer h.mu.Unlock()
if h.cfg == nil {
return nil
}

normalized := normalizedOpenAICompatibilityEntries(h.cfg.OpenAICompatibility)
out := make([]openAICompatibilityWithAuthIndex, len(normalized))
idGen := synthesizer.NewStableIDGenerator()
for i := range normalized {
entry := normalized[i]
providerName := strings.ToLower(strings.TrimSpace(entry.Name))
if providerName == "" {
providerName = "openai-compatibility"
}
idKind := fmt.Sprintf("openai-compatibility:%s", providerName)

response := openAICompatibilityWithAuthIndex{
Name: entry.Name,
Priority: entry.Priority,
Prefix: entry.Prefix,
BaseURL: entry.BaseURL,
Models: entry.Models,
Headers: entry.Headers,
AuthIndex: "",
}
if len(entry.APIKeyEntries) == 0 {
id, _ := idGen.Next(idKind, entry.BaseURL)
response.AuthIndex = liveIndexByID[id]
} else {
response.APIKeyEntries = make([]openAICompatibilityAPIKeyWithAuthIndex, len(entry.APIKeyEntries))
for j := range entry.APIKeyEntries {
apiKeyEntry := entry.APIKeyEntries[j]
id, _ := idGen.Next(idKind, apiKeyEntry.APIKey, entry.BaseURL, apiKeyEntry.ProxyURL)
response.APIKeyEntries[j] = openAICompatibilityAPIKeyWithAuthIndex{
OpenAICompatibilityAPIKey: apiKeyEntry,
AuthIndex: liveIndexByID[id],
}
}
}
out[i] = response
}
return out
}
Loading
Loading