Set functionCallingConfig.mode = 'VALIDATED' when using Claude models
to ensure strict parameter validation, matching opencode-antigravity-auth.
Co-Authored-By: Claude <noreply@anthropic.com>
* 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>
- Add pt.js translation file with complete PT-BR translations
- Add Portuguese option to language selector in settings
- Load pt.js translation file in index.html
Based on PR #108
Co-authored-by: Pedro Farias <feliperodriguesf62@gmail.com>
Co-authored-by: Wha1eChai <whaleora@gmail.com>
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>
* feat: add i18n support with separate translation files
- Extract translations from store.js to separate files for easier management
- Add translation files for English (en.js), Indonesian (id.js), Turkish (tr.js), and Chinese (zh.js)
- Load translations via window.translations object before Alpine store initialization
- Add Bahasa Indonesia option to language selector
* feat: translate remaining hardcoded UI strings
- Update index.html to use t() for Menu and GitHub labels
- Update views to translate Tier, Quota, Live, tier badges, and close button
- Update components to use translated error messages and confirmation dialogs
- Update utils to use translated validation and error messages
- Update app-init.js to use translated OAuth success/error messages
- 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>
- 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>
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>
- 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>
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>
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>
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>
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>
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
- 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
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.
Add comprehensive test suite for /v1/messages/count_tokens endpoint:
- Simple text messages
- Multi-turn conversations
- System prompts (string and array format)
- Tool definitions and tool use/result blocks
- Thinking blocks
- Content arrays with text blocks
- Error handling for invalid requests
- Long text tokenization
Also adds npm script test:counttokens for running tests individually.
Add Anthropic-compatible token counting endpoint using hybrid approach:
- Local estimation with gpt-tokenizer for text content (~95% accuracy)
- API-based counting for complex content (images, documents)
- Automatic fallback to local estimation on API errors
This resolves warnings in LiteLLM and other clients that rely on
pre-request token counting.
Feat(ui): add Turkish language support and UI enhancements
Introduces Turkish language support and several UI/UX improvements to the web management interface.
- Remove nested x-data from save preset modal to fix scope access
- Add newPresetName to parent component state
- Ensure savingPreset state is correctly accessed from the button
- Clear input field on modal open and after successful save
- Move TEST_MODELS and DEFAULT_PRESETS to src/constants.js as single source of truth
- Update test-models.cjs helper to use dynamic import from constants
- Make getTestModels() and getModels() async functions
- Update all test files to await async model config loading
- Remove duplicate THINKING_MODELS and getThinkingModels() from test helper
- Make thinking tests more lenient for Gemini (doesn't always produce thinking blocks)
Co-Authored-By: Claude <noreply@anthropic.com>
Ask users to provide their settings.json or Settings → Claude CLI
screenshot to help diagnose configuration issues faster.
Addresses discussion #113
Co-Authored-By: Claude <noreply@anthropic.com>
- Cooldown now caps API-provided reset times instead of being a fallback
- Fixed misleading UI descriptions for cooldown settings
- Removed unused cooldownDurationMs from settings object
- Updated default fallback values in frontend to 10s
Co-Authored-By: Claude <noreply@anthropic.com>
- Add separate LOAD_CODE_ASSIST_ENDPOINTS (prod first) and
LOAD_CODE_ASSIST_HEADERS (google-api-nodejs-client User-Agent)
- Add duetProject to metadata for project discovery
- Silent fallback when API returns success but no project
(matches opencode-antigravity-auth behavior)
- Only warn when all endpoints fail with actual errors
Fixes#114, addresses discussion #113
Co-Authored-By: Claude <noreply@anthropic.com>
- Add backend storage logic in `src/utils/claude-config.js` to save/load/delete presets
- Add API endpoints (`GET`, `POST`, `DELETE`) for presets in `src/webui/index.js`
- Update `public/views/settings.html` with new Presets UI card and modals
- Update `public/js/components/claude-config.js` with auto-load logic and unsaved changes protection
- Add translations (EN/ZH) for new UI elements in `public/js/store.js`
- Add integration tests in `tests/frontend/test-frontend-settings.cjs`
- Update compiled CSS
Co-Authored-By: Claude <noreply@anthropic.com>