Skip to content

feat: codex channel#2652

Merged
Calcium-Ion merged 12 commits into
QuantumNous:mainfrom
seefs001:feature/codex-oauth
Jan 14, 2026
Merged

feat: codex channel#2652
Calcium-Ion merged 12 commits into
QuantumNous:mainfrom
seefs001:feature/codex-oauth

Conversation

@seefs001
Copy link
Copy Markdown
Collaborator

@seefs001 seefs001 commented Jan 12, 2026

Summary by CodeRabbit

  • New Features

    • Added Codex channel: OAuth sign-in flow, credential management (manual refresh + automated background refresh), streaming support, adaptor integration, new channel option and icon in UI.
    • New Codex OAuth modal in channel editor and Codex Usage modal (quota windows, raw payload export).
    • New API endpoints for Codex OAuth, credential refresh, and usage.
  • Bug Fixes

    • Improved error detail surfaced in responses.
    • Relaxed upstream response size limit to allow larger responses.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 12, 2026

Walkthrough

Adds a new Codex channel (type 57 / APITypeCodex) with a relay adaptor, PKCE OAuth start/complete/refresh flows, Wham usage fetch with refresh-on-401 retry, periodic credential auto-refresh task, controller endpoints/routes, frontend OAuth and usage modals, and supporting DTO/relay adjustments.

Changes

Cohort / File(s) Summary
Channel constants & mappings
constant/api_type.go, constant/channel.go, common/api_type.go
Add APITypeCodex and ChannelTypeCodex (57); update base URL/name mappings; map ChannelTypeCodexAPITypeCodex.
Relay codex adaptor & defs
relay/channel/codex/constants.go, relay/channel/codex/oauth_key.go, relay/channel/codex/adaptor.go, relay/common/relay_info.go, relay/relay_adaptor.go
New codex adaptor and ModelList/ChannelName; OAuthKey parser; mark Codex stream-capable; register adaptor in factory; adaptor implements header setup, Responses routing, and unsupported-endpoint responses.
OAuth service & token helpers
service/codex_oauth.go, service/codex_wham_usage.go
PKCE flow creation, token exchange/refresh, JWT claim extraction helpers; FetchCodexWhamUsage helper to call Codex Wham usage endpoint.
Credential refresh & task
service/codex_credential_refresh.go, service/codex_credential_refresh_task.go, main.go
RefreshCodexChannelCredential implementation and periodic auto-refresh task (master-only) with batching, per-channel timeouts, cache resets, and startup registration.
Controllers & routes
controller/codex_oauth.go, controller/channel.go, controller/codex_usage.go, router/api-router.go
Add OAuth start/complete handlers (generic + channel-scoped), refresh handler, GetCodexChannelUsage with refresh-on-401 retry; wire routes.
Frontend UI & integration
web/src/components/table/channels/modals/CodexOAuthModal.jsx, web/src/components/table/channels/modals/CodexUsageModal.jsx, web/src/components/table/channels/modals/EditChannelModal.jsx, web/src/hooks/channels/useChannelsData.jsx
Add Codex OAuth modal and Usage modal; EditChannelModal supports type 57 (JSON OAuth key, open modal, refresh action); hook fetches usage and opens modal.
Frontend constants & render
web/src/constants/channel.constants.js, web/src/helpers/render.jsx
Add CHANNEL_OPTIONS entry for Codex and map Codex icon to OpenAI icon.
DTO / error handling
dto/error.go
Add Detail field to GeneralErrorResponse and prefer it in ToMessage resolution.
Relay compatibility & responses
relay/channel/openai/chat_via_responses.go, relay/compatible_handler.go
Remove 10MB read-limit for OpenAI responses; refactor pass-through/Responses selection into local flag and helper.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant FrontendModal as Frontend (OAuth Modal)
    participant ControllerOAuth as Controller (OAuth)
    participant ServiceOAuth as Service (OAuth)
    participant ExternalOAuth as External (Codex OAuth)
    participant DB as Database

    User->>FrontendModal: Click "Start OAuth"
    FrontendModal->>ControllerOAuth: POST /codex/oauth/start
    ControllerOAuth->>ServiceOAuth: CreateCodexOAuthAuthorizationFlow()
    ServiceOAuth->>ServiceOAuth: Generate state + PKCE, build authorize URL
    ServiceOAuth-->>ControllerOAuth: {authorize_url, state, verifier}
    ControllerOAuth-->>FrontendModal: Return authorize URL
    User->>ExternalOAuth: Authenticate & authorize (browser)
    ExternalOAuth-->>User: Redirect with code (callback URL)
    User->>FrontendModal: Paste callback URL
    FrontendModal->>ControllerOAuth: POST /codex/oauth/complete (code,state)
    ControllerOAuth->>ServiceOAuth: ExchangeCodexAuthorizationCode(code,verifier)
    ServiceOAuth->>ExternalOAuth: POST token endpoint
    ExternalOAuth-->>ServiceOAuth: {access_token, refresh_token, expires_in, id_token}
    ServiceOAuth->>ControllerOAuth: TokenResult (with JWT claims)
    ControllerOAuth->>DB: Persist channel credential (or return key)
    ControllerOAuth-->>FrontendModal: Success + stored key
Loading
sequenceDiagram
    participant User
    participant Frontend as Client UI
    participant ControllerUsage as Controller (Usage)
    participant ServiceUsage as Service (Wham)
    participant ServiceOAuth as Service (OAuth)
    participant CodexAPI as Codex Wham API
    participant DB as Database

    User->>Frontend: Open usage for channel
    Frontend->>ControllerUsage: GET /api/channel/:id/codex/usage
    ControllerUsage->>DB: Load channel & OAuth key
    ControllerUsage->>ServiceUsage: FetchCodexWhamUsage(access_token)
    ServiceUsage->>CodexAPI: GET /backend-api/wham/usage
    alt 200
        CodexAPI-->>ServiceUsage: 200 + usage
        ServiceUsage-->>ControllerUsage: return data
    else 401/403
        CodexAPI-->>ServiceUsage: 401/403
        ControllerUsage->>ServiceOAuth: RefreshCodexOAuthToken(refresh_token)
        ServiceOAuth->>CodexAPI: POST token endpoint
        CodexAPI-->>ServiceOAuth: new tokens
        ControllerUsage->>DB: Update stored OAuth key + cache
        ControllerUsage->>ServiceUsage: Retry FetchCodexWhamUsage(new_access_token)
        CodexAPI-->>ServiceUsage: 200 + usage
        ServiceUsage-->>ControllerUsage: return data
    end
    ControllerUsage-->>Frontend: {success, payload}
    Frontend->>User: Show Codex Usage modal
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • creamlike1024

Poem

🐇 I hopped a PKCE path at dawn,
keys and tokens tucked upon my lawn,
I nudged a modal, fetched the day,
refreshed credentials on the way,
Codex joined — hooray, hooray! 🌱

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.88% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'feat: codex channel' directly describes the main change - adding support for a new Codex channel type throughout the codebase. It is concise, clear, and aligns with the extensive changes across API types, constants, controllers, relay handlers, and UI components.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

🧹 Recent nitpick comments
service/openaicompat/chat_to_responses.go (1)

124-142: Consider extracting duplicated tool call parsing logic.

The same tool call parsing logic is repeated three times for assistant messages. This could be extracted into a helper function to reduce duplication and improve maintainability.

♻️ Proposed refactor to extract helper function

Add a helper function:

func appendAssistantToolCalls(inputItems []map[string]any, msg dto.Message) []map[string]any {
	if msg.Role != "assistant" {
		return inputItems
	}
	for _, tc := range msg.ParseToolCalls() {
		if strings.TrimSpace(tc.ID) == "" {
			continue
		}
		if tc.Type != "" && tc.Type != "function" {
			continue
		}
		name := strings.TrimSpace(tc.Function.Name)
		if name == "" {
			continue
		}
		inputItems = append(inputItems, map[string]any{
			"type":      "function_call",
			"call_id":   tc.ID,
			"name":      name,
			"arguments": tc.Function.Arguments,
		})
	}
	return inputItems
}

Then replace each duplicated block with:

-			if role == "assistant" {
-				for _, tc := range msg.ParseToolCalls() {
-					// ... 15 lines of duplicated logic
-				}
-			}
+			inputItems = appendAssistantToolCalls(inputItems, msg)

Also applies to: 151-169, 212-230

relay/channel/openai/chat_via_responses.go (1)

84-88: Consider consolidating tool call state into a struct.

Using five separate maps keyed by the same ID is harder to maintain and reason about. A struct would improve clarity.

♻️ Proposed refactor
+type toolCallState struct {
+	index    int
+	name     string
+	args     string
+	nameSent bool
+}
+
-	toolCallIndexByID := make(map[string]int)
-	toolCallNameByID := make(map[string]string)
-	toolCallArgsByID := make(map[string]string)
-	toolCallNameSent := make(map[string]bool)
-	toolCallCanonicalIDByItemID := make(map[string]string)
+	toolCallStates := make(map[string]*toolCallState)
+	toolCallCanonicalIDByItemID := make(map[string]string)

Then access state via toolCallStates[callID].name, etc.


📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6aa9c02 and ecb939d.

📒 Files selected for processing (3)
  • dto/openai_response.go
  • relay/channel/openai/chat_via_responses.go
  • service/openaicompat/chat_to_responses.go
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-21T06:31:11.073Z
Learnt from: jiajunly
Repo: QuantumNous/new-api PR: 1629
File: relay/channel/openai/relay-openai.go:170-174
Timestamp: 2025-08-21T06:31:11.073Z
Learning: In relay/channel/openai/relay-openai.go, the streaming logic for the AddThinkFirst feature is designed so that only the first chunk of a stream gets the "<think>\n" prefix. The final flush in the streaming handler intentionally uses addThink=false because the last chunk should never receive the prefix, even in single-chunk streams where the prefix would have been applied during normal processing.

Applied to files:

  • relay/channel/openai/chat_via_responses.go
📚 Learning: 2025-06-21T03:37:41.726Z
Learnt from: 9Ninety
Repo: QuantumNous/new-api PR: 1273
File: relay/channel/gemini/relay-gemini.go:97-116
Timestamp: 2025-06-21T03:37:41.726Z
Learning: In relay/channel/gemini/relay-gemini.go, the thinking budget calculation logic (including the MaxOutputTokens multiplication) was introduced in PR `#1247`. PR `#1273` focused specifically on decoupling the thoughts summary feature from thinking budget settings and did not modify the existing thinking budget behavior.

Applied to files:

  • relay/channel/openai/chat_via_responses.go
🧬 Code graph analysis (1)
service/openaicompat/chat_to_responses.go (1)
common/json.go (1)
  • Marshal (21-23)
🔇 Additional comments (6)
dto/openai_response.go (1)

375-378: LGTM!

The new OutputIndex and ItemID fields are correctly added to support function call argument streaming events. Using *int for OutputIndex ensures proper omitempty behavior (distinguishing between absent and zero), and the JSON tags follow the existing snake_case convention consistent with the OpenAI API.

service/openaicompat/chat_to_responses.go (1)

57-87: Tool/function message handling looks correct.

The logic properly handles tool and function roles by:

  1. Extracting the tool call ID and output content
  2. Falling back gracefully when content is nil, string, or complex
  3. Emitting function_call_output items with proper structure

The fallback for missing call_id (lines 73-78) uses a user message with a special prefix, which is a reasonable degradation strategy to preserve context.

relay/channel/openai/chat_via_responses.go (4)

90-167: Helper functions for streaming are well-structured.

The sendStartIfNeeded and sendToolCallDelta helpers properly manage streaming state with:

  • Idempotent start emission via sentStart flag
  • Correct error propagation via streamErr
  • Tool call index tracking for proper delta ordering
  • Usage text accumulation for fallback token estimation

The prioritization at lines 106-108 (skipping tool call deltas when text content exists) aligns with the comment about matching non-stream behavior.


220-272: Function call event handling looks correct.

The handling of response.output_item.added/done and response.function_call_arguments.delta events properly:

  • Maps item IDs to canonical call IDs for consistent tracking
  • Computes argument deltas by comparing with previously accumulated args
  • Falls back to full arguments if prefix doesn't match (line 248)

The empty case for response.function_call_arguments.done (lines 271-272) is appropriate since the done event is purely informational.


310-314: Finish reason logic correctly implements OpenAI API semantics.

The logic properly returns "tool_calls" when tool calls were emitted without text output, matching the OpenAI API behavior. The duplication between the in-stream (lines 310-313) and post-stream (lines 352-355) paths is acceptable given the short span.

Also applies to: 352-356


76-77: Dual builder approach for usage tracking is well-designed.

Using separate outputText (for finish reason determination) and usageText (for token estimation including tool call data) builders correctly handles the different semantics needed for each purpose.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Fix all issues with AI agents
In @constant/channel.go:
- Line 120: Replace the incorrect Codex channel base URL string
"https://chatgpt.com" with the proper OpenAI API base
"https://api.openai.com/v1/" so the Codex channel uses the same API endpoint as
the OpenAI channel; locate the entry in the channel list containing
"https://chatgpt.com" (the Codex channel) in constant/channel.go and update that
string to "https://api.openai.com/v1/".

In @controller/channel.go:
- Around line 698-704: The direct DB update bypasses Channel.Update() which runs
important validations (MultiKeySize, status cleanup, UpdateAbilities); replace
the raw update with loading via GetChannelById() (already done), set ch.Key =
string(encoded) and call ch.Update(), check its error and only then call
model.InitChannelCache() and service.ResetProxyClientCache(); if you need
atomicity between DB change and cache refresh, wrap the update and subsequent
cache-refresh-triggering operations in a transaction or ensure you
rollback/cache-only on failure so DB and cache remain consistent.

In @controller/codex_oauth.go:
- Around line 206-216: Session keys are being deleted before the DB update,
which can leave the user unable to retry if
model.DB.Model(&model.Channel{}).Where("id = ?", channelID).Update("key",
string(encoded)).Error fails; move the session.Delete calls (and session.Save)
to after the DB update succeeds and model.InitChannelCache() completes so the
session is only cleared on success, keeping codexOAuthSessionKey(..., "state"),
codexOAuthSessionKey(..., "verifier"), and codexOAuthSessionKey(...,
"created_at") intact if the update returns an error.

In @relay/channel/codex/constants.go:
- Around line 1-9: The ModelList slice in constants.go contains an
invalid/undocumented entry "gpt-5.1-codex-max"; update the ModelList variable to
remove or correct that entry (replace "gpt-5.1-codex-max" with the verified
model name "gpt-5.1-codex-mini" or simply remove the max variant) so that
ModelList only contains valid Codex models (refer to the ModelList symbol and
the string literal "gpt-5.1-codex-max" to locate the change).

In @service/codex_oauth.go:
- Around line 107-116: The code decodes resp.Body into payload before checking
resp.StatusCode, which can misinterpret error responses as missing token fields;
change the logic in the Codex refresh flow to check resp.StatusCode immediately
after receiving resp and handle non-2xx by reading/decoding the error body (or
reading it as a string) and returning a clear error that includes status and
body, and only call json.NewDecoder(resp.Body).Decode(&payload) when
resp.StatusCode indicates success (200–299); update references to resp, payload,
json.NewDecoder.Decode, and the existing status check to implement this ordering
and improved error message.
- Around line 168-176: The code decodes resp.Body into payload before checking
resp.StatusCode; move the status check to occur immediately after receiving resp
(i.e., check resp.StatusCode <200 || >=300 first) and return a formatted error
(optionally including the response body for debugging) before calling
json.NewDecoder(resp.Body). Ensure the same pattern used in
refreshCodexOAuthToken is applied here: only decode into payload when the status
is 2xx and then validate payload.AccessToken/RefreshToken/ExpiresIn.
🧹 Nitpick comments (4)
relay/channel/codex/oauth_key.go (1)

21-29: Consider wrapping the original unmarshal error for debugging.

The original error from common.Unmarshal is discarded, which may make troubleshooting malformed JSON more difficult. Consider using fmt.Errorf to wrap the original error.

♻️ Suggested improvement
 func ParseOAuthKey(raw string) (*OAuthKey, error) {
 	if raw == "" {
 		return nil, errors.New("codex channel: empty oauth key")
 	}
 	var key OAuthKey
 	if err := common.Unmarshal([]byte(raw), &key); err != nil {
-		return nil, errors.New("codex channel: invalid oauth key json")
+		return nil, fmt.Errorf("codex channel: invalid oauth key json: %w", err)
 	}
 	return &key, nil
 }

Note: This would require adding "fmt" to the imports.

router/api-router.go (1)

159-163: LGTM!

The Codex OAuth endpoints are well-organized under the channel route with appropriate AdminAuth protection. The separation between general and channel-specific OAuth flows provides flexibility for both new channel creation and existing channel credential updates.

Consider adding middleware.CriticalRateLimit() to the OAuth endpoints to prevent potential abuse, similar to other sensitive operations in this router (e.g., Lines 30-31, 53-54). OAuth token exchanges involve external API calls that could be exploited for amplification attacks.

♻️ Optional: Add rate limiting to OAuth endpoints
-			channelRoute.POST("/codex/oauth/start", controller.StartCodexOAuth)
-			channelRoute.POST("/codex/oauth/complete", controller.CompleteCodexOAuth)
-			channelRoute.POST("/:id/codex/oauth/start", controller.StartCodexOAuthForChannel)
-			channelRoute.POST("/:id/codex/oauth/complete", controller.CompleteCodexOAuthForChannel)
-			channelRoute.POST("/:id/codex/refresh", controller.RefreshCodexChannelCredential)
+			channelRoute.POST("/codex/oauth/start", middleware.CriticalRateLimit(), controller.StartCodexOAuth)
+			channelRoute.POST("/codex/oauth/complete", middleware.CriticalRateLimit(), controller.CompleteCodexOAuth)
+			channelRoute.POST("/:id/codex/oauth/start", middleware.CriticalRateLimit(), controller.StartCodexOAuthForChannel)
+			channelRoute.POST("/:id/codex/oauth/complete", middleware.CriticalRateLimit(), controller.CompleteCodexOAuthForChannel)
+			channelRoute.POST("/:id/codex/refresh", middleware.CriticalRateLimit(), controller.RefreshCodexChannelCredential)
web/src/components/table/channels/modals/CodexOAuthModal.jsx (1)

123-129: Missing feedback for copy action.

The copy button click handler doesn't provide user feedback on success/failure. The copy utility returns a Promise indicating success.

💡 Suggested improvement
         <Button
           theme='outline'
           disabled={!authorizeUrl || loading}
-          onClick={() => copy(authorizeUrl)}
+          onClick={async () => {
+            const ok = await copy(authorizeUrl);
+            if (ok) {
+              showSuccess(t('已复制'));
+            } else {
+              showError(t('复制失败'));
+            }
+          }}
         >
           {t('复制授权链接')}
         </Button>
controller/codex_oauth.go (1)

98-102: Consider handling session save errors.

The session save error is silently ignored. While session save failures are often non-critical, logging the error would help with debugging issues in production.

💡 Suggested improvement
 session.Set(codexOAuthSessionKey(channelID, "state"), flow.State)
 session.Set(codexOAuthSessionKey(channelID, "verifier"), flow.Verifier)
 session.Set(codexOAuthSessionKey(channelID, "created_at"), time.Now().Unix())
-_ = session.Save()
+if err := session.Save(); err != nil {
+    common.SysLog(fmt.Sprintf("failed to save codex oauth session: %v", err))
+}
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6169f46 and 30de86f.

📒 Files selected for processing (16)
  • common/api_type.go
  • constant/api_type.go
  • constant/channel.go
  • controller/channel.go
  • controller/codex_oauth.go
  • relay/channel/codex/adaptor.go
  • relay/channel/codex/constants.go
  • relay/channel/codex/oauth_key.go
  • relay/common/relay_info.go
  • relay/relay_adaptor.go
  • router/api-router.go
  • service/codex_oauth.go
  • web/src/components/table/channels/modals/CodexOAuthModal.jsx
  • web/src/components/table/channels/modals/EditChannelModal.jsx
  • web/src/constants/channel.constants.js
  • web/src/helpers/render.jsx
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-08-21T06:31:11.073Z
Learnt from: jiajunly
Repo: QuantumNous/new-api PR: 1629
File: relay/channel/openai/relay-openai.go:170-174
Timestamp: 2025-08-21T06:31:11.073Z
Learning: In relay/channel/openai/relay-openai.go, the streaming logic for the AddThinkFirst feature is designed so that only the first chunk of a stream gets the "<think>\n" prefix. The final flush in the streaming handler intentionally uses addThink=false because the last chunk should never receive the prefix, even in single-chunk streams where the prefix would have been applied during normal processing.

Applied to files:

  • relay/common/relay_info.go
📚 Learning: 2025-08-08T17:12:43.157Z
Learnt from: RedwindA
Repo: QuantumNous/new-api PR: 1537
File: relay/gemini_handler.go:330-342
Timestamp: 2025-08-08T17:12:43.157Z
Learning: In the new-api repository, the `GeminiEmbeddingHandler` function in `relay/gemini_handler.go` is designed specifically for native Gemini embedding requests and therefore does not require the `ConvertGeminiRequest` step that is used in the chat handler. The embedding requests are already in the native Gemini format and don't need conversion.

Applied to files:

  • relay/channel/codex/adaptor.go
📚 Learning: 2025-08-27T02:15:25.448Z
Learnt from: AAEE86
Repo: QuantumNous/new-api PR: 1658
File: web/src/components/table/channels/modals/EditChannelModal.jsx:555-569
Timestamp: 2025-08-27T02:15:25.448Z
Learning: In EditChannelModal.jsx, the applyModelMapping function transforms the models list by replacing original model names (mapping values) with display names (mapping keys). The database stores this transformed list containing mapped keys. On channel load, data.models contains these mapped display names, making the initialization filter if (data.models.includes(key)) correct.

Applied to files:

  • web/src/components/table/channels/modals/EditChannelModal.jsx
📚 Learning: 2025-08-27T02:15:25.448Z
Learnt from: AAEE86
Repo: QuantumNous/new-api PR: 1658
File: web/src/components/table/channels/modals/EditChannelModal.jsx:555-569
Timestamp: 2025-08-27T02:15:25.448Z
Learning: In EditChannelModal.jsx, the database stores mapped keys (display names) in the models field after applying model mapping transformations. When loading a channel, data.models contains the mapped keys, not the original model names. The filtering logic if (data.models.includes(key)) in the initialization is correct.

Applied to files:

  • web/src/components/table/channels/modals/EditChannelModal.jsx
🧬 Code graph analysis (8)
relay/common/relay_info.go (1)
constant/channel.go (1)
  • ChannelTypeCodex (57-57)
relay/channel/codex/oauth_key.go (1)
common/json.go (1)
  • Unmarshal (9-11)
router/api-router.go (2)
controller/codex_oauth.go (4)
  • StartCodexOAuth (62-64)
  • CompleteCodexOAuth (113-115)
  • StartCodexOAuthForChannel (66-73)
  • CompleteCodexOAuthForChannel (117-124)
controller/channel.go (1)
  • RefreshCodexChannelCredential (633-719)
web/src/components/table/channels/modals/CodexOAuthModal.jsx (2)
web/src/helpers/utils.jsx (3)
  • showSuccess (157-159)
  • showError (122-151)
  • copy (72-95)
web/src/helpers/render.jsx (1)
  • value (1011-1011)
relay/relay_adaptor.go (3)
constant/api_type.go (1)
  • APITypeCodex (38-38)
relay/channel/codex/adaptor.go (1)
  • Adaptor (20-21)
relay/channel/adapter.go (1)
  • Adaptor (15-32)
common/api_type.go (2)
constant/channel.go (1)
  • ChannelTypeCodex (57-57)
constant/api_type.go (1)
  • APITypeCodex (38-38)
relay/channel/codex/adaptor.go (5)
relay/common/relay_info.go (1)
  • RelayInfo (82-131)
common/json.go (2)
  • Marshal (21-23)
  • Unmarshal (9-11)
relay/constant/relay_mode.go (1)
  • RelayModeResponses (48-48)
relay/common/relay_utils.go (1)
  • GetFullRequestURL (25-37)
relay/channel/codex/oauth_key.go (1)
  • ParseOAuthKey (21-30)
web/src/components/table/channels/modals/EditChannelModal.jsx (2)
web/src/helpers/utils.jsx (4)
  • showSuccess (157-159)
  • showError (122-151)
  • verifyJSON (273-280)
  • verifyJSON (273-280)
web/src/components/table/channels/modals/CodexOAuthModal.jsx (1)
  • CodexOAuthModal (27-145)
