feat: 为 Provider 添加 SupportModels 模型过滤功能#121
Conversation
- 新增 Provider.SupportModels 字段,支持通配符模式匹配(如 claude-*) - Router 在匹配阶段用原始 requestModel 检查 SupportModels,跳过不支持的 Provider - 模型映射在 Executor 阶段执行,确保只对通过检查的 Provider 进行映射 - 前端新增 ProviderSupportModels 组件,支持配置模型过滤规则
📝 Walkthrough总体说明此 PR 为 Provider 添加了模型支持过滤功能,包括域模型字段、路由匹配逻辑、数据库持久化支持以及前端管理界面,使路由选择可按请求的模型类型进行精细化控制。 变更详情
时序流程图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
代码审查工作量🎯 3 (中等复杂度) | ⏱️ ~25 分钟 可能相关的 PR
建议审查者
庆祝诗
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 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: 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
📒 Files selected for processing (7)
internal/domain/model.gointernal/executor/executor.gointernal/repository/sqlite/models.gointernal/repository/sqlite/provider.gointernal/router/router.goweb/src/lib/transport/types.tsweb/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结构体传递路由匹配所需的上下文信息,包括ClientType、ProjectID、RequestModel和APITokenID,清晰地封装了匹配所需的全部参数。
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 目标:
- 使用原始
requestModel进行检查(映射前)- 仅当
SupportModels已配置且requestModel非空时才执行检查- 不支持的模型会跳过该 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.
|
|
||
| // 支持的模型列表(通配符模式) | ||
| // 如果配置了,在 Route 匹配时会检查前置映射后的模型是否在支持列表中 | ||
| // 空数组表示支持所有模型 | ||
| SupportModels []string `json:"supportModels,omitempty"` |
There was a problem hiding this comment.
注释与实际实现可能不一致。
注释中提到"在 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.
| // 支持的模型列表(通配符模式) | |
| // 如果配置了,在 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 或模型映射流程)以避免误导。
| <button | ||
| type="button" | ||
| onClick={() => handleRemoveModel(model)} | ||
| className="text-muted-foreground hover:text-destructive ml-1" | ||
| > | ||
| <Trash2 className="h-3.5 w-3.5" /> | ||
| </button> |
There was a problem hiding this comment.
无障碍性:删除按钮缺少 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.
| <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 处理器不变。
Summary
Provider.SupportModels字段,支持通配符模式匹配(如claude-*、gemini-2.5-*)requestModel检查SupportModels,跳过不支持该模型的 ProviderChanges
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
claude-*claude-3-opus→ 应该匹配成功gemini-2.5-pro→ 应该跳过该 ProviderSummary by CodeRabbit
发布说明
✏️ Tip: You can customize this high-level summary in your review settings.