Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/merge-native-artifacts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,10 @@ done
find "$DEST" -mindepth 3 -maxdepth 3 -type d | sort | while IFS= read -r dir; do
plain=""
if [ -f "$dir/jllama-files.txt" ]; then
plain="$(grep -v -e '^#' -e '^$' "$dir/jllama-files.txt" || true)"
# tr -d '\r': a Windows build may write the list with CRLF; a name carrying its CR would fail
# the existence check below and, worse, miss the awk skip-list, so the CPU modules would land in
# jllama-extras.txt and LlamaLoader would load every one of them.
plain="$(tr -d '\r' < "$dir/jllama-files.txt" | grep -v -e '^#' -e '^$' || true)"
while IFS= read -r f; do
[ -z "$f" ] || [ -f "$dir/$f" ] \
|| { echo "::error::${dir#"$DEST"}/jllama-files.txt names '$f', which the build did not produce" >&2; exit 1; }
Expand Down
88 changes: 65 additions & 23 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1431,24 +1431,32 @@ jobs:
path: ${{ github.workspace }}/llama/src/main/natives/net/ladenthin/llama/

# ---------------------------------------------------------------------------
# Windows Ninja Multi-Config + sccache — the DEFAULT Windows CPU natives.
# The Visual Studio generator ignores CMAKE_{C,CXX}_COMPILER_LAUNCHER, so only the
# Ninja Multi-Config generator can front cl.exe with sccache over Depot WebDAV
# (build.bat probe-guards it). Both generators use the same MSVC toolchain (cl.exe,
# static /MT CRT) on the same runner, so the produced jllama.dll/llama.dll/ggml.dll
# are functionally equivalent with identical runtime dependencies — the only delta
# is build-system plumbing + caching. The Ninja build therefore ships as the
# cpu-windows-* natives jars; the MSVC build above as msvc-windows-*, for anyone who
# wants the Visual-Studio-generator natives. Upstream llama.cpp also
# builds its Windows artifacts with Ninja Multi-Config + MSVC.
# Windows x86-64 CPU natives (cpu-windows-x86-64, the default): the CPU-variants build, as the
# two Linux CPU jars ship it -- GGML_BACKEND_DL + GGML_CPU_ALL_VARIANTS, one ggml-cpu-<level>.dll
# per instruction-set level (14 on x86-64), of which ggml loads the best for the running CPU at
# start-up (CLAUDE.md "CPU variants"). The compiler is plain clang (the GNU driver, the LLVM on
# the runner image's PATH), not cl.exe and not clang-cl: CMake sets MSVC for clang-cl as for
# cl.exe, and ggml's `if (NOT MSVC)` then drops 5 of the 14 variants, so llama/CMakeLists.txt
# refuses both. It needs the MSVC headers, libraries and linker from the developer environment
# all the same (clang targets the MSVC ABI), and it ships the same hybrid CRT as every Windows
# CPU jar -- the CMakeLists spells it for clang (-fms-runtime-lib=static + the UCRT linker
# flags), and verify-native-deps.py holds the directory to the OS imports. Two things this job
# deliberately lacks:
# * -DBUILD_TESTING: the option refuses it (jllama_test calls the CPU and RPC backends, which
# are modules here, not link-time libraries) -- test-cpp-windows-x86_64 runs the C++ suite in
# a static build with the same compiler, the split the Linux CPU jobs have.
# * sccache: upstream adds `-Xclang -fno-pch-timestamp` to every clang TU (llama.cpp's
# CMakeLists), which sccache 0.18.0 refuses to cache -- measured: every TU a miss, the build
# green and the cache inert -- so the install would only cost time. The cl.exe TUs of the
# other Windows Ninja jobs still cache; this one builds cold on every run.
# The 32-bit job below stays the Ninja + cl.exe static build (upstream builds no x86 variants
# either), and the two MSVC-classifier jobs above keep the Visual Studio generator.
# ---------------------------------------------------------------------------

