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
22 changes: 11 additions & 11 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ jobs:
distribution: temurin
- uses: gradle/actions/setup-gradle@v6
with:
gradle-version: "9.7.1"
gradle-version: "9.8.0"
- name: Sign a throwaway artifact via useInMemoryPgpKeys (BouncyCastle)
shell: bash
env:
Expand Down Expand Up @@ -1128,8 +1128,8 @@ jobs:
distribution: temurin
- uses: gradle/actions/setup-gradle@v6
with:
# AGP 9.3.0 (the .github/android-consumer-test fixture) requires Gradle >= 9.5.0.
gradle-version: "9.7.1"
# AGP 9.4.0 (the .github/android-consumer-test fixture) requires Gradle >= 9.6.0.
gradle-version: "9.8.0"
- name: Build core jar (byte-identical classes payload for the AAR)
run: >
mvn -B --no-transfer-progress -pl llama -am -DskipTests -Denforcer.skip=true
Expand Down Expand Up @@ -1259,8 +1259,8 @@ jobs:
distribution: temurin
- uses: gradle/actions/setup-gradle@v6
with:
# AGP 9.3.0 (the .github/android-consumer-test fixture) requires Gradle >= 9.5.0.
gradle-version: "9.7.1"
# AGP 9.4.0 (the .github/android-consumer-test fixture) requires Gradle >= 9.6.0.
gradle-version: "9.8.0"
- name: Enable KVM group permissions (GitHub-hosted runner)
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
Expand Down Expand Up @@ -1353,10 +1353,10 @@ jobs:
distribution: temurin
- uses: gradle/actions/setup-gradle@v6
with:
# AGP 9.3.0 (android-llmservice) requires Gradle >= 9.5.0; also satisfies Kotlin
# AGP 9.4.0 (android-llmservice) requires Gradle >= 9.6.0; also satisfies Kotlin
# 2.4's Gradle-plugin floor. The AAR/lib-only jobs stay on an older Gradle since
# they build no AGP project.
gradle-version: "9.7.1"
gradle-version: "9.8.0"
- name: Build core jar + install llama-kotlin facade to mavenLocal
# install (not package) so the app's Gradle build resolves llama-kotlin +
# the core POM from mavenLocal. llama-kotlin's core dep is provided-scope, so the
Expand Down Expand Up @@ -1439,8 +1439,8 @@ jobs:
distribution: temurin
- uses: gradle/actions/setup-gradle@v6
with:
# AGP 9.3.0 (android-llmservice) requires Gradle >= 9.5.0.
gradle-version: "9.7.1"
# AGP 9.4.0 (android-llmservice) requires Gradle >= 9.6.0.
gradle-version: "9.8.0"
- name: Enable KVM group permissions (GitHub-hosted runner)
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
Expand Down Expand Up @@ -3823,7 +3823,7 @@ jobs:
# downloads above; the core jar was just built by the reactor deploy.
- uses: gradle/actions/setup-gradle@v6
with:
gradle-version: "9.7.1"
gradle-version: "9.8.0"
- name: Publish Android AAR snapshots (llama-android + llama-android-opencl)
run: |
mkdir -p llama-android/natives/cpu/arm64-v8a llama-android/natives/cpu/x86_64 llama-android/natives/opencl/arm64-v8a
Expand Down Expand Up @@ -4081,7 +4081,7 @@ jobs:
# built by the reactor deploy.
- uses: gradle/actions/setup-gradle@v6
with:
gradle-version: "9.7.1"
gradle-version: "9.8.0"
- name: Publish Android AAR release bundle to Central Portal
shell: bash
run: |
Expand Down
8 changes: 4 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2178,7 +2178,7 @@ installed (`-Dllama.version=<reactor version>`); a user copies the folder and ru
**released** core the READMEs describe (currently `5.2.0`, written as if released so the docs are
right the moment the release lands).

