Skip to content

v1.0.4#17

Merged
CSCITech merged 9 commits into
mainfrom
cscitech
Jul 13, 2026
Merged

v1.0.4#17
CSCITech merged 9 commits into
mainfrom
cscitech

Conversation

@CSCITech

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 12, 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

Quota conversion and saturation metadata are centralized, provider billing usage is normalized, and clamp information flows into validation, settlement, and logs. Verification codes gain transactional claiming, quota limits become JavaScript-safe, and billing settings gain an unset-models view with localized states.

Changes

Quota and billing pipeline

Layer / File(s) Summary
Quota and billing contracts
common/quota_math.go, dto/*, pkg/billingexpr/*
Adds checked, strict, rounded, and decimal quota conversions; clamp metadata; unified provider billing DTOs; and cache-write token handling.
Provider usage normalization
relay/channel/*, service/billing_usage.go, service/convert.go, service/openaicompat/*
Preserves provider billing metadata, estimates missing Gemini usage, and converts provider usage into unified records.
Quota enforcement and auditing
relay/helper/*, relay/relay_task.go, service/{quota,text_quota,task_billing,billing}*.go
Uses strict or checked conversions, rejects invalid quota states, records clamps, and attaches saturation details to logs.
Enabled model discovery
model/ability.go
Requires both enabled abilities and enabled channels when listing models.

Verification and quota safety

Layer / File(s) Summary
Transactional verification claims
common/verification.go, controller/misc.go, common/verification_test.go, controller/user_setting_test.go
Claims verification codes during password reset and consumes them only after a successful callback.
Safe quota boundaries
controller/user.go, web/default/src/features/users/*
Enforces JavaScript-safe quota values and validates add, subtract, and override operations in backend and frontend paths.

Unset-model pricing

Layer / File(s) Summary
Unset-price editor
web/default/src/features/system-settings/models/*, web/default/src/features/system-settings/billing/section-registry.tsx
Adds enabled-model loading, saved-value reconstruction, unset-price filtering, restricted actions, and a new pricing tab.
Localized UI states
web/default/src/i18n/locales/*.json
Adds translations for enabled-model loading errors, unset-price empty states, quota validation, and the unset-model tab.

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

Sequence Diagram(s)

sequenceDiagram
  participant Provider
  participant Relay
  participant BillingUsage
  participant QuotaService
  participant ConsumeLog
  Provider->>Relay: return usage metadata
  Relay->>BillingUsage: normalize provider billing usage
  BillingUsage->>QuotaService: provide effective usage
  QuotaService->>QuotaService: convert quota with clamp tracking
  QuotaService->>ConsumeLog: attach billing path and saturation metadata
Loading

Possibly related PRs

Poem

A bunny sees quotas hop,
Clamps keep numbers from the top.
Billing tokens neatly flow,
Verification codes wait below.
Unset models now show—
“Squeak!” says the rabbit, “go!”

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is only a version string and does not describe the changes in this pull request. Use a concise title that names the main code change or feature instead of a release/version label.
Description check ❓ Inconclusive The description is a template with no actual summary of the changes, so it is too vague to evaluate meaningfully. Replace the template with a brief human-written summary of what changed and why.
✅ Passed checks (2 passed)
Check name Status Explanation
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

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

❤️ Share

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

@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: 5

Caution

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

⚠️ Outside diff range comments (1)
service/convert.go (1)

939-945: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Mirror the total-token fallback in the streaming path.

The non-stream converter falls back to PromptTokens + CompletionTokens when TotalTokens is zero, but the streaming path assigns zero directly. Providers that omit total_tokens will therefore produce incorrect Gemini usage metadata.

Proposed fix
 		geminiResponse.UsageMetadata.PromptTokenCount = openAIResponse.Usage.PromptTokens
 		geminiResponse.UsageMetadata.CandidatesTokenCount = openAIResponse.Usage.CompletionTokens
-		geminiResponse.UsageMetadata.TotalTokenCount = openAIResponse.Usage.TotalTokens
+		totalTokens := openAIResponse.Usage.TotalTokens
+		if totalTokens == 0 {
+			totalTokens = openAIResponse.Usage.PromptTokens + openAIResponse.Usage.CompletionTokens
+		}
+		geminiResponse.UsageMetadata.TotalTokenCount = totalTokens
🤖 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/convert.go` around lines 939 - 945, The streaming conversion path
should mirror the non-stream total-token fallback: when populating Gemini usage
metadata from openAIResponse.Usage, use PromptTokens plus CompletionTokens if
TotalTokens is zero, while preserving the provided TotalTokens when nonzero.
Update the streaming converter’s usage assignment near
geminiBillingMetadataFromOpenAIUsage.
🤖 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 `@common/quota_math.go`:
- Around line 65-79: Update saturateQuota’s boundary comparisons so exact
MaxQuota and MinQuota values are treated as valid representable quotas rather
than overflow or underflow; only values beyond those limits should create
QuotaClamp entries, log via SysError, and be rejected by strict callers.
Preserve the existing NaN handling and clamped return behavior.

In `@service/billing.go`:
- Around line 21-36: Extract the shared QuotaClamp and negative preConsumedQuota
validation from PreConsumeBilling and PreConsumeQuota into a helper, then invoke
that helper from both paths. Preserve the existing error construction, status
code, and skip-retry option, and return any validation error before each path
continues.

In `@service/log_info_generate.go`:
- Around line 31-39: Update attachQuotaSaturation to return without logging when
other is nil, while preserving the existing nil checks for relayInfo and
QuotaClamp and the attachment/logging behavior for non-nil maps.
- Around line 19-29: The attachQuotaSaturationToOther function must not
overwrite a non-map other["admin_info"] value. Preserve the existing value or
return without modification when the field has an incompatible type, while
continuing to initialize admin_info only when it is absent and updating
quota_saturation for valid maps.

In
`@web/default/src/features/system-settings/models/model-ratio-visual-editor.tsx`:
- Around line 1039-1047: Refactor the empty-state text rendering in the table
component to remove the three-level nested ternary. Use an IIFE with early
returns or equivalent conditional logic: return the global-filter message first,
then handle unset-filter mode with its loading and no-prices messages, and
finally return the default no-models message.

---

Outside diff comments:
In `@service/convert.go`:
- Around line 939-945: The streaming conversion path should mirror the
non-stream total-token fallback: when populating Gemini usage metadata from
openAIResponse.Usage, use PromptTokens plus CompletionTokens if TotalTokens is
zero, while preserving the provided TotalTokens when nonzero. Update the
streaming converter’s usage assignment near
geminiBillingMetadataFromOpenAIUsage.
🪄 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: 7b859845-e410-4fce-9c7f-a1908d0ddeab

📥 Commits

Reviewing files that changed from the base of the PR and between 23e8d2d and 7abd87f.

📒 Files selected for processing (44)
  • common/quota_math.go
  • common/quota_math_test.go
  • dto/billing_usage.go
  • dto/billing_usage_test.go
  • dto/claude.go
  • dto/gemini.go
  • dto/openai_response.go
  • model/ability.go
  • pkg/billingexpr/round.go
  • pkg/billingexpr/settle.go
  • pkg/billingexpr/types.go
  • relay/channel/claude/relay-claude.go
  • relay/channel/gemini/relay-gemini-native.go
  • relay/channel/gemini/relay-gemini.go
  • relay/channel/gemini/relay_responses.go
  • relay/channel/openai/relay-openai.go
  • relay/channel/openai/relay_image.go
  • relay/channel/openai/relay_responses.go
  • relay/channel/openai/relay_responses_compact.go
  • relay/common/relay_info.go
  • relay/helper/price.go
  • relay/relay_task.go
  • service/billing.go
  • service/billing_usage.go
  • service/convert.go
  • service/log_info_generate.go
  • service/openaicompat/chat_to_responses_response.go
  • service/openaicompat/responses_to_chat.go
  • service/pre_consume_quota.go
  • service/quota.go
  • service/task_billing.go
  • service/text_quota.go
  • service/text_quota_test.go
  • service/tiered_settle.go
  • web/default/src/features/system-settings/billing/section-registry.tsx
  • web/default/src/features/system-settings/models/model-ratio-form.tsx
  • web/default/src/features/system-settings/models/model-ratio-visual-editor.tsx
  • web/default/src/features/system-settings/models/ratio-settings-card.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
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: CodeRabbit
🧰 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 in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for 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 direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.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 supports StreamOptions; if it does, add that channel to streamSupportedChannels.
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 instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first 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 in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for 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 the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • relay/channel/openai/relay_responses_compact.go
  • relay/channel/openai/relay_image.go
  • relay/channel/gemini/relay-gemini-native.go
  • model/ability.go
  • service/pre_consume_quota.go
  • relay/channel/openai/relay_responses.go
  • dto/claude.go
  • pkg/billingexpr/types.go
  • service/billing.go
  • pkg/billingexpr/settle.go
  • service/openaicompat/responses_to_chat.go
  • relay/channel/openai/relay-openai.go
  • service/tiered_settle.go
  • relay/common/relay_info.go
  • dto/billing_usage_test.go
  • pkg/billingexpr/round.go
  • relay/channel/gemini/relay_responses.go
  • relay/helper/price.go
  • service/openaicompat/chat_to_responses_response.go
  • service/billing_usage.go
  • service/convert.go
  • dto/gemini.go
  • dto/openai_response.go
  • service/quota.go
  • service/log_info_generate.go
  • dto/billing_usage.go
  • relay/relay_task.go
  • relay/channel/claude/relay-claude.go
  • common/quota_math_test.go
  • service/task_billing.go
  • common/quota_math.go
  • service/text_quota_test.go
  • relay/channel/gemini/relay-gemini.go
  • service/text_quota.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 to streamSupportedChannels.

Files:

  • relay/channel/openai/relay_responses_compact.go
  • relay/channel/openai/relay_image.go
  • relay/channel/gemini/relay-gemini-native.go
  • relay/channel/openai/relay_responses.go
  • relay/channel/openai/relay-openai.go
  • relay/channel/gemini/relay_responses.go
  • relay/channel/claude/relay-claude.go
  • relay/channel/gemini/relay-gemini.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/system-settings/billing/section-registry.tsx
  • web/default/src/features/system-settings/models/model-ratio-form.tsx
  • web/default/src/features/system-settings/models/ratio-settings-card.tsx
  • web/default/src/features/system-settings/models/model-ratio-visual-editor.tsx
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/system-settings/billing/section-registry.tsx
  • web/default/src/features/system-settings/models/model-ratio-form.tsx
  • web/default/src/features/system-settings/models/ratio-settings-card.tsx
  • web/default/src/features/system-settings/models/model-ratio-visual-editor.tsx
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 omitempty so that absent fields stay omitted while explicit zero/false values are preserved.

Files:

  • dto/claude.go
  • dto/billing_usage_test.go
  • dto/gemini.go
  • dto/openai_response.go
  • dto/billing_usage.go
pkg/billingexpr/**/*.{go,md}

