feat(openai): 支持指定重置卡临期定时使用 - #6290
Open
zenor0 wants to merge 2 commits into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景与动机
当前 OpenAI 重置卡支持手动立即使用,以及按照 5h/7d 用量阈值自动使用,但还无法针对某一张即将到期的重置卡提前安排使用。
重置卡不用白不用。有效期一长,很容易忘记手动使用,等想起来时,重置机会可能已经过期。本 PR 增加“指定重置卡临期定时使用”能力,让管理员选择具体重置卡,并设置在到期前多少分钟自动执行。
设计概览
整体流程如下:
credit_id + expires_at)。accounts.extra,用于展示和创建计划。credit_id。使用稳定的 credit ID
重置卡 ID 是普通资源标识,不是 token 或 credential。本 PR 将该 ID 加入管理端配额响应和缓存,直接、唯一地定位目标卡,不再依赖到期时间匹配或自行生成 selector,从而减少额外的匹配、碰撞和失效分支。
{ "available_count": 2, "credits": [ { "id": "credit_xxx", "expires_at": "2026-08-28T00:00:00Z" } ] }缓存用于展示和创建计划,不作为执行结果的最终事实来源。旧缓存缺少 ID 时仍可展示,但需要刷新完整快照后才能创建计划。
计划与执行语义
每个 OpenAI OAuth 母账号最多保存一个计划:
{ "plan_id": "uuid", "credit_id": "credit_xxx", "expires_at": "2026-08-28T00:00:00Z", "lead_time_minutes": 60 }并发与幂等
消费继续使用
account_id + credit_id生成稳定的redeem_request_id,保证超时重试和多实例并发不会重复消费同一张卡。计划更新与 worker 收尾使用
accounts.extra条件更新(CAS)。worker 只能更新自己读取到的计划,避免旧 worker 在执行结束后清除管理员刚创建的替代计划。对于
Replayed或windows_reset <= 0,执行流程会重新查询实时库存:OPENAI_AUTO_RESET_REPLAY_CONFLICT或OPENAI_AUTO_RESET_NO_EFFECT,不得写入成功状态。API 与管理端
新增 API:
PUT /api/v1/admin/openai/accounts/:id/reset-credit-expiry-targetDELETE /api/v1/admin/openai/accounts/:id/reset-credit-expiry-target设置计划请求:
{ "credit_id": "credit_xxx", "lead_time_minutes": 60 }配额响应中的
rate_limit_reset_credits.credits[]新增可选字段id。管理端支持为每张可用重置卡设置计划、查看预计执行时间和立即执行提示、展示当前计划摘要,以及取消计划。
数据库与持久化
本 PR 没有新增或删除数据库表、字段、索引,也不需要执行 migration。
新增状态复用现有
accounts.extraJSONB 字段:codex_reset_credit_snapshot.credits[].idauto_reset_credit_expiry_targetcodex_auto_reset_credit_state.trigger_reason = "expiry_target"repository 增加针对单个 extra key 的原子条件更新能力,用于保护计划替换与 worker 收尾之间的并发一致性。
相关工作
credit_id定向消费”能力上部分重叠。本 PR 仅将该能力用于服务内部的自动计划,不新增通用手动定向消费 API,也不接受调用方提供的Idempotency-Key。accounts.extra,不引入通用任务引擎或数据库 migration。测试
已覆盖:
已通过后端全量测试、相关 race 测试、前端 ESLint、类型检查、组件测试和生产构建。
English version
Motivation
OpenAI reset credits can currently be used manually or automatically based on 5h/7d usage thresholds, but a specific expiring credit cannot be scheduled in advance.
Unused reset credits are wasted. With a long validity period, it is easy to forget about them until the reset opportunity has already expired. This PR lets an administrator select a specific credit and schedule it for use a configurable number of minutes before expiration.
Design
Quota refresh now retrieves and caches the complete reset-credit inventory (
credit_id + expires_at). An administrator creates a single-credit plan, and the existing worker consumes that exactcredit_idwhen its execution window is reached. A plan whose execution time has already passed runs immediately.Credit IDs are ordinary resource identifiers rather than credentials. Using the stable upstream ID avoids expiry-based matching and custom selectors. The cache supports display and plan creation; live upstream inventory remains the source of truth when an ambiguous execution result must be confirmed.
Each OpenAI OAuth parent account may have one plan containing
plan_id,credit_id,expires_at, andlead_time_minutes. The default lead time is 60 minutes, with an allowed range of 5 to 10080 minutes. A plan authorizes targeted consumption but does not reserve inventory: threshold automation may continue before the execution window, while the targeted plan takes priority inside that window.Concurrency and Idempotency
A stable
redeem_request_idis derived fromaccount_id + credit_id. Conditional updates onaccounts.extraprevent an older worker from clearing a replacement plan.Replayed or zero-effect results are verified against live inventory. A missing target confirms completion; a target that remains available produces
OPENAI_AUTO_RESET_REPLAY_CONFLICTorOPENAI_AUTO_RESET_NO_EFFECT; an unverifiable result keeps the plan for retry.API, UI, and Database
This PR adds:
PUT /api/v1/admin/openai/accounts/:id/reset-credit-expiry-targetDELETE /api/v1/admin/openai/accounts/:id/reset-credit-expiry-targetrate_limit_reset_credits.credits[].idfield.No tables, columns, indexes, or migrations are added. All new state reuses the existing
accounts.extraJSONB column, with per-key CAS updates protecting plan replacement and worker finalization.Related Work
credit_idredemption layer. Here, targeted redemption is internal to scheduled automation; no general manual redemption API or caller-providedIdempotency-Keyis introduced.accounts.extra, without adding a task table or database migration.Tests
Coverage includes plan lifecycle, immediate execution, targeted consumption, multi-instance idempotency, CAS replacement protection, replay and zero-effect verification, query failures, expired targets, unavailable accounts, threshold-plan interaction, and the admin UI.
Backend tests, targeted race tests, frontend linting, type checking, component tests, and the production build all pass.