Commit Graph
35 Commits
Author SHA1 Message Date
Sai-Suraj-27 e28fc5dabb Show the actual accelerate version for transformers env (#49668)
* Log the accelerate version for transformers env

* Few more changes to transformers env

* Small tweaks

* Use get_torch_version()

* Add a test that checks both version and range warning

* Add more tests covering possible scenarios

* parametrize the tests
2026-10-20 15:57:17 +00:00
Wang, Yi 8fa11ce8a6 is_tracing() now recognizes XPU stream capture, alongside the exist… (#49722)
* `is_tracing()` now recognizes XPU stream capture, alongside the existing CUDA capture check. This ensures code executed during XPU graph capture follows tracing-aware paths.

The PR also replaces hard-coded CUDA devices in four continuous-batching serve tests with the selected test accelerator, so those tests can run on XPU. A unit test covers `is_tracing()` when XPU stream capture is active.

No new dependencies are required.

Signed-off-by: Wang, Yi A <yi.a.wang@intel.com>

* make style

Signed-off-by: Wang, Yi A <yi.a.wang@intel.com>

---------

Signed-off-by: Wang, Yi A <yi.a.wang@intel.com>
2026-10-19 08:11:16 +00:00
Arthur 1bd535f3c3 serve: don't crash /v1/models on configs with null architectures (#49509) 2026-10-12 10:58:03 +00:00
Marc Sun 958dbf24b6 v1/systemone endpoint (#49322)
* poc

* systemone

* update test

* docs

* test
2026-10-12 10:56:00 +00:00
Juhyuk choi e159fcef58 Fix backslash handling in generate flag values in transformers chat (#48709)
* Escape generate flag values with json.dumps

* Add tests for backslash and list handling in flag values
2026-09-29 15:00:57 +00:00
Tarek Ziade f441076206 QA: applied ruff rule PLW1514 (#48990) 2026-09-22 06:49:19 +00:00
Lucain 80a79d1bef Use huggingface_hub httpx export (#48685)
Use huggingface_hub httpx export
2026-09-12 09:43:55 +02:00
Tarek Ziade 8fcb52399c QA: Added a MemoryCleanupMixin class for tests (#48681)
* initial draft

* Address serge review: audit the no-grad default and pin the private hook

* You are such a verbose agent.

* Review round from @ydshieh, @vasqu and @stevhliu

* vasqu round 2: docs cross-reference, a note block, a class name, and test_kernels

* @ydshieh round 2: rename the grad knob, name the numbers, explain the rest
2026-09-11 09:16:28 +00:00
Tarek ZiadeandClaude Opus 5 c694707483 Synthetic test assets (#48589)
* Use synthetic CC0 assets instead of third-party licensed media in tests

* work file

* Fix `_format_py_obj` crashing on values it has no branch for

`_format_py_obj` assigns `output` inside a `str`/`int`/`float`/`list`/`tuple`/`dict`
chain with no trailing `else`, so any other type raises
`UnboundLocalError: local variable 'output' referenced before assignment`.

A `torch.Size` hits this: it is a `tuple` subclass, but the branch tests
`__class__.__name__`, which is `"Size"`. Any test whose captured assertion
argument is a shape then loses its report — the CI value capture dies inside
the reporting helper instead of printing the actual value, which is exactly
what the failing test needs.

Fall back to `repr`, which for `torch.Size` gives the copy-pastable
`torch.Size([1, 736, 736])`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Refresh integration expectations recorded against the old third-party assets

Values taken from the A10 run-slow run on this branch
(https://github.com/huggingface/transformers/actions/runs/34103194667), read out
of each job's `captured_info.txt`. Single-GPU and multi-GPU agreed everywhere
they overlapped.

Refreshed: aya_vision, chameleon, chinese_clip, cohere2_vision, cosmos3_omni,
diffusion_gemma (the two minified `generate_with_image_batched*` tests),
fast_vlm, higgs_audio_v2, idefics2, instructblip.

For instructblip both assertions are updated: the run stopped at the token-id
comparison, so the decoded-text expectations come from running the new ids back
through each checkpoint's tokenizer.

Where every key of an `Expectations` dict was recorded against the old asset,
the dict collapses to a single `(None, None)`: only cuda 8.x could be
re-measured, and a stale `("xpu", 3)` / `("cuda", 7)` value is worse than
falling back to the one value we verified.

chmv2 keeps its TODO — the new asset changes the output resolution
(448 -> 736), and the depth slice cannot be re-recorded until a run gets past
the shape assertion.

Left untouched, per the run's own `git bisect` results: edgetam (timm
`FeatureListNet.forward()` signature), the four diffusion_gemma tests that fail
identically on the base commit, and cohere2_vision's OOM / unchanged-fixture
drift / local-path-checkpoint failures.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Fix two more `captured_info` corruptions: backslashes and integer-tensor dtype

Both silently produced a report that cannot be read back, which is the whole
point of the capture:

* `_quote_string` escapes quotes but not backslashes, so a value containing one
  emits a literal that means something else -- and a value *ending* in one
  swallows the closing quote, leaving an unterminated literal. mllama's decoded
  output ends in `\`, so its captured value was unusable.

* `_format_tensor` strips `tensor(` and `)` but a non-default dtype is repr'd as
  a trailing kwarg, e.g. `tensor([83, 362], dtype=torch.int16)`. Stripping only
  the wrapper leaves `dtype=torch.int16` stranded *inside* the literal. Every
  integer tensor hit this (the pp_ocrv5/v6 detection boxes).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Refresh the remaining expectations from the full-coverage GPU run

Round 1 only exercised 16 models -- `get_pr_run_slow_jobs.py` caps its
suggestion at `MAX_NUM_JOBS_TO_SUGGEST = 16` and sorts alphabetically, so
everything from `internvl` on was never run. This is the second pass, over all
58 model dirs plus `pipelines` and `cli`
(https://github.com/huggingface/transformers/actions/runs/34150746428).

Of the 173 failures there, the run's own `git bisect` attributes 87 to this
branch; 41 fail identically on the base commit (edgetam's timm signature
mismatch, four diffusion_gemma tests, cohere2_vision's local-path checkpoints)
and 15 are flaky. 83 of the 87 had a captured value; all of those are refreshed
here.

Two notes on how the values were placed, since both went wrong on the first
attempt:

* Targets are resolved by enclosing test function *and* the assertion's line.
  A file usually holds several `EXPECTED_*` blocks and a test that checks
  several outputs rebinds the same name once per output, so "first match in the
  file" and "last assignment in the function" both write into the wrong test.
  This also fixes a bad round-1 edit that landed the multi-speaker value in
  higgs_audio_v2's `test_single_speaker_smart_voice`.

* Which captured side is the expectation is decided structurally, not from the
  argument name: `assertEqual(EXPECTED, computed)` puts the stale expectation in
  the slot named `first`. Three tests are written that way.

Where every key of an `Expectations` dict was recorded against the old asset the
dict collapses to a single `(None, None)`; only cuda 8.x could be re-measured,
and a stale xpu/rocm value is worse than the one value we verified.

Still marked TODO, awaiting the next run: cosmos3_omni's batched test (OOM),
diffusion_gemma's image-token count and qwen3_asr's timestamps (assertions the
capture does not instrument), qwen2_5_vl's second batch element and
pp_ocrv6_medium_det's boxes (never reached), and instructblip plus
prompt_depth_anything, whose assets were just regenerated:

* `lavis_confusing_pictures.jpg` was flat geometric shapes standing in for the
  LAVIS "man ironing on a taxi" photo, and instructblip-flan-t5 answered "What
  is unusual about this image?" by repeating one sentence until `max_length`.
* `promptda_arkit_depth.png` was saved as RGB, but a prompt-depth map is a
  single-channel metric image -- PromptDepthAnything failed outright with
  "expected input[1, 3, 27, 36] to have 1 channels".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* qwen3_asr: use real Mandarin speech instead of a synthetic sine tone

`audio/mandarin_asr.wav` in the synthetic-assets repo is a 520 Hz sine tone, so
Qwen3-ASR transcribed it as nothing: the expected tokens for the second batch
element collapsed to `[11528, 2240, 151704, 151645, ...]` -- language tag, then
immediate EOS. The test stayed deterministic but stopped exercising
transcription at all.

Point both references at `mandarin_voxcpm_zh.wav`, mirrored into
`hf-internal-testing/dummy-audio-samples` from
`adarshxs/voxcpm2-native-generated-audio-user-ref` (`ref_zh.wav`): 4s of
apache-2.0 Mandarin TTS, transcript "你好世界,人工智能正在改变我们的生活方式。"
per the source's `metadata.json`. Same source repo and licence as the
already-GREEN `zs_short.wav`/`zs_medium.wav` there, and recorded in that repo's
`provenance.jsonl` with the same fields.

Both fixture tests need re-recording against the new clip, so the batched one is
marked again; `test_fixture_timestamps_batched` already was.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Repoint the qwen2_audio/qwen3_asr docs at the real Mandarin clip too

The previous commit only fixed the test and the CI prefetch list, but five doc
snippets still pointed at the sine tone. These are copy-paste examples, so a
reader running them would get an empty transcription and reasonably conclude the
model was broken.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Collapse two pixel-identical duplicate assets

The migration replaced third-party URLs one-for-one, so several assets are the
same picture under a name that records which test it came from. Two pairs are
*exactly* identical, so pointing the tests at a single copy cannot change a
tensor:

  images/gemma_golden_gate.png  == images/dreamstime_golden_gate_flowers.jpg
  images/invoice_docquery_b.png == images/invoice_docquery_a.png  (byte-identical)

Both duplicates are deleted from the assets repo and their entries in the
manifest now resolve to the survivor, so the old-URL mapping stays complete.
Their prefetch entries go too, since the survivors are already listed.

Four further pairs are the same content re-encoded rather than identical
(mistral3_view / mistral3_statue_of_liberty / mistral3_golden_gate against their
originals, and paddle_ocr_demo2 against paddle_general_ocr_001). Collapsing
those would take the count from 40 to 36, but they differ by up to 48/255 per
channel, so each one risks another expectation re-record and is better done as
one deliberate batch than mixed into this refresh.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Collapse the four re-encoded duplicate assets

These are the same picture as an existing asset, re-encoded rather than
byte-identical, so unlike the previous pair they do shift the input tensor
slightly:

  mistral3_view.jpg              -> llava_view.jpg                        (max 8/255,  3.1% of pixels)
  mistral3_statue_of_liberty.jpg -> statue_of_liberty.jpg                 (max 9/255,  2.5%)
  mistral3_golden_gate.jpg       -> dreamstime_golden_gate_flowers.jpg    (max 27/255, 9.8%)
  paddle_ocr_demo2.jpg           -> paddle_general_ocr_001.png            (max 48/255, 100%)

The six tests that consume them are marked for re-recording: two in mistral3,
and all four in `PaddleOCRVLIntegrationTest`, whose URL lives in `setUp`.

`paddle_ocr_demo2.jpg` also appeared in a paddleocr_vl docstring, so the change
went into `modular_paddleocr_vl.py` and `modeling_paddleocr_vl.py` was
regenerated from it.

With this the assets repo is 36 files, every one referenced and every reference
resolving. Two duplicate groups are deliberately kept: `azure_slide_1..4` are
0.998-1.000 correlated but differ in ~2.5% of pixels, and phi4_multimodal's
multi-image test wants four distinct slides -- those want regenerating with more
variety, not deduplicating.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Refresh expectations from the round 3 GPU run

27 of the 33 round-3 failures that `git bisect` attributed to this branch,
across 19 files. Values come from each job's captured_info.txt, not from
re-deriving them.

Stale `Expectations` dicts collapse to a single `(None, None)` key: every
hardware key was recorded against an asset this branch replaces, and only
cuda 8.x can be re-measured on this CI, so a stale ("xpu", 3) is worse than
the one value we verified.

Three pixel_values expectations (qwen2_vl, qwen2_5_omni, qwen3_omni_moe) failed
on a bare `assert torch.allclose(...)`, which the capture helper does not
instrument. That assertion is CPU-only image-processor preprocessing, so those
values are computed off-CI instead; each test's own expected_input_ids
reproduces exactly, qwen2_5_omni's slice agrees with qwen2_vl's independently
computed one, and each recomputes within the test's own atol=3e-3.

Two pre-existing inconsistencies fixed on the way through:

- instructblip::test_inference_vicuna_7b had a refreshed token-id expectation
  next to a stale text expectation, so the two contradicted each other. The
  ids decode to the new text exactly.
- pp_formulanet's expectation held a literal backspace byte, from `\backslash`
  written in a non-raw string.

qwen2_5_vl::test_small_model_integration_test_batch_different_resolutions
needed element [1], not element [0] as its TODO claimed: the loop reaches i=1,
so [0] already passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Make the last two blocked expectations reportable, and drop a stray file

Three of the open TODOs were not waiting on an asset or a measurement -- they
were written as assertion forms the capture helper cannot instrument, so every
round reports "AssertionError: False is not true" and no value, and the next
round would have reported exactly the same thing:

- prompt_depth_anything's two tests used
  `assertTrue(torch.allclose(a, b, atol=1e-3))`. Now
  `torch.testing.assert_close(a, b, atol=1e-3, rtol=1e-5)` -- rtol spelled out
  because that is torch.allclose's default, so the tolerance is unchanged.
- diffusion_gemma's image-token check used `assertTrue(a == b)`, which hides
  both operands. Now `assertEqual`, which also reports them.

Round 3 incidentally disproves what these TODOs claimed: prompt_depth_anything
asserts `predicted_depth.shape == (1, 756, 1008)` *before* the value check, and
that passed, so the single-channel depth map was already in place. The stale
asset was never the problem there.

Also removes src/transformers/utils/hub.py.save, a 40K editor backup committed
by accident in 7a367e7.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Refresh the second DQA expectation layer from round 4

The four DocumentQuestionAnswering tests each hold three or four sequential
expectation blocks against the same invoice. A test aborts at its first failing
assertion, so a round's `captured_info.txt` only ever reports the *first* stale
block per test -- round 3 refreshed layer 1, and round 4 (`34213965306`) reached
and reported layer 2. Bisect confirms all four as ours; the other 24 pipelines
rows in that run are pre-existing and untouched.

Round 4 also settles the question left open when these values were first
recorded. `INVOICE_URL` moved `invoice_docquery_b.png` -> `_a.png` in 1660b7f,
and `_b` is now deleted from the Hub, so the two could not be compared. But both
were ours: `make_document_assets()` in
`.ai/generated_assets/assemble_transformers_synthetic_assets.py` is one
deterministic path whose only per-file variable is `title`, and both entries pass
"INVOICE". Re-running it reproduces `_a` and `_b` with the same sha256, and that
output is byte-identical to the live `_a`. The layer-1 values measured against
`_b` were therefore valid, which is why every one of them passed this round.

Two blocks still hold the old values and are marked; both need measuring rather
than inferring, and `pipelines` is in the next round anyway:

- `test_large_model_pt` line 238 -- the batched form
- `test_large_model_pt_layoutlm` line 354 -- the `word_boxes` path, image=None

`test_large_model_pt_donut` needed nothing: it already asserted
`{"answer": "syn-2026-001"}` and passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Two more `_format_py_obj` bugs that corrupt the value it reports

Same family as the three already fixed in this helper: each one silently
destroys the value the capture report exists to provide.

- A 1-element tuple was rendered without its trailing comma, so `(5,)` came out
  as `(5)` -- which parses back as the int 5, not a tuple. Pasting that into an
  expectation gives `assertEqual(some.shape, 5)`, an assertion that can never
  hold. Found because round 4 reported `pp_ocrv6_medium_det`'s
  `assertEqual(results[0]["scores"].shape, (5,))` expectation as `(5)`.
- An empty list, tuple or dict raised `IndexError` from `element_types[0]` in
  `use_one_line_repr`, taking the whole report down. Plausible input: a
  detection test that finds nothing -- and detection counts in this branch do
  change (pp_ocrv6 went 5 -> 4).

Both round-trip through `ast.literal_eval` now, including nested cases such as
`((1,),)`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Refresh 13 expectations from round 4

Round 4 (`34213965306`) bisect: 20 rows ours, 31 pre-existing, 2 ambiguous,
1 flaky. This lands the 13 ours-rows that produced a usable capture, across
12 files.

Every one of round 3's refreshed tests advanced to a later assertion in this
run and none failed where it had been refreshed, which confirms two things that
had been taken on trust:

- the three `expected_pixel_slice` values derived off-CI from the image
  processor (qwen2_vl 542 -> 550, qwen2_5_omni 653 -> 669, qwen3_omni_moe
  773 -> 789 all cleared the pixel assertion), and
- the invoice byte-identity argument behind the pipelines values.

`prompt_depth_anything` reported real numbers for the first time, which is what
converting its `assertTrue(torch.allclose(...))` was for. So did
`diffusion_gemma`'s image-token count, now 260; its TODO is removed.

Deliberately not refreshed, on the bisect verdict:

- `mllama::test_11b_model_integration_multi_image_generate` is pre-existing. It
  pins the *wrong* answer on purpose -- the comment above it records that the
  quantized model says "dock" where it should say "stop sign". Round 4 returns
  the correct stop-sign answer, so refreshing the string would delete a tracked
  bug and leave the comment contradicting the assertion. Whether the synthetic
  asset has stopped exercising that bug is a separate question.
- `mllama::test_11b_model_integration_batched_generate` is ambiguous, and its
  new value is padded-batch gibberish ("This image showst's a photo of a person
  named ...") -- the same objection as `chameleon::test_model_7b_batched`.
- `instructblip::test_inference_flant5_xl` is ambiguous.
- `diffusion_gemma`'s three `test_minified_*` rows and
  `test_diffusion_gemma_chat_template` are pre-existing; the model is red on
  `main`.
- `qwen2_vl::test_small_model_integration_test_batch` is flaky (CUDA OOM).
- `qwen3_asr::test_fixture_batch_matches` needs a human: both captured sides
  resolve to computed values, so which one is the expectation is not decidable
  structurally.

`pp_ocrv6_medium_det` gets its scores *shape* only (5 -> 4). The scores tensor
still holds five values and the labels shape still asserts `(5,)`, so its TODO
stays: like the DQA tests, it peels one assertion per round.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Clear 6 resolved TODOs, and refresh paddleocr_vl's processor expectations

Round 4 shows six `# TODO(synthetic-assets)` markers no longer describe
anything outstanding. Three guard tests that now simply pass -- cosmos3_omni's
batched integration test (it used to OOM), mistral3's
`test_mistral3_integration_batched_generate`, and paddleocr_vl's
`test_small_model_integration_test_batch`. Three were refreshed from round 4's
capture in the preceding commit: mistral3's multi-image test and both
prompt_depth_anything tests.

paddleocr_vl's remaining failure was `assert 211 == 1389`, a bare assert on
`len(inputs.input_ids[0])`. Everything it checks before the generation is
processor-only work, so it is reproducible off the CI, and two independent
checks say the local run matches this CI: the length comes out 1389, exactly
what the run reported, and the `expected_input_ids` first-ten already in the
file reproduce unchanged. So the token count and the pixel slice are refreshed,
and the three bare asserts become `assertEqual` / `torch.testing.assert_close`
so any later drift is reported with a value instead of a bare "False is not
true".

The same edits apply to `test_small_model_integration_test_flashatt2`, which
feeds the same processor the same messages and so asserts the same numbers; it
did not run this round for want of flash-attn hardware, and would otherwise
have failed identically. `test_small_model_integration_test_batch_flashatt2`
loses its marker for the same reason its non-flash twin did.

`EXPECTED_DECODED_TEXT` is a generation, not preprocessing, so it still needs a
GPU round; both markers now say that rather than blaming the asset.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Two more capture-helper bugs, and instrument assertSequenceEqual

`use_one_line_repr` compared `type(obj) is not type(obj[0])`, but on a dict
`obj[0]` is a *key* lookup rather than positional, so any dict expectation
holding a container value raised `KeyError: 0` and took down the whole
`captured_info.txt` report, not just that one value. Use the dict's single
value as the element to compare. Latent so far: the DQA expectations are lists
of flat dicts, and `word_boxes` is an input, never an expectation.

`assertSequenceEqual` was not patched, so it reported nothing at all. That is
the assertion `pp_doclayout_v2`/`v3` use for `expected_labels`, whose detection
counts change 14 -> 8 and 13 -> 8, so those values were unreachable by any
number of GPU rounds.

Both verified end to end by running pytest with
`patch_testing_methods_to_collect_info()` active and reading the report.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Refresh 7 expectations from round 5

Round 5 (34244551302) brought 7 dirs back green, including all three
`expected_pixel_slice` values that were derived off-CI in round 3 -- those now
clear the generation assertions past them too.

Refreshed:

- pp_ocrv6_medium_det: scores 5 -> 4 values, and the `labels` shape (5,) -> (4,).
  `boxes (4,4,2)` and `scores (4,)` already passed, so three assertions in the
  test agree on 4 detections.
- pp_doclayout_v2 / v3: scores 14 -> 8 and 13 -> 8.
- omdet_turbo: only the third of three batched scores moved, matching the fact
  that exactly one of its three images was repointed.
- paddleocr_vl: the OCR text on all four integration tests. Its `_batch`
  sibling, refreshed in an earlier round, already held the same text.
- pipelines DQA x2: `us-001` -> `SYN-2026-001`, which is what the asset
  generator's deterministic `make_document_assets()` draws.
- qwen3_asr `expected_results_batched.json`: the Mandarin row. This fixture had
  been self-contradictory since round 2, which refreshed its `token_ids` to the
  sine-tone result (`language None`, empty) but left `transcriptions` at the
  original clip's sentence. Both halves now decode to each other, and the text
  matches the transcript recorded in the audio's provenance.jsonl.

The two paddleocr_vl `flashatt2` values are mirrored from the eager tests rather
than measured: `@require_flash_attn` keeps them out of run_models_gpu, so no
round can reach them. Same model, image, prompt, generation args and decode
path; the pairs held identical expectations before the asset swap. Noted in the
code as wanting a local flash-attn run.

`pp_doclayout_v2`/`v3` gain markers for their `expected_labels` next layer,
which had none and was unreportable until assertSequenceEqual was instrumented.
`qwen3_asr::test_fixture_timestamps_batched`'s marker now records the real
blocker: its stale value is an *input* to the forced aligner, so it must be
corrected before timestamps can be measured, and `assertAlmostEqual` is not
instrumented either.

Round 5's bisect matrix died in `actions/download-artifact` with a 403 before
bisecting anything, so these rows were filtered on per-test causal evidence
instead: the test reads an asset this branch repointed, the failure is an
expectation mismatch, and the captured value cross-checks against an
already-passing assertion or the asset's known content.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Refresh 3 expectations from round 6

Round 6 (34262517871) validated every round-5 refresh. Four went green
(pp_ocrv6_medium_det, paddleocr_vl, both pipelines DQA rows, and the qwen3_asr
JSON fixture); the other three advanced past the assertion they were refreshed
at, which is the progress signal rather than "still failing":

- omdet_turbo: scores held, now `expected_slice_boxes`. Only the third of three
  rows changed, the same one-of-three-images signature as its scores.
- pp_doclayout_v2 / v3: scores held, now `expected_labels` -- reported for the
  first time, since assertSequenceEqual had never been instrumented. Both give
  [6, 22, 22, 22, 21, 22, 22, 22]: 8 entries matching the 8 detections, and
  identical between v2 and v3, as expected for one asset through one model
  family.

Bisect was healthy again this round (round 5's 403 was transient) and confirms
the substitute filter used there made no wrong calls: every row it admitted has
gone green or advanced, and every row it excluded is still pre-existing.

Markers retargeted onto `expected_slice_boxes` in v2/v3, the one remaining stale
block in each -- its four rows are the first four of the old detection set.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Never let the capture helper replace a test's own failure

Instrumenting `assertSequenceEqual` in the previous commit was unsafe: it is not
a leaf. `unittest`'s `assertListEqual` delegates to it as
`self.assertSequenceEqual(list1, list2, msg, seq_type=list)`, so a failing
`assertListEqual` enters the patched `assertSequenceEqual` with four positional
args while the parsed call-site expressions still describe the outer call's two.
`positional_args[arg_pos]` then raised `IndexError`, and since the patch wraps
the assertion, that replaced the test's real failure and took down the whole
`captured_info.txt` report. `omdet_turbo::test_inference_object_detection_head_batched`
produced no report at all because of it.

Guarding the `IndexError` alone would be worse than the crash: the indices stay
off by one, so `seq1` would be labelled with `seq2`'s expression and the report
would attribute values to the wrong names, silently.

So reconcile the counts and report nothing when the call-site expressions cannot
be matched to this call, and skip writing a record with no values. Direct
`assertSequenceEqual` calls still capture correctly; delegated ones are skipped,
and the outer `assertListEqual` -- already patched -- reports the same values
with the right expressions.

Note for reproducing: this needs `CI=true`. Without it the inner patched method
swallows the `AssertionError` and defers it to `tearDown`, so the outer patched
method never sees it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Refresh 3 expectations from round 7

Round 7 (34268218309) advanced all three rows again, each past the assertion
refreshed in round 6:

- pp_doclayout_v2 / v3: `expected_slice_boxes`, the last stale block in each.
  Scores and labels from rounds 5-6 both held.
- omdet_turbo: `expected_text_labels`, third of three entries, 6 -> 7 labels.
  Its value came from the unittest diff in `test_outputs.txt` rather than a
  capture, because the report died on the IndexError fixed in the previous
  commit. The diff pins both sides and its context lines prove entries 1-2 are
  unchanged, and the count is independently corroborated: the
  `assertListEqual([len(result["scores"]) ...], [4, 4, 7])` above it passed, so
  image 3 really has 7 detections against a stale expectation listing 6.

Markers are down to 2, and neither is a refresh job: qwen3_asr's batched
timestamps need their aligner input corrected first, and instructblip is waiting
on the lavis_confusing_pictures.jpg re-record.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Refresh pp_doclayout_v3's polygon points from round 8

Round 8 (34320893899) brought omdet_turbo and pp_doclayout_v2 green on both
devices -- every expectation in those two files is now refreshed.

pp_doclayout_v3 advanced once more, into `expected_slice_polygon_points`, a
block no earlier round had reached because it only exists in v3. The new value
needs no further round to trust: `expected_slice_boxes[1]`, refreshed last round
and now passing, is [115.5250, 223.8100, 479.4319, 261.9810], and the polygon is
exactly that box's four corners as integers, within the test's own atol=2. It is
also a shape change, (5,2) -> (4,2), so the old 5-point polygon was not merely
reordered.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Refresh test_load_img_url for the synthetic invoice's size

`tests/utils/test_image_utils.py` imports `INVOICE_URL` from the document QA
pipeline tests, and this branch repointed that constant from the impira/docquery
invoice to the synthetic `invoice_docquery_a.png`. The synthetic asset is
900x1200, so `np.array(img).shape` is (1200, 900, 3) where the test still
asserted the original's (1061, 750, 3). Measured directly off the Hub; this is
pure `load_image`, so it needs no GPU run.

Nine slow-CI rounds could not have caught this: `run-slow` job names are
directories, so a round only ever covers tests/models/* plus pipelines and cli.
Tests under tests/utils surface in PR CI's tests_non_model shards instead.

A sweep for other instances is clean. Of the 44 cross-test imports in the repo,
this is the only one pulling from a file this PR changed; the rest import
test_modeling_common, test_tokenization_common or test_audio_utils, none of
which this branch touches. The four non-model test files referencing the assets
directly (cli/test_serve.py and three pipelines files) are already in the rounds.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Refresh 10 expectations the AMD round measured

Round 10 (34352147816) was the first full-coverage AMD round, and its bisect
blames this branch for 11 rows. They split two ways.

Five are `@require_flash_attn` tests no NVIDIA round can reach, so their values
were never refreshed for the synthetic images at all — MI300 is the only CI that
runs them. In each case ROCm returns exactly what the eager sibling already
expects, so a single value serves both devices rather than a new hardware key:

  qwen2_vl      batch_flashatt2, batch_wo_image_flashatt2
  qwen2_5_vl    batch_flashatt2, batch_wo_image_flashatt2 (element 0)
  qwen2_5_omni  batch_flashatt2 (collapses cuda 8.6 / rocm 9.4, both stale)

The other five are genuine cuda/ROCm divergence that the new images exposed:
collapsing those dicts to `(None, None)` left MI300 reading an A10-recorded
value that used to agree and no longer does. They get a `("rocm", (9, 4))` key.

  fast_vlm  test_small_model_integration_test  (plain str -> Expectations)
  internvl  batched_generate_multi_image, interleaved_images_videos
  mistral3  mistral3_integration_batched_generate_multi_image
  qwen3_vl  test_small_model_integration_test

AMD's reusable workflow lives in `hf-workflows` and does not run
`utils/get_test_reports.py`, so there is no `captured_info.txt` for any of this
— every value here came out of the traceback instead. Each was verified by
feeding the reconstruction back through `unittest.util._common_shorten_repr`
and requiring it to reproduce the report's abbreviation byte for byte,
character counts included. That check is what confirms the two qwen2_vl rows,
whose diffs the report truncated at 1408 and 881 characters.

The 16 remaining AMD rows fail on `main` too and are left alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Drop llava_next's comparison against the original image's dumps

`test_small_model_integration_test` verified the processor output against
`nielsr/test-image::llava_1_6_{input_ids,pixel_values}.pt`, dumps recorded from
the original third-party radar image. Synthetic pixels can never reproduce
them, so the test aborted there and its generation expectation — still the old
"radar chart / MMM-Vet" text — was never reached by any round.

Re-recording the dumps from this very processor would only compare it against
itself, so the check is dropped rather than repointed. The generation assertion
below it still exercises the whole pipeline; it is marked stale for the next
round to measure.

Round 3 read this row as pre-existing and round 10 reads it as ours because
`main` has since added `atol=0.1` to the pixel comparison, which is what made
it start passing there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Align qwen3_asr's batched timestamps against the right transcript

Entry 1's `text` is an *input* to the forced aligner, not an expectation, and it
still held the original third-party clip's transcript — so the test aligned
甚至出现交易几乎停滞的情况。 (13 characters) against audio that says something
else entirely, which is where the 0.0 != 0.4 came from. Re-recording timestamps
against a wrong transcript would have pinned meaningless numbers, so the
transcript is corrected first: it now matches what the ASR test already pins in
`expected_results_batched.json`. The entry count moves 13 -> 19 with it.

`assertAlmostEqual` is uninstrumented, so no CI round can ever report these
values; `Qwen3-ForcedAligner-0.6B-hf` is small enough to measure off-CI, which
is the path taken here (CPU, bfloat16, same batched call the test makes).

Two checks stand behind the numbers:

- entry 0, untouched, reproduces the existing fixture **byte for byte** under
  the same local run — so the measurement agrees with the CI hardware wherever
  the two can be compared;
- the new alignment spans 0.00s to 3.92s, against a clip that is 4.00s long and
  whose speech energy runs 0.00s to 3.90s.

Closes the last row round 10 bisected to this branch on both CUDA and AMD.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Refresh instructblip's flan-t5-xl text, the last ambiguous row

This row was filed ambiguous in rounds 3, 4 and 10, and round 10's capture
settles it: on this branch the token-ids assertion already **passes** and only
the text one fails — the classic half-refreshed pair, one side re-recorded after
the `lavis_confusing_pictures.jpg` regeneration and the other left describing
the flat-geometric-shapes stand-in that preceded it.

The "DIFFERENT error message" bisect verdict is what that looks like from the
outside: `main` still fails on the ids, this branch fails one assertion later.
Read that status as a layer already peeled, not as an undecidable row.

Cross-checked the way this plan recommends for id/text pairs — decoding one into
the other. `AutoTokenizer.from_pretrained("Salesforce/instructblip-flan-t5-xl")`
over the 110 ids the test already expects reproduces the captured
`generated_text` exactly, so the two sides now agree by construction.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Address the review: drop dead helpers, unify glass_breaking, kill the collision

Three review threads, all in `fetch_hub_objects_for_ci.py`.

**`get_synthetic_asset_url` / `get_synthetic_asset_path` (ydshieh).** They have
no callers anywhere in the tree — the tests spell the URL out. Removed rather
than documented.

**"should we use one of these breaking glasses then in all tests?" (zucchini).**
Yes, and it turned out to cost nothing. There were two different
`glass_breaking.mp3`: the synthetic CC0 one this PR added, and
`dummy-audio-samples/glass_breaking.mp3`, whose provenance record reads
`verdict: REVIEW, license: unknown` ("no licence declared; an undeclared licence
is not a permission") — exactly the kind of file this PR exists to remove. Its
only consumer left was `pe_audio`, whose two tests are `@unittest.skip`ped and
assert nothing, so repointing them needs no re-recording and no round. The whole
repo now uses one glass_breaking.

**"doesn't that mean `000000039769` will be overshadowed?" (zucchini).** It
would, and the allowlist entry documented the trap instead of removing it. The
collision is between `coco_panoptic/000000039769.png` and
`val2017/000000039769.png`, both **pre-existing on `main`** and both unused:
nothing resolves either through `url_to_local_path`, and every consumer of that
basename opens the in-repo `tests/fixtures/tests_samples/COCO/000000039769.png`.
The widely used cats image is the `.jpg`, which never collided. So the panoptic
entry is dropped rather than renamed on the Hub.

With both causes gone, `KNOWN_BASENAME_COLLISIONS` goes too and
`_check_basename_collisions` now guards the full 111-URL list unconditionally —
which is the point of having it. It passes with no exemptions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Round 11: llava_next measured, two more ROCm layers, and a reportable aligner test

Round 11 (`34449486455` CUDA / `34449486637` AMD, on `28fce388`, 10 dirs) took
CUDA from 11 ours-rows to 2 and AMD from 27 to 5 — of the AMD five, `fast_vlm`'s
batch row and `instructblip` fail on `main` too.

- `llava_next` — first measurement this value has ever had; the input checks
  used to abort the test before generation. It matches the wording three sibling
  tests in the same file already expect for this image.
- `internvl::interleaved_images_videos` and
  `mistral3::batched_generate_multi_image` — the next ROCm layer, exactly where
  the previous commit predicted: refreshing one `Expectations` block only
  reveals the next, since a test stops at its first failing assertion. Both
  values verified against the report's abbreviation.

Worth noting for the haiku: ROCm returns `calm lake` here but an entirely
different haiku in `batched_generate_multi_image`, so the two are not
transferable — the test's own comment about batching altering the output is
right, and mirroring between them would have been wrong.

`qwen3_asr::test_fixture_timestamps_batched` is not a hardware split: **CUDA and
AMD report the identical `0.24`**, and it is the off-CI measurement that
disagrees by two frames on one boundary. So the fixture wants one CI recording,
not a tolerance and not device keys.

Getting it needs the assertion to be reportable. Element-wise `assertAlmostEqual`
is uninstrumented, so a round yields exactly one of the 38 numbers and names
neither the sample nor the word; `zip` also truncated a short prediction
silently, which is what the separate length check was there to catch. Comparing
each sample as one list subsumes both and lets a single round capture everything.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Pin the aligner timestamps to the values CI measures

Round 12 confirmed llava_next, internvl and mistral3 green, and left exactly one
ours-row on each device: this fixture.

The previous commit made the assertion reportable, and that paid off immediately
— one round captured all 19 timestamps instead of the single number
`assertAlmostEqual` was willing to print. 13 of the 19 disagreed with the off-CI
measurement, every one of them by a single frame or two (0.04-0.08s); the words,
the ordering and the 0.00-3.92s span are identical, so it is boundary placement
drifting between CPU and GPU, not a different alignment.

Sample 0 needed no change: it passed on CI, so no capture was produced for it,
which is its own confirmation.

The fixture now holds GPU-measured values and so no longer reproduces on CPU.
That is the right trade for a `@slow` integration test — CUDA and ROCm report
identical numbers, so one recording covers both devices, exactly as it did on
`main` before this branch.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Regenerate the azure slides, which were four copies of one slide

`azure_slide_1..4` came out of one code path whose only per-file variable was the
header title, so they were 0.994-0.997 correlated while phi4_multimodal's
multi-image test shows them to the model as four distinct slides and asks it to
"Summarize the deck of slides." The deck had one slide in it, four times.

Each is now a different layout of the same subject — a title card, a bulleted
service list, a three-stage diagram with arrows, and a bar chart with axes.
Pairwise correlation drops to 0.04-0.70, the remainder being the shared banner
and background. Still 1280x720, still drawn with PIL, still CC0.

Uploaded as `2414d981` in the dataset repo, with the reasoning recorded in
`metadata/asset_manifest.json` (`7fab93ea`) alongside the other regenerations.

Checked the rest of the set rather than only the pair already flagged: correlating
all 31 images pairwise, the azure slides were the *only* group above 0.90. The
four document assets that share the same generator body sit at 0.77-0.86 —
close, but the model reads different text off each, and their expectations are
settled, so they are left alone.

The generator's other instance of the same flaw is fixed too: it still emitted
`invoice_docquery_b.png` with `_a`'s title, which is how those two became
byte-identical before being collapsed. The earlier description-driven generator
shows the intent was a distinct receipt page; the assembler's single code path is
what lost it. Nothing references `_b`, and the manifest already maps both
impira/docquery revisions to `_a`, so the generator now matches what ships.

phi4_multimodal's expectation is marked stale for the next round to measure.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Round 14: the regenerated slides measured, and one more ROCm key

The full-coverage round (61 dirs, `34465008568` / `34465008470`, on `2c12499b`)
leaves **1 ours-row on CUDA and 3 on AMD**, and two of those are the same test.

- `phi4_multimodal::test_multi_image_vision_text_generation` — the value the
  regenerated slides were always going to need. CUDA and AMD return it
  identically, so it stays a plain string.

  It also confirms the regeneration did what it was for: the model now answers
  "It outlines a four-part..." — picked up from the title card's subtitle, which
  exists only on the new slide 1. It is reading four slides, not one slide four
  times.

- `qwen3_omni_moe::test_small_model_integration_test_multiturn` — a cuda/ROCm
  split (ROCm carries the answer on into ", and the dog is a Labrador
  Retriever."), so it becomes an `Expectations` with a `("rocm", (9, 4))` key.

**`pp_doclayout_v2::test_inference_equivalence_for_static_and_dynamic_anchors_0_float32`
is left alone even though bisect blames this branch.** It builds its inputs from
`prepare_config_and_inputs_for_common()` — random weights, random inputs, no
asset of any kind — and the branch does not touch it. Its max diff wanders
across runs (0.00125, 0.00134, 0.00186, 0.00203) against an `atol=1e-4`, so it
sits 12-20x over tolerance on MI300 whichever commit runs it; rounds 10 and 13
saw it fail on `main` too. Which side a given round blames is a coin flip.

A bisect verdict is evidence, not a conclusion: check the failing test actually
reads something this branch changed before refreshing anything.

The other 14 AMD rows fail on `main` too, and `mllama`'s CUDA row is the
documented padded-batch won't-fix.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 13:41:42 +00:00
0a959de1d2 Fix GPU memory teardown in CLI serve tests (#48618)
* [fix] Free GPU memory between CLI test classes to prevent meta-device OOM

Each tearDownClass now calls cleanup() + sets cls.serve = None to release
GPU memory before the next test class loads a model. Also enables
expandable_segments to reduce fragmentation from sequential large model loads.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [fix] Set expandable_segments via os.environ before CUDA init in CLI tests

set_allocator_settings() is a no-op once the CUDA allocator is first used,
which happens at import time. Setting PYTORCH_CUDA_ALLOC_CONF via os.environ
at module load time (conftest.py top-level) ensures it takes effect before
any CUDA allocation occurs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [fix] Release InferenceThread closure references before blocking on queue.get()

While InferenceThread blocks on queue.get() waiting for the next task, the
local variable `fn` from the previous iteration still holds the submitted
closure. For inference calls this closure captures `model` via
`model.generate(**gen_kwargs)`, keeping the model's GPU tensors alive even
after delete_model() clears all other references.

Explicitly set fn/args/kwargs = None in a finally block so the closure (and
the model it captures) is released before the thread blocks again.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [fix] Clean up: remove unneeded expandable_segments env var, add cleanup comment

The PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True was added to work around
fragmentation, but the InferenceThread fix fully resolves the root cause so it
is not needed. Also adds a short comment on cleanup() calls in tearDownClass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: ydshieh <ydshieh@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-08 14:57:30 +00:00
Marc Sun 0514b65827 Fix generate_flags parsing in transformers chat (#48597)
* Fix `generate_flags` parsing in `transformers chat`

Three bugs in `parse_generate_flags`, reported in #48588:

- a flag without `=` raised `IndexError` from `split("=")[1]`. The
  interactive `!set` path already validates this; the CLI argument path did
  not. It now fails with the same message, as a clean CLI error
- a value containing `=` was silently truncated at the first one
  (`bad_key=a=b` -> `a`); `split("=", 1)` keeps it. The `=` -> `:` string
  replacement below it had to go: unreachable while values were truncated,
  it turned the recovered value into `a:b`
- the `ValueError` for invalid JSON named `generate_flags` and the converted
  string but had no `f` prefix, so it printed the placeholders

Also fixes the argument order in the `generate_flags` help example, which
showed `<base_url> <model_id>` while the signature is `MODEL_ID [BASE_URL]`.

* Report all flags missing `=` at once
2026-09-08 12:35:27 +00:00
Tarek Ziade 892044aa2c CI: Point test fixtures at hf-internal-testing copies we already host (#48521)
* Point test fixtures at hf-internal-testing copies we already host

For 13 of those assets the identical bytes are already stored in
hf-internal-testing, so no copy is needed - only the URL changes:

  - 12 COCO val2017 images -> hf-internal-testing/fixtures-coco
  - bcn_weather.mp3        -> hf-internal-testing/dummy-audio-samples

* Mirror the last two COCO test images into hf-internal-testing

* more copies

* More mirroring

* Mirror audiobox.mp4 out of eustlb/dummy-video-dataset

* Load test images through load_test_image instead of fetching them directly

* Route chat-template urls and multi-line image fetches through the cache helpers

* Drop a dead commented-out image load in the llava test

* remove useless if

* make style

* Wrap the remaining pre-cached urls, keyed on the pre-fetch list
2026-09-04 12:49:34 +00:00
Rémi Ouazan b6c0bfe04c [CB] Fail faster (#48334)
* Regroup fatal error under the bg thread status

* Fail at add request

* Fail fast in get outputs

* Nit

* Actually fail the request before processor is created

* No more loud failure

* Fixed some issues with is_finished
2026-08-27 04:22:03 +00:00
Marc Sun 12f2d15519 Update serve chat parsing (#46267)
* new chat parsing for serve

* fix

* update template
2026-07-23 12:17:47 +00:00
Dhruv Sharma ffae066da3 Route chat management calls to the service root (#47138) (#47303)
* Route chat management calls to the service root (#47138)

transformers chat reuses base_url for the serve management endpoints, so
with the documented base_url ending in /v1 the health check requests
/v1/health and model loading posts to /v1/load_model. The serve app mounts
/health, /load_model and /reset at the service root; only the
OpenAI-compatible inference API lives under /v1.

Derive the management base url by stripping a trailing /v1 segment and use
it for check_health and print_model_load, while the AsyncInferenceClient
keeps the full base_url. A base_url without /v1 is unchanged, and a /v1
under a reverse-proxy prefix keeps the prefix.

Signed-off-by: Dhruv Sharma <dhruv7477@gmail.com>

* Address review: rename helper to get_service_root_url, drop mocked tests

Signed-off-by: Dhruv Sharma <dhruv7477@gmail.com>

* Build the service root url with urlunparse instead of ParseResult._replace

Signed-off-by: Dhruv Sharma <dhruv7477@gmail.com>

---------

Signed-off-by: Dhruv Sharma <dhruv7477@gmail.com>
2026-07-22 15:37:32 +00:00
Dhruv SharmaandTarek Ziade 326ae42d30 Fix CLI compatibility with huggingface_hub 1.22 (#47059) (#47064)
* Fix CLI compatibility with huggingface_hub 1.22 (#47059)

Since huggingface_hub 1.22.0, typer_factory returns a click command group (HFCliTyperGroup) instead of a typer.Typer.

tests/cli drove the app with typer.testing.CliRunner, whose invoke() calls typer get_command() and reads ._add_completion from the group, raising AttributeError in every CLI test. Drive the app with click.testing.CliRunner instead, which invokes the click group natively.

Separately, the serve --reasoning option declared its default as the enum member ReasoningMode.AUTO; click validates defaults against the string choices and rejects it, which breaks transformers serve at runtime under hub 1.22. Use the enum value as the default instead (runtime comparisons are unaffected since ReasoningMode is a str enum).

Signed-off-by: Dhruv Sharma <dhruv7477@gmail.com>

* Use hub-canonical optional enum pattern for serve --reasoning

The previous string default failed the ty check (invalid-parameter-default: str not assignable to ReasoningMode). huggingface_hub own CLI never declares enum-member defaults - every enum option there is declared as SomeEnum | None = None, since the hub click converter does not coerce enum defaults. Mirror that pattern: reasoning defaults to None, which is behaviorally identical to AUTO (neither the ON nor OFF branch fires), and the help text states the effective default.

Signed-off-by: Dhruv Sharma <dhruv7477@gmail.com>

* Clean up comments in conftest.py

Removed outdated comments regarding `typer_factory` behavior based on reviewer's suggestions.

* Keep 'auto' as the serve --reasoning default

Apply the review suggestion: the default stays ReasoningMode.AUTO.value so
the CLI help keeps showing [default: auto]. The type-ignore is required
because ty rejects a str default on a ReasoningMode-annotated parameter,
and the hub CLI framework rejects any union annotation except T | None.
Also sorts the conftest import block (ruff I001 from the previous push).

Signed-off-by: Dhruv Sharma <dhruv7477@gmail.com>

* Make the cli test fixture compatible with huggingface_hub < 1.22

The fixture drives whatever `typer_factory` returned: with hub >= 1.22
the app is already a click command group and is invoked natively; with
older hubs it is a `typer.Typer`, converted via `typer.main.get_command`
before invoking. No change to the supported huggingface_hub range.

Verified against both huggingface_hub 1.21.0 and 1.22.0 (74 passed each).

Signed-off-by: Dhruv Sharma <dhruv7477@gmail.com>

---------

Signed-off-by: Dhruv Sharma <dhruv7477@gmail.com>
Co-authored-by: Tarek Ziade <tarek@ziade.org>
2026-07-07 09:15:18 +00:00
4ab0479eee Streamable chat parsing (#45847)
* scaffolding

* Let's do an initial commit

* Let's do an initial commit

* More cleanup

* More cleanup

* Add the prefill

* One more stash commit

* One more stash commit

* Renames/docstring cleanup

* More renames/docstring cleanup

* More renames/docstring cleanup

* Docstring cleanup

* make fix-repo

* Doc cleanup

* Doc cleanup

* make fix-repo

* No more coerce, merge content types

* Cleanup: Support tokens/arrays/lists correctly for input and prefix

* Add prefix to docs too

* Better initial_events handling, better region handling

* Allow multiple literal matches

* Allow emitting dirty regions

* Doc updates

* Drop `assemble` to just use `transform`

* Lots more doc updates

* Lots more doc updates

* Remove batched handling, lots of cleanup

* Use the new method in test_serve

* Small doc update

* Update docs/source/en/chat_response_parsing.md

Co-authored-by: Pedro Cuenca <pedro@huggingface.co>

* Update docs/source/en/chat_response_parsing.md

Co-authored-by: Pedro Cuenca <pedro@huggingface.co>

* Update docs/source/en/chat_response_parsing.md

Co-authored-by: Pedro Cuenca <pedro@huggingface.co>

* Update src/transformers/models/gemma4/convert_gemma4_weights.py

Co-authored-by: Pedro Cuenca <pedro@huggingface.co>

* Mention the extra

* Fix the example stream so it doesn't refer to the previous example

* Remove the `strip` arg for numerical/bool types because it was meaningless

* Fix convert script bracket bug

* Add a regex compatibility section

* Update regex compatibility section

* jmespath: defeated

* jmespath: defeated

* Flesh out the Cohere example

* Update the docs with proper content_args

* Make start_anchor mandatory

* Update gemma4 template!

* Proper buffering

* Corrected prefix handling

* Type fixes

* make fix-repo

* Pipeline updates, batching changes

* Post-rebase fixes

* Tiny reorder on the version check

* Fix licences + no variable abbreviations

* Cleanups, remove assertion

* Refactor load_response_template

* Lots of little doc examples

* Fix docs to explain prefix a bit better

* Add batching

* Add batching

* Docs cleanup

* Docs cleanup, big block of vasqu comments

* Apply suggestions from code review

Co-authored-by: Anton Vlasjuk <73884904+vasqu@users.noreply.github.com>

* More comment fixes

---------

Co-authored-by: Pedro Cuenca <pedro@huggingface.co>
Co-authored-by: Anton Vlasjuk <73884904+vasqu@users.noreply.github.com>
2026-06-24 14:12:20 +00:00
Yih-Darandydshieh 8e24535c2a Fix TestAppRoutes test failures caused by deprecated asyncio.get_event_loop() on Python 3.10+ (#46340)
* Fix unhandled RuntimeError when AsyncTextIteratorStreamer event loop is closed

Guard `on_finalized_text` against `RuntimeError: Event loop is closed` that
occurs when the background `generate()` thread outlives the consumer's event
loop (e.g. early timeout exit or test teardown in pytest-xdist).

* Fix TestAppRoutes failures on Python 3.10+ by replacing deprecated asyncio.get_event_loop()

Replace `asyncio.get_event_loop().run_until_complete()` with `asyncio.run()`
in all four TestAppRoutes test methods. In pytest-xdist worker threads no
event loop is set up, causing `get_event_loop()` to raise RuntimeError.
`asyncio.run()` always creates its own loop and is the recommended approach
since Python 3.10.

* Revert "Fix unhandled RuntimeError when AsyncTextIteratorStreamer event loop is closed"

This reverts commit 3bac1aa58e.

---------

Co-authored-by: ydshieh <ydshieh@users.noreply.github.com>
2026-06-02 11:31:11 +00:00
Yih-Darandydshieh 39603d0e5c Make more tests work with read-only cache (#46299)
fix

Co-authored-by: ydshieh <ydshieh@users.noreply.github.com>
2026-05-30 16:44:33 +02:00
0b25f8c49c [serve] Support for reasoning (#45690)
* reasoning

* Apply repo consistency fixes

* fix gemma reasoning

* Apply repo consistency fixes

* Update src/transformers/cli/serving/utils.py

Co-authored-by: Lysandre Debut <hi@lysand.re>

* unbloat response

* better reasoning

* Apply repo consistency fixes

* fix qwen3.5

* style

* style

* Apply repo consistency fixes

* fix

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Lysandre Debut <hi@lysand.re>
2026-05-19 08:09:13 +00:00
Marc Sun c641d13ea7 [serve] cb error (#45691)
* cb error

* simpler tests

* fix
2026-04-29 14:13:08 +00:00
0ea540efff Add /v1/completions endpoint (OpenAI legacy completions API) to transformers serve (#44558)
Add /v1/completions endpoint (OpenAI legacy Completions API) to `transformers serve`

Adds support for the legacy text completions endpoint, which accepts a
freeform text prompt (no chat template) and returns generated text in
choices[].text. Supports both streaming and non-streaming modes, suffix
for fill-in-the-middle insertion, and proper finish_reason detection.

The implementation follows the refactored serving architecture: a new
CompletionHandler in serving/completion.py extends BaseHandler, and the
route is registered in serving/server.py.

Co-authored-by: Antigravity <bot@antigravity.ai>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 12:31:37 +00:00
Quentin Gallouédec 243f2d7717 Raise 400 on model mismatch when transformers serve is pinned (#45443)
* Raise 400 on model mismatch when `transformers serve` is pinned

* test

* style
2026-04-20 15:36:01 +00:00
Marc SunandLysandre Debut e15297ebc8 [serve] Update tool call to switch to parse_response (#45485)
* fix tool call to support parse response

* simplify parser

* simplification !

* Update src/transformers/cli/serving/response.py

Co-authored-by: Lysandre Debut <hi@lysand.re>

---------

Co-authored-by: Lysandre Debut <hi@lysand.re>
2026-04-20 15:31:32 +00:00
Marc Sun 9b1a47c6a5 Fix response api support (#45463)
* fix

* update tests

* fix

* better doc
2026-04-16 20:47:58 +00:00
8426e7e63d [serve] Forward tool_calls/tool_call_id in processor inputs (#45418)
* Forward tool-use fields in messages for multi-turn conversations

* Apply repo consistency fixes

* Update src/transformers/cli/serving/utils.py

---------

Co-authored-by: Marc Sun <57196510+SunMarc@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-04-15 20:50:58 +00:00
Marc Sun fd45a42772 Multimodal serve support (#45220)
* add audio and video

* multimodal in chat and response api

* fix !

* remove file

* style

* let's have this here for now

* qwen omni works also

* more coverage for test

* style

* add comment

* update chat completion docs + redirect

* fix

* get

* fix response

* much better doc

* update

* typing
2026-04-15 14:02:30 +00:00
Marc Sun 38593c2e83 [refactor] Serving into proper modules (#44796)
* new serve file

* app

* model_manager done

* update serve

* style

* poc done

* renaming

* fix

* new tests

* update metrics and processor

* hardcode n_batch for now

* add response api + compile

* more tests

* add it for now but we will move it

* remove cache impl

* add back load_model

* fix naming

* add transcription

* tool calls better !

* vlm support for both response and chat endpoints

* update bench

* fix vl test

* first iteration of cb

* cb tests

* typing + review

* update test

* better benchmark

* better stream

* update bench

* fix

* serve refactored

* merge

* update

* fix

* style

* simpler

* style

* update warmup

* remove llamacpp integration for now

* styke

* styke

* style again

* remove annoattion

* review !

* style

* much cleaner

* renamed

* remove bench for now

* batch output

* style

* type

* better tests

* update test

* queue draining

* some logs

* readd nathan feature + some minor fixes

* fix

* guard transcription

* better now

* fix

* adding lock to see if this helps

* remove locks

* lock again

* update bench and remove lock for now
2026-04-01 15:42:00 +00:00
Nathan Habibandremi-or a91232af09 [serving] Fix continuous batching JSON response serialization (#45057)
* Fix continuous batching JSON response serialization

Change model_dump_json() to model_dump() to avoid double JSON encoding.
When using continuous batching with stream=false, the response was being
double-encoded as a string instead of returning a proper JSON object.

* add example script eval-job

* fix script

* Add test for continuous batching non-streaming JSON response

Test verifies that non-streaming responses with continuous batching
return proper JSON objects rather than double-encoded JSON strings.
This is a regression test for the fix where model_dump_json() was
changed to model_dump() in the continuous batching response handler.

* fix ci

* Update eval script to use official transformers repo main branch

Changed dependency from personal fork to official huggingface/transformers@main
for production use of the evaluation script.

* add kernels and flash attn 2

* Add continuous batching configuration CLI arguments to serve command

- Add --cb-block-size, --cb-num-blocks, --cb-max-batch-tokens, --cb-max-memory-percent, and --cb-use-cuda-graph flags
- Flags allow users to customize KV cache and performance settings for continuous batching
- Update transformers_serve_cb_eval_job.py to support and pass through CB config arguments
- Update transformers dependency to use NathanHB/transformers@fix-continuous-batching-json-response branch
- All arguments use auto-inference defaults when not specified (backward compatible)

* Add thread lock for manager creation to avoid double manager

* change transformers dep

---------

Co-authored-by: remi-or <remi.pierre_o@orange.fr>
2026-03-31 12:56:00 +00:00
Lysandre DebutandMarc Sun e94695e574 Propagate the model loading from transformers serve to chat (#44758)
* Propagate the model loading from transformers serve to chat

* Docs and tests

* Apply suggestions from code review

Co-authored-by: Marc Sun <57196510+SunMarc@users.noreply.github.com>

* logigng update

* Adjust docs re Marc's comment

* Remove model name if too long for current console size

* Refactor dual model loading w/ locks

---------

Co-authored-by: Marc Sun <57196510+SunMarc@users.noreply.github.com>
2026-03-19 17:08:03 +00:00
Tarek Ziade 0c89522f2a fix(flaky): enforce manual seed to reduce flakiness (#43794)
This change aims to reduce flakiness in CI tests. We identified two causes of nondeterministic behavior:

-  Some tests were not using a fixed RNG seed, which reduced determinism.
- The cli tests were occasionally triggering I/O errors due to writes on a closed stdout.

This branch was run multiple times and appears to reduce flakiness in all previously unseeded tests. While there’s no deterministic way to prove the improvement, using fixed seeds is still a best practice.
2026-02-06 17:30:28 +01:00
Lysandre Debut 52b988d83d Transformers serve fix (#42570)
* Fix: lacking EOS token + failing AutoProcessor

* Tests

* Tests
2025-12-02 18:19:36 +01:00
Lysandre DebutandLucain 52c5c6582b Correctly return finish reason length when finished (#42157)
* Correctly return finish reason length when finished

* Typos + fixup

* Fix a few tests

* Update src/transformers/cli/chat.py

Co-authored-by: Lucain <lucainp@gmail.com>

---------

Co-authored-by: Lucain <lucainp@gmail.com>
2025-11-27 15:55:55 +01:00
Lysandre Debut 2186f316af Transformers serve -> list all generative models from the cache (#42146)
* Scan cache for generative models
Co-authored-by: Wauplin <lucainp@gmail.com>

* Address test
2025-11-27 15:34:51 +01:00
LucainandLysandre af2a66ced9 Migrate transformers cli to Typer (#41487)
* Add typer-slim as explicit dependency

* Migrate CLI to Typer

* code quality

* bump release candidate

* adapt test_cli.py

* Remove ./commands + adapt tests

* fix quality

* consistency

* doctested

* do not serve model in chat

* style

* will it fix them?

* fix test

* capitalize classes

* Rebase

* Rebase

* tests + fixup

tests + fixup

* csutom error message

* fix ?

* should be good

* fix caplog globally

* inner caplog

* last attempt

* Retry

* Let's try with capsys disabled

---------

Co-authored-by: Lysandre <hi@lysand.re>
2025-10-16 13:29:42 +02:00