Skip to content

feat: 为 Provider 添加 SupportModels 模型过滤功能#121

Merged
awsl233777 merged 1 commit intomainfrom
feat/provider-support-models
Jan 18, 2026
Merged

feat: 为 Provider 添加 SupportModels 模型过滤功能#121
awsl233777 merged 1 commit intomainfrom
feat/provider-support-models

Conversation

@Bowl42
Copy link
Collaborator

@Bowl42 Bowl42 commented Jan 18, 2026

Summary

  • 新增 Provider.SupportModels 字段,支持通配符模式匹配(如 claude-*gemini-2.5-*
  • Router 在路由匹配阶段用原始 requestModel 检查 SupportModels,跳过不支持该模型的 Provider
  • 模型映射在 Executor 阶段执行,确保只对通过检查的 Provider 进行映射计算

Changes

  • internal/domain/model.go: 添加 SupportModels []string 字段
  • internal/repository/sqlite/: 更新 SQLite 模型和序列化逻辑
  • internal/router/router.go: 添加 isModelSupported() 方法和 SupportModels 检查逻辑
  • internal/executor/executor.go: 更新注释说明映射时机
  • web/src/pages/providers/: 新增 ProviderSupportModels 组件用于 UI 配置

Test plan

  • 配置 Provider 的 SupportModels 为 claude-*
  • 请求 claude-3-opus → 应该匹配成功
  • 请求 gemini-2.5-pro → 应该跳过该 Provider
  • 不配置 SupportModels → 所有模型都应该支持

Summary by CodeRabbit

发布说明

  • 新功能
    • 添加了针对供应商的模型级别支持筛选功能。用户现在可以指定每个供应商支持的具体模型,增强了路由匹配的灵活性和精确度。支持通配符模式配置,空数组表示支持所有模型。

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

- 新增 Provider.SupportModels 字段,支持通配符模式匹配(如 claude-*)
- Router 在匹配阶段用原始 requestModel 检查 SupportModels,跳过不支持的 Provider
- 模型映射在 Executor 阶段执行,确保只对通过检查的 Provider 进行映射
- 前端新增 ProviderSupportModels 组件,支持配置模型过滤规则
@coderabbitai
Copy link

coderabbitai bot commented Jan 18, 2026

📝 Walkthrough

总体说明

此 PR 为 Provider 添加了模型支持过滤功能,包括域模型字段、路由匹配逻辑、数据库持久化支持以及前端管理界面,使路由选择可按请求的模型类型进行精细化控制。

变更详情

模块 / 文件 变更说明
域模型
internal/domain/model.go
在 Provider 结构体中新增 SupportModels 字段([]string),支持在路由匹配时按模型过滤,空数组表示支持所有模型
路由引擎
internal/router/router.go
新增 MatchContext 结构体携带路由匹配上下文(ClientType、ProjectID、RequestModel、APITokenID);Router.Match 签名改为接收 MatchContext;添加模型支持检查逻辑 isModelSupported(支持通配符匹配)
执行器
internal/executor/executor.go
更新 router.Match 调用,传递结构化 MatchContext 替代原有分散参数;调整模型映射顺序至路由过滤之后
数据持久化
internal/repository/sqlite/models.go, internal/repository/sqlite/provider.go
在 SQLite Provider 模型新增 SupportModels 文本字段;在 toDomain/toModel 转换方法中添加 SupportModels 的 JSON 序列化/反序列化逻辑
前端类型定义
web/src/lib/transport/types.ts
在 Provider 接口和 CreateProviderData 类型中新增可选字段 supportModels?: string[]
前端编辑界面
web/src/pages/providers/components/provider-edit-flow.tsx
新增 ProviderSupportModels UI 组件管理模型列表;在编辑表单集成该组件;扩展 EditFormData 结构体包含 supportModels 数组;保存时条件性地包含该字段(仅在非空时)

时序流程图

sequenceDiagram
    actor Client as 客户端
    participant Executor as 执行器
    participant Router as 路由器
    participant Providers as Provider 数据
    participant Route as 匹配路由

    Client->>Executor: 发送请求(ClientType, ProjectID, RequestModel)
    Executor->>Router: Match(MatchContext{ClientType, ProjectID, RequestModel, APITokenID})
    
    Router->>Providers: 遍历所有 Provider
    loop 遍历每个 Provider
        Router->>Router: 检查 ClientType 匹配
        alt ClientType 匹配
            Router->>Router: 检查 RequestModel 是否在 SupportModels 中
            alt 模型支持
                Router->>Route: 将 Provider 作为候选加入匹配结果
            else 模型不支持
                Router->>Router: 跳过该 Provider
            end
        else ClientType 不匹配
            Router->>Router: 跳过该 Provider
        end
    end
    
    Router->>Executor: 返回匹配的路由列表 []*MatchedRoute
    Executor->>Client: 返回选定的路由和 Provider
Loading

代码审查工作量

🎯 3 (中等复杂度) | ⏱️ ~25 分钟

可能相关的 PR

建议审查者

  • lxw15337674

庆祝诗

🐰 模型筛选小魔法,
路由匹配更精准,
域数据库前端通,
Provider 功能又增强,
通配符模式显魔力!✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确总结了主要变更:为 Provider 添加 SupportModels 字段用于模型过滤功能,与所有改动保持一致。

✏️ 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.

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: 2

🤖 Fix all issues with AI agents
In `@internal/domain/model.go`:
- Around line 99-103: 注释与实现不一致:在 Route 匹配时字段 SupportModels 实际上是基于原始
requestModel(映射前)进行检查,而模型映射发生在 Executor 阶段;请在 internal/domain/model.go 中更新
SupportModels 的注释以明确说明它匹配的是映射前的原始模型(用于 router.go 的路由匹配),并补充说明模型映射是在 Executor
阶段完成(例如引用 Executor 或模型映射流程)以避免误导。

In `@web/src/pages/providers/components/provider-edit-flow.tsx`:
- Around line 219-225: 删除按钮缺少屏幕阅读器标签:在该 <button>(触发 handleRemoveModel 的按钮,包含
Trash2 图标)上添加一个描述性无障碍属性(例如 aria-label="删除模型" 或 aria-label={t('Remove model')}
以支持本地化),也可同时保留 title 属性以增强可见提示,确保按钮仍为 type="button" 并保持现有 onClick 处理器不变。
🧹 Nitpick comments (1)
web/src/pages/providers/components/provider-edit-flow.tsx (1)

181-188: 建议:支持 Enter 键添加模型

当前用户只能通过点击按钮添加模型,建议添加键盘支持以改善用户体验。

♻️ 建议的改进
+  const handleKeyDown = (e: React.KeyboardEvent) => {
+    if (e.key === 'Enter') {
+      e.preventDefault()
+      handleAddModel()
+    }
+  }
+
   const handleAddModel = () => {
     if (!newModel.trim()) return
     const trimmedModel = newModel.trim()
     if (!supportModels.includes(trimmedModel)) {
       onChange([...supportModels, trimmedModel])
     }
     setNewModel('')
   }

然后在 ModelInput 组件上添加 onKeyDown={handleKeyDown} 属性。

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 16e1fa0 and 213ced6.

📒 Files selected for processing (7)
  • internal/domain/model.go
  • internal/executor/executor.go
  • internal/repository/sqlite/models.go
  • internal/repository/sqlite/provider.go
  • internal/router/router.go
  • web/src/lib/transport/types.ts
  • web/src/pages/providers/components/provider-edit-flow.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
internal/executor/executor.go (3)
internal/router/router.go (1)
  • MatchContext (23-28)
internal/domain/model.go (1)
  • ClientType (6-6)
web/src/lib/transport/types.ts (1)
  • ClientType (8-8)
internal/router/router.go (2)
internal/domain/model.go (3)
  • ClientType (6-6)
  • Provider (76-104)
  • MatchWildcard (608-655)
internal/adapter/provider/antigravity/model_mapping.go (1)
  • MatchWildcard (122-169)
🔇 Additional comments (14)
internal/repository/sqlite/models.go (1)

121-121: LGTM!

新增的 SupportModels 字段遵循了现有的 SupportedClientTypes 字段的模式,使用 text 类型存储 JSON 序列化的数组数据,符合项目的数据存储规范。

internal/executor/executor.go (2)

169-174: LGTM!

使用 MatchContext 结构体传递路由匹配所需的上下文信息,包括 ClientTypeProjectIDRequestModelAPITokenID,清晰地封装了匹配所需的全部参数。


266-266: 注释准确描述了执行顺序。

注释明确说明了模型映射(Model Mapping)在 Router 完成 SupportModels 过滤之后执行,这个执行顺序符合 PR 目标:使用原始 requestModel 进行支持检查,映射则在后续阶段进行。

web/src/lib/transport/types.ts (2)

52-52: LGTM!

supportModels 字段的类型定义与后端 Go 的 domain.Provider 保持一致,可选类型 (?) 对应 Go 中的 omitempty 标签。


61-61: LGTM!

CreateProviderData 中添加 supportModels 字段,确保创建 Provider 时可以传递模型过滤配置。

internal/repository/sqlite/provider.go (2)

87-87: LGTM!

toModel 方法正确使用 toJSON 序列化 SupportModels 字段,与 SupportedClientTypes 的处理方式保持一致。


102-102: LGTM!

toDomain 方法正确使用泛型 fromJSON[[]string] 反序列化 SupportModels 字段,类型参数与 domain 层定义匹配。

internal/router/router.go (4)

22-28: LGTM!

MatchContext 结构体清晰地封装了路由匹配所需的上下文信息,包括客户端类型、项目 ID、请求模型和 API Token ID,提高了 API 的可读性和可扩展性。


109-112: LGTM!

Match 方法签名更新为接收 *MatchContext 指针,并在方法开头提取所需字段,保持了代码简洁性。


205-212: 核心过滤逻辑实现正确。

SupportModels 检查逻辑正确地满足了 PR 目标:

  1. 使用原始 requestModel 进行检查(映射前)
  2. 仅当 SupportModels 已配置且 requestModel 非空时才执行检查
  3. 不支持的模型会跳过该 Provider

条件 len(prov.SupportModels) > 0 && requestModel != "" 确保了空 SupportModels 等同于"支持所有模型"的语义。


237-245: LGTM!

isModelSupported 辅助函数实现简洁,复用了 domain.MatchWildcard 进行通配符匹配,确保了与其他模块(如 ModelMapping)的匹配行为一致。

web/src/pages/providers/components/provider-edit-flow.tsx (3)

292-298: LGTM!

状态初始化逻辑正确,使用 || [] 作为防御性回退处理旧数据兼容性问题。


330-342: LGTM!

负载构建逻辑符合 PR 目标要求:当 supportModels 为空时发送 undefined,后端将视为"支持所有模型"。


517-521: LGTM!

组件集成正确,放置在 Model Mappings 之前符合逻辑流程(先过滤,后映射)。

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +99 to +103

// 支持的模型列表(通配符模式)
// 如果配置了,在 Route 匹配时会检查前置映射后的模型是否在支持列表中
// 空数组表示支持所有模型
SupportModels []string `json:"supportModels,omitempty"`
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

注释与实际实现可能不一致。

注释中提到"在 Route 匹配时会检查前置映射后的模型是否在支持列表中",但根据 PR 目标和 router.go 中的实现,SupportModels 检查使用的是原始 requestModel(映射前),模型映射是在 Executor 阶段执行的。

建议修正注释以匹配实际行为:

📝 建议的注释修改
-	// 支持的模型列表(通配符模式)
-	// 如果配置了,在 Route 匹配时会检查前置映射后的模型是否在支持列表中
-	// 空数组表示支持所有模型
+	// 支持的模型列表(通配符模式)
+	// 如果配置了,在 Route 匹配时会检查原始请求模型是否在支持列表中
+	// 模型映射在 Executor 阶段执行,晚于此检查
+	// 空数组表示支持所有模型
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// 支持的模型列表(通配符模式)
// 如果配置了,在 Route 匹配时会检查前置映射后的模型是否在支持列表中
// 空数组表示支持所有模型
SupportModels []string `json:"supportModels,omitempty"`
// 支持的模型列表(通配符模式)
// 如果配置了,在 Route 匹配时会检查原始请求模型是否在支持列表中
// 模型映射在 Executor 阶段执行,晚于此检查
// 空数组表示支持所有模型
SupportModels []string `json:"supportModels,omitempty"`
🤖 Prompt for AI Agents
In `@internal/domain/model.go` around lines 99 - 103, 注释与实现不一致:在 Route 匹配时字段
SupportModels 实际上是基于原始 requestModel(映射前)进行检查,而模型映射发生在 Executor 阶段;请在
internal/domain/model.go 中更新 SupportModels 的注释以明确说明它匹配的是映射前的原始模型(用于 router.go
的路由匹配),并补充说明模型映射是在 Executor 阶段完成(例如引用 Executor 或模型映射流程)以避免误导。

Comment on lines +219 to +225
<button
type="button"
onClick={() => handleRemoveModel(model)}
className="text-muted-foreground hover:text-destructive ml-1"
>
<Trash2 className="h-3.5 w-3.5" />
</button>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

无障碍性:删除按钮缺少 aria-label

删除按钮没有提供屏幕阅读器可识别的标签,这会影响无障碍访问体验。

♿ 建议的修复
                 <button
                   type="button"
                   onClick={() => handleRemoveModel(model)}
                   className="text-muted-foreground hover:text-destructive ml-1"
+                  aria-label={t('common.remove', 'Remove') + ` ${model}`}
                 >
                   <Trash2 className="h-3.5 w-3.5" />
                 </button>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<button
type="button"
onClick={() => handleRemoveModel(model)}
className="text-muted-foreground hover:text-destructive ml-1"
>
<Trash2 className="h-3.5 w-3.5" />
</button>
<button
type="button"
onClick={() => handleRemoveModel(model)}
className="text-muted-foreground hover:text-destructive ml-1"
aria-label={t('common.remove', 'Remove') + ` ${model}`}
>
<Trash2 className="h-3.5 w-3.5" />
</button>
🤖 Prompt for AI Agents
In `@web/src/pages/providers/components/provider-edit-flow.tsx` around lines 219 -
225, 删除按钮缺少屏幕阅读器标签:在该 <button>(触发 handleRemoveModel 的按钮,包含 Trash2
图标)上添加一个描述性无障碍属性(例如 aria-label="删除模型" 或 aria-label={t('Remove model')}
以支持本地化),也可同时保留 title 属性以增强可见提示,确保按钮仍为 type="button" 并保持现有 onClick 处理器不变。

@awsl233777 awsl233777 merged commit e80a703 into main Jan 18, 2026
2 checks passed
@awsl233777 awsl233777 deleted the feat/provider-support-models branch January 18, 2026 04:15
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.

2 participants