🔇 Additional comments (34)
constant/api_type.go (1)

38-38: LGTM!

The new APITypeCodex constant is correctly placed before the sentinel APITypeDummy, preserving existing iota values.

relay/channel/codex/oauth_key.go (1)

9-19: LGTM!

The OAuthKey struct is well-designed with appropriate JSON tags and optional fields using omitempty. The field selection covers the necessary OAuth token lifecycle data.

controller/channel.go (3)

4-19: LGTM!

The new imports for context, time, and the codex package are correctly added to support the new Codex OAuth functionality.


610-628: LGTM!

The Codex OAuth key validation correctly enforces the JSON object format and ensures required fields (access_token and account_id) are present. The conditional logic appropriately handles both add and update scenarios.


633-671: LGTM!

The RefreshCodexChannelCredential handler follows a solid pattern:

  • Proper input validation for channel ID and type
  • Parses existing OAuth key and validates refresh_token presence
  • Appropriate 10-second timeout for external OAuth call
  • Clear error responses for each failure case
service/codex_oauth.go (4)

17-25: Hardcoded OAuth client credentials and localhost redirect URI.

The OAuth client ID and redirect URI are hardcoded. The localhost:1455 redirect URI suggests this is designed for CLI/local flows. Verify this is the intended design and ensure these values don't need to be configurable for different deployment environments.


215-224: LGTM!

The PKCE implementation correctly follows RFC 7636:

  • 32 bytes of cryptographically random data for the verifier
  • Base64 URL encoding without padding (RawURLEncoding)
  • SHA-256 hash for the S256 challenge method

274-288: JWT claims extraction without signature verification.

The decodeJWTClaims function extracts claims without verifying the JWT signature. This is acceptable here since the token originates from the trusted Codex OAuth server and is used only for extracting metadata (account ID, email) for display purposes, not for authentication decisions.


40-69: LGTM!

The public API surface is well-designed with clear separation between the public functions and internal implementation details. The CreateCodexOAuthAuthorizationFlow function properly encapsulates PKCE state generation.

web/src/helpers/render.jsx (1)

302-305: LGTM!

Adding Codex (case 57) to share the OpenAI icon with cases 1 and 3 is appropriate, as Codex is an OpenAI-based service.

common/api_type.go (1)

76-77: LGTM!

The mapping from ChannelTypeCodex to APITypeCodex follows the established pattern and correctly extends the channel-to-API type translation.

constant/channel.go (2)

57-57: LGTM!

ChannelTypeCodex is correctly assigned value 57 and placed before the ChannelTypeDummy sentinel.


177-177: LGTM!

The ChannelTypeNames mapping entry correctly associates ChannelTypeCodex with the display name "Codex".

web/src/constants/channel.constants.js (1)

187-191: LGTM!

The new Codex channel option is correctly added with value 57, consistent with the backend ChannelTypeCodex constant. The entry follows the existing pattern and styling conventions.

relay/relay_adaptor.go (2)

14-14: LGTM!

The import is correctly placed in alphabetical order.


121-122: LGTM!

The Codex adaptor case follows the established pattern. All 15 methods of the channel.Adaptor interface are properly implemented in codex.Adaptor.

relay/common/relay_info.go (1)

277-277: LGTM!

Adding Codex to streamSupportedChannels is appropriate since Codex uses OpenAI-compatible APIs that support streaming.

web/src/components/table/channels/modals/CodexOAuthModal.jsx (3)

33-52: LGTM!

The startOAuth function correctly manages loading state, validates the response structure, opens the authorization URL in a new tab with security attributes (noopener,noreferrer), and provides appropriate user feedback.


54-84: LGTM!

The completeOAuth function has proper input validation, loading state management, error handling, and correctly invokes callbacks in the right order (onSuccess before onCancel to close the modal).


86-90: LGTM!

The useEffect correctly resets component state when the modal becomes visible, ensuring a clean slate for each OAuth flow attempt.

controller/codex_oauth.go (3)

163-173: LGTM - Proper CSRF protection with state validation.

The state validation correctly prevents CSRF attacks by comparing the returned state with the expected state stored in the session. The check for empty verifier/state also handles session expiration gracefully.


175-182: LGTM - Appropriate timeout for token exchange.

The 15-second context timeout is reasonable for the OAuth token exchange operation, preventing indefinite hangs on external service calls.


31-60: LGTM - Flexible input parsing.

The parseCodexAuthorizationInput function handles multiple input formats gracefully: full URL with query params, code#state format, and plain code. This provides good UX flexibility.

web/src/components/table/channels/modals/EditChannelModal.jsx (7)

218-220: LGTM!

State variables for Codex OAuth modal visibility and credential refresh loading are properly initialized.


843-846: LGTM!

The handler correctly updates the key field and then formats it as JSON. The order is important since formatJsonField reads from inputs state.


1117-1156: LGTM - Thorough validation for Codex OAuth credentials.

The validation properly:

  1. Prevents batch creation for Codex channels
  2. Requires key for new channels
  3. Validates JSON structure
  4. Ensures required fields (access_token, account_id) are present
  5. Re-serializes to normalize the JSON

508-519: LGTM - Proper state reset when switching to Codex channel type.

When the channel type changes to 57 (Codex), the code correctly resets batch mode and vertex-related state since Codex uses a different credential model.


1972-2047: LGTM - Well-structured UI for Codex OAuth flow.

The UI properly:

  • Shows appropriate placeholder with JSON example
  • Provides OAuth authorization button
  • Shows refresh credential button in edit mode with loading state
  • Includes format helper and key viewing options
  • Respects isIonetLocked disabled state

1489-1489: LGTM!

Correctly excludes type 57 (Codex) from batch creation since Codex channels require OAuth credentials that cannot be batch-created.


848-867: No action needed — the refresh endpoint is properly defined and wired.

The endpoint /api/channel/:id/codex/refresh exists in router/api-router.go (line 163) and is correctly routed to controller.RefreshCodexChannelCredential. The frontend code calling this endpoint is correct.

Likely an incorrect or invalid review comment.

relay/channel/codex/adaptor.go (4)

54-91: LGTM - System prompt injection logic is correct.

The logic properly handles three cases:

  1. No existing instructions → set system prompt
  2. Existing instructions with override flag → prepend system prompt
  3. Existing instructions without override → keep existing

The error handling for marshal/unmarshal operations is thorough.


97-106: LGTM - Appropriate mode restriction.

The adaptor correctly restricts to RelayModeResponses only, which aligns with Codex's API design. The delegation to OpenAI handlers for stream/non-stream responses is appropriate since Codex uses OpenAI-compatible response formats.


123-157: LGTM - Robust header setup with validation.

The method properly:

  1. Validates the key is a JSON object
  2. Parses OAuth credentials using ParseOAuthKey
  3. Validates required fields (access_token, account_id)
  4. Sets appropriate headers (Authorization, chatgpt-account-id)
  5. Applies sensible defaults for OpenAI-Beta and originator headers

23-52: LGTM - Clear unsupported endpoint handling.

The stub methods clearly communicate that these endpoints are not supported for the Codex channel, returning consistent error messages.

Comment thread constant/channel.go
"https://ark.cn-beijing.volces.com", //54
"https://api.openai.com", //55
"https://api.replicate.com", //56
"https://chatgpt.com", //57
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

OpenAI Codex API endpoint URL documentation

💡 Result:

Short answer: OpenAI’s Codex/docs live on OpenAI’s developer sites; Codex uses the standard OpenAI REST API base URL (https://api.openai.com/v1/) and Codex-specific guidance is in the Codex docs.

Where to read:

  • Codex developer docs (features, CLI/IDE integration): developers.openai.com/codex. [1]
  • Platform Codex overview & guidance: platform.openai.com/docs/codex. [2]
  • General OpenAI API reference (base endpoint and REST endpoints like /v1/models, /v1/chat/completions, /v1/files): platform.openai.com/docs/api-reference (base URL: https://api.openai.com/v1/). [3]

References:
[1] developers.openai.com/codex.
[2] platform.openai.com/docs/codex.
[3] platform.openai.com/docs/api-reference/introduction.


🏁 Script executed:

# First, let's examine the constant/channel.go file to understand the context
head -n 150 constant/channel.go | tail -n 40

Repository: QuantumNous/new-api

Length of output: 1666


🏁 Script executed:

# Search for where this URL constant is used in the codebase
rg "chatgpt\.com" -B 2 -A 2

Repository: QuantumNous/new-api

Length of output: 318


🏁 Script executed:

# Search for the channel type constant that corresponds to position 57
rg "ChannelType" constant/channel.go | head -n 70 | tail -n 20

Repository: QuantumNous/new-api

Length of output: 876


Fix the Codex channel base URL to use the correct API endpoint.

The URL https://chatgpt.com at line 120 is the ChatGPT web interface, not an API endpoint. According to OpenAI's official documentation, the Codex API uses https://api.openai.com/v1/ as the base endpoint, matching the OpenAI channel at line 119. Requests to chatgpt.com will fail and cannot access the Codex API.

🤖 Prompt for AI Agents
In @constant/channel.go at line 120, Replace the incorrect Codex channel base
URL string "https://chatgpt.com" with the proper OpenAI API base
"https://api.openai.com/v1/" so the Codex channel uses the same API endpoint as
the OpenAI channel; locate the entry in the channel list containing
"https://chatgpt.com" (the Codex channel) in constant/channel.go and update that
string to "https://api.openai.com/v1/".

Comment thread controller/channel.go Outdated
Comment on lines +698 to +704
if err := model.DB.Model(&model.Channel{}).Where("id = ?", ch.Id).Update("key", string(encoded)).Error; err != nil {
common.ApiError(c, err)
return
}

model.InitChannelCache()
service.ResetProxyClientCache()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for Channel.Update method
echo "=== Checking for Channel.Update method ==="
rg -n 'func.*\(.*\*?Channel.*\).*Update\(' --type go

echo "=== Checking for common.Marshal function ==="
rg -n 'func Marshal' --type go

echo "=== Get context around lines 698-704 in controller/channel.go ==="
sed -n '690,720p' controller/channel.go

echo "=== Check the RefreshCodexChannelCredential function signature and context ==="
sed -n '633,650p' controller/channel.go

Repository: QuantumNous/new-api

Length of output: 1610


🏁 Script executed:

#!/bin/bash
# Check the Channel.Update() method implementation
echo "=== Channel.Update() implementation ==="
sed -n '458,480p' model/channel.go

# Also check if there are any validation hooks in the Channel model
echo -e "\n=== Check Channel struct and its methods ==="
sed -n '1,100p' model/channel.go | head -50

Repository: QuantumNous/new-api

Length of output: 3186


🏁 Script executed:

#!/bin/bash
# Get the full Channel.Update() method implementation
echo "=== Full Channel.Update() method ==="
sed -n '458,550p' model/channel.go

Repository: QuantumNous/new-api

Length of output: 3075


🏁 Script executed:

#!/bin/bash
# Verify if Codex channel could be multi-key and what UpdateAbilities does
echo "=== Search for Codex channel type constant ==="
rg -n 'ChannelTypeCodex' --type go

echo "=== Search for UpdateAbilities method ==="
rg -n 'func.*UpdateAbilities' --type go

echo "=== Check if there are other direct DB updates that bypass Channel.Update ==="
rg -n 'Update.*key.*Where.*id' controller/channel.go --type go

Repository: QuantumNous/new-api

Length of output: 842


🏁 Script executed:

#!/bin/bash
# Verify the cache refresh operations
echo "=== Check InitChannelCache implementation ==="
rg -n 'func InitChannelCache' --type go -A 10

echo "=== Check ResetProxyClientCache implementation ==="
rg -n 'func ResetProxyClientCache' --type go -A 5

echo "=== Check UpdateAbilities signature ==="
sed -n '193,210p' model/ability.go

Repository: QuantumNous/new-api

Length of output: 1558


Use ch.Update() to ensure model-layer validations and consistency checks are applied.

The direct model.DB.Model(&model.Channel{}).Where("id = ?", ch.Id).Update("key", string(encoded)) call bypasses critical logic in Channel.Update(), including MultiKeySize recalculation for multi-key channels, status data cleanup, and the UpdateAbilities() call. Since ch is already loaded via GetChannelById(), use ch.Key = string(encoded); ch.Update() instead. Additionally, the direct update and cache refresh are separate operations without transactional wrapping—if either fails, the database state and cache could become inconsistent.

🤖 Prompt for AI Agents
In @controller/channel.go around lines 698 - 704, The direct DB update bypasses
Channel.Update() which runs important validations (MultiKeySize, status cleanup,
UpdateAbilities); replace the raw update with loading via GetChannelById()
(already done), set ch.Key = string(encoded) and call ch.Update(), check its
error and only then call model.InitChannelCache() and
service.ResetProxyClientCache(); if you need atomicity between DB change and
cache refresh, wrap the update and subsequent cache-refresh-triggering
operations in a transaction or ensure you rollback/cache-only on failure so DB
and cache remain consistent.

Comment thread controller/codex_oauth.go
Comment on lines +206 to +216
session.Delete(codexOAuthSessionKey(channelID, "state"))
session.Delete(codexOAuthSessionKey(channelID, "verifier"))
session.Delete(codexOAuthSessionKey(channelID, "created_at"))
_ = session.Save()

if channelID > 0 {
if err := model.DB.Model(&model.Channel{}).Where("id = ?", channelID).Update("key", string(encoded)).Error; err != nil {
common.ApiError(c, err)
return
}
model.InitChannelCache()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Session cleanup occurs before DB operation - potential state inconsistency.

If the DB update (line 212) fails, the session has already been cleared (lines 206-209), preventing the user from retrying without restarting the OAuth flow. Consider moving session cleanup after the DB operation succeeds.

🔧 Proposed fix
-session.Delete(codexOAuthSessionKey(channelID, "state"))
-session.Delete(codexOAuthSessionKey(channelID, "verifier"))
-session.Delete(codexOAuthSessionKey(channelID, "created_at"))
-_ = session.Save()
-
 if channelID > 0 {
     if err := model.DB.Model(&model.Channel{}).Where("id = ?", channelID).Update("key", string(encoded)).Error; err != nil {
         common.ApiError(c, err)
         return
     }
+    session.Delete(codexOAuthSessionKey(channelID, "state"))
+    session.Delete(codexOAuthSessionKey(channelID, "verifier"))
+    session.Delete(codexOAuthSessionKey(channelID, "created_at"))
+    _ = session.Save()
     model.InitChannelCache()
     service.ResetProxyClientCache()
     // ... rest of response
     return
 }

+session.Delete(codexOAuthSessionKey(channelID, "state"))
+session.Delete(codexOAuthSessionKey(channelID, "verifier"))
+session.Delete(codexOAuthSessionKey(channelID, "created_at"))
+_ = session.Save()
+
 c.JSON(http.StatusOK, gin.H{
     // ... response for non-channel case
 })
🤖 Prompt for AI Agents
In @controller/codex_oauth.go around lines 206 - 216, Session keys are being
deleted before the DB update, which can leave the user unable to retry if
model.DB.Model(&model.Channel{}).Where("id = ?", channelID).Update("key",
string(encoded)).Error fails; move the session.Delete calls (and session.Save)
to after the DB update succeeds and model.InitChannelCache() completes so the
session is only cleared on success, keeping codexOAuthSessionKey(..., "state"),
codexOAuthSessionKey(..., "verifier"), and codexOAuthSessionKey(...,
"created_at") intact if the update returns an error.

Comment on lines +116 to +121
func (a *Adaptor) GetRequestURL(info *relaycommon.RelayInfo) (string, error) {
if info.RelayMode != relayconstant.RelayModeResponses {
return "", errors.New("codex channel: only /v1/responses is supported")
}
return relaycommon.GetFullRequestURL(info.ChannelBaseUrl, "/backend-api/codex/responses", info.ChannelType), nil
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

OpenAI Codex API endpoint documentation

💡 Result:

Here are the official OpenAI documentation pages for Codex and related API/endpoint references:

  • Codex overview (product & links to docs): OpenAI Codex page. [1]
  • Codex on the OpenAI/Platform docs (Codex cloud & platform integration): platform docs. [2]
  • Codex CLI reference (commands, flags, config). [3]
  • Codex GitHub action (notes about Responses API endpoint usage / non-default endpoints, including Azure). [4]

If you want specific API endpoint names/hostnames (e.g., api.openai.com, mtls.api.openai.com, Azure endpoints) or a network configuration guide, tell me which environment (public OpenAI vs. Azure OpenAI vs. mTLS) and I’ll fetch exact endpoint details and ports.

Sources:
[1] https://openai.com/codex
[2] https://platform.openai.com/docs/codex
[3] https://developers.openai.com/codex/cli/reference
[4] https://github.com/openai/codex-action


🌐 Web query:

Codex API endpoint path "/v1/codex" OR "/backend-api/codex" OpenAI documentation

💡 Result:

Short answer: OpenAI's public Platform docs do not list a public API endpoint named "/v1/codex" or a documented official endpoint at "/backend-api/codex". The Codex product is exposed via the Codex CLI/SDK and the platform’s documented APIs (Responses/Chat/Completions as appropriate), while paths like "https://chatgpt.com/backend-api/codex/..." appear in implementation/CLI/github discussions as internal/web-backend endpoints used by the Codex CLI/web UI, not as published public API endpoints. [1][2][3][4]

Sources:

  • OpenAI Codex product/docs pages (Codex product is provided via CLI/SDK and platform integrations). [1]
  • OpenAI Platform deprecations/docs (shows Codex-related API transitions and platform docs). [2]
  • openai/codex GitHub issues referencing requests to chatgpt.com/backend-api/codex/responses (shows backend usage, not public platform docs). [3][4]

🏁 Script executed:

cd relay/channel/codex && find . -type f -name "*.go" -o -name "*.md" | head -20

Repository: QuantumNous/new-api

Length of output: 105


🏁 Script executed:

rg "codex|/backend-api|responses" relay/channel/codex/ -A 2 -B 2

Repository: QuantumNous/new-api

Length of output: 5849


🏁 Script executed:

rg "codex" relay/ --type go -l | head -10

Repository: QuantumNous/new-api

Length of output: 182


Use documented OpenAI API endpoint for Codex integration.

The hardcoded path /backend-api/codex/responses is an internal backend endpoint not documented in OpenAI's official Platform API documentation. Using undocumented internal endpoints risks breaking when the backend changes. Verify this endpoint against OpenAI's official API documentation and use only published endpoints, or document why this internal endpoint is necessary and acceptable for your use case.

Additionally, the error message on line 118 states "only /v1/responses is supported" but the code actually calls /backend-api/codex/responses—reconcile this discrepancy.

Comment on lines +1 to +9
package codex

var ModelList = []string{
"gpt-5", "gpt-5-codex", "gpt-5-codex-mini",
"gpt-5.1", "gpt-5.1-codex", "gpt-5.1-codex-max",
"gpt-5.2", "gpt-5.2-codex",
}

const ChannelName = "codex"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

OpenAI Codex API models 2025 available

💡 Result:

As of 2025 (end of year), the main Codex-related API models/releases available from OpenAI were:

  • codex-mini-latest (small/low-latency Codex model for CLI/Responses API). [1]
  • gpt-5-codex (GPT‑5 variant optimized for Codex / Responses API rollout Sept 2025). [2]
  • gpt-5.1-codex (GPT‑5.1 Codex variants added later in 2025, incl. gpt-5.1-codex and gpt-5.1-codex-mini). [3]

Sources: OpenAI Codex announcement and docs. [1] OpenAI — Introducing Codex. [2] OpenAI — Introducing upgrades to Codex (Sept 2025). [3] OpenAI Codex changelog.


🌐 Web query:

OpenAI GPT-5 models 2025 2026

💡 Result:

Here’s a concise timeline and summary of OpenAI’s GPT‑5 family (2025–early 2026), based on OpenAI sources:

  • Announcement — GPT‑5 launched (Aug 7, 2025): introduced as a unified system (gpt‑5‑main, gpt‑5‑thinking, router, plus “pro”/thinking variants) and made default in ChatGPT. (openai.com)
  • System details — model names/variants (main, main‑mini, thinking, thinking‑mini, thinking‑nano, thinking‑pro) and safety framing published in the GPT‑5 System Card. (openai.com)
  • Safety/testing — GPT‑5 bio bug bounty and related safety efforts announced (September 2025) as OpenAI deployed GPT‑5 and invited researchers. (openai.com)
  • Codex integration — GPT‑5‑Codex variant announced for coding/Codex surfaces (Sept 2025) and later added to the Responses API. (openai.com)
  • Iterative upgrades — OpenAI released GPT‑5.1 (Nov 21, 2025) and GPT‑5.2 (Dec 11, 2025) as follow-up improvements (faster, better reasoning, updated knowledge cutoff for 5.2). (academy.openai.com)

If you want specific technical/API details (model IDs, pricing, rollout status for Free/Plus/Pro/Enterprise, or changelog entries) I can fetch and list those exact docs/lines. Which details do you need?

Citations:


Remove or correct "gpt-5.1-codex-max" in the ModelList—it does not match available Codex API models.

The model list contains an unconfirmed variant. Web search confirms that OpenAI released gpt-5.1-codex and gpt-5.1-codex-mini as part of Codex integration in 2025, but no gpt-5.1-codex-max variant has been documented. The pattern suggests gpt-5.1-codex-mini rather than a "max" variant. Verify the correct model name against current OpenAI Codex API documentation and correct the entry accordingly.

Confirmed models from the list:

  • gpt-5-codex
  • gpt-5.1-codex
  • gpt-5.1-codex-mini
  • gpt-5.2
🤖 Prompt for AI Agents
In @relay/channel/codex/constants.go around lines 1 - 9, The ModelList slice in
constants.go contains an invalid/undocumented entry "gpt-5.1-codex-max"; update
the ModelList variable to remove or correct that entry (replace
"gpt-5.1-codex-max" with the verified model name "gpt-5.1-codex-mini" or simply
remove the max variant) so that ModelList only contains valid Codex models
(refer to the ModelList symbol and the string literal "gpt-5.1-codex-max" to
locate the change).

Comment thread service/codex_oauth.go
Comment on lines +107 to +116
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
return nil, err
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("codex oauth refresh failed: status=%d", resp.StatusCode)
}

if strings.TrimSpace(payload.AccessToken) == "" || strings.TrimSpace(payload.RefreshToken) == "" || payload.ExpiresIn <= 0 {
return nil, errors.New("codex oauth refresh response missing fields")
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Check HTTP status code before decoding the response body.

The current order decodes the JSON body first (line 107), then checks the status code (line 110). If the OAuth server returns an error response (e.g., 401), the body may contain error JSON rather than token data. This could cause misleading "missing fields" errors instead of proper HTTP error messages.

🐛 Proposed fix
 	resp, err := client.Do(req)
 	if err != nil {
 		return nil, err
 	}
 	defer resp.Body.Close()

+	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
+		return nil, fmt.Errorf("codex oauth refresh failed: status=%d", resp.StatusCode)
+	}
+
 	var payload struct {
 		AccessToken  string `json:"access_token"`
 		RefreshToken string `json:"refresh_token"`
 		ExpiresIn    int    `json:"expires_in"`
 	}

 	if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
 		return nil, err
 	}
-	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
-		return nil, fmt.Errorf("codex oauth refresh failed: status=%d", resp.StatusCode)
-	}

 	if strings.TrimSpace(payload.AccessToken) == "" || strings.TrimSpace(payload.RefreshToken) == "" || payload.ExpiresIn <= 0 {
 		return nil, errors.New("codex oauth refresh response missing fields")
 	}
🤖 Prompt for AI Agents
In @service/codex_oauth.go around lines 107 - 116, The code decodes resp.Body
into payload before checking resp.StatusCode, which can misinterpret error
responses as missing token fields; change the logic in the Codex refresh flow to
check resp.StatusCode immediately after receiving resp and handle non-2xx by
reading/decoding the error body (or reading it as a string) and returning a
clear error that includes status and body, and only call
json.NewDecoder(resp.Body).Decode(&payload) when resp.StatusCode indicates
success (200–299); update references to resp, payload, json.NewDecoder.Decode,
and the existing status check to implement this ordering and improved error
message.

Comment thread service/codex_oauth.go
Comment on lines +168 to +176
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
return nil, err
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("codex oauth code exchange failed: status=%d", resp.StatusCode)
}
if strings.TrimSpace(payload.AccessToken) == "" || strings.TrimSpace(payload.RefreshToken) == "" || payload.ExpiresIn <= 0 {
return nil, errors.New("codex oauth token response missing fields")
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Same issue: Check HTTP status code before decoding.

This function has the same ordering problem as refreshCodexOAuthToken. The status code check (line 171) should occur before attempting to decode the response body (line 168).

🐛 Proposed fix
 	resp, err := client.Do(req)
 	if err != nil {
 		return nil, err
 	}
 	defer resp.Body.Close()

+	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
+		return nil, fmt.Errorf("codex oauth code exchange failed: status=%d", resp.StatusCode)
+	}
+
 	var payload struct {
 		AccessToken  string `json:"access_token"`
 		RefreshToken string `json:"refresh_token"`
 		ExpiresIn    int    `json:"expires_in"`
 	}
 	if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
 		return nil, err
 	}
