Skip to content

feat: 新增 /v1/models 端点,聚合返回用户可用模型列表#517

Merged
ding113 merged 3 commits intoding113:devfrom
NieiR:feat/models-provider-decision
Jan 3, 2026
Merged

feat: 新增 /v1/models 端点,聚合返回用户可用模型列表#517
ding113 merged 3 commits intoding113:devfrom
NieiR:feat/models-provider-decision

Conversation

@NieiR
Copy link
Contributor

@NieiR NieiR commented Jan 3, 2026

Summary

新增 /v1/models 系列端点,根据用户的 provider 权限和客户端格式返回可用模型列表。

新增端点

端点 说明
GET /v1/models 聚合模型列表(自动检测格式)
GET /v1/responses/models 仅返回 codex 类型
GET /v1/chat/completions/models 仅返回 openai-compatible 类型
GET /v1beta/models Gemini 格式支持

Problem

客户端通常需要通过 /v1/models 端点查询可用模型列表,但之前系统不支持此功能。用户无法:

  • 在客户端应用中动态获取可用模型
  • 根据自己的 provider 权限查看真实可用的模型
  • 通过标准 OpenAI/Claude/Gemini API 格式查询模型

Related Issues:

Solution

实现完整的 /v1/models 端点族,支持多种客户端格式和 provider 类型决策。

模型获取策略

#482 的区别

方面 #482 (已关闭) 本 PR
实现方式 在 proxy 层添加 models-list 格式 在路由层添加独立端点处理函数
Provider 决策 通过现有 proxy 流程 新增 selectProviderByType() 按类型独立决策
Gemini 支持 遇到问题导致关闭 完整支持 /v1beta/models
格式覆盖 支持 header/query 覆盖 (x-cch-api-type, api_type)

技术实现

  • 新增 selectProviderByType() 按类型独立决策 provider
  • 抽取 extractApiKeyFromHeaders() 供非 Guard 流程复用
  • 统一上游请求配置(UPSTREAM_CONFIGS),消除重复代码
  • 支持 header/query 覆盖格式 (x-cch-api-type, api_type)

Changes

Core Changes

  • src/app/v1/_lib/models/available-models.ts (新增 501 行):

    • handleAvailableModels - 聚合式模型列表处理
    • handleCodexModels - 仅返回 codex 类型
    • handleOpenAICompatibleModels - 仅返回 openai-compatible 类型
    • UPSTREAM_CONFIGS - 统一的上游 API 请求配置
    • 格式检测与响应格式化(OpenAI/Anthropic/Gemini)
  • src/app/v1/_lib/proxy/provider-selector.ts (+128):

    • selectProviderByType() - 按 providerType 独立决策
    • 支持对不同 providerType 分别执行完整决策链(分组过滤 → 健康检查 → 优先级 → 加权随机)
  • src/app/v1/_lib/proxy/auth-guard.ts (+37):

    • extractApiKeyFromHeaders() - 抽取为独立函数供复用
    • 支持 Bearer、x-api-key、x-goog-api-key 三种认证方式

Supporting Changes

  • src/app/v1/[...route]/route.ts (+11): 注册 4 个新端点
  • src/app/v1beta/[...route]/route.ts (+4): 注册 Gemini /v1beta/models 端点
  • CHANGELOG.md (+27): 更新 v0.3.40 变更日志

Breaking Changes

无。纯新增功能,0 deletions。

Testing

Automated Tests

  • bun run lint 通过
  • bun run typecheck 通过

Manual Testing

  • 测试 /v1/models 端点自动检测格式(OpenAI/Claude/Gemini)
  • 测试 /v1/responses/models 仅返回 codex 模型
  • 测试 /v1/chat/completions/models 仅返回 openai-compatible 模型
  • 测试 /v1beta/models 返回 Gemini 格式
  • 验证 provider 的 allowedModels 配置优先级
  • 验证上游 API 动态获取回退逻辑
  • 验证 header/query 格式覆盖功能