📄 CodeRabbit inference engine (AGENTS.md)

When working on tiered/dynamic billing expression pricing, first read pkg/billingexpr/expr.md and ensure all code changes in the billing expression system follow the documented design, architecture, token normalization, quota conversion, and versioning patterns.

Files:

  • pkg/billingexpr/types.go
  • pkg/billingexpr/settle.go
  • pkg/billingexpr/round.go
🔇 Additional comments (51)
relay/channel/openai/relay_responses_compact.go (1)

42-45: LGTM!

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

63-70: LGTM!

web/default/src/features/system-settings/billing/section-registry.tsx (1)

115-115: LGTM!

relay/channel/claude/relay-claude.go (2)

663-682: LGTM!


913-915: 🩺 Stability & Availability

buildMessageDeltaPatchUsage(nil, claudeInfo) is nil-safe here.

			> Likely an incorrect or invalid review comment.
web/default/src/features/system-settings/models/model-ratio-form.tsx (1)

83-99: LGTM!

common/quota_math_test.go (1)

12-137: LGTM!

web/default/src/features/system-settings/models/ratio-settings-card.tsx (1)

279-297: LGTM!

Also applies to: 371-371, 460-462, 541-551

web/default/src/features/system-settings/models/model-ratio-visual-editor.tsx (1)

