Add Codex multi-limit support#4
Conversation
wavever
left a comment
There was a problem hiding this comment.
Thanks for this, @lkliu7 — really solid work. It builds cleanly, go vet is quiet, all tests pass (including the two new ones), both READMEs are updated, and the Trigger refactor into triggerOne/buildCodexArgs is nice. The model → models config is a good, backward-compatible addition.
I'd like one change before merging, plus a couple of optional nits.
Please fix: empty model no longer falls back to Codex's default
On main, an empty model means "let Codex pick its own default model" — Trigger only appends -m when c.cfg.Model != "". That behavior is still documented (README and the default config comment: "Empty = use the Codex default model").
With this PR, CodexModels() hardcodes a fallback:
if cfg.Model != "" { return []string{cfg.Model} }
return []string{"gpt-5.4-mini"}so model = "" now always injects -m gpt-5.4-mini. That silently breaks the documented escape hatch and removes the only way for users whose plan doesn't include gpt-5.4-mini to fall back to Codex's default model. (The PR also drops the "Empty = ..." note from the embedded defaultTOML comment while the README still implies it.)
Could you either:
- preserve a way to express "no
-m" (e.g. let an empty model entry skip the flag inbuildCodexArgs), or - if forcing
gpt-5.4-miniis intentional, update all the docs (README EN/zh + config comment) to drop the "Empty = Codex default" promise consistently?
Optional nits (not blocking)
- Model matching in
pickAdditionalWindows— the bidirectionalstrings.Contains(n, m) || strings.Contains(m, n)plus the hardcodedsparkspecial-case can mis-match (e.g.gpt-5.4matching agpt-5.4-codexlimit). It works for today's data sinceadditional_rate_limitsis small, but matching on the exactlimit_name/idwould be more robust and let you drop thesparkspecial-case. status.gore-loads config inside the loop (config.Load()per Codex provider, error ignored), and the per-model expansion logic is duplicated withbg.go. TheCodexprovider already knows its models viaeffectiveModels(); exposing that would avoid the re-read and the duplication.
For context (no action needed): the scheduler still tracks only the primary 5h window, so every configured model is pinged when that window resets — a model with an independent reset time isn't scheduled separately. That matches the PR's stated goal, just noting it so the limitation is documented.
Thanks again — happy to merge once the empty-model case is sorted out.
|
I rebuilt the feature by treating GPT-5.3-Codex-Spark as if it were its own provider, while reusing Codex auth, CLI transport, hooks, and usage endpoint plumbing. Still disabled by default, but possible quality-of-life features for later: on the first ping, if a pro subscription is detected, ask the user if they want |
wavever
left a comment
There was a problem hiding this comment.
Thanks for the thorough rework, @lkliu7 — this is a much cleaner design. All my earlier points are addressed:
- Empty-
modelescape hatch restored —NewCodexkeeps the original behavior (no-mwhenmodelis empty), so "Empty = use the Codex default model" still holds. Spark defaults its own model togpt-5.3-codex-spark. - Robust limit matching —
normalizeCodexLimitNamedoes an exact normalized match againstadditional_rate_limits[].limit_name, dropping the fragile bidirectionalContains/sparkspecial-case. - No status/bg duplication — Spark is a first-class provider, so it flows through the existing
status/bg statusrendering and gets independently scheduled on its own 5h window. - Safe by default — disabled out of the box (with a test asserting it), so existing users don't get an extra quota-consuming ping on upgrade.
Build, go vet, and the full test suite all pass locally, and the new tests cover the spark window selection, the missing-limit error path, dry-run model, and provider selection. Merging now.
Pro subscriptions have separate limits for GPT-5.3-Codex-Spark; updated to ping and monitor this limit.
Changes
modelsconfig support so multiple Codex models can be pinged on each resetadditional_rate_limitswhen availablestatusandbg status