From b6dff3e40c2c7ff212d119f1cff63b5fb10e3faa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 23:12:17 +0000 Subject: [PATCH 01/13] Initial plan From 24b7a64836c1db7c886547d803bcd154d83eb998 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 23:27:08 +0000 Subject: [PATCH 02/13] Port enableSessionTelemetry option and SDK tracing diagnostics from reference implementation Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- .../com/github/copilot/sdk/CopilotClient.java | 40 +++++++++- .../github/copilot/sdk/CopilotSession.java | 26 +++++++ .../com/github/copilot/sdk/JsonRpcClient.java | 11 +++ .../github/copilot/sdk/LoggingHelpers.java | 77 +++++++++++++++++++ .../copilot/sdk/SessionRequestBuilder.java | 2 + .../sdk/json/CreateSessionRequest.java | 15 ++++ .../copilot/sdk/json/ResumeSessionConfig.java | 34 ++++++++ .../sdk/json/ResumeSessionRequest.java | 15 ++++ .../copilot/sdk/json/SessionConfig.java | 34 ++++++++ .../github/copilot/sdk/ConfigCloneTest.java | 38 +++++++++ .../sdk/SessionRequestBuilderTest.java | 70 +++++++++++++++++ 11 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/github/copilot/sdk/LoggingHelpers.java diff --git a/src/main/java/com/github/copilot/sdk/CopilotClient.java b/src/main/java/com/github/copilot/sdk/CopilotClient.java index 58d7b71dc4..5b988d9d2b 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotClient.java +++ b/src/main/java/com/github/copilot/sdk/CopilotClient.java @@ -188,6 +188,7 @@ private CompletableFuture startCore() { private Connection startCoreBody() { Process process = null; + long startNanos = System.nanoTime(); try { JsonRpcClient rpc; @@ -202,6 +203,9 @@ private Connection startCoreBody() { processInfo.port()); } + LoggingHelpers.logTiming(LOG, Level.FINE, "CopilotClient.start transport setup complete. Elapsed={Elapsed}", + startNanos); + Connection connection = new Connection(rpc, process, new ServerRpc(rpc::invoke)); // Register handlers for server-to-client calls @@ -211,10 +215,16 @@ private Connection startCoreBody() { // Verify protocol version verifyProtocolVersion(connection); + LoggingHelpers.logTiming(LOG, Level.FINE, + "CopilotClient.start protocol verification complete. Elapsed={Elapsed}", startNanos); - LOG.info("Copilot client connected"); + LoggingHelpers.logTiming(LOG, Level.FINE, "CopilotClient.start complete. Elapsed={Elapsed}", startNanos); return connection; } catch (Exception e) { + if (!(e instanceof java.util.concurrent.CancellationException)) { + LoggingHelpers.logTiming(LOG, Level.WARNING, e, "CopilotClient.start failed. Elapsed={Elapsed}", + startNanos); + } // Clean up the spawned process if connection setup failed if (process != null) { cleanupCliProcess(process); @@ -417,18 +427,23 @@ public CompletableFuture createSession(SessionConfig config) { + "new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)")); } return ensureConnected().thenCompose(connection -> { + long totalNanos = System.nanoTime(); // Pre-generate session ID so the session can be registered before the RPC call, // ensuring no events emitted by the CLI during creation are lost. String sessionId = config.getSessionId() != null ? config.getSessionId() : java.util.UUID.randomUUID().toString(); + long setupNanos = System.nanoTime(); var session = new CopilotSession(sessionId, connection.rpc); if (options.getExecutor() != null) { session.setExecutor(options.getExecutor()); } SessionRequestBuilder.configureSession(session, config); sessions.put(sessionId, session); + LoggingHelpers.logTiming(LOG, Level.FINE, + "CopilotClient.createSession local setup complete. Elapsed={Elapsed}, SessionId=" + sessionId, + setupNanos); // Extract transform callbacks from the system message config. // Callbacks are registered with the session; a wire-safe copy of the @@ -444,7 +459,12 @@ public CompletableFuture createSession(SessionConfig config) { request.setSystemMessage(extracted.wireSystemMessage()); } + long rpcNanos = System.nanoTime(); return connection.rpc.invoke("session.create", request, CreateSessionResponse.class).thenApply(response -> { + LoggingHelpers.logTiming(LOG, Level.FINE, + "CopilotClient.createSession session creation request completed. Elapsed={Elapsed}, SessionId=" + + sessionId, + rpcNanos); session.setWorkspacePath(response.workspacePath()); session.setCapabilities(response.capabilities()); // If the server returned a different sessionId (e.g. a v2 CLI that ignores @@ -455,9 +475,13 @@ public CompletableFuture createSession(SessionConfig config) { session.setActiveSessionId(returnedId); sessions.put(returnedId, session); } + LoggingHelpers.logTiming(LOG, Level.FINE, + "CopilotClient.createSession complete. Elapsed={Elapsed}, SessionId=" + sessionId, totalNanos); return session; }).exceptionally(ex -> { sessions.remove(sessionId); + LoggingHelpers.logTiming(LOG, Level.WARNING, ex, + "CopilotClient.createSession failed. Elapsed={Elapsed}, SessionId=" + sessionId, totalNanos); throw ex instanceof RuntimeException re ? re : new RuntimeException(ex); }); }); @@ -496,13 +520,18 @@ public CompletableFuture resumeSession(String sessionId, ResumeS + "new ResumeSessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)")); } return ensureConnected().thenCompose(connection -> { + long totalNanos = System.nanoTime(); // Register the session before the RPC call to avoid missing early events. + long setupNanos = System.nanoTime(); var session = new CopilotSession(sessionId, connection.rpc); if (options.getExecutor() != null) { session.setExecutor(options.getExecutor()); } SessionRequestBuilder.configureSession(session, config); sessions.put(sessionId, session); + LoggingHelpers.logTiming(LOG, Level.FINE, + "CopilotClient.resumeSession local setup complete. Elapsed={Elapsed}, SessionId=" + sessionId, + setupNanos); // Extract transform callbacks from the system message config. var extracted = SessionRequestBuilder.extractTransformCallbacks(config.getSystemMessage()); @@ -515,7 +544,12 @@ public CompletableFuture resumeSession(String sessionId, ResumeS request.setSystemMessage(extracted.wireSystemMessage()); } + long rpcNanos = System.nanoTime(); return connection.rpc.invoke("session.resume", request, ResumeSessionResponse.class).thenApply(response -> { + LoggingHelpers.logTiming(LOG, Level.FINE, + "CopilotClient.resumeSession session resume request completed. Elapsed={Elapsed}, SessionId=" + + sessionId, + rpcNanos); session.setWorkspacePath(response.workspacePath()); session.setCapabilities(response.capabilities()); // If the server returned a different sessionId than what was requested, re-key. @@ -525,9 +559,13 @@ public CompletableFuture resumeSession(String sessionId, ResumeS session.setActiveSessionId(returnedId); sessions.put(returnedId, session); } + LoggingHelpers.logTiming(LOG, Level.FINE, + "CopilotClient.resumeSession complete. Elapsed={Elapsed}, SessionId=" + sessionId, totalNanos); return session; }).exceptionally(ex -> { sessions.remove(sessionId); + LoggingHelpers.logTiming(LOG, Level.WARNING, ex, + "CopilotClient.resumeSession failed. Elapsed={Elapsed}, SessionId=" + sessionId, totalNanos); throw ex instanceof RuntimeException re ? re : new RuntimeException(ex); }); }); diff --git a/src/main/java/com/github/copilot/sdk/CopilotSession.java b/src/main/java/com/github/copilot/sdk/CopilotSession.java index c1374320cd..e4cb984644 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotSession.java +++ b/src/main/java/com/github/copilot/sdk/CopilotSession.java @@ -497,13 +497,24 @@ public CompletableFuture send(MessageOptions options) { */ public CompletableFuture sendAndWait(MessageOptions options, long timeoutMs) { ensureNotTerminated(); + long totalNanos = System.nanoTime(); var future = new CompletableFuture(); var lastAssistantMessage = new AtomicReference(); + var firstAssistantMessageLogged = new java.util.concurrent.atomic.AtomicBoolean(false); Consumer handler = evt -> { if (evt instanceof AssistantMessageEvent msg) { lastAssistantMessage.set(msg); + if (firstAssistantMessageLogged.compareAndSet(false, true)) { + LoggingHelpers.logTiming(LOG, Level.FINE, + "CopilotSession.sendAndWait first assistant message. Elapsed={Elapsed}, SessionId=" + + sessionId, + totalNanos); + } } else if (evt instanceof SessionIdleEvent) { + LoggingHelpers.logTiming(LOG, Level.FINE, + "CopilotSession.sendAndWait idle received. Elapsed={Elapsed}, SessionId=" + sessionId, + totalNanos); future.complete(lastAssistantMessage.get()); } else if (evt instanceof SessionErrorEvent errorEvent) { String message = errorEvent.getData() != null ? errorEvent.getData().message() : "session error"; @@ -568,8 +579,23 @@ public CompletableFuture sendAndWait(MessageOptions optio } if (!result.isDone()) { if (ex != null) { + if (ex instanceof TimeoutException) { + LoggingHelpers.logTiming(LOG, Level.WARNING, ex, + "CopilotSession.sendAndWait failed. Elapsed={Elapsed}, SessionId=" + sessionId + + ", CompletedBy=timeout", + totalNanos); + } else if (!(ex instanceof java.util.concurrent.CancellationException)) { + LoggingHelpers.logTiming(LOG, Level.WARNING, ex, + "CopilotSession.sendAndWait failed. Elapsed={Elapsed}, SessionId=" + sessionId + + ", CompletedBy=error", + totalNanos); + } result.completeExceptionally(ex); } else { + LoggingHelpers.logTiming( + LOG, Level.FINE, "CopilotSession.sendAndWait complete. Elapsed={Elapsed}, SessionId=" + + sessionId + ", CompletedBy=idle, AssistantMessageReceived=" + (r != null), + totalNanos); result.complete(r); } } diff --git a/src/main/java/com/github/copilot/sdk/JsonRpcClient.java b/src/main/java/com/github/copilot/sdk/JsonRpcClient.java index 66ab1726df..38f91fb3f7 100644 --- a/src/main/java/com/github/copilot/sdk/JsonRpcClient.java +++ b/src/main/java/com/github/copilot/sdk/JsonRpcClient.java @@ -104,6 +104,7 @@ public void registerMethodHandler(String method, BiConsumer ha * Sends a JSON-RPC request and waits for the response. */ public CompletableFuture invoke(String method, Object params, Class responseType) { + long timingNanos = System.nanoTime(); long id = requestIdCounter.incrementAndGet(); var future = new CompletableFuture(); pendingRequests.put(id, future); @@ -123,6 +124,10 @@ public CompletableFuture invoke(String method, Object params, Class re return future.thenApply(result -> { try { + LoggingHelpers.logTiming(LOG, Level.FINE, + "JsonRpc.invoke JSON-RPC request finished. Elapsed={Elapsed}, Method=" + method + ", RequestId=" + + id + ", Status=Succeeded", + timingNanos); if (responseType == Void.class || responseType == void.class) { return null; } @@ -130,6 +135,12 @@ public CompletableFuture invoke(String method, Object params, Class re } catch (JsonProcessingException e) { throw new CompletionException(e); } + }).exceptionally(ex -> { + LoggingHelpers.logTiming(LOG, Level.WARNING, ex, + "JsonRpc.invoke JSON-RPC request finished. Elapsed={Elapsed}, Method=" + method + ", RequestId=" + + id + ", Status=Failed", + timingNanos); + throw ex instanceof RuntimeException re ? re : new RuntimeException(ex); }); } diff --git a/src/main/java/com/github/copilot/sdk/LoggingHelpers.java b/src/main/java/com/github/copilot/sdk/LoggingHelpers.java new file mode 100644 index 0000000000..654494ef13 --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/LoggingHelpers.java @@ -0,0 +1,77 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk; + +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Internal helper for timing-based diagnostic logging. + */ +final class LoggingHelpers { + + private LoggingHelpers() { + // Utility class + } + + /** + * Formats elapsed time as a human-readable duration string. + * + * @param startNanos + * the start time from {@link System#nanoTime()} + * @return formatted duration (e.g. "PT0.123S") + */ + static String formatElapsed(long startNanos) { + long elapsedNanos = System.nanoTime() - startNanos; + long millis = TimeUnit.NANOSECONDS.toMillis(elapsedNanos); + return String.format("PT%d.%03dS", millis / 1000, millis % 1000); + } + + /** + * Logs a timing message at the given level if the logger accepts it. + * + * @param logger + * the logger to use + * @param level + * the log level + * @param message + * the message template + * @param startNanos + * the start time from {@link System#nanoTime()} + */ + static void logTiming(Logger logger, Level level, String message, long startNanos) { + if (!logger.isLoggable(level)) { + return; + } + logger.log(level, message.replace("{Elapsed}", formatElapsed(startNanos))); + } + + /** + * Logs a timing message at the given level with an exception. + * + * @param logger + * the logger to use + * @param level + * the log level + * @param exception + * the exception, may be {@code null} + * @param message + * the message template + * @param startNanos + * the start time from {@link System#nanoTime()} + */ + static void logTiming(Logger logger, Level level, Throwable exception, String message, long startNanos) { + if (!logger.isLoggable(level)) { + return; + } + String formatted = message.replace("{Elapsed}", formatElapsed(startNanos)); + if (exception != null) { + logger.log(level, formatted, exception); + } else { + logger.log(level, formatted); + } + } +} diff --git a/src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java b/src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java index 91dbd46424..fd96966906 100644 --- a/src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java +++ b/src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java @@ -111,6 +111,7 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config, String sess request.setAvailableTools(config.getAvailableTools()); request.setExcludedTools(config.getExcludedTools()); request.setProvider(config.getProvider()); + request.setEnableSessionTelemetry(config.getEnableSessionTelemetry()); request.setRequestUserInput(config.getOnUserInputRequest() != null ? true : null); request.setHooks(config.getHooks() != null && config.getHooks().hasHooks() ? true : null); request.setWorkingDirectory(config.getWorkingDirectory()); @@ -187,6 +188,7 @@ static ResumeSessionRequest buildResumeRequest(String sessionId, ResumeSessionCo request.setAvailableTools(config.getAvailableTools()); request.setExcludedTools(config.getExcludedTools()); request.setProvider(config.getProvider()); + request.setEnableSessionTelemetry(config.getEnableSessionTelemetry()); request.setRequestUserInput(config.getOnUserInputRequest() != null ? true : null); request.setHooks(config.getHooks() != null && config.getHooks().hasHooks() ? true : null); request.setWorkingDirectory(config.getWorkingDirectory()); 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 5243f99ec2..3a0b90f19a 100644 --- a/src/main/java/com/github/copilot/sdk/json/CreateSessionRequest.java +++ b/src/main/java/com/github/copilot/sdk/json/CreateSessionRequest.java @@ -52,6 +52,9 @@ public final class CreateSessionRequest { @JsonProperty("provider") private ProviderConfig provider; + @JsonProperty("enableSessionTelemetry") + private Boolean enableSessionTelemetry; + @JsonProperty("requestPermission") private Boolean requestPermission; @@ -207,6 +210,18 @@ public void setProvider(ProviderConfig provider) { this.provider = provider; } + /** Gets enable session telemetry flag. @return the flag */ + public Boolean getEnableSessionTelemetry() { + return enableSessionTelemetry; + } + + /** + * Sets enable session telemetry flag. @param enableSessionTelemetry the flag + */ + public void setEnableSessionTelemetry(Boolean enableSessionTelemetry) { + this.enableSessionTelemetry = enableSessionTelemetry; + } + /** Gets request permission flag. @return the flag */ public Boolean getRequestPermission() { return requestPermission; 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 3f0a0706d6..ce368d1736 100644 --- a/src/main/java/com/github/copilot/sdk/json/ResumeSessionConfig.java +++ b/src/main/java/com/github/copilot/sdk/json/ResumeSessionConfig.java @@ -43,6 +43,7 @@ public class ResumeSessionConfig { private List availableTools; private List excludedTools; private ProviderConfig provider; + private Boolean enableSessionTelemetry; private String reasoningEffort; private ModelCapabilitiesOverride modelCapabilities; private PermissionHandler onPermissionRequest; @@ -229,6 +230,38 @@ public ResumeSessionConfig setProvider(ProviderConfig provider) { return this; } + /** + * Enables or disables internal session telemetry for this session. When + * {@code false}, disables session telemetry. When {@code null} (the default) or + * {@code true}, telemetry is enabled for GitHub-authenticated sessions. When a + * custom {@link ProviderConfig} (BYOK) is configured, session telemetry is + * always disabled regardless of this setting. This is independent of + * {@link com.github.copilot.sdk.json.CopilotClientOptions#getTelemetry() + * CopilotClientOptions.Telemetry}, which configures OpenTelemetry export for + * observability. + * + * @return whether session telemetry is enabled + */ + public Boolean getEnableSessionTelemetry() { + return enableSessionTelemetry; + } + + /** + * Enables or disables internal session telemetry for this session. When + * {@code false}, disables session telemetry. When {@code null} (the default) or + * {@code true}, telemetry is enabled for GitHub-authenticated sessions. When a + * custom {@link ProviderConfig} (BYOK) is configured, session telemetry is + * always disabled regardless of this setting. + * + * @param enableSessionTelemetry + * whether to enable session telemetry + * @return this config for method chaining + */ + public ResumeSessionConfig setEnableSessionTelemetry(Boolean enableSessionTelemetry) { + this.enableSessionTelemetry = enableSessionTelemetry; + return this; + } + /** * Gets the reasoning effort level. * @@ -781,6 +814,7 @@ public ResumeSessionConfig clone() { copy.availableTools = this.availableTools != null ? new ArrayList<>(this.availableTools) : null; copy.excludedTools = this.excludedTools != null ? new ArrayList<>(this.excludedTools) : null; copy.provider = this.provider; + copy.enableSessionTelemetry = this.enableSessionTelemetry; copy.reasoningEffort = this.reasoningEffort; copy.modelCapabilities = this.modelCapabilities; copy.onPermissionRequest = this.onPermissionRequest; 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 c5931c275f..9b2c17f1a4 100644 --- a/src/main/java/com/github/copilot/sdk/json/ResumeSessionRequest.java +++ b/src/main/java/com/github/copilot/sdk/json/ResumeSessionRequest.java @@ -53,6 +53,9 @@ public final class ResumeSessionRequest { @JsonProperty("provider") private ProviderConfig provider; + @JsonProperty("enableSessionTelemetry") + private Boolean enableSessionTelemetry; + @JsonProperty("requestPermission") private Boolean requestPermission; @@ -214,6 +217,18 @@ public void setProvider(ProviderConfig provider) { this.provider = provider; } + /** Gets enable session telemetry flag. @return the flag */ + public Boolean getEnableSessionTelemetry() { + return enableSessionTelemetry; + } + + /** + * Sets enable session telemetry flag. @param enableSessionTelemetry the flag + */ + public void setEnableSessionTelemetry(Boolean enableSessionTelemetry) { + this.enableSessionTelemetry = enableSessionTelemetry; + } + /** Gets request permission flag. @return the flag */ public Boolean getRequestPermission() { return requestPermission; 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 4d571990c6..e612d0f8ce 100644 --- a/src/main/java/com/github/copilot/sdk/json/SessionConfig.java +++ b/src/main/java/com/github/copilot/sdk/json/SessionConfig.java @@ -45,6 +45,7 @@ public class SessionConfig { private List availableTools; private List excludedTools; private ProviderConfig provider; + private Boolean enableSessionTelemetry; private PermissionHandler onPermissionRequest; private UserInputHandler onUserInputRequest; private SessionHooks hooks; @@ -283,6 +284,38 @@ public SessionConfig setProvider(ProviderConfig provider) { return this; } + /** + * Enables or disables internal session telemetry for this session. When + * {@code false}, disables session telemetry. When {@code null} (the default) or + * {@code true}, telemetry is enabled for GitHub-authenticated sessions. When a + * custom {@link ProviderConfig} (BYOK) is configured, session telemetry is + * always disabled regardless of this setting. This is independent of + * {@link com.github.copilot.sdk.json.CopilotClientOptions#getTelemetry() + * CopilotClientOptions.Telemetry}, which configures OpenTelemetry export for + * observability. + * + * @return whether session telemetry is enabled + */ + public Boolean getEnableSessionTelemetry() { + return enableSessionTelemetry; + } + + /** + * Enables or disables internal session telemetry for this session. When + * {@code false}, disables session telemetry. When {@code null} (the default) or + * {@code true}, telemetry is enabled for GitHub-authenticated sessions. When a + * custom {@link ProviderConfig} (BYOK) is configured, session telemetry is + * always disabled regardless of this setting. + * + * @param enableSessionTelemetry + * whether to enable session telemetry + * @return this config instance for method chaining + */ + public SessionConfig setEnableSessionTelemetry(Boolean enableSessionTelemetry) { + this.enableSessionTelemetry = enableSessionTelemetry; + return this; + } + /** * Gets the permission request handler. * @@ -835,6 +868,7 @@ public SessionConfig clone() { copy.availableTools = this.availableTools != null ? new ArrayList<>(this.availableTools) : null; copy.excludedTools = this.excludedTools != null ? new ArrayList<>(this.excludedTools) : null; copy.provider = this.provider; + copy.enableSessionTelemetry = this.enableSessionTelemetry; copy.onPermissionRequest = this.onPermissionRequest; copy.onUserInputRequest = this.onUserInputRequest; copy.hooks = this.hooks; diff --git a/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java b/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java index b060c278ab..f7ce3aa4de 100644 --- a/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java +++ b/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java @@ -194,6 +194,44 @@ void messageOptionsCloneBasic() { assertEquals(original.getMode(), cloned.getMode()); } + @Test + void sessionConfigEnableSessionTelemetryCopied() { + SessionConfig original = new SessionConfig(); + original.setEnableSessionTelemetry(false); + + SessionConfig cloned = original.clone(); + + assertFalse(cloned.getEnableSessionTelemetry()); + } + + @Test + void sessionConfigEnableSessionTelemetryDefaultIsNull() { + SessionConfig original = new SessionConfig(); + + SessionConfig cloned = original.clone(); + + assertNull(cloned.getEnableSessionTelemetry()); + } + + @Test + void resumeSessionConfigEnableSessionTelemetryCopied() { + ResumeSessionConfig original = new ResumeSessionConfig(); + original.setEnableSessionTelemetry(false); + + ResumeSessionConfig cloned = original.clone(); + + assertFalse(cloned.getEnableSessionTelemetry()); + } + + @Test + void resumeSessionConfigEnableSessionTelemetryDefaultIsNull() { + ResumeSessionConfig original = new ResumeSessionConfig(); + + ResumeSessionConfig cloned = original.clone(); + + assertNull(cloned.getEnableSessionTelemetry()); + } + @Test void clonePreservesNullFields() { CopilotClientOptions opts = new CopilotClientOptions(); diff --git a/src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java b/src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java index a79c02334c..0d13576eb8 100644 --- a/src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java +++ b/src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java @@ -86,6 +86,20 @@ void testBuildCreateRequestSetsClientName() { assertEquals("my-app", request.getClientName()); } + @Test + void testBuildCreateRequestForwardsEnableSessionTelemetryWhenFalse() { + var config = new SessionConfig().setEnableSessionTelemetry(false); + CreateSessionRequest request = SessionRequestBuilder.buildCreateRequest(config); + assertFalse(request.getEnableSessionTelemetry()); + } + + @Test + void testBuildCreateRequestOmitsEnableSessionTelemetryWhenNotSet() { + var config = new SessionConfig(); + CreateSessionRequest request = SessionRequestBuilder.buildCreateRequest(config); + assertNull(request.getEnableSessionTelemetry()); + } + // ========================================================================= // buildResumeRequest // ========================================================================= @@ -99,6 +113,20 @@ void testBuildResumeRequestNullConfig() { assertEquals("direct", request.getEnvValueMode(), "envValueMode should be 'direct' even for null config"); } + @Test + void testBuildResumeRequestForwardsEnableSessionTelemetryWhenFalse() { + var config = new ResumeSessionConfig().setEnableSessionTelemetry(false); + ResumeSessionRequest request = SessionRequestBuilder.buildResumeRequest("sid-1", config); + assertFalse(request.getEnableSessionTelemetry()); + } + + @Test + void testBuildResumeRequestOmitsEnableSessionTelemetryWhenNotSet() { + var config = new ResumeSessionConfig(); + ResumeSessionRequest request = SessionRequestBuilder.buildResumeRequest("sid-1", config); + assertNull(request.getEnableSessionTelemetry()); + } + @Test void testBuildResumeRequestWithTools() { var tool = ToolDefinition.create("my_tool", "A tool", Map.of("type", "object"), @@ -465,4 +493,46 @@ void testBuildResumeRequestPropagatesInstructionDirectories() { assertEquals(dirs, request.getInstructionDirectories()); } + + // ========================================================================= + // enableSessionTelemetry serialization + // ========================================================================= + + @Test + void testCreateRequestSerializesEnableSessionTelemetryWhenFalse() throws Exception { + var config = new SessionConfig().setEnableSessionTelemetry(false); + CreateSessionRequest request = SessionRequestBuilder.buildCreateRequest(config); + var mapper = JsonRpcClient.getObjectMapper(); + var json = mapper.writeValueAsString(request); + assertTrue(json.contains("\"enableSessionTelemetry\":false"), + "enableSessionTelemetry should be serialized when set to false"); + } + + @Test + void testCreateRequestOmitsEnableSessionTelemetryWhenNull() throws Exception { + var config = new SessionConfig(); + CreateSessionRequest request = SessionRequestBuilder.buildCreateRequest(config); + var mapper = JsonRpcClient.getObjectMapper(); + var json = mapper.writeValueAsString(request); + assertFalse(json.contains("enableSessionTelemetry"), "enableSessionTelemetry should be omitted when null"); + } + + @Test + void testResumeRequestSerializesEnableSessionTelemetryWhenFalse() throws Exception { + var config = new ResumeSessionConfig().setEnableSessionTelemetry(false); + ResumeSessionRequest request = SessionRequestBuilder.buildResumeRequest("sid-tel", config); + var mapper = JsonRpcClient.getObjectMapper(); + var json = mapper.writeValueAsString(request); + assertTrue(json.contains("\"enableSessionTelemetry\":false"), + "enableSessionTelemetry should be serialized when set to false"); + } + + @Test + void testResumeRequestOmitsEnableSessionTelemetryWhenNull() throws Exception { + var config = new ResumeSessionConfig(); + ResumeSessionRequest request = SessionRequestBuilder.buildResumeRequest("sid-tel", config); + var mapper = JsonRpcClient.getObjectMapper(); + var json = mapper.writeValueAsString(request); + assertFalse(json.contains("enableSessionTelemetry"), "enableSessionTelemetry should be omitted when null"); + } } From 3788d8e2f72e384adc64c1f069e2a2c414421b63 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 23:49:15 +0000 Subject: [PATCH 03/13] Update .lastmerge to 066a69c1e849adf1bd98564ab1b52316ec471182, sync pom.xml CLI version, and update scripts/codegen @github/copilot version Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- .lastmerge | 2 +- pom.xml | 2 +- scripts/codegen/package-lock.json | 56 +++++++++++++++---------------- scripts/codegen/package.json | 2 +- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/.lastmerge b/.lastmerge index b3b7aa13d2..142f4f7ab1 100644 --- a/.lastmerge +++ b/.lastmerge @@ -1 +1 @@ -06bfc5d41d72b76527456dee0bd78fe4697bac86 +066a69c1e849adf1bd98564ab1b52316ec471182 diff --git a/pom.xml b/pom.xml index ff35b8ee2e..b1c4b04517 100644 --- a/pom.xml +++ b/pom.xml @@ -94,7 +94,7 @@ reference-impl-sync workflow and deal with the subsequent PR. --> - ^1.0.43-0 + ^1.0.44-2 diff --git a/scripts/codegen/package-lock.json b/scripts/codegen/package-lock.json index a8be998438..f414fec716 100644 --- a/scripts/codegen/package-lock.json +++ b/scripts/codegen/package-lock.json @@ -6,7 +6,7 @@ "": { "name": "copilot-sdk-java-codegen", "dependencies": { - "@github/copilot": "^1.0.43-0", + "@github/copilot": "^1.0.44-2", "json-schema": "^0.4.0", "tsx": "^4.20.6" } @@ -428,26 +428,26 @@ } }, "node_modules/@github/copilot": { - "version": "1.0.43", - "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.43.tgz", - "integrity": "sha512-2FO825Aq4bwmHcXVyplW+CpZaJFUYjqtqjBGnueM31gu4ufn6ReurzB2swBQ6bn4Pquyy2KeodMRPpT6JaLMhw==", + "version": "1.0.44-2", + "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.44-2.tgz", + "integrity": "sha512-MUIR4w+oXjbg1jwUS8B86eMd/bV2gVKZ61a/aEUE4gUrFFpGXO0tNk9OkfLSH5cmlhJY6lzMzb+kKQWoeAbbNQ==", "license": "SEE LICENSE IN LICENSE.md", "bin": { "copilot": "npm-loader.js" }, "optionalDependencies": { - "@github/copilot-darwin-arm64": "1.0.43", - "@github/copilot-darwin-x64": "1.0.43", - "@github/copilot-linux-arm64": "1.0.43", - "@github/copilot-linux-x64": "1.0.43", - "@github/copilot-win32-arm64": "1.0.43", - "@github/copilot-win32-x64": "1.0.43" + "@github/copilot-darwin-arm64": "1.0.44-2", + "@github/copilot-darwin-x64": "1.0.44-2", + "@github/copilot-linux-arm64": "1.0.44-2", + "@github/copilot-linux-x64": "1.0.44-2", + "@github/copilot-win32-arm64": "1.0.44-2", + "@github/copilot-win32-x64": "1.0.44-2" } }, "node_modules/@github/copilot-darwin-arm64": { - "version": "1.0.43", - "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.43.tgz", - "integrity": "sha512-VMaWfoUwIt19TGzmvTv/In5ITgFWfu91ZILt4Lb77gSmVbwbs+DahP2lbvM1s/GtGwOknwhOJLp4q2WMgK3CoQ==", + "version": "1.0.44-2", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.44-2.tgz", + "integrity": "sha512-6o/pvew0FZJG+8saG1K/L1pUIvpz4AWkZitiqH36tDfXdXKx/PUQ+zaFg/KPeHNnxtal5OdE/7iyrJwIqm2gPg==", "cpu": [ "arm64" ], @@ -461,9 +461,9 @@ } }, "node_modules/@github/copilot-darwin-x64": { - "version": "1.0.43", - "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.43.tgz", - "integrity": "sha512-lCxg75zbgtWggb1p+IHhlhmulQj7BKIc+9pUsTwJ3Mjt51kiUYmD6LF2BD1/Ed4M3GMumSu4UTSIv9pL96n0Wg==", + "version": "1.0.44-2", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.44-2.tgz", + "integrity": "sha512-OMNoLNFYUynB4wiplSh4gtD5zVlvfWMKc0jKQ0oItJLGO8GRL9X0ZB2ONB+7JpVvPidz0Yy4+jU0zWNXEjMM5g==", "cpu": [ "x64" ], @@ -477,9 +477,9 @@ } }, "node_modules/@github/copilot-linux-arm64": { - "version": "1.0.43", - "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.43.tgz", - "integrity": "sha512-Jr1rvt/Syz5oVSiU53keRKEV8f5xTLkmiB2qasAV6Emk7K82/BZW5HfW8cDadfHnlAS1+UVPpoO+8ykgx4dikw==", + "version": "1.0.44-2", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.44-2.tgz", + "integrity": "sha512-5WGRADU08hqBTWmQ6JVOYMximzsXGuOdFF4GFRQqfsCR8k4RE8fdPWQJa92BpqMgGWwEVPemq0wB3D4hDM5eWw==", "cpu": [ "arm64" ], @@ -493,9 +493,9 @@ } }, "node_modules/@github/copilot-linux-x64": { - "version": "1.0.43", - "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.43.tgz", - "integrity": "sha512-uyWyPpcwMC1tIHJTA1OPzIm1i/Eeku0NjFzPYnFvpfGug9pkL4xcUr8A2UNl8cVvxq/VQMwtYckV3G12ySJTFw==", + "version": "1.0.44-2", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.44-2.tgz", + "integrity": "sha512-4ZnA2QxEwgrdCePdS5OjuksEGFpJrXgofuELANCpDSHwR3eTV7PynVyqhG6Et7ktN2KzHk7zf8kvtiWVCOxvFg==", "cpu": [ "x64" ], @@ -509,9 +509,9 @@ } }, "node_modules/@github/copilot-win32-arm64": { - "version": "1.0.43", - "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.43.tgz", - "integrity": "sha512-vY3rwkW1h7ixSqYd9XT/xGjxkepvQVJK2q1sYhSPBN4Wvuk37fRjN7ox3QU1lhpxlYQMc/g+ZR58u5cx31n1lw==", + "version": "1.0.44-2", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.44-2.tgz", + "integrity": "sha512-klgSdBZblz9O8BRnTh9uk9uO/INQwVeTBagXuJO7MrZ7JCfBVJyFUYky2tKIjFxlwefyhrRZuniqYeOI9fQc+A==", "cpu": [ "arm64" ], @@ -525,9 +525,9 @@ } }, "node_modules/@github/copilot-win32-x64": { - "version": "1.0.43", - "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.43.tgz", - "integrity": "sha512-AjGsebDbJmBxe9FFf2McSN5r2Joi8cFY879lxaQaXxfGjzOHblzvbhflbsX9x2GnvCfDdDiow413WvOGqKDH8g==", + "version": "1.0.44-2", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.44-2.tgz", + "integrity": "sha512-ziq3abdbMCqtAqdiEWWf6cn0whlWss7rC9VMsO/Vx2gjSEVCeJkmIiRiQO45WikheyXyxEmCTAvOwZLQvs+I9g==", "cpu": [ "x64" ], diff --git a/scripts/codegen/package.json b/scripts/codegen/package.json index 103db29135..66d5565e86 100644 --- a/scripts/codegen/package.json +++ b/scripts/codegen/package.json @@ -7,7 +7,7 @@ "generate:java": "tsx java.ts" }, "dependencies": { - "@github/copilot": "^1.0.43-0", + "@github/copilot": "^1.0.44-2", "json-schema": "^0.4.0", "tsx": "^4.20.6" } From 43f8dfb9df6c8f80a4c677d34c95a3e892235f2d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 01:05:41 +0000 Subject: [PATCH 04/13] Regenerate codegen output Auto-committed by codegen-check workflow. --- .../copilot/sdk/generated/AbortEvent.java | 4 +- .../copilot/sdk/generated/AbortReason.java | 37 +++++++++++++++++++ .../sdk/generated/SubagentStartedEvent.java | 4 +- 3 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 src/generated/java/com/github/copilot/sdk/generated/AbortReason.java diff --git a/src/generated/java/com/github/copilot/sdk/generated/AbortEvent.java b/src/generated/java/com/github/copilot/sdk/generated/AbortEvent.java index d236f04f0b..16cfabc0e6 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/AbortEvent.java +++ b/src/generated/java/com/github/copilot/sdk/generated/AbortEvent.java @@ -35,8 +35,8 @@ public final class AbortEvent extends SessionEvent { @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record AbortEventData( - /** Reason the current turn was aborted (e.g., "user initiated") */ - @JsonProperty("reason") String reason + /** Finite reason code describing why the current turn was aborted */ + @JsonProperty("reason") AbortReason reason ) { } } diff --git a/src/generated/java/com/github/copilot/sdk/generated/AbortReason.java b/src/generated/java/com/github/copilot/sdk/generated/AbortReason.java new file mode 100644 index 0000000000..2bb93b8865 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/AbortReason.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.sdk.generated; + +import javax.annotation.processing.Generated; + +/** + * Finite reason code describing why the current turn was aborted + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum AbortReason { + /** The {@code user_initiated} variant. */ + USER_INITIATED("user_initiated"), + /** The {@code remote_command} variant. */ + REMOTE_COMMAND("remote_command"), + /** The {@code user_abort} variant. */ + USER_ABORT("user_abort"); + + private final String value; + AbortReason(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static AbortReason fromValue(String value) { + for (AbortReason v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown AbortReason value: " + value); + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SubagentStartedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SubagentStartedEvent.java index 6e9926bd4e..4bc945c9c0 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/SubagentStartedEvent.java +++ b/src/generated/java/com/github/copilot/sdk/generated/SubagentStartedEvent.java @@ -42,7 +42,9 @@ public record SubagentStartedEventData( /** Human-readable display name of the sub-agent */ @JsonProperty("agentDisplayName") String agentDisplayName, /** Description of what the sub-agent does */ - @JsonProperty("agentDescription") String agentDescription + @JsonProperty("agentDescription") String agentDescription, + /** Model the sub-agent will run with, when known at start. Surfaced in the timeline for auto-selected sub-agents (e.g. rubber-duck). */ + @JsonProperty("model") String model ) { } } From ea310d6eda7c9c587ae905ea1051f5960ae082c3 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Thu, 7 May 2026 17:31:23 -0400 Subject: [PATCH 05/13] On branch edburns/resolve-fake-test-time-token-failures modified: src/test/java/com/github/copilot/sdk/E2ETestContext.java modified: src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Given that the live API was never used, I see no reason why we should condition the setting of fake tokens on the runtime environment (CI vs local). The replaying proxy intercepts everything regardless of environment. The fake token just satisfies the CLI's startup check — it's never sent to a real API. The `GITHUB_ACTIONS` guard is unnecessary and is what broke local runs. Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- .../github/copilot/sdk/E2ETestContext.java | 22 ++++--------------- .../copilot/sdk/ExecutorWiringTest.java | 8 ++----- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/src/test/java/com/github/copilot/sdk/E2ETestContext.java b/src/test/java/com/github/copilot/sdk/E2ETestContext.java index 58e8400e34..9680148ff6 100644 --- a/src/test/java/com/github/copilot/sdk/E2ETestContext.java +++ b/src/test/java/com/github/copilot/sdk/E2ETestContext.java @@ -270,15 +270,10 @@ public Map getEnvironment() { env.put("REQUESTS_CA_BUNDLE", caFile); env.put("CURL_CA_BUNDLE", caFile); env.put("GIT_SSL_CAINFO", caFile); - env.put("GH_TOKEN", ""); - env.put("GITHUB_TOKEN", ""); - env.put("GH_ENTERPRISE_TOKEN", ""); - env.put("GITHUB_ENTERPRISE_TOKEN", ""); - } - - if ("true".equals(System.getenv("GITHUB_ACTIONS"))) { env.put("GH_TOKEN", "fake-token-for-e2e-tests"); env.put("GITHUB_TOKEN", "fake-token-for-e2e-tests"); + env.put("GH_ENTERPRISE_TOKEN", ""); + env.put("GITHUB_ENTERPRISE_TOKEN", ""); } return env; @@ -291,13 +286,7 @@ public Map getEnvironment() { */ public CopilotClient createClient() { CopilotClientOptions options = new CopilotClientOptions().setCliPath(cliPath).setCwd(workDir.toString()) - .setEnvironment(getEnvironment()); - - // In CI (GitHub Actions), use a fake token to avoid auth issues - String ci = System.getenv("GITHUB_ACTIONS"); - if (ci != null && !ci.isEmpty()) { - options.setGitHubToken("fake-token-for-e2e-tests"); - } + .setEnvironment(getEnvironment()).setGitHubToken("fake-token-for-e2e-tests"); return new CopilotClient(options); } @@ -321,10 +310,7 @@ public CopilotClient createClient(CopilotClientOptions options) { if (options.getEnvironment() == null || options.getEnvironment().isEmpty()) { options.setEnvironment(getEnvironment()); } - - // In CI (GitHub Actions), use a fake token to avoid auth issues - String ci = System.getenv("GITHUB_ACTIONS"); - if (ci != null && !ci.isEmpty() && options.getGitHubToken() == null) { + if (options.getGitHubToken() == null) { options.setGitHubToken("fake-token-for-e2e-tests"); } diff --git a/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java b/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java index f836be89a3..a5eb3a62dc 100644 --- a/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java +++ b/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java @@ -87,12 +87,8 @@ int getTaskCount() { private CopilotClientOptions createOptionsWithExecutor(TrackingExecutor executor) { CopilotClientOptions options = new CopilotClientOptions().setCliPath(ctx.getCliPath()) - .setCwd(ctx.getWorkDir().toString()).setEnvironment(ctx.getEnvironment()).setExecutor(executor); - - String ci = System.getenv("GITHUB_ACTIONS"); - if (ci != null && !ci.isEmpty()) { - options.setGitHubToken("fake-token-for-e2e-tests"); - } + .setCwd(ctx.getWorkDir().toString()).setEnvironment(ctx.getEnvironment()).setExecutor(executor) + .setGitHubToken("fake-token-for-e2e-tests"); return options; } From 18aea824b42be658aa6855a6df1f511ac6e86212 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Thu, 7 May 2026 19:26:36 -0400 Subject: [PATCH 06/13] On branch edburns/resolve-fake-test-time-token-failures modified: pom.xml - Force deterministic ordering. modified: src/test/java/com/github/copilot/sdk/CapiProxy.java - Pass through the fake token concept. modified: src/test/java/com/github/copilot/sdk/CompactionTest.java - Skip flaky test, see https://github.com/github/copilot-sdk/issues/1227 Signed-off-by: Ed Burns Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- pom.xml | 1 + src/test/java/com/github/copilot/sdk/CapiProxy.java | 4 ++++ src/test/java/com/github/copilot/sdk/CompactionTest.java | 7 +++++++ 3 files changed, 12 insertions(+) diff --git a/pom.xml b/pom.xml index b1c4b04517..bbf0e8bc6e 100644 --- a/pom.xml +++ b/pom.xml @@ -319,6 +319,7 @@ maven-surefire-plugin 3.5.5 + alphabetical ${testExecutionAgentArgs} ${surefire.jvm.args} 2 @@ -346,6 +345,30 @@ ${copilot.cli.path} + + + + isolated-resume-tests + test + + test + + + isolated-resume + + + + + default-test + + isolated-resume + + + diff --git a/src/test/java/com/github/copilot/sdk/CopilotSessionTest.java b/src/test/java/com/github/copilot/sdk/CopilotSessionTest.java index 1eb6caa845..fc44880cf8 100644 --- a/src/test/java/com/github/copilot/sdk/CopilotSessionTest.java +++ b/src/test/java/com/github/copilot/sdk/CopilotSessionTest.java @@ -20,7 +20,7 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import com.github.copilot.sdk.generated.SessionEvent; @@ -307,7 +307,7 @@ void testShouldResumeSessionUsingTheSameClient() throws Exception { * @see Snapshot: session/should_resume_a_session_using_a_new_client */ @Test - @Disabled("Passes in isolation but times out in full suite due to test interaction (state leakage or process contention)") + @Tag("isolated-resume") void testShouldResumeSessionUsingNewClient() throws Exception { ctx.configureForTest("session", "should_resume_a_session_using_a_new_client"); diff --git a/src/test/java/com/github/copilot/sdk/StreamingFidelityTest.java b/src/test/java/com/github/copilot/sdk/StreamingFidelityTest.java index 75a13e47f1..d3df63eb06 100644 --- a/src/test/java/com/github/copilot/sdk/StreamingFidelityTest.java +++ b/src/test/java/com/github/copilot/sdk/StreamingFidelityTest.java @@ -14,7 +14,7 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import com.github.copilot.sdk.generated.SessionEvent; @@ -140,7 +140,7 @@ void testShouldNotProduceDeltasWhenStreamingIsDisabled() throws Exception { * @see Snapshot: streaming_fidelity/should_produce_deltas_after_session_resume */ @Test - @Disabled("Passes in isolation but times out in full suite due to test interaction (state leakage or process contention)") + @Tag("isolated-resume") void testShouldProduceDeltasAfterSessionResume() throws Exception { ctx.configureForTest("streaming_fidelity", "should_produce_deltas_after_session_resume"); @@ -194,7 +194,7 @@ void testShouldProduceDeltasAfterSessionResume() throws Exception { * streaming_fidelity/should_not_produce_deltas_after_session_resume_with_streaming_disabled */ @Test - @Disabled("Passes in isolation but times out in full suite due to test interaction (state leakage or process contention)") + @Tag("isolated-resume") void testShouldNotProduceDeltasAfterSessionResumeWithStreamingDisabled() throws Exception { ctx.configureForTest("streaming_fidelity", "should_not_produce_deltas_after_session_resume_with_streaming_disabled");