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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ So you can use local or multi-account CLI access with OpenAI(include Responses)/

## Sponsor

[![z.ai](https://assets.router-for.me/english-5.png)](https://z.ai/subscribe?ic=8JVLJQFSKB)
[![z.ai](https://assets.router-for.me/english-5-0.jpg)](https://z.ai/subscribe?ic=8JVLJQFSKB)

This project is sponsored by Z.ai, supporting us with their GLM CODING PLAN.

Expand Down
2 changes: 1 addition & 1 deletion README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

## 赞助商

[![bigmodel.cn](https://assets.router-for.me/chinese-5.png)](https://www.bigmodel.cn/claude-code?ic=RRVJPB5SII)
[![bigmodel.cn](https://assets.router-for.me/chinese-5-0.jpg)](https://www.bigmodel.cn/claude-code?ic=RRVJPB5SII)

本项目由 Z智谱 提供赞助, 他们通过 GLM CODING PLAN 对本项目提供技术支持。

Expand Down
22 changes: 13 additions & 9 deletions internal/api/handlers/management/auth_files.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"net/http"
"os"
"path/filepath"
"runtime"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -692,17 +693,20 @@ func (h *Handler) authIDForPath(path string) string {
if path == "" {
return ""
}
if h == nil || h.cfg == nil {
return path
}
authDir := strings.TrimSpace(h.cfg.AuthDir)
if authDir == "" {
return path
id := path
if h != nil && h.cfg != nil {
authDir := strings.TrimSpace(h.cfg.AuthDir)
if authDir != "" {
if rel, errRel := filepath.Rel(authDir, path); errRel == nil && rel != "" {
id = rel
}
}
}
if rel, err := filepath.Rel(authDir, path); err == nil && rel != "" {
return rel
// On Windows, normalize ID casing to avoid duplicate auth entries caused by case-insensitive paths.
if runtime.GOOS == "windows" {
id = strings.ToLower(id)
}
return path
return id
}

func (h *Handler) registerAuthFromFile(ctx context.Context, path string, data []byte) error {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -441,9 +441,19 @@ func ConvertClaudeRequestToAntigravity(modelName string, inputRawJSON []byte, _
out, _ = sjson.Set(out, "request.generationConfig.thinkingConfig.includeThoughts", true)
}
case "adaptive", "auto":
// Keep adaptive/auto as a high level sentinel; ApplyThinking resolves it
// to model-specific max capability.
out, _ = sjson.Set(out, "request.generationConfig.thinkingConfig.thinkingLevel", "high")
// Adaptive/auto thinking:
// - If output_config.effort is present, pass it through as thinkingLevel.
// - Otherwise, default to "high".
// ApplyThinking later normalizes/clamps and may convert level → budget per target model.
effort := ""
if v := gjson.GetBytes(rawJSON, "output_config.effort"); v.Exists() && v.Type == gjson.String {
effort = strings.ToLower(strings.TrimSpace(v.String()))
}
if effort != "" {
out, _ = sjson.Set(out, "request.generationConfig.thinkingConfig.thinkingLevel", effort)
} else {
out, _ = sjson.Set(out, "request.generationConfig.thinkingConfig.thinkingLevel", "high")
}
out, _ = sjson.Set(out, "request.generationConfig.thinkingConfig.includeThoughts", true)
}
}
Expand Down
5 changes: 5 additions & 0 deletions internal/watcher/synthesizer/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -72,6 +73,10 @@ func (s *FileSynthesizer) Synthesize(ctx *SynthesisContext) ([]*coreauth.Auth, e
if rel, errRel := filepath.Rel(ctx.AuthDir, full); errRel == nil && rel != "" {
id = rel
}
// On Windows, normalize ID casing to avoid duplicate auth entries caused by case-insensitive paths.
if runtime.GOOS == "windows" {
id = strings.ToLower(id)
}

proxyURL := ""
if p, ok := metadata["proxy_url"].(string); ok {
Expand Down
16 changes: 10 additions & 6 deletions sdk/auth/filestore.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"net/url"
"os"
"path/filepath"
"runtime"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -257,14 +258,17 @@ func (s *FileTokenStore) readAuthFile(path, baseDir string) (*cliproxyauth.Auth,
}

func (s *FileTokenStore) idFor(path, baseDir string) string {
if baseDir == "" {
return path
id := path
if baseDir != "" {
if rel, errRel := filepath.Rel(baseDir, path); errRel == nil && rel != "" {
id = rel
}
}
rel, err := filepath.Rel(baseDir, path)
if err != nil {
return path
// On Windows, normalize ID casing to avoid duplicate auth entries caused by case-insensitive paths.
if runtime.GOOS == "windows" {
id = strings.ToLower(id)
}
return rel
return id
}

func (s *FileTokenStore) resolveAuthPath(auth *cliproxyauth.Auth) (string, error) {
Expand Down
11 changes: 8 additions & 3 deletions sdk/cliproxy/auth/conductor.go
Original file line number Diff line number Diff line change
Expand Up @@ -463,9 +463,14 @@ func (m *Manager) Update(ctx context.Context, auth *Auth) (*Auth, error) {
return nil, nil
}
m.mu.Lock()
if existing, ok := m.auths[auth.ID]; ok && existing != nil && !auth.indexAssigned && auth.Index == "" {
auth.Index = existing.Index
auth.indexAssigned = existing.indexAssigned
if existing, ok := m.auths[auth.ID]; ok && existing != nil {
if !auth.indexAssigned && auth.Index == "" {
auth.Index = existing.Index
auth.indexAssigned = existing.indexAssigned
}
if len(auth.ModelStates) == 0 && len(existing.ModelStates) > 0 {
auth.ModelStates = existing.ModelStates
}
}
auth.EnsureIndex()
m.auths[auth.ID] = auth.Clone()
Expand Down
49 changes: 49 additions & 0 deletions sdk/cliproxy/auth/conductor_update_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package auth

import (
"context"
"testing"
)

func TestManager_Update_PreservesModelStates(t *testing.T) {
m := NewManager(nil, nil, nil)

model := "test-model"
backoffLevel := 7

if _, errRegister := m.Register(context.Background(), &Auth{
ID: "auth-1",
Provider: "claude",
Metadata: map[string]any{"k": "v"},
ModelStates: map[string]*ModelState{
model: {
Quota: QuotaState{BackoffLevel: backoffLevel},
},
},
}); errRegister != nil {
t.Fatalf("register auth: %v", errRegister)
}

if _, errUpdate := m.Update(context.Background(), &Auth{
ID: "auth-1",
Provider: "claude",
Metadata: map[string]any{"k": "v2"},
}); errUpdate != nil {
t.Fatalf("update auth: %v", errUpdate)
}

updated, ok := m.GetByID("auth-1")
if !ok || updated == nil {
t.Fatalf("expected auth to be present")
}
if len(updated.ModelStates) == 0 {
t.Fatalf("expected ModelStates to be preserved")
}
state := updated.ModelStates[model]
if state == nil {
t.Fatalf("expected model state to be present")
}
if state.Quota.BackoffLevel != backoffLevel {
t.Fatalf("expected BackoffLevel to be %d, got %d", backoffLevel, state.Quota.BackoffLevel)
}
}
3 changes: 3 additions & 0 deletions sdk/cliproxy/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,9 @@ func (s *Service) applyCoreAuthAddOrUpdate(ctx context.Context, auth *coreauth.A
auth.CreatedAt = existing.CreatedAt
auth.LastRefreshedAt = existing.LastRefreshedAt
auth.NextRefreshAfter = existing.NextRefreshAfter
if len(auth.ModelStates) == 0 && len(existing.ModelStates) > 0 {
auth.ModelStates = existing.ModelStates
}
op = "update"
_, err = s.coreManager.Update(ctx, auth)
} else {
Expand Down
Loading