Skip to content

fix: include tiered billing models in model listing - #4431

Merged
Calcium-Ion merged 1 commit into
QuantumNous:mainfrom
yyhhyyyyyy:fix/tiered-billing-model-list
Apr 24, 2026
Merged

fix: include tiered billing models in model listing#4431
Calcium-Ion merged 1 commit into
QuantumNous:mainfrom
yyhhyyyyyy:fix/tiered-billing-model-list

Conversation

@yyhhyyyyyy

@yyhhyyyyyy yyhhyyyyyy commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

⚠️ 提交说明 / PR Notice

Important

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

📝 变更描述 / Description

(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)
修复配置“阶梯定价”的模型不会出现在 /v1/models 返回结果中的问题。

🚀 变更类型 / Type of change

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

🔗 关联任务 / Related Issue

✅ 提交前检查项 / Checklist

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

📸 运行证明 / Proof of Work

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

修改前:
image

修改后:
image

Summary by CodeRabbit

  • Bug Fixes

    • Improved model filtering logic to properly exclude models without complete billing configuration.
    • Fixed billing settings cache invalidation to ensure configuration updates are correctly reflected.
  • Tests

    • Added comprehensive tests for tiered billing model filtering behavior under standard and token-limit modes.

@coderabbitai

coderabbitai Bot commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

The PR refactors model billing configuration detection to include tiered billing expressions. It introduces HasModelBillingConfig() as a centralized helper to determine whether a model has any billing configuration and updates ListModels filtering to use this helper instead of ratio_setting, ensuring models with only tiered pricing are included in endpoint responses.

Changes

Cohort / File(s) Summary
Billing Config Centralization
model/pricing.go
Added InvalidatePricingCache() to clear pricing caches and HasModelBillingConfig(modelName) to check if a model has price/ratio or non-empty tiered billing expressions. Tightened BillingExpr assignment logic to only set when expression is non-empty after trimming.
Model List Filtering Updates
controller/model.go, relay/helper/price.go
Updated ListModels filtering to call HasModelBillingConfig() instead of ratio_setting checks. Simplified ContainPriceOrRatio() to delegate to the new centralized helper.
Cache Invalidation & Testing
model/option.go, controller/model_list_test.go
Added billing_setting namespace handling in handleConfigUpdate() to trigger cache invalidation. New comprehensive test file verifying model inclusion/exclusion for tiered billing under standard and token-limit modes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 A tiered model hopped through the gate,
No price tag, but we calculate!
Cache cleared with a billing_setting call,
Now models with just tiers don't fall,
HasModelBillingConfig makes all whole! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: including tiered billing models in model listing, which directly addresses the PR's primary objective.
Linked Issues check ✅ Passed The code changes directly address issue #4430 by implementing model.HasModelBillingConfig() to recognize tiered billing models and including them in /v1/models responses.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the tiered billing model listing issue; no unrelated modifications or scope creep detected.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
controller/model_list_test.go (1)

58-94: Nit: initModelListColumnNames relies on a subtle post-close invariant.

This helper calls model.InitDB() purely as a side effect to initialize commonGroupCol/commonKeyCol, then closes the connection while leaving those package-level column-name variables set. It works but is easy to break if someone later clears or reassigns those globals during InitDB teardown.

