fix(gemini): fetch model list via native v1beta/models endpoint - #2615
Conversation
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
WalkthroughAdded dedicated Gemini model fetching via native Gemini API ( Changes
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
There was a problem hiding this comment.
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. Themodels/prefix trimming is now performed inFetchGeminiModels. 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
nextPageTokenis 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.Nameis exactly"models/"or an empty string, the result afterTrimPrefixwould 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
📒 Files selected for processing (2)
controller/channel.gorelay/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.gocontroller/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.gocontroller/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
FetchModelscorrectly 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
contextandtimeare required for the new timeout handling inFetchGeminiModels.Also applies to: 12-12
1369-1372: LGTM!The struct correctly models the Gemini API response and properly references
dto.GeminiModelfor 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
|
我感觉有俩地方可以再改一下。 |
…tchModels fix(gemini): fetch model list via native v1beta/models endpoint








PR 类型
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分页、超时控制与错误回传。验证方式:
Summary by CodeRabbit
New Features
✏️ Tip: You can customize this high-level summary in your review settings.