feat: Antigravity 端点签名迁移至 gemini:chat,流式 usage 提取重构与请求详情自动刷新

- Antigravity 端点签名从 gemini:cli 统一为 gemini:chat,保留向后兼容,含 DB 迁移
- 流式处理中 usage/completion/text 提取抽离为 _update_ctx_from_provider_event,
  支持 envelope 解包后提取,避免格式转换流程中重复计数
- 新增 has_format_conversion 属性,区分真正的格式转换与 envelope rewrite,
  修正 usage 展示层的格式转换标记
- 请求详情抽屉对未完成请求支持自动轮询刷新,关闭时自动停止
- 按次计费样式调整;实际成本仅在倍率非 1.0 时显示;缓存日志降级为 trace
This commit is contained in:
fawney19
2026-02-07 02:59:02 +08:00
parent ea22f07046
commit 62f852b851
24 changed files with 481 additions and 104 deletions

View File

@@ -1009,7 +1009,7 @@ class AdminRefreshProviderQuotaAdapter(AdminApiAdapter):
# 获取端点:
# - Codex: openai:cli
# - Antigravity: gemini:cli(用于触发 oauth 刷新 + 提供 auth_config.project_id
# - Antigravity: gemini:chat(用于触发 oauth 刷新 + 提供 auth_config.project_id
endpoint = None
if provider_type == ProviderType.CODEX:
for ep in provider.endpoints:
@@ -1019,12 +1019,16 @@ class AdminRefreshProviderQuotaAdapter(AdminApiAdapter):
if not endpoint:
raise InvalidRequestException("找不到有效的 openai:cli 端点")
else:
for ep in provider.endpoints:
if ep.api_format == "gemini:cli" and ep.is_active:
endpoint = ep
# Prefer the new signature, but keep backward-compat with existing DB rows.
for sig in ("gemini:chat", "gemini:cli"):
for ep in provider.endpoints:
if ep.api_format == sig and ep.is_active:
endpoint = ep
break
if endpoint is not None:
break
if not endpoint:
raise InvalidRequestException("找不到有效的 gemini:cli 端点")
raise InvalidRequestException("找不到有效的 gemini:chat/gemini:cli 端点")
results: list[dict] = []
success_count = 0

View File

@@ -70,7 +70,7 @@ async def _resolve_key_auth(
auth_config: dict[str, Any] | None = None
if auth_type == "oauth":
endpoint_api_format = "gemini:cli" if provider_type == ProviderType.ANTIGRAVITY else None
endpoint_api_format = "gemini:chat" if provider_type == ProviderType.ANTIGRAVITY else None
try:
resolved = await resolve_oauth_access_token(
key_id=str(api_key.id),

View File

@@ -1181,6 +1181,7 @@ class AdminUsageDetailAdapter(AdminApiAdapter):
"is_stream": usage_record.is_stream,
"status_code": usage_record.status_code,
"error_message": usage_record.error_message,
"status": usage_record.status,
"response_time_ms": usage_record.response_time_ms,
"first_byte_time_ms": usage_record.first_byte_time_ms, # 首字时间 (TTFB)
"created_at": usage_record.created_at.isoformat() if usage_record.created_at else None,