gateway: a plugin account run out is asked its allowance again as the plugin's provider keeps it — a limited or full plugin account staled "plugin"/user, which no usage is kept under, so the router trusted the allowance it had and the account's rest was marked as "plugin"'s; both now go by UsageAgent ("plugin:grok"). A moved Grok's usage is kept as plugin:grok's, so the built-in's per-home branch needs nothing. TestPluginProvider fails without the change.

This commit is contained in:
yetone committed 2026-10-01 03:41:43 +08:00
1 parent d8f2e17dd7
commit bd5ea31f7c
3 files changed
+35 -2

No files matched your search

+26
View File
@@ -8,6 +8,7 @@ import (
"net/http/httptest"
"os/exec"
"path/filepath"
"slices"
"strings"
"sync"
"testing"
@@ -165,6 +166,14 @@ func TestPluginProvider(t *testing.T) {
mu.Lock()
limited = "Bearer k1"
mu.Unlock()
var staled []string
staleAllowance = func(agent, user string) {
mu.Lock()
staled = append(staled, agent)
mu.Unlock()
provider.StaleAllowance(agent, user)
}
defer func() { staleAllowance = provider.StaleAllowance }()
code, body := postAs(t, s, "", `{"model":"fakeco/fake-1","messages":[{"role":"user","content":"hello"}]}`)
mu.Lock()
last := got[len(got)-1]
@@ -172,6 +181,23 @@ func TestPluginProvider(t *testing.T) {
if code != 200 || !strings.Contains(body, "hi from chat") || last.auth != "Bearer k2" {
t.Fatalf("with the first account limited: %d %s, upstream saw %+v", code, body, last)
}
// the limited account's allowance is asked again as its usage is kept,
// and it rests as that account
mu.Lock()
asked := slices.Clone(staled)
mu.Unlock()
if !slices.Contains(asked, "plugin:fakeco") {
t.Fatalf("the limited account's allowance went stale as %q, not plugin:fakeco", asked)
}
restingUntil.Lock()
var rests []string
for _, r := range restingUntil.note {
rests = append(rests, r.agent)
}
restingUntil.Unlock()
if !slices.Contains(rests, "plugin:fakeco") {
t.Fatalf("the limited account rests as %q, not plugin:fakeco", rests)
}
if err := plugin.SignOut(ctx, "fakeco", ""); err != nil {
t.Fatal(err)
+7 -2
View File
@@ -207,6 +207,9 @@ func renewed(agent, user string) {
func init() { provider.OnRenewed(renewed) }
// staleAllowance is provider.StaleAllowance, swapped in tests.
var staleAllowance = provider.StaleAllowance
// Unrest lifts the rest of what rests by key — an account just verified
// with its vendor, say — so the next request asks it again. False when it
// wasn't resting.
@@ -320,12 +323,14 @@ func (s *Server) restAfterMarked(c candidate, status int, header http.Header, bo
d, r.By = t.Sub(now), "window"
}
}
// an account is kept by the agent its usage is asked of: a plugin's
// by the plugin's provider ("plugin:grok"), not by "plugin"
if a := c.p.Account; a != nil && why != failOther && why != failVerify {
provider.StaleAllowance(a.Agent, a.User) // ask again what it has left
staleAllowance(a.UsageAgent(), a.User) // ask again what it has left
}
r.Until = now.Add(d)
if a := c.p.Account; a != nil {
r.agent, r.user = a.Agent, a.User
r.agent, r.user = a.UsageAgent(), a.User
}
id := c.restKey()
// OpenRouter identifies a provider's shared pool separately from its
+2
View File
@@ -187,6 +187,8 @@ func StaleAllowance(agent, user string) {
loginUsageCache.Lock()
delete(loginUsageCache.m, agent+"/"+strings.ToLower(user))
loginUsageCache.Unlock()
// the built-in keeps Grok's usage by home; a Grok moved to its plugin
// keeps it as "plugin:grok"'s, the line above
if agent == "grok" {
gs := grokLogins()
grokHomeUsage.Lock()