Checklist

  • Base branch set to dev
  • All status checks passed locally
  • No conflicts with main
  • Code follows project conventions
  • Self-review completed

Description enhanced by Claude AI

Summary by CodeRabbit

发布说明

  • 新增功能

    • 添加了模型列表查询接口,支持获取可用模型列表
    • 为多个API端点新增模型查询功能,支持不同客户端格式
  • 文档

    • 更新了变更日志,记录了新增功能、优化项和修复内容

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

github-actions bot and others added 2 commits January 1, 2026 16:49
根据用户的 provider 权限和客户端格式返回可用模型:

- GET /v1/models - 聚合模型列表(自动检测格式)
- GET /v1/responses/models - 仅返回 codex 类型
- GET /v1/chat/completions/models - 仅返回 openai-compatible 类型
- GET /v1beta/models - Gemini 格式支持

模型获取策略:
- 优先返回 provider 配置的 allowedModels 列表
- 若未配置则实时查询上游 API

技术实现:
- 新增 selectProviderByType() 按类型独立决策 provider
- 抽取 extractApiKeyFromHeaders() 供非 Guard 流程复用
- 统一上游请求配置(UPSTREAM_CONFIGS),消除重复代码
- 支持 header/query 覆盖格式 (x-cch-api-type, api_type)
@coderabbitai
Copy link

coderabbitai bot commented Jan 3, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

新增模型列表功能与相关路由,加入模型聚合与格式化的服务端实现、API 密钥提取工具与按类型的提供商选择器,并更新 CHANGELOG 文档;无其他业务逻辑删除,仅新增与路由/文档改动。

Changes

Cohort / File(s) 变更摘要
日志更新
CHANGELOG.md
新增 v0.3.40 发布记录,包含 新增 / 优化 / 修复 / 其他 条目(仅文档内容)
模型可用性实现
src/app/v1/_lib/models/available-models.ts
新增完整可用模型聚合实现:鉴权、客户端目标格式检测/覆盖、按提供商上游抓取与解析、模型去重/排序、三种客户端格式响应编码;导出 handleAvailableModelshandleCodexModelshandleOpenAICompatibleModels
认证助手
src/app/v1/_lib/proxy/auth-guard.ts
新增导出函数 extractApiKeyFromHeaders,支持从 Authorizationx-api-keyx-goog-api-key 提取 API Key
提供商选择器
src/app/v1/_lib/proxy/provider-selector.ts
新增静态方法 ProxyProviderResolver.selectProviderByType(...) 实现按提供商类型过滤、健康检查、优先级与成本权重选择;同时导出 checkProviderGroupMatch
v1 路由
src/app/v1/[...route]/route.ts
注册新的 GET 路由:/models/responses/models/chat/completions/models/chat/models,并引入相应处理器(保留原有 /chat/completions/responses 路由)
v1beta 路由
src/app/v1beta/[...route]/route.ts
为 v1beta 注册 GET /models 路由并导入模型处理器;导出多种 HTTP 方法常量(GET/POST/PUT/DELETE/PATCH/OPTIONS/HEAD)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 我是代码里的小兔子,轻蹦又轻嗅,
新增模型排队来报到,路由门前守候,
提取密钥把门开,提供商们列队走,
聚合去重整齐摆,格式三样送到口,
小兔挥爪说声好,版本日志也记首。 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR标题清晰地总结了主要变更:新增 /v1/models 端点并聚合返回用户可用模型列表,与实际代码改动(新增多个模型查询端点、实现模型聚合与格式化逻辑)完全对应。
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Cache: Disabled due to Reviews > Disable Cache setting

📥 Commits

Reviewing files that changed from the base of the PR and between e592f1b and 16ee53f.

📒 Files selected for processing (1)
  • src/app/v1/_lib/models/available-models.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/app/v1/_lib/models/available-models.ts (6)
