diff --git a/.lastmerge b/.lastmerge
index 2e1ed67d3..e8f667ef7 100644
--- a/.lastmerge
+++ b/.lastmerge
@@ -1 +1 @@
-5016587a62652f3d184b3c6958dfc63359921aa8
+c263dfc69055f9f28ee2d4b121cf617fca5a42dc
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 649255c77..66d72554f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java b/src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java
index 61c06e7f0..90f3c71d8 100644
--- a/src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java
+++ b/src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java
@@ -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());
@@ -71,19 +74,23 @@ 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());
@@ -91,7 +98,6 @@ static ResumeSessionRequest buildResumeRequest(String sessionId, ResumeSessionCo
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());
diff --git a/src/main/java/com/github/copilot/sdk/json/CreateSessionRequest.java b/src/main/java/com/github/copilot/sdk/json/CreateSessionRequest.java
index 522aabd32..d73d82e6a 100644
--- a/src/main/java/com/github/copilot/sdk/json/CreateSessionRequest.java
+++ b/src/main/java/com/github/copilot/sdk/json/CreateSessionRequest.java
@@ -31,6 +31,9 @@ public final class CreateSessionRequest {
@JsonProperty("sessionId")
private String sessionId;
+ @JsonProperty("clientName")
+ private String clientName;
+
@JsonProperty("reasoningEffort")
private String reasoningEffort;
@@ -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;
diff --git a/src/main/java/com/github/copilot/sdk/json/PermissionHandler.java b/src/main/java/com/github/copilot/sdk/json/PermissionHandler.java
index 259c058f3..e987e41ae 100644
--- a/src/main/java/com/github/copilot/sdk/json/PermissionHandler.java
+++ b/src/main/java/com/github/copilot/sdk/json/PermissionHandler.java
@@ -28,6 +28,10 @@
* };
* }
*
+ *
+ * A pre-built handler that approves all requests is available as
+ * {@link #APPROVE_ALL}.
+ *
* @see SessionConfig#setOnPermissionRequest(PermissionHandler)
* @see PermissionRequest
* @see PermissionRequestResult
@@ -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.
*
diff --git a/src/main/java/com/github/copilot/sdk/json/ResumeSessionConfig.java b/src/main/java/com/github/copilot/sdk/json/ResumeSessionConfig.java
index fc790258a..0682699bc 100644
--- a/src/main/java/com/github/copilot/sdk/json/ResumeSessionConfig.java
+++ b/src/main/java/com/github/copilot/sdk/json/ResumeSessionConfig.java
@@ -33,6 +33,7 @@
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResumeSessionConfig {
+ private String clientName;
private String model;
private List tools;
private SystemMessageConfig systemMessage;
@@ -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.
+ *
+ * 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.
*
@@ -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;
diff --git a/src/main/java/com/github/copilot/sdk/json/ResumeSessionRequest.java b/src/main/java/com/github/copilot/sdk/json/ResumeSessionRequest.java
index 5d5228a16..4216e5eef 100644
--- a/src/main/java/com/github/copilot/sdk/json/ResumeSessionRequest.java
+++ b/src/main/java/com/github/copilot/sdk/json/ResumeSessionRequest.java
@@ -29,6 +29,9 @@ public final class ResumeSessionRequest {
@JsonProperty("sessionId")
private String sessionId;
+ @JsonProperty("clientName")
+ private String clientName;
+
@JsonProperty("model")
private String model;
@@ -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;
diff --git a/src/main/java/com/github/copilot/sdk/json/SessionConfig.java b/src/main/java/com/github/copilot/sdk/json/SessionConfig.java
index 064fee9f3..bfed0608e 100644
--- a/src/main/java/com/github/copilot/sdk/json/SessionConfig.java
+++ b/src/main/java/com/github/copilot/sdk/json/SessionConfig.java
@@ -34,6 +34,7 @@
public class SessionConfig {
private String sessionId;
+ private String clientName;
private String model;
private String reasoningEffort;
private List tools;
@@ -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.
+ *
+ * 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.
*
@@ -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;
diff --git a/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java b/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java
index 3bd1b2344..1c5ca6e09 100644
--- a/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java
+++ b/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java
@@ -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());
}
diff --git a/src/test/java/com/github/copilot/sdk/CopilotSessionTest.java b/src/test/java/com/github/copilot/sdk/CopilotSessionTest.java
index d4357e111..6ac77fdb6 100644
--- a/src/test/java/com/github/copilot/sdk/CopilotSessionTest.java
+++ b/src/test/java/com/github/copilot/sdk/CopilotSessionTest.java
@@ -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;
@@ -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();
var lastMessage = new AtomicReference();
diff --git a/src/test/java/com/github/copilot/sdk/HooksTest.java b/src/test/java/com/github/copilot/sdk/HooksTest.java
index c728b9b99..05cd3292b 100644
--- a/src/test/java/com/github/copilot/sdk/HooksTest.java
+++ b/src/test/java/com/github/copilot/sdk/HooksTest.java
@@ -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;
@@ -67,11 +68,12 @@ void testInvokePreToolUseHookWhenModelRunsATool() throws Exception {
var preToolUseInputs = new ArrayList();
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();
@@ -106,11 +108,12 @@ void testInvokePostToolUseHookAfterModelRunsATool() throws Exception {
var postToolUseInputs = new ArrayList();
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();
@@ -147,13 +150,14 @@ void testInvokeBothHooksForSingleToolCall() throws Exception {
var preToolUseInputs = new ArrayList();
var postToolUseInputs = new ArrayList();
- 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();
@@ -192,11 +196,12 @@ void testDenyToolExecutionWhenPreToolUseReturnsDeny() throws Exception {
var preToolUseInputs = new ArrayList();
- 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();
diff --git a/src/test/java/com/github/copilot/sdk/PermissionsTest.java b/src/test/java/com/github/copilot/sdk/PermissionsTest.java
index d07b7c500..b2a1cfe66 100644
--- a/src/test/java/com/github/copilot/sdk/PermissionsTest.java
+++ b/src/test/java/com/github/copilot/sdk/PermissionsTest.java
@@ -18,6 +18,8 @@
import org.junit.jupiter.api.TestInfo;
import com.github.copilot.sdk.events.AssistantMessageEvent;
+import com.github.copilot.sdk.events.ToolExecutionCompleteEvent;
+import com.github.copilot.sdk.json.PermissionHandler;
import com.github.copilot.sdk.json.PermissionRequest;
import com.github.copilot.sdk.json.PermissionRequestResult;
import com.github.copilot.sdk.json.SessionConfig;
@@ -286,4 +288,70 @@ void testShouldHandlePermissionHandlerErrorsGracefully(TestInfo testInfo) throws
session.close();
}
}
+
+ /**
+ * Verifies that tool operations are denied by default when no handler is
+ * provided.
+ *
+ * @see Snapshot:
+ * permissions/should_deny_tool_operations_by_default_when_no_handler_is_provided
+ */
+ @Test
+ void testShouldDenyToolOperationsByDefaultWhenNoHandlerIsProvided(TestInfo testInfo) throws Exception {
+ ctx.configureForTest("permissions", "should_deny_tool_operations_by_default_when_no_handler_is_provided");
+
+ try (CopilotClient client = ctx.createClient()) {
+ CopilotSession session = client.createSession().get();
+
+ final boolean[] permissionDenied = {false};
+ session.on(ToolExecutionCompleteEvent.class, evt -> {
+ if (!evt.getData().success() && evt.getData().error() != null && evt.getData().error().message() != null
+ && evt.getData().error().message().contains("Permission denied")) {
+ permissionDenied[0] = true;
+ }
+ });
+
+ session.sendAndWait(new MessageOptions().setPrompt("Run 'node --version'")).get(60, TimeUnit.SECONDS);
+
+ assertTrue(permissionDenied[0], "Expected a tool.execution_complete event with Permission denied result");
+
+ session.close();
+ }
+ }
+
+ /**
+ * Verifies that tool operations are denied by default when no handler is
+ * provided after resuming a session.
+ *
+ * @see Snapshot:
+ * permissions/should_deny_tool_operations_by_default_when_no_handler_is_provided_after_resume
+ */
+ @Test
+ void testShouldDenyToolOperationsByDefaultWhenNoHandlerIsProvidedAfterResume(TestInfo testInfo) throws Exception {
+ ctx.configureForTest("permissions",
+ "should_deny_tool_operations_by_default_when_no_handler_is_provided_after_resume");
+
+ try (CopilotClient client = ctx.createClient()) {
+ var config = new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL);
+ CopilotSession session1 = client.createSession(config).get();
+ String sessionId = session1.getSessionId();
+ session1.sendAndWait(new MessageOptions().setPrompt("What is 1+1?")).get(60, TimeUnit.SECONDS);
+
+ CopilotSession session2 = client.resumeSession(sessionId).get();
+
+ final boolean[] permissionDenied = {false};
+ session2.on(ToolExecutionCompleteEvent.class, evt -> {
+ if (!evt.getData().success() && evt.getData().error() != null && evt.getData().error().message() != null
+ && evt.getData().error().message().contains("Permission denied")) {
+ permissionDenied[0] = true;
+ }
+ });
+
+ session2.sendAndWait(new MessageOptions().setPrompt("Run 'node --version'")).get(60, TimeUnit.SECONDS);
+
+ assertTrue(permissionDenied[0], "Expected a tool.execution_complete event with Permission denied result");
+
+ session2.close();
+ }
+ }
}
diff --git a/src/test/java/com/github/copilot/sdk/SessionEventsE2ETest.java b/src/test/java/com/github/copilot/sdk/SessionEventsE2ETest.java
index 5af1b445b..758d57c20 100644
--- a/src/test/java/com/github/copilot/sdk/SessionEventsE2ETest.java
+++ b/src/test/java/com/github/copilot/sdk/SessionEventsE2ETest.java
@@ -26,6 +26,8 @@
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;
/**
* E2E tests for session events to verify event lifecycle.
@@ -130,7 +132,8 @@ void testInvokesBuiltInTools_toolExecutionCompleteEvent() throws Exception {
var toolCompletes = new ArrayList();
try (CopilotClient client = ctx.createClient()) {
- CopilotSession session = client.createSession().get();
+ CopilotSession session = client
+ .createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get();
session.on(ToolExecutionStartEvent.class, toolStarts::add);
session.on(ToolExecutionCompleteEvent.class, toolCompletes::add);
@@ -235,7 +238,8 @@ void testInvokesBuiltInTools_eventOrderDuringToolExecution() throws Exception {
var eventTypes = new ArrayList();
try (CopilotClient client = ctx.createClient()) {
- CopilotSession session = client.createSession().get();
+ CopilotSession session = client
+ .createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get();
session.on(event -> eventTypes.add(event.getType()));
diff --git a/src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java b/src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java
index b1737de55..7e9d5ee69 100644
--- a/src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java
+++ b/src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java
@@ -37,6 +37,8 @@ void testBuildCreateRequestNullConfig() {
CreateSessionRequest request = SessionRequestBuilder.buildCreateRequest(null);
assertNotNull(request);
assertNull(request.getModel());
+ assertTrue(request.getRequestPermission(), "requestPermission should be true even for null config");
+ assertEquals("direct", request.getEnvValueMode(), "envValueMode should be 'direct' even for null config");
}
@Test
@@ -65,6 +67,21 @@ void testBuildCreateRequestSetsEnvValueModeToDirect() {
assertEquals("direct", request.getEnvValueMode());
}
+ @Test
+ void testBuildCreateRequestAlwaysSetsRequestPermissionTrue() {
+ // No permission handler set - requestPermission should still be true
+ CreateSessionRequest request = SessionRequestBuilder.buildCreateRequest(new SessionConfig());
+ assertTrue(request.getRequestPermission(),
+ "requestPermission should always be true to enable deny-by-default behavior");
+ }
+
+ @Test
+ void testBuildCreateRequestSetsClientName() {
+ var config = new SessionConfig().setClientName("my-app");
+ CreateSessionRequest request = SessionRequestBuilder.buildCreateRequest(config);
+ assertEquals("my-app", request.getClientName());
+ }
+
// =========================================================================
// buildResumeRequest
// =========================================================================
@@ -74,6 +91,8 @@ void testBuildResumeRequestNullConfig() {
ResumeSessionRequest request = SessionRequestBuilder.buildResumeRequest("sid-1", null);
assertEquals("sid-1", request.getSessionId());
assertNull(request.getModel());
+ assertTrue(request.getRequestPermission(), "requestPermission should be true even for null config");
+ assertEquals("direct", request.getEnvValueMode(), "envValueMode should be 'direct' even for null config");
}
@Test
@@ -142,6 +161,21 @@ void testBuildResumeRequestSetsEnvValueModeToDirect() {
assertEquals("direct", request.getEnvValueMode());
}
+ @Test
+ void testBuildResumeRequestAlwaysSetsRequestPermissionTrue() {
+ // No permission handler set - requestPermission should still be true
+ ResumeSessionRequest request = SessionRequestBuilder.buildResumeRequest("sid-9", new ResumeSessionConfig());
+ assertTrue(request.getRequestPermission(),
+ "requestPermission should always be true to enable deny-by-default behavior");
+ }
+
+ @Test
+ void testBuildResumeRequestSetsClientName() {
+ var config = new ResumeSessionConfig().setClientName("my-app");
+ ResumeSessionRequest request = SessionRequestBuilder.buildResumeRequest("sid-10", config);
+ assertEquals("my-app", request.getClientName());
+ }
+
// =========================================================================
// configureSession (ResumeSessionConfig overload)
// =========================================================================
diff --git a/src/test/java/com/github/copilot/sdk/ToolsTest.java b/src/test/java/com/github/copilot/sdk/ToolsTest.java
index bc392d9f0..a1c66dc49 100644
--- a/src/test/java/com/github/copilot/sdk/ToolsTest.java
+++ b/src/test/java/com/github/copilot/sdk/ToolsTest.java
@@ -21,6 +21,7 @@
import com.github.copilot.sdk.events.AssistantMessageEvent;
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.ToolDefinition;
@@ -62,7 +63,8 @@ void testInvokesBuiltInTools(TestInfo testInfo) throws Exception {
Files.writeString(readmeFile, "# ELIZA, the only chatbot you'll ever need");
try (CopilotClient client = ctx.createClient()) {
- CopilotSession session = client.createSession().get();
+ CopilotSession session = client
+ .createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get();
AssistantMessageEvent response = session
.sendAndWait(