diff --git a/.github/buildcheck/tests/test_versions.py b/.github/buildcheck/tests/test_versions.py index b2f03ca0a..3504e2538 100644 --- a/.github/buildcheck/tests/test_versions.py +++ b/.github/buildcheck/tests/test_versions.py @@ -4,6 +4,7 @@ import io import os +import tempfile import unittest from unittest import mock @@ -62,6 +63,33 @@ def test_only_coordinates_both_use_and_only_differences(self): ["s:p is 2 here and 9 in r1: bump it in every repository"]) +class GradleKotlinTest(unittest.TestCase): + + def test_plugins_are_read_from_every_kts_file_outside_build_output(self): + with tempfile.TemporaryDirectory() as root: + os.makedirs(os.path.join(root, "app", "build")) + with open(os.path.join(root, "app", "build.gradle.kts"), "w", encoding="utf-8") as f: + f.write('plugins {\n id("com.android.application") version "9.4.0"\n' + ' id("org.jetbrains.kotlin.plugin.compose") version "2.4.20"\n' + ' kotlin("jvm") version "2.4.21"\n}\n') + with open(os.path.join(root, "app", "build", "stale.gradle.kts"), "w", encoding="utf-8") as f: + f.write('kotlin("jvm") version "1.0.0"\n') + self.assertEqual(versions.gradle_kotlin_plugins(root), [ + ("app/build.gradle.kts", "org.jetbrains.kotlin.plugin.compose", "2.4.20"), + ("app/build.gradle.kts", "org.jetbrains.kotlin.jvm", "2.4.21"), + ]) + + def test_a_plugin_behind_the_poms_kotlin_is_a_warning_and_nothing_else_is(self): + own = {"org.jetbrains.kotlin:kotlin-stdlib": {"2.4.21"}, "org.jetbrains.kotlinx:kotlinx-coroutines-core": {"1.11.0"}} + plugins = [("app/build.gradle.kts", "org.jetbrains.kotlin.plugin.compose", "2.4.20"), + ("app/build.gradle.kts", "org.jetbrains.kotlin.jvm", "2.4.21")] + self.assertEqual(versions.compare_gradle_kotlin(own, plugins), [ + "org.jetbrains.kotlin.plugin.compose is 2.4.20 in app/build.gradle.kts and the POMs use Kotlin 2.4.21: " + "Dependabot bumps only the POMs, bump the Gradle plugin with them"]) + self.assertEqual(versions.compare_gradle_kotlin({"a:b": {"1"}}, plugins), []) + self.assertEqual(versions.compare_gradle_kotlin(own, []), []) + + class MainTest(unittest.TestCase): def run_main(self, siblings): @@ -87,6 +115,19 @@ def test_differences_are_warnings_and_never_fail(self): self.assertNotIn("BitcoinAddressFinder:", err) self.assertIn("1 version differences", out) + def test_a_gradle_kotlin_plugin_behind_the_poms_is_reported_with_the_other_warnings(self): + kotlin = pom('org.jetbrains.kotlin' + 'kotlin-stdlib2.4.21') + out, err = io.StringIO(), io.StringIO() + with mock.patch.object(versions, "current_repo", return_value="java-llama.cpp"), \ + mock.patch.object(versions, "read_local", return_value=[kotlin]), \ + mock.patch.object(versions, "gradle_kotlin_plugins", return_value=[ + ("android-llmservice/app/build.gradle.kts", "org.jetbrains.kotlin.plugin.compose", "2.4.20")]): + self.assertEqual(versions.main(["x"], "/nowhere", lambda repo, path: kotlin, out, err), 0) + self.assertIn("::warning::org.jetbrains.kotlin.plugin.compose is 2.4.20 in android-llmservice/app/build.gradle.kts " + "and the POMs use Kotlin 2.4.21", err.getvalue()) + self.assertIn("1 version differences", out.getvalue()) + def test_a_missing_pom_skips_that_file_not_the_repository(self): out, err = io.StringIO(), io.StringIO() bumped = pom('org.junit.jupiter' diff --git a/.github/buildcheck/versions.py b/.github/buildcheck/versions.py index 2935a7614..7b1270d83 100644 --- a/.github/buildcheck/versions.py +++ b/.github/buildcheck/versions.py @@ -12,12 +12,17 @@ `${property}` references resolved -- not property names, which differ between repositories and include values that must differ (the Java release). +It also compares the Kotlin the POMs use with every Kotlin Gradle plugin a `*.gradle.kts` of the +repository pins: Dependabot's maven ecosystem bumps `kotlin.version` and never sees the Gradle files, +which is how a Compose compiler plugin stayed one patch release behind the POMs. + Warnings, never failures: a bump lands in four pull requests, and the first one merged would otherwise turn the other three repositories red. The repository's own artifacts (`net.ladenthin:*`) are left out: a sibling depends on the last RELEASE of java-llama.cpp while java-llama.cpp itself is at the next snapshot. """ +import os import re import sys import urllib.request @@ -28,7 +33,7 @@ NS = "{http://maven.apache.org/POM/4.0.0}" POMS = { "java-llama.cpp": ("pom.xml", "llama/pom.xml", "llama-langchain4j/pom.xml", "llama-kotlin/pom.xml", - "llama-platform/pom.xml", "llama-atmosphere-agent/pom.xml"), + "llama-platform/pom.xml", "llama-atmosphere-agent/pom.xml", "examples/server/pom.xml"), "BitcoinAddressFinder": ("pom.xml",), "srcmorph": ("pom.xml", "srcmorph/pom.xml", "srcmorph-cli/pom.xml", "srcmorph-maven-plugin/pom.xml"), "streambuffer": ("pom.xml",), @@ -42,6 +47,11 @@ CONFIGURED = {"palantirJavaFormat": "com.palantir.javaformat:palantir-java-format"} RAW_URL = "https://raw.githubusercontent.com/{owner}/{repo}/HEAD/{path}" PROPERTY = re.compile(r"\$\{([^}]+)\}") +KOTLIN_GROUP = "org.jetbrains.kotlin" +# `id("org.jetbrains.kotlin.plugin.compose") version "2.4.21"` and `kotlin("jvm") version "2.4.21"` +GRADLE_KOTLIN = re.compile( + r'(?:id\("(org\.jetbrains\.kotlin(?:\.[A-Za-z.]+)?)"\)|kotlin\("([A-Za-z.]+)"\))\s+version\s+"([^"]+)"') +SKIPPED_DIRS = {".git", ".gradle", ".idea", "build", "node_modules", "target"} def coordinates(pom_texts): @@ -94,6 +104,38 @@ def compare(own, others): return warnings +def gradle_kotlin_plugins(root): + """(path, plugin id, version) for every Kotlin Gradle plugin a `*.gradle.kts` below root pins, in + path order; build output and the tools' own directories are not searched.""" + found = [] + for dirpath, dirnames, filenames in os.walk(root): + dirnames[:] = sorted(d for d in dirnames if d not in SKIPPED_DIRS) + for name in sorted(filenames): + if not name.endswith(".gradle.kts"): + continue + path = os.path.join(dirpath, name) + with open(path, encoding="utf-8") as f: + text = f.read() + for match in GRADLE_KOTLIN.finditer(text): + plugin = match.group(1) or f"{KOTLIN_GROUP}.{match.group(2)}" + found.append((os.path.relpath(path, root).replace(os.sep, "/"), plugin, match.group(3))) + return found + + +def compare_gradle_kotlin(own, plugins): + """Warnings for every Kotlin Gradle plugin whose version is not one the POMs use for + `org.jetbrains.kotlin:*`; nothing when the POMs use no Kotlin or no Gradle file pins a plugin.""" + maven = set() + for coordinate, used in own.items(): + if coordinate.startswith(KOTLIN_GROUP + ":"): + maven |= used + if not maven: + return [] + return [f"{plugin} is {version} in {path} and the POMs use Kotlin {', '.join(sorted(maven))}: " + f"Dependabot bumps only the POMs, bump the Gradle plugin with them" + for path, plugin, version in plugins if version not in maven] + + def fetch(repo, path): with urllib.request.urlopen(RAW_URL.format(owner=OWNER, repo=repo, path=path), timeout=20) as response: return response.read().decode("utf-8") @@ -129,7 +171,7 @@ def main(argv, root, fetcher=fetch, out=sys.stdout, err=sys.stderr): print(f"::warning::could not read {sibling}'s {path}: {e}", file=err) if texts: others[sibling] = coordinates(texts) - warnings = compare(own, others) + warnings = compare(own, others) + compare_gradle_kotlin(own, gradle_kotlin_plugins(root)) for warning in warnings: print(f"::warning::{warning}", file=err) shared = set(own).intersection(*others.values()) if others else set() diff --git a/.github/shared-files.sha256 b/.github/shared-files.sha256 index e8e1e8d2f..2d0fa4df2 100644 --- a/.github/shared-files.sha256 +++ b/.github/shared-files.sha256 @@ -22,13 +22,14 @@ cbe504ad081ba31ec16e11c11f879c64179ca7741bf0b1d1318a7fc969ed67dd .github/buildc fe36042fbd5444f0b454ad1304cdafde901dd8cec57cfaba7c7086d996dfee27 .github/buildcheck/tests/test_sharedfiles.py 7fe208dd33184b4543328f97b339c95e23c408b120e6bfa6095de4182aeb9a19 .github/check-release-gate.py 1604ccdea83998814a3c1f98f746272222039867b0c7d692355e61495c1c648b .github/check-shared-files.py -e5f1679dc7151b2676b2f587860bbaa17e1b89b44a5a4e9703eb3499248c4a06 .github/buildcheck/versions.py -d454d33b61089b5f7bd6d439e3e5b58e01e7b01eeba6b4c2f7ed3360bbb158f0 .github/buildcheck/tests/test_versions.py +74b4b18af6c5be2af54048de408ec6e138f37f85b9f9ed2fdef258e270a7c90c .github/buildcheck/versions.py +de437064302f9314028afff00e17fc995e48869e07ee402206d23708c7ed355a .github/buildcheck/tests/test_versions.py 0c78f43dd181f079d35edde7cbf25bb22eac92c907845d8dc8eec78e812aa097 .github/check-versions.py 33c70847b6568604e8725d167a9b1d5910cc2a1a5b01fec7362be31b488ddb02 .github/buildcheck/runscripts.py c4967e3011d474ec43dbc797d113685c0a8a01b7cc52e910a1356273e6a67dc9 .github/buildcheck/tests/test_runscripts.py 7ad8f7258c983c91e67db695e5ab6ea0f9279af007a6aa815f92f0d8a74c2ae4 .github/check-run-scripts.py 7da53fdb9537ccf7d3f3740be31f295bacb914fe186304b9ed8a65fd3d3d413e .github/print-crash-logs.sh +fa1469664cb632e210ff3aa0669f15219d160ef13b486abeb978efade55f330b .github/print-host-info.sh c8c02dc39aeacc154fad74071443c6513666aa94ca9f9c5fab49c5f39dea7ee6 .github/verify-signing-key.sh e0b2a4f331eae326b61c71f78d6272d06d99140a85dedb7710f93402de862466 .github/verify-bytecode-version.sh ab45f5c102b47dd16c325d4d9c283d158ba90c05f484eac45b2767885c4462f9 .github/signing-selftest/build.gradle.kts diff --git a/CHANGELOG.md b/CHANGELOG.md index 40052827c..23b26b8fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -142,6 +142,23 @@ 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 local agent speaks ACP through SDK 0.80.0** (`com.agentclientprotocol:acp-core` + + `acp-json-jackson2`, from 0.18.0 -- upstream's binary-incompatible release of 2026-10-08). The wire + format is unchanged, so `AcpServerTest`, which drives the server with plain JSON, is unchanged too; the + port is mechanical: session updates go out through `sendSessionUpdate` without the discriminator + argument the records now write themselves, `session/request_permission` is a call on the prompt + context's `client()`, `awaitTermination()` replaces `await()`, and the constructors that gained the + protocol's new tool-call `name` carry the agent's tool name there (`read_file`, `shell`, ...), so an + editor can show it next to the title. +- **Build tooling in step with the sibling repositories:** Spotless 3.10.4, Checker Framework 4.3.1, + `exec-maven-plugin` 3.6.4 in `examples/server/pom.xml` -- which `check-versions.py` reads now, so the + drift it had (3.6.2 against the reactor's 3.6.4) can no longer go unseen -- and the Compose compiler + plugin 2.4.21, the Kotlin the POMs already used. `check-versions.py` compares the Kotlin Gradle + plugins of every `*.gradle.kts` with the POMs' Kotlin from now on: Dependabot bumps `kotlin.version` + and never sees the Gradle files. +- **`print-host-info.sh` is a shared file** (`.github/shared-files.sha256`, in all four repositories): + the runner's CPU at the top of every test job, which is how a chosen CPU module or a timing is read + against the hardware the job drew. - **Upgraded the pinned llama.cpp from b11538 to b11556**, one reviewed step (18 commits, 96 files, no `tools/ui` change, so the WebUI is unchanged). All twelve patches apply unchanged and every drop-check still finds its defect. In the range: a request pinned to a **busy** slot (`id_slot`, diff --git a/CLAUDE.md b/CLAUDE.md index 06b158cec..dd3983bc1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -342,7 +342,12 @@ resolved) with the siblings' default branches and **warns** per difference. Warn bump lands in four pull requests and the first one merged must not turn the other three red; the repos' own artifacts (`net.ladenthin:*`) are left out. It compares what is used, not property names: those differ between repos and include values that must differ (`maven.compiler.release`). The POM -list per repo is `versions.POMS` -- a new module's POM goes there, in all four copies. +list per repo is `versions.POMS` -- a new module's POM goes there, in all four copies (here also +`examples/server/pom.xml`, whose `exec-maven-plugin` sat two patch releases behind the reactor's unseen +until it was listed). It also compares the Kotlin Gradle plugins of every `*.gradle.kts` with the Kotlin +the POMs use (`org.jetbrains.kotlin:*`): Dependabot's maven ecosystem bumps `kotlin.version` and never +sees the Gradle files, which is how the Compose compiler plugin stayed at 2.4.20 while the POMs went to +2.4.21. **Run scripts parse (`check-run-scripts.py`).** A cleanup once lost the trailing ` \` of six continued lines in `publish.yml` -- each left a line starting with `||`/`&&`, a syntax error in a step only a @@ -357,7 +362,8 @@ file line), folded and plain values as YAML folds them, `${{ ... }}` becomes a w `workflow.py` it reads the two-space layout these workflows use, not general YAML. Shared today: the `buildcheck` modules above marked shared in -`__init__.py` (+ their tests and CLIs), `print-crash-logs.sh`, `verify-signing-key.sh`, +`__init__.py` (+ their tests and CLIs), `print-crash-logs.sh`, `print-host-info.sh` (the runner's CPU at the top of every +test job, so a timing or a chosen CPU module can be read against the hardware), `verify-signing-key.sh`, `verify-bytecode-version.sh`, `smoke-fatjar-cli.sh` (BAF + srcmorph; `sign-fatjars.sh` is srcmorph's alone since jllama ships no fat jar), the signing self-test, `lombok.config`, the issue/PR templates, `CODE_OF_CONDUCT.md`, `claude.yml`, `claude-code-review.yml`, `codeql.yml`, `scorecard.yml`, `reuse.yml`, `osv-scanner.yml`, diff --git a/android-llmservice/CLAUDE.md b/android-llmservice/CLAUDE.md index 851e3799d..62febc185 100644 --- a/android-llmservice/CLAUDE.md +++ b/android-llmservice/CLAUDE.md @@ -22,7 +22,7 @@ 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.20`); `mavenLocal()` first so the freshly-built AAR + façade + Compose compiler plugin (`2.4.21`); `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 @@ -34,7 +34,7 @@ Structure (mirrors the consumer-test's plumbing): 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.20 pin exceeds AGP's 2.2.10 floor, so no other version changed. + separately and its 2.4.21 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 diff --git a/android-llmservice/README.md b/android-llmservice/README.md index 65d8e0a8f..0ae994480 100644 --- a/android-llmservice/README.md +++ b/android-llmservice/README.md @@ -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.20, mavenLocal first +├── settings.gradle.kts # AGP 9.4.0 (built-in Kotlin) + Compose plugin 2.4.21, 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 diff --git a/android-llmservice/settings.gradle.kts b/android-llmservice/settings.gradle.kts index 841b400a8..c920c14c6 100644 --- a/android-llmservice/settings.gradle.kts +++ b/android-llmservice/settings.gradle.kts @@ -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.20) still applies separately and exceeds AGP's + // The Compose compiler plugin (2.4.21) 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.20" + id("org.jetbrains.kotlin.plugin.compose") version "2.4.21" } } diff --git a/examples/server/pom.xml b/examples/server/pom.xml index 85b47ac1e..44f477961 100644 --- a/examples/server/pom.xml +++ b/examples/server/pom.xml @@ -57,7 +57,7 @@ SPDX-License-Identifier: MIT org.codehaus.mojo exec-maven-plugin - 3.6.2 + 3.6.4 ${llama.main} diff --git a/llama-atmosphere-agent/CLAUDE.md b/llama-atmosphere-agent/CLAUDE.md index e18c387ca..5029213c9 100644 --- a/llama-atmosphere-agent/CLAUDE.md +++ b/llama-atmosphere-agent/CLAUDE.md @@ -855,7 +855,10 @@ object before `buildAsync`**, or the handshake message races the listener into a `request(1)` is never called — a flaky test that looked like a server bug. **`--acp` (`AcpServer`, `AcpFrontend`).** The ACP Java SDK (`com.agentclientprotocol:acp-core` + -`acp-json-jackson2`, 0.18.0) over `StdioAcpAgentTransport`. Its sync handlers run on the SDK's own pool, +`acp-json-jackson2`, 0.80.0 -- binary-incompatible with 0.18.0, ported 2026-10-11: session updates go out +through `sendSessionUpdate` without the discriminator argument the records write themselves, +`session/request_permission` is a call on `context.client()`, `awaitTermination()` replaces `await()`, and +the tool-call `name` the protocol added carries the agent's tool name) over `StdioAcpAgentTransport`. Its sync handlers run on the SDK's own pool, so a blocking `session/prompt` does not block `session/cancel` or the answer to a permission request. One `AgentSession` per ACP session, built for the editor's `cwd` (`AgentOptions.withWorkspace`); the model endpoint is opened once per process. **stdout is the protocol**: `run()` keeps the real stdout for diff --git a/llama-atmosphere-agent/pom.xml b/llama-atmosphere-agent/pom.xml index fec2085e5..30bb12f68 100644 --- a/llama-atmosphere-agent/pom.xml +++ b/llama-atmosphere-agent/pom.xml @@ -70,7 +70,7 @@ SPDX-License-Identifier: MIT 4.0.72 4.4.7 12.1.14 - 0.18.0 + 0.80.0 2.0.20 1.0.1 6.1.3 @@ -84,7 +84,7 @@ SPDX-License-Identifier: MIT 3.2.8 0.11.0 3.6.4 - 3.10.3 + 3.10.4 2.102.0 net.ladenthin.llama.atmosphere.LocalAgent diff --git a/llama-atmosphere-agent/src/main/java/net/ladenthin/llama/atmosphere/AcpFrontend.java b/llama-atmosphere-agent/src/main/java/net/ladenthin/llama/atmosphere/AcpFrontend.java index 54db13779..7d1f44f90 100644 --- a/llama-atmosphere-agent/src/main/java/net/ladenthin/llama/atmosphere/AcpFrontend.java +++ b/llama-atmosphere-agent/src/main/java/net/ladenthin/llama/atmosphere/AcpFrontend.java @@ -146,19 +146,18 @@ private synchronized void toolStarted(String tool, @Nullable Map String id = "call_" + toolCounter.incrementAndGet(); openTools.addLast(new String[] {id, tool}); output.clear(); - context.sendUpdate( - sessionId, - new AcpSchema.ToolCall( - "tool_call", - id, - title(tool, arguments), - kind(tool), - AcpSchema.ToolCallStatus.IN_PROGRESS, - null, - locations(arguments), - arguments, - null, - null)); + context.sendSessionUpdate(new AcpSchema.ToolCall( + "tool_call", + id, + title(tool, arguments), + tool, + kind(tool), + AcpSchema.ToolCallStatus.IN_PROGRESS, + null, + locations(arguments), + arguments, + null, + null)); } private synchronized void toolEnded(String tool, String result, AcpSchema.ToolCallStatus status) { @@ -166,10 +165,8 @@ private synchronized void toolEnded(String tool, String result, AcpSchema.ToolCa if (id == null) { return; } - context.sendUpdate( - sessionId, - new AcpSchema.ToolCallUpdateNotification( - "tool_call_update", id, null, null, status, text(cut(result)), null, null, result, null)); + context.sendSessionUpdate(new AcpSchema.ToolCallUpdateNotification( + "tool_call_update", id, null, null, null, status, text(cut(result)), null, null, result, null)); } private @Nullable String takeOpen(String tool) { @@ -217,25 +214,29 @@ private ApprovalResolution askEditor(PendingApproval approval) { AcpSchema.ToolCallUpdate call = new AcpSchema.ToolCallUpdate( id != null ? id : "call_" + toolCounter.incrementAndGet(), title(approval.toolName(), approval.arguments()), + approval.toolName(), kind(approval.toolName()), AcpSchema.ToolCallStatus.PENDING, null, locations(approval.arguments()), approval.arguments(), + null, null); AcpSchema.RequestPermissionResponse answer; try { - answer = context.requestPermission(new AcpSchema.RequestPermissionRequest( - sessionId, - call, - List.of( - new AcpSchema.PermissionOption("allow", "Allow", AcpSchema.PermissionOptionKind.ALLOW_ONCE), - new AcpSchema.PermissionOption( - "always", - "Allow all (switch to auto mode)", - AcpSchema.PermissionOptionKind.ALLOW_ALWAYS), - new AcpSchema.PermissionOption( - "reject", "Reject", AcpSchema.PermissionOptionKind.REJECT_ONCE)))); + answer = context.client() + .requestPermission(new AcpSchema.RequestPermissionRequest( + sessionId, + call, + List.of( + new AcpSchema.PermissionOption( + "allow", "Allow", AcpSchema.PermissionOptionKind.ALLOW_ONCE), + new AcpSchema.PermissionOption( + "always", + "Allow all (switch to auto mode)", + AcpSchema.PermissionOptionKind.ALLOW_ALWAYS), + new AcpSchema.PermissionOption( + "reject", "Reject", AcpSchema.PermissionOptionKind.REJECT_ONCE)))); } catch (RuntimeException e) { // no answer (the editor went away, or the request timed out): the same as nobody to ask return ApprovalResolution.deny(); @@ -247,9 +248,7 @@ private ApprovalResolution askEditor(PendingApproval approval) { case "allow" -> ApprovalResolution.approve(); case "always" -> { agent.mode(ApprovalMode.AUTO); - context.sendUpdate( - sessionId, - new AcpSchema.CurrentModeUpdate("current_mode_update", AcpServer.modeId(ApprovalMode.AUTO))); + context.sendSessionUpdate(new AcpSchema.CurrentModeUpdate(AcpServer.modeId(ApprovalMode.AUTO))); yield ApprovalResolution.approve(); } default -> ApprovalResolution.deny(); @@ -274,19 +273,18 @@ public synchronized void commandOutput(String line) { return; } lastOutputPush = now; - context.sendUpdate( - sessionId, - new AcpSchema.ToolCallUpdateNotification( - "tool_call_update", - id, - null, - null, - AcpSchema.ToolCallStatus.IN_PROGRESS, - text(String.join("\n", output)), - null, - null, - null, - null)); + context.sendSessionUpdate(new AcpSchema.ToolCallUpdateNotification( + "tool_call_update", + id, + null, + null, + null, + AcpSchema.ToolCallStatus.IN_PROGRESS, + text(String.join("\n", output)), + null, + null, + null, + null)); } private static List text(String value) { diff --git a/llama-atmosphere-agent/src/main/java/net/ladenthin/llama/atmosphere/AcpServer.java b/llama-atmosphere-agent/src/main/java/net/ladenthin/llama/atmosphere/AcpServer.java index 6d74c1d59..0fa8fa5ad 100644 --- a/llama-atmosphere-agent/src/main/java/net/ladenthin/llama/atmosphere/AcpServer.java +++ b/llama-atmosphere-agent/src/main/java/net/ladenthin/llama/atmosphere/AcpServer.java @@ -69,7 +69,7 @@ private AcpServer(Function sessionFactory, InputStream in, O AgentSession session = sessionFactory.apply(Path.of(request.cwd())); sessions.put(id, session); announceCommandsSoon(self[0], id); - return new AcpSchema.NewSessionResponse(id, modes(session.mode()), null); + return new AcpSchema.NewSessionResponse(id, modes(session.mode())); }) .promptHandler(this::prompt) .setSessionModeHandler(request -> { @@ -126,7 +126,7 @@ static int run(AgentOptions options, PrintStream err) throws Exception { AcpServer.class.getPackage().getImplementationVersion() == null ? "dev" : AcpServer.class.getPackage().getImplementationVersion())) { - server.agent.await(); + server.agent.awaitTermination(); } } return 0; @@ -145,9 +145,7 @@ private AcpSchema.PromptResponse prompt(AcpSchema.PromptRequest request, SyncPro return new AcpSchema.PromptResponse(AcpSchema.StopReason.CANCELLED); } if (session.mode() != before) { - context.sendUpdate( - request.sessionId(), - new AcpSchema.CurrentModeUpdate("current_mode_update", modeId(session.mode()))); + context.sendSessionUpdate(new AcpSchema.CurrentModeUpdate(modeId(session.mode()))); } return new AcpSchema.PromptResponse( session.stopRequested() ? AcpSchema.StopReason.CANCELLED : AcpSchema.StopReason.END_TURN); @@ -245,8 +243,7 @@ private static void announceCommandsSoon(AcpSyncAgent agent, String sessionId) { // The session id reaches the editor with the response to session/new; an update that // arrives before it names a session the editor does not know yet. Thread.sleep(100); - agent.sendSessionUpdate( - sessionId, new AcpSchema.AvailableCommandsUpdate("available_commands_update", commands())); + agent.sendSessionUpdate(sessionId, new AcpSchema.AvailableCommandsUpdate(commands())); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (RuntimeException e) { diff --git a/llama/pom.xml b/llama/pom.xml index a8a1291fd..6b50b452c 100644 --- a/llama/pom.xml +++ b/llama/pom.xml @@ -61,7 +61,7 @@ SPDX-License-Identifier: MIT - 4.3.0 + 4.3.1 3.8.7 2.0.20 @@ -99,7 +99,7 @@ SPDX-License-Identifier: MIT 4.10.4.1 7.7.4 1.14.0 - 3.10.3 + 3.10.4 2.102.0 UTF-8 2026-09-01T07:57:45Z