diff --git a/backend/internal/service/openai_codex_transform.go b/backend/internal/service/openai_codex_transform.go index dcc30fc1..264bdf95 100644 --- a/backend/internal/service/openai_codex_transform.go +++ b/backend/internal/service/openai_codex_transform.go @@ -90,17 +90,11 @@ func applyCodexOAuthTransform(reqBody map[string]any) codexTransformResult { result.NormalizedModel = normalizedModel } - // 续链场景强制启用 store;非续链仍按原策略强制关闭存储。 - if needsToolContinuation { - if v, ok := reqBody["store"].(bool); !ok || !v { - reqBody["store"] = true - result.Modified = true - } - } else { - if v, ok := reqBody["store"].(bool); !ok || v { - reqBody["store"] = false - result.Modified = true - } + // OAuth 走 ChatGPT internal API 时,store 必须为 false;显式 true 也会强制覆盖。 + // 避免上游返回 "Store must be set to false"。 + if v, ok := reqBody["store"].(bool); !ok || v { + reqBody["store"] = false + result.Modified = true } if v, ok := reqBody["stream"].(bool); !ok || !v { reqBody["stream"] = true diff --git a/backend/internal/service/openai_codex_transform_test.go b/backend/internal/service/openai_codex_transform_test.go index 9663229f..0ff9485a 100644 --- a/backend/internal/service/openai_codex_transform_test.go +++ b/backend/internal/service/openai_codex_transform_test.go @@ -11,7 +11,7 @@ import ( ) func TestApplyCodexOAuthTransform_ToolContinuationPreservesInput(t *testing.T) { - // 续链场景:保留 item_reference 与 id,并启用 store。 + // 续链场景:保留 item_reference 与 id,但不再强制 store=true。 setupCodexCache(t) reqBody := map[string]any{ @@ -25,9 +25,10 @@ func TestApplyCodexOAuthTransform_ToolContinuationPreservesInput(t *testing.T) { applyCodexOAuthTransform(reqBody) + // 未显式设置 store=true,默认为 false。 store, ok := reqBody["store"].(bool) require.True(t, ok) - require.True(t, store) + require.False(t, store) input, ok := reqBody["input"].([]any) require.True(t, ok) @@ -45,8 +46,8 @@ func TestApplyCodexOAuthTransform_ToolContinuationPreservesInput(t *testing.T) { require.Equal(t, "o1", second["id"]) } -func TestApplyCodexOAuthTransform_ToolContinuationForcesStoreTrue(t *testing.T) { - // 续链场景:显式 store=false 也会被强制为 true。 +func TestApplyCodexOAuthTransform_ExplicitStoreFalsePreserved(t *testing.T) { + // 续链场景:显式 store=false 不再强制为 true,保持 false。 setupCodexCache(t) reqBody := map[string]any{ @@ -62,16 +63,35 @@ func TestApplyCodexOAuthTransform_ToolContinuationForcesStoreTrue(t *testing.T) store, ok := reqBody["store"].(bool) require.True(t, ok) - require.True(t, store) + require.False(t, store) } -func TestApplyCodexOAuthTransform_NonContinuationForcesStoreFalseAndStripsIDs(t *testing.T) { - // 非续链场景:强制 store=false,并移除 input 中的 id。 +func TestApplyCodexOAuthTransform_ExplicitStoreTrueForcedFalse(t *testing.T) { + // 显式 store=true 也会强制为 false。 setupCodexCache(t) reqBody := map[string]any{ "model": "gpt-5.1", "store": true, + "input": []any{ + map[string]any{"type": "function_call_output", "call_id": "call_1"}, + }, + "tool_choice": "auto", + } + + applyCodexOAuthTransform(reqBody) + + store, ok := reqBody["store"].(bool) + require.True(t, ok) + require.False(t, store) +} + +func TestApplyCodexOAuthTransform_NonContinuationDefaultsStoreFalseAndStripsIDs(t *testing.T) { + // 非续链场景:未设置 store 时默认 false,并移除 input 中的 id。 + setupCodexCache(t) + + reqBody := map[string]any{ + "model": "gpt-5.1", "input": []any{ map[string]any{"type": "text", "id": "t1", "text": "hi"}, }, diff --git a/frontend/src/components/admin/user/UserBalanceModal.vue b/frontend/src/components/admin/user/UserBalanceModal.vue index 61d4785e..c669c2a5 100644 --- a/frontend/src/components/admin/user/UserBalanceModal.vue +++ b/frontend/src/components/admin/user/UserBalanceModal.vue @@ -3,14 +3,17 @@
{{ user.email.charAt(0).toUpperCase() }}
-

{{ user.email }}

{{ t('admin.users.currentBalance') }}: ${{ user.balance.toFixed(2) }}

+

{{ user.email }}

{{ t('admin.users.currentBalance') }}: ${{ formatBalance(user.balance) }}

-
$
+
+
$
+ +
-
{{ t('admin.users.newBalance') }}:${{ calculateNewBalance().toFixed(2) }}
+
{{ t('admin.users.newBalance') }}:${{ formatBalance(calculateNewBalance()) }}