@@ -22,34 +22,45 @@ import (
2222
2323// --- Helper-level (unit) tests for applyOpenAIFastPolicyToWSResponseCreate ---
2424
25- func TestWSResponseCreate_FilterStripsServiceTier (t * testing.T ) {
25+ func TestWSResponseCreate_DefaultPassesPriorityAndNormalizesFast (t * testing.T ) {
2626 svc := newOpenAIGatewayServiceWithSettings (t , DefaultOpenAIFastPolicySettings ())
2727 account := & Account {Platform : PlatformOpenAI , Type : AccountTypeAPIKey }
2828
2929 frame := []byte (`{"type":"response.create","model":"gpt-5.5","service_tier":"priority","input":[{"type":"input_text","text":"hi"}]}` )
3030 updated , blocked , err := svc .applyOpenAIFastPolicyToWSResponseCreate (context .Background (), account , "gpt-5.5" , frame )
3131 require .NoError (t , err )
3232 require .Nil (t , blocked )
33- require .NotContains (t , string (updated ), ` "service_tier"` , "filter action should strip service_tier " )
33+ require .Equal (t , "priority" , gjson . GetBytes (updated , "service_tier" ). String () , "default policy should preserve priority tier " )
3434 // Other fields preserved.
3535 require .Equal (t , "response.create" , gjson .GetBytes (updated , "type" ).String ())
3636 require .Equal (t , "gpt-5.5" , gjson .GetBytes (updated , "model" ).String ())
3737 require .Equal (t , "hi" , gjson .GetBytes (updated , "input.0.text" ).String ())
38+
39+ frame = []byte (`{"type":"response.create","model":"gpt-5.5","service_tier":"fast"}` )
40+ updated , blocked , err = svc .applyOpenAIFastPolicyToWSResponseCreate (context .Background (), account , "gpt-5.5" , frame )
41+ require .NoError (t , err )
42+ require .Nil (t , blocked )
43+ require .Equal (t , "priority" , gjson .GetBytes (updated , "service_tier" ).String (), "fast alias should normalize before reaching upstream" )
44+
45+ // Mixed-case + whitespace variant should also normalize.
46+ frame = []byte (`{"type":"response.create","model":"gpt-5.5","service_tier":" Fast "}` )
47+ updated , blocked , err = svc .applyOpenAIFastPolicyToWSResponseCreate (context .Background (), account , "gpt-5.5" , frame )
48+ require .NoError (t , err )
49+ require .Nil (t , blocked )
50+ require .Equal (t , "priority" , gjson .GetBytes (updated , "service_tier" ).String ())
3851}
3952
40- func TestWSResponseCreate_FastNormalizedToPriorityThenFiltered (t * testing.T ) {
41- svc := newOpenAIGatewayServiceWithSettings (t , DefaultOpenAIFastPolicySettings ())
53+ func TestWSResponseCreate_ExplicitFilterStripsServiceTier (t * testing.T ) {
54+ svc := newOpenAIGatewayServiceWithSettings (t , openAIFastFilterPriorityPolicy ())
4255 account := & Account {Platform : PlatformOpenAI , Type : AccountTypeAPIKey }
4356
44- // Verbatim "fast" → normalized to "priority" → matches default rule → filter.
45- frame := []byte (`{"type":"response.create","model":"gpt-5.5","service_tier":"fast"}` )
57+ frame := []byte (`{"type":"response.create","model":"gpt-5.5","service_tier":"priority","input":[{"type":"input_text","text":"hi"}]}` )
4658 updated , blocked , err := svc .applyOpenAIFastPolicyToWSResponseCreate (context .Background (), account , "gpt-5.5" , frame )
4759 require .NoError (t , err )
4860 require .Nil (t , blocked )
49- require .NotContains (t , string (updated ), `"service_tier"` )
61+ require .NotContains (t , string (updated ), `"service_tier"` , "filter action should strip service_tier" )
5062
51- // Mixed-case + whitespace variant should also normalize and filter.
52- frame = []byte (`{"type":"response.create","model":"gpt-5.5","service_tier":" Fast "}` )
63+ frame = []byte (`{"type":"response.create","model":"gpt-5.5","service_tier":"fast"}` )
5364 updated , blocked , err = svc .applyOpenAIFastPolicyToWSResponseCreate (context .Background (), account , "gpt-5.5" , frame )
5465 require .NoError (t , err )
5566 require .Nil (t , blocked )
@@ -60,7 +71,7 @@ func TestWSResponseCreate_FlexPassThrough(t *testing.T) {
6071 svc := newOpenAIGatewayServiceWithSettings (t , DefaultOpenAIFastPolicySettings ())
6172 account := & Account {Platform : PlatformOpenAI , Type : AccountTypeAPIKey }
6273
63- // Default policy targets priority only ; flex is left untouched.
74+ // Default policy has no rules ; flex is left untouched.
6475 frame := []byte (`{"type":"response.create","model":"gpt-5.5","service_tier":"flex"}` )
6576 updated , blocked , err := svc .applyOpenAIFastPolicyToWSResponseCreate (context .Background (), account , "gpt-5.5" , frame )
6677 require .NoError (t , err )
@@ -220,8 +231,8 @@ func (f *fakePassthroughFrameConn) Close() error {
220231}
221232
222233// gpt55WhitelistFastPolicy 返回一份强制带 model whitelist 的策略,用于
223- // 验证 capturedSessionModel fallback 的语义(默认策略 whitelist 为空时
224- // fallback 路径无法被观察到)。
234+ // 验证 capturedSessionModel fallback 的语义(默认配置没有规则,fallback
235+ // 路径无法被观察到)。
225236func gpt55WhitelistFastPolicy () * OpenAIFastPolicySettings {
226237 return & OpenAIFastPolicySettings {
227238 Rules : []OpenAIFastPolicyRule {{
@@ -242,7 +253,7 @@ func gpt55WhitelistFastPolicy() *OpenAIFastPolicySettings {
242253// through to the upstream.
243254func TestPolicyEnforcingFrameConn_FollowupFrameWithoutModelUsesCapturedModel (t * testing.T ) {
244255 // 此处特意使用带 whitelist 的策略,以便观察 capturedSessionModel
245- // fallback 是否生效(默认策略 whitelist 为空 ,fallback 与否结果一致,
256+ // fallback 是否生效(默认配置没有规则 ,fallback 与否结果一致,
246257 // 不能用来覆盖此回归)。
247258 svc := newOpenAIGatewayServiceWithSettings (t , gpt55WhitelistFastPolicy ())
248259 account := & Account {Platform : PlatformOpenAI , Type : AccountTypeAPIKey }
@@ -310,13 +321,13 @@ func TestPolicyEnforcingFrameConn_WithoutCapturedFallbackPolicyMisses(t *testing
310321 "sanity: without capturedSessionModel fallback the leak (D5) reproduces — confirms the fix is load-bearing" )
311322}
312323
313- // --- Ingress end-to-end test (filter path) ---
324+ // --- Ingress end-to-end test (explicit filter path) ---
314325
315326// TestWSResponseCreate_IngressFiltersServiceTierBeforeUpstream wires up the
316327// real ProxyResponsesWebSocketFromClient ingress session pipeline against a
317328// captureConn upstream and asserts that a client frame with service_tier=fast
318- // is normalized + filtered out before being written upstream. This is the
319- // integration flavour of TestWSResponseCreate_FilterStripsServiceTier .
329+ // is normalized + filtered out by an explicit admin policy before being
330+ // written upstream .
320331func TestWSResponseCreate_IngressFiltersServiceTierBeforeUpstream (t * testing.T ) {
321332 gin .SetMode (gin .TestMode )
322333
@@ -345,9 +356,9 @@ func TestWSResponseCreate_IngressFiltersServiceTierBeforeUpstream(t *testing.T)
345356 pool .setClientDialerForTest (captureDialer )
346357
347358 repo := & openAIFastPolicyRepoStub {values : map [string ]string {}}
348- defaultJSON , err := json .Marshal (DefaultOpenAIFastPolicySettings ())
359+ filterPolicyJSON , err := json .Marshal (openAIFastFilterPriorityPolicy ())
349360 require .NoError (t , err )
350- repo .values [SettingKeyOpenAIFastPolicySettings ] = string (defaultJSON )
361+ repo .values [SettingKeyOpenAIFastPolicySettings ] = string (filterPolicyJSON )
351362
352363 svc := & OpenAIGatewayService {
353364 cfg : cfg ,
@@ -631,13 +642,13 @@ func TestApplyOpenAIFastPolicyToBody_BlockShortCircuitsUpstream(t *testing.T) {
631642 require .Equal (t , string (body ), string (updated ), "block must not mutate body" )
632643}
633644
634- // TestForwardAsAnthropicMessages_BetaFastModeTriggersOpenAIFastPolicy verifies
635- // the Anthropic-compat entrypoint chain: anthropic-beta: fast-mode → BetaFastMode
636- // detection → ServiceTier="priority" injection (openai_gateway_messages.go:60)
637- // → applyOpenAIFastPolicyToBody filter on default policy → upstream body has
638- // no service_tier. We exercise the same internal pipeline (Anthropic→Responses
639- // + BetaFastMode + policy) without spinning up a real upstream HTTP server.
640- func TestForwardAsAnthropicMessages_BetaFastModeTriggersOpenAIFastPolicy (t * testing.T ) {
645+ // TestForwardAsAnthropicMessages_BetaFastModePassesOpenAIFastPolicyByDefault
646+ // verifies the Anthropic-compat entrypoint chain: anthropic-beta: fast-mode →
647+ // BetaFastMode detection → ServiceTier="priority" injection
648+ // (openai_gateway_messages.go:60) → default OpenAI fast policy pass. We
649+ // exercise the same internal pipeline (Anthropic→Responses + BetaFastMode +
650+ // policy) without spinning up a real upstream HTTP server.
651+ func TestForwardAsAnthropicMessages_BetaFastModePassesOpenAIFastPolicyByDefault (t * testing.T ) {
641652 svc := newOpenAIGatewayServiceWithSettings (t , DefaultOpenAIFastPolicySettings ())
642653 account := & Account {Platform : PlatformOpenAI , Type : AccountTypeAPIKey }
643654
@@ -663,8 +674,9 @@ func TestForwardAsAnthropicMessages_BetaFastModeTriggersOpenAIFastPolicy(t *test
663674 upstreamBody , policyErr := svc .applyOpenAIFastPolicyToBody (context .Background (), account , "gpt-5.5" , responsesBody )
664675 require .NoError (t , policyErr )
665676
666- // Step 4: assert that policy filtered the field before the upstream HTTP request.
667- require .NotContains (t , string (upstreamBody ), `"service_tier"` , "default policy 命中 gpt-5.5 priority 应当 filter 掉 service_tier" )
677+ // Step 4: default policy must preserve the explicit fast/priority request.
678+ require .Equal (t , "priority" , gjson .GetBytes (upstreamBody , "service_tier" ).String (),
679+ "default policy should pass service_tier=priority through to upstream" )
668680}
669681
670682// --- Fix1: passthrough capturedSessionModel must follow session.update ---
@@ -808,7 +820,7 @@ func TestApplyOpenAIFastPolicyToBody_PassNormalizesFastAlias(t *testing.T) {
808820// tier) instead of the user-requested "priority". This test pins the
809821// contract those two helpers must uphold for the adapter's billing path.
810822func TestPassthroughBilling_PostFilterServiceTier (t * testing.T ) {
811- svc := newOpenAIGatewayServiceWithSettings (t , DefaultOpenAIFastPolicySettings ())
823+ svc := newOpenAIGatewayServiceWithSettings (t , openAIFastFilterPriorityPolicy ())
812824 account := & Account {Platform : PlatformOpenAI , Type : AccountTypeAPIKey }
813825
814826 raw := []byte (`{"type":"response.create","model":"gpt-5.5","service_tier":"priority"}` )
@@ -821,7 +833,7 @@ func TestPassthroughBilling_PostFilterServiceTier(t *testing.T) {
821833 require .Equal (t , "priority" , * pre ,
822834 "sanity: raw first frame carries priority that pre-fix billing would have reported" )
823835
824- // Apply policy filter (default rule: gpt-5.5 + priority → filter).
836+ // Apply explicit policy filter (gpt-5.5 + priority → filter).
825837 filtered , blocked , err := svc .applyOpenAIFastPolicyToWSResponseCreate (context .Background (), account , "gpt-5.5" , raw )
826838 require .NoError (t , err )
827839 require .Nil (t , blocked )
@@ -890,17 +902,17 @@ func TestApplyOpenAIFastPolicyToBody_NonStringServiceTier(t *testing.T) {
890902// atomic.Pointer[string] on every successful response.create frame.
891903//
892904// This test pins the four legs of the semantic contract:
893- // - turn 1: service_tier=priority hits the default whitelist filter, so
905+ // - turn 1: service_tier=priority hits the explicit filter rule , so
894906// after filter the upstream sees no tier → billing is nil.
895- // - turn 2: service_tier=flex passes (default rule targets priority only),
907+ // - turn 2: service_tier=flex passes (the filter rule targets priority only),
896908// billing should now reflect "flex".
897909// - turn 3: response.create without any service_tier — the upstream will
898910// treat it as default; we choose to mirror that and overwrite billing
899911// to nil rather than carry over "flex" from turn 2.
900912// - non-response.create frame (response.cancel here) carrying a stray
901913// service_tier-shaped field must NOT clobber the billing pointer.
902914func TestPassthroughBilling_MultiTurnServiceTierFollowsFilteredFrames (t * testing.T ) {
903- svc := newOpenAIGatewayServiceWithSettings (t , DefaultOpenAIFastPolicySettings ())
915+ svc := newOpenAIGatewayServiceWithSettings (t , openAIFastFilterPriorityPolicy ())
904916 account := & Account {Platform : PlatformOpenAI , Type : AccountTypeAPIKey }
905917
906918 // Mirror the production filter closure (openai_ws_v2_passthrough_adapter.go
0 commit comments