Commit graph

8121 commits

Author SHA1 Message Date
mateo-berri
45884b9bd3 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_gemini_prompt_cache_min_tokens_4096
# Conflicts:
#	litellm/model_prices_and_context_window_backup.json
#	model_prices_and_context_window.json
2026-08-19 14:55:44 -07:00
mateo-berri
70a4f9a73a fix(search): refuse AgentCore credentials over plaintext HTTP
A trusted hostname over plain http would expose the bearer token or a
replayable SigV4 signature to network observers. Credentials now only ride
https, with localhost exempt so local MCP stubs keep working.
2026-08-19 14:50:58 -07:00
Mateo Wang
b8d5139701
Merge pull request #37473 from BerriAI/litellm_model_registry_audit_20260819
fix(model_prices): correct gemini 3.1 flash image and deepseek v4 pricing, add openai deprecation dates
2026-08-19 14:50:49 -07:00
mateo-berri
2a4598219d feat(proxy): fast-fail validation for batch input files at /v1/files 2026-08-19 14:43:22 -07:00
yassin
8ef522a2a0 fix(search): read AgentCore structuredContent results
Web-search connector 1.1.0 and later return the machine-readable results in result.structuredContent and may leave the text block as prose, which the parser dropped.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-19 21:41:57 +00:00
Mateo Wang
ccffb77b0e
Merge pull request #37515 from BerriAI/litellm_project_key_all_team_models_sentinel
fix(proxy): accept inherited model sentinels in project key limits
2026-08-19 14:40:34 -07:00
mateo-berri
5eeccf69b6 fix(batches): skip undecodable batch output lines when costing 2026-08-19 14:35:01 -07:00
tin-berri
0de60a2ff2
fix(mcp): stop reporting failed OpenAPI tool calls as successes (#37496)
An OpenAPI-backed MCP tool whose upstream answered 401 came back as a
successful tool result carrying the upstream's rejection as its content, so a
caller saw {"error":"invalid_token"} presented as data and the gateway recorded
the request in its own spend log as call_mcp_tool | success.

Three layers each erased the outcome. The request function returned
response.text whatever the status, _handle_local_mcp_tool caught every exception
and returned it as ordinary TextContent, and both dispatch sites then stamped
isError=False unconditionally. Fixing only the first, which is the obvious fix,
changes nothing, because the two above it still map failure onto the
success-shaped value.

The status is now classified where the response is held: a 401 becomes
MCPUpstreamAuthError so the caller is told to re-authenticate, and every other
non-2xx becomes MCPOpenApiUpstreamError, which carries the status and drops the
upstream body rather than serving it as tool content. _handle_local_mcp_tool no
longer swallows, and the call_tool arm keeps the auth error's type. Nothing new
renders these: call_mcp_tool and call_tool_rest_api already turn them into an
isError result naming the status and into a real 401 with WWW-Authenticate, and
the OpenAPI path simply never reached them.

The result is now byte-identical to the regular MCP path for the same failure.
2026-08-19 14:26:02 -07:00
mateo-berri
20a3a16c2f fix(proxy): populate deployment fields on failed-request spend logs from the standard logging payload 2026-08-19 14:25:43 -07:00
mateo-berri
b3c3e6ebb8 fix(search): default the AgentCore MCP protocol version to the gateway default 2026-08-19 14:25:34 -07:00
tin-berri
afbfc3f8fa
fix(complexity-router): gate the reasoning override on a non-SIMPLE score (#37500)
Two or more reasoning keyword matches promoted a request straight to the
REASONING tier no matter what the weighted score said, so "hi, step by step,
pros and cons" scored 0.100 and still bought the most expensive tier.

Require the score to clear the simple_medium boundary before the override
applies. Promotion from MEDIUM or COMPLEX is unchanged; only prompts the
scorer already placed in the cheapest band stay there.
2026-08-19 14:19:24 -07:00
Mateo Wang
eec27a9cb3
Merge pull request #36593 from BerriAI/devin_ai_lit_5445_perplexity_stream_dict_cost
fix(streaming): accept provider cost objects when propagating usage cost
2026-08-19 14:18:36 -07:00
mateo-berri
77716eeaed fix(model_prices): set prompt_cache_min_tokens=4096 for Gemini 3.5/3.6/3.7 Flash and 3.1 Pro Preview 2026-08-19 14:13:00 -07:00
mateo-berri
46a4eda19e Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_fix_bedrock_adaptive_thinking_token_accounting
# Conflicts:
#	litellm/llms/bedrock/chat/invoke_handler.py
#	litellm/responses/litellm_completion_transformation/transformation.py
#	tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py
#	tests/test_litellm/responses/litellm_completion_transformation/test_reasoning_content_transformation.py
2026-08-19 14:10:53 -07:00
mateo-berri
74f12bf6ef fix(proxy): accept inherited model sentinels in project key limits 2026-08-19 14:09:09 -07:00
tin-berri
a613773fca
feat(auto-router)!: scope shadow eval jobs to multiple keys (#37251)
* feat(auto-router): scope shadow eval jobs to multiple keys

A shadow eval job now covers a set of keys instead of exactly one, and each
key carries its own max_turns budget, so one key exhausting its budget leaves
its siblings sampling. The existing job row already is the per-key unit
(api_key_id, max_turns, stopped_at, and the one-active-per-key-and-direction
partial unique index all live on it), so multi-key is grouping rather than
schema surgery: a new group_id column ties N sibling rows written atomically
by one create_many, the API's job id becomes the group id, and pre-existing
jobs backfill group_id = id so their ids keep resolving. The sampler hot path
is untouched; its test file has a zero-line diff

Results come back pooled plus a per-key breakdown and responses list every key
with its own budget, stop state and read-time labels. The dashboard is adapted
minimally to the new shapes (the picker stays single-key and submits a one-key
list); the multi-select picker and per-key table land in the stacked UI PR

* fix(shadow_eval): derive completed from spent budgets and record operator stops

* fix(shadow_eval): stamp stops atomically and freeze counts at the stamp

The stop endpoint wrote stopped_by and stopped_at as two separate updates, so
a failure between them left a job reading stopped while its unstamped legs
kept sampling, and the retry got 400 already stopped. One UPDATE now stamps
stopped_by and every missing stopped_at together, preserving the stopped_at a
leg earned from its own budget via COALESCE

Attempt counts now exclude attempts that land after a leg's stopped_at, so an
in-flight attempt finishing just after an operator stop can never push a
legacy pre-stopped_by job over its budget and flip it from stopped to
completed at read time

* fix(shadow_eval): backfill stopped_by so legacy stops never read as completions

* chore(ui): regenerate api types for the shadow eval stop fields

* fix(shadow_eval): let the stop statement pick one winner under racing stops

Two operators can both pass the derived-status guard in the race window. The
stop UPDATE now claims only legs with stopped_by still null and the endpoint
judges by its row count, so exactly one caller ever gets the 200 and the loser
gets the same already-stopped 400 a late caller gets

* refactor(shadow_eval): make the stop statement the whole state machine

The status guard ran before the UPDATE, so a stop racing the last budgeted
attempt still claimed the job and it read stopped forever instead of
completed. The statement now claims the job only while a leg still samples
inside the window with no stop recorded, and the endpoint reads once after
writing: a racing operator, a same-instant budget spend, and a repeat stop all
get the 400 naming the status the job actually holds. The pre-write guard and
the hand-built response go away

* chore(ui): regenerate api types for the stop route description
2026-08-19 14:02:15 -07:00
mateo-berri
51cafe4365 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_batch_empty_line_cost
# Conflicts:
#	type-discipline-budget.json
2026-08-19 13:54:57 -07:00
yucheng-berri
a1afc2f433
refactor(ptu): give the rollup a source-agnostic deployment record (#37501)
The flat-cost rollup reads deployments only from LiteLLM_ProxyModelTable, so a PTU
deployment declared in config.yaml never accrues flat cost. Those deployments live in
llm_router.model_list as plain dicts whose id sits in model_info rather than on the entry,
so they do not satisfy the shape _parse_ptu_model reads.

Adds a frozen record in that shape and a factory that maps a router entry onto it, leaving
_parse_ptu_model byte-identical so the existing cases stand as evidence of no behaviour
change. Nothing calls the factory yet; the caller lands with the loader union.

_decode_model_info also stops handing back valid JSON that is not an object. It decoded
a list or a scalar and returned it as a mapping, so the caller read fields off it and
raised, losing the whole run rather than the one bad deployment.
2026-08-19 13:51:31 -07:00
Mateo Wang
0f19b5b9ab
Merge pull request #37361 from sytianhe/litellm_spend_log_timestamps
feat(spend-logs): add lifecycle timestamps
2026-08-19 13:29:49 -07:00
yassin
ae18f055ee fix(search): harden AgentCore gateway trust, error and SSE handling
Refuse to SigV4-sign requests to hosts that are neither an AgentCore gateway
hostname nor AGENTCORE_GATEWAY_URL's host, match gateway hostnames on the URL
host instead of anywhere in the URL, accept the env token when api_base is a
real gateway, raise on tools/call responses with result.isError, and split
CRLF-framed SSE events.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-19 19:07:17 +00:00
tin-berri
da7a10ebbd
fix(mcp): forward the per-server auth header on OpenAPI tool calls (#37410)
Both OpenAPI dispatch arms sourced the upstream credential only from the
deprecated global / BYOK mcp_auth_header and never from mcp_server_auth_headers,
so x-mcp-{alias}-authorization was silently dropped on spec_path servers and the
upstream API received no Authorization at all. The managed path already resolves
it through lookup_mcp_server_auth_in_headers, so the two had drifted.

_resolve_openapi_tool_auth now owns that resolution for both arms. A per-server
value is already a complete header value and is forwarded verbatim, while a BYOK
credential keeps its auth-type prefix, so the two are never conflated into
"Bearer Bearer <token>". The resolved credential is also handed to
resolve_openapi_upstream_auth, whose passthrough arm reads it through
_passthrough_token_from_mcp_auth_header and outranks the ContextVar.

server.py loses its inlined copy of the forwarded-header logic along with its
mcp_server is None guards, which are unreachable after the 503 raised above them.

Credit to the earlier analysis and approach in #33349, which this supersedes
against the current v2 credential resolver.
2026-08-19 11:15:19 -07:00
Mateo Wang
133e72c8fd
Merge pull request #36263 from BerriAI/litellm_replica_registry_read_through
fix(proxy): read through to the DB on registry misses so just-created models, guardrails, and agents resolve on sibling replicas
2026-08-19 10:46:35 -07:00
Mateo Wang
b402fea745
Merge pull request #37451 from BerriAI/litellm_isolate_proxy_url_env_in_tests
fix(tests): keep a host PROXY_BASE_URL out of request-derived URL tests
2026-08-19 10:06:26 -07:00
Devin AI
dcd8bb3f38 test(model_prices): update DeepSeek V4 pricing expectations
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-19 13:47:44 +00:00
mateo-berri
5c6391d7d2 refactor(batches): parameterize the batch output Mapping annotations 2026-08-19 02:15:22 -07:00
mateo-berri
f8a23aab09 fix: gate guardrail read-through to active rows and serialize it with the reload reconcile 2026-08-19 01:46:33 -07:00
mateo-berri
9ef6a8826d test: trim the PROXY_BASE_URL fixture and regression docstrings 2026-08-19 00:56:37 -07:00
mateo-berri
e9c01da233 test: drop unused imports in the direct restore test 2026-08-19 00:54:46 -07:00
mateo-berri
43389e987a test: call _restore_deployment_after_failed_upsert directly for the router coverage gate 2026-08-19 00:54:08 -07:00
mateo-berri
790d645d34 Merge branch 'litellm_internal_staging' of https://github.com/BerriAI/litellm into litellm_replica_registry_read_through
# Conflicts:
#	tests/test_litellm/proxy/test_proxy_server.py
2026-08-19 00:48:03 -07:00
mateo-berri
69133f6baa fix(tests): keep a host PROXY_BASE_URL out of request-derived URL tests
The proxy resolves its own public origin from PROXY_BASE_URL before it
looks at anything on the request, so a developer who has that set for
their own deployment watched 65 OAuth discovery, redirect_uri, and client
registration cases fail against an origin no test ever asked for

An autouse fixture now clears it for every unit test, matching the host
AWS config isolation that already sits beside it, and the tests that do
exercise a configured public origin keep setting it in their own body
2026-08-19 06:21:19 +00:00
Mateo Wang
61029814ab
Merge pull request #37444 from BerriAI/litellm_fix_vertex_batch_cost_assertion
test: derive vertex batch cost expectation from the cost map
2026-08-18 22:58:02 -07:00
mateo-berri
afeed48a70 fix(proxy): serialize read-through with reloads, gate db object types
The model resync now mutates the router under MODEL_RECONCILE_LOCK, and the
agent resync shares the new AGENT_RECONCILE_LOCK with the periodic agent
reload, so a reconcile built from a pre-write DB snapshot can no longer evict
or duplicate what a read-through just registered. Every resync checks
should_load_db_object for its object type, keeping read-through consistent
with what the replica is configured to load, and the a2a raise sites tag
ProxyModelNotFoundError as non-retryable so an agent miss no longer burns the
model resync budget.
2026-08-18 22:43:44 -07:00
mateo-berri
df0d8ff15e test: assert the vertex batch output rate is a real discount 2026-08-18 22:38:13 -07:00
Mateo Wang
559310f077
Merge pull request #37423 from BerriAI/litellm_fix_thinking_bool_crash
fix: accept bool thinking param instead of crashing with AttributeError
2026-08-18 22:30:14 -07:00
Mateo Wang
d6afe728aa
Merge pull request #37365 from BerriAI/litellm_lit_5690_failed_request_token_counts
fix(proxy): record estimated input tokens in spend logs for failed dispatched requests
2026-08-18 22:29:51 -07:00
mateo-berri
3a2728a42f test: derive vertex batch cost expectation from the cost map
The gemini 3.6 flash batch rates landed at half the standard rates in
94a29e0708, so the hardcoded standard-rate expectation started failing
on staging and red-lit misc / Run tests on every PR.
2026-08-18 21:18:16 -07:00
Mateo Wang
8941f2a622
Merge pull request #37424 from BerriAI/litellm_lit_5788_managed_file_fallback_pin
fix(router): keep acreate_file fallbacks inside the requested model group
2026-08-18 21:07:12 -07:00
mateo-berri
ac2db91b06 fix(proxy): single-row read-through resyncs and reload-race hardening
Resync registry misses with single-row DB fetches (guardrail by unique
name, agent by unique id or name, model by name then id) instead of
full-table loads, and bound them with a global budget of 20 resyncs per
5s window per registry that fails closed without negative-caching the
key.

Access group create/update now trust the reconcile outcome snapshot
captured under the reload lock instead of a post-lock router read, so a
concurrent reconcile can no longer surface a false degraded-serving 500.

Router.upsert_deployment restores the previously served deployment when
the replacement add fails under ignore_invalid_deployments, so a bad
update no longer silently drops a healthy deployment from serving.
2026-08-18 21:02:12 -07:00
Mateo Wang
9cb3cf7bef
Merge pull request #37425 from BerriAI/litellm_fix_passthrough_embeddings_unmapped_spend
Some checks are pending
CodSpeed Benchmarks / benchmarks (push) Waiting to run
Unit Tests: Enterprise, Google GenAI & Routing / enterprise-routing (push) Waiting to run
Unit Tests: Integrations (Callbacks & Logging) / integrations (push) Waiting to run
Unit Tests: LLM Provider Transformations / All Other Providers (push) Waiting to run
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy API Endpoints / proxy-endpoints (push) Waiting to run
Unit Tests: Proxy API Endpoints / proxy-server (push) Waiting to run
Unit Tests: Proxy Infrastructure / proxy-infra (push) Waiting to run
Unit Tests: Responses, Caching & Types / responses-caching-types (push) Waiting to run
GitHub Actions Security Analysis / zizmor (push) Waiting to run
Publish basedpyright base counts / publish (push) Waiting to run
Code Quality Checks / code-quality (push) Waiting to run
UI Unit Tests / ui-unit-tests (push) Waiting to run
Unit Tests: Core Utilities / core-utils (push) Waiting to run
Unit Tests: Documentation Validation / documentation (push) Waiting to run
Unit Tests: LLM Provider Transformations / Vertex AI (push) Waiting to run
Unit Tests: MCP, Secrets, Containers & Misc / misc (push) Waiting to run
Unit Tests: Proxy Auth & Key Management / proxy-auth (push) Waiting to run
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / budgets (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
fix(proxy): log spend for OpenAI passthrough embeddings with unmapped models
2026-08-18 20:53:57 -07:00
mateo-berri
608d749983 fix(batches): stop one bad output line from zeroing an entire batch's spend 2026-08-18 20:46:59 -07:00
mateo-berri
dfc30e6b4f Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_replica_registry_read_through
# Conflicts:
#	litellm/proxy/management_endpoints/model_access_group_management_endpoints.py
#	ruff.toml
#	tests/test_litellm/proxy/test_route_llm_request.py
2026-08-18 20:29:09 -07:00
Mateo Wang
16bc32fa23
Merge pull request #33842 from BerriAI/litellm_fix_bedrock_malformed_toolcall_18667
fix(bedrock): degrade gracefully on malformed tool-call arguments
2026-08-18 20:11:55 -07:00
yucheng-berri
71044bf5ea
feat(otel): attribute Prisma database spans to PostgreSQL instead of localhost (#36595)
* feat(otel): attribute Prisma database spans to PostgreSQL instead of localhost

Prisma reaches PostgreSQL through a query engine on loopback, so transport
instrumentation attributes database waits to localhost and operators cannot
tell the work is PostgreSQL or correlate it with the database's own metrics.

Datastore service spans now carry db.system.name, db.system, db.operation.name
and, for PostgreSQL, server.address, server.port and db.namespace derived from
DATABASE_URL, and are emitted as CLIENT spans. Only host, port, database and
schema are read, so no credential reaches an exporter. Endpoint attributes are
omitted when a read replica is configured, because routing is decided per Prisma
call underneath the span.

* fix(otel): reject a mis-split DSN authority and name socket-only databases

An unencoded '/' in the password truncates the URL authority, so urlparse
reports the username as the host and the password tail as the database, which
put credential material in db.namespace. Postgres drivers reject that DSN
outright, so the only safe reading is no endpoint at all.

A hostless 'postgresql:///litellm' is a valid local-socket DSN that Prisma
accepts, and it now yields db.namespace with no server address rather than
nothing. The default schema is matched case-insensitively, since an unquoted
PostgreSQL identifier folds and one deployment must yield one namespace.

* fix(otel): keep a non-default schema in db.namespace

Prisma quotes the schema name, so a DSN with ?schema=PUBLIC provisions a
second schema alongside public rather than reusing it. Observed on a live
proxy: the PUBLIC schema came up with its own 70 tables next to public's 78,
and a key created under one was not visible under the other.

Case-folding the two into a single namespace therefore reported two different
schemas as the same database, which is the misattribution this feature exists
to remove. Match the default literally.

* fix(otel): reject any DSN whose userinfo fell outside the authority

An unencoded '#' or '?' in the password sends the tail to the fragment or
query, leaving the path empty, so the marker check on the database segment
never fired and urlparse's hostname (the database username) was exported as
server.address.

The stranded userinfo '@' is the general tell for every mis-split, so guard on
that instead of enumerating the characters that cause it.

* fix(otel): allow an at-sign inside a well-formed DSN query

The previous guard rejected any DSN whose userinfo at-sign fell outside the
netloc, which also caught libpq parameters that legitimately carry one, so
?application_name=svc@prod and ?user=admin@company.com lost their endpoint
attributes.

Discriminate instead: a PostgreSQL DSN never has a fragment, its database name
cannot hold an unencoded at-sign or slash, and an at-sign in the query is only
suspicious when the query did not parse as parameters.

* fix(otel): resolve the database endpoint per span instead of once per process

The endpoint was cached for the process lifetime on the premise that
DATABASE_URL is deployment-static. It is not. The RDS IAM refresh rebuilds the
URL from DATABASE_HOST/PORT/NAME/SCHEMA on every rotation, the reconnect path
re-reads DATABASE_URL, and the DB-backed environment_variables config overlay
sets arbitrary keys post-startup with no blocklist covering DATABASE_*. A
process that had genuinely failed over kept exporting the old server.

Read the environment per span, which is also what Prisma connects with, so the
span can no longer name a different server than the one serving the query;
get_secret_str consulted a secret manager first and could diverge from it. Only
the parse is memoized, keyed on the URL.

* fix(otel): reject a question-mark mis-split whose tail parses as parameters

A '?' in a password strands the rest of the authority in the query, and that
tail can still parse as key=value, so testing only for an unparseable query let
the login through as server.address. One spelling hijacked the host= parameter
and put the password suffix there directly.

A legitimate at-sign in a query always follows a database path, and a
'?'-mis-split never leaves one, so require both.

* refactor(otel): drop the DSN parse cache that retained rotated credentials

The cache was keyed on the full DATABASE_URL, so up to eight complete DSNs,
each carrying a password or a retired IAM token, stayed referenced for the
process lifetime and outlived the rotation that replaced them. Nothing reached a
span, but a heap dump or crash report would have surfaced them.

Parsing costs about four microseconds against a span emission that costs orders
of magnitude more, so the cache bought nothing worth that.

* fix(otel): avoid a set construction the tightened LIT002 budget rejects

* fix(otel): refuse an ambiguous DSN authority instead of guessing at it

A password holding both an unencoded slash and a query-like tail defeated all
three shape checks: the slash left a clean path carrying the password
remainder, the query still parsed as parameters, and no fragment survived. The
login went out as server.address, the password's leading digits as server.port
and the rest as db.namespace.

A DSN whose at-sign sits in a query parameter is indistinguishable from that
mis-split by any property of the parse; both leave no userinfo, a host, a port
and a path. Guessing wrong publishes a credential fragment, so the ambiguity
now resolves to refusing the endpoint. Such a DSN loses server.address and
db.namespace and keeps the rest of the span; percent-encoding the at-sign
restores them.

Also honour port= alongside host=, which libpq pairs and this read ignored.

* docs(otel): fix a spliced sentence and a stale cache claim in db_endpoint

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-18 20:08:43 -07:00
Mateo Wang
1de398d9aa
Merge pull request #37366 from BerriAI/litellm_e2e_auto_router_regression_pins
fix(router): honor key-level tag filtering in pre-routing and pin auto-router e2e regressions
2026-08-18 20:06:49 -07:00
Mateo Wang
822cd4c4ea
Merge pull request #37377 from BerriAI/devin_ai_lit5757_dashscope_nested_cache_creation
fix(types): map nested prompt_tokens_details.cache_creation_input_tokens to cache_write_tokens
2026-08-18 20:02:17 -07:00
mateo-berri
b7f4f531b3 test(router): type the acreate_file fallback test helpers 2026-08-18 19:57:24 -07:00
mateo-berri
54cc988a9e test: drop restating comment and wrap long call in thinking tests 2026-08-18 19:55:22 -07:00
mateo-berri
f8c8b41bf5 fix(proxy): backfill system prompt from the request body when estimating bridged failure tokens 2026-08-18 19:52:31 -07:00
mateo-berri
81914ebc31 fix(proxy): log spend for OpenAI passthrough embeddings with unmapped models 2026-08-18 19:48:02 -07:00