Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
8508fb7
update
CSCITech Sep 7, 2026
bcb6d23
fix: preserve licensing terms and isolate H3 test
CSCITech Sep 7, 2026
6f3ab9e
fix: preserve timeout sweep scan budget
CSCITech Sep 7, 2026
8ecdde6
fix: gate task plan pricing by adaptor
CSCITech Sep 7, 2026
f9afac3
fix: align task billing snapshot invariants
CSCITech Sep 7, 2026
f54d92c
fix: expose pending task settlements
CSCITech Sep 7, 2026
2dc6b3d
fix: complete manual task billing reconciliation
CSCITech Sep 7, 2026
9008466
fix: close task settlement review gaps
CSCITech Sep 7, 2026
77462d2
fix: protect manual settlement approvals
CSCITech Sep 7, 2026
2d9812b
fix: complete minimax task result settlement flow
CSCITech Sep 8, 2026
6e7533b
fix: address coderabbit review followups
CSCITech Sep 8, 2026
4df9447
fix: close latest task billing review findings
CSCITech Sep 8, 2026
5ba9b1b
fix: address latest task billing review findings
CSCITech Sep 8, 2026
78a8967
fix: address latest frontend review findings
CSCITech Sep 8, 2026
e308d32
fix: harden task usage and settlement quota validation
CSCITech Sep 8, 2026
908e1f9
fix: close task billing review findings
CSCITech Sep 9, 2026
bc1465c
fix: narrow configured task result fallback
CSCITech Sep 9, 2026
54bc207
fix: tighten task billing validation and polling
CSCITech Sep 9, 2026
4807b4f
fix: translate structured image pricing units
CSCITech Sep 9, 2026
8022c0b
fix: scope task id fallback to minimax envelopes
CSCITech Sep 9, 2026
8034331
fix: close task protocol and pricing review findings
CSCITech Sep 9, 2026
7e7057f
test: cover task rate card helpers
CSCITech Sep 9, 2026
24c5157
fix: recover wrapped task results and finalized billing state
CSCITech Sep 9, 2026
2169307
fix: harden task recovery and settlement review
CSCITech Sep 9, 2026
7ff1a9c
fix: harden task recovery and pricing fallback
CSCITech Sep 9, 2026
ad5b623
test: clarify pricing render helper contract
CSCITech Sep 9, 2026
9c77689
fix: bound task usage and localize audit
CSCITech Sep 9, 2026
5c2b228
fix: keep transient task queries retryable
CSCITech Sep 9, 2026
8341e7d
fix: preserve task timestamps on settlement rollback
CSCITech Sep 9, 2026
896b1d3
fix: resume pending task settlements safely
CSCITech Sep 9, 2026
eed94f0
fix: reject empty task polling results
CSCITech Sep 9, 2026
2552994
test: satisfy task settlement errcheck
CSCITech Sep 9, 2026
e7082de
fix: harden MiniMax task result handling
CSCITech Sep 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ jobs:
files: |
max-api-*
checksums-linux.txt
NOTICE
Comment thread
coderabbitai[bot] marked this conversation as resolved.
LICENSE
THIRD-PARTY-LICENSES.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Expand Down Expand Up @@ -107,6 +110,9 @@ jobs:
files: |
max-api-macos-*
checksums-macos.txt
NOTICE
LICENSE
THIRD-PARTY-LICENSES.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Expand Down Expand Up @@ -155,5 +161,8 @@ jobs:
files: |
max-api-*.exe
checksums-windows.txt
NOTICE
LICENSE
THIRD-PARTY-LICENSES.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
48 changes: 36 additions & 12 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
max-api Notices

==== Third-Party Notices ====

This product includes third-party open source software. Copyright notices and
license terms for direct third-party dependencies are listed in
THIRD-PARTY-LICENSES.md.

Redistributed modified versions must retain this complete NOTICE file,
including its third-party, attribution, and additional-term notices.

==== GNU Affero General Public License v3.0 Notices ====

