feat(group): add lowest-ratio AutoOpt with token filters#6088
feat(group): add lowest-ratio AutoOpt with token filters#6088gao-gao-zai wants to merge 3 commits into
Conversation
WalkthroughAdds AutoOpt group policies across token storage, authorization, model and channel selection, API key management, frontend display, tests, and localized UI text. ChangesAutoOpt policy and persistence
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant TokenAuth
participant AutoOptPolicy
participant ModelController
participant ChannelSelector
TokenAuth->>AutoOptPolicy: load token mode and configured groups
AutoOptPolicy-->>ModelController: return ordered eligible groups
ModelController->>ChannelSelector: try channels for candidate groups
ChannelSelector-->>ModelController: return selected channel and group affinity
Possibly related PRs
Suggested labels: Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 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: 1
🧹 Nitpick comments (1)
web/default/src/features/keys/lib/api-key-form.ts (1)
42-58: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winConsider mirroring the backend's AutoOpt group-count/length limit on the frontend.
The PR objective states token creation/update "limit filter lengths" server-side, but this form schema has no upper bound on
auto_opt_groups. Without a client-side max, users can select an arbitrarily large list and only find out it's rejected after a round-trip to the server.🤖 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 42 - 58, The api-key form schema’s auto_opt_groups field lacks the backend’s maximum group-count validation. Update the schema near the auto_opt_groups definition and its superRefine validation to enforce the same maximum length as the backend, with a localized validation message, while preserving the existing AutoOpt whitelist non-empty check.
🤖 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 `@service/channel_select.go`:
- Around line 90-113: The AutoOpt selection path aborts on group errors and does
not preserve cross-group retry progress. In the AutoOpt branch of the
channel-selection function, log GetRandomSatisfiedChannel errors and continue
evaluating remaining groups, then add crossGroupRetry and
ContextKeyAutoGroupIndex handling analogous to the "auto" branch so retries
advance through candidates instead of restarting; if unsupported, document that
behavior explicitly.
---
Nitpick comments:
In `@web/default/src/features/keys/lib/api-key-form.ts`:
- Around line 42-58: The api-key form schema’s auto_opt_groups field lacks the
backend’s maximum group-count validation. Update the schema near the
auto_opt_groups definition and its superRefine validation to enforce the same
maximum length as the backend, with a localized validation message, while
preserving the existing AutoOpt whitelist non-empty check.
🪄 Autofix (Beta)
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: CHILL
Plan: Pro
Run ID: 8100ec0b-5f91-43b0-91df-154594cdf071
📒 Files selected for processing (30)
constant/context_key.gocontroller/group.gocontroller/model.gocontroller/model_list_test.gocontroller/model_owned_by_test.gocontroller/token.gocontroller/token_test.gocontroller/user.gomiddleware/auth.gomiddleware/distributor.gomodel/ability.gomodel/token.goservice/channel_select.goservice/group.goservice/group_test.goweb/default/src/components/model-group-selector.tsxweb/default/src/features/keys/components/api-key-group-combobox.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.tsweb/default/src/features/keys/types.tsweb/default/src/features/playground/api.tsweb/default/src/features/playground/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-TW.jsonweb/default/src/i18n/locales/zh.json
7e02e0b to
e5ebdc2
Compare
|
Addressed the CodeRabbit feedback:
Validation passed: targeted Go packages, TypeScript typecheck, oxlint, UTF-8 boundary check, i18n sync, and production build. |
e5ebdc2 to
94a8e68
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
middleware/distributor.go (1)
122-137: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winOptional: de-duplicate the two affinity group-selection loops.
The new
AutoOptbranch (Lines 122-137) is an exact copy of theautobranch loop body (Lines 112-121); only the candidate-group source differs. Consider extracting a small local closure so the two paths cannot drift apart. A local closure here is justified since it captures the sharedselectGroup/channel/affinityUsablestate and would have two callers.♻️ Proposed refactor
+ selectFromGroups := func(groups []string) { + for _, g := range groups { + if model.IsChannelEnabledForGroupModel(g, modelRequest.Model, preferred.Id) { + selectGroup = g + common.SetContextKey(c, constant.ContextKeyAutoGroup, g) + channel = preferred + affinityUsable = true + service.MarkChannelAffinityUsed(c, g, preferred.Id) + break + } + } + } if usingGroup == "auto" { - autoGroups := service.GetUserAutoGroup(userGroup) - for _, g := range autoGroups { - if model.IsChannelEnabledForGroupModel(g, modelRequest.Model, preferred.Id) { - selectGroup = g - common.SetContextKey(c, constant.ContextKeyAutoGroup, g) - channel = preferred - affinityUsable = true - service.MarkChannelAffinityUsed(c, g, preferred.Id) - break - } - } + selectFromGroups(service.GetUserAutoGroup(userGroup)) } else if service.IsAutoOptGroup(usingGroup) { - autoOptGroups := service.GetUserAutoOptGroupsWithPolicy( + selectFromGroups(service.GetUserAutoOptGroupsWithPolicy( userGroup, common.GetContextKeyString(c, constant.ContextKeyTokenAutoOptMode), common.GetContextKeyStringSlice(c, constant.ContextKeyTokenAutoOptGroups), - ) - for _, g := range autoOptGroups { - if model.IsChannelEnabledForGroupModel(g, modelRequest.Model, preferred.Id) { - selectGroup = g - common.SetContextKey(c, constant.ContextKeyAutoGroup, g) - channel = preferred - affinityUsable = true - service.MarkChannelAffinityUsed(c, g, preferred.Id) - break - } - } + )) } else if model.IsChannelEnabledForGroupModel(usingGroup, modelRequest.Model, preferred.Id) {🤖 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/distributor.go` around lines 122 - 137, Deduplicate the repeated affinity group-selection logic in the auto and AutoOpt branches of the distributor flow. Extract the shared loop body into a local closure that accepts the candidate groups, captures and updates selectGroup, channel, affinityUsable, and affinity state, then invoke it from both branches while preserving the existing selection and break behavior.Source: Coding guidelines
🤖 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.
Nitpick comments:
In `@middleware/distributor.go`:
- Around line 122-137: Deduplicate the repeated affinity group-selection logic
in the auto and AutoOpt branches of the distributor flow. Extract the shared
loop body into a local closure that accepts the candidate groups, captures and
updates selectGroup, channel, affinityUsable, and affinity state, then invoke it
from both branches while preserving the existing selection and break behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f205f812-7da8-48c5-8f57-b30656ef9b42
📒 Files selected for processing (30)
constant/context_key.gocontroller/group.gocontroller/model.gocontroller/model_list_test.gocontroller/model_owned_by_test.gocontroller/token.gocontroller/token_test.gocontroller/user.gomiddleware/auth.gomiddleware/distributor.gomodel/ability.gomodel/token.goservice/channel_select.goservice/group.goservice/group_test.goweb/default/src/components/model-group-selector.tsxweb/default/src/features/keys/components/api-key-group-combobox.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.tsweb/default/src/features/keys/types.tsweb/default/src/features/playground/api.tsweb/default/src/features/playground/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-TW.jsonweb/default/src/i18n/locales/zh.json
✅ Files skipped from review due to trivial changes (6)
- web/default/src/i18n/locales/fr.json
- web/default/src/i18n/locales/zh.json
- web/default/src/i18n/locales/vi.json
- web/default/src/i18n/locales/ja.json
- web/default/src/i18n/locales/zh-TW.json
- web/default/src/i18n/locales/ru.json
🚧 Files skipped from review as they are similar to previous changes (23)
- web/default/src/features/playground/api.ts
- web/default/src/features/keys/components/api-key-group-combobox.tsx
- web/default/src/components/model-group-selector.tsx
- constant/context_key.go
- web/default/src/features/keys/components/api-keys-columns.tsx
- controller/model_list_test.go
- controller/user.go
- controller/token_test.go
- model/ability.go
- controller/model_owned_by_test.go
- controller/group.go
- service/channel_select.go
- controller/token.go
- controller/model.go
- web/default/src/features/playground/types.ts
- web/default/src/features/keys/lib/api-key-form.ts
- middleware/auth.go
- model/token.go
- web/default/src/features/keys/components/api-keys-mutate-drawer.tsx
- web/default/src/features/keys/types.ts
- web/default/src/i18n/locales/en.json
- service/group_test.go
- service/group.go
Important
📝 变更描述 / Description
新增
AutoOpt虚拟分组,在用户当前有权使用且已配置倍率的分组中,按用户实际分组倍率从低到高选择能够服务当前模型的渠道。相同倍率使用分组名稳定排序,渠道选择复用现有缓存、优先级和重试逻辑。令牌可以为
AutoOpt配置白名单或黑名单。创建和更新令牌时,服务端会校验模式和分组权限,限制过滤字段长度,并对分组去重、排序和归一化。请求执行时会再次与用户的当前可用分组取交集,防止历史令牌配置扩大权限;无效配置会拒绝或 fail closed。web/default的令牌编辑界面增加白名单/黑名单切换和多分组选择,并补齐 7 个 locale 的文案。本 PR 不包含 Classic 前端改动。AI 辅助声明:本次代码在 Codex 辅助下实现、审查和验证,提交者将在提交 PR 前人工检查最终差异和本描述。
🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。📸 运行证明 / Proof of Work
Summary by CodeRabbit
New Features
Bug Fixes
Tests
Documentation