Add pxpipe as an experimental fifth Token Saver: Claude-format request
bodies above a configurable size threshold are rendered as dense PNGs
via the pxpipe-proxy library API (transformAnthropicMessages) before
dispatch, cutting estimated input tokens by ~35-60% on token-dense
contexts. Integration follows the Headroom pattern: applied to the final
body in chatCore just before dispatch, fail-open on any error/timeout.
Managed npm install into DATA_DIR/pxpipe, dynamic loader with per-version
cache-bust, JSONL event log with rotation, /api/pxpipe/* endpoints, Token
Saver card (marked experimental) + /dashboard/pxpipe page, and per-request
Activated/Skipped annotation in Request Details. Disabled by default.
Treat configured Headroom proxy as running when its /health endpoint
responds, even if local headroom CLI is not installed. Dashboard
Start/Stop stays limited to local loopback proxies while external
Docker sidecars can be enabled via HEADROOM_URL.
Closes#1948
Co-authored-by: Cursor <cursoragent@cursor.com>
Build on the optional Headroom Token Saver from Carmelo Campos
(PR: feat: add optional Headroom token saver). Add managed start/stop
of the local headroom proxy from the dashboard, install detection,
status probing, and a simplified Token Saver UI.
- detect headroom CLI + python>=3.10, probe proxy /health
- spawn/stop proxy as a detached, pid-tracked process
- /api/headroom/{status,start,stop} routes, gated local-only in dashboardGuard
- one-click Start/Stop Headroom modal, no manual config needed
- claude<->openai shape conversion for /v1/compress via 9router translators
Thanks to Carmelo Campos (@carmelogunsroses) for the original Headroom integration.
Co-authored-by: Cursor <cursoragent@cursor.com>
Panel models in the fusion strategy must answer in prose. When the request
carried tools or prior tool_calls/tool messages, agentic panel models kept
emitting tool_calls instead of prose, so extractPanelText() returned empty
and the engine fell into the 503 "All fusion panel models failed" branch.
Panel fan-out now strips tools/tool_choice and flattens tool turns into
assistant prose (instead of dropping them), so panels keep the context but
cannot loop on tools. The judge still receives the unmodified history.
Co-authored-by: warelik <warelik@WARELIK-MB.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
Adds Fusion as a third combo strategy alongside fallback/round-robin. A
fusion combo fans the prompt out to all member models in parallel, then a
configurable judge model synthesizes one final answer from the panel.
- handleFusionChat in open-sse/services/combo.js: quorum-grace collection
caps the straggler penalty, anonymized sources prevent judge brand-bias,
degrades to a direct answer on single survivor and 503 on total failure.
- chat.js dispatches strategy==="fusion" at both combo entry points.
- Combos dashboard: per-combo strategy Select replaces the round-robin
toggle, fusion reveals a judge picker, plus a strategy/capacity explainer.
- tests/unit/combo-fusion.test.js covers fan-out, judge routing/default,
quorum-grace straggler drop, single-survivor and total-failure degradation.
Co-authored-by: Cursor <cursoragent@cursor.com>
- /api/settings/database now requires current password (header for GET,
body for POST) in addition to session; CLI-token requests exempt
- add verifyDashboardPassword helper reusing login bcrypt check
- profile UI prompts password via modal before export/import
- /v1/web/fetch rejects internal/private/metadata targets via assertPublicUrl
Refs GHSA-qvfm-67h2-2qfx, GHSA-qj3v-64wj-q825
Co-authored-by: Cursor <cursoragent@cursor.com>
Add shared OAuth credential lifecycle manager with provider-aware refresh
decisions. Implement CodexExecutor.refreshCredentials so 401/403 retry
refresh works for Codex, track lastRefreshAt and refresh before the
upstream stale-token window, preserve omitted idToken, and add
per-connection single-flight refresh to avoid refresh-token rotation races.
Merged from PR #1664.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Introduced a caching mechanism for in-flight token refresh requests to prevent race conditions and reduce unnecessary API calls.
- Added error handling for unrecoverable refresh errors, ensuring that the application can gracefully handle token reuse and invalidation scenarios.
- Updated the MITM server management to handle port 443 conflicts, allowing users to kill processes occupying the port before starting the server.
- Improved user feedback in the MitmServerCard component regarding port conflicts and admin privileges.
- Refactored the ComboList component to streamline the display of media provider combos.
This update aims to enhance the reliability and user experience of the token management and MITM functionalities.
- Refactored handleChatCore to include Caveman functionality, allowing for terse-style system prompts to reduce output token usage.
- Updated APIPageClient to manage Caveman settings, including enabling/disabling and selecting compression levels.
- Adjusted AntigravityExecutor to consolidate function declarations for compatibility with Gemini.
- Removed unnecessary console logs during translator initialization across multiple routes.
- Updated refreshCredentials methods in various executors (Antigravity, Base, Default, Github, Kiro) to accept optional proxyOptions for improved proxy handling.
- Modified token refresh logic to utilize proxy-aware fetch for better network management.
- Enhanced usage retrieval functions to support proxy options, ensuring seamless integration with proxy configurations.
- Updated ModelSelectModal and ProviderInfoCard components to incorporate kind filtering for improved user experience in model selection.
- Added validation for API keys in the provider validation route, including support for webSearch/webFetch providers.
- Added new image models for GPT 5.2, 5.3, and 5.4, including capabilities for text-to-image and editing.
- Updated embedding handling to include optional dimensions in requests.
- Introduced support for custom embedding providers, allowing dynamic fetching and validation of custom nodes.
- Improved image generation handling with Codex integration, including progress tracking and error handling.
- Enhanced UI components to support adding custom embeddings and displaying their status.
- Introduced OpenCode Go provider with relevant configurations.
- Enhanced model management by allowing users to add and delete custom models.
- Updated UI components to support model selection for image types.
- Adjusted sidebar visibility to include image media kinds.
- Add claudeHeaderCache.js to intercept and cache live Claude Code client headers
- Forward cached headers dynamically to api.anthropic.com via default.js
- Strip first-party identity headers (x-app, claude-code-* beta) for non-Anthropic upstreams
- Validate and sanitize tool call IDs to match Anthropic pattern (^[a-zA-Z0-9_-]+$)
- Skip thinking blocks when applying cache_control; fix max_tokens buffer (+1024)
- Strip cache_control from thinking blocks in openai-to-claude translator
- Comment out thoughtSignature in Gemini translator (kept for reference)
- Expand .gitignore to match all deploy*.sh variants
Co-authored-by: kwanLeeFrmVi <quanle96@outlook.com>
Closes#433
Made-with: Cursor
When a provider has credentials but all are disabled, return 404 (NOT_FOUND)
instead of 400 (BAD_REQUEST). The combo handler already treats 404 as a
fallbackable error, so it will skip to the next model in the chain.
Previously, the 400 status caused the combo to stop with a hard error,
killing the client (e.g., Claude Code) even though other models in the
combo chain were available.
Also changed log level from error to warn since disabled credentials
are an expected configuration state, not an error.
Fixes#334
Add ability to configure round-robin strategy for individual combos,
similar to per-provider strategy overrides.
Changes:
- Add comboStrategies setting to store per-combo strategy overrides
- Add Round Robin toggle to each combo card in combos page
- Update chat handler to check combo-specific strategy before global
- Combo-specific strategy takes precedence over global comboStrategy
When enabled, each request to that combo will cycle through providers
instead of always starting with the first one.
Made-with: Cursor
- Add comboRotationState Map to track rotation per combo
- Add getRotatedModels() to rotate model order based on strategy
- Pass comboName and comboStrategy to handleComboChat()
- Add comboStrategy setting (default: fallback)
- Add UI toggle for Combo Round Robin in profile settings
When enabled, each request to a combo starts with a different provider
instead of always starting with the first one, distributing load evenly.
Co-authored-by: Antigravity Agent <antigravity@example.com>
- Added new provider models: DeepSeek 3.1, DeepSeek 3.2, and Qwen3 Coder Next.
- Implemented UI changes to support round-robin strategy with sticky limits in the provider detail page.
- Improved logging to display connection names instead of IDs for better clarity.
- Patch Node fetch via undici ProxyAgent when HTTP_PROXY/HTTPS_PROXY/ALL_PROXY is set
- Ensure proxy patch is loaded for both chat pipeline and OAuth token exchange
- Add Dashboard Settings → Network to edit outbound proxy and apply immediately
- Persist outbound proxy settings in local db and initialize on server startup
- Move proxy helpers to src/lib/network/ for better structure
- Rename src/proxy.js → src/dashboardGuard.js to avoid naming confusion
- Re-apply proxy env after DB import
- Fix: close old dispatcher on proxy URL change to prevent connection pool leak
- Fix: idempotency guard to avoid patching globalThis.fetch multiple times
Made-with: Cursor
Cherry-picked from decolua/9router PR #183.
Note: open-sse changes included but need further review due to extensive modifications.
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat: implement Project ID service to fetch and cache real Project IDs from Google Cloud Code API
* fix: implement caching and cleanup for Project ID retrieval
* feat: add project ID invalidation and refresh logic after token updates
* refactor: remove unnecessary format changes
* feat: add on-demand project ID retrieval for antigravity requests
Providers like Antigravity maintain separate quota buckets per model family
(e.g. Claude vs Gemini). A 429 on claude-opus previously locked the entire
account, preventing gemini-pro requests even though its quota was full.
This adds in-memory per-model locking so that only the specific model is
skipped during account selection while other models remain accessible.
Changes:
- Add model-aware lock tracking in auth.js (Map<connectionId:model, expiry>)
- Pass model context from chat handler to auth service
- Multi-bucket behavior gated to known providers (MULTI_BUCKET_PROVIDERS set)
- No database schema changes — locks are in-memory and clear on restart
Closes#110