Skip to content

fix(gemini): fetch model list via native v1beta/models endpoint - #2615

Merged
seefs001 merged 2 commits into
QuantumNous:mainfrom
RedwindA:feat/GeminiNativeFetchModels
Jan 9, 2026
Merged

fix(gemini): fetch model list via native v1beta/models endpoint#2615
seefs001 merged 2 commits into
QuantumNous:mainfrom
RedwindA:feat/GeminiNativeFetchModels

Conversation

@RedwindA

@RedwindA RedwindA commented Jan 9, 2026

Copy link
Copy Markdown
Contributor

PR 类型

  • Bug 修复
  • 新功能
  • 文档更新
  • 其他

PR 是否包含破坏性更新?

PR 描述

close #2612

本次 PR 将 Gemini 类型渠道获取模型列表的请求从 OpenAI 兼容路径切换为 Gemini 原生路径(/v1beta/models),并使用 x-goog-api-key 进行鉴权,以兼容部分仅实现 Gemini 原生接口、未实现 OpenAI 兼容接口的第三方 Gemini 格式渠道。

实现细节:

  • controller/channel.go:在 FetchUpstreamModels / FetchModels 中对 Gemini 渠道做单独处理,调用 Gemini 原生模型获取逻辑;FetchUpstreamModels 额外支持多 Key 渠道优
    先取启用 Key,并传入渠道 proxy 配置。
  • relay/channel/gemini/relay-gemini.go:新增 FetchGeminiModels,请求 GET /v1beta/models 并支持 nextPageToken 分页、超时控制与错误回传。

验证方式:

  • 配置一个 Gemini 类型渠道(含第三方 Gemini 格式渠道),在渠道管理中执行“获取上游模型”,确认能正常返回模型列表。

Summary by CodeRabbit

New Features

  • Added Gemini model fetching capability with pagination support to retrieve available models
  • Enhanced model retrieval infrastructure with proxy configuration options for Gemini requests

✏️ Tip: You can customize this high-level summary in your review settings.

Use the native Gemini Models API (/v1beta/models) instead of the OpenAI-compatible
path when listing models for Gemini channels, improving compatibility with
third-party Gemini-format providers that don't implement OpenAI routes.

- Add paginated model listing with timeout and optional proxy support
- Select an enabled key for multi-key Gemini channels
@coderabbitai

coderabbitai Bot commented Jan 9, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Added dedicated Gemini model fetching via native Gemini API (/v1beta/models) with pagination support, replacing the generic OpenAI-compatible endpoint. This enables proper integration with CLIProxyAPI which only supports the native Gemini interface.

Changes

Cohort / File(s) Summary
Controller Integration
controller/channel.go
Modified FetchUpstreamModels and FetchModels to route Gemini requests to dedicated model-fetching logic instead of generic HTTP flow; added import for Gemini relay package
Gemini Model Fetching
relay/channel/gemini/relay-gemini.go
Introduced GeminiModelsResponse struct and FetchGeminiModels function to handle paginated model retrieval from Gemini API with proxy support, timeouts, and error handling

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Controller
    participant GeminiRelay
    participant GeminiAPI
    
    Client->>Controller: FetchModels(type=Gemini)
    Controller->>GeminiRelay: FetchGeminiModels(baseURL, apiKey, proxyURL)
    loop Pagination Loop (until NextPageToken empty or maxPages reached)
        GeminiRelay->>GeminiAPI: HTTP GET /v1beta/models?pageSize=N&pageToken=T
        GeminiAPI-->>GeminiRelay: GeminiModelsResponse{Models, NextPageToken}
        GeminiRelay->>GeminiRelay: Accumulate model names (trim "models/" prefix)
    end
    GeminiRelay-->>Controller: []string (model names) or error
    Controller-->>Client: models list or error response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A rabbit hops through Gemini's gate,
No more the OpenAI way—
With pagination's steady pace,
Native models light the way! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: switching to Gemini's native v1beta/models endpoint for fetching model lists, which is the core fix described in the PR objectives.
Linked Issues check ✅ Passed The PR implements all key objectives from issue #2612: uses native /v1beta/models endpoint instead of /v1beta/openai/models, adds pagination support, includes timeout control, and enables Gemini channels (including CLIProxyAPI-based) to retrieve model lists successfully.
Out of Scope Changes check ✅ Passed All changes in the PR are directly scoped to implementing the Gemini native endpoint model fetching: controller updates for Gemini channel handling, new relay package with FetchGeminiModels implementation, and go.mod updates for dependencies.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
controller/channel.go (1)

