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
319 changes: 315 additions & 4 deletions java/sdk/src/main/java/com/github/copilot/CopilotClient.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
public final class NativeRuntimeLoader {

static final String RUNTIME_FILENAME = "runtime.node";
static final String COPILOT_CLI_PATH_ENV = "COPILOT_CLI_PATH";
/** Environment variable that overrides where the runtime is loaded from. */
public static final String COPILOT_CLI_PATH_ENV = "COPILOT_CLI_PATH";
static final String VERSION_RESOURCE = "copilot-runtime.properties";

/**
Expand Down Expand Up @@ -113,7 +114,7 @@ public static Path resolve() throws IOException {
String classifier = PlatformDetector.detectClassifier();
String version = readVersion(loader);
Path cacheBase = defaultCacheBase();
return resolve(null, findCliOnPath(), cacheBase, loader, classifier, version);
return resolve(null, findRuntimeOnPath(), cacheBase, loader, classifier, version);
}

/**
Expand Down Expand Up @@ -314,7 +315,12 @@ private static void copyResourceToTemp(URL resource, String resourcePath, Path t
}
}

private static String findCliOnPath() {
/**
* Finds the runtime executable on the {@code PATH}.
*
* @return the absolute path, or {@code null} if none was found
*/
public static String findRuntimeOnPath() {
String pathValue = System.getenv("PATH");
if (pathValue == null || pathValue.isBlank()) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public class CopilotClientOptions {
private String[] cliArgs;
private String cliPath;
private String cliUrl;
private RuntimeConnection connection;
private String copilotHome;
private String cwd;
private Map<String, String> environment;
Expand Down Expand Up @@ -204,6 +205,39 @@ public CopilotClientOptions setCliUrl(String cliUrl) {
return this;
}

/**
* Gets the connection that selects how the client reaches the Copilot runtime.
*
* @return the connection, or {@code null} to infer the transport from
* {@link #isUseStdio()}, {@link #getCliUrl()} and {@link #getCliPath()}
*/
@JsonIgnore
public RuntimeConnection getConnection() {
return connection;
}

/**
* Sets the connection that selects how the client reaches the Copilot runtime.
* <p>
* When set, the connection takes precedence over the transport-selecting
* options {@link #setUseStdio(boolean)}, {@link #setCliUrl(String)},
* {@link #setCliPath(String)}, {@link #setPort(int)} and
* {@link #setTcpConnectionToken(String)}; combining a connection with
* conflicting values for any of those options makes the client constructor
* throw {@link IllegalArgumentException}. Values that match what the connection
* implies are accepted, so the same options instance can be reused across
* multiple client constructions.
*
* @param connection
* the connection, or {@code null} to infer the transport from the
* individual transport options
* @return this options instance for method chaining
*/
public CopilotClientOptions setConnection(RuntimeConnection connection) {
this.connection = connection;
return this;
}

/**
* Gets the base directory for Copilot data (session state, config, etc.).
*
Expand Down Expand Up @@ -754,6 +788,7 @@ public CopilotClientOptions clone() {
copy.cliArgs = this.cliArgs != null ? this.cliArgs.clone() : null;
copy.cliPath = this.cliPath;
copy.cliUrl = this.cliUrl;
copy.connection = this.connection;
copy.copilotHome = this.copilotHome;
copy.cwd = this.cwd;
copy.environment = this.environment != null ? new java.util.HashMap<>(this.environment) : null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------------------------------------------*/

package com.github.copilot.rpc;

import com.github.copilot.CopilotExperimental;

/**
* Hosts the runtime in-process by loading its native library and communicating
* over the C ABI — no child process is spawned by the SDK for JSON-RPC
* transport. Construct with {@link RuntimeConnection#forInProcess()}.
* <p>
* The in-process runtime is self-contained: it carries everything it needs and
* requires no external installation. Because it runs inside the host process,
* per-client process settings ({@code environment}, {@code telemetry},
* {@code cwd}, and {@code cliArgs}) are rejected; configure those on the host
* process instead, or use a child-process connection.
*
* @since 1.0.0
*/
@CopilotExperimental
public final class InProcessRuntimeConnection extends RuntimeConnection {

InProcessRuntimeConnection() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------------------------------------------*/

package com.github.copilot.rpc;

import com.github.copilot.CopilotExperimental;

/**
* Configures how a {@link com.github.copilot.CopilotClient} connects to the
* Copilot runtime.
* <p>
* Instances are created through the factory methods on this class and assigned
* with {@link CopilotClientOptions#setConnection(RuntimeConnection)}:
*
* <pre>{@code
* // Spawn a runtime child process and talk over stdin/stdout (the default).
* new CopilotClientOptions().setConnection(RuntimeConnection.forStdio());
*
* // Spawn a runtime child process listening on a TCP socket.
* new CopilotClientOptions().setConnection(RuntimeConnection.forTcp().setPath("/usr/local/bin/copilot"));
*
* // Connect to an already-running runtime.
* new CopilotClientOptions().setConnection(RuntimeConnection.forUri("localhost:3000"));
* }</pre>
*
* @since 1.0.0
*/
public abstract sealed class RuntimeConnection
permits StdioRuntimeConnection, TcpRuntimeConnection, UriRuntimeConnection, InProcessRuntimeConnection {

RuntimeConnection() {
}

/**
* Spawns a runtime child process and communicates over its stdin/stdout. This
* is the default when no connection is configured.
*
* @return a new stdio connection
*/
public static StdioRuntimeConnection forStdio() {
return new StdioRuntimeConnection();
}

/**
* Spawns a runtime child process at the given path and communicates over its
* stdin/stdout.
*
* @param path
* path to the runtime executable, or {@code null} to use the runtime
* discovered on the {@code PATH}
* @return a new stdio connection
*/
public static StdioRuntimeConnection forStdio(String path) {
return new StdioRuntimeConnection().setPath(path);
}

/**
* Spawns a runtime child process that listens on a TCP socket and connects to
* it.
*
* @return a new TCP connection
*/
public static TcpRuntimeConnection forTcp() {
return new TcpRuntimeConnection();
}

/**
* Connects to an already-running runtime at the given URL.
*
* @param url
* URL of the runtime to connect to; accepts {@code "port"},
* {@code "host:port"}, or a full URL
* @return a new URI connection
* @throws IllegalArgumentException
* if {@code url} is {@code null} or empty
*/
public static UriRuntimeConnection forUri(String url) {
return new UriRuntimeConnection(url);
}

/**
* Hosts the runtime in-process by loading its native library and communicating
* over the C ABI — no child process is spawned by the SDK for JSON-RPC
* transport.
*
* @return a new in-process connection
*/
@CopilotExperimental
public static InProcessRuntimeConnection forInProcess() {
return new InProcessRuntimeConnection();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------------------------------------------*/

package com.github.copilot.rpc;

import java.util.ArrayList;
import java.util.List;

/**
* Spawns a runtime child process and communicates over its stdin/stdout.
* Construct with {@link RuntimeConnection#forStdio()} or
* {@link RuntimeConnection#forStdio(String)}.
*
* @since 1.0.0
*/
public final class StdioRuntimeConnection extends RuntimeConnection {

private String path;
private List<String> args;

StdioRuntimeConnection() {
}

/**
* Returns the path to the runtime executable.
*
* @return the path, or {@code null} to use the runtime discovered on the
* {@code PATH}
*/
public String getPath() {
return path;
}

/**
* Sets the path to the runtime executable.
*
* @param path
* the path, or {@code null} to use the runtime discovered on the
* {@code PATH}
* @return this instance for method chaining
*/
public StdioRuntimeConnection setPath(String path) {
this.path = path;
return this;
}

/**
* Returns the extra command-line arguments passed to the runtime process.
*
* @return the arguments, or {@code null} if none are configured
*/
public List<String> getArgs() {
return args;
}

/**
* Sets extra command-line arguments passed to the runtime process.
*
* @param args
* the arguments, or {@code null} for none
* @return this instance for method chaining
*/
public StdioRuntimeConnection setArgs(List<String> args) {
this.args = args == null ? null : new ArrayList<>(args);
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------------------------------------------*/

package com.github.copilot.rpc;

import java.util.ArrayList;
import java.util.List;

/**
* Spawns a runtime child process listening on a TCP socket and connects to it.
* Construct with {@link RuntimeConnection#forTcp()}.
*
* @since 1.0.0
*/
public final class TcpRuntimeConnection extends RuntimeConnection {

private String path;
private int port;
private String connectionToken;
private List<String> args;

TcpRuntimeConnection() {
}

/**
* Returns the path to the runtime executable.
*
* @return the path, or {@code null} to use the runtime discovered on the
* {@code PATH}
*/
public String getPath() {
return path;
}

/**
* Sets the path to the runtime executable.
*
* @param path
* the path, or {@code null} to use the runtime discovered on the
* {@code PATH}
* @return this instance for method chaining
*/
public TcpRuntimeConnection setPath(String path) {
this.path = path;
return this;
}

/**
* Returns the TCP port the spawned runtime listens on.
*
* @return the port, or {@code 0} to auto-allocate a free port
*/
public int getPort() {
return port;
}

/**
* Sets the TCP port the spawned runtime listens on.
*
* @param port
* the port, or {@code 0} (the default) to auto-allocate a free port
* @return this instance for method chaining
*/
public TcpRuntimeConnection setPort(int port) {
this.port = port;
return this;
}

/**
* Returns the shared secret the SDK sends to the spawned runtime to
* authenticate the TCP connection.
*
* @return the token, or {@code null} to generate one automatically
*/
public String getConnectionToken() {
return connectionToken;
}

/**
* Sets the shared secret the SDK sends to the spawned runtime to authenticate
* the TCP connection.
*
* @param connectionToken
* the token, or {@code null} to generate one automatically
* @return this instance for method chaining
*/
public TcpRuntimeConnection setConnectionToken(String connectionToken) {
this.connectionToken = connectionToken;
return this;
}

/**
* Returns the extra command-line arguments passed to the runtime process.
*
* @return the arguments, or {@code null} if none are configured
*/
public List<String> getArgs() {
return args;
}

/**
* Sets extra command-line arguments passed to the runtime process.
*
* @param args
* the arguments, or {@code null} for none
* @return this instance for method chaining
*/
public TcpRuntimeConnection setArgs(List<String> args) {
this.args = args == null ? null : new ArrayList<>(args);
return this;
}
}
Loading
Loading