src/types/provider.ts (1)
  • Provider (20-113)
src/app/v1/_lib/proxy/auth-guard.ts (1)
  • extractApiKeyFromHeaders (205-232)
src/app/v1/_lib/proxy/format-mapper.ts (1)
  • ClientFormat (29-29)
scripts/sync-settings-keys.js (1)
  • p (102-102)
src/lib/logger.ts (1)
  • logger (168-187)
src/app/v1/_lib/proxy/provider-selector.ts (1)
  • ProxyProviderResolver (211-1124)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: 🌐 API Tests
  • GitHub Check: Docker Build Test
🔇 Additional comments (6)
src/app/v1/_lib/models/available-models.ts (6)

32-70: 认证实现合理,逻辑清晰。

认证流程正确提取 API Key、验证用户状态(禁用、过期),并通过统一的错误格式返回 401 响应。复用 extractApiKeyFromHeaders 也避免了逻辑重复。


75-136: 格式检测逻辑合理。

通过 header 和 query 参数检测客户端格式覆盖,支持多种格式(OpenAI / Anthropic / Gemini),逻辑清晰且灵活。inferOwner 使用前缀匹配推断模型所有者,简单有效。


192-193: 已修复:Gemini API 密钥日志泄露问题。

代码现在正确地将 URL 中的 key 参数替换为 [key=REDACTED] 后再记录日志,有效防止了敏感信息泄露。


390-401: 已修复:模型获取已并行化,提升性能。

代码现在使用 Promise.all 并行获取所有 provider 的模型列表(lines 390-392),并正确实现去重逻辑(lines 394-401)。这显著降低了聚合多个 provider 时的总延迟,解决了之前串行执行累加延迟的问题。


259-276: Provider 类型映射逻辑清晰。

getProviderTypesForFormat 正确地将客户端格式映射到相应的 provider 类型列表,支持多种格式聚合(如 openai 格式聚合 codexopenai-compatible)。使用 exhaustive check 确保所有 case 被覆盖。


418-505: 处理器实现合理,结构清晰。

使用工厂函数 createFixedProviderTypesModelsHandler 为固定 provider 类型创建处理器,避免代码重复。主处理器 handleAvailableModels 正确地整合了认证、格式检测、模型获取和响应格式化。错误处理模式(throw c.json 然后 catch 并返回 Response)保持一致。


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

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @NieiR, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

此拉取请求引入了一系列新的 /v1/models 端点,旨在为用户提供一个聚合的、根据其权限和客户端格式动态返回可用模型列表的功能。这极大地提升了系统的灵活性和可扩展性,允许根据不同的 API 客户端(如 OpenAI、Anthropic、Gemini)和用户配置,智能地展示和管理可用的 AI 模型,同时优化了内部的供应商选择和 API Key 提取逻辑。

Highlights

  • 新增 /v1/models 系列端点: 引入了 /v1/models/v1/responses/models/v1/chat/completions/models/v1beta/models 等新端点,用于根据用户的供应商权限和客户端格式聚合并返回可用的模型列表。
  • 模型获取策略优化: 实现了智能模型获取策略,优先返回供应商配置的 allowedModels 列表,若未配置则实时查询上游 API,确保模型列表的准确性和时效性。
  • 供应商选择逻辑增强: 在 ProxyProviderResolver 中新增了 selectProviderByType() 方法,允许系统根据特定的供应商类型独立决策最优供应商,这对于处理不同模型格式(如 codex 和 openai-compatible)的聚合至关重要。
  • API Key 提取逻辑复用: 将 extractApiKeyFromHeaders() 函数从认证守卫中抽取出来并导出,使其可以在非认证守卫流程中复用,提高了代码的模块化和可维护性。
  • 统一上游请求配置: 通过 UPSTREAM_CONFIGS 统一了各供应商的上游请求配置,消除了重复代码,并支持通过 x-cch-api-typeapi_type 等 header/query 参数覆盖客户端格式。
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions github-actions bot added the size/L Large PR (< 1000 lines) label Jan 3, 2026
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