354-356: Dead code: Gemini branch is now unreachable.

Since Gemini channels return early at line 290, this code path will never execute for ChannelTypeGemini. The models/ prefix trimming is now performed in FetchGeminiModels. Consider removing this dead code.

🧹 Suggested cleanup
 	var ids []string
 	for _, model := range result.Data {
-		id := model.ID
-		if channel.Type == constant.ChannelTypeGemini {
-			id = strings.TrimPrefix(id, "models/")
-		}
-		ids = append(ids, id)
+		ids = append(ids, model.ID)
 	}
relay/channel/gemini/relay-gemini.go (2)

1386-1388: Consider URL-encoding the pageToken.

The nextPageToken is appended directly without URL encoding. While Gemini's tokens are typically URL-safe, encoding ensures correctness if the token contains characters like &, =, or +.

♻️ Suggested fix
+	"net/url"
 		url := fmt.Sprintf("%s/v1beta/models", baseURL)
 		if nextPageToken != "" {
-			url = fmt.Sprintf("%s?pageToken=%s", url, nextPageToken)
+			url = fmt.Sprintf("%s?pageToken=%s", url, url.QueryEscape(nextPageToken))
 		}

1424-1431: Consider filtering empty model names.

If model.Name is exactly "models/" or an empty string, the result after TrimPrefix would be empty and still added to the list.

♻️ Suggested fix
 		for _, model := range modelsResponse.Models {
 			modelNameValue, ok := model.Name.(string)
 			if !ok {
 				continue
 			}
 			modelName := strings.TrimPrefix(modelNameValue, "models/")
+			if modelName == "" {
+				continue
+			}
 			allModels = append(allModels, modelName)
 		}
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9301263 and 07e77b3.

📒 Files selected for processing (2)
  • controller/channel.go
  • relay/channel/gemini/relay-gemini.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: RedwindA
Repo: QuantumNous/new-api PR: 1537
File: relay/gemini_handler.go:330-342
Timestamp: 2025-08-08T17:12:43.157Z
Learning: In the new-api repository, the `GeminiEmbeddingHandler` function in `relay/gemini_handler.go` is designed specifically for native Gemini embedding requests and therefore does not require the `ConvertGeminiRequest` step that is used in the chat handler. The embedding requests are already in the native Gemini format and don't need conversion.
Learnt from: antecanis8
Repo: QuantumNous/new-api PR: 1500
File: relay/channel/gemini/adaptor.go:0-0
Timestamp: 2025-08-04T14:36:34.528Z
Learning: All currently serviced Gemini embedding models support the outputDimensionality parameter, not just specific models like text-embedding-004.
Learnt from: antecanis8
Repo: QuantumNous/new-api PR: 1500
File: relay/channel/gemini/adaptor.go:0-0
Timestamp: 2025-08-04T14:36:34.528Z
Learning: In the Gemini API batchEmbedContents endpoint, each request item in the "requests" array should include its own "model" field, as shown in the official documentation at https://ai.google.dev/api/embeddings?hl=zh-cn#method:-models.batchembedcontents. The model field is not a top-level parameter.
📚 Learning: 2025-08-08T17:12:43.157Z
Learnt from: RedwindA
Repo: QuantumNous/new-api PR: 1537
File: relay/gemini_handler.go:330-342
Timestamp: 2025-08-08T17:12:43.157Z
Learning: In the new-api repository, the `GeminiEmbeddingHandler` function in `relay/gemini_handler.go` is designed specifically for native Gemini embedding requests and therefore does not require the `ConvertGeminiRequest` step that is used in the chat handler. The embedding requests are already in the native Gemini format and don't need conversion.

Applied to files:

  • relay/channel/gemini/relay-gemini.go
  • controller/channel.go
📚 Learning: 2025-06-21T03:37:41.726Z
Learnt from: 9Ninety
Repo: QuantumNous/new-api PR: 1273
File: relay/channel/gemini/relay-gemini.go:97-116
Timestamp: 2025-06-21T03:37:41.726Z
Learning: In relay/channel/gemini/relay-gemini.go, the thinking budget calculation logic (including the MaxOutputTokens multiplication) was introduced in PR #1247. PR #1273 focused specifically on decoupling the thoughts summary feature from thinking budget settings and did not modify the existing thinking budget behavior.

