Files
magpie/internal/gateway/codex_autoreset.go
T
yetone 9bf6d43527 claude: magpie no longer asks Anthropic for a Claude account's usage, and adding a Claude account warns of a ban (the user: 不要伪造任何的 Claude 请求,能否通过 claude cli 获取 / 我害怕被封; 添加账号时要像其他的 Subscription Provider 一样显示风险提示) — the usage was read by magpie itself calling Anthropic's /api/oauth/usage with the account's token, on a timer, for every saved account, and Claude's usage-limit resets (cedar_ember) were listed, spent and auto-spent the same way. Now the usage is what Claude Code's own /usage prints (claude -p /usage, a command Claude Code answers itself without asking a model), run only when Usage is opened or Refresh pressed (GUI, magpie quota, accounts, TUI), for the account Claude Code is signed in to, at most once in 30s; a saved account shows only what Claude Code reported while using it, or the last reading kept. The Claude resets, Auto-use and their settings are gone (Codex's stay). Session jsonl files hold no usage figures, so they aren't read. Starting a Claude sign-in or import (GUI and CLI) first says Anthropic may suspend or ban the account and that it is at the user's own risk. TestClaudeWindowsAsked, TestParseClaudeUsage, TestClaudeUsageRunsClaudeCode, claude-usage-asked.test.cjs and claude-risk.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; routing-auto-reset, codex-auto-reset, quota-families, tray-usages, click-scroll, old-webkit, plugin-signin, usage-alert, usage-ledger pass.
2026-10-01 12:38:25 +08:00

81 lines
2.6 KiB
Go

package gateway
// A Codex rate-limit reset spent by itself: when everyone a request could
// go to is out of their allowance, a ChatGPT account the user lets spend
// its resets, its weekly window used up, spends one and is asked again
// (provider.AutoUseCodexReset has the rules).
import (
"context"
"log"
"strings"
"time"
"github.com/yetone/magpie/internal/provider"
)
// autoResetTimeout bounds the look at an account's week and the reset.
var autoResetTimeout = 20 * time.Second
// autoReset spends a reset of one of cands' Codex accounts, c — the last
// one, just out of its allowance — first: only when every other one of
// them sits out too. It says which account it was and what spending did.
func (s *Server) autoReset(ctx context.Context, cands []candidate, c candidate) (candidate, provider.ResetOutcome, bool) {
for _, x := range cands {
if x.restKey() == c.restKey() {
continue
}
_, resting := restOf(x.restKey())
if !resting && x.restID() != x.restKey() {
_, resting = restOf(x.restID())
}
if !resting {
return candidate{}, provider.ResetOutcome{}, false
}
}
seen := map[string]bool{}
for _, x := range append([]candidate{c}, cands...) {
a := x.p.Account
if a == nil || a.User == "" || seen[x.restKey()] || !provider.AutoResets(a.Agent, a.User) {
continue
}
seen[x.restKey()] = true
if out, ok := autoResetOf(ctx, a.Agent, a.User); ok {
s.Unrest(x.restKey())
return x, out, true
}
}
return candidate{}, provider.ResetOutcome{}, false
}
// autoResetSignedIn is autoReset for a request relayed with Codex's own
// sign-in, the only account there is.
func (s *Server) autoResetSignedIn(ctx context.Context) (string, provider.ResetOutcome, bool) {
who, ok := provider.CodexSignedIn()
if !ok || !provider.CodexAutoReset(who) {
return "", provider.ResetOutcome{}, false
}
out, ok := autoResetOf(ctx, "codex", who)
if ok {
s.Unrest("codex@" + strings.ToLower(who))
}
return who, out, ok
}
// autoResetOf spends one of agent's account user's resets if its rules
// let it, and says whether the windows started again.
func autoResetOf(ctx context.Context, agent, user string) (provider.ResetOutcome, bool) {
ctx, cancel := context.WithTimeout(ctx, autoResetTimeout)
defer cancel()
out, err := provider.AutoUseCodexReset(ctx, user)
switch {
case err != nil:
log.Printf("%s reset for %s not used: %v", agent, user, err)
case out.Code == "reset":
log.Printf("%s reset used for %s, its week used up: %s", agent, user, out.Text())
case out.Code != "":
log.Printf("%s reset for %s not used: %s", agent, user, out.Text())
}
return out, err == nil && out.Code == "reset"
}