factory: an account with no organization asks Factory's whoami for it before it sends, as droid does, and every new token asks again, so its model requests carry X-Factory-Org-Id (#242 tasselx: "Factory: Forbidden" on GLM-5.2)

droid (0.229.0, still the latest) asks /api/cli/whoami about each token it holds and sends the orgId it answers as X-Factory-Org-Id on every request (its auth's Do → _r → Pr/Ar, Ci() spread into xc). Accounts signed in with v0.1.432, or whose org had been dropped after a refusal, kept none, and magpie never asked whoami again after renewing a token, so their requests went with no org and Factory answered its generic 403 {detail:"Forbidden"}. Now an account with no org asks whoami before its request (at most every 10 minutes per account), each renewal asks again, an org whoami refuses is left off and whoami asked without it, and the org, region and whoami's premBaseHostV2 (an org's own host, where droid sends model requests) are kept. whoami goes with droid's three headers only (Authorization, X-Factory-Whoami-Extended, the org). Claude requests carry X-Api-Key: placeholder, as droid's Anthropic client does. A 403 on an account that sent no org asks whoami and retries once; one that stays tells the user to check droid on the same account and model and to sign in again (Provider.Explain, in the gateway's three error paths). Tested with TestFactoryForbiddenWithoutOrg against a fake Factory refusing requests without the org header, the account saved as v0.1.432 did: glm-5.2 succeeds with the exact headers, whoami asked once with droid's headers, a 403 while whoami was down asks again and retries, the enterprise host used, the explanation on 403s only; it fails with the lookup off. The existing Factory tests are updated for the headers and org. go vet, go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried against Factory's real server or tasselx's account.
This commit is contained in:
yetone committed 2026-09-30 10:46:55 +08:00
1 parent 5b6ce747f2
commit 446b39ae44
5 files changed
+355 -30

No files matched your search

+3 -3
View File
@@ -506,7 +506,7 @@ func (s *Server) countTokens(w http.ResponseWriter, r *http.Request) {
}
}
keepRetry(w.Header(), res.Header, b)
writeError(w, provider.Anthropic, res.StatusCode, c.p.Name+": "+provider.APIError(b, res.Status))
writeError(w, provider.Anthropic, res.StatusCode, c.p.Explain(c.p.Name+": "+provider.APIError(b, res.Status), res.StatusCode, b))
return
}
defer res.Body.Close()
@@ -1449,7 +1449,7 @@ func (s *Server) passthrough(w http.ResponseWriter, r *http.Request, p provider.
defer res.Body.Close()
if res.StatusCode >= 400 {
b, _ := io.ReadAll(io.LimitReader(res.Body, 1<<20))
msg := p.Name + ": " + provider.APIError(b, res.Status)
msg := p.Explain(p.Name+": "+provider.APIError(b, res.Status), res.StatusCode, b)
if wrongEndpoint(res.StatusCode, b) {
s.markUnfit(p.ID, model, proto)
if len(s.usable(p, model)) > 0 {
@@ -1756,7 +1756,7 @@ func (s *Server) translate(w http.ResponseWriter, r *http.Request, p provider.Pr
defer res.Body.Close()
if res.StatusCode >= 400 {
b, _ := io.ReadAll(io.LimitReader(res.Body, 1<<20))
msg := p.Name + ": " + provider.APIError(b, res.Status)
msg := p.Explain(p.Name+": "+provider.APIError(b, res.Status), res.StatusCode, b)
if p.Preset == "openrouter" && openRouterSharedPool(b) {
markOpenRouterSharedPool(w)
}
+15
View File
@@ -75,6 +75,9 @@ type Account struct {
// account has put right what it names and the request is worth
// sending once more (a Factory org the server can't reach, factory.go).
retry func(ctx context.Context, status int, body []byte) bool
// explain adds what the user can do about a refusal the account's
// backend answered, "" when there is nothing to add (factory.go).
explain func(status int, body []byte) string
}
// APIs lists the APIs model is served on, as the provider's last model
@@ -161,6 +164,18 @@ func (p Provider) Retry(ctx context.Context, status int, body []byte) bool {
return p.Account.retry(p.Via(ctx), status, body)
}
// Explain is the error a refusal is passed on as: msg, with what the
// user can do about it when the account knows.
func (p Provider) Explain(msg string, status int, body []byte) string {
if p.Account == nil || p.Account.explain == nil {
return msg
}
if more := p.Account.explain(status, body); more != "" {
return msg + " — " + more
}
return msg
}
// Prepare adjusts a request body the way the backend wants it.
func (p Provider) Prepare(body []byte) []byte {
if p.Account != nil && p.Account.body != nil {
+155 -15
View File
@@ -65,13 +65,16 @@ type factoryCreds struct {
// for the record: it is never sent to Factory's API.
Org string `json:"orgId,omitempty"`
// Active is droid's active_organization_id: Factory's own id for the
// org, as /api/cli/whoami answers it, sent as X-Factory-Org-Id. Empty
// sends none and Factory takes the token's org, as droid does before
// it has asked whoami.
// org, as /api/cli/whoami answers it, sent as X-Factory-Org-Id. droid
// asks whoami as soon as it holds a token and keeps its orgId, so its
// requests carry it; an account with none asks before it sends.
Active string `json:"activeOrganizationId,omitempty"`
Email string `json:"email,omitempty"`
UserID string `json:"userId,omitempty"`
Region string `json:"region,omitempty"` // "eu" for an org served from Factory's EU region
// Prem is whoami's premBaseHostV2: an org Factory serves from a host
// of its own, where droid sends its model requests instead.
Prem string `json:"premBaseHost,omitempty"`
}
// base is the Factory API the account's org is served from.
@@ -82,6 +85,19 @@ func (c factoryCreds) base() string {
return factoryAPI
}
// llmBase is where the account's model requests go: the org's own host
// when whoami named one, else its region's API.
func (c factoryCreds) llmBase() string {
if c.Prem != "" {
p := strings.TrimRight(c.Prem, "/")
if !strings.Contains(p, "://") {
p = "https://" + p
}
return p
}
return c.base()
}
type factoryLogin struct {
Login
creds factoryCreds
@@ -277,10 +293,10 @@ func factoryFresh(ctx context.Context, user string) (factoryCreds, error) {
return factoryCreds{}, errors.New("Factory: unreadable sign-in")
}
if c.ExpiresAt > 0 && time.Now().UnixMilli() < c.ExpiresAt-factoryRefreshLead.Milliseconds() {
return c, nil
return factoryOrgOf(ctx, l.User, c), nil
}
if c.Refresh == "" {
return c, nil // nothing to renew it with; let the request try what there is
return factoryOrgOf(ctx, l.User, c), nil // nothing to renew it with; let the request try what there is
}
rctx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 20*time.Second)
t, err := factoryRenew(rctx, c.Refresh, "")
@@ -288,7 +304,7 @@ func factoryFresh(ctx context.Context, user string) (factoryCreds, error) {
if err != nil {
// a hiccup while the token still runs: go on with it
if !factoryRefused(err) && c.ExpiresAt > 0 && time.Now().UnixMilli() < c.ExpiresAt {
return c, nil
return factoryOrgOf(ctx, l.User, c), nil
}
return factoryCreds{}, factoryLapse(l.User, err)
}
@@ -296,9 +312,96 @@ func factoryFresh(ctx context.Context, user string) (factoryCreds, error) {
if t.Refresh != "" {
c.Refresh = t.Refresh
}
// droid asks whoami again for each new token, keeping the org it names
factoryReconcile(ctx, &c)
factoryAsked.Store(strings.ToLower(l.User), time.Now())
return c, factoryEdit(l.User, c, true)
}
// factoryAsked is when each account last asked whoami for its org, so an
// account whoami can't answer doesn't ask before every request.
var factoryAsked sync.Map
// factoryAskAgain is how long an account whose whoami failed waits before
// asking again.
const factoryAskAgain = 10 * time.Minute
// factoryOrgOf fills in an account's active org when it has none: droid
// asks whoami as soon as it holds a token (its auth's Do → Ar) and sends the
// orgId it answers as X-Factory-Org-Id on every request after; Factory
// answered one with none "Forbidden" (#242). Logins kept before magpie
// asked have none. Called under factoryMu.
func factoryOrgOf(ctx context.Context, user string, c factoryCreds) factoryCreds {
if c.Active != "" {
return c
}
key := strings.ToLower(user)
if at, ok := factoryAsked.Load(key); ok && time.Since(at.(time.Time)) < factoryAskAgain {
return c
}
factoryAsked.Store(key, time.Now())
if factoryReconcile(ctx, &c) {
_ = factoryEdit(user, c, false)
}
return c
}
// factoryWho is what /api/cli/whoami tells of an account.
type factoryWho struct {
UserID string `json:"userId"`
OrgID string `json:"orgId"`
Email string `json:"email"`
Region string `json:"region"`
Prem string `json:"premBaseHostV2"`
}
// factoryWhoami asks Factory whose the token is with the headers droid's
// whoami (ZA) sends: the token, X-Factory-Whoami-Extended, and the active
// org when there is one — nothing else.
func factoryWhoami(ctx context.Context, c factoryCreds) (factoryWho, error) {
var who factoryWho
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.base()+"/api/cli/whoami", nil)
if err != nil {
return who, err
}
req.Header.Set("Authorization", "Bearer "+c.Access)
req.Header.Set("X-Factory-Whoami-Extended", "true")
if c.Active != "" {
req.Header.Set("X-Factory-Org-Id", c.Active)
}
res, err := factoryClient.Do(req)
if err != nil {
return who, err
}
defer res.Body.Close()
b, _ := io.ReadAll(io.LimitReader(res.Body, 1<<20))
if res.StatusCode != http.StatusOK {
return who, &factoryStatus{res.StatusCode, "Factory: " + APIError(b, res.Status)}
}
return who, json.Unmarshal(b, &who)
}
// factoryReconcile asks whoami, as droid does for each token it holds, and
// keeps the org, region and host it names: true when any changed. An active
// org whoami refuses is left off and whoami asked again without it.
func factoryReconcile(ctx context.Context, c *factoryCreds) bool {
wctx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 10*time.Second)
defer cancel()
who, err := factoryWhoami(wctx, *c)
var st *factoryStatus
if c.Active != "" && errors.As(err, &st) && st.Code == http.StatusForbidden {
without := *c
without.Active = ""
who, err = factoryWhoami(wctx, without)
}
if err != nil || who.OrgID == "" {
return false
}
before := *c
c.Active, c.Region, c.Prem = who.OrgID, who.Region, who.Prem
return *c != before
}
// ---- Factory's API ----------------------------------------------------------
// factoryHeaders are what droid sends on every call to Factory's API.
@@ -318,16 +421,19 @@ func factoryOrgRefused(status int, body []byte) bool {
return status == http.StatusForbidden && strings.Contains(strings.ToLower(string(body)), "active organization is not accessible")
}
// factoryMendOrg answers Factory refusing an account's org: the active org
// it named is dropped, so the request goes again without the header and
// Factory takes the token's own (droid's org picker retries "without the
// active-org header" so); with no header sent, the token is put in the
// first org /api/cli/org lists, as droid does for a token with none. True
// when there was something to change and the request is worth resending.
// factoryMendOrg answers Factory refusing an account's request. An active
// org it can't reach is left off and whoami asked again without it (droid's
// org picker retries "without the active-org header" so), keeping the org it
// then names or none; with no header sent, the token is put in the first org
// /api/cli/org lists, as droid does for a token with none. Any other 403 to
// an account that sent no org asks whoami for one, as droid would have
// before its first request. True when there was something to change and the
// request is worth resending.
func factoryMendOrg(ctx context.Context, user string, status int, body []byte) bool {
if !factoryOrgRefused(status, body) {
if status != http.StatusForbidden {
return false
}
refused := factoryOrgRefused(status, body)
factoryMu.Lock()
defer factoryMu.Unlock()
l, ok := factoryLookup(user)
@@ -339,9 +445,22 @@ func factoryMendOrg(ctx context.Context, user string, status int, body []byte) b
return false
}
if c.Active != "" {
if !refused {
return false // the org was sent: the refusal is about something else
}
was := c.Active
c.Active = ""
if factoryReconcile(ctx, &c) && c.Active == was {
c.Active = "" // whoami names the org refused: send none
}
factoryAsked.Store(strings.ToLower(l.User), time.Now())
return factoryEdit(l.User, c, false) == nil
}
if !refused {
// no org was sent: ask whoami for the one droid would have sent
factoryAsked.Store(strings.ToLower(l.User), time.Now())
return factoryReconcile(ctx, &c) && c.Active != "" && factoryEdit(l.User, c, false) == nil
}
if c.Refresh == "" {
return false
}
@@ -362,6 +481,20 @@ func factoryMendOrg(ctx context.Context, user string, status int, body []byte) b
return factoryEdit(l.User, c, true) == nil
}
// factoryExplain is what the user can do about a 403 Factory still answers
// once magpie has sent what droid sends: whether Factory lets the account
// use the model is Factory's to say (an org's model policy, a plan without
// it), so droid itself is the test.
func factoryExplain(status int, body []byte) string {
if status != http.StatusForbidden {
return ""
}
if factoryOrgRefused(status, body) {
return "the Factory account's organization changed; remove the account in magpie and sign in to it again"
}
return "Factory refused this account the request; check that `droid`, signed in to the same account and organization, can use this model (an organization's model policy or the plan may not allow it), and if it can, remove the Factory account in magpie and sign in to it again"
}
// factoryFirstOrg is the first WorkOS org /api/cli/org says the account is
// in, "" for none. droid asks it with the bearer token alone.
func factoryFirstOrg(ctx context.Context, c factoryCreds) (string, error) {
@@ -497,8 +630,9 @@ func factoryProvider(a factoryLogin) Provider {
if err != nil {
return err
}
// an EU org is served from Factory's EU region: the request goes there
if base := c.base(); base != factoryAPI && strings.HasPrefix(req.URL.String(), factoryAPI) {
// an EU org is served from Factory's EU region, an on-prem one from
// its own host (whoami's premBaseHostV2): the request goes there
if base := c.llmBase(); base != factoryAPI && strings.HasPrefix(req.URL.String(), factoryAPI) {
if u, err := url.Parse(base + strings.TrimPrefix(req.URL.String(), factoryAPI)); err == nil {
req.URL, req.Host = u, u.Host
}
@@ -518,11 +652,17 @@ func factoryProvider(a factoryLogin) Provider {
if upstream == "openai" {
req.Header.Set("OpenAI-Platform", "org-bHuLtG1fGmYk5YaOihAAXFBw")
}
if strings.Contains(req.URL.Path, "/llm/a/") {
// droid's Anthropic client is made with the key "placeholder",
// which Anthropic's SDK sends beside the bearer token
req.Header.Set("X-Api-Key", "placeholder")
}
return nil
}
acct.retry = func(ctx context.Context, status int, body []byte) bool {
return factoryMendOrg(ctx, user, status, body)
}
acct.explain = factoryExplain
acct.models = factoryCatalog
acct.fetch = func(ctx context.Context) ([]catalog.Model, error) {
ms := factoryCatalog()
+2 -8
View File
@@ -123,18 +123,12 @@ func factorySignedInWith(ctx context.Context, t factoryTokens) (string, error) {
}
}
}
var who struct {
UserID string `json:"userId"`
OrgID string `json:"orgId"`
Email string `json:"email"`
Region string `json:"region"`
}
err := factoryGet(ctx, c, "/api/cli/whoami", map[string]string{"X-Factory-Whoami-Extended": "true"}, &who)
who, err := factoryWhoami(ctx, c)
if err != nil && firstNonEmpty(c.Email, c.UserID) == "" {
return "", err
}
if err == nil {
c.Active, c.Region = who.OrgID, who.Region
c.Active, c.Region, c.Prem = who.OrgID, who.Region, who.Prem
c.Email = firstNonEmpty(c.Email, who.Email)
c.UserID = firstNonEmpty(c.UserID, who.UserID)
}
+180 -4
View File
@@ -20,7 +20,8 @@ func factorySite(t *testing.T, h http.HandlerFunc) *httptest.Server {
t.Cleanup(srv.Close)
oldW, oldA, oldE := factoryWorkOS, factoryAPI, factoryAPIEU
factoryWorkOS, factoryAPI, factoryAPIEU = srv.URL+"/wos", srv.URL, srv.URL+"/eu"
t.Cleanup(func() { factoryWorkOS, factoryAPI, factoryAPIEU = oldW, oldA, oldE })
factoryAsked.Clear()
t.Cleanup(func() { factoryWorkOS, factoryAPI, factoryAPIEU = oldW, oldA, oldE; factoryAsked.Clear() })
return srv
}
@@ -96,8 +97,9 @@ func TestFactorySignIn(t *testing.T) {
}
factoryJSON(w, 200, map[string]any{"workosOrgIds": []string{"org_A", "org_B"}})
case "/api/cli/whoami":
// droid's whoami sends the token and the extended flag alone
if r.Header.Get("Authorization") != "Bearer "+inOrg || r.Header.Get("X-Factory-Whoami-Extended") != "true" ||
r.Header.Get("X-Factory-Org-Id") != "" || r.Header.Get("X-Factory-Client") != "cli" {
r.Header.Get("X-Factory-Org-Id") != "" || r.Header.Get("X-Factory-Client") != "" || r.Header.Get("X-Client-Version") != "" {
w.WriteHeader(401)
return
}
@@ -355,6 +357,12 @@ func factoryOrgSite(t *testing.T, tokens map[string]string, renewed string) func
if r.Header.Get("X-Factory-Org-Id") != "" {
t.Errorf("whoami asked with an org header: %q", r.Header.Get("X-Factory-Org-Id"))
}
if tokens[strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ")] != "org_A" {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(403)
io.WriteString(w, refused)
return
}
factoryJSON(w, 200, map[string]any{"userId": "user_1", "orgId": "fac_A", "region": "us"})
case "/api/cli/org":
factoryJSON(w, 200, map[string]any{"workosOrgIds": []string{"org_A"}})
@@ -472,6 +480,10 @@ func TestFactoryActiveOrg(t *testing.T) {
if code, b := factorySend(t, p); code != 200 {
t.Fatalf("an older login: %d %s", code, b)
}
// it asked whoami, as droid does for a token it holds, and keeps the org
if c := factoryKept(t, "old@example.com"); c.Active != "fac_A" {
t.Fatalf("older login kept active %q", c.Active)
}
}
// Factory refusing the active org magpie sends: it is dropped and the
@@ -503,7 +515,8 @@ func TestFactoryOrgRefused(t *testing.T) {
if code, b := factorySend(t, p); code != 200 {
t.Fatalf("active org gone: %d %s", code, b)
}
if c := factoryKept(t, "ada"); c.Active != "" || c.Access != tokA {
// whoami, asked again without it, names the org the token is in
if c := factoryKept(t, "ada"); c.Active != "fac_A" || c.Access != tokA {
t.Fatalf("ada kept active %q", c.Active)
}
if got := renewed(); len(got) != 0 {
@@ -529,9 +542,172 @@ func TestFactoryOrgRefused(t *testing.T) {
t.Fatalf("usage: %+v", q)
}
// any other refusal is not retried
// any other refusal to an account that sent its org is not retried
if err := SwitchLogin("factory", "cy"); err != nil {
t.Fatal(err)
}
p, _ = find(Accounts(), "factory")
if c := factoryKept(t, "cy"); c.Active != "fac_A" {
t.Fatalf("cy kept active %q", c.Active)
}
if p.Retry(context.Background(), 403, []byte(`{"error":{"message":"model not allowed"}}`)) ||
p.Retry(context.Background(), 401, []byte(`Requested active organization is not accessible`)) {
t.Fatal("retried an unrelated refusal")
}
}
// #242 after v0.1.438: a login kept with no active org sent no
// X-Factory-Org-Id, and Factory answered GLM-5.2 on chat completions with a
// bare 403 {"detail":"Forbidden"}. droid never sends a request without it:
// it asks whoami for each token it holds (droid's auth Do → _r → Ar) and
// keeps the orgId. magpie asks too, with droid's whoami headers alone, and
// sends what droid sends; whoami failing at first, the 403 asks it again and
// the request goes once more. An org served from a host of its own gets its
// model requests there, and a 403 left over says what to do.
func TestFactoryForbiddenWithoutOrg(t *testing.T) {
signIn(t)
tok := factoryToken(map[string]any{"sub": "user_t", "org_id": "org_T"})
forbidden := `{"detail":"Forbidden","status":403,"title":"Forbidden"}`
var mu sync.Mutex
whoamis, whoamiDown := 0, 0
prem := ""
var sent []http.Header
var paths []string
srv := factorySite(t, func(w http.ResponseWriter, r *http.Request) {
mu.Lock()
defer mu.Unlock()
switch r.URL.Path {
case "/api/cli/whoami":
whoamis++
h := r.Header
if h.Get("Authorization") != "Bearer "+tok || h.Get("X-Factory-Whoami-Extended") != "true" || h.Get("X-Factory-Org-Id") != "" ||
h.Get("X-Factory-Client") != "" || h.Get("X-Client-Version") != "" || strings.HasPrefix(h.Get("User-Agent"), "factory-cli") {
t.Errorf("whoami headers: %v", h)
}
if whoamiDown > 0 {
whoamiDown--
w.WriteHeader(502)
return
}
factoryJSON(w, 200, map[string]any{"userId": "user_t", "orgId": "fac_T", "email": "tassel@example.com",
"region": "us", "premBaseHostV2": prem})
case "/api/llm/o/v1/chat/completions", "/api/llm/a/v1/messages", "/prem/api/llm/a/v1/messages":
if r.Header.Get("X-Factory-Org-Id") != "fac_T" {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(403)
io.WriteString(w, forbidden)
return
}
sent = append(sent, r.Header.Clone())
paths = append(paths, r.URL.Path)
io.WriteString(w, `{"id":"ok"}`)
default:
t.Errorf("unexpected %s %s", r.Method, r.URL.Path)
w.WriteHeader(404)
}
})
// kept by v0.1.432: the WorkOS org and no active org
keep := func(user string) Provider {
t.Helper()
auth, _ := json.Marshal(map[string]any{"accessToken": tok, "refreshToken": "r1",
"expiresAt": time.Now().Add(time.Hour).UnixMilli(), "orgId": "org_T", "email": user})
if err := addSideLogin(savedLogin{Agent: "factory", User: user, Auth: auth}, "", func(savedLogin) {}); err != nil {
t.Fatal(err)
}
if err := SwitchLogin("factory", user); err != nil {
t.Fatal(err)
}
p, _ := find(Accounts(), "factory")
return p
}
send := func(p Provider, url string, proto Protocol, body string) (int, string) {
t.Helper()
do := func() (int, []byte) {
req, _ := http.NewRequest("POST", url, strings.NewReader(body))
if err := p.Sign(context.Background(), req, proto, []byte(body)); err != nil {
t.Fatal(err)
}
res, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatal(err)
}
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
return res.StatusCode, b
}
code, b := do()
if code == 403 && p.Retry(context.Background(), code, b) {
code, b = do()
}
return code, string(b)
}
glm := `{"model":"glm-5.2","messages":[{"role":"user","content":"hi"}],"reasoning_effort":"max"}`
// whoami answers: the first request carries the org, as droid's would
p := keep("tassel@example.com")
if code, b := send(p, p.Chat+"/chat/completions", Chat, glm); code != 200 {
t.Fatalf("glm-5.2: %d %s", code, b)
}
if whoamis != 1 || len(sent) != 1 {
t.Fatalf("whoami asked %d times, %d requests through", whoamis, len(sent))
}
h := sent[0]
for k, want := range map[string]string{
"Authorization": "Bearer " + tok, "X-Factory-Client": "cli", "X-Client-Version": factoryVersion,
"User-Agent": "factory-cli/" + factoryVersion, "X-Factory-Org-Id": "fac_T", "x-api-provider": "baseten",
"x-session-id": factorySession, "x-provider-routing-source": "registry_default",
"OpenAI-Platform": "", "X-Api-Key": "",
} {
if got := h.Get(k); got != want {
t.Errorf("%s: %q, want %q", k, got, want)
}
}
if h.Get("x-assistant-message-id") == "" {
t.Error("no x-assistant-message-id")
}
if c := factoryKept(t, "tassel@example.com"); c.Active != "fac_T" {
t.Fatalf("kept active %q", c.Active)
}
// kept: not asked again
if code, _ := send(p, p.Chat+"/chat/completions", Chat, glm); code != 200 || whoamis != 1 {
t.Fatalf("second request: %d, whoami %d", code, whoamis)
}
// Claude goes on Anthropic's Messages with droid's placeholder key
if code, b := send(p, p.Anthropic+"/v1/messages", Anthropic, `{"model":"claude-opus-5-5"}`); code != 200 {
t.Fatalf("claude: %d %s", code, b)
}
if got := sent[len(sent)-1]; got.Get("X-Api-Key") != "placeholder" || got.Get("x-api-provider") != "anthropic" {
t.Errorf("claude headers: %v", got)
}
// whoami down at first: the request is refused, whoami asked again, and
// it goes once more with the org
whoamiDown = 1
p = keep("down@example.com")
if code, b := send(p, p.Chat+"/chat/completions", Chat, glm); code != 200 {
t.Fatalf("after a failed whoami: %d %s", code, b)
}
if c := factoryKept(t, "down@example.com"); c.Active != "fac_T" || whoamis != 3 {
t.Fatalf("kept active %q, whoami %d", c.Active, whoamis)
}
// an org Factory serves from a host of its own
prem = srv.URL + "/prem"
p = keep("prem@example.com")
if code, b := send(p, p.Anthropic+"/v1/messages", Anthropic, `{"model":"claude-opus-5-5"}`); code != 200 {
t.Fatalf("prem: %d %s", code, b)
}
if got := paths[len(paths)-1]; got != "/prem/api/llm/a/v1/messages" {
t.Errorf("prem request went to %s", got)
}
// a 403 still answered says what to do; others pass as they are
msg := p.Explain("Factory: Forbidden", 403, []byte(forbidden))
if !strings.HasPrefix(msg, "Factory: Forbidden — ") || !strings.Contains(msg, "`droid`") || !strings.Contains(msg, "sign in to it again") {
t.Errorf("explained: %s", msg)
}
if got := p.Explain("Factory: overloaded", 529, nil); got != "Factory: overloaded" {
t.Errorf("a 529 explained: %s", got)
}
}