From 8e485e58689a6a576afcc0a75d220d1cc8dc3315 Mon Sep 17 00:00:00 2001 From: hkfires <10558748+hkfires@users.noreply.github.com> Date: Tue, 23 Sep 2025 12:48:30 +0800 Subject: [PATCH] refactor(gemini-web): Remove auto-refresh, auto-close, and caching This commit simplifies the Gemini web client by removing several complex, stateful features. The previous implementation for auto-refreshing cookies and auto-closing the client involved background goroutines, timers, and file system caching, which made the client's lifecycle difficult to manage. The following features have been removed: - The cookie auto-refresh mechanism, including the background goroutine (`rotateCookies`) and related configuration fields. - The file-based caching for the `__Secure-1PSIDTS` token. The `rotate1PSIDTS` function now fetches a new token on every call. - The auto-close functionality, which used timers to close the client after a period of inactivity. - Associated configuration options and methods (`WithAccountLabel`, `WithOnCookiesRefreshed`, `Close`, etc.). By removing this logic, the client becomes more stateless and predictable. The responsibility for managing the client's lifecycle and handling token expiration is now shifted to the caller, leading to a simpler and more robust integration. --- README.md | 2 - README_CN.md | 2 - config.example.yaml | 34 ++-- internal/auth/gemini/gemini-web_token.go | 5 + internal/client/gemini-web/auth.go | 22 +-- internal/client/gemini-web/client.go | 168 +++--------------- internal/config/config.go | 4 - internal/runtime/executor/gemini_web_state.go | 126 ++----------- internal/watcher/watcher.go | 3 - sdk/auth/gemini-web.go | 2 +- sdk/cliproxy/service.go | 3 - 11 files changed, 60 insertions(+), 311 deletions(-) diff --git a/README.md b/README.md index a0c865c0..9874eb05 100644 --- a/README.md +++ b/README.md @@ -296,7 +296,6 @@ The server uses a YAML configuration file (`config.yaml`) located in the project | `gemini-web.code-mode` | boolean | false | Enables code mode for optimized responses in coding-related tasks. | | `gemini-web.max-chars-per-request` | integer | 1,000,000 | The maximum number of characters to send to Gemini Web in a single request. | | `gemini-web.disable-continuation-hint` | boolean | false | Disables the continuation hint for split prompts. | -| `gemini-web.token-refresh-seconds` | integer | 540 | The interval in seconds for background cookie auto-refresh. | ### Example Configuration File @@ -337,7 +336,6 @@ gemini-web: context: true # Enable conversation context reuse code-mode: false # Enable code mode max-chars-per-request: 1000000 # Max characters per request - token-refresh-seconds: 540 # Cookie refresh interval in seconds # Request authentication providers auth: diff --git a/README_CN.md b/README_CN.md index 8b6e1475..b0c0e27b 100644 --- a/README_CN.md +++ b/README_CN.md @@ -308,7 +308,6 @@ console.log(await claudeResponse.json()); | `gemini-web.code-mode` | boolean | false | 是否启用代码模式,优化代码相关任务的响应。 | | `gemini-web.max-chars-per-request` | integer | 1,000,000 | 单次请求发送给 Gemini Web 的最大字符数。 | | `gemini-web.disable-continuation-hint` | boolean | false | 当提示被拆分时,是否禁用连续提示的暗示。 | -| `gemini-web.token-refresh-seconds` | integer | 540 | 后台 Cookie 自动刷新的间隔(秒)。 | ### 配置文件示例 @@ -349,7 +348,6 @@ gemini-web: context: true # 启用会话上下文重用 code-mode: false # 启用代码模式 max-chars-per-request: 1000000 # 单次请求最大字符数 - token-refresh-seconds: 540 # Cookie 刷新间隔(秒) # 请求鉴权提供方 auth: diff --git a/config.example.yaml b/config.example.yaml index 8e29a1ca..9c8666bc 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -71,21 +71,19 @@ openai-compatibility: alias: "kimi-k2" # The alias used in the API. # Gemini Web settings -# gemini-web: -# # Conversation reuse: set to true to enable (default), false to disable. -# context: true -# # Maximum characters per single request to Gemini Web. Requests exceeding this -# # size split into chunks. Only the last chunk carries files and yields the final answer. -# max-chars-per-request: 1000000 -# # Disable the short continuation hint appended to intermediate chunks -# # when splitting long prompts. Default is false (hint enabled by default). -# disable-continuation-hint: false -# # Background token auto-refresh interval seconds (defaults to 540 if unset or <= 0) -# token-refresh-seconds: 540 -# # Code mode: -# # - true: enable XML wrapping hint and attach the coding-partner Gem. -# # Thought merging ( into visible content) applies to STREAMING only; -# # non-stream responses keep reasoning/thought parts separate for clients -# # that expect explicit reasoning fields. -# # - false: disable XML hint and keep separate -# code-mode: false +gemini-web: + # Conversation reuse: set to true to enable (default), false to disable. + context: true + # Maximum characters per single request to Gemini Web. Requests exceeding this + # size split into chunks. Only the last chunk carries files and yields the final answer. + max-chars-per-request: 1000000 + # Disable the short continuation hint appended to intermediate chunks + # when splitting long prompts. Default is false (hint enabled by default). + disable-continuation-hint: false + # Code mode: + # - true: enable XML wrapping hint and attach the coding-partner Gem. + # Thought merging ( into visible content) applies to STREAMING only; + # non-stream responses keep reasoning/thought parts separate for clients + # that expect explicit reasoning fields. + # - false: disable XML hint and keep separate + code-mode: false diff --git a/internal/auth/gemini/gemini-web_token.go b/internal/auth/gemini/gemini-web_token.go index a52981fc..c0f6c81e 100644 --- a/internal/auth/gemini/gemini-web_token.go +++ b/internal/auth/gemini/gemini-web_token.go @@ -8,6 +8,7 @@ import ( "fmt" "os" "path/filepath" + "time" "github.com/router-for-me/CLIProxyAPI/v6/internal/misc" log "github.com/sirupsen/logrus" @@ -18,12 +19,16 @@ type GeminiWebTokenStorage struct { Secure1PSID string `json:"secure_1psid"` Secure1PSIDTS string `json:"secure_1psidts"` Type string `json:"type"` + LastRefresh string `json:"last_refresh,omitempty"` } // SaveTokenToFile serializes the Gemini Web token storage to a JSON file. func (ts *GeminiWebTokenStorage) SaveTokenToFile(authFilePath string) error { misc.LogSavingCredentials(authFilePath) ts.Type = "gemini-web" + if ts.LastRefresh == "" { + ts.LastRefresh = time.Now().Format(time.RFC3339) + } if err := os.MkdirAll(filepath.Dir(authFilePath), 0700); err != nil { return fmt.Errorf("failed to create directory: %v", err) } diff --git a/internal/client/gemini-web/auth.go b/internal/client/gemini-web/auth.go index 65611962..05d8bd48 100644 --- a/internal/client/gemini-web/auth.go +++ b/internal/client/gemini-web/auth.go @@ -151,28 +151,13 @@ func getAccessToken(baseCookies map[string]string, proxy string, verbose bool, i return "", nil, &AuthError{Msg: "Failed to retrieve token."} } -// rotate1psidts refreshes __Secure-1PSIDTS and caches it locally. -func rotate1psidts(cookies map[string]string, proxy string, insecure bool) (string, error) { - psid, ok := cookies["__Secure-1PSID"] +// rotate1PSIDTS refreshes __Secure-1PSIDTS +func rotate1PSIDTS(cookies map[string]string, proxy string, insecure bool) (string, error) { + _, ok := cookies["__Secure-1PSID"] if !ok { return "", &AuthError{Msg: "__Secure-1PSID missing"} } - cacheDir := "temp" - _ = os.MkdirAll(cacheDir, 0o755) - cacheFile := filepath.Join(cacheDir, ".cached_1psidts_"+psid+".txt") - - if st, err := os.Stat(cacheFile); err == nil { - if time.Since(st.ModTime()) <= time.Minute { - if b, errReadFile := os.ReadFile(cacheFile); errReadFile == nil { - v := strings.TrimSpace(string(b)) - if v != "" { - return v, nil - } - } - } - } - tr := &http.Transport{} if proxy != "" { if pu, err := url.Parse(proxy); err == nil { @@ -205,7 +190,6 @@ func rotate1psidts(cookies map[string]string, proxy string, insecure bool) (stri for _, c := range resp.Cookies() { if c.Name == "__Secure-1PSIDTS" { - _ = os.WriteFile(cacheFile, []byte(c.Value), 0o644) return c.Value, nil } } diff --git a/internal/client/gemini-web/client.go b/internal/client/gemini-web/client.go index 6005cb5d..8f84eaa3 100644 --- a/internal/client/gemini-web/client.go +++ b/internal/client/gemini-web/client.go @@ -1,7 +1,6 @@ package geminiwebapi import ( - "context" "encoding/json" "errors" "fmt" @@ -10,30 +9,18 @@ import ( "net/url" "regexp" "strings" - "sync" "time" ) // GeminiClient is the async http client interface (Go port) type GeminiClient struct { - Cookies map[string]string - Proxy string - Running bool - httpClient *http.Client - AccessToken string - Timeout time.Duration - AutoClose bool - CloseDelay time.Duration - closeMu sync.Mutex - closeTimer *time.Timer - AutoRefresh bool - RefreshInterval time.Duration - rotateCancel context.CancelFunc - insecure bool - accountLabel string - // onCookiesRefreshed is an optional callback invoked after cookies - // are refreshed and the __Secure-1PSIDTS value changes. - onCookiesRefreshed func() + Cookies map[string]string + Proxy string + Running bool + httpClient *http.Client + AccessToken string + Timeout time.Duration + insecure bool } var NanoBananaModel = map[string]struct{}{ @@ -43,15 +30,11 @@ var NanoBananaModel = map[string]struct{}{ // NewGeminiClient creates a client. Pass empty strings to auto-detect via browser cookies (not implemented in Go port). func NewGeminiClient(secure1psid string, secure1psidts string, proxy string, opts ...func(*GeminiClient)) *GeminiClient { c := &GeminiClient{ - Cookies: map[string]string{}, - Proxy: proxy, - Running: false, - Timeout: 300 * time.Second, - AutoClose: false, - CloseDelay: 300 * time.Second, - AutoRefresh: true, - RefreshInterval: 540 * time.Second, - insecure: false, + Cookies: map[string]string{}, + Proxy: proxy, + Running: false, + Timeout: 300 * time.Second, + insecure: false, } if secure1psid != "" { c.Cookies["__Secure-1PSID"] = secure1psid @@ -70,21 +53,8 @@ func WithInsecureTLS(insecure bool) func(*GeminiClient) { return func(c *GeminiClient) { c.insecure = insecure } } -// WithAccountLabel sets an identifying label (e.g., token filename sans .json) -// for logging purposes. -func WithAccountLabel(label string) func(*GeminiClient) { - return func(c *GeminiClient) { c.accountLabel = label } -} - -// WithOnCookiesRefreshed registers a callback invoked when cookies are refreshed -// and the __Secure-1PSIDTS value changes. The callback runs in the background -// refresh goroutine; keep it lightweight and non-blocking. -func WithOnCookiesRefreshed(cb func()) func(*GeminiClient) { - return func(c *GeminiClient) { c.onCookiesRefreshed = cb } -} - // Init initializes the access token and http client. -func (c *GeminiClient) Init(timeoutSec float64, autoClose bool, closeDelaySec float64, autoRefresh bool, refreshIntervalSec float64, verbose bool) error { +func (c *GeminiClient) Init(timeoutSec float64, verbose bool) error { // get access token token, validCookies, err := getAccessToken(c.Cookies, c.Proxy, verbose, c.insecure) if err != nil { @@ -108,17 +78,6 @@ func (c *GeminiClient) Init(timeoutSec float64, autoClose bool, closeDelaySec fl c.Running = true c.Timeout = time.Duration(timeoutSec * float64(time.Second)) - c.AutoClose = autoClose - c.CloseDelay = time.Duration(closeDelaySec * float64(time.Second)) - if c.AutoClose { - c.resetCloseTimer() - } - - c.AutoRefresh = autoRefresh - c.RefreshInterval = time.Duration(refreshIntervalSec * float64(time.Second)) - if c.AutoRefresh { - c.startAutoRefresh() - } if verbose { Success("Gemini client initialized successfully.") } @@ -130,94 +89,6 @@ func (c *GeminiClient) Close(delaySec float64) { time.Sleep(time.Duration(delaySec * float64(time.Second))) } c.Running = false - c.closeMu.Lock() - if c.closeTimer != nil { - c.closeTimer.Stop() - c.closeTimer = nil - } - c.closeMu.Unlock() - // Transport/client closed by GC; nothing explicit - if c.rotateCancel != nil { - c.rotateCancel() - c.rotateCancel = nil - } -} - -func (c *GeminiClient) resetCloseTimer() { - c.closeMu.Lock() - defer c.closeMu.Unlock() - if c.closeTimer != nil { - c.closeTimer.Stop() - c.closeTimer = nil - } - c.closeTimer = time.AfterFunc(c.CloseDelay, func() { c.Close(0) }) -} - -func (c *GeminiClient) startAutoRefresh() { - if c.rotateCancel != nil { - c.rotateCancel() - } - ctx, cancel := context.WithCancel(context.Background()) - c.rotateCancel = cancel - go func() { - ticker := time.NewTicker(c.RefreshInterval) - defer ticker.Stop() - for { - select { - case <-ctx.Done(): - return - case <-ticker.C: - // Step 1: rotate __Secure-1PSIDTS - oldTS := "" - if c.Cookies != nil { - oldTS = c.Cookies["__Secure-1PSIDTS"] - } - newTS, err := rotate1psidts(c.Cookies, c.Proxy, c.insecure) - if err != nil { - Warning("Failed to refresh cookies. Background auto refresh canceled: %v", err) - cancel() - return - } - - // Prepare a snapshot of cookies for access token refresh - nextCookies := map[string]string{} - for k, v := range c.Cookies { - nextCookies[k] = v - } - if newTS != "" { - nextCookies["__Secure-1PSIDTS"] = newTS - } - - // Step 2: refresh access token using updated cookies - token, validCookies, err := getAccessToken(nextCookies, c.Proxy, false, c.insecure) - if err != nil { - // Apply rotated cookies even if token refresh fails, then retry on next tick - c.Cookies = nextCookies - Warning("Failed to refresh access token after cookie rotation: %v", err) - } else { - c.AccessToken = token - c.Cookies = validCookies - } - - if c.accountLabel != "" { - DebugRaw("Cookies refreshed [%s]. New __Secure-1PSIDTS: %s", c.accountLabel, MaskToken28(nextCookies["__Secure-1PSIDTS"])) - } else { - DebugRaw("Cookies refreshed. New __Secure-1PSIDTS: %s", MaskToken28(nextCookies["__Secure-1PSIDTS"])) - } - - // Trigger persistence only when TS actually changes - if c.onCookiesRefreshed != nil { - currentTS := "" - if c.Cookies != nil { - currentTS = c.Cookies["__Secure-1PSIDTS"] - } - if currentTS != "" && currentTS != oldTS { - c.onCookiesRefreshed() - } - } - } - } - }() } // ensureRunning mirrors the Python decorator behavior and retries on APIError. @@ -225,7 +96,15 @@ func (c *GeminiClient) ensureRunning() error { if c.Running { return nil } - return c.Init(float64(c.Timeout/time.Second), c.AutoClose, float64(c.CloseDelay/time.Second), c.AutoRefresh, float64(c.RefreshInterval/time.Second), false) + return c.Init(float64(c.Timeout/time.Second), false) +} + +// RotateTS performs a RotateCookies request and returns the new __Secure-1PSIDTS value (if any). +func (c *GeminiClient) RotateTS() (string, error) { + if c == nil { + return "", fmt.Errorf("gemini web client is nil") + } + return rotate1PSIDTS(c.Cookies, c.Proxy, c.insecure) } // GenerateContent sends a prompt (with optional files) and parses the response into ModelOutput. @@ -237,9 +116,6 @@ func (c *GeminiClient) GenerateContent(prompt string, files []string, model Mode if err := c.ensureRunning(); err != nil { return empty, err } - if c.AutoClose { - c.resetCloseTimer() - } // Retry wrapper similar to decorator (retry=2) retries := 2 diff --git a/internal/config/config.go b/internal/config/config.go index 8f413362..6b543a6b 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -120,10 +120,6 @@ type GeminiWebConfig struct { // DisableContinuationHint, when true, disables the continuation hint for split prompts. // The hint is enabled by default. DisableContinuationHint bool `yaml:"disable-continuation-hint,omitempty" json:"disable-continuation-hint,omitempty"` - - // TokenRefreshSeconds controls the background cookie auto-refresh interval in seconds. - // When unset or <= 0, defaults to 540 seconds. - TokenRefreshSeconds int `yaml:"token-refresh-seconds" json:"token-refresh-seconds"` } // RemoteManagement holds management API configuration under 'remote-management'. diff --git a/internal/runtime/executor/gemini_web_state.go b/internal/runtime/executor/gemini_web_state.go index 5ce4770e..2b10a3f0 100644 --- a/internal/runtime/executor/gemini_web_state.go +++ b/internal/runtime/executor/gemini_web_state.go @@ -5,8 +5,6 @@ import ( "context" "errors" "fmt" - "net/http" - "net/url" "path/filepath" "strings" "sync" @@ -18,15 +16,13 @@ import ( "github.com/router-for-me/CLIProxyAPI/v6/internal/constant" "github.com/router-for-me/CLIProxyAPI/v6/internal/interfaces" "github.com/router-for-me/CLIProxyAPI/v6/internal/translator/translator" - cliproxyauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth" cliproxyexecutor "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/executor" "github.com/tidwall/gjson" "github.com/tidwall/sjson" ) const ( - geminiWebDefaultTimeoutSec = 300 - geminiWebDefaultRefreshIntervalSec = 540 + geminiWebDefaultTimeoutSec = 300 ) type geminiWebState struct { @@ -48,15 +44,7 @@ type geminiWebState struct { convData map[string]geminiwebapi.ConversationRecord convIndex map[string]string - refreshInterval time.Duration - lastRefresh time.Time -} - -func (s *geminiWebState) RefreshLead() time.Duration { - if s.refreshInterval > 0 { - return s.refreshInterval - } - return 9 * time.Minute + lastRefresh time.Time } func newGeminiWebState(cfg *config.Config, token *gemini.GeminiWebTokenStorage, storagePath string) *geminiWebState { @@ -84,11 +72,6 @@ func newGeminiWebState(cfg *config.Config, token *gemini.GeminiWebTokenStorage, state.accountID = suffix } state.loadConversationCaches() - intervalSec := geminiWebDefaultRefreshIntervalSec - if cfg != nil && cfg.GeminiWeb.TokenRefreshSeconds > 0 { - intervalSec = cfg.GeminiWeb.TokenRefreshSeconds - } - state.refreshInterval = time.Duration(intervalSec) * time.Second return state } @@ -136,15 +119,9 @@ func (s *geminiWebState) ensureClient() error { s.token.Secure1PSID, s.token.Secure1PSIDTS, proxyURL, - geminiwebapi.WithOnCookiesRefreshed(s.onCookiesRefreshed), ) timeout := geminiWebDefaultTimeoutSec - refresh := geminiWebDefaultRefreshIntervalSec - if s.cfg != nil && s.cfg.GeminiWeb.TokenRefreshSeconds > 0 { - refresh = s.cfg.GeminiWeb.TokenRefreshSeconds - } - // Use explicit refresh; background auto-refresh disabled here - if err := s.client.Init(float64(timeout), false, 300, false, float64(refresh), false); err != nil { + if err := s.client.Init(float64(timeout), false); err != nil { s.client = nil return err } @@ -162,38 +139,25 @@ func (s *geminiWebState) refresh(ctx context.Context) error { s.token.Secure1PSID, s.token.Secure1PSIDTS, proxyURL, - geminiwebapi.WithOnCookiesRefreshed(s.onCookiesRefreshed), ) timeout := geminiWebDefaultTimeoutSec - refresh := geminiWebDefaultRefreshIntervalSec - if s.cfg != nil && s.cfg.GeminiWeb.TokenRefreshSeconds > 0 { - refresh = s.cfg.GeminiWeb.TokenRefreshSeconds - } - // Use explicit refresh; background auto-refresh disabled here - if err := s.client.Init(float64(timeout), false, 300, false, float64(refresh), false); err != nil { + if err := s.client.Init(float64(timeout), false); err != nil { return err } // Attempt rotation proactively to persist new TS sooner - _ = s.tryRotatePSIDTS(proxyURL) + if newTS, err := s.client.RotateTS(); err == nil && newTS != "" && newTS != s.token.Secure1PSIDTS { + s.tokenMu.Lock() + s.token.Secure1PSIDTS = newTS + s.tokenDirty = true + if s.client != nil && s.client.Cookies != nil { + s.client.Cookies["__Secure-1PSIDTS"] = newTS + } + s.tokenMu.Unlock() + } s.lastRefresh = time.Now() return nil } -func (s *geminiWebState) onCookiesRefreshed() { - s.tokenMu.Lock() - defer s.tokenMu.Unlock() - if s.client == nil || s.client.Cookies == nil { - return - } - if v := s.client.Cookies["__Secure-1PSID"]; v != "" { - s.token.Secure1PSID = v - } - if v := s.client.Cookies["__Secure-1PSIDTS"]; v != "" { - s.token.Secure1PSIDTS = v - } - s.tokenDirty = true -} - func (s *geminiWebState) tokenSnapshot() *gemini.GeminiWebTokenStorage { s.tokenMu.Lock() defer s.tokenMu.Unlock() @@ -201,70 +165,6 @@ func (s *geminiWebState) tokenSnapshot() *gemini.GeminiWebTokenStorage { return &c } -// tryRotatePSIDTS performs a best-effort rotation of __Secure-1PSIDTS using -// the public RotateCookies endpoint. On success it updates both the in-memory -// token and the live client's cookie jar so that subsequent requests adopt the -// new value. Any error is ignored by the caller to avoid disrupting refresh. -func (s *geminiWebState) tryRotatePSIDTS(proxy string) error { - cookies := map[string]string{ - "__Secure-1PSID": s.token.Secure1PSID, - "__Secure-1PSIDTS": s.token.Secure1PSIDTS, - } - - tr := &http.Transport{} - if proxy != "" { - if pu, err := url.Parse(proxy); err == nil { - tr.Proxy = http.ProxyURL(pu) - } - } - client := &http.Client{Transport: tr, Timeout: 60 * time.Second} - - req, _ := http.NewRequest(http.MethodPost, geminiwebapi.EndpointRotateCookies, bytes.NewReader([]byte("[000,\"-0000000000000000000\"]"))) - for k, vs := range geminiwebapi.HeadersRotateCookies { - for _, v := range vs { - req.Header.Add(k, v) - } - } - for k, v := range cookies { - req.AddCookie(&http.Cookie{Name: k, Value: v}) - } - - resp, err := client.Do(req) - if err != nil { - return err - } - defer func() { _ = resp.Body.Close() }() - if resp.StatusCode >= 200 && resp.StatusCode < 300 { - for _, c := range resp.Cookies() { - if c == nil { - continue - } - if c.Name == "__Secure-1PSIDTS" && c.Value != "" && c.Value != s.token.Secure1PSIDTS { - s.tokenMu.Lock() - s.token.Secure1PSIDTS = c.Value - s.tokenDirty = true - if s.client != nil && s.client.Cookies != nil { - s.client.Cookies["__Secure-1PSIDTS"] = c.Value - } - s.tokenMu.Unlock() - break - } - } - } - return nil -} - -func (s *geminiWebState) ShouldRefresh(now time.Time, _ *cliproxyauth.Auth) bool { - interval := s.refreshInterval - if interval <= 0 { - interval = time.Duration(geminiWebDefaultRefreshIntervalSec) * time.Second - } - if s.lastRefresh.IsZero() { - return true - } - return now.Sub(s.lastRefresh) >= interval -} - type geminiWebPrepared struct { handlerType string translatedRaw []byte diff --git a/internal/watcher/watcher.go b/internal/watcher/watcher.go index 7d1f43fd..7fbe869f 100644 --- a/internal/watcher/watcher.go +++ b/internal/watcher/watcher.go @@ -461,9 +461,6 @@ func (w *Watcher) reloadConfig() bool { if oldConfig.GeminiWeb.DisableContinuationHint != newConfig.GeminiWeb.DisableContinuationHint { log.Debugf(" gemini-web.disable-continuation-hint: %t -> %t", oldConfig.GeminiWeb.DisableContinuationHint, newConfig.GeminiWeb.DisableContinuationHint) } - if oldConfig.GeminiWeb.TokenRefreshSeconds != newConfig.GeminiWeb.TokenRefreshSeconds { - log.Debugf(" gemini-web.token-refresh-seconds: %d -> %d", oldConfig.GeminiWeb.TokenRefreshSeconds, newConfig.GeminiWeb.TokenRefreshSeconds) - } if oldConfig.GeminiWeb.CodeMode != newConfig.GeminiWeb.CodeMode { log.Debugf(" gemini-web.code-mode: %t -> %t", oldConfig.GeminiWeb.CodeMode, newConfig.GeminiWeb.CodeMode) } diff --git a/sdk/auth/gemini-web.go b/sdk/auth/gemini-web.go index bb5c24f4..992648f2 100644 --- a/sdk/auth/gemini-web.go +++ b/sdk/auth/gemini-web.go @@ -24,6 +24,6 @@ func (a *GeminiWebAuthenticator) Login(ctx context.Context, cfg *config.Config, } func (a *GeminiWebAuthenticator) RefreshLead() *time.Duration { - d := 9 * time.Minute + d := 3 * time.Hour return &d } diff --git a/sdk/cliproxy/service.go b/sdk/cliproxy/service.go index e5546a52..9dbeaedc 100644 --- a/sdk/cliproxy/service.go +++ b/sdk/cliproxy/service.go @@ -322,9 +322,6 @@ func (s *Service) Run(ctx context.Context) error { // Prefer core auth manager auto refresh if available. if s.coreManager != nil { interval := 15 * time.Minute - if sec := s.cfg.GeminiWeb.TokenRefreshSeconds; sec > 0 { - interval = time.Duration(sec) * time.Second - } s.coreManager.StartAutoRefresh(context.Background(), interval) log.Infof("core auth auto-refresh started (interval=%s)", interval) }