-	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
-		return nil, fmt.Errorf("codex oauth code exchange failed: status=%d", resp.StatusCode)
-	}
🤖 Prompt for AI Agents
In @service/codex_oauth.go around lines 168 - 176, The code decodes resp.Body
into payload before checking resp.StatusCode; move the status check to occur
immediately after receiving resp (i.e., check resp.StatusCode <200 || >=300
first) and return a formatted error (optionally including the response body for
debugging) before calling json.NewDecoder(resp.Body). Ensure the same pattern
used in refreshCodexOAuthToken is applied here: only decode into payload when
the status is 2xx and then validate payload.AccessToken/RefreshToken/ExpiresIn.

@seefs001 seefs001 force-pushed the feature/codex-oauth branch from f6afa74 to 8442361 Compare January 13, 2026 10:33
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @controller/codex_usage.go:
- Around line 91-96: Silent error handling in the token persist block can hide
failures from common.Marshal and the DB update; check and handle encErr from
common.Marshal(oauthKey) and capture the error returned by
model.DB.Model(&model.Channel{}).Where("id = ?", ch.Id).Update("key",
string(encoded)).Error, logging both via the existing logger (or processLogger)
and returning or propagating an error so the caller knows persistence failed,
and ensure you don't suppress failures before calling model.InitChannelCache()
and service.ResetProxyClientCache().
🧹 Nitpick comments (4)
service/codex_wham_usage_test.go (1)

14-56: Good test coverage for the happy path and basic validation.

The test correctly verifies request construction, header values, and response handling using a clean mock transport pattern.

Consider adding tests for remaining validation branches (nil client, empty accessToken, empty accountID) and error scenarios (HTTP client failure, body read failure) to improve coverage.

controller/codex_usage.go (1)

77-105: Token refresh failure is not communicated to the user.

When service.RefreshCodexOAuthToken fails (line 81), the code proceeds to return the original 401/403 response without informing the user that a refresh was attempted and failed. This may make debugging difficult.

Consider logging the refresh error or including it in the response message when the upstream status indicates auth failure and refresh was attempted but unsuccessful.

web/src/components/table/channels/modals/CodexUsageModal.jsx (1)

161-168: Consider using instance-based modal closure.

Modal.destroyAll() will close all open modals, which could be disruptive if multiple modals are open simultaneously. If Semi UI supports instance-based closure (e.g., storing the return value of Modal.info() and calling .destroy() on it), that would be more precise.

web/src/hooks/channels/useChannelsData.jsx (1)

749-749: Consider using a named constant for Codex channel type.

The magic number 57 for Codex channel type reduces readability. Consider importing and using a constant (e.g., CHANNEL_TYPE_CODEX) from your constants file for better maintainability and consistency with how other channel types might be referenced.

+import { CHANNEL_TYPE_CODEX } from '../../constants';
 ...
