+ * Called internally when creating or resuming a session with an exit-plan-mode + * handler. + * + * @param handler + * the handler to invoke when an exit-plan-mode request is received + */ + void registerExitPlanModeHandler(ExitPlanModeHandler handler) { + exitPlanModeHandler.set(handler); + } + + /** + * Registers an auto-mode-switch handler for this session. + *
+ * Called internally when creating or resuming a session with an + * auto-mode-switch handler. + * + * @param handler + * the handler to invoke when an auto-mode-switch request is received + */ + void registerAutoModeSwitchHandler(AutoModeSwitchHandler handler) { + autoModeSwitchHandler.set(handler); + } + /** * Sets the capabilities reported by the host for this session. *
@@ -1356,6 +1392,60 @@ CompletableFuture
+ * Called internally when the server requests the user to exit plan mode.
+ *
+ * @param request
+ * the exit-plan-mode request
+ * @return a future that resolves with the exit-plan-mode result
+ */
+ CompletableFuture
+ * Called internally when the server requests to switch to auto mode.
+ *
+ * @param request
+ * the auto-mode-switch request
+ * @return a future that resolves with the auto-mode-switch response
+ */
+ CompletableFuture
@@ -1850,6 +1940,8 @@ public void close() {
permissionHandler.set(null);
userInputHandler.set(null);
elicitationHandler.set(null);
+ exitPlanModeHandler.set(null);
+ autoModeSwitchHandler.set(null);
hooksHandler.set(null);
}
diff --git a/src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java b/src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java
index d085f7fce..53c491930 100644
--- a/src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java
+++ b/src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java
@@ -17,6 +17,8 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.copilot.sdk.generated.SessionEvent;
+import com.github.copilot.sdk.json.AutoModeSwitchRequest;
+import com.github.copilot.sdk.json.ExitPlanModeRequest;
import com.github.copilot.sdk.json.PermissionRequestResult;
import com.github.copilot.sdk.json.PermissionRequestResultKind;
import com.github.copilot.sdk.json.SessionLifecycleEvent;
@@ -79,6 +81,10 @@ void registerHandlers(JsonRpcClient rpc) {
(requestId, params) -> handlePermissionRequest(rpc, requestId, params));
rpc.registerMethodHandler("userInput.request",
(requestId, params) -> handleUserInputRequest(rpc, requestId, params));
+ rpc.registerMethodHandler("exitPlanMode.request",
+ (requestId, params) -> handleExitPlanModeRequest(rpc, requestId, params));
+ rpc.registerMethodHandler("autoModeSwitch.request",
+ (requestId, params) -> handleAutoModeSwitchRequest(rpc, requestId, params));
rpc.registerMethodHandler("hooks.invoke", (requestId, params) -> handleHooksInvoke(rpc, requestId, params));
rpc.registerMethodHandler("systemMessage.transform",
(requestId, params) -> handleSystemMessageTransform(rpc, requestId, params));
@@ -283,6 +289,94 @@ private void handleUserInputRequest(JsonRpcClient rpc, String requestId, JsonNod
});
}
+ private void handleExitPlanModeRequest(JsonRpcClient rpc, String requestId, JsonNode params) {
+ runAsync(() -> {
+ try {
+ String sessionId = params.get("sessionId").asText();
+
+ CopilotSession session = sessions.get(sessionId);
+ if (session == null) {
+ rpc.sendErrorResponse(Long.parseLong(requestId), -32602, "Unknown session " + sessionId);
+ return;
+ }
+
+ var request = new ExitPlanModeRequest();
+ request.setSummary(params.has("summary") ? params.get("summary").asText() : "");
+ if (params.has("planContent") && !params.get("planContent").isNull()) {
+ request.setPlanContent(params.get("planContent").asText());
+ }
+ if (params.has("actions") && params.get("actions").isArray()) {
+ var actions = new ArrayList
+ * Implement this interface to handle requests to switch to auto mode when a
+ * rate limit is encountered. The handler decides whether to approve the switch.
+ *
+ *
+ * Implement this interface to handle requests to exit plan mode. When the agent
+ * finishes planning and wants to proceed, this handler is invoked to get the
+ * user's approval and action selection.
+ *
+ *
+ * When provided, the server will route {@code exitPlanMode.request} callbacks
+ * to this handler.
+ *
+ * @param onExitPlanMode
+ * the exit-plan-mode handler
+ * @return this config instance for method chaining
+ * @see ExitPlanModeHandler
+ * @since 1.0.7
+ */
+ public ResumeSessionConfig setOnExitPlanMode(ExitPlanModeHandler onExitPlanMode) {
+ this.onExitPlanMode = onExitPlanMode;
+ return this;
+ }
+
+ /**
+ * Gets the auto-mode-switch handler.
+ *
+ * @return the auto-mode-switch handler, or {@code null}
+ * @since 1.0.7
+ */
+ public AutoModeSwitchHandler getOnAutoModeSwitch() {
+ return onAutoModeSwitch;
+ }
+
+ /**
+ * Sets a handler for auto-mode-switch requests from the server.
+ *
+ * When provided, the server will route {@code autoModeSwitch.request} callbacks
+ * to this handler.
+ *
+ * @param onAutoModeSwitch
+ * the auto-mode-switch handler
+ * @return this config instance for method chaining
+ * @see AutoModeSwitchHandler
+ * @since 1.0.7
+ */
+ public ResumeSessionConfig setOnAutoModeSwitch(AutoModeSwitchHandler onAutoModeSwitch) {
+ this.onAutoModeSwitch = onAutoModeSwitch;
+ return this;
+ }
+
/**
* Gets the GitHub token for per-session authentication.
*
@@ -839,6 +895,8 @@ public ResumeSessionConfig clone() {
copy.onEvent = this.onEvent;
copy.commands = this.commands != null ? new ArrayList<>(this.commands) : null;
copy.onElicitationRequest = this.onElicitationRequest;
+ copy.onExitPlanMode = this.onExitPlanMode;
+ copy.onAutoModeSwitch = this.onAutoModeSwitch;
copy.gitHubToken = this.gitHubToken;
return copy;
}
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 9b2c17f1a..a1af26970 100644
--- a/src/main/java/com/github/copilot/sdk/json/ResumeSessionRequest.java
+++ b/src/main/java/com/github/copilot/sdk/json/ResumeSessionRequest.java
@@ -116,6 +116,12 @@ public final class ResumeSessionRequest {
@JsonProperty("requestElicitation")
private Boolean requestElicitation;
+ @JsonProperty("requestExitPlanMode")
+ private Boolean requestExitPlanMode;
+
+ @JsonProperty("requestAutoModeSwitch")
+ private Boolean requestAutoModeSwitch;
+
@JsonProperty("modelCapabilities")
private ModelCapabilitiesOverride modelCapabilities;
@@ -439,6 +445,28 @@ public void setRequestElicitation(Boolean requestElicitation) {
this.requestElicitation = requestElicitation;
}
+ /** Gets the requestExitPlanMode flag. @return the flag */
+ public Boolean getRequestExitPlanMode() {
+ return requestExitPlanMode;
+ }
+
+ /** Sets the requestExitPlanMode flag. @param requestExitPlanMode the flag */
+ public void setRequestExitPlanMode(Boolean requestExitPlanMode) {
+ this.requestExitPlanMode = requestExitPlanMode;
+ }
+
+ /** Gets the requestAutoModeSwitch flag. @return the flag */
+ public Boolean getRequestAutoModeSwitch() {
+ return requestAutoModeSwitch;
+ }
+
+ /**
+ * Sets the requestAutoModeSwitch flag. @param requestAutoModeSwitch the flag
+ */
+ public void setRequestAutoModeSwitch(Boolean requestAutoModeSwitch) {
+ this.requestAutoModeSwitch = requestAutoModeSwitch;
+ }
+
/** Gets the model capabilities override. @return the override */
public ModelCapabilitiesOverride getModelCapabilities() {
return modelCapabilities;
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 a4b2769b7..c26c1b5ba 100644
--- a/src/main/java/com/github/copilot/sdk/json/SessionConfig.java
+++ b/src/main/java/com/github/copilot/sdk/json/SessionConfig.java
@@ -66,6 +66,8 @@ public class SessionConfig {
private Consumer
+ * When provided, the server will route {@code exitPlanMode.request} callbacks
+ * to this handler.
+ *
+ * @param onExitPlanMode
+ * the exit-plan-mode handler
+ * @return this config instance for method chaining
+ * @see ExitPlanModeHandler
+ * @since 1.0.7
+ */
+ public SessionConfig setOnExitPlanMode(ExitPlanModeHandler onExitPlanMode) {
+ this.onExitPlanMode = onExitPlanMode;
+ return this;
+ }
+
+ /**
+ * Gets the auto-mode-switch handler.
+ *
+ * @return the auto-mode-switch handler, or {@code null}
+ * @since 1.0.7
+ */
+ public AutoModeSwitchHandler getOnAutoModeSwitch() {
+ return onAutoModeSwitch;
+ }
+
+ /**
+ * Sets a handler for auto-mode-switch requests from the server.
+ *
+ * When provided, the server will route {@code autoModeSwitch.request} callbacks
+ * to this handler.
+ *
+ * @param onAutoModeSwitch
+ * the auto-mode-switch handler
+ * @return this config instance for method chaining
+ * @see AutoModeSwitchHandler
+ * @since 1.0.7
+ */
+ public SessionConfig setOnAutoModeSwitch(AutoModeSwitchHandler onAutoModeSwitch) {
+ this.onAutoModeSwitch = onAutoModeSwitch;
+ return this;
+ }
+
/**
* Gets the GitHub token for per-session authentication.
*
@@ -891,6 +947,8 @@ public SessionConfig clone() {
copy.onEvent = this.onEvent;
copy.commands = this.commands != null ? new ArrayList<>(this.commands) : null;
copy.onElicitationRequest = this.onElicitationRequest;
+ copy.onExitPlanMode = this.onExitPlanMode;
+ copy.onAutoModeSwitch = this.onAutoModeSwitch;
copy.gitHubToken = this.gitHubToken;
return copy;
}
diff --git a/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java b/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java
index f7ce3aa4d..b93e3c74f 100644
--- a/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java
+++ b/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java
@@ -366,6 +366,34 @@ void resumeSessionConfigNewFieldsCloned() {
assertSame(defaultAgent, cloned.getDefaultAgent());
}
+ @Test
+ void sessionConfigCloneCopiesModeSwitchHandlers() {
+ SessionConfig original = new SessionConfig();
+ original.setOnExitPlanMode((request, invocation) -> CompletableFuture
+ .completedFuture(new com.github.copilot.sdk.json.ExitPlanModeResult()));
+ original.setOnAutoModeSwitch((request, invocation) -> CompletableFuture
+ .completedFuture(com.github.copilot.sdk.json.AutoModeSwitchResponse.NO));
+
+ SessionConfig cloned = original.clone();
+
+ assertSame(original.getOnExitPlanMode(), cloned.getOnExitPlanMode());
+ assertSame(original.getOnAutoModeSwitch(), cloned.getOnAutoModeSwitch());
+ }
+
+ @Test
+ void resumeSessionConfigCloneCopiesModeSwitchHandlers() {
+ ResumeSessionConfig original = new ResumeSessionConfig();
+ original.setOnExitPlanMode((request, invocation) -> CompletableFuture
+ .completedFuture(new com.github.copilot.sdk.json.ExitPlanModeResult()));
+ original.setOnAutoModeSwitch((request, invocation) -> CompletableFuture
+ .completedFuture(com.github.copilot.sdk.json.AutoModeSwitchResponse.NO));
+
+ ResumeSessionConfig cloned = original.clone();
+
+ assertSame(original.getOnExitPlanMode(), cloned.getOnExitPlanMode());
+ assertSame(original.getOnAutoModeSwitch(), cloned.getOnAutoModeSwitch());
+ }
+
@Test
void copilotClientOptionsSessionIdleTimeoutCloned() {
CopilotClientOptions original = new CopilotClientOptions();
diff --git a/src/test/java/com/github/copilot/sdk/SessionHandlerTest.java b/src/test/java/com/github/copilot/sdk/SessionHandlerTest.java
index 847734b4a..6b941f77c 100644
--- a/src/test/java/com/github/copilot/sdk/SessionHandlerTest.java
+++ b/src/test/java/com/github/copilot/sdk/SessionHandlerTest.java
@@ -341,4 +341,80 @@ void testRegisterToolsEmptyListClearsTools() {
session.registerTools(List.of());
assertNull(session.getTool("my_tool"));
}
+
+ // ===== Exit Plan Mode handler =====
+
+ @Test
+ void testHandleExitPlanModeRequestNoHandler() throws Exception {
+ var request = new com.github.copilot.sdk.json.ExitPlanModeRequest().setSummary("Test plan");
+
+ var result = session.handleExitPlanModeRequest(request).get();
+
+ assertTrue(result.isApproved());
+ }
+
+ @Test
+ void testHandleExitPlanModeRequestWithHandler() throws Exception {
+ session.registerExitPlanModeHandler((req, inv) -> {
+ assertEquals("handler-test-session", inv.getSessionId());
+ return CompletableFuture.completedFuture(new com.github.copilot.sdk.json.ExitPlanModeResult()
+ .setApproved(false).setSelectedAction("autopilot").setFeedback("Not yet"));
+ });
+ var request = new com.github.copilot.sdk.json.ExitPlanModeRequest().setSummary("Test plan")
+ .setActions(List.of("interactive", "autopilot")).setRecommendedAction("interactive");
+
+ var result = session.handleExitPlanModeRequest(request).get();
+
+ assertFalse(result.isApproved());
+ assertEquals("autopilot", result.getSelectedAction());
+ assertEquals("Not yet", result.getFeedback());
+ }
+
+ @Test
+ void testHandleExitPlanModeRequestHandlerException() throws Exception {
+ session.registerExitPlanModeHandler((req, inv) -> CompletableFuture.failedFuture(new RuntimeException("fail")));
+ var request = new com.github.copilot.sdk.json.ExitPlanModeRequest().setSummary("Plan");
+
+ var result = session.handleExitPlanModeRequest(request).get();
+
+ assertTrue(result.isApproved());
+ }
+
+ // ===== Auto Mode Switch handler =====
+
+ @Test
+ void testHandleAutoModeSwitchRequestNoHandler() throws Exception {
+ var request = new com.github.copilot.sdk.json.AutoModeSwitchRequest().setErrorCode("rate_limited");
+
+ var result = session.handleAutoModeSwitchRequest(request).get();
+
+ assertEquals(com.github.copilot.sdk.json.AutoModeSwitchResponse.NO, result);
+ }
+
+ @Test
+ void testHandleAutoModeSwitchRequestWithHandler() throws Exception {
+ session.registerAutoModeSwitchHandler((req, inv) -> {
+ assertEquals("handler-test-session", inv.getSessionId());
+ assertEquals("user_weekly_rate_limited", req.getErrorCode());
+ assertEquals(1.0, req.getRetryAfterSeconds());
+ return CompletableFuture.completedFuture(com.github.copilot.sdk.json.AutoModeSwitchResponse.YES);
+ });
+ var request = new com.github.copilot.sdk.json.AutoModeSwitchRequest().setErrorCode("user_weekly_rate_limited")
+ .setRetryAfterSeconds(1.0);
+
+ var result = session.handleAutoModeSwitchRequest(request).get();
+
+ assertEquals(com.github.copilot.sdk.json.AutoModeSwitchResponse.YES, result);
+ }
+
+ @Test
+ void testHandleAutoModeSwitchRequestHandlerException() throws Exception {
+ session.registerAutoModeSwitchHandler(
+ (req, inv) -> CompletableFuture.failedFuture(new RuntimeException("fail")));
+ var request = new com.github.copilot.sdk.json.AutoModeSwitchRequest().setErrorCode("rate_limited");
+
+ var result = session.handleAutoModeSwitchRequest(request).get();
+
+ assertEquals(com.github.copilot.sdk.json.AutoModeSwitchResponse.NO, result);
+ }
}
diff --git a/src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java b/src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java
index 0d13576eb..a0a4e2b1e 100644
--- a/src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java
+++ b/src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java
@@ -535,4 +535,144 @@ void testResumeRequestOmitsEnableSessionTelemetryWhenNull() throws Exception {
var json = mapper.writeValueAsString(request);
assertFalse(json.contains("enableSessionTelemetry"), "enableSessionTelemetry should be omitted when null");
}
+
+ // =========================================================================
+ // mode handler request flags
+ // =========================================================================
+
+ @Test
+ void testBuildCreateRequestSetsRequestExitPlanMode() {
+ var config = new SessionConfig().setOnExitPlanMode((request, invocation) -> CompletableFuture
+ .completedFuture(new com.github.copilot.sdk.json.ExitPlanModeResult()));
+
+ CreateSessionRequest request = SessionRequestBuilder.buildCreateRequest(config);
+
+ assertEquals(Boolean.TRUE, request.getRequestExitPlanMode());
+ }
+
+ @Test
+ void testBuildCreateRequestSetsRequestAutoModeSwitch() {
+ var config = new SessionConfig().setOnAutoModeSwitch((request, invocation) -> CompletableFuture
+ .completedFuture(com.github.copilot.sdk.json.AutoModeSwitchResponse.NO));
+
+ CreateSessionRequest request = SessionRequestBuilder.buildCreateRequest(config);
+
+ assertEquals(Boolean.TRUE, request.getRequestAutoModeSwitch());
+ }
+
+ @Test
+ void testBuildCreateRequestOmitsModeRequestFlagsWhenNull() {
+ var config = new SessionConfig();
+
+ CreateSessionRequest request = SessionRequestBuilder.buildCreateRequest(config);
+
+ assertNull(request.getRequestExitPlanMode());
+ assertNull(request.getRequestAutoModeSwitch());
+ }
+
+ @Test
+ void testBuildResumeRequestSetsRequestExitPlanMode() {
+ var config = new ResumeSessionConfig().setOnExitPlanMode((request, invocation) -> CompletableFuture
+ .completedFuture(new com.github.copilot.sdk.json.ExitPlanModeResult()));
+
+ ResumeSessionRequest request = SessionRequestBuilder.buildResumeRequest("test-session", config);
+
+ assertEquals(Boolean.TRUE, request.getRequestExitPlanMode());
+ }
+
+ @Test
+ void testBuildResumeRequestSetsRequestAutoModeSwitch() {
+ var config = new ResumeSessionConfig().setOnAutoModeSwitch((request, invocation) -> CompletableFuture
+ .completedFuture(com.github.copilot.sdk.json.AutoModeSwitchResponse.NO));
+
+ ResumeSessionRequest request = SessionRequestBuilder.buildResumeRequest("test-session", config);
+
+ assertEquals(Boolean.TRUE, request.getRequestAutoModeSwitch());
+ }
+
+ @Test
+ void configureSessionWithExitPlanModeHandler_registersHandler() {
+ CopilotSession session = new CopilotSession("session-1", null);
+
+ var config = new SessionConfig().setOnExitPlanMode((request, invocation) -> CompletableFuture
+ .completedFuture(new com.github.copilot.sdk.json.ExitPlanModeResult()));
+
+ SessionRequestBuilder.configureSession(session, config);
+ }
+
+ @Test
+ void configureSessionWithAutoModeSwitchHandler_registersHandler() {
+ CopilotSession session = new CopilotSession("session-1", null);
+
+ var config = new SessionConfig().setOnAutoModeSwitch((request, invocation) -> CompletableFuture
+ .completedFuture(com.github.copilot.sdk.json.AutoModeSwitchResponse.NO));
+
+ SessionRequestBuilder.configureSession(session, config);
+ }
+
+ @Test
+ void configureResumedSessionWithExitPlanModeHandler_registersHandler() {
+ CopilotSession session = new CopilotSession("session-1", null);
+
+ var config = new ResumeSessionConfig().setOnExitPlanMode((request, invocation) -> CompletableFuture
+ .completedFuture(new com.github.copilot.sdk.json.ExitPlanModeResult()));
+
+ SessionRequestBuilder.configureSession(session, config);
+ }
+
+ @Test
+ void configureResumedSessionWithAutoModeSwitchHandler_registersHandler() {
+ CopilotSession session = new CopilotSession("session-1", null);
+
+ var config = new ResumeSessionConfig().setOnAutoModeSwitch((request, invocation) -> CompletableFuture
+ .completedFuture(com.github.copilot.sdk.json.AutoModeSwitchResponse.NO));
+
+ SessionRequestBuilder.configureSession(session, config);
+ }
+
+ // =========================================================================
+ // mode request flags serialization
+ // =========================================================================
+
+ @Test
+ void testCreateRequestSerializesModeRequestFlags() throws Exception {
+ var config = new SessionConfig()
+ .setOnExitPlanMode((request, invocation) -> CompletableFuture
+ .completedFuture(new com.github.copilot.sdk.json.ExitPlanModeResult()))
+ .setOnAutoModeSwitch((request, invocation) -> CompletableFuture
+ .completedFuture(com.github.copilot.sdk.json.AutoModeSwitchResponse.NO));
+
+ CreateSessionRequest request = SessionRequestBuilder.buildCreateRequest(config);
+ var mapper = JsonRpcClient.getObjectMapper();
+ var json = mapper.writeValueAsString(request);
+
+ assertTrue(json.contains("\"requestExitPlanMode\":true"));
+ assertTrue(json.contains("\"requestAutoModeSwitch\":true"));
+ }
+
+ @Test
+ void testResumeRequestSerializesModeRequestFlags() throws Exception {
+ var config = new ResumeSessionConfig()
+ .setOnExitPlanMode((request, invocation) -> CompletableFuture
+ .completedFuture(new com.github.copilot.sdk.json.ExitPlanModeResult()))
+ .setOnAutoModeSwitch((request, invocation) -> CompletableFuture
+ .completedFuture(com.github.copilot.sdk.json.AutoModeSwitchResponse.NO));
+
+ ResumeSessionRequest request = SessionRequestBuilder.buildResumeRequest("test-session", config);
+ var mapper = JsonRpcClient.getObjectMapper();
+ var json = mapper.writeValueAsString(request);
+
+ assertTrue(json.contains("\"requestExitPlanMode\":true"));
+ assertTrue(json.contains("\"requestAutoModeSwitch\":true"));
+ }
+
+ @Test
+ void testAutoModeSwitchResponseSerialization() throws Exception {
+ var mapper = JsonRpcClient.getObjectMapper();
+
+ assertEquals("\"yes\"", mapper.writeValueAsString(com.github.copilot.sdk.json.AutoModeSwitchResponse.YES));
+ assertEquals("\"yes_always\"",
+ mapper.writeValueAsString(com.github.copilot.sdk.json.AutoModeSwitchResponse.YES_ALWAYS));
+ assertEquals("\"no\"", mapper.writeValueAsString(com.github.copilot.sdk.json.AutoModeSwitchResponse.NO));
+ }
}
Example Usage
+ *
+ * {@code
+ * AutoModeSwitchHandler handler = (request, invocation) -> {
+ * System.out.println("Rate limited: " + request.getErrorCode());
+ * return CompletableFuture.completedFuture(AutoModeSwitchResponse.YES);
+ * };
+ *
+ * var session = client.createSession(
+ * new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setOnAutoModeSwitch(handler))
+ * .get();
+ * }
+ *
+ * @since 1.0.7
+ */
+@FunctionalInterface
+public interface AutoModeSwitchHandler {
+
+ /**
+ * Handles an auto-mode-switch request from the agent.
+ *
+ * @param request
+ * the auto-mode-switch request containing the error code and
+ * retry-after information
+ * @param invocation
+ * context information about the invocation
+ * @return a future that resolves with the user's decision
+ */
+ CompletableFutureExample Usage
+ *
+ * {@code
+ * ExitPlanModeHandler handler = (request, invocation) -> {
+ * System.out.println("Plan summary: " + request.getSummary());
+ * return CompletableFuture
+ * .completedFuture(new ExitPlanModeResult().setApproved(true).setSelectedAction("interactive"));
+ * };
+ *
+ * var session = client
+ * .createSession(
+ * new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setOnExitPlanMode(handler))
+ * .get();
+ * }
+ *
+ * @since 1.0.7
+ */
+@FunctionalInterface
+public interface ExitPlanModeHandler {
+
+ /**
+ * Handles an exit-plan-mode request from the agent.
+ *
+ * @param request
+ * the exit-plan-mode request containing the plan summary and
+ * available actions
+ * @param invocation
+ * context information about the invocation
+ * @return a future that resolves with the user's decision
+ */
+ CompletableFuture