Repository navigation
llama.cpp b11901, TextToSpeech.supportsSpeakerReference() and capabilities in getModelMeta() - #577
Conversation
Fourteen upstream commits, tagged (5320c87ff, commit count 11901). Nothing new to call from Java; the range is robustness and internal work. #31153 bounds every recursion over input with COMMON_RECURSIVE_LIMIT (128): the JSON-schema converter and walks ($ref chains, and a property name of 128+ characters under additionalProperties), Jinja templates and macro calls, the glob matcher; the PEG chat-output parser throws common_peg_recursion_error (an std::invalid_argument) past 64 nested levels of model output, which reaches Java as LlamaException; the grammar's candidate rejection, the SPM resegmentation and the vocab trie no longer recurse per character. #31183 adds mtmd_helper_get_capabilities() and deprecates mtmd_helper_model_can_chat / _support_video, which the project does not call. The rest: DeepSeek-V4.1 review fixes, a Metal output-offset overflow, the SYCL reorder buffer bounded to 32 MiB, CUDA/ARM warning fixes, WebUI layout, upstream CI/tests. All twelve patches apply unchanged (the fail-loud applier on a fresh tree); three patch-target files are in the range (server-context.cpp, server-models.cpp, mtmd-cli.cpp), away from every hunk, and the drop-checks of 0001, 0002, 0003, 0008 and 0021 still find the defects. The root and ggml CMake files, vendor/, licenses/, the WebUI lockfile and the release workflow's toolchain pins are unchanged. Checked locally: check-patches (12 patches, 94 hunks, 0 problems), a syntax-only compile of jllama.cpp, jllama_api.cpp, jllama_engine.cpp, native_server_engine.cpp and tts_engine.cpp against the patched b11901 tree with -Wdeprecated-declarations (no diagnostic); the build and the tests are CI's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HyNstib4maubvCs9kQzWdG
…etModelMeta()
llama.cpp b11901 (#31183) collects what a loaded model pair can do in mtmd_helper_get_capabilities();
two of its answers were not reachable from Java until now.
Speaker reference: tts_engine reads mtmd_helper_cap::audio_gen_spk_ref once at load (Qwen3-TTS and
Pocket TTS clone a voice, Soprano does not). The C API gains jllama_tts_supports_speaker_reference(),
the JNI shell TextToSpeech.supportsSpeakerReference(), FFM FfmTextToSpeech.supportsSpeakerReference().
A pair without a voice encoder now refuses a reference clip before anything is loaded, with a message
naming it (speaker_reference_refusal in tts_params.hpp), instead of the generic "TTS input rejected".
TextToSpeech's closed check moved into requireOpen(), which the SpotBugs WEM suppression now names.
Capabilities: model_meta emits "capabilities": {"chat", "audio_gen", "audio_stream"} from upstream's
server meta (has_cap_chat, has_cap_tts, has_audio_stream), read as ModelMeta.supportsChat(),
supportsAudioGeneration() and supportsAudioStream(); absent, and so false, for a vocab-only load.
Tests: C++ -- the meta capabilities of the random model, with the vision projector and vocab-only;
the C API's argument checks; the refusal rule. Java -- ModelMetaTest (each key isolated, absent
key), TextToSpeechLifecycleTest and FfmTextToSpeechTest over the fake backends, JllamaNativeTest
through the real bool slot. Model-backed -- LlamaModelTest, MultimodalIntegrationTest and
VocabOnlyModelTest assert the capabilities; TtsIntegrationTest loads the pair once and checks
supportsSpeakerReference() plus a synthesis with a voice cloned from the committed sample.wav;
the new FfmTextToSpeechIntegrationTest does the same through FFM, and the llama-ffm CI job fails
when it skipped itself.
Checked locally: the full C++ suite (699/699), the core unit tests touched, llama-ffm verify against
a local libjllama, spotless, spotbugs, javadoc, PIT on ModelMeta (34/34 killed), clang-format 23.1.3.
The model-backed tests need the CI models (Hugging Face is not reachable here).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HyNstib4maubvCs9kQzWdG
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Update llama.cpp revision llama/CMakeLists.txt, llama/src/main/java/.../LlamaCppVersion.java, llama/legal/natives/NOTICE.md, CHANGELOG.md, docs/history/llama-cpp-breaking-changes.md, README.md, CLAUDE.md |
The pinned revision changes from b11887 to b11901. Revision records, upstream history, and documentation are updated. |
Expose model capabilities llama/src/main/cpp/jllama_engine.cpp, llama/src/main/java/.../ModelMeta.java, llama/src/test/cpp/test_c_api.cpp, llama/src/test/java/..., llama-ffm/src/test/java/..., README.md, docs/c-api.md |
Native metadata reports chat, audio-generation, and audio-stream capabilities. ModelMeta adds getters that default to false when fields are absent. Tests cover text-only, vision, and vocab-only metadata. |
Speaker-reference TTS and repeated synthesis
| Layer / File(s) | Summary |
|---|---|
Add TTS capability and synthesis behavior llama/src/main/cpp/tts_*, llama/src/main/cpp/jllama*, llama/src/main/java/.../TextToSpeech.java, llama-ffm/src/main/java/.../FfmTextToSpeech.java, CHANGELOG.md, README.md, docs/c-api.md |
The TTS engine reports speaker-reference support and refuses unsupported reference paths. The engine clears the selected KV-cache sequence before setting input. C, JNI, Java, and FFM APIs expose the capability query. |
Exercise Java and FFM TTS flows llama/src/test/java/.../TextToSpeechLifecycleTest.java, llama/src/test/java/.../TtsIntegrationTest.java, llama-ffm/src/test/java/..., llama-ffm/README.md, .github/workflows/publish.yml, CLAUDE.md |
Tests cover open and closed lifecycle queries, reference-voice synthesis, repeated synthesis, and WAV output. CI requires the FFM TTS integration test. |
s390x typeinfo alignment
| Layer / File(s) | Summary |
|---|---|
Align s390x typeinfo sections .github/manylinux/s390x-toolchain.cmake, .github/manylinux/s390x-typeinfo-names.ld, CHANGELOG.md, CLAUDE.md |
The s390x toolchain passes a linker script that aligns typeinfo-name sections to two bytes. |
Validate s390x typeinfo symbols .github/buildcheck/nativedeps.py, .github/buildcheck/tests/test_nativedeps.py, .github/workflows/publish.yml, CLAUDE.md |
The dependency checker validates static typeinfo-name symbol alignment for s390x libraries. Tests cover parsing, alignment, and violation reporting. |
Priority:
Estimated code review effort: 4 (Complex) | ~45 minutes
Change: Feature
Sequence Diagram(s)
sequenceDiagram
participant TextToSpeech
participant supportsSpeakerReferenceNative
participant jllama_tts_supports_speaker_reference
participant engine_supports_speaker_reference
TextToSpeech->>supportsSpeakerReferenceNative: query with TTS handle
supportsSpeakerReferenceNative->>jllama_tts_supports_speaker_reference: request capability
jllama_tts_supports_speaker_reference->>engine_supports_speaker_reference: read cached capability
engine_supports_speaker_reference-->>jllama_tts_supports_speaker_reference: return support value
jllama_tts_supports_speaker_reference-->>supportsSpeakerReferenceNative: return status and value
supportsSpeakerReferenceNative-->>TextToSpeech: return boolean
Possibly related PRs
- bernardladenthin/java-llama.cpp#573: Adds the s390x 2.28 sysroot toolchain that this change extends with typeinfo linker handling.
- bernardladenthin/java-llama.cpp#568: Documents the s390x glibc requirement; this change implements the s390x 2.28 build path and records its requirements.
Suggested labels: dependencies, github_actions, java
Suggested reviewers: claude
Merge Risk: 
Minimal · up to 58b8e
-
No actionable merge-blocking risk remains after normal checks.
Security architecture risk: 
Low · up to 58b8e
-
The changes preserve existing lifetime controls and reject unsupported inputs earlier. No newly exposed attack path was established, but recovery behavior and parts of the dependency update remain unverified.
Retained concerns
No architecture-level concerns identified.Security review details
-
Security Blast Radius
- inferred — The inspected synthesis-state change operates on one engine's owned context and sequence 0, rather than a shared cross-instance store. Caller-supplied reference paths still reach file loading for supported pairs, a path already present at the base; deployment-specific tenant isolation cannot be inferred from this library code.
Trust Boundaries and Controls
- observed — Both Java interfaces hold their lifecycle read lock across the new query and reject closed instances. Close takes the write lock, preserving handle lifetime while the query executes.
- observed — The speaker-reference flag describes model support, not caller authorization. It narrows unsupported file-loading attempts but does not introduce a filesystem sandbox or a new identity boundary.
Resilience and Maintainability Implications
- observed — The C synthesis bridge initializes output to null and zero, keeps generated bytes local until success, and publishes an allocated copy only afterward. Native error paths therefore do not return a partial WAV through this bridge. Subsequent calls request another sequence reset, but complete upstream-state recovery after partial failure remains unverified.
Hardening Proposals
- proposed — Validate the pinned dependency's full-sequence removal guarantee and exercise partial-failure-then-retry behavior on a reused instance. This would strengthen recovery assurance beyond the successful repeated-call test; it is not a verified defect.
-
Pre-merge checks: 
4
Finishing Touches: 💡 2
-
📝 Generate docstrings: 💡
-
- Commit to this branch
- Create a new PR
🛠️ Fix failing CI checks: 💡
-
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Comment @coderabbitai help to get the list of available commands.
…ma_test
TextToSpeech.synthesize() failed on every call after the first on an instance
("prompt processing failed"; llama.cpp: "inconsistent sequence positions",
X = 61 > Y = 0). The Qwen3-TTS pipeline numbers each prompt from position 0
and leaves the KV cache to the caller -- upstream's server calls prompt_clear()
right before set_input() -- and the engine never cleared it. It now removes
sequence 0 before set_input(). The old integration test loaded a fresh
instance for its single synthesis and could not see it; the one this branch
introduced shares an instance, and the Java test jobs went red on exactly that.
synthesizesAgainOnTheSameInstance pins it independent of the method order, and
the capped syntheses use 8 frames: macOS arm64 without Metal needed more than
300 s for 48 frames with a speaker reference.
The s390x job failed to link jllama_test with "misaligned symbol
_ZTSSt19_Sp_make_shared_tag ... for relocation R_390_PC32DBL" from
gcc-toolset-14's libstdc++_nonshared.a (fs_path80.o). clang emits typeinfo
name strings with char alignment (unchanged on LLVM main), GCC loads them with
LARL, which needs an even address, and the COMDAT copy the link keeps is
clang's: green on main, red as soon as the strings before it add up to an odd
size. .github/manylinux/s390x-typeinfo-names.ld (passed by the toolchain with
-T and INSERT) gives every .rodata._ZTS* section 2-byte alignment. Reproduced
with Ubuntu's s390x cross GCC standing in for the toolset and the real
toolchain file over a sysroot in the RHEL layout: the link fails without the
script and succeeds with it for an executable, a PIE and a shared object, and
the program runs under qemu.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HyNstib4maubvCs9kQzWdG
|
CI status on 58b8eed: Publish run 40400361809 is green. That covers every build, all Java test jobs (Ubuntu, both Windows toolchains, the three macOS jobs, FFM, langchain4j, the agent, the Android emulator), The red checks below are not caused by this PR's change; each is red on
This PR's own failures, fixed:
Generated by Claude Code |
…lity only uncapped verify-native-deps.py reads the static symbol table of the s390x libjllama.so and fails a typeinfo name (_ZTS*) at an odd address -- by every binding, since the export map makes them all local; a library without any fails too. The link only fails where GCC code happens to reference an odd name, so it is no test. The check showed the linker script alone missed the non-COMDAT names (key function classes, lambdas: 444 of 1833 odd in a local build), so the toolchain now passes -fdata-sections (0 of 1833). TtsIntegrationTest: an 8-frame clip may be all silence, and where depends on the sampled codes, which differ per CPU backend (the cloned voice was audible on Linux and silent on Windows, run 40394627911). Only the uncapped synthesis is held to audible samples; the capped ones still check the WAV and its payload. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HyNstib4maubvCs9kQzWdG
|



