Merge pull request #532 from RWDai/opencode/cosmic-nebula

fix: raise group rate limits by access tier
This commit is contained in:
fawney19
2026-05-21 19:39:50 +08:00
committed by GitHub
2 changed files with 66 additions and 18 deletions

View File

@@ -2000,7 +2000,7 @@ fn resolve_effective_rate_limit_policy(
groups: &[aether_data::repository::users::StoredUserGroup],
) -> Option<i32> {
let group_policy = groups.iter().fold(None, |effective, group| {
intersect_rate_limit_policies(
union_rate_limit_policies(
effective,
rate_limit_restriction_from_mode(&group.rate_limit_mode, group.rate_limit),
)
@@ -2073,6 +2073,22 @@ fn intersect_rate_limit_policies(
}
}
fn union_rate_limit_policies(
left: Option<RateLimitRestriction>,
right: Option<RateLimitRestriction>,
) -> Option<RateLimitRestriction> {
match (left, right) {
(None, None) => None,
(Some(value), None) | (None, Some(value)) => Some(value),
(Some(RateLimitRestriction::Unlimited), _) | (_, Some(RateLimitRestriction::Unlimited)) => {
Some(RateLimitRestriction::Unlimited)
}
(Some(RateLimitRestriction::Limited(left)), Some(RateLimitRestriction::Limited(right))) => {
Some(RateLimitRestriction::Limited(left.max(right)))
}
}
}
fn rate_limit_policy_value(policy: Option<RateLimitRestriction>) -> Option<i32> {
match policy {
None => None,
@@ -2358,35 +2374,44 @@ mod tests {
}
#[test]
fn rate_limit_policy_uses_most_restrictive_custom_limit() {
let groups = vec![sample_group(
"restricted",
10,
None,
"unrestricted",
Some(60),
"custom",
)];
fn rate_limit_policy_uses_highest_group_limit_before_user_restriction() {
let groups = vec![
sample_group("default", 10, None, "unrestricted", Some(30), "custom"),
sample_group("tier-1", 20, None, "unrestricted", Some(100), "custom"),
];
assert_eq!(
resolve_effective_rate_limit_policy(Some(120), "custom", &groups),
Some(60)
Some(100)
);
}
#[test]
fn rate_limit_unlimited_does_not_bypass_limited_group() {
fn rate_limit_unlimited_group_overrides_limited_groups() {
let groups = vec![
sample_group("default", 10, None, "unrestricted", Some(30), "custom"),
sample_group("tier-2", 20, None, "unrestricted", Some(0), "custom"),
];
assert_eq!(
resolve_effective_rate_limit_policy(None, "system", &groups),
Some(0)
);
}
#[test]
fn rate_limit_user_policy_still_restricts_group_grants() {
let groups = vec![sample_group(
"restricted",
"tier-1",
10,
None,
"unrestricted",
Some(60),
Some(100),
"custom",
)];
assert_eq!(
resolve_effective_rate_limit_policy(Some(0), "custom", &groups),
resolve_effective_rate_limit_policy(Some(60), "custom", &groups),
Some(60)
);
}

View File

@@ -128,8 +128,25 @@
<div class="space-y-4 border-t border-border/60 pt-5">
<div class="flex flex-wrap items-baseline justify-between gap-x-2 gap-y-1 pb-2 border-b border-border/60">
<span class="text-sm font-medium">组权限</span>
<span class="text-[11px] text-muted-foreground">
多个组与用户额外限制取交集
<span class="flex items-center gap-1 text-[11px] text-muted-foreground">
组权限叠加Key 可再收窄
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<button
type="button"
class="inline-flex h-4 w-4 items-center justify-center rounded-full border border-border/70 bg-muted/40 text-muted-foreground outline-none transition-colors hover:border-primary/50 hover:text-primary focus-visible:border-primary/60 focus-visible:text-primary"
:title="groupPolicyHelpText"
aria-label="查看组权限合并规则"
>
<Info class="h-3 w-3" />
</button>
</TooltipTrigger>
<TooltipContent class="max-w-72 text-xs leading-5">
{{ groupPolicyHelpText }}
</TooltipContent>
</Tooltip>
</TooltipProvider>
</span>
</div>
@@ -247,7 +264,7 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { BadgeCheck, ChevronRight, Plus, Trash2 } from 'lucide-vue-next'
import { BadgeCheck, ChevronRight, Info, Plus, Trash2 } from 'lucide-vue-next'
import {
Badge,
Button,
@@ -255,6 +272,10 @@ import {
Input,
Label,
Switch,
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '@/components/ui'
import { MultiSelect } from '@/components/common'
import { useUsersStore } from '@/stores/users'
@@ -302,6 +323,8 @@ const USER_OPTIONS_CACHE_TTL_MS = 30 * 1000
let dialogUsersLoadedAt = 0
let dialogUsersLoadedVersion = -1
const groupPolicyHelpText = '模型、供应商和端点会在多个用户组之间叠加授权unrestricted 仍表示不限制deny_all 只是不授予额外权限。速率限制按付费档位取更高额度0 表示不限速;用户/API Key 自身限制仍会收窄最终权限。'
const form = ref({
name: '',
allowed_providers_mode: 'unrestricted' as ListPolicyMode,