Skip to content

Commit f61df19

Browse files
authored
Merge pull request #122 from github/copilot/sync-reference-implementation-commits
Reference implementation sync: 4 new commits (2026-04-25)
2 parents c596216 + c9241f1 commit f61df19

28 files changed

Lines changed: 881 additions & 80 deletions

.lastmerge

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
922959f4a7b83509c3620d4881733c6c5677f00c
1+
dd2dcbc439256acfb9feb2cff07c0b9c820091b8

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ ProcessInfo startCliServer() throws IOException, InterruptedException {
8383
args.add("--no-auto-login");
8484
}
8585

86+
if (options.getSessionIdleTimeoutSeconds() != null && options.getSessionIdleTimeoutSeconds() > 0) {
87+
args.add("--session-idle-timeout");
88+
args.add(String.valueOf(options.getSessionIdleTimeoutSeconds()));
89+
}
90+
8691
List<String> command = resolveCliCommand(cliPath, args);
8792

8893
var pb = new ProcessBuilder(command);

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,7 +1224,7 @@ CompletableFuture<PermissionRequestResult> handlePermissionRequest(JsonNode perm
12241224
PermissionHandler handler = permissionHandler.get();
12251225
if (handler == null) {
12261226
PermissionRequestResult result = new PermissionRequestResult();
1227-
result.setKind("denied-no-approval-rule-and-could-not-request-from-user");
1227+
result.setKind(PermissionRequestResultKind.USER_NOT_AVAILABLE);
12281228
return CompletableFuture.completedFuture(result);
12291229
}
12301230

@@ -1235,13 +1235,13 @@ CompletableFuture<PermissionRequestResult> handlePermissionRequest(JsonNode perm
12351235
return handler.handle(request, invocation).exceptionally(ex -> {
12361236
LOG.log(Level.SEVERE, "Permission handler threw an exception", ex);
12371237
PermissionRequestResult result = new PermissionRequestResult();
1238-
result.setKind("denied-no-approval-rule-and-could-not-request-from-user");
1238+
result.setKind(PermissionRequestResultKind.USER_NOT_AVAILABLE);
12391239
return result;
12401240
});
12411241
} catch (Exception e) {
12421242
LOG.log(Level.SEVERE, "Failed to process permission request", e);
12431243
PermissionRequestResult result = new PermissionRequestResult();
1244-
result.setKind("denied-no-approval-rule-and-could-not-request-from-user");
1244+
result.setKind(PermissionRequestResultKind.USER_NOT_AVAILABLE);
12451245
return CompletableFuture.completedFuture(result);
12461246
}
12471247
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config, String sess
118118
request.setIncludeSubAgentStreamingEvents(config.getIncludeSubAgentStreamingEvents());
119119
request.setMcpServers(config.getMcpServers());
120120
request.setCustomAgents(config.getCustomAgents());
121+
request.setDefaultAgent(config.getDefaultAgent());
121122
request.setAgent(config.getAgent());
122123
request.setInfiniteSessions(config.getInfiniteSessions());
123124
request.setSkillDirectories(config.getSkillDirectories());
@@ -135,6 +136,7 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config, String sess
135136
if (config.getOnElicitationRequest() != null) {
136137
request.setRequestElicitation(true);
137138
}
139+
request.setGitHubToken(config.getGitHubToken());
138140

139141
return request;
140142
}
@@ -194,6 +196,7 @@ static ResumeSessionRequest buildResumeRequest(String sessionId, ResumeSessionCo
194196
request.setIncludeSubAgentStreamingEvents(config.getIncludeSubAgentStreamingEvents());
195197
request.setMcpServers(config.getMcpServers());
196198
request.setCustomAgents(config.getCustomAgents());
199+
request.setDefaultAgent(config.getDefaultAgent());
197200
request.setAgent(config.getAgent());
198201
request.setSkillDirectories(config.getSkillDirectories());
199202
request.setDisabledSkills(config.getDisabledSkills());
@@ -209,6 +212,7 @@ static ResumeSessionRequest buildResumeRequest(String sessionId, ResumeSessionCo
209212
if (config.getOnElicitationRequest() != null) {
210213
request.setRequestElicitation(true);
211214
}
215+
request.setGitHubToken(config.getGitHubToken());
212216

213217
return request;
214218
}

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public class CopilotClientOptions {
5252
private Supplier<CompletableFuture<List<ModelInfo>>> onListModels;
5353
private int port;
5454
private TelemetryConfig telemetry;
55+
private Integer sessionIdleTimeoutSeconds;
5556
private Boolean useLoggedInUser;
5657
private boolean useStdio = true;
5758

@@ -430,6 +431,37 @@ public CopilotClientOptions setTelemetry(TelemetryConfig telemetry) {
430431
return this;
431432
}
432433

434+
/**
435+
* Gets the server-wide idle timeout for sessions in seconds.
436+
*
437+
* @return the session idle timeout in seconds, or {@code null} to disable
438+
* (sessions live indefinitely)
439+
* @since 1.3.0
440+
*/
441+
public Integer getSessionIdleTimeoutSeconds() {
442+
return sessionIdleTimeoutSeconds;
443+
}
444+
445+
/**
446+
* Sets the server-wide idle timeout for sessions in seconds.
447+
* <p>
448+
* Sessions without activity for this duration are automatically cleaned up. Set
449+
* to {@code 0} or leave as {@code null} to disable (sessions live
450+
* indefinitely).
451+
* <p>
452+
* This option is only used when the SDK spawns the CLI process; it is ignored
453+
* when connecting to an external server via {@link #setCliUrl(String)}.
454+
*
455+
* @param sessionIdleTimeoutSeconds
456+
* the idle timeout in seconds, or {@code null} to disable
457+
* @return this options instance for method chaining
458+
* @since 1.3.0
459+
*/
460+
public CopilotClientOptions setSessionIdleTimeoutSeconds(Integer sessionIdleTimeoutSeconds) {
461+
this.sessionIdleTimeoutSeconds = sessionIdleTimeoutSeconds;
462+
return this;
463+
}
464+
433465
/**
434466
* Returns whether to use the logged-in user for authentication.
435467
*
@@ -508,6 +540,7 @@ public CopilotClientOptions clone() {
508540
copy.logLevel = this.logLevel;
509541
copy.onListModels = this.onListModels;
510542
copy.port = this.port;
543+
copy.sessionIdleTimeoutSeconds = this.sessionIdleTimeoutSeconds;
511544
copy.telemetry = this.telemetry;
512545
copy.useLoggedInUser = this.useLoggedInUser;
513546
copy.useStdio = this.useStdio;

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ public final class CreateSessionRequest {
7979
@JsonProperty("customAgents")
8080
private List<CustomAgentConfig> customAgents;
8181

82+
@JsonProperty("defaultAgent")
83+
private DefaultAgentConfig defaultAgent;
84+
8285
@JsonProperty("agent")
8386
private String agent;
8487

@@ -106,6 +109,9 @@ public final class CreateSessionRequest {
106109
@JsonProperty("modelCapabilities")
107110
private ModelCapabilitiesOverride modelCapabilities;
108111

112+
@JsonProperty("gitHubToken")
113+
private String gitHubToken;
114+
109115
/** Gets the model name. @return the model */
110116
public String getModel() {
111117
return model;
@@ -278,6 +284,18 @@ public void setCustomAgents(List<CustomAgentConfig> customAgents) {
278284
this.customAgents = customAgents;
279285
}
280286

287+
/** Gets the default agent config. @return the default agent config */
288+
public DefaultAgentConfig getDefaultAgent() {
289+
return defaultAgent;
290+
}
291+
292+
/**
293+
* Sets the default agent config. @param defaultAgent the default agent config
294+
*/
295+
public void setDefaultAgent(DefaultAgentConfig defaultAgent) {
296+
this.defaultAgent = defaultAgent;
297+
}
298+
281299
/** Gets the pre-selected agent name. @return the agent name */
282300
public String getAgent() {
283301
return agent;
@@ -382,4 +400,17 @@ public ModelCapabilitiesOverride getModelCapabilities() {
382400
public void setModelCapabilities(ModelCapabilitiesOverride modelCapabilities) {
383401
this.modelCapabilities = modelCapabilities;
384402
}
403+
404+
/** Gets the GitHub token for per-session authentication. @return the token */
405+
public String getGitHubToken() {
406+
return gitHubToken;
407+
}
408+
409+
/**
410+
* Sets the GitHub token for per-session authentication. @param gitHubToken the
411+
* token
412+
*/
413+
public void setGitHubToken(String gitHubToken) {
414+
this.gitHubToken = gitHubToken;
415+
}
385416
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
*--------------------------------------------------------------------------------------------*/
4+
5+
package com.github.copilot.sdk.json;
6+
7+
import java.util.Collections;
8+
import java.util.List;
9+
10+
import com.fasterxml.jackson.annotation.JsonInclude;
11+
import com.fasterxml.jackson.annotation.JsonProperty;
12+
13+
/**
14+
* Configuration for the default agent (the built-in agent that handles turns
15+
* when no custom agent is selected).
16+
* <p>
17+
* Use {@link #setExcludedTools(List)} to hide specific tools from the default
18+
* agent while keeping them available to custom sub-agents.
19+
*
20+
* <h2>Example Usage</h2>
21+
*
22+
* <pre>{@code
23+
* var config = new SessionConfig().setTools(List.of(secretTool))
24+
* .setDefaultAgent(new DefaultAgentConfig().setExcludedTools(List.of("secret_tool")));
25+
* }</pre>
26+
*
27+
* @see SessionConfig#setDefaultAgent(DefaultAgentConfig)
28+
* @since 1.3.0
29+
*/
30+
@JsonInclude(JsonInclude.Include.NON_NULL)
31+
public class DefaultAgentConfig {
32+
33+
@JsonProperty("excludedTools")
34+
private List<String> excludedTools;
35+
36+
/**
37+
* Gets the list of tool names excluded from the default agent.
38+
*
39+
* @return the list of excluded tool names, or {@code null} if not set
40+
*/
41+
public List<String> getExcludedTools() {
42+
return excludedTools == null ? null : Collections.unmodifiableList(excludedTools);
43+
}
44+
45+
/**
46+
* Sets the list of tool names to exclude from the default agent.
47+
* <p>
48+
* These tools remain available to custom sub-agents that reference them in
49+
* their {@link CustomAgentConfig#setTools(List)} list.
50+
*
51+
* @param excludedTools
52+
* the list of tool names to exclude from the default agent
53+
* @return this config for method chaining
54+
*/
55+
public DefaultAgentConfig setExcludedTools(List<String> excludedTools) {
56+
this.excludedTools = excludedTools;
57+
return this;
58+
}
59+
}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@
2020
* // Check the permission kind
2121
* if ("dangerous-action".equals(request.getKind())) {
2222
* // Deny dangerous actions
23-
* return CompletableFuture.completedFuture(new PermissionRequestResult().setKind("user-denied"));
23+
* return CompletableFuture
24+
* .completedFuture(new PermissionRequestResult().setKind(PermissionRequestResultKind.REJECTED));
2425
* }
2526
*
2627
* // Approve other requests
27-
* return CompletableFuture.completedFuture(new PermissionRequestResult().setKind("user-approved"));
28+
* return CompletableFuture
29+
* .completedFuture(new PermissionRequestResult().setKind(PermissionRequestResultKind.APPROVED));
2830
* };
2931
* }</pre>
3032
*

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

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,37 +19,29 @@
1919
*
2020
* <h2>Well-known kinds</h2>
2121
* <ul>
22-
* <li>{@link #APPROVED} — the permission was approved.</li>
23-
* <li>{@link #DENIED_BY_RULES} — the permission was denied by policy
24-
* rules.</li>
25-
* <li>{@link #DENIED_COULD_NOT_REQUEST_FROM_USER} — the permission was denied
26-
* because no approval rule was found and the user could not be prompted.</li>
27-
* <li>{@link #DENIED_INTERACTIVELY_BY_USER} — the permission was denied
28-
* interactively by the user.</li>
22+
* <li>{@link #APPROVED} — the permission was approved for this one
23+
* instance.</li>
24+
* <li>{@link #REJECTED} — the permission was denied interactively by the
25+
* user.</li>
26+
* <li>{@link #USER_NOT_AVAILABLE} — the permission was denied because user
27+
* confirmation was unavailable.</li>
28+
* <li>{@link #NO_RESULT} — no permission decision was made.</li>
2929
* </ul>
3030
*
3131
* @see PermissionRequestResult
3232
* @since 1.1.0
3333
*/
3434
public final class PermissionRequestResultKind {
3535

36-
/** The permission was approved. */
37-
public static final PermissionRequestResultKind APPROVED = new PermissionRequestResultKind("approved");
38-
39-
/** The permission was denied by policy rules. */
40-
public static final PermissionRequestResultKind DENIED_BY_RULES = new PermissionRequestResultKind(
41-
"denied-by-rules");
42-
43-
/**
44-
* The permission was denied because no approval rule was found and the user
45-
* could not be prompted.
46-
*/
47-
public static final PermissionRequestResultKind DENIED_COULD_NOT_REQUEST_FROM_USER = new PermissionRequestResultKind(
48-
"denied-no-approval-rule-and-could-not-request-from-user");
36+
/** The permission was approved for this one instance. */
37+
public static final PermissionRequestResultKind APPROVED = new PermissionRequestResultKind("approve-once");
4938

5039
/** The permission was denied interactively by the user. */
51-
public static final PermissionRequestResultKind DENIED_INTERACTIVELY_BY_USER = new PermissionRequestResultKind(
52-
"denied-interactively-by-user");
40+
public static final PermissionRequestResultKind REJECTED = new PermissionRequestResultKind("reject");
41+
42+
/** The permission was denied because user confirmation was unavailable. */
43+
public static final PermissionRequestResultKind USER_NOT_AVAILABLE = new PermissionRequestResultKind(
44+
"user-not-available");
5345

5446
/**
5547
* Leaves the pending permission request unanswered.
@@ -66,6 +58,24 @@ public final class PermissionRequestResultKind {
6658
*/
6759
public static final PermissionRequestResultKind NO_RESULT = new PermissionRequestResultKind("no-result");
6860

61+
/**
62+
* @deprecated Use {@link #REJECTED} instead.
63+
*/
64+
@Deprecated
65+
public static final PermissionRequestResultKind DENIED_INTERACTIVELY_BY_USER = REJECTED;
66+
67+
/**
68+
* @deprecated Use {@link #USER_NOT_AVAILABLE} instead.
69+
*/
70+
@Deprecated
71+
public static final PermissionRequestResultKind DENIED_COULD_NOT_REQUEST_FROM_USER = USER_NOT_AVAILABLE;
72+
73+
/**
74+
* @deprecated Use {@link #USER_NOT_AVAILABLE} instead.
75+
*/
76+
@Deprecated
77+
public static final PermissionRequestResultKind DENIED_BY_RULES = USER_NOT_AVAILABLE;
78+
6979
private final String value;
7080

7181
/**

0 commit comments

Comments
 (0)