Summary
5320c87ff). Nothing new to call from Java; mostly robustness and internal work. Recursion limits (#31153): JSON schemas, Jinja templates and chat-output parsing that are nested too deep now fail with an error instead of overflowing the native stack and taking the JVM with them. Grammar sampling and the tokenizer no longer recurse per character. Also a Metal fix for large matmuls, a SYCL memory bound, and DeepSeek-V4.1 cleanup. All 12 patches apply unchanged, and the drop-checks show each defect is still there.TextToSpeech.supportsSpeakerReference(), plusFfmTextToSpeech.supportsSpeakerReference()and the C APIjllama_tts_supports_speaker_reference(). These read llama.cpp's newmtmd_helper_cap::audio_gen_spk_ref(#31183). Qwen3-TTS and Pocket TTS clone a voice from a reference clip; Soprano does not. A pair that cannot clone now refuses a reference clip up front, with a message that names the clip, instead of the generic "TTS input rejected".getModelMeta():ModelMeta.supportsChat(),supportsAudioGeneration()andsupportsAudioStream(). They come from a newcapabilitiesobject (chat/audio_gen/audio_stream) built from upstream's server meta. For a vocab-only load the object is absent, so all three arefalse.Found and fixed by this PR's CI:
synthesize()after the first on oneTextToSpeechfailed ("prompt processing failed"). The Qwen3-TTS pipeline numbers each prompt from position 0 and leaves the KV cache to the caller, and the engine never cleared it. It now removes sequence 0 beforeset_input(). A new test,synthesizesAgainOnTheSameInstance, pins it.jllama_testlink failed with a misaligned typeinfo name. clang emits these strings with the alignment ofchar, while gcc-toolset'slibstdc++_nonshared.aloads them withLARL, which needs an even address. The fix is a linker script plus-fdata-sections.verify-native-deps.pynow fails any s390x typeinfo name at an odd address; in a local build the script alone still left 444 of 1833 odd.Test plan
ModelMetaTestandTextToSpeechLifecycleTest.ModelMeta: 34/34 mutations killed.llama-ffmmvn verifyagainst a locally builtlibjllama: the fake-backend tests pass, andJllamaNativeTestpasses through the real bool slot.LlamaException"TextToSpeech handle is null").LlamaModelTest,MultimodalIntegrationTestandVocabOnlyModelTestcheck the capabilities.TtsIntegrationTestnow loads the pair once. It checkssupportsSpeakerReference()and a synthesis with a voice cloned from the committedsample.wav.FfmTextToSpeechIntegrationTestdoes the same through FFM. Thetest-java-llama-ffmjob fails if this test skips itself.docs/c-api.md,llama-ffm/README.md, CLAUDE.md (counts, test tables, s390x),docs/history/llama-cpp-breaking-changes.mdRelated issues / PRs
Follows the b11887 bump (#566).
Checklist
CONTRIBUTING.mdandCODE_OF_CONDUCT.mdGenerated by Claude Code
Summary by CodeRabbit