Commit graph

9 commits

Author SHA1 Message Date
mateo-berri
f27f48ff0f fix(anthropic): count Converse's own tools and let a raw cachePoint stand in for a tool breakpoint
Converse adds a json_tool_call tool for response_format, or a dummy tool for
tool history, and appends the operator's tool_config cachePoint after it even
when it drops every listed tool. The cache step now counts that point whenever
Converse sends a tool in its tool config, so under drop_params a later 1h
breakpoint goes out as 5m instead of getting Claude's ttl order 400.

A raw Bedrock cachePoint with a ttl right after a tool breakpoint formed one run
with the breakpoint's cachePoint, and Bedrock rejects a run where two points set
a ttl. The raw cachePoint now stands in for that breakpoint, which is not sent,
and keeps its slot of Claude's four at the raw cachePoint's ttl, the same way a
client's cache_control on a block replaces its breakpoint. It does so only when
the breakpoint has the same ttl or none, or under drop_params, so without
drop_params a breakpoint with another ttl is still sent and gets Bedrock's 400.
The step also orders the tools Converse sends with one stable sort instead of a
scan per tool. The Converse tool checks move into a helper, since completion()
grew past what basedpyright analyzes
2026-10-18 02:06:55 +00:00
mateo-berri
b272e193df Merge main into litellm_chat_prompt_cache_breakpoint_to_cache_control
Take the chaos test's upstream port from allocate_port(), the TQ012 rule main added
2026-10-17 04:35:02 +00:00
mateo-berri
eba6dbe815 fix(anthropic): keep a valid breakpoint's 1h when it joins one whose ttl drop_params drops
When breakpoints join into one mark (a tool result's parts, a message and its last block, a tool and its function), the first usable one stayed. A 30m breakpoint counts as usable because drop_params can send it without its ttl, so it took the place of a valid 1h beside it and the joined mark went out at 5m. The first breakpoint Claude takes as sent now stays, and the 30m one is still checked, so it answers 400 without drop_params as before

The timing test for settling thousands of marks moves from tests/unit, whose guide bans clock reads, to a CodSpeed benchmark
2026-10-16 11:20:28 +00:00
devin-ai-integration[bot]
4e49394ade
fix(anthropic): keep trailing user messages with None or empty list content (#41397)
* fix(anthropic): keep user messages with None or empty list content so requests do not end on an assistant turn

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

* fix(anthropic): avoid mutable empty-list construction in sanitizer

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

* fix(anthropic): avoid rebinding sanitizer input

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

* fix(anthropic): keep a trailing user turn whose content key was dropped

litellm.completion strips None fields from every message before the provider
transform, so a user message sent with content null reaches the Anthropic
converter with no content key and raised KeyError. Read the content with get
so that turn gets the same placeholder as an empty list.

* fix(anthropic): only fill user turns with empty content and keep their cache_control

* fix(anthropic): fill each empty user message in place like an empty string

* fix(anthropic): add the placeholder only for an empty turn or a cache breakpoint, in linear time

* test(anthropic): cover the tool-result guard with cache_control and widen the linear-time bound

* test(anthropic): cover empty user turns through the proxy on chat, responses and messages

* test(anthropic): type the empty user turn tests and move the linear-time check to a benchmark

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
2026-10-16 07:41:05 +00:00
devin-ai-integration[bot]
c3a23fe499
refactor: expose core private helpers under public names (#44871)
* refactor: expose core private symbols with compatibility aliases

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

* types: narrow core migration diagnostics

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

* fix: preserve runtime behavior in core symbol migration

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

* fix: preserve core private usage migration behavior

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

* fix: preserve private value rebinding compatibility

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

* fix: restore optional imports and cover public helpers

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

* test: exempt router property from call coverage

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

* test: align recursive detector ignore names

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

---------

Co-authored-by: mateo <mateo@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-07 00:05:27 +00:00
devin-ai-integration[bot]
0abd9267c1
feat(tokenizer): preserve Python defaults with opt-in Rust dispatch (#42174)
* ci: benchmark and gate an installed release wheel

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

* ci: simplify installed-wheel benchmark check

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

* feat(rust): add native tokenizer codec

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

* refactor(tokenizer): route Python tokenization through the Rust extension

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

* style(lint): format tokenizer call

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

* fix(packaging): restore runtime dependencies and native images

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

* fix(tokenizer): preserve Python SDK behavior with Rust tokenizers

* fix(tokenizer): restore compatibility paths

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

* refactor(tokenizer): count custom tokenizers directly

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

* fix(tokenizer): preserve caller-supplied Python tokenizer counts

* fix(tokenizer): reuse packaged vocabularies in the native wheel

* refactor(rust_bridge): route token counting through the catalog as RUST_OPT_IN

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

* fix(spend_tracking): compare tokenizer groups by value

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

* chore(deps): re-resolve filelock under the <4.0 pin

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

* fix(llms): align transformation override signatures with base configs

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

* build(rust): use fat LTO to keep the native wheel under the 35 MB limit

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

* feat(tokenizer): preserve Python defaults with opt-in Rust dispatch

* test(proxy): tolerate missing litellm.utils.Tokenizer when patching it

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

* test(proxy): patch the tokenizer dispatch function instead of the removed alias

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

* feat(tokenizer): give the Rust wrappers the tiktoken and tokenizers surface

Callers of litellm.encoding and litellm.create_tokenizer must see the same
read-only API whichever backend the catalog selects.

- OpenAIEncoding mirrors tiktoken.Encoding: n_vocab, max_token_value,
  token_byte_values, encode_single_token, encode_with_unstable,
  encode_to_numpy, decode_with_offsets, is_special_token, repr; the Rust
  tiktoken crate keeps a Vocabulary beside each CoreBPE and reports the
  requested encoding name (gpt2 stays gpt2).
- HuggingFaceTokenizer mirrors the read-only tokenizers.Tokenizer surface
  (token_to_id, id_to_token, get_vocab, get_vocab_size,
  get_added_tokens_decoder, num_special_tokens_to_add, padding, truncation,
  encode_special_tokens, from_buffer); HuggingFaceEncoding gains the
  char/word/token lookups, pad, truncate, set_sequence_id and merge.
  Mutators stay on the Python tokenizer.
- from_json/from_pretrained claim the fork gate only when the huggingface
  feature is compiled in; the surrogate fallback matches on the Codec.
- Tokenizer caching is keyed on the same catalog Context the dispatch runs
  on; rust_tokenizer reads the encoding name without loading an encoding;
  LITELLM_RUST parsing is cached.
- Drop the unused tiktoken_encoding_for_model export and Error::Download.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(tokenizer): close the exhaustive matches with assert_never

CodeQL reads a `match` over a Literal with no default arm as an implicit
`None` return. `assert_never` makes the exhaustiveness explicit for both the
HuggingFace tokenizer loader and the Rust token-counter factory.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* feat(tokenizer): derive the fast counter from the shared tokenizer

The count-only counter (`fast` feature) and the codec each parsed the same
artifact: TokenCounter took the Anthropic JSON and the tiktoken rank files
from Python while Tokenizer loaded them again. One parse now serves both.

- FastTokenizer builds from a model another loader holds: `from_shared`
  takes the Arc<tokenizers::Tokenizer> the HF codec keeps, and
  `from_*_pairs` take the ranks the tiktoken vocabulary already parsed.
- `FastCounter::fast_counter` in the core crate derives it from either codec;
  encodings the fast scanner does not reproduce are refused.
- Native `Tokenizer.count(text, fast=False)` opts into that counter, built
  once per tokenizer on first use; `TokenCounter.from_tokenizer(tokenizer,
  fast=False)` replaces the JSON and rank-file constructors.
- The Python route counts over the native tokenizers the codec path shares
  (`native_encoding`, `native_anthropic`) and no longer reads rank files;
  the packaged Anthropic tokenizer has one loader, `tokenizer_dispatch.anthropic`.
- Public wrappers gain `count(text, fast=False)`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Yujong Lee <yujong@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 04:41:11 +00:00
Yassin Kortam
60729f733e
test(benchmarks): run shared logging executor inline to make CodSpeed measurements deterministic (#32435) 2026-07-09 11:14:22 +03:00
Yassin Kortam
1eb7122465
test(benchmarks): add CodSpeed benchmarks for inference, MCP and A2A hot paths (#31716)
Guard the per-request CPU cost of the chat completion, MCP tool and A2A
message transforms against regressions on every commit. All benchmarks are
pure in-process work with no network I/O so they stay deterministic under
CodSpeed's simulation mode, and they import under the base dependency set the
benchmark job installs.

Inference covers the full SDK overhead via mock_response (simple, multi-turn,
tools, streaming) plus convert_to_model_response_object as a deterministic
anchor. MCP covers the client-side tool translation and the proxy server-side
tool-name prefix round-trip. A2A covers the client request/response transforms
and the proxy server-ingress message conversion.

Adds the mcp and a2a-sdk packages to the benchmark run since those transform
modules need them, and broadens the workflow triggers to litellm_internal_staging
so the internal branch flow is benchmarked too.
2026-06-30 10:27:12 -07:00
codspeed-hq[bot]
be20a8a93d
Add CodSpeed performance benchmarks (#23676)
Co-authored-by: codspeed-hq[bot] <117304815+codspeed-hq[bot]@users.noreply.github.com>
2026-03-14 18:44:36 -07:00