221-347: LGTM!

Also applies to: 429-491

relay/channel/gemini/relay-gemini-native.go (1)

42-43: LGTM!

model/ability.go (1)

54-58: LGTM!

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

54-57: LGTM!

Also applies to: 148-151

relay/relay_task.go (1)

225-227: LGTM!

Also applies to: 378-390

service/task_billing.go (1)

58-58: LGTM!

Also applies to: 198-198, 248-250, 315-318

service/pre_consume_quota.go (1)

34-39: 🩺 Stability & Availability

Guard relayInfo before dereferencing it model.GetUserQuota(relayInfo.UserId, false) will panic if relayInfo can be nil here.

dto/claude.go (1)

567-567: LGTM!

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

1860-1860: LGTM!

Also applies to: 2966-2966, 4815-4815

pkg/billingexpr/types.go (1)

57-65: LGTM! Clamp is correctly excluded from JSON serialization via json:"-" since it's for internal auditing only.

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

1860-1860: LGTM!

Also applies to: 2966-2966, 4815-4815

pkg/billingexpr/settle.go (1)

21-38: 🎯 Functional Correctness

No issue

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

1860-1860: LGTM!

Also applies to: 2966-2966, 4815-4815

service/convert.go (1)

836-852: LGTM!

Also applies to: 1008-1035

