Merge remote-tracking branch 'origin/master' into gitea/new_feature

# Conflicts:
#	open-sse/handlers/chatCore.js
#	open-sse/services/combo.js
#	src/app/(dashboard)/dashboard/profile/page.js
#	src/app/api/v1/models/route.js
#	src/lib/db/repos/settingsRepo.js
This commit is contained in:
2026-08-17 00:21:51 +07:00
103 changed files with 11250 additions and 3514 deletions

View File

@@ -19,7 +19,43 @@ const CLAUDE_CONFIG = {
const OAUTH_429_COOLDOWN_MS = 180000;
const oauthCooldown = new Map();
export async function getClaudeUsage(accessToken, proxyOptions = null) {
// Dedup + short TTL cache per access token. Many tabs / many accounts / auto-refresh
// all funnel through here; without this each call hits Anthropic and triggers 429.
const USAGE_CACHE_TTL_MS = 300000;
const usageCache = new Map(); // token -> { promise } | { result, expiresAt }
export async function getClaudeUsage(accessToken, proxyOptions = null, options = {}) {
const force = options?.force === true;
// Serve in-flight or fresh cached result (skip on manual force)
if (!force && accessToken) {
const hit = usageCache.get(accessToken);
if (hit?.promise) return hit.promise;
if (hit && hit.expiresAt > Date.now()) return hit.result;
}
const stale = (!force && accessToken && usageCache.get(accessToken)?.result) || null;
const promise = (async () => {
const result = await fetchClaudeUsageRaw(accessToken, proxyOptions);
// Only cache real quota data, not soft-failure {message: ...} payloads
if (accessToken && result?.quotas) {
usageCache.set(accessToken, {
result,
expiresAt: Date.now() + USAGE_CACHE_TTL_MS,
});
return result;
}
// Soft failure (429/error): prefer the last good read over a transient error
if (stale) return stale;
return result;
})();
if (accessToken) usageCache.set(accessToken, { promise });
return promise;
}
async function fetchClaudeUsageRaw(accessToken, proxyOptions = null) {
try {
// Skip OAuth usage call while this token is cooling down from a recent 429
const cooldownUntil = oauthCooldown.get(accessToken);

View File

@@ -161,6 +161,9 @@ export async function getAntigravityUsage(accessToken, providerSpecificData, pro
if (data.models) {
// Filter only recommended/important models (must match PROVIDER_MODELS ag ids)
const importantModels = [
'gemini-3.7-flash-high',
'gemini-3.7-flash-medium',
'gemini-3.7-flash-low',
'gemini-3.6-flash-high',
'gemini-3.6-flash-medium',
'gemini-3.6-flash-low',