max-api
Copyright (c) MAX-API-Next and contributors.
Copyright (c) MAX-API-Next(https://github.com/MAX-API-Next) and contributors.

This project is licensed under the GNU Affero General Public License v3.0.
See LICENSE for the full project license terms.
Expand All @@ -24,10 +35,33 @@ https://github.com/MAX-API-Next/MAX-API
Modified versions must not misrepresent the origin of the software and must
mark their changes in accordance with AGPLv3 Section 7(c).

==== MAX API Temporary Commercial Permission ====

In addition to, and not as a replacement for, AGPLv3, a derivative project
used only by its operator automatically receives a no-fee, non-perpetual
temporary commercial permission for the MAX API additions and modifications
that the MAX API project maintainers have the right to license, without a
separate application or approval, while it keeps either of the following
clearly visible in a prominent homepage, footer, about, legal, or attribution
location:

* a link to https://github.com/MAX-API-Next/MAX-API; or
* an acknowledgement of the MAX-API-Next community with a link to
https://github.com/MAX-API-Next.

This temporary permission does not cover, replace, or waive AGPLv3 or any
license obligation for One API, New API, or other upstream material. It ceases
to apply if the display condition is no longer met, or if it expires, is
amended, or is terminated by a later notice published in this NOTICE, the
project README, or the official MAX-API-Next community. Rights independently
granted by AGPLv3 remain unaffected. Continued use outside this temporary
permission must comply with AGPLv3 or a separate written authorization from
the applicable rights holder.

==== Preserved New API Upstream Notice ====

new-api
Copyright (c) QuantumNous and contributors.
Copyright (c) New API(https://github.com/QuantumNous/new-api/) contributors.
Comment thread
CSCITech marked this conversation as resolved.

This project includes software derived from New API, which is licensed under
the GNU Affero General Public License v3.0. The following additional terms from
Expand All @@ -49,16 +83,6 @@ https://github.com/QuantumNous/new-api
Modified versions must not misrepresent the origin of the software and must
mark their changes in accordance with AGPLv3 Section 7(c).

==== Third-Party Notices ====

This product includes third-party open source software. Copyright notices and
license terms for direct third-party dependencies are listed in
THIRD-PARTY-LICENSES.md.

Apache-2.0 upstream NOTICE entries identified for direct dependencies are
reproduced below. Preserve this file with Docker images, standalone binaries,
frontend bundles, and Electron desktop installers distributed to users.

==== Apache-2.0 Notices ====

AWS SDK for Go
Expand Down
6 changes: 5 additions & 1 deletion README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,11 @@ Multi-node deployments must share `SESSION_SECRET` while using a different `NODE

## 🤝 Legal notes and derivative use

If you create or distribute a derivative version, read [NOTICE](./NOTICE) and [LICENSE](./LICENSE) in full and preserve the legal notices, attributions, original-project link, and change marking required there.
If you create or distribute a derivative version, read [NOTICE](./NOTICE) and [LICENSE](./LICENSE) in full and preserve the legal notices, attributions, original-project link, and change marking required there in a prominent location.

In addition to the default AGPLv3 license, a derivative project used only by its operator automatically receives, without a separate application or approval, the no-fee, non-perpetual temporary commercial permission described in [NOTICE](./NOTICE) for MAX API additions and modifications that the project maintainers have the right to license, while it continuously keeps either the [MAX-API-Next/MAX-API](https://github.com/MAX-API-Next/MAX-API) project link or an acknowledgement of the [MAX-API-Next](https://github.com/MAX-API-Next) community clearly visible in a prominent homepage, footer, About, legal, or attribution location.

This temporary permission does not cover, replace, or waive AGPLv3 or any license obligation for One API, New API, or other upstream material. It ceases to apply if the display condition is no longer met, or if it expires, is amended, or is terminated through NOTICE, the README, or an official MAX-API-Next community notice. Rights independently granted by AGPLv3 remain unaffected; continued use outside the temporary permission must comply with AGPLv3 or a separate written authorization from the applicable rights holder. See [NOTICE](./NOTICE) for the complete terms.

## 📜 License

Expand Down
6 changes: 5 additions & 1 deletion README.fr.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,11 @@ Les déploiements multi-nœuds doivent partager `SESSION_SECRET`, tout en utilis

## 🤝 Mentions légales et développements dérivés

Si vous créez ou distribuez une version dérivée, lisez intégralement [NOTICE](./NOTICE) et [LICENSE](./LICENSE), puis conservez les mentions légales, attributions, lien vers le projet d'origine et marquage des modifications qui y sont requis.
Si vous créez ou distribuez une version dérivée, lisez intégralement [NOTICE](./NOTICE) et [LICENSE](./LICENSE), puis conservez à un emplacement bien visible les mentions légales, attributions, lien vers le projet d'origine et marquage des modifications qui y sont requis.

En complément de la licence AGPLv3 par défaut, un projet dérivé réservé à l'usage de son opérateur bénéficie automatiquement, sans demande ni approbation distincte, de l'autorisation commerciale temporaire, gratuite et non permanente décrite dans [NOTICE](./NOTICE) pour les ajouts et modifications de MAX API que les mainteneurs du projet ont le droit de concéder, tant qu'il affiche clairement soit le lien du projet [MAX-API-Next/MAX-API](https://github.com/MAX-API-Next/MAX-API), soit une mention de la communauté [MAX-API-Next](https://github.com/MAX-API-Next), à un emplacement bien visible de la page d'accueil, du pied de page, de la page À propos, des mentions légales ou des attributions.

Cette autorisation temporaire ne couvre, ne remplace ni ne supprime les obligations de l'AGPLv3, de One API, de New API ou de tout autre composant amont. Elle cesse de s'appliquer si la condition d'affichage n'est plus respectée, ou si elle expire, est modifiée ou prend fin par une mention publiée dans NOTICE, le README ou la communauté officielle MAX-API-Next. Les droits accordés indépendamment par l'AGPLv3 restent inchangés ; toute utilisation poursuivie hors de cette autorisation temporaire doit respecter l'AGPLv3 ou faire l'objet d'une autorisation écrite distincte du titulaire de droits concerné. Consultez [NOTICE](./NOTICE) pour les conditions complètes.

## 📜 Licence

Expand Down
6 changes: 5 additions & 1 deletion README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,11 @@ docker compose up -d

## 🤝 法的事項と二次開発

二次開発版を作成または配布する場合は、[NOTICE](./NOTICE) と [LICENSE](./LICENSE) を全文確認し、そこに定められた法的表示、帰属、原プロジェクトへのリンク、変更表示を保持してください。
二次開発版を作成または配布する場合は、[NOTICE](./NOTICE) と [LICENSE](./LICENSE) を全文確認し、そこに定められた法的表示、帰属、原プロジェクトへのリンク、変更表示を目立つ場所に保持してください。

既定の AGPLv3 ライセンスに加え、運営者自身のみが使用する二次開発プロジェクトは、プロジェクトの保守者が許諾する権利を有する MAX API の追加・変更部分について、[NOTICE](./NOTICE) に定める無料かつ非永久の一時的商用許諾を、別途の申請や承認なく自動的に受けられます。適用中は、ホームページ、フッター、「概要」、法的表示、または帰属表示の目立つ場所に、[MAX-API-Next/MAX-API](https://github.com/MAX-API-Next/MAX-API) のプロジェクトリンク、または [MAX-API-Next](https://github.com/MAX-API-Next) コミュニティへの謝辞のいずれかを明確に表示し続ける必要があります。

この一時的許諾は、AGPLv3、One API、New API、その他の上流素材に関するライセンス義務を対象とせず、置き換えも免除もしません。表示条件を満たさなくなった場合、または NOTICE、README、MAX-API-Next 公式コミュニティの告知により期限切れ、変更、終了となった場合は適用されなくなります。AGPLv3 から独立して付与される権利には影響せず、一時的許諾の範囲外で利用を継続する場合は AGPLv3 を遵守するか、該当する権利者から別途書面による許諾を得る必要があります。完全な条件は [NOTICE](./NOTICE) を参照してください。

## 📜 ライセンス

Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,11 @@ docker compose up -d

## 🤝 法律说明与二次开发

如果你基于本项目进行二次开发或分发,请先完整阅读 [NOTICE](./NOTICE) 和 [LICENSE](./LICENSE),并按其中要求保留法律声明、归属信息、原项目链接和修改标记。
如果你基于本项目进行二次开发或分发,请先完整阅读 [NOTICE](./NOTICE) 和 [LICENSE](./LICENSE),并按其中要求在项目明显位置保留法律声明、归属信息、原项目链接和修改标记。
Comment thread
CSCITech marked this conversation as resolved.

除 AGPLv3 默认授权外,当前阶段,仅供自身使用的二次开发项目如持续在项目主页、页脚、“关于”、法律声明或其他明显位置清晰展示 [MAX-API-Next/MAX-API](https://github.com/MAX-API-Next/MAX-API) 项目链接,或对 [MAX-API-Next](https://github.com/MAX-API-Next) 社区的致谢,即自动免费获得 MAX API 项目方对其有权授权的新增与修改部分所提供的非永久临时商用授权,无需另行申请或审批。

该临时授权不覆盖、替代或免除 AGPLv3、One API、New API 或其他上游许可义务;展示条件不再满足,或项目方通过 NOTICE、README 或 MAX-API-Next 官方社区公告其到期、调整或终止时,该临时授权即不再适用。AGPLv3 独立授予的权利不受影响;超出临时授权继续使用时,须遵守 AGPLv3 或另行取得适用权利人的书面授权。完整条件以 [NOTICE](./NOTICE) 为准。

## 📜 许可证

Expand Down
6 changes: 5 additions & 1 deletion README.zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,11 @@ docker compose up -d

## 🤝 法律说明与二次开发

如果你基于本项目进行二次开发或分发,请先完整阅读 [NOTICE](./NOTICE) 和 [LICENSE](./LICENSE),并按其中要求保留法律声明、归属信息、原项目链接和修改标记。
如果你基于本项目进行二次开发或分发,请先完整阅读 [NOTICE](./NOTICE) 和 [LICENSE](./LICENSE),并按其中要求在项目明显位置保留法律声明、归属信息、原项目链接和修改标记。

除 AGPLv3 默认授权外,当前阶段,仅供自身使用的二次开发项目如持续在项目主页、页脚、“关于”、法律声明或其他明显位置清晰展示 [MAX-API-Next/MAX-API](https://github.com/MAX-API-Next/MAX-API) 项目链接,或对 [MAX-API-Next](https://github.com/MAX-API-Next) 社区的致谢,即自动免费获得 MAX API 项目方对其有权授权的新增与修改部分所提供的非永久临时商用授权,无需另行申请或审批。

该临时授权不覆盖、替代或免除 AGPLv3、One API、New API 或其他上游许可义务;展示条件不再满足,或项目方通过 NOTICE、README 或 MAX-API-Next 官方社区公告其到期、调整或终止时,该临时授权即不再适用。AGPLv3 独立授予的权利不受影响;超出临时授权继续使用时,须遵守 AGPLv3 或另行取得适用权利人的书面授权。完整条件以 [NOTICE](./NOTICE) 为准。

## 📜 许可证

Expand Down
6 changes: 5 additions & 1 deletion README.zh_TW.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,11 @@ docker compose up -d

## 🤝 法律說明與二次開發

如果你基於本專案進行二次開發或散布,請先完整閱讀 [NOTICE](./NOTICE) 和 [LICENSE](./LICENSE),並依其中要求保留法律聲明、歸屬資訊、原專案連結和修改標記。
如果你基於本專案進行二次開發或散布,請先完整閱讀 [NOTICE](./NOTICE) 和 [LICENSE](./LICENSE),並依其中要求在專案明顯位置保留法律聲明、歸屬資訊、原專案連結和修改標記。

除 AGPLv3 預設授權外,現階段,僅供自身使用的二次開發專案如持續在專案首頁、頁尾、「關於」、法律聲明或其他明顯位置清楚展示 [MAX-API-Next/MAX-API](https://github.com/MAX-API-Next/MAX-API) 專案連結,或對 [MAX-API-Next](https://github.com/MAX-API-Next) 社群的致謝,即自動免費取得 MAX API 專案方對其有權授權的新增與修改部分所提供的非永久臨時商用授權,無需另行申請或審批。

此臨時授權不涵蓋、取代或免除 AGPLv3、One API、New API 或其他上游授權義務;展示條件不再符合,或專案方透過 NOTICE、README 或 MAX-API-Next 官方社群公告其到期、調整或終止時,此臨時授權即不再適用。AGPLv3 獨立授予的權利不受影響;超出臨時授權繼續使用時,須遵守 AGPLv3 或另行取得適用權利人的書面授權。完整條件以 [NOTICE](./NOTICE) 為準。

## 📜 許可證

Expand Down
1 change: 1 addition & 0 deletions controller/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var auditContentTemplates = map[string]string{
"billing.reconciliation_blocking_policy_update": "Updated billing reconciliation default user-blocking policy to ${block_user_by_default}",
"billing.reconciliation_review": "Reviewed billing settlement ${settlement_id} (block user: ${block_user})",
"billing.reconciliation_review_batch": "Reviewed and closed ${count} billing reconciliation alerts",
"billing.manual_task_settlement_complete": "Completed manual task billing settlement ${settlement_id} with exact quota ${actual_quota}",
Comment thread
coderabbitai[bot] marked this conversation as resolved.

"channel.create": "Created channel ${name} (type ${type}, count ${count})",
"channel.update": "Updated channel ${name} (ID: ${id})",
Expand Down
77 changes: 76 additions & 1 deletion controller/smart_ops_alert.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ type billingSettlementBatchReviewRequest struct {
Items []model.BillingSettlementReviewTarget `json:"items"`
}

type manualTaskBillingCompletionRequest struct {
Revision int64 `json:"revision"`
ActualQuota *int64 `json:"actual_quota"`
Note string `json:"note"`
}

// ReviewBillingSettlements closes a bounded set of current reconciliation
// alerts after the administrator acknowledges them.
func ReviewBillingSettlements(c *gin.Context) {
Expand All @@ -84,6 +90,9 @@ func ReviewBillingSettlements(c *gin.Context) {
case errors.Is(err, model.ErrBillingSettlementReviewConflict):
status = http.StatusConflict
message = "one or more billing settlement alerts changed; refresh and review again"
case errors.Is(err, model.ErrBillingSettlementCompletionRequired):
status = http.StatusConflict
message = "one or more task settlements require an exact final quota and cannot be batch closed"
}
if status == http.StatusInternalServerError {
common.SysError(fmt.Sprintf("failed to review billing settlements: %v", err))
Expand Down Expand Up @@ -139,6 +148,9 @@ func ReviewBillingSettlement(c *gin.Context) {
case errors.Is(err, model.ErrBillingSettlementReviewConflict):
status = http.StatusConflict
message = "billing settlement is no longer pending manual reconciliation"
case errors.Is(err, model.ErrBillingSettlementCompletionRequired):
status = http.StatusConflict
message = "task settlement requires an exact final quota before it can be closed"
}
if status == http.StatusInternalServerError {
common.SysError(fmt.Sprintf("failed to review billing settlement %d: %v", id, err))
Expand All @@ -161,8 +173,71 @@ func ReviewBillingSettlement(c *gin.Context) {
})
}

// CompleteManualTaskBillingSettlement applies a root administrator's exact
// final quota to a reconciliation-only task settlement. Zero is a valid and
// explicit financial result; omission is rejected.
func CompleteManualTaskBillingSettlement(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil || id <= 0 {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "invalid billing settlement id"})
return
}
var request manualTaskBillingCompletionRequest
if err := common.DecodeJson(c.Request.Body, &request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "invalid manual task billing completion request"})
return
}
result, err := service.CompleteManualTaskBillingSettlement(
id,
request.Revision,
c.GetInt("id"),
request.ActualQuota,
request.Note,
)
if err != nil {
status := http.StatusInternalServerError
message := "failed to complete manual task billing settlement"
switch {
case errors.Is(err, service.ErrInvalidBillingSettlementReconciliationReview):
status = http.StatusBadRequest
message = err.Error()
case errors.Is(err, model.ErrBillingSettlementReviewConflict),
errors.Is(err, model.ErrBillingSettlementOperationConflict),
errors.Is(err, model.ErrBillingSettlementTaskConflict),
errors.Is(err, model.ErrBillingSettlementManualReview):
status = http.StatusConflict
message = "manual task billing settlement could not be applied safely; refresh and reconcile the current record"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
case errors.Is(err, model.ErrTokenQuotaInsufficient):
status = http.StatusConflict
message = "the token quota mirror is inconsistent; repair the token record before completing this settlement"
case errors.Is(err, model.ErrSubscriptionRefundClamped):
status = http.StatusConflict
message = "the subscription usage mirror is lower than the refund; repair the subscription record before completing this settlement"
case errors.Is(err, model.ErrSubscriptionSettlementUnbound),
errors.Is(err, model.ErrSubscriptionSettlementPeriodChanged):
status = http.StatusConflict
message = "the subscription reservation is unbound or its period changed; escalate this record for manual reconciliation"
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
if status == http.StatusInternalServerError {
common.SysError(fmt.Sprintf("failed to complete manual task billing settlement %d: %v", id, err))
}
c.JSON(status, gin.H{"success": false, "message": message})
return
}
recordManageAudit(c, "billing.manual_task_settlement_complete", map[string]interface{}{
"settlement_id": result.SettlementID,
"task_id": result.TaskID,
"target_user_id": result.UserID,
"operation_key": result.OperationKey,
"actual_quota": result.ActualQuota,
"applied_funding_delta": result.AppliedFundingDelta,
"already_applied": result.AlreadyApplied,
})
c.JSON(http.StatusOK, gin.H{"success": true, "data": result})
}

// GetBillingSettlementReconciliation exposes bounded, read-only evidence for
// unresolved positive final settlements. It does not retry or mutate records.
// open billing reconciliation records. It does not retry or mutate records.
func GetBillingSettlementReconciliation(c *gin.Context) {
limit, err := parseIntQuery(c, "limit")
if err != nil {
Expand Down
Loading
Loading