service/log_info_generate.go (1)

5-17: LGTM!

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

1860-1860: LGTM!

Also applies to: 2966-2966, 4815-4815

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

1860-1860: LGTM!

Also applies to: 2966-2966, 4815-4815

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

594-598: LGTM!

service/tiered_settle.go (2)

106-117: LGTM!


21-26: 🎯 Functional Correctness

Drop this comment CacheCreationTokensTotal() returns max(CachedCreationTokens, CacheWriteTokens) and clamps negatives to 0, so it does not sum 5m+1h sub-fields.

			> Likely an incorrect or invalid review comment.
service/openaicompat/responses_to_chat.go (1)

138-150: 🗄️ Data Integrity & Integration

CloneBillingUsage already handles nil and deep-copies the nested usage fields.

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

1860-1860: LGTM!

Also applies to: 2966-2966, 4815-4815

service/quota.go (1)

50-57: LGTM!

Also applies to: 86-86, 139-140, 203-204, 252-252, 334-335, 383-383

relay/common/relay_info.go (1)

169-172: LGTM!

dto/billing_usage_test.go (1)

1-89: LGTM!

Source: Coding guidelines

pkg/billingexpr/round.go (1)

3-14: LGTM!

relay/helper/price.go (1)

116-129: LGTM!

Also applies to: 210-227, 289-292

service/openaicompat/chat_to_responses_response.go (1)

148-165: LGTM!

service/billing_usage.go (1)

1-205: LGTM!

relay/channel/gemini/relay_responses.go (1)

35-35: 🎯 Functional Correctness

No action needed: empty Gemini usage metadata already falls back to text-based usage estimation.

			> Likely an incorrect or invalid review comment.
dto/gemini.go (1)

457-505: LGTM!

dto/openai_response.go (2)

223-244: LGTM!


256-274: 🗄️ Data Integrity & Integration

CacheCreationTokensTotal should keep the max of the two aliases, not sum them. CachedCreationTokens and CacheWriteTokens are carried through as alternate representations of the same cache-creation amount, and downstream billing already normalizes on that single total.

			> Likely an incorrect or invalid review comment.
dto/billing_usage.go (2)

1-71: LGTM!

Also applies to: 102-216


72-101: 🗄️ Data Integrity & Integration

InputTokensDetails != nil is not a billing bug
service/openaicompat/chat_to_responses_response.go only sets usage.InputTokensDetails when the source detail fields are already non-zero, and the other paths just copy an existing pointer. The fallback does not mask real usage in the current codebase.

			> Likely an incorrect or invalid review comment.