这个 PR 引入了一个新的 /v1/models 端点来聚合可用的模型列表,这是一个很棒的功能。实现结构良好,特别是使用 UPSTREAM_CONFIGS 来统一上游 API 调用和使用工厂函数创建处理器。代码通常很清晰,并遵循了现有的模式。

我的审查主要集中在几个关键的改进领域:

  1. 性能: 通过并行运行供应商选择和模型获取,可以显著优化模型聚合逻辑。
  2. 健壮性: 可以更安全地解析上游 API 响应,以防止因意外数据格式而导致的潜在运行时错误。
  3. 诊断: 改进决策上下文日志的详细程度将有助于未来的调试。

总的来说,这是一个坚实的贡献。解决这些问题将使新功能性能更高、更具弹性。

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Additional Comments (1)

  1. src/app/v1/_lib/models/available-models.ts, line 166 (link)

    logic: API credentials exposed in URL query string. Query parameters appear in server logs, proxy logs, and browser history. Move authentication to headers using x-goog-api-key header instead of URL parameter.

6 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

github-actions[bot]

This comment was marked as outdated.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Cache: Disabled due to Reviews > Disable Cache setting

📥 Commits

Reviewing files that changed from the base of the PR and between aadff85 and e592f1b.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • src/app/v1/[...route]/route.ts
  • src/app/v1/_lib/models/available-models.ts
  • src/app/v1/_lib/proxy/auth-guard.ts
  • src/app/v1/_lib/proxy/provider-selector.ts
  • src/app/v1beta/[...route]/route.ts
🧰 Additional context used
🧬 Code graph analysis (4)
src/app/v1/[...route]/route.ts (1)
src/app/v1/_lib/models/available-models.ts (3)
  • handleAvailableModels (466-501)
  • handleCodexModels (450-453)
  • handleOpenAICompatibleModels (458-461)
src/app/v1/_lib/models/available-models.ts (3)
src/app/v1/_lib/proxy/auth-guard.ts (1)
  • extractApiKeyFromHeaders (205-232)
src/app/v1/_lib/proxy/format-mapper.ts (1)
  • ClientFormat (29-29)
src/app/v1/_lib/proxy/provider-selector.ts (1)
  • ProxyProviderResolver (211-1124)
src/app/v1/_lib/proxy/provider-selector.ts (3)
src/types/provider.ts (1)
  • Provider (20-113)
src/types/message.ts (1)
  • ProviderChainItem (8-172)
src/repository/provider.ts (1)
  • findAllProviders (179-237)
src/app/v1beta/[...route]/route.ts (1)
src/app/v1/_lib/models/available-models.ts (1)
  • handleAvailableModels (466-501)
🪛 LanguageTool
CHANGELOG.md