Consider extracting a small dedicated setter (e.g., model.SetColumnNamesForSQLite()) to make the intent explicit and the test setup less coupled to InitDB's internals. Optional — fine to defer.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controller/model_list_test.go` around lines 58 - 94, The test helper
initModelListColumnNames relies on side effects from model.InitDB to populate
package globals commonGroupCol/commonKeyCol and then closes the DB; extract a
dedicated setter in model (e.g., model.SetColumnNamesForSQLite or
model.InitColumnNamesForSQLite) that accepts the SQLite DSN or sets column-name
vars directly, update initModelListColumnNames to call that new setter instead
of model.InitDB and removing the DB open/close and SQL_DSN juggling, and keep
commonGroupCol/commonKeyCol assignment logic inside the new function so tests no
longer depend on InitDB internals.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@model/pricing.go`:
- Around line 80-87: InvalidatePricingCache currently sets pricingMap,
vendorsList, and lastGetPricingTime to nil/zero but leaves dependent caches
(modelSupportEndpointTypes, supportedEndpointMap, modelEnableGroups,
modelQuotaTypeMap) populated causing stale reads; update InvalidatePricingCache
to also nil those dependent maps under the same updatePricingLock (or the
appropriate locks if different) so callers like GetModelSupportEndpointTypes and
GetSupportedEndpointMap see the cleared state immediately, or alternatively
document the narrower invalidation scope—make the change in the
InvalidatePricingCache function and ensure you touch the specific symbols
modelSupportEndpointTypes, supportedEndpointMap, modelEnableGroups,
modelQuotaTypeMap while holding updatePricingLock.

---

Nitpick comments:
In `@controller/model_list_test.go`:
- Around line 58-94: The test helper initModelListColumnNames relies on side
effects from model.InitDB to populate package globals
commonGroupCol/commonKeyCol and then closes the DB; extract a dedicated setter
in model (e.g., model.SetColumnNamesForSQLite or model.InitColumnNamesForSQLite)
that accepts the SQLite DSN or sets column-name vars directly, update
initModelListColumnNames to call that new setter instead of model.InitDB and
removing the DB open/close and SQL_DSN juggling, and keep
commonGroupCol/commonKeyCol assignment logic inside the new function so tests no
longer depend on InitDB internals.
🪄 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: CHILL

Plan: Pro

Run ID: b39e6701-247a-476a-9918-da333037a660

📥 Commits

Reviewing files that changed from the base of the PR and between 2e610e5 and 723aeae.

📒 Files selected for processing (5)
  • controller/model.go
  • controller/model_list_test.go
  • model/option.go
  • model/pricing.go
  • relay/helper/price.go

Comment thread model/pricing.go
Comment on lines +80 to +87
func InvalidatePricingCache() {
updatePricingLock.Lock()
defer updatePricingLock.Unlock()

pricingMap = nil
vendorsList = nil
lastGetPricingTime = time.Time{}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Stale reads from dependent caches between invalidation and next refresh.

InvalidatePricingCache only clears pricingMap, vendorsList, and lastGetPricingTime, but leaves the related caches populated by updatePricing: modelSupportEndpointTypes, supportedEndpointMap, modelEnableGroups, and modelQuotaTypeMap. Callers that read these maps directly (e.g., GetModelSupportEndpointTypes, GetSupportedEndpointMap) will continue to return pre-invalidation data until the next GetPricing() call triggers a rebuild.

For a billing_setting update this is probably fine (the affected fields are BillingMode/BillingExpr on pricing entries, which do get refreshed via pricingMap=nil), but if this helper is ever reused for a wider config change, the behavior could surprise. Consider either documenting the scope or also nilling the dependent maps under their respective locks.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@model/pricing.go` around lines 80 - 87, InvalidatePricingCache currently sets
pricingMap, vendorsList, and lastGetPricingTime to nil/zero but leaves dependent
caches (modelSupportEndpointTypes, supportedEndpointMap, modelEnableGroups,
modelQuotaTypeMap) populated causing stale reads; update InvalidatePricingCache
to also nil those dependent maps under the same updatePricingLock (or the
appropriate locks if different) so callers like GetModelSupportEndpointTypes and
GetSupportedEndpointMap see the cleared state immediately, or alternatively
document the narrower invalidation scope—make the change in the
InvalidatePricingCache function and ensure you touch the specific symbols
modelSupportEndpointTypes, supportedEndpointMap, modelEnableGroups,
modelQuotaTypeMap while holding updatePricingLock.

@Calcium-Ion
Calcium-Ion merged commit e3d64cb into QuantumNous:main Apr 24, 2026
2 checks passed
Jinxuans referenced this pull request in TokFlux-Org/TokFlux May 9, 2026
fix: include tiered billing models in model listing
dreamlx pushed a commit to dreamlx/new-api that referenced this pull request May 24, 2026
…edBillingModel

Upstream test added in v0.13.1 (QuantumNous#4431) forgot to call setupModelListControllerTestDB(t)
in its test body, leaving common.RedisEnabled at its default true. Without
Redis actually initialized, cacheGetUserBase nil-deref panics when ListModels
walks the user/group cache path for an anonymous (id=0) context.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
xyfacai pushed a commit to xyfacai/new-api that referenced this pull request May 30, 2026
…g-model-list

fix: include tiered billing models in model listing
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.

使用阶梯定价的模型未在/v1/models接口正常返回

2 participants