mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-17 08:14:33 +00:00
feat(codex-pool,create_image): collapse primary_first + route pools through create_image chain (#1006)
* refactor(codex-pool): remove redundant primary_first strategy * test(tools): update tool schema fixtures to pointer form * feat(create_image): route Codex pools through chain with member failover Codex pool chain entries now iterate pool members per the pool's own strategy (round_robin or priority_order) and fail over internally before the outer chain advances to the next entry. - ChatGPTOAuthRouter.GenerateImage implements NativeImageProvider: iterates orderedProviders, tries each member, advances round-robin state only on success, aggregates errors on pool exhaustion. - media_provider_chain.wrapPoolProvider wraps a *CodexProvider in a router when RoutingDefaults has extras or a non-primary-first strategy. Solo Codex (no extras) stays unwrapped. - Router exposes ProviderType() so chain telemetry records "chatgpt_oauth". Closes #1008 * feat(ui/builtin-tools): pool badge on create_image chain entries Chain entry card shows a read-only "Pool · <strategy>" badge when the entry's provider is a Codex pool base. Strategy label translates in en/vi/zh. No new toggle or selector — pool config lives on the provider itself. #1008 * refactor(providers): move Codex test helpers to providertest subpackage Addresses code-review High finding: NewTestCodexProviderFast and its staticTestTokenSource were exported from a non-_test.go file, compiling into the production binary. Relocating to internal/providers/providertest/ keeps the helper importable from other packages' tests without leaking test-only symbols into production. Also tightens wrapPoolProvider — pools with zero extra members no longer get wrapped in a router (KISS: nothing to rotate between). - Added CodexProvider.WithRetryConfig as a legitimate fluent option (the test helper now uses the public API). - Dropped the internal-package test helper file. #1008 * docs(pr-1006): add pool badge UI evidence Force-UI style capture of the read-only "Pool · Round-robin" badge on the create_image chain entry card when the selected provider carries settings.codex_pool with extras. Captured against staging gateway. * refactor(ui/builtin-tools): unify pool UX with Create Agent pattern The create_image chain Provider dropdown was listing pool members alongside pool owners, letting users accidentally bypass pool semantics by picking a member directly. Matches the pattern already used by Create Agent: hide pool members, show an inline "Pool" chip on owners. - Filter pool members from the chain Provider dropdown via getChatGPTOAuthPoolOwnership.ownerByMember. - Inline "Pool" chip on owner options, reusing the existing providers:list.poolBadge i18n key. - Drop the separate card-level "Pool · <strategy>" badge — the dropdown chip alone conveys the information without duplication. - Remove the now-unused isPoolProvider / poolStrategyOf helpers and the builtin.mediaChain.poolBadge* i18n keys we briefly introduced. #1008 * docs(pr-1006): add pool-filtered dropdown screenshot * fix(ui/builtin-tools): migrate stale pool-member chain entries on load Red-team blocker: a chain saved before the pool-aware UI landed may reference a pool member by name (e.g. openai-codex-2). After the dropdown started hiding members, such an entry produced: - empty Select trigger (no SelectItem matches the stored value) - conflicting Row 1 label still showing the member name - silent runtime misroute (bare solo call, no pool wrap) parseInitialEntries now consults getChatGPTOAuthPoolOwnership and rewrites any chain entry whose provider is a pool member to the owner's name + id. The next save persists the migrated value. Safe no-op for non-pool entries and for entries already pointing at an owner. Also memoize enabledProviders in the parent form so the card's useMemo boundaries actually hold (minor perf ding flagged by same review). * docs(pr-1006): refresh HTML evidence to match filter-based UX * fix(ui/agent-codex-pool): traffic policy reflects effective strategy under inherit On the agent's OpenAI Account Pool page, when Agent routing mode is Use Provider Defaults, the Traffic Policy buttons painted the draft's placeholder strategy ("priority_order") as selected — contradicting the top-of-page chip which already correctly shows the provider's effective strategy. The removal of primary_first in this PR unmasked the latent bug: the placeholder used to be a deprecated value that didn't match any live button, so nothing appeared selected. Derive selectedStrategy from defaultRouting when mode === "inherit": the button highlight now mirrors what actually runs. Buttons remain disabled in inherit mode (unchanged), but the displayed selection no longer misleads the user. * docs(pr-1006): add screenshot of inherit-mode Traffic Policy fix * fix(permissions): remove duplicate MethodSessionsCompact entry The writeExact slice listed MethodSessionsCompact twice. slices.Contains still returned correct results so runtime behavior is unchanged, but the duplicate entry was dead code. Spotted during review of PR #1006. --------- Co-authored-by: viettranx <edu@200lab.io>
This commit is contained in:
1 parent
f9e6c8817d
commit
abb10976f7
50 files changed
+1616
-242
No files matched your search
+9
-11
@@ -279,7 +279,7 @@ Extended thinking allows LLMs to generate internal reasoning tokens before produ
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
LEVEL["provider.settings.reasoning_defaults<br/>+ agent other_config.reasoning"] --> CHECK{"Provider<br/>supports thinking?"}
|
||||
LEVEL["provider.settings.reasoning_defaults<br/>+ agent reasoning_config"] --> CHECK{"Provider<br/>supports thinking?"}
|
||||
CHECK -->|No| SKIP["Skip — normal request"]
|
||||
CHECK -->|Yes| TYPE{"Provider type?"}
|
||||
|
||||
@@ -668,12 +668,10 @@ Agent override example:
|
||||
```json
|
||||
{
|
||||
"provider": "openai-codex",
|
||||
"other_config": {
|
||||
"reasoning": {
|
||||
"override_mode": "custom",
|
||||
"effort": "xhigh",
|
||||
"fallback": "downgrade"
|
||||
}
|
||||
"reasoning_config": {
|
||||
"override_mode": "custom",
|
||||
"effort": "xhigh",
|
||||
"fallback": "downgrade"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -685,18 +683,18 @@ Routing behavior:
|
||||
- A provider listed in another pool cannot also manage its own pool.
|
||||
- `override_mode: "inherit"` uses the primary provider's `settings.codex_pool`.
|
||||
- `override_mode: "custom"` is limited to routing behavior for that provider-owned pool.
|
||||
- `primary_first` keeps the preferred account fixed. When saved as a custom override with no extra names, it disables the pool for that agent and keeps the agent on the primary account only.
|
||||
- `round_robin` rotates requests across the preferred account plus the provider-owned extra authenticated OpenAI Codex OAuth accounts.
|
||||
- `priority_order` tries the preferred account first, then drains the provider-owned extra accounts in order.
|
||||
- Legacy `primary_first` configs are read back as `priority_order`. Existing agent overrides that explicitly saved an empty `extra_provider_names` list still remain single-account-only after migration.
|
||||
- Retryable upstream failures can fall through to the next eligible OpenAI Codex OAuth account in the same request.
|
||||
- Explicit provider names remain explicit. OAuth auth/logout is still provider-scoped.
|
||||
- Runtime observability for one agent is available at `GET /v1/agents/{id}/codex-pool-activity`, which exposes recent routed traces plus per-alias health derived from those traces.
|
||||
|
||||
Reasoning behavior:
|
||||
- `settings.reasoning_defaults` is provider-owned and reusable across agents.
|
||||
- `reasoning.override_mode: "inherit"` follows the provider default.
|
||||
- `reasoning.override_mode: "custom"` stores an agent-local reasoning policy.
|
||||
- Existing `reasoning` payloads without `override_mode` still behave as custom overrides.
|
||||
- `reasoning_config.override_mode: "inherit"` follows the provider default.
|
||||
- `reasoning_config.override_mode: "custom"` stores an agent-local reasoning policy.
|
||||
- Existing legacy `other_config.reasoning` payloads without `override_mode` still behave as custom overrides.
|
||||
- If no provider default is saved, inherit resolves to reasoning `off`.
|
||||
- Trace metadata surfaces the reasoning `source` so provider-default behavior is no longer implicit.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ Extended thinking allows LLM providers to "think out loud" before producing a fi
|
||||
|
||||
## 1. Configuration
|
||||
|
||||
The reusable default now lives on the provider in `settings.reasoning_defaults`. Agents consume that default by inheriting it, or store a custom override in `other_config.reasoning`. `thinking_level` remains the backward-compatible coarse shim for older builds.
|
||||
The reusable default now lives on the provider in `settings.reasoning_defaults`. Agents consume that default by inheriting it, or store a custom override in top-level `reasoning_config`. `thinking_level` remains the backward-compatible coarse shim for older builds.
|
||||
|
||||
| Level | Behavior |
|
||||
|-------|----------|
|
||||
@@ -35,10 +35,8 @@ The reusable default now lives on the provider in `settings.reasoning_defaults`.
|
||||
|
||||
```json
|
||||
{
|
||||
"other_config": {
|
||||
"reasoning": {
|
||||
"override_mode": "inherit"
|
||||
}
|
||||
"reasoning_config": {
|
||||
"override_mode": "inherit"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -47,13 +45,11 @@ The reusable default now lives on the provider in `settings.reasoning_defaults`.
|
||||
|
||||
```json
|
||||
{
|
||||
"other_config": {
|
||||
"thinking_level": "high",
|
||||
"reasoning": {
|
||||
"override_mode": "custom",
|
||||
"effort": "xhigh",
|
||||
"fallback": "downgrade"
|
||||
}
|
||||
"thinking_level": "high",
|
||||
"reasoning_config": {
|
||||
"override_mode": "custom",
|
||||
"effort": "xhigh",
|
||||
"fallback": "downgrade"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -61,11 +57,11 @@ The reusable default now lives on the provider in `settings.reasoning_defaults`.
|
||||
Rules:
|
||||
- Unset provider defaults and unset agent reasoning both resolve to `off`.
|
||||
- `settings.reasoning_defaults` is provider-owned and reusable across agents.
|
||||
- `reasoning.override_mode` accepts `inherit|custom`.
|
||||
- `reasoning_config.override_mode` accepts `inherit|custom`.
|
||||
- `thinking_level` still accepts `off|low|medium|high`.
|
||||
- `reasoning.effort` accepts `off|auto|none|minimal|low|medium|high|xhigh`.
|
||||
- `reasoning.fallback` accepts `downgrade|off|provider_default`.
|
||||
- Existing `reasoning` payloads without `override_mode` are treated as custom overrides for backward compatibility.
|
||||
- `reasoning_config.effort` accepts `off|auto|none|minimal|low|medium|high|xhigh`.
|
||||
- `reasoning_config.fallback` accepts `downgrade|off|provider_default`.
|
||||
- Existing legacy `other_config.reasoning` payloads without `override_mode` are treated as custom overrides for backward compatibility.
|
||||
- Read path resolves provider defaults first, then applies agent inherit/custom semantics, then falls back to legacy `thinking_level`.
|
||||
- Write path keeps a derived coarse `thinking_level` only for custom agent overrides so rollback to older GoClaw builds stays safe.
|
||||
|
||||
|
||||
+15
-19
@@ -140,20 +140,18 @@ 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`
|
||||
### Codex/OpenAI OAuth Routing in `chatgpt_oauth_routing`
|
||||
|
||||
For agents whose main `provider` is a `chatgpt_oauth` provider, `other_config.chatgpt_oauth_routing`
|
||||
For agents whose main `provider` is a `chatgpt_oauth` provider, top-level `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"
|
||||
}
|
||||
"chatgpt_oauth_routing": {
|
||||
"override_mode": "custom",
|
||||
"strategy": "round_robin"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -164,10 +162,10 @@ Rules:
|
||||
- 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.
|
||||
- Legacy `primary_first` payloads are normalized to `priority_order` on read. Existing agent overrides that explicitly saved `extra_provider_names: []` still remain single-account-only after migration.
|
||||
- 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.
|
||||
@@ -209,30 +207,28 @@ Rules:
|
||||
- the final runtime effort is still normalized against the agent's selected model capabilities
|
||||
- if no provider default is saved, inherit mode resolves to reasoning `off`
|
||||
|
||||
### Agent reasoning policy in `other_config`
|
||||
### Agent reasoning policy in `reasoning_config`
|
||||
|
||||
Agents can now store capability-aware GPT-5/Codex reasoning intent under `other_config.reasoning`.
|
||||
Agents can now store capability-aware GPT-5/Codex reasoning intent under top-level `reasoning_config`.
|
||||
|
||||
```json
|
||||
{
|
||||
"provider": "openai-codex",
|
||||
"model": "gpt-5.4",
|
||||
"other_config": {
|
||||
"reasoning": {
|
||||
"override_mode": "inherit"
|
||||
}
|
||||
"reasoning_config": {
|
||||
"override_mode": "inherit"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Rules:
|
||||
- `reasoning.override_mode` supports `inherit|custom`
|
||||
- `reasoning_config.override_mode` supports `inherit|custom`
|
||||
- `override_mode: "inherit"` tells the agent to follow `settings.reasoning_defaults`
|
||||
- `override_mode: "custom"` stores an agent-local override; the dashboard also writes a derived `thinking_level` shim for rollback safety
|
||||
- `thinking_level` remains the coarse compatibility shim: `off|low|medium|high`
|
||||
- `reasoning.effort` supports `off|auto|none|minimal|low|medium|high|xhigh`
|
||||
- `reasoning.fallback` supports `downgrade|off|provider_default`
|
||||
- existing `reasoning` payloads without `override_mode` continue to behave as custom overrides
|
||||
- `reasoning_config.effort` supports `off|auto|none|minimal|low|medium|high|xhigh`
|
||||
- `reasoning_config.fallback` supports `downgrade|off|provider_default`
|
||||
- existing legacy `other_config.reasoning` payloads without `override_mode` continue to behave as custom overrides
|
||||
- unset reasoning resolves to `off`
|
||||
- the runtime may normalize unsupported efforts, and the actual decision is surfaced in trace span metadata
|
||||
|
||||
@@ -266,7 +262,7 @@ Query parameters:
|
||||
- `limit` optional, defaults to `18`, max `50`
|
||||
|
||||
Response fields:
|
||||
- `strategy`: effective routing strategy (`primary_first`, `round_robin`, or `priority_order`)
|
||||
- `strategy`: effective routing strategy (`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:
|
||||
|
||||
@@ -33,8 +33,6 @@ Implementation is evidence-backed against the native ChatGPT Responses API event
|
||||
- `plans/260422-1349-goclaw-chatgpt-image-gen/` — plan + phase files.
|
||||
- `plans/reports/researcher-260422-1414-codex-native-image-events.md` — native event schema.
|
||||
|
||||
---
|
||||
|
||||
## 2026-04-20
|
||||
|
||||
### Pipeline: accurate context token tracking + dynamic compaction
|
||||
@@ -96,6 +94,21 @@ Implementation is evidence-backed against the native ChatGPT Responses API event
|
||||
|
||||
---
|
||||
|
||||
## 2026-04-22
|
||||
|
||||
### Codex OAuth pool routing strategy cleanup
|
||||
|
||||
**Changes**
|
||||
|
||||
- Removed `primary_first` from the public Codex OAuth routing strategy surface. The API, OpenAPI schema, and web UI now expose only `round_robin` and `priority_order`.
|
||||
- Legacy `primary_first` and `manual` routing values now normalize to `priority_order` on read in the backend store layer.
|
||||
- Activity endpoints now default empty/no-pool responses to `priority_order` instead of `primary_first`.
|
||||
- Agent overrides that explicitly persist `extra_provider_names: []` continue to behave as single-account-only routing after the migration.
|
||||
|
||||
**Docs**
|
||||
|
||||
- Updated `docs/02-providers.md` and `docs/18-http-api.md` to describe the two-strategy model and the compatibility migration.
|
||||
|
||||
## 2026-04-19
|
||||
|
||||
### TTS: Gemini provider + ProviderCapabilities schema engine
|
||||
|
||||
Reference in new issue
Block a user