Skip to content

Commit 7378690

Browse files
Copilotedburns
andauthored
Port copilotHome, tcpConnectionToken, instructionDirectories, continuePendingWork, and MCP OAuth fields from reference implementation
Co-authored-by: edburns <75821+edburns@users.noreply.github.com>
1 parent 88a37e8 commit 7378690

10 files changed

Lines changed: 320 additions & 1 deletion

src/main/java/com/github/copilot/sdk/CliServerManager.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,19 @@ ProcessInfo startCliServer() throws IOException, InterruptedException {
115115
pb.environment().put("COPILOT_SDK_AUTH_TOKEN", options.getGitHubToken());
116116
}
117117

118+
// Set COPILOT_HOME if configured
119+
if (options.getCopilotHome() != null && !options.getCopilotHome().isEmpty()) {
120+
pb.environment().put("COPILOT_HOME", options.getCopilotHome());
121+
}
122+
123+
// Set connection token for TCP mode
124+
if (options.getTcpConnectionToken() != null && !options.getTcpConnectionToken().isEmpty()) {
125+
pb.environment().put("COPILOT_CONNECTION_TOKEN", options.getTcpConnectionToken());
126+
} else if (!options.isUseStdio() && (options.getCliUrl() == null || options.getCliUrl().isEmpty())) {
127+
// Auto-generate connection token for SDK-spawned TCP mode
128+
pb.environment().put("COPILOT_CONNECTION_TOKEN", java.util.UUID.randomUUID().toString());
129+
}
130+
118131
// Set telemetry environment variables if configured
119132
if (options.getTelemetry() != null) {
120133
var telemetry = options.getTelemetry();

src/main/java/com/github/copilot/sdk/CopilotClient.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ public CopilotClient() {
104104
public CopilotClient(CopilotClientOptions options) {
105105
this.options = options != null ? options : new CopilotClientOptions();
106106

107-
// When cliUrl is set, auto-correct useStdio since we're connecting via TCP
107+
// When cliUrl is set, force TCP mode (we connect to an external server, not
108+
// spawn one)
108109
if (this.options.getCliUrl() != null && !this.options.getCliUrl().isEmpty()) {
109110
this.options.setUseStdio(false);
110111
}
@@ -115,6 +116,16 @@ public CopilotClient(CopilotClientOptions options) {
115116
throw new IllegalArgumentException("CliUrl is mutually exclusive with CliPath");
116117
}
117118

119+
// Validate TcpConnectionToken
120+
if (this.options.getTcpConnectionToken() != null) {
121+
if (this.options.getTcpConnectionToken().isEmpty()) {
122+
throw new IllegalArgumentException("TcpConnectionToken must be a non-empty string");
123+
}
124+
if (this.options.isUseStdio()) {
125+
throw new IllegalArgumentException("TcpConnectionToken cannot be used with UseStdio = true");
126+
}
127+
}
128+
118129
// Validate auth options with external server
119130
if (this.options.getCliUrl() != null && !this.options.getCliUrl().isEmpty()
120131
&& (this.options.getGitHubToken() != null || this.options.getUseLoggedInUser() != null)) {

src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config, String sess
122122
request.setAgent(config.getAgent());
123123
request.setInfiniteSessions(config.getInfiniteSessions());
124124
request.setSkillDirectories(config.getSkillDirectories());
125+
request.setInstructionDirectories(config.getInstructionDirectories());
125126
request.setDisabledSkills(config.getDisabledSkills());
126127
request.setConfigDir(config.getConfigDir());
127128
request.setEnableConfigDiscovery(config.getEnableConfigDiscovery());
@@ -192,13 +193,15 @@ static ResumeSessionRequest buildResumeRequest(String sessionId, ResumeSessionCo
192193
request.setConfigDir(config.getConfigDir());
193194
request.setEnableConfigDiscovery(config.getEnableConfigDiscovery());
194195
request.setDisableResume(config.isDisableResume() ? true : null);
196+
request.setContinuePendingWork(config.getContinuePendingWork());
195197
request.setStreaming(config.isStreaming() ? true : null);
196198
request.setIncludeSubAgentStreamingEvents(config.getIncludeSubAgentStreamingEvents());
197199
request.setMcpServers(config.getMcpServers());
198200
request.setCustomAgents(config.getCustomAgents());
199201
request.setDefaultAgent(config.getDefaultAgent());
200202
request.setAgent(config.getAgent());
201203
request.setSkillDirectories(config.getSkillDirectories());
204+
request.setInstructionDirectories(config.getInstructionDirectories());
202205
request.setDisabledSkills(config.getDisabledSkills());
203206
request.setInfiniteSessions(config.getInfiniteSessions());
204207
request.setModelCapabilities(config.getModelCapabilities());

src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,15 @@ public class CopilotClientOptions {
4444
private String[] cliArgs;
4545
private String cliPath;
4646
private String cliUrl;
47+
private String copilotHome;
4748
private String cwd;
4849
private Map<String, String> environment;
4950
private Executor executor;
5051
private String gitHubToken;
5152
private String logLevel = "info";
5253
private Supplier<CompletableFuture<List<ModelInfo>>> onListModels;
5354
private int port;
55+
private String tcpConnectionToken;
5456
private TelemetryConfig telemetry;
5557
private Integer sessionIdleTimeoutSeconds;
5658
private Boolean useLoggedInUser;
@@ -214,6 +216,36 @@ public CopilotClientOptions setCwd(String cwd) {
214216
return this;
215217
}
216218

219+
/**
220+
* Gets the base directory for Copilot data (session state, config, etc.).
221+
*
222+
* @return the Copilot home directory path, or {@code null} to use the CLI
223+
* default ({@code ~/.copilot})
224+
* @since 1.4.0
225+
*/
226+
public String getCopilotHome() {
227+
return copilotHome;
228+
}
229+
230+
/**
231+
* Sets the base directory for Copilot data (session state, config, etc.).
232+
* <p>
233+
* Sets the {@code COPILOT_HOME} environment variable on the spawned CLI
234+
* process. When {@code null}, the CLI defaults to {@code ~/.copilot}.
235+
* <p>
236+
* This option is only used when the SDK spawns the CLI process; it is ignored
237+
* when connecting to an external server via {@link #setCliUrl(String)}.
238+
*
239+
* @param copilotHome
240+
* the Copilot home directory path (must not be {@code null})
241+
* @return this options instance for method chaining
242+
* @since 1.4.0
243+
*/
244+
public CopilotClientOptions setCopilotHome(String copilotHome) {
245+
this.copilotHome = Objects.requireNonNull(copilotHome, "copilotHome must not be null");
246+
return this;
247+
}
248+
217249
/**
218250
* Gets the environment variables for the CLI process.
219251
* <p>
@@ -405,6 +437,33 @@ public CopilotClientOptions setPort(int port) {
405437
return this;
406438
}
407439

440+
/**
441+
* Gets the connection token for the headless CLI server (TCP only).
442+
*
443+
* @return the connection token, or {@code null} if not set
444+
* @since 1.4.0
445+
*/
446+
public String getTcpConnectionToken() {
447+
return tcpConnectionToken;
448+
}
449+
450+
/**
451+
* Sets the connection token for the headless CLI server (TCP only).
452+
* <p>
453+
* When the SDK spawns its own CLI in TCP mode and this is omitted, a UUID is
454+
* generated automatically so the loopback listener is safe by default. Cannot
455+
* be combined with {@link #setUseStdio(boolean)} set to {@code true}.
456+
*
457+
* @param tcpConnectionToken
458+
* the connection token (must not be {@code null} or empty)
459+
* @return this options instance for method chaining
460+
* @since 1.4.0
461+
*/
462+
public CopilotClientOptions setTcpConnectionToken(String tcpConnectionToken) {
463+
this.tcpConnectionToken = Objects.requireNonNull(tcpConnectionToken, "tcpConnectionToken must not be null");
464+
return this;
465+
}
466+
408467
/**
409468
* Gets the OpenTelemetry configuration for the CLI server.
410469
*
@@ -533,6 +592,7 @@ public CopilotClientOptions clone() {
533592
copy.cliArgs = this.cliArgs != null ? this.cliArgs.clone() : null;
534593
copy.cliPath = this.cliPath;
535594
copy.cliUrl = this.cliUrl;
595+
copy.copilotHome = this.copilotHome;
536596
copy.cwd = this.cwd;
537597
copy.environment = this.environment != null ? new java.util.HashMap<>(this.environment) : null;
538598
copy.executor = this.executor;
@@ -541,6 +601,7 @@ public CopilotClientOptions clone() {
541601
copy.onListModels = this.onListModels;
542602
copy.port = this.port;
543603
copy.sessionIdleTimeoutSeconds = this.sessionIdleTimeoutSeconds;
604+
copy.tcpConnectionToken = this.tcpConnectionToken;
544605
copy.telemetry = this.telemetry;
545606
copy.useLoggedInUser = this.useLoggedInUser;
546607
copy.useStdio = this.useStdio;

src/main/java/com/github/copilot/sdk/json/CreateSessionRequest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ public final class CreateSessionRequest {
9191
@JsonProperty("skillDirectories")
9292
private List<String> skillDirectories;
9393

94+
@JsonProperty("instructionDirectories")
95+
private List<String> instructionDirectories;
96+
9497
@JsonProperty("disabledSkills")
9598
private List<String> disabledSkills;
9699

@@ -326,6 +329,18 @@ public void setSkillDirectories(List<String> skillDirectories) {
326329
this.skillDirectories = skillDirectories;
327330
}
328331

332+
/** Gets instruction directories. @return the instruction directory paths */
333+
public List<String> getInstructionDirectories() {
334+
return instructionDirectories == null ? null : Collections.unmodifiableList(instructionDirectories);
335+
}
336+
337+
/**
338+
* Sets instruction directories. @param instructionDirectories the directories
339+
*/
340+
public void setInstructionDirectories(List<String> instructionDirectories) {
341+
this.instructionDirectories = instructionDirectories;
342+
}
343+
329344
/** Gets disabled skills. @return the disabled skill names */
330345
public List<String> getDisabledSkills() {
331346
return disabledSkills == null ? null : Collections.unmodifiableList(disabledSkills);

src/main/java/com/github/copilot/sdk/json/McpHttpServerConfig.java

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ public final class McpHttpServerConfig extends McpServerConfig {
4141
@JsonProperty("headers")
4242
private Map<String, String> headers;
4343

44+
@JsonProperty("oauthClientId")
45+
private String oauthClientId;
46+
47+
@JsonProperty("oauthPublicClient")
48+
private Boolean oauthPublicClient;
49+
50+
@JsonProperty("oauthGrantType")
51+
private String oauthGrantType;
52+
4453
/**
4554
* Gets the server type discriminator.
4655
*
@@ -92,6 +101,79 @@ public McpHttpServerConfig setHeaders(Map<String, String> headers) {
92101
return this;
93102
}
94103

104+
/**
105+
* Gets the optional OAuth client ID for the remote server.
106+
*
107+
* @return the OAuth client ID, or {@code null}
108+
* @since 1.4.0
109+
*/
110+
public String getOauthClientId() {
111+
return oauthClientId;
112+
}
113+
114+
/**
115+
* Sets the optional OAuth client ID for the remote server.
116+
*
117+
* @param oauthClientId
118+
* the OAuth client ID
119+
* @return this config for method chaining
120+
* @since 1.4.0
121+
*/
122+
public McpHttpServerConfig setOauthClientId(String oauthClientId) {
123+
this.oauthClientId = oauthClientId;
124+
return this;
125+
}
126+
127+
/**
128+
* Gets whether this is a public OAuth client.
129+
*
130+
* @return {@code true} if public, {@code null} if not set
131+
* @since 1.4.0
132+
*/
133+
public Boolean getOauthPublicClient() {
134+
return oauthPublicClient;
135+
}
136+
137+
/**
138+
* Sets whether this is a public OAuth client.
139+
*
140+
* @param oauthPublicClient
141+
* {@code true} if public
142+
* @return this config for method chaining
143+
* @since 1.4.0
144+
*/
145+
public McpHttpServerConfig setOauthPublicClient(Boolean oauthPublicClient) {
146+
this.oauthPublicClient = oauthPublicClient;
147+
return this;
148+
}
149+
150+
/**
151+
* Gets the optional OAuth grant type for the remote server.
152+
* <p>
153+
* Valid values: {@code "authorization_code"}, {@code "client_credentials"}.
154+
*
155+
* @return the OAuth grant type, or {@code null}
156+
* @since 1.4.0
157+
*/
158+
public String getOauthGrantType() {
159+
return oauthGrantType;
160+
}
161+
162+
/**
163+
* Sets the optional OAuth grant type for the remote server.
164+
* <p>
165+
* Valid values: {@code "authorization_code"}, {@code "client_credentials"}.
166+
*
167+
* @param oauthGrantType
168+
* the OAuth grant type
169+
* @return this config for method chaining
170+
* @since 1.4.0
171+
*/
172+
public McpHttpServerConfig setOauthGrantType(String oauthGrantType) {
173+
this.oauthGrantType = oauthGrantType;
174+
return this;
175+
}
176+
95177
@Override
96178
public McpHttpServerConfig setTools(List<String> tools) {
97179
super.setTools(tools);

0 commit comments

Comments
 (0)