[uncategorized] ~18-~18: 您的意思是“"不"全”?
Context: ...ithub.com/Privnode-HQ) - Session 详情记录增强,补全请求和响应的完整 payload (#495) - 排行榜输出速率计算优化,修...

(BU)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: pr-review
  • GitHub Check: Greptile Review
  • GitHub Check: pr-description
  • GitHub Check: 🌐 API Tests
  • GitHub Check: pr-label
  • GitHub Check: Docker Build Test
🔇 Additional comments (8)
src/app/v1/_lib/proxy/provider-selector.ts (2)

1020-1027: 分组过滤行为与 pickRandomProvider 不一致

当用户分组内没有匹配的供应商时,pickRandomProvider 方法(lines 652-675)会返回 provider: null 并记录错误日志,而此处会静默回退到所有可见供应商。这可能导致分组隔离策略不一致。

请确认这是预期行为,还是应该保持与 pickRandomProvider 一致的严格分组隔离?


1126-1127: LGTM!

导出 checkProviderGroupMatch 辅助函数,便于在 available-models.ts 等外部模块复用分组匹配逻辑。

src/app/v1beta/[...route]/route.ts (1)

15-16: LGTM!

新增 /models 端点,复用 v1 的 handleAvailableModels 处理函数,路由注册顺序正确(在通配符路由之前)。

CHANGELOG.md (1)

7-31: LGTM!

更新日志内容完整记录了 v0.3.40 版本的新增功能、优化和修复项。静态分析工具关于 "补全" 的提示是误报,此处用词正确。

src/app/v1/[...route]/route.ts (1)

32-36: LGTM!

新增四个模型列表端点,路由结构清晰:

  • /models - 聚合所有可用模型
  • /responses/models - 仅 codex 类型
  • /chat/completions/models/chat/models - 仅 openai-compatible 类型

路由注册顺序正确,在通配符路由之前。

src/app/v1/_lib/models/available-models.ts (3)

258-275: LGTM!

使用 exhaustive check 模式确保所有 ClientFormat 类型都被处理,映射逻辑清晰。


450-461: LGTM!

使用工厂函数创建固定 providerType 的处理器,代码简洁且易于扩展。


466-501: LGTM!

主处理函数结构清晰,支持多种响应格式(OpenAI/Anthropic/Gemini),格式检测和覆盖机制设计合理。

…tching

- Redact Gemini API key from debug logs to prevent credential exposure
- Use Promise.all for parallel model fetching to reduce latency
@NieiR
Copy link
Contributor Author

NieiR commented Jan 3, 2026

Response to Claude AI Review

感谢详细的审查!针对提出的问题逐一回复:

Critical Issues

1. [ERROR-SILENT] fetchModelsWithConfig catch block
刻意设计,不修改。这是容错逻辑:单个 provider 网络抖动不应阻止返回其他 provider 的模型。warn 级别足够排查问题,改成 error 会产生过多噪音。

2. [ERROR-SILENT] 所有 provider 失败时返回空列表
OpenAI 兼容行为,不修改。返回 {"object":"list","data":[]} 是合法的 API 响应,客户端能正常处理。抛错反而会导致客户端崩溃,违反 "never break userspace"。

3. [ERROR-NO-USER-FEEDBACK] catch 块
标准 Hono 模式,不修改throw c.json({...}, 401) 是 Hono 的标准错误返回方式,e instanceof Response 正是为此设计。Hono 框架会自动处理其他未捕获异常。

High Priority

4. [TEST-MISSING-CRITICAL] 缺少测试
→ 同意应该补充测试,将在后续 PR 中添加。核心逻辑(provider 选择、格式检测)已有其他测试覆盖。

Medium Priority

5. [TYPE-WEAK-INVARIANT] 注释编码问题
误报。实际代码中注释是正确的中文:// openai 格式需要对 codex 和 openai-compatible 分别决策,是审查工具读取时的编码问题。

@ding113 ding113 merged commit 9ba464d into ding113:dev Jan 3, 2026
37 of 39 checks passed
@github-project-automation github-project-automation bot moved this from Backlog to Done in Claude Code Hub Roadmap Jan 3, 2026
NieiR added a commit to NieiR/claude-code-hub that referenced this pull request Jan 3, 2026
为 PR ding113#517 引入的模型列表功能补充单元测试,覆盖以下核心逻辑:

- inferOwner: 模型所有者推断(Anthropic/OpenAI/Google/DeepSeek/Alibaba)
- getProviderTypesForFormat: 客户端格式到 Provider 类型映射
- formatOpenAIResponse: OpenAI 格式响应
- formatAnthropicResponse: Anthropic 格式响应
- formatGeminiResponse: Gemini 格式响应

共 23 个测试用例,全部通过。

Related to ding113#517
@NieiR NieiR deleted the feat/models-provider-decision branch January 6, 2026 13:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core area:provider enhancement New feature or request size/L Large PR (< 1000 lines)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants

Comments