Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (4)
📜 Recent review details⏰ Context from checks skipped due to timeout. (1)
🧰 Additional context used📓 Path-based instructions (2)**/*.go📄 CodeRabbit inference engine (CLAUDE.md)
Files:
dto/**/*.go📄 CodeRabbit inference engine (AGENTS.md)
Files:
🔇 Additional comments (5)
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis PR adds saturating quota conversion, normalized-email account handling, quota filtering for logs and tasks, SSRF-protected fetch helpers, task duration and image bounds validation, stream shutdown hardening, and option/group-ratio normalization. ChangesQuota Rounding and Saturation
Estimated code review effort: 5 (Critical) | ~90 minutes SSRF Protected Fetch Client
Estimated code review effort: 4 (Complex) | ~50 minutes User Email Normalization and Auth Flows
Estimated code review effort: 5 (Critical) | ~100 minutes Log and Task Quota Filter Feature
Estimated code review effort: 4 (Complex) | ~75 minutes Task Duration Bounds
Estimated code review effort: 3 (Moderate) | ~40 minutes Streaming and Ping Shutdown Robustness
Estimated code review effort: 4 (Complex) | ~60 minutes Image Count and Token Bounds
Estimated code review effort: 3 (Moderate) | ~35 minutes Option and Group Ratio Normalization
Estimated code review effort: 3 (Moderate) | ~30 minutes Minor Updates
Estimated code review effort: 2 (Simple) | ~15 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant UserController
participant UserModel
participant DB
Client->>UserController: register / email bind / reset password
UserController->>UserModel: NormalizeEmail(email)
UserController->>UserModel: EnsureEmailAvailable(email)
UserModel-->>UserController: available or ErrEmailAlreadyTaken
alt email available
UserController->>DB: WithNormalizedEmailWriteTx(...)
DB-->>UserController: success
else email taken
UserController-->>Client: localized email-taken error
end
sequenceDiagram
participant HTTPClient
participant ProtectedFetchDialer
participant SSRFProtection
participant Resolver
HTTPClient->>ProtectedFetchDialer: DialContext(host, port)
ProtectedFetchDialer->>SSRFProtection: getCachedSSRFProtection()
SSRFProtection-->>ProtectedFetchDialer: config
ProtectedFetchDialer->>Resolver: resolve host
Resolver-->>ProtectedFetchDialer: candidate IPs
ProtectedFetchDialer->>SSRFProtection: ValidateNetworkTarget / ValidateResolvedIP
SSRFProtection-->>ProtectedFetchDialer: allow or block
ProtectedFetchDialer-->>HTTPClient: connection or error
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 12
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
web/default/src/features/usage-logs/lib/utils.ts (1)
207-235: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDuplicate quota_filter inclusion logic.
The
quota_filterconditional inclusion (searchParams.quotaFilter && searchParams.quotaFilter !== QUOTA_FILTER_ALL_VALUE ? { quota_filter: ... } : {}) is duplicated verbatim in bothbuildBaseParamsandbuildApiParams. Consider extracting a small shared helper (e.g.buildQuotaFilterParam(searchParams)) to avoid drift if the exclusion logic changes later.♻️ Proposed refactor
+function buildQuotaFilterParam(searchParams: Record<string, unknown>) { + return searchParams.quotaFilter && + searchParams.quotaFilter !== QUOTA_FILTER_ALL_VALUE + ? { quota_filter: String(searchParams.quotaFilter) } + : {} +}Then use
...buildQuotaFilterParam(searchParams)in both functions.Also applies to: 241-317
🤖 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/features/usage-logs/lib/utils.ts` around lines 207 - 235, The quota_filter inclusion logic is duplicated in buildBaseParams and buildApiParams, so extract the shared conditional into a small helper like buildQuotaFilterParam(searchParams) and reuse it from both functions. Keep the existing QUOTA_FILTER_ALL_VALUE exclusion behavior centralized in that helper, then spread its result alongside the other params in buildBaseParams and buildApiParams to prevent future drift.relay/channel/openai/helper.go (1)
205-210: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winPropagate
ResponseChunkDatafailures fromsendResponsesStreamData
relay/channel/openai/helper.godrops the write error, andrelay/channel/openai/relay_responses.goignores that return in both the pending-flush and live-forward paths. Return the error and stop the stream on failure so client disconnects can end the loop and recordStreamEndReasonClientGone, as the other stream handlers do.🤖 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/openai/helper.go` around lines 205 - 210, The stream write error is being discarded in sendResponsesStreamData, which prevents relay_responses.go from reacting to client disconnects. Update sendResponsesStreamData to return the error from helper.ResponseChunkData instead of ignoring it, then handle that return in both the pending-flush and live-forward paths in relay_responses.go by breaking out of the stream loop and recording StreamEndReasonClientGone when a write fails.relay/channel/openai/relay_image.go (1)
128-138: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winPropagate write errors from
writeOpenaiImageStreamChunkUnlike
writeOpenaiImageStreamPayload, this helper dropsResponseChunkData/StringDatafailures, so an immediate client write error can’t stop the stream viasr.Stop(err). Thread the error back to the callback/caller if this path should abort on write failure.🤖 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/openai/relay_image.go` around lines 128 - 138, The writeOpenaiImageStreamChunk helper is ignoring write failures from ResponseChunkData and StringData, so stream errors cannot be propagated back to stop the session. Update writeOpenaiImageStreamChunk to return an error (or otherwise surface the helper result) and have the caller/callback handle it by stopping the stream via sr.Stop(err) when a client write fails; use the existing writeOpenaiImageStreamPayload flow as the reference for how errors should be threaded through.service/tool_billing.go (1)
39-88: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winClamp
TotalQuotabefore returning.totalQuotasums already-saturated per-item quotas, so the aggregate can still overflow before it reaches the 32-bit quota column downstream. Wrap the final total withcommon.QuotaFromFloattoo.🤖 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 `@service/tool_billing.go` around lines 39 - 88, `ComputeToolCallQuota` currently returns `totalQuota` directly, which can still overflow even though each `ToolCallItem` quota is individually clamped. Update the final `ToolCallResult` construction to pass the accumulated total through `common.QuotaFromFloat` before returning, using the existing `totalQuota` calculation and `common.QuotaPerUnit`/`QuotaFromFloat` flow to keep the aggregate within the quota column range.model/user.go (1)
746-796: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Update()/UpdateWithTx()don't enforce email uniqueness — TOCTOU gap vs.Insert/BindEmailToUser.
InsertandBindEmailToUserwrap their check+write inWithNormalizedEmailWriteTx, serializing writers per normalized email.Update(Line 747) callsUpdateWithTx(DB, ...)directly with the plainDBhandle — no lock, andbuildUserUpdateValues(Line 792-796) writesnormalized_emailstraight into the update map with no call toensureEmailAvailableWithTx/EnsureEmailAvailable. The uniqueness check for this path currently lives only in the controller layer (e.g.controller/user.gocallingEnsureEmailAvailablebeforeUpdate), which is a separate, non-atomic query. Two concurrent profile-email updates targeting the same new address can both pass that pre-check and then both write successfully, producing duplicatenormalized_emailrows — undermining the uniqueness guarantee this PR is building.Route email changes in
UpdateWithTxthroughWithNormalizedEmailWriteTxplus an in-txensureEmailAvailableWithTxcheck, mirroringInsert/BindEmailToUser.🤖 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 746 - 796, The email update path in User.Update/User.UpdateWithTx is still vulnerable to a TOCTOU race because it writes email and normalized_email from buildUserUpdateValues without any in-transaction uniqueness check or email write lock. Update UpdateWithTx to route email-changing updates through WithNormalizedEmailWriteTx and call ensureEmailAvailableWithTx before persisting, mirroring Insert and BindEmailToUser so concurrent updates cannot create duplicate normalized_email values.
🤖 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 `@go.mod`:
- Around line 52-57: Update the dependency versions in go.mod so
golang.org/x/crypto is bumped from v0.51.0 to v0.52.0 or newer, while leaving
the unrelated golang.org/x/image entry alone. Make the change in the module
requirements list where golang.org/x/crypto is declared, and ensure the
resulting version still resolves cleanly with the rest of the golang.org/x/*
set.
In `@model/log.go`:
- Around line 113-124: `applyQuotaFilter` introduces `quota`-based predicates
that can trigger full scans on large `logs` queries used by `GetAllLogs`,
`GetUserLogs`, and `SumUsedQuota`; add an index strategy for the `logs.quota`
column, and consider a composite index with `type` and/or `created_at` if those
filters are commonly combined, so the new quota filter path stays efficient.
- Around line 639-644: `GetAllLogs`, `GetUserLogs`, and `SumUsedQuota` have
grown into long positional-parameter APIs with many same-typed string arguments,
making call sites easy to transpose silently. Refactor these entry points to
accept a request/options struct, similar to `TaskQueryParams` in
`model/midjourney.go`, and move the existing filter fields (including
`quotaFilter`) onto that struct. Update the implementations and all call sites
to use the new struct-based parameter object while preserving the current
filtering behavior in `applyLogFilter`, `applyQuotaFilter`, and related query
helpers.
In `@model/task.go`:
- Around line 408-411: Add test coverage for the new quota update path and
filter wiring. Use the existing model test patterns, especially the
`TestLogQuotaFilters` style in `model/log_test.go`, to verify `UpdateQuota`
updates the record scoped by the task primary key and that `QuotaFilter` is
applied as expected. Reference `Task.UpdateQuota` and the `QuotaFilter` setup
when adding the tests so the new behavior stays covered.
In `@model/user.go`:
- Around line 776-856: The update logic in buildUserUpdateValues is inferring
“full user” from CreatedAt, which can cause empty zero-values like Email to be
written back unintentionally and wipe existing data. Replace this heuristic with
an explicit changed-fields mechanism in buildUserUpdateValues, such as
pointer/nullable fields, a dirty-field list, or a proper struct-diff check, and
only set email/normalized_email and other fields when they were actually
intended to change.
In `@pkg/billingexpr/billingexpr_test.go`:
- Around line 295-298: Add a symmetric negative-infinity table entry to the
billing expression conversion tests so coverage matches the existing +Inf case.
Update the test table in billingexpr_test.go near the values used by the
conversion helper to include math.Inf(-1) expecting math.MinInt32, alongside the
existing math.Inf(1) case, to exercise the r <= math.MinInt32 branch
consistently.
In `@relay/channel/ali/image.go`:
- Around line 57-59: The N-bounds check and error message are duplicated between
ImageRequest handling and the request validation helper, so the logic can drift.
Extract the range check into a shared validator such as dto.ValidateImageN and
have both the image relay path and relay/helper/valid_request.go call it,
keeping the cap and message centralized in one place. Use the existing
imageRequest.Parameters.N validation in image.go as the entry point to replace
the inline bounds check with the shared helper.
In `@relay/common/relay_utils.go`:
- Around line 119-128: The duration resolution logic is duplicated in
validateTaskDurationBounds and the Ali request conversion paths, so centralize
it on TaskSubmitReq with a shared helper such as ResolvedSeconds() that applies
the existing Duration-first, Seconds-fallback, and default/clamp behavior.
Update validateTaskDurationBounds and the
convertToAliRequest/convertToAliKlingRequest flow in the Ali adaptor to call
that helper so validation and billing use the same precedence and future changes
stay consistent.
- Around line 119-128: The validation in validateTaskDurationBounds has two
correctness issues: the error text does not match the actual allowed range, and
the strconv.Atoi fallback for req.Seconds ignores conversion failures. Update
the bounds check and the returned createTaskError message so they describe the
same valid range, and change the parsing path in validateTaskDurationBounds to
detect and reject non-numeric Seconds values instead of silently treating them
as 0; use the existing TaskSubmitReq, DurationValue, and createTaskError flow to
keep the behavior consistent.
In `@relay/helper/common.go`:
- Around line 41-43: The stream helper path still assumes a valid gin context,
so ClaudeData, ClaudeChunkData, and ResponseChunkData can panic on nil context
or missing writer even though requestContextDone() treats nil as done. Update
these helpers to match StringData and PingData by returning early when c == nil
or c.Writer == nil before any c.Render or c.Request.Context() access, and keep
the existing requestContextDone() check as the next guard.
In `@setting/ratio_setting/group_ratio.go`:
- Around line 76-82: ContainsGroupRatio and GetGroupRatio are checking the
reserved-name case with a trimmed value but still using the untrimmed name for
groupRatioMap.Get, so whitespace-padded inputs miss existing entries. Update
these functions to normalize/trim the name once up front and use that trimmed
value for both the reserved-name check and the map lookup, matching the key
format produced by normalizeGroupRatioMap.
In `@web/default/src/features/usage-logs/constants.ts`:
- Around line 152-164: QUOTA_FILTER_VALUES and QUOTA_FILTER_SEARCH_VALUES are
duplicated with the same literals, which can drift and make isQuotaFilterValue
and the route zod enum in $section.tsx disagree. Refactor constants.ts so one
array is derived from the other instead of being hand-maintained separately,
keeping the shared quota filter list in sync for all usages such as
isQuotaFilterValue and z.enum(QUOTA_FILTER_SEARCH_VALUES).
---
Outside diff comments:
In `@model/user.go`:
- Around line 746-796: The email update path in User.Update/User.UpdateWithTx is
still vulnerable to a TOCTOU race because it writes email and normalized_email
from buildUserUpdateValues without any in-transaction uniqueness check or email
write lock. Update UpdateWithTx to route email-changing updates through
WithNormalizedEmailWriteTx and call ensureEmailAvailableWithTx before
persisting, mirroring Insert and BindEmailToUser so concurrent updates cannot
create duplicate normalized_email values.
In `@relay/channel/openai/helper.go`:
- Around line 205-210: The stream write error is being discarded in
sendResponsesStreamData, which prevents relay_responses.go from reacting to
client disconnects. Update sendResponsesStreamData to return the error from
helper.ResponseChunkData instead of ignoring it, then handle that return in both
the pending-flush and live-forward paths in relay_responses.go by breaking out
of the stream loop and recording StreamEndReasonClientGone when a write fails.
In `@relay/channel/openai/relay_image.go`:
- Around line 128-138: The writeOpenaiImageStreamChunk helper is ignoring write
failures from ResponseChunkData and StringData, so stream errors cannot be
propagated back to stop the session. Update writeOpenaiImageStreamChunk to
return an error (or otherwise surface the helper result) and have the
caller/callback handle it by stopping the stream via sr.Stop(err) when a client
write fails; use the existing writeOpenaiImageStreamPayload flow as the
reference for how errors should be threaded through.
In `@service/tool_billing.go`:
- Around line 39-88: `ComputeToolCallQuota` currently returns `totalQuota`
directly, which can still overflow even though each `ToolCallItem` quota is
individually clamped. Update the final `ToolCallResult` construction to pass the
accumulated total through `common.QuotaFromFloat` before returning, using the
existing `totalQuota` calculation and `common.QuotaPerUnit`/`QuotaFromFloat`
flow to keep the aggregate within the quota column range.
In `@web/default/src/features/usage-logs/lib/utils.ts`:
- Around line 207-235: The quota_filter inclusion logic is duplicated in
buildBaseParams and buildApiParams, so extract the shared conditional into a
small helper like buildQuotaFilterParam(searchParams) and reuse it from both
functions. Keep the existing QUOTA_FILTER_ALL_VALUE exclusion behavior
centralized in that helper, then spread its result alongside the other params in
buildBaseParams and buildApiParams to prevent future drift.
🪄 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: ba653d51-2564-4455-97e1-c478712c9d2a
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (83)
common/quota_math.gocommon/quota_math_test.gocommon/ssrf_protection.gocontroller/log.gocontroller/midjourney.gocontroller/misc.gocontroller/model_list_test.gocontroller/oauth.gocontroller/task.gocontroller/task_video.gocontroller/token_test.gocontroller/user.godto/openai_image.gogo.modi18n/keys.goi18n/locales/en.yamli18n/locales/zh-CN.yamli18n/locales/zh-TW.yamlmodel/errors.gomodel/log.gomodel/log_test.gomodel/main.gomodel/midjourney.gomodel/option.gomodel/option_test.gomodel/payment_method_guard_test.gomodel/task.gomodel/topup.gomodel/user.gomodel/user_update_test.gopkg/billingexpr/billingexpr_test.gopkg/billingexpr/round.gorelay/channel/ali/image.gorelay/channel/api_request.gorelay/channel/api_request_test.gorelay/channel/gemini/relay_responses.gorelay/channel/openai/audio.gorelay/channel/openai/helper.gorelay/channel/openai/relay_image.gorelay/channel/openai/responses_via_chat.gorelay/channel/task/ali/adaptor.gorelay/channel/task/gemini/billing.gorelay/channel/task/kling/adaptor.gorelay/common/relay_utils.gorelay/common/relay_utils_test.gorelay/helper/common.gorelay/helper/max_tokens_bounds_test.gorelay/helper/openai_image_request_test.gorelay/helper/price.gorelay/helper/stream_scanner.gorelay/helper/stream_scanner_test.gorelay/helper/valid_request.gorelay/relay_task.goservice/http_client.goservice/protected_fetch_client.goservice/protected_fetch_client_test.goservice/quota.goservice/task_billing.goservice/text_quota.goservice/text_quota_test.goservice/token_counter.goservice/tool_billing.gosetting/ratio_setting/group_ratio.gosetting/ratio_setting/group_ratio_test.gosetting/task_billing_setting/rate_card.gotools/jsonwrapcheck/allowlist.txttypes/price_data.goweb/default/src/components/model-group-selector.tsxweb/default/src/features/usage-logs/components/common-logs-filter-bar.tsxweb/default/src/features/usage-logs/components/quota-filter-select.tsxweb/default/src/features/usage-logs/components/task-logs-filter-bar.tsxweb/default/src/features/usage-logs/constants.tsweb/default/src/features/usage-logs/lib/filter.tsweb/default/src/features/usage-logs/lib/utils.test.tsweb/default/src/features/usage-logs/lib/utils.tsweb/default/src/features/usage-logs/types.tsweb/default/src/i18n/locales/en.jsonweb/default/src/i18n/locales/fr.jsonweb/default/src/i18n/locales/ja.jsonweb/default/src/i18n/locales/ru.jsonweb/default/src/i18n/locales/vi.jsonweb/default/src/i18n/locales/zh.jsonweb/default/src/routes/_authenticated/usage-logs/$section.tsx
💤 Files with no reviewable changes (1)
- tools/jsonwrapcheck/allowlist.txt
📜 Review details
🧰 Additional context used
📓 Path-based instructions (10)
**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType) and must not directly callencoding/jsonfor actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid directAUTO_INCREMENT/SERIAL, usecommonGroupCol/commonKeyColandcommonTrueVal/commonFalseValfor DB-specific SQL, branch withcommon.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supportsStreamOptions; if it does, add that channel tostreamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types withomitemptyso explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, readpkg/billingexpr/expr.mdfirst and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.
**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType) instead of directly importing or callingencoding/jsonfor actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with thecommon.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQLflags when need...
Files:
dto/openai_image.goi18n/keys.gocontroller/task_video.gocontroller/task.gorelay/channel/openai/responses_via_chat.gocommon/quota_math.gocontroller/token_test.gorelay/channel/openai/helper.gorelay/helper/max_tokens_bounds_test.gorelay/channel/task/kling/adaptor.gomodel/errors.gorelay/channel/gemini/relay_responses.gorelay/channel/ali/image.gocontroller/midjourney.gorelay/common/relay_utils_test.gocommon/quota_math_test.gorelay/common/relay_utils.goservice/tool_billing.gopkg/billingexpr/billingexpr_test.gopkg/billingexpr/round.gocommon/ssrf_protection.gotypes/price_data.gorelay/channel/openai/audio.gocontroller/log.goservice/quota.gomodel/midjourney.gorelay/helper/stream_scanner_test.gorelay/channel/task/gemini/billing.goservice/token_counter.goservice/task_billing.gocontroller/model_list_test.gosetting/task_billing_setting/rate_card.gomodel/main.gomodel/task.gorelay/channel/task/ali/adaptor.gorelay/channel/openai/relay_image.gorelay/helper/price.goservice/protected_fetch_client_test.gomodel/topup.gorelay/helper/openai_image_request_test.gomodel/payment_method_guard_test.gorelay/relay_task.goservice/text_quota_test.goservice/text_quota.gorelay/helper/common.gocontroller/oauth.gosetting/ratio_setting/group_ratio.gorelay/helper/stream_scanner.goservice/http_client.gocontroller/misc.gorelay/channel/api_request.gosetting/ratio_setting/group_ratio_test.gorelay/helper/valid_request.gomodel/option.gorelay/channel/api_request_test.gomodel/log.goservice/protected_fetch_client.gocontroller/user.gomodel/log_test.gomodel/user_update_test.gomodel/user.gomodel/option_test.go
dto/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
For request structs parsed from client JSON and then re-marshaled to upstream providers, especially in relay/convert paths, optional scalar fields must use pointer types with
omitemptyso that absent fields stay omitted while explicit zero/false values are preserved.
Files:
dto/openai_image.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 中应合理使用useMemo、useCallback、React.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/usage-logs/$section.tsxweb/default/src/features/usage-logs/lib/filter.tsweb/default/src/features/usage-logs/lib/utils.test.tsweb/default/src/features/usage-logs/constants.tsweb/default/src/components/model-group-selector.tsxweb/default/src/features/usage-logs/components/quota-filter-select.tsxweb/default/src/features/usage-logs/lib/utils.tsweb/default/src/features/usage-logs/types.tsweb/default/src/features/usage-logs/components/common-logs-filter-bar.tsxweb/default/src/features/usage-logs/components/task-logs-filter-bar.tsx
web/default/src/routes/**/*.{ts,tsx}
📄 CodeRabbit inference engine (web/default/AGENTS.md)
路由应使用 TanStack Router,并通过
createFileRoute定义;搜索参数应使用 Zod schema +validateSearch校验;认证与重定向应放在beforeLoad中;导航应优先使用useNavigate或Link,避免直接操作window.location。
Files:
web/default/src/routes/_authenticated/usage-logs/$section.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/usage-logs/lib/filter.tsweb/default/src/features/usage-logs/lib/utils.test.tsweb/default/src/features/usage-logs/lib/utils.ts
web/default/src/features/**
📄 CodeRabbit inference engine (web/default/AGENTS.md)
功能模块应放在
src/features/<feature>/,并按需包含components/、lib/、hooks/、api.ts、types.ts、constants.ts等;通用组件应放在src/components/,通用工具与类型应放在src/lib/。
Files:
web/default/src/features/usage-logs/lib/filter.tsweb/default/src/features/usage-logs/lib/utils.test.tsweb/default/src/features/usage-logs/constants.tsweb/default/src/features/usage-logs/components/quota-filter-select.tsxweb/default/src/features/usage-logs/lib/utils.tsweb/default/src/features/usage-logs/types.tsweb/default/src/features/usage-logs/components/common-logs-filter-bar.tsxweb/default/src/features/usage-logs/components/task-logs-filter-bar.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 tostreamSupportedChannels.
Files:
relay/channel/openai/responses_via_chat.gorelay/channel/openai/helper.gorelay/channel/task/kling/adaptor.gorelay/channel/gemini/relay_responses.gorelay/channel/ali/image.gorelay/channel/openai/audio.gorelay/channel/task/gemini/billing.gorelay/channel/task/ali/adaptor.gorelay/channel/openai/relay_image.gorelay/channel/api_request.gorelay/channel/api_request_test.go
web/default/src/**/*.test.ts
📄 CodeRabbit inference engine (web/default/AGENTS.md)
工具函数与纯逻辑应优先编写单元测试;测试文件应命名为
*.test.ts。
Files:
web/default/src/features/usage-logs/lib/utils.test.ts
pkg/billingexpr/**/*.{go,md}
📄 CodeRabbit inference engine (AGENTS.md)
When working on tiered/dynamic billing expression pricing, first read
pkg/billingexpr/expr.mdand ensure all code changes in the billing expression system follow the documented design, architecture, token normalization, quota conversion, and versioning patterns.
Files:
pkg/billingexpr/billingexpr_test.gopkg/billingexpr/round.go
web/default/src/features/**/constants.ts
📄 CodeRabbit inference engine (web/default/AGENTS.md)
各 feature 的
constants.ts中,成功/错误/提示类消息常量应仅保存 i18n 键,展示时必须通过t()渲染;状态/选项的 label 应统一使用labelKey或label(二选一且同一 feature 内保持一致);新增此类常量时应同步登记翻译键。
Files:
web/default/src/features/usage-logs/constants.ts
🪛 ast-grep (0.44.1)
i18n/keys.go
[warning] 91-91: A credential is hard-coded as a string literal. Secrets stored in source code, such as passwords, API keys, and tokens, can be leaked through version control or binaries and used by internal or external malicious actors. Rotate the exposed secret and load it at runtime from a secure secret vault, a Hardware Security Module (HSM), or an environment variable if permitted by your company policy (e.g. password := os.Getenv("APP_PASSWORD")).
Context: MsgUserPasswordUnset = "user.password_unset"
Note: [CWE-798] Use of Hard-coded Credentials.
(hardcoded-credentials-string-literal-go)
[warning] 92-92: A credential is hard-coded as a string literal. Secrets stored in source code, such as passwords, API keys, and tokens, can be leaked through version control or binaries and used by internal or external malicious actors. Rotate the exposed secret and load it at runtime from a secure secret vault, a Hardware Security Module (HSM), or an environment variable if permitted by your company policy (e.g. password := os.Getenv("APP_PASSWORD")).
Context: MsgUserPasswordResetLinkInvalid = "user.password_reset_link_invalid"
Note: [CWE-798] Use of Hard-coded Credentials.
(hardcoded-credentials-string-literal-go)
🪛 OSV Scanner (2.4.0)
go.mod
[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking key constraints not enforced in golang.org/x/crypto/ssh/agent
(GO-2026-5005)
[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking agent constraints dropped when forwarding keys in golang.org/x/crypto/ssh/agent
(GO-2026-5006)
[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking byte arithmetic causes underflow and panic in golang.org/x/crypto/ssh
(GO-2026-5013)
[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking bypass of certificate restrictions in golang.org/x/crypto/ssh
(GO-2026-5014)
[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking server panic during CheckHostKey/Authenticate in golang.org/x/crypto/ssh
(GO-2026-5015)
[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking memory leak when rejecting channels can lead to DoS in golang.org/x/crypto/ssh
(GO-2026-5016)
[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking client can cause server deadlock on unexpected responses in golang.org/x/crypto/ssh
(GO-2026-5017)
[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking pathological RSA/DSA parameters may cause DoS in golang.org/x/crypto/ssh
(GO-2026-5018)
[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking bypass of FIDO/U2F security keys physical interaction in golang.org/x/crypto/ssh
(GO-2026-5019)
[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking infinite loop on large channel writes in golang.org/x/crypto/ssh
(GO-2026-5020)
[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking auth bypass via unenforced @revoked status in golang.org/x/crypto/ssh/knownhosts
(GO-2026-5021)
[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking VerifiedPublicKeyCallback permissions skip enforcement in golang.org/x/crypto/ssh
(GO-2026-5023)
[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking pathological inputs can lead to client panic in golang.org/x/crypto/ssh/agent
(GO-2026-5033)
[LOW] 53-53: golang.org/x/image 0.41.0: Panic when decoding large WEBP image on 32-bit platforms in golang.org/x/image
(GO-2026-4961)
[LOW] 53-53: golang.org/x/image 0.41.0: Panic on VP8 alpha channel size mismatch in x/image/webp in golang.org/x/image
(GO-2026-5061)
[LOW] 53-53: golang.org/x/image 0.41.0: Lack of limit on tile sizes in x/image/tiff in golang.org/x/image
(GO-2026-5062)
[LOW] 53-53: golang.org/x/image 0.41.0: Panic decoding image with out-of-bounds strip offset in x/image/tiff in golang.org/x/image
(GO-2026-5066)
🔇 Additional comments (91)
common/ssrf_protection.go (1)
282-284: LGTM!Also applies to: 299-301, 425-428
service/protected_fetch_client.go (1)
23-115: LGTM!service/http_client.go (1)
109-113: LGTM!Also applies to: 126-126, 139-144
service/protected_fetch_client_test.go (1)
16-225: LGTM!relay/common/relay_utils_test.go (1)
56-117: LGTM!relay/channel/task/ali/adaptor.go (1)
512-526: LGTM!Also applies to: 552-572, 779-781
relay/channel/task/gemini/billing.go (1)
53-66: LGTM!dto/openai_image.go (1)
14-16: LGTM!relay/helper/valid_request.go (4)
169-175: LGTM! Bounds check correctly guards both multipart and JSONnpaths againstdto.MaxImageN, with negative values already rejected by the*uinttype in the JSON path.Also applies to: 214-217
118-125: LGTM!exceedsMaxTokensLimitcleanly consolidates the previously ad-hoc token bound checks and is consistently applied across Responses/Claude/Text validators, matching the added test coverage.Also applies to: 139-141, 266-268, 291-293
116-117: 🎯 Functional CorrectnessNo change needed
relay/helper/valid_request.goalready importsmath, somath.MaxInt32compiles as written.> Likely an incorrect or invalid review comment.
344-346: 🩺 Stability & AvailabilityNo issue here:
GenerationConfigis a value field, so omittinggenerationConfigleaves the zero value and this access is safe.> Likely an incorrect or invalid review comment.relay/channel/ali/image.go (1)
57-59: LGTM! Necessary check sinceAliImageParameters.Nis a signedintsourced from arbitraryExtra["parameters"]JSON and can otherwise carry negative values that bypass the top-level*uintvalidation invalid_request.go.relay/helper/max_tokens_bounds_test.go (1)
1-67: LGTM! Good coverage ofexceedsMaxTokensLimitacross all four request validators, with a boundary value correctly chosen just abovemaxTokensLimit.relay/helper/openai_image_request_test.go (1)
1-83: LGTM! Covers both JSON and multipartnvalidation paths, including boundary (MaxImageN), default, and negative-value cases.go.mod (1)
7-8: LGTM!controller/token_test.go (1)
552-557: LGTM!Also applies to: 633-638
web/default/src/components/model-group-selector.tsx (1)
61-65: LGTM!controller/oauth.go (1)
4-4: LGTM!Also applies to: 110-125, 267-273, 288-288, 314-314, 359-364
controller/misc.go (1)
4-11: LGTM!Also applies to: 242-246, 285-287, 307-312, 323-327, 341-364
controller/user.go (1)
32-36: LGTM!Also applies to: 192-197, 211-224, 247-250, 635-639, 812-819, 836-855, 1129-1129, 1145-1149
model/topup.go (1)
441-441: LGTM!Also applies to: 469-472, 492-516
controller/model_list_test.go (1)
17-21: LGTM!Also applies to: 246-285, 287-323
model/user_update_test.go (1)
6-18: LGTM!Also applies to: 57-134, 171-204, 259-345, 375-523
model/payment_method_guard_test.go (1)
315-347: LGTM!model/log.go (2)
94-124: LGTM!
856-862: 🎯 Functional CorrectnessConfirm the retry-filter type-scoping change is intentional.
This replaces the previous
else if !isRetryLogFilter(logFilter)with an unconditionalelse, so whenlogType == LogTypeUnknowntheLogTypeConsumeconstraint is now always applied — including when a retry filter (LogFilterRetry/LogFilterErrorRetry/LogFilterEmptyRetry) is active. Previously, retry-filtered queries withLogTypeUnknownhad no type constraint at all, meaning non-consume logs bearing aretry_logmarker (e.g.,LogTypeTopup) could leak into retry-filtered stats/logs.The new
TestSumUsedQuotaRetryFilterIgnoresNonConsumeQuotatest confirms and validates this new behavior, so it appears intentional and correct. However, this control-flow change is unrelated to the quota-filter feature described for this layer and isn't called out in the AI summary or line-range description as a standalone fix — worth flagging to ensure it was a deliberate decision and not an incidental side effect of refactoring this block while addingapplyQuotaFilter.model/log_test.go (1)
27-413: LGTM!model/midjourney.go (1)
29-35: LGTM!Also applies to: 37-63, 65-94, 189-207, 210-225
web/default/src/features/usage-logs/types.ts (1)
71-76: LGTM!Also applies to: 305-320, 339-352, 364-372, 378-386
web/default/src/features/usage-logs/components/quota-filter-select.tsx (1)
1-87: LGTM!web/default/src/features/usage-logs/components/common-logs-filter-bar.tsx (1)
46-46: LGTM!Also applies to: 58-62, 113-116, 137-137, 165-169, 180-180, 203-211, 325-334, 396-396, 406-413
web/default/src/features/usage-logs/lib/filter.ts (1)
46-46: LGTM!model/task.go (1)
163-173: LGTM!Also applies to: 215-296, 458-518
controller/log.go (1)
15-38: LGTM!Also applies to: 69-91, 160-187, 189-217
controller/midjourney.go (1)
257-281: LGTM!Also applies to: 283-307
controller/task.go (1)
22-44: LGTM!Also applies to: 46-69
web/default/src/features/usage-logs/components/task-logs-filter-bar.tsx (1)
25-25: LGTM!Also applies to: 35-39, 94-98, 118-118, 142-163, 180-188, 222-254
web/default/src/routes/_authenticated/usage-logs/$section.tsx (1)
22-25: LGTM!Also applies to: 54-54
web/default/src/features/usage-logs/lib/utils.test.ts (1)
110-142: LGTM!web/default/src/i18n/locales/en.json (1)
116-116: LGTM!Also applies to: 319-319, 2831-2831, 5172-5172
web/default/src/i18n/locales/fr.json (1)
116-116: LGTM!Also applies to: 319-319, 2831-2831, 5172-5172
web/default/src/i18n/locales/ja.json (1)
116-116: LGTM!Also applies to: 319-319, 2831-2831, 5172-5172
web/default/src/i18n/locales/vi.json (1)
116-116: LGTM!Also applies to: 319-319, 2831-2831, 5172-5172
web/default/src/i18n/locales/zh.json (1)
116-116: LGTM!Also applies to: 319-319, 2831-2831, 5172-5172
relay/channel/api_request.go (1)
67-68: LGTM!Also applies to: 405-461, 463-500, 518-530, 599-601
relay/channel/api_request_test.go (1)
8-13: LGTM!Also applies to: 96-112, 253-283, 402-447
relay/helper/stream_scanner.go (1)
28-28: LGTM!Also applies to: 44-49, 70-91, 109-143, 154-166, 191-202, 214-220, 290-290
relay/helper/stream_scanner_test.go (1)
5-5: LGTM!Also applies to: 24-35, 59-95
relay/helper/common.go (3)
28-30: LGTM!Also applies to: 115-117
61-75: 🩺 Stability & Availability | ⚡ Quick winSilent context-done handling okay, but confirm this is acceptable.
ClaudeDatareturnsnil(its declarederror) andClaudeChunkData(void) silently no-op when the context is done, whereasResponseChunkData/StringData/PingDataall surface a "request context done" error to the caller. This is asymmetric but plausibly intentional since these two functions' errors already appear to be discarded by callers. Confirm no caller relies on the error/return ofClaudeDatato detect client disconnects (e.g., forStreamStatus.SetEndReason), otherwise disconnects on the Claude data path won't be recorded the way they now are on the Responses path.Also applies to: 77-85
87-95: LGTM!ResponseChunkDatacorrectly returnsFlushWriter(c)'s error instead of discarding it, enabling callers to detect failed/short-circuited writes.relay/channel/gemini/relay_responses.go (1)
92-95: LGTM! Correctly propagatesResponseChunkData's error and stops emitting further events.relay/channel/openai/relay_image.go (1)
288-301: LGTM!writeOpenaiImageStreamPayload/writeOpenaiImageStreamDonecorrectly return the helper errors, and the unchanged caller (lines 265-277) already handles them to markStreamEndReasonClientGone.relay/channel/openai/responses_via_chat.go (1)
77-80: LGTM! Correctly checksResponseChunkData's error and stops the stream viasr.Stop(streamErr)at the call site.web/default/src/i18n/locales/ru.json (1)
116-116: LGTM!Also applies to: 319-319, 2831-2831, 5172-5172
common/quota_math.go (1)
1-21: LGTM!common/quota_math_test.go (1)
10-18: LGTM!pkg/billingexpr/round.go (1)
8-23: LGTM!service/token_counter.go (1)
199-217: LGTM!Also applies to: 376-396
types/price_data.go (1)
33-41: LGTM!relay/helper/price.go (2)
116-121: LGTM!
202-211: 🗄️ Data Integrity & IntegrationThe int32 ceiling is intentional here. Quota values are capped to match the 32-bit quota columns, so
math.MaxInt32/math.MinInt32is consistent with the persisted schema.> Likely an incorrect or invalid review comment.relay/relay_task.go (3)
129-136: LGTM!
219-225: LGTM!
360-377: LGTM!service/quota.go (1)
50-87: LGTM!service/text_quota.go (2)
141-155: LGTM!
288-313: LGTM!service/text_quota_test.go (2)
21-26: LGTM!
613-621: LGTM!setting/task_billing_setting/rate_card.go (1)
80-80: LGTM!Also applies to: 124-126, 135-137, 219-238
relay/channel/openai/audio.go (1)
106-107: LGTM!relay/channel/task/kling/adaptor.go (1)
505-506: LGTM!controller/task_video.go (1)
192-192: LGTM!service/task_billing.go (2)
311-311: LGTM!
218-230: 🗄️ Data Integrity & IntegrationNo double-settlement path here
RecalculateTaskQuotaruns only after the task is moved to a terminal status under the CAS guard, and the polling scans excludeSUCCESS/FAILUREtasks. A failedUpdateQuota()can leave the persisted quota stale, but it won’t cause the same task to be settled again.> Likely an incorrect or invalid review comment.model/option.go (1)
214-218: LGTM!Also applies to: 247-261, 276-292, 332-335
setting/ratio_setting/group_ratio.go (2)
150-168: 🗄️ Data Integrity & Integration | ⚡ Quick winDuplicate keys that collide after trimming silently overwrite each other non-deterministically.
If the input JSON has two distinct raw keys that trim to the same name (e.g.
{"vip":0.5," vip ":0.9}), the loop writes both intonormalized[trimmedName], and Go's randomized map iteration order means whichever key is visited last wins — non-deterministically across calls/process runs. Since this value feeds directly into billing (GetGroupRatiois multiplied into quota calculations), an ambiguous admin input could silently produce different effective ratios between the moment of validation (CheckGroupRatio) and the moment of application (UpdateGroupRatioByJSONString), or across replicas.Consider detecting the collision and returning an error instead of silently picking one.
🛡️ Proposed fix
normalized := make(map[string]float64, len(checkGroupRatio)) for name, ratio := range checkGroupRatio { trimmedName := strings.TrimSpace(name) if isReservedAutoRouteGroupName(trimmedName) { continue } if ratio < 0 { return nil, errors.New("group ratio must be not less than 0: " + trimmedName) } + if _, exists := normalized[trimmedName]; exists { + return nil, errors.New("duplicate group ratio name after trimming: " + trimmedName) + } normalized[trimmedName] = ratio }
84-98: LGTM!Also applies to: 133-148, 170-183
model/option_test.go (1)
47-99: LGTM!setting/ratio_setting/group_ratio_test.go (1)
9-48: LGTM!i18n/keys.go (1)
91-93: 📐 Maintainability & Code QualityStatic analysis false positive.
The
hardcoded-credentials-string-literal-gowarnings onMsgUserPasswordUnset/MsgUserPasswordResetLinkInvalidare false positives — these are i18n message key identifiers, not credentials.Source: Linters/SAST tools
model/errors.go (1)
12-16: LGTM!i18n/locales/en.yaml (1)
79-81: LGTM!i18n/locales/zh-CN.yaml (1)
43-43: LGTM!Also applies to: 80-82
i18n/locales/zh-TW.yaml (1)
80-82: LGTM!model/user.go (3)
219-269: LGTM!Also applies to: 585-638, 917-1000, 1069-1127
693-713: 🎯 Functional CorrectnessNo issue:
InsertWithTxis only invoked insideWithNormalizedEmailWriteTx, so the named lock stays on the pinned connection through commit.> Likely an incorrect or invalid review comment.
32-32: 🗄️ Data Integrity & IntegrationClarify whether deleted emails should stay reserved
emailQuery()usesUnscoped(), so a soft-deleted user's email still counts as taken. If re-registration after delete should be allowed, this lookup needs to exclude soft-deleted rows; otherwise the current behavior is fine.model/main.go (1)
314-316: LGTM!Also applies to: 392-394, 408-419
| func (t *Task) UpdateQuota() error { | ||
| return DB.Model(t).Update("quota", t.Quota).Error | ||
| } | ||
|
|
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
UpdateQuota correctly scopes by primary key.
DB.Model(t).Update("quota", t.Quota) relies on GORM using t's primary key to build the WHERE clause, which is standard GORM behavior. No test coverage for this new method or the QuotaFilter wiring was included in the provided files — consider adding coverage alongside the existing TestLogQuotaFilters pattern mentioned for model/log_test.go.
🤖 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/task.go` around lines 408 - 411, Add test coverage for the new quota
update path and filter wiring. Use the existing model test patterns, especially
the `TestLogQuotaFilters` style in `model/log_test.go`, to verify `UpdateQuota`
updates the record scoped by the task primary key and that `QuotaFilter` is
applied as expected. Reference `Task.UpdateQuota` and the `QuotaFilter` setup
when adding the tests so the new behavior stays covered.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@dto/openai_image.go`:
- Around line 18-26: ValidateImageN currently rejects values outside [0,
MaxImageN], but its error text in ValidateImageN says the lower bound is 1,
which conflicts with the actual accepted range and caller behavior. Update the
validation message to reflect the real bounds in ValidateImageN, keeping the
existing field handling and MaxImageN check unchanged so API consumers see the
correct valid range.
In `@go.mod`:
- Line 53: The dependency on golang.org/x/image in go.mod is still on a
vulnerable version, so update that module requirement to v0.43.0 or newer. Make
the change in the existing dependency entry for golang.org/x/image and keep the
rest of the module file unchanged.
🪄 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: 5c4305f6-e558-49bc-b908-88a0f21cfe31
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (30)
controller/discord.gocontroller/github.gocontroller/linuxdo.gocontroller/log.gocontroller/oidc.gocontroller/telegram.gocontroller/user.gocontroller/wechat.godto/openai_image.godto/openai_image_test.gogo.modmodel/log.gomodel/log_test.gomodel/task_cas_test.gomodel/user.gomodel/user_update_test.gorelay/channel/ali/image.gorelay/channel/task/ali/adaptor.gorelay/channel/task/ali/adaptor_kling_test.gorelay/channel/task/ali/adaptor_wan27_test.gorelay/common/relay_info.gorelay/common/relay_info_test.gorelay/common/relay_utils.gorelay/common/relay_utils_test.gorelay/helper/common.gorelay/helper/common_test.gorelay/helper/valid_request.gosetting/ratio_setting/group_ratio.gosetting/ratio_setting/group_ratio_test.goweb/default/src/features/usage-logs/constants.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType) and must not directly callencoding/jsonfor actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid directAUTO_INCREMENT/SERIAL, usecommonGroupCol/commonKeyColandcommonTrueVal/commonFalseValfor DB-specific SQL, branch withcommon.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supportsStreamOptions; if it does, add that channel tostreamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types withomitemptyso explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, readpkg/billingexpr/expr.mdfirst and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.
**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType) instead of directly importing or callingencoding/jsonfor actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with thecommon.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQLflags when need...
Files:
controller/log.gorelay/channel/ali/image.gocontroller/telegram.gocontroller/wechat.gocontroller/discord.godto/openai_image.gorelay/common/relay_info.gocontroller/oidc.gorelay/helper/common_test.gorelay/channel/task/ali/adaptor_kling_test.gorelay/channel/task/ali/adaptor_wan27_test.gomodel/task_cas_test.gocontroller/linuxdo.godto/openai_image_test.gocontroller/github.gorelay/channel/task/ali/adaptor.gosetting/ratio_setting/group_ratio_test.gorelay/common/relay_utils_test.gorelay/helper/common.gorelay/helper/valid_request.gorelay/common/relay_info_test.gorelay/common/relay_utils.gosetting/ratio_setting/group_ratio.gocontroller/user.gomodel/log.gomodel/log_test.gomodel/user_update_test.gomodel/user.go
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 tostreamSupportedChannels.
Files:
relay/channel/ali/image.gorelay/channel/task/ali/adaptor_kling_test.gorelay/channel/task/ali/adaptor_wan27_test.gorelay/channel/task/ali/adaptor.go
dto/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
For request structs parsed from client JSON and then re-marshaled to upstream providers, especially in relay/convert paths, optional scalar fields must use pointer types with
omitemptyso that absent fields stay omitted while explicit zero/false values are preserved.
Files:
dto/openai_image.godto/openai_image_test.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 中应合理使用useMemo、useCallback、React.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/usage-logs/constants.ts
web/default/src/features/**/constants.ts
📄 CodeRabbit inference engine (web/default/AGENTS.md)
各 feature 的
constants.ts中,成功/错误/提示类消息常量应仅保存 i18n 键,展示时必须通过t()渲染;状态/选项的 label 应统一使用labelKey或label(二选一且同一 feature 内保持一致);新增此类常量时应同步登记翻译键。
Files:
web/default/src/features/usage-logs/constants.ts
web/default/src/features/**
📄 CodeRabbit inference engine (web/default/AGENTS.md)
功能模块应放在
src/features/<feature>/,并按需包含components/、lib/、hooks/、api.ts、types.ts、constants.ts等;通用组件应放在src/components/,通用工具与类型应放在src/lib/。
Files:
web/default/src/features/usage-logs/constants.ts
🔇 Additional comments (33)
relay/channel/ali/image.go (1)
57-59: 🎯 Functional CorrectnessAddressed: shared N-bounds validator extracted.
This resolves the previously raised duplication concern by centralizing the check in
dto.ValidateImageN.relay/helper/common.go (1)
61-107: 🩺 Stability & AvailabilityAddressed: nil/writer guards added per prior review, and flush error now propagated.
Matches the previously requested fix (nil
c/c.Writerguard onClaudeData,ClaudeChunkData,ResponseChunkData), andResponseChunkDatanow returnsFlushWriter(c)'s error instead of discarding it.controller/log.go (2)
15-53: LGTM!Also applies to: 84-120, 189-227, 229-268
28-44: 🎯 Functional Correctness
quota_filteris normalized to fixed values and applied with bound parameters, so this path is not vulnerable to SQL injection.> Likely an incorrect or invalid review comment.controller/telegram.go (1)
60-61: LGTM!controller/wechat.go (1)
171-172: LGTM!controller/discord.go (1)
213-214: LGTM!relay/common/relay_info.go (1)
736-749: 🎯 Functional CorrectnessResolvedSeconds is already guarded at runtime. The only production callers either use
ResolvedSecondsOrDefaultor runvalidateTaskDurationBounds, which rejects negative values before they can propagate.> Likely an incorrect or invalid review comment.relay/helper/common_test.go (1)
1-22: LGTM!relay/channel/task/ali/adaptor_kling_test.go (1)
90-141: LGTM!relay/channel/task/ali/adaptor_wan27_test.go (1)
47-94: LGTM!model/task_cas_test.go (1)
247-324: LGTM!relay/common/relay_utils_test.go (1)
56-127: LGTM!relay/common/relay_info_test.go (1)
43-84: 🎯 Functional CorrectnessExplicit zero duration falls back to the default here
controller/oidc.go (1)
218-218: 🎯 Functional CorrectnessNo change needed UpdateFields already scopes the write by
user.Idand only applies the requested field(s), so this path is fine.> Likely an incorrect or invalid review comment.controller/github.go (1)
209-210: 🎯 Functional CorrectnessSame
UpdateFieldsverification ascontroller/linuxdo.go.Same scoped-update pattern as
LinuxDoBind; verification ofUpdateFieldssemantics applies here too.dto/openai_image_test.go (1)
10-21: LGTM!web/default/src/features/usage-logs/constants.ts (1)
159-161: LGTM! Derivation fromQUOTA_FILTER_VALUESresolves the previously-flagged drift risk between the filter list and the route's zod enum.relay/channel/task/ali/adaptor.go (2)
513-517: LGTM! Consolidating duration parsing intoResolvedSecondsOrDefaultremoves duplicatedstrconv.Atoi/error-wrapping logic.
542-555: LGTM! The refactor mirrors the pattern inconvertToAliRequest. The initialDuration: 5in the struct literal (line 545) is now redundant since it's unconditionally overwritten right after, but this is harmless dead code not worth a separate fix.go.mod (1)
52-52: LGTM!golang.org/x/cryptov0.52.0 resolves all previously-flagged OSV advisories (GO-2026-5005/5006/5013-5021/5023/5033), addressing the prior review comment.setting/ratio_setting/group_ratio_test.go (1)
34-50: LGTM!controller/linuxdo.go (1)
68-69: 🎯 Functional CorrectnessNo issue:
UpdateFieldsuses the sameupdateWithTxpath and cache refresh asUpdate, so this LinuxDO ID-only write keeps the existing behavior.relay/helper/valid_request.go (1)
169-178: LGTM!Also applies to: 217-221
relay/common/relay_utils.go (1)
119-128: LGTM!Also applies to: 186-190, 209-211
setting/ratio_setting/group_ratio.go (1)
76-83: LGTM!Also applies to: 101-113
controller/user.go (2)
391-391: LGTM!Also applies to: 441-441, 805-833
1092-1099: 🩺 Stability & AvailabilityDelete does not reach the shared update path.
case "delete"returns immediately afteruser.Delete(), soUpdateFields(false, updateFields...)only runs for enable/disable/promote/demote.> Likely an incorrect or invalid review comment.model/log.go (1)
36-42: LGTM!Also applies to: 100-116, 657-695, 746-786, 826-880
model/log_test.go (1)
27-32: LGTM!Also applies to: 206-266
model/user_update_test.go (1)
171-204: LGTM!Also applies to: 206-232
model/user.go (2)
21-46: LGTM!Also applies to: 59-59, 667-717, 773-799, 910-958
801-837: 🗄️ Data Integrity & IntegrationNo lost-update here
copyUnspecifiedUserUpdateValuesdoes not writequota,used_quota, orrequest_count, so this update path does not overwrite those accounting fields.> Likely an incorrect or invalid review comment.
Important
📝 变更描述 / Description
(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)
🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。📸 运行证明 / Proof of Work
(请在此粘贴截图、关键日志或测试报告,以证明变更生效)