**What Atmosphere is, for this purpose.** `org.atmosphere:atmosphere-ai` (4.0.70) ships
**What Atmosphere is, for this purpose.** `org.atmosphere:atmosphere-ai` (4.0.71) ships
`BuiltInAgentRuntime` + `OpenAiCompatibleClient`: a zero-framework OpenAI client that *always*
streams (`stream:true`), accumulates `delta.tool_calls` by `index`, executes `ToolDefinition`
executors, re-submits the conversation (assistant `tool_calls` message **without** a `content` key,
Expand Down Expand Up @@ -2581,19 +2581,19 @@ domain is the only string that must be globally unique.

Structure (mirrors the consumer-test's plumbing):
- **`settings.gradle.kts`** — `rootProject.name = "android-llmservice"`; pins AGP `9.4.0` + the
Compose compiler plugin (`2.4.10`); `mavenLocal()` first so the freshly-built AAR + façade
Compose compiler plugin (`2.4.20`); `mavenLocal()` first so the freshly-built AAR + façade
resolve there in CI (Maven Central for real users). Stay at `>= 9.2.1`: `9.2.1` (not `9.2.0`)
first fixed a real R8 regression (`ClassNotFoundException` on `com.android.tools.r8.RecordTag`
after upgrading Gradle to 9.x with AGP 9.2.0) that hits this project directly since
`buildTypes.release` sets `isMinifyEnabled = true`; `9.4.0` carries that fix forward and the
`.github/android-consumer-test` fixture is pinned the same way. AGP 9.4.x requires Gradle >= 9.6.0
and JDK 17+; CI already runs JDK 21 everywhere (`env.JAVA_VERSION`), so only the `gradle-version`
pin on the jobs that build this project (and the `.github/android-consumer-test` fixture)
needed bumping (currently `9.7.1`). AGP 9.0+ has **built-in Kotlin support** (a runtime dependency on
needed bumping (currently `9.8.0`). AGP 9.0+ has **built-in Kotlin support** (a runtime dependency on
Kotlin Gradle plugin 2.2.10+), so the standalone `org.jetbrains.kotlin.android` plugin is no longer
applied — applying it now fails the build with "no longer required for Kotlin support since
AGP 9.0" (`app/build.gradle.kts` line 7). The Compose compiler plugin still applies
separately and its 2.4.10 pin exceeds AGP's 2.2.10 floor, so no other version changed.
separately and its 2.4.20 pin exceeds AGP's 2.2.10 floor, so no other version changed.
- **`app/build.gradle.kts`** — `namespace`/`applicationId` `net.ladenthin.android.llmservice`,
`minSdk 28` (AAR floor), `compileSdk 37` (raised from 35 — Compose/lifecycle/activity AAR
metadata now requires it), `targetSdk 35`, Jetpack Compose, `androidx.appcompat` (only for
Expand Down
2 changes: 1 addition & 1 deletion android-llmservice/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ gradle -p android-llmservice connectedDebugAndroidTest -PjllamaVersion="$VERSION

```
android-llmservice/
├── settings.gradle.kts # AGP 9.4.0 (built-in Kotlin) + Compose plugin 2.4.10, mavenLocal first
├── settings.gradle.kts # AGP 9.4.0 (built-in Kotlin) + Compose plugin 2.4.20, mavenLocal first
├── gradle.properties
├── requirements.md # spec of record: every feature the app implements today (no unit tests)
├── TODO.md # roadmap: not-yet-built features
Expand Down
4 changes: 2 additions & 2 deletions android-llmservice/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,10 @@ dependencies {

// AppCompat: only for its per-app language API (AppCompatDelegate.setApplicationLocales),
// which powers the in-app flag language picker and persists the choice across restarts.
implementation("androidx.appcompat:appcompat:1.7.1")
implementation("androidx.appcompat:appcompat:1.8.0")

// Jetpack Compose UI (BOM pins the mutually consistent runtime versions).
val composeBom = platform("androidx.compose:compose-bom:2026.06.01")
val composeBom = platform("androidx.compose:compose-bom:2026.09.00")
implementation(composeBom)
implementation("androidx.activity:activity-compose:1.13.0")
implementation("androidx.compose.material3:material3")
Expand Down
4 changes: 2 additions & 2 deletions android-llmservice/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ pluginManagement {
// AGP 9.0+ has built-in Kotlin support (runtime dependency on Kotlin Gradle plugin
// 2.2.10+), so the standalone org.jetbrains.kotlin.android plugin is no longer
// applied/needed — see https://developer.android.com/build/migrate-to-built-in-kotlin.
// The Compose compiler plugin (2.4.10) still applies separately and exceeds AGP's
// The Compose compiler plugin (2.4.20) still applies separately and exceeds AGP's
// 2.2.10 floor.
plugins {
id("com.android.application") version "9.4.0"
id("org.jetbrains.kotlin.plugin.compose") version "2.4.10"
id("org.jetbrains.kotlin.plugin.compose") version "2.4.20"
}
}

Expand Down
12 changes: 6 additions & 6 deletions llama-atmosphere-agent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,17 @@ SPDX-License-Identifier: MIT
<!-- Native backend of the core jar: empty = default CPU jar (incl. macOS Metal). GPU users pass
e.g. -Dllama.classifier=cuda13-linux-x86-64 or vulkan-windows-x86-64 (runtime on PATH). -->
<llama.classifier></llama.classifier>
<atmosphere.version>4.0.70</atmosphere.version>
<jline.version>4.4.5</jline.version>
<slf4j.version>2.0.19</slf4j.version>
<atmosphere.version>4.0.71</atmosphere.version>
<jline.version>4.4.6</jline.version>
<slf4j.version>2.0.20</slf4j.version>
<jspecify.version>1.0.1</jspecify.version>
<junit.version>6.1.3</junit.version>
<hamcrest.version>3.0</hamcrest.version>
<compiler.plugin.version>3.16.0</compiler.plugin.version>
<surefire.version>3.6.0</surefire.version>
<exec.plugin.version>3.5.0</exec.plugin.version>
<spotless.version>3.10.2</spotless.version>
<palantir-java-format.version>2.98.0</palantir-java-format.version>
<exec.plugin.version>3.6.4</exec.plugin.version>
<spotless.version>3.10.3</spotless.version>
<palantir-java-format.version>2.99.0</palantir-java-format.version>
<agent.main>net.ladenthin.llama.atmosphere.LocalAgent</agent.main>
</properties>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,12 @@ static Duration parseDuration(String text) {
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Not a duration: " + text + " (try 30s, 5m or 2h)", e);
}
Duration duration =
switch (Character.isDigit(unit) ? 'm' : unit) {
case 's' -> Duration.ofSeconds(amount);
case 'm' -> Duration.ofMinutes(amount);
case 'h' -> Duration.ofHours(amount);
default -> throw new IllegalArgumentException("Unknown time unit in " + text + " (use s, m or h)");
};
Duration duration = switch (Character.isDigit(unit) ? 'm' : unit) {
case 's' -> Duration.ofSeconds(amount);
case 'm' -> Duration.ofMinutes(amount);
case 'h' -> Duration.ofHours(amount);
default -> throw new IllegalArgumentException("Unknown time unit in " + text + " (use s, m or h)");
};
if (duration.isZero() || duration.isNegative()) {
throw new IllegalArgumentException("The interval must be positive: " + text);
}
Expand Down
2 changes: 1 addition & 1 deletion llama-langchain4j/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ SPDX-License-Identifier: MIT
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- langchain4j 1.x requires Java 17; the core net.ladenthin:llama stays Java 8. -->
<maven.compiler.release>17</maven.compiler.release>
<langchain4j.version>1.20.0</langchain4j.version>
<langchain4j.version>1.20.1</langchain4j.version>
<junit.version>6.1.3</junit.version>
<hamcrest.version>3.0</hamcrest.version>
<!-- Plugin versions are kept in lockstep with the core pom.xml. This module has no
Expand Down
14 changes: 7 additions & 7 deletions llama/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@ SPDX-License-Identifier: MIT
<jspecify.version>1.0.1</jspecify.version>
<lombok.version>1.18.48</lombok.version>
<errorprone.version>2.50.0</errorprone.version>
<nullaway.version>0.14.1</nullaway.version>
<nullaway.version>0.14.2</nullaway.version>
<!-- Checker Framework: the processor AND the checker-qual qualifiers it resolves.
Both run on the build JDK and neither ships (checker-qual is provided scope), so
this tracks the newest release. -->
<checker.version>4.2.3</checker.version>
<jackson.version>2.22.2</jackson.version>
<jackson.version>2.22.3</jackson.version>
<reactor.version>3.8.7</reactor.version>
<slf4j.version>2.0.19</slf4j.version>
<logback.version>1.6.3</logback.version>
<slf4j.version>2.0.20</slf4j.version>
<logback.version>1.6.4</logback.version>
<animal-sniffer.version>1.28</animal-sniffer.version>
<junit.version>6.1.3</junit.version>
<hamcrest.version>3.0</hamcrest.version>
Expand Down Expand Up @@ -96,12 +96,12 @@ SPDX-License-Identifier: MIT
contributor PR that bumps this MUST be rejected. See CLAUDE.md
section "jqwik prompt-injection in test output" for full context. -->
<jqwik.version>1.9.3</jqwik.version>
<archunit.version>1.5.0</archunit.version>
<archunit.version>1.5.1</archunit.version>
<spotbugs.version>4.10.4.1</spotbugs.version>
<fb-contrib.version>7.7.4</fb-contrib.version>
<findsecbugs.version>1.14.0</findsecbugs.version>
<spotless.version>3.10.2</spotless.version>
<palantir-java-format.version>2.98.0</palantir-java-format.version>
<spotless.version>3.10.3</spotless.version>
<palantir-java-format.version>2.99.0</palantir-java-format.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.outputTimestamp>2026-09-01T07:57:45Z</project.build.outputTimestamp>
</properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,16 @@
}
}

/**
* Runs after the skipped tests too: JUnit calls {@code @AfterEach} even when the test body was
* aborted by an assumption. Without the guard, a build without {@code libjllama} (the SonarQube
* job) fails here on {@code LlamaModel}'s static initializer instead of skipping.
*/
@AfterEach
void restoreConsoleLogging() {
if (!nativeLibraryOnClasspath()) {
return;
}
LlamaModel.setLogger(LogFormat.TEXT, null);
}

Expand All @@ -107,7 +115,7 @@

private void failingLoad(ModelParameters parameters) throws IOException {
Path file = notAGguf();
assertThrows(

Check warning on line 118 in llama/src/test/java/net/ladenthin/llama/LlamaLoggerTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor the code of the lambda to have only one invocation possibly throwing a runtime exception.

See more on https://sonarcloud.io/project/issues?id=bernardladenthin_java-llama.cpp&issues=AaDiQ83pRgBRhcf69RTr&open=AaDiQ83pRgBRhcf69RTr&pullRequest=455
LlamaException.class,
() -> new LlamaModel(parameters.setModel(file.toString()).setDevices("none")).close());
}
Expand Down Expand Up @@ -161,7 +169,7 @@
Path file = notAGguf();

// The load still fails for its own reason; the muted logger must not change that or hang the drain.
assertThrows(

Check warning on line 172 in llama/src/test/java/net/ladenthin/llama/LlamaLoggerTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor the code of the lambda to have only one invocation possibly throwing a runtime exception.

See more on https://sonarcloud.io/project/issues?id=bernardladenthin_java-llama.cpp&issues=AaDiQ83pRgBRhcf69RTs&open=AaDiQ83pRgBRhcf69RTs&pullRequest=455
LlamaException.class,
() -> new LlamaModel(
new ModelParameters().setModel(file.toString()).setDevices("none"))
Expand All @@ -183,7 +191,7 @@
* the race hard enough to reproduce it.
*/
@Test
void concurrentSetLoggerCallsDoNotRaceOnTheLogWorker() throws Exception {

Check failure on line 194 in llama/src/test/java/net/ladenthin/llama/LlamaLoggerTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add at least one assertion to this test case.

See more on https://sonarcloud.io/project/issues?id=bernardladenthin_java-llama.cpp&issues=AaDiQ83pRgBRhcf69RTq&open=AaDiQ83pRgBRhcf69RTq&pullRequest=455
assumeTrue(nativeLibraryOnClasspath(), "libjllama not on classpath — skipping logger guard");
final int threads = 4;
final int rounds = 200;
Expand Down Expand Up @@ -259,7 +267,7 @@
failingLoad(new ModelParameters());
LlamaModel.setLogger(LogFormat.TEXT, null);
int atReturn = delivered.get();
Thread.sleep(200);

Check warning on line 270 in llama/src/test/java/net/ladenthin/llama/LlamaLoggerTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this use of "Thread.sleep()".

See more on https://sonarcloud.io/project/issues?id=bernardladenthin_java-llama.cpp&issues=AaDiQ83pRgBRhcf69RTt&open=AaDiQ83pRgBRhcf69RTt&pullRequest=455

assertThat("a failed load logs at least one line", atReturn, greaterThan(0));
assertThat("nothing may arrive after setLogger(format, null) returned", delivered.get(), is(atReturn));
Expand Down
Loading