Skip to content

llama.cpp b11901, TextToSpeech.supportsSpeakerReference() and capabilities in getModelMeta() - #577

Merged
bernardladenthin merged 4 commits into
mainfrom
claude/funny-cori-u2inv0
Oct 27, 2026
Merged

bernardladenthin merged 4 commits into
mainfrom
claude/funny-cori-u2inv0

Conversation

@bernardladenthin

@bernardladenthin bernardladenthin commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • llama.cpp b11887 → b11901 (14 upstream commits, tagged, pinned by commit 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(), plus FfmTextToSpeech.supportsSpeakerReference() and the C API jllama_tts_supports_speaker_reference(). These read llama.cpp's new mtmd_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".
  • Capabilities in getModelMeta(): ModelMeta.supportsChat(), supportsAudioGeneration() and supportsAudioStream(). They come from a new capabilities object (chat / audio_gen / audio_stream) built from upstream's server meta. For a vocab-only load the object is absent, so all three are false.

Found and fixed by this PR's CI:

  • TTS: every synthesize() after the first on one TextToSpeech failed ("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 before set_input(). A new test, synthesizesAgainOnTheSameInstance, pins it.
  • s390x: the jllama_test link failed with a misaligned typeinfo name. clang emits these strings with the alignment of char, while gcc-toolset's libstdc++_nonshared.a loads them with LARL, which needs an even address. The fix is a linker script plus -fdata-sections. verify-native-deps.py now fails any s390x typeinfo name at an odd address; in a local build the script alone still left 444 of 1833 odd.

Test plan

  • Full C++ suite locally: 699/699 tests pass, including the new ones:
    • meta capabilities for a plain model, with a vision projector, and vocab-only
    • C API argument checks for the new function
    • the speaker-reference refusal rule
  • Core unit tests: ModelMetaTest and TextToSpeechLifecycleTest.
  • PIT on ModelMeta: 34/34 mutations killed.
  • llama-ffm mvn verify against a locally built libjllama: the fake-backend tests pass, and JllamaNativeTest passes through the real bool slot.
  • Spotless, SpotBugs, Javadoc and clang-format 23.1.3 are clean.
  • The JNI symbol and the C symbol are exported, and the JNI call reaches the library (checked by reflection: a null handle gives LlamaException "TextToSpeech handle is null").
  • Model-backed tests pass in CI on every Java test job (Ubuntu, both Windows toolchains, the three macOS jobs, FFM):
    • LlamaModelTest, MultimodalIntegrationTest and VocabOnlyModelTest check the capabilities.
    • TtsIntegrationTest now loads the pair once. It checks supportsSpeakerReference() and a synthesis with a voice cloned from the committed sample.wav.
    • The new FfmTextToSpeechIntegrationTest does the same through FFM. The test-java-llama-ffm job fails if this test skips itself.
  • CI is green on this branch: Publish run 40400361809. The only red checks are the ones that are red on every branch; the status comment lists them.
  • Docs / CHANGELOG updated: README, docs/c-api.md, llama-ffm/README.md, CLAUDE.md (counts, test tables, s390x), docs/history/llama-cpp-breaking-changes.md

Related issues / PRs

Follows the b11887 bump (#566).

Checklist

  • I have read CONTRIBUTING.md and CODE_OF_CONDUCT.md
  • My commits follow Conventional Commits (they follow this repository's existing commit style instead)
  • No security-sensitive changes

Generated by Claude Code

Summary by CodeRabbit

  • New Features
    • Model metadata now reports support for chat, audio generation, and audio streaming; unsupported capabilities default to false.
    • Text-to-speech can report whether a model supports speaker-reference voice cloning. Supplying a reference clip to an unsupported model pair returns a clear error.
  • Bug Fixes
    • Updated llama.cpp, including improvements to tokenizer, grammar, and model-output parsing. Deeply nested inputs may still exceed documented limits.
    • Fixed repeated text-to-speech synthesis on the same instance.
    • Improved s390x build compatibility; binaries require glibc 2.28 or newer.

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
@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: ae5082b4-e010-403e-94b1-625e7b1a561d
Commits

Reviewing files that changed from the base of the PR and between 7069179 and 58b8eed.

Files selected for processing: 8
  • .github/buildcheck/nativedeps.py
  • .github/buildcheck/tests/test_nativedeps.py
  • .github/manylinux/s390x-toolchain.cmake
  • .github/manylinux/s390x-typeinfo-names.ld
  • .github/workflows/publish.yml
  • CHANGELOG.md
  • CLAUDE.md
  • llama/src/test/java/net/ladenthin/llama/TtsIntegrationTest.java
Files skipped from review as they are similar to previous changes: 3
  • .github/manylinux/s390x-typeinfo-names.ld
  • .github/workflows/publish.yml
  • CHANGELOG.md

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review.

Walkthrough

The change updates the bundled llama.cpp revision to b11901, adds chat and audio capability metadata, and exposes speaker-reference support across native, Java, and FFM TTS APIs. TTS synthesis clears cached sequence state before input. The change also updates s390x linking and adds alignment checks, tests, CI coverage, and documentation.

Changes: Model capabilities and llama.cpp revision

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: Normal

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
Loading

Possibly related PRs

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: Passed 4
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly summarizes the main changes: the llama.cpp b11901 upgrade, TextToSpeech speaker-reference support, and model capability metadata.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
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

bernardladenthin commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner Author

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), package, every smoke-natives row, the macOS smoke, and the three glibc-floor loads on RHEL 8 (s390x included). The publish jobs were skipped, as expected on a PR.

The red checks below are not caused by this PR's change; each is red on main, on every branch, or on the PRs before this one as well.

This PR's own failures, fixed:

  • TTS (7069179): a second synthesize() on the same instance failed because the KV cache was not cleared. A new test pins it.
  • TTS test (58b8eed): an 8-frame clip with a cloned voice came out silent on the Windows clang job while the same clip was audible on Linux, because the sampled codes differ by CPU backend. Only the uncapped synthesis is held to audible samples now; the capped ones still check the WAV and its payload.
  • s390x (7069179 + 58b8eed): the jllama_test link failed with a misaligned typeinfo name, because clang aligns these strings like char while GCC loads them with LARL. The fix is a linker script plus -fdata-sections. verify-native-deps.py now fails any s390x typeinfo name at an odd address, because the link alone only fails where GCC code happens to reference one. On this head the s390x job reports 0 violations and 699/699 C++ tests passed under qemu.

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
@sonarqubecloud

Copy link
Copy Markdown

@bernardladenthin
bernardladenthin merged commit 1fee05d into main Oct 27, 2026
94 of 99 checks passed
@bernardladenthin
bernardladenthin deleted the claude/funny-cori-u2inv0 branch October 27, 2026 07:07

This branch had an error being deployed

1 failed and 2 active deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants