chore(main): 同步上游 v0.5.50 并保留生产修复 - #7
Merged
Conversation
Ollama: replace informational stub with real quota tracker hitting ollama.com/api/usage (session 5h + weekly 7d, 0..1 ratio) and /api/me plan label; bind handler to apiKey + add features.usageApikey so apikey connections work.
Token refresh: add backgroundTokenRefresh scheduler that refreshes OAuth connections within max(provider lead, 30min) of expiry, independent of inbound traffic (10s after boot, then every 5min, unref'd timers, DISABLE_BACKGROUND_TOKEN_REFRESH kill-switch, fail-open per tick/connection). Registered from custom-server.js (listening) and initializeApp.js. checkAndRefreshToken gains opt-in {force} for the scheduler; request path unchanged.
… dualAuthTypes Free-tier and apikey providers (e.g. cloudflare-ai, byteplus, ollama, vertex) whose registry entry omits authModes were treated as oauth-only, hiding their apikey connections on the providers grid card.
…atible providers getAllAvailableModels() only consulted the static PROVIDER_MODELS catalog, which has no entry for dynamically-registered compatible providers (id like openai-compatible-chat-uuid). Fall back to the connection's own defaultModel/customModels/placeholder, mirroring ModelSelectModal.js.
/api/auth/status did not expose whether the auth cookie corresponds to a valid dashboard session, so /login could only detect "auth disabled" (requireLogin === false) and not "already logged in". Add authenticated to the status response and redirect from /login when it's true.
JetBrains Runtime (JBR 25+) sends an h2c upgrade on OpenAI-compatible requests, which the HTTP/1.1 server would otherwise close. Intercept the upgrade, replay the buffered request through the existing handler, and respond over HTTP/1.1.
With output: "standalone", next build writes server.js under .next/standalone but leaves generated static/public assets in the project root, so starting the standalone server directly (e.g. via PM2) 404s on JS/CSS/font/favicon requests and /login stays stuck loading. Add a postbuild step that copies .next/static and public into the standalone directory, skipping the workspace-traced CLI build which already copies its own assets.
ollama's registry entry lacked authModes, so dualAuthTypes on the providers page defaulted to oauth and its apikey connections showed as No connections on the freeTier card.
…indows `open` derives its own directory from import.meta.url at module scope. Webpack replaces that with the build machine's absolute path as a string literal, so a release built on macOS ships a file:///Users/... URL that fileURLToPath rejects on Windows (no drive letter), throwing on import. refreshXaiToken dynamic-imports the xAI OAuth service, which imports open eagerly, so every Grok token refresh silently failed and was swallowed by a catch that only logs a warning. Add open to serverExternalPackages so it keeps its real import.meta.url at runtime, and bundle it into the CLI package via ensureModuleInBundle (same guard already used for sql.js) since externalizing it means webpack no longer traces/copies it automatically.
Tool schemas carrying uniqueItems, contains, multipleOf, unevaluatedProperties, unevaluatedItems, or contentSchema get rejected by the Gemini API with "Unknown name ...: Cannot find field", failing the whole request. Add them to UNSUPPORTED_SCHEMA_CONSTRAINTS alongside the existing stripped keywords (minItems, maxItems, format, ...).
handleForcedSSEToJson dropped cached prompt tokens in two ways: the Responses branch summed only input_tokens, which excludes cache_read and cache_creation on cache-capable upstreams (measured 2012 reported vs ~5344 actual, 5332 from cache); and the Chat Completions branch computed usage correctly but it didn't always reach the client (an Anthropic response with cache_read_input_tokens: 11022 arrived with no usage field at all). Now folds cache counters into prompt_tokens, surfaces them via prompt_tokens_details, and re-attaches usage before serialisation.
…malize messages for INT Neutralize CLI-agent system prompts that trigger CodeBuddy CN's content filter, add usage/quota tracking for codebuddy-intl sharing CN's logic, and normalize codebuddy-intl request messages to the shape it expects.
Lock GitHub Copilot connections account-wide until 00:00 UTC on the first of next month when the upstream 402 response indicates the monthly additional-usage-limit was hit, instead of only cooling down the requested model for 120s. Other GitHub 402 responses keep the existing model-scoped cooldown.
Adds pt-... token auth as an alternative to OAuth device flow. A PAT can't sign COSY requests directly, so it's exchanged for a short-lived job token (jt-...) plus userId via openapi.qoder.sh, then used for signing. Also fixes job-token traffic (jt-...) being rejected by api3.qoder.sh with 403 "Login expired" — the official qodercli serves jt- traffic from api2.qoder.sh instead, so buildUrl/model-list routing now branches on it. Quota usage and the dashboard add-key modal are updated to resolve PAT credentials and label the field correctly, and bulk-add now validates each key so it gets a real testStatus instead of a hardcoded "unknown".
PAT-to-job-token exchange was duplicated between the executor and the model service, each with its own cache. Consolidate into qoderModels.js and have the executor import it. Also add a qoder case to the API-key validate route - the generic OpenAI-compat probe cannot validate a PAT (needs job-token exchange + COSY signing first), so bulk-add always reported unknown for qoder keys.
The global claudeHeaderCache singleton overlaid the last-seen Claude Code client's identity headers onto every subsequent request, leaking one client's headers (anthropic-beta, user-agent, x-stainless-*, etc.) onto another client/account sharing the same server. Removed the singleton and the claudeOverlay hook entirely, falling back to static per-provider headers. anthropic-beta is now computed per-request from the requested model, gating heavy-agent flags (advanced-tool-use, effort) to opus/sonnet only.
Break out tool schema and tool-history bytes in the size snapshot and add an effective byte-savings percentage so token-saved logs reflect the actual outbound payload reduction, not just processed content.
Adds a guide-type CLI Tools entry for OpenDesign, the open-sourced claude.ai/design skills pack. It has no standalone config - it inherits the host agent's model/provider config - so once the host (Claude Code, Cursor, Codex, Gemini CLI, OpenCode) points at 9Router, /opendesign sessions route through automatically.
Add "ultra" reasoning level for Codex GPT-5.6 Sol and Terra, and expose Max for Luna (Luna falls back Ultra to Max since it is not supported upstream). Scoped to cx/ routes only; Kiro and generic OpenAI routing unchanged.
Missing declaration caused a ReferenceError -> 500 HTML response instead of JSON when clients called POST .../register-session.
Map the Grok OAuth access-token tier claim to the public plan label and prefer it over internal /user entitlement names. Fails open to existing plan detection for opaque or malformed tokens; upstream remains authoritative for access and quota enforcement.
Adds mimo-v2.5-tts as a Media Provider TTS through the existing OpenAI-compatible chat-completions endpoint. Voice is selected via the top-level audio.voice field, and an optional style/language hint is threaded through tts.js -> ttsCore.js -> the new adapter.
Merge the complete generated .next-cli-build/server tree into the packaged CLI after the standalone copy, since Next's standalone output is trace-pruned and can omit route modules (e.g. /api/v1/messages) or chunks loaded dynamically. Add a post-copy integrity check for the required API route artifacts so an incomplete package fails during pack:cli instead of at runtime. Fixes decolua#2945
Fix port 201281 -> 20128/v1 typo in README.zh-CN.md diagram, add RTK Token Saver mention to README.vi.md/README.zh-CN.md, update Tier 3 free providers to 2026 lineup, and drop hardcoded /tmp node_modules path from tests/package.json and tests/README.md.
Cloudflare AI registry entry was missing authType/authModes, causing the dashboard to report "No connections" despite an active API-key connection. Closes decolua#2969
…Request hasValidContent() only treated text/tool_use/tool_result blocks as valid content, so a user message containing only an image block was filtered out as empty. When it was the only non-system message, this left an empty messages array and Anthropic rejected the request.
getAntigravityUsage filtered the fetchAvailableModels response through a hardcoded importantModels list that only contained 3.5 Flash, silently dropping the 3.6 Flash quota buckets so no usage bar rendered.
gemini-3-flash-agent, gemini-3-flash, and gemini-3-pro-image are retired; they no longer need a quota bar in the tracker.
Codex Responses Lite clients routed to a chat-native OpenAI-compatible provider lost tool use in three places: non-streaming Chat responses leaked the raw chat.completion envelope instead of Responses output items, internal reasoning continuity fields leaked into the outbound Chat body causing some upstreams to reject the request, and the Responses to Chat request translator ignored additional_tools, custom_tool_call, and custom_tool_call_output items entirely. Also fixes apiType (chat vs responses) for openai-compatible nodes being resolved from the immutable provider ID instead of the stored node config, so editing a node's API Type had no runtime effect.
- Add config priority chain: ENABLE_REQUEST_LOGS > UI setting > OBSERVABILITY_ENABLED fallback - Fix transaction callback syntax from arrow to function - Update saveRequestDetail guard to early return instead of semicolon - Default enableObservability to false (opt-in)
OpenAI-compatible gateway exposing 300+ models (OpenAI, Claude, Gemini, Qwen, DeepSeek, Kimi, GLM, and more). Registered as p116, append-only.
… providers Add Self-hosted STT/TTS/Embedding providers that read baseUrl per connection instead of a fixed registry endpoint, so 9Router can point at whisper.cpp, faster-whisper, Kokoro-FastAPI, llama-server, vLLM, Infinity, and similar OpenAI-compatible local servers. Self-hosted Embedding refuses to run without a baseUrl rather than falling back to api.openai.com like openaiCompatNode does, since that fallback would silently send input text and the API key to OpenAI under a provider named "Self-hosted". Also fixes embeddingsCore to catch adapter build errors as a 400 instead of letting them escape uncaught, and bounds the upstream fetch with FETCH_CONNECT_TIMEOUT_MS to avoid hanging forever on a dead endpoint. Self-hosted TTS treats a bare model value as the model rather than the voice, since the generic OpenAI TTS convention (bare = voice) is backwards for a provider where the model is the variable part.
detectClientTool only matched the legacy "codex-cli" User-Agent, so the current codex-tui CLI and Codex Desktop (UA "Codex Desktop", originator "codex_work_desktop") fell through to null and lost native passthrough — their requests got re-translated, stripping/overwriting fields like reasoning.summary instead of forwarding the client body as-is. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Enable vision + audioInput capacity-adapter pools by default for new and existing users (mergeWithDefaults backward-compat) - Fall back to oc/mimo-v2.5-free when an enabled pool has no models configured, both in the backend resolver and the combos UI (auto refill on removing the last model from a pool) - Hide PDF/Video from the Vision Adapter UI (PDF never implemented, Video lacks translator support) while keeping the settings shape - Exclude combos from the model picker when opened from the Vision Adapter section - mimo-v2.5 registry entry now declares audioInput/videoInput - Simplify combo strategy and Vision Adapter descriptions
- detectRequiredCapabilities: infer audioInput/videoInput from block type and embedded mime, not just vision/pdf - handleChat / handleSingleModelChat: augment combo and single-model routing with capacity-adapter models when the target lacks a required capability, wrapped with history stripping for the adapter model's context window
Qwen OAuth flow (portal.qwen.ai) stopped working reliably; drop the executor, registry entry, OAuth provider/service, token refresh profile, usage handler, and related test coverage and baselines.
- Endpoint page auto-creates a "Default Key" when no keys exist yet, so /v1 works out of the box without a manual dashboard step - Show/copy key buttons stay visible instead of opacity-0 by default
…rvice Covers pool flattening, model augmentation for required capabilities, context-window history stripping, and the withCapacityAdapterStripping wrapper.
Sync alias-baseline.json and providers-baseline.json with the current registry (poolside, tokenrouter, selfhosted-* providers already added; stale claudeOverlay hook and Kiro X-Amz-Target header already removed).
Adds exact per-model rates for 110 TokenRouter models (pulled from TokenRouter's own pricing API) plus a dedicated thinkingFormat case (reasoning_effort enum low/medium/high/xhigh/max) and the provider logo. Provider registration itself already landed in a prior commit; this fills in what PR decolua#3043 added on top.
…ser only Google fingerprints User-Agent/Client-Metadata on loadCodeAssist and onboardUser, silently refusing to provision a cloudaicompanionProject when they don't match the real IDE. Split antigravity's headers out of the shared gemini-cli constants instead of overwriting them, so the fix doesn't touch gemini-cli or any other provider. Inspired by decolua#3000 (thanks @stoXmod for flagging the resource-exhausted issue), rewritten to keep gemini-cli untouched.
## Features - **Providers**: add TokenRouter (300+ models via OpenAI-compatible gateway) with exact per-model pricing for 110 models and `reasoning_effort` thinking config - **Providers**: add Self-hosted STT / TTS / Embedding — point 9Router at your own OpenAI-compatible speech and embedding servers (whisper.cpp, faster-whisper, Kokoro-FastAPI, llama-server, vLLM, Infinity). Unlike the named cloud providers these read `baseUrl` per connection, so one provider can front several machines - **Combos**: default-enable vision/audio capacity adapter (auto-routes to a vision/audio-capable model when the target lacks that capability, falling back to `oc/mimo-v2.5-free`), wired into chat handler routing - **Endpoint**: auto-provision a "Default Key" for first-time users so `/v1` works without a manual dashboard step - **Codex**: support GPT-5.6 Max/Ultra reasoning-level overrides (cx/ routes only) - **Qoder**: support PAT (Personal Access Token) connections end-to-end, alongside OAuth device flow - **CLI tools**: add OpenDesign (manalkaff/opendesign) support - **Headroom**: report effective payload savings (tool schema/history bytes broken out, byte-savings % reflects actual outbound reduction) - **Ollama**: Cloud quota tracker (session + weekly) + proactive background OAuth token refresh scheduler for all providers ## Fixes - **Providers**: remove Qwen (OAuth flow stopped working reliably) - **Passthrough**: detect codex-tui/Codex Desktop as native Codex client — they were falling through to the translator and losing fields like `reasoning.summary` - **OAuth**: scope antigravity header fixes to loadCodeAssist/onboardUser only - **OAuth**: keep `open` external in the build so xAI/Grok token refresh works on Windows - **OAuth**: declare missing `searchParams` in register-session handler (was a 500 instead of JSON on error) - **DB**: `ENABLE_REQUEST_LOGS` env var now overrides the UI setting correctly; observability defaults to off (opt-in) - **Translator**: preserve Codex Responses Lite tool use across chat-native OpenAI-compatible providers - **Translator**: don't drop image-only user messages in `prepareClaudeRequest` - **Translator**: drop JSON Schema keywords Gemini rejects (`uniqueItems`, `contains`, `multipleOf`, `unevaluatedProperties`, `unevaluatedItems`, `contentSchema`) - **Claude**: remove global header cache that leaked one client's identity headers onto another client/account sharing the server; gate `anthropic-beta` by model instead - **Antigravity**: drop retired Gemini 3.0 quota tiers, show Gemini 3.6 Flash usage bars - **Cloudflare AI**: declare API key authentication (dashboard showed "No connections" despite an active key) - **GitHub Copilot**: hold monthly-exhausted accounts until UTC month reset instead of only cooling down 120s - **CodeBuddy**: dodge Tencent CN content filter, add usage tracking, normalize codebuddy-intl messages - **Usage**: stop losing cached prompt tokens in the forced-SSE→JSON path - **Grok CLI**: display the public subscription tier from the OAuth token claim - **Providers**: count apikey connections for Ollama free-tier card; free-tier/ apikey providers without `authModes` now default to apikey (were treated oauth-only) - **Build**: include static/public assets in standalone output (login page hung on 404s when run via PM2) - **Server**: support IntelliJ IDEA OpenAI-compatible clients over HTTP (h2c upgrade handling) - **Auth**: redirect already-logged-in sessions away from `/login` - **CLI tools**: enable Apply button for dynamic OpenAI/Anthropic-compatible provider connections - **CLI**: include complete API artifacts in the CLI package - **TTS**: a bare self-hosted model name is the MODEL, not the voice — `kokoro` was parsed as a voice against a default model, 404ing or synthesising with the wrong one endpoint that drops packets never returns headers, so the request previously hung indefinitely
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
将 main 同步到上游 v0.5.50,并保留当前生产使用的 Codex/Combo 修复;不包含 PR #6 最后两个未部署提交。