From 3663951d11a2e1963b86d1f4d1667b07043aaa5d Mon Sep 17 00:00:00 2001 From: yangjianbo Date: Wed, 14 Jan 2026 09:17:58 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix(=E7=BD=91=E5=85=B3):=20OAuth=20?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E5=BC=BA=E5=88=B6=20store=3Dfalse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 避免上游 Store 必须为 false 的错误 仅在缺失或 true 时写回 store 测试: go test ./internal/service -run TestApplyCodexOAuthTransform 测试: make test-backend(golangci-lint 已单独执行) --- .../service/openai_codex_transform.go | 19 +++++------ .../service/openai_codex_transform_test.go | 34 +++++++++++++++---- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/backend/internal/service/openai_codex_transform.go b/backend/internal/service/openai_codex_transform.go index dcc30fc1..99c78310 100644 --- a/backend/internal/service/openai_codex_transform.go +++ b/backend/internal/service/openai_codex_transform.go @@ -90,17 +90,14 @@ 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 { + reqBody["store"] = false + result.Modified = true + } else if 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"}, }, From 9c567fad92dd3f3776790a7ad0d8f1d5f78d9d3b Mon Sep 17 00:00:00 2001 From: yangjianbo Date: Wed, 14 Jan 2026 09:46:10 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix(=E7=BD=91=E5=85=B3):=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96=20OAuth=20=E8=AF=B7=E6=B1=82=E4=B8=AD=20store=20?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E7=9A=84=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/service/openai_codex_transform.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/backend/internal/service/openai_codex_transform.go b/backend/internal/service/openai_codex_transform.go index 99c78310..264bdf95 100644 --- a/backend/internal/service/openai_codex_transform.go +++ b/backend/internal/service/openai_codex_transform.go @@ -92,10 +92,7 @@ func applyCodexOAuthTransform(reqBody map[string]any) codexTransformResult { // OAuth 走 ChatGPT internal API 时,store 必须为 false;显式 true 也会强制覆盖。 // 避免上游返回 "Store must be set to false"。 - if v, ok := reqBody["store"].(bool); !ok { - reqBody["store"] = false - result.Modified = true - } else if v { + if v, ok := reqBody["store"].(bool); !ok || v { reqBody["store"] = false result.Modified = true } From 99cbfa1567c5f364dbd9381159a50e30eafeb9bb Mon Sep 17 00:00:00 2001 From: shaw Date: Wed, 14 Jan 2026 10:22:31 +0800 Subject: [PATCH 3/3] =?UTF-8?q?fix(admin):=20=E4=BF=AE=E5=A4=8D=E9=80=80?= =?UTF-8?q?=E6=AC=BE=E9=87=91=E9=A2=9D=E7=B2=BE=E5=BA=A6=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 显示完整余额精度,避免四舍五入导致的退款失败 - 添加"全部"按钮,一键填入完整余额 - 移除最小金额限制,支持任意正数金额 --- .../admin/user/UserBalanceModal.vue | 36 ++++++++++++++----- frontend/src/i18n/locales/en.ts | 1 + frontend/src/i18n/locales/zh.ts | 1 + 3 files changed, 30 insertions(+), 8 deletions(-) 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()) }}