-    if (record?.type === 57) {
+    if (record?.type === CHANNEL_TYPE_CODEX) {
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 30de86f and f6afa74.

📒 Files selected for processing (7)
  • controller/codex_usage.go
  • relay/channel/codex/constants.go
  • router/api-router.go
  • service/codex_wham_usage.go
  • service/codex_wham_usage_test.go
  • web/src/components/table/channels/modals/CodexUsageModal.jsx
  • web/src/hooks/channels/useChannelsData.jsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • relay/channel/codex/constants.go
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-27T02:15:25.448Z
Learnt from: AAEE86
Repo: QuantumNous/new-api PR: 1658
File: web/src/components/table/channels/modals/EditChannelModal.jsx:555-569
Timestamp: 2025-08-27T02:15:25.448Z
Learning: In EditChannelModal.jsx, the database stores mapped keys (display names) in the models field after applying model mapping transformations. When loading a channel, data.models contains the mapped keys, not the original model names. The filtering logic if (data.models.includes(key)) in the initialization is correct.

Applied to files:

  • web/src/hooks/channels/useChannelsData.jsx
🧬 Code graph analysis (3)
web/src/hooks/channels/useChannelsData.jsx (3)
web/src/helpers/api.js (6)
  • res (224-224)
  • res (225-225)
  • res (301-301)
  • res (302-302)
  • API (29-37)
  • API (29-37)
web/src/helpers/utils.jsx (2)
  • showError (122-151)
  • copy (72-95)
web/src/components/table/channels/modals/CodexUsageModal.jsx (2)
  • openCodexUsageModal (92-169)
  • openCodexUsageModal (92-169)
router/api-router.go (3)
controller/codex_oauth.go (4)
  • StartCodexOAuth (62-64)
  • CompleteCodexOAuth (113-115)
  • StartCodexOAuthForChannel (66-73)
  • CompleteCodexOAuthForChannel (117-124)
controller/channel.go (1)
  • RefreshCodexChannelCredential (633-719)
controller/codex_usage.go (1)
  • GetCodexChannelUsage (21-124)
service/codex_wham_usage_test.go (1)
service/codex_wham_usage.go (1)
  • FetchCodexWhamUsage (11-56)
🔇 Additional comments (9)
service/codex_wham_usage.go (1)

1-56: LGTM! Well-structured HTTP client function with proper validation.

The implementation correctly validates inputs, handles URL normalization, and properly propagates context. Error handling is appropriate, returning the status code even when body reading fails.

Minor observation: The originator header check (lines 41-43) will always evaluate to true since the header is never set before this point on a newly created request. If this is intentional as a default value, consider simplifying to just req.Header.Set("originator", "codex_cli_rs") without the conditional, or add a comment clarifying the intent for future extensibility.

service/codex_wham_usage_test.go (1)

58-62: Clean mock transport implementation.

The roundTripperFunc type adapter is a well-established Go idiom for mocking http.RoundTripper.

controller/codex_usage.go (1)

21-124: Overall handler structure is sound.

The handler properly validates inputs, handles the Codex-specific OAuth flow with automatic token refresh, and returns a consistent response structure. The timeout management with multiple contexts is appropriate for the different operations.

router/api-router.go (1)

159-164: LGTM! Routes are properly organized under admin authentication.

The new Codex OAuth and usage endpoints follow the existing routing patterns and are correctly protected by AdminAuth middleware. The separation between channel-specific (/:id/...) and generic (/codex/oauth/...) endpoints aligns with the controller implementations.

web/src/components/table/channels/modals/CodexUsageModal.jsx (3)

25-58: Well-implemented utility functions with proper defensive checks.

The helper functions handle edge cases appropriately with Number.isFinite() checks and fallback values. The formatting logic is clear and user-friendly.


60-90: Clean, reusable RateLimitWindowCard component.

The component properly handles optional windowData with nullish coalescing and presents rate limit information clearly with color-coded progress indicators.


92-169: Overall modal implementation is solid.

The modal properly extracts and displays rate limit data with sensible defaults, provides raw JSON viewing with copy functionality, and has a clean responsive layout.

web/src/hooks/channels/useChannelsData.jsx (2)

749-771: Modal opens even after showing an error - is this intentional?

When res?.data?.success is false (line 754), an error is shown via showError() (line 755), but the modal still opens (line 757) with the failed response payload. This may confuse users who see both an error toast and a modal with error data.

If the intent is to let users inspect the raw error response, consider adding a clarifying comment. Otherwise, the modal opening should be conditional on success.

🔧 Suggested fix if modal should only open on success
       try {
         const res = await API.get(`/api/channel/${record.id}/codex/usage`, {
           skipErrorHandler: true,
         });
         if (!res?.data?.success) {
           showError(res?.data?.message || t('Failed to fetch usage'));
+          return;
         }
         openCodexUsageModal({

39-39: Import added correctly.

The new import aligns with the Codex usage modal feature addition.

Comment thread controller/codex_usage.go
Comment on lines +91 to +96
encoded, encErr := common.Marshal(oauthKey)
if encErr == nil {
_ = model.DB.Model(&model.Channel{}).Where("id = ?", ch.Id).Update("key", string(encoded)).Error
model.InitChannelCache()
service.ResetProxyClientCache()
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Silent error handling may hide persistence failures.

If common.Marshal(oauthKey) fails or the DB update fails, the error is silently discarded. The user will see a successful response (if the retry works), but the refreshed tokens won't be persisted—causing the next request to fail again and trigger another refresh cycle.

🔧 Suggested improvement
 			encoded, encErr := common.Marshal(oauthKey)
-			if encErr == nil {
-				_ = model.DB.Model(&model.Channel{}).Where("id = ?", ch.Id).Update("key", string(encoded)).Error
+			if encErr != nil {
+				common.SysLog(fmt.Sprintf("failed to marshal oauth key for channel %d: %v", ch.Id, encErr))
+			} else if err := model.DB.Model(&model.Channel{}).Where("id = ?", ch.Id).Update("key", string(encoded)).Error; err != nil {
+				common.SysLog(fmt.Sprintf("failed to persist refreshed token for channel %d: %v", ch.Id, err))
+			} else {
 				model.InitChannelCache()
 				service.ResetProxyClientCache()
 			}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
encoded, encErr := common.Marshal(oauthKey)
if encErr == nil {
_ = model.DB.Model(&model.Channel{}).Where("id = ?", ch.Id).Update("key", string(encoded)).Error
model.InitChannelCache()
service.ResetProxyClientCache()
}
encoded, encErr := common.Marshal(oauthKey)
if encErr != nil {
common.SysLog(fmt.Sprintf("failed to marshal oauth key for channel %d: %v", ch.Id, encErr))
} else if err := model.DB.Model(&model.Channel{}).Where("id = ?", ch.Id).Update("key", string(encoded)).Error; err != nil {
common.SysLog(fmt.Sprintf("failed to persist refreshed token for channel %d: %v", ch.Id, err))
} else {
model.InitChannelCache()
service.ResetProxyClientCache()
}
🤖 Prompt for AI Agents
In @controller/codex_usage.go around lines 91 - 96, Silent error handling in the
token persist block can hide failures from common.Marshal and the DB update;
check and handle encErr from common.Marshal(oauthKey) and capture the error
returned by model.DB.Model(&model.Channel{}).Where("id = ?",
ch.Id).Update("key", string(encoded)).Error, logging both via the existing
logger (or processLogger) and returning or propagating an error so the caller
knows persistence failed, and ensure you don't suppress failures before calling
model.InitChannelCache() and service.ResetProxyClientCache().

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
web/src/components/table/channels/modals/CodexUsageModal.jsx (1)

161-168: Modal.destroyAll() closes all open modals — consider using a more targeted approach.

Using Modal.destroyAll() will close every open modal in the application, not just this Codex usage modal. If users have multiple modals open (e.g., an edit modal behind this one), they would all be unexpectedly closed.

♻️ Suggested fix using modal instance destroy

Semi UI Modal.info() returns a modal instance that can be destroyed specifically:

-  Modal.info({
+  const modal = Modal.info({
     title: (
       // ...
     ),
     // ...
     footer: (
       <div className='flex justify-end gap-2'>
-        <Button type='primary' theme='solid' onClick={() => Modal.destroyAll()}>
+        <Button type='primary' theme='solid' onClick={() => modal.destroy()}>
           {t('Close')}
         </Button>
       </div>
     ),
   });
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f6afa74 and 8442361.

📒 Files selected for processing (6)
  • controller/codex_usage.go
  • relay/channel/codex/constants.go
  • router/api-router.go
  • service/codex_wham_usage.go
  • web/src/components/table/channels/modals/CodexUsageModal.jsx
  • web/src/hooks/channels/useChannelsData.jsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • relay/channel/codex/constants.go
  • router/api-router.go
  • controller/codex_usage.go
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-27T02:15:25.448Z
Learnt from: AAEE86
Repo: QuantumNous/new-api PR: 1658
File: web/src/components/table/channels/modals/EditChannelModal.jsx:555-569
Timestamp: 2025-08-27T02:15:25.448Z
Learning: In EditChannelModal.jsx, the database stores mapped keys (display names) in the models field after applying model mapping transformations. When loading a channel, data.models contains the mapped keys, not the original model names. The filtering logic if (data.models.includes(key)) in the initialization is correct.

Applied to files:

  • web/src/hooks/channels/useChannelsData.jsx
🧬 Code graph analysis (1)
web/src/hooks/channels/useChannelsData.jsx (3)
web/src/helpers/api.js (6)
  • res (224-224)
  • res (225-225)
  • res (301-301)
  • res (302-302)
  • API (29-37)
  • API (29-37)
web/src/helpers/utils.jsx (3)
  • showError (122-151)
  • copy (72-95)
  • showSuccess (157-159)
web/src/components/table/channels/modals/CodexUsageModal.jsx (2)
  • openCodexUsageModal (92-169)
  • openCodexUsageModal (92-169)
🔇 Additional comments (5)
service/codex_wham_usage.go (1)

11-56: LGTM — solid input validation and request handling.

The function properly validates inputs, uses context for cancellation, and correctly defers body close before reading.

One minor observation: the check on lines 41-43 if req.Header.Get("originator") == "" is always true for a newly created request, so the conditional is unnecessary — you could simplify to just req.Header.Set("originator", "codex_cli_rs").

web/src/components/table/channels/modals/CodexUsageModal.jsx (2)

25-58: LGTM — well-designed helper utilities.

Good defensive handling of edge cases with Number.isFinite() checks and proper fallback values. The formatting functions are concise and handle invalid inputs gracefully.


60-90: LGTM — clean component with good defensive rendering.

The RateLimitWindowCard properly handles missing/undefined windowData with optional chaining and nullish coalescing defaults.

web/src/hooks/channels/useChannelsData.jsx (2)

39-39: LGTM — import added correctly.


749-771: Modal opens even after showing an error — verify this is intentional.

When res?.data?.success is falsy (line 754), showError() is called but the code still proceeds to open the modal (line 757). This means users see both an error toast and the modal with potentially incomplete/error data.

If intentional (e.g., to show raw error response for debugging), consider adding a comment. Otherwise, you may want to return early after showing the error:

♻️ Suggested change if modal should not open on failure
         const res = await API.get(`/api/channel/${record.id}/codex/usage`, {
           skipErrorHandler: true,
         });
         if (!res?.data?.success) {
           showError(res?.data?.message || t('Failed to fetch usage'));
+          return;
         }
         openCodexUsageModal({

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@relay/channel/openai/chat_via_responses.go`:
- Around line 29-32: The code currently calls io.ReadAll(resp.Body) in
chat_via_responses.go which removes the previous 10MB guard and risks OOM;
restore a bounded read by wrapping resp.Body with io.LimitReader (e.g., limit to
10*1024*1024) before reading and handle ErrUnexpectedEOF/size-truncate cases by
returning a suitable OpenAI error (use types.NewOpenAIError with
types.ErrorCodeReadResponseBodyFailed) from the same function so oversized
responses are rejected gracefully; ensure you still close resp.Body and update
any tests that expect the previous size behavior.

In `@web/src/hooks/channels/useChannelsData.jsx`:
- Around line 749-773: The modal is opened even when the codex usage API returns
success: false; update the block inside the record?.type === 57 branch (the
API.get call and its handling) so that after detecting !res?.data?.success you
log and showError and then return early (i.e., do not call openCodexUsageModal),
and likewise ensure the catch path also returns after showError; specifically
modify the logic around API.get and the openCodexUsageModal call to only invoke
openCodexUsageModal when res?.data?.success is truthy.
🧹 Nitpick comments (2)
relay/compatible_handler.go (1)

220-228: Consider removing redundant checks if helper is only used internally.

The helper has two checks that are redundant given the current call site:

  1. info == nilinfo is used extensively before this call (lines 31, 33, 47, etc.) and would panic if nil
  2. info.RelayMode != RelayModeChatCompletions — already verified by the caller at line 79

If this helper is designed for reuse from other call sites where these preconditions aren't guaranteed, the defensive checks are appropriate. Otherwise, they add minor overhead and cognitive load.

♻️ Simplified version (if only called from TextHelper)
 func shouldChatCompletionsViaResponses(info *relaycommon.RelayInfo) bool {
-	if info == nil {
-		return false
-	}
-	if info.RelayMode != relayconstant.RelayModeChatCompletions {
-		return false
-	}
 	return service.ShouldChatCompletionsUseResponsesGlobal(info.ChannelId, info.OriginModelName)
 }
web/src/components/table/channels/modals/EditChannelModal.jsx (1)

1972-2057: Well-structured UI for Codex channel type.

The Codex (type 57) UI block is comprehensive:

  • TextArea with clear JSON format placeholder and validation hints
  • Context-appropriate action buttons (OAuth, refresh in edit mode, format, view key)
  • Properly integrated CodexOAuthModal with correct event handlers

One minor simplification: Line 2044 includes {batchExtra}, but since batchAllowed excludes type 57, this will always be null. You could remove it from this block for clarity, though it's functionally harmless.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 957615a and f1024b4.

📒 Files selected for processing (6)
  • relay/channel/openai/chat_via_responses.go
  • relay/compatible_handler.go
  • web/src/components/table/channels/modals/CodexOAuthModal.jsx
  • web/src/components/table/channels/modals/CodexUsageModal.jsx
  • web/src/components/table/channels/modals/EditChannelModal.jsx
  • web/src/hooks/channels/useChannelsData.jsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • web/src/components/table/channels/modals/CodexUsageModal.jsx
  • web/src/components/table/channels/modals/CodexOAuthModal.jsx
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-27T02:15:25.448Z
Learnt from: AAEE86
Repo: QuantumNous/new-api PR: 1658
File: web/src/components/table/channels/modals/EditChannelModal.jsx:555-569
Timestamp: 2025-08-27T02:15:25.448Z
Learning: In EditChannelModal.jsx, the applyModelMapping function transforms the models list by replacing original model names (mapping values) with display names (mapping keys). The database stores this transformed list containing mapped keys. On channel load, data.models contains these mapped display names, making the initialization filter if (data.models.includes(key)) correct.

Applied to files:

  • web/src/components/table/channels/modals/EditChannelModal.jsx
📚 Learning: 2025-08-27T02:15:25.448Z
Learnt from: AAEE86
Repo: QuantumNous/new-api PR: 1658
File: web/src/components/table/channels/modals/EditChannelModal.jsx:555-569
Timestamp: 2025-08-27T02:15:25.448Z
Learning: In EditChannelModal.jsx, the database stores mapped keys (display names) in the models field after applying model mapping transformations. When loading a channel, data.models contains the mapped keys, not the original model names. The filtering logic if (data.models.includes(key)) in the initialization is correct.

Applied to files:

  • web/src/components/table/channels/modals/EditChannelModal.jsx
🧬 Code graph analysis (3)
web/src/hooks/channels/useChannelsData.jsx (1)
web/src/components/table/channels/modals/CodexUsageModal.jsx (2)
  • openCodexUsageModal (104-190)
  • openCodexUsageModal (104-190)
web/src/components/table/channels/modals/EditChannelModal.jsx (2)
web/src/helpers/utils.jsx (4)
  • showSuccess (157-159)
  • showError (122-151)
  • verifyJSON (273-280)
  • verifyJSON (273-280)
web/src/components/table/channels/modals/CodexOAuthModal.jsx (1)
  • CodexOAuthModal (27-149)
relay/compatible_handler.go (5)
setting/model_setting/global.go (1)
  • GetGlobalSettings (57-59)
relay/constant/relay_mode.go (1)
  • RelayModeChatCompletions (10-10)
relay/common/relay_info.go (1)
  • RelayInfo (82-131)
service/openai_chat_responses_mode.go (1)
  • ShouldChatCompletionsUseResponsesGlobal (12-14)
service/openaicompat/policy.go (1)
  • ShouldChatCompletionsUseResponsesGlobal (12-18)
🔇 Additional comments (10)
relay/compatible_handler.go (2)

78-82: LGTM - good refactoring to cache global setting.

Caching passThroughGlobal avoids repeated calls to model_setting.GetGlobalSettings() and improves readability. The extracted helper centralizes the decision logic nicely.


102-102: LGTM - consistent use of cached value.

Using the cached passThroughGlobal ensures consistent behavior within the same request handling.

web/src/hooks/channels/useChannelsData.jsx (1)

39-39: LGTM!

Import for openCodexUsageModal is correctly added to support the new Codex usage modal functionality.

web/src/components/table/channels/modals/EditChannelModal.jsx (7)

59-59: LGTM!

Import for CodexOAuthModal is correctly added.


118-119: LGTM!

Type 57 (Codex) secret prompt correctly instructs users about the required JSON format with access_token and account_id.


218-220: LGTM!

State variables for Codex OAuth modal visibility and credential refresh loading state are properly defined.


508-519: LGTM!

When switching to Codex type (57), the code properly resets batch-related state and clears Vertex-specific file uploads, preventing incompatible configurations.


843-867: LGTM with a note.

Both handlers are well-implemented with proper loading states and error handling. The handleRefreshCodexCredential correctly guards against non-edit mode and handles errors gracefully.

Note: After a successful credential refresh, the form's key field is not updated with the new value. If this is intentional (server-side refresh only), consider adding a comment. If users expect to see the new credentials, consider fetching and displaying the updated key.


1117-1156: LGTM!

Comprehensive validation for Codex (type 57) channel submission:

  • Correctly prevents batch creation
  • Requires key for new channels
  • Validates JSON structure and required fields (access_token, account_id)
  • Re-serializes to normalize the JSON

The validation logic is thorough and provides clear error messages to guide users.


1489-1489: LGTM!

Batch creation is correctly disabled for Codex channels (type 57), consistent with the validation logic in the submit handler.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +29 to 32
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, types.NewOpenAIError(err, types.ErrorCodeReadResponseBodyFailed, http.StatusInternalServerError)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Removing the response body size limit introduces memory exhaustion risk.

The previous 10MB limit protected against memory exhaustion from malicious or misbehaving upstream servers. Without a cap, an unbounded response can cause OOM and service disruption.

Consider restoring a size limit using io.LimitReader:

🛡️ Suggested fix to restore size limit
-	body, err := io.ReadAll(resp.Body)
+	const maxResponseSize = 10 << 20 // 10 MB
+	body, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseSize))
 	if err != nil {
 		return nil, types.NewOpenAIError(err, types.ErrorCodeReadResponseBodyFailed, http.StatusInternalServerError)
 	}
+	if len(body) >= maxResponseSize {
+		return nil, types.NewOpenAIError(fmt.Errorf("response body too large"), types.ErrorCodeBadResponseBody, http.StatusInternalServerError)
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, types.NewOpenAIError(err, types.ErrorCodeReadResponseBodyFailed, http.StatusInternalServerError)
}
const maxResponseSize = 10 << 20 // 10 MB
body, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseSize))
if err != nil {
return nil, types.NewOpenAIError(err, types.ErrorCodeReadResponseBodyFailed, http.StatusInternalServerError)
}
if len(body) >= maxResponseSize {
return nil, types.NewOpenAIError(fmt.Errorf("response body too large"), types.ErrorCodeBadResponseBody, http.StatusInternalServerError)
}
🤖 Prompt for AI Agents
In `@relay/channel/openai/chat_via_responses.go` around lines 29 - 32, The code
currently calls io.ReadAll(resp.Body) in chat_via_responses.go which removes the
previous 10MB guard and risks OOM; restore a bounded read by wrapping resp.Body
with io.LimitReader (e.g., limit to 10*1024*1024) before reading and handle
ErrUnexpectedEOF/size-truncate cases by returning a suitable OpenAI error (use
types.NewOpenAIError with types.ErrorCodeReadResponseBodyFailed) from the same
function so oversized responses are rejected gracefully; ensure you still close
resp.Body and update any tests that expect the previous size behavior.

Comment on lines +749 to +773
if (record?.type === 57) {
try {
const res = await API.get(`/api/channel/${record.id}/codex/usage`, {
skipErrorHandler: true,
});
if (!res?.data?.success) {
console.error('Codex usage fetch failed:', res?.data?.message);
showError(t('获取用量失败'));
}
openCodexUsageModal({
t,
record,
payload: res?.data,
onCopy: async (text) => {
const ok = await copy(text);
if (ok) showSuccess(t('已复制'));
else showError(t('复制失败'));
},
});
} catch (error) {
console.error('Codex usage fetch error:', error);
showError(t('获取用量失败'));
}
return;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Modal opens even when API call fails.

When res?.data?.success is false (line 754), the code shows an error message but still proceeds to open the modal (line 758) with potentially incomplete or error data. This leads to confusing UX where the user sees both an error toast and a modal with bad data.

Consider returning early after showing the error to prevent opening the modal on failure:

🐛 Proposed fix
       if (record?.type === 57) {
         try {
           const res = await API.get(`/api/channel/${record.id}/codex/usage`, {
             skipErrorHandler: true,
           });
           if (!res?.data?.success) {
             console.error('Codex usage fetch failed:', res?.data?.message);
             showError(t('获取用量失败'));
+            return;
           }
           openCodexUsageModal({
             t,
             record,
             payload: res?.data,
             onCopy: async (text) => {
               const ok = await copy(text);
               if (ok) showSuccess(t('已复制'));
               else showError(t('复制失败'));
             },
           });
         } catch (error) {
           console.error('Codex usage fetch error:', error);
           showError(t('获取用量失败'));
         }
         return;
       }
🤖 Prompt for AI Agents
In `@web/src/hooks/channels/useChannelsData.jsx` around lines 749 - 773, The modal
is opened even when the codex usage API returns success: false; update the block
inside the record?.type === 57 branch (the API.get call and its handling) so
that after detecting !res?.data?.success you log and showError and then return
early (i.e., do not call openCodexUsageModal), and likewise ensure the catch
path also returns after showError; specifically modify the logic around API.get
and the openCodexUsageModal call to only invoke openCodexUsageModal when
res?.data?.success is truthy.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@service/codex_credential_refresh_task.go`:
- Around line 137-139: Remove the redundant guard around the debug log: delete
the surrounding if common.DebugEnabled conditional and always call
logger.LogDebug(ctx, "codex credential auto-refresh: scanned=%d refreshed=%d",
scanned, refreshed) because LogDebug already checks common.DebugEnabled; update
the block that currently wraps logger.LogDebug so only the direct
logger.LogDebug call remains (refer to logger.LogDebug and the variables scanned
and refreshed).
♻️ Duplicate comments (1)
service/codex_credential_refresh.go (1)

94-96: Direct DB update bypasses model-layer validations.

The raw model.DB.Model(...).Update(...) call bypasses Channel.Update(), which handles MultiKeySize recalculation for multi-key channels, status data cleanup, and UpdateAbilities(). Since ch is already loaded, consider using:

ch.Key = string(encoded)
if err := ch.Update(); err != nil {
    return nil, nil, err
}

This ensures consistency if Codex channels ever become multi-key or if other model-layer hooks are added.

🧹 Nitpick comments (2)
controller/channel.go (1)

632-661: Double timeout context nesting.

The controller creates a 10-second timeout (line 639), and RefreshCodexChannelCredential internally creates another 10-second timeout (line 62 in service/codex_credential_refresh.go). The inner timeout will be constrained by the outer one—if any overhead occurs before the inner timeout starts, the effective refresh window could be less than 10 seconds.

Consider removing the controller-level timeout and relying on the service's internal timeout, or passing the controller's context directly without an additional timeout.

♻️ Suggested simplification
 func RefreshCodexChannelCredential(c *gin.Context) {
 	channelId, err := strconv.Atoi(c.Param("id"))
 	if err != nil {
 		common.ApiError(c, fmt.Errorf("invalid channel id: %w", err))
 		return
 	}
 
-	ctx, cancel := context.WithTimeout(c.Request.Context(), 10*time.Second)
-	defer cancel()
-
-	oauthKey, ch, err := service.RefreshCodexChannelCredential(ctx, channelId, service.CodexCredentialRefreshOptions{ResetCaches: true})
+	oauthKey, ch, err := service.RefreshCodexChannelCredential(c.Request.Context(), channelId, service.CodexCredentialRefreshOptions{ResetCaches: true})
 	if err != nil {
service/codex_credential_refresh.go (1)

19-29: Consolidate duplicate OAuthKey structs across layers.

The codebase has identical struct definitions in two places: OAuthKey in relay/channel/codex/oauth_key.go (lines 9–19) and CodexOAuthKey in service/codex_credential_refresh.go (lines 19–29). Both define the same fields with identical JSON tags. Similarly, parsing logic is duplicated as ParseOAuthKey and parseCodexOAuthKey.

Consider importing and reusing OAuthKey from the relay layer instead of maintaining a parallel struct. This eliminates the maintenance burden of keeping two identical definitions in sync.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f1024b4 and 2aa47cf.

📒 Files selected for processing (4)
  • controller/channel.go
  • main.go
  • service/codex_credential_refresh.go
  • service/codex_credential_refresh_task.go
🧰 Additional context used
🧬 Code graph analysis (4)
main.go (1)
service/codex_credential_refresh_task.go (1)
  • StartCodexCredentialAutoRefreshTask (31-49)
controller/channel.go (4)
constant/channel.go (1)
  • ChannelTypeCodex (57-57)
common/json.go (1)
  • Unmarshal (9-11)
service/codex_credential_refresh.go (2)
  • RefreshCodexChannelCredential (42-104)
  • CodexCredentialRefreshOptions (15-17)
common/gin.go (1)
  • ApiError (141-146)
service/codex_credential_refresh.go (7)
common/json.go (2)
  • Unmarshal (9-11)
  • Marshal (21-23)
model/channel.go (1)
  • Channel (21-58)
constant/channel.go (1)
  • ChannelTypeCodex (57-57)
service/codex_oauth.go (3)
  • RefreshCodexOAuthToken (40-43)
  • ExtractCodexAccountIDFromJWT (226-252)
  • ExtractEmailFromJWT (254-272)
model/main.go (1)
  • DB (64-64)
model/channel_cache.go (1)
  • InitChannelCache (21-86)
service/http_client.go (1)
  • ResetProxyClientCache (71-80)
service/codex_credential_refresh_task.go (6)
common/constants.go (2)
  • IsMasterNode (112-112)
  • DebugEnabled (71-71)
model/channel.go (2)
  • Channel (21-58)
  • ChannelInfo (60-68)
model/main.go (1)
  • DB (64-64)
constant/channel.go (1)
  • ChannelTypeCodex (57-57)
service/codex_credential_refresh.go (2)
  • RefreshCodexChannelCredential (42-104)
  • CodexCredentialRefreshOptions (15-17)
service/http_client.go (1)
  • ResetProxyClientCache (71-80)
🔇 Additional comments (9)
service/codex_credential_refresh.go (2)

31-40: LGTM!

The parsing function correctly validates input and provides clear error messages.


42-87: LGTM!

The credential refresh flow is well-structured with proper validation, timeout handling, and defensive JWT extraction for missing fields.

controller/channel.go (2)

4-10: LGTM!

The new imports are required by the RefreshCodexChannelCredential handler.


609-627: LGTM with minor observation.

The validation correctly enforces Codex key structure. Note that the fmt.Sprintf("%v", v) approach treats a numeric 0 the same as the string "0" which would pass the empty check—this should be fine since token/account values are typically non-empty strings.

service/codex_credential_refresh_task.go (4)

19-24: LGTM!

The constants are well-chosen: 10-minute intervals with a 24-hour expiry threshold provides ample margin for credential refresh without excessive overhead.


31-49: LGTM!

The task initialization correctly uses sync.Once for idempotency, respects master-node configuration, and follows the established pattern of using gopool.Go for managed goroutines.


64-123: LGTM!

The batch processing correctly:

  • Filters for enabled Codex channels
  • Skips multi-key channels (per design)
  • Uses expiry threshold to avoid unnecessary refreshes
  • Logs warnings on failures without aborting the batch

125-135: LGTM!

Efficient cache reset logic—only triggered when credentials were actually refreshed. The panic recovery for InitChannelCache mirrors the defensive pattern used in main.go.

main.go (1)

105-106: LGTM!

The Codex credential auto-refresh task is properly initialized during startup. The placement after AutomaticallyTestChannels is logical, and the comment accurately describes the task's behavior.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +137 to +139
if common.DebugEnabled {
logger.LogDebug(ctx, "codex credential auto-refresh: scanned=%d refreshed=%d", scanned, refreshed)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

rg -n 'func LogDebug' --type go -A 3

Repository: QuantumNous/new-api

Length of output: 286


Remove the redundant if common.DebugEnabled check.

LogDebug already checks common.DebugEnabled internally before formatting and logging. The guard at lines 137-138 is unnecessary and adds a redundant conditional.

Current code (lines 137-139)
	if common.DebugEnabled {
		logger.LogDebug(ctx, "codex credential auto-refresh: scanned=%d refreshed=%d", scanned, refreshed)
	}

Simplify to:

	logger.LogDebug(ctx, "codex credential auto-refresh: scanned=%d refreshed=%d", scanned, refreshed)
🤖 Prompt for AI Agents
In `@service/codex_credential_refresh_task.go` around lines 137 - 139, Remove the
redundant guard around the debug log: delete the surrounding if
common.DebugEnabled conditional and always call logger.LogDebug(ctx, "codex
credential auto-refresh: scanned=%d refreshed=%d", scanned, refreshed) because
LogDebug already checks common.DebugEnabled; update the block that currently
wraps logger.LogDebug so only the direct logger.LogDebug call remains (refer to
logger.LogDebug and the variables scanned and refreshed).

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@relay/channel/codex/adaptor.go`:
- Around line 55-95: The code in ConvertOpenAIResponsesRequest currently
swallows unmarshal errors for request.Instructions when
info.ChannelSetting.SystemPromptOverride is true and replaces the original
instructions with the system prompt; instead, preserve the original
request.Instructions on unmarshal failure and emit a warning (use the
gin.Context c or your existing logger) so the invalid/unparseable payload is
visible; only replace Instructions with the system prompt when unmarshaling
succeeds and indicates an empty string or when you explicitly decide to
fallback, and avoid silently discarding structured instruction payloads.
♻️ Duplicate comments (1)
relay/channel/codex/adaptor.go (1)

120-125: Error message inconsistent with actual endpoint path.

The error message states "only /v1/responses is supported" but the code uses /backend-api/codex/responses. This discrepancy was previously flagged.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2aa47cf and 6aa9c02.

📒 Files selected for processing (1)
  • relay/channel/codex/adaptor.go
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-08T17:12:43.157Z
Learnt from: RedwindA
Repo: QuantumNous/new-api PR: 1537
File: relay/gemini_handler.go:330-342
Timestamp: 2025-08-08T17:12:43.157Z
Learning: In the new-api repository, the `GeminiEmbeddingHandler` function in `relay/gemini_handler.go` is designed specifically for native Gemini embedding requests and therefore does not require the `ConvertGeminiRequest` step that is used in the chat handler. The embedding requests are already in the native Gemini format and don't need conversion.

Applied to files:

  • relay/channel/codex/adaptor.go
🔇 Additional comments (4)
relay/channel/codex/adaptor.go (4)

21-53: LGTM - Consistent unsupported endpoint handling.

The adaptor correctly returns explicit "endpoint not supported" errors for all non-Responses endpoints, which aligns with the Codex channel's limited scope.


97-110: LGTM - Clean delegation pattern.

Request and response handling correctly delegates to the shared infrastructure, with appropriate mode validation and streaming support.


127-151: LGTM - OAuth authentication setup.

The authentication logic properly parses the structured API key, validates required fields, and sets appropriate headers for the Codex backend.


153-158: No issues identified. The originator header is correctly set to "codex_cli_rs", which is the official identifier used by the Codex CLI itself for telemetry purposes. This is documented behavior, not impersonation, and is consistently used across the codebase. The implementation properly follows OpenAI's documented patterns for the Codex CLI.

Likely an incorrect or invalid review comment.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +55 to +95
func (a *Adaptor) ConvertOpenAIResponsesRequest(c *gin.Context, info *relaycommon.RelayInfo, request dto.OpenAIResponsesRequest) (any, error) {
if info != nil && info.ChannelSetting.SystemPrompt != "" {
systemPrompt := info.ChannelSetting.SystemPrompt

if len(request.Instructions) == 0 {
if b, err := common.Marshal(systemPrompt); err == nil {
request.Instructions = b
} else {
return nil, err
}
} else if info.ChannelSetting.SystemPromptOverride {
var existing string
if err := common.Unmarshal(request.Instructions, &existing); err == nil {
existing = strings.TrimSpace(existing)
if existing == "" {
if b, err := common.Marshal(systemPrompt); err == nil {
request.Instructions = b
} else {
return nil, err
}
} else {
if b, err := common.Marshal(systemPrompt + "\n" + existing); err == nil {
request.Instructions = b
} else {
return nil, err
}
}
} else {
if b, err := common.Marshal(systemPrompt); err == nil {
request.Instructions = b
} else {
return nil, err
}
}
}
}

// codex: store must be false
request.Store = json.RawMessage("false")
return request, nil
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Silent discard of instructions on unmarshal failure.

When SystemPromptOverride is true and unmarshaling existing instructions fails (lines 82-88), the original request.Instructions are silently replaced with the system prompt. If the user provided instructions in a non-string format (e.g., the API could support structured instructions), this discards them without warning.

Consider logging a warning or returning an error when existing instructions cannot be parsed:

Suggested approach
 			}
 		} else {
-			if b, err := common.Marshal(systemPrompt); err == nil {
-				request.Instructions = b
-			} else {
-				return nil, err
-			}
+			// Log warning about unparseable instructions being replaced
+			common.SysLog("codex channel: could not parse existing instructions, replacing with system prompt")
+			if b, err := common.Marshal(systemPrompt); err == nil {
+				request.Instructions = b
+			} else {
+				return nil, err
+			}
 		}
🤖 Prompt for AI Agents
In `@relay/channel/codex/adaptor.go` around lines 55 - 95, The code in
ConvertOpenAIResponsesRequest currently swallows unmarshal errors for
request.Instructions when info.ChannelSetting.SystemPromptOverride is true and
replaces the original instructions with the system prompt; instead, preserve the
original request.Instructions on unmarshal failure and emit a warning (use the
gin.Context c or your existing logger) so the invalid/unparseable payload is
visible; only replace Instructions with the system prompt when unmarshaling
succeeds and indicates an empty string or when you explicitly decide to
fallback, and avoid silently discarding structured instruction payloads.

@Calcium-Ion Calcium-Ion merged commit e5cb9ac into QuantumNous:main Jan 14, 2026
1 check passed
dreamlx pushed a commit to dreamlx/new-api that referenced this pull request Feb 1, 2026
主要更新:
- feat: 磁盘请求体缓存 (QuantumNous#2780)
- feat: OpenAI Response API /v1/response/compact (QuantumNous#2644)
- feat: 渠道亲和性 (Channel Affinity) (QuantumNous#2669)
- feat: Codex渠道支持 (QuantumNous#2652)
- feat: Claude/Grok refusal reason显示
- feat: 性能监控和GC控制API
- fix: 用户配额获取逻辑 (QuantumNous#2749)
- fix: Gemini多工具调用索引问题
- fix: 错误时仍本地计费

冲突解决:
- README.md: 保留中文版本
- go.mod: 采用上游较新版本

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
ennnnny pushed a commit to ennnnny/new-api that referenced this pull request Mar 17, 2026
* feat: codex channel

* feat: codex channel

* feat: codex oauth flow

* feat: codex refresh cred

* feat: codex usage

* fix: codex err message detail

* fix: codex setting ui

* feat: codex refresh cred task

* fix: import err

* fix: codex store must be false

* fix: chat -> responses tool call

* fix: chat -> responses tool call
Calcium-Ion added a commit that referenced this pull request Apr 28, 2026
…up (#4265)

* feat: add parameter coverage for the operations: copy, trim_prefix, trim_suffix, ensure_prefix, ensure_suffix, trim_space, to_lower, to_upper, replace, and regex_replace

* fix: CrossGroupRetry default false

移除gorm:"default:false",避免每次 AutoMigrate时都执行ALTER TABLE `tokens` MODIFY COLUMN `cross_group_retry` boolean DEFAULT false
且bool默认false不影响原有功能

* feat: check-in feature integrates Turnstile security check

* feat: add support for Doubao /v1/responses (#2567)

* feat: add support for Doubao /v1/responses

* fix: fix model deployment style issues, lint problems, and i18n gaps. (#2556)

* fix: fix model deployment style issues, lint problems, and i18n gaps.

* fix: adjust the key not to be displayed on the frontend, tested via the backend.

* fix: adjust the sidebar configuration logic to use the default configuration items if they are not defined.

* feat: add plans directory to .gitignore

* fix: 修复 gemini 文件类型不支持 image/jpg

* fix: fix the proxyURL is empty, not using the default HTTP client configuration && the AWS calling side did not apply the relay timeout.

* fix: batch add key backend deduplication

* Merge pull request #2582 from seefs001/fix/tips

fix: add tips for model management and channel testing

* fix(gin): update request body size check to allow zero limit

* feat: add regex pattern to mask API keys in sensitive information

* fix(task): 修复使用 auto 分组时 Task Relay 不记录日志和不扣费的问题

问题描述:
- 使用 auto 分组的令牌调用 /v1/videos 等 Task 接口时,虽然任务能成功创建,
  但使用日志不显示记录,且不会扣费

根本原因:
- Distribute 中间件在选择渠道后,会将实际选中的分组存储在 ContextKeyAutoGroup 中
- 但 RelayTaskSubmit 函数没有从 context 中读取这个值来更新 info.UsingGroup
- 导致 info.UsingGroup 始终是 "auto" 而不是实际选中的分组(如 "sora2逆")
- 当 auto 分组的倍率配置为 0 时,quota 计算结果为 0
- 日志记录条件 "if quota != 0" 不满足,导致日志不记录、不扣费

修复方案:
- 在 RelayTaskSubmit 函数中计算分组倍率之前,添加从 ContextKeyAutoGroup
  获取实际分组的逻辑
- 使用安全的类型断言,避免潜在的 panic 风险

影响范围:
- 仅影响 Task Relay 流程(/v1/videos, /suno, /kling 等接口)
- 不影响使用具体分组令牌的调用
- 不影响其他 Relay 类型(chat/completions 等已有类似处理逻辑)

* 🚀 feat(web): port legacy v2 frontend changes into new UI (deployments, check-in, ollama) + align APIs

Bring over the key frontend functionality introduced in merge `efa3301` and integrate it cleanly into the new `web/src` architecture and design system.

- **Model deployments (io.net)**
  - Align frontend endpoints and payloads with backend deployment routes (`/api/deployments/*`)
  - Add missing deployment operations: details, logs (container-aware), update config, rename, extend duration
  - Improve create-deployment flow (proper request shape, name availability check, price estimation parity)

- **System settings**
  - Enhance io.net deployment settings: allow testing connection with an unsaved API key and add “how to get API key” guidance

- **Channels / Ollama**
  - Improve Ollama model management: live fetch via base_url with fallback to channel fetch, selection + apply flows, delete confirmation
  - Refactor for feature-layer consistency: extract Ollama parsing/normalization utilities into `features/channels/lib`

- **Quality**
  - Ensure TypeScript typecheck passes after refactor and new dialogs/components integration

* Merge pull request #2590 from xyfacai/fix/max-body-limit

fix: 设置默认max req body 为128MB

* docs: update readme

* i18n: add missing translations

* fix(gemini): fetch model list via native v1beta/models endpoint

Use the native Gemini Models API (/v1beta/models) instead of the OpenAI-compatible
path when listing models for Gemini channels, improving compatibility with
third-party Gemini-format providers that don't implement OpenAI routes.

- Add paginated model listing with timeout and optional proxy support
- Select an enabled key for multi-key Gemini channels

* refactor(gemini): 更新 GeminiModelsResponse 以使用 dto.GeminiModel 类型

* fix: remove Minimax from FETCHABLE channels

* fix(minimax): 添加 MiniMax-M2 系列模型到 ModelList

* feat: add doubao video 1.5

* 🤢 chore: remove useless file

* feat: /v1/chat/completion -> /v1/response (#2629)

* feat: /v1/chat/completion -> /v1/response

* fix: clean propertyNames for gemini function

* fix: support snake_case fields in GeminiChatGenerationConfig

* chore: update dependencies and lockfile for improved compatibility

- Updated @clerk/clerk-react to version 5.59.3
- Updated @hookform/resolvers to version 5.2.2
- Updated @lobehub/icons to version 2.48.0
- Updated various Radix UI components to their latest versions
- Updated @tanstack/react-query and related packages for better performance
- Updated axios, i18next, and other libraries for security and feature enhancements
- Updated lockfile to include configVersion and ensure consistency across environments

* Merge pull request #2647 from seefs001/feature/status-code-auto-disable

feat: status code auto-disable configuration

* fix: chat2response setting ui (#2643)

* fix: setting ui

* fix: rm global.chat_completions_to_responses_policy

* fix: rm global.chat_completions_to_responses_policy

* Merge pull request #2627 from seefs001/feature/channel-test-param-override

feat: channel testing supports parameter overriding

* chore: update dependencies and lockfile for improved compatibility

- Updated @lobehub/icons to version 4.0.3
- Updated ai to version 6.0.27
- Updated various libraries including axios, react-day-picker, and streamdown for security and feature enhancements
- Updated devDependencies for eslint, prettier, and typescript for better performance and compatibility
- Updated lockfile to ensure consistency across environments

* chore: update lockfile and Vite configuration for improved build process

- Updated lockfile to version 1 for better compatibility and consistency
- Enhanced Vite configuration to support production optimizations, including code minification and chunking for dependencies
- Added environment-specific console and debugger removal for production builds

* chore: migrate from Vite to Rsbuild for build process

- Added Rsbuild configuration for development and production builds
- Updated package.json scripts to use Rsbuild instead of Vite
- Replaced @tailwindcss/vite with @tailwindcss/postcss in dependencies
- Introduced postcss.config.mjs for Tailwind CSS integration
- Updated TypeScript configuration to include Rsbuild config
- Removed Vite configuration file to streamline the build process

* refactor: optimize user data handling and API calls

- Replaced direct API calls to get user data with cached user information from auth-store in ModelsFilter and SummaryCards components.
- Improved session management in RootComponent and Authenticated route to utilize localStorage for user authentication status, reducing unnecessary API requests.
- Added caching for setup status checks to enhance performance during navigation.

* feat: enhance session validation in authenticated route

- Implemented session verification to check user authentication status via API call only once per session.
- Updated beforeLoad logic to redirect users to the login page if session validation fails or if no user information is available in localStorage.
- Improved user data handling by updating the auth store with fresh user information upon successful session verification.

* refactor: improve useMediaQuery hook for better SSR handling

- Enhanced the useMediaQuery hook to check for window availability before accessing matchMedia, preventing errors during server-side rendering.
- Simplified state initialization and change handling by using a dedicated function to determine initial matches.
- Updated event listener management for improved performance and clarity.

* feat(hooks): export useMediaQuery from hooks index

* refactor: update useMediaQuery imports to use unified hooks index

* fix(rsbuild): fix loadEnv API usage and removeConsole type

* feat: customizable automatic retry status codes

* refactor(hooks): use useSyncExternalStore for better SSR handling in useMediaQuery

* refactor: simplify embedded file structure in main.go

- Updated the embedded file directive to include the entire web/dist directory instead of individual assets, streamlining the build process.

* refactor: replace DropdownMenu with Sheet component in ProfileDropdown

- Updated the ProfileDropdown component to use a Sheet for user interactions instead of a DropdownMenu.
- Enhanced user info display with improved layout and styling.
- Added navigation links and sign-out functionality within the Sheet.

* refactor: streamline ProfileDropdown layout and improve user info display

- Removed unused Badge component and secondary text from user display.
- Enhanced styling for user info section and navigation links.
- Updated sign-out functionality to use a button for better accessibility.

* feat: add System Settings link for super admin in ProfileDropdown

- Introduced a new link to System Settings in the ProfileDropdown, visible only to users with the SUPER_ADMIN role.
- Updated imports to include the Settings icon and adjusted the component logic accordingly.
- Removed the Settings entry from the sidebar data to streamline navigation.

* feat: codex channel (#2652)

* feat: codex channel

* feat: codex channel

* feat: codex oauth flow

* feat: codex refresh cred

* feat: codex usage

* fix: codex err message detail

* fix: codex setting ui

* feat: codex refresh cred task

* fix: import err

* fix: codex store must be false

* fix: chat -> responses tool call

* fix: chat -> responses tool call

* feat(i18n): add missing translations

* fix(i18n): restore missing translations for "360" and add "User Menu" in multiple locales

- Reintroduced the translation for "360" in English, French, Japanese, Russian, Vietnamese, and Chinese locales.
- Added the "User Menu" translation in the same languages to enhance user interface consistency.

* fix: openAI function to gemini function field adjusted to whitelist mode

* feat: TLS_INSECURE_SKIP_VERIFY env

* fix: for chat-based calls to the Claude model, tagging is required. Using Claude's rendering logs, the two approaches handle input rendering differently.

* refactor(system-settings): restructure settings sections and navigation

- Replaced SettingsAccordion with a unified SettingsSection component across various settings sections for consistency.
- Introduced a section registry to manage general settings sections dynamically.
- Updated navigation items in the system settings sidebar to utilize the new section registry.
- Enhanced the GeneralSettings component to support section-based content rendering based on user selection.

* fix(system-settings): remove type assertion for quotaDisplayType in GeneralSettings

- Eliminated the type assertion for quotaDisplayType in the GeneralSettings component to improve type inference and maintain cleaner code.

* refactor(system-settings): update zod import syntax in general settings

- Changed the import statement for zod from a default import to a namespace import for better clarity and consistency in the codebase.

* fix: the login method cannot be displayed under the aff link.

* feat(system-settings): implement generic settings page and enhance navigation

- Added a new generic SettingsPage component to handle loading states, data fetching, and section rendering.
- Integrated section registry for general and authentication settings to streamline navigation and content management.
- Updated URL utility functions to improve query parameter handling for active navigation states.
- Enhanced the system settings sidebar to include authentication section items dynamically.

* refactor(system-settings): replace SettingsAccordion with SettingsSection across authentication settings

- Updated BasicAuthSection, BotProtectionSection, OAuthSection, and PasskeySection to use the new SettingsSection component for consistency.
- Introduced a section registry to manage authentication settings dynamically, enhancing navigation and content rendering.

* feat(system-settings): enhance request limits settings with new section and unified component

- Added a new Request Limits section to the system settings sidebar, integrating it with the section registry for improved navigation.
- Replaced SettingsAccordion with SettingsSection in RateLimitSection, SensitiveWordsSection, and SSRFSection for consistency.
- Updated RequestLimitsSettings to utilize the new SettingsPage component for better data handling and rendering.
- Implemented a search schema for request limits to streamline navigation and section management.

* feat(system-settings): integrate content settings sections with unified component and registry

- Added a new Content section to the system settings sidebar, incorporating it into the section registry for improved navigation.
- Replaced SettingsAccordion with SettingsSection in multiple content-related components for consistency.
- Created a section registry to manage content settings dynamically, enhancing the rendering and navigation experience.
- Updated the ContentSettings component to utilize the new section registry and streamline content display.

* feat(system-settings): enhance integrations settings with unified section registry and components

- Introduced a new section registry for integrations settings, consolidating various settings components for better organization and navigation.
- Replaced SettingsAccordion with SettingsSection in multiple integration-related components for consistency.
- Updated IntegrationSettings to utilize the new SettingsPage component, improving data handling and rendering.
- Added a new integrations section to the system settings sidebar, enhancing user experience and accessibility.

* feat(system-settings): unify model settings with new section registry and components

- Introduced a section registry for model settings, consolidating various model-related components for improved organization and navigation.
- Replaced SettingsAccordion with SettingsSection in multiple model settings components for consistency.
- Updated ModelSettings to utilize the new SettingsPage component, enhancing data handling and rendering.
- Added a new Models section to the system settings sidebar, improving user experience and accessibility.

* feat(system-settings): enhance maintenance settings with unified section registry and components

- Introduced a new section registry for maintenance settings, consolidating various maintenance-related components for improved organization and navigation.
- Replaced SettingsAccordion with SettingsSection in multiple maintenance components for consistency.
- Updated MaintenanceSettings to utilize the new section registry, enhancing data handling and rendering.
- Added a new Maintenance section to the system settings sidebar, improving user experience and accessibility.

* feat(system-settings): update section titles for improved clarity and consistency

- Renamed various section titles across content, integrations, maintenance, models, and request limits to enhance clarity and better reflect their functionalities.
- Adjusted titles such as 'Dashboard' to 'Data Dashboard', 'API Info' to 'API Addresses', and 'Update Checker' to 'System maintenance' for improved user understanding.
- Ensured consistency in naming conventions across all settings sections to streamline user experience and navigation.

* feat(nav-group): enhance collapsible menu behavior and URL matching logic

- Added controlled state management for collapsible menu items to automatically expand based on active sub-item paths.
- Updated the URL matching logic in checkIsActive to improve handling of query parameters and ensure accurate navigation state detection.
- Refactored the collapsible component to utilize the new state management, enhancing user experience in the sidebar navigation.

* feat(system-settings): update system settings navigation and redirect logic

- Changed the link in the profile dropdown to point directly to the general section of system settings with a search parameter for section identification.
- Implemented a redirect in the general settings route to ensure users are directed to the default section if no section parameter is provided, enhancing navigation consistency.

* feat(system-settings): unify route configuration for settings sections

- Refactored route configuration for various system settings sections (auth, content, general, integrations, maintenance, models, request limits) to utilize a new `createSettingsRouteConfig` function.
- This change consolidates the repetitive logic of creating search schemas and handling redirects, improving code maintainability and readability.
- Enhanced navigation by ensuring default sections are loaded when no section parameter is provided.

* feat(url-utils): enhance URL handling and matching logic

- Introduced a new utility function `urlToString` to convert various URL formats (string and object) into a standardized string format.
- Updated the `checkIsActive` function to utilize `urlToString`, improving the accuracy of URL matching and handling of query parameters.
- Refactored URL comparison logic to ensure consistent behavior across different URL types, enhancing navigation state detection.

* feat(system-settings): validate DataExportDefaultTime for improved data handling

- Introduced a new function `validateDataExportDefaultTime` to ensure the `DataExportDefaultTime` value is either 'week', 'hour', or 'day', defaulting to 'hour' for unexpected values.
- Updated the `DataExportDefaultTime` assignment in the settings section to utilize this validation function, enhancing data integrity and user experience.

* perf(system-settings): Improve the i18n of system settings content

- Changed button labels in various sections to use consistent capitalization and translation functions, enhancing user experience.
- Updated validation messages in schemas to utilize translation functions for improved internationalization support.
- Ensured all user-facing strings are properly translated, improving accessibility for non-English users.

* fix(system-settings): update ApiInfoFormValues type inference for improved schema validation

- Changed the type inference for ApiInfoFormValues to utilize ReturnType of createApiInfoSchema, ensuring accurate type representation and enhancing type safety in the API info section.

* fix(chat-settings): improve validation logic for chat settings schema

- Updated the validation logic to ensure that null values are correctly handled and that only objects are accepted as valid items in the chat settings schema.
- Simplified error handling by removing the error message from the catch block, providing a consistent user-facing message for invalid JSON strings.

* fix(system-settings): enhance validation error handling in uptime-kuma schema

- Updated the validation logic for category name, URL, and slug fields to use an object format for error messages, improving clarity and consistency in user feedback.
- Ensured that all validation messages are properly structured to enhance internationalization support.

* fix(i18n): add translations for Uptime Kuma group management

- Added English, French, Japanese, Russian, Vietnamese, and Chinese translations for "Add Uptime Kuma Group" and "Edit Uptime Kuma Group" to enhance internationalization support.
- Included validation messages for category name and slug fields across multiple languages to improve user feedback and accessibility.

* fix(system-settings): improve validation error message structure for SystemName

- Updated the validation logic for the SystemName field to use an object format for error messages, enhancing clarity and consistency in user feedback.
- This change aligns with recent improvements in internationalization support across the system settings schemas.

* perf(i18n): add new validation error message translations

- Added translations for the new validation error message "Invalid JSON format or values out of allowed range" in English, French, Japanese, Russian, Vietnamese, and Chinese.
- This update enhances internationalization support by ensuring users receive clear feedback across multiple languages.

* fix(i18n): update Japanese translation for payment method configuration message

- Corrected the Japanese translation for the message regarding payment methods configuration to use the term "メソッド" instead of "方法" for improved accuracy and consistency in user feedback.
- This change enhances the clarity of the message for Japanese-speaking users.

* fix(i18n): remove unnecessary loading messages from French translations

- Removed the French translations for "Loading settings...", "Loading maintenance settings...", and "Loading content settings..." to streamline the localization file.
- This change improves the clarity and relevance of the translations provided to users.

* fix(i18n): add translations for Uptime Kuma group management in multiple languages

- Added French, Japanese, Russian, Vietnamese, and Chinese translations for "Add Uptime Kuma Group" and "Edit Uptime Kuma Group" to enhance internationalization support.
- This update improves user experience by providing clear and consistent messaging across different languages.

* fix(validation): enhance pricing schema error messages and add translations

- Updated the pricing schema to include localized error messages for validation, ensuring users receive clear feedback when input values are invalid.
- Added new translations for "Exchange rate is required" and "Exchange rate must be greater than 0" in English, French, Japanese, and Chinese to improve internationalization support.
- This change enhances user experience by providing accurate and contextually relevant messages across multiple languages.

* fix: codex Unsupported parameter: max_output_tokens

* fix(model-mapping-editor): simplify JSON parsing logic in useEffect

* fix: jimeng i2v support multi image by metadata

* refactor(models): restructure models section handling and improve UI components

- Replaced tab-based navigation with section-based navigation for better clarity and organization.
- Introduced a new section registry to manage model sections, including 'metadata' and 'deployments'.
- Updated the ModelsContent component to reflect the new section structure and added a Create Deployment button.
- Removed the ModelsTabs component as it was no longer needed.
- Enhanced internationalization support by adding new translations for section descriptions and management tasks.
- Adjusted sidebar configuration to accommodate the new section structure.

* fix: update warning threshold label from '5$' to '2$'

* fix: video content api Priority use url field

* fix: update abortWithOpenAiMessage function to use types.ErrorCode

* feat(deployment): introduce CreateDeploymentDrawer component and update dialog references

- Replaced the CreateDeploymentDialog with a new CreateDeploymentDrawer component for improved user experience.
- Added comprehensive form handling for deployment creation, including validation and price estimation features.
- Updated internationalization files to include new translations for UI elements and descriptions related to deployment configuration.
- Enhanced the ModelsContent component to integrate the new drawer for creating deployments.

* perf(i18n): enhance internationalization for models table and columns

- Updated labels and titles in the ModelsTable and useModelsColumns components to utilize translation functions for improved localization.
- Changed static text for vendor and sync status to dynamic translations, enhancing user experience for non-English speakers.
- Updated empty state messages in the ModelsTable to support internationalization, ensuring clarity for all users.

* fix: fix email send

* fix: issue where consecutive calls to multiple tools in gemini all returned an index of 0

* fix: replace Alibaba's Claude-compatible interface with the new interface

* fix: Only models with the "qwen" designation can use the Claude-compatible interface; others require conversion.

* feat: log shows request conversion

* feat: optimized display

* feat: optimized display

* feat: optimized display

* fix: codex rm Temperature

* Revert "fix: video content api Priority use url field"

* feat: requestId time string use UTC

* feat(qwen): support qwen image sync image model config

* feat: sync old ui

* feat: more ui sync

* feat: replace theme

* fix build

* refactor(web): revert theme colors and variables in CSS

Updated color variables for light and dark themes to improve consistency and visual appeal.

* feat(deployment): enhance deployment access guard and model deployment settings

- Introduced loading phase management in the DeploymentAccessGuard component to provide better user feedback during connection checks.
- Updated the ModelsContent component to prefetch the deployments list while checking connection status, improving data readiness.
- Implemented a caching mechanism for connection status in useModelDeploymentSettings to optimize performance and reduce unnecessary API calls.
- Enhanced loading states and error handling for improved user experience during deployment settings retrieval and connection testing.

* feat(i18n): add new translations for connection and loading states across multiple languages

- Introduced translations for "Checking connection" and "Loading configuration" in English, French, Japanese, Russian, Vietnamese, and Chinese.
- This update enhances the internationalization support, providing clearer user feedback during connection checks and loading phases.

* refactor(pagination): adjust layout and styling for pagination component

- Updated the pagination component to improve layout by removing unnecessary width constraints and enhancing responsiveness.
- Increased minimum width for pagination text to ensure better visibility and alignment across different screen sizes.

* feat(i18n): implement translations for various UI elements across multiple components

- Updated several components to utilize the translation function for titles and placeholders, enhancing internationalization support.
- Added new translation entries for "Filter by name or key..." and "Log Type" in English, French, Japanese, Russian, Vietnamese, and Chinese.
- This update improves user experience by providing localized text in the ChannelsTable, SummaryCards, ApiKeysTable, RedemptionsTable, UsageLogsTable, and UsersTable components.

* feat(i18n): integrate translation support in SummaryCards component

- Added the useTranslation hook to the SummaryCards component to enhance internationalization.
- This update allows for localized text rendering, improving user experience for diverse language speakers.

* feat(dashboard): refactor dashboard structure and introduce section-based navigation

- Removed the tab navigation in favor of a section-based approach, enhancing user experience by providing clearer context for the dashboard content.
- Introduced a new section registry to manage dashboard sections, allowing for easier expansion and maintenance.
- Updated sidebar configuration to reflect the new section structure, ensuring proper navigation links are displayed.
- Added translations for new section titles and descriptions to support internationalization.

* feat(i18n): update time range labels and enhance translation support

- Changed time range labels from shorthand (e.g., '1D') to full text (e.g., '1 Day') for better clarity.
- Updated various components to utilize the translation function for time range labels, improving internationalization.
- Added new translation entries for time ranges in English, French, Japanese, Russian, Vietnamese, and Chinese, enhancing user experience across languages.

* feat(dashboard): enhance type safety and improve component structure

- Updated the Dashboard component to use specific types for model data and filters, enhancing type safety.
- Introduced new types for announcements and FAQs, improving clarity and maintainability.
- Refactored LogStatCards and UptimePanel components to utilize AbortController for better data fetching management.
- Optimized the rendering of announcements and FAQs by using unique keys based on item IDs.
- Improved theme management in ModelCharts by caching the ThemeManager import to reduce dynamic imports.

* feat(agents): add comprehensive guidelines for React and Next.js development

- Introduced a new set of best practices and optimization techniques for React and Next.js applications, aimed at enhancing performance and maintainability.
- Included detailed rules covering various aspects such as event handling, API routes, rendering strategies, and state management.
- Added extensive documentation in AGENTS.md and SKILL.md to support developers in adhering to these practices.
- This update serves as a foundational resource for improving code quality and efficiency in React-based projects.

* chore(web): update package.json dependencies

- Removed outdated dependencies including @base-ui/react, @clerk/clerk-react, and others to streamline the project.
- Updated remaining dependencies to their latest versions for improved performance and security.
- This cleanup enhances the overall maintainability of the project.

* feat(usage-logs): implement section-based navigation and enhance log management

- Introduced a section registry for usage logs, allowing for better organization and navigation between different log categories (common, drawing, task).
- Updated the UsageLogsContent component to dynamically render titles and descriptions based on the selected section.
- Refactored UsageLogsTable and UsageLogsPrimaryButtons components to accept the active log category as a prop, improving modularity.
- Enhanced sidebar configuration to support new section navigation, ensuring users can easily access different log types.
- Updated routing to redirect to the default section if none is specified, improving user experience.

* feat(i18n): enhance internationalization across usage logs components

- Integrated the useTranslation hook in various components related to usage logs, including CommonLogsStats, UsageLogsTable, and column helpers.
- Updated labels, titles, and messages to utilize translation functions, improving localization support.
- Added new translation entries for log-related terms in English, French, Japanese, Russian, Vietnamese, and Chinese, enhancing user experience for diverse language speakers.

* feat(datetime-picker): integrate dayjs for date formatting

- Added dayjs as a dependency to the project for improved date handling.
- Updated the DateTimePicker component to use dayjs for formatting dates, enhancing consistency and readability of date displays.

* feat(date-handling): replace date-fns with dayjs for improved date management

- Updated the project to use dayjs instead of date-fns for date formatting and manipulation, enhancing consistency across components.
- Refactored DatePicker, DateTimePicker, and other components to utilize dayjs for date-related functionalities.
- Added a new dayjs configuration file to extend its capabilities with relative time support.
- Updated AGENTS.md to reflect the new technology stack, emphasizing the use of dayjs for date handling.

* refactor(agents): streamline front-end development guidelines and update technology stack

- Revised AGENTS.md to condense front-end development standards and best practices, making it more accessible for developers and AI assistants.
- Updated the technology stack section to reflect current dependencies, emphasizing the use of Bun, React 19, TypeScript, and other key libraries.
- Enhanced the document structure with a new table format for better readability and navigation, including a comprehensive table of contents for quick access to sections.

* feat(i18n): enhance date picker and datetime picker localization support

- Integrated internationalization support in DatePicker and DateTimePicker components by adding locale handling for multiple languages (English, French, Japanese, Russian, Vietnamese, Chinese).
- Updated the calendar component to accept a locale prop, ensuring proper localization of month and weekday labels.
- Improved user experience by allowing date selection to adapt based on the user's language preference.

* feat(layout): add SectionPageLayout component for structured page layouts

- Introduced a new SectionPageLayout component to facilitate structured layouts for pages with sections, enhancing the organization of content.
- Added subcomponents for Title, Description, Actions, and Content to improve clarity and maintainability of page structures.
- Updated AGENTS.md to include guidelines on avoiding unnecessary destructuring of props for better code readability.

* feat(layout): refactor components to use SectionPageLayout for improved structure

- Replaced AppHeader and Main components with SectionPageLayout across multiple features including Channels, Dashboard, ApiKeys, Models, Redemption Codes, Usage Logs, Users, and Wallet.
- Enhanced page organization by utilizing SectionPageLayout's Title, Description, Actions, and Content subcomponents, improving clarity and maintainability.
- This update standardizes the layout structure across the application, facilitating a more cohesive user experience.

* feat(usage-logs): enhance URL state management and redirection logic

- Added useEffect to synchronize column filters with URL search changes, preventing infinite loops caused by inline references.
- Improved redirection logic in usage logs to clear 'type' from the URL when the section is not 'common', enhancing user experience and URL cleanliness.

* fix(usage-logs): disable global filter and update DataTableToolbar props

- Disabled the global filter in the UsageLogsTable component to streamline the user interface.
- Updated the DataTableToolbar component to accept a null customSearch prop, enhancing flexibility in toolbar configuration.

* feat(routes): implement section-based routing for system settings and dashboard

- Introduced section-based routing for system settings and dashboard features, enhancing navigation and organization.
- Updated route definitions to include dynamic sections, allowing for more granular access to settings and dashboard components.
- Refactored existing routes to redirect to default sections when no specific section is provided, improving user experience.
- Added new section routes for models, usage logs, and system settings, ensuring consistency across the application.
- Removed deprecated routes to streamline the routing structure and improve maintainability.

* refactor(usage-logs): update column helper functions to require config parameter

- Modified createFailReasonColumn and createProgressColumn functions to require a config parameter instead of allowing it to be optional.
- Simplified destructuring of config to enhance clarity and ensure necessary properties are always provided, improving code reliability.

* refactor(usage-logs): improve section ID validation and routing logic

- Introduced a type guard function, isUsageLogsSectionId, to validate section IDs, enhancing type safety and reducing the need for casting.
- Updated UsageLogsContent to utilize the new validation function for determining the active category, improving clarity and reliability.
- Refactored routing logic to use isUsageLogsSectionId for section validation, ensuring proper redirection to the default section when necessary.

* refactor(calendar): update locale documentation for i18n support

- Revised the locale prop documentation in the Calendar component to specify the use of react-day-picker for internationalization, clarifying the expected locale setup for users.

* chore(i18n): remove redundant user information description from locale files

- Removed the user information description from English, French, Japanese, Russian, Vietnamese, and Chinese locale files to streamline translations and improve clarity.

* chore(i18n): streamline locale files by removing redundant entries

- Removed unnecessary entries from English, French, Japanese, Russian, Vietnamese, and Chinese locale files to enhance clarity and reduce clutter.
- Adjusted translations for consistency and improved user experience across multiple languages.

* chore(sidebar): remove deprecated usage logs route from sidebar config

- Eliminated the '/usage-logs' entry from the sidebar configuration to streamline navigation and improve clarity in the sidebar structure.

* refactor(redemption-codes): enhance internationalization support and improve UI consistency

- Updated various components to utilize translation functions for user-facing strings, ensuring a consistent experience across different languages.
- Added meta labels for table columns to improve accessibility and clarity.
- Revised confirmation and action texts in dialogs and tooltips to leverage translation, enhancing user experience.
- Updated locale files to include new translations for improved clarity and consistency.

* feat(masked-value-display): add MaskedValueDisplay component for sensitive data handling

- Introduced a new MaskedValueDisplay component to display masked values with a popover for full value visibility and a copy button for easy access.
- Updated api-keys-columns and redemptions-columns to utilize the new component, enhancing code reusability and UI consistency.
- Revised translation keys in locale files to remove colons for improved clarity.

* refactor(url-utils): simplify query parameter matching logic in checkIsActive function

- Updated the checkIsActive function to streamline the logic for matching URLs with and without query parameters.
- Removed unnecessary checks for query parameters when matching base paths, improving clarity and maintainability of the code.

* fix(channels-table): update group filter label to use translation function

- Replaced hardcoded 'All Groups' label with a translation function call to enhance internationalization support in the ChannelsTable component.

* chore(api-keys): remove deprecated API key action messages and related exports

- Deleted the api-key-actions.ts file, which contained action messages for enabling, disabling, and deleting API keys.
- Updated index.ts to remove the export of getApiKeyActionMessage, streamlining the codebase by eliminating unused functionality.

* refactor(i18n): enhance internationalization support across various components

- Updated multiple components to utilize translation functions for user-facing strings, ensuring a consistent experience across different languages.
- Revised constants and labels in the channels and redemption codes features to use i18n keys, improving maintainability and clarity.
- Ensured that success and error messages leverage translation functions, enhancing user experience and accessibility.
- Streamlined the handling of i18n keys in the constants files for better organization and clarity.

* refactor(i18n): enhance translation support across various components

- Updated multiple components to utilize translation functions for user-facing strings, ensuring a consistent experience across different languages.
- Revised pagination and status labels to use i18n keys, improving maintainability and clarity.
- Enhanced response time formatting to support internationalization, allowing for localized display of time values.
- Updated locale files to include new translations for improved clarity and consistency.

* docs(AGENTS): add type checking requirement for TypeScript changes

- Included a new guideline stating that type checks must be executed after modifying TypeScript or TSX code, ensuring no type errors are left unresolved.
- Updated the document to reflect this addition in the relevant section for better clarity on coding standards.

* feat(combobox-input): add ComboboxInput component for enhanced token selection

- Introduced a new ComboboxInput component to facilitate token name selection with search and filtering capabilities.
- Integrated the ComboboxInput into the UsageLogsFilterDialog for improved user experience when filtering by token name.
- Updated locale files to include new translations for user-facing strings related to token filtering.

* feat(combobox): integrate translation support for custom value prompt

- Added translation functionality to the Combobox component, replacing hardcoded text with a translatable string for the custom value prompt.
- Utilized the useTranslation hook from react-i18next to enhance internationalization support, ensuring a consistent user experience across different languages.

* refactor(i18n): improve Chinese translations for consistency and clarity

- Adjusted spacing in various Chinese translations to enhance readability and maintain consistency across the locale file.
- Updated multiple user-facing strings to ensure proper formatting and alignment with localization standards.

* feat(calendar): add CalendarDropdown component for enhanced dropdown functionality

- Introduced a new CalendarDropdown component to improve user interaction with dropdown selections in the calendar.
- Implemented state management for dropdown visibility and selection handling, enhancing the overall user experience.
- Updated styling for dropdown elements to ensure consistency and better alignment with the UI design.

* fix(balance-query-dialog): handle null currentRow and improve usage query logic

- Updated the BalanceQueryDialog component to safely access currentRow properties using optional chaining.
- Added a check to ensure currentRow is not null before proceeding with usage queries, preventing potential runtime errors.
- Refactored the handleQueryCodexUsage function to use a local variable for currentRow, enhancing code clarity.

* feat(i18n): add new translations for batch creation and channel updates

- Added new translation strings for batch creation instructions across multiple languages, enhancing user guidance.
- Included translations for the "Update Channel" prompt to improve clarity in channel configuration settings.
- Ensured consistency in terminology across locale files for better user experience.

* feat(channel-mutate-drawer): improve API key input handling and update translations

- Refactored the API key input logic in the ChannelMutateDrawer component to enhance readability and maintainability.
- Added new placeholder translations for batch creation and existing key prompts in multiple languages, improving user guidance.
- Ensured consistency in translation strings across locale files for better user experience.

* feat(fetch-models-dialog): implement sorting for model categories

- Added a new function to sort model categories alphabetically, placing 'Other' at the end for easier navigation.
- Updated the rendering logic in the FetchModelsDialog component to utilize the new sorting function for both new and existing models, enhancing user experience.

* refactor(wallet-stats-card): standardize props usage and improve layout consistency

Standardizes props usage and improves layout consistency in wallet stats card

Refactors the wallet stats card component to:
- Use props directly instead of destructuring for consistency
- Add min-w-0 to prevent content overflow
- Adjust text sizing with break-all for proper wrapping
- Implement responsive font sizes (3xl on mobile, 4xl on larger screens)
- Improve leading and tracking for better readability

Refactor wallet stats card for consistency and layout

Standardizes props usage and improves layout consistency in wallet stats card

- Uses props directly instead of destructuring for consistency
- Adds min-w-0 to prevent content overflow
- Adjusts text sizing with break-all for proper wrapping
- Implements responsive font sizes (3xl on mobile, 4xl on larger screens)
- Improves leading and tracking for better readability

* feat(web): add subscription management and admin settings UI

* feat(web): add subscription management and admin settings UI

- Add subscription management module (plans, pricing, toggle status, and related dialogs/tables with Stripe/Creem integration notes)
- Add channel affinity (rules and cache stats), Waffo integration, performance, and Grok model sections to system settings, with extended types and section registry
- Add status code mapping validation/risk warnings, upstream update hooks, and utilities for channels; add available models and sidebar module cards to user profile
- Add chat2link route and useMinimumLoadingTime, useTableCompactMode shared hooks

Made-with: Cursor

* fix: remove duplicate GenerateOAuthCode and add missing TaskBulkUpdate

- remove duplicate GenerateOAuthCode from github.go since oauth.go already has the generic version.
- add model.TaskBulkUpdate for bulk update by upstream task_id strings, fixing task_video.go build failure.

* feat(router): add chat2link and subscriptions routes

- register /chat2link page route under authenticated layout.
- register /subscriptions/ page route under authenticated layout.
- update auto-generated routeTree type definitions and route mappings.

* feat(docker): add development environment setup with Docker Compose

- Introduced docker-compose.dev.yml for local development, including services for new-api, Redis, and PostgreSQL.
- Created Dockerfile.dev for backend-only builds, optimizing the development workflow.
- Updated makefile to include new commands for starting backend services and frontend development.

* feat(web): complete i18n coverage for setup wizard and add language switcher

- wrap all hardcoded English strings in setup-wizard, database-step, usage-mode-step, and complete-step with t() calls, covering step titles, descriptions, form validation messages, and fallback strings.
- add LanguageSwitcher component to the top-right corner of the setup page so users can switch language during initial setup.
- register 25 dynamic i18n keys in static-keys.ts and provide full translations for zh/en/ja/fr/ru/vi.

* feat(i18n): internationalize default version text in workspace-switcher

- remove hardcoded 'Unknown version' default, use t('Unknown version') for i18n fallback
- add "Unknown version" translation entries across all 6 locale files (zh/en/fr/ru/ja/vi)

* feat(i18n): add full i18n coverage for channel-affinity settings page

- replace Chinese t() keys with English keys across three channel-affinity components to align with new frontend i18n conventions.
- add 51 translation entries to all 6 locale files (en/zh/ja/fr/ru/vi) covering main page, rule editor, and cache stats dialog.
- register section-registry dynamic keys in static-keys.ts.

* feat(i18n): add full i18n coverage for Waffo payment settings page

- replace Chinese i18n keys with English keys in waffo-settings-section.tsx for consistency.
- wrap previously hardcoded labels (Pay Method Type / Pay Method Name) with t().
- add 26 Waffo-related translation entries across all 6 locale files (en/zh/fr/ru/ja/vi).

* feat(i18n): add missing translations for global model settings page

- add all 6 locale translations for 3 missing t() keys in global-settings-card.
- register dynamically used 'Grok' key in static-keys.ts for i18n scanner coverage.

* feat(i18n): add full i18n coverage for Grok model settings page

- add translations in all 6 locales (en/zh/fr/ja/ru/vi) for grok-settings-card t() calls.
- cover violation fee toggle, amount input, and official docs link labels.
- include section-registry descriptionKey translation entries.

* feat(i18n): add full i18n coverage for performance settings page

- migrate all t() keys from Chinese to English to align with project conventions.
- add translations for all 6 locales (en/zh/ja/fr/ru/vi) covering disk cache,
  system monitoring, log management, and stats dashboard sections.
- remove 71 obsolete Chinese-keyed entries from every locale file.

* fix(i18n): add 116 missing English translation keys across all locales

- scan all t() calls to identify English keys used in code but absent from locale files.
- add translations for zh/en/fr/ja/ru/vi, keeping key sets and sort order consistent.
- covers system-settings, channels, models, auth, wallet and other modules.

* fix(i18n): add missing translations for log cleanup quick-select and confirm dialog

- wrap quick-select button labels (24 hours ago / 7 days ago / 30 days ago) with t().
- replace hardcoded English strings in purge confirm dialog with t() calls and date interpolation.
- add 5 new translation keys across all 6 locale files (zh/en/fr/ja/ru/vi).

* refactor(web): unify all time display with dayjs formatting

- replace all toLocaleString/toLocaleDateString/toLocaleTimeString and manual padStart concatenation with dayjs.format().
- standardize output: datetime as YYYY-MM-DD HH:mm:ss, date as YYYY-MM-DD, time as HH:mm:ss.
- add formatDateTimeStr, formatDateStr, formatTimeStr dayjs-based helpers in lib/format.ts.
- update 12 files across core utils and feature components.

* refactor(web): replace native datetime-local input with DateTimePicker in announcements

- swap browser-native datetime-local for the project's DateTimePicker component to match the UI used in log cleanup and other pages.
- convert between Date objects and ISO strings to bridge the form's string-based schema.

* refactor(web): replace native HTML elements with design system components

- replace ~35 native <button> with <Button> across pricing, profile, channels modules
- replace native <input>/<textarea>/<label> with <Input>/<Textarea>/<Label> for consistent form styling
- replace native <table> with <Table> components, <details>/<summary> with <Collapsible>
- replace decorative <hr> with <Separator> to ensure global UI consistency

* refactor(web): enhance profile components with design system consistency

- update ProfileSecurityCard to use buttons for security actions, improving accessibility and styling.
- modify AccountBindingsTab layout to a grid for better responsiveness and visual alignment.
- refactor NotificationTab to utilize icons for notification methods, enhancing user experience and clarity.

* fix(i18n): complete i18n coverage for profile page components

- wrap passkey card status badges (enabled/disabled, backup state) and last-used text with t()
- fix hardcoded button labels in security dialogs (change password, access token, delete account)
- internationalize all 2FA dialog strings (setup, disable, backup codes)
- fix email bind dialog description and button state text missing i18n
- wrap remaining hardcoded strings in notification tab and checkin calendar
- add all missing translation entries to zh.json and en.json

* fix(i18n): enhance error messages with translations for deployment access and settings

- wrap connection error messages in DeploymentAccessGuard and IoNetDeploymentSettingsSection with t() for internationalization.
- add missing translation key for "io.net model deployment is not enabled or api key missing" in all locale files (en, fr, ja, ru, vi, zh).

* 🧹 chore(web): resolve all ESLint errors and warnings

Align the Vite/React frontend with the current ESLint flat config and
React Compiler–related rules by fixing violations instead of broad
suppression where practical.

- Replace `any` with concrete types (`unknown`, `Record<string, unknown>`,
  domain types) where upstream/API shapes allow
- Fix duplicate imports, unused bindings, `no-console`, and empty blocks
- Address react-hooks issues: reorder declarations, memoize unstable
  callbacks (`useCallback`), extend dependency arrays, and use targeted
  disables only where sync-from-props in `useEffect` is intentional
- Refactor `motion.create` usage in ai-elements shimmer to avoid creating
  components during render (static-components)
- Stabilize TanStack Query/Mutation hook usage (query keys, `mutate` in
  deps) and add narrowly scoped rule disables where the linter conflicts
  with library patterns
- Disable `react-hooks/incompatible-library` in ESLint config for
  TanStack Table / RHF false positives
- Add file-level `react-refresh/only-export-components` disables for
  registry/provider/column modules that intentionally mix exports

`bun lint` completes with 0 errors and 0 warnings.

* ✨ feat(web): add subscription management to sidebar and align drawer with project conventions

- Register "Subscription Management" nav item in the admin sidebar group
  with CreditCard icon pointing to /subscriptions
- Add subscription module to sidebar config defaults and URL mapping so it
  integrates with the admin sidebar modules toggle in system settings
- Add subscription entry to sidebar-modules-section moduleMeta for the
  maintenance settings UI
- Refactor SubscriptionsMutateDrawer to follow the same patterns used by
  users, redemption-codes, and other mutate drawers:
  - Use shadcn Form/FormField/FormItem/FormControl/FormLabel/FormMessage
    instead of raw register() + Label + manual error display
  - Move SheetFooter outside the form with form attribute association
  - Use SheetClose for the cancel button
  - Reset form state on drawer close
  - Align SheetContent width (sm:max-w-[600px]) and spacing conventions

* ✨ feat(web): overhaul UI/UX with Vercel Geist design alignment

Refactor the entire frontend UI/UX to align with Vercel/OpenAI design
principles, covering layout, animations, skeleton loading, and overall
visual polish.

Motion & Page Transitions:
- Add centralized motion system (lib/motion.ts) with Vercel-style
  transition presets, stagger variants for tables, cards, and sidebars
- Implement AnimatedOutlet for route-level page enter animations
  using TanStack Router pathname keying
- Add PageTransition, StaggerContainer, StaggerItem, CardStagger,
  and TableStagger wrapper components for progressive reveal effects

Skeleton Loading — Vercel Geist Style:
- Replace shadcn default `animate-pulse` with Geist-style shimmer
  sweep animation (linear-gradient + background-position keyframes)
- Add `--skeleton-base` / `--skeleton-highlight` CSS variables tuned
  for both light and dark themes with neutral oklch tones
- Override auto-skeleton-react inline styles via CSS to unify all
  skeleton elements under the same shimmer effect
- Update TableSkeleton with varied column widths for a natural feel
- Add ContentSkeleton and QuerySkeleton wrappers for auto-skeleton
  integration with React Query error/loading states
- Respect prefers-reduced-motion: disable shimmer for accessibility

Layout & Sidebar:
- Upgrade sidebar expand/collapse transitions to cubic-bezier easing
- Add hover micro-interactions (background-color, color, transform)
  to sidebar menu buttons with smooth 150ms transitions
- Fix oklch color compatibility in sidebar outline variant
- Integrate AnimatedOutlet into AuthenticatedLayout for unified
  route-level animations

Theme & CSS:
- Streamline theme.css with cleaner oklch color definitions
- Add CSS table row stagger-in animations with nth-child delays
- Fix hover-scrollbar color bug (hsl → color-mix for oklch compat)
- Add content-auto utility for long list rendering optimization

Cleanup:
- Remove deprecated skeleton-wrapper.tsx
- Remove unused imports and dead code across components
- Add empty-state, error-state, and loading-state utility components

* 🐛 fix(docker): track bun.lock to fix Docker build failure

Remove `web/bun.lock` from `.gitignore` so the lock file is committed
to version control. The Dockerfile `COPY web/bun.lock .` instruction
requires this file to be present in the build context, and ignoring it
caused the build to fail with a "not found" error.

* ⬆️ chore(web): upgrade dependencies and fix all type/lint errors

Upgrade all frontend dependencies to latest stable versions:
- lucide-react 0.562 → 1.7 (major: brand icons removed)
- shiki 3.x → 4.x, eslint 9.x → 10.x, knip 5.x → 6.x
- @rsbuild/core 1.3 → 1.7, @types/node 24 → 25
- tailwindcss/postcss 4.1 → 4.2, motion 12.25 → 12.38
- @tanstack/react-query 5.90 → 5.95, zod 4.3.5 → 4.3.6
- react 19.2.3 → 19.2.4, axios 1.13.2 → 1.13.6
- prettier 3.7 → 3.8, typescript-eslint 8.52 → 8.57
- Add missing optional deps: @xyflow/react, embla-carousel-react

Resolve all TypeScript compilation errors introduced by upgrades:
- Replace lucide-react brand icons (Github) with react-icons/si
- Fix react-hook-form Control/Resolver generics for zod v4
- Fix Record<string, unknown> type constraints across API utils
- Fix axios interceptor return types in lib/api.ts
- Add type assertions for useSettings/useStatus hook returns
- Resolve Badge variant, spread type, and route path mismatches

Resolve all ESLint 10 errors:
- preserve-caught-error: attach cause to re-thrown errors
- no-useless-assignment: refactor redundant variable assignments
- prefer-as-const: use `as const` over literal type assertions
- no-unused-vars: prefix type-only schemas with underscore

Update tsconfig lib from ES2020 to ES2022 for Error.cause support.

* 🐛 fix(web): stop pricing model row from centering its content

Wrapping the row in shadcn <Button variant='ghost'> inherits
`justify-center`, and the inner flex container had no width, so
`justify-between` collapsed and the row appeared centered.

* feat: add Waffo payment integration and related UI components

- Introduced Waffo payment method with support for custom icons and settings.
- Updated payment settings section to include Waffo settings.
- Added Waffo payment request handling in the wallet API.
- Enhanced wallet recharge form to support Waffo payment methods.
- Implemented hooks for Waffo payment processing.
- Updated localization files for new Waffo-related strings.
- Added new payment type and icon for Waffo in constants and UI components.
- Refactored topup info handling to include Waffo payment methods and configurations.

* feat(profile): add admin-only upstream model update notification setting

* fix(web): make sidebar module user settings actually take effect

Previously, saving sidebar module preferences in profile had no effect
because the client ignored user-level sidebar_modules entirely. This
fix wires user config into useSidebarConfig so the sidebar updates
immediately without a page refresh.

Changes:
- Add UserPermissions type with sidebar_settings/sidebar_modules fields
- Refactor useSidebarConfig to merge admin × user config with AND logic
- Sync sidebar_modules to auth store on save for immediate UI updates
- Conditionally render SidebarModulesCard based on user permissions
- Treat null/empty user config as "do not narrow" for legacy users

* feat(web): add custom OAuth provider CRUD and login button support

Migrate custom OAuth from v1 to v2:
- Admin CRUD UI with provider table, form dialog, preset templates, and OIDC discovery
- Login page renders dynamic buttons for custom OAuth providers
- Fix account bindings display showing "Not bound" text when already bound

* feat(web): add ServerAddress, SMTPForceAuthLogin, CreateCacheRatio and group special usable settings

Migrate missing v1 system settings to v2:
- ServerAddress input in General > System Information
- SMTPForceAuthLogin toggle in Integrations > Email
- CreateCacheRatio JSON editor in Models > Ratio
- Group special usable group rules editor in Models > Ratio

* feat(web): wire user subscriptions dialog to users table row actions

The UserSubscriptionsDialog component already existed but had no entry point
in the users table dropdown menu. Add "Manage Subscriptions" menu item.

* chore(web): update i18n translations for new settings and custom OAuth

* 💎 refactor(web): redesign pricing page with flat, typography-driven layout

* 🌐 chore(i18n): complete missing translations and normalize project config

- Add 425+ missing translations across fr, ja, ru, zh, vi locales
  for subscription management, sidebar navigation, Grok settings,
  upstream model updates, pricing page, and other UI components
- Add 37 missing i18n keys used in t() calls but absent from locale
  files (pricing filters, display options, audio/cache labels, etc.)
- Fix stale tech stack info in CLAUDE.md, AGENTS.md, and project.mdc:
  React 18 → 19, Vite → Rsbuild, Semi Design → Radix UI + Tailwind
- Fix i18n key format description: "Chinese source strings" → English
- Deduplicate .cursor/rules/project.mdc to avoid triple-loading the
  same rules already present in root CLAUDE.md and AGENTS.md
- Add i18n-translate Cursor skill for repeatable translation workflow

* 🎨 refactor(web): redesign dashboard with flat, typography-driven layout

Replace Card-based dashboard components with a flat, border-driven design
system consistent with the pricing page, following the ui-style.mdc conventions.

Overview section:
- StatCard: replace Card wrapper with flat flex layout, monospace tabular
  values, uppercase tracking-wider labels, layered opacity hierarchy
- PanelWrapper: replace Card/CardHeader/CardContent with rounded-lg border
  container and border-b header
- SummaryCards: merge three stat cards into a single bordered container
  with divide-x separators; decouple border from stagger animation to
  prevent border deformation during entrance transitions
- ApiInfoPanel/Item: full-width list rows with border-b separators,
  monospace route names, layered opacity for URLs and descriptions
- AnnouncementsPanel: native button rows with hover:bg-muted/40, i18n for
  "Click for details" hint
- FAQPanel: lighter border-border/60 accordion dividers, muted answer text
- UptimePanel: uppercase tracking-wider group headers with bg-muted/30
  background, monospace uptime percentages, fine-grained border opacity

Models section:
- LogStatCards: replace Card with rounded-lg border + divide-x grid,
  fix react-hooks/exhaustive-deps by destructuring props before useEffect
- ModelCharts: replace Card+Tabs with bordered container + custom
  segmented control matching ui-style spec
- Suspense fallbacks: match new flat skeleton layout with accurate
  column structure

Animation:
- Wrap models section in FadeIn with staggered delay
- Keep CardStagger for overview panel grid (each panel has own border)

Other:
- Add ui-style.mdc cursor rule documenting the design language
- Disable react-refresh/only-export-components for src/routes/** in
  eslint config (TanStack Router route files always export Route objects)
- Fix zh.json: "Token-based" translation "基于令牌的" → "按量计费"

* ✨ refactor(web): adopt flat dot-and-text design for all status badges

Replace the bordered/colored-background StatusBadge and Badge components
across the entire frontend with a minimal flat design: a small colored
dot followed by colored text, eliminating visual noise from heavy
borders, backgrounds, and rounded pill shapes.

Key changes:

- Redesign StatusBadge to use dot + text instead of bordered pill style,
  removing cva-based background/border variants in favor of exported
  dotColorMap and textColorMap lookup tables
- Add children prop support to StatusBadge for flexible content rendering
  alongside the existing label prop
- Migrate all Badge usages (except pricing page) to StatusBadge with
  appropriate variant mappings (default→info, secondary→neutral,
  outline→neutral, destructive→danger)
- Consolidate adjacent multi-badge groups into single-dot layouts with
  dot separators (·) to reduce visual clutter in:
  - Channel balance columns (used + remaining)
  - Channel type column (type + IO.NET indicator)
  - User invite info column (invited + revenue + inviter)
  - Usage log stats bar (usage + RPM + TPM)
  - Usage log time/FRT column (time + FRT + stream status)
  - Subscription plan counts (active + expired)
  - Channel affinity scope/regex/key-source columns
  - Prefill group card headers (type + ID)
- Export dotColorMap and textColorMap for direct use in custom inline
  layouts that need consistent status colors without the full component

* ✨ refactor(web): redesign public layout and landing page with modern UI

Overhaul the public-facing layout, header, and homepage to deliver a
polished, animation-rich landing experience inspired by contemporary
SaaS design patterns.

Header:
- Replace sticky header with fixed floating navbar that compacts into
  a pill-shaped glass-morphism bar on scroll (backdrop-blur + ring)
- Add smooth 700ms cubic-bezier transitions for scroll-based shrinking
- Build full-screen mobile menu overlay with staggered entry animations
- Remove background color from logo container, show logo image directly

Homepage sections:
- Hero: gradient text title, radial gradient + grid pattern background,
  interactive terminal demo showcasing API request/response
- Terminal demo: auto-cycles through gpt-4o, claude-sonnet-4-20250514,
  gemini-2.5-pro, deepseek-chat with smooth cross-fade transitions,
  clickable model badges, dual theme support (light/dark), fixed height
- Stats: animated co…
Jinxuans referenced this pull request in Jinxuans/new-api May 9, 2026
…up (#4265)

* feat: add parameter coverage for the operations: copy, trim_prefix, trim_suffix, ensure_prefix, ensure_suffix, trim_space, to_lower, to_upper, replace, and regex_replace

* fix: CrossGroupRetry default false

移除gorm:"default:false",避免每次 AutoMigrate时都执行ALTER TABLE `tokens` MODIFY COLUMN `cross_group_retry` boolean DEFAULT false
且bool默认false不影响原有功能

* feat: check-in feature integrates Turnstile security check

* feat: add support for Doubao /v1/responses (#2567)

* feat: add support for Doubao /v1/responses

* fix: fix model deployment style issues, lint problems, and i18n gaps. (#2556)

* fix: fix model deployment style issues, lint problems, and i18n gaps.

* fix: adjust the key not to be displayed on the frontend, tested via the backend.

* fix: adjust the sidebar configuration logic to use the default configuration items if they are not defined.

* feat: add plans directory to .gitignore

* fix: 修复 gemini 文件类型不支持 image/jpg

* fix: fix the proxyURL is empty, not using the default HTTP client configuration && the AWS calling side did not apply the relay timeout.

* fix: batch add key backend deduplication

* Merge pull request #2582 from seefs001/fix/tips

fix: add tips for model management and channel testing

* fix(gin): update request body size check to allow zero limit

* feat: add regex pattern to mask API keys in sensitive information

* fix(task): 修复使用 auto 分组时 Task Relay 不记录日志和不扣费的问题

问题描述:
- 使用 auto 分组的令牌调用 /v1/videos 等 Task 接口时,虽然任务能成功创建,
  但使用日志不显示记录,且不会扣费

根本原因:
- Distribute 中间件在选择渠道后,会将实际选中的分组存储在 ContextKeyAutoGroup 中
- 但 RelayTaskSubmit 函数没有从 context 中读取这个值来更新 info.UsingGroup
- 导致 info.UsingGroup 始终是 "auto" 而不是实际选中的分组(如 "sora2逆")
- 当 auto 分组的倍率配置为 0 时,quota 计算结果为 0
- 日志记录条件 "if quota != 0" 不满足,导致日志不记录、不扣费

修复方案:
- 在 RelayTaskSubmit 函数中计算分组倍率之前,添加从 ContextKeyAutoGroup
  获取实际分组的逻辑
- 使用安全的类型断言,避免潜在的 panic 风险

影响范围:
- 仅影响 Task Relay 流程(/v1/videos, /suno, /kling 等接口)
- 不影响使用具体分组令牌的调用
- 不影响其他 Relay 类型(chat/completions 等已有类似处理逻辑)

* 🚀 feat(web): port legacy v2 frontend changes into new UI (deployments, check-in, ollama) + align APIs

Bring over the key frontend functionality introduced in merge `efa3301` and integrate it cleanly into the new `web/src` architecture and design system.

- **Model deployments (io.net)**
  - Align frontend endpoints and payloads with backend deployment routes (`/api/deployments/*`)
  - Add missing deployment operations: details, logs (container-aware), update config, rename, extend duration
  - Improve create-deployment flow (proper request shape, name availability check, price estimation parity)

- **System settings**
  - Enhance io.net deployment settings: allow testing connection with an unsaved API key and add “how to get API key” guidance

- **Channels / Ollama**
  - Improve Ollama model management: live fetch via base_url with fallback to channel fetch, selection + apply flows, delete confirmation
  - Refactor for feature-layer consistency: extract Ollama parsing/normalization utilities into `features/channels/lib`

- **Quality**
  - Ensure TypeScript typecheck passes after refactor and new dialogs/components integration

* Merge pull request #2590 from xyfacai/fix/max-body-limit

fix: 设置默认max req body 为128MB

* docs: update readme

* i18n: add missing translations

* fix(gemini): fetch model list via native v1beta/models endpoint

Use the native Gemini Models API (/v1beta/models) instead of the OpenAI-compatible
path when listing models for Gemini channels, improving compatibility with
third-party Gemini-format providers that don't implement OpenAI routes.

- Add paginated model listing with timeout and optional proxy support
- Select an enabled key for multi-key Gemini channels

* refactor(gemini): 更新 GeminiModelsResponse 以使用 dto.GeminiModel 类型

* fix: remove Minimax from FETCHABLE channels

* fix(minimax): 添加 MiniMax-M2 系列模型到 ModelList

* feat: add doubao video 1.5

* 🤢 chore: remove useless file

* feat: /v1/chat/completion -> /v1/response (#2629)

* feat: /v1/chat/completion -> /v1/response

* fix: clean propertyNames for gemini function

* fix: support snake_case fields in GeminiChatGenerationConfig

* chore: update dependencies and lockfile for improved compatibility

- Updated @clerk/clerk-react to version 5.59.3
- Updated @hookform/resolvers to version 5.2.2
- Updated @lobehub/icons to version 2.48.0
- Updated various Radix UI components to their latest versions
- Updated @tanstack/react-query and related packages for better performance
- Updated axios, i18next, and other libraries for security and feature enhancements
- Updated lockfile to include configVersion and ensure consistency across environments

* Merge pull request #2647 from seefs001/feature/status-code-auto-disable

feat: status code auto-disable configuration

* fix: chat2response setting ui (#2643)

* fix: setting ui

* fix: rm global.chat_completions_to_responses_policy

* fix: rm global.chat_completions_to_responses_policy

* Merge pull request #2627 from seefs001/feature/channel-test-param-override

feat: channel testing supports parameter overriding

* chore: update dependencies and lockfile for improved compatibility

- Updated @lobehub/icons to version 4.0.3
- Updated ai to version 6.0.27
- Updated various libraries including axios, react-day-picker, and streamdown for security and feature enhancements
- Updated devDependencies for eslint, prettier, and typescript for better performance and compatibility
- Updated lockfile to ensure consistency across environments

* chore: update lockfile and Vite configuration for improved build process

- Updated lockfile to version 1 for better compatibility and consistency
- Enhanced Vite configuration to support production optimizations, including code minification and chunking for dependencies
- Added environment-specific console and debugger removal for production builds

* chore: migrate from Vite to Rsbuild for build process

- Added Rsbuild configuration for development and production builds
- Updated package.json scripts to use Rsbuild instead of Vite
- Replaced @tailwindcss/vite with @tailwindcss/postcss in dependencies
- Introduced postcss.config.mjs for Tailwind CSS integration
- Updated TypeScript configuration to include Rsbuild config
- Removed Vite configuration file to streamline the build process

* refactor: optimize user data handling and API calls

- Replaced direct API calls to get user data with cached user information from auth-store in ModelsFilter and SummaryCards components.
- Improved session management in RootComponent and Authenticated route to utilize localStorage for user authentication status, reducing unnecessary API requests.
- Added caching for setup status checks to enhance performance during navigation.

* feat: enhance session validation in authenticated route

- Implemented session verification to check user authentication status via API call only once per session.
- Updated beforeLoad logic to redirect users to the login page if session validation fails or if no user information is available in localStorage.
- Improved user data handling by updating the auth store with fresh user information upon successful session verification.

* refactor: improve useMediaQuery hook for better SSR handling

- Enhanced the useMediaQuery hook to check for window availability before accessing matchMedia, preventing errors during server-side rendering.
- Simplified state initialization and change handling by using a dedicated function to determine initial matches.
- Updated event listener management for improved performance and clarity.

* feat(hooks): export useMediaQuery from hooks index

* refactor: update useMediaQuery imports to use unified hooks index

* fix(rsbuild): fix loadEnv API usage and removeConsole type

* feat: customizable automatic retry status codes

* refactor(hooks): use useSyncExternalStore for better SSR handling in useMediaQuery

* refactor: simplify embedded file structure in main.go

- Updated the embedded file directive to include the entire web/dist directory instead of individual assets, streamlining the build process.

* refactor: replace DropdownMenu with Sheet component in ProfileDropdown

- Updated the ProfileDropdown component to use a Sheet for user interactions instead of a DropdownMenu.
- Enhanced user info display with improved layout and styling.
- Added navigation links and sign-out functionality within the Sheet.

* refactor: streamline ProfileDropdown layout and improve user info display

- Removed unused Badge component and secondary text from user display.
- Enhanced styling for user info section and navigation links.
- Updated sign-out functionality to use a button for better accessibility.

* feat: add System Settings link for super admin in ProfileDropdown

- Introduced a new link to System Settings in the ProfileDropdown, visible only to users with the SUPER_ADMIN role.
- Updated imports to include the Settings icon and adjusted the component logic accordingly.
- Removed the Settings entry from the sidebar data to streamline navigation.

* feat: codex channel (#2652)

* feat: codex channel

* feat: codex channel

* feat: codex oauth flow

* feat: codex refresh cred

* feat: codex usage

* fix: codex err message detail

* fix: codex setting ui

* feat: codex refresh cred task

* fix: import err

* fix: codex store must be false

* fix: chat -> responses tool call

* fix: chat -> responses tool call

* feat(i18n): add missing translations

* fix(i18n): restore missing translations for "360" and add "User Menu" in multiple locales

- Reintroduced the translation for "360" in English, French, Japanese, Russian, Vietnamese, and Chinese locales.
- Added the "User Menu" translation in the same languages to enhance user interface consistency.

* fix: openAI function to gemini function field adjusted to whitelist mode

* feat: TLS_INSECURE_SKIP_VERIFY env

* fix: for chat-based calls to the Claude model, tagging is required. Using Claude's rendering logs, the two approaches handle input rendering differently.

* refactor(system-settings): restructure settings sections and navigation

- Replaced SettingsAccordion with a unified SettingsSection component across various settings sections for consistency.
- Introduced a section registry to manage general settings sections dynamically.
- Updated navigation items in the system settings sidebar to utilize the new section registry.
- Enhanced the GeneralSettings component to support section-based content rendering based on user selection.

* fix(system-settings): remove type assertion for quotaDisplayType in GeneralSettings

- Eliminated the type assertion for quotaDisplayType in the GeneralSettings component to improve type inference and maintain cleaner code.

* refactor(system-settings): update zod import syntax in general settings

- Changed the import statement for zod from a default import to a namespace import for better clarity and consistency in the codebase.

* fix: the login method cannot be displayed under the aff link.

* feat(system-settings): implement generic settings page and enhance navigation

- Added a new generic SettingsPage component to handle loading states, data fetching, and section rendering.
- Integrated section registry for general and authentication settings to streamline navigation and content management.
- Updated URL utility functions to improve query parameter handling for active navigation states.
- Enhanced the system settings sidebar to include authentication section items dynamically.

* refactor(system-settings): replace SettingsAccordion with SettingsSection across authentication settings

- Updated BasicAuthSection, BotProtectionSection, OAuthSection, and PasskeySection to use the new SettingsSection component for consistency.
- Introduced a section registry to manage authentication settings dynamically, enhancing navigation and content rendering.

* feat(system-settings): enhance request limits settings with new section and unified component

- Added a new Request Limits section to the system settings sidebar, integrating it with the section registry for improved navigation.
- Replaced SettingsAccordion with SettingsSection in RateLimitSection, SensitiveWordsSection, and SSRFSection for consistency.
- Updated RequestLimitsSettings to utilize the new SettingsPage component for better data handling and rendering.
- Implemented a search schema for request limits to streamline navigation and section management.

* feat(system-settings): integrate content settings sections with unified component and registry

- Added a new Content section to the system settings sidebar, incorporating it into the section registry for improved navigation.
- Replaced SettingsAccordion with SettingsSection in multiple content-related components for consistency.
- Created a section registry to manage content settings dynamically, enhancing the rendering and navigation experience.
- Updated the ContentSettings component to utilize the new section registry and streamline content display.

* feat(system-settings): enhance integrations settings with unified section registry and components

- Introduced a new section registry for integrations settings, consolidating various settings components for better organization and navigation.
- Replaced SettingsAccordion with SettingsSection in multiple integration-related components for consistency.
- Updated IntegrationSettings to utilize the new SettingsPage component, improving data handling and rendering.
- Added a new integrations section to the system settings sidebar, enhancing user experience and accessibility.

* feat(system-settings): unify model settings with new section registry and components

- Introduced a section registry for model settings, consolidating various model-related components for improved organization and navigation.
- Replaced SettingsAccordion with SettingsSection in multiple model settings components for consistency.
- Updated ModelSettings to utilize the new SettingsPage component, enhancing data handling and rendering.
- Added a new Models section to the system settings sidebar, improving user experience and accessibility.

* feat(system-settings): enhance maintenance settings with unified section registry and components

- Introduced a new section registry for maintenance settings, consolidating various maintenance-related components for improved organization and navigation.
- Replaced SettingsAccordion with SettingsSection in multiple maintenance components for consistency.
- Updated MaintenanceSettings to utilize the new section registry, enhancing data handling and rendering.
- Added a new Maintenance section to the system settings sidebar, improving user experience and accessibility.

* feat(system-settings): update section titles for improved clarity and consistency

- Renamed various section titles across content, integrations, maintenance, models, and request limits to enhance clarity and better reflect their functionalities.
- Adjusted titles such as 'Dashboard' to 'Data Dashboard', 'API Info' to 'API Addresses', and 'Update Checker' to 'System maintenance' for improved user understanding.
- Ensured consistency in naming conventions across all settings sections to streamline user experience and navigation.

* feat(nav-group): enhance collapsible menu behavior and URL matching logic

- Added controlled state management for collapsible menu items to automatically expand based on active sub-item paths.
- Updated the URL matching logic in checkIsActive to improve handling of query parameters and ensure accurate navigation state detection.
- Refactored the collapsible component to utilize the new state management, enhancing user experience in the sidebar navigation.

* feat(system-settings): update system settings navigation and redirect logic

- Changed the link in the profile dropdown to point directly to the general section of system settings with a search parameter for section identification.
- Implemented a redirect in the general settings route to ensure users are directed to the default section if no section parameter is provided, enhancing navigation consistency.

* feat(system-settings): unify route configuration for settings sections

- Refactored route configuration for various system settings sections (auth, content, general, integrations, maintenance, models, request limits) to utilize a new `createSettingsRouteConfig` function.
- This change consolidates the repetitive logic of creating search schemas and handling redirects, improving code maintainability and readability.
- Enhanced navigation by ensuring default sections are loaded when no section parameter is provided.

* feat(url-utils): enhance URL handling and matching logic

- Introduced a new utility function `urlToString` to convert various URL formats (string and object) into a standardized string format.
- Updated the `checkIsActive` function to utilize `urlToString`, improving the accuracy of URL matching and handling of query parameters.
- Refactored URL comparison logic to ensure consistent behavior across different URL types, enhancing navigation state detection.

* feat(system-settings): validate DataExportDefaultTime for improved data handling

- Introduced a new function `validateDataExportDefaultTime` to ensure the `DataExportDefaultTime` value is either 'week', 'hour', or 'day', defaulting to 'hour' for unexpected values.
- Updated the `DataExportDefaultTime` assignment in the settings section to utilize this validation function, enhancing data integrity and user experience.

* perf(system-settings): Improve the i18n of system settings content

- Changed button labels in various sections to use consistent capitalization and translation functions, enhancing user experience.
- Updated validation messages in schemas to utilize translation functions for improved internationalization support.
- Ensured all user-facing strings are properly translated, improving accessibility for non-English users.

* fix(system-settings): update ApiInfoFormValues type inference for improved schema validation

- Changed the type inference for ApiInfoFormValues to utilize ReturnType of createApiInfoSchema, ensuring accurate type representation and enhancing type safety in the API info section.

* fix(chat-settings): improve validation logic for chat settings schema

- Updated the validation logic to ensure that null values are correctly handled and that only objects are accepted as valid items in the chat settings schema.
- Simplified error handling by removing the error message from the catch block, providing a consistent user-facing message for invalid JSON strings.

* fix(system-settings): enhance validation error handling in uptime-kuma schema

- Updated the validation logic for category name, URL, and slug fields to use an object format for error messages, improving clarity and consistency in user feedback.
- Ensured that all validation messages are properly structured to enhance internationalization support.

* fix(i18n): add translations for Uptime Kuma group management

- Added English, French, Japanese, Russian, Vietnamese, and Chinese translations for "Add Uptime Kuma Group" and "Edit Uptime Kuma Group" to enhance internationalization support.
- Included validation messages for category name and slug fields across multiple languages to improve user feedback and accessibility.

* fix(system-settings): improve validation error message structure for SystemName

- Updated the validation logic for the SystemName field to use an object format for error messages, enhancing clarity and consistency in user feedback.
- This change aligns with recent improvements in internationalization support across the system settings schemas.

* perf(i18n): add new validation error message translations

- Added translations for the new validation error message "Invalid JSON format or values out of allowed range" in English, French, Japanese, Russian, Vietnamese, and Chinese.
- This update enhances internationalization support by ensuring users receive clear feedback across multiple languages.

* fix(i18n): update Japanese translation for payment method configuration message

- Corrected the Japanese translation for the message regarding payment methods configuration to use the term "メソッド" instead of "方法" for improved accuracy and consistency in user feedback.
- This change enhances the clarity of the message for Japanese-speaking users.

* fix(i18n): remove unnecessary loading messages from French translations

- Removed the French translations for "Loading settings...", "Loading maintenance settings...", and "Loading content settings..." to streamline the localization file.
- This change improves the clarity and relevance of the translations provided to users.

* fix(i18n): add translations for Uptime Kuma group management in multiple languages

- Added French, Japanese, Russian, Vietnamese, and Chinese translations for "Add Uptime Kuma Group" and "Edit Uptime Kuma Group" to enhance internationalization support.
- This update improves user experience by providing clear and consistent messaging across different languages.

* fix(validation): enhance pricing schema error messages and add translations

- Updated the pricing schema to include localized error messages for validation, ensuring users receive clear feedback when input values are invalid.
- Added new translations for "Exchange rate is required" and "Exchange rate must be greater than 0" in English, French, Japanese, and Chinese to improve internationalization support.
- This change enhances user experience by providing accurate and contextually relevant messages across multiple languages.

* fix: codex Unsupported parameter: max_output_tokens

* fix(model-mapping-editor): simplify JSON parsing logic in useEffect

* fix: jimeng i2v support multi image by metadata

* refactor(models): restructure models section handling and improve UI components

- Replaced tab-based navigation with section-based navigation for better clarity and organization.
- Introduced a new section registry to manage model sections, including 'metadata' and 'deployments'.
- Updated the ModelsContent component to reflect the new section structure and added a Create Deployment button.
- Removed the ModelsTabs component as it was no longer needed.
- Enhanced internationalization support by adding new translations for section descriptions and management tasks.
- Adjusted sidebar configuration to accommodate the new section structure.

* fix: update warning threshold label from '5$' to '2$'

* fix: video content api Priority use url field

* fix: update abortWithOpenAiMessage function to use types.ErrorCode

* feat(deployment): introduce CreateDeploymentDrawer component and update dialog references

- Replaced the CreateDeploymentDialog with a new CreateDeploymentDrawer component for improved user experience.
- Added comprehensive form handling for deployment creation, including validation and price estimation features.
- Updated internationalization files to include new translations for UI elements and descriptions related to deployment configuration.
- Enhanced the ModelsContent component to integrate the new drawer for creating deployments.

* perf(i18n): enhance internationalization for models table and columns

- Updated labels and titles in the ModelsTable and useModelsColumns components to utilize translation functions for improved localization.
- Changed static text for vendor and sync status to dynamic translations, enhancing user experience for non-English speakers.
- Updated empty state messages in the ModelsTable to support internationalization, ensuring clarity for all users.

* fix: fix email send

* fix: issue where consecutive calls to multiple tools in gemini all returned an index of 0

* fix: replace Alibaba's Claude-compatible interface with the new interface

* fix: Only models with the "qwen" designation can use the Claude-compatible interface; others require conversion.

* feat: log shows request conversion

* feat: optimized display

* feat: optimized display

* feat: optimized display

* fix: codex rm Temperature

* Revert "fix: video content api Priority use url field"

* feat: requestId time string use UTC

* feat(qwen): support qwen image sync image model config

* feat: sync old ui

* feat: more ui sync

* feat: replace theme

* fix build

* refactor(web): revert theme colors and variables in CSS

Updated color variables for light and dark themes to improve consistency and visual appeal.

* feat(deployment): enhance deployment access guard and model deployment settings

- Introduced loading phase management in the DeploymentAccessGuard component to provide better user feedback during connection checks.
- Updated the ModelsContent component to prefetch the deployments list while checking connection status, improving data readiness.
- Implemented a caching mechanism for connection status in useModelDeploymentSettings to optimize performance and reduce unnecessary API calls.
- Enhanced loading states and error handling for improved user experience during deployment settings retrieval and connection testing.

* feat(i18n): add new translations for connection and loading states across multiple languages

- Introduced translations for "Checking connection" and "Loading configuration" in English, French, Japanese, Russian, Vietnamese, and Chinese.
- This update enhances the internationalization support, providing clearer user feedback during connection checks and loading phases.

* refactor(pagination): adjust layout and styling for pagination component

- Updated the pagination component to improve layout by removing unnecessary width constraints and enhancing responsiveness.
- Increased minimum width for pagination text to ensure better visibility and alignment across different screen sizes.

* feat(i18n): implement translations for various UI elements across multiple components

- Updated several components to utilize the translation function for titles and placeholders, enhancing internationalization support.
- Added new translation entries for "Filter by name or key..." and "Log Type" in English, French, Japanese, Russian, Vietnamese, and Chinese.
- This update improves user experience by providing localized text in the ChannelsTable, SummaryCards, ApiKeysTable, RedemptionsTable, UsageLogsTable, and UsersTable components.

* feat(i18n): integrate translation support in SummaryCards component

- Added the useTranslation hook to the SummaryCards component to enhance internationalization.
- This update allows for localized text rendering, improving user experience for diverse language speakers.

* feat(dashboard): refactor dashboard structure and introduce section-based navigation

- Removed the tab navigation in favor of a section-based approach, enhancing user experience by providing clearer context for the dashboard content.
- Introduced a new section registry to manage dashboard sections, allowing for easier expansion and maintenance.
- Updated sidebar configuration to reflect the new section structure, ensuring proper navigation links are displayed.
- Added translations for new section titles and descriptions to support internationalization.

* feat(i18n): update time range labels and enhance translation support

- Changed time range labels from shorthand (e.g., '1D') to full text (e.g., '1 Day') for better clarity.
- Updated various components to utilize the translation function for time range labels, improving internationalization.
- Added new translation entries for time ranges in English, French, Japanese, Russian, Vietnamese, and Chinese, enhancing user experience across languages.

* feat(dashboard): enhance type safety and improve component structure

- Updated the Dashboard component to use specific types for model data and filters, enhancing type safety.
- Introduced new types for announcements and FAQs, improving clarity and maintainability.
- Refactored LogStatCards and UptimePanel components to utilize AbortController for better data fetching management.
- Optimized the rendering of announcements and FAQs by using unique keys based on item IDs.
- Improved theme management in ModelCharts by caching the ThemeManager import to reduce dynamic imports.

* feat(agents): add comprehensive guidelines for React and Next.js development

- Introduced a new set of best practices and optimization techniques for React and Next.js applications, aimed at enhancing performance and maintainability.
- Included detailed rules covering various aspects such as event handling, API routes, rendering strategies, and state management.
- Added extensive documentation in AGENTS.md and SKILL.md to support developers in adhering to these practices.
- This update serves as a foundational resource for improving code quality and efficiency in React-based projects.

* chore(web): update package.json dependencies

- Removed outdated dependencies including @base-ui/react, @clerk/clerk-react, and others to streamline the project.
- Updated remaining dependencies to their latest versions for improved performance and security.
- This cleanup enhances the overall maintainability of the project.

* feat(usage-logs): implement section-based navigation and enhance log management

- Introduced a section registry for usage logs, allowing for better organization and navigation between different log categories (common, drawing, task).
- Updated the UsageLogsContent component to dynamically render titles and descriptions based on the selected section.
- Refactored UsageLogsTable and UsageLogsPrimaryButtons components to accept the active log category as a prop, improving modularity.
- Enhanced sidebar configuration to support new section navigation, ensuring users can easily access different log types.
- Updated routing to redirect to the default section if none is specified, improving user experience.

* feat(i18n): enhance internationalization across usage logs components

- Integrated the useTranslation hook in various components related to usage logs, including CommonLogsStats, UsageLogsTable, and column helpers.
- Updated labels, titles, and messages to utilize translation functions, improving localization support.
- Added new translation entries for log-related terms in English, French, Japanese, Russian, Vietnamese, and Chinese, enhancing user experience for diverse language speakers.

* feat(datetime-picker): integrate dayjs for date formatting

- Added dayjs as a dependency to the project for improved date handling.
- Updated the DateTimePicker component to use dayjs for formatting dates, enhancing consistency and readability of date displays.

* feat(date-handling): replace date-fns with dayjs for improved date management

- Updated the project to use dayjs instead of date-fns for date formatting and manipulation, enhancing consistency across components.
- Refactored DatePicker, DateTimePicker, and other components to utilize dayjs for date-related functionalities.
- Added a new dayjs configuration file to extend its capabilities with relative time support.
- Updated AGENTS.md to reflect the new technology stack, emphasizing the use of dayjs for date handling.

* refactor(agents): streamline front-end development guidelines and update technology stack

- Revised AGENTS.md to condense front-end development standards and best practices, making it more accessible for developers and AI assistants.
- Updated the technology stack section to reflect current dependencies, emphasizing the use of Bun, React 19, TypeScript, and other key libraries.
- Enhanced the document structure with a new table format for better readability and navigation, including a comprehensive table of contents for quick access to sections.

* feat(i18n): enhance date picker and datetime picker localization support

- Integrated internationalization support in DatePicker and DateTimePicker components by adding locale handling for multiple languages (English, French, Japanese, Russian, Vietnamese, Chinese).
- Updated the calendar component to accept a locale prop, ensuring proper localization of month and weekday labels.
- Improved user experience by allowing date selection to adapt based on the user's language preference.

* feat(layout): add SectionPageLayout component for structured page layouts

- Introduced a new SectionPageLayout component to facilitate structured layouts for pages with sections, enhancing the organization of content.
- Added subcomponents for Title, Description, Actions, and Content to improve clarity and maintainability of page structures.
- Updated AGENTS.md to include guidelines on avoiding unnecessary destructuring of props for better code readability.

* feat(layout): refactor components to use SectionPageLayout for improved structure

- Replaced AppHeader and Main components with SectionPageLayout across multiple features including Channels, Dashboard, ApiKeys, Models, Redemption Codes, Usage Logs, Users, and Wallet.
- Enhanced page organization by utilizing SectionPageLayout's Title, Description, Actions, and Content subcomponents, improving clarity and maintainability.
- This update standardizes the layout structure across the application, facilitating a more cohesive user experience.

* feat(usage-logs): enhance URL state management and redirection logic

- Added useEffect to synchronize column filters with URL search changes, preventing infinite loops caused by inline references.
- Improved redirection logic in usage logs to clear 'type' from the URL when the section is not 'common', enhancing user experience and URL cleanliness.

* fix(usage-logs): disable global filter and update DataTableToolbar props

- Disabled the global filter in the UsageLogsTable component to streamline the user interface.
- Updated the DataTableToolbar component to accept a null customSearch prop, enhancing flexibility in toolbar configuration.

* feat(routes): implement section-based routing for system settings and dashboard

- Introduced section-based routing for system settings and dashboard features, enhancing navigation and organization.
- Updated route definitions to include dynamic sections, allowing for more granular access to settings and dashboard components.
- Refactored existing routes to redirect to default sections when no specific section is provided, improving user experience.
- Added new section routes for models, usage logs, and system settings, ensuring consistency across the application.
- Removed deprecated routes to streamline the routing structure and improve maintainability.

* refactor(usage-logs): update column helper functions to require config parameter

- Modified createFailReasonColumn and createProgressColumn functions to require a config parameter instead of allowing it to be optional.
- Simplified destructuring of config to enhance clarity and ensure necessary properties are always provided, improving code reliability.

* refactor(usage-logs): improve section ID validation and routing logic

- Introduced a type guard function, isUsageLogsSectionId, to validate section IDs, enhancing type safety and reducing the need for casting.
- Updated UsageLogsContent to utilize the new validation function for determining the active category, improving clarity and reliability.
- Refactored routing logic to use isUsageLogsSectionId for section validation, ensuring proper redirection to the default section when necessary.

* refactor(calendar): update locale documentation for i18n support

- Revised the locale prop documentation in the Calendar component to specify the use of react-day-picker for internationalization, clarifying the expected locale setup for users.

* chore(i18n): remove redundant user information description from locale files

- Removed the user information description from English, French, Japanese, Russian, Vietnamese, and Chinese locale files to streamline translations and improve clarity.

* chore(i18n): streamline locale files by removing redundant entries

- Removed unnecessary entries from English, French, Japanese, Russian, Vietnamese, and Chinese locale files to enhance clarity and reduce clutter.
- Adjusted translations for consistency and improved user experience across multiple languages.

* chore(sidebar): remove deprecated usage logs route from sidebar config

- Eliminated the '/usage-logs' entry from the sidebar configuration to streamline navigation and improve clarity in the sidebar structure.

* refactor(redemption-codes): enhance internationalization support and improve UI consistency

- Updated various components to utilize translation functions for user-facing strings, ensuring a consistent experience across different languages.
- Added meta labels for table columns to improve accessibility and clarity.
- Revised confirmation and action texts in dialogs and tooltips to leverage translation, enhancing user experience.
- Updated locale files to include new translations for improved clarity and consistency.

* feat(masked-value-display): add MaskedValueDisplay component for sensitive data handling

- Introduced a new MaskedValueDisplay component to display masked values with a popover for full value visibility and a copy button for easy access.
- Updated api-keys-columns and redemptions-columns to utilize the new component, enhancing code reusability and UI consistency.
- Revised translation keys in locale files to remove colons for improved clarity.

* refactor(url-utils): simplify query parameter matching logic in checkIsActive function

- Updated the checkIsActive function to streamline the logic for matching URLs with and without query parameters.
- Removed unnecessary checks for query parameters when matching base paths, improving clarity and maintainability of the code.

* fix(channels-table): update group filter label to use translation function

- Replaced hardcoded 'All Groups' label with a translation function call to enhance internationalization support in the ChannelsTable component.

* chore(api-keys): remove deprecated API key action messages and related exports

- Deleted the api-key-actions.ts file, which contained action messages for enabling, disabling, and deleting API keys.
- Updated index.ts to remove the export of getApiKeyActionMessage, streamlining the codebase by eliminating unused functionality.

* refactor(i18n): enhance internationalization support across various components

- Updated multiple components to utilize translation functions for user-facing strings, ensuring a consistent experience across different languages.
- Revised constants and labels in the channels and redemption codes features to use i18n keys, improving maintainability and clarity.
- Ensured that success and error messages leverage translation functions, enhancing user experience and accessibility.
- Streamlined the handling of i18n keys in the constants files for better organization and clarity.

* refactor(i18n): enhance translation support across various components

- Updated multiple components to utilize translation functions for user-facing strings, ensuring a consistent experience across different languages.
- Revised pagination and status labels to use i18n keys, improving maintainability and clarity.
- Enhanced response time formatting to support internationalization, allowing for localized display of time values.
- Updated locale files to include new translations for improved clarity and consistency.

* docs(AGENTS): add type checking requirement for TypeScript changes

- Included a new guideline stating that type checks must be executed after modifying TypeScript or TSX code, ensuring no type errors are left unresolved.
- Updated the document to reflect this addition in the relevant section for better clarity on coding standards.

* feat(combobox-input): add ComboboxInput component for enhanced token selection

- Introduced a new ComboboxInput component to facilitate token name selection with search and filtering capabilities.
- Integrated the ComboboxInput into the UsageLogsFilterDialog for improved user experience when filtering by token name.
- Updated locale files to include new translations for user-facing strings related to token filtering.

* feat(combobox): integrate translation support for custom value prompt

- Added translation functionality to the Combobox component, replacing hardcoded text with a translatable string for the custom value prompt.
- Utilized the useTranslation hook from react-i18next to enhance internationalization support, ensuring a consistent user experience across different languages.

* refactor(i18n): improve Chinese translations for consistency and clarity

- Adjusted spacing in various Chinese translations to enhance readability and maintain consistency across the locale file.
- Updated multiple user-facing strings to ensure proper formatting and alignment with localization standards.

* feat(calendar): add CalendarDropdown component for enhanced dropdown functionality

- Introduced a new CalendarDropdown component to improve user interaction with dropdown selections in the calendar.
- Implemented state management for dropdown visibility and selection handling, enhancing the overall user experience.
- Updated styling for dropdown elements to ensure consistency and better alignment with the UI design.

* fix(balance-query-dialog): handle null currentRow and improve usage query logic

- Updated the BalanceQueryDialog component to safely access currentRow properties using optional chaining.
- Added a check to ensure currentRow is not null before proceeding with usage queries, preventing potential runtime errors.
- Refactored the handleQueryCodexUsage function to use a local variable for currentRow, enhancing code clarity.

* feat(i18n): add new translations for batch creation and channel updates

- Added new translation strings for batch creation instructions across multiple languages, enhancing user guidance.
- Included translations for the "Update Channel" prompt to improve clarity in channel configuration settings.
- Ensured consistency in terminology across locale files for better user experience.

* feat(channel-mutate-drawer): improve API key input handling and update translations

- Refactored the API key input logic in the ChannelMutateDrawer component to enhance readability and maintainability.
- Added new placeholder translations for batch creation and existing key prompts in multiple languages, improving user guidance.
- Ensured consistency in translation strings across locale files for better user experience.

* feat(fetch-models-dialog): implement sorting for model categories

- Added a new function to sort model categories alphabetically, placing 'Other' at the end for easier navigation.
- Updated the rendering logic in the FetchModelsDialog component to utilize the new sorting function for both new and existing models, enhancing user experience.

* refactor(wallet-stats-card): standardize props usage and improve layout consistency

Standardizes props usage and improves layout consistency in wallet stats card

Refactors the wallet stats card component to:
- Use props directly instead of destructuring for consistency
- Add min-w-0 to prevent content overflow
- Adjust text sizing with break-all for proper wrapping
- Implement responsive font sizes (3xl on mobile, 4xl on larger screens)
- Improve leading and tracking for better readability

Refactor wallet stats card for consistency and layout

Standardizes props usage and improves layout consistency in wallet stats card

- Uses props directly instead of destructuring for consistency
- Adds min-w-0 to prevent content overflow
- Adjusts text sizing with break-all for proper wrapping
- Implements responsive font sizes (3xl on mobile, 4xl on larger screens)
- Improves leading and tracking for better readability

* feat(web): add subscription management and admin settings UI

* feat(web): add subscription management and admin settings UI

- Add subscription management module (plans, pricing, toggle status, and related dialogs/tables with Stripe/Creem integration notes)
- Add channel affinity (rules and cache stats), Waffo integration, performance, and Grok model sections to system settings, with extended types and section registry
- Add status code mapping validation/risk warnings, upstream update hooks, and utilities for channels; add available models and sidebar module cards to user profile
- Add chat2link route and useMinimumLoadingTime, useTableCompactMode shared hooks

Made-with: Cursor

* fix: remove duplicate GenerateOAuthCode and add missing TaskBulkUpdate

- remove duplicate GenerateOAuthCode from github.go since oauth.go already has the generic version.
- add model.TaskBulkUpdate for bulk update by upstream task_id strings, fixing task_video.go build failure.

* feat(router): add chat2link and subscriptions routes

- register /chat2link page route under authenticated layout.
- register /subscriptions/ page route under authenticated layout.
- update auto-generated routeTree type definitions and route mappings.

* feat(docker): add development environment setup with Docker Compose

- Introduced docker-compose.dev.yml for local development, including services for new-api, Redis, and PostgreSQL.
- Created Dockerfile.dev for backend-only builds, optimizing the development workflow.
- Updated makefile to include new commands for starting backend services and frontend development.

* feat(web): complete i18n coverage for setup wizard and add language switcher

- wrap all hardcoded English strings in setup-wizard, database-step, usage-mode-step, and complete-step with t() calls, covering step titles, descriptions, form validation messages, and fallback strings.
- add LanguageSwitcher component to the top-right corner of the setup page so users can switch language during initial setup.
- register 25 dynamic i18n keys in static-keys.ts and provide full translations for zh/en/ja/fr/ru/vi.

* feat(i18n): internationalize default version text in workspace-switcher

- remove hardcoded 'Unknown version' default, use t('Unknown version') for i18n fallback
- add "Unknown version" translation entries across all 6 locale files (zh/en/fr/ru/ja/vi)

* feat(i18n): add full i18n coverage for channel-affinity settings page

- replace Chinese t() keys with English keys across three channel-affinity components to align with new frontend i18n conventions.
- add 51 translation entries to all 6 locale files (en/zh/ja/fr/ru/vi) covering main page, rule editor, and cache stats dialog.
- register section-registry dynamic keys in static-keys.ts.

* feat(i18n): add full i18n coverage for Waffo payment settings page

- replace Chinese i18n keys with English keys in waffo-settings-section.tsx for consistency.
- wrap previously hardcoded labels (Pay Method Type / Pay Method Name) with t().
- add 26 Waffo-related translation entries across all 6 locale files (en/zh/fr/ru/ja/vi).

* feat(i18n): add missing translations for global model settings page

- add all 6 locale translations for 3 missing t() keys in global-settings-card.
- register dynamically used 'Grok' key in static-keys.ts for i18n scanner coverage.

* feat(i18n): add full i18n coverage for Grok model settings page

- add translations in all 6 locales (en/zh/fr/ja/ru/vi) for grok-settings-card t() calls.
- cover violation fee toggle, amount input, and official docs link labels.
- include section-registry descriptionKey translation entries.

* feat(i18n): add full i18n coverage for performance settings page

- migrate all t() keys from Chinese to English to align with project conventions.
- add translations for all 6 locales (en/zh/ja/fr/ru/vi) covering disk cache,
  system monitoring, log management, and stats dashboard sections.
- remove 71 obsolete Chinese-keyed entries from every locale file.

* fix(i18n): add 116 missing English translation keys across all locales

- scan all t() calls to identify English keys used in code but absent from locale files.
- add translations for zh/en/fr/ja/ru/vi, keeping key sets and sort order consistent.
- covers system-settings, channels, models, auth, wallet and other modules.

* fix(i18n): add missing translations for log cleanup quick-select and confirm dialog

- wrap quick-select button labels (24 hours ago / 7 days ago / 30 days ago) with t().
- replace hardcoded English strings in purge confirm dialog with t() calls and date interpolation.
- add 5 new translation keys across all 6 locale files (zh/en/fr/ja/ru/vi).

* refactor(web): unify all time display with dayjs formatting

- replace all toLocaleString/toLocaleDateString/toLocaleTimeString and manual padStart concatenation with dayjs.format().
- standardize output: datetime as YYYY-MM-DD HH:mm:ss, date as YYYY-MM-DD, time as HH:mm:ss.
- add formatDateTimeStr, formatDateStr, formatTimeStr dayjs-based helpers in lib/format.ts.
- update 12 files across core utils and feature components.

* refactor(web): replace native datetime-local input with DateTimePicker in announcements

- swap browser-native datetime-local for the project's DateTimePicker component to match the UI used in log cleanup and other pages.
- convert between Date objects and ISO strings to bridge the form's string-based schema.

* refactor(web): replace native HTML elements with design system components

- replace ~35 native <button> with <Button> across pricing, profile, channels modules
- replace native <input>/<textarea>/<label> with <Input>/<Textarea>/<Label> for consistent form styling
- replace native <table> with <Table> components, <details>/<summary> with <Collapsible>
- replace decorative <hr> with <Separator> to ensure global UI consistency

* refactor(web): enhance profile components with design system consistency

- update ProfileSecurityCard to use buttons for security actions, improving accessibility and styling.
- modify AccountBindingsTab layout to a grid for better responsiveness and visual alignment.
- refactor NotificationTab to utilize icons for notification methods, enhancing user experience and clarity.

* fix(i18n): complete i18n coverage for profile page components

- wrap passkey card status badges (enabled/disabled, backup state) and last-used text with t()
- fix hardcoded button labels in security dialogs (change password, access token, delete account)
- internationalize all 2FA dialog strings (setup, disable, backup codes)
- fix email bind dialog description and button state text missing i18n
- wrap remaining hardcoded strings in notification tab and checkin calendar
- add all missing translation entries to zh.json and en.json

* fix(i18n): enhance error messages with translations for deployment access and settings

- wrap connection error messages in DeploymentAccessGuard and IoNetDeploymentSettingsSection with t() for internationalization.
- add missing translation key for "io.net model deployment is not enabled or api key missing" in all locale files (en, fr, ja, ru, vi, zh).

* 🧹 chore(web): resolve all ESLint errors and warnings

Align the Vite/React frontend with the current ESLint flat config and
React Compiler–related rules by fixing violations instead of broad
suppression where practical.

- Replace `any` with concrete types (`unknown`, `Record<string, unknown>`,
  domain types) where upstream/API shapes allow
- Fix duplicate imports, unused bindings, `no-console`, and empty blocks
- Address react-hooks issues: reorder declarations, memoize unstable
  callbacks (`useCallback`), extend dependency arrays, and use targeted
  disables only where sync-from-props in `useEffect` is intentional
- Refactor `motion.create` usage in ai-elements shimmer to avoid creating
  components during render (static-components)
- Stabilize TanStack Query/Mutation hook usage (query keys, `mutate` in
  deps) and add narrowly scoped rule disables where the linter conflicts
  with library patterns
- Disable `react-hooks/incompatible-library` in ESLint config for
  TanStack Table / RHF false positives
- Add file-level `react-refresh/only-export-components` disables for
  registry/provider/column modules that intentionally mix exports

`bun lint` completes with 0 errors and 0 warnings.

* ✨ feat(web): add subscription management to sidebar and align drawer with project conventions

- Register "Subscription Management" nav item in the admin sidebar group
  with CreditCard icon pointing to /subscriptions
- Add subscription module to sidebar config defaults and URL mapping so it
  integrates with the admin sidebar modules toggle in system settings
- Add subscription entry to sidebar-modules-section moduleMeta for the
  maintenance settings UI
- Refactor SubscriptionsMutateDrawer to follow the same patterns used by
  users, redemption-codes, and other mutate drawers:
  - Use shadcn Form/FormField/FormItem/FormControl/FormLabel/FormMessage
    instead of raw register() + Label + manual error display
  - Move SheetFooter outside the form with form attribute association
  - Use SheetClose for the cancel button
  - Reset form state on drawer close
  - Align SheetContent width (sm:max-w-[600px]) and spacing conventions

* ✨ feat(web): overhaul UI/UX with Vercel Geist design alignment

Refactor the entire frontend UI/UX to align with Vercel/OpenAI design
principles, covering layout, animations, skeleton loading, and overall
visual polish.

Motion & Page Transitions:
- Add centralized motion system (lib/motion.ts) with Vercel-style
  transition presets, stagger variants for tables, cards, and sidebars
- Implement AnimatedOutlet for route-level page enter animations
  using TanStack Router pathname keying
- Add PageTransition, StaggerContainer, StaggerItem, CardStagger,
  and TableStagger wrapper components for progressive reveal effects

Skeleton Loading — Vercel Geist Style:
- Replace shadcn default `animate-pulse` with Geist-style shimmer
  sweep animation (linear-gradient + background-position keyframes)
- Add `--skeleton-base` / `--skeleton-highlight` CSS variables tuned
  for both light and dark themes with neutral oklch tones
- Override auto-skeleton-react inline styles via CSS to unify all
  skeleton elements under the same shimmer effect
- Update TableSkeleton with varied column widths for a natural feel
- Add ContentSkeleton and QuerySkeleton wrappers for auto-skeleton
  integration with React Query error/loading states
- Respect prefers-reduced-motion: disable shimmer for accessibility

Layout & Sidebar:
- Upgrade sidebar expand/collapse transitions to cubic-bezier easing
- Add hover micro-interactions (background-color, color, transform)
  to sidebar menu buttons with smooth 150ms transitions
- Fix oklch color compatibility in sidebar outline variant
- Integrate AnimatedOutlet into AuthenticatedLayout for unified
  route-level animations

Theme & CSS:
- Streamline theme.css with cleaner oklch color definitions
- Add CSS table row stagger-in animations with nth-child delays
- Fix hover-scrollbar color bug (hsl → color-mix for oklch compat)
- Add content-auto utility for long list rendering optimization

Cleanup:
- Remove deprecated skeleton-wrapper.tsx
- Remove unused imports and dead code across components
- Add empty-state, error-state, and loading-state utility components

* 🐛 fix(docker): track bun.lock to fix Docker build failure

Remove `web/bun.lock` from `.gitignore` so the lock file is committed
to version control. The Dockerfile `COPY web/bun.lock .` instruction
requires this file to be present in the build context, and ignoring it
caused the build to fail with a "not found" error.

* ⬆️ chore(web): upgrade dependencies and fix all type/lint errors

Upgrade all frontend dependencies to latest stable versions:
- lucide-react 0.562 → 1.7 (major: brand icons removed)
- shiki 3.x → 4.x, eslint 9.x → 10.x, knip 5.x → 6.x
- @rsbuild/core 1.3 → 1.7, @types/node 24 → 25
- tailwindcss/postcss 4.1 → 4.2, motion 12.25 → 12.38
- @tanstack/react-query 5.90 → 5.95, zod 4.3.5 → 4.3.6
- react 19.2.3 → 19.2.4, axios 1.13.2 → 1.13.6
- prettier 3.7 → 3.8, typescript-eslint 8.52 → 8.57
- Add missing optional deps: @xyflow/react, embla-carousel-react

Resolve all TypeScript compilation errors introduced by upgrades:
- Replace lucide-react brand icons (Github) with react-icons/si
- Fix react-hook-form Control/Resolver generics for zod v4
- Fix Record<string, unknown> type constraints across API utils
- Fix axios interceptor return types in lib/api.ts
- Add type assertions for useSettings/useStatus hook returns
- Resolve Badge variant, spread type, and route path mismatches

Resolve all ESLint 10 errors:
- preserve-caught-error: attach cause to re-thrown errors
- no-useless-assignment: refactor redundant variable assignments
- prefer-as-const: use `as const` over literal type assertions
- no-unused-vars: prefix type-only schemas with underscore

Update tsconfig lib from ES2020 to ES2022 for Error.cause support.

* 🐛 fix(web): stop pricing model row from centering its content

Wrapping the row in shadcn <Button variant='ghost'> inherits
`justify-center`, and the inner flex container had no width, so
`justify-between` collapsed and the row appeared centered.

* feat: add Waffo payment integration and related UI components

- Introduced Waffo payment method with support for custom icons and settings.
- Updated payment settings section to include Waffo settings.
- Added Waffo payment request handling in the wallet API.
- Enhanced wallet recharge form to support Waffo payment methods.
- Implemented hooks for Waffo payment processing.
- Updated localization files for new Waffo-related strings.
- Added new payment type and icon for Waffo in constants and UI components.
- Refactored topup info handling to include Waffo payment methods and configurations.

* feat(profile): add admin-only upstream model update notification setting

* fix(web): make sidebar module user settings actually take effect

Previously, saving sidebar module preferences in profile had no effect
because the client ignored user-level sidebar_modules entirely. This
fix wires user config into useSidebarConfig so the sidebar updates
immediately without a page refresh.

Changes:
- Add UserPermissions type with sidebar_settings/sidebar_modules fields
- Refactor useSidebarConfig to merge admin × user config with AND logic
- Sync sidebar_modules to auth store on save for immediate UI updates
- Conditionally render SidebarModulesCard based on user permissions
- Treat null/empty user config as "do not narrow" for legacy users

* feat(web): add custom OAuth provider CRUD and login button support

Migrate custom OAuth from v1 to v2:
- Admin CRUD UI with provider table, form dialog, preset templates, and OIDC discovery
- Login page renders dynamic buttons for custom OAuth providers
- Fix account bindings display showing "Not bound" text when already bound

* feat(web): add ServerAddress, SMTPForceAuthLogin, CreateCacheRatio and group special usable settings

Migrate missing v1 system settings to v2:
- ServerAddress input in General > System Information
- SMTPForceAuthLogin toggle in Integrations > Email
- CreateCacheRatio JSON editor in Models > Ratio
- Group special usable group rules editor in Models > Ratio

* feat(web): wire user subscriptions dialog to users table row actions

The UserSubscriptionsDialog component already existed but had no entry point
in the users table dropdown menu. Add "Manage Subscriptions" menu item.

* chore(web): update i18n translations for new settings and custom OAuth

* 💎 refactor(web): redesign pricing page with flat, typography-driven layout

* 🌐 chore(i18n): complete missing translations and normalize project config

- Add 425+ missing translations across fr, ja, ru, zh, vi locales
  for subscription management, sidebar navigation, Grok settings,
  upstream model updates, pricing page, and other UI components
- Add 37 missing i18n keys used in t() calls but absent from locale
  files (pricing filters, display options, audio/cache labels, etc.)
- Fix stale tech stack info in CLAUDE.md, AGENTS.md, and project.mdc:
  React 18 → 19, Vite → Rsbuild, Semi Design → Radix UI + Tailwind
- Fix i18n key format description: "Chinese source strings" → English
- Deduplicate .cursor/rules/project.mdc to avoid triple-loading the
  same rules already present in root CLAUDE.md and AGENTS.md
- Add i18n-translate Cursor skill for repeatable translation workflow

* 🎨 refactor(web): redesign dashboard with flat, typography-driven layout

Replace Card-based dashboard components with a flat, border-driven design
system consistent with the pricing page, following the ui-style.mdc conventions.

Overview section:
- StatCard: replace Card wrapper with flat flex layout, monospace tabular
  values, uppercase tracking-wider labels, layered opacity hierarchy
- PanelWrapper: replace Card/CardHeader/CardContent with rounded-lg border
  container and border-b header
- SummaryCards: merge three stat cards into a single bordered container
  with divide-x separators; decouple border from stagger animation to
  prevent border deformation during entrance transitions
- ApiInfoPanel/Item: full-width list rows with border-b separators,
  monospace route names, layered opacity for URLs and descriptions
- AnnouncementsPanel: native button rows with hover:bg-muted/40, i18n for
  "Click for details" hint
- FAQPanel: lighter border-border/60 accordion dividers, muted answer text
- UptimePanel: uppercase tracking-wider group headers with bg-muted/30
  background, monospace uptime percentages, fine-grained border opacity

Models section:
- LogStatCards: replace Card with rounded-lg border + divide-x grid,
  fix react-hooks/exhaustive-deps by destructuring props before useEffect
- ModelCharts: replace Card+Tabs with bordered container + custom
  segmented control matching ui-style spec
- Suspense fallbacks: match new flat skeleton layout with accurate
  column structure

Animation:
- Wrap models section in FadeIn with staggered delay
- Keep CardStagger for overview panel grid (each panel has own border)

Other:
- Add ui-style.mdc cursor rule documenting the design language
- Disable react-refresh/only-export-components for src/routes/** in
  eslint config (TanStack Router route files always export Route objects)
- Fix zh.json: "Token-based" translation "基于令牌的" → "按量计费"

* ✨ refactor(web): adopt flat dot-and-text design for all status badges

Replace the bordered/colored-background StatusBadge and Badge components
across the entire frontend with a minimal flat design: a small colored
dot followed by colored text, eliminating visual noise from heavy
borders, backgrounds, and rounded pill shapes.

Key changes:

- Redesign StatusBadge to use dot + text instead of bordered pill style,
  removing cva-based background/border variants in favor of exported
  dotColorMap and textColorMap lookup tables
- Add children prop support to StatusBadge for flexible content rendering
  alongside the existing label prop
- Migrate all Badge usages (except pricing page) to StatusBadge with
  appropriate variant mappings (default→info, secondary→neutral,
  outline→neutral, destructive→danger)
- Consolidate adjacent multi-badge groups into single-dot layouts with
  dot separators (·) to reduce visual clutter in:
  - Channel balance columns (used + remaining)
  - Channel type column (type + IO.NET indicator)
  - User invite info column (invited + revenue + inviter)
  - Usage log stats bar (usage + RPM + TPM)
  - Usage log time/FRT column (time + FRT + stream status)
  - Subscription plan counts (active + expired)
  - Channel affinity scope/regex/key-source columns
  - Prefill group card headers (type + ID)
- Export dotColorMap and textColorMap for direct use in custom inline
  layouts that need consistent status colors without the full component

* ✨ refactor(web): redesign public layout and landing page with modern UI

Overhaul the public-facing layout, header, and homepage to deliver a
polished, animation-rich landing experience inspired by contemporary
SaaS design patterns.

Header:
- Replace sticky header with fixed floating navbar that compacts into
  a pill-shaped glass-morphism bar on scroll (backdrop-blur + ring)
- Add smooth 700ms cubic-bezier transitions for scroll-based shrinking
- Build full-screen mobile menu overlay with staggered entry animations
- Remove background color from logo container, show logo image directly

Homepage sections:
- Hero: gradient text title, radial gradient + grid pattern background,
  interactive terminal demo showcasing API request/response
- Terminal demo: auto-cycles through gpt-4o, claude-sonnet-4-20250514,
  gemini-2.5-pro, deepseek-chat with smooth cross-fade transitions,
  clickable model badges, dual theme support (light/dark), fixed height
- Stats: animated co…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants