fix(ai): scope Anthropic credential identity by organization

One Anthropic account email can hold multiple organizations (a Team seat
plus a personal Max plan), each with its own org-scoped OAuth token and
independent 5h/7d limit pools. Credentials were deduped by bare email, so
logging in with the second subscription silently replaced the first, and
usage reports from the two pools merged into one row with mixed numbers.

- capture organization uuid/name at login (token exchange response, with
  a claude_cli/bootstrap fallback); token refreshes never rewrite it
- key anthropic credential identity as email + org; a legacy email-keyed
  row is claimed in place by the first org-scoped login with the same
  email, and org-less credentials never clobber org-scoped rows
- partition usage-report dedupe and the per-credential usage cache by
  org so the two subscriptions' limit pools stay distinct for rotation
- show the organization in omp usage (redaction-safe) and name the
  stored account/org in the login success message
This commit is contained in:
chan1103
2026-07-11 16:32:19 +09:00
parent 2081bae6a6
commit 044d722a36
21 changed files with 717 additions and 63 deletions
+1 -1
View File
@@ -31,7 +31,7 @@ When a provider needs an API key, `omp` resolves it in this order (first match w
1. **Runtime override** — a key supplied for the current process, e.g. CLI `--api-key`. Never persisted.
2. **`models.yml` config key** — an `apiKey` pinned on a custom provider, registered as a config-sourced bearer. This deliberately beats stored OAuth, so a key supplied for a custom `baseUrl`/gateway is honored instead of forwarding an upstream OAuth token the proxy would reject.
3. **Stored API key** — an API-key credential saved in the auth store.
4. **Stored OAuth credential** — refreshed when needed; multiple accounts are ranked/rotated automatically.
4. **Stored OAuth credential** — refreshed when needed; multiple accounts are ranked/rotated automatically. For Anthropic, each organization counts as its own account: one email holding both a Team seat and a personal plan can log in once per subscription (pick the workspace on the browser consent page) and rotation treats them as two accounts.
5. **Provider environment variable** — including values loaded from `.env` files (see [the env-var table](#environment-variables-and-env-files)).
6. **`models.yml` fallback resolver** — keys for custom providers not otherwise registered.