Applied to files:

  • relay/channel/gemini/relay-gemini.go
  • controller/channel.go
🧬 Code graph analysis (1)
relay/channel/gemini/relay-gemini.go (3)
dto/pricing.go (1)
  • GeminiModel (21-35)
service/http_client.go (1)
  • GetHttpClientWithProxy (63-68)
common/json.go (1)
  • Unmarshal (9-11)
🔇 Additional comments (7)
controller/channel.go (3)

14-14: LGTM!

Import added correctly to support the new Gemini-specific model fetching.


264-291: LGTM!

The Gemini-specific handling correctly:

  • Retrieves an enabled key for multi-key channels
  • Passes the channel proxy configuration
  • Follows error handling patterns consistent with Ollama

1102-1117: LGTM!

The Gemini handling in FetchModels correctly uses the native endpoint. Passing an empty proxy URL is appropriate here since this function tests channel configurations before they are saved (no channel object available for proxy settings).

relay/channel/gemini/relay-gemini.go (4)

4-4: LGTM!

Imports for context and time are required for the new timeout handling in FetchGeminiModels.

Also applies to: 12-12


1369-1372: LGTM!

The struct correctly models the Gemini API response and properly references dto.GeminiModel for type consistency across the codebase.


1390-1417: LGTM!

The resource cleanup is correctly implemented:

  • Context timeout of 30 seconds per page is appropriate
  • cancel() is called on all exit paths
  • Response body is closed before context cancellation

1374-1440: Good implementation of paginated model fetching.

The function correctly implements:

  • Native Gemini API authentication (x-goog-api-key)
  • Pagination with safety limit
  • Proxy support via existing service
  • Timeout handling per request
  • Consistent error messaging

@seefs001

seefs001 commented Jan 9, 2026

Copy link
Copy Markdown
Collaborator

我感觉有俩地方可以再改一下。
1.请求对端接口30s固定,这个不应该硬编码吧,有个RelayTimeout
2.针对接入的Gemini渠道是NewAPI上游的情况,这个PR没有实现模型列表请求的Route,这样会让用newapi上游的都404的,这个接口还要负责将其他的模型列表也组装成Gemini这个接口的格式。

@RedwindA

RedwindA commented Jan 9, 2026

Copy link
Copy Markdown
Contributor Author

对于第一点,RelayTimeout一般是个人为设定的很大的值或者默认根本不超时,对于模型列表接口来说,这个30s感觉都多了;

第二点,这个PR没有影响现在的实现吧,newapi现在已经会组装gemini原生格式的模型列表。测试了一下是可以工作的
图片
图片

图片 图片

@seefs001

seefs001 commented Jan 9, 2026

Copy link
Copy Markdown
Collaborator

对于第一点,RelayTimeout一般是个人为设定的很大的值或者默认根本不超时,对于模型列表接口来说,这个30s感觉都多了;

第二点,这个PR没有影响现在的实现吧,newapi现在已经会组装gemini原生格式的模型列表。测试了一下是可以工作的

图片 图片 图片 图片

草你不说我都没发现,这个接口之前有实现过

@seefs001

seefs001 commented Jan 9, 2026

Copy link
Copy Markdown
Collaborator

对于第一点,RelayTimeout一般是个人为设定的很大的值或者默认根本不超时,对于模型列表接口来说,这个30s感觉都多了;

第二点,这个PR没有影响现在的实现吧,newapi现在已经会组装gemini原生格式的模型列表。测试了一下是可以工作的 图片 图片

图片 图片

这个30s回头得看一下怎么定一下合适,因为还有别的类似的地方,仅仅只是调用接口获取数据,没有对话生成视频生成的耗时长的逻辑,应该是得定一下http client的默认的时间

@seefs001
seefs001 merged commit 1a5c8f3 into QuantumNous:main Jan 9, 2026
1 check passed
ennnnny pushed a commit to ennnnny/new-api that referenced this pull request Mar 17, 2026
…tchModels

fix(gemini): fetch model list via native v1beta/models endpoint
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

基于 CLIProxyAPI 的 Gemini 渠道无法获取模型列表

2 participants