feat(providers): support Codex OAuth pools with inherited routing defaults

* feat(auth): support named chatgpt oauth providers

- add provider-scoped ChatGPT OAuth routes and CLI support

- persist refresh tokens per provider and reject provider-type collisions

- wire provider OAuth setup flows in the dashboard and setup UI

Refs #448

* feat(agent): add chatgpt oauth account routing

- add agent other_config routing for manual and round-robin selection

- reuse routed provider resolution across resolver and pending loaders

- add router, parser, and agent advanced dialog coverage for multi-account use

Refs #448

* docs(api): describe chatgpt oauth routing

- document named-provider ChatGPT OAuth auth routes

- describe agent-side account routing and round-robin behavior

- update OpenAPI agent config schema and provider type enum

Refs #448

* fix(store): add missing agent key context helpers

* feat(ui): clarify chatgpt oauth account setup and routing

* docs(providers): align chatgpt oauth alias examples

* feat(agent): add codex pool activity dashboard

* fix(providers): harden codex oauth alias setup

* feat(codex-pool): improve routing dashboard UX

- redesign the Codex/OpenAI pool page around saved-pool checkpoints and live evidence

- add clearer selection, attention, and recent-proof states for pool members

- make the lower panels fill the remaining desktop viewport while staying responsive

* fix(store): resolve context helper merge duplication

* feat(oauth): add codex pool quota and observation APIs

- add quota inspection and observation endpoints for ChatGPT Subscription (OAuth) providers

- teach codex routing to surface pool activity, observation metadata, and quota-aware readiness

- extend tests and HTTP docs/OpenAPI for the new pool monitoring flows

* feat(web): add codex pool quota monitor and controls

- add provider quota fetching, readiness badges, and live routing evidence on the account pool page

- redesign pool setup and activity panels for multi-account management with localized copy updates

- keep the live monitor internally scrollable and compact the account cards for better viewport fit

* fix(web): clarify pool routing labels

- rename the recent request badge from Direct to Selected

- restore compact quota bars in the live pool cards

* feat(codex-pool): add runtime health dashboard

- derive per-provider success and failure health from routed Codex traces

- surface routing, quota, and recent request evidence in the pool UI

- align provider alias guidance and owner access with the dashboard role model

* docs(auth): document tenant scoping and key roles

* fix(auth): harden tenant and codex pool access control

* fix(providers): align codex pool runtime defaults

* feat(ui): tighten codex pool responsive layout

* feat(chatgpt-oauth): refine codex pool management UX

* feat(chatgpt-oauth): surface quota bars on provider pages

- add compact quota bars to Codex provider rows and provider detail

- fetch quota only for ready visible provider rows and ready detail aliases

- fix managed-member detail visibility and tighten provider locale copy
This commit is contained in:
Kai (Tam Nhu) Tran authored and GitHub committed 2026-03-27 09:35:57 +07:00
1 parent e183b459c9
commit 30708ae79d
113 files changed
+11816 -536

No files matched your search

+152
View File
@@ -138,6 +138,82 @@ POST /v1/agents/{id}/wake
Response: `{content, run_id, usage?}`. Used by orchestrators (n8n, Paperclip) to trigger agent runs.
### Codex/OpenAI OAuth Routing in `other_config`
For agents whose main `provider` is a `chatgpt_oauth` provider, `other_config.chatgpt_oauth_routing`
can override or inherit routing behavior while keeping the main `provider` field as the preferred/default account alias.
```json
{
"provider": "openai-codex",
"model": "gpt-5.4",
"other_config": {
"chatgpt_oauth_routing": {
"override_mode": "custom",
"strategy": "round_robin"
}
}
}
```
Rules:
- Provider settings may define reusable `settings.codex_pool` defaults for a primary alias.
- `settings.codex_pool.extra_provider_names` is the authoritative membership list for that pool owner.
- A provider listed in another pool cannot also manage its own pool.
- `override_mode: "inherit"` tells the agent to follow those provider defaults.
- `override_mode: "custom"` stores an agent-local routing override for that provider-owned pool.
- `strategy: "primary_first"` keeps the main `provider` as the preferred account. When saved as a custom override with no extra names, it disables pooling for that agent.
- Provider aliases are arbitrary. `openai-codex`, `codex-work`, and `codex-team` are examples, not required prefixes.
- `strategy: "round_robin"` rotates requests across the main provider plus the provider-owned extra authenticated OpenAI Codex OAuth providers.
- `strategy: "priority_order"` tries the main provider first, then drains the provider-owned extra providers in order.
- Retryable upstream failures can fall through to the next eligible OpenAI Codex OAuth provider in the same request.
- Only enabled and authenticated `chatgpt_oauth` providers participate.
- Provider-scoped auth remains unchanged: `cmd/auth` and `/v1/auth/chatgpt/{provider}/*` still operate on explicit providers.
Provider-level defaults example:
```json
{
"name": "openai-codex",
"provider_type": "chatgpt_oauth",
"settings": {
"codex_pool": {
"strategy": "round_robin",
"extra_provider_names": ["codex-work", "codex-team"]
}
}
}
```
### Codex Pool Activity
| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/v1/agents/{id}/codex-pool-activity` | Summarize recent Codex/OpenAI OAuth pool usage for one agent |
Query parameters:
- `limit` optional, defaults to `18`, max `50`
Response fields:
- `strategy`: effective routing strategy (`primary_first`, `round_robin`, or `priority_order`)
- `pool_providers`: configured primary + extra provider aliases in pool order
- `stats_sample_size`: number of recent routed `llm_call` spans used to derive runtime health. The server derives health from `max(limit, 120)` recent spans even when `recent_requests` is still capped by the requested `limit`.
- `provider_counts`: per-alias routing evidence:
- `request_count`: backward-compatible count of direct selections
- `direct_selection_count`: times the router selected that alias first
- `failover_serve_count`: times that alias only served as failover
- `success_count`, `failure_count`: trace-backed runtime outcomes attributed to that alias. Success is attributed to the alias that actually served the request. On successful failover, earlier attempted aliases receive failures. On terminal error, every attempted alias receives a failure.
- `consecutive_failures`: current newest-first failure streak from recent trace evidence
- `success_rate`, `health_score`, `health_state`: additive runtime health summary. `health_score` is heuristic, but the stable bands are `idle` when there are no recent outcomes, `critical` at 3+ consecutive failures or score `< 40`, `degraded` below `80`, otherwise `healthy`
- `last_selected_at`, `last_failover_at`, `last_used_at`, `last_success_at`, `last_failure_at`: latest timestamps for each evidence type
- `recent_requests`: recent routed Codex calls:
- `span_id`, `trace_id`, `started_at`, `status`, `duration_ms`, `model`
- `selected_provider`: alias chosen first by the router
- `provider_name`: alias that actually served the request. This can be empty on terminal failures where no alias completed the call.
- `attempt_count`, `used_failover`, `failover_providers`
Use `direct_selection_count` plus the `selected_provider` sequence to verify real round-robin behavior. A provider with `failover_serve_count > 0` and `direct_selection_count = 0` was only observed as a rescue target, not as a confirmed round-robin selection.
---
## 5. Skills
@@ -652,11 +728,87 @@ Admin-only endpoints for managing gateway API keys. See [20 — API Keys & Auth]
| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/v1/auth/chatgpt/{provider}/status` | Check ChatGPT OAuth status for a provider |
| `GET` | `/v1/auth/chatgpt/{provider}/quota` | Fetch Codex/OpenAI quota state for a provider |
| `POST` | `/v1/auth/chatgpt/{provider}/start` | Start ChatGPT OAuth flow for a provider |
| `POST` | `/v1/auth/chatgpt/{provider}/callback` | Manual callback handler for a provider |
| `POST` | `/v1/auth/chatgpt/{provider}/logout` | Revoke ChatGPT OAuth token for a provider |
| `GET` | `/v1/auth/openai/status` | Check OpenAI auth status |
| `GET` | `/v1/auth/openai/quota` | Fetch quota state for the default `openai-codex` provider |
| `POST` | `/v1/auth/openai/start` | Start OAuth flow |
| `POST` | `/v1/auth/openai/callback` | Manual callback handler |
| `POST` | `/v1/auth/openai/logout` | Revoke token |
Legacy `/v1/auth/openai/*` routes remain as compatibility aliases for the default `openai-codex` OpenAI Codex OAuth provider.
### Provider Quota Response
`GET /v1/auth/chatgpt/{provider}/quota` and `GET /v1/auth/openai/quota` always return a provider-scoped quota envelope.
Success payload:
```json
{
"provider_name": "openai-codex",
"success": true,
"plan_type": "team",
"windows": [
{
"label": "Primary",
"used_percent": 24,
"remaining_percent": 76,
"reset_after_seconds": 3600,
"reset_at": "2026-03-24T20:15:00Z"
},
{
"label": "Secondary",
"used_percent": 38,
"remaining_percent": 62,
"reset_after_seconds": 604800,
"reset_at": "2026-03-31T19:15:00Z"
}
],
"core_usage": {
"five_hour": {
"label": "Primary",
"remaining_percent": 76,
"reset_after_seconds": 3600,
"reset_at": "2026-03-24T20:15:00Z"
},
"weekly": {
"label": "Secondary",
"remaining_percent": 62,
"reset_after_seconds": 604800,
"reset_at": "2026-03-31T19:15:00Z"
}
},
"last_updated": "2026-03-24T19:15:00Z"
}
```
Failure payload:
```json
{
"provider_name": "openai-codex",
"success": false,
"windows": [],
"error": "Quota metadata is missing for this account.",
"error_code": "missing_account_id",
"action_hint": "Sign in again so GoClaw can restore the ChatGPT account workspace metadata.",
"last_updated": "2026-03-24T19:15:00Z"
}
```
Notes:
- Invalid provider slugs return `400`.
- Missing provider still returns `404`, and provider type conflicts still return `409`.
- Missing quota metadata, expired workspace access, upstream `402`, upstream `403`, and upstream `429` return `200` with a structured failure payload so the dashboard can render actionable state inline.
- `needs_reauth`, `is_forbidden`, and `retryable` are boolean hints for UI/state-machine handling.
- `error_code` can be `missing_account_id`, `reauth_required`, `payment_required`, `quota_api_forbidden`, `quota_endpoint_not_found`, `rate_limited`, `provider_unavailable`, `network_timeout`, `network_error`, `quota_request_failed`, or `unknown_upstream_error`.
- Failure payloads still include `windows: []` so clients can treat the envelope consistently.
- `core_usage.five_hour` and `core_usage.weekly` are derived from upstream windows. When labels drift, GoClaw falls back to shortest-reset and longest-reset usage windows.
---
## 26. System