mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-08 22:21:35 +00:00
Address remaining Greptile feedback: mask token, reuse HTTP client, align columns
- Mask integration_token in GET /vantage/settings response (renamed field to integration_token_masked) - Reuse single httpx.AsyncClient across all batch uploads in deliver() - Align FocusExportEngine.dry_run_export_usage_data to use post-transform FOCUS columns (BilledCost, SubAccountId, ResourceType) matching the Vantage dry-run endpoint Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e07297fa87
commit
4583c90194
4 changed files with 41 additions and 33 deletions
|
|
@ -56,21 +56,25 @@ class FocusVantageDestination(FocusDestination):
|
|||
verbose_logger.debug("Vantage destination: empty content, skipping upload")
|
||||
return
|
||||
|
||||
# Check both size and row-count limits before single-shot upload
|
||||
lines = content.split(b"\n")
|
||||
data_line_count = sum(1 for line in lines[1:] if line.strip())
|
||||
within_limits = (
|
||||
len(content) <= VANTAGE_MAX_BYTES_PER_UPLOAD
|
||||
and data_line_count <= VANTAGE_MAX_ROWS_PER_UPLOAD
|
||||
)
|
||||
if within_limits:
|
||||
await self._upload_csv(content, filename)
|
||||
return
|
||||
# Reuse a single HTTP client for the entire deliver() call
|
||||
async with httpx.AsyncClient(timeout=60.0) as client:
|
||||
# Check both size and row-count limits before single-shot upload
|
||||
lines = content.split(b"\n")
|
||||
data_line_count = sum(1 for line in lines[1:] if line.strip())
|
||||
within_limits = (
|
||||
len(content) <= VANTAGE_MAX_BYTES_PER_UPLOAD
|
||||
and data_line_count <= VANTAGE_MAX_ROWS_PER_UPLOAD
|
||||
)
|
||||
if within_limits:
|
||||
await self._upload_csv(client, content, filename)
|
||||
return
|
||||
|
||||
# Otherwise split into batches respecting both limits
|
||||
await self._upload_batched(content, filename)
|
||||
# Otherwise split into batches respecting both limits
|
||||
await self._upload_batched(client, content, filename)
|
||||
|
||||
async def _upload_csv(self, csv_bytes: bytes, filename: str) -> None:
|
||||
async def _upload_csv(
|
||||
self, client: httpx.AsyncClient, csv_bytes: bytes, filename: str
|
||||
) -> None:
|
||||
url = (
|
||||
f"{self.base_url}/v2/integrations/"
|
||||
f"{self.integration_token}/costs.csv"
|
||||
|
|
@ -79,13 +83,12 @@ class FocusVantageDestination(FocusDestination):
|
|||
"Authorization": f"Bearer {self.api_key}",
|
||||
}
|
||||
|
||||
async with httpx.AsyncClient(timeout=60.0) as client:
|
||||
response = await client.post(
|
||||
url,
|
||||
headers=headers,
|
||||
files={"file": (filename, csv_bytes, "text/csv")},
|
||||
)
|
||||
response.raise_for_status()
|
||||
response = await client.post(
|
||||
url,
|
||||
headers=headers,
|
||||
files={"file": (filename, csv_bytes, "text/csv")},
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
verbose_logger.debug(
|
||||
"Vantage destination: uploaded %d bytes (%s)",
|
||||
|
|
@ -93,7 +96,9 @@ class FocusVantageDestination(FocusDestination):
|
|||
filename,
|
||||
)
|
||||
|
||||
async def _upload_batched(self, csv_bytes: bytes, filename: str) -> None:
|
||||
async def _upload_batched(
|
||||
self, client: httpx.AsyncClient, csv_bytes: bytes, filename: str
|
||||
) -> None:
|
||||
"""Split the CSV into batches and upload each."""
|
||||
lines = csv_bytes.split(b"\n")
|
||||
header = lines[0]
|
||||
|
|
@ -106,14 +111,17 @@ class FocusVantageDestination(FocusDestination):
|
|||
|
||||
# If a single batch still exceeds 2 MB, split further by size
|
||||
if len(batch_csv) > VANTAGE_MAX_BYTES_PER_UPLOAD:
|
||||
await self._upload_size_limited(header, batch_lines, filename, batch_num)
|
||||
await self._upload_size_limited(
|
||||
client, header, batch_lines, filename, batch_num
|
||||
)
|
||||
else:
|
||||
batch_filename = f"{filename}.part{batch_num}"
|
||||
await self._upload_csv(batch_csv, batch_filename)
|
||||
await self._upload_csv(client, batch_csv, batch_filename)
|
||||
batch_num += 1
|
||||
|
||||
async def _upload_size_limited(
|
||||
self,
|
||||
client: httpx.AsyncClient,
|
||||
header: bytes,
|
||||
data_lines: list[bytes],
|
||||
filename: str,
|
||||
|
|
@ -129,7 +137,7 @@ class FocusVantageDestination(FocusDestination):
|
|||
if current_size + line_size > VANTAGE_MAX_BYTES_PER_UPLOAD and current_chunk:
|
||||
batch_csv = header + b"\n" + b"\n".join(current_chunk) + b"\n"
|
||||
batch_filename = f"{filename}.part{batch_offset}_{sub_batch}"
|
||||
await self._upload_csv(batch_csv, batch_filename)
|
||||
await self._upload_csv(client, batch_csv, batch_filename)
|
||||
current_chunk = []
|
||||
current_size = len(header) + 1
|
||||
sub_batch += 1
|
||||
|
|
@ -139,4 +147,4 @@ class FocusVantageDestination(FocusDestination):
|
|||
if current_chunk:
|
||||
batch_csv = header + b"\n" + b"\n".join(current_chunk) + b"\n"
|
||||
batch_filename = f"{filename}.part{batch_offset}_{sub_batch}"
|
||||
await self._upload_csv(batch_csv, batch_filename)
|
||||
await self._upload_csv(client, batch_csv, batch_filename)
|
||||
|
|
|
|||
|
|
@ -55,10 +55,9 @@ class FocusExportEngine:
|
|||
|
||||
summary = {
|
||||
"total_records": len(normalized),
|
||||
"total_spend": self._sum_column(normalized, "spend"),
|
||||
"total_tokens": self._sum_column(normalized, "total_tokens"),
|
||||
"unique_teams": self._count_unique(normalized, "team_id"),
|
||||
"unique_models": self._count_unique(normalized, "model"),
|
||||
"total_spend": self._sum_column(normalized, "BilledCost"),
|
||||
"unique_teams": self._count_unique(normalized, "SubAccountId"),
|
||||
"unique_models": self._count_unique(normalized, "ResourceType"),
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ async def get_vantage_settings(
|
|||
if not settings:
|
||||
return VantageSettingsView(
|
||||
api_key_masked=None,
|
||||
integration_token=None,
|
||||
integration_token_masked=None,
|
||||
base_url=None,
|
||||
status=None,
|
||||
)
|
||||
|
|
@ -164,7 +164,7 @@ async def get_vantage_settings(
|
|||
|
||||
return VantageSettingsView(
|
||||
api_key_masked=masked_settings.get("api_key"),
|
||||
integration_token=settings.get("integration_token"),
|
||||
integration_token_masked=masked_settings.get("integration_token"),
|
||||
base_url=settings.get("base_url"),
|
||||
status="configured",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -62,8 +62,9 @@ class VantageSettingsView(BaseModel):
|
|||
None,
|
||||
description="Masked API key showing only first 4 and last 4 characters",
|
||||
)
|
||||
integration_token: Optional[str] = Field(
|
||||
None, description="Vantage integration token"
|
||||
integration_token_masked: Optional[str] = Field(
|
||||
None,
|
||||
description="Masked integration token showing only first 4 and last 4 characters",
|
||||
)
|
||||
base_url: Optional[str] = Field(None, description="Vantage API base URL")
|
||||
status: Optional[str] = Field(None, description="Configuration status")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue