add force priority fast policy action

This commit is contained in:
NellPoi
2026-07-07 15:27:23 +08:00
parent b5b0ea3460
commit e979990bf9
9 changed files with 82 additions and 7 deletions
@@ -179,6 +179,26 @@ func TestApplyOpenAIFastPolicyToBody_ExplicitFilterRemovesField(t *testing.T) {
require.NotContains(t, string(updated), `"service_tier"`)
}
func TestApplyOpenAIFastPolicyToBody_ForcePriorityRewritesKnownTier(t *testing.T) {
settings := &OpenAIFastPolicySettings{
Rules: []OpenAIFastPolicyRule{{
ServiceTier: OpenAIFastTierAny,
Action: OpenAIFastPolicyActionForcePriority,
Scope: BetaPolicyScopeAll,
}},
}
svc := newOpenAIGatewayServiceWithSettings(t, settings)
account := &Account{Platform: PlatformOpenAI, Type: AccountTypeAPIKey}
for _, tier := range []string{"flex", "auto", "default", "scale", "fast", "priority"} {
body := []byte(`{"model":"gpt-5.5","service_tier":"` + tier + `"}`)
updated, err := svc.applyOpenAIFastPolicyToBody(context.Background(), account, "gpt-5.5", body)
require.NoError(t, err)
require.Equal(t, OpenAIFastTierPriority, gjson.GetBytes(updated, "service_tier").String(),
"tier %q should be forced to priority", tier)
}
}
// TestApplyOpenAIFastPolicyToBody_OfficialTiersBypassDefaultRule 验证默认配置
// 下客户端显式发送的 OpenAI 官方合法 tier 能透传到上游而不被静默剥离。
func TestApplyOpenAIFastPolicyToBody_OfficialTiersBypassDefaultRule(t *testing.T) {
@@ -293,7 +313,7 @@ func TestSetOpenAIFastPolicySettings_Validation(t *testing.T) {
err = svc.SetOpenAIFastPolicySettings(context.Background(), &OpenAIFastPolicySettings{
Rules: []OpenAIFastPolicyRule{{
ServiceTier: OpenAIFastTierPriority,
Action: BetaPolicyActionFilter,
Action: OpenAIFastPolicyActionForcePriority,
Scope: BetaPolicyScopeAll,
}},
})
@@ -303,4 +323,5 @@ func TestSetOpenAIFastPolicySettings_Validation(t *testing.T) {
require.NoError(t, err)
require.Len(t, got.Rules, 1)
require.Equal(t, OpenAIFastTierPriority, got.Rules[0].ServiceTier)
require.Equal(t, OpenAIFastPolicyActionForcePriority, got.Rules[0].Action)
}
@@ -67,6 +67,27 @@ func TestWSResponseCreate_ExplicitFilterStripsServiceTier(t *testing.T) {
require.NotContains(t, string(updated), `"service_tier"`)
}
func TestWSResponseCreate_ForcePriorityRewritesKnownTier(t *testing.T) {
settings := &OpenAIFastPolicySettings{
Rules: []OpenAIFastPolicyRule{{
ServiceTier: OpenAIFastTierAny,
Action: OpenAIFastPolicyActionForcePriority,
Scope: BetaPolicyScopeAll,
}},
}
svc := newOpenAIGatewayServiceWithSettings(t, settings)
account := &Account{Platform: PlatformOpenAI, Type: AccountTypeAPIKey}
for _, tier := range []string{"flex", "auto", "default", "scale", "fast", "priority"} {
frame := []byte(`{"type":"response.create","model":"gpt-5.5","service_tier":"` + tier + `"}`)
updated, blocked, err := svc.applyOpenAIFastPolicyToWSResponseCreate(context.Background(), account, "gpt-5.5", frame)
require.NoError(t, err)
require.Nil(t, blocked)
require.Equal(t, OpenAIFastTierPriority, gjson.GetBytes(updated, "service_tier").String(),
"tier %q should be forced to priority", tier)
}
}
func TestWSResponseCreate_FlexPassThrough(t *testing.T) {
svc := newOpenAIGatewayServiceWithSettings(t, DefaultOpenAIFastPolicySettings())
account := &Account{Platform: PlatformOpenAI, Type: AccountTypeAPIKey}
@@ -2973,6 +2973,10 @@ func (s *OpenAIGatewayService) Forward(ctx context.Context, c *gin.Context, acco
return nil, blocked
case BetaPolicyActionFilter:
markPatchDelete("service_tier")
case OpenAIFastPolicyActionForcePriority:
if rawTier != OpenAIFastTierPriority {
markPatchSet("service_tier", OpenAIFastTierPriority)
}
default:
if normTier != rawTier {
markPatchSet("service_tier", normTier)
@@ -7365,8 +7369,8 @@ func openAIFastPolicySettingsFromContext(ctx context.Context) *OpenAIFastPolicyS
// applyOpenAIFastPolicyToBody applies the OpenAI fast policy to a raw request
// body. When action=filter it removes the service_tier field; when
// action=block it returns (body, *OpenAIFastBlockedError). On pass it
// normalizes the service_tier value (e.g. client alias "fast" → "priority"),
// rewriting the body so the upstream receives a slug it recognizes.
// normalizes the service_tier value (e.g. client alias "fast" → "priority").
// action=force_priority rewrites any matched known tier to "priority".
//
// Rationale for normalize-on-pass: chat-completions / messages 入口在调用本
// 函数之前已经通过 normalizeResponsesBodyServiceTier 把 service_tier 归一化
@@ -7399,6 +7403,12 @@ func (s *OpenAIGatewayService) applyOpenAIFastPolicyToBody(ctx context.Context,
return body, fmt.Errorf("strip service_tier from body: %w", err)
}
return trimmed, nil
case OpenAIFastPolicyActionForcePriority:
updated, err := sjson.SetBytes(body, "service_tier", OpenAIFastTierPriority)
if err != nil {
return body, fmt.Errorf("force service_tier priority on body: %w", err)
}
return updated, nil
default:
// pass:把别名(如 "fast")写回为规范值("priority")。
if normTier == rawTier {
@@ -7435,6 +7445,7 @@ func writeOpenAIFastPolicyBlockedResponse(c *gin.Context, err *OpenAIFastBlocked
//
// - pass: keeps service_tier, normalizing aliases such as "fast" to "priority"
// - filter: returns a copy with top-level service_tier removed
// - force_priority: keeps service_tier and rewrites it to "priority"
// - block: returns (frame, *OpenAIFastBlockedError)
//
// Only frames whose "type" field strictly equals "response.create" are
@@ -7496,6 +7507,12 @@ func (s *OpenAIGatewayService) applyOpenAIFastPolicyToWSResponseCreate(
return frame, nil, fmt.Errorf("strip service_tier from ws frame: %w", err)
}
return trimmed, nil, nil
case OpenAIFastPolicyActionForcePriority:
updated, err := sjson.SetBytes(frame, "service_tier", OpenAIFastTierPriority)
if err != nil {
return frame, nil, fmt.Errorf("force service_tier priority in ws frame: %w", err)
}
return updated, nil, nil
default:
if normTier == rawTier {
return frame, nil, nil
@@ -5336,6 +5336,7 @@ func (s *SettingService) SetOpenAIFastPolicySettings(ctx context.Context, settin
validActions := map[string]bool{
BetaPolicyActionPass: true, BetaPolicyActionFilter: true, BetaPolicyActionBlock: true,
OpenAIFastPolicyActionForcePriority: true,
}
validScopes := map[string]bool{
BetaPolicyScopeAll: true, BetaPolicyScopeOAuth: true, BetaPolicyScopeAPIKey: true, BetaPolicyScopeBedrock: true,
+5 -1
View File
@@ -575,12 +575,16 @@ const (
OpenAIFastTierAny = "all" // 匹配任意已识别的 service_tier
OpenAIFastTierPriority = "priority" // 仅匹配 fast(priority)
OpenAIFastTierFlex = "flex" // 仅匹配 flex
// OpenAIFastPolicyActionForcePriority 会保留 service_tier 字段并强制写成
// priority,用于把 flex/auto/default/scale 等已识别 tier 收敛为 fast。
OpenAIFastPolicyActionForcePriority = "force_priority"
)
// OpenAIFastPolicyRule 单条 OpenAI fast/flex 策略规则
type OpenAIFastPolicyRule struct {
ServiceTier string `json:"service_tier"` // "priority" | "flex" | "auto" | "default" | "scale" | "all"
Action string `json:"action"` // "pass" | "filter" | "block"
Action string `json:"action"` // "pass" | "filter" | "block" | "force_priority"
Scope string `json:"scope"` // "all" | "oauth" | "apikey" | "bedrock"
ErrorMessage string `json:"error_message,omitempty"` // 自定义错误消息 (action=block 时生效)
ModelWhitelist []string `json:"model_whitelist,omitempty"` // 模型匹配模式列表(为空=对所有模型生效)
+2 -2
View File
@@ -1273,11 +1273,11 @@ export async function updateRectifierSettings(
*/
export interface OpenAIFastPolicyRule {
service_tier: "all" | "priority" | "flex";
action: "pass" | "filter" | "block";
action: "pass" | "filter" | "block" | "force_priority";
scope: "all" | "oauth" | "apikey" | "bedrock";
error_message?: string;
model_whitelist?: string[];
fallback_action?: "pass" | "filter" | "block";
fallback_action?: "pass" | "filter" | "block" | "force_priority";
fallback_error_message?: string;
}
+1
View File
@@ -6686,6 +6686,7 @@ export default {
action: 'Action',
actionPass: 'Pass (keep service_tier)',
actionFilter: 'Filter (remove service_tier)',
actionForcePriority: 'Force priority (fast)',
actionBlock: 'Block (reject request)',
scope: 'Scope',
scopeAll: 'All accounts',
+1
View File
@@ -6840,6 +6840,7 @@ export default {
action: '处理方式',
actionPass: '透传(保留 service_tier)',
actionFilter: '过滤(移除 service_tier)',
actionForcePriority: '强制设置 priority(fast)',
actionBlock: '拦截(拒绝请求)',
scope: '生效范围',
scopeAll: '全部账号',
+10 -1
View File
@@ -1158,7 +1158,11 @@
<Select
:modelValue="rule.action"
@update:modelValue="
rule.action = $event as 'pass' | 'filter' | 'block'
rule.action = $event as
| 'pass'
| 'filter'
| 'block'
| 'force_priority'
"
:options="openaiFastPolicyActionOptions"
/>
@@ -1297,6 +1301,7 @@
| 'pass'
| 'filter'
| 'block'
| 'force_priority'
"
:options="openaiFastPolicyActionOptions"
/>
@@ -10115,6 +10120,10 @@ const openaiFastPolicyTierOptions = computed(() => [
const openaiFastPolicyActionOptions = computed(() => [
{ value: "pass", label: t("admin.settings.openaiFastPolicy.actionPass") },
{ value: "filter", label: t("admin.settings.openaiFastPolicy.actionFilter") },
{
value: "force_priority",
label: t("admin.settings.openaiFastPolicy.actionForcePriority"),
},
{ value: "block", label: t("admin.settings.openaiFastPolicy.actionBlock") },
]);