Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📜 Recent review details🧰 Additional context used📓 Path-based instructions (2)web/default/src/**/*.{ts,tsx}📄 CodeRabbit inference engine (web/default/AGENTS.md)
Files:
web/default/src/features/**📄 CodeRabbit inference engine (web/default/AGENTS.md)
Files:
🔇 Additional comments (1)
📝 WalkthroughSummary by CodeRabbit
WalkthroughChangesToken routing policy
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (1 warning, 2 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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: 14
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/default/src/features/keys/lib/api-key-form.ts (1)
62-73: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRemove the empty
ifbranch.The
if (data.unlimited_quota)branch contains only a comment. Invert the condition so the quota check reads directly.♻️ Proposed refactor
- if (data.unlimited_quota) { - // Routing validation still applies to unlimited keys. - } else if ( - data.remain_quota_dollars === undefined || - data.remain_quota_dollars < 0 + // Routing validation below still applies to unlimited keys. + if ( + !data.unlimited_quota && + (data.remain_quota_dollars === undefined || + data.remain_quota_dollars < 0) ) {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/default/src/features/keys/lib/api-key-form.ts` around lines 62 - 73, In the quota validation logic of the API key form, remove the empty unlimited_quota branch and invert the condition so the existing remain_quota_dollars validation runs directly when data.unlimited_quota is false. Preserve the current validation checks and issue details unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@controller/model.go`:
- Around line 243-253: Update getEnabledModelsForGroups to track seen model
names with a map[string]struct{} instead of repeatedly calling
common.StringsContains, while preserving the returned slice of unique models.
Also refactor the model lookup toward a single query that accepts all
ownerGroups through an IN condition, if the model package supports it, rather
than querying once per group.
In `@controller/token.go`:
- Around line 124-126: Update tokenMutationUpdatesRouting and the UpdateToken
routing branch to treat request.CrossGroupRetry as a routing-policy change,
including when it is explicitly false; preserve the existing Routing and Group
checks and ensure standalone cross_group_retry updates apply.
In `@middleware/auth.go`:
- Around line 468-476: Before calling service.ResolveTokenRoutingPolicy in the
token-routing flow, replace an empty userGroup with
setting.GetDefaultAutoRouteKey() so legacy tokens with missing cached groups
route successfully. Also update the routingErr response to pass the error
through common.TranslateMessage(c, ...) instead of exposing routingErr.Error()
directly, while preserving the existing forbidden response and early return.
In `@middleware/distributor.go`:
- Around line 116-139: Update the preferred-channel handling around
GetPreferredChannelByAffinity to iterate routePlan.OrderedGroups in order,
selecting the first group where preferred.Id supports modelRequest.Model. Set
selectGroup and affinity context to that matched group, preserve retry-index
initialization relative to its position, and when no group matches, pass the
unused preference through CacheGetRandomSatisfiedChannel so ordered-group
fallback and cross-group retry state follow the plan ordering.
In `@service/token_routing.go`:
- Around line 209-233: In the policy parsing block around BuildTokenRoutePlan,
perform the ContextKeyTokenRoutingPolicy lookup once and track whether it
produced a valid non-nil model.TokenRoutingPolicy value. Use that parsed-policy
status for plan.Legacy instead of hasStoredPolicy, so unexpected types and nil
pointers that trigger LegacyTokenRoutingPolicy remain marked legacy.
In `@web/default/src/features/keys/components/api-key-routing-editor.tsx`:
- Around line 411-426: Replace the nested ternary in the routes-loading and
empty-options rendering within the API key routing editor with a small component
or helper using if statements and early returns, preserving the existing loading
skeleton, no-options alert, and normal content states.
- Around line 179-189: Update ManualGroupEditor to accept a single props object
typed with its existing fields, then replace every bare value, options,
disabled, and onChange reference in the component body with the corresponding
props.xxx access, matching ManualGroupRow and ApiKeyRoutingEditor.
- Around line 239-276: Update the PopoverTrigger markup so the element carrying
role='combobox' contains only the combobox trigger content, with aria-expanded
reflecting !disabled && open. Move the selected group badges and their remove
buttons, placeholder, and chevron outside that role='combobox' element while
preserving the existing toggleGroup behavior and disabled styling.
In `@web/default/src/features/keys/components/api-keys-columns.tsx`:
- Around line 235-237: Update the TooltipTrigger render element in the manual
routing label branch to use an inline-flex or equivalent non-inline display,
matching the smart branch, so max-w-60 and truncate apply and long labels render
with an ellipsis.
In `@web/default/src/features/keys/components/api-keys-mutate-drawer.tsx`:
- Around line 171-172: Update the routeGroups calculation to use the imported
MAX_MANUAL_ROUTING_GROUPS constant instead of the hardcoded 8 when limiting
option groups, keeping the existing fallback to an empty array.
- Around line 206-259: Update the load effect around getApiKey to read
autoRouteOptions, realGroups, defaultManualGroups, and effectiveAutoRoute from a
ref, and only initialize after the groups query is settled rather than on
loading or refetch identity changes. Track the current request/drawer context so
stale getApiKey responses cannot reset the form or preserved routing state, and
add rejection handling that routes server failures through handleServerError and
displays the standard toast.error feedback.
In `@web/default/src/features/keys/lib/api-key-form.test.ts`:
- Around line 50-72: Extend the api-key form tests around
transformApiKeyToFormDefaults and getApiKeyFormSchema: add coverage for a legacy
key with group '' using supplied defaults, asserting the default group is used,
and add a schema test asserting more than MAX_MANUAL_ROUTING_GROUPS manual
groups is rejected. Import MAX_MANUAL_ROUTING_GROUPS from api-key-form and
preserve the existing legacy real-group test.
In `@web/default/src/features/keys/lib/api-key-form.ts`:
- Around line 237-247: The manualGroups fallback in the routing setup must not
preserve an empty legacy apiKey.group. Update the relevant branch around
routing, legacySmart, and manualGroups so an empty group is excluded and the
supplied availability/manual-group defaults are used instead, while preserving
valid non-empty legacy groups and existing routed behavior.
In `@web/default/src/i18n/locales/ru.json`:
- Line 4369: Update the Russian translation for “Automatic routing is
enabled...” to describe using the ordered list of groups in the selected
automatic route, rather than the order within a selected group; preserve the
existing meaning that automatic routing follows the selected route’s group
order.
---
Outside diff comments:
In `@web/default/src/features/keys/lib/api-key-form.ts`:
- Around line 62-73: In the quota validation logic of the API key form, remove
the empty unlimited_quota branch and invert the condition so the existing
remain_quota_dollars validation runs directly when data.unlimited_quota is
false. Preserve the current validation checks and issue details unchanged.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 02cee46b-2c44-4048-824e-66ee49c319e8
📒 Files selected for processing (35)
.gitignoreconstant/context_key.gocontroller/group.gocontroller/model.gocontroller/model_list_test.gocontroller/model_owned_by_test.gocontroller/token.gocontroller/token_test.gomiddleware/auth.gomiddleware/distributor.gomiddleware/distributor_routing_test.gomodel/ability.gomodel/token.gomodel/token_routing.gomodel/token_routing_test.goservice/channel_select.goservice/channel_select_routing_test.goservice/token_routing.goservice/token_routing_test.goweb/default/src/features/keys/components/api-key-group-combobox.tsxweb/default/src/features/keys/components/api-key-routing-editor.tsxweb/default/src/features/keys/components/api-keys-columns.tsxweb/default/src/features/keys/components/api-keys-mutate-drawer.tsxweb/default/src/features/keys/lib/api-key-form.test.tsweb/default/src/features/keys/lib/api-key-form.tsweb/default/src/features/keys/lib/index.tsweb/default/src/features/keys/types.tsweb/default/src/i18n/locales/en.jsonweb/default/src/i18n/locales/fr.jsonweb/default/src/i18n/locales/ja.jsonweb/default/src/i18n/locales/ru.jsonweb/default/src/i18n/locales/vi.jsonweb/default/src/i18n/locales/zh.jsonweb/default/src/i18n/static-keys.tsweb/default/src/lib/api.ts
💤 Files with no reviewable changes (1)
- web/default/src/i18n/static-keys.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType) and must not directly callencoding/jsonfor actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid directAUTO_INCREMENT/SERIAL, usecommonGroupCol/commonKeyColandcommonTrueVal/commonFalseValfor DB-specific SQL, branch withcommon.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supportsStreamOptions; if it does, add that channel tostreamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types withomitemptyso explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, readpkg/billingexpr/expr.mdfirst and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.
**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType) instead of directly importing or callingencoding/jsonfor actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with thecommon.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQLflags when need...
Files:
model/ability.goconstant/context_key.gomodel/token.gocontroller/group.goservice/channel_select_routing_test.gocontroller/model.gocontroller/model_list_test.gocontroller/model_owned_by_test.goservice/channel_select.gomiddleware/auth.gomodel/token_routing.goservice/token_routing.goservice/token_routing_test.gomiddleware/distributor_routing_test.gocontroller/token.gomiddleware/distributor.gomodel/token_routing_test.gocontroller/token_test.go
web/default/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (web/default/AGENTS.md)
web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用useTranslation()取得t,并通过t()渲染用户可见文本;子组件也应自行使用useTranslation()保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用any,优先使用具体类型或unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用import type。
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用props.xxx以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的types中。
在 React 中应合理使用useMemo、useCallback、React.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态import。
React Query 的数据获取应使用useQuery、变更应使用useMutation;每个查询需配置唯一queryKey,并在成功后对相关查询执行invalidateQueries;服务端错误应统一交给handleServerError。
Axios 请求应使用项目统一的api实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用handleServerError,展示层应使用toast.error等统一方式;文案需走 i18n;路由级错误应由errorComponent承接;表单错误应通过form.setError等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用cn()合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与dark:处理。
应使用语义化 HTML、正确关联label与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用aria-hidden="true"。
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用dangerouslySetInnerHTML;跨域与 Cookie 需配合withCredentials并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过.env读取,并使用VITE_前缀;代码中不得硬编码密钥。
Files:
web/default/src/lib/api.tsweb/default/src/features/keys/lib/index.tsweb/default/src/features/keys/components/api-keys-columns.tsxweb/default/src/features/keys/components/api-key-routing-editor.tsxweb/default/src/features/keys/lib/api-key-form.test.tsweb/default/src/features/keys/components/api-keys-mutate-drawer.tsxweb/default/src/features/keys/components/api-key-group-combobox.tsxweb/default/src/features/keys/lib/api-key-form.tsweb/default/src/features/keys/types.ts
web/default/src/features/**/lib/**/*.ts
📄 CodeRabbit inference engine (web/default/AGENTS.md)
表单应使用 React Hook Form + Zod:在功能模块的
lib/下定义 schema,并用z.infer导出表单类型;useForm应配合@hookform/resolvers/zod进行校验。
Files:
web/default/src/features/keys/lib/index.tsweb/default/src/features/keys/lib/api-key-form.test.tsweb/default/src/features/keys/lib/api-key-form.ts
web/default/src/features/**
📄 CodeRabbit inference engine (web/default/AGENTS.md)
功能模块应放在
src/features/<feature>/,并按需包含components/、lib/、hooks/、api.ts、types.ts、constants.ts等;通用组件应放在src/components/,通用工具与类型应放在src/lib/。
Files:
web/default/src/features/keys/lib/index.tsweb/default/src/features/keys/components/api-keys-columns.tsxweb/default/src/features/keys/components/api-key-routing-editor.tsxweb/default/src/features/keys/lib/api-key-form.test.tsweb/default/src/features/keys/components/api-keys-mutate-drawer.tsxweb/default/src/features/keys/components/api-key-group-combobox.tsxweb/default/src/features/keys/lib/api-key-form.tsweb/default/src/features/keys/types.ts
web/default/src/**/*.test.ts
📄 CodeRabbit inference engine (web/default/AGENTS.md)
工具函数与纯逻辑应优先编写单元测试;测试文件应命名为
*.test.ts。
Files:
web/default/src/features/keys/lib/api-key-form.test.ts
🔇 Additional comments (36)
.gitignore (1)
43-44: LGTM!web/default/src/i18n/locales/en.json (1)
27-27: LGTM!Also applies to: 591-875, 1451-1664, 2339-2340, 2648-2651, 2860-2861, 2963-3085, 3830-3849, 3903-4034, 4140-4210, 4368-4369, 4548-4650, 4919-4919, 5147-5147
web/default/src/i18n/locales/fr.json (1)
27-27: LGTM!Also applies to: 591-591, 875-875, 1451-1451, 1520-1520, 1664-1664, 2339-2340, 2648-2651, 2860-2861, 2963-2963, 3005-3005, 3084-3085, 3830-3830, 3849-3849, 3903-3903, 4034-4034, 4140-4140, 4167-4167, 4190-4194, 4210-4210, 4368-4369, 4548-4548, 4649-4650, 4919-4919, 5147-5147
web/default/src/i18n/locales/ja.json (1)
27-27: LGTM!Also applies to: 591-591, 875-875, 1451-1451, 1520-1520, 1664-1664, 2339-2340, 2648-2651, 2860-2861, 2963-2963, 3005-3005, 3084-3085, 3830-3830, 3849-3849, 3903-3903, 4034-4034, 4140-4140, 4190-4194, 4210-4210, 4368-4369, 4548-4548, 4649-4650, 4919-4919, 5147-5147
web/default/src/i18n/locales/ru.json (1)
27-27: LGTM!Also applies to: 591-591, 875-875, 1451-1451, 1520-1520, 1664-1664, 2339-2340, 2648-2651, 2860-2861, 2963-2963, 3005-3005, 3084-3085, 3830-3830, 3849-3849, 3903-3903, 4034-4034, 4140-4140, 4167-4167, 4190-4194, 4210-4210, 4368-4368, 4548-4548, 4649-4650, 4919-4919, 5147-5147
web/default/src/i18n/locales/vi.json (1)
27-27: LGTM!Also applies to: 591-591, 875-875, 1451-1451, 1520-1520, 1664-1664, 2339-2340, 2648-2651, 2860-2861, 2963-2963, 3005-3005, 3084-3085, 3830-3830, 3849-3849, 3903-3903, 4034-4034, 4140-4140, 4167-4168, 4190-4190, 4194-4194, 4210-4210, 4368-4369, 4548-4548, 4649-4650, 4919-4919, 5147-5147
web/default/src/i18n/locales/zh.json (1)
27-27: LGTM!Also applies to: 591-591, 875-875, 1451-1451, 1520-1520, 1664-1664, 2339-2340, 2648-2651, 2860-2861, 2963-2963, 3005-3005, 3084-3085, 3830-3830, 3849-3849, 3903-3903, 4034-4034, 4140-4140, 4167-4168, 4190-4194, 4210-4210, 4368-4369, 4548-4548, 4649-4650, 4919-4919, 5147-5147
web/default/src/features/keys/components/api-key-group-combobox.tsx (1)
79-83: LGTM!web/default/src/features/keys/types.ts (1)
21-33: LGTM!Also applies to: 58-59, 108-110
web/default/src/features/keys/lib/api-key-form.ts (1)
75-125: LGTM!Also applies to: 163-190, 199-228
web/default/src/features/keys/lib/index.ts (1)
24-28: LGTM!web/default/src/features/keys/components/api-keys-mutate-drawer.tsx (2)
105-109: LGTM!Also applies to: 261-279, 356-361, 417-479, 725-725
148-167: 🎯 Functional CorrectnessKeep the
user_selectablefilter on automatic routes.controller/group.gosends only user-selectable routes inauto_routes, so the drawer should not expose disabled route options, but the current backend normalization only checksuser_selectable.> Likely an incorrect or invalid review comment.web/default/src/features/keys/components/api-keys-columns.tsx (2)
203-229: LGTM!
238-242: 🎯 Functional CorrectnessNo i18next pluralization issue here.
All supported locales define the base
Manual {{count}} groups: {{groups}}key, and the config does not enable missing-key handling behavior that would override fallback to this defined key.> Likely an incorrect or invalid review comment.web/default/src/features/keys/lib/api-key-form.test.ts (1)
74-131: LGTM!Also applies to: 163-211
web/default/src/lib/api.ts (1)
23-23: LGTM!Also applies to: 203-203
constant/context_key.go (1)
22-23: LGTM!service/token_routing.go (1)
33-52: LGTM!Also applies to: 96-163, 269-291
middleware/auth.go (1)
483-487: LGTM!middleware/distributor.go (1)
86-113: LGTM!controller/model.go (1)
189-215: LGTM!Also applies to: 302-302
controller/token.go (2)
20-50: LGTM!Also applies to: 67-122, 245-271, 298-313, 343-405, 432-432
52-65: 🗄️ Data Integrity & IntegrationNo change needed.
tokenMutationRequestcovers the writable token fields persisted byAddTokenandUpdateToken;used_quota,created_time,accessed_time, andkeyare excluded from token mutation on purpose.controller/model_owned_by_test.go (1)
9-9: LGTM!Also applies to: 88-103
controller/token_test.go (1)
19-19: LGTM!Also applies to: 38-45, 133-151, 537-589, 628-663, 665-741, 743-762, 764-799, 801-832
middleware/distributor_routing_test.go (1)
22-44: LGTM!Also applies to: 46-114
model/token_routing.go (1)
26-59: LGTM!model/token.go (1)
31-31: LGTM!Also applies to: 315-315
model/ability.go (1)
189-191: LGTM!service/channel_select.go (1)
102-104: LGTM!Also applies to: 184-244
model/token_routing_test.go (1)
9-49: LGTM!service/token_routing_test.go (1)
13-124: LGTM!service/channel_select_routing_test.go (1)
17-145: LGTM!controller/group.go (1)
41-49: LGTM!controller/model_list_test.go (1)
216-229: LGTM!
| func getEnabledModelsForGroups(ownerGroups []string) []string { | ||
| models := make([]string, 0) | ||
| for _, ownerGroup := range ownerGroups { | ||
| for _, groupModel := range model.GetGroupEnabledModels(ownerGroup) { | ||
| if !common.StringsContains(models, groupModel) { | ||
| models = append(models, groupModel) | ||
| } | ||
| } | ||
| } | ||
| return models | ||
| } |
There was a problem hiding this comment.
🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win
Deduplicate with a set and consider one query for all groups.
common.StringsContains scans the accumulated slice for every candidate model. With up to MaxTokenManualGroups groups and large model catalogs, the cost is quadratic on a request path. model.GetGroupEnabledModels also runs one query per group. Use a map[string]struct{} for deduplication, and consider a single IN query over all owner groups.
♻️ Proposed refactor
func getEnabledModelsForGroups(ownerGroups []string) []string {
models := make([]string, 0)
+ seen := make(map[string]struct{})
for _, ownerGroup := range ownerGroups {
for _, groupModel := range model.GetGroupEnabledModels(ownerGroup) {
- if !common.StringsContains(models, groupModel) {
- models = append(models, groupModel)
- }
+ if _, exists := seen[groupModel]; exists {
+ continue
+ }
+ seen[groupModel] = struct{}{}
+ models = append(models, groupModel)
}
}
return models
}📝 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.
| func getEnabledModelsForGroups(ownerGroups []string) []string { | |
| models := make([]string, 0) | |
| for _, ownerGroup := range ownerGroups { | |
| for _, groupModel := range model.GetGroupEnabledModels(ownerGroup) { | |
| if !common.StringsContains(models, groupModel) { | |
| models = append(models, groupModel) | |
| } | |
| } | |
| } | |
| return models | |
| } | |
| func getEnabledModelsForGroups(ownerGroups []string) []string { | |
| models := make([]string, 0) | |
| seen := make(map[string]struct{}) | |
| for _, ownerGroup := range ownerGroups { | |
| for _, groupModel := range model.GetGroupEnabledModels(ownerGroup) { | |
| if _, exists := seen[groupModel]; exists { | |
| continue | |
| } | |
| seen[groupModel] = struct{}{} | |
| models = append(models, groupModel) | |
| } | |
| } | |
| return models | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@controller/model.go` around lines 243 - 253, Update getEnabledModelsForGroups
to track seen model names with a map[string]struct{} instead of repeatedly
calling common.StringsContains, while preserving the returned slice of unique
models. Also refactor the model lookup toward a single query that accepts all
ownerGroups through an IN condition, if the model package supports it, rather
than querying once per group.
| routingPolicy, legacyRouting, routingErr := service.ResolveTokenRoutingPolicy(token, userGroup) | ||
| if routingErr != nil { | ||
| abortWithOpenAiMessage(c, http.StatusForbidden, routingErr.Error()) | ||
| return | ||
| } | ||
| tokenGroup, crossGroupRetry := service.ProjectTokenRoutingPolicy(routingPolicy) | ||
| if tokenGroup != "" { | ||
| // check common.UserUsableGroups[userGroup] | ||
| if !service.CanUseTokenGroupRuntime(userGroup, tokenGroup) { | ||
| abortWithOpenAiMessage(c, http.StatusForbidden, fmt.Sprintf("无权访问 %s 分组", tokenGroup)) | ||
| return | ||
| } | ||
| // check group in common.GroupRatio | ||
| if !service.IsAutoRouteKey(tokenGroup) && !ratio_setting.ContainsGroupRatio(tokenGroup) { | ||
| abortWithOpenAiMessage(c, http.StatusForbidden, fmt.Sprintf("分组 %s 已被弃用", tokenGroup)) | ||
| return | ||
| } | ||
| userGroup = tokenGroup | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check whether a user group can be empty and how it reaches the token auth path.
set -euo pipefail
# Find the user cache group assignment and any defaulting logic.
rg -nP -C4 '\bGroup\s*(string|=)' --type=go -g '**/user_cache*.go' -g '**/user.go'
rg -nP -C3 'func .*WriteContext' --type=go
rg -nP -C3 'ContextKeyUserGroup' --type=goRepository: MAX-API-Next/MAX-API
Length of output: 158
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Locate middleware/auth.go and service definitions"
fd -a 'auth\.go$|.*service.*\.(go)$' . | sed 's#^\./##' | head -80
echo
echo "Search for ResolveTokenRoutingPolicy and ProjectTokenRoutingPolicy"
rg -n -C 5 'ResolveTokenRoutingPolicy|ProjectTokenRoutingPolicy|LegacyTokenRoutingPolicy|normalizeTokenRoutingPolicy|userCache|UserCache|ContextKeyUserGroup|WriteContext' --type=go .Repository: MAX-API-Next/MAX-API
Length of output: 50376
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Read auth.go token path around lines 320-490"
sed -n '320,490p' middleware/auth.go | cat -n
echo
echo "Read model/user_cache.go"
sed -n '1,220p' model/user_cache.go | cat -n
echo
echo "Read service functions definitions"
rg -n -C 2 'func .*ResolveTokenRoutingPolicy|func .*LegacyTokenRoutingPolicy|func .*NormalizeLegacyTokenRoutingPolicy|func .*NormalizeTokenRoutingPolicy|func .*ProjectTokenRoutingPolicy|func .*IsAutoRouteKey' --type=go .Repository: MAX-API-Next/MAX-API
Length of output: 17308
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Read auth.go token path around lines 320-490"
sed -n '320,490p' middleware/auth.go | cat -n
echo
echo "Read model/user_cache.go"
sed -n '1,220p' model/user_cache.go | cat -n
echo
echo "Read service functions definitions"
rg -n -C 4 'func .*ResolveTokenRoutingPolicy|func .*LegacyTokenRoutingPolicy|func .*NormalizeLegacyTokenRoutingPolicy|func .*NormalizeTokenRoutingPolicy|func .*ProjectTokenRoutingPolicy|func .*IsAutoRouteKey' --type=go .Repository: MAX-API-Next/MAX-API
Length of output: 19700
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Read service/token_routing.go"
sed -n '1,190p' service/token_routing.go | cat -n
echo
echo "Read model token Group defaulting/validation"
rg -n -C 4 'type Token|func .*CreateUserToken|func .*Update.*Token|func .*Ensure.*Token|func .*Validate.*Token|Group.*string|Create.*Group|DefaultGroup|GetDefault' --type=go model service controller | head -240
echo
echo "Read GetUserCache and cache population/update"
sed -n '1500,1840p' model/user.go | cat -n
rg -n -C 3 'func cacheUser|func UpdateUserCache|func Build.*Cache|UserBase|RedisInvalidateVersionedHash|RedisSet' --type=go model/user.go model/user_cache.go model/cache_invalidation_task.go | head -260Repository: MAX-API-Next/MAX-API
Length of output: 37922
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Read service/token_routing.go"
sed -n '1,190p' service/token_routing.go | cat -n
echo
echo "Read model token Group defaulting/validation"
rg -n -C 4 'type Token|func .*CreateUserToken|func .*Update.*Token|func .*Ensure.*Token|func .*Validate.*Token|Group.*string|Create.*Group|DefaultGroup|GetDefault' --type=go model service controller | head -240
echo
echo "Read GetUserCache and cache population/update"
sed -n '1500,1840p' model/user.go | cat -n
rg -n -C 3 'func cacheUser|func UpdateUserCache|func .*(Build|Ensure).*Cache|UserBase|RedisInvalidateVersionedHash|RedisSet' --type=go model/user.go model/user_cache.go model/cache_invalidation_task.go | head -260Repository: MAX-API-Next/MAX-API
Length of output: 40094
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Search token migrations/schema and Group field"
rg -n -C 4 'type Token|Table Name|TableName|Group\s+string|gorm:",|DEFAULT|default'| --type=go model | head -260
fd -i 'migration|mysql|postgres|sqlite|schema|sql' model data config | head -200
echo
echo "Search where User.Group is assigned or trimmed"
rg -n -C 3 'Group\s*[:=]|Update.*Group|Trim\([^)]*Group|strings\.Trim\([^)]*Group|TrimString|SetUserGroup|UpdateUserGroup|groupMap|GroupRatio' --type=go model service controller | head -320
echo
echo "Search where User.Group is changed after create/insert"
rg -n -C 4 'DB.*Model\(&User\)|First\(&[^=]*=.*Group|Update\(&|UpdateAll|AutoMigrate.*User|migration.*Group|schema.*Group|Change.*Group|Modify.*Group|DefaultGroup' --type=go model controller service | head -360Repository: MAX-API-Next/MAX-API
Length of output: 252
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Search token migrations/schema and Group field"
rg -n -C 4 'type Token|Table Name|TableName|Group\s+string|gorm:",|DEFAULT|default' --type=go model | head -260
fd -i 'migration|mysql|postgres|sqlite|schema|sql' model data config | head -200
echo
echo "Search where User.Group is assigned or trimmed"
rg -n -C 3 'Group\s*[:=]|Update.*Group|Trim\([^)]*Group|strings\.Trim\([^)]*Group|SetUserGroup|UpdateUserGroup|groupMap|GroupRatio' --type=go model service controller | head -320
echo
echo "Search where User.Group is changed after create/insert"
rg -n -C 4 'DB.*Model\(&User\)|First\(&[^=]*=.*Group|Update\(&|UpdateAll|AutoMigrate.*User|migration.*Group|schema.*Group|Change.*Group|Modify.*Group|DefaultGroup' --type=go model controller service | head -360Repository: MAX-API-Next/MAX-API
Length of output: 42386
Handle corrupted empty user groups before legacy token routing.
LegacyTokenRoutingPolicy falls back to userGroup, and a legacy token with token.Group and an empty userCache.Group routes through NormalizeLegacyTokenRoutingPolicy as a manual routing policy with Groups: [""], which emits manual routing groups must not be empty. Use userGroup = setting.GetDefaultAutoRouteKey() in middleware/auth.go before calling ResolveTokenRoutingPolicy, so missing user groups do not block legacy tokens. Also replace routingErr.Error() in middleware/auth.go:470 with common.TranslateMessage(c, ...) for consistent client-facing routing errors.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@middleware/auth.go` around lines 468 - 476, Before calling
service.ResolveTokenRoutingPolicy in the token-routing flow, replace an empty
userGroup with setting.GetDefaultAutoRouteKey() so legacy tokens with missing
cached groups route successfully. Also update the routingErr response to pass
the error through common.TranslateMessage(c, ...) instead of exposing
routingErr.Error() directly, while preserving the existing forbidden response
and early return.
|
@coderabbitai review |
|
|
@coderabbitai review |
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/default/src/features/keys/components/api-key-routing-editor.test.tsx`:
- Around line 19-23: Update the ApiKeyRoutingEditor tests to use React Testing
Library and accessible user flows instead of className or Lucide icon selectors.
Query the routing selector by combobox role and accessible name, verify it
opens, and assert that remove buttons are accessible and located outside the
trigger.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 61f07a20-5980-41ca-a78d-2d4dc04b6d67
📒 Files selected for processing (2)
web/default/src/features/keys/components/api-key-routing-editor.test.tsxweb/default/src/features/keys/components/api-key-routing-editor.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
web/default/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (web/default/AGENTS.md)
web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用useTranslation()取得t,并通过t()渲染用户可见文本;子组件也应自行使用useTranslation()保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用any,优先使用具体类型或unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用import type。
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用props.xxx以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的types中。
在 React 中应合理使用useMemo、useCallback、React.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态import。
React Query 的数据获取应使用useQuery、变更应使用useMutation;每个查询需配置唯一queryKey,并在成功后对相关查询执行invalidateQueries;服务端错误应统一交给handleServerError。
Axios 请求应使用项目统一的api实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用handleServerError,展示层应使用toast.error等统一方式;文案需走 i18n;路由级错误应由errorComponent承接;表单错误应通过form.setError等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用cn()合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与dark:处理。
应使用语义化 HTML、正确关联label与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用aria-hidden="true"。
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用dangerouslySetInnerHTML;跨域与 Cookie 需配合withCredentials并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过.env读取,并使用VITE_前缀;代码中不得硬编码密钥。
Files:
web/default/src/features/keys/components/api-key-routing-editor.test.tsxweb/default/src/features/keys/components/api-key-routing-editor.tsx
web/default/src/features/**
📄 CodeRabbit inference engine (web/default/AGENTS.md)
功能模块应放在
src/features/<feature>/,并按需包含components/、lib/、hooks/、api.ts、types.ts、constants.ts等;通用组件应放在src/components/,通用工具与类型应放在src/lib/。
Files:
web/default/src/features/keys/components/api-key-routing-editor.test.tsxweb/default/src/features/keys/components/api-key-routing-editor.tsx
🔇 Additional comments (1)
web/default/src/features/keys/components/api-key-routing-editor.tsx (1)
235-264: LGTM!
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/default/src/features/keys/components/api-key-routing-editor.test.tsx`:
- Line 41: Add explicit TypeScript annotations for the test callback and the
helper logic in api-key-routing-editor.test.tsx: update the test named keep(s)
the maximum manual selection in one accessible selector so its callback has an
explicit return type, and type the nextGroups parameter/value used around the
onManualGroupsChange assertions to match that callback contract. Keep the
existing test behavior unchanged while making the parameter and return types
explicit in the affected test and helper expressions.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: f78abf40-4f29-4979-87af-dcc7ac08e5dc
⛔ Files ignored due to path filters (1)
web/bun.lockis excluded by!**/*.lock
📒 Files selected for processing (2)
web/default/package.jsonweb/default/src/features/keys/components/api-key-routing-editor.test.tsx
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: Backend checks
🧰 Additional context used
📓 Path-based instructions (3)
web/default/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (web/default/AGENTS.md)
web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用useTranslation()取得t,并通过t()渲染用户可见文本;子组件也应自行使用useTranslation()保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用any,优先使用具体类型或unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用import type。
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用props.xxx以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的types中。
在 React 中应合理使用useMemo、useCallback、React.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态import。
React Query 的数据获取应使用useQuery、变更应使用useMutation;每个查询需配置唯一queryKey,并在成功后对相关查询执行invalidateQueries;服务端错误应统一交给handleServerError。
Axios 请求应使用项目统一的api实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用handleServerError,展示层应使用toast.error等统一方式;文案需走 i18n;路由级错误应由errorComponent承接;表单错误应通过form.setError等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用cn()合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与dark:处理。
应使用语义化 HTML、正确关联label与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用aria-hidden="true"。
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用dangerouslySetInnerHTML;跨域与 Cookie 需配合withCredentials并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过.env读取,并使用VITE_前缀;代码中不得硬编码密钥。
Files:
web/default/src/features/keys/components/api-key-routing-editor.test.tsx
web/default/src/features/**
📄 CodeRabbit inference engine (web/default/AGENTS.md)
功能模块应放在
src/features/<feature>/,并按需包含components/、lib/、hooks/、api.ts、types.ts、constants.ts等;通用组件应放在src/components/,通用工具与类型应放在src/lib/。
Files:
web/default/src/features/keys/components/api-key-routing-editor.test.tsx
web/default/**/package.json
📄 CodeRabbit inference engine (web/default/AGENTS.md)
脚本与包管理以
package.json为准;发布前应执行 typecheck、lint、format、生产构建,并检查产物体积与环境变量配置。
Files:
web/default/package.json
🔇 Additional comments (2)
web/default/package.json (1)
85-85: 📐 Maintainability & Code QualityVerify release validation.
Before release, run typecheck, lint, format, and the production build. Check artifact size and environment variable configuration. The PR does not provide validation results.
Source: Coding guidelines
web/default/src/features/keys/components/api-key-routing-editor.test.tsx (1)
20-32: LGTM!
|
@coderabbitai review |
|
|
@coderabbitai review |
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
Important
📝 变更描述 / Description
(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)
🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。📸 运行证明 / Proof of Work
(请在此粘贴截图、关键日志或测试报告,以证明变更生效)