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
2 changes: 1 addition & 1 deletion .lastmerge
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5016587a62652f3d184b3c6958dfc63359921aa8
c263dfc69055f9f28ee2d4b121cf617fca5a42dc
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

> **Upstream sync:** [`github/copilot-sdk@e40d57c`](https://github.com/github/copilot-sdk/commit/e40d57c86e18b495722adbf42045288c03924342)
> **Upstream sync:** [`github/copilot-sdk@c263dfc`](https://github.com/github/copilot-sdk/commit/c263dfc69055f9f28ee2d4b121cf617fca5a42dc)

### Added

- `SessionConfig.setClientName(String)` / `getClientName()` — identifies the application using the SDK; included in the User-Agent header for API requests (upstream: [`397ef66`](https://github.com/github/copilot-sdk/commit/397ef66))
- `ResumeSessionConfig.setClientName(String)` / `getClientName()` — same for resumed sessions
- `PermissionHandler.APPROVE_ALL` — pre-built handler that approves all permission requests (upstream: [`3e2d2b2`](https://github.com/github/copilot-sdk/commit/3e2d2b2))

### Changed

- **Breaking:** permissions are now denied by default when no `OnPermissionRequest` handler is provided. The `requestPermission` flag is always sent as `true` so the server calls back for every permission request; the SDK returns a deny result when no handler is registered (upstream: [`3e2d2b2`](https://github.com/github/copilot-sdk/commit/3e2d2b2))

## [1.0.9] - 2026-02-16

Expand Down
14 changes: 10 additions & 4 deletions src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,28 @@ private SessionRequestBuilder() {
*/
static CreateSessionRequest buildCreateRequest(SessionConfig config) {
var request = new CreateSessionRequest();
// Always request permission callbacks to enable deny-by-default behavior
request.setRequestPermission(true);
// Always send envValueMode=direct for MCP servers
request.setEnvValueMode("direct");
if (config == null) {
return request;
}

request.setModel(config.getModel());
request.setSessionId(config.getSessionId());
request.setClientName(config.getClientName());
request.setReasoningEffort(config.getReasoningEffort());
request.setTools(config.getTools());
request.setSystemMessage(config.getSystemMessage());
request.setAvailableTools(config.getAvailableTools());
request.setExcludedTools(config.getExcludedTools());
request.setProvider(config.getProvider());
request.setRequestPermission(config.getOnPermissionRequest() != null ? true : null);
request.setRequestUserInput(config.getOnUserInputRequest() != null ? true : null);
request.setHooks(config.getHooks() != null && config.getHooks().hasHooks() ? true : null);
request.setWorkingDirectory(config.getWorkingDirectory());
request.setStreaming(config.isStreaming() ? true : null);
request.setMcpServers(config.getMcpServers());
request.setEnvValueMode("direct");
request.setCustomAgents(config.getCustomAgents());
request.setInfiniteSessions(config.getInfiniteSessions());
request.setSkillDirectories(config.getSkillDirectories());
Expand All @@ -71,27 +74,30 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config) {
static ResumeSessionRequest buildResumeRequest(String sessionId, ResumeSessionConfig config) {
var request = new ResumeSessionRequest();
request.setSessionId(sessionId);
// Always request permission callbacks to enable deny-by-default behavior
request.setRequestPermission(true);
// Always send envValueMode=direct for MCP servers
request.setEnvValueMode("direct");

if (config == null) {
return request;
}

request.setModel(config.getModel());
request.setClientName(config.getClientName());
request.setReasoningEffort(config.getReasoningEffort());
request.setTools(config.getTools());
request.setSystemMessage(config.getSystemMessage());
request.setAvailableTools(config.getAvailableTools());
request.setExcludedTools(config.getExcludedTools());
request.setProvider(config.getProvider());
request.setRequestPermission(config.getOnPermissionRequest() != null ? true : null);
request.setRequestUserInput(config.getOnUserInputRequest() != null ? true : null);
request.setHooks(config.getHooks() != null && config.getHooks().hasHooks() ? true : null);
request.setWorkingDirectory(config.getWorkingDirectory());
request.setConfigDir(config.getConfigDir());
request.setDisableResume(config.isDisableResume() ? true : null);
request.setStreaming(config.isStreaming() ? true : null);
request.setMcpServers(config.getMcpServers());
request.setEnvValueMode("direct");
request.setCustomAgents(config.getCustomAgents());
request.setSkillDirectories(config.getSkillDirectories());
request.setDisabledSkills(config.getDisabledSkills());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ public final class CreateSessionRequest {
@JsonProperty("sessionId")
private String sessionId;

@JsonProperty("clientName")
private String clientName;

@JsonProperty("reasoningEffort")
private String reasoningEffort;

Expand Down Expand Up @@ -105,6 +108,16 @@ public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}

/** Gets the client name. @return the client name */
public String getClientName() {
return clientName;
}

/** Sets the client name. @param clientName the client name */
public void setClientName(String clientName) {
this.clientName = clientName;
}

/** Gets the reasoning effort. @return the reasoning effort level */
public String getReasoningEffort() {
return reasoningEffort;
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/com/github/copilot/sdk/json/PermissionHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
* };
* }</pre>
*
* <p>
* A pre-built handler that approves all requests is available as
* {@link #APPROVE_ALL}.
*
* @see SessionConfig#setOnPermissionRequest(PermissionHandler)
* @see PermissionRequest
* @see PermissionRequestResult
Expand All @@ -36,6 +40,14 @@
@FunctionalInterface
public interface PermissionHandler {

/**
* A pre-built handler that approves all permission requests.
*
* @since 1.0.11
*/
PermissionHandler APPROVE_ALL = (request, invocation) -> CompletableFuture
.completedFuture(new PermissionRequestResult().setKind("approved"));

/**
* Handles a permission request from the assistant.
* <p>
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/com/github/copilot/sdk/json/ResumeSessionConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResumeSessionConfig {

private String clientName;
private String model;
private List<ToolDefinition> tools;
private SystemMessageConfig systemMessage;
Expand Down Expand Up @@ -76,6 +77,29 @@ public ResumeSessionConfig setModel(String model) {
return this;
}

/**
* Gets the client name used to identify the application using the SDK.
*
* @return the client name, or {@code null} if not set
*/
public String getClientName() {
return clientName;
}

/**
* Sets the client name to identify the application using the SDK.
* <p>
* This value is included in the User-Agent header for API requests.
*
* @param clientName
* the client name
* @return this config for method chaining
*/
public ResumeSessionConfig setClientName(String clientName) {
this.clientName = clientName;
return this;
}

/**
* Gets the custom tools for this session.
*
Expand Down Expand Up @@ -491,6 +515,7 @@ public ResumeSessionConfig setInfiniteSessions(InfiniteSessionConfig infiniteSes
@Override
public ResumeSessionConfig clone() {
ResumeSessionConfig copy = new ResumeSessionConfig();
copy.clientName = this.clientName;
copy.model = this.model;
copy.tools = this.tools != null ? new ArrayList<>(this.tools) : null;
copy.systemMessage = this.systemMessage;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ public final class ResumeSessionRequest {
@JsonProperty("sessionId")
private String sessionId;

@JsonProperty("clientName")
private String clientName;

@JsonProperty("model")
private String model;

Expand Down Expand Up @@ -99,6 +102,16 @@ public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}

/** Gets the client name. @return the client name */
public String getClientName() {
return clientName;
}

/** Sets the client name. @param clientName the client name */
public void setClientName(String clientName) {
this.clientName = clientName;
}

/** Gets the model name. @return the model */
public String getModel() {
return model;
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/com/github/copilot/sdk/json/SessionConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
public class SessionConfig {

private String sessionId;
private String clientName;
private String model;
private String reasoningEffort;
private List<ToolDefinition> tools;
Expand Down Expand Up @@ -76,6 +77,29 @@ public SessionConfig setSessionId(String sessionId) {
return this;
}

/**
* Gets the client name used to identify the application using the SDK.
*
* @return the client name, or {@code null} if not set
*/
public String getClientName() {
return clientName;
}

/**
* Sets the client name to identify the application using the SDK.
* <p>
* This value is included in the User-Agent header for API requests.
*
* @param clientName
* the client name
* @return this config instance for method chaining
*/
public SessionConfig setClientName(String clientName) {
this.clientName = clientName;
return this;
}

/**
* Gets the AI model to use.
*
Expand Down Expand Up @@ -529,6 +553,7 @@ public SessionConfig setConfigDir(String configDir) {
public SessionConfig clone() {
SessionConfig copy = new SessionConfig();
copy.sessionId = this.sessionId;
copy.clientName = this.clientName;
copy.model = this.model;
copy.reasoningEffort = this.reasoningEffort;
copy.tools = this.tools != null ? new ArrayList<>(this.tools) : null;
Expand Down
2 changes: 2 additions & 0 deletions src/test/java/com/github/copilot/sdk/ConfigCloneTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,14 @@ void copilotClientOptionsEnvironmentIndependence() {
void sessionConfigCloneBasic() {
SessionConfig original = new SessionConfig();
original.setSessionId("my-session");
original.setClientName("my-app");
original.setModel("gpt-4o");
original.setStreaming(true);

SessionConfig cloned = original.clone();

assertEquals(original.getSessionId(), cloned.getSessionId());
assertEquals(original.getClientName(), cloned.getClientName());
assertEquals(original.getModel(), cloned.getModel());
assertEquals(original.isStreaming(), cloned.isStreaming());
}
Expand Down
4 changes: 3 additions & 1 deletion src/test/java/com/github/copilot/sdk/CopilotSessionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.github.copilot.sdk.events.ToolExecutionStartEvent;
import com.github.copilot.sdk.events.UserMessageEvent;
import com.github.copilot.sdk.json.MessageOptions;
import com.github.copilot.sdk.json.PermissionHandler;
import com.github.copilot.sdk.json.SessionConfig;
import com.github.copilot.sdk.json.SystemMessageConfig;
import com.github.copilot.sdk.json.ToolDefinition;
Expand Down Expand Up @@ -180,7 +181,8 @@ void testSendReturnsImmediatelyWhileEventsStreamInBackground() throws Exception
ctx.configureForTest("session", "send_returns_immediately_while_events_stream_in_background");

try (CopilotClient client = ctx.createClient()) {
CopilotSession session = client.createSession().get();
CopilotSession session = client
.createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get();

var events = new ArrayList<String>();
var lastMessage = new AtomicReference<AssistantMessageEvent>();
Expand Down
49 changes: 27 additions & 22 deletions src/test/java/com/github/copilot/sdk/HooksTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.junit.jupiter.api.Test;

import com.github.copilot.sdk.json.MessageOptions;
import com.github.copilot.sdk.json.PermissionHandler;
import com.github.copilot.sdk.json.PostToolUseHookInput;
import com.github.copilot.sdk.json.PreToolUseHookInput;
import com.github.copilot.sdk.json.PreToolUseHookOutput;
Expand Down Expand Up @@ -67,11 +68,12 @@ void testInvokePreToolUseHookWhenModelRunsATool() throws Exception {
var preToolUseInputs = new ArrayList<PreToolUseHookInput>();
final String[] sessionIdHolder = new String[1];

var config = new SessionConfig().setHooks(new SessionHooks().setOnPreToolUse((input, invocation) -> {
preToolUseInputs.add(input);
assertEquals(sessionIdHolder[0], invocation.getSessionId());
return CompletableFuture.completedFuture(PreToolUseHookOutput.allow());
}));
var config = new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
.setHooks(new SessionHooks().setOnPreToolUse((input, invocation) -> {
preToolUseInputs.add(input);
assertEquals(sessionIdHolder[0], invocation.getSessionId());
return CompletableFuture.completedFuture(PreToolUseHookOutput.allow());
}));

try (CopilotClient client = ctx.createClient()) {
CopilotSession session = client.createSession(config).get();
Expand Down Expand Up @@ -106,11 +108,12 @@ void testInvokePostToolUseHookAfterModelRunsATool() throws Exception {
var postToolUseInputs = new ArrayList<PostToolUseHookInput>();
final String[] sessionIdHolder = new String[1];

var config = new SessionConfig().setHooks(new SessionHooks().setOnPostToolUse((input, invocation) -> {
postToolUseInputs.add(input);
assertEquals(sessionIdHolder[0], invocation.getSessionId());
return CompletableFuture.completedFuture(null);
}));
var config = new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
.setHooks(new SessionHooks().setOnPostToolUse((input, invocation) -> {
postToolUseInputs.add(input);
assertEquals(sessionIdHolder[0], invocation.getSessionId());
return CompletableFuture.completedFuture(null);
}));

try (CopilotClient client = ctx.createClient()) {
CopilotSession session = client.createSession(config).get();
Expand Down Expand Up @@ -147,13 +150,14 @@ void testInvokeBothHooksForSingleToolCall() throws Exception {
var preToolUseInputs = new ArrayList<PreToolUseHookInput>();
var postToolUseInputs = new ArrayList<PostToolUseHookInput>();

var config = new SessionConfig().setHooks(new SessionHooks().setOnPreToolUse((input, invocation) -> {
preToolUseInputs.add(input);
return CompletableFuture.completedFuture(PreToolUseHookOutput.allow());
}).setOnPostToolUse((input, invocation) -> {
postToolUseInputs.add(input);
return CompletableFuture.completedFuture(null);
}));
var config = new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
.setHooks(new SessionHooks().setOnPreToolUse((input, invocation) -> {
preToolUseInputs.add(input);
return CompletableFuture.completedFuture(PreToolUseHookOutput.allow());
}).setOnPostToolUse((input, invocation) -> {
postToolUseInputs.add(input);
return CompletableFuture.completedFuture(null);
}));

try (CopilotClient client = ctx.createClient()) {
CopilotSession session = client.createSession(config).get();
Expand Down Expand Up @@ -192,11 +196,12 @@ void testDenyToolExecutionWhenPreToolUseReturnsDeny() throws Exception {

var preToolUseInputs = new ArrayList<PreToolUseHookInput>();

var config = new SessionConfig().setHooks(new SessionHooks().setOnPreToolUse((input, invocation) -> {
preToolUseInputs.add(input);
// Deny all tool calls
return CompletableFuture.completedFuture(PreToolUseHookOutput.deny());
}));
var config = new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
.setHooks(new SessionHooks().setOnPreToolUse((input, invocation) -> {
preToolUseInputs.add(input);
// Deny all tool calls
return CompletableFuture.completedFuture(PreToolUseHookOutput.deny());
}));

try (CopilotClient client = ctx.createClient()) {
CopilotSession session = client.createSession(config).get();
Expand Down
Loading
Loading