[java] Add linux-x64 implementation of in process Copilot CLI - #2301
Open
edburns wants to merge 1 commit into
Open
[java] Add linux-x64 implementation of in process Copilot CLI#2301edburns wants to merge 1 commit into
edburns wants to merge 1 commit into
Conversation
Squashed from PR #2295 (branch edburns/…-review-02). Includes Java multi-module Maven restructure, copilot-native submodule for bundling the Rust CLI runtime, codegen updates, and related workflow changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 90cbda40-cda3-4ecd-b381-9f9ba0573d0a
Contributor
Cross-SDK Consistency Review ✅This PR adds the in-process FFI runtime connection to the Java SDK, bringing it to parity with all other SDK implementations. Feature parity check
API naming consistencyThe Java implementation follows the expected language idioms:
ConclusionNo cross-SDK consistency issues found. This PR completes the in-process FFI feature across all six SDK languages.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Supercedes #2295 .
This PR is the roll up of the agentic work done in the subtasks of #2166 . At each step of those subtasks, the CI was clean and all reviews were applied as appropriate.
PR 2295 — Reviewer's guide: In-process FFI runtime for the Java SDK
TL;DR
This PR does for the Java SDK what #1901 did for .NET and #1915 did for Rust: it adds an in-process connection mode that loads the Copilot runtime (
runtime.nodecdylib) as a native library via JNA, eliminating the need for a separate CLI child process. Currently scoped to linux-x64 only; the entire in-process API surface is marked@CopilotExperimental.The PR also restructures the Java Maven project from a single module into a multi-module reactor to support publishing the native runtime binaries as separate classifier JARs alongside the existing SDK JAR.
What's in the native binary, where does it come from, and how is it loaded?
The binary:
runtime.nodeDespite the
.nodeextension (a napi-rs naming convention),runtime.nodeis an ordinary platform-specific shared library (.soon Linux). It is a Rustcdylibproduced by thesrc/runtimecrate ingithub/copilot-agent-runtime. It exposes two front doors:extern "C"lifecycle/transport entry points callable by any language via FFI without Node.js.The 5 C ABI entry points are:
copilot_runtime_host_startcopilot_runtime_host_shutdowncopilot_runtime_connection_openon_outboundcallback for runtime→SDK data delivery.copilot_runtime_connection_writecopilot_runtime_connection_closeAll JSON-RPC methods travel as data through this fixed 5-function transport; the export surface never changes as the method set grows.
Where it comes from (build-time)
The
copilot-nativeMaven module's build fetches the binary from npm duringgenerate-resources:fetch-native.mjsreads the pinned version and SHA-512 integrity hash for@github/copilot-linux-x64fromnodejs/package-lock.json.npm packto download the exact tarball, verifies it against the integrity hash.runtime.nodeand thecopilotCLI executable into a staging directory.maven-jar-pluginpackages them into a classifier JAR (copilot-sdk-java-runtime-<version>-linux-x64.jar) with the layoutnative/linux-x64/runtime.node.How it's loaded (runtime)
PlatformDetector(303 lines) determines the classifier usingos.name,os.arch, and on Linux, ELF PT_INTERP parsing to distinguish glibc vs musl — no subprocesses, no heuristics.NativeRuntimeLoader(466 lines) resolves the binary in this order:COPILOT_CLI_PATHenv var → checks forruntime.nodealongside the CLI.native/<classifier>/runtime.node→ extracts atomically to~/.copilot/runtime-cache/<version>/<classifier>/runtime.node.runtime.nodealongside the bundledcopilotexecutable.JnaNativeBinding(253 lines) loads the library by absolute path via JNA and maps each C ABI export. Enforces a one-library-per-process invariant (library handle isstatic, never unloaded). Duplicate loads from the same path are silently accepted; different paths are rejected.FfiRuntimeHost(349 lines) orchestrates the lifecycle: starts the host, opens a connection, bridges the bidirectional JSON-RPC transport. Theon_outboundcallback (invoked by native threads) feeds received data into aQueueInputStreamthat the SDK's existingJsonRpcClientreads from.Structural changes
Multi-module Maven reactor
The single-module
java/pom.xmlis now a parent POM (pompackaging) with two submodules:java/pom.xmlcopilot-sdk-java-parentmaven.deploy.skip=true). Holds thereleaseprofile (GPG signing) inherited by all submodules.java/sdk/copilot-sdk-javajava/src/→java/sdk/src/.java/copilot-native/copilot-sdk-java-runtimelinux-x64only, ~20-26 MB).Consumer dependency declaration
Consumer usage
New public API surface (all
@CopilotExperimental)RuntimeConnection(sealed class)forStdio(),forTcp(),forUri(String),forInProcess().StdioRuntimeConnectionTcpRuntimeConnectionUriRuntimeConnectionInProcessRuntimeConnectionCopilotClientOptions.setConnection()/getConnection()The
RuntimeConnectionAPI replaces the previous pattern of settingcliUrl,cliPath,useStdio,port, andtcpConnectionTokenindividually. When aRuntimeConnectionis set, it takes precedence; conflicting legacy options causeIllegalArgumentException.New internal packages
com.github.copilot.ffi(9 classes, ~1,752 lines)FfiRuntimeHostJnaNativeBindingNativeBindingNativeRuntimeLoaderruntime.node: env var → classpath → cache. Atomic extraction with file locking.PlatformDetectorQueueInputStreamFfiOutputStreamconnection_write.OutboundCallbackon_outbound.ReaderThreadFactoryTests for FFI (6 files, ~2,054 lines)
FfiRuntimeHostTestJnaNativeBindingTestNativeRuntimeLoaderTestPlatformDetectorTestQueueInputStreamTestInProcessTransportITCI/workflow changes
java-sdk-inprocessinjava-sdk-tests.yml: runsmvn clean verify -Pinprocesson ubuntu-latest (linux-x64). Usescontinue-on-error: truewhile experimental.java/target/→java/sdk/target/for surefire/failsafe reports and coverage data.-pl sdkto restrict to the SDK module (the native module requires JDK 25 build tools).java/sdk/module layout.✅ Note that the existing java publishing jobs will continue to work as currently written.
Key design decisions (from ADR-007)
JNA over Panama FFM: JNA supports the Java 17 baseline with zero consumer configuration. Panama FFM requires Java 22+ and
--enable-native-accessflags. Performance difference is irrelevant (JSON-RPC I/O dominates).Per-platform classifier JARs over monolithic JAR: A monolithic JAR with all 6 common platforms would be ~132 MB. Classifier JARs let consumers pull only their target platform (~20-26 MB each). An uber-JAR can be assembled via
maven-assembly-pluginif needed.Library-never-unloads pattern: The loaded native library is held in a
staticfield and never released. Native worker threads outlive any individualFfiRuntimeHostinstance; unloading would crash.One library per process: Enforced by a process-wide guard, consistent with Rust, .NET, Go, and Python SDK implementations.
Diff statistics
java/src/→java/sdk/src/)copilot-native/pom.xml(214 lines),fetch-native.mjs(114 lines)Recommended review order
java/docs/adr/adr-007-native-bundling-strategy.md— context, options considered, decision rationale.rpc/RuntimeConnection.java,rpc/InProcessRuntimeConnection.java, andrpc/CopilotClientOptions.java(thesetConnection/getConnectionmethods).NativeBinding.java→JnaNativeBinding.java→FfiRuntimeHost.java→NativeRuntimeLoader.java→PlatformDetector.java.copilot-native/pom.xmlandcopilot-native/scripts/fetch-native.mjs.java/pom.xml(parent) andjava/sdk/pom.xml(child)..github/workflows/java-sdk-tests.yml(new inprocess job, path updates).ffi/test package ande2e/InProcessTransportIT.java.Implementation details.
Implemented agentically using https://aka.ms/coreai/shepherd-task/slides .