Skip to content

v1.0.4-preview.2#9

Merged
CSCITech merged 7 commits into
mainfrom
cscitech
Jul 5, 2026
Merged

v1.0.4-preview.2#9
CSCITech merged 7 commits into
mainfrom
cscitech

Conversation

@CSCITech

@CSCITech CSCITech commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

📝 变更描述 / Description

(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

  • Closes # (如有)

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

(请在此粘贴截图、关键日志或测试报告,以证明变更生效)

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR updates user-setting persistence and cache behavior, expands task request and billing normalization, changes Ollama tool-call handling, adjusts server and web session flows, and refreshes repository maintenance docs and JSON allowlist entries.

Changes

User settings and cache writes

Layer / File(s) Summary
Setting persistence and user update
controller/user.go, controller/subscription.go, model/user.go
User-setting updates now go through model.UpdateUserSetting, and user updates reload and write back records without overwriting accounting fields.
Cache population and field refresh
model/user_cache.go
Redis cache handling now separates full population from partial refreshes, with a dedicated email cache helper.
Quota logs and log tests
model/log.go, model/log_test.go
Quota log writes run synchronously when export is enabled, and the retry-log test fixture reuses a single timestamp.
User update and setting tests
model/user_update_test.go
Tests cover accounting-field preservation, Redis write failures, and missing-user handling for setting updates.

Relay task parsing and task adapters

Layer / File(s) Summary
Task submit shape and merge rules
relay/common/relay_info.go, relay/common/relay_info_test.go, relay/common/relay_utils.go, relay/common/relay_utils_test.go, relay/channel/task/taskcommon/request_body.go, relay/channel/task/taskcommon/path_config_test.go, relay/channel/task/taskcommon/protocol_config.go
Task submit requests now use optional durations, merge and validation logic handle explicit fields more carefully, and result URL extraction uses expanded defaults.
Duration-based billing and provider helpers
relay/channel/task/taskcommon/generic_billing.go, relay/channel/task/taskcommon/generic_billing_test.go, relay/channel/task/doubao/adaptor.go, relay/channel/task/gemini/adaptor.go, relay/channel/task/gemini/billing.go, relay/channel/task/hailuo/adaptor.go, relay/channel/task/jimeng/adaptor.go, relay/channel/task/kling/adaptor.go, relay/channel/task/sora/adaptor.go, relay/channel/task/vertex/adaptor.go, relay/channel/task/vidu/adaptor.go
Billing helpers and several provider adaptors now read duration through DurationValue(), with tests updated for the new duration and video-content behavior.
Request-body and duration tests
relay/channel/task/taskcommon/request_body_test.go, relay/channel/task/taskcommon/generic_billing_test.go, relay/common/relay_info_test.go, relay/common/relay_utils_test.go, relay/channel/task/taskcommon/path_config_test.go
Tests cover field precedence, explicit zero duration preservation, and the updated billing and merge behavior around nested request bodies.
WAN 2.7 Ali request normalization
relay/channel/task/ali/adaptor.go, relay/channel/task/ali/adaptor_wan27_test.go, relay/channel/task/ali/constants.go
The Ali adaptor builds WAN 2.7 input.media payloads from request images and metadata, clears legacy fields, and adds model and test coverage for the new protocol.

Ollama tool-call conversion

Layer / File(s) Summary
Stream and non-stream conversion
relay/channel/ollama/stream.go
Ollama stream and non-stream handlers now decode tool calls through a shared converter, emit OpenAI-shaped tool-call payloads, and set tool-call finish reasons.
Tool-call handler tests
relay/channel/ollama/stream_test.go
New tests cover non-stream and streamed Ollama responses with function tool calls and validate the emitted SSE-like chunks.

Server lifecycle and web session gating

Layer / File(s) Summary
Server shutdown and route guards
main.go, router/api-router.go, web/default/src/routes/_authenticated/route.tsx
The HTTP server now shuts down through an explicit http.Server, the authenticated route changes 401 handling, and the self-update route gains critical rate limiting.
Playground validation and translations
web/default/src/features/playground/index.tsx, web/default/src/i18n/locales/*
The playground now shows translated errors when sending or regenerating is blocked, and new locale strings are added for those messages.
Channel field defaults
web/default/src/features/channels/lib/channel-form.ts, web/default/tests/channel-form.test.ts
The channel form library now exposes scoped defaults for base_url and other, and the test suite checks the values for different channel types.

Repository policy and sync maintenance

Layer / File(s) Summary
Agent docs and ignore rules
AGENTS.md, CLAUDE.md, .gitignore, .agents/skills/*, .agents/upstream-sync/new-api-sync.md
Agent guidance changes, upstream-sync ignore rules are removed, several skill documents are deleted, and sync metadata is refreshed.
JSON allowlist refresh
tools/jsonwrapcheck/allowlist.txt
The jsonwrapcheck allowlist is reshaped around the updated direct encoding/json call sites.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • MAX-API-Next/MAX-API#6 — touches the same taskcommon protocol-config path and configured-task parsing defaults.
  • MAX-API-Next/MAX-API#7 — overlaps with task request merging and billing-duration handling in relay/channel/task/taskcommon.

Poem

A rabbit hopped through caches neat,
Then chased tool calls on silent feet.
With WAN 2.7 and paths made new,
The server bowed out cleanly too. 🐇

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is just a version tag and does not describe the actual changeset. Use a concise, specific title that summarizes the main code change instead of a release/version label.
Description check ❓ Inconclusive The description is a fill-in template and does not provide an actual summary of the changes. Replace the template with a brief manual summary of what changed and why it matters.
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cscitech

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@relay/channel/task/taskcommon/protocol_config.go`:
- Line 58: The ResultURLPaths default slice in protocol_config.go is duplicated
across multiple prefix groups, so refactor it to be built programmatically from
shared leaf keys and prefixes instead of hardcoding every combination. Update
the default construction near the ProtocolConfig defaults to use a helper like
defaultResultURLPaths() (or equivalent) that iterates over the repeated prefix
set and appends the common leaf keys, while preserving the existing top-level
entries at the end. This will keep the ResultURLPaths list consistent and make
future changes to the leaf key set easier to maintain.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 369ff2e1-3a16-4ed2-9329-e9c4cdbb64e4

📥 Commits

Reviewing files that changed from the base of the PR and between c3dba65 and 9c40740.

📒 Files selected for processing (2)
  • relay/channel/task/taskcommon/path_config_test.go
  • relay/channel/task/taskcommon/protocol_config.go
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Backend checks
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrappers in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly calling encoding/json; encoding/json types like json.RawMessage and json.Number may still be used as types.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+ simultaneously: prefer GORM methods over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use cross-DB quoting/boolean helpers when raw SQL is unavoidable, avoid DB-specific functions/operators without fallbacks, and ensure migrations work on all three databases.
For request structs parsed from client JSON and later re-marshaled to upstream providers, especially in relay/convert paths, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved and omitted-only fields remain nil.

**/*.go: Use common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, and common.GetJsonType from common/json.go for all JSON marshal/unmarshal operations; do not directly call encoding/json in business code.
Keep all database code fully compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless cross-DB-safe, and use the provided DB-specific helpers/flags for quoting, booleans, and branching.
For request structs parsed from client JSON and re-marshaled to upstream providers, especially in relay/convert paths, use pointer types with omitempty for optional scalar fields so explicit zero/false values are preserved.

Files:

  • relay/channel/task/taskcommon/protocol_config.go
  • relay/channel/task/taskcommon/path_config_test.go
relay/channel/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.

When implementing a new channel, confirm whether the provider supports StreamOptions; if it does, add the channel to streamSupportedChannels.

Files:

  • relay/channel/task/taskcommon/protocol_config.go
  • relay/channel/task/taskcommon/path_config_test.go
🔇 Additional comments (1)
relay/channel/task/taskcommon/path_config_test.go (1)

274-298: LGTM! Good coverage for the new metadata.url extraction path, and it complements the existing result.video_url test.

Comment thread relay/channel/task/taskcommon/protocol_config.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
relay/channel/ollama/stream.go (1)

145-157: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract duplicated "thinking" decode logic into a helper.

The same trim/unmarshal/fallback logic for Thinking is repeated three times (streaming path, non-stream per-line loop, non-stream single-body fallback), differing only in where the result is written.

♻️ Suggested refactor
func decodeOllamaThinking(thinking json.RawMessage) string {
	if len(thinking) == 0 {
		return ""
	}
	raw := strings.TrimSpace(string(thinking))
	if raw == "" || raw == "null" {
		return ""
	}
	var content string
	if err := common.Unmarshal(thinking, &content); err == nil {
		return content
	}
	return raw
}

Then replace each call site, e.g.:

-			if chunk.Message != nil && len(chunk.Message.Thinking) > 0 {
-				raw := strings.TrimSpace(string(chunk.Message.Thinking))
-				if raw != "" && raw != "null" {
-					var thinkingContent string
-					if err := common.Unmarshal(chunk.Message.Thinking, &thinkingContent); err == nil {
-						delta.Choices[0].Delta.SetReasoningContent(thinkingContent)
-					} else {
-						delta.Choices[0].Delta.SetReasoningContent(raw)
-					}
-				}
-			}
+			if chunk.Message != nil {
+				if tc := decodeOllamaThinking(chunk.Message.Thinking); tc != "" {
+					delta.Choices[0].Delta.SetReasoningContent(tc)
+				}
+			}

Also applies to: 236-248, 268-280

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@relay/channel/ollama/stream.go` around lines 145 - 157, The Ollama thinking
decode logic is duplicated across the streaming and non-streaming paths, so
extract the trim/unmarshal/fallback behavior into a shared helper like
decodeOllamaThinking and use it from the chunk handling in stream.go; keep the
helper responsible only for turning chunk.Message.Thinking into the final
string, and have each call site write that result into
delta.Choices[0].Delta.SetReasoningContent or the equivalent non-stream target.
relay/common/relay_utils.go (1)

253-256: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Inconsistent trimming vs. ValidateMultipartDirect.

This sibling normalization path copies req.Image into req.Images without strings.TrimSpace, while the newly-changed ValidateMultipartDirect (lines 176-177) trims. For consistency (and since a dedicated test was just added to verify trimming behavior), consider applying the same trim here.

🧹 Suggested fix
 	if len(req.Images) == 0 && strings.TrimSpace(req.Image) != "" {
 		// 兼容单图上传
-		req.Images = []string{req.Image}
+		req.Images = []string{strings.TrimSpace(req.Image)}
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@relay/common/relay_utils.go` around lines 253 - 256, The single-image
normalization in the `req.Images` fallback is inconsistent with
`ValidateMultipartDirect` because it copies `req.Image` without trimming first.
Update the `req.Images` assignment in the `relay_utils` normalization path to
use the same `strings.TrimSpace` behavior as `ValidateMultipartDirect`, so
`req.Image` is trimmed before being wrapped into the slice.
controller/user.go (2)

696-746: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate read-modify-write blocks for sidebar_modules and language.

Both branches repeat the same fetch/mutate/persist pattern. Consider extracting a small helper, e.g. updateUserSettingField(userId int, mutate func(*dto.UserSetting)) error, to reduce duplication.

♻️ Suggested consolidation
-	if sidebarModules, sidebarExists := requestData["sidebar_modules"]; sidebarExists {
-		userId := c.GetInt("id")
-		user, err := model.GetUserById(userId, false)
-		if err != nil {
-			common.ApiError(c, err)
-			return
-		}
-
-		// 获取当前用户设置
-		currentSetting := user.GetSetting()
-
-		// 更新sidebar_modules字段
-		if sidebarModulesStr, ok := sidebarModules.(string); ok {
-			currentSetting.SidebarModules = sidebarModulesStr
-		}
-
-		if err := model.UpdateUserSetting(user.Id, currentSetting); err != nil {
-			common.ApiErrorI18n(c, i18n.MsgUpdateFailed)
-			return
-		}
-
-		common.ApiSuccessI18n(c, i18n.MsgUpdateSuccess, nil)
-		return
-	}
-
-	// 检查是否是语言偏好更新请求
-	if language, langExists := requestData["language"]; langExists {
-		userId := c.GetInt("id")
-		user, err := model.GetUserById(userId, false)
-		if err != nil {
-			common.ApiError(c, err)
-			return
-		}
-
-		// 获取当前用户设置
-		currentSetting := user.GetSetting()
-
-		// 更新language字段
-		if langStr, ok := language.(string); ok {
-			currentSetting.Language = langStr
-		}
-
-		if err := model.UpdateUserSetting(user.Id, currentSetting); err != nil {
-			common.ApiErrorI18n(c, i18n.MsgUpdateFailed)
-			return
-		}
-
-		common.ApiSuccessI18n(c, i18n.MsgUpdateSuccess, nil)
-		return
-	}
+	if sidebarModules, sidebarExists := requestData["sidebar_modules"]; sidebarExists {
+		if err := updateUserSettingField(c, func(s *dto.UserSetting) {
+			if v, ok := sidebarModules.(string); ok {
+				s.SidebarModules = v
+			}
+		}); err != nil {
+			return
+		}
+		return
+	}
+
+	if language, langExists := requestData["language"]; langExists {
+		if err := updateUserSettingField(c, func(s *dto.UserSetting) {
+			if v, ok := language.(string); ok {
+				s.Language = v
+			}
+		}); err != nil {
+			return
+		}
+		return
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@controller/user.go` around lines 696 - 746, The `sidebar_modules` and
`language` branches in the user settings update flow duplicate the same
read-modify-write logic. Extract the repeated fetch via `model.GetUserById`,
mutate `user.GetSetting()`, and persist with `model.UpdateUserSetting` into a
small helper (for example, a function used by this handler) so both cases reuse
the same path and only differ in the field mutation.

691-746: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Avoid full-blob writes for user settings

controller/user.go still reads the entire setting JSON, mutates one field, and writes the whole blob back. Concurrent updates to other setting fields can be lost because model.UpdateUserSetting replaces the full column. Patch only the changed key or add merge/optimistic-locking semantics.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@controller/user.go` around lines 691 - 746, The user settings update paths in
controller/user.go still read the full setting blob via GetUserById/GetSetting
and then overwrite it with UpdateUserSetting, which can clobber concurrent
changes. Update the sidebar_modules and language branches so they only patch the
modified key, or add merge/optimistic-locking behavior inside
model.UpdateUserSetting so unchanged setting fields are preserved.
model/user.go (1)

544-565: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Extra round-trip: current is only used to anchor Model().

current is loaded solely to give DB.Model(&current) a primary key; its fields are never read afterward. This could be simplified to DB.Model(&User{Id: user.Id}) to skip the initial SELECT, at the cost of losing the "row must exist" pre-check (which would then surface as a no-op UPDATE matching zero rows instead of ErrRecordNotFound). If existence-checking is intentional, consider a comment noting why the extra query is kept.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@model/user.go` around lines 544 - 565, The Update method in User loads a full
current record only to pass it into DB.Model, which adds an unnecessary SELECT.
Simplify the anchoring in Update by using a lightweight User instance with the
existing Id when calling DB.Model, or if the pre-check is intentional, keep the
current lookup and add a brief comment explaining why the extra
DB.First(&current, user.Id) is required. Use the User.Update method and the
current/newUser variables to locate the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@relay/channel/ollama/stream_test.go`:
- Around line 19-95: The new tool-call coverage only exercises
ollamaChatHandler, but the streaming path in ollamaStreamHandler has the same
tool-call conversion and finish-reason override logic and is currently untested.
Add a streaming-focused test alongside TestOllamaChatHandlerNonStreamToolCalls
that feeds a streamed Ollama response through ollamaStreamHandler and asserts
the emitted OpenAI output includes the converted tool call, generated
ID/type/function fields, and the ToolCalls finish reason.

In `@relay/channel/task/ali/adaptor.go`:
- Around line 223-248: `firstTaskImage` is preferring `req.Image` before
`req.InputReference`, which can select the wrong source for mixed requests.
Update `firstTaskImage` in the adaptor to check `req.InputReference` first, then
fall back to non-empty entries in `req.Images`, and only use `req.Image` last so
it stays consistent with `ValidateMultipartDirect` and the `secondTaskImage`
helper logic.
- Around line 250-291: normalizeWan27I2VInput currently accepts any non-empty
Input.Media, but WAN2.7 i2v must include a first_frame. Update this function to
validate aliReq.Input.Media after normalization and reject requests that only
contain last_frame or driving_audio without any first_frame. Keep the existing
media-building logic and the legacy-field cleanup, but make the final validation
explicitly require a first_frame entry before returning nil.

---

Outside diff comments:
In `@controller/user.go`:
- Around line 696-746: The `sidebar_modules` and `language` branches in the user
settings update flow duplicate the same read-modify-write logic. Extract the
repeated fetch via `model.GetUserById`, mutate `user.GetSetting()`, and persist
with `model.UpdateUserSetting` into a small helper (for example, a function used
by this handler) so both cases reuse the same path and only differ in the field
mutation.
- Around line 691-746: The user settings update paths in controller/user.go
still read the full setting blob via GetUserById/GetSetting and then overwrite
it with UpdateUserSetting, which can clobber concurrent changes. Update the
sidebar_modules and language branches so they only patch the modified key, or
add merge/optimistic-locking behavior inside model.UpdateUserSetting so
unchanged setting fields are preserved.

In `@model/user.go`:
- Around line 544-565: The Update method in User loads a full current record
only to pass it into DB.Model, which adds an unnecessary SELECT. Simplify the
anchoring in Update by using a lightweight User instance with the existing Id
when calling DB.Model, or if the pre-check is intentional, keep the current
lookup and add a brief comment explaining why the extra DB.First(&current,
user.Id) is required. Use the User.Update method and the current/newUser
variables to locate the change.

In `@relay/channel/ollama/stream.go`:
- Around line 145-157: The Ollama thinking decode logic is duplicated across the
streaming and non-streaming paths, so extract the trim/unmarshal/fallback
behavior into a shared helper like decodeOllamaThinking and use it from the
chunk handling in stream.go; keep the helper responsible only for turning
chunk.Message.Thinking into the final string, and have each call site write that
result into delta.Choices[0].Delta.SetReasoningContent or the equivalent
non-stream target.

In `@relay/common/relay_utils.go`:
- Around line 253-256: The single-image normalization in the `req.Images`
fallback is inconsistent with `ValidateMultipartDirect` because it copies
`req.Image` without trimming first. Update the `req.Images` assignment in the
`relay_utils` normalization path to use the same `strings.TrimSpace` behavior as
`ValidateMultipartDirect`, so `req.Image` is trimmed before being wrapped into
the slice.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c5ef4535-8758-4734-b901-1ac07e74e1ee

📥 Commits

Reviewing files that changed from the base of the PR and between 9c40740 and b1dc9c5.

📒 Files selected for processing (20)
  • .agents/upstream-sync/new-api-sync.md
  • controller/subscription.go
  • controller/user.go
  • main.go
  • model/log.go
  • model/user.go
  • model/user_cache.go
  • model/user_update_test.go
  • relay/channel/ollama/stream.go
  • relay/channel/ollama/stream_test.go
  • relay/channel/task/ali/adaptor.go
  • relay/channel/task/ali/adaptor_wan27_test.go
  • relay/channel/task/ali/constants.go
  • relay/channel/task/taskcommon/path_config_test.go
  • relay/channel/task/taskcommon/protocol_config.go
  • relay/common/relay_utils.go
  • relay/common/relay_utils_test.go
  • router/api-router.go
  • tools/jsonwrapcheck/allowlist.txt
  • web/default/src/routes/_authenticated/route.tsx
💤 Files with no reviewable changes (1)
  • tools/jsonwrapcheck/allowlist.txt
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Backend checks
🧰 Additional context used
📓 Path-based instructions (5)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrappers in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly calling encoding/json; encoding/json types like json.RawMessage and json.Number may still be used as types.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+ simultaneously: prefer GORM methods over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use cross-DB quoting/boolean helpers when raw SQL is unavoidable, avoid DB-specific functions/operators without fallbacks, and ensure migrations work on all three databases.
For request structs parsed from client JSON and later re-marshaled to upstream providers, especially in relay/convert paths, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved and omitted-only fields remain nil.

**/*.go: Use common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, and common.GetJsonType from common/json.go for all JSON marshal/unmarshal operations; do not directly call encoding/json in business code.
Keep all database code fully compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless cross-DB-safe, and use the provided DB-specific helpers/flags for quoting, booleans, and branching.
For request structs parsed from client JSON and re-marshaled to upstream providers, especially in relay/convert paths, use pointer types with omitempty for optional scalar fields so explicit zero/false values are preserved.

Files:

  • relay/channel/task/ali/constants.go
  • router/api-router.go
  • relay/common/relay_utils.go
  • relay/common/relay_utils_test.go
  • relay/channel/ollama/stream_test.go
  • controller/subscription.go
  • model/user_update_test.go
  • main.go
  • model/log.go
  • relay/channel/task/taskcommon/path_config_test.go
  • relay/channel/task/taskcommon/protocol_config.go
  • relay/channel/task/ali/adaptor_wan27_test.go
  • model/user.go
  • model/user_cache.go
  • relay/channel/ollama/stream.go
  • relay/channel/task/ali/adaptor.go
  • controller/user.go
relay/channel/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.

When implementing a new channel, confirm whether the provider supports StreamOptions; if it does, add the channel to streamSupportedChannels.

Files:

  • relay/channel/task/ali/constants.go
  • relay/channel/ollama/stream_test.go
  • relay/channel/task/taskcommon/path_config_test.go
  • relay/channel/task/taskcommon/protocol_config.go
  • relay/channel/task/ali/adaptor_wan27_test.go
  • relay/channel/ollama/stream.go
  • relay/channel/task/ali/adaptor.go
web/default/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/default/AGENTS.md)

web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用 useTranslation() 取得 t,并通过 t() 渲染用户可见文本;子组件也应自行使用 useTranslation() 保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用 if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用 any,优先使用具体类型或 unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用 import type
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用 props.xxx 以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的 types 中。
在 React 中应合理使用 useMemouseCallbackReact.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态 import
React Query 的数据获取应使用 useQuery、变更应使用 useMutation;每个查询需配置唯一 queryKey,并在成功后对相关查询执行 invalidateQueries;服务端错误应统一交给 handleServerError
Axios 请求应使用项目统一的 api 实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用 handleServerError,展示层应使用 toast.error 等统一方式;文案需走 i18n;路由级错误应由 errorComponent 承接;表单错误应通过 form.setError 等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用 cn() 合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与 dark: 处理。
应使用语义化 HTML、正确关联 label 与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用 aria-hidden="true"
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用 dangerouslySetInnerHTML;跨域与 Cookie 需配合 withCredentials 并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过 .env 读取,并使用 VITE_ 前缀;代码中不得硬编码密钥。

Files:

  • web/default/src/routes/_authenticated/route.tsx
web/default/src/routes/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/default/AGENTS.md)

路由应使用 TanStack Router,并通过 createFileRoute 定义;搜索参数应使用 Zod schema + validateSearch 校验;认证与重定向应放在 beforeLoad 中;导航应优先使用 useNavigateLink,避免直接操作 window.location

Files:

  • web/default/src/routes/_authenticated/route.tsx
web/default/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

Use bun as the preferred package manager and script runner for the frontend in web/default/ (bun install, bun run dev, bun run build, and bun run i18n:*).

Files:

  • web/default/src/routes/_authenticated/route.tsx
🪛 Betterleaks (1.6.0)
.agents/upstream-sync/new-api-sync.md

[high] 12-12: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 LanguageTool
.agents/upstream-sync/new-api-sync.md

[grammar] ~55-~55: Use a hyphen to join words.
Context: ...unters; add critical rate limit for self update. | ported | Added `UpdateUserSett...

(QB_NEW_EN_HYPHEN)

🪛 markdownlint-cli2 (0.22.1)
.agents/upstream-sync/new-api-sync.md

[warning] 55-55: Spaces inside code span elements

(MD038, no-space-in-code)


[warning] 55-55: Spaces inside code span elements

(MD038, no-space-in-code)


[warning] 55-55: Table column count
Expected: 7; Actual: 8; Too many cells, extra data will be missing

(MD056, table-column-count)

🔇 Additional comments (24)
.agents/upstream-sync/new-api-sync.md (2)

55-55: 📐 Maintainability & Code Quality | ⚡ Quick win

Escape the regex pipe in the verification cell.

The | inside the go test regex is being parsed as another table column, which breaks the Markdown table layout.

Fix
-| `go test ./model -run "TestUserUpdateDoesNotOverwriteAccountingFields|TestUpdateUserSettingOnlyUpdatesSetting"`; broader focused Go test set; `go run ./tools/jsonwrapcheck`; `git diff --check`. | Preserves explicit quota mutation paths and token/cache invalidation logic.
+| `go test ./model -run "TestUserUpdateDoesNotOverwriteAccountingFields\|TestUpdateUserSettingOnlyUpdatesSetting"`; broader focused Go test set; `go run ./tools/jsonwrapcheck`; `git diff --check`. | Preserves explicit quota mutation paths and token/cache invalidation logic.

Source: Linters/SAST tools


9-13: 📐 Maintainability & Code Quality | ⚡ Quick win

Keep the reviewed baseline and queue in sync.

917a2cff... is now recorded as the last reviewed commit, but the queue still lists a pending entry that includes 917a2cff. That makes the sync log internally inconsistent and leaves the next incremental pass ambiguous.

Please confirm whether this range should stop before 917a2cff or whether the baseline should remain on the prior commit.

Also applies to: 58-58

web/default/src/routes/_authenticated/route.tsx (1)

41-57: LGTM!

relay/channel/task/taskcommon/protocol_config.go (1)

37-59: LGTM!

Also applies to: 81-81

relay/channel/task/taskcommon/path_config_test.go (1)

299-327: LGTM!

router/api-router.go (1)

86-86: LGTM!

relay/channel/ollama/stream.go (2)

45-72: LGTM!


202-331: LGTM!

relay/common/relay_utils_test.go (1)

14-33: LGTM!

relay/channel/task/ali/adaptor.go (2)

209-217: LGTM!


422-511: LGTM! The rest of convertToAliRequest's integration with firstTaskImage and normalizeWan27I2VInput matches the added test coverage.

relay/channel/task/ali/constants.go (1)

3-13: LGTM!

relay/channel/task/ali/adaptor_wan27_test.go (1)

1-131: LGTM! Good coverage of the new WAN2.7 media-building, legacy-field-clearing, explicit-metadata-media, and error-path behaviors.

relay/common/relay_utils.go (1)

174-178: 🗄️ Data Integrity & Integration

No precedence bug here. firstTaskImage() already prefers req.Image, so a request with both image and input_reference has a consistent winner in the WAN2.7 path.

			> Likely an incorrect or invalid review comment.
controller/subscription.go (1)

89-95: LGTM! Consistent with the new model.UpdateUserSetting persistence pattern used elsewhere. Note the same read-modify-write-whole-blob caveat flagged in controller/user.go (UpdateSelf) applies here too, since current := user.GetSetting() is read once and the full struct is written back.

controller/user.go (3)

3-5: LGTM!

Also applies to: 38-38, 182-182, 565-565, 603-603, 876-876, 927-927


691-694: LGTM!

Also applies to: 749-758


1341-1341: LGTM! Persisting only the setting column via model.UpdateUserSetting correctly avoids clobbering other columns (e.g. quota) compared to the previous SetSetting+Update(false) pattern.

model/user.go (1)

82-116: LGTM!

Also applies to: 170-170

model/user_update_test.go (1)

1-92: LGTM! Good regression coverage for the accounting-field-preservation fix.

model/user_cache.go (2)

67-77: LGTM!

Also applies to: 109-109, 246-252


79-100: 🩺 Stability & Availability

Role changes already invalidate the user cache

user.Update(false) callers don’t persist Role, and the promote/demote path clears both InvalidateUserCache and InvalidateUserTokensCache after saving, so updateUserRoleCache isn’t needed here.

			> Likely an incorrect or invalid review comment.
model/log.go (2)

15-16: LGTM!


528-542: 🩺 Stability & Availability

No issue here

LogQuotaData only updates the in-memory quota cache under a mutex; it does not do external I/O or background work, so calling it inline here should not add meaningful request latency or expose a new panic risk.

			> Likely an incorrect or invalid review comment.

Comment thread relay/channel/ollama/stream_test.go
Comment thread relay/channel/task/ali/adaptor.go
Comment thread relay/channel/task/ali/adaptor.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
relay/common/relay_info.go (1)

740-766: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve nil for duration: null. null is currently decoded into Duration = &0, which drops the optional-field distinction and can re-emit as an explicit duration: 0.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@relay/common/relay_info.go` around lines 740 - 766, Preserve the nil/optional
distinction in TaskSubmitReq.UnmarshalJSON: the current Duration decoding path
treats duration:null as a zero value and assigns a pointer, which can later
serialize as an explicit 0. Update the duration handling in UnmarshalJSON to
detect null before attempting int/string parsing and leave t.Duration unset when
aux.Duration is null; keep the existing parsing behavior for numeric and string
values in TaskSubmitReq.

Source: Coding guidelines

web/default/src/routes/_authenticated/route.tsx (1)

41-61: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Keep cached sessions usable through transient /api/user/self failures — rethrowing every non-401 aborts authenticated navigation and sends users to the global error page during brief backend/network hiccups, even when a cached user is already present. If that fallback is undesirable, treat non-401 failures as non-fatal here instead of exiting beforeLoad.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/default/src/routes/_authenticated/route.tsx` around lines 41 - 61, The
authenticated route’s beforeLoad logic is treating every non-401 getSelf()
failure as fatal, which breaks navigation when a cached session is still valid.
Update the getSelf()/res handling in the route component to only redirect/reset
auth on an actual 401, and treat transient non-401 errors as non-fatal by
falling back to the existing cached user instead of throwing. Keep the logic
localized around getSelf(), auth.reset(), auth.setUser(), and the redirect call.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/default/src/features/channels/lib/channel-form.ts`:
- Around line 452-459: The channel defaults in getChannelTypeScopedFieldDefaults
use unexplained magic numbers for type checks, so replace the raw 45 and 18
comparisons with named channel-type constants defined alongside the other
channel type symbols in channel-form.ts or the shared channel constants module.
Update the ternary logic in getChannelTypeScopedFieldDefaults to reference those
constants so the base_url and other defaults remain unchanged but the mapping is
self-documenting and easier to maintain.

---

Outside diff comments:
In `@relay/common/relay_info.go`:
- Around line 740-766: Preserve the nil/optional distinction in
TaskSubmitReq.UnmarshalJSON: the current Duration decoding path treats
duration:null as a zero value and assigns a pointer, which can later serialize
as an explicit 0. Update the duration handling in UnmarshalJSON to detect null
before attempting int/string parsing and leave t.Duration unset when
aux.Duration is null; keep the existing parsing behavior for numeric and string
values in TaskSubmitReq.

In `@web/default/src/routes/_authenticated/route.tsx`:
- Around line 41-61: The authenticated route’s beforeLoad logic is treating
every non-401 getSelf() failure as fatal, which breaks navigation when a cached
session is still valid. Update the getSelf()/res handling in the route component
to only redirect/reset auth on an actual 401, and treat transient non-401 errors
as non-fatal by falling back to the existing cached user instead of throwing.
Keep the logic localized around getSelf(), auth.reset(), auth.setUser(), and the
redirect call.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 79864c9c-2d8d-4050-a2c3-cbcadd1cd23b

📥 Commits

Reviewing files that changed from the base of the PR and between 410ebcc and 46790cb.

📒 Files selected for processing (55)
  • .agents/skills/classic-to-default-sync/SKILL.md
  • .agents/skills/i18n-translate/SKILL.md
  • .agents/skills/shadcn-ui/SKILL.md
  • .agents/skills/shadcn-ui/vendor/shadcn/SKILL.md
  • .agents/skills/shadcn-ui/vendor/shadcn/UPSTREAM.txt
  • .agents/skills/shadcn-ui/vendor/shadcn/cli.md
  • .agents/skills/shadcn-ui/vendor/shadcn/customization.md
  • .agents/skills/shadcn-ui/vendor/shadcn/mcp.md
  • .agents/skills/shadcn-ui/vendor/shadcn/rules/base-vs-radix.md
  • .agents/skills/shadcn-ui/vendor/shadcn/rules/composition.md
  • .agents/skills/shadcn-ui/vendor/shadcn/rules/forms.md
  • .agents/skills/shadcn-ui/vendor/shadcn/rules/icons.md
  • .agents/skills/shadcn-ui/vendor/shadcn/rules/styling.md
  • .agents/skills/vercel-react-best-practices/AGENTS.md
  • .agents/upstream-sync/new-api-sync.md
  • .gitignore
  • AGENTS.md
  • CLAUDE.md
  • controller/user.go
  • main.go
  • model/user.go
  • model/user_update_test.go
  • relay/channel/task/ali/adaptor.go
  • relay/channel/task/ali/adaptor_wan27_test.go
  • relay/channel/task/doubao/adaptor.go
  • relay/channel/task/gemini/adaptor.go
  • relay/channel/task/gemini/billing.go
  • relay/channel/task/hailuo/adaptor.go
  • relay/channel/task/jimeng/adaptor.go
  • relay/channel/task/kling/adaptor.go
  • relay/channel/task/sora/adaptor.go
  • relay/channel/task/taskcommon/generic_billing.go
  • relay/channel/task/taskcommon/generic_billing_test.go
  • relay/channel/task/taskcommon/request_body.go
  • relay/channel/task/taskcommon/request_body_test.go
  • relay/channel/task/vertex/adaptor.go
  • relay/channel/task/vidu/adaptor.go
  • relay/common/relay_info.go
  • relay/common/relay_info_test.go
  • relay/common/relay_utils.go
  • relay/common/relay_utils_test.go
  • service/convert.go
  • service/convert_test.go
  • tools/jsonwrapcheck/allowlist.txt
  • web/default/src/features/channels/components/drawers/channel-mutate-drawer.tsx
  • web/default/src/features/channels/lib/channel-form.ts
  • web/default/src/features/playground/index.tsx
  • web/default/src/i18n/locales/en.json
  • web/default/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/ja.json
  • web/default/src/i18n/locales/ru.json
  • web/default/src/i18n/locales/vi.json
  • web/default/src/i18n/locales/zh.json
  • web/default/src/routes/_authenticated/route.tsx
  • web/default/tests/channel-form.test.ts
💤 Files with no reviewable changes (17)
  • .agents/skills/shadcn-ui/vendor/shadcn/UPSTREAM.txt
  • .agents/skills/shadcn-ui/vendor/shadcn/rules/icons.md
  • .agents/skills/shadcn-ui/vendor/shadcn/customization.md
  • .gitignore
  • .agents/skills/i18n-translate/SKILL.md
  • .agents/skills/shadcn-ui/vendor/shadcn/SKILL.md
  • .agents/skills/shadcn-ui/vendor/shadcn/mcp.md
  • .agents/skills/classic-to-default-sync/SKILL.md
  • .agents/skills/shadcn-ui/SKILL.md
  • .agents/skills/shadcn-ui/vendor/shadcn/rules/base-vs-radix.md
  • .agents/skills/shadcn-ui/vendor/shadcn/rules/forms.md
  • .agents/skills/shadcn-ui/vendor/shadcn/cli.md
  • .agents/skills/shadcn-ui/vendor/shadcn/rules/composition.md
  • .agents/skills/vercel-react-best-practices/AGENTS.md
  • .agents/skills/shadcn-ui/vendor/shadcn/rules/styling.md
  • tools/jsonwrapcheck/allowlist.txt
  • .agents/upstream-sync/new-api-sync.md
📜 Review details
🧰 Additional context used
📓 Path-based instructions (10)
web/default/**/*.{json,ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

In web/default/, use bun as the preferred package manager and script runner (bun install, bun run dev, bun run build, bun run i18n:*).

Files:

  • web/default/tests/channel-form.test.ts
  • web/default/src/i18n/locales/ru.json
  • web/default/src/features/channels/lib/channel-form.ts
  • web/default/src/i18n/locales/zh.json
  • web/default/src/i18n/locales/en.json
  • web/default/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/vi.json
  • web/default/src/i18n/locales/ja.json
  • web/default/src/features/playground/index.tsx
  • web/default/src/routes/_authenticated/route.tsx
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

Project identity references, branding, metadata, attributions, and protected names related to max-api and MAX API Next must not be modified, deleted, renamed, or replaced anywhere in the repository.

Files:

  • web/default/tests/channel-form.test.ts
  • CLAUDE.md
  • AGENTS.md
  • relay/common/relay_info_test.go
  • web/default/src/i18n/locales/ru.json
  • web/default/src/features/channels/lib/channel-form.ts
  • relay/channel/task/vertex/adaptor.go
  • relay/channel/task/gemini/billing.go
  • web/default/src/i18n/locales/zh.json
  • web/default/src/i18n/locales/en.json
  • relay/channel/task/gemini/adaptor.go
  • web/default/src/i18n/locales/fr.json
  • relay/channel/task/sora/adaptor.go
  • relay/channel/task/taskcommon/request_body_test.go
  • web/default/src/i18n/locales/vi.json
  • relay/channel/task/jimeng/adaptor.go
  • web/default/src/i18n/locales/ja.json
  • service/convert_test.go
  • web/default/src/features/playground/index.tsx
  • relay/channel/task/kling/adaptor.go
  • relay/common/relay_utils_test.go
  • relay/common/relay_utils.go
  • relay/channel/task/taskcommon/generic_billing_test.go
  • relay/common/relay_info.go
  • main.go
  • relay/channel/task/taskcommon/generic_billing.go
  • service/convert.go
  • web/default/src/routes/_authenticated/route.tsx
  • model/user_update_test.go
  • relay/channel/task/ali/adaptor_wan27_test.go
  • model/user.go
  • relay/channel/task/taskcommon/request_body.go
  • relay/channel/task/hailuo/adaptor.go
  • relay/channel/task/vidu/adaptor.go
  • relay/channel/task/doubao/adaptor.go
  • relay/channel/task/ali/adaptor.go
  • controller/user.go
**/*.{go,md}

📄 CodeRabbit inference engine (CLAUDE.md)

When working on tiered/dynamic billing (expression-based pricing), read and follow pkg/billingexpr/expr.md before changing the expression system.

Files:

  • CLAUDE.md
  • AGENTS.md
  • relay/common/relay_info_test.go
  • relay/channel/task/vertex/adaptor.go
  • relay/channel/task/gemini/billing.go
  • relay/channel/task/gemini/adaptor.go
  • relay/channel/task/sora/adaptor.go
  • relay/channel/task/taskcommon/request_body_test.go
  • relay/channel/task/jimeng/adaptor.go
  • service/convert_test.go
  • relay/channel/task/kling/adaptor.go
  • relay/common/relay_utils_test.go
  • relay/common/relay_utils.go
  • relay/channel/task/taskcommon/generic_billing_test.go
  • relay/common/relay_info.go
  • main.go
  • relay/channel/task/taskcommon/generic_billing.go
  • service/convert.go
  • model/user_update_test.go
  • relay/channel/task/ali/adaptor_wan27_test.go
  • model/user.go
  • relay/channel/task/taskcommon/request_body.go
  • relay/channel/task/hailuo/adaptor.go
  • relay/channel/task/vidu/adaptor.go
  • relay/channel/task/doubao/adaptor.go
  • relay/channel/task/ali/adaptor.go
  • controller/user.go
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType); do not directly call encoding/json for marshal/unmarshal logic.
All database code must be fully compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions, avoid direct AUTO_INCREMENT/SERIAL, and ensure any raw SQL or migrations use the project’s cross-DB helpers and fallbacks.

Files:

  • relay/common/relay_info_test.go
  • relay/channel/task/vertex/adaptor.go
  • relay/channel/task/gemini/billing.go
  • relay/channel/task/gemini/adaptor.go
  • relay/channel/task/sora/adaptor.go
  • relay/channel/task/taskcommon/request_body_test.go
  • relay/channel/task/jimeng/adaptor.go
  • service/convert_test.go
  • relay/channel/task/kling/adaptor.go
  • relay/common/relay_utils_test.go
  • relay/common/relay_utils.go
  • relay/channel/task/taskcommon/generic_billing_test.go
  • relay/common/relay_info.go
  • main.go
  • relay/channel/task/taskcommon/generic_billing.go
  • service/convert.go
  • model/user_update_test.go
  • relay/channel/task/ali/adaptor_wan27_test.go
  • model/user.go
  • relay/channel/task/taskcommon/request_body.go
  • relay/channel/task/hailuo/adaptor.go
  • relay/channel/task/vidu/adaptor.go
  • relay/channel/task/doubao/adaptor.go
  • relay/channel/task/ali/adaptor.go
  • controller/user.go
{dto,relay}/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved.

Files:

  • relay/common/relay_info_test.go
  • relay/channel/task/vertex/adaptor.go
  • relay/channel/task/gemini/billing.go
  • relay/channel/task/gemini/adaptor.go
  • relay/channel/task/sora/adaptor.go
  • relay/channel/task/taskcommon/request_body_test.go
  • relay/channel/task/jimeng/adaptor.go
  • relay/channel/task/kling/adaptor.go
  • relay/common/relay_utils_test.go
  • relay/common/relay_utils.go
  • relay/channel/task/taskcommon/generic_billing_test.go
  • relay/common/relay_info.go
  • relay/channel/task/taskcommon/generic_billing.go
  • relay/channel/task/ali/adaptor_wan27_test.go
  • relay/channel/task/taskcommon/request_body.go
  • relay/channel/task/hailuo/adaptor.go
  • relay/channel/task/vidu/adaptor.go
  • relay/channel/task/doubao/adaptor.go
  • relay/channel/task/ali/adaptor.go
web/default/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/default/AGENTS.md)

web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用 useTranslation() 取得 t,并通过 t() 渲染用户可见文本;子组件也应自行使用 useTranslation() 保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用 if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用 any,优先使用具体类型或 unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用 import type
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用 props.xxx 以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的 types 中。
在 React 中应合理使用 useMemouseCallbackReact.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态 import
React Query 的数据获取应使用 useQuery、变更应使用 useMutation;每个查询需配置唯一 queryKey,并在成功后对相关查询执行 invalidateQueries;服务端错误应统一交给 handleServerError
Axios 请求应使用项目统一的 api 实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用 handleServerError,展示层应使用 toast.error 等统一方式;文案需走 i18n;路由级错误应由 errorComponent 承接;表单错误应通过 form.setError 等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用 cn() 合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与 dark: 处理。
应使用语义化 HTML、正确关联 label 与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用 aria-hidden="true"
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用 dangerouslySetInnerHTML;跨域与 Cookie 需配合 withCredentials 并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过 .env 读取,并使用 VITE_ 前缀;代码中不得硬编码密钥。

Files:

  • web/default/src/features/channels/lib/channel-form.ts
  • web/default/src/features/playground/index.tsx
  • web/default/src/routes/_authenticated/route.tsx
web/default/src/features/**/lib/**/*.ts

📄 CodeRabbit inference engine (web/default/AGENTS.md)

表单应使用 React Hook Form + Zod:在功能模块的 lib/ 下定义 schema,并用 z.infer 导出表单类型;useForm 应配合 @hookform/resolvers/zod 进行校验。

Files:

  • web/default/src/features/channels/lib/channel-form.ts
web/default/src/features/**

📄 CodeRabbit inference engine (web/default/AGENTS.md)

功能模块应放在 src/features/<feature>/,并按需包含 components/lib/hooks/api.tstypes.tsconstants.ts 等;通用组件应放在 src/components/,通用工具与类型应放在 src/lib/

Files:

  • web/default/src/features/channels/lib/channel-form.ts
  • web/default/src/features/playground/index.tsx
relay/channel/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

When implementing a new channel, confirm whether the provider supports StreamOptions; if it does, add the channel to streamSupportedChannels.

Files:

  • relay/channel/task/vertex/adaptor.go
  • relay/channel/task/gemini/billing.go
  • relay/channel/task/gemini/adaptor.go
  • relay/channel/task/sora/adaptor.go
  • relay/channel/task/taskcommon/request_body_test.go
  • relay/channel/task/jimeng/adaptor.go
  • relay/channel/task/kling/adaptor.go
  • relay/channel/task/taskcommon/generic_billing_test.go
  • relay/channel/task/taskcommon/generic_billing.go
  • relay/channel/task/ali/adaptor_wan27_test.go
  • relay/channel/task/taskcommon/request_body.go
  • relay/channel/task/hailuo/adaptor.go
  • relay/channel/task/vidu/adaptor.go
  • relay/channel/task/doubao/adaptor.go
  • relay/channel/task/ali/adaptor.go
web/default/src/routes/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/default/AGENTS.md)

路由应使用 TanStack Router,并通过 createFileRoute 定义;搜索参数应使用 Zod schema + validateSearch 校验;认证与重定向应放在 beforeLoad 中;导航应优先使用 useNavigateLink,避免直接操作 window.location

Files:

  • web/default/src/routes/_authenticated/route.tsx
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: MAX-API-Next/MAX-API

Timestamp: 2026-07-05T14:56:59.365Z
Learning: Do not modify, delete, replace, or remove protected project information related to `max-api` or `max-api-next` anywhere in the repository, including documentation, metadata, configs, code comments, and package/import paths.
Learnt from: CR
Repo: MAX-API-Next/MAX-API

Timestamp: 2026-07-05T14:56:59.365Z
Learning: All non-project process documents must be created and kept under `.tmp/`; do not place scratch notes, drafts, review outputs, or other internal process material in repository root, `docs/`, `.github/`, or source directories unless they are intended as public documentation.
🔇 Additional comments (38)
web/default/tests/channel-form.test.ts (1)

6-6: LGTM!

Also applies to: 137-151

CLAUDE.md (1)

146-146: LGTM!

AGENTS.md (1)

146-146: LGTM!

web/default/src/features/playground/index.tsx (2)

214-214: LGTM!


155-158: 📐 Maintainability & Code Quality

No i18n sync issue. The new strings are already present in all locale files.

relay/common/relay_utils_test.go (1)

14-54: LGTM!

relay/common/relay_utils.go (1)

131-136: LGTM!

Also applies to: 171-179, 256-256

relay/channel/task/hailuo/adaptor.go (1)

151-156: LGTM!

relay/common/relay_info_test.go (1)

6-6: LGTM!

Also applies to: 42-53

relay/channel/task/taskcommon/request_body_test.go (1)

1-95: LGTM!

service/convert_test.go (1)

39-48: LGTM!

Also applies to: 76-88, 93-122

relay/channel/task/kling/adaptor.go (1)

378-390: LGTM!

relay/channel/task/taskcommon/generic_billing_test.go (1)

163-166: LGTM!

Also applies to: 229-229, 238-238

relay/common/relay_info.go (1)

688-735: LGTM!

relay/channel/task/taskcommon/request_body.go (1)

91-186: LGTM!

Also applies to: 252-262

relay/channel/task/vidu/adaptor.go (1)

233-247: LGTM!

web/default/src/i18n/locales/ru.json (1)

3991-3992: LGTM!

relay/channel/task/vertex/adaptor.go (1)

164-166: LGTM!

relay/channel/task/gemini/billing.go (1)

86-88: LGTM!

web/default/src/i18n/locales/zh.json (1)

3991-3992: LGTM!

relay/channel/task/gemini/adaptor.go (1)

94-96: LGTM!

relay/channel/task/sora/adaptor.go (1)

109-112: LGTM!

web/default/src/i18n/locales/en.json (1)

3991-3992: LGTM!

web/default/src/i18n/locales/fr.json (1)

3991-3992: LGTM!

web/default/src/i18n/locales/ja.json (1)

3991-3992: LGTM!

model/user_update_test.go (1)

1-166: LGTM!

relay/channel/task/ali/adaptor_wan27_test.go (1)

1-223: LGTM!

model/user.go (3)

85-85: LGTM!

Also applies to: 174-174


556-572: 🗄️ Data Integrity & Integration

Cache refresh is safe here. updateUserCache() only refreshes Group, Email, Status, Username, and Setting; Quota is updated separately by the atomic quota-delta paths, so this change does not repopulate stale billing data.

			> Likely an incorrect or invalid review comment.

111-114: 🗄️ Data Integrity & Integration

No issue: ensureUserUpdateMatchedTx already handles noop updates. It falls back to a lookup by user id when RowsAffected == 0, so unchanged MySQL updates won’t be turned into 用户不存在.

			> Likely an incorrect or invalid review comment.
relay/channel/task/doubao/adaptor.go (1)

482-483: LGTM!

controller/user.go (1)

927-927: LGTM!

Also applies to: 1025-1027

web/default/src/i18n/locales/vi.json (1)

3991-3992: LGTM!

relay/channel/task/jimeng/adaptor.go (1)

393-398: LGTM!

main.go (1)

210-242: LGTM!

relay/channel/task/taskcommon/generic_billing.go (1)

123-124: LGTM!

Also applies to: 194-215

service/convert.go (1)

38-38: LGTM!

Also applies to: 53-53, 644-663

relay/channel/task/ali/adaptor.go (1)

196-196: LGTM!

Also applies to: 235-253, 444-533, 551-552

Comment thread web/default/src/features/channels/lib/channel-form.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
main.go (3)

236-238: 🚀 Performance & Scalability | 🔵 Trivial

No fallback when srv.Shutdown fails.

If srv.Shutdown(ctx) returns an error (e.g., timeout), the error is only logged; there's no fallback such as srv.Close() to forcibly terminate remaining connections before proceeding to the quota-cache save and process exit.

♻️ Suggested fallback
 	if err := srv.Shutdown(ctx); err != nil {
 		common.SysError(fmt.Sprintf("server forced to shutdown: %v", err))
+		_ = srv.Close()
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@main.go` around lines 236 - 238, The shutdown path in `srv.Shutdown(ctx)`
only logs failures and then continues, so add a forced fallback in the same
shutdown flow when it returns an error. Update the shutdown handling around
`srv.Shutdown` to attempt `srv.Close()` after logging the shutdown error, then
continue with the existing quota-cache save and exit sequence. Keep the fix
localized to the server shutdown logic so the fallback is triggered only when
graceful shutdown fails.

233-233: 🧹 Nitpick | 🔵 Trivial

Verify deployment grace periods cover the new worst-case shutdown duration.

Default SHUTDOWN_TIMEOUT_SECONDS (120s) plus default QUOTA_DATA_CACHE_SAVE_TIMEOUT_SECONDS (30s) sum to up to 150s of shutdown time. Ensure container/orchestrator termination grace periods (e.g., Kubernetes terminationGracePeriodSeconds) are increased accordingly, otherwise SIGKILL may cut the graceful shutdown short.

Also applies to: 240-240

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@main.go` at line 233, The shutdown path in main.go now allows up to 150s
total by combining shutdownTimeout and QUOTA_DATA_CACHE_SAVE_TIMEOUT_SECONDS, so
update the deployment/orchestrator termination grace period to cover that worst
case. Check the service/container config that governs
terminationGracePeriodSeconds or equivalent and raise it accordingly so the
graceful shutdown in the main shutdown flow and cache save can finish before
SIGKILL.

236-264: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Async quota-cache save can race with the deferred CloseDB() on timeout.

When runWithTimeout(saveTimeout, model.SaveQuotaDataCache) times out, the spawned goroutine keeps executing model.SaveQuotaDataCache in the background after runWithTimeout returns false. main() then proceeds to "server exited" and returns, which triggers the deferred model.CloseDB() (registered near the top of main()). This creates a race: the leaked goroutine may still be writing to the database pool concurrently with (or after) it being closed, risking failed writes or noisy errors during shutdown.

Consider either: not closing the DB until the save goroutine truly completes (e.g., track completion via a shared sync.WaitGroup/channel that CloseDB waits on), or accepting the timeout but skipping/cancelling the save via a context-aware SaveQuotaDataCache variant instead of leaving it to run detached.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@main.go` around lines 236 - 264, The detached timeout wrapper in
runWithTimeout can leave model.SaveQuotaDataCache running after main() has moved
on to the deferred model.CloseDB(), creating a shutdown race. Update the
shutdown flow around runWithTimeout and model.SaveQuotaDataCache so the DB is
not closed until the save work is definitely finished, or make the save
cancellable/stop on timeout instead of continuing in the background. Use the
existing runWithTimeout, SaveQuotaDataCache, and CloseDB symbols to coordinate
completion before logging "server exited".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@relay/common/relay_utils.go`:
- Around line 175-179: Trim req.InputReference before using it to populate
req.Images in the relay utility logic, because the current check in the Images
assignment path can treat whitespace-only input_reference as a valid image and
produce an empty entry. Update the conditional around the existing
req.InputReference / req.Image fallback so it only assigns to Images when the
trimmed value is non-empty, matching the behavior already used for the image
fallback branch and preserving correct HasImage() behavior.

---

Outside diff comments:
In `@main.go`:
- Around line 236-238: The shutdown path in `srv.Shutdown(ctx)` only logs
failures and then continues, so add a forced fallback in the same shutdown flow
when it returns an error. Update the shutdown handling around `srv.Shutdown` to
attempt `srv.Close()` after logging the shutdown error, then continue with the
existing quota-cache save and exit sequence. Keep the fix localized to the
server shutdown logic so the fallback is triggered only when graceful shutdown
fails.
- Line 233: The shutdown path in main.go now allows up to 150s total by
combining shutdownTimeout and QUOTA_DATA_CACHE_SAVE_TIMEOUT_SECONDS, so update
the deployment/orchestrator termination grace period to cover that worst case.
Check the service/container config that governs terminationGracePeriodSeconds or
equivalent and raise it accordingly so the graceful shutdown in the main
shutdown flow and cache save can finish before SIGKILL.
- Around line 236-264: The detached timeout wrapper in runWithTimeout can leave
model.SaveQuotaDataCache running after main() has moved on to the deferred
model.CloseDB(), creating a shutdown race. Update the shutdown flow around
runWithTimeout and model.SaveQuotaDataCache so the DB is not closed until the
save work is definitely finished, or make the save cancellable/stop on timeout
instead of continuing in the background. Use the existing runWithTimeout,
SaveQuotaDataCache, and CloseDB symbols to coordinate completion before logging
"server exited".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 920beb58-eef8-4f1a-b79b-fe0acbc48fc2

📥 Commits

Reviewing files that changed from the base of the PR and between 46790cb and 6b9969f.

📒 Files selected for processing (14)
  • main.go
  • main_test.go
  • relay/channel/ollama/stream.go
  • relay/common/relay_utils.go
  • relay/common/relay_utils_test.go
  • web/default/src/features/channels/components/drawers/channel-mutate-drawer.tsx
  • web/default/src/features/channels/constants.ts
  • web/default/src/features/channels/lib/channel-form.ts
  • web/default/src/i18n/locales/en.json
  • web/default/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/ja.json
  • web/default/src/i18n/locales/ru.json
  • web/default/src/i18n/locales/vi.json
  • web/default/src/i18n/locales/zh.json
📜 Review details
🧰 Additional context used
📓 Path-based instructions (7)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: All JSON marshal/unmarshal operations in business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType); do not directly call encoding/json there.
Database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions, avoid raw SQL unless cross-database handling is included, use shared reserved-word/boolean helpers, avoid database-specific functions/operators/types without fallback, and ensure migrations work on all three databases.
For request structs parsed from client JSON and re-marshaled to upstream providers, especially in relay/convert paths, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved.

**/*.go: All JSON marshal/unmarshal operations in business code must use the wrappers in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json.
Use GORM abstractions (Create, Find, Where, Updates, etc.) instead of raw SQL wherever possible, and let GORM handle primary key generation rather than using AUTO_INCREMENT or SERIAL directly.
When raw SQL is unavoidable, use database-specific column quoting and the shared helpers/flags (commonGroupCol, commonKeyCol, common.UsingPostgreSQL, common.UsingSQLite, common.UsingMySQL) to keep the SQL compatible across PostgreSQL, MySQL, and SQLite.
Do not use database-specific SQL features without a cross-DB fallback: avoid MySQL-only functions, PostgreSQL-only operators/JSONB features, SQLite-incompatible ALTER COLUMN, and database-specific column types without fallback.
Request structs parsed from client JSON and re-marshaled to upstream providers (especially in relay/convert paths) must use pointer fields with omitempty for optional scalars so explicit zero/false v...

Files:

  • main_test.go
  • relay/common/relay_utils_test.go
  • main.go
  • relay/common/relay_utils.go
  • relay/channel/ollama/stream.go
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

Do not modify, delete, replace, or remove protected project identifiers and references related to max-api or MAX API Next anywhere in the repository.

Files:

  • main_test.go
  • web/default/src/i18n/locales/en.json
  • web/default/src/features/channels/constants.ts
  • web/default/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/ja.json
  • web/default/src/features/channels/lib/channel-form.ts
  • web/default/src/i18n/locales/ru.json
  • web/default/src/i18n/locales/zh.json
  • relay/common/relay_utils_test.go
  • main.go
  • relay/common/relay_utils.go
  • web/default/src/i18n/locales/vi.json
  • relay/channel/ollama/stream.go
web/default/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/default/AGENTS.md)

web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用 useTranslation() 取得 t,并通过 t() 渲染用户可见文本;子组件也应自行使用 useTranslation() 保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用 if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用 any,优先使用具体类型或 unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用 import type
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用 props.xxx 以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的 types 中。
在 React 中应合理使用 useMemouseCallbackReact.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态 import
React Query 的数据获取应使用 useQuery、变更应使用 useMutation;每个查询需配置唯一 queryKey,并在成功后对相关查询执行 invalidateQueries;服务端错误应统一交给 handleServerError
Axios 请求应使用项目统一的 api 实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用 handleServerError,展示层应使用 toast.error 等统一方式;文案需走 i18n;路由级错误应由 errorComponent 承接;表单错误应通过 form.setError 等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用 cn() 合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与 dark: 处理。
应使用语义化 HTML、正确关联 label 与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用 aria-hidden="true"
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用 dangerouslySetInnerHTML;跨域与 Cookie 需配合 withCredentials 并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过 .env 读取,并使用 VITE_ 前缀;代码中不得硬编码密钥。

Files:

  • web/default/src/features/channels/constants.ts
  • web/default/src/features/channels/lib/channel-form.ts
web/default/src/features/**/constants.ts

📄 CodeRabbit inference engine (web/default/AGENTS.md)

各 feature 的 constants.ts 中,成功/错误/提示类消息常量应仅保存 i18n 键,展示时必须通过 t() 渲染;状态/选项的 label 应统一使用 labelKeylabel(二选一且同一 feature 内保持一致);新增此类常量时应同步登记翻译键。

Files:

  • web/default/src/features/channels/constants.ts
web/default/src/features/**

📄 CodeRabbit inference engine (web/default/AGENTS.md)

功能模块应放在 src/features/<feature>/,并按需包含 components/lib/hooks/api.tstypes.tsconstants.ts 等;通用组件应放在 src/components/,通用工具与类型应放在 src/lib/

Files:

  • web/default/src/features/channels/constants.ts
  • web/default/src/features/channels/lib/channel-form.ts
web/default/src/features/**/lib/**/*.ts

📄 CodeRabbit inference engine (web/default/AGENTS.md)

表单应使用 React Hook Form + Zod:在功能模块的 lib/ 下定义 schema,并用 z.infer 导出表单类型;useForm 应配合 @hookform/resolvers/zod 进行校验。

Files:

  • web/default/src/features/channels/lib/channel-form.ts
relay/channel/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

When implementing a new channel, confirm whether the provider supports StreamOptions; if it does, add the channel to streamSupportedChannels.

When implementing a new channel, verify whether the provider supports StreamOptions, and if it does, add the channel to streamSupportedChannels.

Files:

  • relay/channel/ollama/stream.go
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: MAX-API-Next/MAX-API

Timestamp: 2026-07-05T15:35:20.202Z
Learning: Use `bun` as the preferred package manager and script runner for the frontend in `web/default/` (`bun install`, `bun run dev`, `bun run build`, `bun run i18n:*`).
Learnt from: CR
Repo: MAX-API-Next/MAX-API

Timestamp: 2026-07-05T15:35:20.202Z
Learning: Do not modify, delete, replace, or remove protected project information related to `max-api` or `max-api-next`, including references in README files, licenses, metadata, HTML, Go module paths, Docker/CI configs, comments, docs, and changelogs.
Learnt from: CR
Repo: MAX-API-Next/MAX-API

Timestamp: 2026-07-05T15:35:20.202Z
Learning: All non-project process documents must be created and kept under `.tmp/`; local agent workflow files such as `.agents/skills/` and `.agents/upstream-sync/` are private workspace materials and must not be committed to the public repository.
🔇 Additional comments (14)
main_test.go (1)

1-21: LGTM!

web/default/src/i18n/locales/zh.json (1)

951-951: LGTM!

Also applies to: 3991-3992

relay/common/relay_utils_test.go (1)

35-54: LGTM!

web/default/src/i18n/locales/vi.json (1)

951-951: LGTM!

Also applies to: 3991-3992

relay/channel/ollama/stream.go (1)

24-31: LGTM!

Based on learnings, JSON marshal/unmarshal in business code should use common.Marshal/common.Unmarshal wrappers rather than encoding/json directly — this change correctly complies with that requirement.

Also applies to: 202-333

Source: Coding guidelines

main.go (1)

214-224: 🩺 Stability & Availability

No extra return needed after common.FatalLog common.FatalLog calls os.Exit(1), so the net.Listen failure branch already terminates and won't reach srv.Serve(ln).

			> Likely an incorrect or invalid review comment.
web/default/src/i18n/locales/en.json (1)

951-951: LGTM!

Also applies to: 3991-3992

web/default/src/i18n/locales/fr.json (1)

951-951: LGTM!

Also applies to: 3991-3992

web/default/src/features/channels/constants.ts (1)

82-83: 📐 Maintainability & Code Quality

No duplicate channel-type constants
web/default/src/features/channels/lib/channel-form.ts imports CHANNEL_TYPE_XUNFEI and CHANNEL_TYPE_VOLCENGINE from web/default/src/features/channels/constants.ts, so there’s a single source of truth here.

			> Likely an incorrect or invalid review comment.
web/default/src/i18n/locales/ja.json (2)

951-951: LGTM!


3991-3992: LGTM!

web/default/src/features/channels/lib/channel-form.ts (1)

22-23: LGTM!

Also applies to: 454-465

web/default/src/i18n/locales/ru.json (2)

951-951: LGTM!


3991-3992: LGTM!

Comment thread relay/common/relay_utils.go Outdated
@CSCITech
CSCITech merged commit e84c148 into main Jul 5, 2026
3 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Jul 7, 2026
11 tasks
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.

1 participant