build-windows-x86_64:
name: Build and Test Windows 2025 x86_64 (Ninja Multi-Config + sccache, default)
name: Build Windows 2025 x86_64 (CPU variants, clang, default)
needs: [startgate, build-webui]
runs-on: windows-2025-vs2026
env:
SCCACHE_WEBDAV_TOKEN: ${{ secrets.DEPOT_TOKEN }}
steps:
- uses: actions/checkout@v7
- name: Download shared WebUI assets
Expand All @@ -1460,19 +1468,16 @@ jobs:
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64
- name: Install sccache (shared compiler cache)
if: env.USE_CACHE == 'true' && env.SCCACHE_WEBDAV_TOKEN != ''
continue-on-error: true
uses: ./.github/actions/install-sccache-windows
- name: Display CPU Info
shell: bash
run: bash .github/print-host-info.sh
# `clang --version` first: which LLVM the image put on PATH decides whether patches/0017's
# compiler half is exercised as a warning (clang 20) or as the error it fixes (clang 22+).
- name: Build libraries
shell: cmd
run: |
.github\build.bat -G "Ninja Multi-Config" -DGGML_OPENMP=OFF -DOS_NAME=Windows -DOS_ARCH=x86_64 -DBUILD_TESTING=ON
- name: Run C++ unit tests
run: ctest --test-dir llama/build --output-on-failure
clang --version
.github\build.bat -G "Ninja Multi-Config" -DJLLAMA_CPU_VARIANTS=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DGGML_OPENMP=OFF -DOS_NAME=Windows -DOS_ARCH=x86_64
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
Expand Down Expand Up @@ -2254,6 +2259,38 @@ jobs:
- name: Run C++ unit tests
run: ctest --test-dir llama/build --output-on-failure

test-cpp-windows-x86_64:
name: C++ Tests Windows 2025 x86_64 (clang)
needs: startgate
# The C++ suite with the compiler the shipped Windows x86-64 natives are built with (plain
# clang, see build-windows-x86_64), against the default static build: the shipped CPU-variants
# configuration cannot host jllama_test (its CPU and RPC backends are modules), the same split
# as test-cpp-linux-x86_64 / -aarch64. The two MSVC-classifier jobs run the suite with cl.exe,
# so Windows x86-64 has it under both toolchains -- and patches/0017's compiler half (plain
# clang on a windows-msvc target rejecting the typed _mm_prefetch pointer) is reachable only
# here. No WebUI artifact (the test build uses the empty-asset stub) and no sccache (see the
# build job: clang TUs do not cache).
runs-on: windows-2025-vs2026
steps:
- uses: actions/checkout@v7
- name: Set up MSVC developer environment (x64)
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64
- name: Display CPU Info
shell: bash
run: bash .github/print-host-info.sh
- name: Build libraries
shell: cmd
run: |
clang --version
.github\build.bat -G "Ninja Multi-Config" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DGGML_OPENMP=OFF -DOS_NAME=Windows -DOS_ARCH=x86_64 -DBUILD_TESTING=ON
- name: Verify llama.cpp patches are applied
shell: bash
run: .github/verify-patches-applied.sh
- name: Run C++ unit tests
run: ctest --test-dir llama/build --output-on-failure

build-macos-arm64-metal-15:
name: Build and Test macOS 15 arm64 (Metal)
needs: [startgate, build-webui]
Expand Down Expand Up @@ -2434,8 +2471,12 @@ jobs:
natives-artifact: natives-metal-macos-aarch64
error-artifact: error-log-macos-15-metal

# The model-backed suite against the shipped CPU-variants artifact (jllama.dll + ggml.dll +
# ggml-base.dll + the 14 CPU modules): the loader reads the artifact's jllama-extras.txt /
# jllama-files.txt from the test classpath, pre-loads the two ggml libraries and lets ggml pick
# the CPU module -- a load alone proves little (CLAUDE.md "CPU variants"), this runs inference.
test-java-windows-x86_64:
name: Java Tests Windows 2025 x86_64 (default / Ninja)
name: Java Tests Windows 2025 x86_64 (default / CPU variants, clang)
needs: [build-windows-x86_64, verify-model-cache]
uses: ./.github/workflows/java-tests.yml
with:
Expand All @@ -2444,8 +2485,8 @@ jobs:
error-artifact: windows-output