common/quota_math.go (1)

3-63: LGTM aside from the boundary issue flagged in saturateQuota above (all of these delegate to it).

Also applies to: 81-130

service/text_quota_test.go (1)

321-486: LGTM!

relay/channel/gemini/relay-gemini.go (2)

1061-1070: LGTM aside from the nil-deref risk flagged in patchGeminiZeroCompletionUsage above, which these call sites all inherit.

Also applies to: 1099-1144, 1465-1466, 1475-1480, 1617-1617, 1653-1653


1072-1097: 🩺 Stability & Availability

No issue hereservice.ResponseText2Usage always returns a non-nil *dto.Usage, so estimated.PromptTokens and estimated.CompletionTokens are safe to read.

			> Likely an incorrect or invalid review comment.
service/text_quota.go (4)

141-170: LGTM!


288-291: LGTM! Good defensive clamp on baseTokens, and clean integration with the new checked-decimal quota API.

Also applies to: 307-309, 319-321, 334-334


462-462: LGTM!

Also applies to: 513-523


370-396: 🩺 Stability & Availability

effectiveBillingUsage cannot return nil here. PostTextConsumeQuota only enters this block when usage != nil, and effectiveBillingUsage returns the original usage whenever it doesn't build a replacement.

			> Likely an incorrect or invalid review comment.

Comment thread common/quota_math.go
Comment thread service/billing.go
Comment on lines +21 to +36
if relayInfo != nil && relayInfo.QuotaClamp != nil {
return types.NewErrorWithStatusCode(
relayInfo.QuotaClamp,
types.ErrorCodeModelPriceError,
http.StatusBadRequest,
types.ErrOptionWithSkipRetry(),
)
}
if preConsumedQuota < 0 {
return types.NewErrorWithStatusCode(
fmt.Errorf("pre-consume quota cannot be negative: %d", preConsumedQuota),
types.ErrorCodeModelPriceError,
http.StatusBadRequest,
types.ErrOptionWithSkipRetry(),
)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant files and call sites.
for f in service/billing.go service/pre_consume_quota.go; do
  echo "===== $f ====="
  wc -l "$f"
  cat -n "$f" | sed -n '1,220p'
  echo
done

echo "===== call sites for PreConsumeBilling ====="
rg -n "PreConsumeBilling\(" -S .

echo "===== call sites for NewBillingSession ====="
rg -n "NewBillingSession\(" -S .

echo "===== definition of RelayInfo ====="
rg -n "type RelayInfo struct|type RelayInfo" -S .

Repository: MAX-API-Next/MAX-API

Length of output: 8839


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "===== service/billing.go ====="
cat -n service/billing.go | sed -n '1,220p'

echo "===== service/pre_consume_quota.go ====="
cat -n service/pre_consume_quota.go | sed -n '1,220p'

echo "===== NewBillingSession definition ====="
rg -n "func NewBillingSession|NewBillingSession\(" service -S -A 20 -B 5

echo "===== RelayInfo definition ====="
rg -n "type RelayInfo struct|type RelayInfo" -S -A 30 -B 5 .

Repository: MAX-API-Next/MAX-API

Length of output: 13818


Extract the shared pre-consume validation
PreConsumeBilling and PreConsumeQuota duplicate the same QuotaClamp and negative-quota checks. Pull them into a helper so both paths stay aligned.

🤖 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/billing.go` around lines 21 - 36, Extract the shared QuotaClamp and
negative preConsumedQuota validation from PreConsumeBilling and PreConsumeQuota
into a helper, then invoke that helper from both paths. Preserve the existing
error construction, status code, and skip-retry option, and return any
validation error before each path continues.

Comment thread service/log_info_generate.go
Comment thread service/log_info_generate.go
Comment thread web/default/src/features/system-settings/models/model-ratio-visual-editor.tsx 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: 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 `@service/billing_usage.go`:
- Line 120: Consolidate the duplicated InputTokenDetails-to-PromptTokensDetails
mapping by extracting one shared helper in the dto package, then update
fillPromptTokenDetailsFromInputDetails and UsageFromResponsesUsage to call it.
Preserve the existing conditional-if-zero behavior in
fillPromptTokenDetailsFromInputDetails while ensuring both paths use the same
six-field mapping.
🪄 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: e3f255c0-3d6d-471d-91df-a9ee9e85c18a

📥 Commits

Reviewing files that changed from the base of the PR and between 7abd87f and 5c9f603.

📒 Files selected for processing (10)
  • common/quota_math.go
  • common/quota_math_test.go
  • service/billing.go
  • service/billing_usage.go
  • service/log_info_generate.go
  • service/log_info_generate_test.go
  • service/pre_consume_quota.go
  • service/pre_consume_validation_test.go
  • service/text_quota_test.go
  • web/default/src/features/system-settings/models/model-ratio-visual-editor.tsx
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: CodeRabbit
  • GitHub Check: Backend checks
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for 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 direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.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 supports StreamOptions; if it does, add that channel to streamSupportedChannels.
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 instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first 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 in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for 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 the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • service/billing.go
  • service/pre_consume_validation_test.go
  • service/log_info_generate_test.go
  • service/pre_consume_quota.go
  • service/log_info_generate.go
  • service/text_quota_test.go
  • common/quota_math_test.go
  • common/quota_math.go
  • service/billing_usage.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/system-settings/models/model-ratio-visual-editor.tsx
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/system-settings/models/model-ratio-visual-editor.tsx
🔇 Additional comments (16)
web/default/src/features/system-settings/models/model-ratio-visual-editor.tsx (6)

998-1009: LGTM!


777-791: LGTM!


1042-1053: LGTM!


1132-1137: LGTM!


1168-1191: LGTM!


428-502: 🩺 Stability & Availability

isBasePricingUnset already handles undefined — it takes row?: ModelRow, so savedByName.get(row.name) is safe.

			> Likely an incorrect or invalid review comment.
common/quota_math.go (1)

65-79: LGTM!

common/quota_math_test.go (1)

86-106: LGTM!

service/log_info_generate.go (1)

19-42: LGTM!

service/log_info_generate_test.go (1)

53-123: LGTM!

service/billing.go (2)

18-36: Extraction correctly addresses the earlier duplicate-validation feedback.

validatePreConsumedQuota now centralizes the QuotaClamp and negative-quota checks shared by PreConsumeBilling and PreConsumeQuota, resolving the previously flagged duplication.


19-26: 🎯 Functional Correctness

No issue here *common.QuotaClamp implements error, and types.NewErrorWithStatusCode accepts an error, so this call is valid.

			> Likely an incorrect or invalid review comment.
service/billing_usage.go (1)

103-125: LGTM!

service/pre_consume_quota.go (1)

33-36: Good — resolves the previously flagged duplication.

This now delegates to the shared validatePreConsumedQuota (defined in service/billing.go), eliminating the duplicate QuotaClamp/negative-quota checks that were previously inlined separately in PreConsumeBilling and PreConsumeQuota, exactly as requested in the earlier review. Behavior is covered by the new TestPreConsumeValidationSharedByBillingAndQuota test.

service/pre_consume_validation_test.go (1)

1-61: LGTM!

service/text_quota_test.go (1)

14-14: LGTM!

Also applies to: 450-507

Comment thread service/billing_usage.go
if usage.TotalTokens == 0 {
usage.TotalTokens = usage.PromptTokens + usage.CompletionTokens
}
fillPromptTokenDetailsFromInputDetails(&usage.PromptTokensDetails, usage.InputTokensDetails)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider consolidating with the identical mapping in UsageFromResponsesUsage.

fillPromptTokenDetailsFromInputDetails maps the same six InputTokenDetails fields (CachedTokens, CachedCreationTokens, CacheWriteTokens, TextTokens, ImageTokens, AudioTokens) that UsageFromResponsesUsage in service/openaicompat/responses_to_chat.go already copies from InputTokensDetails into PromptTokensDetails (unconditionally there, conditionally-if-zero here). Two independent implementations of the same field list increase the risk that a future addition to InputTokenDetails gets updated in one place but not the other, silently dropping a billing-relevant field.

Consider extracting a single shared helper (e.g. in dto package) used by both call sites.

Also applies to: 127-149

🤖 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/billing_usage.go` at line 120, Consolidate the duplicated
InputTokenDetails-to-PromptTokensDetails mapping by extracting one shared helper
in the dto package, then update fillPromptTokenDetailsFromInputDetails and
UsageFromResponsesUsage to call it. Preserve the existing conditional-if-zero
behavior in fillPromptTokenDetailsFromInputDetails while ensuring both paths use
the same six-field mapping.

@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 (1)
web/default/src/features/users/components/user-quota-dialog.tsx (1)

68-83: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor duplication: reuse adjustmentValue instead of recomputing.

The override branch recomputes parseQuotaFromDollars(amountValue), duplicating the same computation already stored in adjustmentValue.

♻️ Proposed simplification
       case 'override': {
-        const overrideQuota = parseQuotaFromDollars(amountValue)
-        return `${t('Current quota')}: ${formatQuota(current)} → ${formatQuota(overrideQuota)}`
+        return `${t('Current quota')}: ${formatQuota(current)} → ${formatQuota(adjustmentValue)}`
       }
🤖 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/users/components/user-quota-dialog.tsx` around lines
68 - 83, In getPreviewText, update the override branch to reuse the existing
adjustmentValue rather than calling parseQuotaFromDollars(amountValue) again,
while preserving the current quota preview formatting.
🤖 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/users/lib/quota-safety.ts`:
- Around line 21-25: Simplify isSafeQuotaValue to rely solely on
Number.isSafeInteger(value) and remove the redundant Math.abs(value) <=
Number.MAX_SAFE_INTEGER condition, preserving the function’s existing boolean
behavior.

---

Outside diff comments:
In `@web/default/src/features/users/components/user-quota-dialog.tsx`:
- Around line 68-83: In getPreviewText, update the override branch to reuse the
existing adjustmentValue rather than calling parseQuotaFromDollars(amountValue)
again, while preserving the current quota preview formatting.
🪄 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: f50cb7b6-afb6-422a-b5e3-a58de8ca67ec

📥 Commits

Reviewing files that changed from the base of the PR and between 5c9f603 and 5291db2.

📒 Files selected for processing (19)
  • common/verification.go
  • common/verification_test.go
  • controller/misc.go
  • controller/user.go
  • controller/user_setting_test.go
  • dto/billing_usage_test.go
  • dto/openai_response.go
  • service/billing_usage.go
  • service/openaicompat/responses_compat_test.go
  • service/openaicompat/responses_to_chat.go
  • web/default/src/features/users/components/user-quota-dialog.tsx
  • web/default/src/features/users/lib/quota-safety.test.ts
  • web/default/src/features/users/lib/quota-safety.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
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: CodeRabbit
🧰 Additional context used
📓 Path-based instructions (6)
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/users/lib/quota-safety.test.ts
  • web/default/src/features/users/lib/quota-safety.ts
  • web/default/src/features/users/components/user-quota-dialog.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/users/lib/quota-safety.test.ts
  • web/default/src/features/users/lib/quota-safety.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/users/lib/quota-safety.test.ts
  • web/default/src/features/users/lib/quota-safety.ts
  • web/default/src/features/users/components/user-quota-dialog.tsx
web/default/src/**/*.test.ts

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

工具函数与纯逻辑应优先编写单元测试;测试文件应命名为 *.test.ts

Files:

  • web/default/src/features/users/lib/quota-safety.test.ts
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for 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 direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.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 supports StreamOptions; if it does, add that channel to streamSupportedChannels.
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 instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first 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 in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for 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 the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • controller/misc.go
  • service/openaicompat/responses_compat_test.go
  • dto/openai_response.go
  • dto/billing_usage_test.go
  • common/verification_test.go
  • common/verification.go
  • controller/user.go
  • service/openaicompat/responses_to_chat.go
  • controller/user_setting_test.go
  • service/billing_usage.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 omitempty so that absent fields stay omitted while explicit zero/false values are preserved.

Files:

  • dto/openai_response.go
  • dto/billing_usage_test.go
🔇 Additional comments (22)
web/default/src/features/users/lib/quota-safety.test.ts (1)

1-55: LGTM!

web/default/src/features/users/lib/quota-safety.ts (1)

27-39: LGTM!

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

1860-1860: LGTM!

Also applies to: 2966-2966, 3605-3605, 4816-4816

service/openaicompat/responses_compat_test.go (1)

292-292: LGTM!

Also applies to: 321-321

web/default/src/features/users/components/user-quota-dialog.tsx (1)

60-66: LGTM!

Also applies to: 88-101, 185-196

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

1860-1860: LGTM!

Also applies to: 2966-2966, 3605-3605, 4816-4816

controller/misc.go (1)

351-358: LGTM!

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

1857-1861: LGTM!

Also applies to: 2965-2967, 3604-3606, 4815-4817

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

1860-1860: LGTM!

Also applies to: 2966-2966, 3605-3605, 4816-4816

common/verification_test.go (1)

3-7: LGTM! Good coverage of the failure/panic/concurrent-claim edge cases for the new claim-based verification flow.

Also applies to: 25-45, 47-67, 69-111

common/verification.go (1)

11-15: LGTM! Solid claim/reserve pattern: exclusive concurrent access, panic-safe rollback via defer, and correct no-op guard against concurrent re-registration.

Also applies to: 48-57, 59-94, 96-102

controller/user.go (1)

38-40: LGTM! The JS-safe-integer bound and symmetric subtraction guard are consistent with the existing addition/override validation and are backed by matching unit tests.

Also applies to: 1004-1017, 1105-1113

controller/user_setting_test.go (3)

220-249: LGTM! Bounds assertions correctly mirror the new isValidQuotaSubtraction implementation.


251-287: LGTM! Good regression test for the "code stays valid on DB failure" fix — forces a real GORM update error and checks both the code and the password remain unchanged.


302-332: Minor: description says "replaced," but the old test is still present.

The line-range summary states this test replaced the previous quota upper-bound test, but TestManageUserRejectsQuotaValueAboveInt64Max (unchanged, above this block) is still in the file — so it was added alongside, not replacing it. Not a code issue, just a documentation nuance; the new test itself is correctly implemented and more robust (avoids the int64-JSON-overflow ambiguity of the older test).

service/billing_usage.go (1)

127-129: Resolves prior duplication concern.

This consolidates the InputTokenDetails→PromptTokensDetails field mapping into the shared dto.CopyInputTokenDetails helper, addressing the previously flagged duplication between this function and UsageFromResponsesUsage.

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

1857-1861: LGTM!

Also applies to: 2965-2967, 3604-3606, 4815-4817

dto/openai_response.go (2)

224-230: LGTM!


259-287: LGTM!

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

1860-1860: LGTM!

Also applies to: 2966-2966, 3605-3605, 4816-4816

dto/billing_usage_test.go (1)

66-104: LGTM!

service/openaicompat/responses_to_chat.go (1)

138-143: LGTM!

Comment thread web/default/src/features/users/lib/quota-safety.ts 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: 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 `@web/default/src/features/users/lib/quota-safety.ts`:
- Around line 21-22: Update isSafeQuotaValue to explicitly annotate its return
type as boolean while preserving the existing Number.isSafeInteger validation.
🪄 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: 8e7c6d72-55fb-42e9-92b6-fed8fb377213

📥 Commits

Reviewing files that changed from the base of the PR and between 5291db2 and 444a05e.

📒 Files selected for processing (1)
  • web/default/src/features/users/lib/quota-safety.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: CodeRabbit
🧰 Additional context used
📓 Path-based instructions (3)
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/users/lib/quota-safety.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/users/lib/quota-safety.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/users/lib/quota-safety.ts

Comment thread web/default/src/features/users/lib/quota-safety.ts Outdated
@CSCITech
CSCITech merged commit ec8d02a into main Jul 13, 2026
3 checks passed
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