feat: 新增 Antigravity/Kiro 账户禁用封禁状态监控与展示

- 前端:为 Antigravity 和 Kiro 上游元数据添加禁用/封禁状态字段
- 前端:在密钥详情抽屉中展示账户禁用/封禁警告信息,合并重复的时间格式化函数
- 后端:优化 Antigravity 和 Kiro 适配器的状态检测与上报逻辑

Co-authored-by: AAEE86 <ppk0227@hotmail.com>

Closes #158
This commit is contained in:
fawney19
2026-02-09 17:24:48 +08:00
parent 65658e58d5
commit b14fb31933
6 changed files with 383 additions and 113 deletions

View File

@@ -1419,6 +1419,9 @@ class AdminRefreshProviderQuotaAdapter(AdminApiAdapter):
UpstreamModelsFetchContext,
fetch_models_for_key,
)
from src.services.provider.adapters.antigravity.client import (
AntigravityAccountForbiddenException,
)
fetch_ctx = UpstreamModelsFetchContext(
provider_type="antigravity",
@@ -1428,11 +1431,49 @@ class AdminRefreshProviderQuotaAdapter(AdminApiAdapter):
proxy_config=getattr(provider, "proxy", None),
auth_config=auth_info.decrypted_auth_config,
)
_models, errors, ok, upstream_meta = await fetch_models_for_key(
fetch_ctx, timeout_seconds=10.0
)
try:
_models, errors, ok, upstream_meta = await fetch_models_for_key(
fetch_ctx, timeout_seconds=10.0
)
except AntigravityAccountForbiddenException as e:
# 对齐 AM所有 403 一律标记 is_forbidden 并停用
key.is_active = False
key.oauth_invalid_at = datetime.now(timezone.utc)
key.oauth_invalid_reason = f"账户访问被禁止: {e.reason or e.message}"
# 更新 upstream_metadata 标记封禁状态
forbidden_metadata = {
"antigravity": {
"is_forbidden": True,
"forbidden_reason": e.reason or e.message,
"forbidden_at": int(time.time()),
"updated_at": int(time.time()),
}
}
key.upstream_metadata = merge_upstream_metadata(
key.upstream_metadata, forbidden_metadata
)
db.commit()
logger.warning(
"[ANTIGRAVITY_QUOTA] Key {} 账户访问被禁止,已自动停用: {}",
key.id,
e.reason or e.message,
)
return {
"key_id": key.id,
"key_name": key.name,
"status": "forbidden",
"message": f"账户访问被禁止: {e.reason or e.message}",
"is_forbidden": True,
"auto_disabled": True,
}
if ok and upstream_meta:
# 刷新成功时清除之前的封禁标记(如果账户已恢复)
if "antigravity" in upstream_meta:
upstream_meta["antigravity"]["is_forbidden"] = False
upstream_meta["antigravity"]["forbidden_reason"] = None
upstream_meta["antigravity"]["forbidden_at"] = None
metadata_updates[key.id] = upstream_meta
return {
"key_id": key.id,
@@ -1451,26 +1492,6 @@ class AdminRefreshProviderQuotaAdapter(AdminApiAdapter):
error_msg = "; ".join(errors) if errors else "fetchAvailableModels failed"
# 403 "verify your account" → 标记账号异常
if any(
"403" in e and ("verify" in e.lower() or "permission" in e.lower())
for e in errors
):
from datetime import datetime, timezone
from src.services.provider.oauth_token import (
OAUTH_ACCOUNT_BLOCK_PREFIX,
)
key.oauth_invalid_at = datetime.now(timezone.utc)
key.oauth_invalid_reason = (
f"{OAUTH_ACCOUNT_BLOCK_PREFIX}Google 要求验证账号"
)
# 立即持久化异常标记,使负载均衡能尽快跳过此 Key
# 后续 metadata 更新由外层统一 commit
db.commit()
logger.warning("[QUOTA_REFRESH] Key {} 因 403 verify 已标记为异常", key.id)
return {
"key_id": key.id,
"key_name": key.name,
@@ -1479,6 +1500,9 @@ class AdminRefreshProviderQuotaAdapter(AdminApiAdapter):
}
elif provider_type == ProviderType.KIRO:
from src.services.provider.adapters.kiro.usage import (
KiroAccountBannedException,
)
from src.services.provider.adapters.kiro.usage import (
fetch_kiro_usage_limits as _fetch_kiro_usage_limits,
)
@@ -1516,6 +1540,37 @@ class AdminRefreshProviderQuotaAdapter(AdminApiAdapter):
auth_config=auth_config_data,
proxy_config=proxy_config,
)
except KiroAccountBannedException as e:
# 账户被封禁,自动停用并标记
key.is_active = False
key.oauth_invalid_at = datetime.now(timezone.utc)
key.oauth_invalid_reason = f"账户已封禁: {e.reason or e.message}"
# 更新 upstream_metadata 标记封禁状态
ban_metadata = {
"kiro": {
"is_banned": True,
"ban_reason": e.reason or e.message,
"banned_at": int(time.time()),
"updated_at": int(time.time()),
}
}
key.upstream_metadata = merge_upstream_metadata(
key.upstream_metadata, ban_metadata
)
db.commit()
logger.warning(
"[KIRO_QUOTA] Key {} 账户已封禁,已自动停用: {}",
key.id,
e.reason or e.message,
)
return {
"key_id": key.id,
"key_name": key.name,
"status": "banned",
"message": f"账户已封禁: {e.reason or e.message}",
"is_banned": True,
"auto_disabled": True,
}
except RuntimeError as e:
error_msg = str(e)
# 检查是否需要标记账号异常
@@ -1538,6 +1593,10 @@ class AdminRefreshProviderQuotaAdapter(AdminApiAdapter):
metadata = _parse_kiro_usage_response(usage_data)
if metadata:
# 刷新成功时清除之前的封禁标记(如果账户已恢复)
metadata["is_banned"] = False
metadata["ban_reason"] = None
metadata["banned_at"] = None
# 收集元数据,稍后统一更新数据库(存储到 kiro 子对象)
metadata_updates[key.id] = {"kiro": metadata}