The code-quality check refuses recursive functions and the walk that inspected
extras was one, so the filter no longer walks anything itself. safe_dumps now
builds its JSON-native structure through safe_json_structure, the filter scrubs
the extra through that, and the original object is kept only when the scrubbed
copy compares equal to it. Anything the serializer skipped (non-string keys,
nests past its depth, fields a repr hides) makes the copy differ, so the copy
wins. A host object whose equality raises, as numpy arrays and torch tensors
do, counts as changed instead of breaking the caller's log call
UserApiKeyCache's batch delete ran the two partitions in sequence, so a Redis
failure on the hashed token partition returned before the ordinary management
keys were touched. Both partitions are attempted now and the first failure is
re-raised for the caller to report.
The customer walk kept its position in two locals it reassigned each page. It
now mirrors the window walk in the same file: a page helper returns where the
walk goes next, and the driver rebinds one value.
Team admins are refused until a proxy admin enables a field, then limited to the enabled fields, and resending unchanged budget settings keeps the team's budget reset times
Greptile review follow-ups on the paged end-user cache invalidation.
UserApiKeyCache keeps hashed token keys in a second in-memory partition, and
routes delete_cache / async_delete_cache there. It inherited the new batch
delete unchanged, so a budget cascade cleared the main partition and left the
key object sitting on its pre-reset spend. Override it the way
async_set_cache_pipeline already partitions its entries.
The spend counters and the management cache shared one exception handler, so a
Redis failure on the counters returned before the management cache was touched
at all. Each cache gets its own await and its own handler now.
A failed page read returned the same empty tuple that ends the walk normally,
so a truncated pass was reported as a complete one. The window is advanced by
then and no later tick comes back for the customers past that page, so the walk
now says it was cut short and the service log carries it.
Keep /projects list paging as a pushed history entry, validate the
project key table page size against its offered options, and clear the
key table params through the table-state setters instead of a copied
key list.
The projects list search lives in ?project_search= and its pagination now goes through useUrlTableState, keeping the page and page_size keys. The key table inside a project reads keys_search, keys_page and keys_page_size, resets to its first page on a new search, and no longer snaps a deep-linked page while the key fetch is failing. Closing a project drops its keys_ params so they do not leak into the next project
The organizations list now reads its search (org_search), org ID filter (filter_org_id), sort (sort_by, sort_order) and pagination (page, page_size) from the URL through useUrlTableState. The detail view tabs are controlled by ?org_tab=, and the Edit row action opens ?org=<id>&org_tab=settings in one history entry instead of passing an editOrg flag
A request for a configured model group that the router rejects before picking a deployment (all deployments in cooldown, no healthy deployment) never gets a custom_llm_provider in its logging kwargs. The spend log payload persisted an empty provider, the daily spend tables carried it through, and the Admin UI Usage page rendered those requests under unknown even though every model in the group has a provider
get_logging_payload now takes the proxy router and, when the logged provider is missing, infers it from the model group's deployments. It only attributes when every deployment in the group resolves to the same provider; mixed groups, unknown groups and a missing router leave the value empty as before. Explicitly logged providers keep precedence
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Vertex AI file content retrieval downloaded the whole GCS object into memory
before responding, which made large batch output files (hundreds of MB, image
generation JSONL past 4 GiB) impractical to fetch through the proxy.
Add BaseLLMHTTPHandler.async_retrieve_file_content_streaming, an httpx
stream=True path that hands the byte iterator to the provider config through
the new BaseFilesConfig.transform_file_content_stream hook and closes the
response on completion, early close, and HTTP error. VertexAIFilesConfig peeks
at the first JSONL row: Generate Content batch output is converted to OpenAI
batch format one row at a time (content-length dropped since it changes),
embeddings output stays buffered so fanned-out rows can be regrouped, and
anything else passes through with the upstream content-type and content-length.
vertex_ai joins FILE_CONTENT_STREAMING_PROVIDERS, so the proxy returns a
StreamingResponse for it while OpenAI-compatible providers and the buffered
Vertex path are unchanged.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The agent-runtime branch of /bedrock/{endpoint} (agents, knowledgebases, flows,
retrieveAndGenerate, rerank, generateQuery, optimize-prompt) forwarded every
caller header to AWS next to the SigV4 signature, so a LiteLLM key presented in
x-api-key or x-litellm-api-key reached bedrock-agent-runtime verbatim. Build the
upstream header set explicitly: drop LiteLLM credential headers by name and any
authenticated secret by value, keep the remaining caller headers, and let the
signed headers win on collisions.