After reconcileRenumberedMigrations() rewrites a legacy row (e.g. 028→029),
verify the old version slot is clear. A residual row at the old version
would cause getAppliedVersions() to skip the new migration file at that
version number (028_create_files_and_batches.sql).
Also adds 'batches' table to PHYSICAL_SCHEMA_SENTINELS for physical
schema recovery on upgrade paths.
Prevent upstream 400 failures when clients omit prior
reasoning_content in multi-turn tool-calling conversations.
Capture reasoning_content from streaming and non-streaming assistant
responses, persist it in a memory-plus-SQLite cache keyed by
tool_call_id, and re-inject it on later requests when available.
Add the reasoning cache migration, service layer, authenticated API
endpoints, dashboard tab, and unit coverage to support inspection,
cleanup, and crash recovery.
- Use jsonc-parser to update only provider.omniroute in opencode.json,
preserving MCP servers, comments, and other provider entries
- Add /api/cli-tools/keys endpoint returning raw keys for CLI tools UI
(session-auth protected via requireCliToolsAuth)
- Fix OpenCode guide step 3 to use ICU-style {baseUrl} placeholder
instead of broken {{baseUrl}} across all 40+ locales
- Restore valid OpenCode light/dark SVG logos (were broken HTML downloads)
- Add customCliTab translation key to en.json
- Add modelLabels support for human-readable model names in config
- Fix 9 additional locale files (bn, fa, gu, in, mr, sw, ta, te, ur)
that were added after the original PR and still had double-braces
Co-authored-by: JasonLandbridge <JasonLandbridge@users.noreply.github.com>
Add Bengali, Persian, Gujarati, Indonesian alt, Marathi,
Swahili, Tamil, Telugu, and Urdu message bundles to the app's
locale configuration.
Extend RTL locale support for Persian and Urdu and update project
docs to reflect the broader 40+ language availability.
Two root causes fixed:
1. Schema: cliModelConfigSchema.apiKey was z.string().optional() but
the frontend sends null when cloudEnabled is true. Zod rejects null
for optional strings → validation 400 with structured error object.
Fix: z.string().nullable().optional()
2. Frontend: All 25 tool card error handlers used data.error directly
as React children. When data.error is an object ({message, details}),
React crashes with Error #31 (Objects are not valid as React child).
Fix: extract data.error.message when data.error is an object.
Replace Title Case placeholder values (e.g. 'Eval Controls Title',
'Suite Builder Case Name Label') with proper English text across all
31 locale files. These placeholder keys were auto-generated from
camelCase key names but never populated with meaningful values.
Add limitExhausted, learnedFromHeaders, remainingOfLimit, throttleStatus,
and lastHeaderUpdate keys to all 31 locale files. These keys are used by
the health dashboard rate limit status section and were causing
MISSING_MESSAGE errors in production.
Replace placeholder builtin skill responses with real file, HTTP, and
code-execution flows constrained to per-key workspaces, size limits, and
sanitized request headers.
Harden the Docker sandbox with dropped capabilities, tmpfs-backed
workdirs, configurable runtime limits, and clearer failure behavior for
disabled browser automation.
Also consolidate legacy dashboard usage navigation into logs, remove
stale sidebar and SSE backup artifacts, and expand tests to lock in the
new runtime and routing contracts.
The parseToml function was stripping all value quotes uniformly, turning
every value into a JS string. When toToml re-serialized, unquoted
integers like 2 were wrapped in quotes becoming "2" — a TOML string.
This broke Codex CLI which expects u32 for tui.model_availability_nux:
Error loading config.toml: invalid type: string "2", expected u32
Now parseToml detects booleans (true/false), integers, and floats,
preserving their native JS types. formatTomlValue already handles
number/boolean types correctly, so round-tripping no longer corrupts
third-party config sections.
Prevent repeated provider-limit refresh requests by guarding the bulk
refresh flow with a ref-backed lock instead of a stale callback
dependency.
Also avoid tying eval data loading to translation updates and replace the
fetch failure path with a static error so the effect runs predictably.
Refresh English cost dashboard copy to provide clearer labels and empty
state messaging.
Pass the entered sudo password through endpoint enable and disable
requests so macOS and Linux installs can start or stop Tailscale
without retrying unauthenticated commands.
Also detect and cache the active tailscaled socket before issuing CLI
calls, preferring the system daemon socket when available so status and
funnel operations target the running service correctly.
Populate newly introduced dashboard and provider UI message keys in all
locale bundles to prevent missing translation lookups after the v3.7.0
changes.
Also fix quota reset handling so expired limits are only marked stale
when usage is still pending, adjust combo form dark-mode backgrounds,
and expand the prepublish hash rewrite to handle nested package paths.
Several merges (primarily #1602 by @JasonLandbridge) added new i18n keys
with English values to all locale files instead of translated text.
This commit auto-translates all remaining untranslated pt-BR.json keys
using Google Translate, with manual fixups for technical terms (Proxy,
Fallback, Streaming, Playground, Skills, etc).
commit ff0a718e65
Author: Jean Brito <jean.f.brito@gmail.com>
Date: Sat Apr 25 16:45:23 2026 -0300
feat(providers): add CrofAI as a built-in API-key provider
CrofAI (https://crof.ai) ships an OpenAI-compatible /v1 endpoint with
Bearer auth and a /v1/models discovery route. It hosts a curated set of
hosted open models (DeepSeek V3.2/V4 Pro, Kimi K2.5/K2.6, GLM 4.7/5.x,
Gemma 4, MiniMax M2.5, Qwen3.5/3.6) that today users can only attach
through the generic "Add OpenAI Compatible" flow — losing branding,
defaults, prefix routing, and showing up under "API Key Compatible
Providers" instead of the curated "API Key Providers" section.
This change wires CrofAI as a first-class built-in, mirroring how Kimi
is registered (OpenAI format + bearer auth + seed model list).
Files touched (kept tight):
- src/shared/constants/providers.ts
Add `crof` to APIKEY_PROVIDERS with id/alias/name/icon/color/textIcon/website.
- src/shared/constants/config.ts
Register PROVIDER_ENDPOINTS.crof = "https://crof.ai/v1/chat/completions".
- open-sse/config/providerRegistry.ts
Add a `crof` REGISTRY entry: format "openai", executor "default",
authType "apikey", authHeader "bearer", and a seed model list pulled
from a live GET https://crof.ai/v1/models on 2026-04-25 (DeepSeek,
Kimi, GLM, Gemma, MiniMax, Qwen variants). Runtime /models discovery
keeps the live catalog up to date.
- src/shared/components/ProviderIcon.tsx
Map `crof -> "crof"` in PROVIDER_ICON_MAP. Not added to PNG_PROVIDERS
so the UI falls back to the textIcon ("CR") until a logo asset ships
at public/providers/crof.png.
- tests/unit/crof-provider.test.ts (new)
Pins the registration shape (provider identity, base URL, registry
entry, seed model families). Required by the repo's PR Test Policy.
Verified end-to-end against a locally rebuilt image:
- CrofAI appears under "API Key Providers" alongside GLM Coding/Minimax.
- The connection-add dialog opens with title "Add CrofAI API Key".
- POST /api/providers/validate returns "Valid" against /v1/models.
- POST /api/providers persists a connection (testStatus=active).
- POST /v1/chat/completions { model: "crof/kimi-k2.5", ... } returns 200
with a real Kimi K2.5 response — full proxy path resolves through the
new registry entry.
- npm run test:unit passes locally including tests/unit/crof-provider.test.ts.
Notes for the maintainer:
- No logo file is included; happy to follow up with a PNG for
public/providers/crof.png. Until then the UI uses the "CR" textIcon.
- Pricing (src/shared/constants/pricing.ts) is intentionally not
hardcoded — CrofAI exposes per-model pricing via /v1/models response,
and runtime sync is preferable to stale baked-in numbers. Happy to add
a stub block if requested.
- Anthropic-compatible endpoint (https://anthropic.nahcrof.com/v1/messages)
is not wired in this PR. Users can still add it via "Add Anthropic
Compatible" if needed.
# Conflicts:
# src/shared/components/ProviderIcon.tsx
Require management authentication across combo, settings, skill,
webhook, provider auth, restart, and shutdown management routes to
prevent unauthenticated access to privileged operations.
Tighten the OpenAPI try endpoint to only proxy same-origin OmniRoute API
paths and strip hop-by-hop or forwarded headers before dispatching.
Add unit coverage for the new auth guards and proxy validation rules.
- Added requireManagementAuth to /api/logs/export
- Added requireManagementAuth to /api/logs/console
- Added requireManagementAuth to /api/compliance/audit-log
- Increased minimum password length from 4 to 8 in reset-password CLI
Adds a new chatgpt-web provider that routes through chatgpt.com's internal
backend-api using a Plus/Pro subscription session cookie, enabling access
to GPT-5.x models without an OpenAI API key.
Heavier than perplexity-web/grok-web because chatgpt.com layers more bot
protection — this PR builds out the full pipeline needed to look like a
real browser session.
## New executor: open-sse/executors/chatgpt-web.ts
Auth/request pipeline (per chat completion):
1. exchangeSession() GET /api/auth/session cookie -> JWT (cached ~5min)
2. fetchDpl() GET / scrape data-build + script src
3. runSessionWarmup() GET /backend-api/me, /conversations, /models
4. POST /sentinel/chat-requirements/prepare -> prepare_token
5. POST /sentinel/chat-requirements -> chat-requirements-token + PoW seed/diff
6. solveProofOfWork() SHA3-512 loop -> "gAAAAAB..." sentinel proof token
7. POST /backend-api/f/conversation with all sentinel headers
8. parse SSE stream -> OpenAI chat.completion[.chunk] format
Notable details:
- 18-element prekey config matching chat2api/openai-sentinel (browser fingerprint
values, U+2212 MINUS SIGN in `webdriver−false`). Thin shapes get escalated to
mandatory Turnstile.
- Two-stage Sentinel handshake (/prepare + /chat-requirements) — sending only
the prepare result returns a 403 "Unusual activity" response.
- `turnstile.required: true` from Sentinel is treated as advisory; the conv
endpoint accepts requests without a Turnstile token as long as PoW + chat-
requirements-token are valid. Optional bring-your-own Turnstile via
`providerSpecificData.turnstileToken` for accounts that hard-require it.
- SSE parser tracks message_id and resets the accumulator on a new turn —
chatgpt.com echoes prior assistant messages (with status finished_successfully)
before sending the new turn.
- entity["...","value", ...] internal markup stripped from output (browser
renders these client-side).
- Conversation-continuity cache disabled by default: we send
history_and_training_disabled: true (Temporary Chat mode) and those
conversation_ids expire too fast to reuse — re-using returned 404. Each
request now sends conversation_id: null and replays full history, matching
what Open WebUI and OpenAI-API-style clients send anyway.
## TLS impersonation: open-sse/services/chatgptTlsClient.ts
ChatGPT's Cloudflare config pins cf_clearance to JA3/JA4 TLS fingerprint +
HTTP/2 SETTINGS frame. Plain Node Undici fetch always returns
cf-mitigated: challenge regardless of cookies. The wrapper module loads
`tls-client-node` (Firefox 148 fingerprint) in native runtime mode (.so via
koffi) — managed mode spawns a sidecar that conflicts with OmniRoute's
global fetch proxy patch.
- Lazy singleton TLSClient with process exit hooks
- Streaming-capable (file tail) and non-streaming modes
- Test injection point: __setTlsFetchOverrideForTesting() lets unit tests mock
the client without touching globalThis.fetch
## Provider wiring
- open-sse/executors/index.ts — register ChatGptWebExecutor with cgpt-web alias
- open-sse/config/providerRegistry.ts — registry entry, format=openai,
authHeader=cookie, model gpt-5.3-instant
- src/shared/constants/providers.ts — WEB_COOKIE_PROVIDERS UI metadata
(icon, color, authHint)
- src/lib/providers/validation.ts — validateChatGptWebProvider hits
/api/auth/session via the TLS client, detects cf-mitigated/HTML responses
and returns a clear "paste full Cookie line" hint instead of a generic
"Invalid"
- next.config.mjs — mark tls-client-node, koffi, tough-cookie as external
packages (Turbopack can't bundle the native .so)
## Cookie format
Validator and executor accept any of:
- bare value: "eyJhbGc..."
- unchunked cookie line: "__Secure-next-auth.session-token=eyJ..."
- chunked cookie line: "__Secure-next-auth.session-token.0=...; __Secure-next-auth.session-token.1=..."
- full DevTools Cookie header line: "Cookie: __Secure-next-auth.session-token.0=...; cf_clearance=...; ..."
NextAuth chunks the JWE when it exceeds 4KB; chunked cookies pass through
verbatim (NextAuth reassembles server-side). Recommend pasting the full
DevTools Cookie line so cf_clearance, __cf_bm, _cfuvid, _puid travel along —
without cf_clearance, Cloudflare blocks the request before NextAuth sees it.
## Tests
tests/unit/chatgpt-web.test.ts — 27 tests, all passing:
- Registration + alias resolution
- Token exchange (cookie -> Bearer flow)
- Token cache TTL
- Refreshed cookie surfaced via onCredentialsRefreshed callback
- Sentinel call ordering (session -> prepare -> chat-requirements -> conv)
- Sentinel chat-requirements-token forwarded on conv request
- PoW token has gAAAAAB prefix
- Turnstile.required: true does NOT block conv (passes through)
- Non-streaming chat.completion JSON
- Streaming SSE chunks ending with [DONE]
- Cumulative-parts diffing yields non-overlapping deltas
- Errors: 401 session, 403 sentinel, 429 conv rate-limit
- Empty messages -> 400 without any fetch
- Missing apiKey -> 401 without any fetch
- Cookie format: bare value, unchunked, chunked, "Cookie: ..." DevTools line
- Conversation continuity: each call starts a fresh conversation
- Browser-like headers on conv POST (UA, Origin, Sec-Fetch-Site, Accept)
- Payload shape (action, model=gpt-5-3, history_and_training_disabled)
- Provider registry contains chatgpt-web with gpt-5.3-instant model
Verification: typecheck:core clean, lint clean (no new warnings),
end-to-end manually verified across single-turn, multi-turn (memory
preserved), streaming, and Open WebUI-style sequential growing-history
flows.
## References
- bogdanfinn/tls-client (Go) — TLS impersonation upstream
- fatihkabakk/tls-client-node — Node bindings
- lanqian528/chat2api — Sentinel/PoW/prekey reference impl (Python)
- leetanshaj/openai-sentinel — Prekey config + SHA3-512 solver
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Register AgentRouter across the provider registry, pricing, docs, and
dashboard metadata so it appears as a first-class OpenAI-compatible
passthrough option.
Add a dedicated `/api/models/test` endpoint and provider-page controls
for on-demand single-model diagnostics, including latency feedback and
success/error status, to help verify mappings without triggering broader
connection tests or rate limits.
Align header casing expectations in provider validation tests with the
current registry contract.
Compile MITM utilities as NodeNext ESM for prepublish builds, copy the
CommonJS MITM server into standalone artifacts, and resolve MITM data
paths without relying on Next.js aliases at runtime.
Replace shell-interpolated setup and elevated command flows with
argument-based spawn and execFile helpers for database setup, DNS edits,
certificate install flows, and Tailscale sudo execution. Also tighten
the Electron production CSP, update provider icon loading to use direct
@lobehub/icons imports with local fallbacks, and pin dependency
configuration to avoid unused peer installs and known audit findings.
Add the Codex Auto Review model to the provider registry and prefer
Codex when resolving unprefixed `codex-auto-review` and `gpt-5.5`
requests.
Broaden provider icon mappings and bundled PNG assets so more providers
render correctly in the shared UI. Also tighten chatCore stream cleanup
behavior so streaming responses return immediately while semaphore slots
and model locks are released on completion or failure, with tests and
artifact policy coverage updated accordingly.
Register AWS Polly as an audio provider with SigV4 request signing,
speech engine discovery, and API-key validation for managed provider
flows.
Add Lemonade as a self-hosted OpenAI-compatible provider, expand
static model discovery to audio registries, and support Azure OpenAI
deployment discovery from resource endpoints.
Sanitize sensitive provider-specific AWS fields in API responses and
update related tests and release notes.
* fix(claude): preserve tool_result adjacency in native and CC-compatible paths
* feat(providers): add Petals and Nous Research provider support
Register Nous Research as an OpenAI-compatible gateway with remote
model discovery and validation against chat completions.
Add Petals provider metadata, default config, validation, and a
specialized executor that maps OpenAI-style requests to the public
generate endpoint. Also allow optional API keys and configurable base
URLs for Petals in the dashboard and provider schemas.
Expand provider model and catalog tests to cover both integrations.
* fix(resilience): sync queue updates and clear stale discovery caches
Await runtime request queue updates so limiter settings and auto-enabled
API key protections are recomputed when resilience settings change.
Preserve cancelled batch state for in-flight work by marking input files
processed without generating output artifacts, and replace cached synced
models with an empty set when remote discovery returns no models so the
providers route falls back to the local catalog instead of stale cache.
---------
Co-authored-by: congvc <congvc-dev@gmail.com>
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>