fix: 用量记录保留空 headers/body,格式转换支持同 normalizer 透传

- 用量记录和遥测写入中将 truthiness 检查改为 is not None,
  避免空 dict/list 被误丢弃
- FormatConversionRegistry 新增 _same_normalizer() 方法,
  共享 normalizer 的格式(如 claude:chat/claude:cli)视为同格式透传
- 前端请求详情抽屉按数据可用性智能选择默认数据源
- 视频任务 finalize 支持 headers/original_headers 等别名字段
This commit is contained in:
fawney19
2026-02-21 21:16:35 +08:00
parent b649a69a5e
commit 1e4d0006b9
8 changed files with 179 additions and 61 deletions

View File

@@ -1704,6 +1704,15 @@ class TaskService:
delta = task.completed_at - task.submitted_at
response_time_ms = int(delta.total_seconds() * 1000)
request_headers: dict[str, Any] | None = None
if isinstance(getattr(task, "request_metadata", None), dict):
task_meta = task.request_metadata
for header_key in ("request_headers", "headers", "original_headers"):
raw_headers = task_meta.get(header_key)
if isinstance(raw_headers, dict):
request_headers = dict(raw_headers)
break
try:
await UsageService.record_usage_with_custom_cost(
db=self.db,
@@ -1734,11 +1743,7 @@ class TaskService:
"fallback_created": True,
"video_task_id": task.id,
},
request_headers=(
(task.request_metadata or {}).get("request_headers")
if isinstance(task.request_metadata, dict)
else None
),
request_headers=request_headers,
request_body=getattr(task, "original_request_body", None),
provider_request_headers=None,
response_headers=None,

View File

@@ -108,12 +108,12 @@ def build_usage_params(
# 处理请求头(可能需要脱敏)
processed_request_headers = None
if should_log_headers and request_headers:
if should_log_headers and request_headers is not None:
processed_request_headers = SystemConfigService.mask_sensitive_headers(db, request_headers)
# 处理提供商请求头(可能需要脱敏)
processed_provider_request_headers = None
if should_log_headers and provider_request_headers:
if should_log_headers and provider_request_headers is not None:
processed_provider_request_headers = SystemConfigService.mask_sensitive_headers(
db, provider_request_headers
)
@@ -124,33 +124,33 @@ def build_usage_params(
processed_response_body = None
processed_client_response_body = None
if should_log_body:
if request_body:
if request_body is not None:
processed_request_body = SystemConfigService.truncate_body(
db, request_body, is_request=True
)
if provider_request_body:
if provider_request_body is not None:
processed_provider_request_body = SystemConfigService.truncate_body(
db, provider_request_body, is_request=True
)
if response_body:
if response_body is not None:
processed_response_body = SystemConfigService.truncate_body(
db, response_body, is_request=False
)
if client_response_body:
if client_response_body is not None:
processed_client_response_body = SystemConfigService.truncate_body(
db, client_response_body, is_request=False
)
# 处理响应头
processed_response_headers = None
if should_log_headers and response_headers:
if should_log_headers and response_headers is not None:
processed_response_headers = SystemConfigService.mask_sensitive_headers(
db, response_headers
)
# 处理返回给客户端的响应头
processed_client_response_headers = None
if should_log_headers and client_response_headers:
if should_log_headers and client_response_headers is not None:
processed_client_response_headers = SystemConfigService.mask_sensitive_headers(
db, client_response_headers
)

View File

@@ -45,14 +45,14 @@ class UsageLifecycleMixin:
# 处理请求头
processed_request_headers = None
if should_log_headers and request_headers:
if should_log_headers and request_headers is not None:
processed_request_headers = SystemConfigService.mask_sensitive_headers(
db, request_headers
)
# 处理请求体
processed_request_body = None
if should_log_body and request_body:
if should_log_body and request_body is not None:
processed_request_body = SystemConfigService.truncate_body(
db, request_body, is_request=True
)
@@ -265,17 +265,17 @@ class UsageLifecycleMixin:
should_log_body = SystemConfigService.should_log_body(db)
processed_provider_headers = None
if should_log_headers and provider_request_headers:
if should_log_headers and provider_request_headers is not None:
processed_provider_headers = SystemConfigService.mask_sensitive_headers(
db, provider_request_headers
)
processed_response_headers = None
if should_log_headers and response_headers:
if should_log_headers and response_headers is not None:
processed_response_headers = dict(response_headers)
processed_response_body = None
if should_log_body and response_body:
if should_log_body and response_body is not None:
processed_response_body = SystemConfigService.truncate_body(
db, response_body, is_request=False
)

View File

@@ -252,18 +252,14 @@ class QueueTelemetryWriter(TelemetryWriter):
# Optional: Headers (masked)
if self.include_headers:
if kwargs.get("request_headers"):
data["request_headers"] = self._mask_headers(kwargs["request_headers"])
if kwargs.get("provider_request_headers"):
data["provider_request_headers"] = self._mask_headers(
kwargs["provider_request_headers"]
)
if kwargs.get("response_headers"):
data["response_headers"] = self._mask_headers(kwargs["response_headers"])
if kwargs.get("client_response_headers"):
data["client_response_headers"] = self._mask_headers(
kwargs["client_response_headers"]
)
for _hdr_key in (
"request_headers",
"provider_request_headers",
"response_headers",
"client_response_headers",
):
if kwargs.get(_hdr_key) is not None:
data[_hdr_key] = self._mask_headers(kwargs[_hdr_key])
# Optional: Bodies (truncated)
if self.include_bodies: