Selective fixes from PR #35: Model-specific rate limits & robustness improvements (#37)

* feat: apply local user changes and fixes

* ;D

* Implement OpenAI support, model-specific rate limiting, and robustness fixes

* docs: update pr title

* feat: ensure unique openai models endpoint

* fix: startup banner alignment and removed duplicates

* feat: add model fallback system with --fallback flag

* fix: accounts cli hanging after completion

* feat: add exit option to accounts cli menu

* fix: remove circular dependency warning for fallback flag

* feat: show active modes in banner and hide their flags

* Remove OpenAI compatibility and fallback features from PR #35

Cherry-picked selective fixes from PR #35 while removing:
- OpenAI-compatible API endpoints (/openai/v1/*)
- Model fallback system (fallback-config.js)
- Thinking block skip for Gemini models
- Unnecessary files (pullrequest.md, test-fix.js, test-openai.js)

Retained improvements:
- Network error handling with retry logic
- Model-specific rate limiting
- Enhanced health check with quota info
- CLI fixes (exit option, process.exit)
- Startup banner alignment (debug mode only)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* banner alignment fix

* Refactor: Model-specific rate limits and cleanup deprecated code

- Remove global rate limit fields (isRateLimited, rateLimitResetTime) in favor of model-specific limits (modelRateLimits[modelId])
- Remove deprecated wrapper functions (is429Error, isAuthInvalidError) from handlers
- Filter fetchAvailableModels to only return Claude and Gemini models
- Fix getCurrentStickyAccount() to pass model param after waiting
- Update /account-limits endpoint to show model-specific limits
- Remove multi-account OAuth flow to avoid state mismatch errors

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: show (x/y) limited status in account-limits table

- Status is now "ok" only when all models are available
- Shows "(x/y) limited" when x out of y models are exhausted
- Provides better visibility into partial rate limiting

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* docs: update CLAUDE.md with model-specific rate limiting

- Document modelRateLimits[modelId] for per-model rate tracking
- Add isNetworkError() helper to utilities section

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: M1noa <minoa@minoa.cat>
Co-authored-by: Minoa <altgithub@minoa.cat>
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Badri Narayanan S
2026-01-03 15:33:49 +05:30
committed by GitHub
parent 2d05dd5b62
commit 9c4a712a9a
15 changed files with 474 additions and 194 deletions

View File

@@ -23,6 +23,7 @@ export function formatDuration(ms) {
return `${secs}s`;
}
/**
* Sleep for specified milliseconds
* @param {number} ms - Duration to sleep in milliseconds
@@ -31,3 +32,49 @@ export function formatDuration(ms) {
export function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* Check if an error is a network error (transient)
* @param {Error} error - The error to check
* @returns {boolean} True if it is a network error
*/
export function isNetworkError(error) {
const msg = error.message.toLowerCase();
return (
msg.includes('fetch failed') ||
msg.includes('network error') ||
msg.includes('econnreset') ||
msg.includes('etimedout') ||
msg.includes('socket hang up') ||
msg.includes('timeout')
);
}
/**
* Check if an error is an authentication error (permanent until fixed)
* @param {Error} error - The error to check
* @returns {boolean} True if it is an auth error
*/
export function isAuthError(error) {
const msg = error.message.toLowerCase();
return (
msg.includes('401') ||
msg.includes('unauthenticated') ||
msg.includes('invalid_grant') ||
msg.includes('invalid_client')
);
}
/**
* Check if an error is a rate limit error
* @param {Error} error - The error to check
* @returns {boolean} True if it is a rate limit error
*/
export function isRateLimitError(error) {
const msg = error.message.toLowerCase();
return (
msg.includes('429') ||
msg.includes('resource_exhausted') ||
msg.includes('quota_exhausted')
);
}