# Java/inference validation of the MSVC-built x86_64 DLL (the analogue of
# test-java-windows-x86_64 for the default Ninja build). Loads the MSVC jllama.dll
# via JNI and runs the full model-backed suite, so both Windows generators are
# test-java-windows-x86_64 for the default CPU-variants build). Loads the MSVC jllama.dll
# via JNI and runs the full model-backed suite, so both Windows x86-64 CPU toolchains are
# validated end-to-end before the `msvc-windows` natives jar ships.
test-java-windows-x86_64-msvc:
name: Java Tests Windows 2025 x86_64 (MSVC classifier)
Expand Down Expand Up @@ -2490,6 +2531,7 @@ jobs:
- build-windows-x86_64-openvino
- test-cpp-linux-x86_64
- test-cpp-linux-aarch64
- test-cpp-windows-x86_64
- build-macos-arm64-metal-15
- test-java-linux-x86_64
- test-java-macos-arm64-metal
Expand Down
54 changes: 54 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ from version 5.0.0 onward. Pre-fork releases (`1.x`–`4.2.0`) were authored by
## [Unreleased]

### Added
- **`ModelParameters.enableMetricsEndpoint()` / `enablePropsEndpoint()` / `enableSlotsEndpoint()` /
`disableSlotsEndpoint()`** (`--metrics`, `--props`, `--slots`, `--no-slots`): the HTTP frontend's
endpoint toggles, needed since `NativeServer` attach mode serves the model's own routes (see Fixed).
- **`test-cpp-windows-x86_64`**: the C++ suite on Windows x86-64 with plain clang (a static build with
the tests), the compiler the shipped `cpu-windows-x86-64` natives are built with now; the two MSVC
jobs keep running it with `cl.exe`. Gates both publish jobs like every other job.
- **`-D` overrides for the four shipped test models.** `net.ladenthin.llama.text.model`, `.draft.model`,
`.reasoning.model` and `.rerank.model` override `TestConstants.MODEL_PATH`, `DRAFT_MODEL_PATH`,
`REASONING_MODEL_PATH` and `RERANKING_MODEL_PATH` the way every capability-specific model already had
one, so a developer can run the suite against models already on the machine (README "System
Properties Reference"). The defaults stay the CI model set, which `TestConstantsTest` pins over the
`DEFAULT_*` constants.
- **`InvalidRequestException`** (`net.ladenthin.llama.exception`, a `LlamaException`): the JNI layer now
throws it wherever llama.cpp's own HTTP server answers `400` (`invalid_request_error`) -- a body that is
not valid JSON, a missing `"prompt"` / `"messages"` / `"input_prefix"`, an empty embedding input, an
Expand Down Expand Up @@ -71,6 +83,26 @@ from version 5.0.0 onward. Pre-fork releases (`1.x`–`4.2.0`) were authored by
core's; `check-natives.py` fails when they differ.

### Changed
- **The log sink attaches llama.cpp's log worker to the JVM once per thread, not once per line.**
`LlamaModel.setLogger`'s trampoline used to `AttachCurrentThread` + `DetachCurrentThread` for every
log line, i.e. one `java.lang.Thread` object and a pair of JVMTI thread events per line (13 lines of a
failed load, 13 `Thread` objects). A `thread_local` guard now keeps the attach (as a daemon thread
named `jllama-log-worker`, visible in thread dumps) until the worker thread exits, which
`common_log::pause()` makes a normal exit; each delivery runs in its own local-reference frame.
`LlamaLoggerTest` pins both.
- **`cpu-windows-x86-64` is the CPU-variants build, built with clang** (`build-windows-x86_64`,
`-DJLLAMA_CPU_VARIANTS=ON`): like the two Linux CPU jars since 5.2.0, the directory holds
`jllama.dll`, `ggml.dll`, `ggml-base.dll`, `ggml-rpc.dll` and one `ggml-cpu-<level>.dll` per
instruction-set level (14), of which ggml loads the best for the running CPU -- an AVX-512 / AVX-VNNI
/ AMX machine uses its kernels and a CPU without AVX2 works, where the one static library was built
for one level. Plain clang because only the GNU driver yields all 14 variants (`clang-cl` and
`cl.exe` lose five, CLAUDE.md "CPU variants"); same hybrid CRT, no new runtime dependency
(`verify-native-deps.py` holds the directory to the OS imports). `LlamaLoader` pre-loads
`ggml-base.dll` and `ggml.dll` by full path from `jllama-extras.txt` before `jllama.dll`, so the
import never resolves against a foreign llama.cpp install on `PATH`. The job no longer installs
sccache (upstream's `-Xclang -fno-pch-timestamp` makes every clang TU a cache miss) and no longer
runs `ctest` (the option refuses `BUILD_TESTING`; see `test-cpp-windows-x86_64` under Added). The
32-bit `cpu-windows-x86` jar and the `msvc-windows-*` jars are unchanged.
- **The message of a rejected request is the bare reason** (`"prompt" must not be empty`), no longer the
JSON object `{"code":400,"message":…,"type":"invalid_request_error"}` the old `throw_invalid_request`
wrapped it in: the type is the exception class now (`InvalidRequestException`), as it is for every
Expand Down Expand Up @@ -304,6 +336,28 @@ from version 5.0.0 onward. Pre-fork releases (`1.x`–`4.2.0`) were authored by
4.4.7 (none of the files the agent's carried JLine fixes touch changed between 4.4.6 and 4.4.7).

### Fixed
- **`NativeServer` attach mode no longer leaves a sleep callback into freed memory behind.**
`llama_server_attach` (`patches/0007`) built a `server_routes` on its own stack frame; its
constructor registers a sleeping-state callback on the model's task queue, which has no unregister,
so after `NativeServer.close()` the model's next idle sleep (`--sleep-idle-seconds`) ran the callback
on a destroyed object. The attached server now serves the model's own `server_routes`
(`jllama_context::routes`, alive as long as the model); pinned by
`NativeServerAttachSleepIntegrationTest`. **Behaviour change:** route-level settings therefore come
from the model's `ModelParameters` -- the endpoint toggles `--metrics` / `--props` / `--slots` (new
setters, see Added), `--slot-save-path`, the slot count, the sampling defaults -- and an attach
argument of that kind is parsed and ignored; the attach argv keeps the HTTP side (`--host`, `--port`,
`--api-key`, `--ssl-*`, `--threads-http`, ...).
- **`GGML_CUDA_GRAPHS_DEFAULT` is repeated in the CPU-variants CMake path.** That path adds ggml before
llama.cpp and therefore skips the block in which llama.cpp changes two ggml defaults; it repeated
only `GGML_LLAMAFILE_DEFAULT`. Latent for the shipped CPU jars, but a CUDA backend built as a module
in this path ran without CUDA graphs and lost two thirds of its token generation (measured at b11538
on an RTX 3070, `docs/handover/local-agent-report-b11538-windows.md`). The CMake comment now states
the rule: every `*_DEFAULT` llama.cpp sets before its own `add_subdirectory(ggml)` is repeated.
- **A Windows `JLLAMA_CPU_VARIANTS` build is loadable without the CI merge step.** `CMakeLists.txt`
writes `jllama-extras.txt` (`ggml-base.dll`, `ggml.dll`, the two libraries `jllama.dll` links) next to
the library, byte-identical to what `merge-native-artifacts.sh` derives in CI; without it
`LlamaLoader` extracted `jllama.dll` alone, Windows resolved its `ggml.dll` import from `java.exe`'s
directory or `PATH`, and every model-backed test of a local variants build failed on the load.
- **`OpenAiCompatServer` answers `400`, not `500`, for a request the native layer rejects** -- an empty
`input` array for `/v1/embeddings`, a `/v1/completions` body without a `prompt`, a malformed body, a
message the chat template cannot take, a prompt over the context size -- on every surface (OpenAI,
Expand Down
Loading
Loading