Commit Graph

141 Commits

Author SHA1 Message Date
Badri Narayanan S
f9bdeddd0d Merge pull request #208 from jgor20/fix/webui-console-errors-and-logging
fix(webui): resolve console errors and misleading server logs
2026-02-01 16:10:42 +05:30
Badri Narayanan S
3c2f324eff fix: honor HOST environment variable for server binding
- Update src/index.js to use HOST environment variable for main server
- Update src/auth/oauth.js to use HOST environment variable for OAuth callback server
- Add diagnostic logging to show actual bound address on startup
- Update startup banner to reflect correct host URL

Co-Authored-By: Claude (gemini-3-flash[1m]) <noreply@anthropic.com>
2026-01-31 00:27:19 +05:30
Badri Narayanan S
ca6783f153 chore: bump user agent version to 1.15.8
Co-Authored-By: Claude (claude-opus-4-5-thinking) <noreply@anthropic.com>
2026-01-29 23:55:15 +05:30
jgor20
b012fe0245 fix(server): use originalUrl in request logger and suppress .well-known noise
- Changed logging middleware to use req.originalUrl instead of req.path,
  which was mangled by Express wildcard catch-all path stripping
- Suppress Chrome DevTools /.well-known/ requests from logs (debug-only)
2026-01-28 23:02:00 +00:00
Badri Narayanan S
b64809277c chore: update default haiku model to claude-sonnet-4-5 and gemini-3-flash
- Claude preset: gemini-2.5-flash-lite → claude-sonnet-4-5
- Gemini preset: gemini-2.5-flash-lite → gemini-3-flash
- Remove outdated quota warning about haiku model usage

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-26 14:17:11 +05:30
Badri Narayanan S
bc8d428107 Merge pull request #187 from quocthai0404/fix/issue-176-windows-callback-port
fix: Make OAuth callback port configurable for Windows compatibility (#176)
2026-01-26 13:45:13 +05:30
Badri Narayanan S
683ca41480 fix: strip cache_control fields from content blocks (#189)
Claude Code CLI sends cache_control on text, thinking, tool_use, and
tool_result blocks for prompt caching. Cloud Code API rejects these
with "Extra inputs are not permitted".

- Add cleanCacheControl() to proactively strip cache_control at pipeline entry
- Add sanitizeTextBlock() and sanitizeToolUseBlock() for defense-in-depth
- Update reorderAssistantContent() to use block sanitizers
- Add test-cache-control.cjs with multi-model test coverage
- Update frontend dashboard tests to match current UI design
- Update strategy tests to match v2.4.0 fallback behavior
- Update CLAUDE.md and README.md with recent features

Inspired by Antigravity-Manager's clean_cache_control_from_messages() pattern.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-25 03:27:05 +05:30
Badri Narayanan S
5a85f0cfcc feat: comprehensive rate limit handling overhaul (inspired by opencode-antigravity-auth)
This commit addresses "Max retries exceeded" errors during stress testing where
all accounts would become exhausted simultaneously due to short per-second rate
limits triggering cascading failures.

## Rate Limit Parser (`rate-limit-parser.js`)
- Remove 2s buffer enforcement that caused cascading failures when API returned
  short reset times (200-600ms). Now adds 200ms buffer for sub-500ms resets
- Add `parseRateLimitReason()` for smart backoff based on error type:
  QUOTA_EXHAUSTED, RATE_LIMIT_EXCEEDED, MODEL_CAPACITY_EXHAUSTED, SERVER_ERROR

## Message/Streaming Handlers
- Add per-account+model rate limit state tracking with exponential backoff
- For short rate limits (< 1 second), wait and retry on same account instead
  of switching - prevents thundering herd when all accounts hit per-second limits
- Add throttle wait support for fallback modes (emergency/lastResort)
- Add `calculateSmartBackoff()` with progressive tiers by error type

## HybridStrategy (`hybrid-strategy.js`)
- Refactor `#getCandidates()` to return 4 fallback levels:
  - `normal`: All filters pass (health, tokens, quota)
  - `quota`: Bypass critical quota check
  - `emergency`: Bypass health check when ALL accounts unhealthy
  - `lastResort`: Bypass BOTH health AND token bucket checks
- Add throttle wait times: 500ms for lastResort, 250ms for emergency
- Fix LRU calculation to use seconds (matches opencode-antigravity-auth)

## Health Tracker
- Increase `recoveryPerHour` from 2 to 10 for faster recovery (1 hour vs 5 hours)

## Account Manager
- Add consecutive failure tracking: `getConsecutiveFailures()`,
  `incrementConsecutiveFailures()`, `resetConsecutiveFailures()`
- Add cooldown mechanism separate from rate limits with `CooldownReason`
- Reset consecutive failures on successful request

## Base Strategy
- Add `isAccountCoolingDown()` check in `isAccountUsable()`

## Constants
- Replace fixed `CAPACITY_RETRY_DELAY_MS` with progressive `CAPACITY_BACKOFF_TIERS_MS`
- Add `BACKOFF_BY_ERROR_TYPE` for smart backoff
- Add `QUOTA_EXHAUSTED_BACKOFF_TIERS_MS` for progressive quota backoff
- Add `MIN_BACKOFF_MS` floor to prevent "Available in 0s" loops
- Increase `MAX_CAPACITY_RETRIES` from 3 to 5
- Reduce `RATE_LIMIT_DEDUP_WINDOW_MS` from 5s to 2s

## Frontend
- Remove `capacityRetryDelayMs` config (replaced by progressive tiers)
- Update default `maxCapacityRetries` display from 3 to 5

## Testing
- Add `tests/stress-test.cjs` for concurrent request stress testing

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-24 22:43:53 +05:30
quocthai0404
54fc1da829 fix: make OAuth callback port configurable for Windows compatibility (#176)
- Add OAUTH_CALLBACK_PORT environment variable (default: 51121)
- Implement automatic port fallback (51122-51126) on EACCES/EADDRINUSE
- Add Windows-specific troubleshooting in error messages and README
- Document configuration in config.example.json

Closes #176
2026-01-24 14:28:31 +07:00
董飞祥
9992c4ab27 feat: Add manual OAuth authorization mode for WebUI (#131)
* feat: add manual OAuth flow support in WebUI

* fix: reset add account modal state on close

* feat: display custom API key in startup banner

* fix: move translations to separate files and optimize import API

* fix: remove orphaned model-manager.js and cleanup callback server on manual auth

---------

Co-authored-by: Badri Narayanan S <59133612+badrisnarayanan@users.noreply.github.com>
2026-01-23 18:53:29 +05:30
Badri Narayanan S
0fa945b069 fix: don't count rate limit waits as failed retry attempts
When all accounts are rate-limited or token-exhausted, the retry loop
was incorrectly counting the wait time as a failed attempt. This caused
premature "Max retries exceeded" errors when we were just patiently
waiting for accounts to become available.

- Add attempt-- after sleeping for rate limits or strategy waits
- Add #diagnoseNoCandidates() to hybrid strategy for better logging
- Add getTimeUntilNextToken() and getMinTimeUntilToken() to token tracker
- Return waitMs from hybrid strategy when all accounts are token-blocked

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 14:29:24 +05:30
Badri Narayanan S
7aa1508b27 ignore count requests 2026-01-23 14:10:00 +05:30
Wha1eChai
07e413d1ec security: redact sensitive config values and protect update endpoints 2026-01-23 16:12:31 +08:00
Badri Narayanan S
9efe5cd75d fix(webui): add missing config fields to API handler
The POST /api/config endpoint was missing validation for several
Advanced Server Settings fields, causing the sliders to fail silently.
Added support for: rateLimitDedupWindowMs, maxConsecutiveFailures,
extendedCooldownMs, capacityRetryDelayMs, maxCapacityRetries.

Fixes #181

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 12:13:03 +05:30
jgor20
7ed9305b5b fix: remove unused weight from quota config
The quota scoring weight is managed in HybridStrategy's DEFAULT_WEIGHTS,
not in the config.quota block. Removed to avoid confusion.
2026-01-21 20:52:14 +00:00
jgor20
2f5babba99 feat(strategy): add quota-awareness to hybrid account selection
The hybrid strategy now considers account quota levels when selecting
accounts, preventing any single account from being drained to 0%.

- Add QuotaTracker class to track per-account quota levels
- Exclude accounts with critical quota (<5%) from selection
- Add quota component to scoring formula (weight: 3)
- Fall back to critical accounts when no alternatives exist
- Add 18 new tests for quota-aware selection

Scoring formula: Health×2 + Tokens×5 + Quota×3 + LRU×0.1

An attempt at resolving  badrisnarayanan/antigravity-claude-proxy#171
2026-01-21 11:15:38 +00:00
jgor20
e51e3ff56a feat(config): add configurable max accounts limit (#156)
Adds `maxAccounts` configuration parameter to control the maximum number of Google accounts.

**Changes:**
- New config field `maxAccounts` (default: 10, range: 1-100)
- Settings page: slider control for adjusting limit
- Accounts page: counter badge (e.g., "8/10") with visual feedback
- Add button disabled when limit reached
- Server-side validation on account creation

**Breaking Changes:** None
2026-01-21 04:34:57 +08:00
Badri Narayanan S
11f135ef32 fix: simplify 403/404 endpoint fallback log messages
Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-20 23:41:17 +05:30
Badri Narayanan S
8d8f170f18 fix: add explicit logging for 403/404 endpoint fallback
Adds logging when 403/404 errors trigger endpoint fallback (daily → prod).
The retry behavior was already working but silently - now it's visible.
Matches opencode-antigravity-auth error handling behavior.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-20 23:33:44 +05:30
Badri Narayanan S
c8fbf37be9 fix: replace pickNext() with selectAccount() in /v1/models endpoint
Fixes regression where /v1/models returned 500 error because
pickNext() method was removed in v2.2.x refactor.

Fixes #164

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-20 21:03:03 +05:30
Badri Narayanan S
b0c3a61130 fix: use allowedTiers only for onboarding (not paidTier)
paidTier values like g1-pro-tier and g1-ultra-tier are rejected by
the onboardUser API with 400 INVALID_ARGUMENT. This matches the
opencode-antigravity-auth reference which only uses allowedTiers.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-19 20:19:40 +05:30
Badri Narayanan S
2175118f9f feat: align project discovery with opencode-antigravity-auth reference
- Store project IDs in composite refresh token format (refreshToken|projectId|managedProjectId)
- Add parseRefreshParts() and formatRefreshParts() for token handling
- Extract and persist subscription tier during project discovery
- Fetch subscription in blocking mode when missing from cached accounts
- Fix conditional duetProject setting to match reference implementation
- Export parseTierId() for reuse across modules

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-19 14:21:30 +05:30
Badri Narayanan S
9311c6fdf7 Merge pull request #151 from pedrofariasx/fix/windows-oauth-url
fix: Escape OAuth URL parameters for Windows CLI
2026-01-19 11:43:29 +05:30
Pedro Farias
a8ca1b79f3 fix: escape ampersands in OAuth URL on Windows 2026-01-19 02:26:55 -03:00
Badri Narayanan S
c8c7a5a8aa refactor: move STRATEGY_LABELS to constants.js and make banner dynamic
Consolidate strategy configuration by moving STRATEGY_LABELS from
strategies/index.js to constants.js. Update startup banner to
dynamically display strategy options from SELECTION_STRATEGIES.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-18 12:59:33 +05:30
Badri Narayanan S
5ae19a5b72 feat: add configurable account selection strategies
Refactor account selection into a strategy pattern with three options:
- Sticky: cache-optimized, stays on same account until rate-limited
- Round-robin: load-balanced, rotates every request
- Hybrid (default): smart distribution using health scores, token buckets, and LRU

The hybrid strategy uses multiple signals for optimal account selection:
health tracking for reliability, client-side token buckets for rate limiting,
and LRU freshness to prefer rested accounts.

Includes WebUI settings for strategy selection and unit tests.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-18 03:48:43 +05:30
Badri Narayanan S
973234372b chore: remove unused code and suppress noisy Claude Code logs
- Delete unused files: retry.js, app-init.js, model-manager.js
- Remove duplicate error helpers from helpers.js (exist in errors.js)
- Remove unused exports from signature-cache.js, logger.js
- Remove unused frontend code: ErrorHandler methods, validators, canDelete, destroy
- Make internal functions private in thinking-utils.js
- Remove commented-out code from constants.js
- Remove deprecated .glass-panel CSS class
- Add silent handler for Claude Code event logging (/api/event_logging/batch)
- Suppress logging for /v1/messages/count_tokens (501 responses)
- Fix catch-all to use originalUrl (wildcard strips req.path)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-18 01:36:24 +05:30
Badri Narayanan S
c52d32572a Merge pull request #141 from jgor20/fix/spawn-browser-launch
refactor(cli): use spawn instead of exec for browser launch
2026-01-18 01:01:59 +05:30
Pedro Farias
6a6c4829ca feat: server reliability and observability improvements 2026-01-17 13:21:15 -03:00
jgor20
cbade78e86 Merge branch 'badrisnarayanan:main' into fix/spawn-browser-launch 2026-01-17 13:31:21 +00:00
jgor20
71a808ed31 refactor(cli): use spawn instead of exec for browser launch
Replace shell command execution with spawn for cleaner process handling.

Uses array arguments instead of string interpolation.
2026-01-17 13:13:49 +00:00
Badri Narayanan S
ed68f4b21e fix: enable strict tool parameter validation for Claude models
Set functionCallingConfig.mode = 'VALIDATED' when using Claude models
to ensure strict parameter validation, matching opencode-antigravity-auth.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-17 14:47:48 +05:30
Marvin
480b4a0bc1 fix: preserve whitespace-only chunks in SSE stream (#139)
* fix: preserve whitespace-only chunks in SSE stream

Fixes issue #138 where Claude models would swallow spaces between words because whitespace-only chunks (e.g., " ") were being filtered out as empty.

Changes:
- Modified sse-streamer.js to only skip truly empty strings (""), preserving strings that contain only whitespace.
- Added regression test case in tests/test-streaming-whitespace.cjs to verify whitespace preservation.

* test: add streaming whitespace regression test to main suite

---------

Co-authored-by: walczak <walczak@ial.ruhr>
2026-01-17 12:16:28 +05:30
Badri Narayanan S
2516e90d06 Revert "fix: check allowedTiers when paidTier is free for tier detection"
This reverts commit 11a1879fc7.
2026-01-15 21:26:08 +05:30
Badri Narayanan S
11a1879fc7 fix: check allowedTiers when paidTier is free for tier detection
Some accounts have paidTier.id = "free-tier" but allowedTiers includes
"standard-tier", meaning they can use Pro-level quotas even though their
Google One subscription doesn't grant Antigravity benefits.

New priority:
1. paidTier - if Pro/Ultra, use immediately
2. allowedTiers - if paidTier is free, check for higher tiers
3. currentTier - fallback if still unknown
4. allowedTiers default - final fallback

This fixes accounts that show as "free" but actually have Pro access
through programs other than Google One AI.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-15 21:23:19 +05:30
Badri Narayanan S
9ffb83ab74 fix: improve onboarding flow for non-free tier accounts
- Use raw API tier IDs (e.g., 'free-tier', 'g1-pro-tier') consistently
- Pass DEFAULT_PROJECT_ID for non-free tiers during onboarding
- Fix free tier detection to use .includes('free') instead of exact match
- Upgrade onboarding error logs from debug to warn for visibility
- Add debug logging for onboarding request parameters

Fixes onboarding failures for Pro/Ultra accounts that were previously
failing because the API requires a project ID for paid tier onboarding.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-15 20:25:10 +05:30
Badri Narayanan S
9809337190 fix: improve subscription tier detection with paidTier priority and verbose logging
- Use parseTierId() consistently for all tier sources (paidTier, currentTier, allowedTiers)
- Add tierSource tracking to identify which field tier was detected from
- Add verbose debug logging to show all tier-related fields from loadCodeAssist API
- Fix onboarding to prioritize paidTier > currentTier > allowedTiers (consistent with model-api.js)

This helps diagnose issues where Pro/Ultra accounts are incorrectly detected as free.
Fixes #128

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-15 20:08:30 +05:30
Badri Narayanan S
2a0c110f9b fix: try model fallback before throwing RESOURCE_EXHAUSTED error
When all accounts are rate-limited for > 2 minutes, now attempts
model fallback (if enabled) before throwing the error. This allows
quota-exhausted accounts to gracefully fall back to alternate models.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-15 16:41:02 +05:30
Badri Narayanan S
77363c679e fix: accurate quota reporting with project ID and improved rate limit handling
- Pass project ID to fetchAvailableModels for accurate per-project quota
- Treat missing remainingFraction with resetTime as 0% (exhausted)
- Fix double-escaped regex in rate-limit-parser.js (\\d -> \d)
- Use ANTIGRAVITY_HEADERS for loadCodeAssist consistency
- Store actual reset time from API instead of capping at default
- Add getRateLimitInfo() for detailed rate limit state
- Handle disabled accounts in rate limit checks

Fixes issue where free tier accounts showed 100% quota but were actually exhausted.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-15 16:18:13 +05:30
Badri Narayanan S
a20cba90ee Merge pull request #125 from IrvanFza/feat/webui-notif
docs: update startup message to mention WebUI
2026-01-15 12:46:42 +05:30
Irvan Fauziansyah
915ee88e80 docs: update startup message to mention WebUI
- Changed "Server running at" to "Server and WebUI running at"
- Clarifies that the web interface is available at the same port
2026-01-15 14:10:27 +07:00
Badri Narayanan S
44632dc301 feat: add automatic user onboarding for accounts without projects
When loadCodeAssist returns no project, automatically call onboardUser API
to provision a managed project. This handles first-time setup for new accounts.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-15 12:27:37 +05:30
Badri Narayanan S
896bf81a36 revert: remove count_tokens endpoint (caused regression)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-14 23:43:16 +05:30
Badri Narayanan S
fa29de7183 fix: handle unsigned thinking blocks in tool loops (#120)
When Claude Code strips thinking signatures it doesn't recognize,
the proxy would drop unsigned thinking blocks, causing the error
"Expected thinking but found text". This fix detects unsigned
thinking blocks and triggers recovery to close the tool loop.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-14 23:01:13 +05:30
Badri Narayanan S
dee7512bd8 fix: improve subscription tier detection for Pro accounts
The tier detection was incorrectly showing Pro accounts as "free" due to:
1. paidTier field being flaky/missing from some API responses
2. standard-tier not being recognized as a Pro tier
3. No fallback to allowedTiers when currentTier is missing

Changes:
- Add parseTierId() helper to centralize tier ID parsing
- Recognize "standard-tier" as Pro (Gemini Code Assist paid tier)
- Add fallback chain: paidTier > currentTier > allowedTiers
- Return "unknown" instead of incorrectly defaulting to "free"

Fixes #121

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-14 21:27:24 +05:30
Badri Narayanan S
772dabe7e4 fix: defer inlineData parts to end of array for parallel tool calls (#91)
When multiple tool_results contain images, the inlineData parts were
being interleaved between functionResponse parts, breaking Claude's API
requirement that functionResponse parts be consecutive.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-14 21:04:36 +05:30
behemoth-phucnm
d33de409d4 docs: fix misleading tokenizer comments 2026-01-14 19:31:43 +07:00
minhphuc429
7da7e887bf feat: use official tokenizers for 99.99% accuracy
Replace gpt-tokenizer with model-specific official tokenizers:
- Claude models: @anthropic-ai/tokenizer (official Anthropic tokenizer)
- Gemini models: @lenml/tokenizer-gemini (GemmaTokenizer)

Changes:
- Add @anthropic-ai/tokenizer and @lenml/tokenizer-gemini dependencies
- Remove gpt-tokenizer dependency
- Update count-tokens.js with model-aware tokenization
- Use getModelFamily() to select appropriate tokenizer
- Lazy-load Gemini tokenizer (138MB) on first use
- Default to local estimation for all content types (no API calls)

Tested with all supported models:
- claude-sonnet-4-5, claude-opus-4-5-thinking, claude-sonnet-4-5-thinking
- gemini-3-flash, gemini-3-pro-low, gemini-3-pro-high
2026-01-14 16:04:13 +07:00
minhphuc429
2bdecf6e96 fix: ensure account manager initialized for count_tokens
- Add ensureInitialized() call before count_tokens handler
- Use hybrid approach: local estimation for text, API for images/docs
- This prevents "No accounts available" error on first request
2026-01-14 15:43:25 +07:00
minhphuc429
df81ba5632 feat: use API-based token counting for 100% accuracy
Switch from local estimation (gpt-tokenizer) to API-based counting
via Google Cloud Code API for accurate token counts. Falls back to
local estimation if API call fails.
2026-01-14 15:36:47 +07:00